1 #ifndef FIRMWARE_LOAD_NG_H
2 #define FIRMWARE_LOAD_NG_H
3
4 #define MIN(a,b) ((a) < (b) ? (a) : (b))
5 #define MAX(a,b) ((a) > (b) ? (a) : (b))
6
7 // Digic 2-5+ (ignoring S1)
8 #define FW_ARCH_ARMv5 1
9 // Digic 6, 7
10 #define FW_ARCH_ARMv7 2
11
12 // additional arch flags
13 #define FW_ARCH_FL_VMSA 1 // firmware implements Virtual Memory System Architecture, i.e. has MMU
14
15 // for clarity of thumb bit manipulations
16 #define ADR_SET_THUMB(x) ((x)|1)
17 #define ADR_CLEAR_THUMB(x) ((x)&~1)
18 #define ADR_IS_THUMB(x) ((x)&1)
19
20 #define ADR_ALIGN4(x) ((x)&~0x3)
21 #define ADR_ALIGN2(x) ((x)&~0x1)
22
23 #define ADR_IS_ALIGN4(x) (((x)&0x3)==0)
24
25 // address regions
26 #define ADR_RANGE_INVALID 0
27 #define ADR_RANGE_ROM 1
28 #define ADR_RANGE_RAM_CODE 2
29 #define ADR_RANGE_INIT_DATA 3
30
31 #define ADR_RANGE_FL_NONE 0
32 #define ADR_RANGE_FL_TCM 1 // TCM
33 #define ADR_RANGE_FL_EVEC 2 // exception vector
34
35 // Stores a range of valid data in the firmware dump (used to skip over empty blocks)
36 typedef struct bufrange {
37 uint32_t *p;
38 int off; // NOTE these are in 32 bit blocks, not bytes
39 int len;
40 struct bufrange* next;
41 } BufRange;
42
43
44 // TODO may want to make run-time adjustable
45 #define ADR_HIST_SIZE 64
46 typedef struct {
47 // circular buffer of previous adr values, for backtracking
48 // use addresses rather than insn, because you might want to scan with detail off and then backtrack with on
49 // addresses have thumb bit set when disassembling in thumb mode
50 int cur; // index of current address, after iter
51 int count; // total number of valid entries
52 uint32_t adrs[ADR_HIST_SIZE];
53 } adr_hist_t;
54
55 // state for disassembly iteration
56 typedef struct {
57 const uint8_t *code; // pointer into buffer for code
58 uint64_t adr; // firmware address - must be 64 bit for capstone iter, never has thumb bit set
59 // points to the next instruction to disassemble, insn->address gives the most
60 // recently disassembled address
61 size_t size; // remaining code size
62 cs_insn *insn; // cached instruction
63 uint32_t thumb; // thumb state
64 uint32_t insn_min_size; // 2 or 4, depending on thumb/arm state
65 csh cs_handle; // capstone handle to use with this state, updated for arm/thumb transitions
66 adr_hist_t ah; // history of previous instructions
67 } iter_state_t;
68
69 // struct for regions of ROM that are copied elsewhere
70 typedef struct {
71 uint8_t *buf;
72 uint32_t start; // copied / relocated firmware address
73 uint32_t src_start; // source ROM firmware address
74 int bytes; // size in bytes
75 int type; // ADR_RANGE_* define
76 int flags; // ADR_RANGE_FL_*
77 } adr_range_t;
78
79 #define FW_MAX_ADR_RANGES 10
80
81 #define FW_MAX_DRYOS_VERS 10
82
83 // scale factor for combined version + patch
84 #define FW_DRYOS_VER_MUL 100
85
86 // loaded firmware
87 typedef struct {
88 union {
89 uint8_t *buf8; // Firmware data
90 uint32_t *buf32; // Firmware data
91 };
92 BufRange *br, *last; // Valid ranges
93
94 int arch; // firmware CPU arch, set by caller at load time
95 int arch_flags; // additional CPU arch information, inferred
96 uint32_t base; // Base address of the firmware in the camera
97 int main_offs; // Offset of main firmware from the start of the dump
98
99 uint32_t memisostart; // Start address of the Canon heap memory (where CHDK is loaded)
100
101 int size8; // Size of the firmware (as loaded from the dump) in bytes
102 int size32; // Size of the firmware in 32 bit words
103
104 int dryos_ver; // main firmware DryOS version number
105 int dryos_ver_patch; // main firmware DryOS patch number (e.g 58p3 = 3)
106 int dryos_ver_full; // main firmware DryOS version number * FW_DRYOS_VER_MUL + patch level
107 const char *dryos_ver_str; // main firmware DryOS version string
108 uint32_t dryos_ver_adr; // address of main firmware DryOS version string
109 uint32_t dryos_ver_ref_adr; // address of pointer used to identify main fw string
110 uint32_t dryos_ver_list[FW_MAX_DRYOS_VERS]; // addresses of all found DryOS version strings
111 uint32_t dryos_ver_count; // number of version strings found
112
113 char *firmware_ver_str; // Camera firmware version string
114
115 // TODO duplicated with adr_range stuff below
116 uint32_t data_start; // Start address of DATA section in RAM
117 uint32_t data_init_start; // Start address of initialisation section for DATA in ROM
118 int data_len; // Length of data section in bytes
119
120 // address ranges for ROM and copied data
121 int adr_range_count;
122 adr_range_t adr_ranges[FW_MAX_ADR_RANGES];
123
124 // convenience values to optimize code searching
125 uint32_t rom_code_search_min_adr; // minimum ROM address for normal code searches (i.e. firmware start)
126 uint32_t rom_code_search_max_adr; // max ROM address for normal code searches, i.e. before copied data / code if known
127 // Values loaded from stubs & other files
128 stub_values *sv;
129
130 uint32_t thumb_default; // 1 if initial firmware code is expected to be thumb, 0 for arm.
131 csh cs_handle_thumb; // capstone handle for thumb disassembly
132 csh cs_handle_arm; // capstone handle for arm disassembly
133 iter_state_t* is;
134 } firmware;
135
136 /*
137 convert firmware address to pointer, or NULL if not in valid range
138 */
139 uint8_t* adr2ptr(firmware *fw, uint32_t adr);
140
141 // as above, but include initialized data area (NOTE may change on camera at runtime!)
142 uint8_t* adr2ptr_with_data(firmware *fw, uint32_t adr);
143
144 // return constant string describing type
145 const char* adr_range_type_str(int type);
146
147 // return constant string describing type + flags
148 const char* adr_range_desc_str(adr_range_t *r);
149
150 // convert pointer into buf into firmware address
151 // current doesn't sanity check or adjust ranges
152 uint32_t ptr2adr(firmware *fw, uint8_t *ptr);
153
154 // return address range struct for adr, or NULL if not in known range
155 adr_range_t *adr_get_range(firmware *fw, uint32_t adr);
156
157 // return what kind of range adr is in
158 int adr_get_range_type(firmware *fw, uint32_t adr);
159
160 // return true if adr is in firmware DATA or BSS
161 int adr_is_var(firmware *fw, uint32_t adr);
162
163 // return true if adr is in the ROM search range, or one of the copied RAM code regions
164 int adr_is_main_fw_code(firmware *fw, uint32_t adr);
165
166 //
167 // Find the index of a string in the firmware
168 // Assumes the string starts on a 32bit boundary.
169 // String + terminating zero byte should be at least 4 bytes long
170 // Handles multiple string instances
171 int find_Nth_str(firmware *fw, char *str, int N);
172
173 // above, N=1
174 int find_str(firmware *fw, char *str);
175
176 // find sequence of bytes, starting from star_adr, up to max_adr, any alignment
177 // returns firmware address or 0
178 // use repeated calls to find multiple
179 // NOTE only handles ROM addresses
180 uint32_t find_next_bytes_range(firmware *fw, const void *bytes, size_t len, uint32_t start_adr, uint32_t max_adr);
181
182 // find up to maxmatch matching byte sequences, storing addresses in result
183 // returns count
184 int find_bytes_all(firmware *fw, const void *bytes, size_t len, uint32_t adr, uint32_t *result, int maxmatch);
185
186 // find index of string, starting from address, str can start at any address
187 // returns firmware address or 0
188 // use repeated calls to find multiple
189 // NOTE only handles ROM addresses
190 uint32_t find_next_str_bytes(firmware *fw, const char *str, uint32_t adr);
191
192 // as above, but ending within range of LDR pc or ADR from main fw code
193 uint32_t find_next_str_bytes_main_fw(firmware *fw, const char *str, uint32_t adr);
194
195 // as find_next_str_bytes, but without terminating null
196 uint32_t find_next_substr_bytes(firmware *fw, const char *str, uint32_t adr);
197
198 // find a string within range of LDR pc or ADR, starting from main fw
199 // i.e., a string directly referenced from main code
200 uint32_t find_str_bytes_main_fw(firmware *fw, const char *str);
201
202 // as find_next_str_bytes, first match
203 uint32_t find_str_bytes(firmware *fw, const char *str);
204
205 int isASCIIstring(firmware *fw, uint32_t adr);
206
207 /*
208 return firmware address of 32 bit value, starting at address "start", up to "maxadr"
209 */
210 uint32_t find_u32_adr_range(firmware *fw, uint32_t val, uint32_t start, uint32_t maxadr);
211
212 /*
213 return firmware address of 32 bit value, starting at address "start", to end of dump
214 */
215 uint32_t find_u32_adr(firmware *fw, uint32_t val, uint32_t start);
216
217 // return u32 value at adr
218 uint32_t fw_u32(firmware *fw, uint32_t adr);
219
220 // memcmp, but using a firmware address, returning 1 adr/size out of range
221 int fw_memcmp(firmware *fw, uint32_t adr,const void *cmp, size_t n);
222
223 // ****** address history functions ******
224 // reset address history to empty
225 void adr_hist_reset(adr_hist_t *ah);
226
227 // return the index of current entry + i. may be negative or positive, wraps. Does not check validity
228 int adr_hist_index(adr_hist_t *ah, int i);
229
230 // add an entry to address history
231 void adr_hist_add(adr_hist_t *ah, uint32_t adr);
232
233 // return the i'th previous entry in this history, or 0 if not valid (maybe should be -1?)
234 // i= 0 = most recently disassembled instruction, if any
235 uint32_t adr_hist_get(adr_hist_t *ah, int i);
236
237 // ****** instruction analysis utilities ******
238 // handle varying instruction ID enums in different capstone versions
239 // note these take an arm_insn enum, NOT a cs_insn *
240 #if CS_API_MAJOR < 4
241 // is insn_id a full reg MOV (does not include MOVT)
242 #define IS_INSN_ID_MOVx(insn_id) ((insn_id) == ARM_INS_MOV || (insn_id) == ARM_INS_MOVS || (insn_id) == ARM_INS_MOVW)
243 // is insn_id a a sub*
244 #define IS_INSN_ID_SUBx(insn_id) ((insn_id) == ARM_INS_SUB || (insn_id) == ARM_INS_SUBW || (insn_id) == ARM_INS_SUBS)
245 #else
246 #define IS_INSN_ID_MOVx(insn_id) ((insn_id) == ARM_INS_MOV || (insn_id) == ARM_INS_MOVW)
247 #define IS_INSN_ID_SUBx(insn_id) ((insn_id) == ARM_INS_SUB || (insn_id) == ARM_INS_SUBW)
248 #endif
249
250
251 // is insn an ARM instruction?
252 // like cs_insn_group(cs_handle,insn,ARM_GRP_ARM) but doesn't require handle and doesn't check or report errors
253 int isARM(cs_insn *insn);
254
255 /*
256 is insn a PC relative load?
257 */
258 int isLDR_PC(cs_insn *insn);
259
260 /*
261 is insn a PC relative load to PC?
262 */
263 int isLDR_PC_PC(cs_insn *insn);
264
265 // if insn is LDR Rn, [pc,#x] return pointer to value, otherwise null
266 uint32_t* LDR_PC2valptr_thumb(firmware *fw, cs_insn *insn);
267 uint32_t* LDR_PC2valptr_arm(firmware *fw, cs_insn *insn);
268 uint32_t* LDR_PC2valptr(firmware *fw, cs_insn *insn);
269
270 // return the address of value loaded by LDR rd, [pc, #x] or 0 if not LDR PC
271 uint32_t LDR_PC2adr(firmware *fw, cs_insn *insn);
272
273 // is insn address calculated with subw rd, pc, ...
274 int isSUBW_PC(cs_insn *insn);
275
276 // is insn address calculated with addw rd, pc, ...
277 int isADDW_PC(cs_insn *insn);
278
279 // is insn ADD rd, pc, #x (only generated for ARM in capstone)
280 int isADD_PC(cs_insn *insn);
281
282 // is insn SUB rd, pc, #x (only generated for ARM in capstone)
283 int isSUB_PC(cs_insn *insn);
284
285 // does insn look like a function return?
286 int isRETx(cs_insn *insn);
287
288 // does insn push LR (function start -ish)
289 int isPUSH_LR(cs_insn *insn);
290
291 // does insn pop LR (func end before tail call)
292 int isPOP_LR(cs_insn *insn);
293
294 // does insn pop PC
295 int isPOP_PC(cs_insn *insn);
296
297 // is the instruction ADD* rx, imm
298 int isADDx_imm(cs_insn *insn);
299
300 // is the instruction SUB* rx, imm
301 int isSUBx_imm(cs_insn *insn);
302
303 // is the instruction an ADR or ADR-like instruction?
304 int isADRx(cs_insn *insn);
305
306 // return value generated by an ADR or ADR-like instruction, or 0 (which should be rarely generated by ADR)
307 uint32_t ADRx2adr(firmware *fw, cs_insn *insn);
308
309 // return the value generated by an ADR (ie, the location of the value as a firmware address)
310 // NOTE not checked if it is in dump
311 uint32_t ADR2adr(firmware *fw, cs_insn *insn);
312
313 // if insn is adr/ AKA ADD Rn, pc,#x return pointer to value, otherwise null
314 uint32_t* ADR2valptr(firmware *fw, cs_insn *insn);
315
316 // return value loaded by PC relative LDR instruction, or 0 if out of range
317 uint32_t LDR_PC2val(firmware *fw, cs_insn *insn);
318
319 // return the target of B instruction, or 0 if current instruction isn't B
320 // both ARM and thumb instructions will NOT have the thumb bit set,
321 // thumbness must be determined from current state
322 uint32_t B_target(firmware *fw, cs_insn *insn);
323
324 // return the target of CBZ / CBNZ instruction, or 0 if current instruction isn't CBx
325 uint32_t CBx_target(firmware *fw, cs_insn *insn);
326
327 // return the target of BLX instruction, or 0 if current instruction isn't BLX imm
328 uint32_t BLXimm_target(firmware *fw, cs_insn *insn);
329
330 // return the target of BL instruction, or 0 if current instruction isn't BL
331 // both ARM and thumb instructions will NOT have the thumb bit set,
332 // thumbness must be determined from current state
333 uint32_t BL_target(firmware *fw, cs_insn *insn);
334
335 // as above, but also including B for tail calls
336 uint32_t B_BL_target(firmware *fw, cs_insn *insn);
337
338 // as above, but also including BLX imm
339 uint32_t B_BL_BLXimm_target(firmware *fw, cs_insn *insn);
340
341 // BX PC (mode change, small jump) Does NOT set thumb bit
342 uint32_t BX_PC_target(__attribute__ ((unused))firmware *fw, cs_insn *insn);
343
344 // results from get_TBx_PC_info
345 typedef struct {
346 uint32_t start; // address of first jumptable entry
347 uint32_t count; // number of entries, from preceding cmp, first_target or first invalid value
348 uint32_t first_target; // lowest jumptable target address (presumably, >= end of jump table in normal code)
349 int bytes; // size of jump table entries: 1 = tbb, 2=tbh
350 } tbx_info_t; // tbb/tbh info
351
352 // get the (likely) range of jumptable entries from a pc relative TBB or TBH instruction
353 // returns 0 on error or if instruction is not TBB/TBH, otherwise 1
354 int get_TBx_PC_info(firmware *fw,iter_state_t *is, tbx_info_t *ti);
355
356 // ****** disassembly iterator utilities ******
357 // allocate a new iterator state, optionally initializing at adr (0/invalid OK)
358 iter_state_t *disasm_iter_new(firmware *fw, uint32_t adr);
359
360 // free iterator state and associated resources
361 void disasm_iter_free(iter_state_t *is);
362
363 // set iterator to adr, without clearing history (for branch following)
364 // thumb bit in adr sets mode
365 int disasm_iter_set(firmware *fw, iter_state_t *is, uint32_t adr);
366
367 // initialize iterator state at adr, clearing history
368 // thumb bit in adr sets mode
369 int disasm_iter_init(firmware *fw, iter_state_t *is, uint32_t adr);
370
371 /*
372 disassemble next instruction, recording address in history
373 returns false if state invalid or disassembly fails
374 if disassembly fails, is->adr is not incremented
375 */
376 int disasm_iter(firmware *fw, iter_state_t *is);
377
378 // ***** disassembly utilities operating on the default iterator state *****
379 // use the fw_disasm_iter functions to disassemble without setting up a new state,
380 // but beware some other functions might change them
381 /*
382 initialize iter state to begin iterating at adr
383 */
384 int fw_disasm_iter_start(firmware *fw, uint32_t adr);
385
386 // disassemble the next instruction, updating cached state
387 int fw_disasm_iter(firmware *fw);
388
389 // disassemble single instruction at given adr, updating cached values
390 // history is cleared
391 int fw_disasm_iter_single(firmware *fw, uint32_t adr);
392
393 // ****** standalone disassembly without an iter_state ******
394 /*
395 disassemble up to count instructions starting at firmware address adr
396 allocates and returns insns in insn, can be freed with cs_free(insn, count)
397 returns actual number disassembled, less than count on error
398 */
399 // UNUSED for now
400 //size_t fw_disasm_adr(firmware *fw, uint32_t adr, unsigned count, cs_insn **insn);
401
402
403 // ***** utilities for searching disassembly over large ranges ******
404 /*
405 callback used by fw_search_insn, called on valid instructions
406 _search continues iterating until callback returns non-zero.
407 is points to the most recently disassembled instruction
408 callback may advance is directly by calling disasm_iter
409 v1 and udata are passed through from the call to _search
410 */
411 typedef uint32_t (*search_insn_fn)(firmware *fw, iter_state_t *is, uint32_t v1, void *udata);
412
413 /*
414 iterate over firmware disassembling, calling callback described above after each
415 successful disassembly iteration. If disassembly fails, the iter state is advanced
416 2 bytes without calling the callback.
417 starts at address is taken from the iter_state, which should be initialized by disasm_iter_new()
418 disasm_iter_init(), or a previous search or iter call.
419 end defaults to end of ram code or rom code (before init data, if known), based on start
420 v1 and udata are provided to the callback
421 */
422 uint32_t fw_search_insn(firmware *fw, iter_state_t *is, search_insn_fn f,uint32_t v1, void *udata, uint32_t adr_end);
423
424 // ****** callbacks for use with fw_search_insn ******
425 // search for constant references
426 uint32_t search_disasm_const_ref(firmware *fw, iter_state_t *is, uint32_t val, void *unused);
427
428 // search for string ref
429 uint32_t search_disasm_str_ref(firmware *fw, iter_state_t *is, uint32_t val, void *str);
430
431 // search for calls/jumps to immediate addresses
432 // thumb bit in address should be set appropriately
433 // returns 1 if found, address can be obtained from insn
434 uint32_t search_disasm_calls(firmware *fw, iter_state_t *is, uint32_t val, void *unused);
435
436 // callback for use with search_disasm_calls_multi
437 // adr is the matching address
438 typedef int (*search_calls_multi_fn)(firmware *fw, iter_state_t *is, uint32_t adr);
439
440 // structure used to define functions searched for, and functions to handle matches
441 // fn should be address with thumb bit set appropriately
442 typedef struct {
443 uint32_t adr;
444 search_calls_multi_fn fn;
445 } search_calls_multi_data_t;
446
447 // a search_calls_multi_fn that just returns 1
448 int search_calls_multi_end(firmware *fw, iter_state_t *is, uint32_t adr);
449
450 // Search for calls to multiple functions (more efficient than multiple passes)
451 // if adr is found in null terminated search_calls_multi_data array, returns fn return value
452 // otherwise 0
453 uint32_t search_disasm_calls_multi(firmware *fw, iter_state_t *is, uint32_t unused, void *userdata);
454
455 // as above, but check for single level of veneers
456 uint32_t search_disasm_calls_veneer_multi(firmware *fw, iter_state_t *is, uint32_t unused, void *userdata);
457
458 // ****** utilities for extracting register values ******
459 /*
460 backtrack through is_init state history picking up constants loaded into r0-r3
461 return bitmask of regs with values found
462 affects fw->is, does not affect is_init
463
464 NOTE values may be inaccurate for many reasons, doesn't track all reg affecting ops,
465 doesn't account for branches landing in the middle of inspected code
466 doesn't account for many conditional cases
467 */
468 int get_call_const_args(firmware *fw, iter_state_t *is_init, int max_backtrack, uint32_t *res);
469
470 /*
471 starting from is_init, look for a direct jump, such as
472 B <target>
473 LDR PC, [pc, #x]
474 BX PC
475 movw ip, #x
476 movt ip, #x
477 bx ip
478 if found, return target address with thumb bit set appropriately
479 NOTE does not check for conditional
480 uses fw->is
481 does not check CBx, since it would generally be part of a function not a veneer
482 */
483 uint32_t get_direct_jump_target(firmware *fw, iter_state_t *is_init);
484
485 /*
486 return target of any single instruction branch or function call instruction,
487 with thumb bit set appropriately
488 returns 0 if current instruction not branch/call
489 */
490 uint32_t get_branch_call_insn_target(firmware *fw, iter_state_t *is);
491
492 /*
493 search up to max_search_ins for first LDR, =value
494 and then match up to max_seq_insns for a sequence like
495 LDR Rbase,=adr
496 ... possible intervening ins
497 SUB Rbase,#adj // optional, may be any add/sub variant
498 ... possible intervening ins
499 LDR Rval,[Rbase + #off]
500
501 returns 1 if found, 0 if not
502 stores registers and constants in *result if successful
503
504 NOTE bad values are possible with intervening ins, short sequences recommended
505
506 TODO similar code for STR would be useful, but in many cases would have to handle load or move into reg_val
507 */
508 typedef struct {
509 arm_reg reg_base;
510 arm_reg reg_val;
511 uint32_t adr_base; // address from original LDR
512 uint32_t adr_adj; // address adjusted by adj if present, normally struct address useful for stubs comments
513 uint32_t adr_final; // full address
514 // offsets are guaranteed to be small
515 int adj;
516 int off;
517 } var_ldr_desc_t;
518 int find_and_get_var_ldr(firmware *fw,
519 iter_state_t *is,
520 int max_search_insns,
521 int max_seq_insns,
522 arm_reg match_val_reg, // ARM_REG_INVALID for any
523 var_ldr_desc_t *result);
524
525 /*
526 check for, and optionally return information about
527 functions with return values that can be completely determined
528 from disassembly
529 uses fw->is
530 */
531 // constants below may as flags on input, and as return valaue
532 // no simple function found
533 #define MATCH_SIMPLE_FUNC_NONE 0x0
534 // immediately returns, with no value
535 #define MATCH_SIMPLE_FUNC_NULLSUB 0x1
536 // immediately returns with a MOV constant
537 #define MATCH_SIMPLE_FUNC_IMM 0x2
538 // TODO LDR pc, =const, ADR
539 // TODO could also do pointer derefs and return pointer info without val
540 #define MATCH_SIMPLE_FUNC_ANY 0x3
541 typedef struct {
542 int ftype;
543 uint32_t retval;
544 } simple_func_desc_t;
545 int check_simple_func(firmware *fw, uint32_t adr, int match_ftype, simple_func_desc_t *info);
546
547 /*
548 advance iter_state is trying to find the last function called by a function
549 function assumed to PUSH LR, POP LR or PC (many small functions don't!)
550 either the last BL/BLXimm before pop {... PC}
551 or B after POP {... LR}
552 MOV or LDR to R0-R3 are allowed between POP LR and the final B
553 If a POP occurs before min_insns, the match fails
554 Calls before min_insns are ignored
555 */
556 uint32_t find_last_call_from_func(firmware *fw, iter_state_t *is,int min_insns, int max_insns);
557
558 // ****** utilities for matching instructions and instruction sequences ******
559
560 // use XXX_INVALID (=0) for don't care
561 typedef struct {
562 arm_op_type type; // ARM_OP_... REG, IMM, MEM support additional tests
563 arm_reg reg1; // reg for register type operands, base for mem
564 uint32_t flags; //
565 int32_t imm; // immediate value for imm, disp for mem
566 arm_reg reg2; // index reg form mem, or second reg for reg range
567 } op_match_t;
568 #define MATCH_OP_FL_IMM 0x0001 // use IMM value
569 #define MATCH_OP_FL_LAST 0x0002 // ignore all following ops, only check count
570 // macros for initializing above
571 // type reg1 flags imm reg2
572 #define MATCH_OP_ANY {ARM_OP_INVALID,ARM_REG_INVALID, 0, 0, ARM_REG_INVALID}
573 #define MATCH_OP_REST_ANY {ARM_OP_INVALID,ARM_REG_INVALID, MATCH_OP_FL_LAST, 0, ARM_REG_INVALID}
574 #define MATCH_OP_REG_ANY {ARM_OP_REG, ARM_REG_INVALID, 0, 0, ARM_REG_INVALID}
575 #define MATCH_OP_REG(r) {ARM_OP_REG, ARM_REG_##r, 0, 0, ARM_REG_INVALID}
576 #define MATCH_OP_REG_RANGE(r1,r2) {ARM_OP_REG, ARM_REG_##r1, 0, 0, ARM_REG_##r2}
577 #define MATCH_OP_IMM_ANY {ARM_OP_IMM, ARM_REG_INVALID, 0, 0, ARM_REG_INVALID}
578 #define MATCH_OP_IMM(imm) {ARM_OP_IMM, ARM_REG_INVALID, MATCH_OP_FL_IMM, (imm), ARM_REG_INVALID}
579 #define MATCH_OP_PIMM_ANY {ARM_OP_PIMM, ARM_REG_INVALID, 0, 0, ARM_REG_INVALID}
580 #define MATCH_OP_PIMM(imm) {ARM_OP_PIMM, ARM_REG_INVALID, MATCH_OP_FL_IMM, (imm), ARM_REG_INVALID}
581 #define MATCH_OP_CIMM_ANY {ARM_OP_CIMM, ARM_REG_INVALID, 0, 0, ARM_REG_INVALID}
582 #define MATCH_OP_CIMM(imm) {ARM_OP_CIMM, ARM_REG_INVALID, MATCH_OP_FL_IMM, (imm), ARM_REG_INVALID}
583 #define MATCH_OP_MEM_ANY {ARM_OP_MEM, ARM_REG_INVALID, 0, 0, ARM_REG_INVALID}
584 #define MATCH_OP_MEM(rb,ri,imm) {ARM_OP_MEM, ARM_REG_##rb, MATCH_OP_FL_IMM, (imm), ARM_REG_##ri}
585 #define MATCH_OP_MEM_BASE(r) {ARM_OP_MEM, ARM_REG_##r, 0, 0, ARM_REG_INVALID}
586 #define MATCH_OP_MEM_REGS(rb,ri) {ARM_OP_MEM, ARM_REG_##rb, 0, 0, ARM_REG_##ri}
587
588 #define MATCH_MAX_OPS 16
589
590 #define MATCH_OPCOUNT_ANY -1 // match any operands specified in operands, without checking count
591 #define MATCH_OPCOUNT_IGNORE -2 // don't check ops at all
592
593 #define MATCH_INS(ins,opcount) ARM_INS_##ins,(opcount),ARM_CC_INVALID
594 #define MATCH_INS_CC(ins,cc,opcount) ARM_INS_##ins,(opcount),ARM_CC_##cc
595
596 // use id ARM_INS_INVALID for don't care, ARM_INS_ENDING to end list of matches
597 typedef struct {
598 arm_insn id;
599 int op_count; // negative = special values above
600 arm_cc cc; // match condition code _INVALID = don't care
601 op_match_t operands[MATCH_MAX_OPS];
602 } insn_match_t;
603
604 // some common matches for insn_match_find_next
605 // match a B instruction
606 extern const insn_match_t match_b[];
607
608 // match a BL instruction
609 extern const insn_match_t match_bl[];
610
611 // match B and BL
612 extern const insn_match_t match_b_bl[];
613
614 // match B and BL, and BLX with an immediate
615 extern const insn_match_t match_b_bl_blximm[];
616
617 // match only calls: BL or BLX imm
618 extern const insn_match_t match_bl_blximm[];
619
620 // match BX LR
621 extern const insn_match_t match_bxlr[];
622
623 // match BX <any reg>
624 extern const insn_match_t match_bxreg[];
625
626 // match BLX <any reg>
627 extern const insn_match_t match_blxreg[];
628
629 // match LDR rx [pc, ...]
630 extern const insn_match_t match_ldr_pc[];
631
632 // check if single insn matches values defined by match
633 int insn_match(cs_insn *insn, const insn_match_t *match);
634
635 // check if single insn matches any of the provided matches
636 int insn_match_any(cs_insn *insn,const insn_match_t *match);
637
638 // iterate is until current instruction matches any of the provided matches or until limit reached
639 int insn_match_find_next(firmware *fw, iter_state_t *is, int max_insns, const insn_match_t *match);
640
641 // iterate is until current has matched any of the provided matches N times or until max_insns reached
642 int insn_match_find_nth(firmware *fw, iter_state_t *is, int max_insns, int num_to_match, const insn_match_t *match);
643
644 // iterate as long as sequence of instructions matches sequence defined in match
645 int insn_match_seq(firmware *fw, iter_state_t *is, const insn_match_t *match);
646
647 // find next matching sequence starting within max_insns
648 int insn_match_find_next_seq(firmware *fw, iter_state_t *is, int max_insns, const insn_match_t *match);
649
650 #define FIND_CONST_REF_MATCH_ANY 0
651 #define FIND_CONST_REF_MATCH_SEQ 1
652 /*
653 find instruction or sequence that receives specified constant in specified r0-r3 reg
654 search starting from is to max_search_bytes
655 allow up to max_gap_insns between constant load and match, generally small (4-8 max)
656 returns address of match with thumb bit set according to mode, or 0 on failure
657 modifies is and fw->is
658 */
659 int find_const_ref_match(firmware *fw,
660 iter_state_t *is,
661 int max_search_bytes,
662 int max_gap_insns,
663 arm_reg match_reg, // must be R0-R3
664 uint32_t val,
665 const insn_match_t *match,
666 int match_type);
667
668 /*
669 find call that receives specified constant in specified r0-r3 reg
670 search starting from is to max_search_bytes
671 allow up to max_gap_insns between constant load and call, generally small (4-8 max)
672 returns address of call with thumb bit set according to mode, or 0 on failure
673 modifies is and fw->is
674 */
675 int find_const_ref_call(firmware *fw,
676 iter_state_t *is,
677 int max_search_bytes,
678 int max_gap_insns, // insns between ref and call
679 arm_reg match_reg, // must be R0-R3
680 uint32_t val);
681
682
683 // ****** utilities for non-disasm searching ******
684 // Search the firmware for something. The desired matching is performed using the supplied 'func' function.
685 // Continues searching until 'func' returns non-zero - then returns 1
686 // otherwise returns 0.
687 // Uses the BufRange structs to speed up searching
688 // Note: this version searches byte by byte in the firmware dump instead of by words
689 // borrowed from finsig_dryos
690 typedef int (*search_bytes_fn)(firmware*, int k);
691 int fw_search_bytes(firmware *fw, search_bytes_fn func);
692
693 // ****** firmware loading / initialization / de-allocation ******
694 // add given address range
695 void fw_add_adr_range(firmware *fw, uint32_t start, uint32_t end, uint32_t src_start, int type, int flags);
696
697 // load firmware and initialize stuff that doesn't require disassembly
698 void firmware_load(firmware *fw, const char *filename, uint32_t base_adr,int fw_arch);
699
700 // initialize capstone state for loaded fw
701 int firmware_init_capstone(firmware *fw);
702
703 // init basic copied RAM code / data ranges - init_capstone must be called first
704 void firmware_init_data_ranges(firmware *fw);
705
706 // free resources associated with fw
707 void firmware_unload(firmware *fw);
708
709 // get iter_state instruction address with optional thumb bit
710 #define iter_state_adr(is) ((uint32_t)is->insn->address | is->thumb)
711 #endif