Merge pull request #1555 from myreg/trace-addr

Add option to print virtual address to trace.py
diff --git a/docs/kernel-versions.md b/docs/kernel-versions.md
index 554847c..9514944 100644
--- a/docs/kernel-versions.md
+++ b/docs/kernel-versions.md
@@ -123,6 +123,7 @@
 `BPF_FUNC_get_socket_cookie()` | 4.12 | [91b8270f2a4d](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=91b8270f2a4d1d9b268de90451cdca63a70052d6)
 `BPF_FUNC_get_socket_uid()` | 4.12 | [6acc5c291068](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=6acc5c2910689fc6ee181bf63085c5efff6a42bd)
 `BPF_FUNC_get_stackid()` | 4.6 | [d5a3b1f69186](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=d5a3b1f691865be576c2bffa708549b8cdccda19)
+`BPF_FUNC_getsockopt()` | 4.15 | [cd86d1fd2102](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=cd86d1fd21025fdd6daf23d1288da405e7ad0ec6)
 `BPF_FUNC_ktime_get_ns()` | 4.1 | [d9847d310ab4](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=d9847d310ab4003725e6ed1822682e24bd406908)
 `BPF_FUNC_l3_csum_replace()` | 4.1 | [91bc4822c3d6](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=91bc4822c3d61b9bb7ef66d3b77948a4f9177954)
 `BPF_FUNC_l4_csum_replace()` | 4.1 | [91bc4822c3d6](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=91bc4822c3d61b9bb7ef66d3b77948a4f9177954)
