535 lines
17 KiB
C
535 lines
17 KiB
C
/**
|
|
* \file
|
|
* \brief Debugging functions
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2008-2011, ETH Zurich.
|
|
* Copyright (c) 2015, 2016 Hewlett Packard Enterprise Development LP.
|
|
* All rights reserved.
|
|
*
|
|
* This file is distributed under the terms in the attached LICENSE file.
|
|
* If you do not find this file, copies can be found by writing to:
|
|
* ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <aos/aos.h>
|
|
#include <aos/caddr.h>
|
|
#include <aos/debug.h>
|
|
#include <aos/sys_debug.h>
|
|
#include <aos/dispatch.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
#include <barrelfish_kpi/dispatcher_shared.h>
|
|
#include <stdio.h>
|
|
|
|
#define DISP_MEMORY_SIZE 1024 // size of memory dump in bytes
|
|
|
|
/**
|
|
* \brief Print a message and abort.
|
|
*
|
|
* Something irrecoverably bad happened. Print a panic message, then abort.
|
|
*/
|
|
void user_panic_fn(const char *file, const char *func, int line,
|
|
const char *msg, ...)
|
|
{
|
|
va_list ap;
|
|
char msg_str[128];
|
|
//int msg_str_cc;
|
|
va_start(ap, msg);
|
|
//msg_str_cc =
|
|
vsnprintf(msg_str, sizeof(msg_str), msg, ap);
|
|
va_end(ap);
|
|
|
|
char str[256];
|
|
//int strcc =
|
|
snprintf(str, sizeof(str), "%.*s.%u in %s() %s:%d\n%s\n",
|
|
DISP_NAME_LEN, disp_name(), disp_get_current_core_id(),
|
|
func, file, line, msg_str);
|
|
sys_print(str, sizeof(str));
|
|
|
|
abort();
|
|
}
|
|
|
|
/*
|
|
* Have this invocation here to make debug_cap_identify work for domains that
|
|
* have no monitor connection but hold Kernel cap (e.g. init)
|
|
*/
|
|
static inline errval_t
|
|
invoke_kernel_identify_cap(capaddr_t cap, int level, struct capability *out)
|
|
{
|
|
return cap_invoke4(cap_kernel, KernelCmd_Identify_cap, cap, level,
|
|
(uintptr_t)out).error;
|
|
}
|
|
|
|
errval_t debug_cap_identify(struct capref cap, struct capability *ret)
|
|
{
|
|
if (get_cap_addr(cap) == 0) {
|
|
return SYS_ERR_CAP_NOT_FOUND;
|
|
}
|
|
|
|
uint8_t level = get_cap_level(cap);
|
|
capaddr_t caddr = get_cap_addr(cap);
|
|
errval_t err = invoke_kernel_identify_cap(caddr, level, ret);
|
|
if (err_is_ok(err)) {
|
|
// we have kernel cap, return result;
|
|
return SYS_ERR_OK;
|
|
}
|
|
|
|
// TODO: For a generic implementation, query the monitor. See libbarrelfish.
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* \brief Enable fine-grained tracing of cap operations on address range
|
|
* [start_addr, start_addr+size)
|
|
* \arg types enable tracing for given set of ORed ObjType_s
|
|
* \arg start_addr start of region to trace for
|
|
* \arg size size of region to trace for
|
|
*/
|
|
errval_t debug_cap_trace_ctrl(uintptr_t types, genpaddr_t start_addr, gensize_t size)
|
|
{
|
|
if (types) {
|
|
printf("enabling pmem tracing: 0x%"PRIxGENPADDR"--0x%"PRIxGENPADDR
|
|
" for types 0x%"PRIxPTR"\n",
|
|
start_addr, start_addr+size, types);
|
|
}
|
|
return sys_debug_cap_trace_ctrl(types, start_addr, size);
|
|
}
|
|
|
|
/**
|
|
* \brief Dump own hw page tables
|
|
*/
|
|
errval_t debug_dump_hw_ptables(void* vaddr)
|
|
{
|
|
return invoke_dispatcher_dump_ptables(cap_dispatcher, (lvaddr_t)vaddr);
|
|
}
|
|
|
|
void debug_printf(const char *fmt, ...)
|
|
{
|
|
struct thread *me = thread_self();
|
|
va_list argptr;
|
|
char id[32] = "-";
|
|
char str[1024];
|
|
size_t len;
|
|
|
|
if (me) {
|
|
snprintf(id, sizeof(id), "%"PRIuPTR, thread_get_id(me));
|
|
}
|
|
len = snprintf(str, sizeof(str), "\033[34m%.*s.\033[31m%u.%s\033[0m: ",
|
|
DISP_NAME_LEN, disp_name(), disp_get_current_core_id(), id);
|
|
if (len < sizeof(str)) {
|
|
va_start(argptr, fmt);
|
|
vsnprintf(str + len, sizeof(str) - len, fmt, argptr);
|
|
va_end(argptr);
|
|
}
|
|
sys_print(str, sizeof(str));
|
|
}
|
|
|
|
/**
|
|
* \brief Function to do the actual printing based on the type of capability
|
|
*/
|
|
// TODO Fix this for all new cap types
|
|
//STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
|
|
int debug_print_cap(char *buf, size_t len, struct capability *cap)
|
|
{
|
|
char *mappingtype;
|
|
switch (cap->type) {
|
|
case ObjType_PhysAddr:
|
|
return snprintf(buf, len,
|
|
"physical address range cap (0x%" PRIxGENPADDR ":%" PRIuGENSIZE ")",
|
|
cap->u.physaddr.base, cap->u.physaddr.bytes);
|
|
|
|
case ObjType_RAM:
|
|
return snprintf(buf, len, "RAM cap (0x%" PRIxGENPADDR ":%" PRIuGENSIZE ")",
|
|
cap->u.ram.base, cap->u.ram.bytes);
|
|
|
|
case ObjType_L1CNode: {
|
|
int ret = snprintf(buf, len, "L1 CNode cap "
|
|
"(allocated bytes %#"PRIxGENSIZE
|
|
", rights mask %#"PRIxCAPRIGHTS")",
|
|
cap->u.l1cnode.allocated_bytes, cap->u.l1cnode.rightsmask);
|
|
return ret;
|
|
}
|
|
|
|
case ObjType_L2CNode: {
|
|
return snprintf(buf, len, "L2 CNode cap "
|
|
"(cnode=%"PRIxLPADDR")"
|
|
"(rights mask %#"PRIxCAPRIGHTS")",
|
|
cap->u.l2cnode.cnode,
|
|
cap->u.l2cnode.rightsmask);
|
|
}
|
|
|
|
case ObjType_EndPointUMP:
|
|
return snprintf(buf, len, "EndPoint UMP cap (0x%" PRIxGENPADDR ":%"
|
|
PRIuGENSIZE "), if=%" PRIu32,
|
|
cap->u.endpointump.base, cap->u.endpointump.bytes,
|
|
cap->u.endpointump.iftype);
|
|
|
|
case ObjType_Dispatcher:
|
|
return snprintf(buf, len, "Dispatcher cap %p", cap->u.dispatcher.dcb);
|
|
|
|
case ObjType_Frame:
|
|
return snprintf(buf, len, "Frame cap (0x%" PRIxGENPADDR ":%" PRIuGENSIZE ")",
|
|
cap->u.frame.base, cap->u.frame.bytes);
|
|
|
|
case ObjType_DevFrame:
|
|
return snprintf(buf, len, "Device Frame cap (0x%" PRIxGENPADDR ":%" PRIuGENSIZE ")",
|
|
cap->u.frame.base, cap->u.devframe.bytes);
|
|
|
|
case ObjType_VNode_ARM_l1:
|
|
return snprintf(buf, len, "ARM L1 table at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_arm_l1.base);
|
|
|
|
case ObjType_VNode_ARM_l2:
|
|
return snprintf(buf, len, "ARM L2 table at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_arm_l2.base);
|
|
|
|
case ObjType_VNode_AARCH64_l0:
|
|
return snprintf(buf, len, "AARCH64 L0 table at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_aarch64_l0.base);
|
|
|
|
case ObjType_VNode_AARCH64_l1:
|
|
return snprintf(buf, len, "AARCH64 L1 table at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_aarch64_l1.base);
|
|
|
|
case ObjType_VNode_AARCH64_l2:
|
|
return snprintf(buf, len, "AARCH64 L2 table at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_aarch64_l2.base);
|
|
|
|
case ObjType_VNode_AARCH64_l3:
|
|
return snprintf(buf, len, "AARCH64 L3 table at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_aarch64_l3.base);
|
|
|
|
case ObjType_VNode_x86_32_ptable:
|
|
return snprintf(buf, len, "x86_32 Page table at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_x86_32_ptable.base);
|
|
|
|
case ObjType_VNode_x86_32_pdir:
|
|
return snprintf(buf, len, "x86_32 Page directory at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_x86_32_pdir.base);
|
|
|
|
case ObjType_VNode_x86_32_pdpt:
|
|
return snprintf(buf, len, "x86_32 PDPT at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_x86_32_pdpt.base);
|
|
|
|
case ObjType_VNode_x86_64_ptable:
|
|
return snprintf(buf, len, "x86_64 Page table at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_x86_64_ptable.base);
|
|
|
|
case ObjType_VNode_x86_64_pdir:
|
|
return snprintf(buf, len, "x86_64 Page directory at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_x86_64_pdir.base);
|
|
|
|
case ObjType_VNode_x86_64_pdpt:
|
|
return snprintf(buf, len, "x86_64 PDPT at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_x86_64_pdpt.base);
|
|
|
|
case ObjType_VNode_x86_64_pml4:
|
|
return snprintf(buf, len, "x86_64 PML4 at 0x%" PRIxGENPADDR,
|
|
cap->u.vnode_x86_64_pml4.base);
|
|
|
|
case ObjType_Frame_Mapping:
|
|
mappingtype = "Frame";
|
|
goto ObjType_Mapping;
|
|
case ObjType_DevFrame_Mapping:
|
|
mappingtype = "DevFrame";
|
|
goto ObjType_Mapping;
|
|
|
|
case ObjType_VNode_x86_64_pml4_Mapping:
|
|
mappingtype = "x86_64 PML4";
|
|
goto ObjType_Mapping;
|
|
case ObjType_VNode_x86_64_pdpt_Mapping:
|
|
mappingtype = "x86_64 PDPT";
|
|
goto ObjType_Mapping;
|
|
case ObjType_VNode_x86_64_pdir_Mapping:
|
|
mappingtype = "x86_64 PDIR";
|
|
goto ObjType_Mapping;
|
|
case ObjType_VNode_x86_64_ptable_Mapping:
|
|
mappingtype = "x86_64 PTABLE";
|
|
goto ObjType_Mapping;
|
|
|
|
case ObjType_VNode_x86_32_pdpt_Mapping:
|
|
mappingtype = "x86_32 PDPT";
|
|
goto ObjType_Mapping;
|
|
case ObjType_VNode_x86_32_pdir_Mapping:
|
|
mappingtype = "x86_32 PDIR";
|
|
goto ObjType_Mapping;
|
|
case ObjType_VNode_x86_32_ptable_Mapping:
|
|
mappingtype = "x86_32 PTABLE";
|
|
goto ObjType_Mapping;
|
|
|
|
case ObjType_VNode_ARM_l1_Mapping:
|
|
mappingtype = "ARM l1";
|
|
goto ObjType_Mapping;
|
|
case ObjType_VNode_ARM_l2_Mapping:
|
|
mappingtype = "ARM l2";
|
|
goto ObjType_Mapping;
|
|
|
|
case ObjType_VNode_AARCH64_l0_Mapping:
|
|
mappingtype = "AARCH64 l0";
|
|
goto ObjType_Mapping;
|
|
case ObjType_VNode_AARCH64_l1_Mapping:
|
|
mappingtype = "AARCH64 l1";
|
|
goto ObjType_Mapping;
|
|
case ObjType_VNode_AARCH64_l2_Mapping:
|
|
mappingtype = "AARCH64 l2";
|
|
goto ObjType_Mapping;
|
|
case ObjType_VNode_AARCH64_l3_Mapping:
|
|
mappingtype = "AARCH64 l3";
|
|
goto ObjType_Mapping;
|
|
|
|
case ObjType_EndPointLMP:
|
|
return snprintf(buf, len, "EndPoint cap (disp %p offset 0x%" PRIxLVADDR ")",
|
|
cap->u.endpointlmp.listener, cap->u.endpointlmp.epoffset);
|
|
|
|
|
|
ObjType_Mapping:
|
|
return snprintf(buf, len, "%s Mapping (%s cap @%p, "
|
|
"ptable cap @0x%p, entry=%hu, pte_count=%hu)",
|
|
mappingtype, mappingtype,
|
|
cap->u.frame_mapping.cap,
|
|
cap->u.frame_mapping.ptable,
|
|
cap->u.frame_mapping.entry,
|
|
cap->u.frame_mapping.pte_count);
|
|
|
|
case ObjType_IRQTable:
|
|
return snprintf(buf, len, "IRQTable cap");
|
|
|
|
case ObjType_IRQSrc:
|
|
return snprintf(buf, len, "IRQSrc cap (vec: %"PRIu64"-%"PRIu64")",
|
|
cap->u.irqsrc.vec_start, cap->u.irqsrc.vec_end);
|
|
|
|
case ObjType_IRQDest:
|
|
return snprintf(buf, len, "IRQDest cap (vec: %"PRIu64", cpu: %"PRIu64")",
|
|
cap->u.irqdest.vector, cap->u.irqdest.cpu);
|
|
|
|
case ObjType_IO:
|
|
return snprintf(buf, len, "IO cap (0x%hx-0x%hx)",
|
|
cap->u.io.start, cap->u.io.end);
|
|
|
|
case ObjType_Kernel:
|
|
return snprintf(buf, len, "Kernel cap");
|
|
|
|
case ObjType_KernelControlBlock:
|
|
return snprintf(buf, len, "Kernel control block cap");
|
|
|
|
case ObjType_ID:
|
|
return snprintf(buf, len, "ID capability (coreid 0x%" PRIxCOREID
|
|
" core_local_id 0x%" PRIx32 ")", cap->u.id.coreid,
|
|
cap->u.id.core_local_id);
|
|
|
|
case ObjType_ProcessManager:
|
|
return snprintf(buf, len, "Process manager capability");
|
|
|
|
case ObjType_Domain:
|
|
return snprintf(buf, len, "Domain capability (coreid 0x%" PRIxCOREID
|
|
" core_local_id 0x%" PRIx32 ")", cap->u.domain.coreid,
|
|
cap->u.domain.core_local_id);
|
|
|
|
case ObjType_PerfMon:
|
|
return snprintf(buf, len, "PerfMon cap");
|
|
|
|
case ObjType_Null:
|
|
return snprintf(buf, len, "Null cap (empty slot)");
|
|
|
|
default:
|
|
return snprintf(buf, len, "UNKNOWN TYPE! (%d)", cap->type);
|
|
}
|
|
}
|
|
|
|
int debug_print_cap_at_capref(char *buf, size_t len, struct capref cap)
|
|
{
|
|
struct capability capability;
|
|
errval_t err;
|
|
|
|
if (capref_is_null(cap)) {
|
|
return snprintf(buf, len, "(null cap)");
|
|
}
|
|
|
|
err = invoke_cap_identify(cap, &capability);
|
|
if (err_is_fail(err)) {
|
|
return snprintf(buf, len, "(ERROR identifying cap!)");
|
|
} else {
|
|
return debug_print_cap(buf, len, &capability);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Walk and debug print a L2 CNode
|
|
*/
|
|
static void walk_cspace_l2(struct capref l2cnode){
|
|
errval_t err;
|
|
struct capability cap;
|
|
struct cnoderef cnode = build_cnoderef(l2cnode, 1);
|
|
|
|
debug_printf(" Printing L2 CNode at L1 slot=%d\n", l2cnode.slot);
|
|
|
|
for(int i=0; i<L2_CNODE_SLOTS; i++){
|
|
struct capref pos = {
|
|
.cnode = cnode, .slot = i
|
|
};
|
|
|
|
// Get cap data
|
|
err = invoke_cap_identify(pos, &cap);
|
|
if (err_no(err) == SYS_ERR_IDENTIFY_LOOKUP ||
|
|
err_no(err) == SYS_ERR_CAP_NOT_FOUND ||
|
|
err_no(err) == SYS_ERR_LMP_CAPTRANSFER_SRC_LOOKUP) {
|
|
continue;
|
|
} else if (err_is_fail(err)) {
|
|
DEBUG_ERR(err, "debug_cap_identify failed");
|
|
return;
|
|
}
|
|
|
|
char buf[256];
|
|
size_t prpos = 0;
|
|
|
|
prpos += snprintf(buf, sizeof(buf),
|
|
"slot %" PRIuCADDR " caddr 0x%" PRIxCADDR " is a ",
|
|
pos.slot, get_cap_addr(pos));
|
|
assert(prpos < sizeof(buf));
|
|
prpos += debug_print_cap(&buf[prpos], sizeof(buf) - prpos, &cap);
|
|
assert(prpos < sizeof(buf));
|
|
debug_printf(" %s\n", buf);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Dump an arbitrary cspace, given the root
|
|
*
|
|
* \bug Works correct only for own cspace. (to fix this cap_identify must
|
|
* be made to work with all caps)
|
|
*
|
|
*/
|
|
void debug_cspace(struct capref root)
|
|
{
|
|
struct capability root_cap;
|
|
struct capability l2_cap;
|
|
|
|
/* find out size of root cnode */
|
|
errval_t err = invoke_cap_identify(root, &root_cap);
|
|
assert(err_is_ok(err));
|
|
assert(root_cap.type == ObjType_L1CNode);
|
|
|
|
size_t c1size = 0;
|
|
err = invoke_cnode_get_size(root, &c1size);
|
|
assert(err_is_ok(err));
|
|
|
|
int l1slots = c1size/sizeof(struct capability);
|
|
debug_printf("Printing L1 CNode (slots=%u)\n", l1slots);
|
|
for(int slot=0; slot < l1slots; slot++){
|
|
|
|
struct cnoderef cnode = build_cnoderef(root, 0);
|
|
struct capref pos = {
|
|
.cnode = cnode, .slot = slot
|
|
};
|
|
err = invoke_cap_identify(pos, &l2_cap);
|
|
|
|
// If cap type was Null, kernel returns error
|
|
if (err_no(err) == SYS_ERR_IDENTIFY_LOOKUP ||
|
|
err_no(err) == SYS_ERR_CAP_NOT_FOUND ||
|
|
err_no(err) == SYS_ERR_LMP_CAPTRANSFER_SRC_LOOKUP) {
|
|
continue;
|
|
} else if (err_is_fail(err)) {
|
|
DEBUG_ERR(err, "debug_cap_identify failed");
|
|
return;
|
|
}
|
|
walk_cspace_l2(pos);
|
|
}
|
|
}
|
|
|
|
void debug_my_cspace(void)
|
|
{
|
|
debug_cspace(cap_root);
|
|
}
|
|
|
|
int debug_print_capref(char *buf, size_t len, struct capref cap)
|
|
{
|
|
return snprintf(buf, len, "CSpace root addr 0x%08" PRIxCADDR", "
|
|
"CNode addr 0x%08" PRIxCADDR
|
|
", level = %d, slot %" PRIuCADDR ", level = %d",
|
|
get_croot_addr(cap), get_cnode_addr(cap),
|
|
get_cnode_level(cap), cap.slot, get_cap_level(cap));
|
|
}
|
|
|
|
int debug_print_cnoderef(char *buf, size_t len, struct cnoderef cnode)
|
|
{
|
|
return snprintf(buf, len, "CSpace root addr 0x%08"PRIxCADDR", "
|
|
"CNode addr 0x%08"PRIxCADDR", level = %d",
|
|
cnode.croot, cnode.cnode, cnode.level);
|
|
}
|
|
|
|
void debug_dump_mem(lvaddr_t start_addr, lvaddr_t end_addr, lvaddr_t point)
|
|
{
|
|
debug_printf("Dumping memory in range 0x%" PRIxLVADDR
|
|
" to 0x%" PRIxLVADDR ":\n",
|
|
start_addr, end_addr);
|
|
|
|
for (uintptr_t *p = (void *)start_addr; (uintptr_t)p < end_addr; p++) {
|
|
uint8_t *bytes = (void *)p;
|
|
char buf[32];
|
|
size_t bufpos = 0;
|
|
for (int i = 0; i < sizeof(uintptr_t); i++) {
|
|
bufpos += snprintf(&buf[bufpos], sizeof(buf) - bufpos, "%02x ", bytes[i]);
|
|
assert(bufpos < sizeof(buf));
|
|
}
|
|
debug_printf("%p: %.*s %*" PRIxPTR "%s\n", p, (int)sizeof(buf), buf,
|
|
(int)sizeof(uintptr_t) * 2, *p,
|
|
p == (uintptr_t *)point ? " <== We are here" : "");
|
|
}
|
|
}
|
|
|
|
void debug_dump_mem_around_addr(lvaddr_t addr)
|
|
{
|
|
/* lvaddr_t page_aligned_addr = ROUND_DOWN(addr, BASE_PAGE_SIZE); */
|
|
lvaddr_t start_addr = ROUND_DOWN(addr - DISP_MEMORY_SIZE/2, sizeof(uintptr_t));
|
|
lvaddr_t end_addr = ROUND_UP(addr + 2 * DISP_MEMORY_SIZE, sizeof(uintptr_t));
|
|
|
|
/* if (start_addr < page_aligned_addr) { */
|
|
/* start_addr = page_aligned_addr; */
|
|
/* } */
|
|
/* if (end_addr > page_aligned_addr + BASE_PAGE_SIZE) { */
|
|
/* end_addr = page_aligned_addr + BASE_PAGE_SIZE; */
|
|
/* } */
|
|
|
|
debug_dump_mem(start_addr, end_addr, addr);
|
|
}
|
|
|
|
void debug_err(const char *file, const char *func, int line, errval_t err,
|
|
const char *msg, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
char str[256];
|
|
char *leader = (err == 0) ? "SUCCESS" : "ERROR";
|
|
//int strcc =
|
|
snprintf(str, sizeof(str), "%s: %.*s.%u in %s() %s:%d\n%s: ",
|
|
leader, DISP_NAME_LEN, disp_name(), disp_get_current_core_id(),
|
|
func, file, line, leader);
|
|
sys_print(str, sizeof(str));
|
|
|
|
if (msg != NULL) {
|
|
va_start(ap, msg);
|
|
//int strcc2 =
|
|
vsnprintf(str, sizeof(str), msg, ap);
|
|
va_end(ap);
|
|
sys_print(str, sizeof(str));
|
|
}
|
|
sys_print("\n", 1);
|
|
|
|
if (err != 0) {
|
|
err_print_calltrace(err);
|
|
}
|
|
}
|
|
|
|
bool debug_notify_syscall = false;
|
|
|
|
void debug_control_plane_forbidden(void);
|
|
void debug_control_plane_forbidden(void)
|
|
{
|
|
debug_notify_syscall = true;
|
|
}
|