* GNU General Public License for more details.
*/
+#include "main.h"
#include "list.h"
#include "util.h"
+#include "args.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
-/* The header that fwcutter puts in to every .fw file */
-struct fw_header {
- /* Type of the firmware data */
- uint8_t type;
- /* Version number of the firmware data format */
- uint8_t ver;
- uint8_t __padding[2];
- /* Size of the data. For ucode and PCM this is in bytes.
- * For IV this is in number-of-ivs. */
- uint32_t size;
-} __attribute__ ((__packed__));
-
struct bin_instruction {
unsigned int opcode;
};
struct disassembler_context {
+ /* The architecture of the input file. */
+ unsigned int arch;
+
struct bin_instruction *code;
size_t nr_insns;
};
-static FILE *infile;
+FILE *infile;
+FILE *outfile;
+const char *infile_name;
const char *outfile_name;
snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
stmt->u.insn.operands[0] = str;
- disasm_std_operand(stmt, 0, 1, 0);
- disasm_std_operand(stmt, 1, 2, 0);
- stmt->u.insn.is_labelref = 3;
+ /* We don't disassemble the first and second operand, as
+ * that always is a dummy r0 operand.
+ * disasm_std_operand(stmt, 0, 1, 0);
+ * disasm_std_operand(stmt, 1, 2, 0);
+ * stmt->u.insn.is_labelref = 3;
+ */
+ stmt->u.insn.is_labelref = 1;
stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
break;
case 0x700:
snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
stmt->u.insn.operands[0] = str;
- disasm_std_operand(stmt, 0, 1, 0);
- disasm_std_operand(stmt, 1, 2, 0);
- stmt->u.insn.is_labelref = 3;
+ /* We don't disassemble the first and second operand, as
+ * that always is a dummy r0 operand.
+ * disasm_std_operand(stmt, 0, 1, 0);
+ * disasm_std_operand(stmt, 1, 2, 0);
+ * stmt->u.insn.is_labelref = 3;
+ */
+ stmt->u.insn.is_labelref = 1;
stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
break;
default:
static void emit_asm(struct disassembler_context *ctx)
{
struct statement *stmt;
- FILE *fd;
int first, i;
+ int err;
+ unsigned int addr = 0;
- 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);
+ if (cmdargs.print_addresses)
+ fprintf(outfile, "/* %03X */", addr);
+ 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");
+ addr++;
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;
unsigned char tmp[sizeof(uint64_t)];
uint64_t codeword;
struct fw_header hdr;
+ int err;
- ret = fread(&hdr, 1, sizeof(hdr), infile);
- if (!ret || 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);
- }
+ err = open_input_file();
+ if (err)
+ goto error;
- if (hdr.type != 'u') {
- fprintf(stderr, "Not a microcode image\n");
- exit(1);
+ if (!cmdargs.no_header) {
+ ret = fread(&hdr, 1, sizeof(hdr), infile);
+ if (ret != sizeof(hdr)) {
+ fprintf(stderr, "Corrupt input file (not fwcutter output)\n");
+ goto err_close;
+ }
+ if (hdr.type != FW_TYPE_UCODE) {
+ fprintf(stderr, "Corrupt input file. Not a microcode image.\n");
+ goto err_close;
+ }
+ if (hdr.ver != FW_HDR_VER) {
+ fprintf(stderr, "Invalid input file header version.\n");
+ goto err_close;
+ }
}
while (1) {
break;
if (ret != sizeof(uint64_t)) {
fprintf(stderr, "Corrupt input file (not 8 byte aligned)\n");
- exit(1);
+ goto err_free_code;
}
codeword = 0;
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;
}