Hello community,

here is the log from the commit of package bcc for openSUSE:Factory checked in 
at 2017-03-12 20:05:02
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/bcc (Old)
 and      /work/SRC/openSUSE:Factory/.bcc.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "bcc"

Sun Mar 12 20:05:02 2017 rev:5 rq:478085 version:0.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/bcc/bcc.changes  2017-03-03 17:55:02.428090760 
+0100
+++ /work/SRC/openSUSE:Factory/.bcc.new/bcc.changes     2017-03-12 
20:05:04.992560381 +0100
@@ -1,0 +2,18 @@
+Fri Mar 10 02:20:39 UTC 2017 - [email protected]
+
+- Update to 0.3.0
+  + Added s390x support. Needs 4.10 Kernel
+  + Restrict rewrite of unary operators to dereference operator
+  + cmake: Explicitly mark static libraries as such
+  + Fix bpf_dins_pkt rewrite in BinaryOperator
+  + cc: Symbol resolution with multiple executable regions per
+    module
+  + cc: Fix assertion for debug builds
+  + cc: Don't parse the same module multiple times for USDT probes
+  + add XDP return values to python interface
+  + python: handle null module in BPF.sym
+  + filetop: support specifying sort column via cmdline argument
+  + cc: Retry symbol resolution using perfmap
+  + cc: Handle nested functions correctly when resolving symbols
+
+-------------------------------------------------------------------

Old:
----
  bcc-v0.2.0+git1488325605.4d0d430.tar.xz

New:
----
  bcc-v0.3.0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ bcc.spec ++++++
--- /var/tmp/diff_new_pack.9e1EsI/_old  2017-03-12 20:05:05.948425124 +0100
+++ /var/tmp/diff_new_pack.9e1EsI/_new  2017-03-12 20:05:05.948425124 +0100
@@ -16,7 +16,7 @@
 #
 
 
-%define libversion 0.2.0
+%define libversion 0.3.0
 %ifarch ppc64 aarch64 ppc64le
 %{!?with_lua: %global with_lua 0}
 %else
@@ -24,7 +24,7 @@
 %endif
 
 Name:           bcc
-Version:        0.2.0+git1488325605.4d0d430
+Version:        0.3.0
 Release:        0
 Summary:        BPF Compiler Collection (BCC)
 License:        Apache-2.0

++++++ bcc-v0.2.0+git1488325605.4d0d430.tar.xz -> bcc-v0.3.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/.travis.yml 
new/bcc-v0.3.0/.travis.yml
--- old/bcc-v0.2.0+git1488325605.4d0d430/.travis.yml    1970-01-01 
01:00:00.000000000 +0100
+++ new/bcc-v0.3.0/.travis.yml  2017-03-10 03:07:20.000000000 +0100
@@ -0,0 +1,6 @@
+language: generic
+install:
+  - sudo apt-get install -y python-pip
+  - sudo pip install pep8
+script:
+  - find tools/ -type f -name "*.py" | xargs pep8 -r --show-source 
--ignore=E123,E125,E126,E127,E128,E302
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/debian/changelog 
new/bcc-v0.3.0/debian/changelog
--- old/bcc-v0.2.0+git1488325605.4d0d430/debian/changelog       2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/debian/changelog     2017-03-10 03:07:20.000000000 +0100
@@ -1,3 +1,16 @@
+bcc (0.3.0-1) unstable; urgency=low
+
+  * Many bugfixes
+  * Many tools converted to perf ring buffer
+  * New utilities in tools/
+   * capable, cpuunclaimed, dbslower, dbstat, deadlock_detector, llcstat,
+     mountsnoop, runqlen, slabratetop, syscount, tcplife, tcptop, ttysnoop,
+     ucalls, uflow, ugc, uobjnew, ustat, uthreads
+  * New C++ API
+  * Support for kernel up to 4.10
+
+ -- Brenden Blanco <[email protected]>  Thu, 09 Mar 2017 19:08:08 +0000
+
 bcc (0.2.0-1) unstable; urgency=low
 
   * Add many new utilities in tools/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/debian/rules 
new/bcc-v0.3.0/debian/rules
--- old/bcc-v0.2.0+git1488325605.4d0d430/debian/rules   2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/debian/rules 2017-03-10 03:07:20.000000000 +0100
@@ -11,6 +11,10 @@
 %:
        dh $@ --buildsystem=cmake --parallel
 
+# tests cannot be run in parallel
+override_dh_auto_test:
+       dh_auto_test -O--buildsystem=cmake -O--no-parallel
+
 # FIXME: LLVM_DEFINITIONS is broken somehow in LLVM cmake upstream
 override_dh_auto_configure:
        dh_auto_configure -- -DREVISION_LAST=$(UPSTREAM_VERSION) 
-DREVISION=$(UPSTREAM_VERSION) -DLLVM_DEFINITIONS="-D_GNU_SOURCE 
-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/docs/tutorial_bcc_python_developer.md 
new/bcc-v0.3.0/docs/tutorial_bcc_python_developer.md
--- old/bcc-v0.2.0+git1488325605.4d0d430/docs/tutorial_bcc_python_developer.md  
2017-03-01 00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/docs/tutorial_bcc_python_developer.md        2017-03-10 
03:07:20.000000000 +0100
@@ -96,7 +96,7 @@
 
 1. ```b.attach_kprobe(event="sys_clone", fn_name="hello")```: Creates a kprobe 
for the sys_clone() kernel function, which will execute our defined hello() 
function. You can call attach_kprobe() more than once, and attach your C 
function to multiple kernel functions.
 
-1. ```b.trace_fields()```: Returns a fixed set of fields from trace_pipe. 
Simalar to trace_print(), this is handy for hacking, but for real tooling we 
should switch to BPF_PERF_OUTPUT().
+1. ```b.trace_fields()```: Returns a fixed set of fields from trace_pipe. 
Similar to trace_print(), this is handy for hacking, but for real tooling we 
should switch to BPF_PERF_OUTPUT().
 
 ### Lesson 4. sync_timing.py
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/man/man8/filetop.8 
new/bcc-v0.3.0/man/man8/filetop.8
--- old/bcc-v0.2.0+git1488325605.4d0d430/man/man8/filetop.8     2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/man/man8/filetop.8   2017-03-10 03:07:20.000000000 +0100
@@ -2,14 +2,15 @@
 .SH NAME
 filetop \- File reads and writes by filename and process. Top for files.
 .SH SYNOPSIS
-.B filetop [\-h] [\-C] [\-r MAXROWS] [\-p PID] [interval] [count]
+.B filetop [\-h] [\-C] [\-r MAXROWS] [\-s {reads,writes,rbytes,wbytes}] [\-p 
PID] [interval] [count]
 .SH DESCRIPTION
 This is top for files.
 
