diff options
Diffstat (limited to 'usr/src/cmd')
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_disasm.c | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_disasm.c b/usr/src/cmd/mdb/common/mdb/mdb_disasm.c index 94a02ebd25..494fc8f659 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_disasm.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_disasm.c @@ -191,6 +191,7 @@ typedef struct dis_buf { mdb_tgt_addr_t db_nextaddr; uchar_t db_buf[DISBUFSZ]; ssize_t db_bufsize; + boolean_t db_readerr; } dis_buf_t; /* @@ -267,9 +268,19 @@ libdisasm_read(void *data, uint64_t pc, void *buf, size_t buflen) size_t len; if (pc - db->db_addr >= db->db_bufsize) { - if ((db->db_bufsize = mdb_tgt_aread(db->db_tgt, db->db_as, - db->db_buf, sizeof (db->db_buf), pc)) == -1) + if (mdb_tgt_aread(db->db_tgt, db->db_as, db->db_buf, + sizeof (db->db_buf), pc) != -1) { + db->db_bufsize = sizeof (db->db_buf); + } else if (mdb_tgt_aread(db->db_tgt, db->db_as, db->db_buf, + buflen, pc) != -1) { + db->db_bufsize = buflen; + } else { + if (!db->db_readerr) + mdb_warn("failed to read instruction at %#lr", + (uintptr_t)pc); + db->db_readerr = B_TRUE; return (-1); + } db->db_addr = pc; } @@ -300,12 +311,17 @@ libdisasm_ins2str(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as, dis_set_data(dhp, &db); /* - * Attempt to disassemble the instruction + * Attempt to disassemble the instruction. If this fails because of an + * unknown opcode, drive on anyway. If it fails because we couldn't + * read from the target, bail out immediately. */ if (dis_disassemble(dhp, pc, buf, len) != 0) (void) mdb_snprintf(buf, len, "***ERROR--unknown op code***"); + if (db.db_readerr) + return (pc); + /* * Return the updated location */ @@ -322,9 +338,13 @@ libdisasm_previns(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as, /* * Set the libdisasm data to point to our buffer. This will be * passed as the first argument to the lookup and read functions. + * We set 'readerr' to B_TRUE to turn off the mdb_warn() in + * libdisasm_read, because the code works by probing backwards until a + * valid address is found. */ db.db_tgt = t; db.db_as = as; + db.db_readerr = B_TRUE; dis_set_data(dhp, &db); |