• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // A Disassembler object is used to disassemble a block of code instruction by
6 // instruction. The default implementation of the NameConverter object can be
7 // overriden to modify register names or to do symbol lookup on addresses.
8 //
9 // The example below will disassemble a block of code and print it to stdout.
10 //
11 //   NameConverter converter;
12 //   Disassembler d(converter);
13 //   for (byte* pc = begin; pc < end;) {
14 //     v8::internal::EmbeddedVector<char, 256> buffer;
15 //     byte* prev_pc = pc;
16 //     pc += d.InstructionDecode(buffer, pc);
17 //     printf("%p    %08x      %s\n",
18 //            prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
19 //   }
20 //
21 // The Disassembler class also has a convenience method to disassemble a block
22 // of code into a FILE*, meaning that the above functionality could also be
23 // achieved by just calling Disassembler::Disassemble(stdout, begin, end);
24 
25 
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 
31 #include "src/v8.h"
32 
33 #if V8_TARGET_ARCH_MIPS
34 
35 #include "src/base/platform/platform.h"
36 #include "src/disasm.h"
37 #include "src/macro-assembler.h"
38 #include "src/mips/constants-mips.h"
39 
40 namespace v8 {
41 namespace internal {
42 
43 //------------------------------------------------------------------------------
44 
45 // Decoder decodes and disassembles instructions into an output buffer.
46 // It uses the converter to convert register names and call destinations into
47 // more informative description.
48 class Decoder {
49  public:
Decoder(const disasm::NameConverter & converter,v8::internal::Vector<char> out_buffer)50   Decoder(const disasm::NameConverter& converter,
51           v8::internal::Vector<char> out_buffer)
52     : converter_(converter),
53       out_buffer_(out_buffer),
54       out_buffer_pos_(0) {
55     out_buffer_[out_buffer_pos_] = '\0';
56   }
57 
~Decoder()58   ~Decoder() {}
59 
60   // Writes one disassembled instruction into 'buffer' (0-terminated).
61   // Returns the length of the disassembled machine instruction in bytes.
62   int InstructionDecode(byte* instruction);
63 
64  private:
65   // Bottleneck functions to print into the out_buffer.
66   void PrintChar(const char ch);
67   void Print(const char* str);
68 
69   // Printing of common values.
70   void PrintRegister(int reg);
71   void PrintFPURegister(int freg);
72   void PrintRs(Instruction* instr);
73   void PrintRt(Instruction* instr);
74   void PrintRd(Instruction* instr);
75   void PrintFs(Instruction* instr);
76   void PrintFt(Instruction* instr);
77   void PrintFd(Instruction* instr);
78   void PrintSa(Instruction* instr);
79   void PrintSd(Instruction* instr);
80   void PrintSs1(Instruction* instr);
81   void PrintSs2(Instruction* instr);
82   void PrintBc(Instruction* instr);
83   void PrintCc(Instruction* instr);
84   void PrintFunction(Instruction* instr);
85   void PrintSecondaryField(Instruction* instr);
86   void PrintUImm16(Instruction* instr);
87   void PrintSImm16(Instruction* instr);
88   void PrintXImm16(Instruction* instr);
89   void PrintXImm21(Instruction* instr);
90   void PrintXImm26(Instruction* instr);
91   void PrintCode(Instruction* instr);   // For break and trap instructions.
92   // Printing of instruction name.
93   void PrintInstructionName(Instruction* instr);
94 
95   // Handle formatting of instructions and their options.
96   int FormatRegister(Instruction* instr, const char* option);
97   int FormatFPURegister(Instruction* instr, const char* option);
98   int FormatOption(Instruction* instr, const char* option);
99   void Format(Instruction* instr, const char* format);
100   void Unknown(Instruction* instr);
101 
102   // Each of these functions decodes one particular instruction type.
103   void DecodeTypeRegister(Instruction* instr);
104   void DecodeTypeImmediate(Instruction* instr);
105   void DecodeTypeJump(Instruction* instr);
106 
107   const disasm::NameConverter& converter_;
108   v8::internal::Vector<char> out_buffer_;
109   int out_buffer_pos_;
110 
111   DISALLOW_COPY_AND_ASSIGN(Decoder);
112 };
113 
114 
115 // Support for assertions in the Decoder formatting functions.
116 #define STRING_STARTS_WITH(string, compare_string) \
117   (strncmp(string, compare_string, strlen(compare_string)) == 0)
118 
119 
120 // Append the ch to the output buffer.
PrintChar(const char ch)121 void Decoder::PrintChar(const char ch) {
122   out_buffer_[out_buffer_pos_++] = ch;
123 }
124 
125 
126 // Append the str to the output buffer.
Print(const char * str)127 void Decoder::Print(const char* str) {
128   char cur = *str++;
129   while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
130     PrintChar(cur);
131     cur = *str++;
132   }
133   out_buffer_[out_buffer_pos_] = 0;
134 }
135 
136 
137 // Print the register name according to the active name converter.
PrintRegister(int reg)138 void Decoder::PrintRegister(int reg) {
139   Print(converter_.NameOfCPURegister(reg));
140 }
141 
142 
PrintRs(Instruction * instr)143 void Decoder::PrintRs(Instruction* instr) {
144   int reg = instr->RsValue();
145   PrintRegister(reg);
146 }
147 
148 
PrintRt(Instruction * instr)149 void Decoder::PrintRt(Instruction* instr) {
150   int reg = instr->RtValue();
151   PrintRegister(reg);
152 }
153 
154 
PrintRd(Instruction * instr)155 void Decoder::PrintRd(Instruction* instr) {
156   int reg = instr->RdValue();
157   PrintRegister(reg);
158 }
159 
160 
161 // Print the FPUregister name according to the active name converter.
PrintFPURegister(int freg)162 void Decoder::PrintFPURegister(int freg) {
163   Print(converter_.NameOfXMMRegister(freg));
164 }
165 
166 
PrintFs(Instruction * instr)167 void Decoder::PrintFs(Instruction* instr) {
168   int freg = instr->RsValue();
169   PrintFPURegister(freg);
170 }
171 
172 
PrintFt(Instruction * instr)173 void Decoder::PrintFt(Instruction* instr) {
174   int freg = instr->RtValue();
175   PrintFPURegister(freg);
176 }
177 
178 
PrintFd(Instruction * instr)179 void Decoder::PrintFd(Instruction* instr) {
180   int freg = instr->RdValue();
181   PrintFPURegister(freg);
182 }
183 
184 
185 // Print the integer value of the sa field.
PrintSa(Instruction * instr)186 void Decoder::PrintSa(Instruction* instr) {
187   int sa = instr->SaValue();
188   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
189 }
190 
191 
192 // Print the integer value of the rd field, when it is not used as reg.
PrintSd(Instruction * instr)193 void Decoder::PrintSd(Instruction* instr) {
194   int sd = instr->RdValue();
195   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sd);
196 }
197 
198 
199 // Print the integer value of the rd field, when used as 'ext' size.
PrintSs1(Instruction * instr)200 void Decoder::PrintSs1(Instruction* instr) {
201   int ss = instr->RdValue();
202   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss + 1);
203 }
204 
205 
206 // Print the integer value of the rd field, when used as 'ins' size.
PrintSs2(Instruction * instr)207 void Decoder::PrintSs2(Instruction* instr) {
208   int ss = instr->RdValue();
209   int pos = instr->SaValue();
210   out_buffer_pos_ +=
211       SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss - pos + 1);
212 }
213 
214 
215 // Print the integer value of the cc field for the bc1t/f instructions.
PrintBc(Instruction * instr)216 void Decoder::PrintBc(Instruction* instr) {
217   int cc = instr->FBccValue();
218   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", cc);
219 }
220 
221 
222 // Print the integer value of the cc field for the FP compare instructions.
PrintCc(Instruction * instr)223 void Decoder::PrintCc(Instruction* instr) {
224   int cc = instr->FCccValue();
225   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "cc(%d)", cc);
226 }
227 
228 
229 // Print 16-bit unsigned immediate value.
PrintUImm16(Instruction * instr)230 void Decoder::PrintUImm16(Instruction* instr) {
231   int32_t imm = instr->Imm16Value();
232   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
233 }
234 
235 
236 // Print 16-bit signed immediate value.
PrintSImm16(Instruction * instr)237 void Decoder::PrintSImm16(Instruction* instr) {
238   int32_t imm = ((instr->Imm16Value()) << 16) >> 16;
239   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
240 }
241 
242 
243 // Print 16-bit hexa immediate value.
PrintXImm16(Instruction * instr)244 void Decoder::PrintXImm16(Instruction* instr) {
245   int32_t imm = instr->Imm16Value();
246   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
247 }
248 
249 
250 // Print 21-bit immediate value.
PrintXImm21(Instruction * instr)251 void Decoder::PrintXImm21(Instruction* instr) {
252   uint32_t imm = instr->Imm21Value();
253   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
254 }
255 
256 
257 // Print 26-bit immediate value.
PrintXImm26(Instruction * instr)258 void Decoder::PrintXImm26(Instruction* instr) {
259   uint32_t imm = instr->Imm26Value() << kImmFieldShift;
260   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
261 }
262 
263 
264 // Print 26-bit immediate value.
PrintCode(Instruction * instr)265 void Decoder::PrintCode(Instruction* instr) {
266   if (instr->OpcodeFieldRaw() != SPECIAL)
267     return;  // Not a break or trap instruction.
268   switch (instr->FunctionFieldRaw()) {
269     case BREAK: {
270       int32_t code = instr->Bits(25, 6);
271       out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
272                                   "0x%05x (%d)", code, code);
273       break;
274                 }
275     case TGE:
276     case TGEU:
277     case TLT:
278     case TLTU:
279     case TEQ:
280     case TNE: {
281       int32_t code = instr->Bits(15, 6);
282       out_buffer_pos_ +=
283           SNPrintF(out_buffer_ + out_buffer_pos_, "0x%03x", code);
284       break;
285     }
286     default:  // Not a break or trap instruction.
287     break;
288   }
289 }
290 
291 
292 // Printing of instruction name.
PrintInstructionName(Instruction * instr)293 void Decoder::PrintInstructionName(Instruction* instr) {
294 }
295 
296 
297 // Handle all register based formatting in this function to reduce the
298 // complexity of FormatOption.
FormatRegister(Instruction * instr,const char * format)299 int Decoder::FormatRegister(Instruction* instr, const char* format) {
300   DCHECK(format[0] == 'r');
301   if (format[1] == 's') {  // 'rs: Rs register.
302     int reg = instr->RsValue();
303     PrintRegister(reg);
304     return 2;
305   } else if (format[1] == 't') {  // 'rt: rt register.
306     int reg = instr->RtValue();
307     PrintRegister(reg);
308     return 2;
309   } else if (format[1] == 'd') {  // 'rd: rd register.
310     int reg = instr->RdValue();
311     PrintRegister(reg);
312     return 2;
313   }
314   UNREACHABLE();
315   return -1;
316 }
317 
318 
319 // Handle all FPUregister based formatting in this function to reduce the
320 // complexity of FormatOption.
FormatFPURegister(Instruction * instr,const char * format)321 int Decoder::FormatFPURegister(Instruction* instr, const char* format) {
322   DCHECK(format[0] == 'f');
323   if (format[1] == 's') {  // 'fs: fs register.
324     int reg = instr->FsValue();
325     PrintFPURegister(reg);
326     return 2;
327   } else if (format[1] == 't') {  // 'ft: ft register.
328     int reg = instr->FtValue();
329     PrintFPURegister(reg);
330     return 2;
331   } else if (format[1] == 'd') {  // 'fd: fd register.
332     int reg = instr->FdValue();
333     PrintFPURegister(reg);
334     return 2;
335   } else if (format[1] == 'r') {  // 'fr: fr register.
336     int reg = instr->FrValue();
337     PrintFPURegister(reg);
338     return 2;
339   }
340   UNREACHABLE();
341   return -1;
342 }
343 
344 
345 // FormatOption takes a formatting string and interprets it based on
346 // the current instructions. The format string points to the first
347 // character of the option string (the option escape has already been
348 // consumed by the caller.)  FormatOption returns the number of
349 // characters that were consumed from the formatting string.
FormatOption(Instruction * instr,const char * format)350 int Decoder::FormatOption(Instruction* instr, const char* format) {
351   switch (format[0]) {
352     case 'c': {   // 'code for break or trap instructions.
353       DCHECK(STRING_STARTS_WITH(format, "code"));
354       PrintCode(instr);
355       return 4;
356     }
357     case 'i': {   // 'imm16u or 'imm26.
358       if (format[3] == '1') {
359         DCHECK(STRING_STARTS_WITH(format, "imm16"));
360         if (format[5] == 's') {
361           DCHECK(STRING_STARTS_WITH(format, "imm16s"));
362           PrintSImm16(instr);
363         } else if (format[5] == 'u') {
364           DCHECK(STRING_STARTS_WITH(format, "imm16u"));
365           PrintSImm16(instr);
366         } else {
367           DCHECK(STRING_STARTS_WITH(format, "imm16x"));
368           PrintXImm16(instr);
369         }
370         return 6;
371       } else if (format[3] == '2' && format[4] == '1') {
372         DCHECK(STRING_STARTS_WITH(format, "imm21x"));
373         PrintXImm21(instr);
374         return 6;
375       } else if (format[3] == '2' && format[4] == '6') {
376         DCHECK(STRING_STARTS_WITH(format, "imm26x"));
377         PrintXImm26(instr);
378         return 6;
379       }
380     }
381     case 'r': {   // 'r: registers.
382       return FormatRegister(instr, format);
383     }
384     case 'f': {   // 'f: FPUregisters.
385       return FormatFPURegister(instr, format);
386     }
387     case 's': {   // 'sa.
388       switch (format[1]) {
389         case 'a': {
390           DCHECK(STRING_STARTS_WITH(format, "sa"));
391           PrintSa(instr);
392           return 2;
393         }
394         case 'd': {
395           DCHECK(STRING_STARTS_WITH(format, "sd"));
396           PrintSd(instr);
397           return 2;
398         }
399         case 's': {
400           if (format[2] == '1') {
401               DCHECK(STRING_STARTS_WITH(format, "ss1"));  /* ext size */
402               PrintSs1(instr);
403               return 3;
404           } else {
405               DCHECK(STRING_STARTS_WITH(format, "ss2"));  /* ins size */
406               PrintSs2(instr);
407               return 3;
408           }
409         }
410       }
411     }
412     case 'b': {   // 'bc - Special for bc1 cc field.
413       DCHECK(STRING_STARTS_WITH(format, "bc"));
414       PrintBc(instr);
415       return 2;
416     }
417     case 'C': {   // 'Cc - Special for c.xx.d cc field.
418       DCHECK(STRING_STARTS_WITH(format, "Cc"));
419       PrintCc(instr);
420       return 2;
421     }
422   }
423   UNREACHABLE();
424   return -1;
425 }
426 
427 
428 // Format takes a formatting string for a whole instruction and prints it into
429 // the output buffer. All escaped options are handed to FormatOption to be
430 // parsed further.
Format(Instruction * instr,const char * format)431 void Decoder::Format(Instruction* instr, const char* format) {
432   char cur = *format++;
433   while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
434     if (cur == '\'') {  // Single quote is used as the formatting escape.
435       format += FormatOption(instr, format);
436     } else {
437       out_buffer_[out_buffer_pos_++] = cur;
438     }
439     cur = *format++;
440   }
441   out_buffer_[out_buffer_pos_]  = '\0';
442 }
443 
444 
445 // For currently unimplemented decodings the disassembler calls Unknown(instr)
446 // which will just print "unknown" of the instruction bits.
Unknown(Instruction * instr)447 void Decoder::Unknown(Instruction* instr) {
448   Format(instr, "unknown");
449 }
450 
451 
DecodeTypeRegister(Instruction * instr)452 void Decoder::DecodeTypeRegister(Instruction* instr) {
453   switch (instr->OpcodeFieldRaw()) {
454     case COP1:    // Coprocessor instructions.
455       switch (instr->RsFieldRaw()) {
456         case BC1:   // bc1 handled in DecodeTypeImmediate.
457           UNREACHABLE();
458           break;
459         case MFC1:
460           Format(instr, "mfc1    'rt, 'fs");
461           break;
462         case MFHC1:
463           Format(instr, "mfhc1   'rt, 'fs");
464           break;
465         case MTC1:
466           Format(instr, "mtc1    'rt, 'fs");
467           break;
468         // These are called "fs" too, although they are not FPU registers.
469         case CTC1:
470           Format(instr, "ctc1    'rt, 'fs");
471           break;
472         case CFC1:
473           Format(instr, "cfc1    'rt, 'fs");
474           break;
475         case MTHC1:
476           Format(instr, "mthc1   'rt, 'fs");
477           break;
478         case D:
479           switch (instr->FunctionFieldRaw()) {
480             case ADD_D:
481               Format(instr, "add.d   'fd, 'fs, 'ft");
482               break;
483             case SUB_D:
484               Format(instr, "sub.d   'fd, 'fs, 'ft");
485               break;
486             case MUL_D:
487               Format(instr, "mul.d   'fd, 'fs, 'ft");
488               break;
489             case DIV_D:
490               Format(instr, "div.d   'fd, 'fs, 'ft");
491               break;
492             case ABS_D:
493               Format(instr, "abs.d   'fd, 'fs");
494               break;
495             case MOV_D:
496               Format(instr, "mov.d   'fd, 'fs");
497               break;
498             case NEG_D:
499               Format(instr, "neg.d   'fd, 'fs");
500               break;
501             case SQRT_D:
502               Format(instr, "sqrt.d  'fd, 'fs");
503               break;
504             case CVT_W_D:
505               Format(instr, "cvt.w.d 'fd, 'fs");
506               break;
507             case CVT_L_D:
508               Format(instr, "cvt.l.d 'fd, 'fs");
509               break;
510             case TRUNC_W_D:
511               Format(instr, "trunc.w.d 'fd, 'fs");
512               break;
513             case TRUNC_L_D:
514               Format(instr, "trunc.l.d 'fd, 'fs");
515               break;
516             case ROUND_W_D:
517               Format(instr, "round.w.d 'fd, 'fs");
518               break;
519             case FLOOR_W_D:
520               Format(instr, "floor.w.d 'fd, 'fs");
521               break;
522             case CEIL_W_D:
523               Format(instr, "ceil.w.d 'fd, 'fs");
524               break;
525             case CVT_S_D:
526               Format(instr, "cvt.s.d 'fd, 'fs");
527               break;
528             case C_F_D:
529               Format(instr, "c.f.d   'fs, 'ft, 'Cc");
530               break;
531             case C_UN_D:
532               Format(instr, "c.un.d  'fs, 'ft, 'Cc");
533               break;
534             case C_EQ_D:
535               Format(instr, "c.eq.d  'fs, 'ft, 'Cc");
536               break;
537             case C_UEQ_D:
538               Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
539               break;
540             case C_OLT_D:
541               Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
542               break;
543             case C_ULT_D:
544               Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
545               break;
546             case C_OLE_D:
547               Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
548               break;
549             case C_ULE_D:
550               Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
551               break;
552             default:
553               Format(instr, "unknown.cop1.d");
554               break;
555           }
556           break;
557         case S:
558           UNIMPLEMENTED_MIPS();
559           break;
560         case W:
561           switch (instr->FunctionFieldRaw()) {
562             case CVT_S_W:   // Convert word to float (single).
563               Format(instr, "cvt.s.w 'fd, 'fs");
564               break;
565             case CVT_D_W:   // Convert word to double.
566               Format(instr, "cvt.d.w 'fd, 'fs");
567               break;
568             default:
569               UNREACHABLE();
570           }
571           break;
572         case L:
573           switch (instr->FunctionFieldRaw()) {
574             case CVT_D_L:
575               Format(instr, "cvt.d.l 'fd, 'fs");
576               break;
577             case CVT_S_L:
578               Format(instr, "cvt.s.l 'fd, 'fs");
579               break;
580             case CMP_UN:
581               Format(instr, "cmp.un.d  'fd,  'fs, 'ft");
582               break;
583             case CMP_EQ:
584               Format(instr, "cmp.eq.d  'fd,  'fs, 'ft");
585               break;
586             case CMP_UEQ:
587               Format(instr, "cmp.ueq.d  'fd,  'fs, 'ft");
588               break;
589             case CMP_LT:
590               Format(instr, "cmp.lt.d  'fd,  'fs, 'ft");
591               break;
592             case CMP_ULT:
593               Format(instr, "cmp.ult.d  'fd,  'fs, 'ft");
594               break;
595             case CMP_LE:
596               Format(instr, "cmp.le.d  'fd,  'fs, 'ft");
597               break;
598             case CMP_ULE:
599               Format(instr, "cmp.ule.d  'fd,  'fs, 'ft");
600               break;
601             case CMP_OR:
602               Format(instr, "cmp.or.d  'fd,  'fs, 'ft");
603               break;
604             case CMP_UNE:
605               Format(instr, "cmp.une.d  'fd,  'fs, 'ft");
606               break;
607             case CMP_NE:
608               Format(instr, "cmp.ne.d  'fd,  'fs, 'ft");
609               break;
610             default:
611               UNREACHABLE();
612           }
613           break;
614         case PS:
615           UNIMPLEMENTED_MIPS();
616           break;
617         default:
618           UNREACHABLE();
619       }
620       break;
621     case COP1X:
622       switch (instr->FunctionFieldRaw()) {
623         case MADD_D:
624           Format(instr, "madd.d  'fd, 'fr, 'fs, 'ft");
625           break;
626         default:
627           UNREACHABLE();
628       }
629       break;
630     case SPECIAL:
631       switch (instr->FunctionFieldRaw()) {
632         case JR:
633           Format(instr, "jr      'rs");
634           break;
635         case JALR:
636           Format(instr, "jalr    'rs");
637           break;
638         case SLL:
639           if ( 0x0 == static_cast<int>(instr->InstructionBits()))
640             Format(instr, "nop");
641           else
642             Format(instr, "sll     'rd, 'rt, 'sa");
643           break;
644         case SRL:
645           if (instr->RsValue() == 0) {
646             Format(instr, "srl     'rd, 'rt, 'sa");
647           } else {
648             if (IsMipsArchVariant(kMips32r2)) {
649               Format(instr, "rotr    'rd, 'rt, 'sa");
650             } else {
651               Unknown(instr);
652             }
653           }
654           break;
655         case SRA:
656           Format(instr, "sra     'rd, 'rt, 'sa");
657           break;
658         case SLLV:
659           Format(instr, "sllv    'rd, 'rt, 'rs");
660           break;
661         case SRLV:
662           if (instr->SaValue() == 0) {
663             Format(instr, "srlv    'rd, 'rt, 'rs");
664           } else {
665             if (IsMipsArchVariant(kMips32r2)) {
666               Format(instr, "rotrv   'rd, 'rt, 'rs");
667             } else {
668               Unknown(instr);
669             }
670           }
671           break;
672         case SRAV:
673           Format(instr, "srav    'rd, 'rt, 'rs");
674           break;
675         case MFHI:
676           if (instr->Bits(25, 16) == 0) {
677             Format(instr, "mfhi    'rd");
678           } else {
679             if ((instr->FunctionFieldRaw() == CLZ_R6)
680                 && (instr->FdValue() == 1)) {
681               Format(instr, "clz     'rd, 'rs");
682             } else if ((instr->FunctionFieldRaw() == CLO_R6)
683                 && (instr->FdValue() == 1)) {
684               Format(instr, "clo     'rd, 'rs");
685             }
686           }
687           break;
688         case MFLO:
689           Format(instr, "mflo    'rd");
690           break;
691         case MULT:  // @Mips32r6 == MUL_MUH.
692           if (!IsMipsArchVariant(kMips32r6)) {
693             Format(instr, "mult    'rs, 'rt");
694           } else {
695             if (instr->SaValue() == MUL_OP) {
696               Format(instr, "mul    'rd, 'rs, 'rt");
697             } else {
698               Format(instr, "muh    'rd, 'rs, 'rt");
699             }
700           }
701           break;
702         case MULTU:  // @Mips32r6 == MUL_MUH_U.
703           if (!IsMipsArchVariant(kMips32r6)) {
704             Format(instr, "multu   'rs, 'rt");
705           } else {
706             if (instr->SaValue() == MUL_OP) {
707               Format(instr, "mulu   'rd, 'rs, 'rt");
708             } else {
709               Format(instr, "muhu   'rd, 'rs, 'rt");
710             }
711           }
712           break;
713         case DIV:  // @Mips32r6 == DIV_MOD.
714           if (!IsMipsArchVariant(kMips32r6)) {
715             Format(instr, "div     'rs, 'rt");
716           } else {
717             if (instr->SaValue() == DIV_OP) {
718               Format(instr, "div    'rd, 'rs, 'rt");
719             } else {
720               Format(instr, "mod    'rd, 'rs, 'rt");
721             }
722           }
723           break;
724         case DIVU:  // @Mips32r6 == DIV_MOD_U.
725           if (!IsMipsArchVariant(kMips32r6)) {
726             Format(instr, "divu    'rs, 'rt");
727           } else {
728             if (instr->SaValue() == DIV_OP) {
729               Format(instr, "divu   'rd, 'rs, 'rt");
730             } else {
731               Format(instr, "modu   'rd, 'rs, 'rt");
732             }
733           }
734           break;
735         case ADD:
736           Format(instr, "add     'rd, 'rs, 'rt");
737           break;
738         case ADDU:
739           Format(instr, "addu    'rd, 'rs, 'rt");
740           break;
741         case SUB:
742           Format(instr, "sub     'rd, 'rs, 'rt");
743           break;
744         case SUBU:
745           Format(instr, "subu    'rd, 'rs, 'rt");
746           break;
747         case AND:
748           Format(instr, "and     'rd, 'rs, 'rt");
749           break;
750         case OR:
751           if (0 == instr->RsValue()) {
752             Format(instr, "mov     'rd, 'rt");
753           } else if (0 == instr->RtValue()) {
754             Format(instr, "mov     'rd, 'rs");
755           } else {
756             Format(instr, "or      'rd, 'rs, 'rt");
757           }
758           break;
759         case XOR:
760           Format(instr, "xor     'rd, 'rs, 'rt");
761           break;
762         case NOR:
763           Format(instr, "nor     'rd, 'rs, 'rt");
764           break;
765         case SLT:
766           Format(instr, "slt     'rd, 'rs, 'rt");
767           break;
768         case SLTU:
769           Format(instr, "sltu    'rd, 'rs, 'rt");
770           break;
771         case BREAK:
772           Format(instr, "break, code: 'code");
773           break;
774         case TGE:
775           Format(instr, "tge     'rs, 'rt, code: 'code");
776           break;
777         case TGEU:
778           Format(instr, "tgeu    'rs, 'rt, code: 'code");
779           break;
780         case TLT:
781           Format(instr, "tlt     'rs, 'rt, code: 'code");
782           break;
783         case TLTU:
784           Format(instr, "tltu    'rs, 'rt, code: 'code");
785           break;
786         case TEQ:
787           Format(instr, "teq     'rs, 'rt, code: 'code");
788           break;
789         case TNE:
790           Format(instr, "tne     'rs, 'rt, code: 'code");
791           break;
792         case MOVZ:
793           Format(instr, "movz    'rd, 'rs, 'rt");
794           break;
795         case MOVN:
796           Format(instr, "movn    'rd, 'rs, 'rt");
797           break;
798         case MOVCI:
799           if (instr->Bit(16)) {
800             Format(instr, "movt    'rd, 'rs, 'bc");
801           } else {
802             Format(instr, "movf    'rd, 'rs, 'bc");
803           }
804           break;
805         case SELEQZ_S:
806           Format(instr, "seleqz    'rd, 'rs, 'rt");
807           break;
808         case SELNEZ_S:
809           Format(instr, "selnez    'rd, 'rs, 'rt");
810           break;
811         default:
812           UNREACHABLE();
813       }
814       break;
815     case SPECIAL2:
816       switch (instr->FunctionFieldRaw()) {
817         case MUL:
818           Format(instr, "mul     'rd, 'rs, 'rt");
819           break;
820         case CLZ:
821           if (!IsMipsArchVariant(kMips32r6)) {
822             Format(instr, "clz     'rd, 'rs");
823           }
824           break;
825         default:
826           UNREACHABLE();
827       }
828       break;
829     case SPECIAL3:
830       switch (instr->FunctionFieldRaw()) {
831         case INS: {
832           if (IsMipsArchVariant(kMips32r2)) {
833             Format(instr, "ins     'rt, 'rs, 'sa, 'ss2");
834           } else {
835             Unknown(instr);
836           }
837           break;
838         }
839         case EXT: {
840           if (IsMipsArchVariant(kMips32r2)) {
841             Format(instr, "ext     'rt, 'rs, 'sa, 'ss1");
842           } else {
843             Unknown(instr);
844           }
845           break;
846         }
847         default:
848           UNREACHABLE();
849       }
850       break;
851     default:
852       UNREACHABLE();
853   }
854 }
855 
856 
DecodeTypeImmediate(Instruction * instr)857 void Decoder::DecodeTypeImmediate(Instruction* instr) {
858   switch (instr->OpcodeFieldRaw()) {
859     case COP1:
860       switch (instr->RsFieldRaw()) {
861         case BC1:
862           if (instr->FBtrueValue()) {
863             Format(instr, "bc1t    'bc, 'imm16u");
864           } else {
865             Format(instr, "bc1f    'bc, 'imm16u");
866           }
867           break;
868         case BC1EQZ:
869           Format(instr, "bc1eqz    'ft, 'imm16u");
870           break;
871         case BC1NEZ:
872           Format(instr, "bc1nez    'ft, 'imm16u");
873           break;
874         case W:  // CMP.S instruction.
875           switch (instr->FunctionValue()) {
876             case CMP_AF:
877               Format(instr, "cmp.af.S    'ft, 'fs, 'fd");
878               break;
879             case CMP_UN:
880               Format(instr, "cmp.un.S    'ft, 'fs, 'fd");
881               break;
882             case CMP_EQ:
883               Format(instr, "cmp.eq.S    'ft, 'fs, 'fd");
884               break;
885             case CMP_UEQ:
886               Format(instr, "cmp.ueq.S   'ft, 'fs, 'fd");
887               break;
888             case CMP_LT:
889               Format(instr, "cmp.lt.S    'ft, 'fs, 'fd");
890               break;
891             case CMP_ULT:
892               Format(instr, "cmp.ult.S   'ft, 'fs, 'fd");
893               break;
894             case CMP_LE:
895               Format(instr, "cmp.le.S    'ft, 'fs, 'fd");
896               break;
897             case CMP_ULE:
898               Format(instr, "cmp.ule.S   'ft, 'fs, 'fd");
899               break;
900             case CMP_OR:
901               Format(instr, "cmp.or.S    'ft, 'fs, 'fd");
902               break;
903             case CMP_UNE:
904               Format(instr, "cmp.une.S   'ft, 'fs, 'fd");
905               break;
906             case CMP_NE:
907               Format(instr, "cmp.ne.S    'ft, 'fs, 'fd");
908               break;
909             default:
910               UNREACHABLE();
911           }
912           break;
913         case L:  // CMP.D instruction.
914           switch (instr->FunctionValue()) {
915             case CMP_AF:
916               Format(instr, "cmp.af.D    'ft, 'fs, 'fd");
917               break;
918             case CMP_UN:
919               Format(instr, "cmp.un.D    'ft, 'fs, 'fd");
920               break;
921             case CMP_EQ:
922               Format(instr, "cmp.eq.D    'ft, 'fs, 'fd");
923               break;
924             case CMP_UEQ:
925               Format(instr, "cmp.ueq.D   'ft, 'fs, 'fd");
926               break;
927             case CMP_LT:
928               Format(instr, "cmp.lt.D    'ft, 'fs, 'fd");
929               break;
930             case CMP_ULT:
931               Format(instr, "cmp.ult.D   'ft, 'fs, 'fd");
932               break;
933             case CMP_LE:
934               Format(instr, "cmp.le.D    'ft, 'fs, 'fd");
935               break;
936             case CMP_ULE:
937               Format(instr, "cmp.ule.D   'ft, 'fs, 'fd");
938               break;
939             case CMP_OR:
940               Format(instr, "cmp.or.D    'ft, 'fs, 'fd");
941               break;
942             case CMP_UNE:
943               Format(instr, "cmp.une.D   'ft, 'fs, 'fd");
944               break;
945             case CMP_NE:
946               Format(instr, "cmp.ne.D    'ft, 'fs, 'fd");
947               break;
948             default:
949               UNREACHABLE();
950           }
951           break;
952         case S:
953           switch (instr->FunctionValue()) {
954             case SEL:
955               Format(instr, "sel.S    'ft, 'fs, 'fd");
956               break;
957             case SELEQZ_C:
958               Format(instr, "seleqz.S 'ft, 'fs, 'fd");
959               break;
960             case SELNEZ_C:
961               Format(instr, "selnez.S 'ft, 'fs, 'fd");
962               break;
963             case MIN:
964               Format(instr, "min.S    'ft, 'fs, 'fd");
965               break;
966             case MINA:
967               Format(instr, "mina.S   'ft, 'fs, 'fd");
968               break;
969             case MAX:
970               Format(instr, "max.S    'ft, 'fs, 'fd");
971               break;
972             case MAXA:
973               Format(instr, "maxa.S   'ft, 'fs, 'fd");
974               break;
975             default:
976               UNREACHABLE();
977           }
978           break;
979         case D:
980           switch (instr->FunctionValue()) {
981             case SEL:
982               Format(instr, "sel.D    'ft, 'fs, 'fd");
983               break;
984             case SELEQZ_C:
985               Format(instr, "seleqz.D 'ft, 'fs, 'fd");
986               break;
987             case SELNEZ_C:
988               Format(instr, "selnez.D 'ft, 'fs, 'fd");
989               break;
990             case MIN:
991               Format(instr, "min.D    'ft, 'fs, 'fd");
992               break;
993             case MINA:
994               Format(instr, "mina.D   'ft, 'fs, 'fd");
995               break;
996             case MAX:
997               Format(instr, "max.D    'ft, 'fs, 'fd");
998               break;
999             case MAXA:
1000               Format(instr, "maxa.D   'ft, 'fs, 'fd");
1001               break;
1002             default:
1003               UNREACHABLE();
1004           }
1005           break;
1006         default:
1007           UNREACHABLE();
1008       }
1009 
1010       break;  // Case COP1.
1011     // ------------- REGIMM class.
1012     case REGIMM:
1013       switch (instr->RtFieldRaw()) {
1014         case BLTZ:
1015           Format(instr, "bltz    'rs, 'imm16u");
1016           break;
1017         case BLTZAL:
1018           Format(instr, "bltzal  'rs, 'imm16u");
1019           break;
1020         case BGEZ:
1021           Format(instr, "bgez    'rs, 'imm16u");
1022           break;
1023         case BGEZAL:
1024           Format(instr, "bgezal  'rs, 'imm16u");
1025           break;
1026         case BGEZALL:
1027           Format(instr, "bgezall 'rs, 'imm16u");
1028           break;
1029         default:
1030           UNREACHABLE();
1031       }
1032     break;  // Case REGIMM.
1033     // ------------- Branch instructions.
1034     case BEQ:
1035       Format(instr, "beq     'rs, 'rt, 'imm16u");
1036       break;
1037     case BNE:
1038       Format(instr, "bne     'rs, 'rt, 'imm16u");
1039       break;
1040     case BLEZ:
1041       if ((instr->RtFieldRaw() == 0)
1042           && (instr->RsFieldRaw() != 0)) {
1043         Format(instr, "blez    'rs, 'imm16u");
1044       } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1045           && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1046         Format(instr, "bgeuc    'rs, 'rt, 'imm16u");
1047       } else if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1048           && (instr->RtFieldRaw() != 0)) {
1049         Format(instr, "bgezalc  'rs, 'imm16u");
1050       } else if ((instr->RsFieldRaw() == 0)
1051           && (instr->RtFieldRaw() != 0)) {
1052         Format(instr, "blezalc  'rs, 'imm16u");
1053       } else {
1054         UNREACHABLE();
1055       }
1056       break;
1057     case BGTZ:
1058       if ((instr->RtFieldRaw() == 0)
1059           && (instr->RsFieldRaw() != 0)) {
1060         Format(instr, "bgtz    'rs, 'imm16u");
1061       } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1062           && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1063         Format(instr, "bltuc   'rs, 'rt, 'imm16u");
1064       } else if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1065           && (instr->RtFieldRaw() != 0)) {
1066         Format(instr, "bltzalc 'rt, 'imm16u");
1067       } else if ((instr->RsFieldRaw() == 0)
1068           && (instr->RtFieldRaw() != 0)) {
1069         Format(instr, "bgtzalc 'rt, 'imm16u");
1070       } else {
1071         UNREACHABLE();
1072       }
1073       break;
1074     case BLEZL:
1075       if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1076           && (instr->RtFieldRaw() != 0)) {
1077         Format(instr, "bgezc    'rt, 'imm16u");
1078       } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1079           && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1080         Format(instr, "bgec     'rs, 'rt, 'imm16u");
1081       } else if ((instr->RsFieldRaw() == 0)
1082           && (instr->RtFieldRaw() != 0)) {
1083         Format(instr, "blezc    'rt, 'imm16u");
1084       } else {
1085         UNREACHABLE();
1086       }
1087       break;
1088     case BGTZL:
1089       if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1090           && (instr->RtFieldRaw() != 0)) {
1091         Format(instr, "bltzc    'rt, 'imm16u");
1092       } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1093           && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1094         Format(instr, "bltc     'rs, 'rt, 'imm16u");
1095       } else if ((instr->RsFieldRaw() == 0)
1096           && (instr->RtFieldRaw() != 0)) {
1097         Format(instr, "bgtzc    'rt, 'imm16u");
1098       } else {
1099         UNREACHABLE();
1100       }
1101       break;
1102     case BEQZC:
1103       if (instr->RsFieldRaw() != 0) {
1104         Format(instr, "beqzc   'rs, 'imm21x");
1105       }
1106       break;
1107     case BNEZC:
1108       if (instr->RsFieldRaw() != 0) {
1109         Format(instr, "bnezc   'rs, 'imm21x");
1110       }
1111       break;
1112     // ------------- Arithmetic instructions.
1113     case ADDI:
1114       if (!IsMipsArchVariant(kMips32r6)) {
1115         Format(instr, "addi    'rt, 'rs, 'imm16s");
1116       } else {
1117         // Check if BOVC or BEQC instruction.
1118         if (instr->RsFieldRaw() >= instr->RtFieldRaw()) {
1119           Format(instr, "bovc  'rs, 'rt, 'imm16s");
1120         } else if (instr->RsFieldRaw() < instr->RtFieldRaw()) {
1121           Format(instr, "beqc  'rs, 'rt, 'imm16s");
1122         } else {
1123           UNREACHABLE();
1124         }
1125       }
1126       break;
1127     case DADDI:
1128       if (IsMipsArchVariant(kMips32r6)) {
1129         // Check if BNVC or BNEC instruction.
1130         if (instr->RsFieldRaw() >= instr->RtFieldRaw()) {
1131           Format(instr, "bnvc  'rs, 'rt, 'imm16s");
1132         } else if (instr->RsFieldRaw() < instr->RtFieldRaw()) {
1133           Format(instr, "bnec  'rs, 'rt, 'imm16s");
1134         } else {
1135           UNREACHABLE();
1136         }
1137       }
1138       break;
1139     case ADDIU:
1140       Format(instr, "addiu   'rt, 'rs, 'imm16s");
1141       break;
1142     case SLTI:
1143       Format(instr, "slti    'rt, 'rs, 'imm16s");
1144       break;
1145     case SLTIU:
1146       Format(instr, "sltiu   'rt, 'rs, 'imm16u");
1147       break;
1148     case ANDI:
1149       Format(instr, "andi    'rt, 'rs, 'imm16x");
1150       break;
1151     case ORI:
1152       Format(instr, "ori     'rt, 'rs, 'imm16x");
1153       break;
1154     case XORI:
1155       Format(instr, "xori    'rt, 'rs, 'imm16x");
1156       break;
1157     case LUI:
1158       if (!IsMipsArchVariant(kMips32r6)) {
1159         Format(instr, "lui     'rt, 'imm16x");
1160       } else {
1161         if (instr->RsValue() != 0) {
1162           Format(instr, "aui     'rt, 'imm16x");
1163         } else {
1164           Format(instr, "lui     'rt, 'imm16x");
1165         }
1166       }
1167       break;
1168     // ------------- Memory instructions.
1169     case LB:
1170       Format(instr, "lb      'rt, 'imm16s('rs)");
1171       break;
1172     case LH:
1173       Format(instr, "lh      'rt, 'imm16s('rs)");
1174       break;
1175     case LWL:
1176       Format(instr, "lwl     'rt, 'imm16s('rs)");
1177       break;
1178     case LW:
1179       Format(instr, "lw      'rt, 'imm16s('rs)");
1180       break;
1181     case LBU:
1182       Format(instr, "lbu     'rt, 'imm16s('rs)");
1183       break;
1184     case LHU:
1185       Format(instr, "lhu     'rt, 'imm16s('rs)");
1186       break;
1187     case LWR:
1188       Format(instr, "lwr     'rt, 'imm16s('rs)");
1189       break;
1190     case PREF:
1191       Format(instr, "pref    'rt, 'imm16s('rs)");
1192       break;
1193     case SB:
1194       Format(instr, "sb      'rt, 'imm16s('rs)");
1195       break;
1196     case SH:
1197       Format(instr, "sh      'rt, 'imm16s('rs)");
1198       break;
1199     case SWL:
1200       Format(instr, "swl     'rt, 'imm16s('rs)");
1201       break;
1202     case SW:
1203       Format(instr, "sw      'rt, 'imm16s('rs)");
1204       break;
1205     case SWR:
1206       Format(instr, "swr     'rt, 'imm16s('rs)");
1207       break;
1208     case LWC1:
1209       Format(instr, "lwc1    'ft, 'imm16s('rs)");
1210       break;
1211     case LDC1:
1212       Format(instr, "ldc1    'ft, 'imm16s('rs)");
1213       break;
1214     case SWC1:
1215       Format(instr, "swc1    'ft, 'imm16s('rs)");
1216       break;
1217     case SDC1:
1218       Format(instr, "sdc1    'ft, 'imm16s('rs)");
1219       break;
1220     default:
1221       printf("a 0x%x \n", instr->OpcodeFieldRaw());
1222       UNREACHABLE();
1223       break;
1224   }
1225 }
1226 
1227 
DecodeTypeJump(Instruction * instr)1228 void Decoder::DecodeTypeJump(Instruction* instr) {
1229   switch (instr->OpcodeFieldRaw()) {
1230     case J:
1231       Format(instr, "j       'imm26x");
1232       break;
1233     case JAL:
1234       Format(instr, "jal     'imm26x");
1235       break;
1236     default:
1237       UNREACHABLE();
1238   }
1239 }
1240 
1241 
1242 // Disassemble the instruction at *instr_ptr into the output buffer.
InstructionDecode(byte * instr_ptr)1243 int Decoder::InstructionDecode(byte* instr_ptr) {
1244   Instruction* instr = Instruction::At(instr_ptr);
1245   // Print raw instruction bytes.
1246   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
1247                                    "%08x       ",
1248                                    instr->InstructionBits());
1249   switch (instr->InstructionType()) {
1250     case Instruction::kRegisterType: {
1251       DecodeTypeRegister(instr);
1252       break;
1253     }
1254     case Instruction::kImmediateType: {
1255       DecodeTypeImmediate(instr);
1256       break;
1257     }
1258     case Instruction::kJumpType: {
1259       DecodeTypeJump(instr);
1260       break;
1261     }
1262     default: {
1263       Format(instr, "UNSUPPORTED");
1264       UNSUPPORTED_MIPS();
1265     }
1266   }
1267   return Instruction::kInstrSize;
1268 }
1269 
1270 
1271 } }  // namespace v8::internal
1272 
1273 
1274 
1275 //------------------------------------------------------------------------------
1276 
1277 namespace disasm {
1278 
NameOfAddress(byte * addr) const1279 const char* NameConverter::NameOfAddress(byte* addr) const {
1280   v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1281   return tmp_buffer_.start();
1282 }
1283 
1284 
NameOfConstant(byte * addr) const1285 const char* NameConverter::NameOfConstant(byte* addr) const {
1286   return NameOfAddress(addr);
1287 }
1288 
1289 
NameOfCPURegister(int reg) const1290 const char* NameConverter::NameOfCPURegister(int reg) const {
1291   return v8::internal::Registers::Name(reg);
1292 }
1293 
1294 
NameOfXMMRegister(int reg) const1295 const char* NameConverter::NameOfXMMRegister(int reg) const {
1296   return v8::internal::FPURegisters::Name(reg);
1297 }
1298 
1299 
NameOfByteCPURegister(int reg) const1300 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1301   UNREACHABLE();  // MIPS does not have the concept of a byte register.
1302   return "nobytereg";
1303 }
1304 
1305 
NameInCode(byte * addr) const1306 const char* NameConverter::NameInCode(byte* addr) const {
1307   // The default name converter is called for unknown code. So we will not try
1308   // to access any memory.
1309   return "";
1310 }
1311 
1312 
1313 //------------------------------------------------------------------------------
1314 
Disassembler(const NameConverter & converter)1315 Disassembler::Disassembler(const NameConverter& converter)
1316     : converter_(converter) {}
1317 
1318 
~Disassembler()1319 Disassembler::~Disassembler() {}
1320 
1321 
InstructionDecode(v8::internal::Vector<char> buffer,byte * instruction)1322 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1323                                     byte* instruction) {
1324   v8::internal::Decoder d(converter_, buffer);
1325   return d.InstructionDecode(instruction);
1326 }
1327 
1328 
1329 // The MIPS assembler does not currently use constant pools.
ConstantPoolSizeAt(byte * instruction)1330 int Disassembler::ConstantPoolSizeAt(byte* instruction) {
1331   return -1;
1332 }
1333 
1334 
Disassemble(FILE * f,byte * begin,byte * end)1335 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1336   NameConverter converter;
1337   Disassembler d(converter);
1338   for (byte* pc = begin; pc < end;) {
1339     v8::internal::EmbeddedVector<char, 128> buffer;
1340     buffer[0] = '\0';
1341     byte* prev_pc = pc;
1342     pc += d.InstructionDecode(buffer, pc);
1343     v8::internal::PrintF(f, "%p    %08x      %s\n",
1344         prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
1345   }
1346 }
1347 
1348 
1349 #undef UNSUPPORTED
1350 
1351 }  // namespace disasm
1352 
1353 #endif  // V8_TARGET_ARCH_MIPS
1354