]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add support for PIC executables (e.g. firefox on Ubuntu 11) by adding
authorJulian Seward <jseward@acm.org>
Sun, 26 Jun 2011 09:26:48 +0000 (09:26 +0000)
committerJulian Seward <jseward@acm.org>
Sun, 26 Jun 2011 09:26:48 +0000 (09:26 +0000)
the "auxv" protocol packet to gdbsrv.  (Philippe Waroquiers,
philippe.waroquiers@skynet.be).  Bug 214909 comment 108.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11836

12 files changed:
coregrind/m_clientstate.c
coregrind/m_gdbserver/server.c
coregrind/m_initimg/initimg-linux.c
coregrind/pub_core_clientstate.h
gdbserver_tests/Makefile.am
gdbserver_tests/main_pic.c [new file with mode: 0644]
gdbserver_tests/mcmain_pic.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcmain_pic.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcmain_pic.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/mcmain_pic.stdout.exp [new file with mode: 0644]
gdbserver_tests/mcmain_pic.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mcmain_pic.vgtest [new file with mode: 0644]

index d6dc7b2a58d8212e4cd73026ba0c0edf169042de..d487540e1559b11090b69137112564f7719f59f8 100644 (file)
@@ -51,6 +51,10 @@ Addr  VG_(clstk_base)  = 0;
 Addr  VG_(clstk_end)   = 0;
 UWord VG_(clstk_id)    = 0;
 
+/* linux only: where is the client auxv ? */
+/* This is set up as part of setup_client_stack in initimg-linux.c. */
+UWord* VG_(client_auxv) = NULL;
+
 Addr  VG_(brk_base)    = 0;       /* start of brk */
 Addr  VG_(brk_limit)   = 0;       /* current brk */
 
index 546fe3b09857b529ad593ecbf39ee72651cade0e..db4d1f75de7870ec0ebdebdbf8e975cec30e8b92 100644 (file)
@@ -26,6 +26,7 @@
 #include "pub_core_options.h"
 #include "pub_core_translate.h"
 #include "pub_core_mallocfree.h"
+#include "pub_core_initimg.h"
 
 unsigned long cont_thread;
 unsigned long general_thread;
@@ -580,6 +581,59 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p)
       }
    }
 
+   if (strncmp ("qXfer:auxv:read:", arg_own_buf, 16) == 0) {
+      unsigned char *data;
+      int n;
+      CORE_ADDR ofs;
+      unsigned int len;
+      char *annex;
+
+      /* Reject any annex; grab the offset and length.  */
+      if (decode_xfer_read (arg_own_buf + 16, &annex, &ofs, &len) < 0
+          || annex[0] != '\0') {
+         strcpy (arg_own_buf, "E00");
+         return;
+      }
+
+      if (len > PBUFSIZ - 2)
+         len = PBUFSIZ - 2;
+      data = malloc (len);
+
+      {
+         UWord *client_auxv = VG_(client_auxv);
+         unsigned int client_auxv_len = 0;
+         while (*client_auxv != 0) {
+            dlog(4, "auxv %lld %llx\n",
+                 (ULong)*client_auxv,
+                 (ULong)*(client_auxv+1));
+            client_auxv++;
+            client_auxv++;
+            client_auxv_len += 2 * sizeof(UWord);
+         }
+         client_auxv_len += 2 * sizeof(UWord);
+         dlog(4, "auxv len %d\n", client_auxv_len);
+
+         if (ofs >= client_auxv_len)
+            n = -1;
+         else {
+            n = client_auxv_len - ofs;
+            VG_(memcpy) (data, (unsigned char *) VG_(client_auxv), n);
+         }
+      }
+
+      if (n < 0)
+         write_enn (arg_own_buf);
+      else if (n > len)
+         *new_packet_len_p = write_qxfer_response (arg_own_buf, data, len, 1);
+      else
+         *new_packet_len_p = write_qxfer_response (arg_own_buf, data, n, 0);
+      
+      free (data);
+      
+      return;
+   }
+
+
    /* Protocol features query.  */
    if (strncmp ("qSupported", arg_own_buf, 10) == 0
        && (arg_own_buf[10] == ':' || arg_own_buf[10] == '\0')) {
@@ -589,6 +643,8 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p)
       
       strcat (arg_own_buf, ";QStartNoAckMode+");
       strcat (arg_own_buf, ";QPassSignals+");
