]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
PR432215 Add debuginfod functionality
authorAaron Merey <amerey@redhat.com>
Fri, 19 Feb 2021 03:58:25 +0000 (22:58 -0500)
committerMark Wielaard <mark@klomp.org>
Fri, 26 Feb 2021 00:38:42 +0000 (01:38 +0100)
debuginfod is an HTTP server for distributing ELF/DWARF debugging
information.  When a debuginfo file cannot be found locally, Valgrind
is able to query debuginfod servers for the file using its build-id.

readelf.c: Add debuginfod_find_debug_file(). Spawns a child process to
exec `debuginfod-find` in order to query servers for the debuginfo
file. Also add helper debuginfod_find_path().

pub_core_pathscan.h: Moved from priv_initimg_pathscan.h in order to use
VG_(find_executable)() in readelf.c.

docs: Add information regarding debuginfod to valgrind.1

memcheck/tests/linux: Add new test debuginfod-check.

tests/vg_regtest.in: Clear $DEBUGINFOD_URLS before running any tests.

https://bugs.kde.org/show_bug.cgi?id=432215

18 files changed:
.gitignore
NEWS
configure.ac
coregrind/Makefile.am
coregrind/m_debuginfo/readelf.c
coregrind/m_initimg/initimg-darwin.c
coregrind/m_initimg/initimg-linux.c
coregrind/m_initimg/initimg-solaris.c
coregrind/m_pathscan.c [moved from coregrind/m_initimg/initimg-pathscan.c with 95% similarity]
coregrind/pub_core_pathscan.h [moved from coregrind/m_initimg/priv_initimg_pathscan.h with 78% similarity]
docs/xml/manual-core.xml
docs/xml/valgrind-manpage.xml
memcheck/tests/linux/Makefile.am
memcheck/tests/linux/debuginfod-check.c [new file with mode: 0644]
memcheck/tests/linux/debuginfod-check.pl [new file with mode: 0755]
memcheck/tests/linux/debuginfod-check.stderr.exp [new file with mode: 0644]
memcheck/tests/linux/debuginfod-check.vgtest.in [new file with mode: 0644]
tests/vg_regtest.in

index 3afc37f4cdc1197eb2ce5710c6d469f0a0dbf842..c22c0315a225ef7ed0168eb3c0e496385c9e60c0 100644 (file)
 /memcheck/tests/linux/sys-execveat
 /memcheck/tests/linux/check_execveat
 /memcheck/tests/linux/enomem
