V8 Project
disasm-mips.cc
Go to the documentation of this file.
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 
36 #include "src/disasm.h"
37 #include "src/macro-assembler.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:
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 
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 
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.
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.
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.
138 void Decoder::PrintRegister(int reg) {
139  Print(converter_.NameOfCPURegister(reg));
140 }
141 
142 
143 void Decoder::PrintRs(Instruction* instr) {
144  int reg = instr->RsValue();
145  PrintRegister(reg);
146 }
147 
148 
149 void Decoder::PrintRt(Instruction* instr) {
150  int reg = instr->RtValue();
151  PrintRegister(reg);
152 }
153 
154 
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.
162 void Decoder::PrintFPURegister(int freg) {
163  Print(converter_.NameOfXMMRegister(freg));
164 }
165 
166 
167 void Decoder::PrintFs(Instruction* instr) {
168  int freg = instr->RsValue();
169  PrintFPURegister(freg);
170 }
171 
172 
173 void Decoder::PrintFt(Instruction* instr) {
174  int freg = instr->RtValue();
175  PrintFPURegister(freg);
176 }
177 
178 
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
447 void Decoder::Unknown(Instruction* instr) {
448  Format(instr, "unknown");
449 }
450 
451 
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:
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:
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 {
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 {
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.
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.
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.
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.
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:
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: {
833  Format(instr, "ins 'rt, 'rs, 'sa, 'ss2");
834  } else {
835  Unknown(instr);
836  }
837  break;
838  }
839  case EXT: {
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 
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:
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 
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.
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()) {
1251  DecodeTypeRegister(instr);
1252  break;
1253  }
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 
1279 const char* NameConverter::NameOfAddress(byte* addr) const {
1280  v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1281  return tmp_buffer_.start();
1282 }
1283 
1284 
1285 const char* NameConverter::NameOfConstant(byte* addr) const {
1286  return NameOfAddress(addr);
1287 }
1288 
1289 
1290 const char* NameConverter::NameOfCPURegister(int reg) const {
1291  return v8::internal::Registers::Name(reg);
1292 }
1293 
1294 
1295 const char* NameConverter::NameOfXMMRegister(int reg) const {
1297 }
1298 
1299 
1300 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 
1306 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 
1315 Disassembler::Disassembler(const NameConverter& converter)
1316  : converter_(converter) {}
1317 
1318 
1319 Disassembler::~Disassembler() {}
1320 
1321 
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.
1330 int Disassembler::ConstantPoolSizeAt(byte* instruction) {
1331  return -1;
1332 }
1333 
1334 
1335 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1336  NameConverter converter;
1337  Disassembler d(converter);
1338  for (byte* pc = begin; pc < end;) {
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
Disassembler(const NameConverter &converter)
v8::internal::EmbeddedVector< char, 128 > tmp_buffer_
Definition: disasm.h:26
virtual const char * NameInCode(byte *addr) const
virtual const char * NameOfByteCPURegister(int reg) const
virtual const char * NameOfXMMRegister(int reg) const
virtual const char * NameOfAddress(byte *addr) const
virtual const char * NameOfCPURegister(int reg) const
virtual const char * NameOfConstant(byte *addr) const
static const char * Name(int reg)
static Instruction * At(byte *pc)
static const char * Name(int reg)
T * start() const
Definition: vector.h:47
#define UNIMPLEMENTED_MIPS()
#define UNSUPPORTED_MIPS()
@ kMips32r6
@ kMips32r2
#define IsMipsArchVariant(check)
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK(condition)
Definition: logging.h:205
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:244
Definition: disasm.h:8
int int32_t
Definition: unicode.cc:24
int SNPrintF(Vector< char > str, const char *format,...)
Definition: utils.cc:105
const Register pc
void PrintF(const char *format,...)
Definition: utils.cc:80
const int kImmFieldShift
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20