Print this page
6066 dis: support for System/370, System/390, and z/Architecture ELF bins
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Dan McDonald <danmcd@omniti.com>
6070 libdisasm: attach/detach arch ops should be optional
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Dan McDonald <danmcd@omniti.com>
6069 libdisasm: instrlen arch op should have a sane default
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Dan McDonald <danmcd@omniti.com>
6068 libdisasm: previnstr arch op should have a sane default
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Dan McDonald <danmcd@omniti.com>

*** 50,67 **** --- 50,73 ---- extern dis_arch_t dis_arch_i386; #endif #if !defined(DIS_STANDALONE) || defined(__sparc) extern dis_arch_t dis_arch_sparc; #endif + #if !defined(DIS_STANDALONE) || defined(__s390) || defined(__s390x) + extern dis_arch_t dis_arch_s390; + #endif static dis_arch_t *dis_archs[] = { #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64) &dis_arch_i386, #endif #if !defined(DIS_STANDALONE) || defined(__sparc) &dis_arch_sparc, #endif + #if !defined(DIS_STANDALONE) || defined(__s390) || defined(__s390x) + &dis_arch_s390, + #endif NULL }; /* * For the standalone library, we need to link against mdb's malloc/free.
*** 141,151 **** --- 147,159 ---- } void dis_handle_destroy(dis_handle_t *dhp) { + if (dhp->dh_arch->da_handle_detach != NULL) dhp->dh_arch->da_handle_detach(dhp); + dis_free(dhp, sizeof (dis_handle_t)); } dis_handle_t * dis_handle_create(int flags, void *data, dis_lookup_f lookup_func,
*** 179,189 **** /* * Allow the architecture-specific code to allocate * its private data. */ ! if (arch->da_handle_attach(dhp) != 0) { dis_free(dhp, sizeof (dis_handle_t)); /* dis errno already set */ return (NULL); } --- 187,198 ---- /* * Allow the architecture-specific code to allocate * its private data. */ ! if (arch->da_handle_attach != NULL && ! arch->da_handle_attach(dhp) != 0) { dis_free(dhp, sizeof (dis_handle_t)); /* dis errno already set */ return (NULL); }
*** 194,206 **** --- 203,273 ---- dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen) { return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen)); } + /* + * On some instruction sets (e.g., x86), we have no choice except to + * disassemble everything from the start of the symbol, and stop when we + * have reached our instruction address. If we're not in the middle of a + * known symbol, then we return the same address to indicate failure. + */ + static uint64_t + dis_generic_previnstr(dis_handle_t *dhp, uint64_t pc, int n) + { + uint64_t *hist, addr, start; + int cur, nseen; + uint64_t res = pc; + + if (n <= 0) + return (pc); + + if (dhp->dh_lookup(dhp->dh_data, pc, NULL, 0, &start, NULL) != 0 || + start == pc) + return (res); + + hist = dis_zalloc(sizeof (uint64_t) * n); + + for (cur = 0, nseen = 0, addr = start; addr < pc; addr = dhp->dh_addr) { + hist[cur] = addr; + cur = (cur + 1) % n; + nseen++; + + /* if we cannot make forward progress, give up */ + if (dis_disassemble(dhp, addr, NULL, 0) != 0) + goto done; + } + + if (addr != pc) { + /* + * We scanned past %pc, but didn't find an instruction that + * started at %pc. This means that either the caller specified + * an invalid address, or we ran into something other than code + * during our scan. Virtually any combination of bytes can be + * construed as a valid Intel instruction, so any non-code bytes + * we encounter will have thrown off the scan. + */ + goto done; + } + + res = hist[(cur + n - MIN(n, nseen)) % n]; + + done: + dis_free(hist, sizeof (uint64_t) * n); + return (res); + } + + /* + * Return the nth previous instruction's address. Return the same address + * to indicate failure. + */ uint64_t dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n) { + if (dhp->dh_arch->da_previnstr == NULL) + return (dis_generic_previnstr(dhp, pc, n)); + return (dhp->dh_arch->da_previnstr(dhp, pc, n)); } int dis_min_instrlen(dis_handle_t *dhp)
*** 212,224 **** --- 279,303 ---- dis_max_instrlen(dis_handle_t *dhp) { return (dhp->dh_arch->da_max_instrlen(dhp)); } + static int + dis_generic_instrlen(dis_handle_t *dhp, uint64_t pc) + { + if (dis_disassemble(dhp, pc, NULL, 0) != 0) + return (-1); + + return (dhp->dh_addr - pc); + } + int dis_instrlen(dis_handle_t *dhp, uint64_t pc) { + if (dhp->dh_arch->da_instrlen == NULL) + return (dis_generic_instrlen(dhp, pc)); + return (dhp->dh_arch->da_instrlen(dhp, pc)); } int dis_vsnprintf(char *restrict s, size_t n, const char *restrict format,