1/*
2 * Copyright 2008, Fran��ois Revol, revol@free.fr
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <OS.h>
7#include <KernelExport.h>
8
9#include <debug.h>
10
11#include "disasm_arch.h"
12#include "elf.h"
13#include "udis86.h"
14
15
16static ud_t sUDState;
17static addr_t sCurrentReadAddress;
18static void (*sSyntax)(ud_t *) = UD_SYN_ATT;
19static unsigned int sVendor = UD_VENDOR_INTEL;
20
21
22static int
23read_next_byte(struct ud*)
24{
25	uint8_t buffer;
26	if (debug_memcpy(B_CURRENT_TEAM, &buffer, (void*)sCurrentReadAddress, 1)
27			!= B_OK) {
28		kprintf("<read fault>\n");
29		return UD_EOI;
30	}
31
32	sCurrentReadAddress++;
33	return buffer;
34}
35
36
37static const char*
38resolve_symbol(struct ud*, uint64_t address, int64_t* offset)
39{
40	const char* symbolName;
41	addr_t baseAddress;
42	status_t error;
43
44	if (IS_KERNEL_ADDRESS(address)) {
45		error = elf_debug_lookup_symbol_address(address, &baseAddress,
46			&symbolName, NULL, NULL);
47	} else {
48		error = elf_debug_lookup_user_symbol_address(
49			debug_get_debugged_thread()->team, address, &baseAddress,
50			&symbolName, NULL, NULL);
51	}
52
53	if (error != B_OK)
54		return NULL;
55
56	*offset = address - baseAddress;
57	return symbolName;
58}
59
60
61static void
62setup_disassembler(addr_t where)
63{
64	ud_set_input_hook(&sUDState, &read_next_byte);
65	sCurrentReadAddress	= where;
66#ifdef __x86_64__
67	ud_set_mode(&sUDState, 64);
68#else
69	ud_set_mode(&sUDState, 32);
70#endif
71	ud_set_pc(&sUDState, (uint64_t)where);
72	ud_set_syntax(&sUDState, sSyntax);
73	ud_set_vendor(&sUDState, sVendor);
74	ud_set_sym_resolver(&sUDState, resolve_symbol);
75}
76
77
78extern "C" void
79disasm_arch_assert(const char *condition)
80{
81	kprintf("assert: %s\n", condition);
82}
83
84
85status_t
86disasm_arch_dump_insns(addr_t where, int count, addr_t baseAddress,
87	int backCount)
88{
89	int skipCount = 0;
90
91	if (backCount > 0) {
92		// count the instructions from base address to start address
93		setup_disassembler(baseAddress);
94		addr_t address = baseAddress;
95		int baseCount = 0;
96		int len;
97		while (address < where && (len = ud_disassemble(&sUDState)) >= 1) {
98			address += len;
99			baseCount++;
100		}
101
102		if (address == where) {
103			if (baseCount > backCount)
104				skipCount = baseCount - backCount;
105			count += baseCount;
106		} else
107			baseAddress = where;
108	} else
109		baseAddress = where;
110
111	setup_disassembler(baseAddress);
112
113	for (int i = 0; i < count; i++) {
114		int ret;
115		ret = ud_disassemble(&sUDState);
116		if (ret < 1)
117			break;
118
119		if (skipCount > 0) {
120			skipCount--;
121			continue;
122		}
123
124		addr_t address = (addr_t)ud_insn_off(&sUDState);
125		if (address == where)
126			kprintf("\x1b[34m");
127
128		// TODO: dig operands and lookup symbols
129		kprintf("0x%08lx: %16.16s\t%s\n", address, ud_insn_hex(&sUDState),
130			ud_insn_asm(&sUDState));
131
132		if (address == where)
133			kprintf("\x1b[m");
134	}
135	return B_OK;
136}
137
138
139status_t
140disasm_arch_init()
141{
142	ud_init(&sUDState);
143	// XXX: check for AMD and set sVendor;
144	return B_OK;
145}
146
147
148status_t
149disasm_arch_fini()
150{
151	return B_OK;
152}
153
154
155