+/memcheck/tests/linux/debuginfod-check
+/memcheck/tests/linux/debuginfod-check.vgtest
+/memcheck/tests/linux/.debuginfod/
 
 # /memcheck/tests/mips32/
 /memcheck/tests/mips32/*.stderr.diff
diff --git a/NEWS b/NEWS
index a20f96f0c632bf9cb5166eb0de2ce064491c1a4a..3a34269869d0ae3157d9cfed004f7fa0b4aefb65 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -35,6 +35,12 @@ support for X86/macOS 10.13, AMD64/macOS 10.13 and nanoMIPS/Linux.
     Valgrind.  The vector-packed-decimal facility is currently not
     exploited by the standard toolchain and libraries.
 
+* Valgrind now supports debuginfod, an HTTP server for distributing
+  ELF/DWARF debugging information. When a debuginfo file cannot be
+  found locally, Valgrind is able to query debuginfod servers for the
+  file using its build-id. See the user manual for more information
+  about debuginfod support.
+
 * ==================== TOOL CHANGES ====================
 
 * DHAT:
@@ -125,6 +131,7 @@ where XXXXXX is the bug number as listed below.
 432672  vg_regtest: test-specific environment variables not reset between tests
 432809  VEX should support REX.W + POPF
 432861  PPC modsw and modsd give incorrect results for 1 mod 12
+432215  Add debuginfod functionality
 n-i-bz  helgrind: If hg_cli__realloc fails, return NULL.
 429352  PPC ISA 3.1 support is missing, part 7
 
index 4648450fe3b1395041293a4e25c2068b4fe49491..595003b46d4529d63bb3baead480feb8078fe454 100755 (executable)
@@ -4903,6 +4903,7 @@ AC_CONFIG_FILES([
    memcheck/tests/amd64/Makefile
    memcheck/tests/x86/Makefile
    memcheck/tests/linux/Makefile
+   memcheck/tests/linux/debuginfod-check.vgtest
    memcheck/tests/darwin/Makefile
    memcheck/tests/solaris/Makefile
    memcheck/tests/amd64-linux/Makefile
index 1753fb633c53b9393d2b9b5291317324ccf7604b..be097f44f567930f67826355532782c1dd20a7d7 100644 (file)
@@ -212,6 +212,7 @@ noinst_HEADERS = \
        pub_core_mallocfree.h   \
        pub_core_options.h      \
        pub_core_oset.h         \
+       pub_core_pathscan.h     \
        pub_core_poolalloc.h    \
        pub_core_rangemap.h     \
        pub_core_redir.h        \
@@ -267,7 +268,6 @@ noinst_HEADERS = \
        m_gdbserver/target.h \
        m_gdbserver/valgrind_low.h \
        m_gdbserver/gdb/signals.h \
-       m_initimg/priv_initimg_pathscan.h \
        m_scheduler/priv_sema.h \
        m_scheduler/priv_sched-lock.h \
        m_scheduler/priv_sched-lock-impl.h \
@@ -317,6 +317,7 @@ COREGRIND_SOURCES_COMMON = \
        m_mallocfree.c \
        m_options.c \
        m_oset.c \
+       m_pathscan.c \
        m_poolalloc.c \
        m_rangemap.c \
        m_redir.c \
@@ -403,7 +404,6 @@ COREGRIND_SOURCES_COMMON = \
        m_initimg/initimg-linux.c \
        m_initimg/initimg-darwin.c \
        m_initimg/initimg-solaris.c \
-       m_initimg/initimg-pathscan.c \
        m_mach/mach_basics.c \
        m_mach/mach_msg.c \
        m_mach/mach_traps-x86-darwin.S \
index 404034df06b1759df0a3617a770436e63f7569cd..3f5f48c7033f3adfe4c05ceafa9ae83cd8bc9bce 100644 (file)
 #include "pub_core_libcbase.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcproc.h"
 #include "pub_core_machine.h"      /* VG_ELF_CLASS */
 #include "pub_core_options.h"
 #include "pub_core_oset.h"
+#include "pub_core_pathscan.h"     /* find_executable */
 #include "pub_core_syscall.h"
 #include "pub_core_tooliface.h"    /* VG_(needs) */
 #include "pub_core_xarray.h"
@@ -1281,6 +1284,135 @@ DiImage* open_debug_file( const HChar* name, const HChar* buildid, UInt crc,
    return dimg;
 }
 
