| 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> // NOLINT | 5 #include <setjmp.h> // NOLINT |
| 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/disassembler.h" | 18 #include "vm/disassembler.h" |
| 19 #include "vm/lockers.h" | 19 #include "vm/lockers.h" |
| 20 #include "vm/native_arguments.h" | 20 #include "vm/native_arguments.h" |
| 21 #include "vm/stack_frame.h" | 21 #include "vm/stack_frame.h" |
| 22 #include "vm/os_thread.h" | 22 #include "vm/os_thread.h" |
| 23 | 23 |
| 24 namespace dart { | 24 namespace dart { |
| 25 | 25 |
| 26 DEFINE_FLAG(int, trace_sim_after, -1, | 26 DEFINE_FLAG(uint64_t, trace_sim_after, ULLONG_MAX, |
| 27 "Trace simulator execution after instruction count reached."); | 27 "Trace simulator execution after instruction count reached."); |
| 28 DEFINE_FLAG(int, stop_sim_at, -1, | 28 DEFINE_FLAG(uint64_t, stop_sim_at, ULLONG_MAX, |
| 29 "Instruction address or instruction count to stop simulator at."); | 29 "Instruction address or instruction count to stop simulator at."); |
| 30 | 30 |
| 31 | 31 |
| 32 // This macro provides a platform independent use of sscanf. The reason for | 32 // This macro provides a platform independent use of sscanf. The reason for |
| 33 // SScanF not being implemented in a platform independent way through | 33 // SScanF not being implemented in a platform independent way through |
| 34 // OS in the same way as SNPrint is that the Windows C Run-Time | 34 // OS in the same way as SNPrint is that the Windows C Run-Time |
| 35 // Library does not provide vsscanf. | 35 // Library does not provide vsscanf. |
| 36 #define SScanF sscanf // NOLINT | 36 #define SScanF sscanf // NOLINT |
| 37 | 37 |
| 38 | 38 |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 return false; | 191 return false; |
| 192 } | 192 } |
| 193 *value = *(reinterpret_cast<int64_t*>(addr)); | 193 *value = *(reinterpret_cast<int64_t*>(addr)); |
| 194 return true; | 194 return true; |
| 195 } | 195 } |
| 196 } | 196 } |
| 197 if (strcmp("pc", desc) == 0) { | 197 if (strcmp("pc", desc) == 0) { |
| 198 *value = sim_->get_pc(); | 198 *value = sim_->get_pc(); |
| 199 return true; | 199 return true; |
| 200 } | 200 } |
| 201 if (strcmp("icount", desc) == 0) { | |
| 202 *value = sim_->get_icount(); | |
| 203 return true; | |
| 204 } | |
| 205 bool retval = SScanF(desc, "0x%"Px64, value) == 1; | 201 bool retval = SScanF(desc, "0x%"Px64, value) == 1; |
| 206 if (!retval) { | 202 if (!retval) { |
| 207 retval = SScanF(desc, "%"Px64, value) == 1; | 203 retval = SScanF(desc, "%"Px64, value) == 1; |
| 208 } | 204 } |
| 209 return retval; | 205 return retval; |
| 210 } | 206 } |
| 211 | 207 |
| 212 | 208 |
| 213 bool SimulatorDebugger::GetSValue(char* desc, uint32_t* value) { | 209 bool SimulatorDebugger::GetSValue(char* desc, uint32_t* value) { |
| 214 VRegister vreg = LookupVRegisterByName(desc); | 210 VRegister vreg = LookupVRegisterByName(desc); |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { | 470 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { |
| 475 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 471 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 476 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { | 472 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { |
| 477 // Execute the one instruction we broke at with breakpoints disabled. | 473 // Execute the one instruction we broke at with breakpoints disabled. |
| 478 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 474 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 479 // Leave the debugger shell. | 475 // Leave the debugger shell. |
| 480 done = true; | 476 done = true; |
| 481 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { | 477 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { |
| 482 if (args == 2) { | 478 if (args == 2) { |
| 483 uint64_t value; | 479 uint64_t value; |
| 484 if (GetValue(arg1, &value)) { | 480 if (strcmp(arg1, "icount") == 0) { |
| 481 value = sim_->get_icount(); |
| 482 OS::Print("icount: %"Pu64" 0x%"Px64"\n", value, value); |
| 483 } else if (GetValue(arg1, &value)) { |
| 485 OS::Print("%s: %"Pu64" 0x%"Px64"\n", arg1, value, value); | 484 OS::Print("%s: %"Pu64" 0x%"Px64"\n", arg1, value, value); |
| 486 } else { | 485 } else { |
| 487 OS::Print("%s unrecognized\n", arg1); | 486 OS::Print("%s unrecognized\n", arg1); |
| 488 } | 487 } |
| 489 } else { | 488 } else { |
| 490 OS::Print("print <reg or value or *addr>\n"); | 489 OS::Print("print <reg or icount or value or *addr>\n"); |
| 491 } | 490 } |
| 492 } else if ((strcmp(cmd, "pf") == 0) || | 491 } else if ((strcmp(cmd, "pf") == 0) || |
| 493 (strcmp(cmd, "printfloat") == 0)) { | 492 (strcmp(cmd, "printfloat") == 0)) { |
| 494 if (args == 2) { | 493 if (args == 2) { |
| 495 uint32_t value; | 494 uint32_t value; |
| 496 if (GetSValue(arg1, &value)) { | 495 if (GetSValue(arg1, &value)) { |
| 497 float svalue = bit_cast<float, uint32_t>(value); | 496 float svalue = bit_cast<float, uint32_t>(value); |
| 498 OS::Print("%s: %d 0x%x %.8g\n", | 497 OS::Print("%s: %d 0x%x %.8g\n", |
| 499 arg1, value, value, svalue); | 498 arg1, value, value, svalue); |
| 500 } else { | 499 } else { |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 634 OS::Print("V flag: %d\n", sim_->v_flag_); | 633 OS::Print("V flag: %d\n", sim_->v_flag_); |
| 635 } else if (strcmp(cmd, "unstop") == 0) { | 634 } else if (strcmp(cmd, "unstop") == 0) { |
| 636 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; | 635 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; |
| 637 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); | 636 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); |
| 638 if (stop_instr->IsExceptionGenOp()) { | 637 if (stop_instr->IsExceptionGenOp()) { |
| 639 stop_instr->SetInstructionBits(Instr::kNopInstruction); | 638 stop_instr->SetInstructionBits(Instr::kNopInstruction); |
| 640 } else { | 639 } else { |
| 641 OS::Print("Not at debugger stop.\n"); | 640 OS::Print("Not at debugger stop.\n"); |
| 642 } | 641 } |
| 643 } else if (strcmp(cmd, "trace") == 0) { | 642 } else if (strcmp(cmd, "trace") == 0) { |
| 644 if (FLAG_trace_sim_after == -1) { | 643 if (FLAG_trace_sim_after == ULLONG_MAX) { |
| 645 FLAG_trace_sim_after = sim_->get_icount(); | 644 FLAG_trace_sim_after = sim_->get_icount(); |
| 646 OS::Print("execution tracing on\n"); | 645 OS::Print("execution tracing on\n"); |
| 647 } else { | 646 } else { |
| 648 FLAG_trace_sim_after = -1; | 647 FLAG_trace_sim_after = ULLONG_MAX; |
| 649 OS::Print("execution tracing off\n"); | 648 OS::Print("execution tracing off\n"); |
| 650 } | 649 } |
| 651 } else if (strcmp(cmd, "bt") == 0) { | 650 } else if (strcmp(cmd, "bt") == 0) { |
| 652 PrintBacktrace(); | 651 PrintBacktrace(); |
| 653 } else { | 652 } else { |
| 654 OS::Print("Unknown command: %s\n", cmd); | 653 OS::Print("Unknown command: %s\n", cmd); |
| 655 } | 654 } |
| 656 } | 655 } |
| 657 delete[] line; | 656 delete[] line; |
| 658 } | 657 } |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1057 // validity. | 1056 // validity. |
| 1058 uword Simulator::StackTop() const { | 1057 uword Simulator::StackTop() const { |
| 1059 // To be safe in potential stack underflows we leave some buffer above and | 1058 // To be safe in potential stack underflows we leave some buffer above and |
| 1060 // set the stack top. | 1059 // set the stack top. |
| 1061 return reinterpret_cast<uword>(stack_) + | 1060 return reinterpret_cast<uword>(stack_) + |
| 1062 (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer); | 1061 (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer); |
| 1063 } | 1062 } |
| 1064 | 1063 |
| 1065 | 1064 |
| 1066 bool Simulator::IsTracingExecution() const { | 1065 bool Simulator::IsTracingExecution() const { |
| 1067 // Integer flag values are signed, so we must cast to unsigned. | 1066 return icount_ > FLAG_trace_sim_after; |
| 1068 // The default of -1 hence becomes the maximum unsigned value. | |
| 1069 return (static_cast<uintptr_t>(icount_) > | |
| 1070 static_cast<uintptr_t>(FLAG_trace_sim_after)); | |
| 1071 } | 1067 } |
| 1072 | 1068 |
| 1073 | 1069 |
| 1074 intptr_t Simulator::ReadX(uword addr, Instr* instr) { | 1070 intptr_t Simulator::ReadX(uword addr, Instr* instr) { |
| 1075 if ((addr & 7) == 0) { | 1071 if ((addr & 7) == 0) { |
| 1076 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | 1072 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
| 1077 return *ptr; | 1073 return *ptr; |
| 1078 } | 1074 } |
| 1079 UnalignedAccess("read", addr, instr); | 1075 UnalignedAccess("read", addr, instr); |
| 1080 return 0; | 1076 return 0; |
| (...skipping 2219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3300 } else { | 3296 } else { |
| 3301 UnimplementedInstruction(instr); | 3297 UnimplementedInstruction(instr); |
| 3302 } | 3298 } |
| 3303 } | 3299 } |
| 3304 | 3300 |
| 3305 | 3301 |
| 3306 // Executes the current instruction. | 3302 // Executes the current instruction. |
| 3307 void Simulator::InstructionDecode(Instr* instr) { | 3303 void Simulator::InstructionDecode(Instr* instr) { |
| 3308 pc_modified_ = false; | 3304 pc_modified_ = false; |
| 3309 if (IsTracingExecution()) { | 3305 if (IsTracingExecution()) { |
| 3310 OS::Print("%" Pd " ", icount_); | 3306 OS::Print("%"Pu64, icount_); |
| 3311 const uword start = reinterpret_cast<uword>(instr); | 3307 const uword start = reinterpret_cast<uword>(instr); |
| 3312 const uword end = start + Instr::kInstrSize; | 3308 const uword end = start + Instr::kInstrSize; |
| 3313 Disassembler::Disassemble(start, end); | 3309 Disassembler::Disassemble(start, end); |
| 3314 } | 3310 } |
| 3315 | 3311 |
| 3316 if (instr->IsDPImmediateOp()) { | 3312 if (instr->IsDPImmediateOp()) { |
| 3317 DecodeDPImmediate(instr); | 3313 DecodeDPImmediate(instr); |
| 3318 } else if (instr->IsCompareBranchOp()) { | 3314 } else if (instr->IsCompareBranchOp()) { |
| 3319 DecodeCompareBranch(instr); | 3315 DecodeCompareBranch(instr); |
| 3320 } else if (instr->IsLoadStoreOp()) { | 3316 } else if (instr->IsLoadStoreOp()) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3333 set_pc(reinterpret_cast<int64_t>(instr) + Instr::kInstrSize); | 3329 set_pc(reinterpret_cast<int64_t>(instr) + Instr::kInstrSize); |
| 3334 } | 3330 } |
| 3335 } | 3331 } |
| 3336 | 3332 |
| 3337 | 3333 |
| 3338 void Simulator::Execute() { | 3334 void Simulator::Execute() { |
| 3339 // Get the PC to simulate. Cannot use the accessor here as we need the | 3335 // Get the PC to simulate. Cannot use the accessor here as we need the |
| 3340 // raw PC value and not the one used as input to arithmetic instructions. | 3336 // raw PC value and not the one used as input to arithmetic instructions. |
| 3341 uword program_counter = get_pc(); | 3337 uword program_counter = get_pc(); |
| 3342 | 3338 |
| 3343 if (FLAG_stop_sim_at == 0) { | 3339 if (FLAG_stop_sim_at == ULLONG_MAX) { |
| 3344 // Fast version of the dispatch loop without checking whether the simulator | 3340 // Fast version of the dispatch loop without checking whether the simulator |
| 3345 // should be stopping at a particular executed instruction. | 3341 // should be stopping at a particular executed instruction. |
| 3346 while (program_counter != kEndSimulatingPC) { | 3342 while (program_counter != kEndSimulatingPC) { |
| 3347 Instr* instr = reinterpret_cast<Instr*>(program_counter); | 3343 Instr* instr = reinterpret_cast<Instr*>(program_counter); |
| 3348 icount_++; | 3344 icount_++; |
| 3349 if (IsIllegalAddress(program_counter)) { | 3345 if (IsIllegalAddress(program_counter)) { |
| 3350 HandleIllegalAccess(program_counter, instr); | 3346 HandleIllegalAccess(program_counter, instr); |
| 3351 } else { | 3347 } else { |
| 3352 InstructionDecode(instr); | 3348 InstructionDecode(instr); |
| 3353 } | 3349 } |
| 3354 program_counter = get_pc(); | 3350 program_counter = get_pc(); |
| 3355 } | 3351 } |
| 3356 } else { | 3352 } else { |
| 3357 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when | 3353 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when |
| 3358 // we reach the particular instruction count or address. | 3354 // we reach the particular instruction count or address. |
| 3359 while (program_counter != kEndSimulatingPC) { | 3355 while (program_counter != kEndSimulatingPC) { |
| 3360 Instr* instr = reinterpret_cast<Instr*>(program_counter); | 3356 Instr* instr = reinterpret_cast<Instr*>(program_counter); |
| 3361 icount_++; | 3357 icount_++; |
| 3362 if (static_cast<intptr_t>(icount_) == FLAG_stop_sim_at) { | 3358 if (icount_ == FLAG_stop_sim_at) { |
| 3363 SimulatorDebugger dbg(this); | 3359 SimulatorDebugger dbg(this); |
| 3364 dbg.Stop(instr, "Instruction count reached"); | 3360 dbg.Stop(instr, "Instruction count reached"); |
| 3365 } else if (reinterpret_cast<intptr_t>(instr) == FLAG_stop_sim_at) { | 3361 } else if (reinterpret_cast<uint64_t>(instr) == FLAG_stop_sim_at) { |
| 3366 SimulatorDebugger dbg(this); | 3362 SimulatorDebugger dbg(this); |
| 3367 dbg.Stop(instr, "Instruction address reached"); | 3363 dbg.Stop(instr, "Instruction address reached"); |
| 3368 } else if (IsIllegalAddress(program_counter)) { | 3364 } else if (IsIllegalAddress(program_counter)) { |
| 3369 HandleIllegalAccess(program_counter, instr); | 3365 HandleIllegalAccess(program_counter, instr); |
| 3370 } else { | 3366 } else { |
| 3371 InstructionDecode(instr); | 3367 InstructionDecode(instr); |
| 3372 } | 3368 } |
| 3373 program_counter = get_pc(); | 3369 program_counter = get_pc(); |
| 3374 } | 3370 } |
| 3375 } | 3371 } |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3505 set_register(NULL, kExceptionObjectReg, bit_cast<int64_t>(raw_exception)); | 3501 set_register(NULL, kExceptionObjectReg, bit_cast<int64_t>(raw_exception)); |
| 3506 set_register(NULL, kStackTraceObjectReg, bit_cast<int64_t>(raw_stacktrace)); | 3502 set_register(NULL, kStackTraceObjectReg, bit_cast<int64_t>(raw_stacktrace)); |
| 3507 buf->Longjmp(); | 3503 buf->Longjmp(); |
| 3508 } | 3504 } |
| 3509 | 3505 |
| 3510 } // namespace dart | 3506 } // namespace dart |
| 3511 | 3507 |
| 3512 #endif // !defined(HOST_ARCH_ARM64) | 3508 #endif // !defined(HOST_ARCH_ARM64) |
| 3513 | 3509 |
| 3514 #endif // defined TARGET_ARCH_ARM64 | 3510 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |