tracechild.cc revision 6417
1/* 2 * Copyright (c) 2006-2009 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Ali Saidi 29 * Gabe Black 30 */ 31 32#include <iostream> 33#include <errno.h> 34#include <stdint.h> 35#include <cstring> 36 37#include "tracechild_arm.hh" 38 39using namespace std; 40 41const char* ARMTraceChild::regNames[numregs] = { 42 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 43 "r8", "r9", "r10", "fp", "r12", "sp", "lr", "pc", 44 "cpsr" }; 45 46 47ARMTraceChild::ARMTraceChild() 48{ 49 for (int x = 0; x < numregs; x++) { 50 memset(®s, 0, sizeof(regs)); 51 memset(&oldregs, 0, sizeof(regs)); 52 regDiffSinceUpdate[x] = false; 53 } 54} 55 56bool ARMTraceChild::sendState(int socket) 57{ 58 uint32_t regVal = 0; 59 uint32_t message[numregs + 1]; 60 int pos = 1; 61 message[0] = 0; 62 for (int x = 0; x < numregs; x++) { 63 if (regDiffSinceUpdate[x]) { 64 message[0] = message[0] | (1 << x); 65 message[pos++] = getRegVal(x); 66 } 67 } 68 69 size_t sent = 0; 70 size_t toSend = pos * sizeof(message[0]); 71 uint8_t *messagePtr = (uint8_t *)message; 72 while (toSend != 0) { 73 sent = write(socket, messagePtr, toSend); 74 if (sent == -1) { 75 cerr << "Write failed! " << strerror(errno) << endl; 76 tracing = false; 77 return false; 78 } 79 toSend -= sent; 80 messagePtr += sent; 81 } 82 83 return true; 84} 85 86uint32_t ARMTraceChild::getRegs(user_regs &myregs, int num) 87{ 88 assert(num < numregs && num >= 0); 89 return myregs.uregs[num]; 90} 91 92bool ARMTraceChild::update(int pid) 93{ 94 oldregs = regs; 95 if(ptrace(PTRACE_GETREGS, pid, 0, ®s) != 0) 96 { 97 cerr << "update: " << strerror(errno) << endl; 98 return false; 99 } 100 101 for(unsigned int x = 0; x < numregs; x++) 102 regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); 103 return true; 104} 105 106int64_t ARMTraceChild::getRegVal(int num) 107{ 108 return getRegs(regs, num); 109} 110 111int64_t ARMTraceChild::getOldRegVal(int num) 112{ 113 return getRegs(oldregs, num); 114} 115 116char * ARMTraceChild::printReg(int num) 117{ 118 sprintf(printBuffer, "0x%08X", (uint32_t)getRegVal(num)); 119 return printBuffer; 120} 121 122ostream & ARMTraceChild::outputStartState(ostream & os) 123{ 124 uint32_t sp = getSP(); 125 uint32_t pc = getPC(); 126 uint32_t highestInfo = 0; 127 char obuf[1024]; 128 sprintf(obuf, "Initial stack pointer = 0x%08x\n", sp); 129 os << obuf; 130 sprintf(obuf, "Initial program counter = 0x%08x\n", pc); 131 os << obuf; 132 133 //Output the argument count 134 int32_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 135 sprintf(obuf, "0x%08x: Argc = 0x%08x\n", sp, cargc); 136 os << obuf; 137 sp += 4; 138 139 //Output argv pointers 140 int argCount = 0; 141 int32_t cargv; 142 do 143 { 144 cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 145 sprintf(obuf, "0x%08x: argv[%d] = 0x%08x\n", 146 sp, argCount++, cargv); 147 if(cargv) 148 if(highestInfo < cargv) 149 highestInfo = cargv; 150 os << obuf; 151 sp += 4; 152 } while(cargv); 153 154 //Output the envp pointers 155 int envCount = 0; 156 uint32_t cenvp; 157 do 158 { 159 cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 160 sprintf(obuf, "0x%08x: envp[%d] = 0x%08x\n", 161 sp, envCount++, cenvp); 162 os << obuf; 163 sp += 4; 164 } while(cenvp); 165 uint32_t auxType, auxVal; 166 do 167 { 168 auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 169 sp += 4; 170 auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 171 sp += 4; 172 sprintf(obuf, "0x%08x: Auxiliary vector = {0x%08x, 0x%08x}\n", 173 sp - 8, auxType, auxVal); 174 os << obuf; 175 } while(auxType != 0 || auxVal != 0); 176 //Print out the argument strings, environment strings, and file name. 177 string current; 178 uint32_t buf; 179 uint32_t currentStart = sp; 180 bool clearedInitialPadding = false; 181 do 182 { 183 buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 184 char * cbuf = (char *)&buf; 185 for(int x = 0; x < sizeof(uint32_t); x++) 186 { 187 if(cbuf[x]) 188 current += cbuf[x]; 189 else 190 { 191 sprintf(obuf, "0x%08x: \"%s\"\n", 192 currentStart, current.c_str()); 193 os << obuf; 194 current = ""; 195 currentStart = sp + x + 1; 196 } 197 } 198 sp += 4; 199 clearedInitialPadding = clearedInitialPadding || buf != 0; 200 } while(!clearedInitialPadding || buf != 0 || sp <= highestInfo); 201 return os; 202} 203 204bool ARMTraceChild::step() 205{ 206 const uint32_t bkpt_inst = 0xe7f001f0; 207 208 uint32_t lr = getRegVal(14); 209 uint32_t pc = getPC(); 210 uint32_t lrOp; 211 212 // Since ARM uses software breakpoints behind the scenes, they don't work 213 // in read only areas like the page of routines provided by the kernel. The 214 // link register generally holds the address the process wants to the 215 // kernel to return to after it's done, so we'll install a software 216 // breakpoint there. If the lr happens to point to the next instruction 217 // we'll leave out our breakpoint to avoid an infinite loop. This isn't a 218 // fool proof strategy, but it should work well in all the reasonable 219 // scenarios I can think of right now. 220 221 if (pc != lr) { 222 lrOp = ptrace(PTRACE_PEEKDATA, pid, lr, 0); 223 ptrace(PTRACE_POKEDATA, pid, lr, bkpt_inst); 224 } 225 ptraceSingleStep(); 226 if (pc != lr) { 227 ptrace(PTRACE_POKEDATA, pid, lr, lrOp); 228 } 229} 230 231 232TraceChild * genTraceChild() 233{ 234 return new ARMTraceChild; 235} 236 237