+#if defined(VGO_linux)
+/* Return the path of the debuginfod-find executable. */
+static
+const HChar* debuginfod_find_path( void )
+{
+  static const HChar* path = (const HChar*) -1;
+
+  if (path == (const HChar*) -1) {
+     if (VG_(getenv)("DEBUGINFOD_URLS") == NULL
+         || VG_(strcmp)("", VG_(getenv("DEBUGINFOD_URLS"))) == 0)
+        path = NULL;
+     else
+        path = VG_(find_executable)("debuginfod-find");
+  }
+
+  return path;
+}
+
+/* Try to find a separate debug file with |buildid| via debuginfod. If found,
+   return its DiImage. Searches for a local debuginfod-find executable and
+   runs it in a child process in order to download the debug file. */
+static
+DiImage* find_debug_file_debuginfod( const HChar* objpath,
+                                     HChar** debugpath,
+                                     const HChar* buildid,
+                                     const UInt crc, Bool rel_ok )
+{
+#  define BUF_SIZE 4096
+   Int          out_fds[2], err_fds[2]; /* pipe fds */
+   DiImage*     dimg = NULL;            /* the img we found */
+   HChar        buf[BUF_SIZE];          /* executable output buffer */
+   const HChar* path;                   /* executable path */
+   SizeT        len;                    /* number of bytes read int buf */
+   Int          ret;                    /* result of read call */
+
+   if (buildid == NULL)
+      return NULL;
+
+   if ((path = debuginfod_find_path()) == NULL)
+      return NULL;
+
+   if (VG_(pipe)(out_fds) != 0
+       || VG_(pipe)(err_fds) != 0)
+      return NULL;
+
+   if (VG_(clo_verbosity) > 1)
+      VG_(umsg)("Downloading debug info for %s...\n", objpath);
+
+   /* Run debuginfod-find to query servers for the debuginfo. */
+   Int pid = VG_(fork)();
+   if (pid == 0) {
+      const HChar *argv[4] = { path, "debuginfo", buildid, (HChar*)0 };
+
+      /* Redirect stdout and stderr */
+      SysRes res = VG_(dup2)(out_fds[1], 1);
+      if (sr_Res(res) < 0)
+         VG_(exit)(1);
+
+      res = VG_(dup2)(err_fds[1], 2);
+      if (sr_Res(res) < 0)
+         VG_(exit)(1);
+
+      /* Disable extra stderr output since it does not play well with umesg */
+      VG_(env_unsetenv)(VG_(client_envp), "DEBUGINFOD_VERBOSE", NULL);
+      VG_(env_unsetenv)(VG_(client_envp), "DEBUGINFOD_PROGRESS", NULL);
+
+      VG_(close)(out_fds[0]);
+      VG_(close)(err_fds[0]);
+      VG_(execv)(argv[0], argv);
+
+      /* If we are still alive here, execv failed. */
+      VG_(exit)(1);
+   }
+
+   VG_(close)(out_fds[1]);
+   VG_(close)(err_fds[1]);
+
+   if (pid < 0) {
+      if (VG_(clo_verbosity) > 1)
+         VG_(umsg)("Server Error\n");
+      goto out;
+   }
+   VG_(waitpid)(pid, NULL, 0);
+
+   /* Set dimg if download was successful. */
+   len = 0;
+   ret = -1;
+   while (len >= 0 && len < BUF_SIZE) {
+      ret = VG_(read)(out_fds[0], buf + len, BUF_SIZE - len);
+      if (ret <= 0)
+         break;
+      len += ret;
+   }
+   if (ret >= 0 && len > 0
+       && buf[0] == '/' && buf[len-1] == '\n') {
+
+      /* Remove newline from filename before trying to open debug file */
+      buf[len-1] = '\0';
+      dimg = open_debug_file(buf, buildid, crc, rel_ok, NULL);
+      if (dimg != NULL) {
+         /* Success */
+         if (*debugpath)
+            ML_(dinfo_free)(*debugpath);
+
+         *debugpath = ML_(dinfo_strdup)("di.fdfd.1", buf);
+         if (VG_(clo_verbosity) > 1)
+            VG_(umsg)("Successfully downloaded debug file for %s\n",
+                      objpath);
+         goto out;
+      }
+   }
+
+   /* Download failed so try to print error message. */
+   HChar* nl;
+   if (VG_(read)(err_fds[0], buf, BUF_SIZE) > 0
+       && (nl = VG_(strchr)(buf, '\n'))) {
+      *nl = '\0';
+      if (VG_(clo_verbosity) > 1)
+         VG_(umsg)("%s\n", buf);
+   } else
+      if (VG_(clo_verbosity) > 1)
+         VG_(umsg)("Server Error\n");
+
+out:
+   VG_(close)(out_fds[0]);
+   VG_(close)(err_fds[0]);
+   return dimg;
+}
+#endif
 
 /* Try to find a separate debug file for a given object file.  If
    found, return its DiImage, which should be freed by the caller.  If
@@ -1381,6 +1513,11 @@ DiImage* find_debug_file( struct _DebugInfo* di,
       ML_(dinfo_free)(objdir);
    }
 
+#  if defined(VGO_linux)
+   if (dimg == NULL)
+      dimg = find_debug_file_debuginfod(objpath, &debugpath, buildid, crc, rel_ok);
+#  endif
+
    if (dimg != NULL) {
       vg_assert(debugpath);
       TRACE_SYMTAB("\n");
index e2662476ad2ba18ffc113b8307dbce190e64d076..564d2fdaa7eaf4ba46d28289eed6f64105d3ae8a 100644 (file)
@@ -46,7 +46,7 @@
 #include "pub_core_options.h"
 #include "pub_core_tooliface.h"       /* VG_TRACK */
 #include "pub_core_threadstate.h"     /* ThreadArchState */
