Mercurial > hg > dmlib
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", |