]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
gdbserver: Fixes for ARM-Thumb (#214909 c 76)
authorJulian Seward <jseward@acm.org>
Tue, 17 May 2011 16:35:11 +0000 (16:35 +0000)
committerJulian Seward <jseward@acm.org>
Tue, 17 May 2011 16:35:11 +0000 (16:35 +0000)
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

coregrind/m_gdbserver/server.c
coregrind/m_gdbserver/server.h
coregrind/m_gdbserver/valgrind-low-arm.c

index 2d3ce907f9bc145144ab7fdd2b7f837ab559ee0b..069d1dcfbb669ea8b9f071815b83f19c2631967c 100644 (file)
@@ -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, 
index 2b6ae0e0b6dbe08f7ff4a0a4a44c12e8b475be5f..be2b548f3bbb14e0b7d9f885457791c022566da4 100644 (file)
@@ -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);
 
index d4cec3c5aba424ade5db196866bc417189b1d4d2..5767793e9678488b9661d693a75f34c8a9a9d273 100644 (file)
@@ -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: