From 038db8fb497789ea9b367f771544442507cede18 Mon Sep 17 00:00:00 2001 From: Josef 'Jeff' Sipek Date: Fri, 16 Oct 2015 01:21:30 -0400 Subject: [PATCH] 6068 libdisasm: previnstr arch op should have a sane default Reviewed by: Robert Mustacchi Approved by: Dan McDonald --- usr/src/lib/libdisasm/common/dis_i386.c | 52 ---------------------------- usr/src/lib/libdisasm/common/dis_sparc.c | 5 --- usr/src/lib/libdisasm/common/libdisasm.c | 58 ++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 57 deletions(-) diff --git a/usr/src/lib/libdisasm/common/dis_i386.c b/usr/src/lib/libdisasm/common/dis_i386.c index 4a17968634..beb66cdc0d 100644 --- a/usr/src/lib/libdisasm/common/dis_i386.c +++ b/usr/src/lib/libdisasm/common/dis_i386.c @@ -172,57 +172,6 @@ dis_i386_min_instrlen(dis_handle_t *dhp) return (1); } -/* - * Return the previous instruction. On 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_i386_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); -} - static int dis_i386_supports_flags(int flags) { @@ -249,7 +198,6 @@ dis_arch_t dis_arch_i386 = { .da_handle_attach = dis_i386_handle_attach, .da_handle_detach = dis_i386_handle_detach, .da_disassemble = dis_i386_disassemble, - .da_previnstr = dis_i386_previnstr, .da_min_instrlen = dis_i386_min_instrlen, .da_max_instrlen = dis_i386_max_instrlen, .da_instrlen = dis_i386_instrlen, diff --git a/usr/src/lib/libdisasm/common/dis_sparc.c b/usr/src/lib/libdisasm/common/dis_sparc.c index e7f7d61045..224fe9042d 100644 --- a/usr/src/lib/libdisasm/common/dis_sparc.c +++ b/usr/src/lib/libdisasm/common/dis_sparc.c @@ -197,11 +197,6 @@ 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) diff --git a/usr/src/lib/libdisasm/common/libdisasm.c b/usr/src/lib/libdisasm/common/libdisasm.c index 7f040a04b8..ce48a2da8b 100644 --- a/usr/src/lib/libdisasm/common/libdisasm.c +++ b/usr/src/lib/libdisasm/common/libdisasm.c @@ -196,9 +196,67 @@ 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)); } -- 2.11.4.GIT