comparison tools/fanalyze.c @ 2034:45ad06bb60c4

Implement offset dump mode in fanalyze.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 29 Nov 2018 13:16:02 +0200
parents 5fe25336a474
children 472ca1dbc2d3
comparison
equal deleted inserted replaced
2033:cf966e66c9af 2034:45ad06bb60c4
10 #include "dmargs.h" 10 #include "dmargs.h"
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 32 15 #define SET_MAX_VALUES 64
16 16
17 17
18 /* Typedefs 18 /* Typedefs
19 */ 19 */
20 typedef struct 20 typedef struct
60 }; 60 };
61 61
62 62
63 typedef struct 63 typedef struct
64 { 64 {
65 int type;
66 Uint32 value;
67 } DMGrepValue;
68
69
70 typedef struct
71 {
65 char *name; 72 char *name;
66 uint32_t nmax; 73 Uint32 nmax;
67 unsigned int bsize; 74 unsigned int bsize;
68 } DMGrepDef; 75 } DMGrepDef;
69 76
70 77
71 static const DMGrepDef dmGrepTypes[DMGV_last] = 78 static const DMGrepDef dmGrepTypes[DMGV_last] =
76 { "32bit (word) LE" , (1UL << 32) - 1, 4 }, 83 { "32bit (word) LE" , (1UL << 32) - 1, 4 },
77 { "32bit (word) BE" , (1UL << 32) - 1, 4 }, 84 { "32bit (word) BE" , (1UL << 32) - 1, 4 },
78 }; 85 };
79 86
80 87
81 typedef struct 88 enum
82 { 89 {
83 int type; 90 FA_ANALYZE,
84 uint32_t value; 91 FA_GREP,
85 } DMGrepValue; 92 FA_OFFSET,
93 };
86 94
87 95
88 /* Global variables 96 /* Global variables
89 */ 97 */
98 int setMode = FA_ANALYZE;
90 int nsrcFiles = 0; // Number of source files 99 int nsrcFiles = 0; // Number of source files
91 DMSourceFile srcFiles[SET_MAX_FILES]; // Source file names 100 DMSourceFile srcFiles[SET_MAX_FILES]; // Source file names
92 DMStats totalStats; 101 DMStats totalStats;
93 int nsetGrepValues = 0; 102 int nsetGrepValues = 0;
94 DMGrepValue setGrepValues[SET_MAX_VALUES]; 103 DMGrepValue setGrepValues[SET_MAX_VALUES];
98 */ 107 */
99 static const DMOptArg optList[] = 108 static const DMOptArg optList[] =
100 { 109 {
101 { 0, '?', "help", "Show this help", OPT_NONE }, 110 { 0, '?', "help", "Show this help", OPT_NONE },
102 { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, 111 { 1, 'v', "verbose", "Be more verbose", OPT_NONE },
103 { 2, 'g', "grep", "Binary grep mode <val>[,<le|be>[8|16|32]]", OPT_ARGREQ }, 112 { 2, 'g', "grep", "Binary grep <val>[,<le|be>[8|16|32]]", OPT_ARGREQ },
113 { 3, 'o', "offset", "Show data in offset <offset>,<le|be>[8|16|32]]", OPT_ARGREQ },
104 }; 114 };
105 115
106 static const int optListN = sizeof(optList) / sizeof(optList[0]); 116 static const int optListN = sizeof(optList) / sizeof(optList[0]);
107 117
108 118
111 dmPrintBanner(stdout, dmProgName, "[options] <input file #1> <input file #2> [...]"); 121 dmPrintBanner(stdout, dmProgName, "[options] <input file #1> <input file #2> [...]");
112 dmArgsPrintHelp(stdout, optList, optListN, 0); 122 dmArgsPrintHelp(stdout, optList, optListN, 0);
113 } 123 }
114 124
115 125
116 int argParseGrepValue(const char *arg) 126 int argParseGrepValue(const char *arg, const int mode)
117 { 127 {
118 const char *sep = strchr(arg, ','); 128 const char *sep = strchr(arg, ',');
119 char *vspec, *vstr; 129 char *vspec, *vstr;
120 int vtype = -1, ret = DMERR_OK; 130 int vtype = -1, ret = DMERR_OK;
121 uint32_t vval; 131 Uint32 vval;
132
133 if (setMode != FA_ANALYZE && setMode != mode)
134 {
135 dmErrorMsg("Options specifying multiple operating modes can't be used.\n");
136 return DMERR_INVALID_ARGS;
137 }
138 setMode = mode;
122 139
123 // Do we have spec? 140 // Do we have spec?
124 if (sep != NULL) 141 if (sep != NULL)
125 { 142 {
126 vspec = dm_strdup_trim(sep + 1, DM_TRIM_BOTH); 143 vspec = dm_strdup_trim(sep + 1, DM_TRIM_BOTH);
176 "Not a valid integer value '%s'.\n", 193 "Not a valid integer value '%s'.\n",
177 vstr); 194 vstr);
178 goto out; 195 goto out;
179 } 196 }
180 197
181 // Check if we need to guess size 198 if (mode == FA_GREP)
182 if (vtype < 0) 199 {
183 { 200 // Check if we need to guess size
184 for (int n = DMGV_last; n >= 0; n--) 201 if (vtype < 0)
185 { 202 {
186 const DMGrepDef *def = &dmGrepTypes[n]; 203 for (int n = DMGV_last; n >= 0; n--)
187 if (vval <= def->nmax) 204 {
188 vtype = n; 205 const DMGrepDef *def = &dmGrepTypes[n];
189 } 206 if (vval <= def->nmax)
190 } 207 vtype = n;
191 208 }
192 if (vtype < 0) 209 }
193 { 210
194 ret = dmError(DMERR_INVALID_ARGS, 211 if (vtype < 0)
195 "Could not guess value type for '%s'.\n", 212 {
196 arg); 213 ret = dmError(DMERR_INVALID_ARGS,
197 goto out; 214 "Could not guess value type for '%s'.\n",
198 } 215 arg);
199 216 goto out;
200 // Check range 217 }
201 if (vval > dmGrepTypes[vtype].nmax) 218
202 { 219 // Check range
203 ret = dmError(DMERR_INVALID_ARGS, 220 if (vval > dmGrepTypes[vtype].nmax)
204 "Integer value %d <= %d <= %d out of range for type %s.\n", 221 {
205 vval, 0, dmGrepTypes[vtype].nmax, dmGrepTypes[vtype].name); 222 ret = dmError(DMERR_INVALID_ARGS,
206 223 "Integer value %d <= %d <= %d out of range for type %s.\n",
207 goto out; 224 vval, 0, dmGrepTypes[vtype].nmax, dmGrepTypes[vtype].name);
225
226 goto out;
227 }
228 }
229 else
230 if (mode == FA_OFFSET)
231 {
232 if (vtype < 0)
233 vtype = DMGV_uint8;
208 } 234 }
209 235
210 if (nsetGrepValues < SET_MAX_VALUES) 236 if (nsetGrepValues < SET_MAX_VALUES)
211 { 237 {
212 DMGrepValue *node = &setGrepValues[nsetGrepValues++]; 238 DMGrepValue *node = &setGrepValues[nsetGrepValues++];
218 vval, vval); 244 vval, vval);
219 } 245 }
220 else 246 else
221 { 247 {
222 ret = dmError(DMERR_BOUNDS, 248 ret = dmError(DMERR_BOUNDS,
223 "Too many greps specified (max %d).", 249 "Too many values specified (max %d).",
224 SET_MAX_VALUES); 250 SET_MAX_VALUES);
225 } 251 }
226 252
227 out: 253 out:
228 dmFree(vspec); 254 dmFree(vspec);
245 case 1: 271 case 1:
246 dmVerbosity++; 272 dmVerbosity++;
247 break; 273 break;
248 274
249 case 2: 275 case 2:
250 return argParseGrepValue(optArg) == DMERR_OK; 276 return argParseGrepValue(optArg, FA_GREP) == DMERR_OK;
277
278 case 3:
279 return argParseGrepValue(optArg, FA_OFFSET) == DMERR_OK;
251 280
252 default: 281 default:
253 dmErrorMsg("Unknown argument '%s'.\n", currArg); 282 dmErrorMsg("Unknown argument '%s'.\n", currArg);
254 return FALSE; 283 return FALSE;
255 } 284 }
305 } 334 }
306 printf("\n\n"); 335 printf("\n\n");
307 } 336 }
308 337
309 338
339 BOOL dmGetData(const int type, const DMSourceFile *file, const size_t offs, Uint32 *mval)
340 {
341 Uint8 *data = file->data + offs;
342 if (offs + dmGrepTypes[type].bsize >= file->size)
343 return FALSE;
344
345 switch (type)
346 {
347 case DMGV_uint8:
348 *mval = *((uint8_t *) data);
349 break;
350
351 case DMGV_uint16_le:
352 *mval = DM_LE16_TO_NATIVE(*((Uint16 *) data));
353 break;
354
355 case DMGV_uint16_be:
356 *mval = DM_BE16_TO_NATIVE(*((Uint16 *) data));
357 break;
358
359 case DMGV_uint32_le:
360 *mval = DM_LE32_TO_NATIVE(*((Uint32 *) data));
361 break;
362
363 case DMGV_uint32_be:
364 *mval = DM_BE32_TO_NATIVE(*((Uint32 *) data));
365 break;
366
367 default:
368 return FALSE;
369 }
370 return TRUE;
371 }
372
373
310 int main(int argc, char *argv[]) 374 int main(int argc, char *argv[])
311 { 375 {
312 DMCompElem *compBuf = NULL; 376 DMCompElem *compBuf = NULL;
313 size_t compBufSize = 0, totalSize = 0; 377 size_t compBufSize = 0, totalSize = 0;
314 int res; 378 int res;
349 totalSize += file->size; 413 totalSize += file->size;
350 dmInitStats(&file->stats); 414 dmInitStats(&file->stats);
351 } 415 }
352 416
353 417
354 // Check if we are in grep mode 418 //
355 if (nsetGrepValues > 0) 419 // Check what operating mode we are in
420 //
421 if (setMode == FA_GREP)
356 { 422 {
357 for (int nfile = 0; nfile < nsrcFiles; nfile++) 423 for (int nfile = 0; nfile < nsrcFiles; nfile++)
358 { 424 {
359 DMSourceFile *file = &srcFiles[nfile]; 425 DMSourceFile *file = &srcFiles[nfile];
360 dmPrint(0, "\n%s:\n", file->filename); 426 dmPrint(0, "\n%s\n", file->filename);
361 427
362 for (int n = 0; n < nsetGrepValues; n++) 428 for (int n = 0; n < nsetGrepValues; n++)
363 { 429 {
364 DMGrepValue *node = &setGrepValues[n]; 430 DMGrepValue *node = &setGrepValues[n];
365 const DMGrepDef *def = &dmGrepTypes[node->type]; 431 const DMGrepDef *def = &dmGrepTypes[node->type];
366 432
367 for (size_t offs = 0; offs + def->bsize < file->size; offs++) 433 for (size_t offs = 0; offs + def->bsize < file->size; offs++)
368 { 434 {
369 uint32_t mval = -1; 435 Uint32 mval;
370 switch (node->type) 436 dmGetData(node->type, file, offs, &mval);
371 {
372 case DMGV_uint8:
373 mval = *((uint8_t *) (file->data + offs));
374 break;
375
376 case DMGV_uint16_le:
377 mval = DM_LE16_TO_NATIVE(*((uint16_t *) (file->data + offs)));
378 break;
379
380 case DMGV_uint16_be:
381 mval = DM_BE16_TO_NATIVE(*((uint16_t *) (file->data + offs)));
382 break;
383
384 case DMGV_uint32_le:
385 mval = DM_LE32_TO_NATIVE(*((uint32_t *) (file->data + offs)));
386 break;
387
388 case DMGV_uint32_be:
389 mval = DM_BE32_TO_NATIVE(*((uint32_t *) (file->data + offs)));
390 break;
391 }
392 437
393 if (mval == node->value) 438 if (mval == node->value)
394 { 439 {
395 dmPrint(0, "%08x : %s match %d / 0x%x\n", 440 dmPrint(0, "%08x : %s match %d / 0x%x\n",
396 offs, def->name, mval, mval); 441 offs, def->name, mval, mval);
397
398 } 442 }
399 } 443 }
400 } 444 }
401 } 445 }
402 goto out; 446 }
403 } 447 else
404 448 if (setMode == FA_OFFSET)
405 // Allocate comparision buffer 449 {
406 // XXX: integer overflow? 450 for (int nfile = 0; nfile < nsrcFiles; nfile++)
407 dmPrint(2, "Allocating %d element (%d bytes) comparision buffer.\n", 451 {
408 compBufSize, compBufSize * sizeof(DMCompElem)); 452 DMSourceFile *file = &srcFiles[nfile];
409 453 dmPrint(1, "#%03d: %s\n", nfile + 1, file->filename);
410 if ((compBuf = dmCalloc(compBufSize, sizeof(DMCompElem))) == NULL) 454 }
411 { 455
412 dmErrorMsg("Out of memory. Could not allocate comparision buffer!\n"); 456 printf(" offset :");
413 goto out; 457 for (int nfile = 0; nfile < nsrcFiles; nfile++)
414 } 458 printf(" %03d ", nfile + 1);
415 459 printf("\n");
416 // Begin analyzing .. 460
417 dmPrint(2, "Analyzing ..\n"); 461 printf("==========");
418 for (int nfile = 0; nfile < nsrcFiles; nfile++) 462 for (int nfile = 0; nfile < nsrcFiles; nfile++)
419 { 463 printf("===========");
420 DMSourceFile *file = &srcFiles[nfile]; 464 printf("\n");
421 465
422 for (size_t offs = 0; offs < file->size; offs++) 466 for (int n = 0; n < nsetGrepValues; n++)
423 { 467 {
424 Uint8 bv = file->data[offs]; 468 DMGrepValue *node = &setGrepValues[n];
425 totalStats.cv[bv].count++; 469 const DMGrepDef *def = &dmGrepTypes[node->type];
426 file->stats.cv[bv].count++; 470 printf("%08x : ", node->value);
471
472 for (int nfile = 0; nfile < nsrcFiles; nfile++)
473 {
474 DMSourceFile *file = &srcFiles[nfile];
475 Uint32 mval;
476 char mfmt[32];
477 int npad, nwidth;
478
479 if (dmGetData(node->type, file, node->value, &mval))
480 {
481 snprintf(mfmt, sizeof(mfmt), "%%0%dx", def->bsize * 2);
482 nwidth = def->bsize * 2;
483 }
484 else
485 {
486 strcpy(mfmt, "----");
487 nwidth = 4;
488 }
489
490 npad = (10 - nwidth) / 2;
491 for (int q = 0; q < npad; q++)
492 putchar(' ');
493
494 printf(mfmt, mval);
495
496 for (int q = 0; q < npad; q++)
497 putchar(' ');
498 }
499 printf("\n");
500 }
501 }
502 else
503 if (setMode == FA_ANALYZE)
504 {
505 // Allocate comparision buffer
506 // XXX: integer overflow?
507 dmPrint(2, "Allocating %d element (%d bytes) comparision buffer.\n",
508 compBufSize, compBufSize * sizeof(DMCompElem));
509
510 if ((compBuf = dmCalloc(compBufSize, sizeof(DMCompElem))) == NULL)
511 {
512 dmErrorMsg("Out of memory. Could not allocate comparision buffer!\n");
513 goto out;
514 }
515
516 // Begin analyzing ..
517 dmPrint(2, "Analyzing ..\n");
518 for (int nfile = 0; nfile < nsrcFiles; nfile++)
519 {
520 DMSourceFile *file = &srcFiles[nfile];
521
522 for (size_t offs = 0; offs < file->size; offs++)
523 {
524 Uint8 bv = file->data[offs];
525 totalStats.cv[bv].count++;
526 file->stats.cv[bv].count++;
527 }
528
529 for (size_t offs = 0; offs < compBufSize; offs++)
530 {
531 Uint8 data = offs < file->size ? file->data[offs] : 0;
532 compBuf[offs].stats[data]++;
533 }
427 } 534 }
428 535
429 for (size_t offs = 0; offs < compBufSize; offs++) 536 for (size_t offs = 0; offs < compBufSize; offs++)
430 { 537 {
431 Uint8 data = offs < file->size ? file->data[offs] : 0; 538 DMCompElem *el = &compBuf[offs];
432 compBuf[offs].stats[data]++; 539 for (int n = 0; n < SET_MAX_ELEMS; n++)
433 } 540 {
434 } 541 if (el->stats[n] > 0)
435 542 {
436 for (size_t offs = 0; offs < compBufSize; offs++) 543 el->variants++;
437 { 544 el->data = n;
438 DMCompElem *el = &compBuf[offs]; 545 }
439 for (int n = 0; n < SET_MAX_ELEMS; n++) 546 }
440 { 547 }
441 if (el->stats[n] > 0) 548
442 { 549 // Display results
443 el->variants++; 550 for (size_t offs = 0, n = 0; offs < compBufSize; offs++)
444 el->data = n; 551 {
445 } 552 DMCompElem *el = &compBuf[offs];
446 } 553 BOOL var = el->variants > 1;
447 } 554
448 555 if (n == 0)
449 // Display results 556 printf("%08" DM_PRIx_SIZE_T " | ", offs);
450 for (size_t offs = 0, n = 0; offs < compBufSize; offs++) 557
451 { 558 if (var)
452 DMCompElem *el = &compBuf[offs]; 559 printf("[%2d] ", el->variants);
453 BOOL var = el->variants > 1; 560 else
454 561 printf(" %02x ", el->data);
455 if (n == 0) 562
456 printf("%08" DM_PRIx_SIZE_T " | ", offs); 563 if (++n >= 16)
457 564 {
458 if (var) 565 printf("\n");
459 printf("[%2d] ", el->variants); 566 n = 0;
460 else 567 }
461 printf(" %02x ", el->data); 568 }
462 569
463 if (++n >= 16) 570 printf("\n");
464 { 571
465 printf("\n"); 572 // Attempt further analysis
466 n = 0; 573 for (int nfile = 0; nfile < nsrcFiles; nfile++)
467 } 574 {
468 } 575 DMSourceFile *file = &srcFiles[nfile];
469 576 size_t len = file->size > compBufSize ? compBufSize : file->size;
470 printf("\n"); 577 for (size_t offs = 0; offs + 4 < len; offs++)
471 578 {
472 // Attempt further analysis 579 DMCompElem *elem = &compBuf[offs];
473 for (int nfile = 0; nfile < nsrcFiles; nfile++) 580
474 { 581 for (int variant = 3; variant >= 0; variant--)
475 DMSourceFile *file = &srcFiles[nfile]; 582 {
476 size_t len = file->size > compBufSize ? compBufSize : file->size; 583 size_t nmax = (variant < 2) ? sizeof(Uint16) : sizeof(Uint32);
477 for (size_t offs = 0; offs + 4 < len; offs++) 584 Uint32 tmp = 0;
585
586 for (size_t n = 0; n < nmax; n++)
587 {
588 size_t boffs = (variant & 1) ? n : nmax - n;
589
590 tmp <<= 8;
591 tmp |= file->data[offs + boffs];
592 }
593
594 if (file->size - tmp < 32)
595 {
596 elem->interest[variant] += 32 - (file->size - tmp);
597 elem->interestF[variant]++;
598 }
599 }
600 }
601 }
602
603 printf("\nMore findings:\n");
604 for (size_t offs = 0; offs + 4 < compBufSize; offs++)
478 { 605 {
479 DMCompElem *elem = &compBuf[offs]; 606 DMCompElem *elem = &compBuf[offs];
480 607
481 for (int variant = 3; variant >= 0; variant--) 608 for (int variant = 0; variant < 4; variant++)
482 { 609 if (elem->interestF[variant] > 0)
483 size_t nmax = (variant < 2) ? sizeof(Uint16) : sizeof(Uint32); 610 {
484 Uint32 tmp = 0; 611 printf("%08" DM_PRIx_SIZE_T " | V%d : %d / %d\n",
485 612 offs, variant,
486 for (size_t n = 0; n < nmax; n++) 613 elem->interestF[variant], elem->interest[variant]);
487 { 614 }
488 size_t boffs = (variant & 1) ? n : nmax - n; 615 }
489 616
490 tmp <<= 8; 617 printf("\nGlobal most used bytes:\n");
491 tmp |= file->data[offs + boffs]; 618 dmPrintStats(&totalStats, 16, totalSize);
492 } 619
493 620 for (int nfile = 0; nfile < nsrcFiles; nfile++)
494 if (file->size - tmp < 32) 621 {
495 { 622 DMSourceFile *file = &srcFiles[nfile];
496 elem->interest[variant] += 32 - (file->size - tmp); 623 printf("Most used bytes for '%s':\n", file->filename);
497 elem->interestF[variant]++; 624 dmPrintStats(&file->stats, 16, file->size);
498 } 625 }
499 } 626 }
500 } 627 else
501 } 628 {
502 629 dmErrorMsg("Invalid operating mode?\n");
503 printf("\nMore findings:\n");
504 for (size_t offs = 0; offs + 4 < compBufSize; offs++)
505 {
506 DMCompElem *elem = &compBuf[offs];
507
508 for (int variant = 0; variant < 4; variant++)
509 if (elem->interestF[variant] > 0)
510 {
511 printf("%08" DM_PRIx_SIZE_T " | V%d : %d / %d\n",
512 offs, variant,
513 elem->interestF[variant], elem->interest[variant]);
514 }
515 }
516
517 printf("\nGlobal most used bytes:\n");
518 dmPrintStats(&totalStats, 16, totalSize);
519
520 for (int nfile = 0; nfile < nsrcFiles; nfile++)
521 {
522 DMSourceFile *file = &srcFiles[nfile];
523 printf("Most used bytes for '%s':\n", file->filename);
524 dmPrintStats(&file->stats, 16, file->size);
525 } 630 }
526 631
527 out: 632 out:
528 for (int nfile = 0; nfile < nsrcFiles; nfile++) 633 for (int nfile = 0; nfile < nsrcFiles; nfile++)
529 { 634 {