OLD | NEW |
| (Empty) |
1 // Copyright 2007-2008 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 "disasm.h" | |
61 #include "macro-assembler.h" | |
62 #include "platform.h" | |
63 | |
64 | |
65 namespace assembler { namespace arm { | |
66 | |
67 namespace v8i = v8::internal; | |
68 | |
69 | |
70 //------------------------------------------------------------------------------ | |
71 | |
72 // Decoder decodes and disassembles instructions into an output buffer. | |
73 // It uses the converter to convert register names and call destinations into | |
74 // more informative description. | |
75 class Decoder { | |
76 public: | |
77 Decoder(const disasm::NameConverter& converter, | |
78 v8::internal::Vector<char> out_buffer) | |
79 : converter_(converter), | |
80 out_buffer_(out_buffer), | |
81 out_buffer_pos_(0) { | |
82 out_buffer_[out_buffer_pos_] = '\0'; | |
83 } | |
84 | |
85 ~Decoder() {} | |
86 | |
87 // Writes one disassembled instruction into 'buffer' (0-terminated). | |
88 // Returns the length of the disassembled machine instruction in bytes. | |
89 int InstructionDecode(byte* instruction); | |
90 | |
91 private: | |
92 // Bottleneck functions to print into the out_buffer. | |
93 void PrintChar(const char ch); | |
94 void Print(const char* str); | |
95 | |
96 // Printing of common values. | |
97 void PrintRegister(int reg); | |
98 void PrintCondition(Instr* instr); | |
99 void PrintShiftRm(Instr* instr); | |
100 void PrintShiftImm(Instr* instr); | |
101 void PrintPU(Instr* instr); | |
102 void PrintSoftwareInterrupt(SoftwareInterruptCodes swi); | |
103 | |
104 // Handle formatting of instructions and their options. | |
105 int FormatRegister(Instr* instr, const char* option); | |
106 int FormatOption(Instr* instr, const char* option); | |
107 void Format(Instr* instr, const char* format); | |
108 void Unknown(Instr* instr); | |
109 | |
110 // Each of these functions decodes one particular instruction type, a 3-bit | |
111 // field in the instruction encoding. | |
112 // Types 0 and 1 are combined as they are largely the same except for the way | |
113 // they interpret the shifter operand. | |
114 void DecodeType01(Instr* instr); | |
115 void DecodeType2(Instr* instr); | |
116 void DecodeType3(Instr* instr); | |
117 void DecodeType4(Instr* instr); | |
118 void DecodeType5(Instr* instr); | |
119 void DecodeType6(Instr* instr); | |
120 void DecodeType7(Instr* instr); | |
121 | |
122 const disasm::NameConverter& converter_; | |
123 v8::internal::Vector<char> out_buffer_; | |
124 int out_buffer_pos_; | |
125 | |
126 DISALLOW_COPY_AND_ASSIGN(Decoder); | |
127 }; | |
128 | |
129 | |
130 // Support for assertions in the Decoder formatting functions. | |
131 #define STRING_STARTS_WITH(string, compare_string) \ | |
132 (strncmp(string, compare_string, strlen(compare_string)) == 0) | |
133 | |
134 | |
135 // Append the ch to the output buffer. | |
136 void Decoder::PrintChar(const char ch) { | |
137 out_buffer_[out_buffer_pos_++] = ch; | |
138 } | |
139 | |
140 | |
141 // Append the str to the output buffer. | |
142 void Decoder::Print(const char* str) { | |
143 char cur = *str++; | |
144 while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) { | |
145 PrintChar(cur); | |
146 cur = *str++; | |
147 } | |
148 out_buffer_[out_buffer_pos_] = 0; | |
149 } | |
150 | |
151 | |
152 // These condition names are defined in a way to match the native disassembler | |
153 // formatting. See for example the command "objdump -d <binary file>". | |
154 static const char* cond_names[max_condition] = { | |
155 "eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" , | |
156 "hi", "ls", "ge", "lt", "gt", "le", "", "invalid", | |
157 }; | |
158 | |
159 | |
160 // Print the condition guarding the instruction. | |
161 void Decoder::PrintCondition(Instr* instr) { | |
162 Print(cond_names[instr->ConditionField()]); | |
163 } | |
164 | |
165 | |
166 // Print the register name according to the active name converter. | |
167 void Decoder::PrintRegister(int reg) { | |
168 Print(converter_.NameOfCPURegister(reg)); | |
169 } | |
170 | |
171 | |
172 // These shift 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* shift_names[max_shift] = { | |
175 "lsl", "lsr", "asr", "ror" | |
176 }; | |
177 | |
178 | |
179 // Print the register shift operands for the instruction. Generally used for | |
180 // data processing instructions. | |
181 void Decoder::PrintShiftRm(Instr* instr) { | |
182 Shift shift = instr->ShiftField(); | |
183 int shift_amount = instr->ShiftAmountField(); | |
184 int rm = instr->RmField(); | |
185 | |
186 PrintRegister(rm); | |
187 | |
188 if ((instr->RegShiftField() == 0) && (shift == LSL) && (shift_amount == 0)) { | |
189 // Special case for using rm only. | |
190 return; | |
191 } | |
192 if (instr->RegShiftField() == 0) { | |
193 // by immediate | |
194 if ((shift == ROR) && (shift_amount == 0)) { | |
195 Print(", RRX"); | |
196 return; | |
197 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) { | |
198 shift_amount = 32; | |
199 } | |
200 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, | |
201 ", %s #%d", | |
202 shift_names[shift], shift_amount); | |
203 } else { | |
204 // by register | |
205 int rs = instr->RsField(); | |
206 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, | |
207 ", %s ", shift_names[shift]); | |
208 PrintRegister(rs); | |
209 } | |
210 } | |
211 | |
212 | |
213 // Print the immediate operand for the instruction. Generally used for data | |
214 // processing instructions. | |
215 void Decoder::PrintShiftImm(Instr* instr) { | |
216 int rotate = instr->RotateField() * 2; | |
217 int immed8 = instr->Immed8Field(); | |
218 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate)); | |
219 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, | |
220 "#%d", imm); | |
221 } | |
222 | |
223 | |
224 // Print PU formatting to reduce complexity of FormatOption. | |
225 void Decoder::PrintPU(Instr* instr) { | |
226 switch (instr->PUField()) { | |
227 case 0: { | |
228 Print("da"); | |
229 break; | |
230 } | |
231 case 1: { | |
232 Print("ia"); | |
233 break; | |
234 } | |
235 case 2: { | |
236 Print("db"); | |
237 break; | |
238 } | |
239 case 3: { | |
240 Print("ib"); | |
241 break; | |
242 } | |
243 default: { | |
244 UNREACHABLE(); | |
245 break; | |
246 } | |
247 } | |
248 } | |
249 | |
250 | |
251 // Print SoftwareInterrupt codes. Factoring this out reduces the complexity of | |
252 // the FormatOption method. | |
253 void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) { | |
254 switch (swi) { | |
255 case call_rt_r5: | |
256 Print("call_rt_r5"); | |
257 return; | |
258 case call_rt_r2: | |
259 Print("call_rt_r2"); | |
260 return; | |
261 case break_point: | |
262 Print("break_point"); | |
263 return; | |
264 case simulator_fp_add: | |
265 Print("simulator_fp_add"); | |
266 return; | |
267 case simulator_fp_mul: | |
268 Print("simulator_fp_mul"); | |
269 return; | |
270 case simulator_fp_sub: | |
271 Print("simulator_fp_sub"); | |
272 return; | |
273 default: | |
274 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, | |
275 "%d", | |
276 swi); | |
277 return; | |
278 } | |
279 } | |
280 | |
281 | |
282 // Handle all register based formatting in this function to reduce the | |
283 // complexity of FormatOption. | |
284 int Decoder::FormatRegister(Instr* instr, const char* format) { | |
285 ASSERT(format[0] == 'r'); | |
286 if (format[1] == 'n') { // 'rn: Rn register | |
287 int reg = instr->RnField(); | |
288 PrintRegister(reg); | |
289 return 2; | |
290 } else if (format[1] == 'd') { // 'rd: Rd register | |
291 int reg = instr->RdField(); | |
292 PrintRegister(reg); | |
293 return 2; | |
294 } else if (format[1] == 's') { // 'rs: Rs register | |
295 int reg = instr->RsField(); | |
296 PrintRegister(reg); | |
297 return 2; | |
298 } else if (format[1] == 'm') { // 'rm: Rm register | |
299 int reg = instr->RmField(); | |
300 PrintRegister(reg); | |
301 return 2; | |
302 } else if (format[1] == 'l') { | |
303 // 'rlist: register list for load and store multiple instructions | |
304 ASSERT(STRING_STARTS_WITH(format, "rlist")); | |
305 int rlist = instr->RlistField(); | |
306 int reg = 0; | |
307 Print("{"); | |
308 // Print register list in ascending order, by scanning the bit mask. | |
309 while (rlist != 0) { | |
310 if ((rlist & 1) != 0) { | |
311 PrintRegister(reg); | |
312 if ((rlist >> 1) != 0) { | |
313 Print(", "); | |
314 } | |
315 } | |
316 reg++; | |
317 rlist >>= 1; | |
318 } | |
319 Print("}"); | |
320 return 5; | |
321 } | |
322 UNREACHABLE(); | |
323 return -1; | |
324 } | |
325 | |
326 | |
327 // FormatOption takes a formatting string and interprets it based on | |
328 // the current instructions. The format string points to the first | |
329 // character of the option string (the option escape has already been | |
330 // consumed by the caller.) FormatOption returns the number of | |
331 // characters that were consumed from the formatting string. | |
332 int Decoder::FormatOption(Instr* instr, const char* format) { | |
333 switch (format[0]) { | |
334 case 'a': { // 'a: accumulate multiplies | |
335 if (instr->Bit(21) == 0) { | |
336 Print("ul"); | |
337 } else { | |
338 Print("la"); | |
339 } | |
340 return 1; | |
341 } | |
342 case 'b': { // 'b: byte loads or stores | |
343 if (instr->HasB()) { | |
344 Print("b"); | |
345 } | |
346 return 1; | |
347 } | |
348 case 'c': { // 'cond: conditional execution | |
349 ASSERT(STRING_STARTS_WITH(format, "cond")); | |
350 PrintCondition(instr); | |
351 return 4; | |
352 } | |
353 case 'h': { // 'h: halfword operation for extra loads and stores | |
354 if (instr->HasH()) { | |
355 Print("h"); | |
356 } else { | |
357 Print("b"); | |
358 } | |
359 return 1; | |
360 } | |
361 case 'l': { // 'l: branch and link | |
362 if (instr->HasLink()) { | |
363 Print("l"); | |
364 } | |
365 return 1; | |
366 } | |
367 case 'm': { | |
368 if (format[1] == 'e') { // 'memop: load/store instructions | |
369 ASSERT(STRING_STARTS_WITH(format, "memop")); | |
370 if (instr->HasL()) { | |
371 Print("ldr"); | |
372 } else { | |
373 Print("str"); | |
374 } | |
375 return 5; | |
376 } | |
377 // 'msg: for simulator break instructions | |
378 ASSERT(STRING_STARTS_WITH(format, "msg")); | |
379 byte* str = | |
380 reinterpret_cast<byte*>(instr->InstructionBits() & 0x0fffffff); | |
381 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, | |
382 "%s", converter_.NameInCode(str)); | |
383 return 3; | |
384 } | |
385 case 'o': { | |
386 if (format[3] == '1') { | |
387 // 'off12: 12-bit offset for load and store instructions | |
388 ASSERT(STRING_STARTS_WITH(format, "off12")); | |
389 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, | |
390 "%d", instr->Offset12Field()); | |
391 return 5; | |
392 } | |
393 // 'off8: 8-bit offset for extra load and store instructions | |
394 ASSERT(STRING_STARTS_WITH(format, "off8")); | |
395 int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField(); | |
396 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, | |
397 "%d", offs8); | |
398 return 4; | |
399 } | |
400 case 'p': { // 'pu: P and U bits for load and store instructions | |
401 ASSERT(STRING_STARTS_WITH(format, "pu")); | |
402 PrintPU(instr); | |
403 return 2; | |
404 } | |
405 case 'r': { | |
406 return FormatRegister(instr, format); | |
407 } | |
408 case 's': { | |
409 if (format[1] == 'h') { // 'shift_op or 'shift_rm | |
410 if (format[6] == 'o') { // 'shift_op | |
411 ASSERT(STRING_STARTS_WITH(format, "shift_op")); | |
412 if (instr->TypeField() == 0) { | |
413 PrintShiftRm(instr); | |
414 } else { | |
415 ASSERT(instr->TypeField() == 1); | |
416 PrintShiftImm(instr); | |
417 } | |
418 return 8; | |
419 } else { // 'shift_rm | |
420 ASSERT(STRING_STARTS_WITH(format, "shift_rm")); | |
421 PrintShiftRm(instr); | |
422 return 8; | |
423 } | |
424 } else if (format[1] == 'w') { // 'swi | |
425 ASSERT(STRING_STARTS_WITH(format, "swi")); | |
426 PrintSoftwareInterrupt(instr->SwiField()); | |
427 return 3; | |
428 } else if (format[1] == 'i') { // 'sign: signed extra loads and stores | |
429 ASSERT(STRING_STARTS_WITH(format, "sign")); | |
430 if (instr->HasSign()) { | |
431 Print("s"); | |
432 } | |
433 return 4; | |
434 } | |
435 // 's: S field of data processing instructions | |
436 if (instr->HasS()) { | |
437 Print("s"); | |
438 } | |
439 return 1; | |
440 } | |
441 case 't': { // 'target: target of branch instructions | |
442 ASSERT(STRING_STARTS_WITH(format, "target")); | |
443 int off = (instr->SImmed24Field() << 2) + 8; | |
444 out_buffer_pos_ += v8i::OS::SNPrintF( | |
445 out_buffer_ + out_buffer_pos_, | |
446 "%+d -> %s", | |
447 off, | |
448 converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off)); | |
449 return 6; | |
450 } | |
451 case 'u': { // 'u: signed or unsigned multiplies | |
452 if (instr->Bit(22) == 0) { | |
453 Print("u"); | |
454 } else { | |
455 Print("s"); | |
456 } | |
457 return 1; | |
458 } | |
459 case 'w': { // 'w: W field of load and store instructions | |
460 if (instr->HasW()) { | |
461 Print("!"); | |
462 } | |
463 return 1; | |
464 } | |
465 default: { | |
466 UNREACHABLE(); | |
467 break; | |
468 } | |
469 } | |
470 UNREACHABLE(); | |
471 return -1; | |
472 } | |
473 | |
474 | |
475 // Format takes a formatting string for a whole instruction and prints it into | |
476 // the output buffer. All escaped options are handed to FormatOption to be | |
477 // parsed further. | |
478 void Decoder::Format(Instr* instr, const char* format) { | |
479 char cur = *format++; | |
480 while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) { | |
481 if (cur == '\'') { // Single quote is used as the formatting escape. | |
482 format += FormatOption(instr, format); | |
483 } else { | |
484 out_buffer_[out_buffer_pos_++] = cur; | |
485 } | |
486 cur = *format++; | |
487 } | |
488 out_buffer_[out_buffer_pos_] = '\0'; | |
489 } | |
490 | |
491 | |
492 // For currently unimplemented decodings the disassembler calls Unknown(instr) | |
493 // which will just print "unknown" of the instruction bits. | |
494 void Decoder::Unknown(Instr* instr) { | |
495 Format(instr, "unknown"); | |
496 } | |
497 | |
498 | |
499 void Decoder::DecodeType01(Instr* instr) { | |
500 int type = instr->TypeField(); | |
501 if ((type == 0) && instr->IsSpecialType0()) { | |
502 // multiply instruction or extra loads and stores | |
503 if (instr->Bits(7, 4) == 9) { | |
504 if (instr->Bit(24) == 0) { | |
505 // multiply instructions | |
506 if (instr->Bit(23) == 0) { | |
507 if (instr->Bit(21) == 0) { | |
508 Format(instr, "mul'cond's 'rd, 'rm, 'rs"); | |
509 } else { | |
510 Format(instr, "mla'cond's 'rd, 'rm, 'rs, 'rn"); | |
511 } | |
512 } else { | |
513 Format(instr, "'um'al'cond's 'rn, 'rd, 'rs, 'rm"); | |
514 } | |
515 } else { | |
516 Unknown(instr); // not used by V8 | |
517 } | |
518 } else { | |
519 // extra load/store instructions | |
520 switch (instr->PUField()) { | |
521 case 0: { | |
522 if (instr->Bit(22) == 0) { | |
523 Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm"); | |
524 } else { | |
525 Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8"); | |
526 } | |
527 break; | |
528 } | |
529 case 1: { | |
530 if (instr->Bit(22) == 0) { | |
531 Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm"); | |
532 } else { | |
533 Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8"); | |
534 } | |
535 break; | |
536 } | |
537 case 2: { | |
538 if (instr->Bit(22) == 0) { | |
539 Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w"); | |
540 } else { | |
541 Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w"); | |
542 } | |
543 break; | |
544 } | |
545 case 3: { | |
546 if (instr->Bit(22) == 0) { | |
547 Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w"); | |
548 } else { | |
549 Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w"); | |
550 } | |
551 break; | |
552 } | |
553 default: { | |
554 // The PU field is a 2-bit field. | |
555 UNREACHABLE(); | |
556 break; | |
557 } | |
558 } | |
559 return; | |
560 } | |
561 } else { | |
562 switch (instr->OpcodeField()) { | |
563 case AND: { | |
564 Format(instr, "and'cond's 'rd, 'rn, 'shift_op"); | |
565 break; | |
566 } | |
567 case EOR: { | |
568 Format(instr, "eor'cond's 'rd, 'rn, 'shift_op"); | |
569 break; | |
570 } | |
571 case SUB: { | |
572 Format(instr, "sub'cond's 'rd, 'rn, 'shift_op"); | |
573 break; | |
574 } | |
575 case RSB: { | |
576 Format(instr, "rsb'cond's 'rd, 'rn, 'shift_op"); | |
577 break; | |
578 } | |
579 case ADD: { | |
580 Format(instr, "add'cond's 'rd, 'rn, 'shift_op"); | |
581 break; | |
582 } | |
583 case ADC: { | |
584 Format(instr, "adc'cond's 'rd, 'rn, 'shift_op"); | |
585 break; | |
586 } | |
587 case SBC: { | |
588 Format(instr, "sbc'cond's 'rd, 'rn, 'shift_op"); | |
589 break; | |
590 } | |
591 case RSC: { | |
592 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_op"); | |
593 break; | |
594 } | |
595 case TST: { | |
596 if (instr->HasS()) { | |
597 Format(instr, "tst'cond 'rn, 'shift_op"); | |
598 } else { | |
599 Unknown(instr); // not used by V8 | |
600 } | |
601 break; | |
602 } | |
603 case TEQ: { | |
604 if (instr->HasS()) { | |
605 Format(instr, "teq'cond 'rn, 'shift_op"); | |
606 } else { | |
607 Unknown(instr); // not used by V8 | |
608 } | |
609 break; | |
610 } | |
611 case CMP: { | |
612 if (instr->HasS()) { | |
613 Format(instr, "cmp'cond 'rn, 'shift_op"); | |
614 } else { | |
615 Unknown(instr); // not used by V8 | |
616 } | |
617 break; | |
618 } | |
619 case CMN: { | |
620 if (instr->HasS()) { | |
621 Format(instr, "cmn'cond 'rn, 'shift_op"); | |
622 } else { | |
623 Unknown(instr); // not used by V8 | |
624 } | |
625 break; | |
626 } | |
627 case ORR: { | |
628 Format(instr, "orr'cond's 'rd, 'rn, 'shift_op"); | |
629 break; | |
630 } | |
631 case MOV: { | |
632 Format(instr, "mov'cond's 'rd, 'shift_op"); | |
633 break; | |
634 } | |
635 case BIC: { | |
636 Format(instr, "bic'cond's 'rd, 'rn, 'shift_op"); | |
637 break; | |
638 } | |
639 case MVN: { | |
640 Format(instr, "mvn'cond's 'rd, 'shift_op"); | |
641 break; | |
642 } | |
643 default: { | |
644 // The Opcode field is a 4-bit field. | |
645 UNREACHABLE(); | |
646 break; | |
647 } | |
648 } | |
649 } | |
650 } | |
651 | |
652 | |
653 void Decoder::DecodeType2(Instr* instr) { | |
654 switch (instr->PUField()) { | |
655 case 0: { | |
656 if (instr->HasW()) { | |
657 Unknown(instr); // not used in V8 | |
658 } | |
659 Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12"); | |
660 break; | |
661 } | |
662 case 1: { | |
663 if (instr->HasW()) { | |
664 Unknown(instr); // not used in V8 | |
665 } | |
666 Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12"); | |
667 break; | |
668 } | |
669 case 2: { | |
670 Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w"); | |
671 break; | |
672 } | |
673 case 3: { | |
674 Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w"); | |
675 break; | |
676 } | |
677 default: { | |
678 // The PU field is a 2-bit field. | |
679 UNREACHABLE(); | |
680 break; | |
681 } | |
682 } | |
683 } | |
684 | |
685 | |
686 void Decoder::DecodeType3(Instr* instr) { | |
687 switch (instr->PUField()) { | |
688 case 0: { | |
689 ASSERT(!instr->HasW()); | |
690 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm"); | |
691 break; | |
692 } | |
693 case 1: { | |
694 ASSERT(!instr->HasW()); | |
695 Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm"); | |
696 break; | |
697 } | |
698 case 2: { | |
699 Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w"); | |
700 break; | |
701 } | |
702 case 3: { | |
703 Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w"); | |
704 break; | |
705 } | |
706 default: { | |
707 // The PU field is a 2-bit field. | |
708 UNREACHABLE(); | |
709 break; | |
710 } | |
711 } | |
712 } | |
713 | |
714 | |
715 void Decoder::DecodeType4(Instr* instr) { | |
716 ASSERT(instr->Bit(22) == 0); // Privileged mode currently not supported. | |
717 if (instr->HasL()) { | |
718 Format(instr, "ldm'cond'pu 'rn'w, 'rlist"); | |
719 } else { | |
720 Format(instr, "stm'cond'pu 'rn'w, 'rlist"); | |
721 } | |
722 } | |
723 | |
724 | |
725 void Decoder::DecodeType5(Instr* instr) { | |
726 Format(instr, "b'l'cond 'target"); | |
727 } | |
728 | |
729 | |
730 void Decoder::DecodeType6(Instr* instr) { | |
731 // Coprocessor instructions currently not supported. | |
732 Unknown(instr); | |
733 } | |
734 | |
735 | |
736 void Decoder::DecodeType7(Instr* instr) { | |
737 if (instr->Bit(24) == 1) { | |
738 Format(instr, "swi'cond 'swi"); | |
739 } else { | |
740 // Coprocessor instructions currently not supported. | |
741 Unknown(instr); | |
742 } | |
743 } | |
744 | |
745 | |
746 // Disassemble the instruction at *instr_ptr into the output buffer. | |
747 int Decoder::InstructionDecode(byte* instr_ptr) { | |
748 Instr* instr = Instr::At(instr_ptr); | |
749 // Print raw instruction bytes. | |
750 out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, | |
751 "%08x ", | |
752 instr->InstructionBits()); | |
753 if (instr->ConditionField() == special_condition) { | |
754 Format(instr, "break 'msg"); | |
755 return Instr::kInstrSize; | |
756 } | |
757 switch (instr->TypeField()) { | |
758 case 0: | |
759 case 1: { | |
760 DecodeType01(instr); | |
761 break; | |
762 } | |
763 case 2: { | |
764 DecodeType2(instr); | |
765 break; | |
766 } | |
767 case 3: { | |
768 DecodeType3(instr); | |
769 break; | |
770 } | |
771 case 4: { | |
772 DecodeType4(instr); | |
773 break; | |
774 } | |
775 case 5: { | |
776 DecodeType5(instr); | |
777 break; | |
778 } | |
779 case 6: { | |
780 DecodeType6(instr); | |
781 break; | |
782 } | |
783 case 7: { | |
784 DecodeType7(instr); | |
785 break; | |
786 } | |
787 default: { | |
788 // The type field is 3-bits in the ARM encoding. | |
789 UNREACHABLE(); | |
790 break; | |
791 } | |
792 } | |
793 return Instr::kInstrSize; | |
794 } | |
795 | |
796 | |
797 } } // namespace assembler::arm | |
798 | |
799 | |
800 | |
801 //------------------------------------------------------------------------------ | |
802 | |
803 namespace disasm { | |
804 | |
805 namespace v8i = v8::internal; | |
806 | |
807 | |
808 static const int kMaxRegisters = 16; | |
809 | |
810 // These register names are defined in a way to match the native disassembler | |
811 // formatting. See for example the command "objdump -d <binary file>". | |
812 static const char* reg_names[kMaxRegisters] = { | |
813 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | |
814 "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", | |
815 }; | |
816 | |
817 | |
818 const char* NameConverter::NameOfAddress(byte* addr) const { | |
819 static v8::internal::EmbeddedVector<char, 32> tmp_buffer; | |
820 v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr); | |
821 return tmp_buffer.start(); | |
822 } | |
823 | |
824 | |
825 const char* NameConverter::NameOfConstant(byte* addr) const { | |
826 return NameOfAddress(addr); | |
827 } | |
828 | |
829 | |
830 const char* NameConverter::NameOfCPURegister(int reg) const { | |
831 const char* result; | |
832 if ((0 <= reg) && (reg < kMaxRegisters)) { | |
833 result = reg_names[reg]; | |
834 } else { | |
835 result = "noreg"; | |
836 } | |
837 return result; | |
838 } | |
839 | |
840 | |
841 const char* NameConverter::NameOfByteCPURegister(int reg) const { | |
842 UNREACHABLE(); // ARM does not have the concept of a byte register | |
843 return "nobytereg"; | |
844 } | |
845 | |
846 | |
847 const char* NameConverter::NameOfXMMRegister(int reg) const { | |
848 UNREACHABLE(); // ARM does not have any XMM registers | |
849 return "noxmmreg"; | |
850 } | |
851 | |
852 | |
853 const char* NameConverter::NameInCode(byte* addr) const { | |
854 // The default name converter is called for unknown code. So we will not try | |
855 // to access any memory. | |
856 return ""; | |
857 } | |
858 | |
859 | |
860 //------------------------------------------------------------------------------ | |
861 | |
862 Disassembler::Disassembler(const NameConverter& converter) | |
863 : converter_(converter) {} | |
864 | |
865 | |
866 Disassembler::~Disassembler() {} | |
867 | |
868 | |
869 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, | |
870 byte* instruction) { | |
871 assembler::arm::Decoder d(converter_, buffer); | |
872 return d.InstructionDecode(instruction); | |
873 } | |
874 | |
875 | |
876 int Disassembler::ConstantPoolSizeAt(byte* instruction) { | |
877 int instruction_bits = *(reinterpret_cast<int*>(instruction)); | |
878 if ((instruction_bits & 0xfff00000) == 0x03000000) { | |
879 return instruction_bits & 0x0000ffff; | |
880 } else { | |
881 return -1; | |
882 } | |
883 } | |
884 | |
885 | |
886 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { | |
887 NameConverter converter; | |
888 Disassembler d(converter); | |
889 for (byte* pc = begin; pc < end;) { | |
890 v8::internal::EmbeddedVector<char, 128> buffer; | |
891 buffer[0] = '\0'; | |
892 byte* prev_pc = pc; | |
893 pc += d.InstructionDecode(buffer, pc); | |
894 fprintf(f, "%p %08x %s\n", | |
895 prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start()); | |
896 } | |
897 } | |
898 | |
899 | |
900 } // namespace disasm | |
OLD | NEW |