Fixing statetrace to work with 32 bit SPARC processes, as well as rewritting it's...
authorGabe Black <gblack@eecs.umich.edu>
Tue, 6 Mar 2007 01:54:20 +0000 (20:54 -0500)
committerGabe Black <gblack@eecs.umich.edu>
Tue, 6 Mar 2007 01:54:20 +0000 (20:54 -0500)
--HG--
extra : convert_revision : 69b1668a850519ab98b02c525ec41ff727eb6036

util/statetrace/arch/tracechild_sparc.cc
util/statetrace/arch/tracechild_sparc.hh
util/statetrace/statetrace.cc
util/statetrace/tracechild.cc
util/statetrace/tracechild.hh

index bad81b647b493424fcfe47fff57a01b184bb886d..2f42330e4ba6ae0d0f0980a16b1c49661d37d9aa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2006-2007 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -151,7 +151,6 @@ int64_t getRegs(regs & myregs, fpu & myfpu,
 
 bool SparcTraceChild::update(int pid)
 {
-    static const int stackBias = 2047;
     memcpy(&oldregs, &theregs, sizeof(regs));
     memcpy(&oldfpregs, &thefpregs, sizeof(fpu));
     memcpy(oldLocals, locals, 8 * sizeof(uint64_t));
@@ -161,7 +160,8 @@ bool SparcTraceChild::update(int pid)
         cerr << "Update failed" << endl;
         return false;
     }
-    uint64_t StackPointer = getRegVal(O6);
+    uint64_t StackPointer = getSP();
+    const int stackBias = (StackPointer % 1) ? 2047 : 0;
     for(unsigned int x = 0; x < 8; x++)
     {
         locals[x] = ptrace(PTRACE_PEEKTEXT, pid,
@@ -182,8 +182,76 @@ SparcTraceChild::SparcTraceChild()
         regDiffSinceUpdate[x] = false;
 }
 
+int SparcTraceChild::getTargets(uint32_t inst, uint64_t pc, uint64_t npc,
+        uint64_t &target1, uint64_t &target2)
+{
+    //We can identify the instruction categories we care about using the top
+    //10 bits of the instruction, excluding the annul bit in the 3rd most
+    //significant bit position and the condition field. We'll call these
+    //bits the "sig" for signature.
+    uint32_t sig = (inst >> 22) & 0x307;
+    uint32_t cond = (inst >> 25) & 0xf;
+    bool annul = (inst & (1 << 29));
+
+    //Check if it's a ba...
+    bool ba = (cond == 0x8) &&
+        (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
+    //or a bn...
+    bool bn = (cond == 0x0) &&
+        (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
+    //or a bcc
+    bool bcc = (cond & 0x7) &&
+        (sig == 0x1 || sig == 0x2 || sig == 0x3 || sig == 0x5 || sig == 0x6);
+
+    if(annul)
+    {
+        if(bcc)
+        {
+            target1 = npc;
+            target2 = npc + 4;
+            return 2;
+        }
+        else if(ba)
+        {
+            //This branches immediately to the effective address of the branch
+            //which we'll have to calculate.
+            uint64_t disp = 0;
+            int64_t extender = 0;
+            //Figure out how big the displacement field is, and grab the bits
+            if(sig == 0x1 || sig == 0x5)
+            {
+                disp = inst & ((1 << 19) - 1);
+                extender = 1 << 18;
+            }
+            else
+            {
+                disp = inst & ((1 << 22) - 1);
+                extender = 1 << 21;
+            }
+            //This does sign extension, believe it or not.
+            disp = (disp ^ extender) - extender;
+            //Multiply the displacement by 4. I'm assuming the compiler is
+            //smart enough to turn this into a shift.
+            disp *= 4;
+            target1 = pc + disp;
+        }
+        else if(bn)
+            target1 = npc + 4;
+        else
+            target1 = npc;
+        return 1;
+    }
+    else
+    {
+        target1 = npc;
+        return 1;
+    }
+}
+
 bool SparcTraceChild::step()
 {
+    //Increment the count of the number of instructions executed
+    instructions++;
     //Two important considerations are that the address of the instruction
     //being breakpointed should be word (64bit) aligned, and that both the
     //next instruction and the instruction after that need to be breakpointed
@@ -193,6 +261,8 @@ bool SparcTraceChild::step()
      * Useful constants
      */
     const static uint64_t breakInst = 0x91d02001;
+    const static uint64_t lowBreakInst = breakInst;
+    const static uint64_t highBreakInst = breakInst << 32;
     const static uint64_t breakWord = breakInst | (breakInst << 32);
     const static uint64_t lowMask = 0xFFFFFFFFULL;
     const static uint64_t highMask = lowMask << 32;
@@ -212,60 +282,39 @@ bool SparcTraceChild::step()
     bool unalignedNPC = nextPC & 7;
     uint64_t alignedNPC = nextPC & (~7);
 
-    /*
-     * Store the original contents of the child process's memory
-     */
-    originalInst = ptrace(PTRACE_PEEKTEXT, pid, alignedNPC, 0);
-    //Save a ptrace call if we can
-    if(unalignedNPC)
-    {
-        originalAnnulInst = ptrace(PTRACE_PEEKTEXT, pid, alignedNPC+8, 0);
-    }
+    //Get the current instruction
+    uint64_t curInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC);
+    curInst = unalignedPC ? (curInst & 0xffffffffULL) : (curInst >> 32);
 
-    /*
-     * Prepare breakpointed copies of child processes memory
-     */
-    uint64_t newInst, newAnnulInst;
-    //If the current instruction is in the same word as the npc
-    if(alignedPC == alignedNPC)
-    {
-        //Make sure we only replace the other part
-        if(unalignedPC)
-            newInst = (originalInst & lowMask) | (breakWord & highMask);
-        else
-            newInst = (originalInst & highMask) | (breakWord & lowMask);
-    }
-    else
-    {
-        //otherwise replace the whole thing
-        newInst = breakWord;
-    }
-    //If the current instruction is in the same word as the word after
-    //the npc
-    if(alignedPC == alignedNPC+8)
-    {
-        //Make sure we only replace the other part
-        if(unalignedPC)
-            newAnnulInst = (originalAnnulInst & lowMask) | (breakWord & highMask);
-        else
-            newAnnulInst = (originalAnnulInst & highMask) | (breakWord & lowMask);
-    }
-    else
-    {
-        //otherwise replace the whole thing
-        newAnnulInst = breakWord;
-    }
+    uint64_t bp1, bp2;
+    int numTargets = getTargets(curInst, currentPC, nextPC, bp1, bp2);
+    assert(numTargets == 1 || numTargets == 2);
+
+    bool unalignedBp1 = bp1 & 7;
+    uint64_t alignedBp1 = bp1 & (~7);
+    bool unalignedBp2 = bp2 & 7;
+    uint64_t alignedBp2 = bp2 & (~7);
+    uint64_t origBp1, origBp2;
 
     /*
-     * Stuff the breakpoint instructions into the child's address space.
+     * Set the first breakpoint
      */
-    //Replace the word at npc
-    if(ptrace(PTRACE_POKETEXT, pid, alignedNPC, newInst) != 0)
+    origBp1 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp1, 0);
+    uint64_t newBp1 = origBp1;
+    newBp1 &= unalignedBp1 ? highMask : lowMask;
+    newBp1 |= unalignedBp1 ? lowBreakInst : highBreakInst;
+    if(ptrace(PTRACE_POKETEXT, pid, alignedBp1, newBp1) != 0)
         cerr << "Poke failed" << endl;
-    //Replace the next word, if necessary
-    if(unalignedNPC)
+    /*
+     * Set the second breakpoint if necessary
+     */
+    if(numTargets == 2)
     {
-        if(ptrace(PTRACE_POKETEXT, pid, alignedNPC+8, newAnnulInst) != 0)
+        origBp2 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp2, 0);
+        uint64_t newBp2 = origBp2;
+        newBp2 &= unalignedBp2 ? highMask : lowMask;
+        newBp2 |= unalignedBp2 ? lowBreakInst : highBreakInst;
+        if(ptrace(PTRACE_POKETEXT, pid, alignedBp2, newBp2) != 0)
             cerr << "Poke failed" << endl;
     }
 
@@ -285,16 +334,16 @@ bool SparcTraceChild::step()
     update(pid);
 
     /*
-     * Put back the original contents of the childs address space
+     * Put back the original contents of the childs address space in the
+     * reverse order.
      */
-    if(ptrace(PTRACE_POKETEXT, pid, alignedNPC, originalInst) != 0)
-        cerr << "Repoke failed" << endl;
-    if(unalignedNPC)
+    if(numTargets == 2)
     {
-        if(ptrace(PTRACE_POKETEXT, pid, alignedNPC+8, originalAnnulInst) != 0)
-            cerr << "Repoke failed" << endl;
+        if(ptrace(PTRACE_POKETEXT, pid, alignedBp2, origBp2) != 0)
+            cerr << "Poke failed" << endl;
     }
-    return true;
+    if(ptrace(PTRACE_POKETEXT, pid, alignedBp1, origBp1) != 0)
+        cerr << "Poke failed" << endl;
 }
 
 int64_t SparcTraceChild::getRegVal(int num)
@@ -315,39 +364,56 @@ char * SparcTraceChild::printReg(int num)
 
 ostream & SparcTraceChild::outputStartState(ostream & os)
 {
+    bool v8 = false;
     uint64_t sp = getSP();
+    if(sp % 1)
+    {
+        os << "Detected a 64 bit executable.\n";
+        v8 = false;
+    }
+    else
+    {
+        os << "Detected a 32 bit executable.\n";
+        v8 = true;
+    }
     uint64_t pc = getPC();
     char obuf[1024];
     sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp);
     os << obuf;
     sprintf(obuf, "Initial program counter = 0x%016llx\n", pc);
     os << obuf;
-    //Take out the stack bias
-    sp += 2047;
+    if(!v8)
+    {
+        //Take out the stack bias
+        sp += 2047;
+    }
     //Output the window save area
     for(unsigned int x = 0; x < 16; x++)
     {
         uint64_t regspot = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
+        if(v8) regspot = regspot >> 32;
         sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n",
                 sp, x+1, regspot);
         os << obuf;
-        sp += 8;
+        sp += v8 ? 4 : 8;
     }
     //Output the argument count
     uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
