#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,
"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]
);
}
}
}
+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 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) {
+ 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));
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
*/
+
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. */
- 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);