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(&regs, 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, &regs) != 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