+    if(v8) cargc = cargc >> 32;
     sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc);
     os << obuf;
-    sp += 8;
+    sp += v8 ? 4 : 8;
     //Output argv pointers
     int argCount = 0;
     uint64_t cargv;
     do
     {
         cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
+        if(v8) cargv = cargv >> 32;
         sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n",
                 sp, argCount++, cargv);
         os << obuf;
-        sp += 8;
+        sp += v8 ? 4 : 8;
     } while(cargv);
     //Output the envp pointers
     int envCount = 0;
@@ -355,20 +421,23 @@ ostream & SparcTraceChild::outputStartState(ostream & os)
     do
     {
         cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
+        if(v8) cenvp = cenvp >> 32;
         sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n",
                 sp, envCount++, cenvp);
         os << obuf;
-        sp += 8;
+        sp += v8 ? 4 : 8;
     } while(cenvp);
     uint64_t auxType, auxVal;
     do
     {
         auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
-        sp += 8;
+        if(v8) auxType = auxType >> 32;
+        sp += (v8 ? 4 : 8);
         auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
-        sp += 8;
+        if(v8) auxVal = auxVal >> 32;
+        sp += (v8 ? 4 : 8);
         sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
-                sp - 16, auxType, auxVal);
+                sp - 8, auxType, auxVal);
         os << obuf;
     } while(auxType != 0 || auxVal != 0);
     //Print out the argument strings, environment strings, and file name.
