dasm: Rewrite cmdline arg parsing and remove the bin wrapper script.
authorMichael Buesch <mb@bu3sch.de>
Sun, 18 Nov 2007 13:57:35 +0000 (14:57 +0100)
committerMichael Buesch <mb@bu3sch.de>
Sun, 18 Nov 2007 13:57:35 +0000 (14:57 +0100)
Signed-off-by: Michael Buesch <mb@bu3sch.de>
disassembler/Makefile
disassembler/args.c [new file with mode: 0644]
disassembler/args.h [new file with mode: 0644]
disassembler/b43-dasm [deleted file]
disassembler/main.c
disassembler/main.h [new file with mode: 0644]

index 39392222dceb0f2f6d69700814e7f77a265222e5..e664722dbbc8ebc42741a3ffe0824277756af805 100644 (file)
@@ -1,26 +1,28 @@
-CC = gcc
-PREFIX = /usr/local
-CFLAGS = -std=gnu99 -O2 -fomit-frame-pointer -Wall -D_BSD_SOURCE -D_GNU_SOURCE
-LDFLAGS =
+CC             ?= gcc
 
-BINARY = b43-dasm.bin
-OBJECTS = main.o util.o
+PREFIX         ?= /usr/local
 
-all: $(BINARY)
+CFLAGS         ?= -O2 -fomit-frame-pointer
+CFLAGS         += -std=gnu99 -Wall -D_BSD_SOURCE -D_GNU_SOURCE
+LDFLAGS                ?=
 
-main.o: util.h list.h
+BIN = b43-dasm
+OBJECTS = main.o util.o args.o
+
+all: $(BIN)
+
+main.o: main.h util.h list.h args.h
 
 util.o: util.h
 
-$(BINARY): $(OBJECTS)
-       $(CC) $(CFLAGS) -o $(BINARY) $(OBJECTS) $(LDFLAGS)
+$(BIN): $(OBJECTS)
+       $(CC) $(CFLAGS) -o $(BIN) $(OBJECTS) $(LDFLAGS)
 
 install: all
-       -install -o 0 -g 0 -m 755 $(BINARY) $(PREFIX)/bin/
-       -cp b43-dasm b43-dasm.inst
-       -sed -i -e 's/installed=0/installed=1/' b43-dasm.inst
-       -install -o 0 -g 0 -m 755 b43-dasm.inst $(PREFIX)/bin/b43-dasm
-       -rm -f b43-dasm.inst
+       -install -o 0 -g 0 -m 755 $(BIN) $(PREFIX)/bin/
 
 clean:
