📄 disass.c
字号:
/* * disass.c - single instruction disassembler * Copyright (C) ARM Limited, 1991-1998. All rights reserved. *//* * RCS $Revision: 1.1 $ * Checkin $Date: 1999/03/11 11:53:37 $ * Revising $Author: rivimey $ */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>/* #include "host.h" */#include "disass.h"#include "distool.h"/* ---------------- Local variables ---------------------- */static char const **regnames, **fregnames;static dis_cb *cb_proc;static void *cb_arg;char const *hexprefix = "0x";void Dis_AddNote(char *notes, char const *fmt, ...) { va_list ap; va_start(ap, fmt); if (notes[0] != 0) { notes += strlen(notes); strcpy(notes, ", "); notes += 2; } _vsprintf(notes, fmt, ap); va_end(ap);}void Dis_CheckValue(unsigned32 field, unsigned32 val, char const *s, char *notes) { if (field != val) Dis_AddNote(notes, "%s = %s%lx", s, hexprefix, field);}void Dis_CheckZero(unsigned32 field, char const *s, char *notes) { Dis_CheckValue(field, 0, s, notes);}char *Dis_OutF(char *o, char const *fmt, ...) { va_list ap; va_start(ap, fmt); _vsprintf(o, fmt, ap); va_end(ap); return o + strlen(o);}char *Dis_OutS(const char *s, char *o) { /* All strings are very short: no point to any cleverness which a library strcpy might give us. */ char ch; for (; (ch = *s++) != 0;) o = Dis_OutC(ch, o); return o;}char *Dis_cond(unsigned32 instr, char *o) { const char *ccnames = "EQ\0\0NE\0\0CS\0\0CC\0\0MI\0\0PL\0\0VS\0\0VC\0\0\HI\0\0LS\0\0GE\0\0LT\0\0GT\0\0LE\0\0\0\0\0\0NV"; return Dis_OutS(ccnames+4*(int)bits(28,31), o);}char *Dis_ArmReg(unsigned32 rno, int ch, char *o) { if (regnames == NULL) if (rno == 15) o = Dis_OutS("pc", o); else o = Dis_OutF(o, "r%ld", rno); else o = Dis_OutS(regnames[rno], o); if (ch != 0) o = Dis_OutC(ch, o); return o;}static char *FP_Reg(unsigned32 rno, int ch, char *o) { if (fregnames == NULL) o = Dis_OutF(o, "f%ld", rno); else o = Dis_OutS(fregnames[rno], o); if (ch != 0) o = Dis_OutC(ch, o); return o;}static char *shiftedreg(unsigned32 instr, char *o) { const char *shiftname = "LSL\0LSR\0ASR\0ROR" + 4*(int)bits(5,6); o = Dis_ArmReg(bits(0,3), 0, o); /* offset is a (shifted) reg */ if (bit(4)) { /* register shift */ o = Dis_OutF(o, ",%s ", shiftname); o = Dis_ArmReg(bits(8,11), 0, o); } else if (bits(5,11)!=0) { /* immediate shift */ if (bits(5,11)==3) o = Dis_OutS(",RRX", o); else { o = Dis_OutF(o, ",%s ", shiftname); if (bits(5,11)==1 || bits(5,11)==2) o = Dis_OutI(32L, o); else o = Dis_OutI(bits(7,11), o); } } return o;}static char *outn(unsigned32 n, unsigned32 pos, char *o){ if (!pos) o = Dis_OutC('-', o); if (n < 10) o = Dis_OutF(o, "%ld", n); else o = Dis_OutX(n, o); return o;}static char *outh(unsigned32 n, unsigned32 pos, char *o) { o = Dis_OutC('#', o); o = outn(n, pos, o); return o;}char *Dis_spacetocol9(char *start, char *o) { /* Ensure at least one space output */ int k = 9 - (o - start); do o = Dis_OutC(' ', o); while (--k > 0); return o;}static char *t_opcode(const char *op, char *o){ char *start = o; o = Dis_OutS(op, o); return Dis_spacetocol9(start, o);}char *Dis_ArmOpCode(unsigned32 instr, const char *op, int ch, char *o) { char *start = o; o = Dis_OutS(op, o); o = Dis_cond(instr, o); if (ch != 0) o = Dis_OutC(ch, o); return Dis_spacetocol9(start, o);}char *Dis_ArmOpCodeF(char *o, unsigned32 instr, const char *fmt, ...) { /* fmt is of the form "<string>$<printf-format>", where $ is * where to insert the condition code */ va_list ap; char *start = o; const char *dollar; va_start(ap, fmt); dollar = strchr(fmt, '$'); if (dollar == NULL) return Dis_ArmOpCode(instr, fmt, 0, o); memcpy(o, fmt, dollar-fmt); /* copy part of string */ o = Dis_cond(instr, o + (dollar-fmt)); _vsprintf(o, dollar+1, ap); va_end(ap); return Dis_spacetocol9(start, o+strlen(o));}static char *ArmOutAddress( unsigned32 instr, unsigned32 address, int32 offset, int w, char *o, bool fromCPDT) { char *oldo = o; if (bits(16,19)==15 && bit(24) && !bit(25)) { /* pc based, pre, imm */ if (!bit(23)) offset = -offset; address = address+offset+8; if (cb_proc != NULL) o = cb_proc((bit(20) ? D_LOADPCREL : D_STOREPCREL), offset, address, w, cb_arg, o); if (oldo == o) o = Dis_OutX(address, o); } else { if (bit(24) && !bit(25) && cb_proc != NULL) /* pre, imm */ o = cb_proc((bit(20) ? D_LOAD : D_STORE), (bit(23) ? offset : -offset), bits(16,19), w, cb_arg, o); if (oldo == o) { o = Dis_OutC('[', o); o = Dis_ArmReg(bits(16,19), (bit(24) ? 0 : ']'), o); o = Dis_OutC(',', o); if (!bit(25)) { /* offset is an immediate */ /* there's a special case for CPDT's of the 'options' field */ if (fromCPDT && !bit(24) && !bit(21) && bit(23)) { o = Dis_OutC('{', o); o = outn(offset/4, bit(23), o); o = Dis_OutC('}', o); } else { o = outh(offset, bit(23), o); } } else { if (!bit(23)) o = Dis_OutC('-', o); o = shiftedreg(instr, o); } if (bit(24)) { o = Dis_OutC(']', o); if (bit(21)) o = Dis_OutC('!', o); } } } return o;}char *Dis_ArmOutAddress(unsigned32 instr, unsigned32 address, int32 offset, int w, char *o){ return ArmOutAddress(instr, address, offset, w, o, FALSE);}static char *outregset(unsigned32 instr, char *o) { bool started = NO, string = NO; unsigned32 i, first = 0, last = 0; o = Dis_OutC('{', o); for (i=0; i<16; i++) { if (bit(i)) { if (!started) { o = Dis_ArmReg(i, 0, o); started=YES; first=last=i; } else if (i==last+1) { string=YES; last=i; } else { if (i>last+1 && string) { o = Dis_OutC((first == last-1) ? ',' : '-', o); o = Dis_ArmReg(last, 0, o); string=NO; } o = Dis_OutC(',', o); o = Dis_ArmReg(i, 0, o); first=last=i; } } } if (string) { o = Dis_OutC((first == last-1) ? ',' : '-', o); o = Dis_ArmReg(last, 0, o); } o = Dis_OutC('}', o); return o;}static char *generic_cpdo(int cpno, unsigned32 instr, char *o) { o = Dis_ArmOpCode(instr, "CDP", 0, o); o = Dis_OutF(o, "p%d,", cpno); o = Dis_OutX(bits(20,23), o); o = Dis_OutC(',', o); o = Dis_OutF(o, "c%ld,", bits(12,15)); /* CRd */ o = Dis_OutF(o, "c%ld,", bits(16,19)); /* CRn */ o = Dis_OutF(o, "c%ld,", bits(0,3)); /* CRm */ o = Dis_OutF(o, "%ld", bits(5,7)); return o;}static char *generic_cprt(int cpno, unsigned32 instr, char *o) { o = Dis_ArmOpCode(instr, (bit(20) ? "MRC" : "MCR"), 0, o); o = Dis_OutF(o, "p%d,", cpno); o = Dis_OutX(bits(21,23), o); o = Dis_OutC(',', o); o = Dis_ArmReg(bits(12,15), ',', o); o = Dis_OutF(o, "c%ld,", bits(16,19)); /* CRn */ o = Dis_OutF(o, "c%ld,", bits(0,3)); /* CRm */ o = Dis_OutF(o, "%ld", bits(5,7)); return o;}static char *generic_cpdt(int cpno, unsigned32 instr, unsigned32 address, char *o, char *notes) { o = Dis_ArmOpCode(instr, (bit(20) ? "LDC" : "STC"), (bit(22) ? 'L' : 0), o); o = Dis_OutF(o, "p%d,", cpno); o = Dis_OutF(o, "c%ld,", bits(12,15)); if (!bit(24) && !bit(21)) { if (bit(23)) { } else Dis_AddNote(notes, "Postindexed, Down, no WB"); } return ArmOutAddress(instr, address, 4*bits(0,7), 0, o, TRUE);}static char *HandleGenericCoPro(int cpno, Disass_CPOpType type, unsigned32 instr, unsigned32 address, char *o, char *notes) { IGNORE(notes); switch (type) { case CP_DP: return generic_cpdo(cpno, instr, o); case CP_RT: return generic_cprt(cpno, instr, o); case CP_DT: return generic_cpdt(cpno, instr, address, o, notes); } return NULL; /* can't be reached*/}static char fp_dt_widthname(unsigned32 instr) { return "SDEP"[bit(15) + 2*bit(22)];}static char fp_widthname(unsigned32 instr) { return "SDEP"[bit(7) + 2*bit(19)];}static const char *fp_rounding(unsigned32 instr) { return "\0\0P\0M\0Z" + 2*bits(5,6);}static char *fp_mfield(unsigned32 instr, char *o) { unsigned32 r = bits(0,2); if (bit(3)) { if (r < 6) o = Dis_OutI(r, o); else o = Dis_OutS((r == 6 ? "#0.5" : "#10"), o); } else o = FP_Reg(r, 0, o); return o;}static char *fp_cpdo(unsigned32 instr, char *o, char *notes) { const char *opset; char *start = o; if (bit(15)) /* unary */ opset = "\MVF\0MNF\0ABS\0RND\0SQT\0LOG\0LGN\0EXP\0\SIN\0COS\0TAN\0ASN\0ACS\0ATN\0URD\0NRM"; else opset = "\ADF\0MUF\0SUF\0RSF\0DVF\0RDF\0POW\0RPW\0\RMF\0FML\0FDV\0FRD\0POL\0XX1\0XX2\0XX3"; o = Dis_OutS(opset + 4*bits(20,23), o); o = Dis_cond(instr, o); o = Dis_OutC(fp_widthname(instr), o); o = Dis_OutS(fp_rounding(instr), o); o = Dis_spacetocol9(start, o); o = FP_Reg(bits(12,14), ',', o); /* Fd */ if (!bit(15)) o = FP_Reg(bits(16,18), ',', o); /* Fn */ else if (bits(16,18) != 0) Dis_CheckZero(bits(16,18), "Fn", notes); return fp_mfield(instr, o);}static char *fp_cprt(unsigned32 instr, char *o, char *notes) { int op = (int)bits(20,23); IGNORE(notes); if (bits(12,15)==15) { /* ARM register = pc */ if ((op & 9) != 9) return NULL; /* Invalid: decode as generic */ else op = (op>>1)-4; o = Dis_ArmOpCode(instr, "CMF\0\0CNF\0\0CMFE\0CNFE" + 5*op, 0, o); o = FP_Reg(bits(16,18), ',', o); return fp_mfield(instr, o); } else { char *start = o; if (op > 5) return NULL; o = Dis_OutS("FLT\0FIX\0WFS\0RFS\0WFC\0RFC" + 4*op, o); o = Dis_cond(instr, o); if (op == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -