3 * \brief Debugging functions
7 * Copyright (c) 2008-2011, ETH Zurich.
8 * Copyright (c) 2015, 2016 Hewlett Packard Enterprise Development LP.
11 * This file is distributed under the terms in the attached LICENSE file.
12 * If you do not find this file, copies can be found by writing to:
13 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
17 #include <barrelfish/barrelfish.h>
18 #include <barrelfish/caddr.h>
19 #include <barrelfish/debug.h>
20 #include <barrelfish/sys_debug.h>
21 #include <barrelfish/dispatch.h>
22 #include <if/monitor_blocking_rpcclient_defs.h>
27 #include <barrelfish_kpi/dispatcher_shared.h>
29 #define DISP_MEMORY_SIZE 1024 // size of memory dump in bytes
32 * \brief Print a message and abort.
34 * Something irrecoverably bad happened. Print a panic message, then abort.
36 void user_panic_fn(const char *file, const char *func, int line,
44 vsnprintf(msg_str, sizeof(msg_str), msg, ap);
49 snprintf(str, sizeof(str), "%.*s.%u in %s() %s:%d\n%s\n",
50 DISP_NAME_LEN, disp_name(), disp_get_core_id(),
51 func, file, line, msg_str);
52 sys_print(str, sizeof(str));
57 errval_t debug_cap_identify(struct capref cap, struct capability *ret)
61 if (get_cap_addr(cap) == 0) {
62 return SYS_ERR_CAP_NOT_FOUND;
66 monitor_blocking_caprep_t caprep;
67 struct capability capability;
70 struct monitor_blocking_rpc_client *r = get_monitor_blocking_rpc_client();
72 return LIB_ERR_MONITOR_RPC_NULL;
74 err = r->vtbl.cap_identify(r, cap, &msgerr, &u.caprep);
75 if (err_is_fail(err)){
77 } else if (err_is_fail(msgerr)) {
88 * \brief Enable fine-grained tracing of cap operations on address range
89 * [start_addr, start_addr+size)
90 * \arg types enable tracing for given set of ORed ObjType_s
91 * \arg start_addr start of region to trace for
92 * \arg size size of region to trace for
94 errval_t debug_cap_trace_ctrl(uintptr_t types, genpaddr_t start_addr, gensize_t size)
97 printf("enabling pmem tracing: 0x%"PRIxGENPADDR"--0x%"PRIxGENPADDR
98 " for types 0x%"PRIxPTR"\n",
99 start_addr, start_addr+size, types);
101 return sys_debug_cap_trace_ctrl(types, start_addr, size);
105 * \brief Dump own hw page tables
107 errval_t debug_dump_hw_ptables(void)
109 return invoke_dispatcher_dump_ptables(cap_dispatcher);
112 void debug_printf(const char *fmt, ...)
114 struct thread *me = thread_self();
121 snprintf(id, sizeof(id), "%"PRIuPTR, thread_get_id(me));
122 len = snprintf(str, sizeof(str), "\033[34m%.*s.\033[31m%u.%s\033[0m: ",
123 DISP_NAME_LEN, disp_name(), disp_get_core_id(), id);
124 if (len < sizeof(str)) {
125 va_start(argptr, fmt);
126 vsnprintf(str + len, sizeof(str) - len, fmt, argptr);
129 sys_print(str, sizeof(str));
133 * \brief Function to do the actual printing based on the type of capability
135 STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
136 int debug_print_cap(char *buf, size_t len, struct capability *cap)
139 case ObjType_PhysAddr:
140 return snprintf(buf, len,
141 "physical address range cap (0x%" PRIxGENPADDR ":0x%" PRIuGENSIZE ")",
142 cap->u.physaddr.base, cap->u.physaddr.bytes);
145 return snprintf(buf, len, "RAM cap (0x%" PRIxGENPADDR ":0x%" PRIuGENSIZE ")",
146 cap->u.ram.base, cap->u.ram.bytes);
148 case ObjType_CNode: {
149 int ret = snprintf(buf, len, "CNode cap "
150 "(bits %u, rights mask 0x%" PRIxCAPRIGHTS ")",
151 cap->u.cnode.bits, cap->u.cnode.rightsmask);
152 if (cap->u.cnode.guard_size != 0 && ret < len) {
153 ret += snprintf(&buf[ret], len - ret, " (guard 0x%" PRIxCADDR ":%u)",
154 cap->u.cnode.guard, cap->u.cnode.guard_size);
159 case ObjType_Dispatcher:
160 return snprintf(buf, len, "Dispatcher cap %p", cap->u.dispatcher.dcb);
163 return snprintf(buf, len, "Frame cap (0x%" PRIxGENPADDR ":0x%" PRIuGENSIZE ")",
164 cap->u.frame.base, cap->u.frame.bytes);
166 case ObjType_DevFrame:
167 return snprintf(buf, len, "Device Frame cap (0x%" PRIxGENPADDR ":%" PRIuGENSIZE ")",
168 cap->u.frame.base, cap->u.devframe.bytes);
170 case ObjType_VNode_ARM_l1:
171 return snprintf(buf, len, "ARM L1 table at 0x%" PRIxGENPADDR,
172 cap->u.vnode_arm_l1.base);
174 case ObjType_VNode_ARM_l2:
175 return snprintf(buf, len, "ARM L2 table at 0x%" PRIxGENPADDR,
176 cap->u.vnode_arm_l2.base);
178 case ObjType_VNode_AARCH64_l0:
179 return snprintf(buf, len, "AARCH64 L0 table at 0x%" PRIxGENPADDR,
180 cap->u.vnode_aarch64_l0.base);
182 case ObjType_VNode_AARCH64_l1:
183 return snprintf(buf, len, "AARCH64 L1 table at 0x%" PRIxGENPADDR,
184 cap->u.vnode_aarch64_l1.base);
186 case ObjType_VNode_AARCH64_l2:
187 return snprintf(buf, len, "AARCH64 L2 table at 0x%" PRIxGENPADDR,
188 cap->u.vnode_aarch64_l2.base);
190 case ObjType_VNode_AARCH64_l3:
191 return snprintf(buf, len, "AARCH64 L3 table at 0x%" PRIxGENPADDR,
192 cap->u.vnode_aarch64_l3.base);
194 case ObjType_VNode_x86_32_ptable:
195 return snprintf(buf, len, "x86_32 Page table at 0x%" PRIxGENPADDR,
196 cap->u.vnode_x86_32_ptable.base);
198 case ObjType_VNode_x86_32_pdir:
199 return snprintf(buf, len, "x86_32 Page directory at 0x%" PRIxGENPADDR,
200 cap->u.vnode_x86_32_pdir.base);
202 case ObjType_VNode_x86_32_pdpt:
203 return snprintf(buf, len, "x86_32 PDPT at 0x%" PRIxGENPADDR,
204 cap->u.vnode_x86_32_pdpt.base);
206 case ObjType_VNode_x86_64_ptable:
207 return snprintf(buf, len, "x86_64 Page table at 0x%" PRIxGENPADDR,
208 cap->u.vnode_x86_64_ptable.base);
210 case ObjType_VNode_x86_64_pdir:
211 return snprintf(buf, len, "x86_64 Page directory at 0x%" PRIxGENPADDR,
212 cap->u.vnode_x86_64_pdir.base);
214 case ObjType_VNode_x86_64_pdpt:
215 return snprintf(buf, len, "x86_64 PDPT at 0x%" PRIxGENPADDR,
216 cap->u.vnode_x86_64_pdpt.base);
218 case ObjType_VNode_x86_64_pml4:
219 return snprintf(buf, len, "x86_64 PML4 at 0x%" PRIxGENPADDR,
220 cap->u.vnode_x86_64_pml4.base);
222 case ObjType_Frame_Mapping:
223 return snprintf(buf, len, "Frame Mapping (Frame cap @0x%p, "
224 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
225 cap->u.frame_mapping.frame,
226 cap->u.frame_mapping.pte,
227 cap->u.frame_mapping.pte_count);
229 case ObjType_DevFrame_Mapping:
230 return snprintf(buf, len, "DevFrame Mapping (DevFrame cap @0x%p, "
231 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
232 cap->u.devframe_mapping.frame,
233 cap->u.devframe_mapping.pte,
234 cap->u.devframe_mapping.pte_count);
236 case ObjType_VNode_x86_64_pml4_Mapping:
237 return snprintf(buf, len, "x86_64 PML4 Mapping (x86_64 PML4 cap @0x%p, "
238 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
239 cap->u.vnode_x86_64_pml4_mapping.frame,
240 cap->u.vnode_x86_64_pml4_mapping.pte,
241 cap->u.vnode_x86_64_pml4_mapping.pte_count);
243 case ObjType_VNode_x86_64_pdpt_Mapping:
244 return snprintf(buf, len, "x86_64 PDPT Mapping (x86_64 PDPT cap @0x%p, "
245 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
246 cap->u.vnode_x86_64_pdpt_mapping.frame,
247 cap->u.vnode_x86_64_pdpt_mapping.pte,
248 cap->u.vnode_x86_64_pdpt_mapping.pte_count);
250 case ObjType_VNode_x86_64_pdir_Mapping:
251 return snprintf(buf, len, "x86_64 PDIR Mapping (x86_64 PDIR cap @0x%p, "
252 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
253 cap->u.vnode_x86_64_pdir_mapping.frame,
254 cap->u.vnode_x86_64_pdir_mapping.pte,
255 cap->u.vnode_x86_64_pdir_mapping.pte_count);
257 case ObjType_VNode_x86_64_ptable_Mapping:
258 return snprintf(buf, len, "x86_64 PTABLE Mapping (x86_64 PTABLE cap @0x%p, "
259 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
260 cap->u.vnode_x86_64_ptable_mapping.frame,
261 cap->u.vnode_x86_64_ptable_mapping.pte,
262 cap->u.vnode_x86_64_ptable_mapping.pte_count);
264 case ObjType_VNode_x86_32_pdpt_Mapping:
265 return snprintf(buf, len, "x86_32 PDPT Mapping (x86_32 PDPT cap @0x%p, "
266 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
267 cap->u.vnode_x86_32_pdpt_mapping.frame,
268 cap->u.vnode_x86_32_pdpt_mapping.pte,
269 cap->u.vnode_x86_32_pdpt_mapping.pte_count);
271 case ObjType_VNode_x86_32_pdir_Mapping:
272 return snprintf(buf, len, "x86_32 PDIR Mapping (x86_32 PDIR cap @0x%p, "
273 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
274 cap->u.vnode_x86_32_pdir_mapping.frame,
275 cap->u.vnode_x86_32_pdir_mapping.pte,
276 cap->u.vnode_x86_32_pdir_mapping.pte_count);
278 case ObjType_VNode_x86_32_ptable_Mapping:
279 return snprintf(buf, len, "x86_32 PTABLE Mapping (x86_32 PTABLE cap @0x%p, "
280 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
281 cap->u.vnode_x86_32_ptable_mapping.frame,
282 cap->u.vnode_x86_32_ptable_mapping.pte,
283 cap->u.vnode_x86_32_ptable_mapping.pte_count);
285 case ObjType_VNode_ARM_l1_Mapping:
286 return snprintf(buf, len, "ARM l1 Mapping (ARM l1 cap @0x%p, "
287 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
288 cap->u.vnode_arm_l1_mapping.frame,
289 cap->u.vnode_arm_l1_mapping.pte,
290 cap->u.vnode_arm_l1_mapping.pte_count);
292 case ObjType_VNode_ARM_l2_Mapping:
293 return snprintf(buf, len, "ARM l2 Mapping (ARM l2 cap @0x%p, "
294 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
295 cap->u.vnode_arm_l2_mapping.frame,
296 cap->u.vnode_arm_l2_mapping.pte,
297 cap->u.vnode_arm_l2_mapping.pte_count);
299 case ObjType_VNode_AARCH64_l0_Mapping:
300 return snprintf(buf, len, "AARCH64 l0 Mapping (AARCH64 l0 cap @0x%p, "
301 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
302 cap->u.vnode_aarch64_l0_mapping.frame,
303 cap->u.vnode_aarch64_l0_mapping.pte,
304 cap->u.vnode_aarch64_l0_mapping.pte_count);
306 case ObjType_VNode_AARCH64_l1_Mapping:
307 return snprintf(buf, len, "AARCH64 l1 Mapping (AARCH64 l1 cap @0x%p, "
308 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
309 cap->u.vnode_aarch64_l1_mapping.frame,
310 cap->u.vnode_aarch64_l1_mapping.pte,
311 cap->u.vnode_aarch64_l1_mapping.pte_count);
313 case ObjType_VNode_AARCH64_l2_Mapping:
314 return snprintf(buf, len, "AARCH64 l2 Mapping (AARCH64 l2 cap @0x%p, "
315 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
316 cap->u.vnode_aarch64_l2_mapping.frame,
317 cap->u.vnode_aarch64_l2_mapping.pte,
318 cap->u.vnode_aarch64_l2_mapping.pte_count);
320 case ObjType_VNode_AARCH64_l3_Mapping:
321 return snprintf(buf, len, "AARCH64 l3 Mapping (AARCH64 l3 cap @0x%p, "
322 "pte @0x%"PRIxLVADDR", pte_count=%hu)",
323 cap->u.vnode_aarch64_l3_mapping.frame,
324 cap->u.vnode_aarch64_l3_mapping.pte,
325 cap->u.vnode_aarch64_l3_mapping.pte_count);
328 case ObjType_IRQTable:
329 return snprintf(buf, len, "IRQTable cap");
331 case ObjType_IRQDest:
332 return snprintf(buf, len, "IRQDest cap (vec: %"PRIu64", ctrl: %"PRIu64")",
333 cap->u.irqdest.vector, cap->u.irqdest.controller);
335 case ObjType_EndPoint:
336 return snprintf(buf, len, "EndPoint cap (disp %p offset 0x%" PRIxLVADDR ")",
337 cap->u.endpoint.listener, cap->u.endpoint.epoffset);
340 return snprintf(buf, len, "IO cap (0x%hx-0x%hx)",
341 cap->u.io.start, cap->u.io.end);
344 return snprintf(buf, len, "Kernel cap");
346 case ObjType_KernelControlBlock:
347 return snprintf(buf, len, "Kernel control block cap");
350 return snprintf(buf, len, "ID capability (coreid 0x%" PRIxCOREID
351 " core_local_id 0x%" PRIx32 ")", cap->u.id.coreid,
352 cap->u.id.core_local_id);
354 case ObjType_PerfMon:
355 return snprintf(buf, len, "PerfMon cap");
358 return snprintf(buf, len, "Null cap (empty slot)");
361 return snprintf(buf, len, "UNKNOWN TYPE! (%d)", cap->type);
365 int debug_print_cap_at_capref(char *buf, size_t len, struct capref cap)
367 struct capability capability;
370 if (capref_is_null(cap)) {
371 return snprintf(buf, len, "(null cap)");
374 err = debug_cap_identify(cap, &capability);
375 if (err_is_fail(err)) {
376 return snprintf(buf, len, "(ERROR identifying cap!)");
378 return debug_print_cap(buf, len, &capability);
383 * \brief Walk the cspace printing all non-null capabilities
385 * \param cnode cnode to walk
386 * \param level depth in the cspace
388 * \bug assumes guards are always zero
390 static void walk_cspace(struct cnoderef cnode, uint8_t level)
392 struct capability cap;
395 struct capref pos = {
396 .cnode = cnode, .slot = 0
399 // If too many bits resolved, return
400 if (pos.cnode.address_bits + pos.cnode.guard_size + pos.cnode.size_bits
405 // Walk through all the slots in the CNode
406 for (pos.slot = 0; pos.slot < (((capaddr_t)1) << cnode.size_bits); pos.slot++) {
408 err = debug_cap_identify(pos, &cap);
410 // If cap type was Null, kernel returns error
411 if (err_no(err) == SYS_ERR_IDENTIFY_LOOKUP ||
412 err_no(err) == SYS_ERR_CAP_NOT_FOUND ||
413 err_no(err) == SYS_ERR_LMP_CAPTRANSFER_SRC_LOOKUP) {
415 } else if (err_is_fail(err)) {
416 DEBUG_ERR(err, "debug_cap_identify failed");
423 // Print the stats for the child slot
424 for(int i = 0; i < level; i++) {
425 prpos += snprintf(&buf[prpos], sizeof(buf) - prpos, " ");
426 assert(prpos < sizeof(buf));
428 prpos += snprintf(&buf[prpos], sizeof(buf) - prpos,
429 "slot %" PRIuCADDR " caddr 0x%" PRIxCADDR " (%u bits) is a ",
430 pos.slot, get_cap_addr(pos), get_cap_valid_bits(pos));
431 assert(prpos < sizeof(buf));
432 prpos += debug_print_cap(&buf[prpos], sizeof(buf) - prpos, &cap);
433 assert(prpos < sizeof(buf));
434 debug_printf("%s\n", buf);
436 // If CNode type, descend into it
437 if (cap.type == ObjType_CNode) {
438 struct cnoderef childcn = {
439 .address = get_cap_addr(pos),
440 .address_bits = get_cap_valid_bits(pos),
441 .size_bits = cap.u.cnode.bits,
442 .guard_size = cap.u.cnode.guard_size,
444 walk_cspace(childcn, level + 1);
450 * \brief Dump an arbitrary cspace, given the root
452 void debug_cspace(struct capref root)
454 struct capability cap;
456 /* find out size of root cnode */
457 errval_t err = debug_cap_identify(root, &cap);
458 assert(err_is_ok(err));
460 struct cnoderef cnode = {
461 .address = get_cap_addr(root),
462 .address_bits = get_cap_valid_bits(root),
463 .size_bits = cap.u.cnode.bits,
464 .guard_size = cap.u.cnode.guard_size,
467 walk_cspace(cnode, 0);
470 void debug_my_cspace(void)
472 // XXX: Assume my root CNode has a size of #DEFAULT_CNODE_BITS
473 struct cnoderef cnode = {
476 .size_bits = DEFAULT_CNODE_BITS,
480 walk_cspace(cnode, 0);
483 int debug_print_capref(char *buf, size_t len, struct capref cap)
485 return snprintf(buf, len, "CNode addr 0x%08" PRIxCADDR
486 ", vbits = %d, slot %" PRIuCADDR ", vbits = %d",
487 get_cnode_addr(cap), get_cnode_valid_bits(cap), cap.slot,
488 get_cap_valid_bits(cap));
491 void debug_dump_mem(lvaddr_t start_addr, lvaddr_t end_addr, lvaddr_t point)
493 debug_printf("Dumping memory in range 0x%" PRIxLVADDR
494 " to 0x%" PRIxLVADDR ":\n",
495 start_addr, end_addr);
497 for (uintptr_t *p = (void *)start_addr; (uintptr_t)p < end_addr; p++) {
498 uint8_t *bytes = (void *)p;
501 for (int i = 0; i < sizeof(uintptr_t); i++) {
502 bufpos += snprintf(&buf[bufpos], sizeof(buf) - bufpos, "%02x ", bytes[i]);
503 assert(bufpos < sizeof(buf));
505 debug_printf("%p: %.*s %*" PRIxPTR "%s\n", p, (int)sizeof(buf), buf,
506 (int)sizeof(uintptr_t) * 2, *p,
507 p == (uintptr_t *)point ? " <== We are here" : "");
511 void debug_dump_mem_around_addr(lvaddr_t addr)
513 /* lvaddr_t page_aligned_addr = ROUND_DOWN(addr, BASE_PAGE_SIZE); */
514 lvaddr_t start_addr = ROUND_DOWN(addr - DISP_MEMORY_SIZE/2, sizeof(uintptr_t));
515 lvaddr_t end_addr = ROUND_UP(addr + DISP_MEMORY_SIZE/2, sizeof(uintptr_t));
517 /* if (start_addr < page_aligned_addr) { */
518 /* start_addr = page_aligned_addr; */
520 /* if (end_addr > page_aligned_addr + BASE_PAGE_SIZE) { */
521 /* end_addr = page_aligned_addr + BASE_PAGE_SIZE; */
524 debug_dump_mem(start_addr, end_addr, addr);
527 void debug_err(const char *file, const char *func, int line, errval_t err,
528 const char *msg, ...)
533 char *leader = (err == 0) ? "SUCCESS" : "ERROR";
535 snprintf(str, sizeof(str), "%s: %.*s.%u in %s() %s:%d\n%s: ",
536 leader, DISP_NAME_LEN, disp_name(), disp_get_core_id(),
537 func, file, line, leader);
538 sys_print(str, sizeof(str));
543 vsnprintf(str, sizeof(str), msg, ap);
545 sys_print(str, sizeof(str));
550 err_print_calltrace(err);
554 bool debug_notify_syscall = false;
556 void debug_control_plane_forbidden(void);
557 void debug_control_plane_forbidden(void)
559 debug_notify_syscall = true;