| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are |
| 4 // met: |
| 5 // |
| 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. |
| 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
| 28 // A Disassembler object is used to disassemble a block of code instruction by |
| 29 // instruction. The default implementation of the NameConverter object can be |
| 30 // overriden to modify register names or to do symbol lookup on addresses. |
| 31 // |
| 32 // The example below will disassemble a block of code and print it to stdout. |
| 33 // |
| 34 // NameConverter converter; |
| 35 // Disassembler d(converter); |
| 36 // for (byte* pc = begin; pc < end;) { |
| 37 // char buffer[128]; |
| 38 // buffer[0] = '\0'; |
| 39 // byte* prev_pc = pc; |
| 40 // pc += d.InstructionDecode(buffer, sizeof buffer, pc); |
| 41 // printf("%p %08x %s\n", |
| 42 // prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer); |
| 43 // } |
| 44 // |
| 45 // The Disassembler class also has a convenience method to disassemble a block |
| 46 // of code into a FILE*, meaning that the above functionality could also be |
| 47 // achieved by just calling Disassembler::Disassemble(stdout, begin, end); |
| 48 |
| 49 |
| 50 #include <assert.h> |
| 51 #include <stdio.h> |
| 52 #include <stdarg.h> |
| 53 #include <string.h> |
| 54 #ifndef WIN32 |
| 55 #include <stdint.h> |
| 56 #endif |
| 57 |
| 58 #include "v8.h" |
| 59 |
| 60 #include "constants-arm.h" |
| 61 #include "disasm.h" |
| 62 #include "macro-assembler.h" |
| 63 #include "instr-thumb2.h" |
| 64 #include "platform.h" |
| 65 |
| 66 |
| 67 namespace assembler { |
| 68 namespace arm { |
| 69 |
| 70 namespace v8i = v8::internal; |
| 71 |
| 72 |
| 73 //------------------------------------------------------------------------------ |
| 74 |
| 75 // Decoder decodes and disassembles instructions into an output buffer. |
| 76 // It uses the converter to convert register names and call destinations into |
| 77 // more informative description. |
| 78 class Decoder { |
| 79 public: |
| 80 Decoder(const disasm::NameConverter& converter, |
| 81 v8::internal::Vector<char> out_buffer) |
| 82 : converter_(converter), |
| 83 out_buffer_(out_buffer), |
| 84 out_buffer_pos_(0) { |
| 85 out_buffer_[out_buffer_pos_] = '\0'; |
| 86 } |
| 87 |
| 88 ~Decoder() {} |
| 89 |
| 90 // Writes one disassembled instruction into 'buffer' (0-terminated). |
| 91 // Returns the length of the disassembled machine instruction in bytes. |
| 92 int InstructionDecode(byte* instruction); |
| 93 int InstructionDecodeArm(byte* instruction); |
| 94 int InstructionDecodeThumb2(const InstrThumb2& instr); |
| 95 |
| 96 private: |
| 97 // Bottleneck functions to print into the out_buffer. |
| 98 void PrintChar(const char ch); |
| 99 void Print(const char* str); |
| 100 |
| 101 // Printing of common values. |
| 102 void PrintRegister(int reg); |
| 103 void PrintSRegister(int reg); |
| 104 void PrintDRegister(int reg); |
| 105 int FormatVFPRegister(Instr* instr, const char* format); |
| 106 int FormatVFPinstruction(Instr* instr, const char* format); |
| 107 void PrintCondition(Instr* instr); |
| 108 void PrintShiftRm(Instr* instr); |
| 109 void PrintShiftRm(const InstrThumb2& instr); |
| 110 void PrintShiftImm(Instr* instr); |
| 111 void PrintShiftImm(const InstrThumb2& instr); |
| 112 void PrintPU(Instr* instr); |
| 113 void PrintSoftwareInterrupt(SoftwareInterruptCodes swi); |
| 114 |
| 115 // Handle formatting of instructions and their options. |
| 116 int FormatRegister(Instr* instr, const char* option); |
| 117 int FormatRegister(const InstrThumb2& instr, const char* option); |
| 118 int FormatOption(Instr* instr, const char* option); |
| 119 int FormatOption(const InstrThumb2& instr, const char* option); |
| 120 void Format(Instr* instr, const char* format); |
| 121 void Format(const InstrThumb2& instr, const char* format); |
| 122 void Unknown(Instr* instr); |
| 123 void Unknown(const InstrThumb2& instr); |
| 124 |
| 125 // Each of these functions decodes one particular instruction type, a 3-bit |
| 126 // field in the instruction encoding. |
| 127 // Types 0 and 1 are combined as they are largely the same except for the way |
| 128 // they interpret the shifter operand. |
| 129 void DecodeType01(Instr* instr); |
| 130 void DecodeType2(Instr* instr); |
| 131 void DecodeType3(Instr* instr); |
| 132 void DecodeType4(Instr* instr); |
| 133 void DecodeType5(Instr* instr); |
| 134 void DecodeType6(Instr* instr); |
| 135 void DecodeType7(Instr* instr); |
| 136 void DecodeUnconditional(Instr* instr); |
| 137 // For VFP support. |
| 138 void DecodeTypeVFP(Instr* instr); |
| 139 void DecodeType6CoprocessorIns(Instr* instr); |
| 140 |
| 141 |
| 142 const disasm::NameConverter& converter_; |
| 143 v8::internal::Vector<char> out_buffer_; |
| 144 int out_buffer_pos_; |
| 145 |
| 146 DISALLOW_COPY_AND_ASSIGN(Decoder); |
| 147 }; |
| 148 |
| 149 |
| 150 // Support for assertions in the Decoder formatting functions. |
| 151 #define STRING_STARTS_WITH(string, compare_string) \ |
| 152 (strncmp(string, compare_string, strlen(compare_string)) == 0) |
| 153 |
| 154 |
| 155 // Append the ch to the output buffer. |
| 156 void Decoder::PrintChar(const char ch) { |
| 157 out_buffer_[out_buffer_pos_++] = ch; |
| 158 } |
| 159 |
| 160 |
| 161 // Append the str to the output buffer. |
| 162 void Decoder::Print(const char* str) { |
| 163 char cur = *str++; |
| 164 while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) { |
| 165 PrintChar(cur); |
| 166 cur = *str++; |
| 167 } |
| 168 out_buffer_[out_buffer_pos_] = 0; |
| 169 } |
| 170 |
| 171 |
| 172 // These condition names are defined in a way to match the native disassembler |
| 173 // formatting. See for example the command "objdump -d <binary file>". |
| 174 static const char* cond_names[max_condition] = { |
| 175 "eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" , |
| 176 "hi", "ls", "ge", "lt", "gt", "le", "", "invalid", |
| 177 }; |
| 178 |
| 179 |
| 180 // Print the condition guarding the instruction. |
| 181 void Decoder::PrintCondition(Instr* instr) { |
| 182 Print(cond_names[instr->ConditionField()]); |
| 183 } |
| 184 |
| 185 |
| 186 // Print the register name according to the active name converter. |
| 187 void Decoder::PrintRegister(int reg) { |
| 188 Print(converter_.NameOfCPURegister(reg)); |
| 189 } |
| 190 |
| 191 // Print the VFP S register name according to the active name converter. |
| 192 void Decoder::PrintSRegister(int reg) { |
| 193 Print(assembler::arm::VFPRegisters::Name(reg)); |
| 194 } |
| 195 |
| 196 // Print the VFP D register name according to the active name converter. |
| 197 void Decoder::PrintDRegister(int reg) { |
| 198 Print(assembler::arm::VFPRegisters::Name(reg + 32)); |
| 199 } |
| 200 |
| 201 |
| 202 // These shift names are defined in a way to match the native disassembler |
| 203 // formatting. See for example the command "objdump -d <binary file>". |
| 204 static const char* shift_names[max_shift] = { |
| 205 "lsl", "lsr", "asr", "ror" |
| 206 }; |
| 207 |
| 208 |
| 209 // Print the register shift operands for the instruction. Generally used for |
| 210 // data processing instructions. |
| 211 void Decoder::PrintShiftRm(Instr* instr) { |
| 212 Shift shift = instr->ShiftField(); |
| 213 int shift_amount = instr->ShiftAmountField(); |
| 214 int rm = instr->RmField(); |
| 215 |
| 216 PrintRegister(rm); |
| 217 |
| 218 if ((instr->RegShiftField() == 0) && (shift == LSL) && (shift_amount == 0)) { |
| 219 // Special case for using rm only. |
| 220 return; |
| 221 } |
| 222 if (instr->RegShiftField() == 0) { |
| 223 // by immediate |
| 224 if ((shift == ROR) && (shift_amount == 0)) { |
| 225 Print(", RRX"); |
| 226 return; |
| 227 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) { |
| 228 shift_amount = 32; |
| 229 } |
| 230 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 231 ", %s #%d", |
| 232 shift_names[shift], shift_amount); |
| 233 } else { |
| 234 // by register |
| 235 int rs = instr->RsField(); |
| 236 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 237 ", %s ", shift_names[shift]); |
| 238 PrintRegister(rs); |
| 239 } |
| 240 } |
| 241 |
| 242 void Decoder::PrintShiftRm(const InstrThumb2& instr) { |
| 243 int shift = instr.Type(); |
| 244 int shift_amount = instr.Imm(); |
| 245 int rm = instr.Rm(); |
| 246 |
| 247 PrintRegister(rm); |
| 248 |
| 249 if (instr.Variant() != VARIANT_REGISTER_SHIFTED_REGISTER) { |
| 250 if (shift == no_shift) { |
| 251 // Special case for using rm only. |
| 252 return; |
| 253 } |
| 254 if (shift == RRX) { |
| 255 Print(", RRX"); |
| 256 return; |
| 257 } |
| 258 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 259 ", %s #%d", |
| 260 shift_names[shift], shift_amount); |
| 261 } else { |
| 262 UNIMPLEMENTED(); |
| 263 // // by register |
| 264 // int rs = instr->Rs(); |
| 265 // out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 266 // ", %s ", shift_names[shift]); |
| 267 // PrintRegister(rs); |
| 268 } |
| 269 } |
| 270 |
| 271 |
| 272 |
| 273 // Print the immediate operand for the instruction. Generally used for data |
| 274 // processing instructions. |
| 275 void Decoder::PrintShiftImm(Instr* instr) { |
| 276 int rotate = instr->RotateField() * 2; |
| 277 int immed8 = instr->Immed8Field(); |
| 278 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate)); |
| 279 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 280 "#%d", imm); |
| 281 } |
| 282 |
| 283 void Decoder::PrintShiftImm(const InstrThumb2& instr) { |
| 284 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 285 "#%d", instr.Imm()); |
| 286 } |
| 287 |
| 288 |
| 289 // Print PU formatting to reduce complexity of FormatOption. |
| 290 void Decoder::PrintPU(Instr* instr) { |
| 291 switch (instr->PUField()) { |
| 292 case 0: { |
| 293 Print("da"); |
| 294 break; |
| 295 } |
| 296 case 1: { |
| 297 Print("ia"); |
| 298 break; |
| 299 } |
| 300 case 2: { |
| 301 Print("db"); |
| 302 break; |
| 303 } |
| 304 case 3: { |
| 305 Print("ib"); |
| 306 break; |
| 307 } |
| 308 default: { |
| 309 UNREACHABLE(); |
| 310 break; |
| 311 } |
| 312 } |
| 313 } |
| 314 |
| 315 |
| 316 // Print SoftwareInterrupt codes. Factoring this out reduces the complexity of |
| 317 // the FormatOption method. |
| 318 void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) { |
| 319 switch (swi) { |
| 320 case call_rt_redirected: |
| 321 Print("call_rt_redirected"); |
| 322 return; |
| 323 case break_point: |
| 324 Print("break_point"); |
| 325 return; |
| 326 default: |
| 327 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 328 "%d", |
| 329 swi); |
| 330 return; |
| 331 } |
| 332 } |
| 333 |
| 334 |
| 335 // Handle all register based formatting in this function to reduce the |
| 336 // complexity of FormatOption. |
| 337 int Decoder::FormatRegister(Instr* instr, const char* format) { |
| 338 ASSERT(format[0] == 'r'); |
| 339 if (format[1] == 'n') { // 'rn: Rn register |
| 340 int reg = instr->RnField(); |
| 341 PrintRegister(reg); |
| 342 return 2; |
| 343 } else if (format[1] == 'd') { // 'rd: Rd register |
| 344 int reg = instr->RdField(); |
| 345 PrintRegister(reg); |
| 346 return 2; |
| 347 } else if (format[1] == 's') { // 'rs: Rs register |
| 348 int reg = instr->RsField(); |
| 349 PrintRegister(reg); |
| 350 return 2; |
| 351 } else if (format[1] == 'm') { // 'rm: Rm register |
| 352 int reg = instr->RmField(); |
| 353 PrintRegister(reg); |
| 354 return 2; |
| 355 } else if (format[1] == 't') { // 'rt: Rt register |
| 356 int reg = instr->RtField(); |
| 357 PrintRegister(reg); |
| 358 return 2; |
| 359 } else if (format[1] == 'l') { |
| 360 // 'rlist: register list for load and store multiple instructions |
| 361 ASSERT(STRING_STARTS_WITH(format, "rlist")); |
| 362 int rlist = instr->RlistField(); |
| 363 int reg = 0; |
| 364 Print("{"); |
| 365 // Print register list in ascending order, by scanning the bit mask. |
| 366 while (rlist != 0) { |
| 367 if ((rlist & 1) != 0) { |
| 368 PrintRegister(reg); |
| 369 if ((rlist >> 1) != 0) { |
| 370 Print(", "); |
| 371 } |
| 372 } |
| 373 reg++; |
| 374 rlist >>= 1; |
| 375 } |
| 376 Print("}"); |
| 377 return 5; |
| 378 } |
| 379 UNREACHABLE(); |
| 380 return -1; |
| 381 } |
| 382 |
| 383 int Decoder::FormatRegister(const InstrThumb2& instr, const char* format) { |
| 384 ASSERT(format[0] == 'r'); |
| 385 if (format[1] == 'n') { // 'rn: Rn register |
| 386 int reg = instr.Rn(); |
| 387 PrintRegister(reg); |
| 388 return 2; |
| 389 } else if (format[1] == 'd') { // 'rd: Rd register |
| 390 int reg = instr.Rd(); |
| 391 PrintRegister(reg); |
| 392 return 2; |
| 393 } else if (format[1] == 's') { // 'rs: Rs register |
| 394 int reg = instr.Rs(); |
| 395 PrintRegister(reg); |
| 396 return 2; |
| 397 } else if (format[1] == 'm') { // 'rm: Rm register |
| 398 int reg = instr.Rm(); |
| 399 PrintRegister(reg); |
| 400 return 2; |
| 401 } else if (format[1] == 't') { // 'rt: Rt register |
| 402 int reg = instr.Rt(); |
| 403 PrintRegister(reg); |
| 404 return 2; |
| 405 } else if (format[1] == 'l') { |
| 406 // 'rlist: register list for load and store multiple instructions |
| 407 ASSERT(STRING_STARTS_WITH(format, "rlist")); |
| 408 UNIMPLEMENTED(); |
| 409 // int rlist = instr->RlistField(); |
| 410 // int reg = 0; |
| 411 // Print("{"); |
| 412 // // Print register list in ascending order, by scanning the bit mask. |
| 413 // while (rlist != 0) { |
| 414 // if ((rlist & 1) != 0) { |
| 415 // PrintRegister(reg); |
| 416 // if ((rlist >> 1) != 0) { |
| 417 // Print(", "); |
| 418 // } |
| 419 // } |
| 420 // reg++; |
| 421 // rlist >>= 1; |
| 422 // } |
| 423 // Print("}"); |
| 424 return 5; |
| 425 } |
| 426 UNREACHABLE(); |
| 427 return -1; |
| 428 } |
| 429 |
| 430 |
| 431 // Handle all VFP register based formatting in this function to reduce the |
| 432 // complexity of FormatOption. |
| 433 int Decoder::FormatVFPRegister(Instr* instr, const char* format) { |
| 434 ASSERT((format[0] == 'S') || (format[0] == 'D')); |
| 435 |
| 436 if (format[1] == 'n') { |
| 437 int reg = instr->VnField(); |
| 438 if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->NField())); |
| 439 if (format[0] == 'D') PrintDRegister(reg); |
| 440 return 2; |
| 441 } else if (format[1] == 'm') { |
| 442 int reg = instr->VmField(); |
| 443 if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->MField())); |
| 444 if (format[0] == 'D') PrintDRegister(reg); |
| 445 return 2; |
| 446 } else if (format[1] == 'd') { |
| 447 int reg = instr->VdField(); |
| 448 if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->DField())); |
| 449 if (format[0] == 'D') PrintDRegister(reg); |
| 450 return 2; |
| 451 } |
| 452 |
| 453 UNREACHABLE(); |
| 454 return -1; |
| 455 } |
| 456 |
| 457 |
| 458 int Decoder::FormatVFPinstruction(Instr* instr, const char* format) { |
| 459 Print(format); |
| 460 return 0; |
| 461 } |
| 462 |
| 463 |
| 464 // FormatOption takes a formatting string and interprets it based on |
| 465 // the current instructions. The format string points to the first |
| 466 // character of the option string (the option escape has already been |
| 467 // consumed by the caller.) FormatOption returns the number of |
| 468 // characters that were consumed from the formatting string. |
| 469 int Decoder::FormatOption(Instr* instr, const char* format) { |
| 470 switch (format[0]) { |
| 471 case 'a': { // 'a: accumulate multiplies |
| 472 if (instr->Bit(21) == 0) { |
| 473 Print("ul"); |
| 474 } else { |
| 475 Print("la"); |
| 476 } |
| 477 return 1; |
| 478 } |
| 479 case 'b': { // 'b: byte loads or stores |
| 480 if (instr->HasB()) { |
| 481 Print("b"); |
| 482 } |
| 483 return 1; |
| 484 } |
| 485 case 'c': { // 'cond: conditional execution |
| 486 ASSERT(STRING_STARTS_WITH(format, "cond")); |
| 487 PrintCondition(instr); |
| 488 return 4; |
| 489 } |
| 490 case 'h': { // 'h: halfword operation for extra loads and stores |
| 491 if (instr->HasH()) { |
| 492 Print("h"); |
| 493 } else { |
| 494 Print("b"); |
| 495 } |
| 496 return 1; |
| 497 } |
| 498 case 'l': { // 'l: branch and link |
| 499 if (instr->HasLink()) { |
| 500 Print("l"); |
| 501 } |
| 502 return 1; |
| 503 } |
| 504 case 'm': { |
| 505 if (format[1] == 'e') { // 'memop: load/store instructions |
| 506 ASSERT(STRING_STARTS_WITH(format, "memop")); |
| 507 if (instr->HasL()) { |
| 508 Print("ldr"); |
| 509 } else { |
| 510 Print("str"); |
| 511 } |
| 512 return 5; |
| 513 } |
| 514 // 'msg: for simulator break instructions |
| 515 ASSERT(STRING_STARTS_WITH(format, "msg")); |
| 516 byte* str = |
| 517 reinterpret_cast<byte*>(instr->InstructionBits() & 0x0fffffff); |
| 518 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 519 "%s", converter_.NameInCode(str)); |
| 520 return 3; |
| 521 } |
| 522 case 'o': { |
| 523 if ((format[3] == '1') && (format[4] == '2')) { |
| 524 // 'off12: 12-bit offset for load and store instructions |
| 525 ASSERT(STRING_STARTS_WITH(format, "off12")); |
| 526 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 527 "%d", instr->Offset12Field()); |
| 528 return 5; |
| 529 } else if ((format[3] == '1') && (format[4] == '6')) { |
| 530 ASSERT(STRING_STARTS_WITH(format, "off16to20")); |
| 531 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 532 "%d", instr->Bits(20, 16) +1); |
| 533 return 9; |
| 534 } else if (format[3] == '7') { |
| 535 ASSERT(STRING_STARTS_WITH(format, "off7to11")); |
| 536 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 537 "%d", instr->ShiftAmountField()); |
| 538 return 8; |
| 539 } |
| 540 // 'off8: 8-bit offset for extra load and store instructions |
| 541 ASSERT(STRING_STARTS_WITH(format, "off8")); |
| 542 int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField(); |
| 543 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 544 "%d", offs8); |
| 545 return 4; |
| 546 } |
| 547 case 'p': { // 'pu: P and U bits for load and store instructions |
| 548 ASSERT(STRING_STARTS_WITH(format, "pu")); |
| 549 PrintPU(instr); |
| 550 return 2; |
| 551 } |
| 552 case 'r': { |
| 553 return FormatRegister(instr, format); |
| 554 } |
| 555 case 's': { |
| 556 if (format[1] == 'h') { // 'shift_op or 'shift_rm |
| 557 if (format[6] == 'o') { // 'shift_op |
| 558 ASSERT(STRING_STARTS_WITH(format, "shift_op")); |
| 559 if (instr->TypeField() == 0) { |
| 560 PrintShiftRm(instr); |
| 561 } else { |
| 562 ASSERT(instr->TypeField() == 1); |
| 563 PrintShiftImm(instr); |
| 564 } |
| 565 return 8; |
| 566 } else { // 'shift_rm |
| 567 ASSERT(STRING_STARTS_WITH(format, "shift_rm")); |
| 568 PrintShiftRm(instr); |
| 569 return 8; |
| 570 } |
| 571 } else if (format[1] == 'w') { // 'swi |
| 572 ASSERT(STRING_STARTS_WITH(format, "swi")); |
| 573 PrintSoftwareInterrupt(instr->SwiField()); |
| 574 return 3; |
| 575 } else if (format[1] == 'i') { // 'sign: signed extra loads and stores |
| 576 ASSERT(STRING_STARTS_WITH(format, "sign")); |
| 577 if (instr->HasSign()) { |
| 578 Print("s"); |
| 579 } |
| 580 return 4; |
| 581 } |
| 582 // 's: S field of data processing instructions |
| 583 if (instr->HasS()) { |
| 584 Print("s"); |
| 585 } |
| 586 return 1; |
| 587 } |
| 588 case 't': { // 'target: target of branch instructions |
| 589 ASSERT(STRING_STARTS_WITH(format, "target")); |
| 590 int off = (instr->SImmed24Field() << 2) + 8; |
| 591 out_buffer_pos_ += v8i::OS::SNPrintF( |
| 592 out_buffer_ + out_buffer_pos_, |
| 593 "%+d -> %s", |
| 594 off, |
| 595 converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off)); |
| 596 return 6; |
| 597 } |
| 598 case 'u': { // 'u: signed or unsigned multiplies |
| 599 // The manual gets the meaning of bit 22 backwards in the multiply |
| 600 // instruction overview on page A3.16.2. The instructions that |
| 601 // exist in u and s variants are the following: |
| 602 // smull A4.1.87 |
| 603 // umull A4.1.129 |
| 604 // umlal A4.1.128 |
| 605 // smlal A4.1.76 |
| 606 // For these 0 means u and 1 means s. As can be seen on their individual |
| 607 // pages. The other 18 mul instructions have the bit set or unset in |
| 608 // arbitrary ways that are unrelated to the signedness of the instruction. |
| 609 // None of these 18 instructions exist in both a 'u' and an 's' variant. |
| 610 |
| 611 if (instr->Bit(22) == 0) { |
| 612 Print("u"); |
| 613 } else { |
| 614 Print("s"); |
| 615 } |
| 616 return 1; |
| 617 } |
| 618 case 'v': { |
| 619 return FormatVFPinstruction(instr, format); |
| 620 } |
| 621 case 'S': |
| 622 case 'D': { |
| 623 return FormatVFPRegister(instr, format); |
| 624 } |
| 625 case 'w': { // 'w: W field of load and store instructions |
| 626 if (instr->HasW()) { |
| 627 Print("!"); |
| 628 } |
| 629 return 1; |
| 630 } |
| 631 default: { |
| 632 UNREACHABLE(); |
| 633 break; |
| 634 } |
| 635 } |
| 636 UNREACHABLE(); |
| 637 return -1; |
| 638 } |
| 639 |
| 640 int Decoder::FormatOption(const InstrThumb2& instr, const char* format) { |
| 641 switch (format[0]) { |
| 642 // TODO(haustein) Re-enable code below |
| 643 // case 'a': { // 'a: accumulate multiplies |
| 644 // if (instr->Bit(21) == 0) { |
| 645 // Print("ul"); |
| 646 // } else { |
| 647 // Print("la"); |
| 648 // } |
| 649 // return 1; |
| 650 // } |
| 651 // case 'b': { // 'b: byte loads or stores |
| 652 // if (instr->HasB()) { |
| 653 // Print("b"); |
| 654 // } |
| 655 // return 1; |
| 656 // } |
| 657 // case 'c': { // 'cond: conditional execution |
| 658 // ASSERT(STRING_STARTS_WITH(format, "cond")); |
| 659 // PrintCondition(instr); |
| 660 // return 4; |
| 661 // } |
| 662 // case 'h': { // 'h: halfword operation for extra loads and stores |
| 663 // if (instr->HasH()) { |
| 664 // Print("h"); |
| 665 // } else { |
| 666 // Print("b"); |
| 667 // } |
| 668 // return 1; |
| 669 // } |
| 670 // case 'l': { // 'l: branch and link |
| 671 // if (instr->HasLink()) { |
| 672 // Print("l"); |
| 673 // } |
| 674 // return 1; |
| 675 // } |
| 676 // case 'm': { |
| 677 // if (format[1] == 'e') { // 'memop: load/store instructions |
| 678 // ASSERT(STRING_STARTS_WITH(format, "memop")); |
| 679 // if (instr->HasL()) { |
| 680 // Print("ldr"); |
| 681 // } else { |
| 682 // Print("str"); |
| 683 // } |
| 684 // return 5; |
| 685 // } |
| 686 // // 'msg: for simulator break instructions |
| 687 // ASSERT(STRING_STARTS_WITH(format, "msg")); |
| 688 // byte* str = |
| 689 // reinterpret_cast<byte*>(instr->InstructionBits() & 0x0fffffff); |
| 690 // out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 691 // "%s", converter_.NameInCode(str)); |
| 692 // return 3; |
| 693 // } |
| 694 // case 'o': { |
| 695 // if ((format[3] == '1') && (format[4] == '2')) { |
| 696 // // 'off12: 12-bit offset for load and store instructions |
| 697 // ASSERT(STRING_STARTS_WITH(format, "off12")); |
| 698 // out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 699 // "%d", instr->Offset12Field()); |
| 700 // return 5; |
| 701 // } else if ((format[3] == '1') && (format[4] == '6')) { |
| 702 // ASSERT(STRING_STARTS_WITH(format, "off16to20")); |
| 703 // out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 704 // "%d", instr->Bits(20, 16) +1); |
| 705 // return 9; |
| 706 // } else if (format[3] == '7') { |
| 707 // ASSERT(STRING_STARTS_WITH(format, "off7to11")); |
| 708 // out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 709 // "%d", instr->ShiftAmountField()); |
| 710 // return 8; |
| 711 // } |
| 712 // // 'off8: 8-bit offset for extra load and store instructions |
| 713 // ASSERT(STRING_STARTS_WITH(format, "off8")); |
| 714 // int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField(); |
| 715 // out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 716 // "%d", offs8); |
| 717 // return 4; |
| 718 // } |
| 719 // case 'p': { // 'pu: P and U bits for load and store instructions |
| 720 // ASSERT(STRING_STARTS_WITH(format, "pu")); |
| 721 // PrintPU(instr); |
| 722 // return 2; |
| 723 // } |
| 724 case 'r': { |
| 725 return FormatRegister(instr, format); |
| 726 } |
| 727 case 's': { |
| 728 if (format[1] == 'h') { // 'shift_op or 'shift_rm |
| 729 if (format[6] == 'o') { // 'shift_op |
| 730 ASSERT(STRING_STARTS_WITH(format, "shift_op")); |
| 731 if (instr.Type() == 0) { |
| 732 PrintShiftRm(instr); |
| 733 } else { |
| 734 ASSERT(instr.Type() == 1); |
| 735 PrintShiftImm(instr); |
| 736 } |
| 737 return 8; |
| 738 } else { // 'shift_rm |
| 739 ASSERT(STRING_STARTS_WITH(format, "shift_rm")); |
| 740 PrintShiftRm(instr); |
| 741 return 8; |
| 742 } |
| 743 // TODO(haustein) Re-enable code below |
| 744 // } else if (format[1] == 'w') { // 'swi |
| 745 // ASSERT(STRING_STARTS_WITH(format, "swi")); |
| 746 // PrintSoftwareInterrupt(instr->SwiField()); |
| 747 // return 3; |
| 748 // } else if (format[1] == 'i') { // 'sign: signed extra loads and stores |
| 749 // ASSERT(STRING_STARTS_WITH(format, "sign")); |
| 750 // if (instr->HasSign()) { |
| 751 // Print("s"); |
| 752 // return 4; |
| 753 } |
| 754 // 's: S field of data processing instructions |
| 755 if (instr.HasS()) { |
| 756 Print("s"); |
| 757 } |
| 758 return 1; |
| 759 } |
| 760 // TODO(haustein) Re-enable code for 't', 'u', 'v', 'S', 'D', 'w' below. |
| 761 // case 't': { // 'target: target of branch instructions |
| 762 // ASSERT(STRING_STARTS_WITH(format, "target")); |
| 763 // int off = (instr->SImmed24Field() << 2) + 8; |
| 764 // out_buffer_pos_ += v8i::OS::SNPrintF( |
| 765 // out_buffer_ + out_buffer_pos_, |
| 766 // "%+d -> %s", |
| 767 // off, |
| 768 // converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off)); |
| 769 // return 6; |
| 770 // } |
| 771 // case 'u': { // 'u: signed or unsigned multiplies |
| 772 // // The manual gets the meaning of bit 22 backwards in the multiply |
| 773 // // instruction overview on page A3.16.2. The instructions that |
| 774 // // exist in u and s variants are the following: |
| 775 // // smull A4.1.87 |
| 776 // // umull A4.1.129 |
| 777 // // umlal A4.1.128 |
| 778 // // smlal A4.1.76 |
| 779 // // For these 0 means u and 1 means s. As can be seen on their individual |
| 780 // // pages. The other 18 mul instructions have the bit set or unset in |
| 781 // // arbitrary ways that are unrelated to the signedness of the instruction. |
| 782 // // None of these 18 instructions exist in both a 'u' and an 's' variant. |
| 783 // |
| 784 // if (instr->Bit(22) == 0) { |
| 785 // Print("u"); |
| 786 // } else { |
| 787 // Print("s"); |
| 788 // } |
| 789 // return 1; |
| 790 // } |
| 791 // case 'v': { |
| 792 // return FormatVFPinstruction(instr, format); |
| 793 // } |
| 794 // case 'S': |
| 795 // case 'D': { |
| 796 // return FormatVFPRegister(instr, format); |
| 797 // } |
| 798 // case 'w': { // 'w: W field of load and store instructions |
| 799 // if (instr->HasW()) { |
| 800 // Print("!"); |
| 801 // } |
| 802 // return 1; |
| 803 // } |
| 804 default: { |
| 805 UNIMPLEMENTED(); |
| 806 break; |
| 807 } |
| 808 } |
| 809 UNREACHABLE(); |
| 810 return -1; |
| 811 } |
| 812 |
| 813 |
| 814 // Format takes a formatting string for a whole instruction and prints it into |
| 815 // the output buffer. All escaped options are handed to FormatOption to be |
| 816 // parsed further. |
| 817 void Decoder::Format(Instr* instr, const char* format) { |
| 818 char cur = *format++; |
| 819 while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) { |
| 820 if (cur == '\'') { // Single quote is used as the formatting escape. |
| 821 format += FormatOption(instr, format); |
| 822 } else { |
| 823 out_buffer_[out_buffer_pos_++] = cur; |
| 824 } |
| 825 cur = *format++; |
| 826 } |
| 827 out_buffer_[out_buffer_pos_] = '\0'; |
| 828 } |
| 829 |
| 830 |
| 831 void Decoder::Format(const InstrThumb2& instr, const char* format) { |
| 832 char cur = *format++; |
| 833 while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) { |
| 834 if (cur == '\'') { // Single quote is used as the formatting escape. |
| 835 format += FormatOption(instr, format); |
| 836 } else { |
| 837 out_buffer_[out_buffer_pos_++] = cur; |
| 838 } |
| 839 cur = *format++; |
| 840 } |
| 841 out_buffer_[out_buffer_pos_] = '\0'; |
| 842 } |
| 843 |
| 844 |
| 845 |
| 846 // For currently unimplemented decodings the disassembler calls Unknown(instr) |
| 847 // which will just print "unknown" of the instruction bits. |
| 848 void Decoder::Unknown(Instr* instr) { |
| 849 Format(instr, "unknown"); |
| 850 } |
| 851 |
| 852 |
| 853 void Decoder::DecodeType01(Instr* instr) { |
| 854 int type = instr->TypeField(); |
| 855 if ((type == 0) && instr->IsSpecialType0()) { |
| 856 // multiply instruction or extra loads and stores |
| 857 if (instr->Bits(7, 4) == 9) { |
| 858 if (instr->Bit(24) == 0) { |
| 859 // multiply instructions |
| 860 if (instr->Bit(23) == 0) { |
| 861 if (instr->Bit(21) == 0) { |
| 862 // The MUL instruction description (A 4.1.33) refers to Rd as being |
| 863 // the destination for the operation, but it confusingly uses the |
| 864 // Rn field to encode it. |
| 865 Format(instr, "mul'cond's 'rn, 'rm, 'rs"); |
| 866 } else { |
| 867 // The MLA instruction description (A 4.1.28) refers to the order |
| 868 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the |
| 869 // Rn field to encode the Rd register and the Rd field to encode |
| 870 // the Rn register. |
| 871 Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd"); |
| 872 } |
| 873 } else { |
| 874 // The signed/long multiply instructions use the terms RdHi and RdLo |
| 875 // when referring to the target registers. They are mapped to the Rn |
| 876 // and Rd fields as follows: |
| 877 // RdLo == Rd field |
| 878 // RdHi == Rn field |
| 879 // The order of registers is: <RdLo>, <RdHi>, <Rm>, <Rs> |
| 880 Format(instr, "'um'al'cond's 'rd, 'rn, 'rm, 'rs"); |
| 881 } |
| 882 } else { |
| 883 Unknown(instr); // not used by V8 |
| 884 } |
| 885 } else { |
| 886 // extra load/store instructions |
| 887 switch (instr->PUField()) { |
| 888 case 0: { |
| 889 if (instr->Bit(22) == 0) { |
| 890 Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm"); |
| 891 } else { |
| 892 Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8"); |
| 893 } |
| 894 break; |
| 895 } |
| 896 case 1: { |
| 897 if (instr->Bit(22) == 0) { |
| 898 Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm"); |
| 899 } else { |
| 900 Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8"); |
| 901 } |
| 902 break; |
| 903 } |
| 904 case 2: { |
| 905 if (instr->Bit(22) == 0) { |
| 906 Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w"); |
| 907 } else { |
| 908 Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w"); |
| 909 } |
| 910 break; |
| 911 } |
| 912 case 3: { |
| 913 if (instr->Bit(22) == 0) { |
| 914 Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w"); |
| 915 } else { |
| 916 Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w"); |
| 917 } |
| 918 break; |
| 919 } |
| 920 default: { |
| 921 // The PU field is a 2-bit field. |
| 922 UNREACHABLE(); |
| 923 break; |
| 924 } |
| 925 } |
| 926 return; |
| 927 } |
| 928 } else { |
| 929 switch (instr->OpcodeField()) { |
| 930 case AND: { |
| 931 Format(instr, "and'cond's 'rd, 'rn, 'shift_op"); |
| 932 break; |
| 933 } |
| 934 case EOR: { |
| 935 Format(instr, "eor'cond's 'rd, 'rn, 'shift_op"); |
| 936 break; |
| 937 } |
| 938 case SUB: { |
| 939 Format(instr, "sub'cond's 'rd, 'rn, 'shift_op"); |
| 940 break; |
| 941 } |
| 942 case RSB: { |
| 943 Format(instr, "rsb'cond's 'rd, 'rn, 'shift_op"); |
| 944 break; |
| 945 } |
| 946 case ADD: { |
| 947 Format(instr, "add'cond's 'rd, 'rn, 'shift_op"); |
| 948 break; |
| 949 } |
| 950 case ADC: { |
| 951 Format(instr, "adc'cond's 'rd, 'rn, 'shift_op"); |
| 952 break; |
| 953 } |
| 954 case SBC: { |
| 955 Format(instr, "sbc'cond's 'rd, 'rn, 'shift_op"); |
| 956 break; |
| 957 } |
| 958 case RSC: { |
| 959 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_op"); |
| 960 break; |
| 961 } |
| 962 case TST: { |
| 963 if (instr->HasS()) { |
| 964 Format(instr, "tst'cond 'rn, 'shift_op"); |
| 965 } else { |
| 966 Unknown(instr); // not used by V8 |
| 967 } |
| 968 break; |
| 969 } |
| 970 case TEQ: { |
| 971 if (instr->HasS()) { |
| 972 Format(instr, "teq'cond 'rn, 'shift_op"); |
| 973 } else { |
| 974 switch (instr->Bits(7, 4)) { |
| 975 case BX: |
| 976 Format(instr, "bx'cond 'rm"); |
| 977 break; |
| 978 case BLX: |
| 979 Format(instr, "blx'cond 'rm"); |
| 980 break; |
| 981 default: |
| 982 Unknown(instr); // not used by V8 |
| 983 break; |
| 984 } |
| 985 } |
| 986 break; |
| 987 } |
| 988 case CMP: { |
| 989 if (instr->HasS()) { |
| 990 Format(instr, "cmp'cond 'rn, 'shift_op"); |
| 991 } else { |
| 992 Unknown(instr); // not used by V8 |
| 993 } |
| 994 break; |
| 995 } |
| 996 case CMN: { |
| 997 if (instr->HasS()) { |
| 998 Format(instr, "cmn'cond 'rn, 'shift_op"); |
| 999 } else { |
| 1000 switch (instr->Bits(7, 4)) { |
| 1001 case CLZ: |
| 1002 Format(instr, "clz'cond 'rd, 'rm"); |
| 1003 break; |
| 1004 default: |
| 1005 Unknown(instr); // not used by V8 |
| 1006 break; |
| 1007 } |
| 1008 } |
| 1009 break; |
| 1010 } |
| 1011 case ORR: { |
| 1012 Format(instr, "orr'cond's 'rd, 'rn, 'shift_op"); |
| 1013 break; |
| 1014 } |
| 1015 case MOV: { |
| 1016 Format(instr, "mov'cond's 'rd, 'shift_op"); |
| 1017 break; |
| 1018 } |
| 1019 case BIC: { |
| 1020 Format(instr, "bic'cond's 'rd, 'rn, 'shift_op"); |
| 1021 break; |
| 1022 } |
| 1023 case MVN: { |
| 1024 Format(instr, "mvn'cond's 'rd, 'shift_op"); |
| 1025 break; |
| 1026 } |
| 1027 default: { |
| 1028 // The Opcode field is a 4-bit field. |
| 1029 UNREACHABLE(); |
| 1030 break; |
| 1031 } |
| 1032 } |
| 1033 } |
| 1034 } |
| 1035 |
| 1036 |
| 1037 void Decoder::DecodeType2(Instr* instr) { |
| 1038 switch (instr->PUField()) { |
| 1039 case 0: { |
| 1040 if (instr->HasW()) { |
| 1041 Unknown(instr); // not used in V8 |
| 1042 } |
| 1043 Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12"); |
| 1044 break; |
| 1045 } |
| 1046 case 1: { |
| 1047 if (instr->HasW()) { |
| 1048 Unknown(instr); // not used in V8 |
| 1049 } |
| 1050 Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12"); |
| 1051 break; |
| 1052 } |
| 1053 case 2: { |
| 1054 Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w"); |
| 1055 break; |
| 1056 } |
| 1057 case 3: { |
| 1058 Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w"); |
| 1059 break; |
| 1060 } |
| 1061 default: { |
| 1062 // The PU field is a 2-bit field. |
| 1063 UNREACHABLE(); |
| 1064 break; |
| 1065 } |
| 1066 } |
| 1067 } |
| 1068 |
| 1069 |
| 1070 void Decoder::DecodeType3(Instr* instr) { |
| 1071 switch (instr->PUField()) { |
| 1072 case 0: { |
| 1073 ASSERT(!instr->HasW()); |
| 1074 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm"); |
| 1075 break; |
| 1076 } |
| 1077 case 1: { |
| 1078 ASSERT(!instr->HasW()); |
| 1079 Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm"); |
| 1080 break; |
| 1081 } |
| 1082 case 2: { |
| 1083 Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w"); |
| 1084 break; |
| 1085 } |
| 1086 case 3: { |
| 1087 if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) { |
| 1088 uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16)); |
| 1089 uint32_t lsbit = static_cast<uint32_t>(instr->ShiftAmountField()); |
| 1090 uint32_t msbit = widthminus1 + lsbit; |
| 1091 if (msbit <= 31) { |
| 1092 Format(instr, "ubfx'cond 'rd, 'rm, #'off7to11, #'off16to20"); |
| 1093 } else { |
| 1094 UNREACHABLE(); |
| 1095 } |
| 1096 } else { |
| 1097 Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w"); |
| 1098 } |
| 1099 break; |
| 1100 } |
| 1101 default: { |
| 1102 // The PU field is a 2-bit field. |
| 1103 UNREACHABLE(); |
| 1104 break; |
| 1105 } |
| 1106 } |
| 1107 } |
| 1108 |
| 1109 |
| 1110 void Decoder::DecodeType4(Instr* instr) { |
| 1111 ASSERT(instr->Bit(22) == 0); // Privileged mode currently not supported. |
| 1112 if (instr->HasL()) { |
| 1113 Format(instr, "ldm'cond'pu 'rn'w, 'rlist"); |
| 1114 } else { |
| 1115 Format(instr, "stm'cond'pu 'rn'w, 'rlist"); |
| 1116 } |
| 1117 } |
| 1118 |
| 1119 |
| 1120 void Decoder::DecodeType5(Instr* instr) { |
| 1121 Format(instr, "b'l'cond 'target"); |
| 1122 } |
| 1123 |
| 1124 |
| 1125 void Decoder::DecodeType6(Instr* instr) { |
| 1126 DecodeType6CoprocessorIns(instr); |
| 1127 } |
| 1128 |
| 1129 |
| 1130 void Decoder::DecodeType7(Instr* instr) { |
| 1131 if (instr->Bit(24) == 1) { |
| 1132 Format(instr, "swi'cond 'swi"); |
| 1133 } else { |
| 1134 DecodeTypeVFP(instr); |
| 1135 } |
| 1136 } |
| 1137 |
| 1138 void Decoder::DecodeUnconditional(Instr* instr) { |
| 1139 if (instr->Bits(7, 4) == 0xB && instr->Bits(27, 25) == 0 && instr->HasL()) { |
| 1140 Format(instr, "'memop'h'pu 'rd, "); |
| 1141 bool immediate = instr->HasB(); |
| 1142 switch (instr->PUField()) { |
| 1143 case 0: { |
| 1144 // Post index, negative. |
| 1145 if (instr->HasW()) { |
| 1146 Unknown(instr); |
| 1147 break; |
| 1148 } |
| 1149 if (immediate) { |
| 1150 Format(instr, "['rn], #-'imm12"); |
| 1151 } else { |
| 1152 Format(instr, "['rn], -'rm"); |
| 1153 } |
| 1154 break; |
| 1155 } |
| 1156 case 1: { |
| 1157 // Post index, positive. |
| 1158 if (instr->HasW()) { |
| 1159 Unknown(instr); |
| 1160 break; |
| 1161 } |
| 1162 if (immediate) { |
| 1163 Format(instr, "['rn], #+'imm12"); |
| 1164 } else { |
| 1165 Format(instr, "['rn], +'rm"); |
| 1166 } |
| 1167 break; |
| 1168 } |
| 1169 case 2: { |
| 1170 // Pre index or offset, negative. |
| 1171 if (immediate) { |
| 1172 Format(instr, "['rn, #-'imm12]'w"); |
| 1173 } else { |
| 1174 Format(instr, "['rn, -'rm]'w"); |
| 1175 } |
| 1176 break; |
| 1177 } |
| 1178 case 3: { |
| 1179 // Pre index or offset, positive. |
| 1180 if (immediate) { |
| 1181 Format(instr, "['rn, #+'imm12]'w"); |
| 1182 } else { |
| 1183 Format(instr, "['rn, +'rm]'w"); |
| 1184 } |
| 1185 break; |
| 1186 } |
| 1187 default: { |
| 1188 // The PU field is a 2-bit field. |
| 1189 UNREACHABLE(); |
| 1190 break; |
| 1191 } |
| 1192 } |
| 1193 return; |
| 1194 } |
| 1195 Format(instr, "break 'msg"); |
| 1196 } |
| 1197 |
| 1198 |
| 1199 // void Decoder::DecodeTypeVFP(Instr* instr) |
| 1200 // vmov: Sn = Rt |
| 1201 // vmov: Rt = Sn |
| 1202 // vcvt: Dd = Sm |
| 1203 // vcvt: Sd = Dm |
| 1204 // Dd = vadd(Dn, Dm) |
| 1205 // Dd = vsub(Dn, Dm) |
| 1206 // Dd = vmul(Dn, Dm) |
| 1207 // Dd = vdiv(Dn, Dm) |
| 1208 // vcmp(Dd, Dm) |
| 1209 // VMRS |
| 1210 void Decoder::DecodeTypeVFP(Instr* instr) { |
| 1211 ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) ); |
| 1212 |
| 1213 if (instr->Bit(23) == 1) { |
| 1214 if ((instr->Bits(21, 19) == 0x7) && |
| 1215 (instr->Bits(18, 16) == 0x5) && |
| 1216 (instr->Bits(11, 9) == 0x5) && |
| 1217 (instr->Bit(8) == 1) && |
| 1218 (instr->Bit(6) == 1) && |
| 1219 (instr->Bit(4) == 0)) { |
| 1220 Format(instr, "vcvt.s32.f64'cond 'Sd, 'Dm"); |
| 1221 } else if ((instr->Bits(21, 19) == 0x7) && |
| 1222 (instr->Bits(18, 16) == 0x0) && |
| 1223 (instr->Bits(11, 9) == 0x5) && |
| 1224 (instr->Bit(8) == 1) && |
| 1225 (instr->Bit(7) == 1) && |
| 1226 (instr->Bit(6) == 1) && |
| 1227 (instr->Bit(4) == 0)) { |
| 1228 Format(instr, "vcvt.f64.s32'cond 'Dd, 'Sm"); |
| 1229 } else if ((instr->Bit(21) == 0x0) && |
| 1230 (instr->Bit(20) == 0x0) && |
| 1231 (instr->Bits(11, 9) == 0x5) && |
| 1232 (instr->Bit(8) == 1) && |
| 1233 (instr->Bit(6) == 0) && |
| 1234 (instr->Bit(4) == 0)) { |
| 1235 Format(instr, "vdiv.f64'cond 'Dd, 'Dn, 'Dm"); |
| 1236 } else if ((instr->Bits(21, 20) == 0x3) && |
| 1237 (instr->Bits(19, 16) == 0x4) && |
| 1238 (instr->Bits(11, 9) == 0x5) && |
| 1239 (instr->Bit(8) == 0x1) && |
| 1240 (instr->Bit(6) == 0x1) && |
| 1241 (instr->Bit(4) == 0x0)) { |
| 1242 Format(instr, "vcmp.f64'cond 'Dd, 'Dm"); |
| 1243 } else if ((instr->Bits(23, 20) == 0xF) && |
| 1244 (instr->Bits(19, 16) == 0x1) && |
| 1245 (instr->Bits(11, 8) == 0xA) && |
| 1246 (instr->Bits(7, 5) == 0x0) && |
| 1247 (instr->Bit(4) == 0x1) && |
| 1248 (instr->Bits(3, 0) == 0x0)) { |
| 1249 if (instr->Bits(15, 12) == 0xF) |
| 1250 Format(instr, "vmrs'cond APSR, FPSCR"); |
| 1251 else |
| 1252 Unknown(instr); // Not used by V8. |
| 1253 } else { |
| 1254 Unknown(instr); // Not used by V8. |
| 1255 } |
| 1256 } else if (instr->Bit(21) == 1) { |
| 1257 if ((instr->Bit(20) == 0x1) && |
| 1258 (instr->Bits(11, 9) == 0x5) && |
| 1259 (instr->Bit(8) == 0x1) && |
| 1260 (instr->Bit(6) == 0) && |
| 1261 (instr->Bit(4) == 0)) { |
| 1262 Format(instr, "vadd.f64'cond 'Dd, 'Dn, 'Dm"); |
| 1263 } else if ((instr->Bit(20) == 0x1) && |
| 1264 (instr->Bits(11, 9) == 0x5) && |
| 1265 (instr->Bit(8) == 0x1) && |
| 1266 (instr->Bit(6) == 1) && |
| 1267 (instr->Bit(4) == 0)) { |
| 1268 Format(instr, "vsub.f64'cond 'Dd, 'Dn, 'Dm"); |
| 1269 } else if ((instr->Bit(20) == 0x0) && |
| 1270 (instr->Bits(11, 9) == 0x5) && |
| 1271 (instr->Bit(8) == 0x1) && |
| 1272 (instr->Bit(6) == 0) && |
| 1273 (instr->Bit(4) == 0)) { |
| 1274 Format(instr, "vmul.f64'cond 'Dd, 'Dn, 'Dm"); |
| 1275 } else { |
| 1276 Unknown(instr); // Not used by V8. |
| 1277 } |
| 1278 } else { |
| 1279 if ((instr->Bit(20) == 0x0) && |
| 1280 (instr->Bits(11, 8) == 0xA) && |
| 1281 (instr->Bits(6, 5) == 0x0) && |
| 1282 (instr->Bit(4) == 1) && |
| 1283 (instr->Bits(3, 0) == 0x0)) { |
| 1284 Format(instr, "vmov'cond 'Sn, 'rt"); |
| 1285 } else if ((instr->Bit(20) == 0x1) && |
| 1286 (instr->Bits(11, 8) == 0xA) && |
| 1287 (instr->Bits(6, 5) == 0x0) && |
| 1288 (instr->Bit(4) == 1) && |
| 1289 (instr->Bits(3, 0) == 0x0)) { |
| 1290 Format(instr, "vmov'cond 'rt, 'Sn"); |
| 1291 } else { |
| 1292 Unknown(instr); // Not used by V8. |
| 1293 } |
| 1294 } |
| 1295 } |
| 1296 |
| 1297 |
| 1298 // Decode Type 6 coprocessor instructions. |
| 1299 // Dm = vmov(Rt, Rt2) |
| 1300 // <Rt, Rt2> = vmov(Dm) |
| 1301 // Ddst = MEM(Rbase + 4*offset). |
| 1302 // MEM(Rbase + 4*offset) = Dsrc. |
| 1303 void Decoder::DecodeType6CoprocessorIns(Instr* instr) { |
| 1304 ASSERT((instr->TypeField() == 6)); |
| 1305 |
| 1306 if (instr->CoprocessorField() != 0xB) { |
| 1307 Unknown(instr); // Not used by V8. |
| 1308 } else { |
| 1309 switch (instr->OpcodeField()) { |
| 1310 case 0x2: |
| 1311 // Load and store double to two GP registers |
| 1312 if (instr->Bits(7, 4) != 0x1) { |
| 1313 Unknown(instr); // Not used by V8. |
| 1314 } else if (instr->HasL()) { |
| 1315 Format(instr, "vmov'cond 'rt, 'rn, 'Dm"); |
| 1316 } else { |
| 1317 Format(instr, "vmov'cond 'Dm, 'rt, 'rn"); |
| 1318 } |
| 1319 break; |
| 1320 case 0x8: |
| 1321 if (instr->HasL()) { |
| 1322 Format(instr, "vldr'cond 'Dd, ['rn - 4*'off8]"); |
| 1323 } else { |
| 1324 Format(instr, "vstr'cond 'Dd, ['rn - 4*'off8]"); |
| 1325 } |
| 1326 break; |
| 1327 case 0xC: |
| 1328 if (instr->HasL()) { |
| 1329 Format(instr, "vldr'cond 'Dd, ['rn + 4*'off8]"); |
| 1330 } else { |
| 1331 Format(instr, "vstr'cond 'Dd, ['rn + 4*'off8]"); |
| 1332 } |
| 1333 break; |
| 1334 default: |
| 1335 Unknown(instr); // Not used by V8. |
| 1336 break; |
| 1337 } |
| 1338 } |
| 1339 } |
| 1340 |
| 1341 |
| 1342 // Disassemble the instruction at *instr_ptr into the output buffer. |
| 1343 int Decoder::InstructionDecode(byte* instr_ptr) { |
| 1344 if (reinterpret_cast<int32_t>(instr_ptr) & 1) { |
| 1345 InstrThumb2 instr(instr_ptr); |
| 1346 return InstructionDecodeThumb2(instr); |
| 1347 } else { |
| 1348 return InstructionDecodeArm(instr_ptr); |
| 1349 } |
| 1350 } |
| 1351 |
| 1352 int Decoder::InstructionDecodeArm(byte* instr_ptr) { |
| 1353 Instr* instr = Instr::At(instr_ptr); |
| 1354 // Print raw instruction bytes. |
| 1355 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, |
| 1356 "%08x ", |
| 1357 instr->InstructionBits()); |
| 1358 if (instr->ConditionField() == special_condition) { |
| 1359 DecodeUnconditional(instr); |
| 1360 return Instr::kInstrSize; |
| 1361 } |
| 1362 switch (instr->TypeField()) { |
| 1363 case 0: |
| 1364 case 1: { |
| 1365 DecodeType01(instr); |
| 1366 break; |
| 1367 } |
| 1368 case 2: { |
| 1369 DecodeType2(instr); |
| 1370 break; |
| 1371 } |
| 1372 case 3: { |
| 1373 DecodeType3(instr); |
| 1374 break; |
| 1375 } |
| 1376 case 4: { |
| 1377 DecodeType4(instr); |
| 1378 break; |
| 1379 } |
| 1380 case 5: { |
| 1381 DecodeType5(instr); |
| 1382 break; |
| 1383 } |
| 1384 case 6: { |
| 1385 DecodeType6(instr); |
| 1386 break; |
| 1387 } |
| 1388 case 7: { |
| 1389 DecodeType7(instr); |
| 1390 break; |
| 1391 } |
| 1392 default: { |
| 1393 // The type field is 3-bits in the ARM encoding. |
| 1394 UNREACHABLE(); |
| 1395 break; |
| 1396 } |
| 1397 } |
| 1398 return Instr::kInstrSize; |
| 1399 } |
| 1400 |
| 1401 |
| 1402 int Decoder::InstructionDecodeThumb2(const InstrThumb2& instr) { |
| 1403 switch (instr.Op()) { |
| 1404 case OP_ADD: |
| 1405 Format(instr, "and's 'rd, 'rn, 'shift_op"); |
| 1406 break; |
| 1407 case OP_AND: |
| 1408 Format(instr, "and's 'rd, 'rn, 'shift_op"); |
| 1409 break; |
| 1410 case OP_SUB: |
| 1411 Format(instr, "sub's 'rd, 'rn, 'shift_op"); |
| 1412 break; |
| 1413 default: |
| 1414 UNIMPLEMENTED(); |
| 1415 break; |
| 1416 } |
| 1417 return instr.Size(); |
| 1418 } |
| 1419 |
| 1420 |
| 1421 } } // namespace assembler::arm |
| 1422 |
| 1423 |
| 1424 |
| 1425 //------------------------------------------------------------------------------ |
| 1426 |
| 1427 namespace disasm { |
| 1428 |
| 1429 namespace v8i = v8::internal; |
| 1430 |
| 1431 |
| 1432 const char* NameConverter::NameOfAddress(byte* addr) const { |
| 1433 static v8::internal::EmbeddedVector<char, 32> tmp_buffer; |
| 1434 v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr); |
| 1435 return tmp_buffer.start(); |
| 1436 } |
| 1437 |
| 1438 |
| 1439 const char* NameConverter::NameOfConstant(byte* addr) const { |
| 1440 return NameOfAddress(addr); |
| 1441 } |
| 1442 |
| 1443 |
| 1444 const char* NameConverter::NameOfCPURegister(int reg) const { |
| 1445 return assembler::arm::Registers::Name(reg); |
| 1446 } |
| 1447 |
| 1448 |
| 1449 const char* NameConverter::NameOfByteCPURegister(int reg) const { |
| 1450 UNREACHABLE(); // ARM does not have the concept of a byte register |
| 1451 return "nobytereg"; |
| 1452 } |
| 1453 |
| 1454 |
| 1455 const char* NameConverter::NameOfXMMRegister(int reg) const { |
| 1456 UNREACHABLE(); // ARM does not have any XMM registers |
| 1457 return "noxmmreg"; |
| 1458 } |
| 1459 |
| 1460 |
| 1461 const char* NameConverter::NameInCode(byte* addr) const { |
| 1462 // The default name converter is called for unknown code. So we will not try |
| 1463 // to access any memory. |
| 1464 return ""; |
| 1465 } |
| 1466 |
| 1467 |
| 1468 //------------------------------------------------------------------------------ |
| 1469 |
| 1470 Disassembler::Disassembler(const NameConverter& converter) |
| 1471 : converter_(converter) {} |
| 1472 |
| 1473 |
| 1474 Disassembler::~Disassembler() {} |
| 1475 |
| 1476 |
| 1477 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, |
| 1478 byte* instruction) { |
| 1479 assembler::arm::Decoder d(converter_, buffer); |
| 1480 return d.InstructionDecode(instruction); |
| 1481 } |
| 1482 |
| 1483 |
| 1484 int Disassembler::ConstantPoolSizeAt(byte* instruction) { |
| 1485 int instruction_bits = *(reinterpret_cast<int*>(instruction)); |
| 1486 if ((instruction_bits & 0xfff00000) == 0x03000000) { |
| 1487 return instruction_bits & 0x0000ffff; |
| 1488 } else { |
| 1489 return -1; |
| 1490 } |
| 1491 } |
| 1492 |
| 1493 |
| 1494 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { |
| 1495 NameConverter converter; |
| 1496 Disassembler d(converter); |
| 1497 for (byte* pc = begin; pc < end;) { |
| 1498 v8::internal::EmbeddedVector<char, 128> buffer; |
| 1499 buffer[0] = '\0'; |
| 1500 byte* prev_pc = pc; |
| 1501 pc += d.InstructionDecode(buffer, pc); |
| 1502 fprintf(f, "%p %08x %s\n", |
| 1503 prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start()); |
| 1504 } |
| 1505 } |
| 1506 |
| 1507 |
| 1508 } // namespace disasm |
| OLD | NEW |