2 Default exception handler
4 Copyright (c) 2008-2010, Apple Inc. All rights reserved.
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
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.
17 #include <Library/BaseLib.h>
18 #include <Library/PrintLib.h>
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
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
43 #define ENDIAN_FORMAT 21
53 THUMB_INSTRUCTIONS gOp
[] = {
54 // Thumb 16-bit instrucitons
56 { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5
},
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
},
66 { "AND" , 0x4000, 0xffc0, DATA_FORMAT5
},
68 { "ASR" , 0x1000, 0xf800, DATA_FORMAT4
},
69 { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5
},
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
},
78 { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5
},
79 { "BKPT", 0xdf00, 0xff00, IMMED_8
},
80 { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5
},
82 { "CMP" , 0x2800, 0xf100, DATA_FORMAT3
},
83 { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5
},
84 { "CMP" , 0x4500, 0xff00, DATA_FORMAT8
},
86 { "CPS" , 0xb660, 0xffe8, CPS_FORMAT
},
87 { "CPY" , 0x4600, 0xff00, DATA_FORMAT8
},
88 { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5
},
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
},
102 { "LSL" , 0x0000, 0xf800, DATA_FORMAT4
},
103 { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5
},
104 { "LSR" , 0x0001, 0xf800, DATA_FORMAT4
},
105 { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5
},
107 { "MOV" , 0x2000, 0xf800, DATA_FORMAT3
},
108 { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3
},
109 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8
},
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
},
118 { "REV" , 0xba00, 0xffc0, DATA_FORMAT5
},
119 { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5
},
120 { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5
},
122 { "ROR" , 0x41c0, 0xffc0, DATA_FORMAT5
},
123 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5
},
124 { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT
},
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
},
136 { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2
},
137 { "SUB" , 0x3800, 0xf800, DATA_FORMAT3
},
138 { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1
},
139 { "SUB" , 0xb080, 0xff80, DATA_FORMAT7
},
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
}
151 // 32-bit Thumb instructions op1 01
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>{!}
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
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>
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>}]
179 // 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx Data-processing
180 // 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx Coprocessor
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
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
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
200 CHAR8 mThumbMregListStr
[4*15 + 1];
207 UINTN Index
, Start
, End
;
211 Str
= mThumbMregListStr
;
213 AsciiStrCat (Str
, "{");
215 for (Index
= 0, First
= TRUE
; Index
<= 9; Index
++) {
216 if ((OpCode
& (1 << Index
)) != 0) {
218 for (Index
++; ((OpCode
& (1 << Index
)) != 0) && (Index
<= 9); Index
++) {
223 AsciiStrCat (Str
, ",");
229 AsciiStrCat (Str
, gReg
[(Start
== 9)?15:Start
]);
230 AsciiStrCat (Str
, ", ");
232 AsciiStrCat (Str
, gReg
[Start
]);
233 AsciiStrCat (Str
, "-");
234 AsciiStrCat (Str
, gReg
[(End
== 9)?15:End
]);
239 AsciiStrCat (Str
, "ERROR");
241 AsciiStrCat (Str
, "}");
243 // BugBug: Make caller pass in buffer it is cleaner
244 return mThumbMregListStr
;
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.
259 @param Insturction ARM instruction to disassemble.
263 DisassembleThumbInstruction (
264 IN UINT16
*OpCodePtr
,
269 UINT16 OpCode
= *OpCodePtr
;
274 BOOLEAN H1
, H2
, imod
;
277 // These register names match branch form, but not others
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
;
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);
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
);
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);
302 case LOAD_STORE_FORMAT4
:
304 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [sp, #0x%x]", (OpCode
>> 8) & 7, OpCode
& 0xff);
307 case LOAD_STORE_MULTIPLE_FORMAT1
:
308 // <Rn>!, <registers>
309 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d!, %a", (OpCode
>> 8) & 7, ThumbMRegList (!BIT8
& OpCode
));
311 case LOAD_STORE_MULTIPLE_FORMAT2
:
312 // <Rn>!, <registers>
314 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d!, %a", (OpCode
>> 8) & 7, ThumbMRegList (OpCode
));
319 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%x", OpCode
& 0xff);
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));
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));
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);
336 target_addr
= OpCode
& 0x3ff;
338 // PC + 2 +/- target_addr
339 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", PC
+ 2 + SignExtend (target_addr
));
341 case BRANCH_EXCHANGE
:
342 // A6.3.3 BX|BLX <Rm>
343 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d", gReg
[Rn
| (H2
? 8:0)]);
347 // A6.4.3 <Rd>, <Rn>, <Rm>
348 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, r%d", Rd
, Rn
, Rm
);
351 // A6.4.3 <Rd>, <Rn>, #3_bit_immed
352 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rd
, Rn
, Rm
);
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);
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);
363 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>
364 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d", Rd
, Rn
);
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);
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);
375 // A6.4.3 SP, SP, #<7_Bit_immed>
376 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " sp, sp 0x%x", (OpCode
& 0x7f)*4);
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)]);
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");
390 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", (OpCode
& BIT3
) == 0 ? "LE":"BE");