diff --git a/docs/reference_guide.md b/docs/reference_guide.md
index d88eec7..b89d140 100644
--- a/docs/reference_guide.md
+++ b/docs/reference_guide.md
@@ -21,7 +21,8 @@
         - [4. bpf_get_current_pid_tgid()](#4-bpf_get_current_pid_tgid)
         - [5. bpf_get_current_uid_gid()](#5-bpf_get_current_uid_gid)
         - [6. bpf_get_current_comm()](#6-bpf_get_current_comm)
-        - [7. bpf_log2l()](#7-bpflog2l)
+        - [7. bpf_get_current_task()](#7-bpf_get_current_task)
+        - [8. bpf_log2l()](#8-bpflog2l)
     - [Debugging](#debugging)
         - [1. bpf_override_return()](#1-bpf_override_return)
     - [Output](#output)
@@ -316,7 +317,30 @@
 [search /examples](https://github.com/iovisor/bcc/search?q=bpf_get_current_comm+path%3Aexamples&type=Code),
 [search /tools](https://github.com/iovisor/bcc/search?q=bpf_get_current_comm+path%3Atools&type=Code)
 
-### 7. bpf_log2l()
+### 7. bpf_get_current_task()
+
+Syntax: ```bpf_get_current_task()```
+
+Return: current task as a pointer to struct task_struct.
+
+Returns a pointer to the current task's task_struct object. This helper can be used to compute the on-CPU time for a process, identify kernel threads, get the current CPU's run queue, or retrieve many other pieces of information.
+
+With Linux 4.13, due to issues with field randomization, you may need two #define directives before the includes:
+```C
+#define randomized_struct_fields_start  struct {
+#define randomized_struct_fields_end    };
+#include <linux/sched.h>
+
+int do_trace(void *ctx) {
+    struct task_struct *t = (struct task_struct *)bpf_get_current_task();
+[...]
+```
+
+Examples in situ:
+[search /examples](https://github.com/iovisor/bcc/search?q=bpf_get_current_task+path%3Aexamples&type=Code),
+[search /tools](https://github.com/iovisor/bcc/search?q=bpf_get_current_task+path%3Atools&type=Code)
+
+### 8. bpf_log2l()
 
 Syntax: ```unsigned int bpf_log2l(unsigned long v)```
 
diff --git a/man/man8/funccount.8 b/man/man8/funccount.8
index 6c1623a..9039ab3 100644
--- a/man/man8/funccount.8
+++ b/man/man8/funccount.8
@@ -2,7 +2,7 @@
 .SH NAME
 funccount \- Count function, tracepoint, and USDT probe calls matching a pattern. Uses Linux eBPF/bcc.
 .SH SYNOPSIS
-.B funccount [\-h] [\-p PID] [\-i INTERVAL] [\-T] [\-r] [\-d] pattern
+.B funccount [\-h] [\-p PID] [\-i INTERVAL] [\-d DURATION] [\-T] [\-r] [\-D] pattern
 .SH DESCRIPTION
 This tool is a quick way to determine which functions are being called,
 and at what rate. It uses in-kernel eBPF maps to count function calls.
@@ -36,7 +36,7 @@
 \-r
 Use regular expressions for the search pattern.
 .TP
-\-d
+\-D
 Print the BPF program before starting (for debugging purposes).
 .SH EXAMPLES
 .TP
diff --git a/src/cc/export/helpers.h b/src/cc/export/helpers.h
index 1d25c6e..1fa4a64 100644
--- a/src/cc/export/helpers.h
+++ b/src/cc/export/helpers.h
@@ -250,6 +250,30 @@
   (void *) BPF_FUNC_perf_event_read_value;
 static int (*bpf_perf_prog_read_value)(void *ctx, void *buf, u32 buf_size) =
   (void *) BPF_FUNC_perf_prog_read_value;
+static int (*bpf_current_task_under_cgroup)(void *map, int index) =
+  (void *) BPF_FUNC_current_task_under_cgroup;
+static u32 (*bpf_get_socket_cookie)(void *ctx) =
+  (void *) BPF_FUNC_get_socket_cookie;
+static u64 (*bpf_get_socket_uid)(void *ctx) =
+  (void *) BPF_FUNC_get_socket_uid;
+static int (*bpf_getsockopt)(void *ctx, int level, int optname, void *optval, int optlen) =
+  (void *) BPF_FUNC_getsockopt;
+static int (*bpf_redirect_map)(void *map, int key, int flags) =
+  (void *) BPF_FUNC_redirect_map;
+static int (*bpf_set_hash)(void *ctx, u32 hash) =
+  (void *) BPF_FUNC_set_hash;
+static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, int optlen) =
+  (void *) BPF_FUNC_setsockopt;
+static int (*bpf_skb_adjust_room)(void *ctx, int len_diff, u32 mode, u64 flags) =
+  (void *) BPF_FUNC_skb_adjust_room;
+static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) =
+  (void *) BPF_FUNC_skb_under_cgroup;
+static int (*bpf_sk_redirect_map)(void *ctx, void *map, int key, int flags) =
+  (void *) BPF_FUNC_sk_redirect_map;
+static int (*bpf_sock_map_update)(void *map, void *key, void *value, unsigned long long flags) =
+  (void *) BPF_FUNC_sock_map_update;
+static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) =
+  (void *) BPF_FUNC_xdp_adjust_meta;
 
 /* bcc_get_stackid will return a negative value in the case of an error
  *
diff --git a/src/cc/frontends/clang/CMakeLists.txt b/src/cc/frontends/clang/CMakeLists.txt
index a6228fc..105278c 100644
--- a/src/cc/frontends/clang/CMakeLists.txt
+++ b/src/cc/frontends/clang/CMakeLists.txt
@@ -10,3 +10,4 @@
 endif()
 
 add_library(clang_frontend STATIC loader.cc b_frontend_action.cc tp_frontend_action.cc kbuild_helper.cc ../../common.cc)
+target_link_libraries(clang_frontend bcc-static)
diff --git a/src/cc/frontends/clang/b_frontend_action.cc b/src/cc/frontends/clang/b_frontend_action.cc
index c42fb62..257167e 100644
--- a/src/cc/frontends/clang/b_frontend_action.cc
+++ b/src/cc/frontends/clang/b_frontend_action.cc
@@ -778,7 +778,8 @@
       return false;
     }
 
-    fe_.table_storage().VisitMapType(table, C, key_type, leaf_type);
+    if (!table.is_extern)
+      fe_.table_storage().VisitMapType(table, C, key_type, leaf_type);
     fe_.table_storage().Insert(local_path, move(table));
   } else if (const PointerType *P = Decl->getType()->getAs<PointerType>()) {
     // if var is a pointer to a packet type, clone the annotation into the var
diff --git a/src/cc/libbpf.c b/src/cc/libbpf.c
index 6e24ccf..41f1560 100644
--- a/src/cc/libbpf.c
+++ b/src/cc/libbpf.c
@@ -84,6 +84,72 @@
 
 #define min(x, y) ((x) < (y) ? (x) : (y))
 
+struct bpf_helper {
+  char *name;
+  char *required_version;
+};
+
+static struct bpf_helper helpers[] = {
+  {"map_lookup_elem", "3.19"},
+  {"map_update_elem", "3.19"},
+  {"map_delete_elem", "3.19"},
+  {"probe_read", "4.1"},
+  {"ktime_get_ns", "4.1"},
+  {"trace_printk", "4.1"},
+  {"get_prandom_u32", "4.1"},
+  {"get_smp_processor_id", "4.1"},
+  {"skb_store_bytes", "4.1"},
+  {"l3_csum_replace", "4.1"},
+  {"l4_csum_replace", "4.1"},
+  {"tail_call", "4.2"},
+  {"clone_redirect", "4.2"},
+  {"get_current_pid_tgid", "4.2"},
+  {"get_current_uid_gid", "4.2"},
+  {"get_current_comm", "4.2"},
+  {"get_cgroup_classid", "4.3"},
+  {"skb_vlan_push", "4.3"},
+  {"skb_vlan_pop", "4.3"},
+  {"skb_get_tunnel_key", "4.3"},
+  {"skb_set_tunnel_key", "4.3"},
+  {"perf_event_read", "4.3"},
+  {"redirect", "4.4"},
+  {"get_route_realm", "4.4"},
+  {"perf_event_output", "4.4"},
+  {"skb_load_bytes", "4.5"},
+  {"get_stackid", "4.6"},
+  {"csum_diff", "4.6"},
+  {"skb_get_tunnel_opt", "4.6"},
+  {"skb_set_tunnel_opt", "4.6"},
+  {"skb_change_proto", "4.8"},
+  {"skb_change_type", "4.8"},
+  {"skb_under_cgroup", "4.8"},
+  {"get_hash_recalc", "4.8"},
+  {"get_current_task", "4.8"},
+  {"probe_write_user", "4.8"},
+  {"current_task_under_cgroup", "4.9"},
+  {"skb_change_tail", "4.9"},
+  {"skb_pull_data", "4.9"},
+  {"csum_update", "4.9"},
+  {"set_hash_invalid", "4.9"},
+  {"get_numa_node_id", "4.10"},
+  {"skb_change_head", "4.10"},
+  {"xdp_adjust_head", "4.10"},
+  {"probe_read_str", "4.11"},
+  {"get_socket_cookie", "4.12"},
+  {"get_socket_uid", "4.12"},
+  {"set_hash", "4.13"},
+  {"setsockopt", "4.13"},
+  {"skb_adjust_room", "4.13"},
+  {"redirect_map", "4.14"},
+  {"sk_redirect_map", "4.14"},
+  {"sock_map_update", "4.14"},
+  {"xdp_adjust_meta", "4.15"},
+  {"perf_event_read_value", "4.15"},
+  {"perf_prog_read_value", "4.15"},
+  {"getsockopt", "4.15"},
+  {"override_return", "4.16"},
+};
+
 static int probe_perf_reader_page_cnt = 8;
 
 static uint64_t ptr_to_u64(void *ptr)
@@ -245,6 +311,22 @@
       "bpf_probe_read is automatic by the bcc rewriter, other times "
       "you'll need to be explicit.\n\n");
   }
+
+  // helper function not found in kernel
+  char *helper_str = strstr(log, "invalid func ");
+  if (helper_str != NULL) {
+    helper_str += strlen("invalid func ");
+    char *str = strchr(helper_str, '#');
+    if (str != NULL) {
+      helper_str = str + 1;
+    }
+    int helper_id = atoi(helper_str);
+    if (helper_id && helper_id < sizeof(helpers) / sizeof(struct bpf_helper)) {
+      struct bpf_helper helper = helpers[helper_id - 1];
+      fprintf(stderr, "HINT: bpf_%s missing (added in Linux %s).\n\n",
+              helper.name, helper.required_version);
+    }
+  }
 }
 #define ROUND_UP(x, n) (((x) + (n) - 1u) & ~((n) - 1u))
 
diff --git a/src/python/bcc/table.py b/src/python/bcc/table.py
index aa037f6..d88b402 100644
--- a/src/python/bcc/table.py
+++ b/src/python/bcc/table.py
@@ -205,6 +205,11 @@
             errstr = os.strerror(ct.get_errno())
             raise Exception("Could not update table: %s" % errstr)
 
+    def __delitem__(self, key):
+        res = lib.bpf_delete_elem(self.map_fd, ct.byref(key))
+        if res < 0:
+            raise KeyError
+
     # override the MutableMapping's implementation of these since they
     # don't handle KeyError nicely
     def itervalues(self):
@@ -391,11 +396,6 @@
         for k in self: i += 1
         return i
 
-    def __delitem__(self, key):
-        res = lib.bpf_delete_elem(self.map_fd, ct.byref(key))
-        if res < 0:
-            raise KeyError
-
 class LruHash(HashTable):
     def __init__(self, *args, **kwargs):
         super(LruHash, self).__init__(*args, **kwargs)
@@ -430,11 +430,12 @@
 
     def __delitem__(self, key):
         key = self._normalize_key(key)
-        # Deleting from array type maps does not have an effect, so
-        # zero out the entry instead.
+        super(ArrayBase, self).__delitem__(key)
+
+    def clearitem(self, key):
+        key = self._normalize_key(key)
         leaf = self.Leaf()
-        res = lib.bpf_update_elem(self.map_fd, ct.byref(key), ct.byref(leaf),
-                                  0)
+        res = lib.bpf_update_elem(self.map_fd, ct.byref(key), ct.byref(leaf), 0)
         if res < 0:
             raise Exception("Could not clear item")
 
@@ -461,6 +462,9 @@
     def __init__(self, *args, **kwargs):
         super(Array, self).__init__(*args, **kwargs)
 
+    def __delitem__(self, key):
+        # Delete in Array type does not have an effect, so zero out instead
+        self.clearitem(key)
 
 class ProgArray(ArrayBase):
     def __init__(self, *args, **kwargs):
@@ -473,12 +477,6 @@
             leaf = self.Leaf(leaf.fd)
         super(ProgArray, self).__setitem__(key, leaf)
 
-    def __delitem__(self, key):
-        key = self._normalize_key(key)
-        res = lib.bpf_delete_elem(self.map_fd, ct.byref(key))
-        if res < 0:
-            raise Exception("Could not delete item")
-
 class PerfEventArray(ArrayBase):
 
     def __init__(self, *args, **kwargs):
@@ -494,8 +492,7 @@
         if key not in self._open_key_fds:
             return
         # Delete entry from the array
-        c_key = self._normalize_key(key)
-        lib.bpf_delete_elem(self.map_fd, ct.byref(c_key))
+        super(PerfEventArray, self).__delitem__(key)
         key_id = (id(self), key)
         if key_id in self.bpf.open_kprobes:
             # The key is opened for perf ring buffer
@@ -665,6 +662,10 @@
     def __setitem__(self, key, leaf):
         super(PerCpuArray, self).__setitem__(key, leaf)
 
+    def __delitem__(self, key):
+        # Delete in this type does not have an effect, so zero out instead
+        self.clearitem(key)
+
     def sum(self, key):
         if isinstance(self.Leaf(), ct.Structure):
             raise IndexError("Leaf must be an integer type for default sum functions")
@@ -728,10 +729,5 @@
         for k in self: i += 1
         return i
 
-    def __delitem__(self, key):
-        res = lib.bpf_delete_elem(self.map_fd, ct.byref(key))
-        if res < 0:
-            raise KeyError
-
     def clear(self):
         pass
diff --git a/tests/python/test_clang.py b/tests/python/test_clang.py
index ba8c02f..58c808e 100755
--- a/tests/python/test_clang.py
+++ b/tests/python/test_clang.py
@@ -400,6 +400,7 @@
     def test_exported_maps(self):
         b1 = BPF(text="""BPF_TABLE_PUBLIC("hash", int, int, table1, 10);""")
         b2 = BPF(text="""BPF_TABLE("extern", int, int, table1, 10);""")
+        t = b2["table1"]
 
     def test_syntax_error(self):
         with self.assertRaises(Exception):
diff --git a/tools/opensnoop.py b/tools/opensnoop.py
index 112c56a..6d011e9 100755
--- a/tools/opensnoop.py
+++ b/tools/opensnoop.py
@@ -68,7 +68,7 @@
 BPF_HASH(infotmp, u64, struct val_t);
 BPF_PERF_OUTPUT(events);
 
-int trace_entry(struct pt_regs *ctx, const char __user *filename)
+int trace_entry(struct pt_regs *ctx, int dfd, const char __user *filename)
 {
     struct val_t val = {};
     u64 id = bpf_get_current_pid_tgid();
@@ -124,8 +124,8 @@
 
 # initialize BPF
 b = BPF(text=bpf_text)
-b.attach_kprobe(event="sys_open", fn_name="trace_entry")
-b.attach_kretprobe(event="sys_open", fn_name="trace_return")
+b.attach_kprobe(event="do_sys_open", fn_name="trace_entry")
+b.attach_kretprobe(event="do_sys_open", fn_name="trace_return")
 
 TASK_COMM_LEN = 16    # linux/sched.h
 NAME_MAX = 255        # linux/limits.h