--- /dev/null	Sun Dec 16 13:00:31 2012
+++ new/usr/src/lib/libdisasm/common/dis_i386.c	Sun Dec 16 13:00:31 2012
@@ -0,0 +1,249 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
+ */
+
+#include <libdisasm.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "dis_tables.h"
+#include "libdisasm_impl.h"
+
+typedef struct dis_handle_i386 {
+	int		dhx_mode;
+	dis86_t		dhx_dis;
+	uint64_t	dhx_end;
+} dis_handle_i386_t;
+
+/*
+ * Returns true if we are near the end of a function.  This is a cheap hack at
+ * detecting NULL padding between functions.  If we're within a few bytes of the
+ * next function, or past the start, then return true.
+ */
+static int
+check_func(void *data)
+{
+	dis_handle_t *dhp = data;
+	uint64_t start;
+	size_t len;
+
+	if (dhp->dh_lookup(dhp->dh_data, dhp->dh_addr, NULL, 0, &start, &len)
+	    != 0)
+		return (0);
+
+	if (start < dhp->dh_addr)
+		return (dhp->dh_addr > start + len - 0x10);
+
+	return (1);
+}
+
+static int
+get_byte(void *data)
+{
+	uchar_t byte;
+	dis_handle_t *dhp = data;
+
+	if (dhp->dh_read(dhp->dh_data, dhp->dh_addr, &byte, sizeof (byte)) !=
+	    sizeof (byte))
+		return (-1);
+
+	dhp->dh_addr++;
+
+	return ((int)byte);
+}
+
+static int
+do_lookup(void *data, uint64_t addr, char *buf, size_t buflen)
+{
+	dis_handle_t *dhp = data;
+
+	return (dhp->dh_lookup(dhp->dh_data, addr, buf, buflen, NULL, NULL));
+}
+
+static void
+dis_i386_handle_detach(dis_handle_t *dhp)
+{
+	dis_free(dhp->dh_arch_private, sizeof (dis_handle_i386_t));
+	dhp->dh_arch_private = NULL;
+}
+
+static int
+dis_i386_handle_attach(dis_handle_t *dhp)
+{
+	dis_handle_i386_t *dhx;
+
+	/*
+	 * Validate architecture flags
+	 */
+	if (dhp->dh_flags & ~(DIS_X86_SIZE16 | DIS_X86_SIZE32 | DIS_X86_SIZE64 |
+	    DIS_OCTAL | DIS_NOIMMSYM)) {
+		(void) dis_seterrno(E_DIS_INVALFLAG);
+		return (-1);
+	}
+
+	/*
+	 * Create and initialize the internal structure
+	 */
+	if ((dhx = dis_zalloc(sizeof (dis_handle_i386_t))) == NULL) {
+		(void) dis_seterrno(E_DIS_NOMEM);
+		return (-1);
+	}
+	dhp->dh_arch_private = dhx;
+
+	/*
+	 * Initialize x86-specific architecture structure
+	 */
+	if (dhp->dh_flags & DIS_X86_SIZE16)
+		dhx->dhx_mode = SIZE16;
+	else if (dhp->dh_flags & DIS_X86_SIZE64)
+		dhx->dhx_mode = SIZE64;
+	else
+		dhx->dhx_mode = SIZE32;
+
+	if (dhp->dh_flags & DIS_OCTAL)
+		dhx->dhx_dis.d86_flags = DIS_F_OCTAL;
+
+	dhx->dhx_dis.d86_sprintf_func = snprintf;
+	dhx->dhx_dis.d86_get_byte = get_byte;
+	dhx->dhx_dis.d86_sym_lookup = do_lookup;
+	dhx->dhx_dis.d86_check_func = check_func;
+
+	dhx->dhx_dis.d86_data = dhp;
+
+	return (0);
+}
+
+static int
+dis_i386_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf,
+    size_t buflen)
+{
+	dis_handle_i386_t *dhx = dhp->dh_arch_private;
+	dhp->dh_addr = addr;
+
+	/* DIS_NOIMMSYM might not be set until now, so update */
+	if (dhp->dh_flags & DIS_NOIMMSYM)
+		dhx->dhx_dis.d86_flags |= DIS_F_NOIMMSYM;
+	else
+		dhx->dhx_dis.d86_flags &= ~DIS_F_NOIMMSYM;
+
+	if (dtrace_disx86(&dhx->dhx_dis, dhx->dhx_mode) != 0)
+		return (-1);
+
+	if (buf != NULL)
+		dtrace_disx86_str(&dhx->dhx_dis, dhx->dhx_mode, addr, buf,
+		    buflen);
+
+	return (0);
+}
+
+/* ARGSUSED */
+static int
+dis_i386_max_instrlen(dis_handle_t *dhp)
+{
+	return (15);
+}
+
+/* ARGSUSED */
+static int
+dis_i386_min_instrlen(dis_handle_t *dhp)
+{
+	return (1);
+}
+
+#define	MIN(a, b)	((a) < (b) ? (a) : (b))
+
+/*
+ * 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)
+{
+	int archflags = flags & DIS_ARCH_MASK;
+
+	if (archflags == DIS_X86_SIZE16 || archflags == DIS_X86_SIZE32 ||
+	    archflags == DIS_X86_SIZE64)
+		return (1);
+
+	return (0);
+}
+
+dis_arch_t dis_arch_i386 = {
+	dis_i386_supports_flags,
+	dis_i386_handle_attach,
+	dis_i386_handle_detach,
+	dis_i386_disassemble,
+	dis_i386_previnstr,
+	dis_i386_min_instrlen,
+	dis_i386_max_instrlen
+};