-This traces file reads and writes, and prints a per-file summary every
-interval (by default, 1 second). The summary is sorted on the highest read
-throughput (Kbytes). By default only IO on regular files is shown. The -a
-option will list all file types (sokets, FIFOs, etc).
+This traces file reads and writes, and prints a per-file summary every interval
+(by default, 1 second). By default the summary is sorted on the highest read
+throughput (Kbytes). Sorting order can be changed via -s option. By default 
only
+IO on regular files is shown. The -a option will list all file types (sokets,
+FIFOs, etc).
 
 This uses in-kernel eBPF maps to store per process summaries for efficiency.
 
@@ -39,6 +40,9 @@
 \-r MAXROWS
 Maximum number of rows to print. Default is 20.
 .TP
+\-s {reads,writes,rbytes,wbytes}
+Sort column. Default is rbytes (read throughput).
+.TP
 \-p PID
 Trace this PID only.
 .TP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/CMakeLists.txt 
new/bcc-v0.3.0/src/cc/CMakeLists.txt
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/CMakeLists.txt  2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/cc/CMakeLists.txt        2017-03-10 03:07:20.000000000 
+0100
@@ -39,7 +39,7 @@
 set_target_properties(bcc-shared PROPERTIES VERSION ${REVISION_LAST} SOVERSION 
0)
 set_target_properties(bcc-shared PROPERTIES OUTPUT_NAME bcc)
 
-add_library(bcc-loader-static libbpf.c perf_reader.c bcc_elf.c bcc_perf_map.c 
bcc_proc.c)
+add_library(bcc-loader-static STATIC libbpf.c perf_reader.c bcc_elf.c 
bcc_perf_map.c bcc_proc.c)
 add_library(bcc-static STATIC bpf_common.cc bpf_module.cc shared_table.cc 
exported_files.cc bcc_syms.cc usdt_args.cc usdt.cc common.cc BPF.cc BPFTable.cc)
 set_target_properties(bcc-static PROPERTIES OUTPUT_NAME bcc)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/bcc_syms.cc 
new/bcc-v0.3.0/src/cc/bcc_syms.cc
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/bcc_syms.cc     2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/cc/bcc_syms.cc   2017-03-10 03:07:20.000000000 +0100
@@ -101,7 +101,11 @@
 int ProcSyms::_add_module(const char *modname, uint64_t start, uint64_t end,
                           void *payload) {
   ProcSyms *ps = static_cast<ProcSyms *>(payload);
-  ps->modules_.emplace_back(modname, start, end);
+  auto it = std::find_if(ps->modules_.begin(), ps->modules_.end(),
+               [=](const ProcSyms::Module &m) { return m.name_ == modname; });
+  if (it == ps->modules_.end())
+    it = ps->modules_.insert(ps->modules_.end(), modname);
+  it->ranges_.push_back(ProcSyms::Module::Range(start, end));
   return 0;
 }
 
@@ -114,15 +118,30 @@
   sym->demangle_name = nullptr;
   sym->offset = 0x0;
 
+  const char *original_module = nullptr;
   for (Module &mod : modules_) {
-    if (addr >= mod.start_ && addr < mod.end_) {
+    if (mod.contains(addr)) {
       bool res = mod.find_addr(addr, sym);
       if (sym->name) {
         sym->demangle_name = abi::__cxa_demangle(sym->name, nullptr, nullptr, 
nullptr);
         if (!sym->demangle_name)
           sym->demangle_name = sym->name;
       }
-      return res;
+      // If we have a match, return right away. But if we don't have a match in
+      // this module, we might have a match in the perf map (even though the
+      // module itself doesn't have symbols). Wait until we see the perf map if
+      // any, but keep the original module name for reporting.
+      if (res) {
+        // If we have already seen this module, report the original name rather
+        // than the perf map name:
+        if (original_module)
+          sym->module = original_module;
+        return res;
+      } else {
+        // Record the module to which this symbol belongs, so that even if it's
+        // later found using a perf map, we still report the right module name.
+        original_module = mod.name_.c_str();
+      }
     }
   }
   return false;
@@ -140,8 +159,8 @@
   return false;
 }
 
-ProcSyms::Module::Module(const char *name, uint64_t start, uint64_t end)
-  : name_(name), start_(start), end_(end) {
+ProcSyms::Module::Module(const char *name)
+  : name_(name) {
   is_so_ = bcc_elf_is_shared_obj(name) == 1;
 }
 
@@ -169,12 +188,20 @@
   std::sort(syms_.begin(), syms_.end());
 }
 
