ARM: Make sure the target process doesn't run away from statetrace.
authorGabe Black <gblack@eecs.umich.edu>
Wed, 29 Jul 2009 07:14:43 +0000 (00:14 -0700)
committerGabe Black <gblack@eecs.umich.edu>
Wed, 29 Jul 2009 07:14:43 +0000 (00:14 -0700)
src/arch/arm/nativetrace.cc
util/statetrace/arch/tracechild_arm.cc

index 7c9c70e0ce449cb3fbed0c60d6f1633a9d02af36..90c5e5c255e60a75f94ead892c8b0320912960f0 100644 (file)
@@ -104,8 +104,13 @@ Trace::ArmNativeTrace::ThreadState::update(ThreadContext *tc)
 void
 Trace::ArmNativeTrace::check(NativeTraceRecord *record)
 {
+    ThreadContext *tc = record->getThread();
+    // This area is read only on the target. It can't stop there to tell us
+    // what's going on, so we should skip over anything there also.
+    if (tc->readNextPC() > 0xffff0000)
+        return;
     nState.update(this);
-    mState.update(record->getThread());
+    mState.update(tc);
 
     bool errorFound = false;
     // Regular int regs
index 4687b46f08ece47de63d687a83a28f6ab4b60572..b52c0694a94c0ae5d18d460712c7295a24c6bc47 100644 (file)
@@ -203,22 +203,28 @@ ostream & ARMTraceChild::outputStartState(ostream & os)
 
 bool ARMTraceChild::step()
 {
+    const uint32_t bkpt_inst = 0xe7f001f0;
 
-    const uint32_t bkpt_inst = 0xE1200070;
-    const uint32_t bkpt_mask = 0xFFF000F0;
-
-    const uint32_t swi_inst = 0x0F0000000;
-    const uint32_t swi_mask = 0x0F0000000;
-
-    uint32_t next_op = ptrace(PTRACE_PEEKDATA, pid, getPC(), 0);
-    if ((next_op & swi_mask) == swi_inst) {
-        ptrace(PTRACE_POKEDATA, pid, next_op + sizeof(uint32_t), bkpt_inst);
-        ptraceSingleStep();
-        ptrace(PTRACE_POKEDATA, pid, next_op + sizeof(uint32_t), next_op);
-    } 
-    else
-    {
-        ptraceSingleStep();
+    uint32_t lr = getRegVal(14);
+    uint32_t pc = getPC();
+    uint32_t lrOp;
+
+    // Since ARM uses software breakpoints behind the scenes, they don't work
+    // in read only areas like the page of routines provided by the kernel. The
+    // link register generally holds the address the process wants to the
+    // kernel to return to after it's done, so we'll install a software
+    // breakpoint there. If the lr happens to point to the next instruction
+    // we'll leave out our breakpoint to avoid an infinite loop. This isn't a
+    // fool proof strategy, but it should work well in all the reasonable
+    // scenarios I can think of right now.
+
+    if (pc != lr) {
+        lrOp = ptrace(PTRACE_PEEKDATA, pid, lr, 0);
+        ptrace(PTRACE_POKEDATA, pid, lr, bkpt_inst);
+    }
+    ptraceSingleStep();
+    if (pc != lr) {
+        ptrace(PTRACE_POKEDATA, pid, lr, lrOp);
     }
 }