argdist, trace: Native tracepoint support (#724)

* Remove tracepoint.py

The `Tracepoint` class which implements the necessary
support for the tracepoint kprobe-based hack is no
longer needed and can be removed.

* argdist: Native tracepoint support

This commit migrates argdist to use the native bcc/BPF
tracepoint support instead of the hackish kprobe-
based approach. The resulting programs are cleaner
and likely more efficient.

As a result of this change, there is a slight API
change in how argdist is used with tracepoints. To
access fields from the tracepoint structure, the user
is expected to use `args->field` directly. This
leverages most of the built-in bcc support for
generating the tracepoint probe function.

* trace: Native tracepoint support

This commit migrates trace to use the native bcc/BPF
tracepoint support instead of the hackish kprobe-
based approach. The resulting programs are cleaner
and likely more efficient.

As with argdist, users are now expected to use the
`args` structure pointer to access the tracepoint's
arguments.

For example:

```
trace 't:irq:irq_handler_entry (args->irq != 27) "irq %d", args->irq'
```
diff --git a/tools/trace.py b/tools/trace.py
index 742587b..0cb1c3e 100755
--- a/tools/trace.py
+++ b/tools/trace.py
@@ -9,7 +9,7 @@
 # Licensed under the Apache License, Version 2.0 (the "License")
 # Copyright (C) 2016 Sasha Goldshtein.
 
-from bcc import BPF, Tracepoint, Perf, USDT
+from bcc import BPF, USDT
 from functools import partial
 from time import sleep, strftime
 import argparse
@@ -138,10 +138,8 @@
                 if self.probe_type == "t":
                         self.tp_category = parts[1]
                         self.tp_event = parts[2]
-                        self.tp = Tracepoint.enable_tracepoint(
-                                        self.tp_category, self.tp_event)
                         self.library = ""       # kernel
-                        self.function = "perf_trace_%s" % self.tp_event
+                        self.function = ""      # generated from TRACEPOINT_PROBE
                 elif self.probe_type == "u":
                         self.library = parts[1]
                         self.usdt_name = parts[2]
@@ -357,9 +355,6 @@
 
                 prefix = ""
                 signature = "struct pt_regs *ctx"
-                if self.probe_type == "t":
-                        data_decl += self.tp.generate_struct()
-                        prefix = self.tp.generate_get_struct()
 
                 data_fields = ""
                 for i, expr in enumerate(self.values):
@@ -377,8 +372,14 @@
           ctx, BPF_F_REUSE_STACKID
         );""" % self.stacks_name
 
-                text = """
-int %s(%s)
+                if self.probe_type == "t":
+                        heading = "TRACEPOINT_PROBE(%s, %s)" % \
+                                  (self.tp_category, self.tp_event)
+                        ctx_name = "args"
+                else:
+                        heading = "int %s(%s)" % (self.probe_name, signature)
+                        ctx_name = "ctx"
+                text = heading + """
 {
         %s
         %s
@@ -391,15 +392,14 @@
         bpf_get_current_comm(&__data.comm, sizeof(__data.comm));
 %s
 %s
-        %s.perf_submit(ctx, &__data, sizeof(__data));
+        %s.perf_submit(%s, &__data, sizeof(__data));
         return 0;
 }
 """
-                text = text % (self.probe_name, signature,
-                               pid_filter, prefix,
+                text = text % (pid_filter, prefix,
                                self._generate_usdt_filter_read(), self.filter,
                                self.struct_name, data_fields,
-                               stack_trace, self.events_name)
+                               stack_trace, self.events_name, ctx_name)
 
                 return data_decl + "\n" + text
 
@@ -464,9 +464,10 @@
                 if self.probe_type == "r":
                         bpf.attach_kretprobe(event=self.function,
                                              fn_name=self.probe_name)
-                elif self.probe_type == "p" or self.probe_type == "t":
+                elif self.probe_type == "p":
                         bpf.attach_kprobe(event=self.function,
                                           fn_name=self.probe_name)
+                # Note that tracepoints don't need an explicit attach
 
         def _attach_u(self, bpf):
                 libpath = BPF.find_library(self.library)
@@ -511,7 +512,7 @@
         Trace returns from __kmalloc which returned a null pointer
 trace 'r:c:malloc (retval) "allocated = %p", retval
         Trace returns from malloc and print non-NULL allocated buffers
-trace 't:block:block_rq_complete "sectors=%d", tp.nr_sector'
+trace 't:block:block_rq_complete "sectors=%d", args->nr_sector'
         Trace the block_rq_complete kernel tracepoint and print # of tx sectors
 trace 'u:pthread:pthread_create (arg4 != 0)'
         Trace the USDT probe pthread_create when its 4th argument is non-zero
@@ -558,8 +559,6 @@
 """
                 self.program += BPF.generate_auto_includes(
                         map(lambda p: p.raw_probe, self.probes))
-                self.program += Tracepoint.generate_decl()
-                self.program += Tracepoint.generate_entry_probe()
                 for probe in self.probes:
                         self.program += probe.generate_program(
                                         self.args.include_self)
@@ -580,7 +579,6 @@
                                 print(probe.usdt.get_text())
                         usdt_contexts.append(probe.usdt)
                 self.bpf = BPF(text=self.program, usdt_contexts=usdt_contexts)
-                Tracepoint.attach(self.bpf)
                 for probe in self.probes:
                         if self.args.verbose:
                                 print(probe)