@@ -380,7 +449,7 @@ ostream & SparcTraceChild::outputStartState(ostream & os)
     {
         buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
         char * cbuf = (char *)&buf;
-        for(int x = 0; x < sizeof(uint64_t); x++)
+        for(int x = 0; x < sizeof(uint32_t); x++)
         {
             if(cbuf[x])
                 current += cbuf[x];
@@ -393,7 +462,7 @@ ostream & SparcTraceChild::outputStartState(ostream & os)
                 currentStart = sp + x + 1;
             }
         }
-        sp += 8;
+        sp += (v8 ? 4 : 8);
         clearedInitialPadding = clearedInitialPadding || buf != 0;
     } while(!clearedInitialPadding || buf != 0);
     return os;
index 80770211a88a1ee23b303f278ec469c628c9bb21..8b4ff9aaed5c1a6e9459a59831e300edce3173ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2006-2007 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -78,6 +78,12 @@ private:
         int64_t oldInputs[8];
         bool regDiffSinceUpdate[numregs];
 
+        //This calculates where the pc might go after the current instruction.
+        //while this equals npc for most instructions, it doesn't for all of
+        //them. The return value is the number of actual potential targets.
+        int getTargets(uint32_t inst, uint64_t pc, uint64_t npc,
+                uint64_t &target1, uint64_t &target2);
+
 protected:
         bool update(int pid);
 
