From: Julian Seward Date: Sun, 26 Jun 2011 09:26:48 +0000 (+0000) Subject: Add support for PIC executables (e.g. firefox on Ubuntu 11) by adding X-Git-Tag: svn/VALGRIND_3_7_0~401 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7be9d63ed04c4197f678c3e3be40aa89e81f01af;p=thirdparty%2Fvalgrind.git Add support for PIC executables (e.g. firefox on Ubuntu 11) by adding 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 --- diff --git a/coregrind/m_clientstate.c b/coregrind/m_clientstate.c index d6dc7b2a58..d487540e15 100644 --- a/coregrind/m_clientstate.c +++ b/coregrind/m_clientstate.c @@ -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 */ diff --git a/coregrind/m_gdbserver/server.c b/coregrind/m_gdbserver/server.c index 546fe3b098..db4d1f75de 100644 --- a/coregrind/m_gdbserver/server.c +++ b/coregrind/m_gdbserver/server.c @@ -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) { diff --git a/coregrind/m_initimg/initimg-linux.c b/coregrind/m_initimg/initimg-linux.c index 3250343b50..66508003f7 100644 --- a/coregrind/m_initimg/initimg-linux.c +++ b/coregrind/m_initimg/initimg-linux.c @@ -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; diff --git a/coregrind/pub_core_clientstate.h b/coregrind/pub_core_clientstate.h index 4742330b2b..0766dd901d 100644 --- a/coregrind/pub_core_clientstate.h +++ b/coregrind/pub_core_clientstate.h @@ -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 diff --git a/gdbserver_tests/Makefile.am b/gdbserver_tests/Makefile.am index 763a37414f..91eb02e8d7 100644 --- a/gdbserver_tests/Makefile.am +++ b/gdbserver_tests/Makefile.am @@ -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 index 0000000000..e452b30757 --- /dev/null +++ b/gdbserver_tests/main_pic.c @@ -0,0 +1,14 @@ +#include + +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 index 0000000000..7f8de97521 --- /dev/null +++ b/gdbserver_tests/mcmain_pic.stderr.exp @@ -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 index 0000000000..ed5d4208ec --- /dev/null +++ b/gdbserver_tests/mcmain_pic.stderrB.exp @@ -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 index 0000000000..aa658db5bc --- /dev/null +++ b/gdbserver_tests/mcmain_pic.stdinB.gdb @@ -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 index 0000000000..b20748433e --- /dev/null +++ b/gdbserver_tests/mcmain_pic.stdout.exp @@ -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 index 0000000000..4bb0a69266 --- /dev/null +++ b/gdbserver_tests/mcmain_pic.stdoutB.exp @@ -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........
+$3 = (void (*)(char *)) 0x........ +Continuing. diff --git a/gdbserver_tests/mcmain_pic.vgtest b/gdbserver_tests/mcmain_pic.vgtest new file mode 100644 index 0000000000..80ea6109f0 --- /dev/null +++ b/gdbserver_tests/mcmain_pic.vgtest @@ -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 +