3 * \brief Debugging functions
7 * Copyright (c) 2008, 2009, 2010, 2011, ETH Zurich.
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
16 #include <barrelfish/barrelfish.h>
17 #include <barrelfish/caddr.h>
18 #include <barrelfish/debug.h>
19 #include <barrelfish/sys_debug.h>
20 #include <barrelfish/dispatch.h>
21 #include <if/monitor_blocking_rpcclient_defs.h>
26 #include <barrelfish_kpi/dispatcher_shared.h>
28 #define DISP_MEMORY_SIZE 1024 // size of memory dump in bytes
31 * \brief Print a message and abort.
33 * Something irrecoverably bad happened. Print a panic message, then abort.
35 void user_panic_fn(const char *file, const char *func, int line,
43 vsnprintf(msg_str, sizeof(msg_str), msg, ap);
48 snprintf(str, sizeof(str), "%.*s.%u in %s() %s:%d\n%s\n",
49 DISP_NAME_LEN, disp_name(), disp_get_core_id(),
50 func, file, line, msg_str);
51 sys_print(str, sizeof(str));
56 errval_t debug_cap_identify(struct capref cap, struct capability *ret)
60 if (get_cap_addr(cap) == 0) {
61 return SYS_ERR_CAP_NOT_FOUND;
65 monitor_blocking_caprep_t caprep;
66 struct capability capability;
69 struct monitor_blocking_rpc_client *r = get_monitor_blocking_rpc_client();
71 return LIB_ERR_MONITOR_RPC_NULL;
73 err = r->vtbl.cap_identify(r, cap, &msgerr, &u.caprep);
74 if (err_is_fail(err)){
76 } else if (err_is_fail(msgerr)) {
87 * \brief Enable fine-grained tracing of cap operations on address range
88 * [start_addr, start_addr+size)
90 errval_t debug_cap_trace_ctrl(bool enable, genpaddr_t start_addr, gensize_t size)
93 printf("enabling pmem tracing: 0x%"PRIxGENPADDR"--0x%"PRIxGENPADDR"\n",
94 start_addr, start_addr+size);
96 return sys_debug_cap_trace_ctrl(enable, start_addr, size);
100 * \brief Dump own hw page tables
102 errval_t debug_dump_hw_ptables(void)
104 return invoke_dispatcher_dump_ptables(cap_dispatcher);
107 void debug_printf(const char *fmt, ...)
113 len = snprintf(str, sizeof(str), "\033[34m%.*s.\033[31m%u.%lu\033[0m: ", DISP_NAME_LEN, disp_name(),
114 disp_get_core_id(), thread_id());
115 if (len < sizeof(str)) {
116 va_start(argptr, fmt);
117 vsnprintf(str + len, sizeof(str) - len, fmt, argptr);
120 sys_print(str, sizeof(str));
124 * \brief Function to do the actual printing based on the type of capability
126 int debug_print_cap(char *buf, size_t len, struct capability *cap)
129 case ObjType_PhysAddr:
130 return snprintf(buf, len,
131 "physical address range cap (0x%" PRIxGENPADDR ":%u)",
132 cap->u.physaddr.base, cap->u.physaddr.bits);
135 return snprintf(buf, len, "RAM cap (0x%" PRIxGENPADDR ":%u)",
136 cap->u.ram.base, cap->u.ram.bits);
138 case ObjType_CNode: {
139 int ret = snprintf(buf, len, "CNode cap "
140 "(bits %u, rights mask 0x%" PRIxCAPRIGHTS ")",
141 cap->u.cnode.bits, cap->u.cnode.rightsmask);
142 if (cap->u.cnode.guard_size != 0 && ret < len) {
143 ret += snprintf(&buf[ret], len - ret, " (guard 0x%" PRIxCADDR ":%u)",
144 cap->u.cnode.guard, cap->u.cnode.guard_size);
149 case ObjType_Dispatcher:
150 return snprintf(buf, len, "Dispatcher cap %p", cap->u.dispatcher.dcb);
153 return snprintf(buf, len, "Frame cap (0x%" PRIxGENPADDR ":%u)",
154 cap->u.frame.base, cap->u.frame.bits);
156 case ObjType_DevFrame:
157 return snprintf(buf, len, "Device Frame cap (0x%" PRIxGENPADDR ":%u)",
158 cap->u.frame.base, cap->u.devframe.bits);
160 case ObjType_VNode_ARM_l1:
161 return snprintf(buf, len, "ARM L1 table at 0x%" PRIxGENPADDR,
162 cap->u.vnode_arm_l1.base);
164 case ObjType_VNode_ARM_l2:
165 return snprintf(buf, len, "ARM L2 table at 0x%" PRIxGENPADDR,
166 cap->u.vnode_arm_l2.base);
168 case ObjType_VNode_x86_32_ptable:
169 return snprintf(buf, len, "x86_32 Page table at 0x%" PRIxGENPADDR,
170 cap->u.vnode_x86_32_ptable.base);
172 case ObjType_VNode_x86_32_pdir:
173 return snprintf(buf, len, "x86_32 Page directory at 0x%" PRIxGENPADDR,
174 cap->u.vnode_x86_32_pdir.base);
176 case ObjType_VNode_x86_32_pdpt:
177 return snprintf(buf, len, "x86_32 PDPT at 0x%" PRIxGENPADDR,
178 cap->u.vnode_x86_32_pdpt.base);
180 case ObjType_VNode_x86_64_ptable:
181 return snprintf(buf, len, "x86_64 Page table at 0x%" PRIxGENPADDR,
182 cap->u.vnode_x86_64_ptable.base);
184 case ObjType_VNode_x86_64_pdir:
185 return snprintf(buf, len, "x86_64 Page directory at 0x%" PRIxGENPADDR,
186 cap->u.vnode_x86_64_pdir.base);
188 case ObjType_VNode_x86_64_pdpt:
189 return snprintf(buf, len, "x86_64 PDPT at 0x%" PRIxGENPADDR,
190 cap->u.vnode_x86_64_pdpt.base);
192 case ObjType_VNode_x86_64_pml4:
193 return snprintf(buf, len, "x86_64 PML4 at 0x%" PRIxGENPADDR,
194 cap->u.vnode_x86_64_pml4.base);
196 case ObjType_IRQTable:
197 return snprintf(buf, len, "IRQTable cap");
199 case ObjType_EndPoint:
200 return snprintf(buf, len, "EndPoint cap (disp %p offset 0x%" PRIxLVADDR ")",
201 cap->u.endpoint.listener, cap->u.endpoint.epoffset);
204 return snprintf(buf, len, "IO cap (0x%hx-0x%hx)",
205 cap->u.io.start, cap->u.io.end);
208 return snprintf(buf, len, "Kernel cap");
211 return snprintf(buf, len, "ID capability (coreid 0x%" PRIxCOREID
212 " core_local_id 0x%" PRIx32 ")", cap->u.id.coreid,
213 cap->u.id.core_local_id);
215 case ObjType_PerfMon:
216 return snprintf(buf, len, "PerfMon cap");
219 return snprintf(buf, len, "Null cap (empty slot)");
222 return snprintf(buf, len, "UNKNOWN TYPE! (%d)", cap->type);
226 int debug_print_cap_at_capref(char *buf, size_t len, struct capref cap)
228 struct capability capability;
231 if (capref_is_null(cap)) {
232 return snprintf(buf, len, "(null cap)");
235 err = debug_cap_identify(cap, &capability);
236 if (err_is_fail(err)) {
237 return snprintf(buf, len, "(ERROR identifying cap!)");
239 return debug_print_cap(buf, len, &capability);
244 * \brief Walk the cspace printing all non-null capabilities
246 * \param cnode cnode to walk
247 * \param level depth in the cspace
249 * \bug assumes guards are always zero
251 static void walk_cspace(struct cnoderef cnode, uint8_t level)
253 struct capability cap;
256 struct capref pos = {
257 .cnode = cnode, .slot = 0
260 // If too many bits resolved, return
261 if (pos.cnode.address_bits + pos.cnode.guard_size + pos.cnode.size_bits
266 // Walk through all the slots in the CNode
267 for (pos.slot = 0; pos.slot < (((capaddr_t)1) << cnode.size_bits); pos.slot++) {
269 err = debug_cap_identify(pos, &cap);
271 // If cap type was Null, kernel returns error
272 if (err_no(err) == SYS_ERR_IDENTIFY_LOOKUP ||
273 err_no(err) == SYS_ERR_CAP_NOT_FOUND ||
274 err_no(err) == SYS_ERR_LMP_CAPTRANSFER_SRC_LOOKUP) {
276 } else if (err_is_fail(err)) {
277 DEBUG_ERR(err, "debug_cap_identify failed");
284 // Print the stats for the child slot
285 for(int i = 0; i < level; i++) {
286 prpos += snprintf(&buf[prpos], sizeof(buf) - prpos, " ");
287 assert(prpos < sizeof(buf));
289 prpos += snprintf(&buf[prpos], sizeof(buf) - prpos,
290 "slot %" PRIuCADDR " caddr 0x%" PRIxCADDR " (%u bits) is a ",
291 pos.slot, get_cap_addr(pos), get_cap_valid_bits(pos));
292 assert(prpos < sizeof(buf));
293 prpos += debug_print_cap(&buf[prpos], sizeof(buf) - prpos, &cap);
294 assert(prpos < sizeof(buf));
295 debug_printf("%s\n", buf);
297 // If CNode type, descend into it
298 if (cap.type == ObjType_CNode) {
299 struct cnoderef childcn = {
300 .address = get_cap_addr(pos),
301 .address_bits = get_cap_valid_bits(pos),
302 .size_bits = cap.u.cnode.bits,
303 .guard_size = cap.u.cnode.guard_size,
305 walk_cspace(childcn, level + 1);
311 * \brief Dump an arbitrary cspace, given the root
313 void debug_cspace(struct capref root)
315 struct capability cap;
317 /* find out size of root cnode */
318 errval_t err = debug_cap_identify(root, &cap);
319 assert(err_is_ok(err));
321 struct cnoderef cnode = {
322 .address = get_cap_addr(root),
323 .address_bits = get_cap_valid_bits(root),
324 .size_bits = cap.u.cnode.bits,
325 .guard_size = cap.u.cnode.guard_size,
328 walk_cspace(cnode, 0);
331 void debug_my_cspace(void)
333 // XXX: Assume my root CNode has a size of #DEFAULT_CNODE_BITS
334 struct cnoderef cnode = {
337 .size_bits = DEFAULT_CNODE_BITS,
341 walk_cspace(cnode, 0);
344 int debug_print_capref(char *buf, size_t len, struct capref cap)
346 return snprintf(buf, len, "CNode addr 0x%08" PRIxCADDR
347 ", vbits = %d, slot %" PRIuCADDR ", vbits = %d",
348 get_cnode_addr(cap), get_cnode_valid_bits(cap), cap.slot,
349 get_cap_valid_bits(cap));
352 void debug_dump_mem(lvaddr_t start_addr, lvaddr_t end_addr, lvaddr_t point)
354 debug_printf("Dumping memory in range 0x%" PRIxLVADDR
355 " to 0x%" PRIxLVADDR ":\n",
356 start_addr, end_addr);
358 for (uintptr_t *p = (void *)start_addr; (uintptr_t)p < end_addr; p++) {
359 uint8_t *bytes = (void *)p;
362 for (int i = 0; i < sizeof(uintptr_t); i++) {
363 bufpos += snprintf(&buf[bufpos], sizeof(buf) - bufpos, "%02x ", bytes[i]);
364 assert(bufpos < sizeof(buf));
366 debug_printf("%p: %.*s %*" PRIxPTR "%s\n", p, (int)sizeof(buf), buf,
367 (int)sizeof(uintptr_t) * 2, *p,
368 p == (uintptr_t *)point ? " <== We are here" : "");
372 void debug_dump_mem_around_addr(lvaddr_t addr)
374 /* lvaddr_t page_aligned_addr = ROUND_DOWN(addr, BASE_PAGE_SIZE); */
375 lvaddr_t start_addr = ROUND_DOWN(addr - DISP_MEMORY_SIZE/2, sizeof(uintptr_t));
376 lvaddr_t end_addr = ROUND_UP(addr + DISP_MEMORY_SIZE/2, sizeof(uintptr_t));
378 /* if (start_addr < page_aligned_addr) { */
379 /* start_addr = page_aligned_addr; */
381 /* if (end_addr > page_aligned_addr + BASE_PAGE_SIZE) { */
382 /* end_addr = page_aligned_addr + BASE_PAGE_SIZE; */
385 debug_dump_mem(start_addr, end_addr, addr);
388 void debug_err(const char *file, const char *func, int line, errval_t err,
389 const char *msg, ...)
394 char *leader = (err == 0) ? "SUCCESS" : "ERROR";
396 snprintf(str, sizeof(str), "%s: %.*s.%u in %s() %s:%d\n%s: ",
397 leader, DISP_NAME_LEN, disp_name(), disp_get_core_id(),
398 func, file, line, leader);
399 sys_print(str, sizeof(str));
404 vsnprintf(str, sizeof(str), msg, ap);
406 sys_print(str, sizeof(str));
411 err_print_calltrace(err);