xref: /haiku/src/add-ons/kernel/debugger/disasm/x86/disasm_arch.cpp (revision 909af08f4328301fbdef1ffb41f566c3b5bec0c7)
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 #include <stdio.h>
11 
12 #include "Zycore/Format.h"
13 #include "Zydis/Zydis.h"
14 
15 #include "disasm_arch.h"
16 #include "elf.h"
17 
18 
19 static ZydisDecoder sDecoder;
20 static ZydisFormatter sFormatter;
21 static ZydisFormatterFunc sDefaultPrintAddressAbsolute;
22 
23 
24 static ZyanStatus
25 ZydisFormatterPrintAddressAbsolute(const ZydisFormatter* formatter, ZydisFormatterBuffer* buffer,
26 	ZydisFormatterContext* context)
27 {
28 	ZyanU64 address;
29 	ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand,
30 		context->runtime_address, &address));
31 
32 	const char* symbolName;
33 	addr_t baseAddress;
34 	status_t error;
35 
36 	if (IS_KERNEL_ADDRESS(address)) {
37 		error = elf_debug_lookup_symbol_address(address, &baseAddress,
38 			&symbolName, NULL, NULL);
39 	} else {
40 		error = elf_debug_lookup_user_symbol_address(
41 			debug_get_debugged_thread()->team, address, &baseAddress,
42 			&symbolName, NULL, NULL);
43 	}
44 
45 	if (error == B_OK) {
46 		ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, ZYDIS_TOKEN_SYMBOL));
47 		ZyanString* string;
48 		ZYAN_CHECK(ZydisFormatterBufferGetString(buffer, &string));
49 		int64_t offset = address - baseAddress;
50 		if (offset == 0)
51 			return ZyanStringAppendFormat(string, "<%s>", symbolName);
52 		return ZyanStringAppendFormat(string, "<%s+0x%" B_PRIx64 ">", symbolName, offset);
53 	}
54 
55 	return sDefaultPrintAddressAbsolute(formatter, buffer, context);
56 }
57 
58 
59 extern "C" void
60 diasm_arch_assert_fail(const char* assertion, const char* file, unsigned int line,
61 	const char* function)
62 {
63 	kprintf("assert_fail: %s\n", assertion);
64 	while (true)
65 		;
66 }
67 
68 
69 extern "C" void
70 disasm_arch_assert(const char *condition)
71 {
72 	kprintf("assert: %s\n", condition);
73 }
74 
75 
76 status_t
77 disasm_arch_dump_insns(addr_t where, int count, addr_t baseAddress,
78 	int backCount)
79 {
80 	ZyanU8 buffer[ZYDIS_MAX_INSTRUCTION_LENGTH];
81 	ZydisDecodedInstruction instruction;
82 	int skipCount = 0;
83 
84 	if (backCount > 0) {
85 		// count the instructions from base address to start address
86 		addr_t address = baseAddress;
87 
88 		int baseCount = 0;
89 
90 		while (address < where
91 			&& debug_memcpy(B_CURRENT_TEAM, &buffer, (const void*)address, sizeof(buffer)) == B_OK
92 			&& ZYAN_SUCCESS(ZydisDecoderDecodeInstruction(&sDecoder,
93 				(ZydisDecoderContext*)ZYAN_NULL, buffer, sizeof(buffer), &instruction))) {
94 			address += instruction.length;
95 			baseCount++;
96 		}
97 
98 		if (address == where) {
99 			if (baseCount > backCount)
100 				skipCount = baseCount - backCount;
101 			count += baseCount;
102 		} else
103 			baseAddress = where;
104 	} else
105 		baseAddress = where;
106 
107 	ZyanUSize offset = 0;
108 
109 	for (int i = 0; i < count; i++, offset += instruction.length) {
110 		if (debug_memcpy(B_CURRENT_TEAM, &buffer, (const void*)(baseAddress + offset),
111 				sizeof(buffer))
112 			!= B_OK) {
113 			kprintf("<read fault>\n");
114 			break;
115 		}
116 		ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
117 		if (!ZYAN_SUCCESS(ZydisDecoderDecodeFull(&sDecoder, buffer, sizeof(buffer), &instruction,
118 				operands))) {
119 			break;
120 		}
121 		if (skipCount > 0) {
122 			skipCount--;
123 			continue;
124 		}
125 
126 		addr_t address = baseAddress + offset;
127 		if (address == where)
128 			kprintf("\x1b[34m");
129 
130 		char hexString[32];
131 		char* srcHex = hexString;
132 		for (ZyanUSize i = 0; i < instruction.length; i++) {
133 			sprintf(srcHex, "%02" PRIx8, buffer[i]);
134 			srcHex += 2;
135 		}
136 
137 		char formatted[1024];
138 		if (ZYAN_SUCCESS(ZydisFormatterFormatInstruction(&sFormatter, &instruction, operands,
139 				instruction.operand_count_visible, formatted, sizeof(formatted),
140 				baseAddress + offset, NULL))) {
141 			kprintf("%#16llx: %16.16s\t%s\n", static_cast<unsigned long long>(address), hexString,
142 				formatted);
143 		} else {
144 			kprintf("%#16llx: failed-to-format\n", static_cast<unsigned long long>(address));
145 		}
146 		if (address == where)
147 			kprintf("\x1b[m");
148 	}
149 	return B_OK;
150 }
151 
152 
153 status_t
154 disasm_arch_init()
155 {
156 #ifdef __x86_64__
157 	ZydisDecoderInit(&sDecoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
158 #else
159 	ZydisDecoderInit(&sDecoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_STACK_WIDTH_32);
160 #endif
161 
162 	ZydisFormatterInit(&sFormatter, ZYDIS_FORMATTER_STYLE_ATT);
163 	ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE);
164 	ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_HEX_UPPERCASE, ZYAN_FALSE);
165 	ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_ADDR_PADDING_ABSOLUTE,
166 		ZYDIS_PADDING_DISABLED);
167 	ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_ADDR_PADDING_RELATIVE,
168 		ZYDIS_PADDING_DISABLED);
169 	ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_DISP_PADDING,
170 		ZYDIS_PADDING_DISABLED);
171 	ZydisFormatterSetProperty(&sFormatter, ZYDIS_FORMATTER_PROP_IMM_PADDING,
172 		ZYDIS_PADDING_DISABLED);
173 
174 	sDefaultPrintAddressAbsolute = (ZydisFormatterFunc)&ZydisFormatterPrintAddressAbsolute;
175 	ZydisFormatterSetHook(&sFormatter, ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS,
176 		(const void**)&sDefaultPrintAddressAbsolute);
177 
178 	// XXX: check for AMD and set sVendor;
179 	return B_OK;
180 }
181 
182 
183 status_t
184 disasm_arch_fini()
185 {
186 	return B_OK;
187 }
188 
189 
190