-       -rm -f *~ *.o *.orig *.rej $(BINARY)
+       -rm -f *~ *.o *.orig *.rej
+
+distclean: clean
+       -rm -f $(BIN)
diff --git a/disassembler/args.c b/disassembler/args.c
new file mode 100644 (file)
index 0000000..2848089
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *   Copyright (C) 2006-2007  Michael Buesch <mb@bu3sch.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ */
+
+#include "args.h"
+#include "main.h"
+#include "util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+int _debug;
+
+struct cmdline_args cmdargs = {
+       .arch = 5,      /* Default to v5 architecture. */
+};
+
+#define ARG_MATCH              0
+#define ARG_NOMATCH            1
+#define ARG_ERROR              -1
+
+static int do_cmp_arg(char **argv, int *pos,
+                     const char *template,
+                     int allow_merged,
+                     char **param)
+{
+       char *arg;
+       char *next_arg;
+       size_t arg_len, template_len;
+
+       arg = argv[*pos];
+       next_arg = argv[*pos + 1];
+       arg_len = strlen(arg);
+       template_len = strlen(template);
+
+       if (param) {
+               /* Maybe we have a merged parameter here.
+                * A merged parameter is "-pfoobar" for example.
+                */
+               if (allow_merged && arg_len > template_len) {
+                       if (memcmp(arg, template, template_len) == 0) {
+                               *param = arg + template_len;
+                               return ARG_MATCH;
+                       }
+                       return ARG_NOMATCH;
+               } else if (arg_len != template_len)
+                       return ARG_NOMATCH;
+               *param = next_arg;
+       }
+       if (strcmp(arg, template) == 0) {
+               if (param) {
+                       /* Skip the parameter on the next iteration. */
+                       (*pos)++;
+                       if (*param == 0) {
+                               fprintf(stderr, "%s needs a parameter\n", arg);
+                               return ARG_ERROR;
+                       }
+               }
+               return ARG_MATCH;
+       }
+
+       return ARG_NOMATCH;
+}
+
+/* Simple and lean command line argument parsing. */
+static int cmp_arg(char **argv, int *pos,
+                  const char *long_template,
+                  const char *short_template,
+                  char **param)
+{
+       int err;
+
+       if (long_template) {
+               err = do_cmp_arg(argv, pos, long_template, 0, param);
+               if (err == ARG_MATCH || err == ARG_ERROR)
+                       return err;
+       }
+       err = ARG_NOMATCH;
+       if (short_template)
+               err = do_cmp_arg(argv, pos, short_template, 1, param);
+       return err;
+}
+
+static void usage(int argc, char **argv)
+{
+       fprintf(stderr, "Usage: %s INPUT_FILE OUTPUT_FILE [OPTIONS]\n", argv[0]);
+       fprintf(stderr, "  -a|--arch ARCH      The architecture type of the input file\n");
+       fprintf(stderr, "  -h|--help           Print this help\n");
+       fprintf(stderr, "  -d|--debug          Print verbose debugging info\n");
+       fprintf(stderr, "                      Repeat for more verbose debugging\n");
+}
+
+int parse_args(int argc, char **argv)
+{
+       int i;
+       int res;
+       char *param;
+
+       infile_name = NULL;
+       outfile_name = NULL;
+
+       for (i = 1; i < argc; i++) {
+               if ((res = cmp_arg(argv, &i, "--help", "-h", 0)) == ARG_MATCH) {
+                       usage(argc, argv);
+                       return 1;
+               } else if ((res = cmp_arg(argv, &i, "--debug", "-d", 0)) == ARG_MATCH) {
+                       _debug++;
+               } else if ((res = cmp_arg(argv, &i, "--arch", "-a", &param)) == ARG_MATCH) {
+                       unsigned long arch;
+                       char *tail;
+
+                       arch = strtol(param, &tail, 0);
+                       if (strlen(tail) || (arch != 5)) {
+                               fprintf(stderr, "Unsupported architecture \"%s\"\n",
+                                       param);
+                               return -1;
+                       }
+                       cmdargs.arch = arch;
+               } else {
+                       if (!infile_name) {
+                               infile_name = argv[i];
+                               continue;
+                       }
+                       if (!outfile_name) {
+                               outfile_name = argv[i];
+                               continue;
+                       }
+                       fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
+                       goto out_usage;
+               }
+       }
+       if (!infile_name || !outfile_name)
+               goto out_usage;
+
+       return 0;
+out_usage:
+       usage(argc, argv);
+       return -1;
+}
+
+int open_input_file(void)
+{
+       if (strcmp(infile_name, "-") == 0) {
+               infile = stdin;
+       } else {
+               infile = fopen(infile_name, "r");
+               if (!infile) {
+                       fprintf(stderr, "Could not open INPUT_FILE %s\n",
+                               infile_name);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+void close_input_file(void)
+{
+       if (strcmp(infile_name, "-") != 0)
+               fclose(infile);
+}
+
+int open_output_file(void)
+{
+       if (strcmp(outfile_name, "-") == 0) {
+               outfile = stdout;
+       } else {
+               outfile = fopen(outfile_name, "w+");
+               if (!outfile) {
+                       fprintf(stderr, "Could not open OUTPUT_FILE %s\n",
+                               outfile_name);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+void close_output_file(void)
+{
+       if (strcmp(outfile_name, "-") != 0)
+               fclose(outfile);
+}
diff --git a/disassembler/args.h b/disassembler/args.h
new file mode 100644 (file)
index 0000000..d13fa66
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef B43_DASM_ARGS_H_
+#define B43_DASM_ARGS_H_
+
+struct cmdline_args {
+       unsigned int arch;
+};
+
+int parse_args(int argc, char **argv);
+
+int open_input_file(void);
+void close_input_file(void);
+int open_output_file(void);
+void close_output_file(void);
+
+extern int _debug;
+extern struct cmdline_args cmdargs;
+
+#define IS_DEBUG               (_debug > 0)
+#define IS_VERBOSE_DEBUG       (_debug > 1)
+#define IS_INSANE_DEBUG                (_debug > 2)
+
+#endif /* B43_DASM_ARGS_H_ */
diff --git a/disassembler/b43-dasm b/disassembler/b43-dasm
deleted file mode 100755 (executable)
index be48c71..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-installed=0
-
-if [ $# -ne 2 ]; then
-       echo "Usage: $0 input_file.fw output_file.asm"
-       exit 1
-fi
-
-if [ -z "$B43_DASM" ]; then
-       if [ $installed -eq 0 ] && [ -x "./b43-dasm.bin" ]; then
-               B43_DASM="./b43-dasm.bin"
-       else
-               B43_DASM="b43-dasm.bin"
-       fi
-fi
-
-infile="$1"
-outfile="$2"
-
-cat "$infile" | $B43_DASM "$outfile"
-
index e984480ebedce68de9ae477c2672021c65e59aa7..8ae804077b7055552788cac7fffd80a346a0b958 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "list.h"
 #include "util.h"
+#include "args.h"
 
 #include <stdio.h>
 #include <stdint.h>
@@ -64,6 +65,9 @@ struct statement {
 };
 
 struct disassembler_context {
+       /* The architecture of the input file. */
+       unsigned int arch;
+
        struct bin_instruction *code;
        size_t nr_insns;
 
@@ -71,7 +75,9 @@ struct disassembler_context {
 };
 
 
-static FILE *infile;
+FILE *infile;
+FILE *outfile;
+const char *infile_name;
 const char *outfile_name;
 
 
@@ -635,48 +641,46 @@ static void resolve_labels(struct disassembler_context *ctx)
 static void emit_asm(struct disassembler_context *ctx)
 {
        struct statement *stmt;
-       FILE *fd;
        int first, i;
+       int err;
 
-       fd = fopen(outfile_name, "w+");
-       if (!fd) {
-               fprintf(stderr, "Could not open output file \"%s\"\n",
-                       outfile_name);
+       err = open_output_file();
+       if (err)
                exit(1);
-       }
-       /* FIXME: We currently only support v5 architecture. */
-       fprintf(fd, "%%arch 5\n\n");
+
+       fprintf(outfile, "%%arch %u\n\n", ctx->arch);
        list_for_each_entry(stmt, &ctx->stmt_list, list) {
                switch (stmt->type) {
                case STMT_INSN:
-                       fprintf(fd, "\t%s", stmt->u.insn.name);
+                       fprintf(outfile, "\t%s", stmt->u.insn.name);
                        first = 1;
                        for (i = 0; i < ARRAY_SIZE(stmt->u.insn.operands); i++) {
                                if (stmt->u.insn.is_labelref == i) {
-                                       fprintf(fd, ",%s",
+                                       fprintf(outfile, ",%s",
                                                stmt->u.insn.labelref->u.label.name);
                                }
                                if (!stmt->u.insn.operands[i])
                                        continue;
                                if (first)
-                                       fprintf(fd, "\t");
+                                       fprintf(outfile, "\t");
                                if (!first)
-                                       fprintf(fd, ",");
+                                       fprintf(outfile, ",");
                                first = 0;
-                               fprintf(fd, "%s",
+                               fprintf(outfile, "%s",
                                        stmt->u.insn.operands[i]);
                        }
-                       fprintf(fd, "\n");
+                       fprintf(outfile, "\n");
                        break;
                case STMT_LABEL:
-                       fprintf(fd, "%s:\n", stmt->u.label.name);
+                       fprintf(outfile, "%s:\n", stmt->u.label.name);
                        break;
                }
        }
-       fclose(fd);
+
+       close_output_file();
 }
 
-static void read_input(struct disassembler_context *ctx)
+static int read_input(struct disassembler_context *ctx)
 {
        size_t size = 0, pos = 0;
        size_t ret;
@@ -684,21 +688,24 @@ static void read_input(struct disassembler_context *ctx)
        unsigned char tmp[sizeof(uint64_t)];
        uint64_t codeword;
        struct fw_header hdr;
+       int err;
+
+       err = open_input_file();
+       if (err)
+               goto error;
 
        ret = fread(&hdr, 1, sizeof(hdr), infile);
-       if (!ret || ret != sizeof(hdr)) {
+       if (ret != sizeof(hdr)) {
                fprintf(stderr, "Corrupt input file (not fwcutter output)\n");
-               exit(1);
-       }       
-
-       if (hdr.ver != 1) {
-               fprintf(stderr, "Invalid fwcutter header version\n");
-               exit(1);
+               goto err_close;
        }
-
        if (hdr.type != 'u') {
-               fprintf(stderr, "Not a microcode image\n");
-               exit(1);
+               fprintf(stderr, "Corrupt input file. Not a microcode image.\n");
+               goto err_close;
+       }
+       if (hdr.ver != 1) {
+               fprintf(stderr, "Invalid input file header version.\n");
+               goto err_close;
        }
 
        while (1) {
@@ -711,7 +718,7 @@ static void read_input(struct disassembler_context *ctx)
                        break;
                if (ret != sizeof(uint64_t)) {
                        fprintf(stderr, "Corrupt input file (not 8 byte aligned)\n");
-                       exit(1);
+                       goto err_free_code;
                }
 
                codeword = 0;
@@ -735,41 +742,50 @@ static void read_input(struct disassembler_context *ctx)
 
        ctx->code = code;
        ctx->nr_insns = pos;
+
+       close_input_file();
+
+       return 0;
+
+err_free_code:
+       free(code);
+err_close:
+       close_input_file();
+error:
+       return -1;
 }
 
 static void disassemble(void)
 {
        struct disassembler_context ctx;
+       int err;
 
        memset(&ctx, 0, sizeof(ctx));
        INIT_LIST_HEAD(&ctx.stmt_list);
+       ctx.arch = cmdargs.arch;
 
-       read_input(&ctx);
+       err = read_input(&ctx);
+       if (err)
+               exit(1);
        disasm_opcodes(&ctx);
        resolve_labels(&ctx);
        emit_asm(&ctx);
 }
 
-static void usage(int argc, char **argv)
-{
-       fprintf(stderr, "Usage: %s output_file\n", argv[0]);
-}
-
-static void parse_args(int argc, char **argv)
-{
-       if (argc != 2) {
-               usage(argc, argv);
-               exit(1);
-       }
-       outfile_name = argv[1];
-}
-
 int main(int argc, char **argv)
 {
-       infile = stdin;
-       parse_args(argc, argv);
+       int err, res = 1;
+
+       err = parse_args(argc, argv);
+       if (err < 0)
+               goto out;
+       if (err > 0) {
+               res = 0;
+               goto out;
+       }
        disassemble();
-
+       res = 0;
+out:
        /* Lazyman simply leaks all allocated memory. */
-       return 0;
+       return res;
 }
diff --git a/disassembler/main.h b/disassembler/main.h
new file mode 100644 (file)
index 0000000..d3ceb37
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef B43_DASM_MAIN_H_
+#define B43_DASM_MAIN_H_
+
+#include <stdio.h>
+
+
+FILE *infile;
+FILE *outfile;
+const char *infile_name;
+const char *outfile_name;
+
+#endif /* B43_DASM_MAIN_H_ */