The Pedigree Project  0.1
arm_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", "srav",
43  "jr", // 8
44  "jalr", 0, 0, "syscall", "break", 0, "sync",
45  "mfhi", // 16
46  "mthi", "mflo", "mtlo", 0, 0, 0, 0,
47  "mult", // 24
48  "multu", "div", "divu", 0, 0, 0, 0,
49  "add", // 32
50  "addu", "sub", "subu", "and", "or", "xor", "nor",
51  0, // 40
52  0, "slt", "sltu", 0, 0, 0, 0,
53  "tge", // 48
54  "tgeu", "tlt", "tltu", "teq", 0, "tne", 0,
55  0, // 56
56  0, 0, 0, 0, 0, 0, 0};
57 
58 const char *g_pRegimm[32] = {
59  "bltz", "bgez", "bltzl", "bgezl", 0, 0, 0, 0,
60  "tgei", // 8
61  "tgeiu", "tlti", "tltiu", "teqi", 0, "tnei", 0,
62  "bltzal", // 16
63  "bgezal", "bltzall", "bgezall", 0, 0, 0, 0,
64  0, // 24
65  0, 0, 0, 0, 0, 0, 0};
66 
67 const char *g_pCopzRs[32] = {"mfc", 0, "cfc", 0, "mtc", 0, "ctc", 0,
68  "bc", // 8
69  0, 0, 0, 0, 0, 0, 0,
70  "co", // 16
71  "co", "co", "co", "co", "co", "co", "co",
72  "co", // 24
73  "co", "co", "co", "co", "co", "co", "co"};
74 
75 const char *g_pCopzRt[32] = {"f", "t", "fl", "tl", 0, 0, 0, 0,
76  0, // 8
77  0, 0, 0, 0, 0, 0, 0,
78  0, // 16
79  0, 0, 0, 0, 0, 0, 0,
80  0, // 24
81  0, 0, 0, 0, 0, 0, 0};
82 
83 const char *g_pCp0Function[64] = {0, "tlbr", "tlbwi", 0, 0, 0, "tlbwr", 0,
84  "tlbp", // 8
85  0, 0, 0, 0, 0, 0, 0,
86  "rfe", // 16
87  0, 0, 0, 0, 0, 0, 0,
88  "eret", // 24
89  0, 0, 0, 0, 0, 0, 0,
90  0, // 32
91  0, 0, 0, 0, 0, 0, 0,
92  0, // 40
93  0, 0, 0, 0, 0, 0, 0,
94  0, // 48
95  0, 0, 0, 0, 0, 0, 0,
96  0, // 56
97  0, 0, 0, 0, 0, 0, 0};
98 
99 const char *g_pRegisters[32] = {
100  "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2",
101  "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5",
102  "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"};
103 
104 Arm926EDisassembler::Arm926EDisassembler() : m_nLocation(0)
105 {
106 }
107 
108 Arm926EDisassembler::~Arm926EDisassembler()
109 {
110 }
111 
112 void Arm926EDisassembler::setLocation(uintptr_t nLocation)
113 {
114  m_nLocation = nLocation;
115 }
116 
118 {
119  return m_nLocation;
120 }
121 
123 {
124 }
125 
127 {
128  uint32_t nInstruction = *reinterpret_cast<uint32_t *>(m_nLocation);
129  m_nLocation += 4;
130 
131  // SLL $zero, $zero, 0 == nop.
132  if (nInstruction == 0)
133  {
134  text += "nop";
135  return;
136  }
137 
138  // Grab the instruction opcode.
139  int nOpcode = (nInstruction >> 26) & 0x3F;
140 
141  // Handle special opcodes.
142  if (nOpcode == 0)
143  {
144  disassembleSpecial(nInstruction, text);
145  }
146  else if (nOpcode == 1)
147  {
148  disassembleRegImm(nInstruction, text);
149  }
150  else
151  {
152  disassembleOpcode(nInstruction, text);
153  }
154 }
155 
156 void Arm926EDisassembler::disassembleSpecial(
157  uint32_t nInstruction, LargeStaticString &text)
158 {
159  // Special instructions are R-Types.
160  uint32_t nRs = (nInstruction >> 21) & 0x1F;
161  uint32_t nRt = (nInstruction >> 16) & 0x1F;
162  uint32_t nRd = (nInstruction >> 11) & 0x1F;
163  uint32_t nShamt = (nInstruction >> 6) & 0x1F;
164  uint32_t nFunct = nInstruction & 0x3F;
165 
166  if (g_pSpecial[nFunct] == 0)
167  return;
168 
169  switch (nFunct)
170  {
171  case 00: // SLL
172  case 02: // SRL
173  case 03: // SRA
174  text += g_pSpecial[nFunct];
175  text += " ";
176  text += g_pRegisters[nRd];
177  text += ", ";
178  text += g_pRegisters[nRt];
179  text += ", ";
180  text += nShamt;
181  break;
182  case 04: // SLLV
183  case 06: // SRLV
184  case 07: // SRAV
185  text += g_pSpecial[nFunct];
186  text += " ";
187  text += g_pRegisters[nRd];
188  text += ", ";
189  text += g_pRegisters[nRt];
190  text += ", ";
191  text += g_pRegisters[nRs];
192  break;
193  case 010: // JR
194  text += "jr ";
195  text += g_pRegisters[nRs];
196  break;
197  case 011: // JALR
198  {
199  text += "jalr ";
200  if (nRd != 31)
201  {
202  text += g_pRegisters[nRd];
203  text += ", ";
204  }
205  text += g_pRegisters[nRs];
206  break;
207  }
208  case 014: // SYSCALL
209  case 015: // BREAK
210  case 017: // SYNC
211  text += g_pSpecial[nFunct];
212  break;
213  case 020: // MFHI
214  case 022: // MFLO
215  text += g_pSpecial[nFunct];
216  text += " ";
217  text += g_pRegisters[nRd];
218  break;
219  case 021: // MTHI
220  case 023: // MTLO
221  text += g_pSpecial[nFunct];
222  text += " ";
223  text += g_pRegisters[nRs];
224  break;
225  case 030: // MULT
226  case 031: // MULTU
227  case 032: // DIV
228  case 033: // DIVU
229  case 060: // TGE
230  case 061: // TGEU
231  case 062: // TLT
232  case 063: // TLTU
233  case 064: // TEQ
234  case 065: // TNE
235  text += g_pSpecial[nFunct];
236  text += " ";
237  text += g_pRegisters[nRs];
238  text += " ";
239  text += g_pRegisters[nRt];
240  break;
241  case 041: // ADDU
242  if (nRt == 0)
243  {
244  // If this is an add of zero, it is actually a "move".
245  text += "move ";
246  text += g_pRegisters[nRd];
247  text += ", ";
248  text += g_pRegisters[nRs];
249  break;
250  }
251  // Fall through.
252  default:
253  {
254  text += g_pSpecial[nFunct];
255  text += " ";
256  text += g_pRegisters[nRd];
257  text += ", ";
258  text += g_pRegisters[nRs];
259  text += ", ";
260  text += g_pRegisters[nRt];
261  }
262  };
263 }
264 
265 void Arm926EDisassembler::disassembleRegImm(
266  uint32_t nInstruction, LargeStaticString &text)
267 {
268  uint32_t nRs = (nInstruction >> 21) & 0x1F;
269  uint32_t nOp = (nInstruction >> 16) & 0x1F;
270  uint16_t nImmediate = nInstruction & 0xFFFF;
271  uint32_t nTarget = (nImmediate << 2) + m_nLocation;
272 
273  switch (nOp)
274  {
275  case 010: // TGEI
276  case 011: // TGEIU
277  case 012: // TLTI
278  case 013: // TLTIU
279  case 014: // TEQI
280  case 016: // TNEI
281  text += g_pRegimm[nOp];
282  text += " ";
283  text += g_pRegisters[nRs];
284  text += ", ";
285  text.append(static_cast<int16_t>(nImmediate), 10);
286  break;
287  default:
288  text += g_pRegimm[nOp];
289  text += " ";
290  text += g_pRegisters[nRs];
291  text += ", 0x";
292  text.append(nTarget, 16);
293  };
294 }
295 
296 void Arm926EDisassembler::disassembleOpcode(
297  uint32_t nInstruction, LargeStaticString &text)
298 {
299  // Opcode instructions are J-Types, or I-Types.
300  // Jump target is the lower 26 bits shifted left 2 bits, OR'd with the high
301  // 4 bits of the delay slot.
302  uint32_t nTarget =
303  ((nInstruction & 0x03FFFFFF) << 2) | (m_nLocation & 0xF0000000);
304  uint16_t nImmediate = nInstruction & 0x0000FFFF;
305  uint32_t nRt = (nInstruction >> 16) & 0x1F;
306  uint32_t nRs = (nInstruction >> 21) & 0x1F;
307  int nOpcode = (nInstruction >> 26) & 0x3F;
308 
309  switch (nOpcode)
310  {
311  case 02: // J
312  case 03: // JAL
313  text += g_pOpcodes[nOpcode];
314  text += " 0x";
315  text.append(nTarget, 16);
316  break;
317  case 006: // BLEZ
318  case 007: // BGTZ
319  case 026: // BLEZL
320  case 027: // BGTZL
321  text += g_pOpcodes[nOpcode];
322  text += " ";
323  text += g_pRegisters[nRs];
324  text += ", 0x";
325  text.append(
326  (static_cast<uint32_t>(nImmediate) << 2) + m_nLocation, 16);
327  break;
328  case 004: // BEQ
329  case 005: // BNE
330  case 024: // BEQL
331  case 025: // BNEL
332  text += g_pOpcodes[nOpcode];
333  text += " ";
334  text += g_pRegisters[nRs];
335  text += ", ";
336  text += g_pRegisters[nRt];
337  text += ", 0x";
338  text.append(
339  (static_cast<uint32_t>(nImmediate) << 2) + m_nLocation, 16);
340  break;
341  case 010: // ADDI
342  case 011: // ADDIU
343  case 012: // SLTI
344  case 013: // SLTIU
345  case 014: // ANDI
346  case 015: // ORI
347  case 016: // XORI
348  text += g_pOpcodes[nOpcode];
349  text += " ";
350  text += g_pRegisters[nRt];
351  text += ", ";
352  text += g_pRegisters[nRs];
353  text += ", ";
354  text.append(static_cast<short>(nImmediate), 10);
355  break;
356  case 017: // LUI
357  text += "lui ";
358  text += g_pRegisters[nRt];
359  text += ", 0x";
360  text.append(nImmediate, 16);
361  break;
362  case 020: // COP0
363  case 021: // COP1
364  case 022: // COP2
365  case 023: // COP3
366  {
367  if (nRs == 8) // BC
368  {
369  text += g_pCopzRs[nRs];
370  text.append(static_cast<unsigned char>(nOpcode & 0x3));
371  text += g_pCopzRt[nRt];
372  text += ", 0x";
373  text.append((nImmediate << 2) + m_nLocation, 16);
374  }
375  else if (nOpcode == 020 /* CP0 */ && nRs >= 16 /* CO */)
376  {
377  text += g_pCp0Function[nInstruction & 0x1F];
378  }
379  else
380  {
381  text += g_pCopzRs[nRs];
382  text.append(static_cast<unsigned char>(nOpcode & 0x3));
383  text += " ";
384  text += g_pRegisters[nRt];
385  text += ", ";
386  text.append(((nInstruction >> 11) & 0x1F), 10);
387  }
388  break;
389  }
390  default:
391  text += g_pOpcodes[nOpcode];
392  text += " ";
393  text += g_pRegisters[nRt];
394  text += ", ";
395  text.append(static_cast<short>(nImmediate), 10);
396  text += "(";
397  text += g_pRegisters[nRs];
398  text += ")";
399  break;
400  }
401 }
void setLocation(uintptr_t nLocation)
void disassemble(LargeStaticString &text)