nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 Copyright (c) 2013, Jurriaan Bremer
3 All rights reserved.
4  
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
13 * Neither the name of the darm developer(s) nor the names of its
14 contributors may be used to endorse or promote products derived from this
15 software without specific prior written permission.
16  
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include "darm.h"
34 #include "darm-internal.h"
35 #include "thumb-tbl.h"
36  
37 #define BITMSK_8 ((1 << 8) - 1)
38  
39 static int thumb_disasm(darm_t *d, uint16_t w)
40 {
41 d->instr = thumb_instr_labels[w >> 8];
42 d->instr_type = thumb_instr_types[w >> 8];
43  
44 switch ((uint32_t) d->instr_type) {
45 case T_THUMB_ONLY_IMM8:
46 d->I = B_SET;
47 d->imm = w & BITMSK_8;
48 return 0;
49  
50 case T_THUMB_COND_BRANCH:
51 d->cond = (w >> 8) & b1111;
52 d->I = B_SET;
53 d->imm = (uint32_t)(int8_t)(w & BITMSK_8) << 1;
54 return 0;
55  
56 case T_THUMB_UNCOND_BRANCH:
57 d->I = B_SET;
58 d->imm = w & ((1 << 11) - 1);
59  
60 // manually sign-extend it
61 if(((d->imm >> 10) & 1) != 0) {
62 d->imm |= ~((1 << 11) - 1);
63 }
64  
65 // finally, shift it one byte to the left
66 d->imm <<= 1;
67 return 0;
68  
69 case T_THUMB_SHIFT_IMM:
70 d->Rd = (w >> 0) & b111;
71 d->Rm = (w >> 3) & b111;
72 d->shift = (w >> 6) & b11111;
73  
74 // if the shift is zero and this is the lsl instruction, then this is
75 // actually a mov instruction
76 if(d->shift == 0 && d->instr == I_LSL) {
77 d->instr = I_MOV;
78 }
79 else {
80 // set the correct shift-type
81 switch ((uint32_t) d->instr) {
82 case I_ASR:
83 d->shift_type = S_ASR;
84 break;
85  
86 case I_LSL:
87 d->shift_type = S_LSL;
88 break;
89  
90 case I_LSR:
91 d->shift_type = S_LSR;
92 break;
93 }
94 }
95 return 0;
96  
97 case T_THUMB_STACK:
98 d->I = B_SET;
99 d->imm = (w & BITMSK_8) << 2;
100 d->Rn = SP;
101 d->Rt = (w >> 8) & b111;
102 d->U = B_SET;
103 d->W = B_UNSET;
104 d->P = B_SET;
105 return 0;
106  
107 case T_THUMB_LDR_PC:
108 d->I = B_SET;
109 d->imm = (w & BITMSK_8) << 2;
110 d->Rn = PC;
111 d->Rt = (w >> 8) & b111;
112 d->U = B_SET;
113 d->W = B_UNSET;
114 d->P = B_SET;
115 return 0;
116  
117 case T_THUMB_GPI:
118 d->instr = type_gpi_instr_lookup[(w >> 6) & b1111];
119 switch ((uint32_t) d->instr) {
120 case I_AND: case I_EOR: case I_LSL: case I_LSR:
121 case I_ASR: case I_ADC: case I_SBC: case I_ROR:
122 d->Rd = d->Rn = w & b111;
123 d->Rm = (w >> 3) & b111;
124 return 0;
125  
126 case I_TST: case I_CMP: case I_CMN:
127 d->Rn = w & b111;
128 d->Rm = (w >> 3) & b111;
129 return 0;
130  
131 case I_RSB:
132 d->I = B_SET;
133 d->imm = 0;
134 d->Rd = w & b111;
135 d->Rn = (w >> 3) & b111;
136 return 0;
137  
138 case I_ORR: case I_BIC:
139 d->Rn = w & b111;
140 // fall-through as the mvn handler is almost the same, except
141 // for parsing Rn
142  
143 case I_MVN:
144 d->Rd = w & b111;
145 d->Rm = (w >> 3) & b111;
146 return 0;
147  
148 case I_MUL:
149 d->Rd = d->Rm = w & b111;
150 d->Rn = (w >> 3) & b111;
151 return 0;
152 }
153  
154 case T_THUMB_BRANCH_REG:
155 d->instr = (w >> 7) & 1 ? I_BLX : I_BX;
156 d->Rm = (w >> 3) & b1111;
157 return 0;
158  
159 case T_THUMB_IT_HINTS:
160 // one of the hints instructions (instructions that hint the cpu and
161 // don't take any operands)
162 if((w & b1111) == 0) {
163 d->instr = type_hints_instr_lookup[(w >> 4) & b111];
164 return d->instr == I_INVLD ? -1 : 0;
165 }
166  
167 // if-then instruction
168 d->instr = I_IT;
169 d->mask = w & b1111;
170 d->firstcond = (w >> 4) & b1111;
171 return 0;
172  
173 case T_THUMB_HAS_IMM8:
174 d->I = B_SET;
175 d->imm = w & BITMSK_8;
176  
177 switch ((uint32_t) d->instr) {
178 case I_ADD: case I_SUB:
179 d->Rd = d->Rn = (w >> 8) & b111;
180 return 0;
181  
182 case I_ADR:
183 d->Rn = PC;
184 d->U = B_SET;
185 d->imm <<= 2;
186 // fall-through as adr also has to set Rd
187  
188 case I_MOV:
189 d->Rd = (w >> 8) & b111;
190 return 0;
191  
192 case I_CMP:
193 d->Rn = (w >> 8) & b111;
194 return 0;
195 }
196  
197 case T_THUMB_EXTEND:
198 d->instr = type_extend_instr_lookup[(w >> 6) & b11];
199 d->Rd = w & b111;
200 d->Rm = (w >> 3) & b111;
201 return 0;
202  
203 case T_THUMB_MOD_SP_IMM:
204 d->instr = (w >> 7) & 1 ? I_SUB : I_ADD;
205 d->Rd = d->Rn = SP;
206 d->I = B_SET;
207 d->imm = (w & 0x7f) << 2;
208 return 0;
209  
210 case T_THUMB_3REG:
211 d->Rd = (w >> 0) & b111;
212 d->Rn = (w >> 3) & b111;
213 d->Rm = (w >> 6) & b111;
214 return 0;
215  
216 case T_THUMB_2REG_IMM:
217 d->Rd = w & b111;
218 d->Rn = (w >> 3) & b111;
219 d->I = B_SET;
220 d->imm = (w >> 6) & b111;
221 return 0;
222  
223 case T_THUMB_ADD_SP_IMM:
224 d->I = B_SET;
225 d->imm = (w & BITMSK_8) << 2;
226 d->Rn = SP;
227 d->Rd = (w >> 8) & b111;
228 return 0;
229  
230 case T_THUMB_MOV4:
231 // D is the 8th bit and has to become the 3th bit, to function as
232 // highest bit for Rd
233 d->Rd = ((w >> 4) & 8) | (w & b111);
234 d->Rm = (w >> 3) & b1111;
235 return 0;
236  
237 case T_THUMB_RW_MEMI:
238 d->Rt = w & b111;
239 d->Rn = (w >> 3) & b111;
240 d->I = B_SET;
241 d->imm = (w >> 6) & b11111;
242  
243 // some instructions require some shifting for the immediate
244 switch ((uint32_t) d->instr) {
245 case I_LDR: case I_STR:
246 d->imm <<= 2;
247 break;
248  
249 case I_LDRH: case I_STRH:
250 d->imm <<= 1;
251 break;
252 }
253  
254 d->P = B_SET;
255 d->U = B_SET;
256 d->W = B_UNSET;
257 return 0;
258  
259 case T_THUMB_RW_MEMO:
260 d->Rt = (w >> 0) & b111;
261 d->Rn = (w >> 3) & b111;
262 d->Rm = (w >> 6) & b111;
263 d->P = B_SET;
264 d->U = B_SET;
265 d->W = B_UNSET;
266 return 0;
267  
268 case T_THUMB_RW_REG:
269 // TODO write-back support for LDM
270 d->reglist = w & BITMSK_8;
271 d->Rn = (w >> 8) & b111;
272 return 0;
273  
274 case T_THUMB_REV:
275 d->instr = type_rev_instr_lookup[(w >> 6) & b11];
276 if(d->instr == I_INVLD) return -1;
277  
278 d->Rd = (w >> 0) & b111;
279 d->Rm = (w >> 3) & b111;
280 return 0;
281  
282 case T_THUMB_SETEND:
283 d->E = (w >> 4) & b1;
284 return 0;
285  
286 case T_THUMB_PUSHPOP:
287 d->reglist = w & BITMSK_8;
288  
289 // for push we have to set LR
290 if(d->instr == I_PUSH) {
291 d->reglist |= ((w >> 8) & 1) << LR;
292 }
293 // for pop we have to set PC
294 else {
295 d->reglist |= ((w >> 8) & 1) << PC;
296 }
297 return 0;
298  
299 case T_THUMB_CMP:
300 // the 4th bit for Rn is stored as the 7th bit
301 d->Rn = (w & b111) | ((w >> 4) & b1000);
302 d->Rm = (w >> 3) & b1111;
303 return 0;
304  
305 case T_THUMB_MOD_SP_REG:
306 // a8.8.6 t2 (also implies a8.8.10 t2)
307 d->Rd = d->Rn = ((w >> 4) & b1000) | (w & b0111);
308 d->Rm = (w >> 3) & b1111;
309  
310 // a8.8.10 t1
311 if(d->Rm == SP) {
312 d->Rd = d->Rm = d->Rn;
313 d->Rn = SP;
314 }
315 return 0;
316  
317 case T_THUMB_CBZ:
318 d->instr = (w >> 11) & 1 ? I_CBNZ : I_CBZ;
319 d->Rn = w & b111;
320 d->Rm = PC;
321 d->U = B_SET;
322 d->I = B_SET;
323 d->imm = ((w >> 2) & (b11111 << 1)) | ((w >> 3) & (1 << 6));
324 return 0;
325 }
326 return -1;
327 }
328  
329 int darm_thumb_disasm(darm_t *d, uint16_t w)
330 {
331 darm_init(d);
332 d->w = w;
333  
334 // we set all conditional flags to "execute always" by default, as most
335 // thumb instructions don't feature a conditional flag
336 d->cond = C_AL;
337  
338 switch (w >> 11) {
339 case b11101: case b11110: case b11111:
340 return -1;
341  
342 default:
343 return thumb_disasm(d, w);
344 }
345 }