* Copyright 2008, FranΓ§ois Revol, revol@free.fr
* Distributed under the terms of the MIT License.
*/
#include <OS.h>
#include <KernelExport.h>
#include <debug.h>
#include <stdio.h>
#include "Zycore/Format.h"
#include "Zydis/Zydis.h"
#include "disasm_arch.h"
#include "elf.h"
static ZydisDecoder sDecoder;
static ZydisFormatter sFormatter;
static ZydisFormatterFunc sDefaultPrintAddressAbsolute;
static ZyanStatus
ZydisFormatterPrintAddressAbsolute(const ZydisFormatter* formatter, ZydisFormatterBuffer* buffer,
ZydisFormatterContext* context)
{
ZyanU64 address;
ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand,
context->runtime_address, &address));
const char* symbolName;
addr_t baseAddress;
status_t error;
if (IS_KERNEL_ADDRESS(address)) {
error = elf_debug_lookup_symbol_address(address, &baseAddress,
&symbolName, NULL, NULL);
} else {
error = elf_debug_lookup_user_symbol_address(
debug_get_debugged_thread()->team, address, &baseAddress,
&symbolName, NULL, NULL);
}
if (error == B_OK) {
ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, ZYDIS_TOKEN_SYMBOL));
ZyanString* string;
ZYAN_CHECK(ZydisFormatterBufferGetString(buffer, &string));
int64_t offset = address - baseAddress;
if (offset == 0)
return ZyanStringAppendFormat(string, "<%s>", symbolName);
return ZyanStringAppendFormat(string, "<%s+0x%" B_PRIx64 ">", symbolName, offset);
}
return sDefaultPrintAddressAbsolute(formatter, buffer, context);
}
extern "C" void
diasm_arch_assert_fail(const char* assertion, const char* file, unsigned int line,
const char* function)
{
kprintf("assert_fail: %s\n", assertion);
while (true)
;
}
extern "C" void
disasm_arch_assert(const char *condition)
{
kprintf("assert: %s\n", condition);
}
status_t
disasm_arch_dump_insns(addr_t where, int count, addr_t baseAddress,
int backCount)
{
ZyanU8 buffer[ZYDIS_MAX_INSTRUCTION_LENGTH];
ZydisDecodedInstruction instruction;
int skipCount = 0;
if (backCount > 0) {
addr_t address = baseAddress;
int baseCount = 0;
while (address < where
&& debug_memcpy(B_CURRENT_TEAM, &buffer, (const void*)address, sizeof(buffer)) == B_OK
&& ZYAN_SUCCESS(ZydisDecoderDecodeInstruction(&sDecoder,
(ZydisDecoderContext*)ZYAN_NULL, buffer, sizeof(buffer), &instruction))) {
address += instruction.length;
baseCount++;
}
if (address == where) {
if (baseCount > backCount)
skipCount = baseCount - backCount;
count += baseCount;
} else
baseAddress = where;
} else
baseAddress = where;
ZyanUSize offset = 0;
for (int i = 0; i < count; i++, offset += instruction.length) {
if (debug_memcpy(B_CURRENT_TEAM, &buffer, (const void*)(baseAddress + offset),
sizeof(buffer))
!= B_OK) {
kprintf("<read fault>\n");
break;
}
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
if (!ZYAN_SUCCESS(ZydisDecoderDecodeFull(&sDecoder, buffer, sizeof(buffer), &instruction,
operands))) {
break;
}
if (skipCount > 0) {
skipCount--;
continue;
}
addr_t address = baseAddress + offset;
if (address == where)
kprintf("\x1b[34m");
char hexString[32];
char* srcHex = hexString;
for (ZyanUSize i = 0; i < instruction.length; i++) {
sprintf(srcHex, "%02" PRIx8, buffer[i]);
srcHex += 2;
}
char formatted[1024];
if (ZYAN_SUCCESS(ZydisFormatterFormatInstruction(&sFormatter, &instruction, operands,
instruction.operand_count_visible, formatted, sizeof(formatted),
baseAddress + offset, NULL))) {
kprintf("%#16llx: %16.16s\t%s\n", static_cast<unsigned long long>(address), hexString,
formatted);
} else {
kprintf("%#16llx: failed-to-format\n", static_cast<unsigned long long>(address));
}
if (address == where)
kprintf("\x1b[m");
}
return B_OK;
}
status_t
disasm_arch_init()
{
#ifdef __x86_64__
ZydisDecoderInit(&sDecoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
#else
ZydisDecoderInit(&sDecoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_STACK_WIDTH_32);
#endif
ZydisFormatterInit(&sFormatter, ZYDIS_FORMATTER_STYLE_ATT);
ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE);
ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_HEX_UPPERCASE, ZYAN_FALSE);
ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_ADDR_PADDING_ABSOLUTE,
ZYDIS_PADDING_DISABLED);
ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_ADDR_PADDING_RELATIVE,
ZYDIS_PADDING_DISABLED);
ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_DISP_PADDING,
ZYDIS_PADDING_DISABLED);
ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_IMM_PADDING,
ZYDIS_PADDING_DISABLED);
sDefaultPrintAddressAbsolute = (ZydisFormatterFunc)&ZydisFormatterPrintAddressAbsolute;
ZydisFormatterSetHook(&sFormatter, ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS,
(const void**)&sDefaultPrintAddressAbsolute);
return B_OK;
}
status_t
disasm_arch_fini()
{
return B_OK;
}