| 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 "vm/disassembler.h" | 5 #include "vm/disassembler.h" |
| 6 | 6 |
| 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. | 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 8 #if defined(TARGET_ARCH_MIPS) | 8 #if defined(TARGET_ARCH_MIPS) |
| 9 #include "platform/assert.h" | 9 #include "platform/assert.h" |
| 10 | 10 |
| 11 namespace dart { | 11 namespace dart { |
| 12 | 12 |
| 13 class MIPSDecoder : public ValueObject { | 13 class MIPSDecoder : public ValueObject { |
| 14 public: | 14 public: |
| 15 MIPSDecoder(char* buffer, size_t buffer_size) | 15 MIPSDecoder(char* buffer, size_t buffer_size) |
| 16 : buffer_(buffer), | 16 : buffer_(buffer), |
| 17 buffer_size_(buffer_size), | 17 buffer_size_(buffer_size), |
| 18 buffer_pos_(0) { | 18 buffer_pos_(0) { |
| 19 buffer_[buffer_pos_] = '\0'; | 19 buffer_[buffer_pos_] = '\0'; |
| 20 } | 20 } |
| 21 | 21 |
| 22 ~MIPSDecoder() {} | 22 ~MIPSDecoder() {} |
| 23 | 23 |
| 24 // Writes one disassembled instruction into 'buffer' (0-terminated). | 24 // Writes one disassembled instruction into 'buffer' (0-terminated). |
| 25 void InstructionDecode(Instr* instr); | 25 // Returns true if the instruction was successfully decoded, false otherwise. |
| 26 bool InstructionDecode(Instr* instr); |
| 26 | 27 |
| 27 private: | 28 private: |
| 28 // Bottleneck functions to print into the out_buffer. | 29 // Bottleneck functions to print into the out_buffer. |
| 29 void Print(const char* str); | 30 void Print(const char* str); |
| 30 | 31 |
| 31 // Printing of common values. | 32 // Printing of common values. |
| 32 void PrintRegister(Register reg); | 33 void PrintRegister(Register reg); |
| 33 | 34 |
| 34 int FormatRegister(Instr* instr, const char* format); | 35 int FormatRegister(Instr* instr, const char* format); |
| 35 int FormatOption(Instr* instr, const char* format); | 36 int FormatOption(Instr* instr, const char* format); |
| 36 void Format(Instr* instr, const char* format); | 37 void Format(Instr* instr, const char* format); |
| 38 void Unknown(Instr* instr); |
| 37 | 39 |
| 38 void DecodeSpecial(Instr* instr); | 40 bool DecodeSpecial(Instr* instr); |
| 39 void DecodeSpecial2(Instr* instr); | 41 bool DecodeSpecial2(Instr* instr); |
| 40 void DecodeSpecial3(Instr* instr); | |
| 41 | 42 |
| 42 // Convenience functions. | 43 // Convenience functions. |
| 43 char* get_buffer() const { return buffer_; } | 44 char* get_buffer() const { return buffer_; } |
| 44 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } | 45 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } |
| 45 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } | 46 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } |
| 46 | 47 |
| 47 char* buffer_; // Decode instructions into this buffer. | 48 char* buffer_; // Decode instructions into this buffer. |
| 48 size_t buffer_size_; // The size of the character buffer. | 49 size_t buffer_size_; // The size of the character buffer. |
| 49 size_t buffer_pos_; // Current character position in buffer. | 50 size_t buffer_pos_; // Current character position in buffer. |
| 50 | 51 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 } | 108 } |
| 108 | 109 |
| 109 | 110 |
| 110 // FormatOption takes a formatting string and interprets it based on | 111 // FormatOption takes a formatting string and interprets it based on |
| 111 // the current instructions. The format string points to the first | 112 // the current instructions. The format string points to the first |
| 112 // character of the option string (the option escape has already been | 113 // character of the option string (the option escape has already been |
| 113 // consumed by the caller.) FormatOption returns the number of | 114 // consumed by the caller.) FormatOption returns the number of |
| 114 // characters that were consumed from the formatting string. | 115 // characters that were consumed from the formatting string. |
| 115 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { | 116 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { |
| 116 switch (format[0]) { | 117 switch (format[0]) { |
| 118 case 'c': { |
| 119 ASSERT(STRING_STARTS_WITH(format, "code")); |
| 120 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 121 remaining_size_in_buffer(), |
| 122 "%d", instr->BreakCodeField()); |
| 123 return 4; |
| 124 } |
| 117 case 'h': { | 125 case 'h': { |
| 118 ASSERT(STRING_STARTS_WITH(format, "hint")); | 126 ASSERT(STRING_STARTS_WITH(format, "hint")); |
| 119 if (instr->SaField() != 0) { | 127 if (instr->SaField() == 0x10) { |
| 120 UNIMPLEMENTED(); | 128 // The high bit of the SA field is the only one that means something for |
| 129 // JALR and JR. TODO(zra): Fill in the other cases for PREF if needed. |
| 130 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 131 remaining_size_in_buffer(), |
| 132 ".hb"); |
| 133 } else if (instr->SaField() != 0) { |
| 134 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 135 remaining_size_in_buffer(), |
| 136 ".unknown"); |
| 121 } | 137 } |
| 122 return 4; | 138 return 4; |
| 123 } | 139 } |
| 124 case 'i': { | 140 case 'i': { |
| 125 ASSERT(STRING_STARTS_WITH(format, "imm")); | 141 ASSERT(STRING_STARTS_WITH(format, "imm")); |
| 126 if (format[3] == 'u') { | 142 if (format[3] == 'u') { |
| 127 int32_t imm = instr->UImmField(); | 143 int32_t imm = instr->UImmField(); |
| 128 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 144 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 129 remaining_size_in_buffer(), | 145 remaining_size_in_buffer(), |
| 130 "0x%x", | 146 "0x%x", |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 format += FormatOption(instr, format); | 185 format += FormatOption(instr, format); |
| 170 } else { | 186 } else { |
| 171 buffer_[buffer_pos_++] = cur; | 187 buffer_[buffer_pos_++] = cur; |
| 172 } | 188 } |
| 173 cur = *format++; | 189 cur = *format++; |
| 174 } | 190 } |
| 175 buffer_[buffer_pos_] = '\0'; | 191 buffer_[buffer_pos_] = '\0'; |
| 176 } | 192 } |
| 177 | 193 |
| 178 | 194 |
| 179 void MIPSDecoder::DecodeSpecial(Instr* instr) { | 195 // For currently unimplemented decodings the disassembler calls Unknown(instr) |
| 196 // which will just print "unknown" of the instruction bits. |
| 197 void MIPSDecoder::Unknown(Instr* instr) { |
| 198 Format(instr, "unknown"); |
| 199 } |
| 200 |
| 201 |
| 202 bool MIPSDecoder::DecodeSpecial(Instr* instr) { |
| 203 bool decoded = true; |
| 204 |
| 180 ASSERT(instr->OpcodeField() == SPECIAL); | 205 ASSERT(instr->OpcodeField() == SPECIAL); |
| 181 switch (instr->FunctionField()) { | 206 switch (instr->FunctionField()) { |
| 182 case ADDU: { | 207 case ADDU: { |
| 183 Format(instr, "addu 'rd, 'rs, 'rt"); | 208 Format(instr, "addu 'rd, 'rs, 'rt"); |
| 184 break; | 209 break; |
| 185 } | 210 } |
| 186 case AND: { | 211 case AND: { |
| 187 Format(instr, "and 'rd, 'rs, 'rt"); | 212 Format(instr, "and 'rd, 'rs, 'rt"); |
| 188 break; | 213 break; |
| 189 } | 214 } |
| 215 case BREAK: { |
| 216 Format(instr, "break 'code"); |
| 217 break; |
| 218 } |
| 190 case DIV: { | 219 case DIV: { |
| 191 Format(instr, "div 'rs, 'rt"); | 220 Format(instr, "div 'rs, 'rt"); |
| 192 break; | 221 break; |
| 193 } | 222 } |
| 194 case DIVU: { | 223 case DIVU: { |
| 195 Format(instr, "divu 'rs, 'rt"); | 224 Format(instr, "divu 'rs, 'rt"); |
| 196 break; | 225 break; |
| 197 } | 226 } |
| 198 case MFHI: { | 227 case MFHI: { |
| 199 Format(instr, "mfhi 'rd"); | 228 Format(instr, "mfhi 'rd"); |
| 200 break; | 229 break; |
| 201 } | 230 } |
| 202 case MFLO: { | 231 case MFLO: { |
| 203 Format(instr, "mflo 'rd"); | 232 Format(instr, "mflo 'rd"); |
| 204 break; | 233 break; |
| 205 } | 234 } |
| 206 case SLL: { | 235 case SLL: { |
| 207 if ((instr->RdField() == R0) && | 236 if ((instr->RdField() == R0) && |
| 208 (instr->RtField() == R0) && | 237 (instr->RtField() == R0) && |
| 209 (instr->SaField() == 0)) { | 238 (instr->SaField() == 0)) { |
| 210 Format(instr, "nop"); | 239 Format(instr, "nop"); |
| 211 } else { | 240 } else { |
| 212 Format(instr, "sll 'rd, 'rt, 'sa"); | 241 Format(instr, "sll 'rd, 'rt, 'sa"); |
| 213 } | 242 } |
| 214 break; | 243 break; |
| 215 } | 244 } |
| 216 case JR: { | 245 case JR: { |
| 217 ASSERT(instr->RtField() == R0); | |
| 218 ASSERT(instr->RdField() == R0); | |
| 219 Format(instr, "jr'hint 'rs"); | 246 Format(instr, "jr'hint 'rs"); |
| 220 break; | 247 break; |
| 221 } | 248 } |
| 222 default: { | 249 default: { |
| 223 OS::PrintErr("DecodeSpecial: 0x%x\n", instr->InstructionBits()); | 250 Unknown(instr); |
| 224 UNREACHABLE(); | 251 decoded = false; |
| 225 break; | 252 break; |
| 226 } | 253 } |
| 227 } | 254 } |
| 255 |
| 256 return decoded; |
| 228 } | 257 } |
| 229 | 258 |
| 230 | 259 |
| 231 void MIPSDecoder::DecodeSpecial2(Instr* instr) { | 260 bool MIPSDecoder::DecodeSpecial2(Instr* instr) { |
| 261 bool decoded = true; |
| 262 |
| 232 ASSERT(instr->OpcodeField() == SPECIAL2); | 263 ASSERT(instr->OpcodeField() == SPECIAL2); |
| 233 switch (instr->FunctionField()) { | 264 switch (instr->FunctionField()) { |
| 234 case CLO: { | 265 case CLO: { |
| 235 Format(instr, "clo 'rd, 'rs"); | 266 Format(instr, "clo 'rd, 'rs"); |
| 236 break; | 267 break; |
| 237 } | 268 } |
| 238 case CLZ: { | 269 case CLZ: { |
| 239 Format(instr, "clz 'rd, 'rs"); | 270 Format(instr, "clz 'rd, 'rs"); |
| 240 break; | 271 break; |
| 241 } | 272 } |
| 242 default: { | 273 default: { |
| 243 OS::PrintErr("DecodeSpecial2: 0x%x\n", instr->InstructionBits()); | 274 Unknown(instr); |
| 244 UNREACHABLE(); | 275 decoded = false; |
| 245 break; | 276 break; |
| 246 } | 277 } |
| 247 } | 278 } |
| 279 |
| 280 return decoded; |
| 248 } | 281 } |
| 249 | 282 |
| 250 | 283 |
| 251 void MIPSDecoder::DecodeSpecial3(Instr* instr) { | 284 bool MIPSDecoder::InstructionDecode(Instr* instr) { |
| 252 ASSERT(instr->OpcodeField() == SPECIAL3); | 285 bool decoded = true; |
| 253 switch (instr->FunctionField()) { | |
| 254 default: { | |
| 255 OS::PrintErr("DecodeSpecial3: 0x%x\n", instr->InstructionBits()); | |
| 256 UNREACHABLE(); | |
| 257 break; | |
| 258 } | |
| 259 } | |
| 260 } | |
| 261 | 286 |
| 262 | |
| 263 void MIPSDecoder::InstructionDecode(Instr* instr) { | |
| 264 switch (instr->OpcodeField()) { | 287 switch (instr->OpcodeField()) { |
| 265 case SPECIAL: { | 288 case SPECIAL: { |
| 266 DecodeSpecial(instr); | 289 decoded = DecodeSpecial(instr); |
| 267 break; | 290 break; |
| 268 } | 291 } |
| 269 case SPECIAL2: { | 292 case SPECIAL2: { |
| 270 DecodeSpecial2(instr); | 293 decoded = DecodeSpecial2(instr); |
| 271 break; | |
| 272 } | |
| 273 case SPECIAL3: { | |
| 274 DecodeSpecial3(instr); | |
| 275 break; | 294 break; |
| 276 } | 295 } |
| 277 case ADDIU: { | 296 case ADDIU: { |
| 278 Format(instr, "addiu 'rt, 'rs, 'imms"); | 297 Format(instr, "addiu 'rt, 'rs, 'imms"); |
| 279 break; | 298 break; |
| 280 } | 299 } |
| 281 case ANDI: { | 300 case ANDI: { |
| 282 Format(instr, "andi 'rt, 'rs, 'immu"); | 301 Format(instr, "andi 'rt, 'rs, 'immu"); |
| 283 break; | 302 break; |
| 284 } | 303 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 312 } | 331 } |
| 313 case SH: { | 332 case SH: { |
| 314 Format(instr, "sh 'rt, 'imms('rs)"); | 333 Format(instr, "sh 'rt, 'imms('rs)"); |
| 315 break; | 334 break; |
| 316 } | 335 } |
| 317 case SW: { | 336 case SW: { |
| 318 Format(instr, "sw 'rt, 'imms('rs)"); | 337 Format(instr, "sw 'rt, 'imms('rs)"); |
| 319 break; | 338 break; |
| 320 } | 339 } |
| 321 default: { | 340 default: { |
| 322 OS::PrintErr("Undecoded instruction: 0x%x\n", instr->InstructionBits()); | 341 Unknown(instr); |
| 323 UNREACHABLE(); | 342 decoded = false; |
| 324 break; | 343 break; |
| 325 } | 344 } |
| 326 } | 345 } |
| 346 |
| 347 return decoded; |
| 327 } | 348 } |
| 328 | 349 |
| 329 | 350 |
| 330 int Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, | 351 int Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, |
| 331 char* human_buffer, intptr_t human_size, | 352 char* human_buffer, intptr_t human_size, |
| 332 uword pc) { | 353 uword pc) { |
| 333 MIPSDecoder decoder(human_buffer, human_size); | 354 MIPSDecoder decoder(human_buffer, human_size); |
| 334 Instr* instr = Instr::At(pc); | 355 Instr* instr = Instr::At(pc); |
| 335 decoder.InstructionDecode(instr); | 356 if (decoder.InstructionDecode(instr)) { |
| 336 OS::SNPrint(hex_buffer, hex_size, "%08x", instr->InstructionBits()); | 357 OS::SNPrint(hex_buffer, hex_size, "%08x", instr->InstructionBits()); |
| 337 return Instr::kInstrSize; | 358 return Instr::kInstrSize; |
| 359 } else { |
| 360 return -Instr::kInstrSize; |
| 361 } |
| 338 } | 362 } |
| 339 | 363 |
| 340 | 364 |
| 341 void Disassembler::Disassemble(uword start, | 365 bool Disassembler::Disassemble(uword start, |
| 342 uword end, | 366 uword end, |
| 343 DisassemblyFormatter* formatter, | 367 DisassemblyFormatter* formatter, |
| 344 const Code::Comments& comments) { | 368 const Code::Comments& comments) { |
| 345 ASSERT(formatter != NULL); | 369 ASSERT(formatter != NULL); |
| 370 bool success = true; |
| 346 char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form. | 371 char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form. |
| 347 char human_buffer[kUserReadableBufferSize]; // Human-readable instruction. | 372 char human_buffer[kUserReadableBufferSize]; // Human-readable instruction. |
| 348 uword pc = start; | 373 uword pc = start; |
| 349 intptr_t comment_finger = 0; | 374 intptr_t comment_finger = 0; |
| 350 while (pc < end) { | 375 while (pc < end) { |
| 351 const intptr_t offset = pc - start; | 376 const intptr_t offset = pc - start; |
| 352 while (comment_finger < comments.Length() && | 377 while (comment_finger < comments.Length() && |
| 353 comments.PCOffsetAt(comment_finger) <= offset) { | 378 comments.PCOffsetAt(comment_finger) <= offset) { |
| 354 formatter->Print( | 379 formatter->Print( |
| 355 " ;; %s\n", | 380 " ;; %s\n", |
| 356 String::Handle(comments.CommentAt(comment_finger)).ToCString()); | 381 String::Handle(comments.CommentAt(comment_finger)).ToCString()); |
| 357 comment_finger++; | 382 comment_finger++; |
| 358 } | 383 } |
| 359 int instruction_length = DecodeInstruction(hex_buffer, | 384 int instruction_length = DecodeInstruction(hex_buffer, |
| 360 sizeof(hex_buffer), | 385 sizeof(hex_buffer), |
| 361 human_buffer, | 386 human_buffer, |
| 362 sizeof(human_buffer), | 387 sizeof(human_buffer), |
| 363 pc); | 388 pc); |
| 364 formatter->ConsumeInstruction(hex_buffer, | 389 if (instruction_length > 0) { |
| 365 sizeof(hex_buffer), | 390 formatter->ConsumeInstruction(hex_buffer, |
| 366 human_buffer, | 391 sizeof(hex_buffer), |
| 367 sizeof(human_buffer), | 392 human_buffer, |
| 368 pc); | 393 sizeof(human_buffer), |
| 369 pc += instruction_length; | 394 pc); |
| 395 pc += instruction_length; |
| 396 } else { |
| 397 ASSERT(instruction_length < 0); |
| 398 success = false; |
| 399 pc += (-instruction_length); |
| 400 } |
| 370 } | 401 } |
| 402 |
| 403 return success; |
| 371 } | 404 } |
| 372 | 405 |
| 373 } // namespace dart | 406 } // namespace dart |
| 374 | 407 |
| 375 #endif // defined TARGET_ARCH_MIPS | 408 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |