Chromium Code Reviews| 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 <math.h> // for isnan. | 5 #include <math.h> // for isnan. |
| 6 #include <setjmp.h> | 6 #include <setjmp.h> |
| 7 #include <stdlib.h> | 7 #include <stdlib.h> |
| 8 | 8 |
| 9 #include "vm/globals.h" | 9 #include "vm/globals.h" |
| 10 #if defined(TARGET_ARCH_ARM64) | 10 #if defined(TARGET_ARCH_ARM64) |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 DEFINE_FLAG(int, stop_sim_at, 0, "Address to stop simulator at."); | 28 DEFINE_FLAG(int, stop_sim_at, 0, "Address 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 // The SimulatorDebugger class is used by the simulator while debugging | |
| 39 // simulated MIPS code. | |
|
regis
2014/04/16 19:55:43
MIPS -> ARM64
zra
2014/04/16 19:57:42
Done.
| |
| 40 class SimulatorDebugger { | |
| 41 public: | |
| 42 explicit SimulatorDebugger(Simulator* sim); | |
| 43 ~SimulatorDebugger(); | |
| 44 | |
| 45 void Stop(Instr* instr, const char* message); | |
| 46 void Debug(); | |
| 47 char* ReadLine(const char* prompt); | |
| 48 | |
| 49 private: | |
| 50 Simulator* sim_; | |
| 51 | |
| 52 bool GetValue(char* desc, int64_t* value); | |
| 53 // TODO(zra): GetVValue for doubles. | |
| 54 // TODO(zra): Breakpoints. | |
| 55 }; | |
| 56 | |
| 57 | |
| 58 SimulatorDebugger::SimulatorDebugger(Simulator* sim) { | |
| 59 sim_ = sim; | |
| 60 } | |
| 61 | |
| 62 | |
| 63 SimulatorDebugger::~SimulatorDebugger() { | |
| 64 } | |
| 65 | |
| 66 void SimulatorDebugger::Stop(Instr* instr, const char* message) { | |
| 67 OS::Print("Simulator hit %s\n", message); | |
| 68 Debug(); | |
| 69 } | |
| 70 | |
| 71 | |
| 72 static Register LookupCpuRegisterByName(const char* name) { | |
| 73 static const char* kNames[] = { | |
| 74 "r0", "r1", "r2", "r3", | |
| 75 "r4", "r5", "r6", "r7", | |
| 76 "r8", "r9", "r10", "r11", | |
| 77 "r12", "r13", "r14", "r15", | |
| 78 "r16", "r17", "r18", "r19", | |
| 79 "r20", "r21", "r22", "r23", | |
| 80 "r24", "r25", "r26", "r27", | |
| 81 "r28", "r29", "r30", | |
| 82 | |
| 83 "ip0", "ip1", "pp", "ctx", "fp", "lr", "sp", "zr", | |
| 84 }; | |
| 85 static const Register kRegisters[] = { | |
| 86 R0, R1, R2, R3, R4, R5, R6, R7, | |
| 87 R8, R9, R10, R11, R12, R13, R14, R15, | |
| 88 R16, R17, R18, R19, R20, R21, R22, R23, | |
| 89 R24, R25, R26, R27, R28, R29, R30, | |
| 90 | |
| 91 IP0, IP1, PP, CTX, FP, LR, SP, ZR, | |
| 92 }; | |
| 93 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters)); | |
| 94 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) { | |
| 95 if (strcmp(kNames[i], name) == 0) { | |
| 96 return kRegisters[i]; | |
| 97 } | |
| 98 } | |
| 99 return kNoRegister; | |
| 100 } | |
| 101 | |
| 102 | |
| 103 bool SimulatorDebugger::GetValue(char* desc, int64_t* value) { | |
| 104 Register reg = LookupCpuRegisterByName(desc); | |
| 105 if (reg != kNoRegister) { | |
| 106 *value = sim_->get_register(reg); | |
| 107 return true; | |
| 108 } | |
| 109 if (desc[0] == '*') { | |
| 110 int64_t addr; | |
| 111 if (GetValue(desc + 1, &addr)) { | |
| 112 if (Simulator::IsIllegalAddress(addr)) { | |
| 113 return false; | |
| 114 } | |
| 115 *value = *(reinterpret_cast<int64_t*>(addr)); | |
| 116 return true; | |
| 117 } | |
| 118 } | |
| 119 if (strcmp("pc", desc) == 0) { | |
| 120 *value = sim_->get_pc(); | |
| 121 return true; | |
| 122 } | |
| 123 bool retval = SScanF(desc, "0x%"Px64, value) == 1; | |
| 124 if (!retval) { | |
| 125 retval = SScanF(desc, "%"Px64, value) == 1; | |
| 126 } | |
| 127 return retval; | |
| 128 } | |
| 129 | |
| 130 | |
| 131 void SimulatorDebugger::Debug() { | |
| 132 intptr_t last_pc = -1; | |
| 133 bool done = false; | |
| 134 | |
| 135 #define COMMAND_SIZE 63 | |
| 136 #define ARG_SIZE 255 | |
| 137 | |
| 138 #define STR(a) #a | |
| 139 #define XSTR(a) STR(a) | |
| 140 | |
| 141 char cmd[COMMAND_SIZE + 1]; | |
| 142 char arg1[ARG_SIZE + 1]; | |
| 143 char arg2[ARG_SIZE + 1]; | |
| 144 | |
| 145 // make sure to have a proper terminating character if reaching the limit | |
| 146 cmd[COMMAND_SIZE] = 0; | |
| 147 arg1[ARG_SIZE] = 0; | |
| 148 arg2[ARG_SIZE] = 0; | |
| 149 | |
| 150 // TODO(zra): Undo all set breakpoints while running in the debugger shell. | |
| 151 // This will make them invisible to all commands. | |
| 152 // UndoBreakpoints(); | |
| 153 | |
| 154 while (!done) { | |
| 155 if (last_pc != sim_->get_pc()) { | |
| 156 last_pc = sim_->get_pc(); | |
| 157 if (Simulator::IsIllegalAddress(last_pc)) { | |
| 158 OS::Print("pc is out of bounds: 0x%" Px "\n", last_pc); | |
| 159 } else { | |
| 160 Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize); | |
| 161 } | |
| 162 } | |
| 163 char* line = ReadLine("sim> "); | |
| 164 if (line == NULL) { | |
| 165 FATAL("ReadLine failed"); | |
| 166 } else { | |
| 167 // Use sscanf to parse the individual parts of the command line. At the | |
| 168 // moment no command expects more than two parameters. | |
| 169 int args = SScanF(line, | |
| 170 "%" XSTR(COMMAND_SIZE) "s " | |
| 171 "%" XSTR(ARG_SIZE) "s " | |
| 172 "%" XSTR(ARG_SIZE) "s", | |
| 173 cmd, arg1, arg2); | |
| 174 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { | |
| 175 OS::Print("c/cont -- continue execution\n" | |
| 176 "disasm -- disassemble instrs at current pc location\n" | |
| 177 " other variants are:\n" | |
| 178 " disasm <address>\n" | |
| 179 " disasm <address> <number_of_instructions>\n" | |
| 180 " by default 10 instrs are disassembled\n" | |
| 181 "gdb -- transfer control to gdb\n" | |
| 182 "h/help -- print this help string\n" | |
| 183 "p/print <reg or value or *addr> -- print integer value\n" | |
| 184 "po/printobject <*reg or *addr> -- print object\n" | |
| 185 "si/stepi -- single step an instruction\n" | |
| 186 "q/quit -- Quit the debugger and exit the program\n"); | |
| 187 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { | |
| 188 OS::Print("Quitting\n"); | |
| 189 OS::Exit(0); | |
| 190 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { | |
| 191 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | |
| 192 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { | |
| 193 // Execute the one instruction we broke at with breakpoints disabled. | |
| 194 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | |
| 195 // Leave the debugger shell. | |
| 196 done = true; | |
| 197 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { | |
| 198 if (args == 2) { | |
| 199 int64_t value; | |
| 200 if (GetValue(arg1, &value)) { | |
| 201 OS::Print("%s: %"Pu64" 0x%"Px64"\n", arg1, value, value); | |
| 202 } else { | |
| 203 OS::Print("%s unrecognized\n", arg1); | |
| 204 } | |
| 205 } else { | |
| 206 OS::Print("print <reg or value or *addr>\n"); | |
| 207 } | |
| 208 } else if ((strcmp(cmd, "po") == 0) || | |
| 209 (strcmp(cmd, "printobject") == 0)) { | |
| 210 if (args == 2) { | |
| 211 int64_t value; | |
| 212 // Make the dereferencing '*' optional. | |
| 213 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) || | |
| 214 GetValue(arg1, &value)) { | |
| 215 if (Isolate::Current()->heap()->Contains(value)) { | |
| 216 OS::Print("%s: \n", arg1); | |
| 217 #if defined(DEBUG) | |
| 218 const Object& obj = Object::Handle( | |
| 219 reinterpret_cast<RawObject*>(value)); | |
| 220 obj.Print(); | |
| 221 #endif // defined(DEBUG) | |
| 222 } else { | |
| 223 OS::Print("0x%"Px64" is not an object reference\n", value); | |
| 224 } | |
| 225 } else { | |
| 226 OS::Print("%s unrecognized\n", arg1); | |
| 227 } | |
| 228 } else { | |
| 229 OS::Print("printobject <*reg or *addr>\n"); | |
| 230 } | |
| 231 } else if (strcmp(cmd, "disasm") == 0) { | |
| 232 int64_t start = 0; | |
| 233 int64_t end = 0; | |
| 234 if (args == 1) { | |
| 235 start = sim_->get_pc(); | |
| 236 end = start + (10 * Instr::kInstrSize); | |
| 237 } else if (args == 2) { | |
| 238 if (GetValue(arg1, &start)) { | |
| 239 // no length parameter passed, assume 10 instructions | |
| 240 if (Simulator::IsIllegalAddress(start)) { | |
| 241 // If start isn't a valid address, warn and use PC instead | |
| 242 OS::Print("First argument yields invalid address: 0x%"Px64"\n", | |
| 243 start); | |
| 244 OS::Print("Using PC instead"); | |
| 245 start = sim_->get_pc(); | |
| 246 } | |
| 247 end = start + (10 * Instr::kInstrSize); | |
| 248 } | |
| 249 } else { | |
| 250 intptr_t length; | |
| 251 if (GetValue(arg1, &start) && GetValue(arg2, &length)) { | |
| 252 if (Simulator::IsIllegalAddress(start)) { | |
| 253 // If start isn't a valid address, warn and use PC instead | |
| 254 OS::Print("First argument yields invalid address: 0x%"Px64"\n", | |
| 255 start); | |
| 256 OS::Print("Using PC instead\n"); | |
| 257 start = sim_->get_pc(); | |
| 258 } | |
| 259 end = start + (length * Instr::kInstrSize); | |
| 260 } | |
| 261 } | |
| 262 Disassembler::Disassemble(start, end); | |
| 263 } else if (strcmp(cmd, "gdb") == 0) { | |
| 264 OS::Print("relinquishing control to gdb\n"); | |
| 265 OS::DebugBreak(); | |
| 266 OS::Print("regaining control from gdb\n"); | |
| 267 } else { | |
| 268 OS::Print("Unknown command: %s\n", cmd); | |
| 269 } | |
| 270 } | |
| 271 delete[] line; | |
| 272 } | |
| 273 | |
| 274 // TODO(zra): Add all the breakpoints back to stop execution and enter the | |
| 275 // debugger shell when hit. | |
| 276 // RedoBreakpoints(); | |
| 277 | |
| 278 #undef COMMAND_SIZE | |
| 279 #undef ARG_SIZE | |
| 280 | |
| 281 #undef STR | |
| 282 #undef XSTR | |
| 283 } | |
| 284 | |
| 285 | |
| 286 char* SimulatorDebugger::ReadLine(const char* prompt) { | |
| 287 char* result = NULL; | |
| 288 char line_buf[256]; | |
| 289 intptr_t offset = 0; | |
| 290 bool keep_going = true; | |
| 291 OS::Print("%s", prompt); | |
| 292 while (keep_going) { | |
| 293 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { | |
| 294 // fgets got an error. Just give up. | |
| 295 if (result != NULL) { | |
| 296 delete[] result; | |
| 297 } | |
| 298 return NULL; | |
| 299 } | |
| 300 intptr_t len = strlen(line_buf); | |
| 301 if (len > 1 && | |
| 302 line_buf[len - 2] == '\\' && | |
| 303 line_buf[len - 1] == '\n') { | |
| 304 // When we read a line that ends with a "\" we remove the escape and | |
| 305 // append the remainder. | |
| 306 line_buf[len - 2] = '\n'; | |
| 307 line_buf[len - 1] = 0; | |
| 308 len -= 1; | |
| 309 } else if ((len > 0) && (line_buf[len - 1] == '\n')) { | |
| 310 // Since we read a new line we are done reading the line. This | |
| 311 // will exit the loop after copying this buffer into the result. | |
| 312 keep_going = false; | |
| 313 } | |
| 314 if (result == NULL) { | |
| 315 // Allocate the initial result and make room for the terminating '\0' | |
| 316 result = new char[len + 1]; | |
| 317 if (result == NULL) { | |
| 318 // OOM, so cannot readline anymore. | |
| 319 return NULL; | |
| 320 } | |
| 321 } else { | |
| 322 // Allocate a new result with enough room for the new addition. | |
| 323 intptr_t new_len = offset + len + 1; | |
| 324 char* new_result = new char[new_len]; | |
| 325 if (new_result == NULL) { | |
| 326 // OOM, free the buffer allocated so far and return NULL. | |
| 327 delete[] result; | |
| 328 return NULL; | |
| 329 } else { | |
| 330 // Copy the existing input into the new array and set the new | |
| 331 // array as the result. | |
| 332 memmove(new_result, result, offset); | |
| 333 delete[] result; | |
| 334 result = new_result; | |
| 335 } | |
| 336 } | |
| 337 // Copy the newly read line into the result. | |
| 338 memmove(result + offset, line_buf, len); | |
| 339 offset += len; | |
| 340 } | |
| 341 ASSERT(result != NULL); | |
| 342 result[offset] = '\0'; | |
| 343 return result; | |
| 344 } | |
| 345 | |
| 346 | |
| 38 Simulator::Simulator() { | 347 Simulator::Simulator() { |
| 39 // Setup simulator support first. Some of this information is needed to | 348 // Setup simulator support first. Some of this information is needed to |
| 40 // setup the architecture state. | 349 // setup the architecture state. |
| 41 // We allocate the stack here, the size is computed as the sum of | 350 // We allocate the stack here, the size is computed as the sum of |
| 42 // the size specified by the user and the buffer space needed for | 351 // the size specified by the user and the buffer space needed for |
| 43 // handling stack overflow exceptions. To be safe in potential | 352 // handling stack overflow exceptions. To be safe in potential |
| 44 // stack underflows we also add some underflow buffer space. | 353 // stack underflows we also add some underflow buffer space. |
| 45 stack_ = new char[(Isolate::GetSpecifiedStackSize() + | 354 stack_ = new char[(Isolate::GetSpecifiedStackSize() + |
| 46 Isolate::kStackSizeBuffer + | 355 Isolate::kStackSizeBuffer + |
| 47 kSimulatorStackUnderflowSize)]; | 356 kSimulatorStackUnderflowSize)]; |
| (...skipping 562 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 610 } | 919 } |
| 611 const int64_t imm19 = instr->SImm19Field(); | 920 const int64_t imm19 = instr->SImm19Field(); |
| 612 const int64_t dest = get_pc() + (imm19 << 2); | 921 const int64_t dest = get_pc() + (imm19 << 2); |
| 613 if (ConditionallyExecute(instr)) { | 922 if (ConditionallyExecute(instr)) { |
| 614 set_pc(dest); | 923 set_pc(dest); |
| 615 } | 924 } |
| 616 } | 925 } |
| 617 | 926 |
| 618 | 927 |
| 619 void Simulator::DecodeExceptionGen(Instr* instr) { | 928 void Simulator::DecodeExceptionGen(Instr* instr) { |
| 620 UnimplementedInstruction(instr); | 929 if ((instr->Bits(0, 2) == 1) && (instr->Bits(2, 3) == 0) && |
| 930 (instr->Bits(21, 3) == 0)) { | |
| 931 // Format(instr, "svc 'imm16"); | |
| 932 UnimplementedInstruction(instr); | |
| 933 } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) && | |
| 934 (instr->Bits(21, 3) == 1)) { | |
| 935 // Format(instr, "brk 'imm16"); | |
| 936 UnimplementedInstruction(instr); | |
| 937 } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) && | |
| 938 (instr->Bits(21, 3) == 2)) { | |
| 939 // Format(instr, "hlt 'imm16"); | |
| 940 uint16_t imm = static_cast<uint16_t>(instr->Imm16Field()); | |
| 941 if (imm == kImmExceptionIsDebug) { | |
| 942 SimulatorDebugger dbg(this); | |
| 943 const char* message = *reinterpret_cast<const char**>( | |
| 944 reinterpret_cast<intptr_t>(instr) - 2 * Instr::kInstrSize); | |
| 945 set_pc(get_pc() + Instr::kInstrSize); | |
| 946 dbg.Stop(instr, message); | |
| 947 } else if (imm == kImmExceptionIsPrintf) { | |
| 948 const char* message = *reinterpret_cast<const char**>( | |
| 949 reinterpret_cast<intptr_t>(instr) - 2 * Instr::kInstrSize); | |
| 950 OS::Print("Simulator hit: %s", message); | |
| 951 } else { | |
| 952 UnimplementedInstruction(instr); | |
| 953 } | |
| 954 } | |
| 621 } | 955 } |
| 622 | 956 |
| 623 | 957 |
| 624 void Simulator::DecodeSystem(Instr* instr) { | 958 void Simulator::DecodeSystem(Instr* instr) { |
| 625 if ((instr->Bits(0, 8) == 0x5f) && (instr->Bits(12, 4) == 2) && | 959 if ((instr->Bits(0, 8) == 0x5f) && (instr->Bits(12, 4) == 2) && |
| 626 (instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) && | 960 (instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) && |
| 627 (instr->Bit(21) == 0)) { | 961 (instr->Bit(21) == 0)) { |
| 628 if (instr->Bits(8, 4) == 0) { | 962 if (instr->Bits(8, 4) == 0) { |
| 629 // Format(instr, "nop"); | 963 // Format(instr, "nop"); |
| 630 } else { | 964 } else { |
| (...skipping 792 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1423 int64_t return_value; | 1757 int64_t return_value; |
| 1424 return_value = get_register(R0); | 1758 return_value = get_register(R0); |
| 1425 return return_value; | 1759 return return_value; |
| 1426 } | 1760 } |
| 1427 | 1761 |
| 1428 } // namespace dart | 1762 } // namespace dart |
| 1429 | 1763 |
| 1430 #endif // !defined(HOST_ARCH_ARM64) | 1764 #endif // !defined(HOST_ARCH_ARM64) |
| 1431 | 1765 |
| 1432 #endif // defined TARGET_ARCH_ARM64 | 1766 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |