📄 dsmlib.c
字号:
/* dsmLib.c - ARM disassembler *//* * Copyright 1991-1998 Advanced RISC Machines Ltd. and Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01e,04sep98,cdp make Thumb support dependent on ARM_THUMB.01d,27oct97,kkk took out "***EOF***" line from end of file.01c,10oct97,jpd tidied.01b,19jun97,jpd added Thumb (ARM7TDMI_T) support.01a,15aug96,jpd written, based on 680X0 version 03o and also ARM Ltd.'s disassembler sources*//*This library contains everything necessary to print ARM and Thumbobject code in assembly language format. The disassembly is done innative ARM/Thumb format.The programming interface is via dsmInst(), which prints a single disassembledinstruction, and dsmNbytes(), which reports the size of an instruction.To disassemble from the shell, use l(), which calls thislibrary to do the actual work. See dbgLib() for details.INTERNALThis code is very largely based on the ARM Ltd. disassembler code, and sodoes not conform to the recommended structure for VxWorks disassemblers.INCLUDE FILE: dsmLib.hSEE ALSO: dbgLib.I "ARM Architecture Reference Manual,".I "ARM 7TDMI Data Sheet,".I "ARM 710A Data Sheet,".I "ARM 810 Data Sheet,".I "Digital Semiconductor SA-110 Microprocessor Technical Reference Manual."*/#include "vxWorks.h"#include "dsmLib.h"#include "string.h"#include "stdio.h"#include "errnoLib.h"/* * check that this compiler does sign extension when an int is shifted right * because code below relies on its doing so. */#if (((INT32)-1L) >> 1) > 0# error right shifting an int does not perform sign extension#endif#if (ARM_THUMB)#define INCLUDE_THUMB_DISASM#undef INCLUDE_ARM_DISASM#else#undef INCLUDE_THUMB_DISASM#define INCLUDE_ARM_DISASM#endif/* ---------------- Output Functions --------------------- */#define outc(h) (printf("%c",h))#define outf(f,s) (printf(f,s))#define outi(n) outf("#%ld",(unsigned long)n)#define outx(n) (printf("0x%lx",(unsigned long)n))#define outs(s) (printf("%s", s), (strlen(s)))/* ---------------- Bit twiddlers ------------------------ *//* * The casts to UINT32 in bit() and bits() are redundant, but required by * some buggy compilers. */#define bp(n) (((UINT32)1L<<(n)))#define bit(n) (((UINT32)(instr & bp(n)))>>(n))#define bits(m,n) (((UINT32)(instr & (bp(n)-bp(m)+bp(n))))>>(m))#define ror(n,b) (((n)>>(b))|((n)<<(32-(b)))) /* n right rotated b bits *//********************************************************************************* reg - display register name** RETURNS: N/A** NOMANUAL**/LOCAL void reg ( UINT32 rno, /* register number */ int ch /* char to display after reg, 0 => do nothing */ ) { /* Replace "r15" with "pc" */ if (rno == 15) outs("pc"); else outf("r%d", rno); if (ch != 0) outc(ch); return; } /* reg() *//********************************************************************************* outh - display immediate value in hex** RETURNS: N/A** NOMANUAL**/LOCAL void outh ( UINT32 n, /* number to display */ UINT32 pos /* whether number is positive */ ) { /* ARM assembler immediate values are preceded by '#' */ outc('#'); if (!pos) outc('-'); /* decimal values by default, precede hex values with '0x' */ if (n < 10) outf("%d", n); else outx(n); return; } /* outh() *//********************************************************************************* spacetocol9 - tab to column 9** RETURNS: N/A** NOMANUAL**/LOCAL void spacetocol9 ( int l /* current column position */ ) { for (; l < 9 ; l++) outc(' '); return; } /* spacetocol9() *//********************************************************************************* outregset - display register set of load/store multiple instruction** RETURNS: N/A** NOMANUAL**/LOCAL void outregset ( UINT32 instr /* the value of the instruction */ ) { BOOL started = FALSE, string = FALSE; UINT32 i, first = 0, last = 0; /* display the start of list char */ outc('{'); /* check for presence of each register in list */ for (i = 0; i < 16; i++) { if (bit(i)) { /* register is in list */ if (!started) { /* not currently doing a consecutive list of reg numbers */ reg(i, 0); /* print starting register */ started = TRUE; first = last = i; } else /* currently in a list */ if (i == last+1) { string = TRUE; last = i; } else /* not consecutive */ { if (i > last+1 && string) { outc((first == last-1) ? ',' : '-'); reg(last, 0); string = FALSE; } outc(','); reg(i, 0); first = last = i; } } } /* endfor */ if (string) { outc((first == last-1) ? ',' : '-'); reg(last, 0); } outc('}'); return; } /* outregset() *//********************************************************************************* cond - display condition code of instruction** RETURNS: number of characters written.** NOMANUAL**/LOCAL int cond ( UINT32 instr ) { 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 outs(ccnames+4*(int)bits(28,31)); } /* cond() *//********************************************************************************* opcode - display the opcode of an ARM instruction** This routine is also used in the display of a conditional branch ARM* instruction.** RETURNS: N/A** NOMANUAL**/LOCAL void opcode ( UINT32 instr, /* the value of the instruction */ const char *op, /* the opcode as a string */ char ch /* any additional suffix char 0 => display nothing */ ) { int l; /* display the opcode */ l = outs(op); /* display any condition code */ l += cond(instr); /* display any suffix character */ if (ch != 0) { outc(ch); l++; } /* pad with spaces to column 9 */ spacetocol9(l); return; } /* opcode() */#ifdef INCLUDE_ARM_DISASM/********************************************************************************* freg - display FP register name** RETURNS: N/A** NOMANUAL**/LOCAL void freg ( UINT32 rno, /* register number */ int ch /* char to display after reg, 0 => do nothing */ ) { outf("f%d", rno); if (ch != 0) outc(ch); return; } /* freg() *//********************************************************************************* shiftedreg - display shifted register operand** RETURNS: N/A** NOMANUAL**/LOCAL void shiftedreg ( UINT32 instr ) { char *shiftname = "LSL\0LSR\0ASR\0ROR" + 4*(int)bits(5,6); /* display register name */ reg(bits(0,3), 0); /* offset is a (shifted) reg */ if (bit(4)) { /* register shift */ outf(",%s ", shiftname); reg(bits(8,11), 0); } else if (bits(5,11) != 0) { /* immediate shift */ if (bits(5,11) == 3) outs(",RRX"); else { outf(",%s ", shiftname); if (bits(5,11) == 1 || bits(5,11) == 2) outi(32L); else outi(bits(7,11)); } } return; } /* shiftedreg() *//********************************************************************************* outAddress - display an address as part of an instruction** RETURNS: N/A** NOMANUAL**/LOCAL void outAddress ( UINT32 instr, /* value of instruction */ UINT32 address, /* address */ INT32 offset, /* any offset part of instruction */ VOIDFUNCPTR prtAddress /* routine to print addresses as symbols */ ) { if (bits(16,19) == 15 && bit(24) && !bit(25)) { /* pc based, pre, imm */ if (!bit(23)) offset = -offset; address = address + offset + 8; prtAddress(address); } else { outc('['); reg(bits(16,19), (bit(24) ? 0 : ']')); outc(','); if (!bit(25)) { /* offset is an immediate */ outh(offset, bit(23)); } else { if (!bit(23)) outc('-'); shiftedreg(instr); } if (bit(24)) { outc(']'); if (bit(21)) outc('!'); } } return; } /* outAddress() *//********************************************************************************* generic_cpdo - display generic coprocessor data processing instruction** RETURNS: N/A** NOMANUAL**/LOCAL void generic_cpdo ( UINT32 instr ) { opcode(instr, "CDP", 0); outf("p%d,", bits(8,11)); outx(bits(20,23)); outc(','); outf("c%d,", bits(12,15)); /* CRd */ outf("c%d,", bits(16,19)); /* CRn */ outf("c%d,", bits(0,3)); /* CRm */ outh(bits(5,7),1); return; } /* generic_cpdo() *//********************************************************************************* generic_cprt - display generic coprocessor register transfer instruction** RETURNS: N/A** NOMANUAL**/LOCAL void generic_cprt ( UINT32 instr ) { opcode(instr, (bit(20) ? "MRC" : "MCR"), 0); outf("p%d,", bits(8,11)); outx(bits(21,23)); outc(','); reg(bits(12,15), ','); outf("c%d,",bits(16,19)); /* CRn */ outf("c%d,",bits(0,3)); /* CRm */ outh(bits(5,7),1); return; } /* generic_cprt() *//********************************************************************************* generic_cpdt - display a generic coprocessor data transfer instruction** RETURNS: N/A** NOMANUAL**/LOCAL void generic_cpdt ( UINT32 instr, UINT32 address, VOIDFUNCPTR prtAddress ) { opcode(instr, (bit(20) ? "LDC" : "STC"), (bit(22) ? 'L' : 0)); outf("p%d,",bits(8,11)); outf("c%d,",bits(12,15)); outAddress(instr, address, 4*bits(0,7), prtAddress); return; } /* generic_cpdt() *//********************************************************************************* fp_dt_widthname - display floating-point data transfer width name** RETURNS: the character representing the width specifier** NOMANUAL**/LOCAL char fp_dt_widthname ( UINT32 instr ) { return "SDEP"[bit(15) + 2*bit(22)]; } /* fp_dt_widthname() *//********************************************************************************* fp_widthname - display floating-point width name** RETURNS: the character representing the width name** NOMANUAL**/LOCAL char fp_widthname ( UINT32 instr ) { return "SDEP"[bit(7) + 2*bit(19)]; } /* fp_widthname() *//********************************************************************************* fp_rounding - display floating-point rounding** RETURNS: the character representing the rounding** NOMANUAL**/LOCAL char *fp_rounding ( UINT32 instr ) { return "\0\0P\0M\0Z" + 2*bits(5,6); } /* fp_rounding() *//********************************************************************************* fp_mfield - display FP field** RETURNS: N/A** NOMANUAL**/LOCAL void fp_mfield ( UINT32 instr ) { UINT32 r = bits(0,2); if (bit(3)) { if (r < 6) outi(r); else outs((r == 6 ? "#0.5" : "#10")); } else freg(r, 0); return; } /* fp_mfield() *//********************************************************************************* fp_cpdo - display FP op** RETURNS: N/A** NOMANUAL**/LOCAL void fp_cpdo ( UINT32 instr, BOOL * oddity ) { char *opset; int l; 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"; l = outs(opset + 4*bits(20,23)); l += cond(instr); outc(fp_widthname(instr)); l++; l += outs(fp_rounding(instr)); spacetocol9(l); freg(bits(12,14), ','); /* Fd */ if (!bit(15)) freg(bits(16,18), ','); /* Fn */ else if (bits(16,18) != 0) /* odd monadic (Fn != 0) ... */ *oddity = TRUE; fp_mfield(instr); return; } /* fp_cpdo() *//********************************************************************************* fp_cprt - display floating-point register transfer instruction** RETURNS: N/A** NOMANUAL**/LOCAL void fp_cprt ( UINT32 instr ) { int op = (int)bits(20,23); if (bits(12,15) == 15) /* ARM register = pc */ { if ((op & 9) != 9) op = 4; else op = (op>>1)-4; opcode(instr, "CMF\0\0CNF\0\0CMFE\0CNFE\0???" + 5*op, 0); freg(bits(16,18), ','); fp_mfield(instr); return; } else { int l; if (op > 7) op = 7; l = outs("FLT\0FIX\0WFS\0RFS\0WFC\0RFC\0???\0???" + 4*op); l += cond(instr); outc(fp_widthname(instr)); l++; l += outs(fp_rounding(instr)); spacetocol9(l); if (bits(20,23) == 0) /* FLT */ { freg(bits(16,18), ','); } reg(bits(12,15), 0); if (bits(20,23) == 1) /* FIX */ { outc(','); fp_mfield(instr); } } return; } /* fp_cprt() *//********************************************************************************* fp_cpdt - display floating-point data transfer instruction** RETURNS: N/A** NOMANUAL**/LOCAL void fp_cpdt ( UINT32 instr, UINT32 address, VOIDFUNCPTR prtAddress ) { if (!bit(24) && !bit(21)) { /* oddity: post and not writeback */ generic_cpdt(instr, address, prtAddress); } else { opcode(instr, (bit(20) ? "LDF" : "STF"), fp_dt_widthname(instr)); freg(bits(12,14), ','); outAddress(instr, address, 4*bits(0,7), prtAddress); } return; } /* fp_cpdt() *//********************************************************************************* fm_cpdt - display floating-point load/store multiple instruction** RETURNS: N/A** NOMANUAL**/LOCAL void fm_cpdt ( UINT32 instr, UINT32 address, VOIDFUNCPTR prtAddress ) { if (!bit(24) && !bit(21)) { /* oddity: post and not writeback */ generic_cpdt(instr, address, prtAddress); return; } opcode(instr, (bit(20) ? "LFM" : "SFM"), 0); freg(bits(12,14), ','); { int count = (int)(bit(15) + 2*bit(22)); outf("%d,", count==0 ? 4: count); } outAddress(instr, address, 4*bits(0,7), prtAddress); return; } /* fm_cpdt() *//********************************************************************************* disass_32 - disassemble an ARM (32-bit) instruction** RETURNS: size of instruction, in bytes** NOMANUAL**/LOCAL UINT32 disass_32 ( UINT32 instr, /* the value of the instruction */ UINT32 address, /* the address to print before instruction */ VOIDFUNCPTR prtAddress /* routine to print addresses as symbols */ ) { BOOL oddity = FALSE; switch (bits(24,27)) { case 0: if (bit(23) == 1 && bits(4,7) == 9) { /* Long Multiply */ opcode(instr, bit(21) ? (bit(22) ? "SMLAL" : "UMLAL") : (bit(22) ? "SMULL" : "UMULL"), bit(20) ? 'S' : 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -