Added a.out format for NED binaries to track symbols through to the disassembler.
[ned1] / neddis / neddis.c
index 96256d0..306666e 100644 (file)
@@ -8,8 +8,11 @@
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
+#include <stdbool.h>
 
 
-#define VERSION 1
+#include "../common/a.out.h"
+
+#define VERSION 2
 
 enum syllables {
     MVSTCK  = 0b00001111,
 
 enum syllables {
     MVSTCK  = 0b00001111,
@@ -60,6 +63,8 @@ print_usage(char ** argv)
             "Usage: %s -i <file>\n"
             "  -h         Help (prints this message)\n"
             "  -i <file>  Specify a binary image file to disassemble.\n"
             "Usage: %s -i <file>\n"
             "  -h         Help (prints this message)\n"
             "  -i <file>  Specify a binary image file to disassemble.\n"
+            "  -s         Print summary of information in a.out exec header.\n"
+            "  -l         Print labels and organize disassembled code by label.\n"
             , VERSION, argv[0]
     );
 }
             , VERSION, argv[0]
     );
 }
@@ -160,6 +165,110 @@ print_formatC_mnemonics(uint32_t word)
     }
 }
 
     }
 }
 
+void
+parse_aout_file(FILE * input, struct exec * aout_exec, uint32_t ** text_segment,
+                struct nlist ** symbol_table, uint32_t * symbol_count)
+{
+    uint32_t read_count = 0;
+
+    /* Read in and check the a.out header. */
+    for (uint32_t i=0; i<8; i++) {
+        switch (i) {
+            case 0: read_count = fread(&(aout_exec->a_midmag), 4, 1, input); break;
+            case 1: read_count = fread(&(aout_exec->a_text),   4, 1, input); break;
+            case 2: read_count = fread(&(aout_exec->a_data),   4, 1, input); break;
+            case 3: read_count = fread(&(aout_exec->a_bss),    4, 1, input); break;
+            case 4: read_count = fread(&(aout_exec->a_syms),   4, 1, input); break;
+            case 5: read_count = fread(&(aout_exec->a_entry),  4, 1, input); break;
+            case 6: read_count = fread(&(aout_exec->a_trsize), 4, 1, input); break;
+            case 7: read_count = fread(&(aout_exec->a_drsize), 4, 1, input); break;
+        }
+        if (read_count != 1) {
+            fprintf(stderr, "ERROR: Invalid a.out header.\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+    if (N_BADMAG(*aout_exec)) {
+        fprintf(stderr, "ERROR: Invalid magic number in a.out header.\n");
+        exit(EXIT_FAILURE);
+    } else if (N_GETMID(*aout_exec) != MID_NED) {
+        fprintf(stderr, "ERROR: Executable not intended for NED Machine ID.\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Read in the text segment. */
+    uint32_t text_segment_size = (N_DATOFF(*aout_exec) - N_TXTOFF(*aout_exec));
+    *text_segment = malloc(text_segment_size + 4);
+    (*text_segment)[0] = text_segment_size / 4;
+    read_count = fread(&((*text_segment)[1]), 1, text_segment_size, input);
+    if (read_count != text_segment_size) {
+        fprintf(stderr, "ERROR: Failed to read entire text segment.\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Read in the symbol table. */
+    *symbol_count = ((N_STROFF(*aout_exec) - N_SYMOFF(*aout_exec)) / 20); /* 20 bytes per symbol. */
+    *symbol_table = malloc((*symbol_count) * sizeof(struct nlist));
+    for (uint32_t i=0; i < *symbol_count; i++) {
+        for (uint32_t j=0; j<5; j++) {
+            switch (j) {
+                case 0: read_count = fread(&((*symbol_table)[i].n_un.n_strx), 4, 1, input); break;
+                case 1: read_count = fread(&((*symbol_table)[i].n_type),      4, 1, input); break;
+                case 2: read_count = fread(&((*symbol_table)[i].n_other),     4, 1, input); break;
+                case 3: read_count = fread(&((*symbol_table)[i].n_desc),      4, 1, input); break;
+                case 4: read_count = fread(&((*symbol_table)[i].n_value),     4, 1, input); break;
+            }
+            if (read_count != 1) {
+                fprintf(stderr, "ERROR: Unable to read entire symbol table.\n");
+                exit(EXIT_FAILURE);
+            }
+        }
+    }
+
+    /* Read in the string table and update the symbol table entries with pointers to new strings. */
+    uint32_t string_table_size;
+    read_count = fread(&string_table_size, 4, 1, input);
+    if (read_count != 1) {
+        fprintf(stderr, "ERROR: Failed to read string table size.\n");
+        exit(EXIT_FAILURE);
+    }
+    for (uint32_t i=0; i < *symbol_count; i++) {
+        uint32_t len = 0;
+        if (i < ((*symbol_count)-1)) {
+            len = ((*symbol_table)[i+1].n_un.n_strx - (*symbol_table)[i].n_un.n_strx);
+        } else {
+            len = (string_table_size - (*symbol_table)[i].n_un.n_strx);
+        }
+        (*symbol_table)[i].n_un.n_name = malloc(len);
+        read_count = fread((*symbol_table)[i].n_un.n_name, 1, len, input);
+        if (read_count != len) {
+            fprintf(stderr, "ERROR: Failed to read a string from the string table.\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+}
+
+void
+print_aout_summary(struct exec * aout_exec)
+{
+    printf("\n  Summary\n"
+           " =====================================\n"
+           "  Magic:             0x%08x\n"
+           "  Machine ID:        0x%08x\n"
+           "  Flags:             0x%08x\n"
+           "  Text Size:         0x%08x bytes\n"
+           "  Data Size:         0x%08x bytes\n"
+           "  BSS Size:          0x%08x bytes\n"
+           "  Symbol Table Size: 0x%08x bytes\n"
+           "  Entry Point:       0x%08x\n"
+           "  Text Reloc. Size:  0x%08x bytes\n"
+           "  Data Reloc. Size:  0x%08x bytes\n\n\n",
+            N_GETMAGIC(*aout_exec), N_GETMID(*aout_exec), N_GETFLAG(*aout_exec),
+            aout_exec->a_text, aout_exec->a_data, aout_exec->a_bss, aout_exec->a_syms, 
+            aout_exec->a_entry, aout_exec->a_trsize, aout_exec->a_drsize
+        );
+}
+
 int
 main(int argc, char ** argv)
 {
 int
 main(int argc, char ** argv)
 {
@@ -168,8 +277,16 @@ main(int argc, char ** argv)
      */
     int c;
     FILE * input = NULL;
      */
     int c;
     FILE * input = NULL;
-    while ((c = getopt(argc,argv,"i:h")) != -1) {
+    bool display_summary = false;
+    bool display_labels = false;
+    while ((c = getopt(argc,argv,"i:hsl")) != -1) {
         switch (c) {
         switch (c) {
+            case 'l':
+                display_labels = true;
+                break;
+            case 's':
+                display_summary = true;
+                break;
             case 'i':
                 if ((input = fopen(optarg, "r")) == NULL) {
                     fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
             case 'i':
                 if ((input = fopen(optarg, "r")) == NULL) {
                     fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
@@ -189,14 +306,33 @@ main(int argc, char ** argv)
         exit(EXIT_FAILURE);
     }
 
         exit(EXIT_FAILURE);
     }
 
+    struct exec aout_exec;
+    uint32_t * text_segment;
+    struct nlist * symbol_table;
+    uint32_t symbol_count;
+    parse_aout_file(input, &aout_exec, &text_segment, &symbol_table, &symbol_count);
+
+    if (display_summary) print_aout_summary(&aout_exec);
+
     /*
      * Main Loop
      */
     /*
      * Main Loop
      */
+
     print_header();
     uint32_t word;
     print_header();
     uint32_t word;
-    uint32_t offset = 0;
+    uint32_t offset = aout_exec.a_entry;
     /* Since all NED instructions are one word (4 bytes) wide, read in one word increments. */
     /* Since all NED instructions are one word (4 bytes) wide, read in one word increments. */
-    while (fread(&word, 4, 1, input)) {
+    uint32_t i = 1;
+    while (i < text_segment[0]) {
+        if (display_labels) {
+            for (uint32_t i=0; i < symbol_count; i++) {
+                if (offset == symbol_table[i].n_value) {
+                    printf("\n%s:\n", symbol_table[i].n_un.n_name);
+                }
+            }
+        }
+        word = text_segment[i];
+        i++;
         printf("0x%08x", offset);
         printf("    ");
         printf("0x%08x", word);
         printf("0x%08x", offset);
         printf("    ");
         printf("0x%08x", word);