changeset 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 750a7e125546
children 4109967ef832
files tools/fanalyze.c
diffstat 1 files changed, 228 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- 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 <val>[,<le|be>[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",