debuginfod: add client context
authorMark Wielaard <mark@klomp.org>
Sun, 17 Nov 2019 21:17:26 +0000 (22:17 +0100)
committerMark Wielaard <mark@klomp.org>
Sat, 23 Nov 2019 00:03:13 +0000 (01:03 +0100)
Add a mandatory debuginfod_begin()/_end() call pair to manage a client
object that represents persistent but non-global state.  From libdwfl,
dlopen the debuginfod.so client library early on.  This hopefully
makes sure that the code (and the libcurl.so dependency) is loaded
before the program goes into multi-threaded mode.

Signed-off-by: Mark Wielaard <mark@klomp.org>
14 files changed:
debuginfod/debuginfod-client.c
debuginfod/debuginfod-find.c
debuginfod/debuginfod.cxx
debuginfod/debuginfod.h
debuginfod/libdebuginfod.map
doc/debuginfod_begin.3 [new file with mode: 0644]
doc/debuginfod_end.3 [new file with mode: 0644]
doc/debuginfod_find_debuginfo.3
libdwfl/Makefile.am
libdwfl/debuginfod-client.c [new file with mode: 0644]
libdwfl/dwfl_build_id_find_elf.c
libdwfl/dwfl_end.c
libdwfl/find-debuginfo.c
libdwfl/libdwflP.h

index 64dd608..6e62b86 100644 (file)
   #include <fts.h>
 #endif
 
+struct debuginfod_client
+{
+  /* Progress/interrupt callback function. */
+  debuginfod_progressfn_t progressfn;
+
+  /* Can contain all other context, like cache_path, server_urls,
+     timeout or other info gotten from environment variables, the
+     handle data, etc. So those don't have to be reparsed and
+     recreated on each request.  */
+};
 
 /* The cache_clean_interval_s file within the debuginfod cache specifies
    how frequently the cache should be cleaned. The file's st_mtime represents
@@ -99,9 +109,6 @@ static const char url_delim_char = ' ';
 static const char *server_timeout_envvar = DEBUGINFOD_TIMEOUT_ENV_VAR;
 static int server_timeout = 5;
 
-/* Progress/interrupt callback function. */
-static debuginfod_progressfn_t progressfn;
-
 /* Data associated with a particular CURL easy handle. Passed to
    the write callback.  */
 struct handle_data
@@ -181,7 +188,9 @@ debuginfod_init_cache (char *cache_path, char *interval_path, char *maxage_path)
 /* Delete any files that have been unmodied for a period
    longer than $DEBUGINFOD_CACHE_CLEAN_INTERVAL_S.  */
 static int
