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