bcc: Add __user attribute to support bpf_probe_read_user in argdist

argdist traces probe functions and its parameter values.

Add functionality to convert:
- All userspace probes char * read to bpf_probe_read_user()
- Syscall/kprobes char* params with __user attribute to bpf_probe_read_user()

Signed-off-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Acked-by: Ilya Leoshkevich <iii@linux.ibm.com>
diff --git a/tools/argdist.py b/tools/argdist.py
index 695b5b3..0e9078c 100755
--- a/tools/argdist.py
+++ b/tools/argdist.py
@@ -9,7 +9,7 @@
 # Licensed under the Apache License, Version 2.0 (the "License")
 # Copyright (C) 2016 Sasha Goldshtein.
 
-from bcc import BPF, USDT
+from bcc import BPF, USDT, StrcmpRewrite
 from time import sleep, strftime
 import argparse
 import re
@@ -41,6 +41,10 @@
                         param_type = param[0:index + 1].strip()
                         param_name = param[index + 1:].strip()
                         self.param_types[param_name] = param_type
+                        # Maintain list of user params. Then later decide to
+                        # switch to bpf_probe_read or bpf_probe_read_user.
+                        if "__user" in param_type.split():
+                                self.probe_user_list.add(param_name)
 
         def _generate_entry(self):
                 self.entry_probe_func = self.probe_func_name + "_entry"
@@ -182,6 +186,8 @@
                 self.pid = tool.args.pid
                 self.cumulative = tool.args.cumulative or False
                 self.raw_spec = specifier
+                self.probe_user_list = set()
+                self.bin_cmp = False
                 self._validate_specifier()
 
                 spec_and_label = specifier.split('#')
@@ -250,32 +256,16 @@
                 self.usdt_ctx.enable_probe(
                         self.function, self.probe_func_name)
 
-        def _generate_streq_function(self, string):
-                fname = "streq_%d" % Probe.streq_index
-                Probe.streq_index += 1
-                self.streq_functions += """
-static inline bool %s(char const *ignored, char const *str) {
-        char needle[] = %s;
-        char haystack[sizeof(needle)];
-        bpf_probe_read(&haystack, sizeof(haystack), (void *)str);
-        for (int i = 0; i < sizeof(needle) - 1; ++i) {
-                if (needle[i] != haystack[i]) {
-                        return false;
-                }
-        }
-        return true;
-}
-                """ % (fname, string)
-                return fname
-
         def _substitute_exprs(self):
                 def repl(expr):
                         expr = self._substitute_aliases(expr)
-                        matches = re.finditer('STRCMP\\(("[^"]+\\")', expr)
-                        for match in matches:
-                                string = match.group(1)
-                                fname = self._generate_streq_function(string)
-                                expr = expr.replace("STRCMP", fname, 1)
+                        rdict = StrcmpRewrite.rewrite_expr(expr,
+                                self.bin_cmp, self.library,
+                                self.probe_user_list, self.streq_functions,
+                                Probe.streq_index)
+                        expr = rdict["expr"]
+                        self.streq_functions = rdict["streq_functions"]
+                        Probe.streq_index = rdict["probeid"]
                         return expr.replace("$retval", "PT_REGS_RC(ctx)")
                 for i in range(0, len(self.exprs)):
                         self.exprs[i] = repl(self.exprs[i])
@@ -305,9 +295,14 @@
         def _generate_field_assignment(self, i):
                 text = self._generate_usdt_arg_assignment(i)
                 if self._is_string(self.expr_types[i]):
-                        return (text + "        bpf_probe_read(&__key.v%d.s," +
+                        if self.is_user or \
+                            self.exprs[i] in self.probe_user_list:
+                                probe_readfunc = "bpf_probe_read_user"
+                        else:
+                                probe_readfunc = "bpf_probe_read"
+                        return (text + "        %s(&__key.v%d.s," +
                                 " sizeof(__key.v%d.s), (void *)%s);\n") % \
-                                (i, i, self.exprs[i])
+                                (probe_readfunc, i, i, self.exprs[i])
                 else:
                         return text + "        __key.v%d = %s;\n" % \
                                (i, self.exprs[i])