tracechild.cc revision 8229
16407SN/A/* 27414SN/A * Copyright (c) 2010 ARM Limited 37414SN/A * All rights reserved 47414SN/A * 57414SN/A * The license below extends only to copyright in the software and shall 67414SN/A * not be construed as granting a license to any other intellectual 77414SN/A * property including but not limited to intellectual property relating 87414SN/A * to a hardware implementation of the functionality of the software 97414SN/A * licensed hereunder. You may use the software subject to the license 107414SN/A * terms below provided that you ensure that this notice is replicated 117414SN/A * unmodified and in its entirety in all distributions of the software, 127414SN/A * modified or unmodified, in source code or in binary form. 137414SN/A * 146407SN/A * Copyright (c) 2006-2009 The Regents of The University of Michigan 156407SN/A * All rights reserved. 166407SN/A * 176407SN/A * Redistribution and use in source and binary forms, with or without 186407SN/A * modification, are permitted provided that the following conditions are 196407SN/A * met: redistributions of source code must retain the above copyright 206407SN/A * notice, this list of conditions and the following disclaimer; 216407SN/A * redistributions in binary form must reproduce the above copyright 226407SN/A * notice, this list of conditions and the following disclaimer in the 236407SN/A * documentation and/or other materials provided with the distribution; 246407SN/A * neither the name of the copyright holders nor the names of its 256407SN/A * contributors may be used to endorse or promote products derived from 266407SN/A * this software without specific prior written permission. 276407SN/A * 286407SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 296407SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 306407SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 316407SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 326407SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 336407SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 346407SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 356407SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 366407SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 376407SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 386407SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 396407SN/A * 406407SN/A * Authors: Ali Saidi 416407SN/A * Gabe Black 426407SN/A */ 436407SN/A 448229Snate@binkert.org#include <stdint.h> 458229Snate@binkert.org 468229Snate@binkert.org#include <cerrno> 478229Snate@binkert.org#include <cstdio> 488229Snate@binkert.org#include <cstring> 496407SN/A#include <iostream> 506407SN/A 518113Sgblack@eecs.umich.edu#include "arch/arm/tracechild.hh" 526407SN/A 536407SN/Ausing namespace std; 546407SN/A 556407SN/AARMTraceChild::ARMTraceChild() 566407SN/A{ 577414SN/A foundMvn = false; 587414SN/A 596411SN/A for (int x = 0; x < numregs; x++) { 606411SN/A memset(®s, 0, sizeof(regs)); 616411SN/A memset(&oldregs, 0, sizeof(regs)); 626407SN/A regDiffSinceUpdate[x] = false; 636411SN/A } 646407SN/A} 656407SN/A 668108SN/Abool 678108SN/AARMTraceChild::sendState(int socket) 686407SN/A{ 696407SN/A uint32_t regVal = 0; 706411SN/A uint32_t message[numregs + 1]; 716411SN/A int pos = 1; 726411SN/A message[0] = 0; 736411SN/A for (int x = 0; x < numregs; x++) { 746411SN/A if (regDiffSinceUpdate[x]) { 756411SN/A message[0] = message[0] | (1 << x); 766411SN/A message[pos++] = getRegVal(x); 776411SN/A } 786411SN/A } 796411SN/A 806411SN/A size_t sent = 0; 816411SN/A size_t toSend = pos * sizeof(message[0]); 826411SN/A uint8_t *messagePtr = (uint8_t *)message; 836411SN/A while (toSend != 0) { 846411SN/A sent = write(socket, messagePtr, toSend); 856411SN/A if (sent == -1) { 866407SN/A cerr << "Write failed! " << strerror(errno) << endl; 876407SN/A tracing = false; 886407SN/A return false; 896407SN/A } 906411SN/A toSend -= sent; 916411SN/A messagePtr += sent; 926407SN/A } 937414SN/A 946407SN/A return true; 956407SN/A} 966407SN/A 978108SN/Auint32_t 988108SN/AARMTraceChild::getRegs(user_regs &myregs, int num) 996407SN/A{ 1006407SN/A assert(num < numregs && num >= 0); 1016407SN/A return myregs.uregs[num]; 1026407SN/A} 1036407SN/A 1048108SN/Abool 1058108SN/AARMTraceChild::update(int pid) 1066407SN/A{ 1076407SN/A oldregs = regs; 1088108SN/A if (ptrace(PTRACE_GETREGS, pid, 0, ®s) != 0) { 1096407SN/A cerr << "update: " << strerror(errno) << endl; 1106407SN/A return false; 1116407SN/A } 1127414SN/A 1138108SN/A for (unsigned int x = 0; x < numregs; x++) 1146407SN/A regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); 1156407SN/A return true; 1166407SN/A} 1176407SN/A 1188108SN/Aint64_t 1198108SN/AARMTraceChild::getRegVal(int num) 1206407SN/A{ 1218108SN/A return getRegs(regs, num); 1226407SN/A} 1236407SN/A 1248108SN/Aint64_t 1258108SN/AARMTraceChild::getOldRegVal(int num) 1266407SN/A{ 1278108SN/A return getRegs(oldregs, num); 1286407SN/A} 1296407SN/A 1308108SN/Aostream & 1318108SN/AARMTraceChild::outputStartState(ostream & os) 1326407SN/A{ 1336407SN/A uint32_t sp = getSP(); 1346407SN/A uint32_t pc = getPC(); 1356407SN/A uint32_t highestInfo = 0; 1366407SN/A char obuf[1024]; 1376407SN/A sprintf(obuf, "Initial stack pointer = 0x%08x\n", sp); 1386407SN/A os << obuf; 1396407SN/A sprintf(obuf, "Initial program counter = 0x%08x\n", pc); 1406407SN/A os << obuf; 1416407SN/A 1426407SN/A //Output the argument count 1436407SN/A int32_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 1446407SN/A sprintf(obuf, "0x%08x: Argc = 0x%08x\n", sp, cargc); 1456407SN/A os << obuf; 1466407SN/A sp += 4; 1476407SN/A 1486407SN/A //Output argv pointers 1496407SN/A int argCount = 0; 1506407SN/A int32_t cargv; 1518108SN/A do { 1526407SN/A cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 1536407SN/A sprintf(obuf, "0x%08x: argv[%d] = 0x%08x\n", 1546407SN/A sp, argCount++, cargv); 1556407SN/A if(cargv) 1566407SN/A if(highestInfo < cargv) 1576407SN/A highestInfo = cargv; 1586407SN/A os << obuf; 1596407SN/A sp += 4; 1606407SN/A } while(cargv); 1616407SN/A 1626407SN/A //Output the envp pointers 1636407SN/A int envCount = 0; 1646407SN/A uint32_t cenvp; 1658108SN/A do { 1666407SN/A cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 1676407SN/A sprintf(obuf, "0x%08x: envp[%d] = 0x%08x\n", 1686407SN/A sp, envCount++, cenvp); 1696407SN/A os << obuf; 1706407SN/A sp += 4; 1716407SN/A } while(cenvp); 1726407SN/A uint32_t auxType, auxVal; 1738108SN/A do { 1746407SN/A auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 1756407SN/A sp += 4; 1766407SN/A auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 1776407SN/A sp += 4; 1786407SN/A sprintf(obuf, "0x%08x: Auxiliary vector = {0x%08x, 0x%08x}\n", 1796407SN/A sp - 8, auxType, auxVal); 1806407SN/A os << obuf; 1816407SN/A } while(auxType != 0 || auxVal != 0); 1826407SN/A //Print out the argument strings, environment strings, and file name. 1836407SN/A string current; 1846407SN/A uint32_t buf; 1856407SN/A uint32_t currentStart = sp; 1866407SN/A bool clearedInitialPadding = false; 1878108SN/A do { 1886407SN/A buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 1896407SN/A char * cbuf = (char *)&buf; 1908108SN/A for (int x = 0; x < sizeof(uint32_t); x++) { 1918108SN/A if (cbuf[x]) 1926407SN/A current += cbuf[x]; 1938108SN/A else { 1946407SN/A sprintf(obuf, "0x%08x: \"%s\"\n", 1956407SN/A currentStart, current.c_str()); 1966407SN/A os << obuf; 1976407SN/A current = ""; 1986407SN/A currentStart = sp + x + 1; 1996407SN/A } 2006407SN/A } 2016407SN/A sp += 4; 2026407SN/A clearedInitialPadding = clearedInitialPadding || buf != 0; 2036407SN/A } while(!clearedInitialPadding || buf != 0 || sp <= highestInfo); 2046407SN/A return os; 2056407SN/A} 2066407SN/A 2078108SN/Abool 2088108SN/AARMTraceChild::step() 2096407SN/A{ 2106417SN/A const uint32_t bkpt_inst = 0xe7f001f0; 2116407SN/A 2126417SN/A uint32_t lr = getRegVal(14); 2136417SN/A uint32_t pc = getPC(); 2147414SN/A uint32_t lrOp, subsOp; 2157414SN/A char obuf[128]; 2167414SN/A bool patch = false; 2176407SN/A 2186417SN/A // Since ARM uses software breakpoints behind the scenes, they don't work 2196417SN/A // in read only areas like the page of routines provided by the kernel. The 2206417SN/A // link register generally holds the address the process wants to the 2216417SN/A // kernel to return to after it's done, so we'll install a software 2227414SN/A // breakpoint there. 2237414SN/A // 2247414SN/A // Calls into the kernel user page always follow the form: 2257414SN/A // MVN ... 2267414SN/A // <possible MOV lr,...> 2277414SN/A // SUB PC, ... 2287414SN/A // 2297414SN/A // So we look for this pattern and set a breakpoint on the LR at the SUB 2307414SN/A // instruction. 2316407SN/A 2327414SN/A 2337414SN/A subsOp = ptrace(PTRACE_PEEKDATA, pid, pc, 0); 2347414SN/A if ((subsOp & 0xFFFF0FFF) == 0xe3e00a0f) 2357414SN/A foundMvn = true; 2367414SN/A 2377414SN/A if (foundMvn && ((subsOp & 0xFFF0F000) == 0xe240f000)) { 2387414SN/A foundMvn = false; 2396417SN/A lrOp = ptrace(PTRACE_PEEKDATA, pid, lr, 0); 2406417SN/A ptrace(PTRACE_POKEDATA, pid, lr, bkpt_inst); 2417414SN/A patch = true; 2426417SN/A } 2436417SN/A ptraceSingleStep(); 2447414SN/A 2457414SN/A if (patch) 2466417SN/A ptrace(PTRACE_POKEDATA, pid, lr, lrOp); 2476407SN/A} 2486407SN/A 2496407SN/A 2508108SN/ATraceChild * 2518108SN/AgenTraceChild() 2526407SN/A{ 2536407SN/A return new ARMTraceChild; 2546407SN/A} 2556407SN/A 256