-#include "priv_initimg_pathscan.h"
+#include "pub_core_pathscan.h"        /* find_executable */
 #include "pub_core_initimg.h"         /* self */
 
 
@@ -64,7 +64,7 @@ static void load_client ( /*OUT*/ExeInfo* info,
    SysRes res;
 
    vg_assert( VG_(args_the_exename) != NULL);
-   exe_name = ML_(find_executable)( VG_(args_the_exename) );
+   exe_name = VG_(find_executable)( VG_(args_the_exename) );
 
    if (!exe_name) {
       VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename));
index cb7902446a584a05f29f8898e0533110c140c31d..73dab34363a0bb59914d8f9861b3a1a35c79a6a2 100644 (file)
@@ -47,7 +47,7 @@
 #include "pub_core_syscall.h"
 #include "pub_core_tooliface.h"       /* VG_TRACK */
 #include "pub_core_threadstate.h"     /* ThreadArchState */
-#include "priv_initimg_pathscan.h"
+#include "pub_core_pathscan.h"        /* find_executable */
 #include "pub_core_initimg.h"         /* self */
 
 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
@@ -73,7 +73,7 @@ static void load_client ( /*MOD*/ExeInfo* info,
    SysRes res;
 
    vg_assert( VG_(args_the_exename) != NULL);
-   exe_name = ML_(find_executable)( VG_(args_the_exename) );
+   exe_name = VG_(find_executable)( VG_(args_the_exename) );
 
    if (!exe_name) {
       VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename));
index 0a6c385b769da5423d78423c3c9ca9162e14faad..3e473c8803c081da648122b97d1f5673d86ece36 100644 (file)
@@ -51,7 +51,7 @@
 #include "pub_core_syswrap.h"
 #include "pub_core_tooliface.h"       /* VG_TRACK */
 #include "pub_core_threadstate.h"     /* ThreadArchState */
-#include "priv_initimg_pathscan.h"
+#include "pub_core_pathscan.h"        /* find_executable */
 #include "pub_core_initimg.h"         /* self */
 
 
@@ -68,7 +68,7 @@ static void load_client(/*OUT*/ExeInfo *info,
    SysRes res;
 
    vg_assert(VG_(args_the_exename));
-   exe_name = ML_(find_executable)(VG_(args_the_exename));
+   exe_name = VG_(find_executable)(VG_(args_the_exename));
 
    if (!exe_name) {
       VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename));
similarity index 95%
rename from coregrind/m_initimg/initimg-pathscan.c
rename to coregrind/m_pathscan.c
index f5f825f3b1c67a65549a14b4a6cbc6761daf4397..02b371486e77e8086f988a63ed2d7ab264a3d3a5 100644 (file)
@@ -1,6 +1,6 @@
 
 /*--------------------------------------------------------------------*/
-/*--- Startup: search PATH for an executable    initimg-pathscan.c ---*/
+/*--- search PATH for an executable                   m_pathscan.c ---*/
 /*--------------------------------------------------------------------*/
 
 /*
@@ -33,9 +33,7 @@
 #include "pub_core_libcproc.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_mallocfree.h"
-#include "pub_core_initimg.h"         /* self */
-
-#include "priv_initimg_pathscan.h"
+#include "pub_core_pathscan.h"         /* self */
 
 
 /*====================================================================*/
