argdist, trace: Support non-C identifier names
authorSasha Goldshtein <goldshtn@gmail.com>
Sat, 14 Jan 2017 11:17:40 +0000 (11:17 +0000)
committerSasha Goldshtein <goldshtn@gmail.com>
Sat, 14 Jan 2017 11:17:40 +0000 (11:17 +0000)
When argdist or trace face a function that has characters
in its name that are not valid in C identifier, they now
replace these characters with an underscore (`_`) when
generating function names and structure names to include
in the BPF program. As a result, it is now possible to
trace functions that have these identifiers in their names,
such as Golang functions like `fmt.Println`.

tools/argdist.py
tools/trace.py

index 2e3aad5..3bcf43a 100755 (executable)
@@ -159,7 +159,7 @@ u64 __time = bpf_ktime_get_ns();
                 if parts[0] not in ["r", "p", "t", "u"]:
                         self._bail("probe type must be 'p', 'r', 't', or 'u'" +
                                    " but got '%s'" % parts[0])
-                if re.match(r"\w+\(.*\)", parts[2]) is None:
+                if re.match(r"\S+\(.*\)", parts[2]) is None:
                         self._bail(("function signature '%s' has an invalid " +
                                     "format") % parts[2])
 
@@ -173,6 +173,9 @@ u64 __time = bpf_ktime_get_ns();
                         self._bail("no exprs specified")
                 self.exprs = exprs.split(',')
 
+        def _make_valid_identifier(self, ident):
+                return re.sub(r'[^A-Za-z0-9_]', '_', ident)
+
         def __init__(self, tool, type, specifier):
                 self.usdt_ctx = None
                 self.streq_functions = ""
@@ -196,8 +199,9 @@ u64 __time = bpf_ktime_get_ns();
                         self.tp_event = self.function
                 elif self.probe_type == "u":
                         self.library = parts[1]
-                        self.probe_func_name = "%s_probe%d" % \
-                                (self.function, Probe.next_probe_index)
+                        self.probe_func_name = self._make_valid_identifier(
+                                "%s_probe%d" % \
+                                (self.function, Probe.next_probe_index))
                         self._enable_usdt_probe()
                 else:
                         self.library = parts[1]
@@ -233,10 +237,12 @@ u64 __time = bpf_ktime_get_ns();
                 self.entry_probe_required = self.probe_type == "r" and \
                         (any(map(check, self.exprs)) or check(self.filter))
 
-                self.probe_func_name = "%s_probe%d" % \
-                        (self.function, Probe.next_probe_index)
-                self.probe_hash_name = "%s_hash%d" % \
-                        (self.function, Probe.next_probe_index)
+                self.probe_func_name = self._make_valid_identifier(
+                        "%s_probe%d" % \
+                        (self.function, Probe.next_probe_index))
+                self.probe_hash_name = self._make_valid_identifier(
+                        "%s_hash%d" % \
+                        (self.function, Probe.next_probe_index))
                 Probe.next_probe_index += 1
 
         def _enable_usdt_probe(self):
index 80212b4..8ac9201 100755 (executable)
@@ -76,8 +76,7 @@ class Probe(object):
                 self.probe_num = Probe.probe_count
                 self.probe_name = "probe_%s_%d" % \
                                 (self._display_function(), self.probe_num)
-                if self.probe_name.find(".") > 0:   # for golang
-                    self.probe_name = self.probe_name.replace(".", "_DOT_")
+                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,