changeset 2225:837c79747ea4

Add functionality for grepping multiple consecutive values (8/16/32 le/be) and also wildcard values specified with '?'.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 14 Jun 2019 18:00:18 +0300
parents a36c81c3df85
children 6037ba60730a
files tools/fanalyze.c
diffstat 1 files changed, 175 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/tools/fanalyze.c	Fri Jun 14 12:13:23 2019 +0300
+++ b/tools/fanalyze.c	Fri Jun 14 18:00:18 2019 +0300
@@ -13,6 +13,7 @@
 #define SET_MAX_FILES    64
 #define SET_MAX_ELEMS    256
 #define SET_MAX_VALUES   64
+#define SET_MAX_GREPLIST 64
 
 
 /* Typedefs
@@ -72,7 +73,9 @@
 {
     int type;
     int disp;
-    Uint32 value;
+    int nvalues;
+    Uint32 values[SET_MAX_GREPLIST];
+    BOOL vwildcards[SET_MAX_GREPLIST];
 } DMGrepValue;
 
 
@@ -131,8 +134,8 @@
 {
     {  0, '?', "help",        "Show this help", OPT_NONE },
     {  1, 'v', "verbose",     "Be more verbose", OPT_NONE },
-    {  2, 'g', "grep",        "Binary grep <val>[,<le|be>[8|16|32]]", OPT_ARGREQ },
-    {  3, 'o', "offset",      "Show data in offset <offset>,<le|be>[8|16|32][d|x]]", OPT_ARGREQ },
+    {  2, 'g', "grep",        "Binary grep <val>[,<val2>...][:<le|be>[8|16|32]]", OPT_ARGREQ },
+    {  3, 'o', "offset",      "Show data in offset <offset>:<le|be>[8|16|32][d|x]]", OPT_ARGREQ },
 };
 
 static const int optListN = sizeof(optList) / sizeof(optList[0]);
@@ -142,15 +145,96 @@
 {
     dmPrintBanner(stdout, dmProgName, "[options] <input file #1> <input file #2> [...]");
     dmArgsPrintHelp(stdout, optList, optListN, 0);
+
+    fprintf(stdout,
+    "\n"
+    "Value lists for grep function can contain wildcard '?' (or '#') which\n"
+    "matches any value of the specified (or inferred) type. For example:\n"
+    "-g 0x0f,7,5,?,5,?,? will match sequence of bytes 0f 07 05 ?? 05 ?? ??\n"
+    "and -g 0xe,0x1001,?,2023:le16 will match le16 value 000e 1001 ???? 07e7\n"
+    );
+}
+
+
+BOOL dmGetData(const int type, const DMSourceFile *file, const size_t offs, Uint32 *mval)
+{
+    Uint8 *data = file->data + offs;
+    if (offs + dmGrepTypes[type].bsize >= file->size)
+    {
+        *mval = 0;
+        return FALSE;
+    }
+
+    switch (type)
+    {
+        case DMGV_UINT8:
+            *mval = *((Uint8 *) data);
+            break;
+
+        case DMGV_UINT16_LE:
+            *mval = DM_LE16_TO_NATIVE(*((Uint16 *) data));
+            break;
+
+        case DMGV_UINT16_BE:
+            *mval = DM_BE16_TO_NATIVE(*((Uint16 *) data));
+            break;
+
+        case DMGV_UINT32_LE:
+            *mval = DM_LE32_TO_NATIVE(*((Uint32 *) data));
+            break;
+
+        case DMGV_UINT32_BE:
+            *mval = DM_BE32_TO_NATIVE(*((Uint32 *) data));
+            break;
+
+        default:
+            *mval = 0;
+            return FALSE;
+    }
+    return TRUE;
+}
+
+
+void dmPrintGrepValueList(const DMGrepValue *node, const BOOL match, DMSourceFile *file, const size_t offs)
+{
+    char vfmt[16];
+
+    snprintf(vfmt, sizeof(vfmt), "%%%s%d%s%%s",
+        node->disp == DMGS_HEX ? "0" : "",
+        dmGrepTypes[node->type].bsize * 2,
+        node->disp == DMGS_HEX ? "x" : "d");
+
+    for (int n = 0; n < node->nvalues; n++)
+    {
+        const char *veol = (n < node->nvalues - 1) ? " " : "\n";
+
+        if (match)
+        {
+            Uint32 mval;
+            dmGetData(node->type, file, offs + n, &mval);
+            dmPrint(1, vfmt, mval, veol);
+        }
+        else
+        {
+            if (node->vwildcards[n])
+                dmPrint(1, "?%s", veol);
+            else
+                dmPrint(1, vfmt, node->values[n], veol);
+        }
+    }
 }
 
 
 int argParseGrepValue(const char *arg, const int mode)
 {
-    const char *sep = strchr(arg, ',');
-    char *vspec, *vstr;
-    int vdisp = DMGS_HEX, vtype = -1, ret = DMERR_OK;
-    Uint32 vval;
+    const char *specsep = strchr(arg, ':');
+    char *vspec, *vstr, *vsep;
+    int vdisp = DMGS_HEX, vtype = -1, ret = DMERR_OK, nvalues;
+    BOOL more;
+    Uint32 vvalues[SET_MAX_GREPLIST];
+    BOOL vwildcards[SET_MAX_GREPLIST];
+
+    memset(vwildcards, 0, sizeof(vwildcards));
 
     if (setMode != FA_ANALYZE && setMode != mode)
     {
@@ -160,10 +244,10 @@
     setMode = mode;
 
     // Do we have spec?
-    if (sep != NULL)
+    if (specsep != NULL)
     {
-        vspec = dm_strdup_trim(sep + 1, DM_TRIM_BOTH);
-        vstr = dm_strndup_trim(arg, sep - arg, DM_TRIM_BOTH);
+        vspec = dm_strdup_trim(specsep + 1, DM_TRIM_BOTH);
+        vstr = dm_strndup_trim(arg, specsep - arg, DM_TRIM_BOTH);
     }
     else
     {
@@ -237,12 +321,56 @@
         }
     }
 
-    // Get value
-    if (!dmGetIntVal(vstr, &vval, NULL))
+    // Get list of values
+    char *vtmp = vstr;
+    nvalues = 0;
+    do
+    {
+        if (nvalues >= SET_MAX_GREPLIST)
+        {
+            ret = dmError(DMERR_BOUNDS,
+                "Too many greplist values specified '%s'.\n",
+                vstr);
+            goto out;
+        }
+
+        if ((vsep = strchr(vtmp, ',')) != NULL)
+        {
+            *vsep = 0;
+            more = TRUE;
+        }
+        else
+            more = FALSE;
+
+        if (vtmp[0] == '#' || vtmp[0] == '?')
+        {
+            vwildcards[nvalues] = TRUE;
+            if (mode == FA_OFFSET)
+            {
+                ret = dmError(DMERR_INVALID_ARGS,
+                    "Offset mode does not allow wildcard values.\n");
+                goto out;
+            }
+        }
+        else
+        if (!dmGetIntVal(vtmp, &vvalues[nvalues], NULL))
+        {
+            ret = dmError(DMERR_INVALID_ARGS,
+                "Not a valid integer value '%s'.\n",
+                vtmp);
+            goto out;
+        }
+
+        nvalues++;
+
+        if (more)
+            vtmp = vsep + 1;
+    } while (more);
+
+    if (vwildcards[0])
     {
         ret = dmError(DMERR_INVALID_ARGS,
-            "Not a valid integer value '%s'.\n",
-            vstr);
+            "First grep value can not be a wildcard.\n");
         goto out;
     }
 
@@ -254,7 +382,7 @@
             for (int n = DMGV_last; n >= 0; n--)
             {
                 const DMGrepType *def = &dmGrepTypes[n];
-                if (vval <= def->nmax)
+                if (vvalues[0] <= def->nmax)
                     vtype = n;
             }
         }
@@ -268,11 +396,12 @@
         }
 
         // Check range
-        if (vval > dmGrepTypes[vtype].nmax)
+        for (int n = 0; n < nvalues; n++)
+        if (!vwildcards[n] && vvalues[n] > 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);
+                vvalues[n], 0, dmGrepTypes[vtype].nmax, dmGrepTypes[vtype].name);
 
             goto out;
         }
@@ -287,13 +416,17 @@
     if (nsetGrepValues < SET_MAX_VALUES)
     {
         DMGrepValue *node = &setGrepValues[nsetGrepValues++];
+
         node->type = vtype;
         node->disp = vdisp;
-        node->value = vval;
+        node->nvalues = nvalues;
+        memcpy(node->values, vvalues, sizeof(vvalues[0]) * nvalues);
+        memcpy(node->vwildcards, vwildcards, sizeof(vwildcards[0]) * nvalues);
 
-        dmMsg(1, "Grep value %s : %d / 0x%x\n",
-            dmGrepTypes[vtype].name,
-            vval, vval);
+        dmMsg(1, "Grep %ss : ",
+            dmGrepTypes[vtype].name);
+
+        dmPrintGrepValueList(node, FALSE, NULL, 0);
     }
     else
     {
@@ -388,45 +521,6 @@
 }
 
 
-BOOL dmGetData(const int type, const DMSourceFile *file, const size_t offs, Uint32 *mval)
-{
-    Uint8 *data = file->data + offs;
-    if (offs + dmGrepTypes[type].bsize >= file->size)
-    {
-        *mval = 0;
-        return FALSE;
-    }
-
-    switch (type)
-    {
-        case DMGV_UINT8:
-            *mval = *((Uint8 *) data);
-            break;
-
-        case DMGV_UINT16_LE:
-            *mval = DM_LE16_TO_NATIVE(*((Uint16 *) data));
-            break;
-
-        case DMGV_UINT16_BE:
-            *mval = DM_BE16_TO_NATIVE(*((Uint16 *) data));
-            break;
-
-        case DMGV_UINT32_LE:
-            *mval = DM_LE32_TO_NATIVE(*((Uint32 *) data));
-            break;
-
-        case DMGV_UINT32_BE:
-            *mval = DM_BE32_TO_NATIVE(*((Uint32 *) data));
-            break;
-
-        default:
-            *mval = 0;
-            return FALSE;
-    }
-    return TRUE;
-}
-
-
 int main(int argc, char *argv[])
 {
     DMCompElem *compBuf = NULL;
@@ -486,15 +580,28 @@
                 DMGrepValue *node = &setGrepValues[n];
                 const DMGrepType *def = &dmGrepTypes[node->type];
 
-                for (size_t offs = 0; offs + def->bsize < file->size; offs++)
+                for (size_t offs = 0; offs + (def->bsize * node->nvalues) < file->size; offs++)
                 {
-                    Uint32 mval;
-                    dmGetData(node->type, file, offs, &mval);
+                    BOOL match = TRUE;
+                    for (int n = 0; n < node->nvalues; n++)
+                    if (!node->vwildcards[n])
+                    {
+                        Uint32 mval;
+                        dmGetData(node->type, file, offs + n, &mval);
 
-                    if (mval == node->value)
+                        if (mval != node->values[n])
+                        {
+                            match = FALSE;
+                            break;
+                        }
+                    }
+
+                    if (match)
                     {
-                        dmPrint(0, "%08x : %s match %d / 0x%x\n",
-                            offs, def->name, mval, mval);
+                        dmPrint(0, "%08x : %s match ",
+                            offs, def->name);
+
+                        dmPrintGrepValueList(node, TRUE, file, offs);
                     }
                 }
             }
@@ -523,7 +630,7 @@
         {
             DMGrepValue *node = &setGrepValues[n];
             const DMGrepType *def = &dmGrepTypes[node->type];
-            printf("%08x : ", node->value);
+            printf("%08x : ", node->values[0]);
 
             for (int nfile = 0; nfile < nsrcFiles; nfile++)
             {
@@ -532,7 +639,7 @@
                 char mstr[32];
                 int npad, nwidth;
 
-                if (dmGetData(node->type, file, node->value, &mval))
+                if (dmGetData(node->type, file, node->values[0], &mval))
                 {
                     char mfmt[16];
                     nwidth = def->bsize * 2;