+bool ProcSyms::Module::contains(uint64_t addr) const {
+  for (const auto &range : ranges_) {
+    if (addr >= range.start && addr < range.end)
+      return true;
+  }
+  return false;
+}
+
 bool ProcSyms::Module::find_name(const char *symname, uint64_t *addr) {
   load_sym_table();
 
   for (Symbol &s : syms_) {
     if (*(s.name) == symname) {
-      *addr = is_so() ? start_ + s.start : s.start;
+      *addr = is_so() ? start() + s.start : s.start;
       return true;
     }
   }
@@ -182,7 +209,7 @@
 }
 
 bool ProcSyms::Module::find_addr(uint64_t addr, struct bcc_symbol *sym) {
-  uint64_t offset = is_so() ? (addr - start_) : addr;
+  uint64_t offset = is_so() ? (addr - start()) : addr;
 
   load_sym_table();
 
@@ -190,16 +217,34 @@
   sym->offset = offset;
 
   auto it = std::upper_bound(syms_.begin(), syms_.end(), Symbol(nullptr, 
offset, 0));
-  if (it != syms_.begin())
-    --it;
-  else
-    it = syms_.end();
+  if (it == syms_.begin())
+    return false;
 
-  if (it != syms_.end()
-      && offset >= it->start && offset < it->start + it->size) {
-    sym->name = it->name->c_str();
-    sym->offset = (offset - it->start);
-    return true;
+  // 'it' points to the symbol whose start address is strictly greater than
+  // the address we're looking for. Start stepping backwards as long as the
+  // current symbol is still below the desired address, and see if the end
+  // of the current symbol (start + size) is above the desired address. Once
+  // we have a matching symbol, return it. Note that simply looking at '--it'
+  // is not enough, because symbols can be nested. For example, we could be
+  // looking for offset 0x12 with the following symbols available:
+  // SYMBOL   START   SIZE    END
+  // goo      0x0     0x6     0x0 + 0x6 = 0x6
+  // foo      0x6     0x10    0x6 + 0x10 = 0x16
+  // bar      0x8     0x4     0x8 + 0x4 = 0xc
+  // baz      0x16    0x10    0x16 + 0x10 = 0x26
+  // The upper_bound lookup will return baz, and then going one symbol back
+  // brings us to bar, which does not contain offset 0x12 and is nested inside
+  // foo. Going back one more symbol brings us to foo, which contains 0x12
+  // and is a match.
+  for (--it; offset >= it->start; --it) {
+    if (offset < it->start + it->size) {
+      sym->name = it->name->c_str();
+      sym->offset = (offset - it->start);
+      return true;
+    }
+    // But don't step beyond begin()!
+    if (it == syms_.begin())
+      break;
   }
 
   return false;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/export/helpers.h 
new/bcc-v0.3.0/src/cc/export/helpers.h
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/export/helpers.h        
2017-03-01 00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/cc/export/helpers.h      2017-03-10 03:07:20.000000000 
+0100
@@ -468,6 +468,17 @@
 #define PT_REGS_RC(ctx)                ((ctx)->gpr[3])
 #define PT_REGS_IP(ctx)                ((ctx)->nip)
 #define PT_REGS_SP(ctx)                ((ctx)->sp)
+#elif defined(__s390x__)
+#define PT_REGS_PARM1(x) ((x)->gprs[2])
+#define PT_REGS_PARM2(x) ((x)->gprs[3])
+#define PT_REGS_PARM3(x) ((x)->gprs[4])
+#define PT_REGS_PARM4(x) ((x)->gprs[5])
+#define PT_REGS_PARM5(x) ((x)->gprs[6])
+#define PT_REGS_RET(x) ((x)->gprs[14])
+#define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER 
*/
+#define PT_REGS_RC(x) ((x)->gprs[2])
+#define PT_REGS_SP(x) ((x)->gprs[15])
+#define PT_REGS_IP(x) ((x)->psw.addr)
 #elif defined(__x86_64__)
 #define PT_REGS_PARM1(ctx)     ((ctx)->di)
 #define PT_REGS_PARM2(ctx)     ((ctx)->si)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/b/CMakeLists.txt 
new/bcc-v0.3.0/src/cc/frontends/b/CMakeLists.txt
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/b/CMakeLists.txt      
2017-03-01 00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/cc/frontends/b/CMakeLists.txt    2017-03-10 
03:07:20.000000000 +0100
@@ -11,5 +11,5 @@
   set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/lexer.ll.cc 
PROPERTIES COMPILE_FLAGS "-Wno-deprecated-register")
 endif()
 
-add_library(b_frontend loader.cc codegen_llvm.cc node.cc parser.cc printer.cc
+add_library(b_frontend STATIC loader.cc codegen_llvm.cc node.cc parser.cc 
printer.cc
   type_check.cc ${BISON_Parser_OUTPUTS} ${FLEX_Lexer_OUTPUTS})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/CMakeLists.txt 
new/bcc-v0.3.0/src/cc/frontends/clang/CMakeLists.txt
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/CMakeLists.txt  
2017-03-01 00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/cc/frontends/clang/CMakeLists.txt        2017-03-10 
03:07:20.000000000 +0100
@@ -2,4 +2,4 @@
 # Licensed under the Apache License, Version 2.0 (the "License")
 
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} 
-DKERNEL_MODULES_DIR='\"${BCC_KERNEL_MODULES_DIR}\"'")
-add_library(clang_frontend loader.cc b_frontend_action.cc 
tp_frontend_action.cc kbuild_helper.cc ../../common.cc)
+add_library(clang_frontend STATIC loader.cc b_frontend_action.cc 
tp_frontend_action.cc kbuild_helper.cc ../../common.cc)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/b_frontend_action.cc
 new/bcc-v0.3.0/src/cc/frontends/clang/b_frontend_action.cc
--- 
old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/b_frontend_action.cc
    2017-03-01 00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/cc/frontends/clang/b_frontend_action.cc  2017-03-10 
03:07:20.000000000 +0100
@@ -39,11 +39,17 @@
 };
 const char *calling_conv_regs_ppc[] = {"gpr[3]", "gpr[4]", "gpr[5]",
                                        "gpr[6]", "gpr[7]", "gpr[8]"};
+
+const char *calling_conv_regs_s390x[] = {"gprs[2]", "gprs[3]", "gprs[4]",
+                                        "gprs[5]", "gprs[6]" };
+
 const char *calling_conv_regs_arm64[] = {"regs[0]", "regs[1]", "regs[2]",
                                        "regs[3]", "regs[4]", "regs[5]"};
 // todo: support more archs
 #if defined(__powerpc__)
 const char **calling_conv_regs = calling_conv_regs_ppc;
+#elif defined(__s390x__)
+const char **calling_conv_regs = calling_conv_regs_s390x;
 #elif defined(__aarch64__)
 const char **calling_conv_regs = calling_conv_regs_arm64;
 #else
