OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include <setjmp.h> | 5 #include <setjmp.h> |
6 #include <stdlib.h> | 6 #include <stdlib.h> |
7 | 7 |
8 #include "vm/globals.h" | 8 #include "vm/globals.h" |
9 #if defined(TARGET_ARCH_ARM64) | 9 #if defined(TARGET_ARCH_ARM64) |
10 | 10 |
11 // Only build the simulator if not compiling for real ARM hardware. | 11 // Only build the simulator if not compiling for real ARM hardware. |
12 #if !defined(HOST_ARCH_ARM64) | 12 #if !defined(HOST_ARCH_ARM64) |
13 | 13 |
14 #include "vm/simulator.h" | 14 #include "vm/simulator.h" |
15 | 15 |
16 #include "vm/assembler.h" | 16 #include "vm/assembler.h" |
17 #include "vm/constants_arm64.h" | 17 #include "vm/constants_arm64.h" |
18 #include "vm/cpu.h" | |
19 #include "vm/disassembler.h" | 18 #include "vm/disassembler.h" |
20 #include "vm/lockers.h" | 19 #include "vm/lockers.h" |
21 #include "vm/native_arguments.h" | 20 #include "vm/native_arguments.h" |
22 #include "vm/stack_frame.h" | 21 #include "vm/stack_frame.h" |
23 #include "vm/thread.h" | 22 #include "vm/thread.h" |
24 | 23 |
25 namespace dart { | 24 namespace dart { |
26 | 25 |
27 DEFINE_FLAG(bool, trace_sim, false, "Trace simulator execution."); | 26 DEFINE_FLAG(bool, trace_sim, false, "Trace simulator execution."); |
28 DEFINE_FLAG(int, stop_sim_at, 0, "Address to stop simulator at."); | 27 DEFINE_FLAG(int, stop_sim_at, 0, |
| 28 "Instruction address or instruction count to stop simulator at."); |
29 | 29 |
30 | 30 |
31 // This macro provides a platform independent use of sscanf. The reason for | 31 // This macro provides a platform independent use of sscanf. The reason for |
32 // SScanF not being implemented in a platform independent way through | 32 // SScanF not being implemented in a platform independent way through |
33 // OS in the same way as SNPrint is that the Windows C Run-Time | 33 // OS in the same way as SNPrint is that the Windows C Run-Time |
34 // Library does not provide vsscanf. | 34 // Library does not provide vsscanf. |
35 #define SScanF sscanf // NOLINT | 35 #define SScanF sscanf // NOLINT |
36 | 36 |
37 | 37 |
38 // SimulatorSetjmpBuffer are linked together, and the last created one | 38 // SimulatorSetjmpBuffer are linked together, and the last created one |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 explicit SimulatorDebugger(Simulator* sim); | 85 explicit SimulatorDebugger(Simulator* sim); |
86 ~SimulatorDebugger(); | 86 ~SimulatorDebugger(); |
87 | 87 |
88 void Stop(Instr* instr, const char* message); | 88 void Stop(Instr* instr, const char* message); |
89 void Debug(); | 89 void Debug(); |
90 char* ReadLine(const char* prompt); | 90 char* ReadLine(const char* prompt); |
91 | 91 |
92 private: | 92 private: |
93 Simulator* sim_; | 93 Simulator* sim_; |
94 | 94 |
95 bool GetValue(char* desc, int64_t* value); | 95 bool GetValue(char* desc, uint64_t* value); |
96 bool GetSValue(char* desc, int32_t* value); | 96 bool GetSValue(char* desc, uint32_t* value); |
97 bool GetDValue(char* desc, int64_t* value); | 97 bool GetDValue(char* desc, uint64_t* value); |
98 bool GetQValue(char* desc, simd_value_t* value); | 98 bool GetQValue(char* desc, simd_value_t* value); |
99 // TODO(zra): Breakpoints. | 99 |
| 100 static intptr_t GetApproximateTokenIndex(const Code& code, uword pc); |
| 101 |
| 102 static void PrintDartFrame(uword pc, uword fp, uword sp, |
| 103 const Function& function, |
| 104 intptr_t token_pos, |
| 105 bool is_optimized, |
| 106 bool is_inlined); |
| 107 void PrintBacktrace(); |
| 108 |
| 109 // Set or delete a breakpoint. Returns true if successful. |
| 110 bool SetBreakpoint(Instr* breakpc); |
| 111 bool DeleteBreakpoint(Instr* breakpc); |
| 112 |
| 113 // Undo and redo all breakpoints. This is needed to bracket disassembly and |
| 114 // execution to skip past breakpoints when run from the debugger. |
| 115 void UndoBreakpoints(); |
| 116 void RedoBreakpoints(); |
100 }; | 117 }; |
101 | 118 |
102 | 119 |
103 SimulatorDebugger::SimulatorDebugger(Simulator* sim) { | 120 SimulatorDebugger::SimulatorDebugger(Simulator* sim) { |
104 sim_ = sim; | 121 sim_ = sim; |
105 } | 122 } |
106 | 123 |
107 | 124 |
108 SimulatorDebugger::~SimulatorDebugger() { | 125 SimulatorDebugger::~SimulatorDebugger() { |
109 } | 126 } |
110 | 127 |
| 128 |
111 void SimulatorDebugger::Stop(Instr* instr, const char* message) { | 129 void SimulatorDebugger::Stop(Instr* instr, const char* message) { |
112 OS::Print("Simulator hit %s\n", message); | 130 OS::Print("Simulator hit %s\n", message); |
113 Debug(); | 131 Debug(); |
114 } | 132 } |
115 | 133 |
116 | 134 |
117 static Register LookupCpuRegisterByName(const char* name) { | 135 static Register LookupCpuRegisterByName(const char* name) { |
118 static const char* kNames[] = { | 136 static const char* kNames[] = { |
119 "r0", "r1", "r2", "r3", | 137 "r0", "r1", "r2", "r3", |
120 "r4", "r5", "r6", "r7", | 138 "r4", "r5", "r6", "r7", |
(...skipping 27 matching lines...) Expand all Loading... |
148 static VRegister LookupVRegisterByName(const char* name) { | 166 static VRegister LookupVRegisterByName(const char* name) { |
149 int reg_nr = -1; | 167 int reg_nr = -1; |
150 bool ok = SScanF(name, "v%d", ®_nr); | 168 bool ok = SScanF(name, "v%d", ®_nr); |
151 if (ok && (0 <= reg_nr) && (reg_nr < kNumberOfVRegisters)) { | 169 if (ok && (0 <= reg_nr) && (reg_nr < kNumberOfVRegisters)) { |
152 return static_cast<VRegister>(reg_nr); | 170 return static_cast<VRegister>(reg_nr); |
153 } | 171 } |
154 return kNoVRegister; | 172 return kNoVRegister; |
155 } | 173 } |
156 | 174 |
157 | 175 |
158 bool SimulatorDebugger::GetValue(char* desc, int64_t* value) { | 176 bool SimulatorDebugger::GetValue(char* desc, uint64_t* value) { |
159 Register reg = LookupCpuRegisterByName(desc); | 177 Register reg = LookupCpuRegisterByName(desc); |
160 if (reg != kNoRegister) { | 178 if (reg != kNoRegister) { |
161 if (reg == ZR) { | 179 if (reg == ZR) { |
162 *value = 0; | 180 *value = 0; |
163 return true; | 181 return true; |
164 } | 182 } |
165 *value = sim_->get_register(reg); | 183 *value = sim_->get_register(reg); |
166 return true; | 184 return true; |
167 } | 185 } |
168 if (desc[0] == '*') { | 186 if (desc[0] == '*') { |
169 int64_t addr; | 187 uint64_t addr; |
170 if (GetValue(desc + 1, &addr)) { | 188 if (GetValue(desc + 1, &addr)) { |
171 if (Simulator::IsIllegalAddress(addr)) { | 189 if (Simulator::IsIllegalAddress(addr)) { |
172 return false; | 190 return false; |
173 } | 191 } |
174 *value = *(reinterpret_cast<int64_t*>(addr)); | 192 *value = *(reinterpret_cast<int64_t*>(addr)); |
175 return true; | 193 return true; |
176 } | 194 } |
177 } | 195 } |
178 if (strcmp("pc", desc) == 0) { | 196 if (strcmp("pc", desc) == 0) { |
179 *value = sim_->get_pc(); | 197 *value = sim_->get_pc(); |
180 return true; | 198 return true; |
181 } | 199 } |
| 200 if (strcmp("icount", desc) == 0) { |
| 201 *value = sim_->get_icount(); |
| 202 return true; |
| 203 } |
182 bool retval = SScanF(desc, "0x%"Px64, value) == 1; | 204 bool retval = SScanF(desc, "0x%"Px64, value) == 1; |
183 if (!retval) { | 205 if (!retval) { |
184 retval = SScanF(desc, "%"Px64, value) == 1; | 206 retval = SScanF(desc, "%"Px64, value) == 1; |
185 } | 207 } |
186 return retval; | 208 return retval; |
187 } | 209 } |
188 | 210 |
189 | 211 |
190 bool SimulatorDebugger::GetSValue(char* desc, int32_t* value) { | 212 bool SimulatorDebugger::GetSValue(char* desc, uint32_t* value) { |
191 VRegister vreg = LookupVRegisterByName(desc); | 213 VRegister vreg = LookupVRegisterByName(desc); |
192 if (vreg != kNoVRegister) { | 214 if (vreg != kNoVRegister) { |
193 *value = sim_->get_vregisters(vreg, 0); | 215 *value = sim_->get_vregisters(vreg, 0); |
194 return true; | 216 return true; |
195 } | 217 } |
196 if (desc[0] == '*') { | 218 if (desc[0] == '*') { |
197 int64_t addr; | 219 uint64_t addr; |
198 if (GetValue(desc + 1, &addr)) { | 220 if (GetValue(desc + 1, &addr)) { |
199 if (Simulator::IsIllegalAddress(addr)) { | 221 if (Simulator::IsIllegalAddress(addr)) { |
200 return false; | 222 return false; |
201 } | 223 } |
202 *value = *(reinterpret_cast<int32_t*>(addr)); | 224 *value = *(reinterpret_cast<uint32_t*>(addr)); |
203 return true; | 225 return true; |
204 } | 226 } |
205 } | 227 } |
206 return false; | 228 return false; |
207 } | 229 } |
208 | 230 |
209 | 231 |
210 bool SimulatorDebugger::GetDValue(char* desc, int64_t* value) { | 232 bool SimulatorDebugger::GetDValue(char* desc, uint64_t* value) { |
211 VRegister vreg = LookupVRegisterByName(desc); | 233 VRegister vreg = LookupVRegisterByName(desc); |
212 if (vreg != kNoVRegister) { | 234 if (vreg != kNoVRegister) { |
213 *value = sim_->get_vregisterd(vreg, 0); | 235 *value = sim_->get_vregisterd(vreg, 0); |
214 return true; | 236 return true; |
215 } | 237 } |
216 if (desc[0] == '*') { | 238 if (desc[0] == '*') { |
217 int64_t addr; | 239 uint64_t addr; |
218 if (GetValue(desc + 1, &addr)) { | 240 if (GetValue(desc + 1, &addr)) { |
219 if (Simulator::IsIllegalAddress(addr)) { | 241 if (Simulator::IsIllegalAddress(addr)) { |
220 return false; | 242 return false; |
221 } | 243 } |
222 *value = *(reinterpret_cast<int64_t*>(addr)); | 244 *value = *(reinterpret_cast<uint64_t*>(addr)); |
223 return true; | 245 return true; |
224 } | 246 } |
225 } | 247 } |
226 return false; | 248 return false; |
227 } | 249 } |
228 | 250 |
229 | 251 |
230 bool SimulatorDebugger::GetQValue(char* desc, simd_value_t* value) { | 252 bool SimulatorDebugger::GetQValue(char* desc, simd_value_t* value) { |
231 VRegister vreg = LookupVRegisterByName(desc); | 253 VRegister vreg = LookupVRegisterByName(desc); |
232 if (vreg != kNoVRegister) { | 254 if (vreg != kNoVRegister) { |
233 sim_->get_vregister(vreg, value); | 255 sim_->get_vregister(vreg, value); |
234 return true; | 256 return true; |
235 } | 257 } |
236 if (desc[0] == '*') { | 258 if (desc[0] == '*') { |
237 int64_t addr; | 259 uint64_t addr; |
238 if (GetValue(desc + 1, &addr)) { | 260 if (GetValue(desc + 1, &addr)) { |
239 if (Simulator::IsIllegalAddress(addr)) { | 261 if (Simulator::IsIllegalAddress(addr)) { |
240 return false; | 262 return false; |
241 } | 263 } |
242 *value = *(reinterpret_cast<simd_value_t*>(addr)); | 264 *value = *(reinterpret_cast<simd_value_t*>(addr)); |
243 return true; | 265 return true; |
244 } | 266 } |
245 } | 267 } |
246 return false; | 268 return false; |
247 } | 269 } |
248 | 270 |
249 | 271 |
| 272 intptr_t SimulatorDebugger::GetApproximateTokenIndex(const Code& code, |
| 273 uword pc) { |
| 274 intptr_t token_pos = -1; |
| 275 const PcDescriptors& descriptors = |
| 276 PcDescriptors::Handle(code.pc_descriptors()); |
| 277 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind); |
| 278 while (iter.MoveNext()) { |
| 279 if (iter.Pc() == pc) { |
| 280 return iter.TokenPos(); |
| 281 } else if ((token_pos <= 0) && (iter.Pc() > pc)) { |
| 282 token_pos = iter.TokenPos(); |
| 283 } |
| 284 } |
| 285 return token_pos; |
| 286 } |
| 287 |
| 288 |
| 289 void SimulatorDebugger::PrintDartFrame(uword pc, uword fp, uword sp, |
| 290 const Function& function, |
| 291 intptr_t token_pos, |
| 292 bool is_optimized, |
| 293 bool is_inlined) { |
| 294 const Script& script = Script::Handle(function.script()); |
| 295 const String& func_name = String::Handle(function.QualifiedUserVisibleName()); |
| 296 const String& url = String::Handle(script.url()); |
| 297 intptr_t line = -1; |
| 298 intptr_t column = -1; |
| 299 if (token_pos >= 0) { |
| 300 script.GetTokenLocation(token_pos, &line, &column); |
| 301 } |
| 302 OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd |
| 303 ":%" Pd ")\n", |
| 304 pc, fp, sp, |
| 305 is_optimized ? (is_inlined ? "inlined " : "optimized ") : "", |
| 306 func_name.ToCString(), |
| 307 url.ToCString(), |
| 308 line, column); |
| 309 } |
| 310 |
| 311 |
| 312 void SimulatorDebugger::PrintBacktrace() { |
| 313 StackFrameIterator frames(sim_->get_register(FP), |
| 314 sim_->get_register(SP), |
| 315 sim_->get_pc(), |
| 316 StackFrameIterator::kDontValidateFrames); |
| 317 StackFrame* frame = frames.NextFrame(); |
| 318 ASSERT(frame != NULL); |
| 319 Function& function = Function::Handle(); |
| 320 Function& inlined_function = Function::Handle(); |
| 321 Code& code = Code::Handle(); |
| 322 Code& unoptimized_code = Code::Handle(); |
| 323 while (frame != NULL) { |
| 324 if (frame->IsDartFrame()) { |
| 325 code = frame->LookupDartCode(); |
| 326 function = code.function(); |
| 327 if (code.is_optimized()) { |
| 328 // For optimized frames, extract all the inlined functions if any |
| 329 // into the stack trace. |
| 330 InlinedFunctionsIterator it(code, frame->pc()); |
| 331 while (!it.Done()) { |
| 332 // Print each inlined frame with its pc in the corresponding |
| 333 // unoptimized frame. |
| 334 inlined_function = it.function(); |
| 335 unoptimized_code = it.code(); |
| 336 uword unoptimized_pc = it.pc(); |
| 337 it.Advance(); |
| 338 if (!it.Done()) { |
| 339 PrintDartFrame(unoptimized_pc, frame->fp(), frame->sp(), |
| 340 inlined_function, |
| 341 GetApproximateTokenIndex(unoptimized_code, |
| 342 unoptimized_pc), |
| 343 true, true); |
| 344 } |
| 345 } |
| 346 // Print the optimized inlining frame below. |
| 347 } |
| 348 PrintDartFrame(frame->pc(), frame->fp(), frame->sp(), |
| 349 function, |
| 350 GetApproximateTokenIndex(code, frame->pc()), |
| 351 code.is_optimized(), false); |
| 352 } else { |
| 353 OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s frame\n", |
| 354 frame->pc(), frame->fp(), frame->sp(), |
| 355 frame->IsEntryFrame() ? "entry" : |
| 356 frame->IsExitFrame() ? "exit" : |
| 357 frame->IsStubFrame() ? "stub" : "invalid"); |
| 358 } |
| 359 frame = frames.NextFrame(); |
| 360 } |
| 361 } |
| 362 |
| 363 |
| 364 bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) { |
| 365 // Check if a breakpoint can be set. If not return without any side-effects. |
| 366 if (sim_->break_pc_ != NULL) { |
| 367 return false; |
| 368 } |
| 369 |
| 370 // Set the breakpoint. |
| 371 sim_->break_pc_ = breakpc; |
| 372 sim_->break_instr_ = breakpc->InstructionBits(); |
| 373 // Not setting the breakpoint instruction in the code itself. It will be set |
| 374 // when the debugger shell continues. |
| 375 return true; |
| 376 } |
| 377 |
| 378 |
| 379 bool SimulatorDebugger::DeleteBreakpoint(Instr* breakpc) { |
| 380 if (sim_->break_pc_ != NULL) { |
| 381 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); |
| 382 } |
| 383 |
| 384 sim_->break_pc_ = NULL; |
| 385 sim_->break_instr_ = 0; |
| 386 return true; |
| 387 } |
| 388 |
| 389 |
| 390 void SimulatorDebugger::UndoBreakpoints() { |
| 391 if (sim_->break_pc_ != NULL) { |
| 392 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); |
| 393 } |
| 394 } |
| 395 |
| 396 |
| 397 void SimulatorDebugger::RedoBreakpoints() { |
| 398 if (sim_->break_pc_ != NULL) { |
| 399 sim_->break_pc_->SetInstructionBits(Instr::kSimulatorBreakpointInstruction); |
| 400 } |
| 401 } |
| 402 |
| 403 |
250 void SimulatorDebugger::Debug() { | 404 void SimulatorDebugger::Debug() { |
251 intptr_t last_pc = -1; | 405 intptr_t last_pc = -1; |
252 bool done = false; | 406 bool done = false; |
253 | 407 |
254 #define COMMAND_SIZE 63 | 408 #define COMMAND_SIZE 63 |
255 #define ARG_SIZE 255 | 409 #define ARG_SIZE 255 |
256 | 410 |
257 #define STR(a) #a | 411 #define STR(a) #a |
258 #define XSTR(a) STR(a) | 412 #define XSTR(a) STR(a) |
259 | 413 |
260 char cmd[COMMAND_SIZE + 1]; | 414 char cmd[COMMAND_SIZE + 1]; |
261 char arg1[ARG_SIZE + 1]; | 415 char arg1[ARG_SIZE + 1]; |
262 char arg2[ARG_SIZE + 1]; | 416 char arg2[ARG_SIZE + 1]; |
263 | 417 |
264 // make sure to have a proper terminating character if reaching the limit | 418 // make sure to have a proper terminating character if reaching the limit |
265 cmd[COMMAND_SIZE] = 0; | 419 cmd[COMMAND_SIZE] = 0; |
266 arg1[ARG_SIZE] = 0; | 420 arg1[ARG_SIZE] = 0; |
267 arg2[ARG_SIZE] = 0; | 421 arg2[ARG_SIZE] = 0; |
268 | 422 |
269 // TODO(zra): Undo all set breakpoints while running in the debugger shell. | 423 // Undo all set breakpoints while running in the debugger shell. This will |
270 // This will make them invisible to all commands. | 424 // make them invisible to all commands. |
271 // UndoBreakpoints(); | 425 UndoBreakpoints(); |
272 | 426 |
273 while (!done) { | 427 while (!done) { |
274 if (last_pc != sim_->get_pc()) { | 428 if (last_pc != sim_->get_pc()) { |
275 last_pc = sim_->get_pc(); | 429 last_pc = sim_->get_pc(); |
276 if (Simulator::IsIllegalAddress(last_pc)) { | 430 if (Simulator::IsIllegalAddress(last_pc)) { |
277 OS::Print("pc is out of bounds: 0x%" Px "\n", last_pc); | 431 OS::Print("pc is out of bounds: 0x%" Px "\n", last_pc); |
278 } else { | 432 } else { |
279 Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize); | 433 Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize); |
280 } | 434 } |
281 } | 435 } |
282 char* line = ReadLine("sim> "); | 436 char* line = ReadLine("sim> "); |
283 if (line == NULL) { | 437 if (line == NULL) { |
284 FATAL("ReadLine failed"); | 438 FATAL("ReadLine failed"); |
285 } else { | 439 } else { |
286 // Use sscanf to parse the individual parts of the command line. At the | 440 // Use sscanf to parse the individual parts of the command line. At the |
287 // moment no command expects more than two parameters. | 441 // moment no command expects more than two parameters. |
288 int args = SScanF(line, | 442 int args = SScanF(line, |
289 "%" XSTR(COMMAND_SIZE) "s " | 443 "%" XSTR(COMMAND_SIZE) "s " |
290 "%" XSTR(ARG_SIZE) "s " | 444 "%" XSTR(ARG_SIZE) "s " |
291 "%" XSTR(ARG_SIZE) "s", | 445 "%" XSTR(ARG_SIZE) "s", |
292 cmd, arg1, arg2); | 446 cmd, arg1, arg2); |
293 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { | 447 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { |
294 OS::Print("c/cont -- continue execution\n" | 448 OS::Print("c/cont -- continue execution\n" |
295 "disasm -- disassemble instrs at current pc location\n" | 449 "disasm -- disassemble instrs at current pc location\n" |
296 " other variants are:\n" | 450 " other variants are:\n" |
297 " disasm <address>\n" | 451 " disasm <address>\n" |
298 " disasm <address> <number_of_instructions>\n" | 452 " disasm <address> <number_of_instructions>\n" |
299 " by default 10 instrs are disassembled\n" | 453 " by default 10 instrs are disassembled\n" |
| 454 "del -- delete breakpoints\n" |
300 "flags -- print flag values\n" | 455 "flags -- print flag values\n" |
301 "gdb -- transfer control to gdb\n" | 456 "gdb -- transfer control to gdb\n" |
302 "h/help -- print this help string\n" | 457 "h/help -- print this help string\n" |
303 "p/print <reg or value or *addr> -- print integer value\n" | 458 "break <address> -- set break point at specified address\n" |
| 459 "p/print <reg or icount or value or *addr> -- print integer\n" |
304 "pf/printfloat <vreg or *addr> --print float value\n" | 460 "pf/printfloat <vreg or *addr> --print float value\n" |
305 "pd/printdouble <vreg or *addr> -- print double value\n" | 461 "pd/printdouble <vreg or *addr> -- print double value\n" |
306 "pq/printquad <vreg or *addr> -- print vector register\n" | 462 "pq/printquad <vreg or *addr> -- print vector register\n" |
307 "po/printobject <*reg or *addr> -- print object\n" | 463 "po/printobject <*reg or *addr> -- print object\n" |
308 "si/stepi -- single step an instruction\n" | 464 "si/stepi -- single step an instruction\n" |
| 465 "trace -- toggle execution tracing mode\n" |
| 466 "bt -- print backtrace\n" |
| 467 "unstop -- if current pc is a stop instr make it a nop\n" |
309 "q/quit -- Quit the debugger and exit the program\n"); | 468 "q/quit -- Quit the debugger and exit the program\n"); |
310 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { | 469 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { |
311 OS::Print("Quitting\n"); | 470 OS::Print("Quitting\n"); |
312 OS::Exit(0); | 471 OS::Exit(0); |
313 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { | 472 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { |
314 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 473 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
315 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { | 474 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { |
316 // Execute the one instruction we broke at with breakpoints disabled. | 475 // Execute the one instruction we broke at with breakpoints disabled. |
317 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 476 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
318 // Leave the debugger shell. | 477 // Leave the debugger shell. |
319 done = true; | 478 done = true; |
320 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { | 479 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { |
321 if (args == 2) { | 480 if (args == 2) { |
322 int64_t value; | 481 uint64_t value; |
323 if (GetValue(arg1, &value)) { | 482 if (GetValue(arg1, &value)) { |
324 OS::Print("%s: %"Pu64" 0x%"Px64"\n", arg1, value, value); | 483 OS::Print("%s: %"Pu64" 0x%"Px64"\n", arg1, value, value); |
325 } else { | 484 } else { |
326 OS::Print("%s unrecognized\n", arg1); | 485 OS::Print("%s unrecognized\n", arg1); |
327 } | 486 } |
328 } else { | 487 } else { |
329 OS::Print("print <reg or value or *addr>\n"); | 488 OS::Print("print <reg or value or *addr>\n"); |
330 } | 489 } |
331 } else if ((strcmp(cmd, "pf") == 0) || | 490 } else if ((strcmp(cmd, "pf") == 0) || |
332 (strcmp(cmd, "printfloat") == 0)) { | 491 (strcmp(cmd, "printfloat") == 0)) { |
333 if (args == 2) { | 492 if (args == 2) { |
334 int32_t value; | 493 uint32_t value; |
335 if (GetSValue(arg1, &value)) { | 494 if (GetSValue(arg1, &value)) { |
336 float svalue = bit_cast<float, int32_t>(value); | 495 float svalue = bit_cast<float, uint32_t>(value); |
337 OS::Print("%s: %d 0x%x %.8g\n", | 496 OS::Print("%s: %d 0x%x %.8g\n", |
338 arg1, value, value, svalue); | 497 arg1, value, value, svalue); |
339 } else { | 498 } else { |
340 OS::Print("%s unrecognized\n", arg1); | 499 OS::Print("%s unrecognized\n", arg1); |
341 } | 500 } |
342 } else { | 501 } else { |
343 OS::Print("printfloat <vreg or *addr>\n"); | 502 OS::Print("printfloat <vreg or *addr>\n"); |
344 } | 503 } |
345 } else if ((strcmp(cmd, "pd") == 0) || | 504 } else if ((strcmp(cmd, "pd") == 0) || |
346 (strcmp(cmd, "printdouble") == 0)) { | 505 (strcmp(cmd, "printdouble") == 0)) { |
347 if (args == 2) { | 506 if (args == 2) { |
348 int64_t long_value; | 507 uint64_t long_value; |
349 if (GetDValue(arg1, &long_value)) { | 508 if (GetDValue(arg1, &long_value)) { |
350 double dvalue = bit_cast<double, int64_t>(long_value); | 509 double dvalue = bit_cast<double, uint64_t>(long_value); |
351 OS::Print("%s: %"Pu64" 0x%"Px64" %.8g\n", | 510 OS::Print("%s: %"Pu64" 0x%"Px64" %.8g\n", |
352 arg1, long_value, long_value, dvalue); | 511 arg1, long_value, long_value, dvalue); |
353 } else { | 512 } else { |
354 OS::Print("%s unrecognized\n", arg1); | 513 OS::Print("%s unrecognized\n", arg1); |
355 } | 514 } |
356 } else { | 515 } else { |
357 OS::Print("printdouble <vreg or *addr>\n"); | 516 OS::Print("printdouble <vreg or *addr>\n"); |
358 } | 517 } |
359 } else if ((strcmp(cmd, "pq") == 0) || | 518 } else if ((strcmp(cmd, "pq") == 0) || |
360 (strcmp(cmd, "printquad") == 0)) { | 519 (strcmp(cmd, "printquad") == 0)) { |
(...skipping 20 matching lines...) Expand all Loading... |
381 OS::Print("%s: %d 0x%x %.8g\n", arg1, s3, s3, sval3); | 540 OS::Print("%s: %d 0x%x %.8g\n", arg1, s3, s3, sval3); |
382 } else { | 541 } else { |
383 OS::Print("%s unrecognized\n", arg1); | 542 OS::Print("%s unrecognized\n", arg1); |
384 } | 543 } |
385 } else { | 544 } else { |
386 OS::Print("printquad <vreg or *addr>\n"); | 545 OS::Print("printquad <vreg or *addr>\n"); |
387 } | 546 } |
388 } else if ((strcmp(cmd, "po") == 0) || | 547 } else if ((strcmp(cmd, "po") == 0) || |
389 (strcmp(cmd, "printobject") == 0)) { | 548 (strcmp(cmd, "printobject") == 0)) { |
390 if (args == 2) { | 549 if (args == 2) { |
391 int64_t value; | 550 uint64_t value; |
392 // Make the dereferencing '*' optional. | 551 // Make the dereferencing '*' optional. |
393 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) || | 552 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) || |
394 GetValue(arg1, &value)) { | 553 GetValue(arg1, &value)) { |
395 if (Isolate::Current()->heap()->Contains(value)) { | 554 if (Isolate::Current()->heap()->Contains(value)) { |
396 OS::Print("%s: \n", arg1); | 555 OS::Print("%s: \n", arg1); |
397 #if defined(DEBUG) | 556 #if defined(DEBUG) |
398 const Object& obj = Object::Handle( | 557 const Object& obj = Object::Handle( |
399 reinterpret_cast<RawObject*>(value)); | 558 reinterpret_cast<RawObject*>(value)); |
400 obj.Print(); | 559 obj.Print(); |
401 #endif // defined(DEBUG) | 560 #endif // defined(DEBUG) |
402 } else { | 561 } else { |
403 OS::Print("0x%"Px64" is not an object reference\n", value); | 562 OS::Print("0x%"Px64" is not an object reference\n", value); |
404 } | 563 } |
405 } else { | 564 } else { |
406 OS::Print("%s unrecognized\n", arg1); | 565 OS::Print("%s unrecognized\n", arg1); |
407 } | 566 } |
408 } else { | 567 } else { |
409 OS::Print("printobject <*reg or *addr>\n"); | 568 OS::Print("printobject <*reg or *addr>\n"); |
410 } | 569 } |
411 } else if (strcmp(cmd, "disasm") == 0) { | 570 } else if (strcmp(cmd, "disasm") == 0) { |
412 int64_t start = 0; | 571 uint64_t start = 0; |
413 int64_t end = 0; | 572 uint64_t end = 0; |
414 if (args == 1) { | 573 if (args == 1) { |
415 start = sim_->get_pc(); | 574 start = sim_->get_pc(); |
416 end = start + (10 * Instr::kInstrSize); | 575 end = start + (10 * Instr::kInstrSize); |
417 } else if (args == 2) { | 576 } else if (args == 2) { |
418 if (GetValue(arg1, &start)) { | 577 if (GetValue(arg1, &start)) { |
419 // no length parameter passed, assume 10 instructions | 578 // No length parameter passed, assume 10 instructions. |
420 if (Simulator::IsIllegalAddress(start)) { | 579 if (Simulator::IsIllegalAddress(start)) { |
421 // If start isn't a valid address, warn and use PC instead | 580 // If start isn't a valid address, warn and use PC instead. |
422 OS::Print("First argument yields invalid address: 0x%"Px64"\n", | 581 OS::Print("First argument yields invalid address: 0x%"Px64"\n", |
423 start); | 582 start); |
424 OS::Print("Using PC instead"); | 583 OS::Print("Using PC instead\n"); |
425 start = sim_->get_pc(); | 584 start = sim_->get_pc(); |
426 } | 585 } |
427 end = start + (10 * Instr::kInstrSize); | 586 end = start + (10 * Instr::kInstrSize); |
428 } | 587 } |
429 } else { | 588 } else { |
430 int64_t length; | 589 uint64_t length; |
431 if (GetValue(arg1, &start) && GetValue(arg2, &length)) { | 590 if (GetValue(arg1, &start) && GetValue(arg2, &length)) { |
432 if (Simulator::IsIllegalAddress(start)) { | 591 if (Simulator::IsIllegalAddress(start)) { |
433 // If start isn't a valid address, warn and use PC instead | 592 // If start isn't a valid address, warn and use PC instead. |
434 OS::Print("First argument yields invalid address: 0x%"Px64"\n", | 593 OS::Print("First argument yields invalid address: 0x%"Px64"\n", |
435 start); | 594 start); |
436 OS::Print("Using PC instead\n"); | 595 OS::Print("Using PC instead\n"); |
437 start = sim_->get_pc(); | 596 start = sim_->get_pc(); |
438 } | 597 } |
439 end = start + (length * Instr::kInstrSize); | 598 end = start + (length * Instr::kInstrSize); |
440 } | 599 } |
441 } | 600 } |
442 Disassembler::Disassemble(start, end); | 601 if ((start > 0) && (end > start)) { |
| 602 Disassembler::Disassemble(start, end); |
| 603 } else { |
| 604 OS::Print("disasm [<address> [<number_of_instructions>]]\n"); |
| 605 } |
| 606 } else if (strcmp(cmd, "gdb") == 0) { |
| 607 OS::Print("relinquishing control to gdb\n"); |
| 608 OS::DebugBreak(); |
| 609 OS::Print("regaining control from gdb\n"); |
| 610 } else if (strcmp(cmd, "break") == 0) { |
| 611 if (args == 2) { |
| 612 uint64_t addr; |
| 613 if (GetValue(arg1, &addr)) { |
| 614 if (!SetBreakpoint(reinterpret_cast<Instr*>(addr))) { |
| 615 OS::Print("setting breakpoint failed\n"); |
| 616 } |
| 617 } else { |
| 618 OS::Print("%s unrecognized\n", arg1); |
| 619 } |
| 620 } else { |
| 621 OS::Print("break <addr>\n"); |
| 622 } |
| 623 } else if (strcmp(cmd, "del") == 0) { |
| 624 if (!DeleteBreakpoint(NULL)) { |
| 625 OS::Print("deleting breakpoint failed\n"); |
| 626 } |
443 } else if (strcmp(cmd, "flags") == 0) { | 627 } else if (strcmp(cmd, "flags") == 0) { |
444 OS::Print("APSR: "); | 628 OS::Print("APSR: "); |
445 OS::Print("N flag: %d; ", sim_->n_flag_); | 629 OS::Print("N flag: %d; ", sim_->n_flag_); |
446 OS::Print("Z flag: %d; ", sim_->z_flag_); | 630 OS::Print("Z flag: %d; ", sim_->z_flag_); |
447 OS::Print("C flag: %d; ", sim_->c_flag_); | 631 OS::Print("C flag: %d; ", sim_->c_flag_); |
448 OS::Print("V flag: %d\n", sim_->v_flag_); | 632 OS::Print("V flag: %d\n", sim_->v_flag_); |
449 } else if (strcmp(cmd, "gdb") == 0) { | 633 } else if (strcmp(cmd, "unstop") == 0) { |
450 OS::Print("relinquishing control to gdb\n"); | 634 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; |
451 OS::DebugBreak(); | 635 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); |
452 OS::Print("regaining control from gdb\n"); | 636 if (stop_instr->IsExceptionGenOp()) { |
| 637 stop_instr->SetInstructionBits(Instr::kNopInstruction); |
| 638 } else { |
| 639 OS::Print("Not at debugger stop.\n"); |
| 640 } |
| 641 } else if (strcmp(cmd, "trace") == 0) { |
| 642 FLAG_trace_sim = !FLAG_trace_sim; |
| 643 OS::Print("execution tracing %s\n", FLAG_trace_sim ? "on" : "off"); |
| 644 } else if (strcmp(cmd, "bt") == 0) { |
| 645 PrintBacktrace(); |
453 } else { | 646 } else { |
454 OS::Print("Unknown command: %s\n", cmd); | 647 OS::Print("Unknown command: %s\n", cmd); |
455 } | 648 } |
456 } | 649 } |
457 delete[] line; | 650 delete[] line; |
458 } | 651 } |
459 | 652 |
460 // TODO(zra): Add all the breakpoints back to stop execution and enter the | 653 // Add all the breakpoints back to stop execution and enter the debugger |
461 // debugger shell when hit. | 654 // shell when hit. |
462 // RedoBreakpoints(); | 655 RedoBreakpoints(); |
463 | 656 |
464 #undef COMMAND_SIZE | 657 #undef COMMAND_SIZE |
465 #undef ARG_SIZE | 658 #undef ARG_SIZE |
466 | 659 |
467 #undef STR | 660 #undef STR |
468 #undef XSTR | 661 #undef XSTR |
469 } | 662 } |
470 | 663 |
471 | 664 |
472 char* SimulatorDebugger::ReadLine(const char* prompt) { | 665 char* SimulatorDebugger::ReadLine(const char* prompt) { |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
799 | 992 |
800 | 993 |
801 int64_t Simulator::get_last_pc() const { | 994 int64_t Simulator::get_last_pc() const { |
802 return last_pc_; | 995 return last_pc_; |
803 } | 996 } |
804 | 997 |
805 | 998 |
806 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) { | 999 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) { |
807 uword fault_pc = get_pc(); | 1000 uword fault_pc = get_pc(); |
808 uword last_pc = get_last_pc(); | 1001 uword last_pc = get_last_pc(); |
809 // TODO(zra): drop into debugger. | |
810 char buffer[128]; | 1002 char buffer[128]; |
811 snprintf(buffer, sizeof(buffer), | 1003 snprintf(buffer, sizeof(buffer), |
812 "illegal memory access at 0x%" Px ", pc=0x%" Px ", last_pc=0x%" Px"\n", | 1004 "illegal memory access at 0x%" Px ", pc=0x%" Px ", last_pc=0x%" Px"\n", |
813 addr, fault_pc, last_pc); | 1005 addr, fault_pc, last_pc); |
814 SimulatorDebugger dbg(this); | 1006 SimulatorDebugger dbg(this); |
815 dbg.Stop(instr, buffer); | 1007 dbg.Stop(instr, buffer); |
816 // The debugger will return control in non-interactive mode. | 1008 // The debugger will return control in non-interactive mode. |
817 FATAL("Cannot continue execution after illegal memory access."); | 1009 FATAL("Cannot continue execution after illegal memory access."); |
818 } | 1010 } |
819 | 1011 |
(...skipping 651 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1471 | 1663 |
1472 | 1664 |
1473 void Simulator::DecodeExceptionGen(Instr* instr) { | 1665 void Simulator::DecodeExceptionGen(Instr* instr) { |
1474 if ((instr->Bits(0, 2) == 1) && (instr->Bits(2, 3) == 0) && | 1666 if ((instr->Bits(0, 2) == 1) && (instr->Bits(2, 3) == 0) && |
1475 (instr->Bits(21, 3) == 0)) { | 1667 (instr->Bits(21, 3) == 0)) { |
1476 // Format(instr, "svc 'imm16"); | 1668 // Format(instr, "svc 'imm16"); |
1477 UnimplementedInstruction(instr); | 1669 UnimplementedInstruction(instr); |
1478 } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) && | 1670 } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) && |
1479 (instr->Bits(21, 3) == 1)) { | 1671 (instr->Bits(21, 3) == 1)) { |
1480 // Format(instr, "brk 'imm16"); | 1672 // Format(instr, "brk 'imm16"); |
1481 UnimplementedInstruction(instr); | 1673 SimulatorDebugger dbg(this); |
| 1674 uint16_t imm = static_cast<uint16_t>(instr->Imm16Field()); |
| 1675 char buffer[32]; |
| 1676 snprintf(buffer, sizeof(buffer), "brk #0x%x", imm); |
| 1677 set_pc(get_pc() + Instr::kInstrSize); |
| 1678 dbg.Stop(instr, buffer); |
1482 } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) && | 1679 } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) && |
1483 (instr->Bits(21, 3) == 2)) { | 1680 (instr->Bits(21, 3) == 2)) { |
1484 // Format(instr, "hlt 'imm16"); | 1681 // Format(instr, "hlt 'imm16"); |
1485 uint16_t imm = static_cast<uint16_t>(instr->Imm16Field()); | 1682 uint16_t imm = static_cast<uint16_t>(instr->Imm16Field()); |
1486 if (imm == kImmExceptionIsDebug) { | 1683 if (imm == Instr::kSimulatorMessageCode) { |
1487 SimulatorDebugger dbg(this); | 1684 SimulatorDebugger dbg(this); |
1488 const char* message = *reinterpret_cast<const char**>( | 1685 const char* message = *reinterpret_cast<const char**>( |
1489 reinterpret_cast<intptr_t>(instr) - 2 * Instr::kInstrSize); | 1686 reinterpret_cast<intptr_t>(instr) - 2 * Instr::kInstrSize); |
1490 set_pc(get_pc() + Instr::kInstrSize); | 1687 set_pc(get_pc() + Instr::kInstrSize); |
1491 dbg.Stop(instr, message); | 1688 dbg.Stop(instr, message); |
1492 } else if (imm == kImmExceptionIsPrintf) { | 1689 } else if (imm == Instr::kSimulatorBreakCode) { |
1493 const char* message = *reinterpret_cast<const char**>( | 1690 SimulatorDebugger dbg(this); |
1494 reinterpret_cast<intptr_t>(instr) - 2 * Instr::kInstrSize); | 1691 dbg.Stop(instr, "breakpoint"); |
1495 OS::Print("Simulator hit: %s", message); | 1692 } else if (imm == Instr::kSimulatorRedirectCode) { |
1496 } else if (imm == kImmExceptionIsRedirectedCall) { | |
1497 DoRedirectedCall(instr); | 1693 DoRedirectedCall(instr); |
1498 } else { | 1694 } else { |
1499 UnimplementedInstruction(instr); | 1695 UnimplementedInstruction(instr); |
1500 } | 1696 } |
| 1697 } else { |
| 1698 UnimplementedInstruction(instr); |
1501 } | 1699 } |
1502 } | 1700 } |
1503 | 1701 |
1504 | 1702 |
1505 void Simulator::DecodeSystem(Instr* instr) { | 1703 void Simulator::DecodeSystem(Instr* instr) { |
1506 if ((instr->Bits(0, 8) == 0x1f) && (instr->Bits(12, 4) == 2) && | 1704 if ((instr->Bits(0, 8) == 0x1f) && (instr->Bits(12, 4) == 2) && |
1507 (instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) && | 1705 (instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) && |
1508 (instr->Bit(21) == 0)) { | 1706 (instr->Bit(21) == 0)) { |
1509 if (instr->Bits(8, 4) == 0) { | 1707 if (instr->Bits(8, 4) == 0) { |
1510 // Format(instr, "nop"); | 1708 // Format(instr, "nop"); |
(...skipping 1604 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3115 icount_++; | 3313 icount_++; |
3116 if (IsIllegalAddress(program_counter)) { | 3314 if (IsIllegalAddress(program_counter)) { |
3117 HandleIllegalAccess(program_counter, instr); | 3315 HandleIllegalAccess(program_counter, instr); |
3118 } else { | 3316 } else { |
3119 InstructionDecode(instr); | 3317 InstructionDecode(instr); |
3120 } | 3318 } |
3121 program_counter = get_pc(); | 3319 program_counter = get_pc(); |
3122 } | 3320 } |
3123 } else { | 3321 } else { |
3124 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when | 3322 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when |
3125 // we reach the particular instruction count. | 3323 // we reach the particular instruction count or address. |
3126 while (program_counter != kEndSimulatingPC) { | 3324 while (program_counter != kEndSimulatingPC) { |
3127 Instr* instr = reinterpret_cast<Instr*>(program_counter); | 3325 Instr* instr = reinterpret_cast<Instr*>(program_counter); |
3128 icount_++; | 3326 icount_++; |
3129 if (icount_ == FLAG_stop_sim_at) { | 3327 if (static_cast<intptr_t>(icount_) == FLAG_stop_sim_at) { |
3130 // TODO(zra): Add a debugger. | 3328 SimulatorDebugger dbg(this); |
3131 UNIMPLEMENTED(); | 3329 dbg.Stop(instr, "Instruction count reached"); |
| 3330 } else if (reinterpret_cast<intptr_t>(instr) == FLAG_stop_sim_at) { |
| 3331 SimulatorDebugger dbg(this); |
| 3332 dbg.Stop(instr, "Instruction address reached"); |
3132 } else if (IsIllegalAddress(program_counter)) { | 3333 } else if (IsIllegalAddress(program_counter)) { |
3133 HandleIllegalAccess(program_counter, instr); | 3334 HandleIllegalAccess(program_counter, instr); |
3134 } else { | 3335 } else { |
3135 InstructionDecode(instr); | 3336 InstructionDecode(instr); |
3136 } | 3337 } |
3137 program_counter = get_pc(); | 3338 program_counter = get_pc(); |
3138 } | 3339 } |
3139 } | 3340 } |
3140 } | 3341 } |
3141 | 3342 |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3269 set_register(NULL, kExceptionObjectReg, bit_cast<int64_t>(raw_exception)); | 3470 set_register(NULL, kExceptionObjectReg, bit_cast<int64_t>(raw_exception)); |
3270 set_register(NULL, kStackTraceObjectReg, bit_cast<int64_t>(raw_stacktrace)); | 3471 set_register(NULL, kStackTraceObjectReg, bit_cast<int64_t>(raw_stacktrace)); |
3271 buf->Longjmp(); | 3472 buf->Longjmp(); |
3272 } | 3473 } |
3273 | 3474 |
3274 } // namespace dart | 3475 } // namespace dart |
3275 | 3476 |
3276 #endif // !defined(HOST_ARCH_ARM64) | 3477 #endif // !defined(HOST_ARCH_ARM64) |
3277 | 3478 |
3278 #endif // defined TARGET_ARCH_ARM64 | 3479 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |