xref: /haiku/src/system/kernel/arch/riscv64/arch_debug.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
1 /*
2  * Copyright 2019-2020, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  * 		Adrien Destugues <pulkomandy@pulkomandy.tk>
7  */
8 
9 
10 #include <arch/debug.h>
11 #include <vm/VMAddressSpace.h>
12 #include <vm/VMArea.h>
13 #include <elf.h>
14 #include <kimage.h>
15 #include <arch/generic/user_memory.h>
16 #include <AutoDeleterDrivers.h>
17 
18 
19 kernel_args *sKernelArgs;
20 bool sInitCalled = false;
21 
22 
23 static void
24 WriteImage(preloaded_image* _image)
25 {
26 	preloaded_elf64_image* image = (preloaded_elf64_image*)_image;
27 	dprintf("image %p\n", image);
28 	dprintf("image \"%s\"\n", (char*)image->name);
29 	dprintf("  text: 0x%" B_PRIxADDR " - 0x%" B_PRIxADDR ",%"
30 		B_PRIdSSIZE "\n", image->text_region.start,
31 		image->text_region.start + image->text_region.size,
32 		image->text_region.delta);
33 	dprintf("  data: 0x%" B_PRIxADDR " - 0x%" B_PRIxADDR ", %"
34 		B_PRIdSSIZE "\n", image->data_region.start,
35 		image->data_region.start + image->data_region.size,
36 		image->data_region.delta);
37 }
38 
39 
40 static void
41 WriteImages()
42 {
43 	WriteImage(sKernelArgs->kernel_image);
44 
45 	preloaded_image* image = sKernelArgs->preloaded_images;
46 	while (image != NULL) {
47 		WriteImage(image);
48 		image = image->next;
49 	}
50 }
51 
52 
53 static bool
54 AddressInImage(preloaded_image* _image, addr_t adr)
55 {
56 	preloaded_elf64_image* image = (preloaded_elf64_image*)_image;
57 	if (adr >= image->text_region.start
58 			&& adr < image->text_region.start + image->text_region.size) {
59 		return true;
60 	}
61 
62 	if (adr >= image->data_region.start
63 			&& adr < image->data_region.start + image->data_region.size) {
64 		return true;
65 	}
66 
67 	return false;
68 }
69 
70 
71 static bool
72 SymbolAt(preloaded_image* _image, addr_t adr, const char **name, ssize_t *ofs)
73 {
74 	preloaded_elf64_image* image = (preloaded_elf64_image*)_image;
75 	adr -= image->text_region.delta;
76 	for (uint32 i = 0; i < image->num_debug_symbols; i++) {
77 		Elf64_Sym& sym = image->debug_symbols[i];
78 		if (sym.st_shndx != STN_UNDEF && adr >= sym.st_value
79 			&& adr < sym.st_value + sym.st_size) {
80 			if (name != NULL)
81 				*name = &image->debug_string_table[sym.st_name];
82 			if (ofs != NULL)
83 				*ofs = adr - sym.st_value;
84 			return true;
85 		}
86 	}
87 	return false;
88 }
89 
90 
91 static preloaded_image*
92 FindImage(addr_t adr)
93 {
94 	if (AddressInImage(sKernelArgs->kernel_image, adr))
95 		return sKernelArgs->kernel_image;
96 
97 	preloaded_image* image = sKernelArgs->preloaded_images;
98 	while (image != NULL) {
99 		if (AddressInImage(image, adr))
100 			return image;
101 		image = image->next;
102 	}
103 
104 	return NULL;
105 }
106 
107 
108 static VMArea*
109 FindArea(addr_t adr)
110 {
111 	if (IS_KERNEL_ADDRESS(adr)) {
112 		VMAddressSpacePutter addrSpace(VMAddressSpace::GetKernel());
113 		return addrSpace->LookupArea(adr);
114 	}
115 	if (IS_USER_ADDRESS(adr)) {
116 		VMAddressSpacePutter addrSpace(VMAddressSpace::GetCurrent());
117 		return addrSpace->LookupArea(adr);
118 	}
119 	return NULL;
120 }
121 
122 
123 static status_t
124 lookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress,
125 	const char** _symbolName, const char** _imageName, bool* _exactMatch)
126 {
127 	status_t status = B_ENTRY_NOT_FOUND;
128 
129 	if (IS_KERNEL_ADDRESS(address)) {
130 		// a kernel symbol
131 		status = elf_debug_lookup_symbol_address(address, _baseAddress,
132 			_symbolName, _imageName, _exactMatch);
133 	} else if (true && thread != NULL && thread->team != NULL) {
134 		// try a lookup using the userland runtime loader structures
135 		status = elf_debug_lookup_user_symbol_address(thread->team, address,
136 			_baseAddress, _symbolName, _imageName, _exactMatch);
137 
138 		if (status != B_OK) {
139 			// try to locate the image in the images loaded into user space
140 			status = image_debug_lookup_user_symbol_address(thread->team,
141 				address, _baseAddress, _symbolName, _imageName, _exactMatch);
142 		}
143 	}
144 
145 	return status;
146 }
147 
148 
149 void
150 WritePCBoot(addr_t pc)
151 {
152 	preloaded_image* image = FindImage(pc);
153 	if (image != NULL) {
154 		const char *name;
155 		ssize_t ofs;
156 		if (SymbolAt(image, pc, &name, &ofs)) {
157 			dprintf("<%s> %s + %" B_PRIdSSIZE, (char*)image->name, name, ofs);
158 			return;
159 		}
160 		dprintf("<%s> 0x%" B_PRIxADDR, (char*)image->name,
161 			pc - ((preloaded_elf64_image*)image)->text_region.delta);
162 		return;
163 	}
164 /*
165 	VMArea* area = FindArea(pc);
166 	if (area != NULL) {
167 		dprintf("<%s> 0x%" B_PRIxADDR, area->name, pc - area->Base());
168 		return;
169 	}
170 */
171 	dprintf("0x%" B_PRIxADDR, pc);
172 }
173 
174 
175 void
176 WritePC(addr_t pc)
177 {
178 	dprintf("0x%" B_PRIxADDR " ", pc);
179 	if (!sInitCalled) {
180 		WritePCBoot(pc); return;
181 	}
182 
183 	addr_t baseAddress;
184 	const char* symbolName;
185 	const char* imageName;
186 	bool exactMatch;
187 	if (lookup_symbol(thread_get_current_thread(), pc, &baseAddress,
188 		&symbolName, &imageName, &exactMatch) >= B_OK) {
189 		if (symbolName != NULL) {
190 			dprintf("<%s> %s + %" B_PRIdSSIZE, imageName, symbolName,
191 				pc - baseAddress);
192 			return;
193 		}
194 		dprintf("<%s> 0x%" B_PRIxADDR, imageName, pc - baseAddress);
195 		return;
196 	}
197 
198 	VMArea* area = FindArea(pc);
199 	if (area != NULL) {
200 		dprintf("<%s> 0x%" B_PRIxADDR, area->name, pc - area->Base());
201 		return;
202 	}
203 
204 	dprintf("0x%" B_PRIxADDR, pc);
205 }
206 
207 
208 static void
209 DumpMemory(uint64* adr, size_t len)
210 {
211 	while (len > 0) {
212 		if ((addr_t)adr % 0x10 == 0)
213 			dprintf("%08" B_PRIxADDR " ", (addr_t)adr);
214 		uint64 val;
215 		if (user_memcpy(&val, adr++, sizeof(val)) < B_OK) {
216 			dprintf(" ????????????????");
217 		} else {
218 			dprintf(" %016" B_PRIx64, val);
219 		}
220 		if ((addr_t)adr % 0x10 == 0)
221 			dprintf("\n");
222 		len -= 8;
223 	}
224 	if ((addr_t)adr % 0x10 != 0)
225 		dprintf("\n");
226 }
227 
228 
229 void
230 DoStackTrace(addr_t fp, addr_t pc)
231 {
232 	dprintf("Stack:\n");
233 	dprintf("FP: 0x%" B_PRIxADDR, fp);
234 	if (pc != 0) {
235 		dprintf(", PC: "); WritePC(pc);
236 	}
237 	dprintf("\n");
238 	addr_t oldFp = fp;
239 	while (fp != 0) {
240 		if ((pc >= (addr_t)&strcpy && pc < (addr_t)&strcpy + 32)
241 				|| (pc >= (addr_t)&memset && pc < (addr_t)&memset + 34)) {
242 			if (user_memcpy(&fp, (uint64*)fp - 1, sizeof(pc)) < B_OK)
243 				break;
244 			pc = 0;
245 		} else {
246 			if (user_memcpy(&pc, (uint64*)fp - 1, sizeof(pc)) < B_OK)
247 				break;
248 			if (user_memcpy(&fp, (uint64*)fp - 2, sizeof(pc)) < B_OK)
249 				break;
250 		}
251 		dprintf("FP: 0x%" B_PRIxADDR, fp);
252 		dprintf(", PC: "); WritePC((pc == 0) ? 0 : pc - 1);
253 		dprintf("\n");
254 /*
255 		if (IS_KERNEL_ADDRESS(oldFp) && IS_KERNEL_ADDRESS(fp))
256 			DumpMemory((uint64*)oldFp, (addr_t)fp - (addr_t)oldFp);
257 */
258 		oldFp = fp;
259 	}
260 }
261 
262 
263 static int
264 stack_trace(int argc, char **argv)
265 {
266 	if (argc >= 2) {
267 		thread_id id = strtoul(argv[1], NULL, 0);
268 		Thread* thread = Thread::GetDebug(id);
269 		if (thread == NULL) {
270 			kprintf("could not find thread %" B_PRId32 "\n", id);
271 			return 0;
272 		}
273 		uint64 oldSatp = Satp();
274 		SetSatp(thread->arch_info.context.satp);
275 		DoStackTrace(thread->arch_info.context.s[0], thread->arch_info.context.ra);
276 		SetSatp(oldSatp);
277 		return 0;
278 	}
279 	DoStackTrace(Fp(), 0);
280 	return 0;
281 }
282 
283 
284 void
285 arch_debug_stack_trace(void)
286 {
287 	DoStackTrace(Fp(), 0);
288 }
289 
290 
291 bool
292 arch_debug_contains_call(Thread *thread, const char *symbol,
293 	addr_t start, addr_t end)
294 {
295 	return false;
296 }
297 
298 
299 void *
300 arch_debug_get_caller(void)
301 {
302 	return NULL;
303 }
304 
305 
306 void
307 arch_debug_save_registers(struct arch_debug_registers* registers)
308 {
309 }
310 
311 
312 static void __attribute__((naked))
313 HandleFault()
314 {
315 	asm volatile("ld a0, 0(sp)");
316 	asm volatile("li a1, 1");
317 	asm volatile("call longjmp");
318 }
319 
320 
321 void
322 arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer,
323 	void (*function)(void*), void* parameter)
324 {
325 	cpu->fault_handler = (addr_t)&HandleFault;
326 	cpu->fault_handler_stack_pointer = (addr_t)&jumpBuffer;
327 	function(parameter);
328 }
329 
330 
331 bool
332 arch_is_debug_variable_defined(const char* variableName)
333 {
334 	// TODO: Implement!
335 	return false;
336 }
337 
338 
339 status_t
340 arch_set_debug_variable(const char* variableName, uint64 value)
341 {
342 	// TODO: Implement!
343 	return B_ENTRY_NOT_FOUND;
344 }
345 
346 
347 status_t
348 arch_get_debug_variable(const char* variableName, uint64* value)
349 {
350 	// TODO: Implement!
351 	return B_ENTRY_NOT_FOUND;
352 }
353 
354 
355 int32
356 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
357 	int32 skipIframes, int32 skipFrames, uint32 flags)
358 {
359 	return 0;
360 }
361 
362 
363 ssize_t
364 arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
365 {
366 	// TODO: Implement!
367 	return B_NOT_SUPPORTED;
368 }
369 
370 
371 void*
372 arch_debug_get_interrupt_pc(bool* _isSyscall)
373 {
374 	// TODO: Implement!
375 	return NULL;
376 }
377 
378 
379 void
380 arch_debug_unset_current_thread(void)
381 {
382 	// TODO: Implement!
383 }
384 
385 
386 status_t
387 arch_debug_init_early(kernel_args *args)
388 {
389 	dprintf("arch_debug_init_early()\n");
390 	sKernelArgs = args;
391 	WriteImages();
392 	return B_OK;
393 }
394 
395 
396 status_t
397 arch_debug_init(kernel_args *args)
398 {
399 	sInitCalled = true;
400 
401 	add_debugger_command("where", &stack_trace, "Same as \"sc\"");
402 	add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
403 	add_debugger_command("sc", &stack_trace, "Stack crawl for current thread");
404 
405 	return B_OK;
406 }
407