/* $NetBSD: kshell_disassem.c,v 1.6 1997/10/14 09:01:40 mark Exp $ */ /* * Copyright (c) 1994 Mark Brinicombe. * Copyright (c) 1994 Brini. * All rights reserved. * * This code is derived from software written for Brini by Mark Brinicombe * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Brini. * 4. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * RiscBSD kernel project * * disassem.c * * Debug / Monitor disassembler * * Created : 09/10/94 */ /* * The disassembler now duplicates a lot of code with the debugger. * The main reason there are two is that this one has extra interactive * support for following branches durinhg disassembly and this one uses * printf() with the one in db_disassem.c uses db_printf(). */ /* Special compilation symbols * * DISASSEM_COLOUR - Use colour in dissassembly */ /*#define DISASSEM_COLOUR */ /* Include standard header files */ #include #include /* Local header files */ #include typedef u_int (*instruction_decoder) (u_int addr, u_int word); typedef struct _opcodes { u_int mask; u_int pattern; u_int colour; instruction_decoder decoder; } opcodes_struct; static u_int instruction_swi __P((u_int addr, u_int word)); static u_int instruction_branch __P((u_int addr, u_int word)); static u_int instruction_mul __P((u_int addr, u_int word)); static u_int instruction_mla __P((u_int addr, u_int word)); static u_int instruction_ldrstr __P((u_int addr, u_int word)); static u_int instruction_ldmstm __P((u_int addr, u_int word)); static u_int instruction_dataproc __P((u_int addr, u_int word)); static u_int instruction_swap __P((u_int addr, u_int word)); static u_int instruction_mrs __P((u_int addr, u_int word)); static u_int instruction_msr __P((u_int addr, u_int word)); static u_int instruction_msrf __P((u_int addr, u_int word)); static u_int instruction_mrcmcr __P((u_int addr, u_int word)); static u_int instruction_cdp __P((u_int addr, u_int word)); static u_int instruction_cdt __P((u_int addr, u_int word)); static u_int instruction_fpabinop __P((u_int addr, u_int word)); static u_int instruction_fpaunop __P((u_int addr, u_int word)); static u_int instruction_ldfstf __P((u_int addr, u_int word)); /* Declare global variables */ opcodes_struct opcodes[] = { { 0x0f000000, 0x0f000000, 7, instruction_swi }, { 0x0e000000, 0x0a000000, 7, instruction_branch }, { 0x0fe000f0, 0x00000090, 7, instruction_mul }, { 0x0fe000f0, 0x00200090, 7, instruction_mla }, { 0x0e000000, 0x04000000, 7, instruction_ldrstr }, { 0x0c000010, 0x04000000, 7, instruction_ldrstr }, { 0x0e000000, 0x08000000, 6, instruction_ldmstm }, { 0x0FB00FF0, 0x01000090, 7, instruction_swap }, { 0x0FBF0FFF, 0x010F0000, 1, instruction_mrs }, { 0x0DBFFFF0, 0x0129F000, 1, instruction_msr }, { 0x0DBFFFF0, 0x0128F000, 1, instruction_msrf }, { 0x0C000000, 0x00000000, 7, instruction_dataproc }, { 0x0F008F10, 0x0E000100, 3, instruction_fpabinop }, { 0x0F008F10, 0x0E008100, 3, instruction_fpaunop }, { 0x0E000F00, 0x0C000100, 3, instruction_ldfstf }, { 0x0F000010, 0x0E000010, 2, instruction_mrcmcr }, { 0x0F000010, 0x0E000000, 2, instruction_cdp }, { 0x0E000000, 0x0C000000, 2, instruction_cdt }, { 0x00000000, 0x00000000, 0, NULL } }; char *opcode_conditions[] = { "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV" }; char *opcode_data_procs[] = { "AND", "EOR", "SUB", "RSB", "ADD", "ADC", "SBC", "RSC", "TST", "TEQ", "CMP", "CMN", "ORR", "MOV", "BIC", "MVN" }; char *opcode_shifts[] = { "LSL", "LSR", "ASR", "ROR" }; char *opcode_block_transfers[] = { "DA", "IA", "DB", "IB" }; char *opcode_stack_block_transfers[] = { "FA", "EA", "FD", "FA" }; char *opcode_fpabinops[] = { "ADF", "MUF", "SUF", "RSF", "DVF", "RDF", "POW", "RPW", "RMF", "FML", "FDV", "FRD", "POL", "???", "???", "???", "???" }; char *opcode_fpaunops[] = { "MVF", "MNF", "ABS", "RND", "SQT", "LOG", "LGN", "EXP", "SIN", "COS", "TAN", "ASN", "ACS", "ATN", "???", "???", "???" }; char *opcode_fpaconstants[] = { "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0" }; char *opcode_fpa_rounding[] = { "", "P", "M", "Z" }; char *opcode_fpa_precision[] = { "S", "D", "E", "P" }; #define opcode_condition(x) opcode_conditions[x >> 28] #define opcode_s(x) ((x & 0x00100000) ? "S" : "") #define opcode_b(x) ((x & 0x00400000) ? "B" : "") #define opcode_t(x) ((x & 0x01200000) == 0x00200000 ? "T" : "") #define opcode_dataproc(x) opcode_data_procs[(x >> 21) & 0x0f] #define opcode_shift(x) opcode_shifts[(x >> 5) & 3] #define opcode_blktrans(x) opcode_block_transfers[(x >> 23) & 3] #define opcode_stkblktrans(x) opcode_stack_block_transfers[(x >> 23) & 3] #define opcode_fpabinop(x) opcode_fpabinops[(x >> 20) & 0x0f] #define opcode_fpaunop(x) opcode_fpaunops[(x >> 20) & 0x0f] #define opcode_fpaimm(x) opcode_fpaconstants[x & 0x07] #define opcode_fparnd(x) opcode_fpa_rounding[(x >> 5) & 0x03] #define opcode_fpaprec(x) opcode_fpa_precision[(((x >> 18) & 2)|(x >> 7)) & 3] /* Declare external variables */ extern caddr_t shell_ident; int readhex __P((char *buf)); /* Local function prototypes */ u_int disassemble __P((u_char *addr)); static u_int do_disassemble __P((u_char *)); /* Now for the main code */ /* dis - disassembles memory */ void shell_disassem(argc, argv) int argc; char *argv[]; { u_char *addr; if (argc < 2) { printf("Syntax: dis \n\r"); return; } /* Decode the one argument */ addr = (u_char *)readhex(argv[1]); printf("Interactive disassembly\n\r"); do_disassemble(addr); } static u_int do_disassemble(addr) u_char *addr; { u_int result; int quit = 0; int key = 0; int count = 1; do { result = disassemble(addr); --count; if (count == 0) { count = 1; key = cngetc(); switch (key) { case 'Q' : case 'q' : case 0x1b : case 0x03 : case 0x04 : case 0x10b : quit = 1; break; case 0x09 : case 'r' : case 'R' : case 0x103 : count = 16; addr += 4; break; case 0x102 : count = 16; addr -= 124; break; case 0x0d : case 0x101 : addr = addr + 4; break; case 'B' : case 'b' : case 0x100: addr = addr - 4; break; case '+' : case '=' : case 0x104 : addr = addr + 0x80; break; case '-' : case '_' : case 0x105 : addr = addr - 0x80; break; case ' ' : quit = do_disassemble((u_char *)result); break; case 'J' : case 'j' : addr = (u_char *)result; break; case '/' : case '?' : printf("\'\xe3\' - Backwards 1 word\n\r"); printf("\'\xe4\' - Forwards 1 word\n\r"); printf("\'\xe5\' - Backwords 16 words\n\r"); printf("\'\xe6\' - Forwards 16 words\n\r"); printf("\'Q\' - Quit\n\r"); printf("\'B\' - Back a word\n\r"); printf("\'R\' - Disassemble 16 words\n\r"); printf("\'J\' - Jump to address\n\r"); printf("\' \' - Branch to address\n\r"); printf(" - Return from branch\n\r"); printf("\'-\' - Skip backwards 128 words\n\r"); printf("\'+\' - Skip forwards 128 words\n\r"); break; } } else { addr += 4; } } while (!quit && key != 0x08); return(quit); } static void printascii(byte) int byte; { byte &= 0x7f; if (byte < 0x20) #ifdef DISASSEM_COLOUR printf("\x1b[31m%c\x1b[0m", byte + '@'); #else printf("%c", byte + '@'); #endif else if (byte == 0x7f) #ifdef DISASSEM_COLOUR printf("\x1b[31m?\x1b[0m"); #else printf("?"); #endif else printf("%c", byte); } u_int disassemble(addr) u_char *addr; { int loop; u_int word; u_int result = 0; printf("%08x : ", (u_int)addr); word = *((u_int *)addr); for (loop = 0; loop < 4; ++loop) printascii(addr[loop]); printf(" : %08x : ", word); loop = 0; while (opcodes[loop].mask != 0) { if ((word & opcodes[loop].mask) == opcodes[loop].pattern) { #ifdef DISASSEM_COLOUR printf("\x1b[3%dm", opcodes[loop].colour); #endif result = (*opcodes[loop].decoder)((u_int )addr, word); #ifdef DISASSEM_COLOUR printf("\x1b[0m"); #endif break; } ++loop; } if (opcodes[loop].mask == 0) printf("Undefined instruction"); printf("\n\r"); return(result); } static u_int instruction_swi(addr, word) u_int addr; u_int word; { printf("SWI%s\t0x%08x", opcode_condition(word), (word & 0x00ffffff)); return(addr); } static u_int instruction_branch(addr, word) u_int addr; u_int word; { u_int branch; branch = ((word << 2) & 0x03ffffff); if (branch & 0x02000000) branch |= 0xfc000000; branch += addr + 8; if (word & 0x01000000) printf("BL%s\t0x%08x", opcode_condition(word), branch); else printf("B%s\t0x%08x", opcode_condition(word), branch); return(branch); } static u_int instruction_mul(addr, word) u_int addr; u_int word; { printf("MUL%s%s\t", opcode_condition(word), opcode_s(word)); printf("r%d, r%d, r%d", (word >> 16) & 0x0f, word & 0x0f, (word >> 8) & 0x0f); return(addr); } static u_int instruction_mla(addr, word) u_int addr; u_int word; { printf("MLA%s%s\t", opcode_condition(word), opcode_s(word)); printf("r%d, r%d, r%d, r%d", (word >> 16) & 0x0f, word & 0x0f, (word >> 8) & 0x0f, (word >> 12) & 0x0f); return(addr); } static void register_shift(word) u_int word; { printf("r%d", (word & 0x0f)); if ((word & 0x00000ff0) == 0) ; else if ((word & 0x00000ff0) == 0x00000060) printf(", RRX"); else { if (word & 0x10) printf(", %s r%d", opcode_shift(word), (word >> 8) & 0x0f); else printf(", %s #%d", opcode_shift(word), (word >> 7) & 0x1f); } } static u_int instruction_ldrstr(addr, word) u_int addr; u_int word; { printf("%s%s%s%s\t", (word & 0x00100000) ? "LDR" : "STR", opcode_condition(word), opcode_b(word), opcode_t(word)); printf("r%d, ", (word >> 12) & 0x0f); if (((word >> 16) & 0x0f) == 16) { /* u_int location; location = addr + 8; addr = */ } else { printf("[r%d", (word >> 16) & 0x0f); printf("%s, ", (word & (1 << 24)) ? "" : "]"); if (!(word & 0x00800000)) printf("-"); if (word & (1 << 25)) register_shift(word); else printf("#0x%04x", word & 0xfff); if (word & (1 << 24)) printf("]"); if (word & (1 << 21)) printf("!"); } return(addr); } static u_int instruction_ldmstm(addr, word) u_int addr; u_int word; { int loop; int start; printf("%s%s%s\t", (word & 0x00100000) ? "LDM" : "STM", opcode_condition(word), opcode_blktrans(word)); printf("r%d", (word >> 16) & 0x0f); if (word & (1 << 21)) printf("!"); printf(", {"); start = -1; for (loop = 0; loop < 17; ++loop) { if (start != -1) { if (!(word & (1 << loop)) || loop == 16) { if (start == loop - 1) printf("r%d, ", start); else printf("r%d-r%d, ", start, loop - 1); start = -1; } } else { if (word & (1 << loop)) start = loop; } } printf("\x7f\x7f}"); if (word & (1 << 22)) printf("^"); return(addr); } static u_int instruction_dataproc(addr, word) u_int addr; u_int word; { if ((word & 0x01800000) == 0x01000000) word = word & ~(1<<20); printf("%s%s%s\t", opcode_dataproc(word), opcode_condition(word), opcode_s(word)); if ((word & 0x01800000) != 0x01000000) printf("r%d, ", (word >> 12) & 0x0f); if ((word & 0x01a00000) != 0x01a00000) printf("r%d, ", (word >> 16) & 0x0f); if (word & 0x02000000) { printf("#&%08x", (word & 0xff) << (((word >> 7) & 0x1e))); } else { register_shift(word); } return(addr); } static u_int instruction_swap(addr, word) u_int addr; u_int word; { printf("SWP%s%s\t", opcode_condition(word), opcode_b(word)); printf("r%d, r%d, [r%d]", (word >> 12) & 0x0f, (word & 0x0f), (word >> 16) & 0x0f); return(addr); } static u_int instruction_mrs(addr, word) u_int addr; u_int word; { printf("MRS%s\tr%d, ", opcode_condition(word), (word >> 12) & 0x0f); printf("%s", (word & 0x00400000) ? "SPSR" : "CPSR"); return(addr); } static u_int instruction_msr(addr, word) u_int addr; u_int word; { printf("MSR%s\t", opcode_condition(word)); printf("%s, r%d", (word & 0x00400000) ? "SPSR" : "CPSR", word & 0x0f); return(addr); } static u_int instruction_msrf(addr, word) u_int addr; u_int word; { printf("MSR%s\t", opcode_condition(word)); printf("%s_flg, ", (word & 0x00400000) ? "SPSR" : "CPSR"); if (word & 0x02000000) printf("#0x%08x", (word & 0xff) << (32 - ((word >> 7) & 0x1e))); else printf("r%d", word &0x0f); return(addr); } static u_int instruction_mrcmcr(addr, word) u_int addr; u_int word; { printf("%s%s\t", (word & (1 << 20)) ? "MRC" : "MCR", opcode_condition(word)); printf("CP #%d, %d, ", (word >> 8) & 0x0f, (word >> 21) & 0x07); printf("r%d, cr%d, cr%d", (word >> 12) & 0x0f, (word >> 16) & 0x0f, word & 0x0f); if (((word >> 5) & 0x07) != 0) printf(", %d", (word >> 5) & 0x07); return(addr); } static u_int instruction_cdp(addr, word) u_int addr; u_int word; { printf("CDP%s\t", opcode_condition(word)); printf("CP #%d, %d, ", (word >> 8) & 0x0f, (word >> 20) & 0x0f); printf("cr%d, cr%d, cr%d", (word >> 12) & 0x0f, (word >> 16) & 0x0f, word & 0x0f); printf(", %d", (word >> 5) & 0x07); return(addr); } static u_int instruction_cdt(addr, word) u_int addr; u_int word; { printf("%s%s%s\t", (word & (1 << 20)) ? "LDC" : "STC", opcode_condition(word), (word & (1 << 22)) ? "L" : ""); printf("CP #%d, cr%d, ", (word >> 8) & 0x0f, (word >> 12) & 0x0f); printf("[r%d", (word >> 16) & 0x0f); printf("%s, ", (word & (1 << 24)) ? "" : "]"); if (!(word & (1 << 23))) printf("-"); printf("#0x%02x", word & 0xff); if (word & (1 << 24)) printf("]"); if (word & (1 << 21)) printf("!"); return(addr); } static u_int instruction_fpabinop(addr, word) u_int addr; u_int word; { printf("%s%s%s%s\t", opcode_fpabinop(word), opcode_condition(word), opcode_fpaprec(word), opcode_fparnd(word)); printf("f%d, f%d, ", (word >> 12) & 0x07, (word >> 16) & 0x07); if (word & (1 << 3)) printf("#%s", opcode_fpaimm(word)); else printf("f%d", word & 0x07); return(addr); } static u_int instruction_fpaunop(addr, word) u_int addr; u_int word; { printf("%s%s%s%s\t", opcode_fpaunop(word), opcode_condition(word), opcode_fpaprec(word), opcode_fparnd(word)); printf("f%d, ", (word >> 12) & 0x07); if (word & (1 << 3)) printf("#%s", opcode_fpaimm(word)); else printf("f%d", word & 0x07); return(addr); } static u_int instruction_ldfstf(addr, word) u_int addr; u_int word; { printf("%s%s%s\t", (word & (1 << 20)) ? "LDF" : "STF", opcode_condition(word), (word & (1 << 22)) ? "L" : ""); printf("f%d, [r%d", (word >> 12) & 0x07, (word >> 16) & 0x0f); printf("%s, ", (word & (1 << 24)) ? "" : "]"); if (!(word & (1 << 23))) printf("-"); printf("#0x%03x", (word & 0xff) << 2); if (word & (1 << 24)) printf("]"); if (word & (1 << 21)) printf("!"); return(addr); } /* End of kshell_disassem.c */