]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
debuginfod-client: Add debuginfod_set_verbose_fd and DEBUGINFOD_VERBOSE
authorMark Wielaard <mark@klomp.org>
Tue, 10 Nov 2020 23:23:08 +0000 (00:23 +0100)
committerMark Wielaard <mark@klomp.org>
Mon, 23 Nov 2020 15:58:36 +0000 (16:58 +0100)
Introduce a new function debuginfod_set_verbose_fd which will produce
verbose output on a given file descriptor (STDERR_FILENO if the
environment variable DEBUGINFOD_VERBOSE is set) showing how the search
for a particular client query is going.

Example output:

debuginfod_find_debuginfo 1234567890
server urls "https://debuginfod.elfutils.org/ http://dbgd.usersys.com:3632/"
checking build-id
checking cache dir /home/mark/.cache/debuginfod_client
using timeout 90
init server 0 https://debuginfod.elfutils.org/
url 0 https://debuginfod.elfutils.org/buildid/1234567890/debuginfo
init server 1 http://dbgd.usersys.com:3632/
url 1 http://dbgd.usersys.com:3632/buildid/1234567890/debuginfo
query 2 urls in parallel
server response HTTP response code said error
url 0 The requested URL returned error: 404 Not Found
server response HTTP response code said error
url 1 The requested URL returned error: 404 Not Found
not found No such file or directory (err=-2)

Signed-off-by: Mark Wielaard <mark@klomp.org>
debuginfod/ChangeLog
debuginfod/debuginfod-client.c
debuginfod/debuginfod-find.c
debuginfod/debuginfod.h
debuginfod/libdebuginfod.map
doc/ChangeLog
doc/debuginfod_find_debuginfo.3

index b3c812856b22659e53d8dd4a8a05bc3fa779ec73..bd4dbf403f308d2bc79f6895147c91e78e1f1453 100644 (file)
@@ -1,3 +1,19 @@
+2020-11-11  Mark Wielaard  <mark@klomp.org>
+
+       * debuginfod-client.c (debuginfod_set_verbose_fd): New function.
+       (struct debuginfod_client): Add verbose_fd.
+       (struct handle_data): Add errbuf.
+       (debuginfod_query_server): Produce verbose output when
+       debuginfod_client verbose_fd is set. Only clear old data and set
+       default_headers when any work is done. Always goto out when setting
+       rc to an error value. Use CURLOPT_ERRORBUFFER to get more error
+       output when verbose output is requested.
+       * debuginfod.h (DEBUGINFOD_VERBOSE_ENV_VAR): New.
+       (debuginfod_set_verbose_fd): Added.
+       * debuginfod-find.c (parse_opt): Set debuginfod_set_verbose_fd on -v.
+       * bdebuginfod.map (ELFUTILS_0.183): New section, add
+       debuginfod_set_verbose_fd.
+
 2020-11-21  Mark Wielaard  <mark@klomp.org>
 
        * debuginfod.cxx (handle_root): New function.
index ce1d819b97e68d03ef2cb89239bbd0437855c6b5..2bf1543abe59eada3cb0de16857ccdd25ee4c6ed 100644 (file)
@@ -56,6 +56,7 @@ int debuginfod_find_source (debuginfod_client *c, const unsigned char *b,
                             int s, const char *f, char **p)  { return -ENOSYS; }
 void debuginfod_set_progressfn(debuginfod_client *c,
                               debuginfod_progressfn_t fn) { }
+void debuginfod_set_verbose_fd(debuginfod_client *c, int fd) { }
 void debuginfod_set_user_data (debuginfod_client *c, void *d) { }
 void* debuginfod_get_user_data (debuginfod_client *c) { return NULL; }
 const char* debuginfod_get_url (debuginfod_client *c) { return NULL; }
@@ -115,6 +116,9 @@ struct debuginfod_client
      debuginfod_end needs to terminate. */
   int default_progressfn_printed_p;
 
+  /* File descriptor to output any verbose messages if > 0.  */
+  int verbose_fd;
+
   /* 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
@@ -158,6 +162,9 @@ struct handle_data
   /* URL queried by this handle.  */
   char url[PATH_MAX];
 
+  /* error buffer for this handle.  */
+  char errbuf[CURL_ERROR_SIZE];
+
   /* This handle.  */
   CURL *handle;
 
