Add bcc_usdt_enable_fully_specified_probe to avoid usdt provider collisions
diff --git a/src/cc/bcc_usdt.h b/src/cc/bcc_usdt.h
index a031bc6..0c54809 100644
--- a/src/cc/bcc_usdt.h
+++ b/src/cc/bcc_usdt.h
@@ -70,6 +70,8 @@
                           struct bcc_usdt_argument *argument);
 
 int bcc_usdt_enable_probe(void *, const char *, const char *);
+#define BCC_USDT_HAS_FULLY_SPECIFIED_PROBE
+int bcc_usdt_enable_fully_specified_probe(void *, const char *, const char *, const char *);
 const char *bcc_usdt_genargs(void **ctx_array, int len);
 const char *bcc_usdt_get_probe_argctype(
   void *ctx, const char* probe_name, const int arg_index
diff --git a/src/cc/usdt.h b/src/cc/usdt.h
index 406cfd5..f746d03 100644
--- a/src/cc/usdt.h
+++ b/src/cc/usdt.h
@@ -280,6 +280,7 @@
   Probe *get(int pos) { return probes_[pos].get(); }
 
   bool enable_probe(const std::string &probe_name, const std::string &fn_name);
+  bool enable_probe(const std::string &provider_name, const std::string &probe_name, const std::string &fn_name);
 
   typedef void (*each_cb)(struct bcc_usdt *);
   void each(each_cb callback);
diff --git a/src/cc/usdt/usdt.cc b/src/cc/usdt/usdt.cc
index c91faa0..5f78509 100644
--- a/src/cc/usdt/usdt.cc
+++ b/src/cc/usdt/usdt.cc
@@ -295,24 +295,46 @@
 
 bool Context::enable_probe(const std::string &probe_name,
                            const std::string &fn_name) {
+  return enable_probe("", probe_name, fn_name);
+}
+
+bool Context::enable_probe(const std::string &provider_name,
+                           const std::string &probe_name,
+                           const std::string &fn_name) {
   if (pid_stat_ && pid_stat_->is_stale())
     return false;
 
-  // FIXME: we may have issues here if the context has two same probes's
-  // but different providers. For example, libc:setjmp and rtld:setjmp,
-  // libc:lll_futex_wait and rtld:lll_futex_wait.
+  unsigned int matches = 0;
   Probe *found_probe = nullptr;
   for (auto &p : probes_) {
     if (p->name_ == probe_name) {
-      if (found_probe != nullptr) {
-         fprintf(stderr, "Two same-name probes (%s) but different providers\n",
-                 probe_name.c_str());
-         return false;
+      if (found_probe == nullptr && provider_name == "")
+      {
+        found_probe = p.get();
+        matches++;
       }
-      found_probe = p.get();
+      else if (found_probe != nullptr && provider_name == "")
+      {
+        fprintf(stderr, "Found duplicate provider (%s) for underspecified probe (%s)\n",
+                p->provider().c_str(), p->name().c_str());
+        matches++;
+      } else if (provider_name != "" && p->provider() == provider_name)
+      {
+        found_probe = p.get();
+        matches++;
+      }
     }
   }
 
+  if (matches > 1) {
+    fprintf(stderr, "Found %i duplicate providers for underpecified probe (%s)\n",
+                matches, fn_name.c_str());
+    return false;
+  } else if(matches < 1) {
+    fprintf(stderr, "No matches found for probe (%s)\n", fn_name.c_str());
+    return false;
+  }
+
   if (found_probe != nullptr)
     return found_probe->enable(fn_name);
 
@@ -448,6 +470,14 @@
   return ctx->enable_probe(probe_name, fn_name) ? 0 : -1;
 }
 
+int bcc_usdt_enable_fully_specified_probe(void *usdt,
+                                          const char *provider_name,
+                                          const char *probe_name,
+                                          const char *fn_name) {
+  USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
+  return ctx->enable_probe(provider_name, probe_name, fn_name) ? 0 : -1;
+}
+
 const char *bcc_usdt_genargs(void **usdt_array, int len) {
   static std::string storage_;
   std::ostringstream stream;