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 598271SAli.Saidi@ARM.com memset(®s, 0, sizeof(regs)); 608271SAli.Saidi@ARM.com memset(&oldregs, 0, sizeof(regs)); 618271SAli.Saidi@ARM.com memset(&fpregs, 0, sizeof(vfp_regs)); 628271SAli.Saidi@ARM.com memset(&oldfpregs, 0, sizeof(vfp_regs)); 638271SAli.Saidi@ARM.com 646411SN/A for (int x = 0; x < numregs; x++) { 656407SN/A regDiffSinceUpdate[x] = false; 666411SN/A } 678271SAli.Saidi@ARM.com 688271SAli.Saidi@ARM.com assert(sizeof(regs.uregs)/sizeof(regs.uregs[0]) > CPSR); 696407SN/A} 706407SN/A 718108SN/Abool 728108SN/AARMTraceChild::sendState(int socket) 736407SN/A{ 746407SN/A uint32_t regVal = 0; 758271SAli.Saidi@ARM.com uint64_t message[numregs + 1]; 766411SN/A int pos = 1; 776411SN/A message[0] = 0; 786411SN/A for (int x = 0; x < numregs; x++) { 796411SN/A if (regDiffSinceUpdate[x]) { 808271SAli.Saidi@ARM.com message[0] = message[0] | (1ULL << x); 816411SN/A message[pos++] = getRegVal(x); 826411SN/A } 836411SN/A } 846411SN/A 856411SN/A size_t sent = 0; 866411SN/A size_t toSend = pos * sizeof(message[0]); 876411SN/A uint8_t *messagePtr = (uint8_t *)message; 886411SN/A while (toSend != 0) { 896411SN/A sent = write(socket, messagePtr, toSend); 906411SN/A if (sent == -1) { 916407SN/A cerr << "Write failed! " << strerror(errno) << endl; 926407SN/A tracing = false; 936407SN/A return false; 946407SN/A } 956411SN/A toSend -= sent; 966411SN/A messagePtr += sent; 976407SN/A } 987414SN/A 996407SN/A return true; 1006407SN/A} 1016407SN/A 1028108SN/Auint32_t 1038108SN/AARMTraceChild::getRegs(user_regs &myregs, int num) 1046407SN/A{ 1058271SAli.Saidi@ARM.com assert(num <= CPSR && num >= 0); 1066407SN/A return myregs.uregs[num]; 1076407SN/A} 1086407SN/A 1098271SAli.Saidi@ARM.comuint64_t 1108271SAli.Saidi@ARM.comARMTraceChild::getFpRegs(vfp_regs &my_fp_regs, int num) 1118271SAli.Saidi@ARM.com{ 1128271SAli.Saidi@ARM.com assert(num >= F0 && num < numregs); 1138271SAli.Saidi@ARM.com if (num == FPSCR) 1148271SAli.Saidi@ARM.com return my_fp_regs.fpscr; 1158271SAli.Saidi@ARM.com 1168271SAli.Saidi@ARM.com num -= F0; 1178271SAli.Saidi@ARM.com return my_fp_regs.fpregs[num]; 1188271SAli.Saidi@ARM.com} 1198271SAli.Saidi@ARM.com 1208108SN/Abool 1218108SN/AARMTraceChild::update(int pid) 1226407SN/A{ 1236407SN/A oldregs = regs; 1248108SN/A if (ptrace(PTRACE_GETREGS, pid, 0, ®s) != 0) { 1256407SN/A cerr << "update: " << strerror(errno) << endl; 1266407SN/A return false; 1276407SN/A } 1287414SN/A 1298271SAli.Saidi@ARM.com const uint32_t get_vfp_regs = 32; 1308271SAli.Saidi@ARM.com 1318271SAli.Saidi@ARM.com oldfpregs = fpregs; 1328271SAli.Saidi@ARM.com if (ptrace((__ptrace_request)get_vfp_regs, pid, 0, &fpregs) != 0) { 1338271SAli.Saidi@ARM.com cerr << "update: " << strerror(errno) << endl; 1348271SAli.Saidi@ARM.com return false; 1358271SAli.Saidi@ARM.com } 1368271SAli.Saidi@ARM.com 1378108SN/A for (unsigned int x = 0; x < numregs; x++) 1386407SN/A regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); 1398271SAli.Saidi@ARM.com 1406407SN/A return true; 1416407SN/A} 1426407SN/A 1438108SN/Aint64_t 1448108SN/AARMTraceChild::getRegVal(int num) 1456407SN/A{ 1468271SAli.Saidi@ARM.com if (num <= CPSR) 1478271SAli.Saidi@ARM.com return getRegs(regs, num); 1488271SAli.Saidi@ARM.com else 1498271SAli.Saidi@ARM.com return (int64_t)getFpRegs(fpregs, num); 1506407SN/A} 1516407SN/A 1528108SN/Aint64_t 1538108SN/AARMTraceChild::getOldRegVal(int num) 1546407SN/A{ 1558271SAli.Saidi@ARM.com if (num <= CPSR) 1568271SAli.Saidi@ARM.com return getRegs(oldregs, num); 1578271SAli.Saidi@ARM.com else 1588271SAli.Saidi@ARM.com return (int64_t)getFpRegs(oldfpregs, num); 1596407SN/A} 1606407SN/A 1618108SN/Aostream & 1628108SN/AARMTraceChild::outputStartState(ostream & os) 1636407SN/A{ 1646407SN/A uint32_t sp = getSP(); 1656407SN/A uint32_t pc = getPC(); 1666407SN/A uint32_t highestInfo = 0; 1676407SN/A char obuf[1024]; 1686407SN/A sprintf(obuf, "Initial stack pointer = 0x%08x\n", sp); 1696407SN/A os << obuf; 1706407SN/A sprintf(obuf, "Initial program counter = 0x%08x\n", pc); 1716407SN/A os << obuf; 1726407SN/A 1736407SN/A //Output the argument count 1746407SN/A int32_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 1756407SN/A sprintf(obuf, "0x%08x: Argc = 0x%08x\n", sp, cargc); 1766407SN/A os << obuf; 1776407SN/A sp += 4; 1786407SN/A 1796407SN/A //Output argv pointers 1806407SN/A int argCount = 0; 1816407SN/A int32_t cargv; 1828108SN/A do { 1836407SN/A cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 1846407SN/A sprintf(obuf, "0x%08x: argv[%d] = 0x%08x\n", 1856407SN/A sp, argCount++, cargv); 18611321Ssteve.reinhardt@amd.com if (cargv) 18711321Ssteve.reinhardt@amd.com if (highestInfo < cargv) 1886407SN/A highestInfo = cargv; 1896407SN/A os << obuf; 1906407SN/A sp += 4; 19111321Ssteve.reinhardt@amd.com } while (cargv); 1926407SN/A 1936407SN/A //Output the envp pointers 1946407SN/A int envCount = 0; 1956407SN/A uint32_t cenvp; 1968108SN/A do { 1976407SN/A cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 1986407SN/A sprintf(obuf, "0x%08x: envp[%d] = 0x%08x\n", 1996407SN/A sp, envCount++, cenvp); 2006407SN/A os << obuf; 2016407SN/A sp += 4; 20211321Ssteve.reinhardt@amd.com } while (cenvp); 2036407SN/A uint32_t auxType, auxVal; 2048108SN/A do { 2056407SN/A auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 2066407SN/A sp += 4; 2076407SN/A auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 2086407SN/A sp += 4; 2096407SN/A sprintf(obuf, "0x%08x: Auxiliary vector = {0x%08x, 0x%08x}\n", 2106407SN/A sp - 8, auxType, auxVal); 2116407SN/A os << obuf; 21211321Ssteve.reinhardt@amd.com } while (auxType != 0 || auxVal != 0); 2136407SN/A //Print out the argument strings, environment strings, and file name. 2146407SN/A string current; 2156407SN/A uint32_t buf; 2166407SN/A uint32_t currentStart = sp; 2176407SN/A bool clearedInitialPadding = false; 2188108SN/A do { 2196407SN/A buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 2206407SN/A char * cbuf = (char *)&buf; 2218108SN/A for (int x = 0; x < sizeof(uint32_t); x++) { 2228108SN/A if (cbuf[x]) 2236407SN/A current += cbuf[x]; 2248108SN/A else { 2256407SN/A sprintf(obuf, "0x%08x: \"%s\"\n", 2266407SN/A currentStart, current.c_str()); 2276407SN/A os << obuf; 2286407SN/A current = ""; 2296407SN/A currentStart = sp + x + 1; 2306407SN/A } 2316407SN/A } 2326407SN/A sp += 4; 2336407SN/A clearedInitialPadding = clearedInitialPadding || buf != 0; 23411321Ssteve.reinhardt@amd.com } while (!clearedInitialPadding || buf != 0 || sp <= highestInfo); 2356407SN/A return os; 2366407SN/A} 2376407SN/A 2388108SN/Abool 2398108SN/AARMTraceChild::step() 2406407SN/A{ 2416417SN/A const uint32_t bkpt_inst = 0xe7f001f0; 2426407SN/A 2436417SN/A uint32_t lr = getRegVal(14); 2446417SN/A uint32_t pc = getPC(); 2457414SN/A uint32_t lrOp, subsOp; 2467414SN/A char obuf[128]; 2477414SN/A bool patch = false; 2486407SN/A 2496417SN/A // Since ARM uses software breakpoints behind the scenes, they don't work 2506417SN/A // in read only areas like the page of routines provided by the kernel. The 2516417SN/A // link register generally holds the address the process wants to the 2526417SN/A // kernel to return to after it's done, so we'll install a software 2537414SN/A // breakpoint there. 2547414SN/A // 2557414SN/A // Calls into the kernel user page always follow the form: 2567414SN/A // MVN ... 2577414SN/A // <possible MOV lr,...> 2587414SN/A // SUB PC, ... 2597414SN/A // 2607414SN/A // So we look for this pattern and set a breakpoint on the LR at the SUB 2617414SN/A // instruction. 2626407SN/A 2637414SN/A 2647414SN/A subsOp = ptrace(PTRACE_PEEKDATA, pid, pc, 0); 2657414SN/A if ((subsOp & 0xFFFF0FFF) == 0xe3e00a0f) 2667414SN/A foundMvn = true; 2677414SN/A 2687414SN/A if (foundMvn && ((subsOp & 0xFFF0F000) == 0xe240f000)) { 2697414SN/A foundMvn = false; 2706417SN/A lrOp = ptrace(PTRACE_PEEKDATA, pid, lr, 0); 2716417SN/A ptrace(PTRACE_POKEDATA, pid, lr, bkpt_inst); 2727414SN/A patch = true; 2736417SN/A } 2746417SN/A ptraceSingleStep(); 2757414SN/A 2767414SN/A if (patch) 2776417SN/A ptrace(PTRACE_POKEDATA, pid, lr, lrOp); 2786407SN/A} 2796407SN/A 2806407SN/A 2818108SN/ATraceChild * 2828108SN/AgenTraceChild() 2836407SN/A{ 2846407SN/A return new ARMTraceChild; 2856407SN/A} 2866407SN/A 287