@@ -200,7 +206,7 @@
   return true;
 }
 bool ProbeVisitor::VisitUnaryOperator(UnaryOperator *E) {
-  if (E->getOpcode() == UO_AddrOf)
+  if (E->getOpcode() != UO_Deref)
     return true;
   if (memb_visited_.find(E) != memb_visited_.end())
     return true;
@@ -521,7 +527,6 @@
   if (!E->isAssignmentOp())
     return true;
   Expr *LHS = E->getLHS()->IgnoreImplicit();
-  Expr *RHS = E->getRHS()->IgnoreImplicit();
   if (MemberExpr *Memb = dyn_cast<MemberExpr>(LHS)) {
     if (DeclRefExpr *Base = 
dyn_cast<DeclRefExpr>(Memb->getBase()->IgnoreImplicit())) {
       if (DeprecatedAttr *A = Base->getDecl()->getAttr<DeprecatedAttr>()) {
@@ -534,10 +539,10 @@
             uint64_t ofs = C.getFieldOffset(F);
             uint64_t sz = F->isBitField() ? F->getBitWidthValue(C) : 
C.getTypeSize(F->getType());
             string base = 
rewriter_.getRewrittenText(expansionRange(Base->getSourceRange()));
-            string rhs = 
rewriter_.getRewrittenText(expansionRange(RHS->getSourceRange()));
             string text = "bpf_dins_pkt(" + fn_args_[0]->getName().str() + ", 
(u64)" + base + "+" + to_string(ofs >> 3)
-                + ", " + to_string(ofs & 0x7) + ", " + to_string(sz) + ", " + 
rhs + ")";
-            rewriter_.ReplaceText(expansionRange(E->getSourceRange()), text);
+                + ", " + to_string(ofs & 0x7) + ", " + to_string(sz) + ",";
+            rewriter_.ReplaceText(expansionRange(SourceRange(E->getLocStart(), 
E->getOperatorLoc())), text);
+            rewriter_.InsertTextAfterToken(E->getLocEnd(), ")");
           }
         }
       }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/loader.cc 
new/bcc-v0.3.0/src/cc/frontends/clang/loader.cc
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/loader.cc       
2017-03-01 00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/cc/frontends/clang/loader.cc     2017-03-10 
03:07:20.000000000 +0100
@@ -172,6 +172,8 @@
 #else
   driver::Driver drv("", "powerpc64-unknown-linux-gnu", diags);
 #endif
+#elif defined(__s390x__)
+  driver::Driver drv("", "s390x-ibm-linux-gnu", diags);
 #elif defined(__aarch64__)
   driver::Driver drv("", "aarch64-unknown-linux-gnu", diags);
 #else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/libbpf.c 
new/bcc-v0.3.0/src/cc/libbpf.c
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/libbpf.c        2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/cc/libbpf.c      2017-03-10 03:07:20.000000000 +0100
@@ -46,6 +46,8 @@
 #ifndef __NR_bpf
 #if defined(__powerpc64__)
 #define __NR_bpf 361
+#elif defined(__s390x__)
+#define __NR_bpf 351
 #elif defined(__aarch64__)
 #define __NR_bpf 280
 #else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/syms.h 
new/bcc-v0.3.0/src/cc/syms.h
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/syms.h  2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/cc/syms.h        2017-03-10 03:07:20.000000000 +0100
@@ -79,15 +79,22 @@
   };
 
   struct Module {
-    Module(const char *name, uint64_t start, uint64_t end);
+    struct Range {
+      uint64_t start;
+      uint64_t end;
+      Range(uint64_t s, uint64_t e) : start(s), end(e) {}
+    };
+
+    Module(const char *name);
     std::string name_;
-    uint64_t start_;
-    uint64_t end_;
+    std::vector<Range> ranges_;
     bool is_so_;
     std::unordered_set<std::string> symnames_;
     std::vector<Symbol> syms_;
 
     void load_sym_table();
+    bool contains(uint64_t addr) const;
+    uint64_t start() const { return ranges_.begin()->start; }
     bool find_addr(uint64_t addr, struct bcc_symbol *sym);
     bool find_name(const char *symname, uint64_t *addr);
     bool is_so() const { return is_so_; }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/usdt.cc 
new/bcc-v0.3.0/src/cc/usdt.cc
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/usdt.cc 2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/cc/usdt.cc       2017-03-10 03:07:20.000000000 +0100
@@ -63,7 +63,7 @@
 }
 
 bool Probe::add_to_semaphore(int16_t val) {
-  assert(pid_ && attached_semaphore_);
+  assert(pid_);
 
   if (!attached_semaphore_) {
     uint64_t addr;
@@ -200,7 +200,13 @@
 }
 
 int Context::_each_module(const char *modpath, uint64_t, uint64_t, void *p) {
-  bcc_elf_foreach_usdt(modpath, _each_probe, p);
+  Context *ctx = static_cast<Context *>(p);
+  // Modules may be reported multiple times if they contain more than one
+  // executable region. We are going to parse the ELF on disk anyway, so we
+  // don't need these duplicates.
+  if (ctx->modules_.insert(modpath).second /*inserted new?*/) {
+    bcc_elf_foreach_usdt(modpath, _each_probe, p);
+  }
   return 0;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/usdt.h 
new/bcc-v0.3.0/src/cc/usdt.h
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/usdt.h  2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/cc/usdt.h        2017-03-10 03:07:20.000000000 +0100
@@ -191,6 +191,7 @@
 
 class Context {
   std::vector<std::unique_ptr<Probe>> probes_;
+  std::unordered_set<std::string> modules_;
 
   optional<int> pid_;
   optional<ProcStat> pid_stat_;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/src/python/bcc/__init__.py 
new/bcc-v0.3.0/src/python/bcc/__init__.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/python/bcc/__init__.py     
2017-03-01 00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/python/bcc/__init__.py   2017-03-10 03:07:20.000000000 
+0100
@@ -118,6 +118,12 @@
     XDP = 6
     PERF_EVENT = 7
 
+    # from xdp_action uapi/linux/bpf.h
+    XDP_ABORTED = 0
+    XDP_DROP = 1
+    XDP_PASS = 2
+    XDP_TX = 3
+
     _probe_repl = re.compile("[^a-zA-Z0-9_]")
     _sym_caches = {}
 
@@ -989,12 +995,12 @@
         returned. When show_module is True, the module name is also included.
         When show_offset is True, the instruction offset as a hexadecimal
         number is also included in the string.
-        
+
         A pid of less than zero will access the kernel symbol cache.
 
         Example output when both show_module and show_offset are True:
             "start_thread+0x202 [libpthread-2.24.so]"
-        
+
         Example output when both show_module and show_offset are False:
             "start_thread"
         """
@@ -1002,7 +1008,8 @@
         offset = "+0x%x" % offset if show_offset and name is not None else ""
         name = name or "[unknown]"
         name = name + offset
-        module = " [%s]" % os.path.basename(module) if show_module else ""
+        module = " [%s]" % os.path.basename(module) \
+            if show_module and module is not None else ""
         return name + module
 
     @staticmethod
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/src/python/bcc/usdt.py 
new/bcc-v0.3.0/src/python/bcc/usdt.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/src/python/bcc/usdt.py 2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/src/python/bcc/usdt.py       2017-03-10 03:07:20.000000000 
+0100
@@ -130,7 +130,7 @@
                 raise USDTException("USDT failed to instrument PID %d" % pid)
         elif path:
             self.path = path
-            self.context = lib.bcc_usdt_new_frompath(path)
+            self.context = lib.bcc_usdt_new_frompath(path.encode('ascii'))
             if self.context == None:
                 raise USDTException("USDT failed to instrument path %s" % path)
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/tests/python/test_clang.py 
new/bcc-v0.3.0/tests/python/test_clang.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tests/python/test_clang.py     
2017-03-01 00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tests/python/test_clang.py   2017-03-10 03:07:20.000000000 
+0100
@@ -392,5 +392,35 @@
         t = b["act"]
         self.assertEquals(len(t), 32);
 
+    def test_bpf_dins_pkt_rewrite(self):
+        text = """
+#include <bcc/proto.h>
+int dns_test(struct __sk_buff *skb) {
+    u8 *cursor = 0;
+    struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
+    if(ethernet->type == ETH_P_IP) {
+        struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
+        ip->src = ip->dst;
+        return 0;
+    }
+    return -1;
+}
+        """
+        b = BPF(text=text)
+
+    def test_unary_operator(self):
+        text = """
+#include <linux/fs.h>
+#include <uapi/linux/ptrace.h>
+int trace_read_entry(struct pt_regs *ctx, struct file *file) {
+    return !file->f_op->read_iter;
+}
+        """
+        b = BPF(text=text)
+        b.attach_kprobe(event="__vfs_read", fn_name="trace_read_entry")
+
 if __name__ == "__main__":
     main()
+
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/argdist.py 
new/bcc-v0.3.0/tools/argdist.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/argdist.py       2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/argdist.py     2017-03-10 03:07:20.000000000 +0100
@@ -200,7 +200,7 @@
                 elif self.probe_type == "u":
                         self.library = parts[1]
                         self.probe_func_name = self._make_valid_identifier(
-                                "%s_probe%d" % \
+                                "%s_probe%d" %
                                 (self.function, Probe.next_probe_index))
                         self._enable_usdt_probe()
                 else:
@@ -238,10 +238,10 @@
                         (any(map(check, self.exprs)) or check(self.filter))
 
                 self.probe_func_name = self._make_valid_identifier(
-                        "%s_probe%d" % \
+                        "%s_probe%d" %
                         (self.function, Probe.next_probe_index))
                 self.probe_hash_name = self._make_valid_identifier(
-                        "%s_hash%d" % \
+                        "%s_hash%d" %
                         (self.function, Probe.next_probe_index))
                 Probe.next_probe_index += 1
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/tools/cpuunclaimed.py 
new/bcc-v0.3.0/tools/cpuunclaimed.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/cpuunclaimed.py  2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/cpuunclaimed.py        2017-03-10 03:07:20.000000000 
+0100
@@ -169,10 +169,10 @@
     if args.timestamp:
         print("TIME", end=",")
     print("TIMESTAMP_ns", end=",")
-    print(",".join("CPU" + str(c) for c in xrange(ncpu)), end="")
+    print(",".join("CPU" + str(c) for c in range(ncpu)), end="")
     if args.fullcsv:
         print(",", end="")
-        print(",".join("OFFSET_ns_CPU" + str(c) for c in xrange(ncpu)), end="")
+        print(",".join("OFFSET_ns_CPU" + str(c) for c in range(ncpu)), end="")
     print()
 else:
     print(("Sampling run queues... Output every %s seconds. " +
@@ -255,10 +255,10 @@
                     if args.timestamp:
                         print("%-8s" % strftime("%H:%M:%S"), end=",")
                     print("%d" % g_time, end=",")
-                    print(",".join(str(lens[c]) for c in xrange(ncpu)), end="")
+                    print(",".join(str(lens[c]) for c in range(ncpu)), end="")
                     if args.fullcsv:
                         print(",", end="")
-                        print(",".join(str(offs[c]) for c in xrange(ncpu)))
+                        print(",".join(str(offs[c]) for c in range(ncpu)))
                     else:
                         print()
             else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/dbslower.py 
new/bcc-v0.3.0/tools/dbslower.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/dbslower.py      2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/dbslower.py    2017-03-10 03:07:20.000000000 +0100
@@ -13,7 +13,7 @@
 #
 # Strongly inspired by Brendan Gregg's work on the mysqld_qslower script.
 #
-# Copyright 2017, Sasha Goldshtein 
+# Copyright 2017, Sasha Goldshtein
 # Licensed under the Apache License, Version 2.0
 #
 # 15-Feb-2017   Sasha Goldshtein   Created this.
@@ -27,7 +27,7 @@
     dbslower postgres            # trace PostgreSQL queries slower than 1ms
     dbslower postgres -p 188 322 # trace specific PostgreSQL processes
     dbslower mysql -p 480 -m 30  # trace MySQL queries slower than 30ms
-    dbslower mysql -p 480 -v     # trace MySQL queries and print the BPF 
program
+    dbslower mysql -p 480 -v     # trace MySQL queries & print the BPF program
 """
 parser = argparse.ArgumentParser(
     description="",
@@ -134,4 +134,3 @@
 bpf["events"].open_perf_buffer(print_event, page_cnt=64)
 while True:
     bpf.kprobe_poll()
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/dbstat.py 
new/bcc-v0.3.0/tools/dbstat.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/dbstat.py        2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/dbstat.py      2017-03-10 03:07:20.000000000 +0100
@@ -8,7 +8,7 @@
 # This tool uses USDT probes, which means it needs MySQL and PostgreSQL built
 # with USDT (DTrace) support.
 #
-# Copyright 2017, Sasha Goldshtein 
+# Copyright 2017, Sasha Goldshtein
 # Licensed under the Apache License, Version 2.0
 #
 # 15-Feb-2017   Sasha Goldshtein   Created this.
@@ -80,7 +80,7 @@
 }
 """
 program = program.replace("SCALE", str(1000 if args.microseconds else 1000000))
-program = program.replace("FILTER", "" if args.threshold == 0 else \
+program = program.replace("FILTER", "" if args.threshold == 0 else
         "if (delta / 1000000 < %d) { return 0; }" % args.threshold)
 
 usdts = map(lambda pid: USDT(pid=pid), args.pids)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/filetop.py 
new/bcc-v0.3.0/tools/filetop.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/filetop.py       2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/filetop.py     2017-03-10 03:07:20.000000000 +0100
@@ -38,6 +38,9 @@
     help="don't clear the screen")
 parser.add_argument("-r", "--maxrows", default=20,
     help="maximum rows to print, default 20")
+parser.add_argument("-s", "--sort", default="rbytes",
+    choices=["reads", "writes", "rbytes", "wbytes"],
+    help="sort column, default rbytes")
 parser.add_argument("-p", "--pid", type=int, metavar="PID", dest="tgid",
     help="trace this PID only")
 parser.add_argument("interval", nargs="?", default=1,
@@ -184,7 +187,8 @@
     counts = b.get_table("counts")
     line = 0
     for k, v in reversed(sorted(counts.items(),
-                                key=lambda counts: counts[1].rbytes)):
+                                key=lambda counts:
+                                  getattr(counts[1], args.sort))):
         name = k.name.decode()
         if k.name_len > DNAME_INLINE_LEN:
             name = name[:-3] + "..."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/tools/filetop_example.txt 
new/bcc-v0.3.0/tools/filetop_example.txt
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/filetop_example.txt      
2017-03-01 00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/filetop_example.txt    2017-03-10 03:07:20.000000000 
+0100
@@ -29,10 +29,11 @@
 26628  ld               12     0      52      0       R swap.o
 [...]
 
-This shows various files read and written during a Linux kernel build. The
-output is sorted by the total read size in Kbytes (R_Kb). This is instrumenting
-at the VFS interface, so this is reads and writes that may return entirely
-from the file system cache (page cache).
+This shows various files read and written during a Linux kernel build. By
+default the output is sorted by the total read size in Kbytes (R_Kb). Sorting
+order can be changed via -s option. This is instrumenting at the VFS interface,
+so this is reads and writes that may return entirely from the file system cache
+(page cache).
 
 While not printed, the average read and write size can be calculated by
 dividing R_Kb by READS, and the same for writes.
@@ -146,6 +147,8 @@
   -C, --noclear         don't clear the screen
   -r MAXROWS, --maxrows MAXROWS
                         maximum rows to print, default 20
+  -s {reads,writes,rbytes,wbytes}, --sort {reads,writes,rbytes,wbytes}
+                        sort column, default rbytes
   -p PID, --pid PID     trace this PID only
 
 examples:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/tools/funclatency.py 
new/bcc-v0.3.0/tools/funclatency.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/funclatency.py   2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/funclatency.py 2017-03-10 03:07:20.000000000 +0100
@@ -90,7 +90,6 @@
 # define BPF program
 bpf_text = """
 #include <uapi/linux/ptrace.h>
-#include <linux/blkdev.h>
 
 typedef struct ip_pid {
     u64 ip;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/tools/old/memleak.py 
new/bcc-v0.3.0/tools/old/memleak.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/old/memleak.py   2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/old/memleak.py 2017-03-10 03:07:20.000000000 +0100
@@ -186,8 +186,9 @@
         allocs.update(&address, &info);
 
         if (SHOULD_PRINT) {
-                bpf_trace_printk("alloc exited, size = %lu, result = %lx, 
frames = %d\\n",
-                                 info.size, address, info.num_frames);
+                bpf_trace_printk("alloc exited, size = %lu, result = %lx,"
+                                 "frames = %d\\n", info.size, address,
+                                 info.num_frames);
         }
         return 0;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/bcc-v0.2.0+git1488325605.4d0d430/tools/old/offwaketime.py 
new/bcc-v0.3.0/tools/old/offwaketime.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/old/offwaketime.py       
1970-01-01 01:00:00.000000000 +0100
+++ new/bcc-v0.3.0/tools/old/offwaketime.py     2017-03-10 03:07:20.000000000 
+0100
@@ -0,0 +1,284 @@
+#!/usr/bin/python
+#
+# offwaketime   Summarize blocked time by kernel off-CPU stack + waker stack
+#               For Linux, uses BCC, eBPF.
+#
+# USAGE: offwaketime [-h] [-u] [-p PID] [-T] [duration]
+#
+# The current implementation uses an unrolled loop for x86_64, and was written
+# as a proof of concept. This implementation should be replaced in the future
+# with an appropriate bpf_ call, when available.
+#
+# The Off-CPU stack is currently limited to a stack trace depth of 20
+# (maxtdepth), and the waker stack limited to 10 (maxwdepth). This is also
+# limited to kernel stacks, and x86_64 only. Check for future versions, where
+# these limitations should be removed.
+#
+# Copyright 2016 Netflix, Inc.
+# Licensed under the Apache License, Version 2.0 (the "License")
+#
+# 20-Jan-2016   Brendan Gregg   Created this.
+
+from __future__ import print_function
+from bcc import BPF
+from time import sleep
+import argparse
+import signal
+
+# arguments
+examples = """examples:
+    ./offwaketime             # trace off-CPU + waker stack time until Ctrl-C
+    ./offwaketime 5           # trace for 5 seconds only
+    ./offwaketime -f 5        # 5 seconds, and output in folded format
+    ./offwaketime -u          # don't include kernel threads (user only)
+    ./offwaketime -p 185      # trace fo PID 185 only
+"""
+parser = argparse.ArgumentParser(
+    description="Summarize blocked time by kernel stack trace + waker stack",
+    formatter_class=argparse.RawDescriptionHelpFormatter,
+    epilog=examples)
+parser.add_argument("-u", "--useronly", action="store_true",
+    help="user threads only (no kernel threads)")
+parser.add_argument("-p", "--pid",
+    help="trace this PID only")
+parser.add_argument("-v", "--verbose", action="store_true",
+    help="show raw addresses")
+parser.add_argument("-f", "--folded", action="store_true",
+    help="output folded format")
+parser.add_argument("duration", nargs="?", default=99999999,
+    help="duration of trace, in seconds")
+args = parser.parse_args()
+folded = args.folded
+duration = int(args.duration)
+debug = 0
+maxwdepth = 10    # and MAXWDEPTH
+maxtdepth = 20    # and MAXTDEPTH
+if args.pid and args.useronly:
+    print("ERROR: use either -p or -u.")
+    exit()
+
+# signal handler
+def signal_ignore(signal, frame):
+    print()
+
+# define BPF program
+bpf_text = """
+#include <uapi/linux/ptrace.h>
+#include <linux/sched.h>
+
+#define MAXWDEPTH      10
+#define MAXTDEPTH      20
+#define MINBLOCK_US    1
+
+struct key_t {
+    char waker[TASK_COMM_LEN];
+    char target[TASK_COMM_LEN];
+    u64 wret[MAXWDEPTH];
+    u64 tret[MAXTDEPTH];
+};
+BPF_HASH(counts, struct key_t);
+BPF_HASH(start, u32);
+struct wokeby_t {
+    char name[TASK_COMM_LEN];
+    u64 ret[MAXWDEPTH];
+};
+BPF_HASH(wokeby, u32, struct wokeby_t);
+
+static u64 get_frame(u64 *bp) {
+    if (*bp) {
+        // The following stack walker is x86_64 specific
+        u64 ret = 0;
+        if (bpf_probe_read(&ret, sizeof(ret), (void *)(*bp+8)))
+            return 0;
+        if (bpf_probe_read(bp, sizeof(*bp), (void *)*bp))
+            *bp = 0;
+        if (ret < __START_KERNEL_map)
+            return 0;
+        return ret;
+    }
+    return 0;
+}
+
+int waker(struct pt_regs *ctx, struct task_struct *p) {
+    u32 pid = p->pid;
+
+    if (!(FILTER))
+        return 0;
+
+    u64 bp = 0;
+    struct wokeby_t woke = {};
+    int depth = 0;
+    bpf_get_current_comm(&woke.name, sizeof(woke.name));
+    bp = ctx->bp;
+
+    // unrolled loop (MAXWDEPTH):
+    if (!(woke.ret[depth++] = get_frame(&bp))) goto out;
+    if (!(woke.ret[depth++] = get_frame(&bp))) goto out;
+    if (!(woke.ret[depth++] = get_frame(&bp))) goto out;
+    if (!(woke.ret[depth++] = get_frame(&bp))) goto out;
+    if (!(woke.ret[depth++] = get_frame(&bp))) goto out;
+    if (!(woke.ret[depth++] = get_frame(&bp))) goto out;
+    if (!(woke.ret[depth++] = get_frame(&bp))) goto out;
+    if (!(woke.ret[depth++] = get_frame(&bp))) goto out;
+    if (!(woke.ret[depth++] = get_frame(&bp))) goto out;
+    woke.ret[depth] = get_frame(&bp);
+
+out:
+    wokeby.update(&pid, &woke);
+    return 0;
+}
+
+int oncpu(struct pt_regs *ctx, struct task_struct *p) {
+    u32 pid = p->pid;
+    u64 ts, *tsp;
+
+    // record previous thread sleep time
+    if (FILTER) {
+        ts = bpf_ktime_get_ns();
+        start.update(&pid, &ts);
+    }
+
+    // calculate current thread's delta time
+    pid = bpf_get_current_pid_tgid();
+    tsp = start.lookup(&pid);
+    if (tsp == 0)
+        return 0;        // missed start or filtered
+    u64 delta = bpf_ktime_get_ns() - *tsp;
+    start.delete(&pid);
+    delta = delta / 1000;
+    if (delta < MINBLOCK_US)
+        return 0;
+
+    // create map key
+    u64 zero = 0, *val, bp = 0;
+    int depth = 0;
+    struct key_t key = {};
+    struct wokeby_t *woke;
+    bpf_get_current_comm(&key.target, sizeof(key.target));
+    bp = ctx->bp;
+
+    // unrolled loop (MAXTDEPTH):
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    if (!(key.tret[depth++] = get_frame(&bp))) goto out;
+    key.tret[depth] = get_frame(&bp);
+
+out:
+    woke = wokeby.lookup(&pid);
+    if (woke) {
+        __builtin_memcpy(&key.wret, woke->ret, sizeof(key.wret));
+        __builtin_memcpy(&key.waker, woke->name, TASK_COMM_LEN);
+        wokeby.delete(&pid);
+    }
+
+    val = counts.lookup_or_init(&key, &zero);
+    (*val) += delta;
+    return 0;
+}
+"""
+if args.pid:
+    filter = 'pid == %s' % args.pid
+elif args.useronly:
+    filter = '!(p->flags & PF_KTHREAD)'
+else:
+    filter = '1'
+bpf_text = bpf_text.replace('FILTER', filter)
+if debug:
+    print(bpf_text)
+
+# initialize BPF
+b = BPF(text=bpf_text)
+b.attach_kprobe(event="finish_task_switch", fn_name="oncpu")
+b.attach_kprobe(event="try_to_wake_up", fn_name="waker")
+matched = b.num_open_kprobes()
+if matched == 0:
+    print("0 functions traced. Exiting.")
+    exit()
+
+# header
+if not folded:
+    print("Tracing blocked time (us) by kernel off-CPU and waker stack",
+        end="")
+    if duration < 99999999:
+        print(" for %d secs." % duration)
+    else:
+        print("... Hit Ctrl-C to end.")
+
+# output
+while (1):
+    try:
+        sleep(duration)
+    except KeyboardInterrupt:
+        # as cleanup can take many seconds, trap Ctrl-C:
+        signal.signal(signal.SIGINT, signal_ignore)
+
+    if not folded:
+        print()
+    counts = b.get_table("counts")
+    for k, v in sorted(counts.items(), key=lambda counts: counts[1].value):
+        if folded:
+            # fold target stack
+            line = k.target + ";"
+            for i in reversed(range(0, maxtdepth)):
+                if k.tret[i] == 0:
+                    continue
+                line = line + b.ksym(k.tret[i])
+                if i != 0:
+                    line = line + ";"
+
+            # add delimiter
+            line = line + ";-"
+
+            # fold waker stack
+            for i in range(0, maxwdepth):
+                line = line + ";"
+                if k.wret[i] == 0:
+                    break
+                line = line + b.ksym(k.wret[i])
+            if i != 0:
+                line = line + ";" + k.waker
+
+            # print as a line
+            print("%s %d" % (line, v.value))
+        else:
+            # print wakeup name then stack in reverse order
+            print("    %-16s %s" % ("waker:", k.waker))
+            for i in reversed(range(0, maxwdepth)):
+                if k.wret[i] == 0:
+                    continue
+                print("    %-16x %s" % (k.wret[i],
+                    b.ksym(k.wret[i])))
+
+            # print delimiter
+            print("    %-16s %s" % ("-", "-"))
+
+            # print default multi-line stack output
+            for i in range(0, maxtdepth):
+                if k.tret[i] == 0:
+                    break
+                print("    %-16x %s" % (k.tret[i],
+                    b.ksym(k.tret[i])))
+            print("    %-16s %s" % ("target:", k.target))
+            print("        %d\n" % v.value)
+    counts.clear()
+
+    if not folded:
+        print("Detaching...")
+    exit()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/syscount.py 
new/bcc-v0.3.0/tools/syscount.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/syscount.py      2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/syscount.py    2017-03-10 03:07:20.000000000 +0100
@@ -23,7 +23,8 @@
 #  cat syscallent.h | awk -F, '{ gsub(/[ \t"}]/, "", $4);
 #                                gsub(/[ \t/*]/, "", $5);
 #                                print "    "$5": \""$4"\","; }
-#                              BEGIN { print "syscalls = {" } END { print "}" 
}'
+#                              BEGIN { print "syscalls = {" }
+#                              END { print "}" }'
 #
 syscalls = {
     0: "read",
@@ -459,7 +460,7 @@
 
 def agg_colval(key):
     if args.process:
-        return "%-6d %-15s" % (key.value, comm_for_pid(key.value)) 
+        return "%-6d %-15s" % (key.value, comm_for_pid(key.value))
     else:
         return syscalls.get(key.value, "[unknown: %d]" % key.value)
 
@@ -478,7 +479,8 @@
     data = bpf["data"]
     print("[%s]" % strftime("%H:%M:%S"))
     print("%-22s %8s %16s" % (agg_colname, "COUNT", time_colname))
-    for k, v in sorted(data.items(), key=lambda kv: 
-kv[1].total_ns)[:args.top]:
+    for k, v in sorted(data.items(),
+                       key=lambda kv: -kv[1].total_ns)[:args.top]:
         if k.value == 0xFFFFFFFF:
             continue    # happens occasionally, we don't need it
         print(("%-22s %8d " + ("%16.6f" if args.milliseconds else "%16.3f")) %
@@ -497,4 +499,3 @@
         if not args.interval:
             print_stats()
         break
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/tplist.py 
new/bcc-v0.3.0/tools/tplist.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/tplist.py        2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/tplist.py      2017-03-10 03:07:20.000000000 +0100
@@ -64,17 +64,17 @@
                                 print_tpoint(category, event)
 
 def print_usdt_argument_details(location):
-        for idx in xrange(0, location.num_arguments):
+        for idx in range(0, location.num_arguments):
                 arg = location.get_argument(idx)
-                print("    argument #%d %s" % (idx+1, arg))
+                print("    argument #%d %s" % (idx + 1, arg))
 
 def print_usdt_details(probe):
         if args.verbosity > 0:
                 print(probe)
                 if args.verbosity > 1:
-                        for idx in xrange(0, probe.num_locations):
+                        for idx in range(0, probe.num_locations):
                                 loc = probe.get_location(idx)
-                                print("  location #%d %s" % (idx+1, loc))
+                                print("  location #%d %s" % (idx + 1, loc))
                                 print_usdt_argument_details(loc)
                 else:
                         print("  %d location(s)" % probe.num_locations)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/trace.py 
new/bcc-v0.3.0/tools/trace.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/trace.py 2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/trace.py       2017-03-10 03:07:20.000000000 +0100
@@ -53,7 +53,8 @@
                 self.probe_num = Probe.probe_count
                 self.probe_name = "probe_%s_%d" % \
                                 (self._display_function(), self.probe_num)
-                self.probe_name = re.sub(r'[^A-Za-z0-9_]', '_', 
self.probe_name)
+                self.probe_name = re.sub(r'[^A-Za-z0-9_]', '_',
+                                         self.probe_name)
 
         def __str__(self):
                 return "%s:%s:%s FLT=%s ACT=%s/%s" % (self.probe_type,
@@ -81,7 +82,8 @@
                                              text).groups()
 
                 self._parse_spec(spec)
-                self.signature = sig[1:-1] if sig else None # remove the parens
+                # Remove the parens
+                self.signature = sig[1:-1] if sig else None
                 if self.signature and self.probe_type in ['u', 't']:
                         self._bail("USDT and tracepoint probes can't have " +
                                    "a function signature; use arg1, arg2, " +
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/ucalls.py 
new/bcc-v0.3.0/tools/ucalls.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/ucalls.py        2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/ucalls.py      2017-03-10 03:07:20.000000000 +0100
@@ -257,7 +257,8 @@
                            bpf["systimes"].items())
             data.extend(syscalls)
         else:
-            syscalls = map(lambda kv: (bpf.ksym(kv[0].value), (kv[1].value, 
0)),
+            syscalls = map(lambda kv: (bpf.ksym(kv[0].value),
+                                       (kv[1].value, 0)),
                            bpf["syscounts"].items())
             data.extend(syscalls)
 
@@ -294,8 +295,8 @@
         data = data[-args.top:]
     for key, value in data:
         if args.latency:
-            time = value[1]/1000000.0 if args.milliseconds else \
-                   value[1]/1000.0
+            time = value[1] / 1000000.0 if args.milliseconds else \
+                   value[1] / 1000.0
             print("%-50s %8d %6.2f" % (key, value[0], time))
         else:
             print("%-50s %8d" % (key, value[0]))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/uflow.py 
new/bcc-v0.3.0/tools/uflow.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/uflow.py 2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/uflow.py       2017-03-10 03:07:20.000000000 +0100
@@ -97,7 +97,7 @@
 def enable_probe(probe_name, func_name, read_class, read_method, is_return):
     global program, trace_template, usdt
     depth = "*depth + 1" if not is_return else "*depth | (1ULL << 63)"
-    update = "++(*depth);" if not is_return else  "if (*depth) --(*depth);"
+    update = "++(*depth);" if not is_return else "if (*depth) --(*depth);"
     filter_class = "if (!prefix_class(data.clazz)) { return 0; }" \
                    if args.clazz else ""
     filter_method = "if (!prefix_method(data.method)) { return 0; }" \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/ugc.py 
new/bcc-v0.3.0/tools/ugc.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/ugc.py   2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/ugc.py 2017-03-10 03:07:20.000000000 +0100
@@ -134,8 +134,10 @@
     bpf_probe_read(&event.string1, sizeof(event.string1), (void *)manager);
     bpf_probe_read(&event.string2, sizeof(event.string2), (void *)pool);
     """
-    formatter = lambda e: "%s %s used=%d->%d max=%d->%d" % \
-                (e.string1, e.string2, e.field1, e.field3, e.field2, e.field4)
+
+    def formatter(e):
+        "%s %s used=%d->%d max=%d->%d" % \
+            (e.string1, e.string2, e.field1, e.field3, e.field2, e.field4)
     probes.append(Probe("mem__pool__gc__begin", "mem__pool__gc__end",
                         begin_save, end_save, formatter))
     probes.append(Probe("gc__begin", "gc__end",
@@ -155,8 +157,10 @@
     event.field1 = e->field1;
     event.field2 = objs;
     """
-    formatter = lambda event: "gen %d GC collected %d objects" % \
-                              (event.field1, event.field2)
+
+    def formatter(event):
+        "gen %d GC collected %d objects" % \
+            (event.field1, event.field2)
     probes.append(Probe("gc__start", "gc__done",
                         begin_save, end_save, formatter))
 #
@@ -214,10 +218,10 @@
 
 def print_event(cpu, data, size):
     event = ct.cast(data, ct.POINTER(GCEvent)).contents
-    elapsed = event.elapsed_ns/1000000 if args.milliseconds else \
-              event.elapsed_ns/1000
+    elapsed = event.elapsed_ns / 1000000 if args.milliseconds else \
+              event.elapsed_ns / 1000
     description = probes[event.probe_index].format(event)
-    if args.filter and not args.filter in description:
+    if args.filter and args.filter not in description:
         return
     print("%-8.3f %-8.2f %s" % (time.time() - start_ts, elapsed, description))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/uobjnew.py 
new/bcc-v0.3.0/tools/uobjnew.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/uobjnew.py       2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/uobjnew.py     2017-03-10 03:07:20.000000000 +0100
@@ -110,7 +110,8 @@
     usdt.enable_probe_or_bail("object__create", "object_alloc_entry")
     for thing in ["string", "hash", "array"]:
         program += create_template.replace("THETHING", thing)
-        usdt.enable_probe_or_bail("%s__create" % thing, "%s_alloc_entry" % 
thing)
+        usdt.enable_probe_or_bail("%s__create" % thing,
+                                  "%s_alloc_entry" % thing)
 #
 # C
 #
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/ustat.py 
new/bcc-v0.3.0/tools/ustat.py
--- old/bcc-v0.2.0+git1488325605.4d0d430/tools/ustat.py 2017-03-01 
00:46:45.000000000 +0100
+++ new/bcc-v0.3.0/tools/ustat.py       2017-03-10 03:07:20.000000000 +0100
@@ -244,8 +244,9 @@
             counts.update(probe.get_counts(self.bpf))
             targets.update(probe.targets)
         if self.args.sort:
-            counts = sorted(counts.items(), key=lambda kv:
-                            -kv[1].get(self.args.sort.upper(), 0))
+            sort_field = self.args.sort.upper()
+            counts = sorted(counts.items(),
+                            key=lambda kv: -kv[1].get(sort_field, 0))
         else:
             counts = sorted(counts.items(), key=lambda kv: kv[0])
         for pid, stats in counts:


Reply via email to