123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032 |
- /*
- * Copyright (C) 2006-2010 Michael Buesch <m@bues.ch>
- *
- * 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 "main.h"
- #include "list.h"
- #include "util.h"
- #include "args.h"
- #include <stdio.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- struct bin_instruction {
- unsigned int opcode;
- unsigned int operands[3];
- };
- struct statement {
- enum {
- STMT_INSN,
- STMT_LABEL,
- } type;
- union {
- struct {
- struct bin_instruction *bin;
- const char *name;
- const char *operands[5];
- int labelref_operand;
- unsigned int labeladdr;
- struct statement *labelref;
- } insn;
- struct {
- char *name;
- } label;
- } u;
- struct list_head list;
- };
- struct disassembler_context {
- /* The architecture of the input file. */
- unsigned int arch;
- struct bin_instruction *code;
- size_t nr_insns;
- struct list_head stmt_list;
- };
- FILE *infile;
- FILE *outfile;
- const char *infile_name;
- const char *outfile_name;
- #define _msg_helper(type, msg, x...) do { \
- fprintf(stderr, "Disassembler " type \
- ":\n " msg "\n" ,##x); \
- } while (0)
- #define dasm_error(msg, x...) do { \
- _msg_helper("ERROR", msg ,##x); \
- exit(1); \
- } while (0)
- #define dasm_int_error(msg, x...) \
- dasm_error("Internal error (bug): " msg ,##x)
- #define dasm_warn(msg, x...) \
- _msg_helper("warning", msg ,##x)
- #define asm_info(msg, x...) \
- _msg_helper("info", msg ,##x)
- static const char * gen_raw_code(unsigned int operand)
- {
- char *ret;
- ret = xmalloc(6);
- snprintf(ret, 6, "@%X", operand);
- return ret;
- }
- static const char * disasm_mem_operand(unsigned int operand)
- {
- char *ret;
- ret = xmalloc(9);
- snprintf(ret, 9, "[0x%X]", operand);
- return ret;
- }
- static const char * disasm_indirect_mem_operand(unsigned int operand)
- {
- char *ret;
- unsigned int offset, reg;
- switch (cmdargs.arch) {
- case 5:
- offset = (operand & 0x3F);
- reg = ((operand >> 6) & 0x7);
- break;
- case 15:
- offset = (operand & 0x7F);
- reg = ((operand >> 7) & 0x7);
- break;
- default:
- dasm_int_error("disasm_indirect_mem_operand invalid arch");
- }
- ret = xmalloc(12);
- snprintf(ret, 12, "[0x%02X,off%u]", offset, reg);
- return ret;
- }
- static const char * disasm_imm_operand(unsigned int operand)
- {
- char *ret;
- unsigned int signmask;
- unsigned int mask;
- switch (cmdargs.arch) {
- case 5:
- signmask = (1 << 9);
- mask = 0x3FF;
- break;
- case 15:
- signmask = (1 << 10);
- mask = 0x7FF;
- break;
- default:
- dasm_int_error("disasm_imm_operand invalid arch");
- }
- operand &= mask;
- ret = xmalloc(7);
- if (operand & signmask)
- operand = (operand | (~mask & 0xFFFF));
- snprintf(ret, 7, "0x%X", operand);
- return ret;
- }
- static const char * disasm_spr_operand(unsigned int operand)
- {
- char *ret;
- unsigned int mask;
- switch (cmdargs.arch) {
- case 5:
- mask = 0x1FF;
- break;
- case 15:
- mask = 0x7FF;
- break;
- default:
- dasm_int_error("disasm_spr_operand invalid arch");
- }
- ret = xmalloc(8);
- snprintf(ret, 8, "spr%X", (operand & mask));
- return ret;
- }
- static const char * disasm_gpr_operand(unsigned int operand)
- {
- char *ret;
- unsigned int mask;
- switch (cmdargs.arch) {
- case 5:
- mask = 0x3F;
- break;
- case 15:
- mask = 0x7F;
- break;
- default:
- dasm_int_error("disasm_gpr_operand invalid arch");
- }
- ret = xmalloc(5);
- snprintf(ret, 5, "r%u", (operand & mask));
- return ret;
- }
- static void disasm_raw_operand(struct statement *stmt,
- int oper_idx,
- int out_idx)
- {
- unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
- stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
- }
- static void disasm_std_operand(struct statement *stmt,
- int oper_idx,
- int out_idx)
- {
- unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
- switch (cmdargs.arch) {
- case 5:
- if (!(operand & 0x800)) {
- stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
- return;
- } else if ((operand & 0xC00) == 0xC00) {
- stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
- return;
- } else if ((operand & 0xFC0) == 0xBC0) {
- stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
- return;
- } else if ((operand & 0xE00) == 0x800) {
- stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
- return;
- } else if ((operand & 0xE00) == 0xA00) {
- stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
- return;
- }
- break;
- case 15:
- if (!(operand & 0x1000)) {
- stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
- return;
- } else if ((operand & 0x1800) == 0x1800) {
- stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
- return;
- } else if ((operand & 0x1F80) == 0x1780) {
- stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
- return;
- } else if ((operand & 0x1C00) == 0x1000) {
- stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
- return;
- } else if ((operand & 0x1C00) == 0x1400) {
- stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
- return;
- }
- break;
- default:
- dasm_int_error("disasm_std_operand invalid arch");
- }
- /* No luck. Disassemble to raw operand. */
- disasm_raw_operand(stmt, oper_idx, out_idx);
- }
- static void disasm_opcode_raw(struct disassembler_context *ctx,
- struct statement *stmt,
- int raw_operands)
- {
- stmt->u.insn.name = gen_raw_code(stmt->u.insn.bin->opcode);
- if (raw_operands) {
- disasm_raw_operand(stmt, 0, 0);
- disasm_raw_operand(stmt, 1, 1);
- disasm_raw_operand(stmt, 2, 2);
- } else {
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- }
- }
- static void disasm_constant_opcodes(struct disassembler_context *ctx,
- struct statement *stmt)
- {
- struct bin_instruction *bin = stmt->u.insn.bin;
- switch (bin->opcode) {
- case 0x101:
- stmt->u.insn.name = "mul";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x1C0:
- stmt->u.insn.name = "add";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x1C2:
- stmt->u.insn.name = "add.";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x1C1:
- stmt->u.insn.name = "addc";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x1C3:
- stmt->u.insn.name = "addc.";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x1D0:
- stmt->u.insn.name = "sub";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x1D2:
- stmt->u.insn.name = "sub.";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x1D1:
- stmt->u.insn.name = "subc";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x1D3:
- stmt->u.insn.name = "subc.";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x130:
- stmt->u.insn.name = "sra";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x160:
- stmt->u.insn.name = "or";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x140:
- stmt->u.insn.name = "and";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x170:
- stmt->u.insn.name = "xor";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x120:
- stmt->u.insn.name = "sr";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x110:
- stmt->u.insn.name = "sl";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x1A0:
- stmt->u.insn.name = "rl";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x1B0:
- stmt->u.insn.name = "rr";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x150:
- stmt->u.insn.name = "nand";
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- disasm_std_operand(stmt, 2, 2);
- break;
- case 0x040:
- stmt->u.insn.name = "jand";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case (0x040 | 0x1):
- stmt->u.insn.name = "jnand";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case 0x050:
- stmt->u.insn.name = "js";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case (0x050 | 0x1):
- stmt->u.insn.name = "jns";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case 0x0D0:
- stmt->u.insn.name = "je";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case (0x0D0 | 0x1):
- stmt->u.insn.name = "jne";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case 0x0D2:
- stmt->u.insn.name = "jls";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case (0x0D2 | 0x1):
- stmt->u.insn.name = "jges";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case 0x0D4:
- stmt->u.insn.name = "jgs";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case (0x0D4 | 0x1):
- stmt->u.insn.name = "jles";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case 0x0D6:
- stmt->u.insn.name = "jdn";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case (0x0D6 | 0x1):
- stmt->u.insn.name = "jdpz";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case 0x0D8:
- stmt->u.insn.name = "jdp";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case (0x0D8 | 0x1):
- stmt->u.insn.name = "jdnz";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case 0x0DA:
- stmt->u.insn.name = "jl";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case (0x0DA | 0x1):
- stmt->u.insn.name = "jge";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case 0x0DC:
- stmt->u.insn.name = "jg";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case (0x0DC | 0x1):
- stmt->u.insn.name = "jle";
- stmt->u.insn.labelref_operand = 2;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 1, 1);
- break;
- case 0x002: {
- char *str;
- switch (cmdargs.arch) {
- case 5:
- stmt->u.insn.name = "call";
- stmt->u.insn.labelref_operand = 1;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- str = xmalloc(4);
- snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
- stmt->u.insn.operands[0] = str;
- break;
- case 15:
- //FIXME: This opcode is different on r15. Decode raw for now.
- disasm_opcode_raw(ctx, stmt, 1);
- break;
- }
- break;
- }
- case 0x003: {
- char *str;
- stmt->u.insn.name = "ret";
- str = xmalloc(4);
- snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
- stmt->u.insn.operands[0] = str;
- str = xmalloc(4);
- snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[2]);
- stmt->u.insn.operands[2] = str;
- break;
- }
- case 0x004: {
- if (cmdargs.arch != 15) {
- dasm_error("arch 15 'calls' instruction found in arch %d binary",
- cmdargs.arch);
- }
- stmt->u.insn.name = "calls";
- stmt->u.insn.labelref_operand = 0;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- if (stmt->u.insn.bin->operands[0] != 0x1780 ||
- stmt->u.insn.bin->operands[1] != 0x1780)
- dasm_warn("r15 calls: Invalid first or second argument");
- break;
- }
- case 0x005: {
- if (cmdargs.arch != 15) {
- dasm_error("arch 15 'rets' instruction found in arch %d binary",
- cmdargs.arch);
- }
- stmt->u.insn.name = "rets";
- if (stmt->u.insn.bin->operands[0] != 0x1780 ||
- stmt->u.insn.bin->operands[1] != 0x1780 ||
- stmt->u.insn.bin->operands[2] != 0)
- dasm_warn("r15 rets: Invalid argument(s)");
- break;
- }
- case 0x1E0: {
- unsigned int flags, mask;
- switch (cmdargs.arch) {
- case 5:
- mask = 0x3FF;
- break;
- case 15:
- mask = 0x7FF;
- break;
- default:
- dasm_int_error("TKIP invalid arch");
- }
- flags = stmt->u.insn.bin->operands[1];
- switch (flags & mask) {
- case 0x1:
- stmt->u.insn.name = "tkiph";
- break;
- case (0x1 | 0x2):
- stmt->u.insn.name = "tkiphs";
- break;
- case 0x0:
- stmt->u.insn.name = "tkipl";
- break;
- case (0x0 | 0x2):
- stmt->u.insn.name = "tkipls";
- break;
- default:
- dasm_error("Invalid TKIP flags %X", flags);
- }
- disasm_std_operand(stmt, 0, 0);
- disasm_std_operand(stmt, 2, 2);
- break;
- }
- case 0x001: {
- unsigned int mask;
- stmt->u.insn.name = "nap";
- switch (cmdargs.arch) {
- case 5:
- mask = 0xBC0;
- break;
- case 15:
- mask = 0x1780;
- break;
- default:
- dasm_int_error("NAP invalid arch");
- }
- if (stmt->u.insn.bin->operands[0] != mask) {
- dasm_warn("NAP: invalid first argument 0x%04X\n",
- stmt->u.insn.bin->operands[0]);
- }
- if (stmt->u.insn.bin->operands[1] != mask) {
- dasm_warn("NAP: invalid second argument 0x%04X\n",
- stmt->u.insn.bin->operands[1]);
- }
- if (stmt->u.insn.bin->operands[2] != 0) {
- dasm_warn("NAP: invalid third argument 0x%04X\n",
- stmt->u.insn.bin->operands[2]);
- }
- break;
- }
- case 0x000:
- disasm_opcode_raw(ctx, stmt, 1);
- break;
- default:
- disasm_opcode_raw(ctx, stmt, (cmdargs.unknown_decode == 0));
- break;
- }
- }
- static void disasm_opcodes(struct disassembler_context *ctx)
- {
- struct bin_instruction *bin;
- size_t i;
- struct statement *stmt;
- char *str;
- for (i = 0; i < ctx->nr_insns; i++) {
- bin = &(ctx->code[i]);
- stmt = xmalloc(sizeof(struct statement));
- stmt->type = STMT_INSN;
- INIT_LIST_HEAD(&stmt->list);
- stmt->u.insn.bin = bin;
- stmt->u.insn.labelref_operand = -1; /* none */
- switch (bin->opcode & 0xF00) {
- case 0x200:
- stmt->u.insn.name = "srx";
- str = xmalloc(3);
- snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
- stmt->u.insn.operands[0] = str;
- str = xmalloc(3);
- snprintf(str, 3, "%d", (bin->opcode & 0x00F));
- stmt->u.insn.operands[1] = str;
- disasm_std_operand(stmt, 0, 2);
- disasm_std_operand(stmt, 1, 3);
- disasm_std_operand(stmt, 2, 4);
- break;
- case 0x300:
- stmt->u.insn.name = "orx";
- str = xmalloc(3);
- snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
- stmt->u.insn.operands[0] = str;
- str = xmalloc(3);
- snprintf(str, 3, "%d", (bin->opcode & 0x00F));
- stmt->u.insn.operands[1] = str;
- disasm_std_operand(stmt, 0, 2);
- disasm_std_operand(stmt, 1, 3);
- disasm_std_operand(stmt, 2, 4);
- break;
- case 0x400:
- stmt->u.insn.name = "jzx";
- str = xmalloc(3);
- snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
- stmt->u.insn.operands[0] = str;
- str = xmalloc(3);
- snprintf(str, 3, "%d", (bin->opcode & 0x00F));
- stmt->u.insn.operands[1] = str;
- disasm_std_operand(stmt, 0, 2);
- disasm_std_operand(stmt, 1, 3);
- stmt->u.insn.labelref_operand = 4;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- break;
- case 0x500:
- stmt->u.insn.name = "jnzx";
- str = xmalloc(3);
- snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
- stmt->u.insn.operands[0] = str;
- str = xmalloc(3);
- snprintf(str, 3, "%d", (bin->opcode & 0x00F));
- stmt->u.insn.operands[1] = str;
- disasm_std_operand(stmt, 0, 2);
- disasm_std_operand(stmt, 1, 3);
- stmt->u.insn.labelref_operand = 4;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- break;
- case 0x600:
- stmt->u.insn.name = "jnext";
- str = xmalloc(5);
- snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
- stmt->u.insn.operands[0] = str;
- /* We don't disassemble the first and second operand, as
- * that always is a dummy r0 operand.
- * disasm_std_operand(stmt, 0, 1);
- * disasm_std_operand(stmt, 1, 2);
- * stmt->u.insn.labelref_operand = 3;
- */
- stmt->u.insn.labelref_operand = 1;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- break;
- case 0x700:
- stmt->u.insn.name = "jext";
- str = xmalloc(5);
- snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
- stmt->u.insn.operands[0] = str;
- /* We don't disassemble the first and second operand, as
- * that always is a dummy r0 operand.
- * disasm_std_operand(stmt, 0, 1);
- * disasm_std_operand(stmt, 1, 2);
- * stmt->u.insn.labelref_operand = 3;
- */
- stmt->u.insn.labelref_operand = 1;
- stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
- break;
- default:
- disasm_constant_opcodes(ctx, stmt);
- break;
- }
- list_add_tail(&stmt->list, &ctx->stmt_list);
- }
- }
- static struct statement * get_label_at(struct disassembler_context *ctx,
- unsigned int addr)
- {
- unsigned int addrcnt = 0;
- struct statement *stmt, *ret, *prev;
- list_for_each_entry(stmt, &ctx->stmt_list, list) {
- if (stmt->type != STMT_INSN)
- continue;
- if (addrcnt == addr) {
- prev = list_entry(stmt->list.prev, struct statement, list);
- if (prev->type == STMT_LABEL)
- return prev;
- ret = xmalloc(sizeof(struct statement));
- INIT_LIST_HEAD(&ret->list);
- ret->type = STMT_LABEL;
- list_add(&ret->list, &prev->list);
- return ret;
- }
- addrcnt++;
- }
- return NULL;
- }
- static void resolve_labels(struct disassembler_context *ctx)
- {
- struct statement *stmt;
- struct statement *label;
- struct statement *n;
- unsigned int labeladdr;
- unsigned int namecnt = 0;
- /* Resolve label references */
- list_for_each_entry_safe(stmt, n, &ctx->stmt_list, list) {
- if (stmt->type != STMT_INSN)
- continue;
- if (stmt->u.insn.labelref_operand < 0)
- continue; /* Doesn't have label reference operand. */
- labeladdr = stmt->u.insn.labeladdr;
- label = get_label_at(ctx, labeladdr);
- if (!label)
- dasm_error("Labeladdress %X out of bounds", labeladdr);
- stmt->u.insn.labelref = label;
- }
- /* Name the labels */
- list_for_each_entry(stmt, &ctx->stmt_list, list) {
- if (stmt->type != STMT_LABEL)
- continue;
- stmt->u.label.name = xmalloc(20);
- snprintf(stmt->u.label.name, 20, "L%u", namecnt);
- namecnt++;
- }
- }
- static void emit_asm(struct disassembler_context *ctx)
- {
- struct statement *stmt;
- int first;
- int err;
- unsigned int i, addr = 0;
- err = open_output_file();
- if (err)
- exit(1);
- fprintf(outfile, "%%arch %u\n", ctx->arch);
- fprintf(outfile, "%%start entry\n\n");
- fprintf(outfile, "entry:\n");
- list_for_each_entry(stmt, &ctx->stmt_list, list) {
- switch (stmt->type) {
- case STMT_INSN:
- if (cmdargs.print_addresses)
- fprintf(outfile, "/* %04X */", 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.operands[i] &&
- (stmt->u.insn.labelref_operand < 0 ||
- (unsigned int)stmt->u.insn.labelref_operand != i))
- continue;
- if (first)
- fprintf(outfile, "\t");
- if (!first)
- fprintf(outfile, ", ");
- first = 0;
- if (stmt->u.insn.labelref_operand >= 0 &&
- (unsigned int)stmt->u.insn.labelref_operand == i) {
- fprintf(outfile, "%s",
- stmt->u.insn.labelref->u.label.name);
- } else {
- fprintf(outfile, "%s",
- stmt->u.insn.operands[i]);
- }
- }
- fprintf(outfile, "\n");
- addr++;
- break;
- case STMT_LABEL:
- fprintf(outfile, "%s:\n", stmt->u.label.name);
- break;
- }
- }
- close_output_file();
- }
- static int read_input(struct disassembler_context *ctx)
- {
- size_t size = 0, pos = 0;
- size_t ret;
- struct bin_instruction *code = NULL;
- unsigned char tmp[sizeof(uint64_t)];
- uint64_t codeword = 0;
- struct fw_header hdr;
- int err;
- err = open_input_file();
- if (err)
- goto error;
- switch (cmdargs.informat) {
- case FMT_RAW_LE32:
- case FMT_RAW_BE32:
- /* Nothing */
- break;
- case FMT_B43:
- ret = fread(&hdr, 1, sizeof(hdr), infile);
- if (ret != sizeof(hdr)) {
- fprintf(stderr, "Corrupt input file (no b43 header found)\n");
- goto err_close;
- }
- if (hdr.type != FW_TYPE_UCODE) {
- fprintf(stderr, "Corrupt input file. Not a b43 microcode image.\n");
- goto err_close;
- }
- if (hdr.ver != FW_HDR_VER) {
- fprintf(stderr, "Invalid input file header version.\n");
- goto err_close;
- }
- break;
- }
- while (1) {
- if (pos >= size) {
- size += 512;
- code = xrealloc(code, size * sizeof(struct bin_instruction));
- }
- ret = fread(tmp, 1, sizeof(uint64_t), infile);
- if (!ret)
- break;
- if (ret != sizeof(uint64_t)) {
- fprintf(stderr, "Corrupt input file (not 8 byte aligned)\n");
- goto err_free_code;
- }
- switch (cmdargs.informat) {
- case FMT_B43:
- case FMT_RAW_BE32:
- codeword = 0;
- codeword |= ((uint64_t)tmp[0]) << 56;
- codeword |= ((uint64_t)tmp[1]) << 48;
- codeword |= ((uint64_t)tmp[2]) << 40;
- codeword |= ((uint64_t)tmp[3]) << 32;
- codeword |= ((uint64_t)tmp[4]) << 24;
- codeword |= ((uint64_t)tmp[5]) << 16;
- codeword |= ((uint64_t)tmp[6]) << 8;
- codeword |= ((uint64_t)tmp[7]);
- codeword = ((codeword & (uint64_t)0xFFFFFFFF00000000ULL) >> 32) |
- ((codeword & (uint64_t)0x00000000FFFFFFFFULL) << 32);
- break;
- case FMT_RAW_LE32:
- codeword = 0;
- codeword |= ((uint64_t)tmp[7]) << 56;
- codeword |= ((uint64_t)tmp[6]) << 48;
- codeword |= ((uint64_t)tmp[5]) << 40;
- codeword |= ((uint64_t)tmp[4]) << 32;
- codeword |= ((uint64_t)tmp[3]) << 24;
- codeword |= ((uint64_t)tmp[2]) << 16;
- codeword |= ((uint64_t)tmp[1]) << 8;
- codeword |= ((uint64_t)tmp[0]);
- break;
- }
- switch (cmdargs.arch) {
- case 5:
- if (codeword >> 48) {
- fprintf(stderr, "Instruction format error at 0x%X (upper not clear). "
- "Wrong input format or architecture?\n", (unsigned int)pos);
- goto err_free_code;
- }
- code[pos].opcode = (codeword >> 36) & 0xFFF;
- code[pos].operands[2] = codeword & 0xFFF;
- code[pos].operands[1] = (codeword >> 12) & 0xFFF;
- code[pos].operands[0] = (codeword >> 24) & 0xFFF;
- break;
- case 15:
- if (codeword >> 51) {
- fprintf(stderr, "Instruction format error at 0x%X (upper not clear). "
- "Wrong input format or architecture?\n", (unsigned int)pos);
- goto err_free_code;
- }
- code[pos].opcode = (codeword >> 39) & 0xFFF;
- code[pos].operands[2] = codeword & 0x1FFF;
- code[pos].operands[1] = (codeword >> 13) & 0x1FFF;
- code[pos].operands[0] = (codeword >> 26) & 0x1FFF;
- break;
- default:
- fprintf(stderr, "Internal error: read_input unknown arch %u\n",
- cmdargs.arch);
- goto err_free_code;
- }
- pos++;
- }
- 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;
- err = read_input(&ctx);
- if (err)
- exit(1);
- disasm_opcodes(&ctx);
- resolve_labels(&ctx);
- emit_asm(&ctx);
- }
- int main(int argc, char **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 res;
- }
|