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