+      if (VG_(client_auxv))
+         strcat (arg_own_buf, ";qXfer:auxv:read+");
 
       if ((*the_target->target_xml)() != NULL
           || (*the_target->shadow_target_xml)() != NULL) {
index 3250343b506968420762f4a07876dc7c30a796bc..66508003f7851d7766032e9cc066a955d22a1e08 100644 (file)
@@ -611,6 +611,11 @@ Addr setup_client_stack( void*  init_sp,
    /* --- auxv --- */
    auxv = (struct auxv *)ptr;
    *client_auxv = (UInt *)auxv;
+   VG_(client_auxv) = (UWord *)*client_auxv;
+   // ??? According to 'man proc', auxv is a array of unsigned long
+   // terminated by two zeros. Why is valgrind working with UInt ?
+   // We do not take ULong* (as ULong 8 bytes on a 32 bits),
+   // => we take UWord*
 
 #  if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
    auxv[0].a_type  = AT_IGNOREPPC;
@@ -658,6 +663,11 @@ Addr setup_client_stack( void*  init_sp,
             break;
 
          case AT_BASE:
+            /* When gdbserver sends the auxv to gdb, the AT_BASE has
+               to be ignored, as otherwise gdb adds this offset
+               to loaded shared libs, causing wrong address
+               relocation e.g. when inserting breaks. */
+            auxv->a_type = AT_IGNORE;
             auxv->u.a_val = info->interp_base;
             break;
 
index 4742330b2b034dc3e5adebed5368eeb6012c5f5d..0766dd901d656c6cd5754044ac93ce85a7d491ad 100644 (file)
@@ -46,6 +46,10 @@ extern Addr  VG_(clstk_base);         // client stack range
 extern Addr  VG_(clstk_end);
 extern UWord VG_(clstk_id);      // client stack id
 
+/* linux only: where is the client auxv ? */
+/* This is setup as part of setup_client_stack in initimg-linux.c. */
+extern UWord* VG_(client_auxv);
+
 extern Addr  VG_(brk_base);     // start of brk
 extern Addr  VG_(brk_limit);    // current brk
 
index 763a37414fc8f8a0c984f04430b65174e5dd476e..91eb02e8d781144051ca1df0c853b52f237e21e1 100644 (file)
@@ -44,6 +44,7 @@ EXTRA_DIST = \
        mcleak.stdinB.gdb \
        mcleak.stdoutB.exp \
        mcleak.vgtest \
+       mcmain_pic.vgtest \
        mcsignopass.stderrB.exp \
        mcsignopass.stderr.exp \
        mcsignopass.stdinB.gdb \
@@ -82,6 +83,7 @@ check_PROGRAMS = \
        clean_after_fork \
        fork_chain \
        sleepers \
+       main_pic \
        t \
        watchpoints
 
@@ -89,3 +91,6 @@ AM_CFLAGS   += $(AM_FLAG_M3264_PRI)
 AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
 
 LDADD = -lpthread
+
+main_pic_LDFLAGS = -pie
+main_pic_CFLAGS         = $(AM_CFLAGS) -fPIC
diff --git a/gdbserver_tests/main_pic.c b/gdbserver_tests/main_pic.c
new file mode 100644 (file)
index 0000000..e452b30
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+static void another_func(char *msg)
+{
+   printf ("another func called msg %s\n", msg);
+}
+
+int main (int argc, char *argv[])
+{
+   printf("address of main %p\n", &main);
+   printf("address of another_func %p\n", &another_func);
+   another_func("called from main");
+   return 0;
+}
diff --git a/gdbserver_tests/mcmain_pic.stderr.exp b/gdbserver_tests/mcmain_pic.stderr.exp
new file mode 100644 (file)
index 0000000..7f8de97
--- /dev/null
@@ -0,0 +1,13 @@
+
+(action at startup) vgdb me ... 
+
+
+
+HEAP SUMMARY:
+    in use at exit: 16 bytes in 1 blocks
+  total heap usage: 1 allocs, 0 frees, 16 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/gdbserver_tests/mcmain_pic.stderrB.exp b/gdbserver_tests/mcmain_pic.stderrB.exp
new file mode 100644 (file)
index 0000000..ed5d420
--- /dev/null
@@ -0,0 +1,3 @@
+relaying data between gdb and process ....
+vgdb-error value changed from 0 to 999999
+Remote connection closed
diff --git a/gdbserver_tests/mcmain_pic.stdinB.gdb b/gdbserver_tests/mcmain_pic.stdinB.gdb
new file mode 100644 (file)
index 0000000..aa658db
--- /dev/null
@@ -0,0 +1,16 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcmain_pic
+echo vgdb launched process attached\n
+monitor vg.set vgdb-error 999999
+#
+# break
+break main
+#
+continue
+# first break encountered.
+print another_func("called from gdb")
+#
+print &main
+print &another_func
+continue
+quit
diff --git a/gdbserver_tests/mcmain_pic.stdout.exp b/gdbserver_tests/mcmain_pic.stdout.exp
new file mode 100644 (file)
index 0000000..b207484
--- /dev/null
@@ -0,0 +1,4 @@
+another func called msg called from gdb
+address of main 0x........
+address of another_func 0x........
+another func called msg called from main
diff --git a/gdbserver_tests/mcmain_pic.stdoutB.exp b/gdbserver_tests/mcmain_pic.stdoutB.exp
new file mode 100644 (file)
index 0000000..4bb0a69
--- /dev/null
@@ -0,0 +1,8 @@
+Breakpoint 1 at 0x........: file main_pic.c, line 10.
+Continuing.
+Breakpoint 1, main (argc=1, argv=0x........) at main_pic.c:10
+10        printf("address of main %p\n", &main);
+$1 = void
+$2 = (int (*)(int, char **)) 0x........ <main>
+$3 = (void (*)(char *)) 0x........ <another_func>
+Continuing.
diff --git a/gdbserver_tests/mcmain_pic.vgtest b/gdbserver_tests/mcmain_pic.vgtest
new file mode 100644 (file)
index 0000000..80ea610
--- /dev/null
@@ -0,0 +1,16 @@
+# test that gdbserver/gdb properly handle a PIC executable
+# On linux, this implies a proper transfer of the auxv
+# information via the gdbserver protocol packet qXfer:auxv:read:
+# The content of the auxv data can be shown by gdb using
+# gdb command 'info auxv'
+prereq: test -e gdb
+prog: main_pic
+vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcmain_pic
+stdout_filter: filter_gdb
+stderr_filter: filter_memcheck_monitor
+progB: gdb
+argsB: --quiet -l 60 --nx ./main_pic
+stdinB: mcmain_pic.stdinB.gdb
+stdoutB_filter: filter_gdb
+stderrB_filter: filter_memcheck_monitor
+