trace.py: support an optional provider name for the probe spec
diff --git a/src/cc/bcc_usdt.h b/src/cc/bcc_usdt.h
index 86e24e4..3efdfa4 100644
--- a/src/cc/bcc_usdt.h
+++ b/src/cc/bcc_usdt.h
@@ -77,6 +77,9 @@
 const char *bcc_usdt_get_probe_argctype(
   void *ctx, const char* probe_name, const int arg_index
 );
+const char *bcc_usdt_get_fully_specified_probe_argctype(
+  void *ctx, const char* provider_name, const char* probe_name, const int arg_index
+);
 
 typedef void (*bcc_usdt_uprobe_cb)(const char *, const char *, uint64_t, int);
 void bcc_usdt_foreach_uprobe(void *usdt, bcc_usdt_uprobe_cb callback);
diff --git a/src/cc/usdt/usdt.cc b/src/cc/usdt/usdt.cc
index 0c02601..c992bbb 100644
--- a/src/cc/usdt/usdt.cc
+++ b/src/cc/usdt/usdt.cc
@@ -506,6 +506,15 @@
   return "";
 }
 
+const char *bcc_usdt_get_fully_specified_probe_argctype(
+  void *ctx, const char* provider_name, const char* probe_name, const int arg_index
+) {
+  USDT::Probe *p = static_cast<USDT::Context *>(ctx)->get(provider_name, probe_name);
+  if (p)
+    return p->get_arg_ctype(arg_index).c_str();
+  return "";
+}
+
 void bcc_usdt_foreach(void *usdt, bcc_usdt_cb callback) {
   USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
   ctx->each(callback);
diff --git a/src/python/bcc/libbcc.py b/src/python/bcc/libbcc.py
index 0f33215..d2c4d2e 100644
--- a/src/python/bcc/libbcc.py
+++ b/src/python/bcc/libbcc.py
@@ -231,6 +231,9 @@
 lib.bcc_usdt_get_probe_argctype.restype = ct.c_char_p
 lib.bcc_usdt_get_probe_argctype.argtypes = [ct.c_void_p, ct.c_char_p, ct.c_int]
 
+lib.bcc_usdt_get_fully_specified_probe_argctype.restype = ct.c_char_p
+lib.bcc_usdt_get_fully_specified_probe_argctype.argtypes = [ct.c_void_p, ct.c_char_p, ct.c_char_p, ct.c_int]
+
 class bcc_usdt(ct.Structure):
     _fields_ = [
             ('provider', ct.c_char_p),
diff --git a/src/python/bcc/usdt.py b/src/python/bcc/usdt.py
index 021222f..67525c2 100644
--- a/src/python/bcc/usdt.py
+++ b/src/python/bcc/usdt.py
@@ -182,8 +182,14 @@
         return lib.bcc_usdt_genargs(ctx_array, 1).decode()
 
     def get_probe_arg_ctype(self, probe_name, arg_index):
-        return lib.bcc_usdt_get_probe_argctype(
-            self.context, probe_name.encode('ascii'), arg_index).decode()
+        probe_parts = probe_name.split(":", 1)
+        if len(probe_parts) == 1:
+            return lib.bcc_usdt_get_probe_argctype(
+                self.context, probe_name.encode('ascii'), arg_index).decode()
+        else:
+            (provider_name, probe) = probe_parts
+            return lib.bcc_usdt_get_fully_specified_probe_argctype(
+                self.context, provider_name.encode('ascii'), probe.encode('ascii'), arg_index).decode()
 
     def enumerate_probes(self):
         probes = []
diff --git a/tools/trace.py b/tools/trace.py
index 8b2ca35..c87edef 100755
--- a/tools/trace.py
+++ b/tools/trace.py
@@ -160,8 +160,9 @@
                         self.library = ""       # kernel
                         self.function = ""      # from TRACEPOINT_PROBE
                 elif self.probe_type == "u":
-                        self.library = ':'.join(parts[1:-1])
-                        self.usdt_name = parts[-1]
+                        # u:<library>[:<provider>]:<probe> where :<provider> is optional
+                        self.library = parts[1]
+                        self.usdt_name = ":".join(parts[2:])
                         self.function = ""      # no function, just address
                         # We will discover the USDT provider by matching on
                         # the USDT name in the specified library
@@ -180,8 +181,17 @@
                 target = Probe.pid if Probe.pid and Probe.pid != -1 \
                                    else Probe.tgid
                 self.usdt = USDT(path=self.library, pid=target)
+
+                parts = self.usdt_name.split(":")
+                if len(parts) == 1:
+                        provider_name = None
+                        usdt_name = parts[0].encode("ascii")
+                else:
+                        provider_name = parts[0].encode("ascii")
+                        usdt_name = parts[1].encode("ascii")
                 for probe in self.usdt.enumerate_probes():
-                        if probe.name == self.usdt_name.encode('ascii'):
+                        if ((not provider_name or probe.provider == provider_name)
+                                        and probe.name == usdt_name):
                                 return  # Found it, will enable later
                 self._bail("unrecognized USDT probe %s" % self.usdt_name)
 
@@ -677,6 +687,8 @@
         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
+trace 'u:pthread:libpthread:pthread_create (arg4 != 0)'
+        Ditto, but the provider name "libpthread" is specified.
 trace 'p::SyS_nanosleep(struct timespec *ts) "sleep for %lld ns", ts->tv_nsec'
         Trace the nanosleep syscall and print the sleep duration in ns
 trace -c /sys/fs/cgroup/system.slice/workload.service '__x64_sys_nanosleep' '__x64_sys_clone'