@@ -498,28 +505,51 @@ debuginfod_query_server (debuginfod_client *c,
   char *target_cache_tmppath = NULL;
   char suffix[PATH_MAX + 1]; /* +1 for zero terminator.  */
   char build_id_bytes[MAX_BUILD_ID_BYTES * 2 + 1];
+  int vfd = c->verbose_fd;
   int rc;
 
-  /* Clear the obsolete URL from a previous _find operation. */
-  free (c->url);
-  c->url = NULL;
-
-  add_default_headers(c);
+  if (vfd >= 0)
+    {
+      dprintf (vfd, "debuginfod_find_%s ", type);
+      if (build_id_len == 0) /* expect clean hexadecimal */
+       dprintf (vfd, "%s", (const char *) build_id);
+      else
+       for (int i = 0; i < build_id_len; i++)
+         dprintf (vfd, "%02x", build_id[i]);
+      if (filename != NULL)
+       dprintf (vfd, " %s\n", filename);
+      dprintf (vfd, "\n");
+    }
 
   /* Is there any server we can query?  If not, don't do any work,
      just return with ENOSYS.  Don't even access the cache.  */
   urls_envvar = getenv(server_urls_envvar);
+  if (vfd >= 0)
+    dprintf (vfd, "server urls \"%s\"\n",
+            urls_envvar != NULL ? urls_envvar : "");
   if (urls_envvar == NULL || urls_envvar[0] == '\0')
     {
       rc = -ENOSYS;
       goto out;
     }
 
+  /* Clear the obsolete URL from a previous _find operation. */
+  free (c->url);
+  c->url = NULL;
+
+  add_default_headers(c);
+
   /* Copy lowercase hex representation of build_id into buf.  */
+  if (vfd >= 0)
+    dprintf (vfd, "checking build-id\n");
   if ((build_id_len >= MAX_BUILD_ID_BYTES) ||
       (build_id_len == 0 &&
        strlen ((const char *) build_id) > MAX_BUILD_ID_BYTES*2))
-    return -EINVAL;
+    {
+      rc = -EINVAL;
+      goto out;
+    }
+
   if (build_id_len == 0) /* expect clean hexadecimal */
     strcpy (build_id_bytes, (const char *) build_id);
   else
@@ -528,8 +558,13 @@ debuginfod_query_server (debuginfod_client *c,
 
   if (filename != NULL)
     {
+      if (vfd >= 0)
+       dprintf (vfd, "checking filename\n");
       if (filename[0] != '/') // must start with /
-        return -EINVAL;
+       {
+         rc = -EINVAL;
+         goto out;
+       }
 
       /* copy the filename to suffix, s,/,#,g */
       unsigned q = 0;
@@ -559,6 +594,9 @@ debuginfod_query_server (debuginfod_client *c,
   else
     suffix[0] = '\0';
 
+  if (suffix[0] != '\0' && vfd >= 0)
+    dprintf (vfd, "suffix %s\n", suffix);
+
   /* set paths needed to perform the query
 
      example format
@@ -630,6 +668,10 @@ debuginfod_query_server (debuginfod_client *c,
   /* XXX combine these */
   xalloc_str (interval_path, "%s/%s", cache_path, cache_clean_interval_filename);
   xalloc_str (maxage_path, "%s/%s", cache_path, cache_max_unused_age_filename);
+
+  if (vfd >= 0)
+    dprintf (vfd, "checking cache dir %s\n", cache_path);
+
   rc = debuginfod_init_cache(cache_path, interval_path, maxage_path);
   if (rc != 0)
     goto out;
@@ -653,6 +695,9 @@ debuginfod_query_server (debuginfod_client *c,
   if (timeout_envvar != NULL)
     timeout = atoi (timeout_envvar);
 
+  if (vfd >= 0)
+    dprintf (vfd, "using timeout %ld\n", timeout);
+
   /* make a copy of the envvar so it can be safely modified.  */
   server_urls = strdup(urls_envvar);
   if (server_urls == NULL)
@@ -719,6 +764,9 @@ debuginfod_query_server (debuginfod_client *c,
   /* Initialize each handle.  */
   for (int i = 0; i < num_urls && server_url != NULL; i++)
     {
+      if (vfd >= 0)
+       dprintf (vfd, "init server %d %s\n", i, server_url);
+
       data[i].fd = fd;
       data[i].target_handle = &target_handle;
       data[i].handle = curl_easy_init();
@@ -745,7 +793,12 @@ debuginfod_query_server (debuginfod_client *c,
         snprintf(data[i].url, PATH_MAX, "%s%s/%s/%s", server_url,
                  slashbuildid, build_id_bytes, type);
 
+      if (vfd >= 0)
+       dprintf (vfd, "url %d %s\n", i, data[i].url);
+
       curl_easy_setopt(data[i].handle, CURLOPT_URL, data[i].url);
+      if (vfd >= 0)
+       curl_easy_setopt(data[i].handle, CURLOPT_ERRORBUFFER, data[i].errbuf);
       curl_easy_setopt(data[i].handle,
                        CURLOPT_WRITEFUNCTION,
                        debuginfod_write_callback);
@@ -778,8 +831,12 @@ debuginfod_query_server (debuginfod_client *c,
     }
 
   /* Query servers in parallel.  */
+  if (vfd >= 0)
+    dprintf (vfd, "query %d urls in parallel\n", num_urls);
   int still_running;
   long loops = 0;
+  int committed_to = -1;
+  bool verbose_reported = false;
   do
     {
       /* Wait 1 second, the minimum DEBUGINFOD_TIMEOUT.  */
@@ -787,9 +844,23 @@ debuginfod_query_server (debuginfod_client *c,
 
       /* If the target file has been found, abort the other queries.  */
       if (target_handle != NULL)
-        for (int i = 0; i < num_urls; i++)
-          if (data[i].handle != target_handle)
-            curl_multi_remove_handle(curlm, data[i].handle);
+       {
+         for (int i = 0; i < num_urls; i++)
+           if (data[i].handle != target_handle)
+             curl_multi_remove_handle(curlm, data[i].handle);
+           else
+             committed_to = i;
+       }
+
+      if (vfd >= 0 && !verbose_reported && committed_to >= 0)
+       {
+         bool pnl = (c->default_progressfn_printed_p && vfd == STDERR_FILENO);
+         dprintf (vfd, "%scommitted to url %d\n", pnl ? "\n" : "",
+                  committed_to);
+         if (pnl)
+           c->default_progressfn_printed_p = 0;
+         verbose_reported = true;
+       }
 
       CURLMcode curlm_res = curl_multi_perform(curlm, &still_running);
       if (curlm_res != CURLM_OK)
@@ -863,6 +934,23 @@ debuginfod_query_server (debuginfod_client *c,
       msg = curl_multi_info_read(curlm, &num_msg);
       if (msg != NULL && msg->msg == CURLMSG_DONE)
         {
+         if (vfd >= 0)
+           {
+             bool pnl = (c->default_progressfn_printed_p
+                         && vfd == STDERR_FILENO);
+             dprintf (vfd, "%sserver response %s\n", pnl ? "\n" : "",
+                      curl_easy_strerror (msg->data.result));
+             if (pnl)
+               c->default_progressfn_printed_p = 0;
+             for (int i = 0; i < num_urls; i++)
+               if (msg->easy_handle == data[i].handle)
+                 {
+                   if (strlen (data[i].errbuf) > 0)
+                     dprintf (vfd, "url %d %s\n", i, data[i].errbuf);
+                   break;
+                 }
+           }
+
           if (msg->data.result != CURLE_OK)
             {
               /* Unsucessful query, determine error code.  */
@@ -946,6 +1034,14 @@ debuginfod_query_server (debuginfod_client *c,
   if (verified_handle == NULL)
     goto out1;
 
+  if (vfd >= 0)
+    {
+      bool pnl = c->default_progressfn_printed_p && vfd == STDERR_FILENO;
+      dprintf (vfd, "%sgot file from server\n", pnl ? "\n" : "");
+      if (pnl)
+       c->default_progressfn_printed_p = 0;
+    }
+
   /* we've got one!!!! */
   time_t mtime;
   CURLcode curl_res = curl_easy_getinfo(verified_handle, CURLINFO_FILETIME, (void*) &mtime);
@@ -1005,6 +1101,14 @@ debuginfod_query_server (debuginfod_client *c,
   if (c->default_progressfn_printed_p)
     dprintf(STDERR_FILENO, "\n");
 
+  if (vfd >= 0)
+    {
+      if (rc < 0)
+       dprintf (vfd, "not found %s (err=%d)\n", strerror (-rc), rc);
+      else
+       dprintf (vfd, "found %s (fd=%d)\n", target_cache_path, rc);
+    }
+
   free (cache_path);
   free (maxage_path);
   free (interval_path);
@@ -1027,6 +1131,10 @@ debuginfod_begin (void)
     {
       if (getenv(DEBUGINFOD_PROGRESS_ENV_VAR))
        client->progressfn = default_progressfn;
+      if (getenv(DEBUGINFOD_VERBOSE_ENV_VAR))
+       client->verbose_fd = STDERR_FILENO;
+      else
+       client->verbose_fd = -1;
     }
   return client;
 }
@@ -1125,6 +1233,12 @@ debuginfod_set_progressfn(debuginfod_client *client,
   client->progressfn = fn;
 }
 
+void
+debuginfod_set_verbose_fd(debuginfod_client *client, int fd)
+{
+  client->verbose_fd = fd;
+}
+
 
 /* NB: these are thread-unsafe. */
 __attribute__((constructor)) attribute_hidden void libdebuginfod_ctor(void)
index 5f9bccc388a7aecbde517a48a5e994168cf1dea1..3e8ab203d02548b64427c26a52e7d2e6d1f1de7c 100644 (file)
@@ -98,7 +98,9 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
   switch (key)
     {
     case 'v': verbose++;
-      debuginfod_set_progressfn (client, & progressfn); break;
+      debuginfod_set_progressfn (client, & progressfn);
+      debuginfod_set_verbose_fd (client, STDERR_FILENO);
+      break;
     default: return ARGP_ERR_UNKNOWN;
     }
   return 0;
index 8d90838b4cb2aabb55ada0231aa3b1f43fd3c0d2..4ee86ce9086ef4de5dfed67f14e38cc64f40d261 100644 (file)
@@ -34,6 +34,7 @@
 #define DEBUGINFOD_CACHE_PATH_ENV_VAR "DEBUGINFOD_CACHE_PATH"
 #define DEBUGINFOD_TIMEOUT_ENV_VAR "DEBUGINFOD_TIMEOUT"
 #define DEBUGINFOD_PROGRESS_ENV_VAR "DEBUGINFOD_PROGRESS"
+#define DEBUGINFOD_VERBOSE_ENV_VAR "DEBUGINFOD_VERBOSE"
 
 /* Handle for debuginfod-client connection.  */
 typedef struct debuginfod_client debuginfod_client;
@@ -75,6 +76,8 @@ typedef int (*debuginfod_progressfn_t)(debuginfod_client *c, long a, long b);
 void debuginfod_set_progressfn(debuginfod_client *c,
                               debuginfod_progressfn_t fn);
 
+void debuginfod_set_verbose_fd(debuginfod_client *c, int fd);
+
 /* Set the user parameter.  */
 void debuginfod_set_user_data (debuginfod_client *client, void *value);
 
index b8edfb016054a3a49629bc608afa620a7592cb5e..7d2f5882fed3e22c60329244970a356f07377b0b 100644 (file)
@@ -14,4 +14,7 @@ ELFUTILS_0.179 {
   debuginfod_get_user_data;
   debuginfod_get_url;
   debuginfod_add_http_header;
-};
+} ELFUTILS_0.178;
+ELFUTILS_0.183 {
+  debuginfod_set_verbose_fd;
+} ELFUTILS_0.179;
index 8c33f1749c7f8fce7d9822ae3b177780ecf58bf6..fdf352e7ebcc34a9928e598f975a1256905cd2d7 100644 (file)
@@ -1,3 +1,10 @@
+2020-11-11  Mark Wielaard  <mark@klomp.org>
+
+       * debuginfod_find_debuginfo.3: Document debuginfod_set_verbose_fd
+       and DEBUGINFOD_VERBOSE.
+       * debuginfod_set_verbose_fd.3: New redirect to
+       debuginfod_find_debuginfo.3
+
 2020-10-29  Frank Ch. Eigler  <fche@redhat.com>
 
        PR26775
index eec04e5eaefd0f4f1a9586c1c8c9381f25e3d98e..3c6d52f56d38a0ca01404b35bc35fcddc1b6fda1 100644 (file)
@@ -50,6 +50,8 @@ OPTIONAL FUNCTIONS
 .BI "                                       long a, long b);"
 .BI "void debuginfod_set_progressfn(debuginfod_client *" client ","
 .BI "                               debuginfod_progressfn_t " progressfn ");"
+.BI "void debuginfod_set_verbose_fd(debuginfod_client *" client ","
+.BI "                               int " fd ");"
 .BI "void debuginfod_set_user_data(debuginfod_client *" client ","
 .BI "                              void *" data ");"
 .BI "void* debuginfod_get_user_data(debuginfod_client *" client ");"
@@ -143,6 +145,15 @@ continue the work, or any other value to stop work as soon as
 possible.  Consequently, the \fBdebuginfod_find_*\fP() function will
 likely return with an error, but might still succeed.
 
+.SS "VERBOSE OUTPUT"
+
+The \fBdebuginfod_find_*\fP() functions may use several techniques
+to retrieve the requested files, through the cache or through one
+or multiple servers or file URLs. To show how a query is handled hte
+.BR debuginfod_set_verbose_fd ()
+can be used to set a particular file descriptor on which verbose
+output is given about the query steps and eventual errors encountered.
+
 .SS "USER DATA POINTER"
 
 A single \fIvoid *\fP pointer associated with the connection handle
@@ -235,6 +246,12 @@ configure a default progressfn.  This function will append a simple
 progress message periodically to stderr.  The default is no progress
 function output.
 
+.TP 21
+.B DEBUGINFOD_VERBOSE
+This environment variable governs the default file descriptor for
+verbose output.  If set, and if a verbose fd is not explicitly set,
+then the verbose output will be produced on STDERR_FILENO.
+
 .TP 21
 .B DEBUGINFOD_CACHE_PATH
 This environment variable governs the location of the cache where