Added a library for the default exception handler and started to add a dissasembler...
[mirror_edk2.git] / ArmPkg / Library / DefaultExceptionHandlerLib / ThumbDisassembler.c
1 /** @file
2 Default exception handler
3
4 Copyright (c) 2008-2010, Apple Inc. All rights reserved.
5
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include <Base.h>
17 #include <Library/BaseLib.h>
18 #include <Library/PrintLib.h>
19
20 extern CHAR8 *gReg[];
21
22 #define LOAD_STORE_FORMAT1 1
23 #define LOAD_STORE_FORMAT2 2
24 #define LOAD_STORE_FORMAT3 3
25 #define LOAD_STORE_FORMAT4 4
26 #define LOAD_STORE_MULTIPLE_FORMAT1 5
27 #define LOAD_STORE_MULTIPLE_FORMAT2 6
28 #define IMMED_8 7
29 #define CONDITIONAL_BRANCH 8
30 #define UNCONDITIONAL_BRANCH 9
31 #define UNCONDITIONAL_BRANCH_SHORT 109
32 #define BRANCH_EXCHANGE 10
33 #define DATA_FORMAT1 11
34 #define DATA_FORMAT2 12
35 #define DATA_FORMAT3 13
36 #define DATA_FORMAT4 14
37 #define DATA_FORMAT5 15
38 #define DATA_FORMAT6_SP 16
39 #define DATA_FORMAT6_PC 116
40 #define DATA_FORMAT7 17
41 #define DATA_FORMAT8 19
42 #define CPS_FORMAT 20
43 #define ENDIAN_FORMAT 21
44
45
46 typedef struct {
47 CHAR8 *Start;
48 UINT32 OpCode;
49 UINT32 Mask;
50 UINT32 AddressMode;
51 } THUMB_INSTRUCTIONS;
52
53 THUMB_INSTRUCTIONS gOp[] = {
54 // Thumb 16-bit instrucitons
55 // Op Mask Format
56 { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5 },
57
58 { "ADD" , 0x1c00, 0xfe00, DATA_FORMAT2 },
59 { "ADD" , 0x3000, 0xf800, DATA_FORMAT3 },
60 { "ADD" , 0x1800, 0xfe00, DATA_FORMAT1 },
61 { "ADD" , 0x4400, 0xff00, DATA_FORMAT8 }, // A8.6.9
62 { "ADD" , 0xa000, 0xf100, DATA_FORMAT6_PC },
63 { "ADD" , 0xa100, 0xf100, DATA_FORMAT6_SP },
64 { "ADD" , 0xb000, 0xff10, DATA_FORMAT7 },
65
66 { "AND" , 0x4000, 0xffc0, DATA_FORMAT5 },
67
68 { "ASR" , 0x1000, 0xf800, DATA_FORMAT4 },
69 { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5 },
70
71 { "B" , 0xd000, 0xf000, CONDITIONAL_BRANCH },
72 { "B" , 0xe000, 0xf100, UNCONDITIONAL_BRANCH_SHORT },
73 { "BL" , 0xf100, 0xf100, UNCONDITIONAL_BRANCH },
74 { "BLX" , 0xe100, 0xf100, UNCONDITIONAL_BRANCH },
75 { "BLX" , 0x4780, 0xff80, BRANCH_EXCHANGE },
76 { "BX" , 0x4700, 0xff80, BRANCH_EXCHANGE },
77
78 { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5 },
79 { "BKPT", 0xdf00, 0xff00, IMMED_8 },
80 { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5 },
81
82 { "CMP" , 0x2800, 0xf100, DATA_FORMAT3 },
83 { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5 },
84 { "CMP" , 0x4500, 0xff00, DATA_FORMAT8 },
85
86 { "CPS" , 0xb660, 0xffe8, CPS_FORMAT },
87 { "CPY" , 0x4600, 0xff00, DATA_FORMAT8 },
88 { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5 },
89
90 { "LDMIA" , 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },
91 { "LDR" , 0x6800, 0xf800, LOAD_STORE_FORMAT1 },
92 { "LDR" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2 },
93 { "LDR" , 0x4800, 0xf800, LOAD_STORE_FORMAT3 },
94 { "LDR" , 0x9800, 0xf800, LOAD_STORE_FORMAT4 },
95 { "LDRB" , 0x7800, 0xf800, LOAD_STORE_FORMAT1 },
96 { "LDRB" , 0x5c00, 0xfe00, LOAD_STORE_FORMAT2 },
97 { "LDRH" , 0x8800, 0xf800, LOAD_STORE_FORMAT1 },
98 { "LDRH" , 0x7a00, 0xfe00, LOAD_STORE_FORMAT2 },
99 { "LDRSB" , 0x5600, 0xfe00, LOAD_STORE_FORMAT2 },
100 { "LDRSH" , 0x5e00, 0xfe00, LOAD_STORE_FORMAT2 },
101
102 { "LSL" , 0x0000, 0xf800, DATA_FORMAT4 },
103 { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5 },
104 { "LSR" , 0x0001, 0xf800, DATA_FORMAT4 },
105 { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5 },
106
107 { "MOV" , 0x2000, 0xf800, DATA_FORMAT3 },
108 { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3 },
109 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },
110
111 { "MUL" , 0x4340, 0xffc0, DATA_FORMAT5 },
112 { "MVN" , 0x41c0, 0xffc0, DATA_FORMAT5 },
113 { "NEG" , 0x4240, 0xffc0, DATA_FORMAT5 },
114 { "ORR" , 0x4180, 0xffc0, DATA_FORMAT5 },
115 { "POP" , 0xbc00, 0xfe00, LOAD_STORE_MULTIPLE_FORMAT2 },
116 { "POP" , 0xe400, 0xfe00, LOAD_STORE_MULTIPLE_FORMAT2 },
117
118 { "REV" , 0xba00, 0xffc0, DATA_FORMAT5 },
119 { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5 },
120 { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5 },
121
122 { "ROR" , 0x41c0, 0xffc0, DATA_FORMAT5 },
123 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5 },
124 { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT },
125
126 { "STMIA" , 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },
127 { "STR" , 0x6000, 0xf800, LOAD_STORE_FORMAT1 },
128 { "STR" , 0x5000, 0xfe00, LOAD_STORE_FORMAT2 },
129 { "STR" , 0x4000, 0xf800, LOAD_STORE_FORMAT3 },
130 { "STR" , 0x9000, 0xf800, LOAD_STORE_FORMAT4 },
131 { "STRB" , 0x7000, 0xf800, LOAD_STORE_FORMAT1 },
132 { "STRB" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2 },
133 { "STRH" , 0x8000, 0xf800, LOAD_STORE_FORMAT1 },
134 { "STRH" , 0x5200, 0xfe00, LOAD_STORE_FORMAT2 },
135
136 { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2 },
137 { "SUB" , 0x3800, 0xf800, DATA_FORMAT3 },
138 { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1 },
139 { "SUB" , 0xb080, 0xff80, DATA_FORMAT7 },
140
141 { "SWI" , 0xdf00, 0xff00, IMMED_8 },
142 { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5 },
143 { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5 },
144 { "TST" , 0x4200, 0xffc0, DATA_FORMAT5 },
145 { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5 },
146 { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5 }
147
148 #if 0
149 ,
150
151 // 32-bit Thumb instructions op1 01
152
153 // 1110 100x x0xx xxxx xxxx xxxx xxxx xxxx Load/store multiple
154 { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT }, // SRSDB<c> SP{!},#<mode>
155 { "SRS" , 0xe98dc000, 0xffdffff0, SRS_IA_FORMAT }, // SRS{IA}<c> SP{!},#<mode>
156 { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT }, // RFEDB<c> <Rn>{!}
157 { "RFE" , 0xe990c000, 0xffd0ffff, RFE_IA_FORMAT }, // RFE{IA}<c> <Rn>{!}
158
159 { "STM" , 0xe8800000, 0xffd00000, STM_FORMAT }, // STM<c>.W <Rn>{!},<registers>
160 { "LDM" , 0xe8900000, 0xffd00000, STM_FORMAT }, // LDR<c>.W <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]
161 { "POP" , 0xe8bd0000, 0xffff2000, REGLIST_FORMAT }, // POP<c>.W <registers> >1 register
162 { "POP" , 0xf85d0b04, 0xffff0fff, RT_FORMAT }, // POP<c>.W <registers> 1 register
163
164 { "STMDB", 0xe9000000, 0xffd00000, STM_FORMAT }, // STMDB
165 { "PUSH" , 0xe8bd0000, 0xffffa000, REGLIST_FORMAT }, // PUSH<c>.W <registers> >1 register
166 { "PUSH" , 0xf84d0b04, 0xffff0fff, RT_FORMAT }, // PUSH<c>.W <registers> 1 register
167 { "LDMDB", 0xe9102000, 0xffd02000, STM_FORMAT }, // LDMDB<c> <Rn>{!},<registers>
168
169 // 1110 100x x1xx xxxx xxxx xxxx xxxx xxxx Load/store dual,
170 { "STREX" , 0xe0400000, 0xfff000f0, 3REG_IMM8_FORMAT }, // STREX<c> <Rd>,<Rt>,[<Rn>{,#<imm>}]
171 { "STREXB", 0xe8c00f40, 0xfff00ff0, 3REG_FORMAT }, // STREXB<c> <Rd>,<Rt>,[<Rn>]
172 { "STREXD", 0xe8c00070, 0xfff000f0, 4REG_FORMAT }, // STREXD<c> <Rd>,<Rt>,<Rt2>,[<Rn>]
173 { "STREXH", 0xe8c00f70, 0xfff00ff0, 3REG_FORMAT }, // STREXH<c> <Rd>,<Rt>,[<Rn>]
174 { "STRH", 0xf8c00000, 0xfff00000, 2REG_IMM8_FORMAT }, // STRH<c>.W <Rt>,[<Rn>{,#<imm12>}]
175 { "STRH", 0xf8200000, 0xfff00000, }, // STRH<c>.W <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]
176
177
178
179 // 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx Data-processing
180 // 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx Coprocessor
181
182 // 1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx Data-processing modified immediate
183 // 1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx Data-processing plain immediate
184 // 1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx Branches
185
186 // 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx Store single data item
187 // 1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx SIMD or load/store
188 // 1111 100x x001 xxxx xxxx xxxx xxxx xxxx Load byte, memory hints
189 // 1111 100x x011 xxxx xxxx xxxx xxxx xxxx Load halfword, memory hints
190 // 1111 100x x101 xxxx xxxx xxxx xxxx xxxx Load word
191
192 // 1111 1 010 xxxx xxxx xxxx xxxx xxxx xxxx Data-processing register
193 // 1111 1 011 0xxx xxxx xxxx xxxx xxxx xxxx Multiply
194 // 1111 1 011 1xxx xxxx xxxx xxxx xxxx xxxx Long Multiply
195 // 1111 1 1xx xxxx xxxx xxxx xxxx xxxx xxxx Coprocessor
196 #endif
197 };
198
199
200 CHAR8 mThumbMregListStr[4*15 + 1];
201
202 CHAR8 *
203 ThumbMRegList (
204 UINT32 OpCode
205 )
206 {
207 UINTN Index, Start, End;
208 CHAR8 *Str;
209 BOOLEAN First;
210
211 Str = mThumbMregListStr;
212 *Str = '\0';
213 AsciiStrCat (Str, "{");
214 // R0 - R7, PC
215 for (Index = 0, First = TRUE; Index <= 9; Index++) {
216 if ((OpCode & (1 << Index)) != 0) {
217 Start = End = Index;
218 for (Index++; ((OpCode & (1 << Index)) != 0) && (Index <= 9); Index++) {
219 End = Index;
220 }
221
222 if (!First) {
223 AsciiStrCat (Str, ",");
224 } else {
225 First = FALSE;
226 }
227
228 if (Start == End) {
229 AsciiStrCat (Str, gReg[(Start == 9)?15:Start]);
230 AsciiStrCat (Str, ", ");
231 } else {
232 AsciiStrCat (Str, gReg[Start]);
233 AsciiStrCat (Str, "-");
234 AsciiStrCat (Str, gReg[(End == 9)?15:End]);
235 }
236 }
237 }
238 if (First) {
239 AsciiStrCat (Str, "ERROR");
240 }
241 AsciiStrCat (Str, "}");
242
243 // BugBug: Make caller pass in buffer it is cleaner
244 return mThumbMregListStr;
245 }
246
247 UINT32
248 SignExtend (
249 IN UINT32 Data
250 )
251 {
252 return 0;
253 }
254
255 /**
256 DEBUG print the faulting instruction. We cheat and only decode instructions that access
257 memory. If the instruction is not found we dump the instruction in hex.
258
259 @param Insturction ARM instruction to disassemble.
260
261 **/
262 VOID
263 DisassembleThumbInstruction (
264 IN UINT16 *OpCodePtr,
265 OUT CHAR8 *Buf,
266 OUT UINTN Size
267 )
268 {
269 UINT16 OpCode = *OpCodePtr;
270 UINT32 Index;
271 UINT32 Offset;
272 UINT16 Rd, Rn, Rm;
273 INT32 target_addr;
274 BOOLEAN H1, H2, imod;
275 UINT32 PC;
276
277 // These register names match branch form, but not others
278 Rd = OpCode & 0x7;
279 Rn = (OpCode >> 3) & 0x7;
280 Rm = (OpCode >> 6) & 0x7;
281 H1 = (OpCode & BIT7) != 0;
282 H2 = (OpCode & BIT6) != 0;
283 imod = (OpCode & BIT4) != 0;
284 PC = (UINT32)(UINTN)*OpCodePtr;
285
286 for (Index = 0; Index < sizeof (gOp)/sizeof (THUMB_INSTRUCTIONS); Index++) {
287 if ((OpCode & gOp[Index].Mask) == gOp[Index].OpCode) {
288 Offset = AsciiSPrint (Buf, Size, "%a", gOp[Index].Start);
289 switch (gOp[Index].AddressMode) {
290 case LOAD_STORE_FORMAT1:
291 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
292 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, (OpCode >> 7) & 7, (OpCode >> 6) & 0x1f);
293 break;
294 case LOAD_STORE_FORMAT2:
295 // A6.5.1 <Rd>, [<Rn>, <Rm>]
296 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d, r%d]", Rd, (OpCode >> 3) & 7, Rm);
297 break;
298 case LOAD_STORE_FORMAT3:
299 // A6.5.1 <Rd>, [PC, #<8_bit_offset>]
300 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [pc, #0x%x]", (OpCode >> 8) & 7, OpCode & 0xff);
301 break;
302 case LOAD_STORE_FORMAT4:
303 // FIX ME!!!!!
304 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [sp, #0x%x]", (OpCode >> 8) & 7, OpCode & 0xff);
305 break;
306
307 case LOAD_STORE_MULTIPLE_FORMAT1:
308 // <Rn>!, <registers>
309 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d!, %a", (OpCode >> 8) & 7, ThumbMRegList (!BIT8 & OpCode));
310 break;
311 case LOAD_STORE_MULTIPLE_FORMAT2:
312 // <Rn>!, <registers>
313 // BIT8 is PC
314 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d!, %a", (OpCode >> 8) & 7, ThumbMRegList (OpCode));
315 break;
316
317 case IMMED_8:
318 // A6.7 <immed_8>
319 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%x", OpCode & 0xff);
320 break;
321
322 case CONDITIONAL_BRANCH:
323 // A6.3.1 B<cond> <target_address>
324 AsciiSPrint (&Buf[Offset], Size - Offset, "%a 0x%04x", PC + 4 + SignExtend ((OpCode & 0xff) << 1));
325 break;
326 case UNCONDITIONAL_BRANCH_SHORT:
327 // A6.3.2 B <target_address>
328 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 4 + SignExtend ((OpCode & 0x3ff) << 1));
329 break;
330 case UNCONDITIONAL_BRANCH:
331 // A6.3.2 BL|BLX <target_address> ; Produces two 16-bit instructions
332 target_addr = *(OpCodePtr - 1);
333 if ((target_addr & 0xf800) == 0xf000) {
334 target_addr = ((target_addr & 0x3ff) << 12) | (OpCode & 0x3ff);
335 } else {
336 target_addr = OpCode & 0x3ff;
337 }
338 // PC + 2 +/- target_addr
339 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 2 + SignExtend (target_addr));
340 break;
341 case BRANCH_EXCHANGE:
342 // A6.3.3 BX|BLX <Rm>
343 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d", gReg[Rn | (H2 ? 8:0)]);
344 break;
345
346 case DATA_FORMAT1:
347 // A6.4.3 <Rd>, <Rn>, <Rm>
348 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, r%d", Rd, Rn, Rm);
349 break;
350 case DATA_FORMAT2:
351 // A6.4.3 <Rd>, <Rn>, #3_bit_immed
352 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rd, Rn, Rm);
353 break;
354 case DATA_FORMAT3:
355 // A6.4.3 <Rd>|<Rn>, #8_bit_immed
356 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", (OpCode >> 8) & 0x7, OpCode & 0xff);
357 break;
358 case DATA_FORMAT4:
359 // A6.4.3 <Rd>|<Rm>, #immed_5
360 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rn, Rd, (OpCode >> 6) & 0x1f);
361 break;
362 case DATA_FORMAT5:
363 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>
364 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d", Rd, Rn);
365 break;
366 case DATA_FORMAT6_SP:
367 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
368 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, sp, 0x%x", (OpCode >> 8) & 7, OpCode & 0xff);
369 break;
370 case DATA_FORMAT6_PC:
371 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
372 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, pc, 0x%x", (OpCode >> 8) & 7, OpCode & 0xff);
373 break;
374 case DATA_FORMAT7:
375 // A6.4.3 SP, SP, #<7_Bit_immed>
376 AsciiSPrint (&Buf[Offset], Size - Offset, " sp, sp 0x%x", (OpCode & 0x7f)*4);
377 break;
378 case DATA_FORMAT8:
379 // A6.4.3 <Rd>|<Rn>, <Rm>
380 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd | (H1 ? 8:0)], gReg[Rn | (H2 ? 8:0)]);
381 break;
382
383 case CPS_FORMAT:
384 // A7.1.24
385 AsciiSPrint (&Buf[Offset], Size - Offset, "%a %a%a%a", imod ? "ID":"IE", ((OpCode & BIT2) == 0) ? "":"a", ((OpCode & BIT1) == 0) ? "":"i", ((OpCode & BIT0) == 0) ? "":"f");
386 break;
387
388 case ENDIAN_FORMAT:
389 // A7.1.24
390 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", (OpCode & BIT3) == 0 ? "LE":"BE");
391 break;
392 }
393 }
394 }
395
396
397 }
398
399