From: Julian Seward Date: Tue, 17 May 2011 16:35:11 +0000 (+0000) Subject: gdbserver: Fixes for ARM-Thumb (#214909 c 76) X-Git-Tag: svn/VALGRIND_3_7_0~469 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4c205c2b435f3704f2bfd3249f8329c9b8b6f52d;p=thirdparty%2Fvalgrind.git gdbserver: Fixes for ARM-Thumb (#214909 c 76) fix arm thumb by transforming an address to its thumb form when needed * added a function thumb_pc transforming a pc to its thumb form if needed (using an heuristic to guess if this is a thumb address) * when program counter is modified by gdb, use thumb_pc * use thumb_pc in monitor command vg.translate (I was able to check that this improves inferior call on a small thumb compiled executable + mcinfcallRU test) but I could not compile all tests with thumb). (Philippe Waroquiers, philippe.waroquiers@skynet.be) git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11768 --- diff --git a/coregrind/m_gdbserver/server.c b/coregrind/m_gdbserver/server.c index 2d3ce907f9..069d1dcfbb 100644 --- a/coregrind/m_gdbserver/server.c +++ b/coregrind/m_gdbserver/server.c @@ -294,6 +294,12 @@ int handle_gdb_valgrind_command (char* mon, OutputSink* sink_wanted_at_return) valgrind_set_single_stepping(True); // to force gdbserver instrumentation. } +# if defined(VGA_arm) + // on arm, we need to (potentially) convert this address + // to the thumb form. + address = thumb_pc (address); +# endif + VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/, address, /*debugging*/True, diff --git a/coregrind/m_gdbserver/server.h b/coregrind/m_gdbserver/server.h index 2b6ae0e0b6..be2b548f3b 100644 --- a/coregrind/m_gdbserver/server.h +++ b/coregrind/m_gdbserver/server.h @@ -94,7 +94,19 @@ extern void remote_finish(FinishReason reason); and does VG_(umsg). If info != NULL, info added in VG_(usmg). */ extern void reset_valgrind_sink(char* info); +/* For ARM usage. + Guesses if pc is a thumb pc. + In this case, returns pc with the thumb bit set (bit0) + else just returns pc. + + The guess is based on the following set of check: + if bit0 set => thumb + else if bit1 set => thumb + else uses the debuginfo to guess. + If debug info not found for this pc, assumes arm */ +extern Addr thumb_pc (Addr pc); + /* True if gdbserver is single stepping the valgrind process */ extern Bool valgrind_single_stepping(void); diff --git a/coregrind/m_gdbserver/valgrind-low-arm.c b/coregrind/m_gdbserver/valgrind-low-arm.c index d4cec3c5ab..5767793e96 100644 --- a/coregrind/m_gdbserver/valgrind-low-arm.c +++ b/coregrind/m_gdbserver/valgrind-low-arm.c @@ -31,6 +31,7 @@ #include "pub_core_threadstate.h" #include "pub_core_transtab.h" #include "pub_core_gdbserver.h" +#include "pub_core_debuginfo.h" #include "valgrind_low.h" @@ -122,6 +123,57 @@ void set_pc (CORE_ADDR newpc) dlog(1, "set pc not changed %p\n", C2v (newpc)); } +Addr thumb_pc (Addr pc) +{ + // If the thumb bit (bit 0) is already set, we trust it. + if (pc & 1) { + dlog (1, "%p = thumb (bit0 is set)\n", C2v (pc)); + return pc; + } + + // Here, bit 0 is not set. + // For a pc aligned on 4 bytes, we have to use the debug + // info to determine the thumb-ness. + // else (aligned on 2 bytes), we trust this is a thumb + // address and we set the thumb bit. + + if (pc & 2) { + dlog (1, "bit0 not set, bit1 set => %p = thumb\n", C2v (pc)); + return pc | 1; + } + + // pc aligned on 4 bytes. We need to use debug info. + { + Char fnname[200]; // ??? max size + Addr entrypoint; + Addr ptoc; // unused but needed. + // If this is a thumb instruction, we need to ask + // the debug info with the bit0 set + // (why can't debug info do that for us ???) + // (why if this is a 4 bytes thumb instruction ???) + if (VG_(get_fnname_raw) (pc | 1, fnname, 200)) { + if (VG_(lookup_symbol_SLOW)( "*", fnname, &entrypoint, &ptoc )) { + dlog (1, "fnname %s lookupsym %p => %p %s.\n", + fnname, C2v(entrypoint), C2v(pc), + (entrypoint & 1 ? "thumb" : "arm")); + if (entrypoint & 1) + return pc | 1; + else + return pc; + + } else { + dlog (1, "%p fnname %s lookupsym failed?. Assume arm\n", + C2v (pc), fnname); + return pc; + } + } else { + // Can't find function name. We assume this is arm + dlog (1, "%p unknown fnname?. Assume arm\n", C2v (pc)); + return pc; + } + } +} + /* store registers in the guest state (gdbserver_to_valgrind) or fetch register from the guest state (valgrind_to_gdbserver). */ static @@ -153,7 +205,15 @@ void transfer_register (ThreadId tid, int abs_regno, void * buf, case 12: VG_(transfer) (&arm->guest_R12, buf, dir, size, mod); break; case 13: VG_(transfer) (&arm->guest_R13, buf, dir, size, mod); break; case 14: VG_(transfer) (&arm->guest_R14, buf, dir, size, mod); break; - case 15: VG_(transfer) (&arm->guest_R15T, buf, dir, size, mod); break; + case 15: { + VG_(transfer) (&arm->guest_R15T, buf, dir, size, mod); + if (dir == gdbserver_to_valgrind && *mod) { + // If gdb is changing the PC, we have to set the thumb bit + // if needed. + arm->guest_R15T = thumb_pc(arm->guest_R15T); + } + break; + } case 16: case 17: case 18: