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