Print this page
3317 dis(1) should support cross-target disassembly

*** 25,34 **** --- 25,35 ---- */ /* * Copyright 2007 Jason King. All rights reserved. * Use is subject to license terms. + * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org> */ /* * The sparc disassembler is mostly straightforward, each instruction is * represented by an inst_t structure. The inst_t definitions are organized
*** 100,223 **** #if !defined(DIS_STANDALONE) static void do_binary(uint32_t); #endif /* DIS_STANDALONE */ ! dis_handle_t * ! dis_handle_create(int flags, void *data, dis_lookup_f lookup_func, ! dis_read_f read_func) { #if !defined(DIS_STANDALONE) char *opt = NULL; char *opt2, *save, *end; #endif - dis_handle_t *dhp; ! if ((flags & (DIS_SPARC_V8|DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0) { (void) dis_seterrno(E_DIS_INVALFLAG); ! return (NULL); } ! if ((dhp = dis_zalloc(sizeof (struct dis_handle))) == NULL) { (void) dis_seterrno(E_DIS_NOMEM); return (NULL); } ! ! dhp->dh_lookup = lookup_func; ! dhp->dh_read = read_func; ! dhp->dh_flags = flags; ! dhp->dh_data = data; ! dhp->dh_debug = DIS_DEBUG_COMPAT; #if !defined(DIS_STANDALONE) opt = getenv("_LIBDISASM_DEBUG"); if (opt == NULL) ! return (dhp); opt2 = strdup(opt); if (opt2 == NULL) { dis_handle_destroy(dhp); (void) dis_seterrno(E_DIS_NOMEM); ! return (NULL); } save = opt2; while (opt2 != NULL) { end = strchr(opt2, ','); if (end != 0) *end++ = '\0'; if (strcasecmp("synth-all", opt2) == 0) ! dhp->dh_debug |= DIS_DEBUG_SYN_ALL; if (strcasecmp("compat", opt2) == 0) ! dhp->dh_debug |= DIS_DEBUG_COMPAT; if (strcasecmp("synth-none", opt2) == 0) ! dhp->dh_debug &= ~(DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT); if (strcasecmp("binary", opt2) == 0) ! dhp->dh_debug |= DIS_DEBUG_PRTBIN; if (strcasecmp("format", opt2) == 0) ! dhp->dh_debug |= DIS_DEBUG_PRTFMT; if (strcasecmp("all", opt2) == 0) ! dhp->dh_debug = DIS_DEBUG_ALL; if (strcasecmp("none", opt2) == 0) ! dhp->dh_debug = DIS_DEBUG_NONE; opt2 = end; } free(save); #endif /* DIS_STANDALONE */ ! return (dhp); ! } ! ! void ! dis_handle_destroy(dis_handle_t *dhp) ! { ! dis_free(dhp, sizeof (dis_handle_t)); ! } ! ! void ! dis_set_data(dis_handle_t *dhp, void *data) ! { ! dhp->dh_data = data; ! } ! ! void ! dis_flags_set(dis_handle_t *dhp, int f) ! { ! dhp->dh_flags |= f; } ! void ! dis_flags_clear(dis_handle_t *dhp, int f) { ! dhp->dh_flags &= ~f; } /* ARGSUSED */ ! int ! dis_max_instrlen(dis_handle_t *dhp) { return (4); } /* * The dis_i386.c comment for this says it returns the previous instruction, * however, I'm fairly sure it's actually returning the _address_ of the * nth previous instruction. */ /* ARGSUSED */ ! uint64_t ! dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n) { if (n <= 0) return (pc); if (pc < n) --- 101,212 ---- #if !defined(DIS_STANDALONE) static void do_binary(uint32_t); #endif /* DIS_STANDALONE */ ! static void ! dis_sparc_handle_detach(dis_handle_t *dhp) ! { ! dis_free(dhp->dh_arch_private, sizeof (dis_handle_sparc_t)); ! dhp->dh_arch_private = NULL; ! } ! ! static int ! dis_sparc_handle_attach(dis_handle_t *dhp) { + dis_handle_sparc_t *dhx; #if !defined(DIS_STANDALONE) char *opt = NULL; char *opt2, *save, *end; #endif ! /* Validate architecture flags */ ! if ((dhp->dh_flags & (DIS_SPARC_V8|DIS_SPARC_V9|DIS_SPARC_V9_SGI)) ! == 0) { (void) dis_seterrno(E_DIS_INVALFLAG); ! return (-1); } ! if ((dhx = dis_zalloc(sizeof (dis_handle_sparc_t))) == NULL) { (void) dis_seterrno(E_DIS_NOMEM); return (NULL); } ! dhx->dhx_debug = DIS_DEBUG_COMPAT; ! dhp->dh_arch_private = dhx; #if !defined(DIS_STANDALONE) opt = getenv("_LIBDISASM_DEBUG"); if (opt == NULL) ! return (0); opt2 = strdup(opt); if (opt2 == NULL) { dis_handle_destroy(dhp); + dis_free(dhx, sizeof (dis_handle_sparc_t)); (void) dis_seterrno(E_DIS_NOMEM); ! return (-1); } save = opt2; while (opt2 != NULL) { end = strchr(opt2, ','); if (end != 0) *end++ = '\0'; if (strcasecmp("synth-all", opt2) == 0) ! dhx->dhx_debug |= DIS_DEBUG_SYN_ALL; if (strcasecmp("compat", opt2) == 0) ! dhx->dhx_debug |= DIS_DEBUG_COMPAT; if (strcasecmp("synth-none", opt2) == 0) ! dhx->dhx_debug &= ~(DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT); if (strcasecmp("binary", opt2) == 0) ! dhx->dhx_debug |= DIS_DEBUG_PRTBIN; if (strcasecmp("format", opt2) == 0) ! dhx->dhx_debug |= DIS_DEBUG_PRTFMT; if (strcasecmp("all", opt2) == 0) ! dhx->dhx_debug = DIS_DEBUG_ALL; if (strcasecmp("none", opt2) == 0) ! dhx->dhx_debug = DIS_DEBUG_NONE; opt2 = end; } free(save); #endif /* DIS_STANDALONE */ ! return (0); } ! /* ARGSUSED */ ! static int ! dis_sparc_max_instrlen(dis_handle_t *dhp) { ! return (4); } /* ARGSUSED */ ! static int ! dis_sparc_min_instrlen(dis_handle_t *dhp) { return (4); } /* * The dis_i386.c comment for this says it returns the previous instruction, * however, I'm fairly sure it's actually returning the _address_ of the * nth previous instruction. */ /* ARGSUSED */ ! static uint64_t ! dis_sparc_previnstr(dis_handle_t *dhp, uint64_t pc, int n) { if (n <= 0) return (pc); if (pc < n)
*** 225,264 **** return (pc - n*4); } /* ARGSUSED */ ! int ! dis_instrlen(dis_handle_t *dhp, uint64_t pc) { return (4); } ! int ! dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen) { const table_t *tp = &initial_table; const inst_t *inp = NULL; uint32_t instr; uint32_t idx = 0; if (dhp->dh_read(dhp->dh_data, addr, &instr, sizeof (instr)) != sizeof (instr)) return (-1); ! dhp->dh_buf = buf; ! dhp->dh_buflen = buflen; dhp->dh_addr = addr; buf[0] = '\0'; /* this allows sparc code to be tested on x86 */ instr = BE_32(instr); #if !defined(DIS_STANDALONE) ! if ((dhp->dh_debug & DIS_DEBUG_PRTBIN) != 0) do_binary(instr); #endif /* DIS_STANDALONE */ /* CONSTCOND */ while (1) { --- 214,257 ---- return (pc - n*4); } /* ARGSUSED */ ! static int ! dis_sparc_instrlen(dis_handle_t *dhp, uint64_t pc) { return (4); } ! static int ! dis_sparc_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, ! size_t buflen) { + dis_handle_sparc_t *dhx = dhp->dh_arch_private; const table_t *tp = &initial_table; const inst_t *inp = NULL; uint32_t instr; uint32_t idx = 0; if (dhp->dh_read(dhp->dh_data, addr, &instr, sizeof (instr)) != sizeof (instr)) return (-1); ! dhx->dhx_buf = buf; ! dhx->dhx_buflen = buflen; dhp->dh_addr = addr; buf[0] = '\0'; /* this allows sparc code to be tested on x86 */ + #if !defined(DIS_STANDALONE) instr = BE_32(instr); + #endif /* DIS_STANDALONE */ #if !defined(DIS_STANDALONE) ! if ((dhx->dhx_debug & DIS_DEBUG_PRTBIN) != 0) do_binary(instr); #endif /* DIS_STANDALONE */ /* CONSTCOND */ while (1) {
*** 339,343 **** --- 332,359 ---- (void) fprintf(stderr, "DISASM: "); prt_binary(instr, 32); (void) fprintf(stderr, "\n"); } #endif /* DIS_STANDALONE */ + + static int + dis_sparc_supports_flags(int flags) + { + int archflags = flags & DIS_ARCH_MASK; + + if (archflags == DIS_SPARC_V8 || + (archflags & (DIS_SPARC_V9 | DIS_SPARC_V8)) == DIS_SPARC_V9) + return (1); + + return (0); + } + + const dis_arch_t dis_arch_sparc = { + dis_sparc_supports_flags, + dis_sparc_handle_attach, + dis_sparc_handle_detach, + dis_sparc_disassemble, + dis_sparc_previnstr, + dis_sparc_min_instrlen, + dis_sparc_max_instrlen, + dis_sparc_instrlen + };