The Pedigree Project  0.1
mips_common/Disassembler.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "Disassembler.h"
21 
22 const char *g_pOpcodes[64] = {
23  0, // Special
24  0, // RegImm
25  "j ", "jal ", "beq ", "bne ", "blez ", "bgtz ",
26  "addi ", // 8
27  "addiu ", "slti ", "sltiu ", "andi ", "ori ", "xori ", "lui ",
28  "cop0 ", // 16
29  "cop1 ", "cop2 ", "cop3 ", "beql ", "bnel ", "blezl ", "bgtzl ",
30  0, // 24
31  0, 0, 0, 0, 0, 0, 0,
32  "lb ", // 32
33  "lh ", "lwl ", "lw ", "lbu ", "lhu ", "lwr ", 0,
34  "sb ", // 40
35  "sh ", "swl ", "sw ", 0, 0, "swr ", "cache ",
36  "ll ", // 48
37  "lwc1 ", "lwc2 ", "lwc3 ", 0, "ldc1 ", "ldc2 ", "ldc3 ",
38  "sc ", // 56
39  "swc1 ", "swc2 ", "swc3 ", 0, "sdc1 ", "sdc2 ", "sdc3 "};
40 
41 const char *g_pSpecial[64] = {
42  "sll ", 0, "srl ", "sra ", "sllv ", 0, "srlv ",
43  "srav ",
44  "jr ", // 8
45  "jalr ", 0, 0, "syscall", "break ", 0, "sync ",
46  "mfhi ", // 16
47  "mthi ", "mflo ", "mtlo ", 0, 0, 0, 0,
48  "mult ", // 24
49  "multu ", "div ", "divu ", 0, 0, 0, 0,
50  "add ", // 32
51  "addu ", "sub ", "subu ", "and ", "or ", "xor ", "nor ",
52  0, // 40
53  0, "slt ", "sltu ", 0, 0, 0, 0,
54  "tge ", // 48
55  "tgeu ", "tlt ", "tltu ", "teq ", 0, "tne ", 0,
56  0, // 56
57  0, 0, 0, 0, 0, 0, 0};
58 
59 const char *g_pRegimm[32] = {
60  "bltz ", "bgez ", "bltzl ", "bgezl ", 0, 0, 0, 0,
61  "tgei ", // 8
62  "tgeiu ", "tlti ", "tltiu ", "teqi ", 0, "tnei ", 0,
63  "bltzal", // 16
64  "bgezal", "bltzall", "bgezall", 0, 0, 0, 0,
65  0, // 24
66  0, 0, 0, 0, 0, 0, 0};
67 
68 const char *g_pCopzRs[32] = {"mfc", 0, "cfc", 0, "mtc", 0, "ctc", 0,
69  "bc", // 8
70  0, 0, 0, 0, 0, 0, 0,
71  "co", // 16
72  "co", "co", "co", "co", "co", "co", "co",
73  "co", // 24
74  "co", "co", "co", "co", "co", "co", "co"};
75 
76 const char *g_pCopzRt[32] = {"f", "t", "fl", "tl", 0, 0, 0, 0,
77  0, // 8
78  0, 0, 0, 0, 0, 0, 0,
79  0, // 16
80  0, 0, 0, 0, 0, 0, 0,
81  0, // 24
82  0, 0, 0, 0, 0, 0, 0};
83 
84 const char *g_pCp0Function[64] = {0, "tlbr", "tlbwi", 0, 0, 0, "tlbwr", 0,
85  "tlbp", // 8
86  0, 0, 0, 0, 0, 0, 0,
87  "rfe", // 16
88  0, 0, 0, 0, 0, 0, 0,
89  "eret", // 24
90  0, 0, 0, 0, 0, 0, 0,
91  0, // 32
92  0, 0, 0, 0, 0, 0, 0,
93  0, // 40
94  0, 0, 0, 0, 0, 0, 0,
95  0, // 48
96  0, 0, 0, 0, 0, 0, 0,
97  0, // 56
98  0, 0, 0, 0, 0, 0, 0};
99 
100 const char *g_pRegisters[32] = {
101  "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2",
102  "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5",
103  "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"};
104 
105 MipsDisassembler::MipsDisassembler() : m_nLocation(0)
106 {
107 }
108 
109 MipsDisassembler::~MipsDisassembler()
110 {
111 }
112 
113 void MipsDisassembler::setLocation(uintptr_t nLocation)
114 {
115  m_nLocation = nLocation;
116 }
117 
119 {
120  return m_nLocation;
121 }
122 
123 void MipsDisassembler::setMode(size_t nMode)
124 {
125 }
126 
128 {
129  uint32_t nInstruction = *reinterpret_cast<uint32_t *>(m_nLocation);
130  m_nLocation += 4;
131 
132  // SLL $zero, $zero, 0 == nop.
133  if (nInstruction == 0)
134  {
135  text += "nop";
136  return;
137  }
138 
139  // Grab the instruction opcode.
140  int nOpcode = (nInstruction >> 26) & 0x3F;
141 
142  // Handle special opcodes.
143  if (nOpcode == 0)
144  {
145  disassembleSpecial(nInstruction, text);
146  }
147  else if (nOpcode == 1)
148  {
149  disassembleRegImm(nInstruction, text);
150  }
151  else
152  {
153  disassembleOpcode(nInstruction, text);
154  }
155 }
156 
157 void MipsDisassembler::disassembleSpecial(
158  uint32_t nInstruction, LargeStaticString &text)
159 {
160  // Special instructions are R-Types.
161  uint32_t nRs = (nInstruction >> 21) & 0x1F;
162  uint32_t nRt = (nInstruction >> 16) & 0x1F;
163  uint32_t nRd = (nInstruction >> 11) & 0x1F;
164  uint32_t nShamt = (nInstruction >> 6) & 0x1F;
165  uint32_t nFunct = nInstruction & 0x3F;
166 
167  if (g_pSpecial[nFunct] == 0)
168  return;
169 
170  switch (nFunct)
171  {
172  case 00: // SLL
173  case 02: // SRL
174  case 03: // SRA
175  text += g_pSpecial[nFunct];
176  text += " ";
177  text += g_pRegisters[nRd];
178  text += ", ";
179  text += g_pRegisters[nRt];
180  text += ", ";
181  text += nShamt;
182  break;
183  case 04: // SLLV
184  case 06: // SRLV
185  case 07: // SRAV
186  text += g_pSpecial[nFunct];
187  text += " ";
188  text += g_pRegisters[nRd];
189  text += ", ";
190  text += g_pRegisters[nRt];
191  text += ", ";
192  text += g_pRegisters[nRs];
193  break;
194  case 010: // JR
195  text += "jr ";
196  text += g_pRegisters[nRs];
197  break;
198  case 011: // JALR
199  {
200  text += "jalr ";
201  if (nRd != 31)
202  {
203  text += g_pRegisters[nRd];
204  text += ", ";
205  }
206  text += g_pRegisters[nRs];
207  break;
208  }
209  case 014: // SYSCALL
210  case 015: // BREAK
211  case 017: // SYNC
212  text += g_pSpecial[nFunct];
213  break;
214  case 020: // MFHI
215  case 022: // MFLO
216  text += g_pSpecial[nFunct];
217  text += " ";
218  text += g_pRegisters[nRd];
219  break;
220  case 021: // MTHI
221  case 023: // MTLO
222  text += g_pSpecial[nFunct];
223  text += " ";
224  text += g_pRegisters[nRs];
225  break;
226  case 030: // MULT
227  case 031: // MULTU
228  case 032: // DIV
229  case 033: // DIVU
230  case 060: // TGE
231  case 061: // TGEU
232  case 062: // TLT
233  case 063: // TLTU
234  case 064: // TEQ
235  case 065: // TNE
236  text += g_pSpecial[nFunct];
237  text += " ";
238  text += g_pRegisters[nRs];
239  text += ", ";
240  text += g_pRegisters[nRt];
241  break;
242  case 041: // ADDU
243  if (nRt == 0)
244  {
245  // If this is an add of zero, it is actually a "move".
246  text += "move ";
247  text += g_pRegisters[nRd];
248  text += ", ";
249  text += g_pRegisters[nRs];
250  break;
251  }
252  // Fall through.
253  default:
254  {
255  text += g_pSpecial[nFunct];
256  text += " ";
257  text += g_pRegisters[nRd];
258  text += ", ";
259  text += g_pRegisters[nRs];
260  text += ", ";
261  text += g_pRegisters[nRt];
262  }
263  };
264 }
265 
266 void MipsDisassembler::disassembleRegImm(
267  uint32_t nInstruction, LargeStaticString &text)
268 {
269  uint32_t nRs = (nInstruction >> 21) & 0x1F;
270  uint32_t nOp = (nInstruction >> 16) & 0x1F;
271  uint16_t nImmediate = nInstruction & 0xFFFF;
272  uint32_t nTarget = (nImmediate << 2) + m_nLocation;
273 
274  switch (nOp)
275  {
276  case 010: // TGEI
277  case 011: // TGEIU
278  case 012: // TLTI
279  case 013: // TLTIU
280  case 014: // TEQI
281  case 016: // TNEI
282  text += g_pRegimm[nOp];
283  text += " ";
284  text += g_pRegisters[nRs];
285  text += ", ";
286  text.append(static_cast<int16_t>(nImmediate), 10);
287  break;
288  default:
289  text += g_pRegimm[nOp];
290  text += " ";
291  text += g_pRegisters[nRs];
292  text += ", 0x";
293  text.append(nTarget, 16);
294  };
295 }
296 
297 void MipsDisassembler::disassembleOpcode(
298  uint32_t nInstruction, LargeStaticString &text)
299 {
300  // Opcode instructions are J-Types, or I-Types.
301  // Jump target is the lower 26 bits shifted left 2 bits, OR'd with the high
302  // 4 bits of the delay slot.
303  uint32_t nTarget =
304  ((nInstruction & 0x03FFFFFF) << 2) | (m_nLocation & 0xF0000000);
305  uint16_t nImmediate = nInstruction & 0x0000FFFF;
306  uint32_t nRt = (nInstruction >> 16) & 0x1F;
307  uint32_t nRs = (nInstruction >> 21) & 0x1F;
308  int nOpcode = (nInstruction >> 26) & 0x3F;
309 
310  switch (nOpcode)
311  {
312  case 02: // J
313  case 03: // JAL
314  text += g_pOpcodes[nOpcode];
315  text += " 0x";
316  text.append(nTarget, 16);
317  break;
318  case 006: // BLEZ
319  case 007: // BGTZ
320  case 026: // BLEZL
321  case 027: // BGTZL
322  text += g_pOpcodes[nOpcode];
323  text += " ";
324  text += g_pRegisters[nRs];
325  text += ", 0x";
326  text.append(
327  (static_cast<uint32_t>(nImmediate) << 2) + m_nLocation, 16);
328  break;
329  case 004: // BEQ
330  case 005: // BNE
331  case 024: // BEQL
332  case 025: // BNEL
333  text += g_pOpcodes[nOpcode];
334  text += " ";
335  text += g_pRegisters[nRs];
336  text += ", ";
337  text += g_pRegisters[nRt];
338  text += ", 0x";
339  text.append(
340  (static_cast<uint32_t>(nImmediate) << 2) + m_nLocation, 16);
341  break;
342  case 010: // ADDI
343  case 011: // ADDIU
344  case 012: // SLTI
345  case 013: // SLTIU
346  case 014: // ANDI
347  case 015: // ORI
348  case 016: // XORI
349  text += g_pOpcodes[nOpcode];
350  text += " ";
351  text += g_pRegisters[nRt];
352  text += ", ";
353  text += g_pRegisters[nRs];
354  text += ", ";
355  text.append(static_cast<short>(nImmediate), 10);
356  break;
357  case 017: // LUI
358  text += "lui ";
359  text += g_pRegisters[nRt];
360  text += ", 0x";
361  text.append(nImmediate, 16);
362  break;
363  case 020: // COP0
364  case 021: // COP1
365  case 022: // COP2
366  case 023: // COP3
367  {
368  if (nRs == 8) // BC
369  {
370  text += g_pCopzRs[nRs];
371  text.append(static_cast<unsigned char>(nOpcode & 0x3));
372  text += g_pCopzRt[nRt];
373  text += ", 0x";
374  text.append((nImmediate << 2) + m_nLocation, 16);
375  }
376  else if (nOpcode == 020 /* CP0 */ && nRs >= 16 /* CO */)
377  {
378  text += g_pCp0Function[nInstruction & 0x1F];
379  }
380  else
381  {
382  text += g_pCopzRs[nRs];
383  text.append(static_cast<unsigned char>(nOpcode & 0x3));
384  text += " ";
385  text += g_pRegisters[nRt];
386  text += ", ";
387  text.append(((nInstruction >> 11) & 0x1F), 10);
388  }
389  break;
390  }
391  default:
392  text += g_pOpcodes[nOpcode];
393  text += " ";
394  text += g_pRegisters[nRt];
395  text += ", ";
396  text.append(static_cast<short>(nImmediate), 10);
397  text += "(";
398  text += g_pRegisters[nRs];
399  text += ")";
400  break;
401  }
402 }
void disassemble(LargeStaticString &text)
void setMode(size_t nMode)
void setLocation(uintptr_t nLocation)