| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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_ARM) | 9 #if defined(TARGET_ARCH_ARM) |
| 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_ARM) | 12 #if !defined(HOST_ARCH_ARM) |
| 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_arm.h" | 17 #include "vm/constants_arm.h" |
| 18 #include "vm/cpu.h" | 18 #include "vm/cpu.h" |
| 19 #include "vm/disassembler.h" | 19 #include "vm/disassembler.h" |
| 20 #include "vm/lockers.h" | 20 #include "vm/lockers.h" |
| 21 #include "vm/native_arguments.h" | 21 #include "vm/native_arguments.h" |
| 22 #include "vm/stack_frame.h" | 22 #include "vm/stack_frame.h" |
| 23 #include "vm/os_thread.h" | 23 #include "vm/os_thread.h" |
| 24 | 24 |
| 25 namespace dart { | 25 namespace dart { |
| 26 | 26 |
| 27 DEFINE_FLAG(int, trace_sim_after, -1, | 27 DEFINE_FLAG(uint64_t, trace_sim_after, ULLONG_MAX, |
| 28 "Trace simulator execution after instruction count reached."); | 28 "Trace simulator execution after instruction count reached."); |
| 29 DEFINE_FLAG(int, stop_sim_at, -1, | 29 DEFINE_FLAG(uint64_t, stop_sim_at, ULLONG_MAX, |
| 30 "Instruction address or instruction count to stop simulator at."); | 30 "Instruction address or instruction count to stop simulator at."); |
| 31 | 31 |
| 32 | 32 |
| 33 // This macro provides a platform independent use of sscanf. The reason for | 33 // This macro provides a platform independent use of sscanf. The reason for |
| 34 // SScanF not being implemented in a platform independent way through | 34 // SScanF not being implemented in a platform independent way through |
| 35 // OS in the same way as SNPrint is that the Windows C Run-Time | 35 // OS in the same way as SNPrint is that the Windows C Run-Time |
| 36 // Library does not provide vsscanf. | 36 // Library does not provide vsscanf. |
| 37 #define SScanF sscanf // NOLINT | 37 #define SScanF sscanf // NOLINT |
| 38 | 38 |
| 39 | 39 |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 if (desc[0] == '*') { | 193 if (desc[0] == '*') { |
| 194 uint32_t addr; | 194 uint32_t addr; |
| 195 if (GetValue(desc + 1, &addr)) { | 195 if (GetValue(desc + 1, &addr)) { |
| 196 if (Simulator::IsIllegalAddress(addr)) { | 196 if (Simulator::IsIllegalAddress(addr)) { |
| 197 return false; | 197 return false; |
| 198 } | 198 } |
| 199 *value = *(reinterpret_cast<uint32_t*>(addr)); | 199 *value = *(reinterpret_cast<uint32_t*>(addr)); |
| 200 return true; | 200 return true; |
| 201 } | 201 } |
| 202 } | 202 } |
| 203 if (strcmp("icount", desc) == 0) { | |
| 204 *value = sim_->get_icount(); | |
| 205 return true; | |
| 206 } | |
| 207 bool retval = SScanF(desc, "0x%x", value) == 1; | 203 bool retval = SScanF(desc, "0x%x", value) == 1; |
| 208 if (!retval) { | 204 if (!retval) { |
| 209 retval = SScanF(desc, "%x", value) == 1; | 205 retval = SScanF(desc, "%x", value) == 1; |
| 210 } | 206 } |
| 211 return retval; | 207 return retval; |
| 212 } | 208 } |
| 213 | 209 |
| 214 | 210 |
| 215 bool SimulatorDebugger::GetFValue(char* desc, float* value) { | 211 bool SimulatorDebugger::GetFValue(char* desc, float* value) { |
| 216 SRegister sreg = LookupSRegisterByName(desc); | 212 SRegister sreg = LookupSRegisterByName(desc); |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { | 451 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { |
| 456 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 452 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 457 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { | 453 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { |
| 458 // Execute the one instruction we broke at with breakpoints disabled. | 454 // Execute the one instruction we broke at with breakpoints disabled. |
| 459 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 455 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 460 // Leave the debugger shell. | 456 // Leave the debugger shell. |
| 461 done = true; | 457 done = true; |
| 462 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { | 458 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { |
| 463 if (args == 2) { | 459 if (args == 2) { |
| 464 uint32_t value; | 460 uint32_t value; |
| 465 if (GetValue(arg1, &value)) { | 461 if (strcmp(arg1, "icount") == 0) { |
| 462 const uint64_t icount = sim_->get_icount(); |
| 463 OS::Print("icount: %"Pu64" 0x%"Px64"\n", icount, icount); |
| 464 } else if (GetValue(arg1, &value)) { |
| 466 OS::Print("%s: %u 0x%x\n", arg1, value, value); | 465 OS::Print("%s: %u 0x%x\n", arg1, value, value); |
| 467 } else { | 466 } else { |
| 468 OS::Print("%s unrecognized\n", arg1); | 467 OS::Print("%s unrecognized\n", arg1); |
| 469 } | 468 } |
| 470 } else { | 469 } else { |
| 471 OS::Print("print <reg or value or *addr>\n"); | 470 OS::Print("print <reg or icount or value or *addr>\n"); |
| 472 } | 471 } |
| 473 } else if ((strcmp(cmd, "ps") == 0) || | 472 } else if ((strcmp(cmd, "ps") == 0) || |
| 474 (strcmp(cmd, "printsingle") == 0)) { | 473 (strcmp(cmd, "printsingle") == 0)) { |
| 475 if (args == 2) { | 474 if (args == 2) { |
| 476 float fvalue; | 475 float fvalue; |
| 477 if (GetFValue(arg1, &fvalue)) { | 476 if (GetFValue(arg1, &fvalue)) { |
| 478 uint32_t value = bit_cast<uint32_t, float>(fvalue); | 477 uint32_t value = bit_cast<uint32_t, float>(fvalue); |
| 479 OS::Print("%s: 0%u 0x%x %.8g\n", arg1, value, value, fvalue); | 478 OS::Print("%s: 0%u 0x%x %.8g\n", arg1, value, value, fvalue); |
| 480 } else { | 479 } else { |
| 481 OS::Print("%s unrecognized\n", arg1); | 480 OS::Print("%s unrecognized\n", arg1); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 OS::Print("V flag: %d\n", sim_->fp_v_flag_); | 587 OS::Print("V flag: %d\n", sim_->fp_v_flag_); |
| 589 } else if (strcmp(cmd, "unstop") == 0) { | 588 } else if (strcmp(cmd, "unstop") == 0) { |
| 590 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; | 589 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; |
| 591 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); | 590 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); |
| 592 if (stop_instr->IsSvc() || stop_instr->IsBkpt()) { | 591 if (stop_instr->IsSvc() || stop_instr->IsBkpt()) { |
| 593 stop_instr->SetInstructionBits(Instr::kNopInstruction); | 592 stop_instr->SetInstructionBits(Instr::kNopInstruction); |
| 594 } else { | 593 } else { |
| 595 OS::Print("Not at debugger stop.\n"); | 594 OS::Print("Not at debugger stop.\n"); |
| 596 } | 595 } |
| 597 } else if (strcmp(cmd, "trace") == 0) { | 596 } else if (strcmp(cmd, "trace") == 0) { |
| 598 if (FLAG_trace_sim_after == -1) { | 597 if (FLAG_trace_sim_after == ULLONG_MAX) { |
| 599 FLAG_trace_sim_after = sim_->get_icount(); | 598 FLAG_trace_sim_after = sim_->get_icount(); |
| 600 OS::Print("execution tracing on\n"); | 599 OS::Print("execution tracing on\n"); |
| 601 } else { | 600 } else { |
| 602 FLAG_trace_sim_after = -1; | 601 FLAG_trace_sim_after = ULLONG_MAX; |
| 603 OS::Print("execution tracing off\n"); | 602 OS::Print("execution tracing off\n"); |
| 604 } | 603 } |
| 605 } else if (strcmp(cmd, "bt") == 0) { | 604 } else if (strcmp(cmd, "bt") == 0) { |
| 606 PrintBacktrace(); | 605 PrintBacktrace(); |
| 607 } else { | 606 } else { |
| 608 OS::Print("Unknown command: %s\n", cmd); | 607 OS::Print("Unknown command: %s\n", cmd); |
| 609 } | 608 } |
| 610 } | 609 } |
| 611 delete[] line; | 610 delete[] line; |
| 612 } | 611 } |
| (...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1179 // validity. | 1178 // validity. |
| 1180 uword Simulator::StackTop() const { | 1179 uword Simulator::StackTop() const { |
| 1181 // To be safe in potential stack underflows we leave some buffer above and | 1180 // To be safe in potential stack underflows we leave some buffer above and |
| 1182 // set the stack top. | 1181 // set the stack top. |
| 1183 return reinterpret_cast<uword>(stack_) + | 1182 return reinterpret_cast<uword>(stack_) + |
| 1184 (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer); | 1183 (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer); |
| 1185 } | 1184 } |
| 1186 | 1185 |
| 1187 | 1186 |
| 1188 bool Simulator::IsTracingExecution() const { | 1187 bool Simulator::IsTracingExecution() const { |
| 1189 // Integer flag values are signed, so we must cast to unsigned. | 1188 return icount_ > FLAG_trace_sim_after; |
| 1190 // The default of -1 hence becomes the maximum unsigned value. | |
| 1191 return (static_cast<uintptr_t>(icount_) > | |
| 1192 static_cast<uintptr_t>(FLAG_trace_sim_after)); | |
| 1193 } | 1189 } |
| 1194 | 1190 |
| 1195 | 1191 |
| 1196 // Unsupported instructions use Format to print an error and stop execution. | 1192 // Unsupported instructions use Format to print an error and stop execution. |
| 1197 void Simulator::Format(Instr* instr, const char* format) { | 1193 void Simulator::Format(Instr* instr, const char* format) { |
| 1198 OS::Print("Simulator found unsupported instruction:\n 0x%p: %s\n", | 1194 OS::Print("Simulator found unsupported instruction:\n 0x%p: %s\n", |
| 1199 instr, | 1195 instr, |
| 1200 format); | 1196 format); |
| 1201 UNIMPLEMENTED(); | 1197 UNIMPLEMENTED(); |
| 1202 } | 1198 } |
| (...skipping 2381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3584 UnimplementedInstruction(instr); | 3580 UnimplementedInstruction(instr); |
| 3585 } | 3581 } |
| 3586 } | 3582 } |
| 3587 } | 3583 } |
| 3588 | 3584 |
| 3589 | 3585 |
| 3590 // Executes the current instruction. | 3586 // Executes the current instruction. |
| 3591 void Simulator::InstructionDecode(Instr* instr) { | 3587 void Simulator::InstructionDecode(Instr* instr) { |
| 3592 pc_modified_ = false; | 3588 pc_modified_ = false; |
| 3593 if (IsTracingExecution()) { | 3589 if (IsTracingExecution()) { |
| 3594 OS::Print("%" Pd " ", icount_); | 3590 OS::Print("%"Pu64, icount_); |
| 3595 const uword start = reinterpret_cast<uword>(instr); | 3591 const uword start = reinterpret_cast<uword>(instr); |
| 3596 const uword end = start + Instr::kInstrSize; | 3592 const uword end = start + Instr::kInstrSize; |
| 3597 Disassembler::Disassemble(start, end); | 3593 Disassembler::Disassemble(start, end); |
| 3598 } | 3594 } |
| 3599 if (instr->ConditionField() == kSpecialCondition) { | 3595 if (instr->ConditionField() == kSpecialCondition) { |
| 3600 if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) { | 3596 if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) { |
| 3601 // Format(instr, "clrex"); | 3597 // Format(instr, "clrex"); |
| 3602 ClearExclusive(); | 3598 ClearExclusive(); |
| 3603 } else { | 3599 } else { |
| 3604 if (instr->IsSIMDDataProcessing()) { | 3600 if (instr->IsSIMDDataProcessing()) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3649 set_register(PC, reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | 3645 set_register(PC, reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
| 3650 } | 3646 } |
| 3651 } | 3647 } |
| 3652 | 3648 |
| 3653 | 3649 |
| 3654 void Simulator::Execute() { | 3650 void Simulator::Execute() { |
| 3655 // Get the PC to simulate. Cannot use the accessor here as we need the | 3651 // Get the PC to simulate. Cannot use the accessor here as we need the |
| 3656 // raw PC value and not the one used as input to arithmetic instructions. | 3652 // raw PC value and not the one used as input to arithmetic instructions. |
| 3657 uword program_counter = get_pc(); | 3653 uword program_counter = get_pc(); |
| 3658 | 3654 |
| 3659 if (FLAG_stop_sim_at == 0) { | 3655 if (FLAG_stop_sim_at == ULLONG_MAX) { |
| 3660 // Fast version of the dispatch loop without checking whether the simulator | 3656 // Fast version of the dispatch loop without checking whether the simulator |
| 3661 // should be stopping at a particular executed instruction. | 3657 // should be stopping at a particular executed instruction. |
| 3662 while (program_counter != kEndSimulatingPC) { | 3658 while (program_counter != kEndSimulatingPC) { |
| 3663 Instr* instr = reinterpret_cast<Instr*>(program_counter); | 3659 Instr* instr = reinterpret_cast<Instr*>(program_counter); |
| 3664 icount_++; | 3660 icount_++; |
| 3665 if (IsIllegalAddress(program_counter)) { | 3661 if (IsIllegalAddress(program_counter)) { |
| 3666 HandleIllegalAccess(program_counter, instr); | 3662 HandleIllegalAccess(program_counter, instr); |
| 3667 } else { | 3663 } else { |
| 3668 InstructionDecode(instr); | 3664 InstructionDecode(instr); |
| 3669 } | 3665 } |
| 3670 program_counter = get_pc(); | 3666 program_counter = get_pc(); |
| 3671 } | 3667 } |
| 3672 } else { | 3668 } else { |
| 3673 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when | 3669 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when |
| 3674 // we reach the particular instruction count or address. | 3670 // we reach the particular instruction count or address. |
| 3675 while (program_counter != kEndSimulatingPC) { | 3671 while (program_counter != kEndSimulatingPC) { |
| 3676 Instr* instr = reinterpret_cast<Instr*>(program_counter); | 3672 Instr* instr = reinterpret_cast<Instr*>(program_counter); |
| 3677 icount_++; | 3673 icount_++; |
| 3678 if (icount_ == FLAG_stop_sim_at) { | 3674 if (icount_ == FLAG_stop_sim_at) { |
| 3679 SimulatorDebugger dbg(this); | 3675 SimulatorDebugger dbg(this); |
| 3680 dbg.Stop(instr, "Instruction count reached"); | 3676 dbg.Stop(instr, "Instruction count reached"); |
| 3681 } else if (reinterpret_cast<intptr_t>(instr) == FLAG_stop_sim_at) { | 3677 } else if (reinterpret_cast<uint64_t>(instr) == FLAG_stop_sim_at) { |
| 3682 SimulatorDebugger dbg(this); | 3678 SimulatorDebugger dbg(this); |
| 3683 dbg.Stop(instr, "Instruction address reached"); | 3679 dbg.Stop(instr, "Instruction address reached"); |
| 3684 } else if (IsIllegalAddress(program_counter)) { | 3680 } else if (IsIllegalAddress(program_counter)) { |
| 3685 HandleIllegalAccess(program_counter, instr); | 3681 HandleIllegalAccess(program_counter, instr); |
| 3686 } else { | 3682 } else { |
| 3687 InstructionDecode(instr); | 3683 InstructionDecode(instr); |
| 3688 } | 3684 } |
| 3689 program_counter = get_pc(); | 3685 program_counter = get_pc(); |
| 3690 } | 3686 } |
| 3691 } | 3687 } |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3882 set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception)); | 3878 set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception)); |
| 3883 set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace)); | 3879 set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace)); |
| 3884 buf->Longjmp(); | 3880 buf->Longjmp(); |
| 3885 } | 3881 } |
| 3886 | 3882 |
| 3887 } // namespace dart | 3883 } // namespace dart |
| 3888 | 3884 |
| 3889 #endif // !defined(HOST_ARCH_ARM) | 3885 #endif // !defined(HOST_ARCH_ARM) |
| 3890 | 3886 |
| 3891 #endif // defined TARGET_ARCH_ARM | 3887 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |