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);