aos/lib/aos/debug.c
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

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;
}