disasm: when no instruction is found, consider a naked prefix
authorH. Peter Anvin <hpa@zytor.com>
Thu, 19 Mar 2009 06:10:19 +0000 (23:10 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Thu, 19 Mar 2009 06:10:19 +0000 (23:10 -0700)
If we can't find a matching instruction, rather than printing it as a
"db" literal, consider first if we can disassemble it as a naked prefix.

disasm.c
disasm.h
ndisasm.c

index 63fd37b..f410418 100644 (file)
--- a/disasm.c
+++ b/disasm.c
@@ -1420,8 +1420,86 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
     return length;
 }
 
-int32_t eatbyte(uint8_t *data, char *output, int outbufsize)
+/*
+ * This is called when we don't have a complete instruction.  If it
+ * is a standalone *single-byte* prefix show it as such, otherwise
+ * print it as a literal.
+ */
+int32_t eatbyte(uint8_t *data, char *output, int outbufsize, int segsize)
 {
-    snprintf(output, outbufsize, "db 0x%02X", *data);
+    uint8_t byte = *data;
+    const char *str = NULL;
+    
+    switch (byte) {
+    case 0xF2:
+       str = "rep";
+       break;
+    case 0xF3:
+       str = "repne";
+       break;
+    case 0x9B:
+       str = "wait";
+       break;
+    case 0xF0:
+       str = "lock";
+       break;
+    case 0x2E:
+       str = "cs";
+       break;
+    case 0x36:
+       str = "ss";
+       break;
+    case 0x3E:
+       str = "ss";
+       break;
+    case 0x26:
+       str = "es";
+       break;
+    case 0x64:
+       str = "fs";
+       break;
+    case 0x65:
+       str = "gs";
+       break;
+    case 0x66:
+       str = (segsize == 16) ? "o32" : "o16";
+       break;
+    case 0x67:
+       str = (segsize == 32) ? "a16" : "a32";
+       break;
+    case REX_P + 0x0:
+    case REX_P + 0x1:
+    case REX_P + 0x2:
+    case REX_P + 0x3:
+    case REX_P + 0x4:
+    case REX_P + 0x5:
+    case REX_P + 0x6:
+    case REX_P + 0x7:
+    case REX_P + 0x8:
+    case REX_P + 0x9:
+    case REX_P + 0xA:
+    case REX_P + 0xB:
+    case REX_P + 0xC:
+    case REX_P + 0xD:
+    case REX_P + 0xE:
+    case REX_P + 0xF:
+       if (segsize == 64) {
+           snprintf(output, outbufsize, "rex%s%s%s%s%s",
+                    (byte == REX_P) ? "" : ".",
+                    (byte & REX_W) ? "w" : "",
+                    (byte & REX_R) ? "r" : "",
+                    (byte & REX_X) ? "x" : "",
+                    (byte & REX_B) ? "b" : "");
+           break;
+       }
+       /* else fall through */
+    default:
+       snprintf(output, outbufsize, "db 0x%02x", byte);
+       break;
+    }
+
+    if (str)
+       strcpy(output, str);
+
     return 1;
 }
index 56785ce..6467730 100644 (file)
--- a/disasm.h
+++ b/disasm.h
@@ -13,6 +13,6 @@
 
 int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
             int32_t offset, int autosync, uint32_t prefer);
-int32_t eatbyte(uint8_t *data, char *output, int outbufsize);
+int32_t eatbyte(uint8_t *data, char *output, int outbufsize, int segsize);
 
 #endif
index 766119b..75fc325 100644 (file)
--- a/ndisasm.c
+++ b/ndisasm.c
@@ -273,7 +273,8 @@ int main(int argc, char **argv)
         if ((nextsync || synclen) &&
            (uint32_t)offset == nextsync) {
             if (synclen) {
-                fprintf(stdout, "%08"PRIX32"  skipping 0x%"PRIX32" bytes\n", offset, synclen);
+                fprintf(stdout, "%08"PRIX32"  skipping 0x%"PRIX32" bytes\n",
+                       offset, synclen);
                 offset += synclen;
                 skip(synclen, fp);
             }
@@ -282,12 +283,12 @@ int main(int argc, char **argv)
         }
         while (p > q && (p - q >= INSN_MAX || lenread == 0)) {
             lendis =
-                disasm((uint8_t *) q, outbuf, sizeof(outbuf), bits, offset, autosync,
-                       prefer);
+                disasm((uint8_t *) q, outbuf, sizeof(outbuf), bits,
+                      offset, autosync, prefer);
             if (!lendis || lendis > (p - q)
                 || ((nextsync || synclen) &&
                    (uint32_t)lendis > nextsync - offset))
-                lendis = eatbyte((uint8_t *) q, outbuf, sizeof(outbuf));
+                lendis = eatbyte((uint8_t *) q, outbuf, sizeof(outbuf), bits);
             output_ins(offset, (uint8_t *) q, lendis, outbuf);
             q += lendis;
             offset += lendis;