posixcompat: properly handle PTHREAD_MUTEX_RECURSIVE and BF thread id assignment.
[barrelfish] / lib / barrelfish / debug.c
1 /**
2  * \file
3  * \brief Debugging functions
4  */
5
6 /*
7  * Copyright (c) 2008, 2009, 2010, 2011, ETH Zurich.
8  * All rights reserved.
9  *
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.
13  */
14
15 #include <stdio.h>
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>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <inttypes.h>
26 #include <barrelfish_kpi/dispatcher_shared.h>
27
28 #define DISP_MEMORY_SIZE            1024 // size of memory dump in bytes
29
30 /**
31  * \brief Print a message and abort.
32  *
33  * Something irrecoverably bad happened. Print a panic message, then abort.
34  */
35 void user_panic_fn(const char *file, const char *func, int line,
36                    const char *msg, ...)
37 {
38     va_list ap;
39     char msg_str[128];
40     //int msg_str_cc;
41     va_start(ap, msg);
42     //msg_str_cc =
43         vsnprintf(msg_str, sizeof(msg_str), msg, ap);
44     va_end(ap);
45
46     char str[256];
47     //int strcc =
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));
52
53     abort();
54 }
55
56 errval_t debug_cap_identify(struct capref cap, struct capability *ret)
57 {
58     errval_t err, msgerr;
59
60     if (get_cap_addr(cap) == 0) {
61         return SYS_ERR_CAP_NOT_FOUND;
62     }
63
64     union {
65         monitor_blocking_caprep_t caprep;
66         struct capability capability;
67     } u;
68
69     struct monitor_blocking_rpc_client *r = get_monitor_blocking_rpc_client();
70     if (!r) {
71         return LIB_ERR_MONITOR_RPC_NULL;
72     }
73     err = r->vtbl.cap_identify(r, cap, &msgerr, &u.caprep);
74     if (err_is_fail(err)){
75         return err;
76     } else if (err_is_fail(msgerr)) {
77         return msgerr;
78     }
79
80     assert(ret != NULL);
81     *ret = u.capability;
82
83     return msgerr;
84 }
85
86 /**
87  * \brief Enable fine-grained tracing of cap operations on address range
88  * [start_addr, start_addr+size)
89  */
90 errval_t debug_cap_trace_ctrl(bool enable, genpaddr_t start_addr, gensize_t size)
91 {
92     if (enable) {
93         printf("enabling pmem tracing: 0x%"PRIxGENPADDR"--0x%"PRIxGENPADDR"\n",
94                 start_addr, start_addr+size);
95     }
96     return sys_debug_cap_trace_ctrl(enable, start_addr, size);
97 }
98
99 /**
100  * \brief Dump own hw page tables
101  */
102 errval_t debug_dump_hw_ptables(void)
103 {
104     return invoke_dispatcher_dump_ptables(cap_dispatcher);
105 }
106
107 void debug_printf(const char *fmt, ...)
108 {
109     va_list argptr;
110     char str[256];
111     size_t len;
112
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);
118         va_end(argptr);
119     }
120     sys_print(str, sizeof(str));
121 }
122
123 /**
124  * \brief Function to do the actual printing based on the type of capability
125  */
126 int debug_print_cap(char *buf, size_t len, struct capability *cap)
127 {
128     switch (cap->type) {
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);
133
134     case ObjType_RAM:
135         return snprintf(buf, len, "RAM cap (0x%" PRIxGENPADDR ":%u)",
136                         cap->u.ram.base, cap->u.ram.bits);
137
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);
145         }
146         return ret;
147     }
148
149     case ObjType_Dispatcher:
150         return snprintf(buf, len, "Dispatcher cap %p", cap->u.dispatcher.dcb);
151
152     case ObjType_Frame:
153         return snprintf(buf, len, "Frame cap (0x%" PRIxGENPADDR ":%u)",
154                         cap->u.frame.base, cap->u.frame.bits);
155
156     case ObjType_DevFrame:
157         return snprintf(buf, len, "Device Frame cap (0x%" PRIxGENPADDR ":%u)",
158                         cap->u.frame.base, cap->u.devframe.bits);
159
160     case ObjType_VNode_ARM_l1:
161         return snprintf(buf, len, "ARM L1 table at 0x%" PRIxGENPADDR,
162                         cap->u.vnode_arm_l1.base);
163
164     case ObjType_VNode_ARM_l2:
165         return snprintf(buf, len, "ARM L2 table at 0x%" PRIxGENPADDR,
166                         cap->u.vnode_arm_l2.base);
167
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);
171
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);
175
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);
179
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);
183
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);
187
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);
191
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);
195
196     case ObjType_IRQTable:
197         return snprintf(buf, len, "IRQTable cap");
198
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);
202
203     case ObjType_IO:
204         return snprintf(buf, len, "IO cap (0x%hx-0x%hx)",
205                         cap->u.io.start, cap->u.io.end);
206
207     case ObjType_Kernel:
208         return snprintf(buf, len, "Kernel cap");
209
210     case ObjType_ID:
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);
214
215     case ObjType_PerfMon:
216         return snprintf(buf, len, "PerfMon cap");
217
218     case ObjType_Null:
219         return snprintf(buf, len, "Null cap (empty slot)");
220
221     default:
222         return snprintf(buf, len, "UNKNOWN TYPE! (%d)", cap->type);
223     }
224 }
225
226 int debug_print_cap_at_capref(char *buf, size_t len, struct capref cap)
227 {
228     struct capability capability;
229     errval_t err;
230
231     if (capref_is_null(cap)) {
232         return snprintf(buf, len, "(null cap)");
233     }
234
235     err = debug_cap_identify(cap, &capability);
236     if (err_is_fail(err)) {
237         return snprintf(buf, len, "(ERROR identifying cap!)");
238     } else {
239         return debug_print_cap(buf, len, &capability);
240     }
241 }
242
243 /**
244  * \brief Walk the cspace printing all non-null capabilities
245  *
246  * \param cnode         cnode to walk
247  * \param level         depth in the cspace
248  *
249  * \bug assumes guards are always zero
250  */
251 static void walk_cspace(struct cnoderef cnode, uint8_t level)
252 {
253     struct capability cap;
254     errval_t err;
255
256     struct capref pos = {
257         .cnode = cnode, .slot = 0
258     };
259
260     // If too many bits resolved, return
261     if (pos.cnode.address_bits + pos.cnode.guard_size + pos.cnode.size_bits
262         > CPTR_BITS) {
263         return;
264     }
265
266     // Walk through all the slots in the CNode
267     for (pos.slot = 0; pos.slot < (((capaddr_t)1) << cnode.size_bits); pos.slot++) {
268         // Get cap data
269         err = debug_cap_identify(pos, &cap);
270
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) {
275             continue;
276         } else if (err_is_fail(err)) {
277             DEBUG_ERR(err, "debug_cap_identify failed");
278             return;
279         }
280
281         char buf[256];
282         size_t prpos = 0;
283
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));
288         }
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);
296
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,
304             };
305             walk_cspace(childcn, level + 1);
306         }
307     }
308 }
309
310 /**
311  * \brief Dump an arbitrary cspace, given the root
312  */
313 void debug_cspace(struct capref root)
314 {
315     struct capability cap;
316
317     /* find out size of root cnode */
318     errval_t err = debug_cap_identify(root, &cap);
319     assert(err_is_ok(err));
320
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,
326     };
327
328     walk_cspace(cnode, 0);
329 }
330
331 void debug_my_cspace(void)
332 {
333     // XXX: Assume my root CNode has a size of #DEFAULT_CNODE_BITS
334     struct cnoderef cnode = {
335         .address = 0,
336         .address_bits = 0,
337         .size_bits = DEFAULT_CNODE_BITS,
338         .guard_size = 0,
339     };
340
341     walk_cspace(cnode, 0);
342 }
343
344 int debug_print_capref(char *buf, size_t len, struct capref cap)
345 {
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));
350 }
351
352 void debug_dump_mem(lvaddr_t start_addr, lvaddr_t end_addr, lvaddr_t point)
353 {
354     debug_printf("Dumping memory in range 0x%" PRIxLVADDR
355                  " to 0x%" PRIxLVADDR ":\n",
356                  start_addr, end_addr);
357
358     for (uintptr_t *p = (void *)start_addr; (uintptr_t)p < end_addr; p++) {
359         uint8_t *bytes = (void *)p;
360         char buf[32];
361         size_t bufpos = 0;
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));
365         }
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" : "");
369     }
370 }
371
372 void debug_dump_mem_around_addr(lvaddr_t addr)
373 {
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));
377
378     /* if (start_addr < page_aligned_addr) { */
379     /*     start_addr = page_aligned_addr; */
380     /* } */
381     /* if (end_addr > page_aligned_addr + BASE_PAGE_SIZE) { */
382     /*     end_addr = page_aligned_addr + BASE_PAGE_SIZE; */
383     /* } */
384
385     debug_dump_mem(start_addr, end_addr, addr);
386 }
387
388 void debug_err(const char *file, const char *func, int line, errval_t err,
389                const char *msg, ...)
390 {
391     va_list ap;
392
393     char str[256];
394     char *leader = (err == 0) ? "SUCCESS" : "ERROR";
395     //int strcc =
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));
400
401     if (msg != NULL) {
402         va_start(ap, msg);
403         //int strcc2 =
404             vsnprintf(str, sizeof(str), msg, ap);
405         va_end(ap);
406         sys_print(str, sizeof(str));
407     }
408     sys_print("\n", 1);
409
410     if (err != 0) {
411         err_print_calltrace(err);
412     }
413 }