|
From: <sv...@va...> - 2011-05-17 16:35:19
|
Author: sewardj
Date: 2011-05-17 17:35:11 +0100 (Tue, 17 May 2011)
New Revision: 11768
Log:
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, phi...@sk...)
Modified:
trunk/coregrind/m_gdbserver/server.c
trunk/coregrind/m_gdbserver/server.h
trunk/coregrind/m_gdbserver/valgrind-low-arm.c
Modified: trunk/coregrind/m_gdbserver/server.c
===================================================================
--- trunk/coregrind/m_gdbserver/server.c 2011-05-17 16:29:29 UTC (rev 11767)
+++ trunk/coregrind/m_gdbserver/server.c 2011-05-17 16:35:11 UTC (rev 11768)
@@ -294,6 +294,12 @@
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,
Modified: trunk/coregrind/m_gdbserver/server.h
===================================================================
--- trunk/coregrind/m_gdbserver/server.h 2011-05-17 16:29:29 UTC (rev 11767)
+++ trunk/coregrind/m_gdbserver/server.h 2011-05-17 16:35:11 UTC (rev 11768)
@@ -94,7 +94,19 @@
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);
Modified: trunk/coregrind/m_gdbserver/valgrind-low-arm.c
===================================================================
--- trunk/coregrind/m_gdbserver/valgrind-low-arm.c 2011-05-17 16:29:29 UTC (rev 11767)
+++ trunk/coregrind/m_gdbserver/valgrind-low-arm.c 2011-05-17 16:35:11 UTC (rev 11768)
@@ -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 @@
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 @@
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:
|