# HG changeset patch # User Matti Hamalainen # Date 1543314051 -7200 # Node ID 8a9ef75fd3cd223befdbf824e99c594144d4b905 # Parent 750a7e1255464e02db2f601c5f6f1f94de549836 Implemement simple binary grep functionality in fanalyze. diff -r 750a7e125546 -r 8a9ef75fd3cd tools/fanalyze.c --- a/tools/fanalyze.c Tue Nov 27 11:31:10 2018 +0200 +++ b/tools/fanalyze.c Tue Nov 27 12:20:51 2018 +0200 @@ -10,8 +10,9 @@ #include "dmargs.h" #include "dmfile.h" -#define SET_MAX_FILES 16 +#define SET_MAX_FILES 64 #define SET_MAX_ELEMS 256 +#define SET_MAX_VALUES 32 /* Typedefs @@ -47,11 +48,50 @@ } DMSourceFile; +enum +{ + DMGV_uint8 = 0, + DMGV_uint16_le, + DMGV_uint16_be, + DMGV_uint32_le, + DMGV_uint32_be, + + DMGV_last +}; + + +typedef struct +{ + char *name; + uint32_t nmax; + unsigned int bsize; +} DMGrepDef; + + +static const DMGrepDef dmGrepTypes[DMGV_last] = +{ + { "8bit (byte)" , (1UL << 8) - 1, 1 }, + { "16bit (word) LE" , (1UL << 16) - 1, 2 }, + { "16bit (word) BE" , (1UL << 16) - 1, 2 }, + { "32bit (word) LE" , (1UL << 32) - 1, 4 }, + { "32bit (word) BE" , (1UL << 32) - 1, 4 }, +}; + + +typedef struct +{ + int type; + uint32_t value; +} DMGrepValue; + + /* Global variables */ -int nsrcFiles = 0; // Number of source files -DMSourceFile srcFiles[SET_MAX_FILES]; // Source file names -DMStats totalStats; +int nsrcFiles = 0; // Number of source files +DMSourceFile srcFiles[SET_MAX_FILES]; // Source file names +DMStats totalStats; +int nsetGrepValues = 0; +DMGrepValue setGrepValues[SET_MAX_VALUES]; /* Arguments @@ -60,6 +100,7 @@ { { 0, '?', "help", "Show this help", OPT_NONE }, { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 2, 'g', "grep", "Binary grep mode [,[8|16|32]]", OPT_ARGREQ }, }; static const int optListN = sizeof(optList) / sizeof(optList[0]); @@ -72,24 +113,145 @@ } +int argParseGrepValue(const char *arg) +{ + const char *sep = strchr(arg, ','); + char *vspec, *vstr; + int vtype = -1, ret = DMERR_OK; + uint32_t vval; + + // Do we have spec? + if (sep != NULL) + { + vspec = dm_strdup_trim(sep + 1, DM_TRIM_BOTH); + vstr = dm_strndup_trim(arg, sep - arg, DM_TRIM_BOTH); + } + else + { + vspec = NULL; + vstr = dm_strdup(arg); + } + + // Parse spec if any + if (vspec != NULL) + { + BOOL vendianess = TRUE; + char *vtmp = vspec; + + // Get endianess specifier, if any + if (dm_strncasecmp(vtmp, "le", 2) == 0) + { + vendianess = TRUE; + vtmp += 2; + } + else + if (dm_strncasecmp(vtmp, "be", 2) == 0) + { + vendianess = FALSE; + vtmp += 2; + } + + // Get value bit size + if (strcmp(vtmp, "8") == 0) + vtype = DMGV_uint8; + else + if (strcmp(vtmp, "16") == 0) + vtype = vendianess ? DMGV_uint16_le : DMGV_uint16_be; + else + if (strcmp(vtmp, "32") == 0) + vtype = vendianess ? DMGV_uint32_le : DMGV_uint32_be; + else + { + ret = dmError(DMERR_INVALID_ARGS, + "Invalid grep type '%s'.\n", + vspec); + goto out; + } + } + + // Get value + if (!dmGetIntVal(vstr, &vval, NULL)) + { + ret = dmError(DMERR_INVALID_ARGS, + "Not a valid integer value '%s'.\n", + vstr); + goto out; + } + + // Check if we need to guess size + if (vtype < 0) + { + for (int n = DMGV_last; n >= 0; n--) + { + const DMGrepDef *def = &dmGrepTypes[n]; + if (vval <= def->nmax) + vtype = n; + } + } + + if (vtype < 0) + { + ret = dmError(DMERR_INVALID_ARGS, + "Could not guess value type for '%s'.\n", + arg); + goto out; + } + + // Check range + if (vval > dmGrepTypes[vtype].nmax) + { + ret = dmError(DMERR_INVALID_ARGS, + "Integer value %d <= %d <= %d out of range for type %s.\n", + vval, 0, dmGrepTypes[vtype].nmax, dmGrepTypes[vtype].name); + + goto out; + } + + if (nsetGrepValues < SET_MAX_VALUES) + { + DMGrepValue *node = &setGrepValues[nsetGrepValues++]; + node->type = vtype; + node->value = vval; + + dmMsg(1, "Grep value %s : %d / 0x%x\n", + dmGrepTypes[vtype].name, + vval, vval); + } + else + { + ret = dmError(DMERR_BOUNDS, + "Too many greps specified (max %d).", + SET_MAX_VALUES); + } + +out: + dmFree(vspec); + dmFree(vstr); + return ret; +} + + BOOL argHandleOpt(const int optN, char *optArg, char *currArg) { (void) optArg; switch (optN) { - case 0: - argShowHelp(); - exit(0); - break; + case 0: + argShowHelp(); + exit(0); + break; - case 1: - dmVerbosity++; - break; + case 1: + dmVerbosity++; + break; - default: - dmErrorMsg("Unknown argument '%s'.\n", currArg); - return FALSE; + case 2: + return argParseGrepValue(optArg) == DMERR_OK; + + default: + dmErrorMsg("Unknown argument '%s'.\n", currArg); + return FALSE; } return TRUE; @@ -188,6 +350,58 @@ dmInitStats(&file->stats); } + + // Check if we are in grep mode + if (nsetGrepValues > 0) + { + for (int nfile = 0; nfile < nsrcFiles; nfile++) + { + DMSourceFile *file = &srcFiles[nfile]; + dmPrint(0, "\n%s:\n", file->filename); + + for (int n = 0; n < nsetGrepValues; n++) + { + DMGrepValue *node = &setGrepValues[n]; + const DMGrepDef *def = &dmGrepTypes[node->type]; + + for (size_t offs = 0; offs + def->bsize < file->size; offs++) + { + uint32_t mval = -1; + switch (node->type) + { + case DMGV_uint8: + mval = *((uint8_t *) (file->data + offs)); + break; + + case DMGV_uint16_le: + mval = DM_LE16_TO_NATIVE(*((uint16_t *) (file->data + offs))); + break; + + case DMGV_uint16_be: + mval = DM_BE16_TO_NATIVE(*((uint16_t *) (file->data + offs))); + break; + + case DMGV_uint32_le: + mval = DM_LE32_TO_NATIVE(*((uint32_t *) (file->data + offs))); + break; + + case DMGV_uint32_be: + mval = DM_BE32_TO_NATIVE(*((uint32_t *) (file->data + offs))); + break; + } + + if (mval == node->value) + { + dmPrint(0, "%08x : %s match %d / 0x%x\n", + offs, def->name, mval, mval); + + } + } + } + } + goto out; + } + // Allocate comparision buffer // XXX: integer overflow? dmPrint(2, "Allocating %d element (%d bytes) comparision buffer.\n",