Mercurial > hg > dmlib
comparison tools/fanalyze.c @ 2225:837c79747ea4
Add functionality for grepping multiple consecutive values (8/16/32 le/be)
and also wildcard values specified with '?'.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 14 Jun 2019 18:00:18 +0300 |
parents | 1662730053d0 |
children | 02d17784fdef |
comparison
equal
deleted
inserted
replaced
2224:a36c81c3df85 | 2225:837c79747ea4 |
---|---|
11 #include "dmfile.h" | 11 #include "dmfile.h" |
12 | 12 |
13 #define SET_MAX_FILES 64 | 13 #define SET_MAX_FILES 64 |
14 #define SET_MAX_ELEMS 256 | 14 #define SET_MAX_ELEMS 256 |
15 #define SET_MAX_VALUES 64 | 15 #define SET_MAX_VALUES 64 |
16 #define SET_MAX_GREPLIST 64 | |
16 | 17 |
17 | 18 |
18 /* Typedefs | 19 /* Typedefs |
19 */ | 20 */ |
20 typedef struct | 21 typedef struct |
70 | 71 |
71 typedef struct | 72 typedef struct |
72 { | 73 { |
73 int type; | 74 int type; |
74 int disp; | 75 int disp; |
75 Uint32 value; | 76 int nvalues; |
77 Uint32 values[SET_MAX_GREPLIST]; | |
78 BOOL vwildcards[SET_MAX_GREPLIST]; | |
76 } DMGrepValue; | 79 } DMGrepValue; |
77 | 80 |
78 | 81 |
79 typedef struct | 82 typedef struct |
80 { | 83 { |
129 */ | 132 */ |
130 static const DMOptArg optList[] = | 133 static const DMOptArg optList[] = |
131 { | 134 { |
132 { 0, '?', "help", "Show this help", OPT_NONE }, | 135 { 0, '?', "help", "Show this help", OPT_NONE }, |
133 { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, | 136 { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, |
134 { 2, 'g', "grep", "Binary grep <val>[,<le|be>[8|16|32]]", OPT_ARGREQ }, | 137 { 2, 'g', "grep", "Binary grep <val>[,<val2>...][:<le|be>[8|16|32]]", OPT_ARGREQ }, |
135 { 3, 'o', "offset", "Show data in offset <offset>,<le|be>[8|16|32][d|x]]", OPT_ARGREQ }, | 138 { 3, 'o', "offset", "Show data in offset <offset>:<le|be>[8|16|32][d|x]]", OPT_ARGREQ }, |
136 }; | 139 }; |
137 | 140 |
138 static const int optListN = sizeof(optList) / sizeof(optList[0]); | 141 static const int optListN = sizeof(optList) / sizeof(optList[0]); |
139 | 142 |
140 | 143 |
141 void argShowHelp() | 144 void argShowHelp() |
142 { | 145 { |
143 dmPrintBanner(stdout, dmProgName, "[options] <input file #1> <input file #2> [...]"); | 146 dmPrintBanner(stdout, dmProgName, "[options] <input file #1> <input file #2> [...]"); |
144 dmArgsPrintHelp(stdout, optList, optListN, 0); | 147 dmArgsPrintHelp(stdout, optList, optListN, 0); |
148 | |
149 fprintf(stdout, | |
150 "\n" | |
151 "Value lists for grep function can contain wildcard '?' (or '#') which\n" | |
152 "matches any value of the specified (or inferred) type. For example:\n" | |
153 "-g 0x0f,7,5,?,5,?,? will match sequence of bytes 0f 07 05 ?? 05 ?? ??\n" | |
154 "and -g 0xe,0x1001,?,2023:le16 will match le16 value 000e 1001 ???? 07e7\n" | |
155 ); | |
156 } | |
157 | |
158 | |
159 BOOL dmGetData(const int type, const DMSourceFile *file, const size_t offs, Uint32 *mval) | |
160 { | |
161 Uint8 *data = file->data + offs; | |
162 if (offs + dmGrepTypes[type].bsize >= file->size) | |
163 { | |
164 *mval = 0; | |
165 return FALSE; | |
166 } | |
167 | |
168 switch (type) | |
169 { | |
170 case DMGV_UINT8: | |
171 *mval = *((Uint8 *) data); | |
172 break; | |
173 | |
174 case DMGV_UINT16_LE: | |
175 *mval = DM_LE16_TO_NATIVE(*((Uint16 *) data)); | |
176 break; | |
177 | |
178 case DMGV_UINT16_BE: | |
179 *mval = DM_BE16_TO_NATIVE(*((Uint16 *) data)); | |
180 break; | |
181 | |
182 case DMGV_UINT32_LE: | |
183 *mval = DM_LE32_TO_NATIVE(*((Uint32 *) data)); | |
184 break; | |
185 | |
186 case DMGV_UINT32_BE: | |
187 *mval = DM_BE32_TO_NATIVE(*((Uint32 *) data)); | |
188 break; | |
189 | |
190 default: | |
191 *mval = 0; | |
192 return FALSE; | |
193 } | |
194 return TRUE; | |
195 } | |
196 | |
197 | |
198 void dmPrintGrepValueList(const DMGrepValue *node, const BOOL match, DMSourceFile *file, const size_t offs) | |
199 { | |
200 char vfmt[16]; | |
201 | |
202 snprintf(vfmt, sizeof(vfmt), "%%%s%d%s%%s", | |
203 node->disp == DMGS_HEX ? "0" : "", | |
204 dmGrepTypes[node->type].bsize * 2, | |
205 node->disp == DMGS_HEX ? "x" : "d"); | |
206 | |
207 for (int n = 0; n < node->nvalues; n++) | |
208 { | |
209 const char *veol = (n < node->nvalues - 1) ? " " : "\n"; | |
210 | |
211 if (match) | |
212 { | |
213 Uint32 mval; | |
214 dmGetData(node->type, file, offs + n, &mval); | |
215 dmPrint(1, vfmt, mval, veol); | |
216 } | |
217 else | |
218 { | |
219 if (node->vwildcards[n]) | |
220 dmPrint(1, "?%s", veol); | |
221 else | |
222 dmPrint(1, vfmt, node->values[n], veol); | |
223 } | |
224 } | |
145 } | 225 } |
146 | 226 |
147 | 227 |
148 int argParseGrepValue(const char *arg, const int mode) | 228 int argParseGrepValue(const char *arg, const int mode) |
149 { | 229 { |
150 const char *sep = strchr(arg, ','); | 230 const char *specsep = strchr(arg, ':'); |
151 char *vspec, *vstr; | 231 char *vspec, *vstr, *vsep; |
152 int vdisp = DMGS_HEX, vtype = -1, ret = DMERR_OK; | 232 int vdisp = DMGS_HEX, vtype = -1, ret = DMERR_OK, nvalues; |
153 Uint32 vval; | 233 BOOL more; |
234 Uint32 vvalues[SET_MAX_GREPLIST]; | |
235 BOOL vwildcards[SET_MAX_GREPLIST]; | |
236 | |
237 memset(vwildcards, 0, sizeof(vwildcards)); | |
154 | 238 |
155 if (setMode != FA_ANALYZE && setMode != mode) | 239 if (setMode != FA_ANALYZE && setMode != mode) |
156 { | 240 { |
157 dmErrorMsg("Options specifying multiple operating modes can't be used.\n"); | 241 dmErrorMsg("Options specifying multiple operating modes can't be used.\n"); |
158 return DMERR_INVALID_ARGS; | 242 return DMERR_INVALID_ARGS; |
159 } | 243 } |
160 setMode = mode; | 244 setMode = mode; |
161 | 245 |
162 // Do we have spec? | 246 // Do we have spec? |
163 if (sep != NULL) | 247 if (specsep != NULL) |
164 { | 248 { |
165 vspec = dm_strdup_trim(sep + 1, DM_TRIM_BOTH); | 249 vspec = dm_strdup_trim(specsep + 1, DM_TRIM_BOTH); |
166 vstr = dm_strndup_trim(arg, sep - arg, DM_TRIM_BOTH); | 250 vstr = dm_strndup_trim(arg, specsep - arg, DM_TRIM_BOTH); |
167 } | 251 } |
168 else | 252 else |
169 { | 253 { |
170 vspec = NULL; | 254 vspec = NULL; |
171 vstr = dm_strdup(arg); | 255 vstr = dm_strdup(arg); |
235 vspec); | 319 vspec); |
236 goto out; | 320 goto out; |
237 } | 321 } |
238 } | 322 } |
239 | 323 |
240 // Get value | 324 // Get list of values |
241 if (!dmGetIntVal(vstr, &vval, NULL)) | 325 char *vtmp = vstr; |
326 nvalues = 0; | |
327 do | |
328 { | |
329 if (nvalues >= SET_MAX_GREPLIST) | |
330 { | |
331 ret = dmError(DMERR_BOUNDS, | |
332 "Too many greplist values specified '%s'.\n", | |
333 vstr); | |
334 goto out; | |
335 } | |
336 | |
337 if ((vsep = strchr(vtmp, ',')) != NULL) | |
338 { | |
339 *vsep = 0; | |
340 more = TRUE; | |
341 } | |
342 else | |
343 more = FALSE; | |
344 | |
345 if (vtmp[0] == '#' || vtmp[0] == '?') | |
346 { | |
347 vwildcards[nvalues] = TRUE; | |
348 if (mode == FA_OFFSET) | |
349 { | |
350 ret = dmError(DMERR_INVALID_ARGS, | |
351 "Offset mode does not allow wildcard values.\n"); | |
352 goto out; | |
353 } | |
354 } | |
355 else | |
356 if (!dmGetIntVal(vtmp, &vvalues[nvalues], NULL)) | |
357 { | |
358 ret = dmError(DMERR_INVALID_ARGS, | |
359 "Not a valid integer value '%s'.\n", | |
360 vtmp); | |
361 goto out; | |
362 } | |
363 | |
364 nvalues++; | |
365 | |
366 if (more) | |
367 vtmp = vsep + 1; | |
368 } while (more); | |
369 | |
370 if (vwildcards[0]) | |
242 { | 371 { |
243 ret = dmError(DMERR_INVALID_ARGS, | 372 ret = dmError(DMERR_INVALID_ARGS, |
244 "Not a valid integer value '%s'.\n", | 373 "First grep value can not be a wildcard.\n"); |
245 vstr); | |
246 goto out; | 374 goto out; |
247 } | 375 } |
248 | 376 |
249 if (mode == FA_GREP) | 377 if (mode == FA_GREP) |
250 { | 378 { |
252 if (vtype < 0) | 380 if (vtype < 0) |
253 { | 381 { |
254 for (int n = DMGV_last; n >= 0; n--) | 382 for (int n = DMGV_last; n >= 0; n--) |
255 { | 383 { |
256 const DMGrepType *def = &dmGrepTypes[n]; | 384 const DMGrepType *def = &dmGrepTypes[n]; |
257 if (vval <= def->nmax) | 385 if (vvalues[0] <= def->nmax) |
258 vtype = n; | 386 vtype = n; |
259 } | 387 } |
260 } | 388 } |
261 | 389 |
262 if (vtype < 0) | 390 if (vtype < 0) |
266 arg); | 394 arg); |
267 goto out; | 395 goto out; |
268 } | 396 } |
269 | 397 |
270 // Check range | 398 // Check range |
271 if (vval > dmGrepTypes[vtype].nmax) | 399 for (int n = 0; n < nvalues; n++) |
400 if (!vwildcards[n] && vvalues[n] > dmGrepTypes[vtype].nmax) | |
272 { | 401 { |
273 ret = dmError(DMERR_INVALID_ARGS, | 402 ret = dmError(DMERR_INVALID_ARGS, |
274 "Integer value %d <= %d <= %d out of range for type %s.\n", | 403 "Integer value %d <= %d <= %d out of range for type %s.\n", |
275 vval, 0, dmGrepTypes[vtype].nmax, dmGrepTypes[vtype].name); | 404 vvalues[n], 0, dmGrepTypes[vtype].nmax, dmGrepTypes[vtype].name); |
276 | 405 |
277 goto out; | 406 goto out; |
278 } | 407 } |
279 } | 408 } |
280 else | 409 else |
285 } | 414 } |
286 | 415 |
287 if (nsetGrepValues < SET_MAX_VALUES) | 416 if (nsetGrepValues < SET_MAX_VALUES) |
288 { | 417 { |
289 DMGrepValue *node = &setGrepValues[nsetGrepValues++]; | 418 DMGrepValue *node = &setGrepValues[nsetGrepValues++]; |
419 | |
290 node->type = vtype; | 420 node->type = vtype; |
291 node->disp = vdisp; | 421 node->disp = vdisp; |
292 node->value = vval; | 422 node->nvalues = nvalues; |
293 | 423 memcpy(node->values, vvalues, sizeof(vvalues[0]) * nvalues); |
294 dmMsg(1, "Grep value %s : %d / 0x%x\n", | 424 memcpy(node->vwildcards, vwildcards, sizeof(vwildcards[0]) * nvalues); |
295 dmGrepTypes[vtype].name, | 425 |
296 vval, vval); | 426 dmMsg(1, "Grep %ss : ", |
427 dmGrepTypes[vtype].name); | |
428 | |
429 dmPrintGrepValueList(node, FALSE, NULL, 0); | |
297 } | 430 } |
298 else | 431 else |
299 { | 432 { |
300 ret = dmError(DMERR_BOUNDS, | 433 ret = dmError(DMERR_BOUNDS, |
301 "Too many values specified (max %d).", | 434 "Too many values specified (max %d).", |
386 } | 519 } |
387 printf("\n\n"); | 520 printf("\n\n"); |
388 } | 521 } |
389 | 522 |
390 | 523 |
391 BOOL dmGetData(const int type, const DMSourceFile *file, const size_t offs, Uint32 *mval) | |
392 { | |
393 Uint8 *data = file->data + offs; | |
394 if (offs + dmGrepTypes[type].bsize >= file->size) | |
395 { | |
396 *mval = 0; | |
397 return FALSE; | |
398 } | |
399 | |
400 switch (type) | |
401 { | |
402 case DMGV_UINT8: | |
403 *mval = *((Uint8 *) data); | |
404 break; | |
405 | |
406 case DMGV_UINT16_LE: | |
407 *mval = DM_LE16_TO_NATIVE(*((Uint16 *) data)); | |
408 break; | |
409 | |
410 case DMGV_UINT16_BE: | |
411 *mval = DM_BE16_TO_NATIVE(*((Uint16 *) data)); | |
412 break; | |
413 | |
414 case DMGV_UINT32_LE: | |
415 *mval = DM_LE32_TO_NATIVE(*((Uint32 *) data)); | |
416 break; | |
417 | |
418 case DMGV_UINT32_BE: | |
419 *mval = DM_BE32_TO_NATIVE(*((Uint32 *) data)); | |
420 break; | |
421 | |
422 default: | |
423 *mval = 0; | |
424 return FALSE; | |
425 } | |
426 return TRUE; | |
427 } | |
428 | |
429 | |
430 int main(int argc, char *argv[]) | 524 int main(int argc, char *argv[]) |
431 { | 525 { |
432 DMCompElem *compBuf = NULL; | 526 DMCompElem *compBuf = NULL; |
433 size_t compBufSize = 0, totalSize = 0; | 527 size_t compBufSize = 0, totalSize = 0; |
434 int res; | 528 int res; |
484 for (int n = 0; n < nsetGrepValues; n++) | 578 for (int n = 0; n < nsetGrepValues; n++) |
485 { | 579 { |
486 DMGrepValue *node = &setGrepValues[n]; | 580 DMGrepValue *node = &setGrepValues[n]; |
487 const DMGrepType *def = &dmGrepTypes[node->type]; | 581 const DMGrepType *def = &dmGrepTypes[node->type]; |
488 | 582 |
489 for (size_t offs = 0; offs + def->bsize < file->size; offs++) | 583 for (size_t offs = 0; offs + (def->bsize * node->nvalues) < file->size; offs++) |
490 { | 584 { |
491 Uint32 mval; | 585 BOOL match = TRUE; |
492 dmGetData(node->type, file, offs, &mval); | 586 for (int n = 0; n < node->nvalues; n++) |
493 | 587 if (!node->vwildcards[n]) |
494 if (mval == node->value) | |
495 { | 588 { |
496 dmPrint(0, "%08x : %s match %d / 0x%x\n", | 589 Uint32 mval; |
497 offs, def->name, mval, mval); | 590 dmGetData(node->type, file, offs + n, &mval); |
591 | |
592 if (mval != node->values[n]) | |
593 { | |
594 match = FALSE; | |
595 break; | |
596 } | |
597 } | |
598 | |
599 if (match) | |
600 { | |
601 dmPrint(0, "%08x : %s match ", | |
602 offs, def->name); | |
603 | |
604 dmPrintGrepValueList(node, TRUE, file, offs); | |
498 } | 605 } |
499 } | 606 } |
500 } | 607 } |
501 } | 608 } |
502 } | 609 } |
521 | 628 |
522 for (int n = 0; n < nsetGrepValues; n++) | 629 for (int n = 0; n < nsetGrepValues; n++) |
523 { | 630 { |
524 DMGrepValue *node = &setGrepValues[n]; | 631 DMGrepValue *node = &setGrepValues[n]; |
525 const DMGrepType *def = &dmGrepTypes[node->type]; | 632 const DMGrepType *def = &dmGrepTypes[node->type]; |
526 printf("%08x : ", node->value); | 633 printf("%08x : ", node->values[0]); |
527 | 634 |
528 for (int nfile = 0; nfile < nsrcFiles; nfile++) | 635 for (int nfile = 0; nfile < nsrcFiles; nfile++) |
529 { | 636 { |
530 DMSourceFile *file = &srcFiles[nfile]; | 637 DMSourceFile *file = &srcFiles[nfile]; |
531 Uint32 mval; | 638 Uint32 mval; |
532 char mstr[32]; | 639 char mstr[32]; |
533 int npad, nwidth; | 640 int npad, nwidth; |
534 | 641 |
535 if (dmGetData(node->type, file, node->value, &mval)) | 642 if (dmGetData(node->type, file, node->values[0], &mval)) |
536 { | 643 { |
537 char mfmt[16]; | 644 char mfmt[16]; |
538 nwidth = def->bsize * 2; | 645 nwidth = def->bsize * 2; |
539 snprintf(mfmt, sizeof(mfmt), "%%0%d%s", | 646 snprintf(mfmt, sizeof(mfmt), "%%0%d%s", |
540 nwidth, dmGrepDisp[node->disp].fmt); | 647 nwidth, dmGrepDisp[node->disp].fmt); |