-debuginfod_clean_cache(char *cache_path, char *interval_path, char *max_unused_path)
+debuginfod_clean_cache(debuginfod_client *c,
+                      char *cache_path, char *interval_path,
+                      char *max_unused_path)
 {
   struct stat st;
   FILE *interval_file;
@@ -236,8 +245,8 @@ debuginfod_clean_cache(char *cache_path, char *interval_path, char *max_unused_p
   while ((f = fts_read(fts)) != NULL)
     {
       files++;
-      if (progressfn) /* inform/check progress callback */
-        if ((*progressfn) (files, 0))
+      if (c->progressfn) /* inform/check progress callback */
+        if ((c->progressfn) (c, files, 0))
           break;
 
       switch (f->fts_info)
@@ -275,7 +284,8 @@ debuginfod_clean_cache(char *cache_path, char *interval_path, char *max_unused_p
    descriptor for the target, otherwise return an error code.
 */
 static int
-debuginfod_query_server (const unsigned char *build_id,
+debuginfod_query_server (debuginfod_client *c,
+                        const unsigned char *build_id,
                          int build_id_len,
                          const char *type,
                          const char *filename,
@@ -366,7 +376,7 @@ debuginfod_query_server (const unsigned char *build_id,
   int rc = debuginfod_init_cache(cache_path, interval_path, maxage_path);
   if (rc != 0)
     goto out;
-  rc = debuginfod_clean_cache(cache_path, interval_path, maxage_path);
+  rc = debuginfod_clean_cache(c, cache_path, interval_path, maxage_path);
   if (rc != 0)
     goto out;
 
@@ -501,7 +511,7 @@ debuginfod_query_server (const unsigned char *build_id,
     {
       CURLMcode curl_res;
 
-      if (progressfn) /* inform/check progress callback */
+      if (c->progressfn) /* inform/check progress callback */
         {
           loops ++;
           long pa = loops; /* default params for progress callback */
@@ -541,7 +551,7 @@ debuginfod_query_server (const unsigned char *build_id,
 #endif
             }
 
-          if ((*progressfn) (pa, pb))
+          if ((*c->progressfn) (c, pa, pb))
             break;
         }
 
@@ -674,41 +684,59 @@ debuginfod_query_server (const unsigned char *build_id,
   return rc;
 }
 
-
 /* See debuginfod.h  */
+debuginfod_client  *
+debuginfod_begin (void)
+{
+  debuginfod_client *client;
+  size_t size = sizeof (struct debuginfod_client);
+  client = (debuginfod_client *) malloc (size);
+  if (client != NULL)
+    client->progressfn = NULL;
+  return client;
+}
+
+void
+debuginfod_end (debuginfod_client *client)
+{
+  free (client);
+}
+
 int
-debuginfod_find_debuginfo (const unsigned char *build_id, int build_id_len,
+debuginfod_find_debuginfo (debuginfod_client *client,
+                          const unsigned char *build_id, int build_id_len,
                            char **path)
 {
-  return debuginfod_query_server(build_id, build_id_len,
+  return debuginfod_query_server(client, build_id, build_id_len,
                                  "debuginfo", NULL, path);
 }
 
 
 /* See debuginfod.h  */
 int
-debuginfod_find_executable(const unsigned char *build_id, int build_id_len,
+debuginfod_find_executable(debuginfod_client *client,
+                          const unsigned char *build_id, int build_id_len,
                            char **path)
 {
-  return debuginfod_query_server(build_id, build_id_len,
+  return debuginfod_query_server(client, build_id, build_id_len,
                                  "executable", NULL, path);
 }
 
 /* See debuginfod.h  */
-int debuginfod_find_source(const unsigned char *build_id, int build_id_len,
+int debuginfod_find_source(debuginfod_client *client,
+                          const unsigned char *build_id, int build_id_len,
                            const char *filename, char **path)
 {
-  return debuginfod_query_server(build_id, build_id_len,
+  return debuginfod_query_server(client, build_id, build_id_len,
                                  "source", filename, path);
 }
 
 
-debuginfod_progressfn_t
-debuginfod_set_progressfn(debuginfod_progressfn_t fn)
+void
+debuginfod_set_progressfn(debuginfod_client *client,
+                         debuginfod_progressfn_t fn)
 {
-  debuginfod_progressfn_t it = progressfn;
-  progressfn = fn;
-  return it;
+  client->progressfn = fn;
 }
 
 
index 4c1a94c..8bd3a3d 100644 (file)
@@ -49,9 +49,11 @@ static const struct argp_option options[] =
    { NULL, 0, NULL, 0, NULL, 0 }
   };
 
+/* debuginfod connection handle.  */
+static debuginfod_client *client;
 
-
-int progressfn(long a, long b)
+int progressfn(debuginfod_client *c __attribute__((__unused__)),
+              long a, long b)
 {
   fprintf (stderr, "Progress %ld / %ld\n", a, b);
   return 0;
@@ -64,7 +66,7 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
   (void) state;
   switch (key)
     {
-    case 'v': debuginfod_set_progressfn (& progressfn); break;
+    case 'v': debuginfod_set_progressfn (client, & progressfn); break;
     default: return ARGP_ERR_UNKNOWN;
     }
   return 0;
@@ -82,6 +84,13 @@ static struct argp argp =
 int
 main(int argc, char** argv)
 {
+  client = debuginfod_begin ();
+  if (client == NULL)
+    {
+      fprintf(stderr, "Couldn't create debuginfod client context\n");
+      return 1;
+    }
+
   int remaining;
   (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER|ARGP_NO_ARGS, &remaining, NULL);
 
@@ -98,9 +107,13 @@ main(int argc, char** argv)
      debuginfod_find_* function. If FILETYPE is "source"
      then ensure a FILENAME was also supplied as an argument.  */
   if (strcmp(argv[remaining], "debuginfo") == 0)
-    rc = debuginfod_find_debuginfo((unsigned char *)argv[remaining+1], 0, &cache_name);
+    rc = debuginfod_find_debuginfo(client,
+                                  (unsigned char *)argv[remaining+1], 0,
+                                  &cache_name);
   else if (strcmp(argv[remaining], "executable") == 0)
-    rc = debuginfod_find_executable((unsigned char *)argv[remaining+1], 0, &cache_name);
+    rc = debuginfod_find_executable(client,
+                                   (unsigned char *)argv[remaining+1], 0,
+                                   &cache_name);
   else if (strcmp(argv[remaining], "source") == 0)
     {
       if (remaining+2 == argc || argv[3][0] != '/')
@@ -108,8 +121,8 @@ main(int argc, char** argv)
           fprintf(stderr, "If FILETYPE is \"source\" then absolute /FILENAME must be given\n");
           return 1;
         }
-      rc = debuginfod_find_source((unsigned char *)argv[remaining+1], 0,
-                                 argv[remaining+2], &cache_name);
+      rc = debuginfod_find_source(client, (unsigned char *)argv[remaining+1],
+                                 0, argv[remaining+2], &cache_name);
     }
   else
     {
@@ -126,5 +139,7 @@ main(int argc, char** argv)
   printf("%s\n", cache_name);
 
   free (cache_name);
+  debuginfod_end (client);
+
   return 0;
 }
index e2535ce..f4bbc7b 100644 (file)
@@ -944,7 +944,7 @@ handle_buildid_match (int64_t b_mtime,
 
 
 static int
-debuginfod_find_progress (long a, long b)
+debuginfod_find_progress (debuginfod_client *, long a, long b)
 {
   if (verbose > 4)
     obatched(clog) << "federated debuginfod progress=" << a << "/" << b << endl;
@@ -1036,15 +1036,28 @@ static struct MHD_Response* handle_buildid (const string& buildid /* unsafe */,
   // is to defer to other debuginfo servers.
 
   int fd = -1;
-  if (artifacttype == "debuginfo")
-    fd = debuginfod_find_debuginfo ((const unsigned char*) buildid.c_str(), 0,
-                                   NULL);
-  else if (artifacttype == "executable")
-    fd = debuginfod_find_executable ((const unsigned char*) buildid.c_str(), 0,
-                                    NULL);
-  else if (artifacttype == "source")
-    fd = debuginfod_find_source ((const unsigned char*) buildid.c_str(), 0,
-                                suffix.c_str(), NULL);
+  debuginfod_client *client = debuginfod_begin ();
+  if (client != NULL)
+    {
+      debuginfod_set_progressfn (client, & debuginfod_find_progress);
+
+      if (artifacttype == "debuginfo")
+       fd = debuginfod_find_debuginfo (client,
+                                       (const unsigned char*) buildid.c_str(),
+                                       0, NULL);
+      else if (artifacttype == "executable")
+       fd = debuginfod_find_executable (client,
+                                        (const unsigned char*) buildid.c_str(),
+                                        0, NULL);
+      else if (artifacttype == "source")
+       fd = debuginfod_find_source (client,
+                                    (const unsigned char*) buildid.c_str(),
+                                    0, suffix.c_str(), NULL);
+    }
+  else
+    fd = -errno; /* Set by debuginfod_begin.  */
+  debuginfod_end (client);
+
   if (fd >= 0)
     {
       inc_metric ("http_responses_total","result","upstream");
@@ -2508,8 +2521,6 @@ main (int argc, char *argv[])
              "cannot run database schema ddl: %s", sqlite3_errmsg(db));
     }
 
-  (void) debuginfod_set_progressfn (& debuginfod_find_progress);
-
   // Start httpd server threads.  Separate pool for IPv4 and IPv6, in
   // case the host only has one protocol stack.
   MHD_Daemon *d4 = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
index 0620f02..6b1b1cc 100644 (file)
 #define DEBUGINFOD_CACHE_PATH_ENV_VAR "DEBUGINFOD_CACHE_PATH"
 #define DEBUGINFOD_TIMEOUT_ENV_VAR "DEBUGINFOD_TIMEOUT"
 
+/* Handle for debuginfod-client connection.  */
+typedef struct debuginfod_client debuginfod_client;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/* Create a handle for a new debuginfod-client session.  */
+debuginfod_client *debuginfod_begin (void);
+
 /* Query the urls contained in $DEBUGINFOD_URLS for a file with
    the specified type and build id.  If build_id_len == 0, the
    build_id is supplied as a lowercase hexadecimal string; otherwise
@@ -48,21 +54,28 @@ extern "C" {
    strdup'd copy of the name of the same file in the cache.
    Caller must free() it later. */
   
-int debuginfod_find_debuginfo (const unsigned char *build_id,
+int debuginfod_find_debuginfo (debuginfod_client *client,
+                              const unsigned char *build_id,
                                int build_id_len,
                                char **path);
 
-int debuginfod_find_executable (const unsigned char *build_id,
+int debuginfod_find_executable (debuginfod_client *client,
+                               const unsigned char *build_id,
                                 int build_id_len,
                                 char **path);
 
-int debuginfod_find_source (const unsigned char *build_id,
+int debuginfod_find_source (debuginfod_client *client,
+                           const unsigned char *build_id,
                             int build_id_len,
                             const char *filename,
                             char **path);
 
-typedef int (*debuginfod_progressfn_t)(long a, long b);
-debuginfod_progressfn_t debuginfod_set_progressfn(debuginfod_progressfn_t fn);
+typedef int (*debuginfod_progressfn_t)(debuginfod_client *c, long a, long b);
+void debuginfod_set_progressfn(debuginfod_client *c,
+                              debuginfod_progressfn_t fn);
+
+/* Release debuginfod client connection context handle.  */
+void debuginfod_end (debuginfod_client *client);
 
 #ifdef __cplusplus
 }
index b322cba..0d26f93 100644 (file)
@@ -1,6 +1,8 @@
 ELFUTILS_0 { };
 ELFUTILS_0.178 {
   global:
+  debuginfod_begin;
+  debuginfod_end;
   debuginfod_find_debuginfo;
   debuginfod_find_executable;
   debuginfod_find_source;
diff --git a/doc/debuginfod_begin.3 b/doc/debuginfod_begin.3
new file mode 100644 (file)
index 0000000..1627993
--- /dev/null
@@ -0,0 +1 @@
+.so man3/debuginfod_find_debuginfo.3
diff --git a/doc/debuginfod_end.3 b/doc/debuginfod_end.3
new file mode 100644 (file)
index 0000000..1627993
--- /dev/null
@@ -0,0 +1 @@
+.so man3/debuginfod_find_debuginfo.3
index d8d9236..be8eed0 100644 (file)
@@ -21,15 +21,39 @@ debuginfod_find_debuginfo \- request debuginfo from debuginfod
 .nf
 .B #include <elfutils/debuginfod.h>
 .PP
-.BI "int debuginfod_find_debuginfo(const unsigned char *" build_id ", int " build_id_len ", char ** " path ");"
-.BI "int debuginfod_find_executable(const unsigned char *" build_id ", int " build_id_len ", char ** " path ");"
-.BI "int debuginfod_find_source(const unsigned char *" build_id ", int " build_id_len ", const char *" filename ", char ** " path ");"
-.BI "typedef int (*debuginfo_progressfn_t)(long a, long b);"
-.BI "debuginfo_progressfn_t debuginfod_set_progressfn(debuginfo_progressfn_t " progressfn ");"
+.BI "debuginfod_client *debuginfod_begin(void);"
+.BI "void debuginfod_end(debuginfod_client *" client ");"
+
+.BI "int debuginfod_find_debuginfo(debuginfod_client *" client ","
+.BI "                              const unsigned char *" build_id ","
+.BI "                              int " build_id_len ","
+.BI "                              char ** " path ");"
+.BI "int debuginfod_find_executable(debuginfod_client *" client ","
+.BI "                               const unsigned char *" build_id ","
+.BI "                               int " build_id_len ","
+.BI "                               char ** " path ");"
+.BI "int debuginfod_find_source(debuginfod_client *" client ","
+.BI "                           const unsigned char *" build_id ","
+.BI "                           int " build_id_len ","
+.BI "                           const char *" filename ","
+.BI "                           char ** " path ");"
+
+.BI "typedef int (*debuginfo_progressfn_t)(debuginfod_client *" client ","
+.BI "                                      long a, long b);"
+.BI "void debuginfod_set_progressfn(debuginfod_client *" client ","
+.BI "                               debuginfo_progressfn_t " progressfn ");"
 
 Link with \fB-ldebuginfod\fP.
 
 .SH DESCRIPTION
+
+.BR debuginfod_begin ()
+creates a \fBdebuginfod_client\fP connection handle that should be used
+with all other calls.
+.BR debuginfod_end ()
+should be called on the \fBclient\fP handle to release all state and
+storage when done.
+
 .BR debuginfod_find_debuginfo (),
 .BR debuginfod_find_executable (),
 and
@@ -65,9 +89,14 @@ The URLs in \fB$DEBUGINFOD_URLS\fP may be queried in parallel. As soon
 as a debuginfod server begins transferring the target file all of the
 connections to the other servers are closed.
 
-These functions are MT-safe.
+A \fBclient\fP handle should be used from only one thread at a time.
 
 .SH "RETURN VALUE"
+
+\fBdebuginfod_begin\fP returns the \fBdebuginfod_client\fP handle to
+use with all other calls.  On error \fBNULL\fP will be returned and
+\fBerrno\fP will be set.
+
 If a find family function is successful, the resulting file is saved
 to the client cache and a file descriptor to that file is returned.
 The caller needs to \fBclose\fP() this descriptor.  Otherwise, a
@@ -75,12 +104,12 @@ negative error code is returned.
 
 .SH "PROGRESS CALLBACK"
 
-As the \fBdebuginfod_find_*\fP() functions may block for seconds or longer, a progress
-callback function is called periodically, if configured with
+As the \fBdebuginfod_find_*\fP() functions may block for seconds or
+longer, a progress callback function is called periodically, if
+configured with
 .BR debuginfod_set_progressfn ().
-This function sets a new progress callback function (or NULL) and
-returns the previously set function (or NULL).  This function may be
-MT-unsafe.
+This function sets a new progress callback function (or NULL) for the
+client handle.
 
 The given callback function is called from the context of each thread
 that is invoking any of the other lookup functions.  It is given two
index 29046e9..47bd62a 100644 (file)
@@ -70,7 +70,7 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
                    link_map.c core-file.c open.c image-header.c \
                    dwfl_frame.c frame_unwind.c dwfl_frame_pc.c \
                    linux-pid-attach.c linux-core-attach.c dwfl_frame_regs.c \
-                   gzip.c
+                   gzip.c debuginfod-client.c
 
 if BZLIB
 libdwfl_a_SOURCES += bzip2.c
diff --git a/libdwfl/debuginfod-client.c b/libdwfl/debuginfod-client.c
new file mode 100644 (file)
index 0000000..ee604ad
--- /dev/null
@@ -0,0 +1,131 @@
+/* Try to get an ELF or debug file through the debuginfod.
+   Copyright (C) 2019 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwflP.h"
+#include <dlfcn.h>
+
+static __typeof__ (debuginfod_begin) *fp_debuginfod_begin;
+static __typeof__ (debuginfod_find_executable) *fp_debuginfod_find_executable;
+static __typeof__ (debuginfod_find_debuginfo) *fp_debuginfod_find_debuginfo;
+static __typeof__ (debuginfod_end) *fp_debuginfod_end;
+
+/* NB: this is slightly thread-unsafe */
+
+static debuginfod_client *
+get_client (Dwfl *dwfl)
+{
+  if (dwfl->debuginfod != NULL)
+    return dwfl->debuginfod;
+
+  if (fp_debuginfod_begin != NULL)
+    {
+      dwfl->debuginfod = (*fp_debuginfod_begin) ();
+      return dwfl->debuginfod;
+    }
+
+  return NULL;
+}
+
+int
+__libdwfl_debuginfod_find_executable (Dwfl *dwfl,
+                                     const unsigned char *build_id_bits,
+                                     size_t build_id_len)
+{
+  int fd = -1;
+  if (build_id_len > 0)
+    {
+      debuginfod_client *c = get_client (dwfl);
+      if (c != NULL)
+       fd = (*fp_debuginfod_find_executable) (c, build_id_bits,
+                                              build_id_len, NULL);
+    }
+
+  return fd;
+}
+
+int
+__libdwfl_debuginfod_find_debuginfo (Dwfl *dwfl,
+                                    const unsigned char *build_id_bits,
+                                    size_t build_id_len)
+{
+  int fd = -1;
+  if (build_id_len > 0)
+    {
+      debuginfod_client *c = get_client (dwfl);
+      if (c != NULL)
+       fd = (*fp_debuginfod_find_debuginfo) (c, build_id_bits,
+                                             build_id_len, NULL);
+    }
+
+  return fd;
+}
+
+void
+__libdwfl_debuginfod_end (debuginfod_client *c)
+{
+  if (c != NULL)
+    (*fp_debuginfod_end) (c);
+}
+
+/* Try to get the libdebuginfod library functions to make sure
+   everything is initialized early.  */
+void __attribute__ ((constructor))
+__libdwfl_debuginfod_init (void)
+{
+  void *debuginfod_so = dlopen("libdebuginfod-" VERSION ".so", RTLD_LAZY);
+
+  if (debuginfod_so == NULL)
+    debuginfod_so = dlopen("libdebuginfod.so", RTLD_LAZY);
+
+  if (debuginfod_so != NULL)
+    {
+      fp_debuginfod_begin = dlsym (debuginfod_so, "debuginfod_begin");
+      fp_debuginfod_find_executable = dlsym (debuginfod_so,
+                                            "debuginfod_find_executable");
+      fp_debuginfod_find_debuginfo = dlsym (debuginfod_so,
+                                           "debuginfod_find_debuginfo");
+      fp_debuginfod_end = dlsym (debuginfod_so, "debuginfod_end");
+
+      /* We either get them all, or we get none.  */
+      if (fp_debuginfod_begin == NULL
+         || fp_debuginfod_find_executable == NULL
+         || fp_debuginfod_find_debuginfo == NULL
+         || fp_debuginfod_end == NULL)
+       {
+         fp_debuginfod_begin = NULL;
+         fp_debuginfod_find_executable = NULL;
+         fp_debuginfod_find_debuginfo = NULL;
+         fp_debuginfod_end = NULL;
+         dlclose (debuginfod_so);
+       }
+    }
+}
index b775f50..4e56143 100644 (file)
@@ -34,9 +34,7 @@
 #include <inttypes.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include <dlfcn.h>
 #include "system.h"
-#include "debuginfod.h"
 
 
 int
@@ -189,31 +187,15 @@ dwfl_build_id_find_elf (Dwfl_Module *mod,
       free (*file_name);
       *file_name = NULL;
     }
-  else {
-    /* NB: this is slightly thread-unsafe */
-    static __typeof__ (debuginfod_find_executable) *fp_debuginfod_find_executable;
-
-    if (fp_debuginfod_find_executable == NULL)
-      {
-        void *debuginfod_so = dlopen("libdebuginfod-" VERSION ".so", RTLD_LAZY);
-        if (debuginfod_so == NULL)
-          debuginfod_so = dlopen("libdebuginfod.so", RTLD_LAZY);
-        if (debuginfod_so != NULL)
-          fp_debuginfod_find_executable = dlsym (debuginfod_so, "debuginfod_find_executable");
-        if (fp_debuginfod_find_executable == NULL)
-          fp_debuginfod_find_executable = (void *) -1; /* never try again */
-      }
-
-    if (fp_debuginfod_find_executable != NULL && fp_debuginfod_find_executable != (void *) -1)
-      {
-        /* If all else fails and a build-id is available, query the
-           debuginfo-server if enabled.  */
-        if (fd < 0 && mod->build_id_len > 0)
-          fd = (*fp_debuginfod_find_executable) (mod->build_id_bits,
-                                                mod->build_id_len,
-                                                NULL);
-      }
-  }
+  else
+    {
+      /* If all else fails and a build-id is available, query the
+        debuginfo-server if enabled.  */
+      if (fd < 0 && mod->build_id_len > 0)
+       fd = __libdwfl_debuginfod_find_executable (mod->dwfl,
+                                                  mod->build_id_bits,
+                                                  mod->build_id_len);
+    }
 
   if (fd < 0 && errno == 0 && mod->build_id_len > 0)
     /* Setting this with no file yet loaded is a marker that
index 74ee9e0..4f6c722 100644 (file)
@@ -39,6 +39,8 @@ dwfl_end (Dwfl *dwfl)
   if (dwfl == NULL)
     return;
 
+  __libdwfl_debuginfod_end (dwfl->debuginfod);
+
   if (dwfl->process)
     __libdwfl_process_free (dwfl->process);
 
index ffc07f9..4085764 100644 (file)
 #endif
 
 #include "libdwflP.h"
-#include "debuginfod.h"
 #include <stdio.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include <dlfcn.h>
 #include <sys/stat.h>
 #include "system.h"
 
@@ -400,29 +398,8 @@ dwfl_standard_find_debuginfo (Dwfl_Module *mod,
       free (canon);
     }
 
-  {
-    /* NB: this is slightly thread-unsafe */
-    static __typeof__ (debuginfod_find_debuginfo) *fp_debuginfod_find_debuginfo;
-
-    if (fp_debuginfod_find_debuginfo == NULL)
-      {
-        void *debuginfod_so = dlopen("libdebuginfod-" VERSION ".so", RTLD_LAZY);
-        if (debuginfod_so == NULL)
-          debuginfod_so = dlopen("libdebuginfod.so", RTLD_LAZY);
-        if (debuginfod_so != NULL)
-          fp_debuginfod_find_debuginfo = dlsym (debuginfod_so, "debuginfod_find_debuginfo");
-        if (fp_debuginfod_find_debuginfo == NULL)
-          fp_debuginfod_find_debuginfo = (void *) -1; /* never try again */
-      }
-
-    if (fp_debuginfod_find_debuginfo != NULL && fp_debuginfod_find_debuginfo != (void *) -1)
-      {
-        /* If all else fails and a build-id is available, query the
-           debuginfo-server if enabled.  */
-        if (fd < 0 && bits_len > 0)
-          fd = (*fp_debuginfod_find_debuginfo) (bits, bits_len, NULL);
-      }
-  }
+  if (fd < 0 && bits_len > 0)
+    fd = __libdwfl_debuginfod_find_debuginfo (mod->dwfl, bits, bits_len);
 
   return fd;
 }
index 6b2d486..f631f94 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "../libdw/libdwP.h"   /* We need its INTDECLs.  */
 #include "../libdwelf/libdwelfP.h"
+#include "../debuginfod/debuginfod.h"
 
 typedef struct Dwfl_Process Dwfl_Process;
 
@@ -114,6 +115,7 @@ struct Dwfl_User_Core
 struct Dwfl
 {
   const Dwfl_Callbacks *callbacks;
+  debuginfod_client *debuginfod;
 
   Dwfl_Module *modulelist;    /* List in order used by full traversals.  */
 
@@ -634,6 +636,19 @@ extern Dwfl_Error __libdw_open_elf (int fd, Elf **elfp) internal_function;
 extern bool __libdwfl_dynamic_vaddr_get (Elf *elf, GElf_Addr *vaddrp)
   internal_function;
 
+/* Internal interface to libdebuginfod (if installed).  */
+int
+__libdwfl_debuginfod_find_executable (Dwfl *dwfl,
+                                     const unsigned char *build_id_bits,
+                                     size_t build_id_len);
+int
+__libdwfl_debuginfod_find_debuginfo (Dwfl *dwfl,
+                                    const unsigned char *build_id_bits,
+                                    size_t build_id_len);
+void
+__libdwfl_debuginfod_end (debuginfod_client *c);
+
+
 /* These are working nicely for --core, but are not ready to be
    exported interfaces quite yet.  */