* Added option "-b <count>" to "dis". It causes up to <count>

instructions to be printed before the given address. The feature is
  implemented by looking up the address of the previous symbol for the
  given address and disassembling forward (two passes).
* The instuction at given address is printed highlighted (blue).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27191 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2008-08-24 21:53:43 +00:00
parent 1b20a9a58e
commit 23fdebca54
7 changed files with 113 additions and 28 deletions

View File

@ -1,6 +1,6 @@
SubDir HAIKU_TOP src add-ons kernel debugger disasm ;
UsePrivateHeaders kernel ;
UsePrivateKernelHeaders ;
KernelAddon <kdebug>disasm :
disasm.cpp

View File

@ -5,6 +5,8 @@
#include <arch/debug.h>
#include <debug.h>
#include <elf.h>
#include <kernel.h>
#include <signal.h>
#include "disasm_arch.h"
@ -13,15 +15,29 @@
int
disasm_command(int argc, char **argv)
{
if (argc > 3) {
int argi = 1;
// get back count
uint64 backCount = 0;
if (argi < argc && strcmp(argv[argi], "-b") == 0) {
if (++argi >= argc) {
print_debugger_command_usage(argv[0]);
return 0;
}
if (!evaluate_debug_expression(argv[argi++], &backCount, false))
return 0;
}
if (argi + 2 < argc) {
print_debugger_command_usage(argv[0]);
return 0;
}
// get PC
uint64 pc;
if (argc >= 2) {
if (!evaluate_debug_expression(argv[1], &pc, false))
if (argi < argc) {
if (!evaluate_debug_expression(argv[argi++], &pc, false))
return 0;
} else {
pc = (addr_t)arch_debug_get_interrupt_pc();
@ -33,14 +49,37 @@ disasm_command(int argc, char **argv)
// get count
uint64 count = 10;
if (argc >= 3) {
if (!evaluate_debug_expression(argv[2], &count, false))
if (argi < argc) {
if (!evaluate_debug_expression(argv[argi++], &count, false))
return 0;
}
// TODO: autoincrement
disasm_arch_dump_insns((addr_t)pc, count);
// if back count is given, compute base address
addr_t baseAddress = 0;
if (backCount > 0) {
status_t error;
const char *symbol;
const char *imageName;
bool exactMatch;
if (IS_KERNEL_ADDRESS(pc)) {
error = elf_debug_lookup_symbol_address(pc, &baseAddress, &symbol,
&imageName, &exactMatch);
} else {
error = elf_debug_lookup_user_symbol_address(
debug_get_debugged_thread()->team, pc, &baseAddress, &symbol,
&imageName, &exactMatch);
}
if (error != B_OK) {
baseAddress = 0;
backCount = 0;
}
}
disasm_arch_dump_insns((addr_t)pc, count, baseAddress, backCount);
return 0;
}
@ -56,11 +95,14 @@ std_ops(int32 op, ...)
return err;
return add_debugger_command_etc("dis", disasm_command,
"Print disassembly at address",
"[ <address> [ <count> ] ]\n"
"[ -b <back count> ] [ <address> [ <count> ] ]\n"
"Prints disassembly at address.\n"
" <address> - Address at which to start disassembling\n"
" (defaults to current PC).\n"
" <count> - Number of instructions to disassemble.\n", 0);
" <address> - Address at which to start disassembling\n"
" (defaults to current PC).\n"
" <count> - Number of instructions to disassemble\n"
" starting at <address>.\n"
" -b <back count> - Number of instruction to disassemble before\n"
" <address>.\n", 0);
} else if (op == B_MODULE_UNINIT) {
remove_debugger_command("dis", disasm_command);
return disasm_arch_fini();

View File

@ -12,7 +12,8 @@ extern "C" {
extern status_t disasm_arch_init();
extern status_t disasm_arch_fini();
extern status_t disasm_arch_dump_insns(addr_t where, int count);
extern status_t disasm_arch_dump_insns(addr_t where, int count,
addr_t baseAddress, int backCount);
#ifdef __cplusplus
}

View File

@ -8,7 +8,8 @@
#include "disasm_arch.h"
status_t
disasm_arch_dump_insns(addr_t where, int count)
disasm_arch_dump_insns(addr_t where, int count, addr_t baseAddress,
int backCount)
{
return ENOENT;
}

View File

@ -8,7 +8,8 @@
#include "disasm_arch.h"
status_t
disasm_arch_dump_insns(addr_t where, int count)
disasm_arch_dump_insns(addr_t where, int count, addr_t baseAddress,
int backCount)
{
return ENOENT;
}

View File

@ -9,6 +9,7 @@
#include "disasm_arch.h"
#include "udis86.h"
static ud_t sUDState;
static addr_t sCurrentReadAddress;
static void (*sSyntax)(ud_t *) = UD_SYN_ATT;
@ -29,6 +30,18 @@ read_next_byte(struct ud*)
}
static void
setup_disassembler(addr_t where)
{
ud_set_input_hook(&sUDState, &read_next_byte);
sCurrentReadAddress = where;
ud_set_mode(&sUDState, 32);
ud_set_pc(&sUDState, (uint64_t)where);
ud_set_syntax(&sUDState, sSyntax);
ud_set_vendor(&sUDState, sVendor);
}
extern "C" void
disasm_arch_assert(const char *condition)
{
@ -37,27 +50,54 @@ disasm_arch_assert(const char *condition)
status_t
disasm_arch_dump_insns(addr_t where, int count)
disasm_arch_dump_insns(addr_t where, int count, addr_t baseAddress,
int backCount)
{
//status_t err;
int i;
int skipCount = 0;
ud_set_input_hook(&sUDState, &read_next_byte);
sCurrentReadAddress = where;
ud_set_mode(&sUDState, 32);
ud_set_pc(&sUDState, (uint64_t)where);
ud_set_syntax(&sUDState, sSyntax);
ud_set_vendor(&sUDState, sVendor);
for (i = 0; i < count; i++) {
if (backCount > 0) {
// count the instructions from base address to start address
setup_disassembler(baseAddress);
addr_t address = baseAddress;
int baseCount = 0;
int len;
while (address < where && (len = ud_disassemble(&sUDState)) >= 1) {
address += len;
baseCount++;
}
if (address == where) {
if (baseCount > backCount)
skipCount = baseCount - backCount;
count += baseCount;
} else
baseAddress = where;
} else
baseAddress = where;
setup_disassembler(baseAddress);
for (int i = 0; i < count; i++) {
int ret;
ret = ud_disassemble(&sUDState);
if (ret < 1)
break;
if (skipCount > 0) {
skipCount--;
continue;
}
addr_t address = (addr_t)ud_insn_off(&sUDState);
if (address == where)
kprintf("\x1b[34m");
// TODO: dig operands and lookup symbols
kprintf("0x%08lx: %16.16s\t%s\n",
(uint32)(/*where +*/ ud_insn_off(&sUDState)),
ud_insn_hex(&sUDState),
kprintf("0x%08lx: %16.16s\t%s\n", address, ud_insn_hex(&sUDState),
ud_insn_asm(&sUDState));
if (address == where)
kprintf("\x1b[m");
}
return B_OK;
}