17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5dc0093f4Seschrock * Common Development and Distribution License (the "License").
6dc0093f4Seschrock * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
2280148899SSurya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
25*7aa76ffcSBryan Cantrill /*
26*7aa76ffcSBryan Cantrill * Copyright 2011 Joyent, Inc. All rights reserved.
27*7aa76ffcSBryan Cantrill */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #include <mdb/mdb_disasm_impl.h>
307c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
317c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h>
327c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
337c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
347c478bd9Sstevel@tonic-gate #include <mdb/mdb_nv.h>
357c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
367c478bd9Sstevel@tonic-gate
37dc0093f4Seschrock #include <libdisasm.h>
38dc0093f4Seschrock
397c478bd9Sstevel@tonic-gate int
mdb_dis_select(const char * name)407c478bd9Sstevel@tonic-gate mdb_dis_select(const char *name)
417c478bd9Sstevel@tonic-gate {
427c478bd9Sstevel@tonic-gate mdb_var_t *v = mdb_nv_lookup(&mdb.m_disasms, name);
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate if (v != NULL) {
457c478bd9Sstevel@tonic-gate mdb.m_disasm = mdb_nv_get_cookie(v);
467c478bd9Sstevel@tonic-gate return (0);
477c478bd9Sstevel@tonic-gate }
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate if (mdb.m_target == NULL) {
507c478bd9Sstevel@tonic-gate if (mdb.m_defdisasm != NULL)
517c478bd9Sstevel@tonic-gate strfree(mdb.m_defdisasm);
527c478bd9Sstevel@tonic-gate mdb.m_defdisasm = strdup(name);
537c478bd9Sstevel@tonic-gate return (0);
547c478bd9Sstevel@tonic-gate }
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NODIS));
577c478bd9Sstevel@tonic-gate }
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate mdb_disasm_t *
mdb_dis_create(mdb_dis_ctor_f * ctor)607c478bd9Sstevel@tonic-gate mdb_dis_create(mdb_dis_ctor_f *ctor)
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate mdb_disasm_t *dp = mdb_zalloc(sizeof (mdb_disasm_t), UM_SLEEP);
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate if ((dp->dis_module = mdb.m_lmod) == NULL)
657c478bd9Sstevel@tonic-gate dp->dis_module = &mdb.m_rmod;
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate if (ctor(dp) == 0) {
687c478bd9Sstevel@tonic-gate mdb_var_t *v = mdb_nv_lookup(&mdb.m_disasms, dp->dis_name);
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate if (v != NULL) {
717c478bd9Sstevel@tonic-gate dp->dis_ops->dis_destroy(dp);
727c478bd9Sstevel@tonic-gate mdb_free(dp, sizeof (mdb_disasm_t));
737c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_DISEXISTS);
747c478bd9Sstevel@tonic-gate return (NULL);
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_disasms, dp->dis_name, NULL,
787c478bd9Sstevel@tonic-gate (uintptr_t)dp, MDB_NV_RDONLY | MDB_NV_SILENT);
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate if (mdb.m_disasm == NULL) {
817c478bd9Sstevel@tonic-gate mdb.m_disasm = dp;
827c478bd9Sstevel@tonic-gate } else if (mdb.m_defdisasm != NULL &&
837c478bd9Sstevel@tonic-gate strcmp(mdb.m_defdisasm, dp->dis_name) == 0) {
847c478bd9Sstevel@tonic-gate mdb.m_disasm = dp;
857c478bd9Sstevel@tonic-gate strfree(mdb.m_defdisasm);
867c478bd9Sstevel@tonic-gate mdb.m_defdisasm = NULL;
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate return (dp);
907c478bd9Sstevel@tonic-gate }
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate mdb_free(dp, sizeof (mdb_disasm_t));
937c478bd9Sstevel@tonic-gate return (NULL);
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate void
mdb_dis_destroy(mdb_disasm_t * dp)977c478bd9Sstevel@tonic-gate mdb_dis_destroy(mdb_disasm_t *dp)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate mdb_var_t *v = mdb_nv_lookup(&mdb.m_disasms, dp->dis_name);
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate ASSERT(v != NULL);
1027c478bd9Sstevel@tonic-gate mdb_nv_remove(&mdb.m_disasms, v);
1037c478bd9Sstevel@tonic-gate dp->dis_ops->dis_destroy(dp);
1047c478bd9Sstevel@tonic-gate mdb_free(dp, sizeof (mdb_disasm_t));
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate if (mdb.m_disasm == dp)
1077c478bd9Sstevel@tonic-gate (void) mdb_dis_select("default");
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate mdb_tgt_addr_t
mdb_dis_ins2str(mdb_disasm_t * dp,mdb_tgt_t * t,mdb_tgt_as_t as,char * buf,size_t len,mdb_tgt_addr_t addr)1117c478bd9Sstevel@tonic-gate mdb_dis_ins2str(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
1127c478bd9Sstevel@tonic-gate char *buf, size_t len, mdb_tgt_addr_t addr)
1137c478bd9Sstevel@tonic-gate {
1147c478bd9Sstevel@tonic-gate return (dp->dis_ops->dis_ins2str(dp, t, as, buf, len, addr));
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate mdb_tgt_addr_t
mdb_dis_previns(mdb_disasm_t * dp,mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,uint_t n)1187c478bd9Sstevel@tonic-gate mdb_dis_previns(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
1197c478bd9Sstevel@tonic-gate mdb_tgt_addr_t addr, uint_t n)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate return (dp->dis_ops->dis_previns(dp, t, as, addr, n));
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate mdb_tgt_addr_t
mdb_dis_nextins(mdb_disasm_t * dp,mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr)1257c478bd9Sstevel@tonic-gate mdb_dis_nextins(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
1267c478bd9Sstevel@tonic-gate mdb_tgt_addr_t addr)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate return (dp->dis_ops->dis_nextins(dp, t, as, addr));
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1327c478bd9Sstevel@tonic-gate int
cmd_dismode(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1337c478bd9Sstevel@tonic-gate cmd_dismode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc > 1)
1367c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate if (argc != 0) {
1397c478bd9Sstevel@tonic-gate const char *name;
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate if (argv->a_type == MDB_TYPE_STRING)
1427c478bd9Sstevel@tonic-gate name = argv->a_un.a_str;
1437c478bd9Sstevel@tonic-gate else
1447c478bd9Sstevel@tonic-gate name = numtostr(argv->a_un.a_val, 10, NTOS_UNSIGNED);
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate if (mdb_dis_select(name) == -1) {
1477c478bd9Sstevel@tonic-gate warn("failed to set disassembly mode");
1487c478bd9Sstevel@tonic-gate return (DCMD_ERR);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate mdb_printf("disassembly mode is %s (%s)\n",
1537c478bd9Sstevel@tonic-gate mdb.m_disasm->dis_name, mdb.m_disasm->dis_desc);
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate return (DCMD_OK);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1597c478bd9Sstevel@tonic-gate static int
print_dis(mdb_var_t * v,void * ignore)1607c478bd9Sstevel@tonic-gate print_dis(mdb_var_t *v, void *ignore)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate mdb_disasm_t *dp = mdb_nv_get_cookie(v);
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate mdb_printf("%-24s - %s\n", dp->dis_name, dp->dis_desc);
1657c478bd9Sstevel@tonic-gate return (0);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1697c478bd9Sstevel@tonic-gate int
cmd_disasms(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1707c478bd9Sstevel@tonic-gate cmd_disasms(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1717c478bd9Sstevel@tonic-gate {
1727c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc != 0)
1737c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate mdb_nv_sort_iter(&mdb.m_disasms, print_dis, NULL, UM_SLEEP | UM_GC);
1767c478bd9Sstevel@tonic-gate return (DCMD_OK);
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate
179dc0093f4Seschrock /*
180dc0093f4Seschrock * Generic libdisasm disassembler interfaces.
181dc0093f4Seschrock */
182dc0093f4Seschrock
183dc0093f4Seschrock #define DISBUFSZ 64
184dc0093f4Seschrock
185dc0093f4Seschrock /*
186dc0093f4Seschrock * Internal structure used by the read and lookup routines.
187dc0093f4Seschrock */
188dc0093f4Seschrock typedef struct dis_buf {
189dc0093f4Seschrock mdb_tgt_t *db_tgt;
190dc0093f4Seschrock mdb_tgt_as_t db_as;
191dc0093f4Seschrock mdb_tgt_addr_t db_addr;
192dc0093f4Seschrock mdb_tgt_addr_t db_nextaddr;
193dc0093f4Seschrock uchar_t db_buf[DISBUFSZ];
194dc0093f4Seschrock ssize_t db_bufsize;
195108ba071Seschrock boolean_t db_readerr;
196dc0093f4Seschrock } dis_buf_t;
197dc0093f4Seschrock
198dc0093f4Seschrock /*
199dc0093f4Seschrock * Disassembler support routine for lookup up an address. Rely on mdb's "%a"
200dc0093f4Seschrock * qualifier to convert the address to a symbol.
201dc0093f4Seschrock */
202dc0093f4Seschrock /*ARGSUSED*/
203dc0093f4Seschrock static int
libdisasm_lookup(void * data,uint64_t addr,char * buf,size_t buflen,uint64_t * start,size_t * len)204dc0093f4Seschrock libdisasm_lookup(void *data, uint64_t addr, char *buf, size_t buflen,
205dc0093f4Seschrock uint64_t *start, size_t *len)
206dc0093f4Seschrock {
207d79705c6Seschrock char c;
208dc0093f4Seschrock GElf_Sym sym;
209dc0093f4Seschrock
210d79705c6Seschrock if (buf != NULL) {
211dc0093f4Seschrock #ifdef __sparc
212dc0093f4Seschrock uint32_t instr[3];
213dc0093f4Seschrock uint32_t dtrace_id;
214dc0093f4Seschrock
215dc0093f4Seschrock /*
216dc0093f4Seschrock * On SPARC, DTrace FBT trampoline entries have a sethi/or pair
217dc0093f4Seschrock * that indicates the dtrace probe id; this may appear as the
218dc0093f4Seschrock * first two instructions or one instruction into the
219dc0093f4Seschrock * trampoline.
220dc0093f4Seschrock */
221dc0093f4Seschrock if (mdb_vread(instr, sizeof (instr), (uintptr_t)addr) ==
222dc0093f4Seschrock sizeof (instr)) {
223dc0093f4Seschrock if ((instr[0] & 0xfffc0000) == 0x11000000 &&
224dc0093f4Seschrock (instr[1] & 0xffffe000) == 0x90122000) {
225dc0093f4Seschrock dtrace_id = (instr[0] << 10) |
226dc0093f4Seschrock (instr[1] & 0x1fff);
227dc0093f4Seschrock (void) mdb_snprintf(buf, sizeof (buf), "dt=%#x",
228dc0093f4Seschrock dtrace_id);
229dc0093f4Seschrock goto out;
230dc0093f4Seschrock } else if ((instr[1] & 0xfffc0000) == 0x11000000 &&
231dc0093f4Seschrock (instr[2] & 0xffffe000) == 0x90122000) {
232dc0093f4Seschrock dtrace_id = (instr[1] << 10) |
233dc0093f4Seschrock (instr[2] & 0x1fff);
234dc0093f4Seschrock (void) mdb_snprintf(buf, sizeof (buf), "dt=%#x",
235dc0093f4Seschrock dtrace_id);
236dc0093f4Seschrock goto out;
237dc0093f4Seschrock }
238dc0093f4Seschrock }
239dc0093f4Seschrock #endif
240d79705c6Seschrock (void) mdb_snprintf(buf, buflen, "%a", (uintptr_t)addr);
241dc0093f4Seschrock }
242dc0093f4Seschrock
243dc0093f4Seschrock #ifdef __sparc
244dc0093f4Seschrock out:
245dc0093f4Seschrock #endif
246dc0093f4Seschrock if (mdb_lookup_by_addr(addr, MDB_SYM_FUZZY, &c, 1, &sym) < 0)
247dc0093f4Seschrock return (-1);
248dc0093f4Seschrock if (start != NULL)
249dc0093f4Seschrock *start = sym.st_value;
250dc0093f4Seschrock if (len != NULL)
251dc0093f4Seschrock *len = sym.st_size;
252dc0093f4Seschrock
253dc0093f4Seschrock return (0);
254dc0093f4Seschrock }
255dc0093f4Seschrock
256dc0093f4Seschrock /*
257dc0093f4Seschrock * Disassembler support routine for reading from the target. Rather than having
258dc0093f4Seschrock * to read one byte at a time, we read from the address space in chunks. If the
259dc0093f4Seschrock * current address doesn't lie within our buffer range, we read in the chunk
260dc0093f4Seschrock * starting from the given address.
261dc0093f4Seschrock */
262dc0093f4Seschrock static int
libdisasm_read(void * data,uint64_t pc,void * buf,size_t buflen)263dc0093f4Seschrock libdisasm_read(void *data, uint64_t pc, void *buf, size_t buflen)
264dc0093f4Seschrock {
265dc0093f4Seschrock dis_buf_t *db = data;
266dc0093f4Seschrock size_t offset;
267dc0093f4Seschrock size_t len;
268dc0093f4Seschrock
269dc0093f4Seschrock if (pc - db->db_addr >= db->db_bufsize) {
270108ba071Seschrock if (mdb_tgt_aread(db->db_tgt, db->db_as, db->db_buf,
271108ba071Seschrock sizeof (db->db_buf), pc) != -1) {
272108ba071Seschrock db->db_bufsize = sizeof (db->db_buf);
273108ba071Seschrock } else if (mdb_tgt_aread(db->db_tgt, db->db_as, db->db_buf,
274108ba071Seschrock buflen, pc) != -1) {
275108ba071Seschrock db->db_bufsize = buflen;
276108ba071Seschrock } else {
277108ba071Seschrock if (!db->db_readerr)
278108ba071Seschrock mdb_warn("failed to read instruction at %#lr",
279108ba071Seschrock (uintptr_t)pc);
280108ba071Seschrock db->db_readerr = B_TRUE;
281dc0093f4Seschrock return (-1);
282108ba071Seschrock }
283dc0093f4Seschrock db->db_addr = pc;
284dc0093f4Seschrock }
285dc0093f4Seschrock
286dc0093f4Seschrock offset = pc - db->db_addr;
287dc0093f4Seschrock
288dc0093f4Seschrock len = MIN(buflen, db->db_bufsize - offset);
289dc0093f4Seschrock
29080148899SSurya Prakki (void) memcpy(buf, (char *)db->db_buf + offset, len);
291dc0093f4Seschrock db->db_nextaddr = pc + len;
292dc0093f4Seschrock
293dc0093f4Seschrock return (len);
294dc0093f4Seschrock }
295dc0093f4Seschrock
296dc0093f4Seschrock static mdb_tgt_addr_t
libdisasm_ins2str(mdb_disasm_t * dp,mdb_tgt_t * t,mdb_tgt_as_t as,char * buf,size_t len,mdb_tgt_addr_t pc)297dc0093f4Seschrock libdisasm_ins2str(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
298dc0093f4Seschrock char *buf, size_t len, mdb_tgt_addr_t pc)
299dc0093f4Seschrock {
300dc0093f4Seschrock dis_handle_t *dhp = dp->dis_data;
301dc0093f4Seschrock dis_buf_t db = { 0 };
302f576acbeSdmick const char *p;
303dc0093f4Seschrock
304dc0093f4Seschrock /*
305dc0093f4Seschrock * Set the libdisasm data to point to our buffer. This will be
306dc0093f4Seschrock * passed as the first argument to the lookup and read functions.
307dc0093f4Seschrock */
308dc0093f4Seschrock db.db_tgt = t;
309dc0093f4Seschrock db.db_as = as;
310dc0093f4Seschrock
311dc0093f4Seschrock dis_set_data(dhp, &db);
312dc0093f4Seschrock
313f576acbeSdmick if ((p = mdb_tgt_name(t)) != NULL && strcmp(p, "proc") == 0) {
314e0070315Sdmick /* check for ELF ET_REL type; turn on NOIMMSYM if so */
315e0070315Sdmick
316e0070315Sdmick GElf_Ehdr leh;
317e0070315Sdmick
318e0070315Sdmick if (mdb_tgt_getxdata(t, "ehdr", &leh, sizeof (leh)) != -1 &&
319e0070315Sdmick leh.e_type == ET_REL) {
320e0070315Sdmick dis_flags_set(dhp, DIS_NOIMMSYM);
321e0070315Sdmick } else {
322e0070315Sdmick dis_flags_clear(dhp, DIS_NOIMMSYM);
323e0070315Sdmick }
324e0070315Sdmick }
325e0070315Sdmick
326dc0093f4Seschrock /*
327108ba071Seschrock * Attempt to disassemble the instruction. If this fails because of an
328108ba071Seschrock * unknown opcode, drive on anyway. If it fails because we couldn't
329108ba071Seschrock * read from the target, bail out immediately.
330dc0093f4Seschrock */
331dc0093f4Seschrock if (dis_disassemble(dhp, pc, buf, len) != 0)
332dc0093f4Seschrock (void) mdb_snprintf(buf, len,
333dc0093f4Seschrock "***ERROR--unknown op code***");
334dc0093f4Seschrock
335108ba071Seschrock if (db.db_readerr)
336108ba071Seschrock return (pc);
337108ba071Seschrock
338dc0093f4Seschrock /*
339dc0093f4Seschrock * Return the updated location
340dc0093f4Seschrock */
341dc0093f4Seschrock return (db.db_nextaddr);
342dc0093f4Seschrock }
343dc0093f4Seschrock
344dc0093f4Seschrock static mdb_tgt_addr_t
libdisasm_previns(mdb_disasm_t * dp,mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t pc,uint_t n)345dc0093f4Seschrock libdisasm_previns(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
346dc0093f4Seschrock mdb_tgt_addr_t pc, uint_t n)
347dc0093f4Seschrock {
348dc0093f4Seschrock dis_handle_t *dhp = dp->dis_data;
349dc0093f4Seschrock dis_buf_t db = { 0 };
350dc0093f4Seschrock
351dc0093f4Seschrock /*
352dc0093f4Seschrock * Set the libdisasm data to point to our buffer. This will be
353dc0093f4Seschrock * passed as the first argument to the lookup and read functions.
354108ba071Seschrock * We set 'readerr' to B_TRUE to turn off the mdb_warn() in
355108ba071Seschrock * libdisasm_read, because the code works by probing backwards until a
356108ba071Seschrock * valid address is found.
357dc0093f4Seschrock */
358dc0093f4Seschrock db.db_tgt = t;
359dc0093f4Seschrock db.db_as = as;
360108ba071Seschrock db.db_readerr = B_TRUE;
361dc0093f4Seschrock
362dc0093f4Seschrock dis_set_data(dhp, &db);
363dc0093f4Seschrock
364dc0093f4Seschrock return (dis_previnstr(dhp, pc, n));
365dc0093f4Seschrock }
366dc0093f4Seschrock
367dc0093f4Seschrock /*ARGSUSED*/
368dc0093f4Seschrock static mdb_tgt_addr_t
libdisasm_nextins(mdb_disasm_t * dp,mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t pc)369dc0093f4Seschrock libdisasm_nextins(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
370dc0093f4Seschrock mdb_tgt_addr_t pc)
371dc0093f4Seschrock {
372dc0093f4Seschrock mdb_tgt_addr_t npc;
373dc0093f4Seschrock char c;
374dc0093f4Seschrock
375dc0093f4Seschrock if ((npc = libdisasm_ins2str(dp, t, as, &c, 1, pc)) == pc)
376dc0093f4Seschrock return (pc);
377dc0093f4Seschrock
378dc0093f4Seschrock /*
379dc0093f4Seschrock * Probe the address to make sure we can read something from it - we
380dc0093f4Seschrock * want the address we return to actually contain something.
381dc0093f4Seschrock */
382dc0093f4Seschrock if (mdb_tgt_aread(t, as, &c, 1, npc) != 1)
383dc0093f4Seschrock return (pc);
384dc0093f4Seschrock
385dc0093f4Seschrock return (npc);
386dc0093f4Seschrock }
387dc0093f4Seschrock
388dc0093f4Seschrock static void
libdisasm_destroy(mdb_disasm_t * dp)389dc0093f4Seschrock libdisasm_destroy(mdb_disasm_t *dp)
390dc0093f4Seschrock {
391dc0093f4Seschrock dis_handle_t *dhp = dp->dis_data;
392dc0093f4Seschrock
393dc0093f4Seschrock dis_handle_destroy(dhp);
394dc0093f4Seschrock }
395dc0093f4Seschrock
396dc0093f4Seschrock static const mdb_dis_ops_t libdisasm_ops = {
397dc0093f4Seschrock libdisasm_destroy,
398dc0093f4Seschrock libdisasm_ins2str,
399dc0093f4Seschrock libdisasm_previns,
400dc0093f4Seschrock libdisasm_nextins
401dc0093f4Seschrock };
402dc0093f4Seschrock
403dc0093f4Seschrock /*
404dc0093f4Seschrock * Generic function for creating a libdisasm-backed disassembler. Creates an
405dc0093f4Seschrock * MDB disassembler with the given name backed by libdis with the given flags.
406dc0093f4Seschrock */
407dc0093f4Seschrock static int
libdisasm_create(mdb_disasm_t * dp,const char * name,const char * desc,int flags)408dc0093f4Seschrock libdisasm_create(mdb_disasm_t *dp, const char *name,
409dc0093f4Seschrock const char *desc, int flags)
410dc0093f4Seschrock {
411dc0093f4Seschrock if ((dp->dis_data = dis_handle_create(flags, NULL, libdisasm_lookup,
412dc0093f4Seschrock libdisasm_read)) == NULL)
413dc0093f4Seschrock return (-1);
414dc0093f4Seschrock
415dc0093f4Seschrock dp->dis_name = name;
416dc0093f4Seschrock dp->dis_ops = &libdisasm_ops;
417dc0093f4Seschrock dp->dis_desc = desc;
418dc0093f4Seschrock
419dc0093f4Seschrock return (0);
420dc0093f4Seschrock }
421dc0093f4Seschrock
422dc0093f4Seschrock #if defined(__i386) || defined(__amd64)
423dc0093f4Seschrock static int
ia16_create(mdb_disasm_t * dp)424*7aa76ffcSBryan Cantrill ia16_create(mdb_disasm_t *dp)
425*7aa76ffcSBryan Cantrill {
426*7aa76ffcSBryan Cantrill return (libdisasm_create(dp,
427*7aa76ffcSBryan Cantrill "ia16",
428*7aa76ffcSBryan Cantrill "Intel 16-bit disassembler",
429*7aa76ffcSBryan Cantrill DIS_X86_SIZE16));
430*7aa76ffcSBryan Cantrill }
431*7aa76ffcSBryan Cantrill
432*7aa76ffcSBryan Cantrill static int
ia32_create(mdb_disasm_t * dp)433dc0093f4Seschrock ia32_create(mdb_disasm_t *dp)
434dc0093f4Seschrock {
435dc0093f4Seschrock return (libdisasm_create(dp,
436dc0093f4Seschrock "ia32",
437dc0093f4Seschrock "Intel 32-bit disassembler",
438dc0093f4Seschrock DIS_X86_SIZE32));
439dc0093f4Seschrock }
440dc0093f4Seschrock #endif
441dc0093f4Seschrock
442dc0093f4Seschrock #if defined(__amd64)
443dc0093f4Seschrock static int
amd64_create(mdb_disasm_t * dp)444dc0093f4Seschrock amd64_create(mdb_disasm_t *dp)
445dc0093f4Seschrock {
446dc0093f4Seschrock return (libdisasm_create(dp,
447dc0093f4Seschrock "amd64",
448dc0093f4Seschrock "AMD64 and IA32e 64-bit disassembler",
449dc0093f4Seschrock DIS_X86_SIZE64));
450dc0093f4Seschrock }
451dc0093f4Seschrock #endif
452dc0093f4Seschrock
453dc0093f4Seschrock #if defined(__sparc)
454dc0093f4Seschrock static int
sparc1_create(mdb_disasm_t * dp)455dc0093f4Seschrock sparc1_create(mdb_disasm_t *dp)
456dc0093f4Seschrock {
457dc0093f4Seschrock return (libdisasm_create(dp,
458dc0093f4Seschrock "1",
459dc0093f4Seschrock "SPARC-v8 disassembler",
460dc0093f4Seschrock DIS_SPARC_V8));
461dc0093f4Seschrock }
462dc0093f4Seschrock
463dc0093f4Seschrock static int
sparc2_create(mdb_disasm_t * dp)464dc0093f4Seschrock sparc2_create(mdb_disasm_t *dp)
465dc0093f4Seschrock {
466dc0093f4Seschrock return (libdisasm_create(dp,
467dc0093f4Seschrock "2",
468dc0093f4Seschrock "SPARC-v9 disassembler",
469dc0093f4Seschrock DIS_SPARC_V9));
470dc0093f4Seschrock }
471dc0093f4Seschrock
472dc0093f4Seschrock static int
sparc4_create(mdb_disasm_t * dp)473dc0093f4Seschrock sparc4_create(mdb_disasm_t *dp)
474dc0093f4Seschrock {
475dc0093f4Seschrock return (libdisasm_create(dp,
476dc0093f4Seschrock "4",
477dc0093f4Seschrock "UltraSPARC1-v9 disassembler",
478dc0093f4Seschrock DIS_SPARC_V9 | DIS_SPARC_V9_SGI));
479dc0093f4Seschrock }
480dc0093f4Seschrock
481dc0093f4Seschrock static int
sparcv8_create(mdb_disasm_t * dp)482dc0093f4Seschrock sparcv8_create(mdb_disasm_t *dp)
483dc0093f4Seschrock {
484dc0093f4Seschrock return (libdisasm_create(dp,
485dc0093f4Seschrock "v8",
486dc0093f4Seschrock "SPARC-v8 disassembler",
487dc0093f4Seschrock DIS_SPARC_V8));
488dc0093f4Seschrock }
489dc0093f4Seschrock
490dc0093f4Seschrock static int
sparcv9_create(mdb_disasm_t * dp)491dc0093f4Seschrock sparcv9_create(mdb_disasm_t *dp)
492dc0093f4Seschrock {
493dc0093f4Seschrock return (libdisasm_create(dp,
494dc0093f4Seschrock "v9",
495dc0093f4Seschrock "SPARC-v9 disassembler",
496dc0093f4Seschrock DIS_SPARC_V9));
497dc0093f4Seschrock }
498dc0093f4Seschrock
499dc0093f4Seschrock static int
sparcv9plus_create(mdb_disasm_t * dp)500dc0093f4Seschrock sparcv9plus_create(mdb_disasm_t *dp)
501dc0093f4Seschrock {
502dc0093f4Seschrock return (libdisasm_create(dp,
503dc0093f4Seschrock "v9plus",
504dc0093f4Seschrock "UltraSPARC1-v9 disassembler",
505dc0093f4Seschrock DIS_SPARC_V9 | DIS_SPARC_V9_SGI));
506dc0093f4Seschrock }
507dc0093f4Seschrock #endif
508dc0093f4Seschrock
5097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5107c478bd9Sstevel@tonic-gate static void
defdis_destroy(mdb_disasm_t * dp)5117c478bd9Sstevel@tonic-gate defdis_destroy(mdb_disasm_t *dp)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate /* Nothing to do here */
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5177c478bd9Sstevel@tonic-gate static mdb_tgt_addr_t
defdis_ins2str(mdb_disasm_t * dp,mdb_tgt_t * t,mdb_tgt_as_t as,char * buf,size_t len,mdb_tgt_addr_t addr)5187c478bd9Sstevel@tonic-gate defdis_ins2str(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
5197c478bd9Sstevel@tonic-gate char *buf, size_t len, mdb_tgt_addr_t addr)
5207c478bd9Sstevel@tonic-gate {
5217c478bd9Sstevel@tonic-gate return (addr);
5227c478bd9Sstevel@tonic-gate }
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5257c478bd9Sstevel@tonic-gate static mdb_tgt_addr_t
defdis_previns(mdb_disasm_t * dp,mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,uint_t n)5267c478bd9Sstevel@tonic-gate defdis_previns(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
5277c478bd9Sstevel@tonic-gate mdb_tgt_addr_t addr, uint_t n)
5287c478bd9Sstevel@tonic-gate {
5297c478bd9Sstevel@tonic-gate return (addr);
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5337c478bd9Sstevel@tonic-gate static mdb_tgt_addr_t
defdis_nextins(mdb_disasm_t * dp,mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr)5347c478bd9Sstevel@tonic-gate defdis_nextins(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
5357c478bd9Sstevel@tonic-gate mdb_tgt_addr_t addr)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate return (addr);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate static const mdb_dis_ops_t defdis_ops = {
5417c478bd9Sstevel@tonic-gate defdis_destroy,
5427c478bd9Sstevel@tonic-gate defdis_ins2str,
5437c478bd9Sstevel@tonic-gate defdis_previns,
5447c478bd9Sstevel@tonic-gate defdis_nextins
5457c478bd9Sstevel@tonic-gate };
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate static int
defdis_create(mdb_disasm_t * dp)5487c478bd9Sstevel@tonic-gate defdis_create(mdb_disasm_t *dp)
5497c478bd9Sstevel@tonic-gate {
5507c478bd9Sstevel@tonic-gate dp->dis_name = "default";
5517c478bd9Sstevel@tonic-gate dp->dis_desc = "default no-op disassembler";
5527c478bd9Sstevel@tonic-gate dp->dis_ops = &defdis_ops;
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate return (0);
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate
5577c478bd9Sstevel@tonic-gate mdb_dis_ctor_f *const mdb_dis_builtins[] = {
558dc0093f4Seschrock defdis_create,
5597c478bd9Sstevel@tonic-gate #if defined(__amd64)
560*7aa76ffcSBryan Cantrill ia16_create,
5617c478bd9Sstevel@tonic-gate ia32_create,
5627c478bd9Sstevel@tonic-gate amd64_create,
5637c478bd9Sstevel@tonic-gate #elif defined(__i386)
564*7aa76ffcSBryan Cantrill ia16_create,
5657c478bd9Sstevel@tonic-gate ia32_create,
566dc0093f4Seschrock #elif defined(__sparc)
567dc0093f4Seschrock sparc1_create,
568dc0093f4Seschrock sparc2_create,
569dc0093f4Seschrock sparc4_create,
570dc0093f4Seschrock sparcv8_create,
571dc0093f4Seschrock sparcv9_create,
572dc0093f4Seschrock sparcv9plus_create,
5737c478bd9Sstevel@tonic-gate #endif
5747c478bd9Sstevel@tonic-gate NULL
5757c478bd9Sstevel@tonic-gate };
576