11541Srgrimes/*
21541Srgrimes * Copyright 2008, Fran��ois Revol, revol@free.fr
31541Srgrimes * Distributed under the terms of the MIT License.
41541Srgrimes */
51541Srgrimes
61541Srgrimes#include <OS.h>
71541Srgrimes#include <KernelExport.h>
81541Srgrimes
91541Srgrimes#include <debug.h>
101541Srgrimes
111541Srgrimes#include "disasm_arch.h"
121541Srgrimes#include "elf.h"
131541Srgrimes#include "udis86.h"
141541Srgrimes
151541Srgrimes
161541Srgrimesstatic ud_t sUDState;
171541Srgrimesstatic addr_t sCurrentReadAddress;
181541Srgrimesstatic void (*sSyntax)(ud_t *) = UD_SYN_ATT;
191541Srgrimesstatic unsigned int sVendor = UD_VENDOR_INTEL;
201541Srgrimes
211541Srgrimes
221541Srgrimesstatic int
231541Srgrimesread_next_byte(struct ud*)
241541Srgrimes{
251541Srgrimes	uint8_t buffer;
261541Srgrimes	if (debug_memcpy(B_CURRENT_TEAM, &buffer, (void*)sCurrentReadAddress, 1)
271541Srgrimes			!= B_OK) {
281541Srgrimes		kprintf("<read fault>\n");
291541Srgrimes		return UD_EOI;
301541Srgrimes	}
311541Srgrimes
321541Srgrimes	sCurrentReadAddress++;
331541Srgrimes	return buffer;
341541Srgrimes}
351541Srgrimes
361541Srgrimes
3722521Sdysonstatic const char*
3850477Speterresolve_symbol(struct ud*, uint64_t address, int64_t* offset)
391541Srgrimes{
401541Srgrimes	const char* symbolName;
411541Srgrimes	addr_t baseAddress;
421541Srgrimes	status_t error;
4376166Smarkm
4476166Smarkm	if (IS_KERNEL_ADDRESS(address)) {
451541Srgrimes		error = elf_debug_lookup_symbol_address(address, &baseAddress,
467090Sbde			&symbolName, NULL, NULL);
477090Sbde	} else {
4874927Sjhb		error = elf_debug_lookup_user_symbol_address(
4976166Smarkm			debug_get_debugged_thread()->team, address, &baseAddress,
5076166Smarkm			&symbolName, NULL, NULL);
5177031Sru	}
527090Sbde
5322579Smpp	if (error != B_OK)
5422579Smpp		return NULL;
5522521Sdyson
5622521Sdyson	*offset = address - baseAddress;
5722521Sdyson	return symbolName;
587090Sbde}
591541Srgrimes
601541Srgrimes
611541Srgrimesstatic void
621541Srgrimessetup_disassembler(addr_t where)
631541Srgrimes{
641541Srgrimes	ud_set_input_hook(&sUDState, &read_next_byte);
651541Srgrimes	sCurrentReadAddress	= where;
661541Srgrimes#ifdef __x86_64__
671541Srgrimes	ud_set_mode(&sUDState, 64);
681541Srgrimes#else
691541Srgrimes	ud_set_mode(&sUDState, 32);
701541Srgrimes#endif
711541Srgrimes	ud_set_pc(&sUDState, (uint64_t)where);
721541Srgrimes	ud_set_syntax(&sUDState, sSyntax);
731541Srgrimes	ud_set_vendor(&sUDState, sVendor);
741541Srgrimes	ud_set_sym_resolver(&sUDState, resolve_symbol);
751541Srgrimes}
761541Srgrimes
771541Srgrimes
781541Srgrimesextern "C" void
791541Srgrimesdisasm_arch_assert(const char *condition)
801541Srgrimes{
811541Srgrimes	kprintf("assert: %s\n", condition);
821541Srgrimes}
831541Srgrimes
841541Srgrimes
851541Srgrimesstatus_t
861541Srgrimesdisasm_arch_dump_insns(addr_t where, int count, addr_t baseAddress,
871541Srgrimes	int backCount)
881541Srgrimes{
891541Srgrimes	int skipCount = 0;
901541Srgrimes
911541Srgrimes	if (backCount > 0) {
921541Srgrimes		// count the instructions from base address to start address
931541Srgrimes		setup_disassembler(baseAddress);
941541Srgrimes		addr_t address = baseAddress;
951541Srgrimes		int baseCount = 0;
961541Srgrimes		int len;
971541Srgrimes		while (address < where && (len = ud_disassemble(&sUDState)) >= 1) {
981541Srgrimes			address += len;
991541Srgrimes			baseCount++;
1001541Srgrimes		}
1011541Srgrimes
1021541Srgrimes		if (address == where) {
1031541Srgrimes			if (baseCount > backCount)
1041541Srgrimes				skipCount = baseCount - backCount;
10512595Sbde			count += baseCount;
10612595Sbde		} else
1071541Srgrimes			baseAddress = where;
1081541Srgrimes	} else
1091541Srgrimes		baseAddress = where;
1101541Srgrimes
1111541Srgrimes	setup_disassembler(baseAddress);
1121541Srgrimes
11374927Sjhb	for (int i = 0; i < count; i++) {
1141541Srgrimes		int ret;
1151541Srgrimes		ret = ud_disassemble(&sUDState);
11669958Srwatson		if (ret < 1)
11769958Srwatson			break;
11869958Srwatson
11969958Srwatson		if (skipCount > 0) {
12069958Srwatson			skipCount--;
12169958Srwatson			continue;
12269958Srwatson		}
12369958Srwatson
12469958Srwatson		addr_t address = (addr_t)ud_insn_off(&sUDState);
12569958Srwatson		if (address == where)
1261541Srgrimes			kprintf("\x1b[34m");
1271541Srgrimes
1281541Srgrimes		// TODO: dig operands and lookup symbols
1291541Srgrimes		kprintf("0x%08lx: %16.16s\t%s\n", address, ud_insn_hex(&sUDState),
13074927Sjhb			ud_insn_asm(&sUDState));
13173918Sjhb
13273918Sjhb		if (address == where)
13374927Sjhb			kprintf("\x1b[m");
13474927Sjhb	}
13573918Sjhb	return B_OK;
1361541Srgrimes}
13774996Sjhb
13873918Sjhb
13974927Sjhbstatus_t
14074927Sjhbdisasm_arch_init()
14173918Sjhb{
1421541Srgrimes	ud_init(&sUDState);
1431541Srgrimes	// XXX: check for AMD and set sVendor;
1441541Srgrimes	return B_OK;
1451541Srgrimes}
1461541Srgrimes
1471541Srgrimes
1481541Srgrimesstatus_t
1491541Srgrimesdisasm_arch_fini()
1501541Srgrimes{
1511541Srgrimes	return B_OK;
1526569Sdg}
1531541Srgrimes
1541541Srgrimes
1551541Srgrimes