comparison tools/fanalyze.c @ 2028:8a9ef75fd3cd

Implemement simple binary grep functionality in fanalyze.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 27 Nov 2018 12:20:51 +0200
parents 8e38fa3c4f98
children 5fe25336a474
comparison
equal deleted inserted replaced
2027:750a7e125546 2028:8a9ef75fd3cd
8 #include "dmtool.h" 8 #include "dmtool.h"
9 #include "dmlib.h" 9 #include "dmlib.h"
10 #include "dmargs.h" 10 #include "dmargs.h"
11 #include "dmfile.h" 11 #include "dmfile.h"
12 12
13 #define SET_MAX_FILES 16 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 16
16 17
17 /* Typedefs 18 /* Typedefs
18 */ 19 */
19 typedef struct 20 typedef struct
45 size_t size; // offset, crop_start, crop_end, doCrop? 46 size_t size; // offset, crop_start, crop_end, doCrop?
46 DMStats stats; 47 DMStats stats;
47 } DMSourceFile; 48 } DMSourceFile;
48 49
49 50
51 enum
52 {
53 DMGV_uint8 = 0,
54 DMGV_uint16_le,
55 DMGV_uint16_be,
56 DMGV_uint32_le,
57 DMGV_uint32_be,
58
59 DMGV_last
60 };
61
62
63 typedef struct
64 {
65 char *name;
66 uint32_t nmax;
67 unsigned int bsize;
68 } DMGrepDef;
69
70
71 static const DMGrepDef dmGrepTypes[DMGV_last] =
72 {
73 { "8bit (byte)" , (1UL << 8) - 1, 1 },
74 { "16bit (word) LE" , (1UL << 16) - 1, 2 },
75 { "16bit (word) BE" , (1UL << 16) - 1, 2 },
76 { "32bit (word) LE" , (1UL << 32) - 1, 4 },
77 { "32bit (word) BE" , (1UL << 32) - 1, 4 },
78 };
79
80
81 typedef struct
82 {
83 int type;
84 uint32_t value;
85 } DMGrepValue;
86
87
50 /* Global variables 88 /* Global variables
51 */ 89 */
52 int nsrcFiles = 0; // Number of source files 90 int nsrcFiles = 0; // Number of source files
53 DMSourceFile srcFiles[SET_MAX_FILES]; // Source file names 91 DMSourceFile srcFiles[SET_MAX_FILES]; // Source file names
54 DMStats totalStats; 92 DMStats totalStats;
93 int nsetGrepValues = 0;
94 DMGrepValue setGrepValues[SET_MAX_VALUES];
55 95
56 96
57 /* Arguments 97 /* Arguments
58 */ 98 */
59 static const DMOptArg optList[] = 99 static const DMOptArg optList[] =
60 { 100 {
61 { 0, '?', "help", "Show this help", OPT_NONE }, 101 { 0, '?', "help", "Show this help", OPT_NONE },
62 { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, 102 { 1, 'v', "verbose", "Be more verbose", OPT_NONE },
103 { 2, 'g', "grep", "Binary grep mode <val>[,<le|be>[8|16|32]]", OPT_ARGREQ },
63 }; 104 };
64 105
65 static const int optListN = sizeof(optList) / sizeof(optList[0]); 106 static const int optListN = sizeof(optList) / sizeof(optList[0]);
66 107
67 108
70 dmPrintBanner(stdout, dmProgName, "[options] <input file #1> <input file #2> [...]"); 111 dmPrintBanner(stdout, dmProgName, "[options] <input file #1> <input file #2> [...]");
71 dmArgsPrintHelp(stdout, optList, optListN, 0); 112 dmArgsPrintHelp(stdout, optList, optListN, 0);
72 } 113 }
73 114
74 115
116 int argParseGrepValue(const char *arg)
117 {
118 const char *sep = strchr(arg, ',');
119 char *vspec, *vstr;
120 int vtype = -1, ret = DMERR_OK;
121 uint32_t vval;
122
123 // Do we have spec?
124 if (sep != NULL)
125 {
126 vspec = dm_strdup_trim(sep + 1, DM_TRIM_BOTH);
127 vstr = dm_strndup_trim(arg, sep - arg, DM_TRIM_BOTH);
128 }
129 else
130 {
131 vspec = NULL;
132 vstr = dm_strdup(arg);
133 }
134
135 // Parse spec if any
136 if (vspec != NULL)
137 {
138 BOOL vendianess = TRUE;
139 char *vtmp = vspec;
140
141 // Get endianess specifier, if any
142 if (dm_strncasecmp(vtmp, "le", 2) == 0)
143 {
144 vendianess = TRUE;
145 vtmp += 2;
146 }
147 else
148 if (dm_strncasecmp(vtmp, "be", 2) == 0)
149 {
150 vendianess = FALSE;
151 vtmp += 2;
152 }
153
154 // Get value bit size
155 if (strcmp(vtmp, "8") == 0)
156 vtype = DMGV_uint8;
157 else
158 if (strcmp(vtmp, "16") == 0)
159 vtype = vendianess ? DMGV_uint16_le : DMGV_uint16_be;
160 else
161 if (strcmp(vtmp, "32") == 0)
162 vtype = vendianess ? DMGV_uint32_le : DMGV_uint32_be;
163 else
164 {
165 ret = dmError(DMERR_INVALID_ARGS,
166 "Invalid grep type '%s'.\n",
167 vspec);
168 goto out;
169 }
170 }
171
172 // Get value
173 if (!dmGetIntVal(vstr, &vval, NULL))
174 {
175 ret = dmError(DMERR_INVALID_ARGS,
176 "Not a valid integer value '%s'.\n",
177 vstr);
178 goto out;
179 }
180
181 // Check if we need to guess size
182 if (vtype < 0)
183 {
184 for (int n = DMGV_last; n >= 0; n--)
185 {
186 const DMGrepDef *def = &dmGrepTypes[n];
187 if (vval <= def->nmax)
188 vtype = n;
189 }
190 }
191
192 if (vtype < 0)
193 {
194 ret = dmError(DMERR_INVALID_ARGS,
195 "Could not guess value type for '%s'.\n",
196 arg);
197 goto out;
198 }
199
200 // Check range
201 if (vval > dmGrepTypes[vtype].nmax)
202 {
203 ret = dmError(DMERR_INVALID_ARGS,
204 "Integer value %d <= %d <= %d out of range for type %s.\n",
205 vval, 0, dmGrepTypes[vtype].nmax, dmGrepTypes[vtype].name);
206
207 goto out;
208 }
209
210 if (nsetGrepValues < SET_MAX_VALUES)
211 {
212 DMGrepValue *node = &setGrepValues[nsetGrepValues++];
213 node->type = vtype;
214 node->value = vval;
215
216 dmMsg(1, "Grep value %s : %d / 0x%x\n",
217 dmGrepTypes[vtype].name,
218 vval, vval);
219 }
220 else
221 {
222 ret = dmError(DMERR_BOUNDS,
223 "Too many greps specified (max %d).",
224 SET_MAX_VALUES);
225 }
226
227 out:
228 dmFree(vspec);
229 dmFree(vstr);
230 return ret;
231 }
232
233
75 BOOL argHandleOpt(const int optN, char *optArg, char *currArg) 234 BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
76 { 235 {
77 (void) optArg; 236 (void) optArg;
78 237
79 switch (optN) 238 switch (optN)
80 { 239 {
81 case 0: 240 case 0:
82 argShowHelp(); 241 argShowHelp();
83 exit(0); 242 exit(0);
84 break; 243 break;
85 244
86 case 1: 245 case 1:
87 dmVerbosity++; 246 dmVerbosity++;
88 break; 247 break;
89 248
90 default: 249 case 2:
91 dmErrorMsg("Unknown argument '%s'.\n", currArg); 250 return argParseGrepValue(optArg) == DMERR_OK;
92 return FALSE; 251
252 default:
253 dmErrorMsg("Unknown argument '%s'.\n", currArg);
254 return FALSE;
93 } 255 }
94 256
95 return TRUE; 257 return TRUE;
96 } 258 }
97 259
184 if (!compBufSize || file->size < compBufSize) 346 if (!compBufSize || file->size < compBufSize)
185 compBufSize = file->size; 347 compBufSize = file->size;
186 348
187 totalSize += file->size; 349 totalSize += file->size;
188 dmInitStats(&file->stats); 350 dmInitStats(&file->stats);
351 }
352
353
354 // Check if we are in grep mode
355 if (nsetGrepValues > 0)
356 {
357 for (int nfile = 0; nfile < nsrcFiles; nfile++)
358 {
359 DMSourceFile *file = &srcFiles[nfile];
360 dmPrint(0, "\n%s:\n", file->filename);
361
362 for (int n = 0; n < nsetGrepValues; n++)
363 {
364 DMGrepValue *node = &setGrepValues[n];
365 const DMGrepDef *def = &dmGrepTypes[node->type];
366
367 for (size_t offs = 0; offs + def->bsize < file->size; offs++)
368 {
369 uint32_t mval = -1;
370 switch (node->type)
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
393 if (mval == node->value)
394 {
395 dmPrint(0, "%08x : %s match %d / 0x%x\n",
396 offs, def->name, mval, mval);
397
398 }
399 }
400 }
401 }
402 goto out;
189 } 403 }
190 404
191 // Allocate comparision buffer 405 // Allocate comparision buffer
192 // XXX: integer overflow? 406 // XXX: integer overflow?
193 dmPrint(2, "Allocating %d element (%d bytes) comparision buffer.\n", 407 dmPrint(2, "Allocating %d element (%d bytes) comparision buffer.\n",