@@ -117,7 +115,7 @@ static Bool match_executable(const HChar *entry)
 }
 
 // Returns NULL if it wasn't found.
-const HChar* ML_(find_executable) ( const HChar* exec )
+const HChar* VG_(find_executable) ( const HChar* exec )
 {
    vg_assert(NULL != exec);
 
similarity index 78%
rename from coregrind/m_initimg/priv_initimg_pathscan.h
rename to coregrind/pub_core_pathscan.h
index e6ffb4a8b03bc89f36fdeb623dec3e163b835398..d84953ab21d34da4276408ba814eeb7d9da8f83e 100644 (file)
@@ -1,7 +1,7 @@
 
 /*--------------------------------------------------------------------*/
-/*--- Startup: search PATH for an executable                       ---*/
-/*---                                      priv_initimg-pathscan.h ---*/
+/*--- Search PATH for an executable                                ---*/
+/*---                                                 m_pathscan.h ---*/
 /*--------------------------------------------------------------------*/
 
 /*
    The GNU General Public License is contained in the file COPYING.
 */
 
-#ifndef __PRIV_INITIMG_PATHSCAN_H
-#define __PRIV_INITIMG_PATHSCAN_H
+#ifndef __PUB_CORE_PATHSCAN_H
+#define __PUB_CORE_PATHSCAN_H
 
 #include "pub_core_basics.h"   // HChar
 
-extern const HChar* ML_(find_executable) ( const HChar* exec );
+extern const HChar* VG_(find_executable) ( const HChar* exec );
 
-#endif // ndef __PRIV_INITIMG_PATHSCAN_H
+#endif // ndef __PUB_CORE_PATHSCAN_H
index 5d52d2e3bec92bbe4603f8498bd56076a3decbc7..dc33e12696d63c95ef998599e062db0328410632 100644 (file)
@@ -592,6 +592,30 @@ to <computeroutput>malloc.</computeroutput>.</para>
 </sect1>
 
 
+<sect1 id="manual-core.debuginfod"
+       xreflabel="Debuginfod">
+<title>Debuginfod</title>
+
+<para id="debuginfod.para.1">Valgrind supports the downloading of debuginfo
+files via debuginfod, an HTTP server for distributing ELF/DWARF debugging
+information. When a debuginfo file cannot be found locally, Valgrind is able
+to query debuginfod servers for the file using its build-id.</para>
+
+<para id="debuginfod.para.2">In order to use this feature
+<computeroutput>debuginfod-find</computeroutput> must be installed and
+<computeroutput>$DEBUGINFOD_URLS</computeroutput> must contain URLs of
+debuginfod servers. Valgrind does not support
+<computeroutput>debuginfod-find</computeroutput> verbose output that is
+normally enabled with <computeroutput>$DEBUGINFOD_PROGRESS</computeroutput>
+and <computeroutput>$DEBUGINFOD_VERBOSE</computeroutput>. These environment
+variables will be ignored.</para>
+
+<para id="debuginfod.para.3">For more information regarding debuginfod, see
+https://sourceware.org/elfutils/Debuginfod.html</para>
+
+</sect1>
+
+
 <sect1 id="manual-core.options" 
        xreflabel="Core Command-line Options">
 <title>Core Command-line Options</title>
@@ -1462,6 +1486,10 @@ that can report errors, e.g. Memcheck, but not Cachegrind.</para>
       you want to use it, you will have to recompile it by hand using
       the command shown at the top
       of <computeroutput>auxprogs/valgrind-di-server.c</computeroutput>.</para>
+
+      <para>Valgrind can also download debuginfo via debuginfod. See the
+      DEBUGINFOD section for more information.</para>
+
     </listitem>
   </varlistentry>
 
index 3c893c680e471ccc57d352495712340028c8740c..5c16c6eb35da00e2a72662038fe544284580c55c 100644 (file)
@@ -221,6 +221,19 @@ system: <filename>&vg-docs-path;</filename>, or online:
 
 </refsect1>
 
+<refsect1 id="debuginfod">
+<title>Debuginfod</title>
+
+<xi:include href="manual-core.xml"
+            xpointer="debuginfod.para.1"
+            xmlns:xi="http://www.w3.org/2001/XInclude" />
+<xi:include href="manual-core.xml"
+            xpointer="debuginfod.para.2"
+            xmlns:xi="http://www.w3.org/2001/XInclude" />
+<xi:include href="manual-core.xml"
+            xpointer="debuginfod.para.3"
+            xmlns:xi="http://www.w3.org/2001/XInclude" />
+</refsect1>
 
 <refsect1 id="see_also">
 <title>See Also</title>
index 7e796aa7faae4c4ea6fd2860905a573944168c50..90a24e4abef27438f2bf3bb9b40d345e364add20 100644 (file)
@@ -6,6 +6,7 @@ dist_noinst_SCRIPTS = filter_stderr
 EXTRA_DIST = \
        brk.stderr.exp brk.vgtest \
        capget.vgtest capget.stderr.exp capget.stderr.exp2 capget.stderr.exp3 \
+       debuginfod-check.stderr.exp debuginfod-check.vgtest.in \
        dlclose_leak-no-keep.stderr.exp dlclose_leak-no-keep.stdout.exp \
            dlclose_leak-no-keep.vgtest \
        dlclose_leak.stderr.exp dlclose_leak.stdout.exp \
@@ -37,6 +38,7 @@ check_PROGRAMS = \
        brk \
        capget \
        check_preadv2_pwritev2 \
+       debuginfod-check \
        dlclose_leak dlclose_leak_so.so \
        ioctl-tiocsig \
        getregset \
diff --git a/memcheck/tests/linux/debuginfod-check.c b/memcheck/tests/linux/debuginfod-check.c
new file mode 100644 (file)
index 0000000..185139a
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+
+int main() {
+       char *p = malloc(1);
+        p[-1] = 0;
+        return 0;
+}
diff --git a/memcheck/tests/linux/debuginfod-check.pl b/memcheck/tests/linux/debuginfod-check.pl
new file mode 100755 (executable)
index 0000000..4a2c1c1
--- /dev/null
@@ -0,0 +1,116 @@
+#! /usr/bin/perl
+use warnings;
+use strict;
+use Cwd;
+use IPC::Open3;
+
+our $dir = Cwd::realpath("./.debuginfod");
+our $pid = 0;
+
+# Kill the server and remove temporary files.
+sub cleanup_and_exit($) {
+    my $exit_code = $_[0];
+    mysystem("rm -rf $dir");
+    if ($pid != 0) {
+        kill "INT", $pid;
+    }
+    exit $exit_code;
+}
+
+# Propagate Ctrl-C and exit if command results in an error.
+sub mysystem($)
+{
+    my $exit_code = system($_[0]);
+    ($exit_code == 2) and cleanup_and_exit(1); # Exit if SIGINT
+    if ($exit_code != 0) {
+        #warn "Error while executing: $_[0]";
+        cleanup_and_exit(1);
+    }
+    return $exit_code;
+}
+
+# Check that debuginfod and debuginfod-find can be found
+mysystem("debuginfod --help > /dev/null");
+mysystem("debuginfod-find --help > /dev/null");
+
+$SIG{'INT'} = sub { cleanup_and_exit(1) };
+
+my $testname = "debuginfod-check";
+my $tmp = "$dir/debuginfod_test.tmp";
+my $dbg = "$dir/dbg";
+mysystem("rm -rf $dir");
+mysystem("mkdir -p $dbg");
+
+# Compile the test executable, strip its debuginfo and store it so
+# that valgrind cannot find it without debuginfod.
+mysystem("gcc -O0 -g -o $testname $testname.c");
+mysystem("objcopy --only-keep-debug $testname $testname.debug");
+mysystem("objcopy --strip-unneeded $testname");
+mysystem("objcopy --add-gnu-debuglink=$testname.debug $testname");
+mysystem("mv $testname.debug $dbg");
+mysystem("readelf -n $testname > $tmp 2>&1");
+
+my $buildid = "";
+open(TMP, '<', $tmp);
+while (my $out = <TMP>) {
+    if ($out =~ /Build ID: ([0-9a-f]*)/) {
+        $buildid = $1;
+    }
+}
+
+if ($buildid eq "") {
+    warn "can't find $testname build-id";
+    cleanup_and_exit(1);
+}
+
+my $found_port = 0;
+my $port = 7999;
+
+# Find an unused port
+while ($found_port == 0 and $port < 65536) {
+    $port++;
+    $pid = open3(undef, "TMP", undef,
+                 "debuginfod", "-d", "$dir/db", '-F', "$dbg", "--port=$port");
+    for (my $i = 0; $i < 5 and $found_port == 0; $i++) {
+        while (my $got = <TMP>) {
+            if ($got =~ /Failed to bind/) {
+                last;
+            } elsif ($got =~ /started http server/) {
+                $found_port = 1;
+                last;
+            }
+        }
+    }
+}
+
+if ($port == 65536) {
+    warn "No available ports";
+    cleanup_and_exit(1);
+}
+
+my $server_ready = 0;
+
+# Confirm that the server is ready to be queried
+for (my $i = 0; $i < 10 and $server_ready == 0; $i++) {
+    sleep 1;
+    my $got = `curl -s http://localhost:$port/metrics`;
+    if ($got =~ /ready 1/
+        and $got =~ /thread_work_total\{role=\"traverse\"\} 1/
+        and $got =~ /thread_work_pending\{role=\"scan\"\} 0/
+        and $got =~ /thread_busy\{role=\"scan\"\} 0/) {
+        $server_ready = 1;
+    }
+}
+
+if ($server_ready == 0) {
+    warn "Can't start debuginfod server";
+    cleanup_and_exit(1);
+}
+
+# Query the server and store the debuginfo in the client cache for valgrind to find.
+my $myres = mysystem("DEBUGINFOD_CACHE_PATH=$dir DEBUGINFOD_URLS=http://localhost:$port debuginfod-find debuginfo $buildid > /dev/null 2>&1");
+if ($myres != 0) {
+    cleanup_and_exit(1);
+}
+kill "INT", $pid;
+exit 0;
diff --git a/memcheck/tests/linux/debuginfod-check.stderr.exp b/memcheck/tests/linux/debuginfod-check.stderr.exp
new file mode 100644 (file)
index 0000000..98236be
--- /dev/null
@@ -0,0 +1,6 @@
+Invalid write of size 1
+   at 0x........: main (debuginfod-check.c:5)
+ Address 0x........ is 1 bytes before a block of size 1 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (debuginfod-check.c:4)
+
diff --git a/memcheck/tests/linux/debuginfod-check.vgtest.in b/memcheck/tests/linux/debuginfod-check.vgtest.in
new file mode 100644 (file)
index 0000000..308e16c
--- /dev/null
@@ -0,0 +1,4 @@
+prereq: ./debuginfod-check.pl
+prog: debuginfod-check
+vgopts: -q
+env: DEBUGINFOD_URLS=localhost DEBUGINFOD_CACHE_PATH=@abs_top_builddir@/memcheck/tests/linux/.debuginfod
index c7cc60124b7849a1b94758415e20a641f94fb21c..0fe63411a1c166df51fc4e018b9c790e03e59d8e 100755 (executable)
@@ -699,6 +699,8 @@ sub warn_about_EXTRA_REGTEST_OPTS()
 
 # nuke VALGRIND_OPTS
 $ENV{"VALGRIND_OPTS"} = "";
+# nuke DEBUGINFOD_URLS
+$ENV{"DEBUGINFOD_URLS"} = "";
 
 if ($ENV{"EXTRA_REGTEST_OPTS"}) {
     print "\n";