index 78fdf9393da5e2911c52204ea57404115ec7a645..e5baee3955e62738b0074e3572e871e021c21aa8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2006-2007 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -145,9 +145,13 @@ int main(int argc, char * argv[], char * envp[])
                         return 1;
                 }
         }
-        for(unsigned int x = startProgramArgs; x < argc; x++)
-            args += argv[x];
-        if(!child->startTracing(argv[startProgramArgs], args.c_str()))
+        /*for(unsigned int x = startProgramArgs; x < argc; x++)
+        {
+            cout << "Adding argument " << argv[x];
+            args += string(" ") + argv[x];
+        }*/
+        if(!child->startTracing(argv[startProgramArgs],
+                    argv + startProgramArgs))
         {
                 cerr << "Couldn't start target program" << endl;
                 return 1;
index 292c45658aa924dfdc572f28a9758429bded1286..130f9690fc356176fb63e85c33f9962b3468843d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2006-2007 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,8 +36,9 @@
 
 using namespace std;
 
-bool TraceChild::startTracing(const char * pathToFile, const char * arg)
+bool TraceChild::startTracing(const char * pathToFile, char * const argv[])
 {
+        instructions = 0;
         pid = fork();
         if(pid == -1)
         {
@@ -53,7 +54,7 @@ bool TraceChild::startTracing(const char * pathToFile, const char * arg)
                 ptrace(PTRACE_TRACEME, 0, 0, 0);
 
                 //Start the program to trace
-                execl(pathToFile, arg);
+                execv(pathToFile, argv);
 
                 //We should never get here, so this is an error!
                 return false;
@@ -121,6 +122,8 @@ bool TraceChild::doWait()
         {
                 cerr << "Program exited! Exit status is "
                         << WEXITSTATUS(wait_val) << endl;
+                cerr << "Executed " << instructions
+                        << " instructions." << endl;
                 tracing = false;
                 return false;
         }
@@ -132,6 +135,8 @@ bool TraceChild::doWait()
                 if(WCOREDUMP(wait_val))
                         cerr << "Program core dumped!" << endl;
                 tracing = false;
+                cerr << "Executed " << instructions
+                        << " instructions." << endl;
                 return false;
         }
         if(WIFSTOPPED(wait_val) && WSTOPSIG(wait_val) != SIGTRAP)
@@ -139,6 +144,8 @@ bool TraceChild::doWait()
                 cerr << "Program stopped by signal "
                         << WSTOPSIG(wait_val) << endl;
                 tracing = false;
+                cerr << "Executed " << instructions
+                        << " instructions." << endl;
                 return false;
         }
         return true;
index f9c23b781e42a32cb1005f1748e2a0b68ca8941e..84fa595d854292eac845c2a620673ebddd312ec7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2006-2007 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,11 +37,13 @@ class TraceChild : public RegState
 {
 protected:
         int pid;
+        uint64_t instructions;
         bool tracing;
 public:
-        TraceChild() : tracing(false)
+        TraceChild() : tracing(false), instructions(0)
         {;}
-        virtual bool startTracing(const char * pathToFile, const char * arg);
+        virtual bool startTracing(const char * pathToFile,
+                char * const argv[]);
         virtual bool stopTracing();
         virtual bool step();
         virtual uint64_t getPC() = 0;