From 8e088efd3349d321b24ece41d7579aa0905c7c2d Mon Sep 17 00:00:00 2001 From: 0aids Date: Mon, 8 Jun 2026 20:12:51 +1000 Subject: [PATCH 01/27] weird ass linking problems sort of fixed cmake -B build -S . -DCMAKE_SYSTEM_NAME=Generic -DCMAKE_C_COMPILER_TARGET=aarch64-none-elf -DCMAKE_CXX_COMPILER_TARGET=aarch64-none-elf -DCMAKE_C_COMPILER_WORKS=ON -DCMAKE_CXX_COMPILER_WORKS=ON -DLIBUNWIND_IS_BAREMETAL=ON -DLIBUNWIND_ENABLE_SHARED=OFF -DLIBUNWIND_ENABLE_THREADS=OFF -DLIBUNWIND_USE_COMPILER_RT=ON -DLIBUNWIND_ENABLE_PEDANTIC=OFF -DLIBUNWIND_ENABLE_ASSERTIONS=OFF -DCMAKE_BUILD_TYPE=Debug -DLIBUNWIND_ENABLE_STATIC=ON -DCMAKE_ASM_COMPILER="$CC" -DCMAKE_ASM_COMPILER_WORKS=ON -DCMAKE_CXX_FLAGS="-fno-exceptions" Signed-off-by: 0aids --- .gitmodules | 3 + dep/libunwind | 1 + dep/llvm-project | 1 + examples/backtrace_test/Makefile | 42 ++++ examples/backtrace_test/backtracer.c | 30 +++ examples/backtrace_test/faulter.c | 12 + .../backtrace_test/lwip_include/arch/cc.h | 70 ++++++ .../backtrace_test/lwip_include/lwipopts.h | 208 ++++++++++++++++++ examples/backtrace_test/meta.py | 48 ++++ examples/backtrace_test/posix_test.mk | 122 ++++++++++ examples/backtrace_test/unwind.ld | 40 ++++ 11 files changed, 577 insertions(+) create mode 160000 dep/libunwind create mode 160000 dep/llvm-project create mode 100644 examples/backtrace_test/Makefile create mode 100644 examples/backtrace_test/backtracer.c create mode 100644 examples/backtrace_test/faulter.c create mode 100644 examples/backtrace_test/lwip_include/arch/cc.h create mode 100644 examples/backtrace_test/lwip_include/lwipopts.h create mode 100644 examples/backtrace_test/meta.py create mode 100644 examples/backtrace_test/posix_test.mk create mode 100644 examples/backtrace_test/unwind.ld diff --git a/.gitmodules b/.gitmodules index 7ddfb0378..154ebccaf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule "dep/wasm-micro-runtime"] path = dep/wasm-micro-runtime url = https://github.com/au-ts/wasm-micro-runtime +[submodule "dep/libunwind"] + path = dep/libunwind + url = https://github.com/libunwind/libunwind.git diff --git a/dep/libunwind b/dep/libunwind new file mode 160000 index 000000000..473b1da68 --- /dev/null +++ b/dep/libunwind @@ -0,0 +1 @@ +Subproject commit 473b1da68ee145e887f7a39150208f252e9a3a7a diff --git a/dep/llvm-project b/dep/llvm-project new file mode 160000 index 000000000..7da29bc52 --- /dev/null +++ b/dep/llvm-project @@ -0,0 +1 @@ +Subproject commit 7da29bc529d74d327804ad25e49e0cdeccfed263 diff --git a/examples/backtrace_test/Makefile b/examples/backtrace_test/Makefile new file mode 100644 index 000000000..eea066f56 --- /dev/null +++ b/examples/backtrace_test/Makefile @@ -0,0 +1,42 @@ +# +# Copyright 2026, UNSW +# +# SPDX-License-Identifier: BSD-2-Clause +# + +ifeq ($(strip $(MICROKIT_SDK)),) +$(error MICROKIT_SDK must be specified) +endif +override MICROKIT_SDK:=$(abspath ${MICROKIT_SDK}) + +export LIONSOS ?= $(abspath ../..) +export POSIX_TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +export MICROKIT_CONFIG ?= debug +export BUILD_DIR ?= $(abspath build) +export MICROKIT_BOARD ?= qemu_virt_aarch64 + +IMAGE_FILE := $(BUILD_DIR)/posix_test.img +REPORT_FILE := $(BUILD_DIR)/report.txt + +all: ${IMAGE_FILE} + +qemu qemu-gdb ${IMAGE_FILE} ${REPORT_FILE} clean clobber libunwind.a: ${BUILD_DIR}/Makefile FORCE + ${MAKE} -C ${BUILD_DIR} MICROKIT_SDK=${MICROKIT_SDK} $(notdir $@) + +${BUILD_DIR}/Makefile: posix_test.mk Makefile + mkdir -p ${BUILD_DIR} + cp posix_test.mk $@ + echo "export LIONSOS ?= ${LIONSOS}" > $@ + echo "export POSIX_TEST_DIR ?= ${POSIX_TEST_DIR}" >> $@ + echo "export BUILD_DIR := ${BUILD_DIR}" >> $@ + echo "export MICROKIT_BOARD ?= ${MICROKIT_BOARD}" >> $@ + echo "export MICROKIT_SDK ?= ${MICROKIT_SDK}" >> $@ + echo "export MICROKIT_CONFIG ?= ${MICROKIT_CONFIG}" >> $@ + cat posix_test.mk >> $@ + +submodules: + git submodule update --init $(LIONSOS)/dep/sddf + git submodule update --init $(LIONSOS)/dep/libmicrokitco + git submodule update --init $(LIONSOS)/dep/libunwind + +FORCE: diff --git a/examples/backtrace_test/backtracer.c b/examples/backtrace_test/backtracer.c new file mode 100644 index 000000000..1940c9eec --- /dev/null +++ b/examples/backtrace_test/backtracer.c @@ -0,0 +1,30 @@ +#include +#include +#define UNW_LOCAL_ONLY +#include + +void show_backtrace (void) { + unw_cursor_t cursor; unw_context_t uc; + unw_word_t ip, sp; + + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + while (unw_step(&cursor) > 0) { + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + printf ("ip = %lx, sp = %lx\n", (long) ip, (long) sp); + } +} + +void init() { + microkit_dbg_puts("BACKTRACER | Backtracer initialised!\n"); + show_backtrace(); +} +seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, + microkit_msginfo *reply_msginfo) { + + microkit_dbg_puts("BACKTRACER | Fault received!\n"); + return 0; +} +void notified(microkit_channel ch) {} +microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) {} diff --git a/examples/backtrace_test/faulter.c b/examples/backtrace_test/faulter.c new file mode 100644 index 000000000..233e0c534 --- /dev/null +++ b/examples/backtrace_test/faulter.c @@ -0,0 +1,12 @@ +#include +#include +#include + +void init() { + microkit_dbg_puts("FAULTER | Faulter initialised!\n"); + // Cause a fault immediately + volatile int* happy = (void*)UINTPTR_MAX; + volatile int notHappy = *happy; +} +void notified(microkit_channel ch) {} +microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) {} diff --git a/examples/backtrace_test/lwip_include/arch/cc.h b/examples/backtrace_test/lwip_include/arch/cc.h new file mode 100644 index 000000000..ef493c8f5 --- /dev/null +++ b/examples/backtrace_test/lwip_include/arch/cc.h @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + */ +#pragma once + +#include +#include +#include + +typedef uint8_t u8_t; +typedef uint16_t u16_t; +typedef uint32_t u32_t; +typedef uint64_t u64_t; + +typedef int8_t s8_t; +typedef int16_t s16_t; +typedef int32_t s32_t; +typedef int64_t s64_t; + +typedef uintptr_t mem_ptr_t; + +#define U16_F "u" +#define S16_F "d" +#define X16_F "x" +#define U32_F "u" +#define S32_F "d" +#define X32_F "x" +#define SZT_F "lu" + +// BYTE_ORDER might be defined by the architecture +#ifndef BYTE_ORDER +#if defined(__BYTE_ORDER__) +#define BYTE_ORDER __BYTE_ORDER__ +#elif defined(__BIG_ENDIAN) +#define BYTE_ORDER BIG_ENDIAN +#elif defined(__LITTLE_ENDIAN) +#define BYTE_ORDER LITTLE_ENDIAN +#else +#error Unable to detemine system endianess +#endif +#endif + +#define LWIP_CHKSUM_ALGORITHM 3 + +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END + +#define LWIP_PLATFORM_BYTESWAP 1 +#define LWIP_PLATFORM_HTONS(x) ( (((u16_t)(x))>>8) | (((x)&0xFF)<<8) ) +#define LWIP_PLATFORM_HTONL(x) ( (((u32_t)(x))>>24) | (((x)&0xFF0000)>>8) \ + | (((x)&0xFF00)<<8) | (((x)&0xFF)<<24) ) + +#define LWIP_RAND rand + +/* Plaform specific diagnostic output */ +#define LWIP_PLATFORM_DIAG(x) \ + do { \ + sddf_dprintf x ; \ + } while(0) + +#define LWIP_PLATFORM_ASSERT(x) \ + do { \ + if (!x) { \ + sddf_dprintf("assertion violated: %s : %s:%d:%s\n", \ + #x, __FILE__, __LINE__, __FUNCTION__); \ + while(1); \ + } \ + } while(0) diff --git a/examples/backtrace_test/lwip_include/lwipopts.h b/examples/backtrace_test/lwip_include/lwipopts.h new file mode 100644 index 000000000..3df69029a --- /dev/null +++ b/examples/backtrace_test/lwip_include/lwipopts.h @@ -0,0 +1,208 @@ +/* + * Copyright 2022, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +#if defined(CONFIG_PLAT_QEMU_ARM_VIRT) || defined(CONFIG_PLAT_QEMU_RISCV_VIRT) +// We don't need to do any address conflict detection on QEMU +// as it creates it's own isolated network. +// +// Disabling this option drastically decreases the time to +// complete DHCP on QEMU. +#define LWIP_DHCP_DOES_ACD_CHECK 0 +#endif + +/** + * Use lwIP without OS-awareness (no thread, semaphores, mutexes or mboxes). + */ +#define NO_SYS 1 + +/** + * Enable Netconn API (require to use api_lib.c). + */ +#define LWIP_NETCONN 0 + +/** + * Enable Socket API (require to use sockets.c). + */ +#define LWIP_SOCKET 0 + +/** + * Enable IGMP module inside the IP stack. + */ +#define LWIP_IGMP 1 + +/** + * Turn on DNS module. UDP must be available for DNS transport. + */ +#define LWIP_DNS 1 + +/** + * Enable DHCP module. + */ +#define LWIP_DHCP 1 + +/** + * Should be set to the alignment of the CPU. + */ +#define MEM_ALIGNMENT 4 + +/** + * The size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#define MEM_SIZE 0x30000 + +/** + * Enable code to support static ARP table entries (using + * etharp_add_static_entry/etharp_remove_static_entry). + */ +#define ETHARP_SUPPORT_STATIC_ENTRIES 1 + +/** + * Enable inter-task protection (and task-vs-interrupt protection) + * for certain critical regions during buffer allocation, deallocation + * and memory allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT 0 + +/** + * Support a callback function whenever an interface changes its + * up/down status (i.e., due to DHCP IP acquisition). + */ +#define LWIP_NETIF_STATUS_CALLBACK 1 + +/** + * Set options to 1 to enable checking of checksums in software for incoming + * packets. We leave the checksum checking on RX to hardware. + */ +#define CHECKSUM_CHECK_IP 0 +#define CHECKSUM_CHECK_UDP 0 +#define CHECKSUM_CHECK_TCP 0 +#define CHECKSUM_CHECK_ICMP 0 +#define CHECKSUM_CHECK_ICMP6 0 + +/** + * Set options to 1 to generate checksums in software for outgoing packets. + */ +#ifdef NETWORK_HW_HAS_CHECKSUM + +/* Leave the checksum checking on tx to hw */ +#define CHECKSUM_GEN_IP 0 +#define CHECKSUM_GEN_UDP 0 +#define CHECKSUM_GEN_TCP 0 +#define CHECKSUM_GEN_ICMP 0 +#define CHECKSUM_GEN_ICMP6 0 + +#else + +#define CHECKSUM_GEN_IP 1 +#define CHECKSUM_GEN_UDP 1 +#define CHECKSUM_GEN_TCP 1 +#define CHECKSUM_GEN_ICMP 1 +#define CHECKSUM_GEN_ICMP6 1 + +#endif + +/** + * TCP Maximum segment size. For the receive side, this MSS is advertised + * to the remote side when opening a connection. For the transmit size, this + * MSS sets an upper limit on the MSS advertised by the remote host. + */ +#define TCP_MSS 1460 + +/** + * The size of a TCP window - Maximum data we can receive at once. This + * must be at least (2 * TCP_MSS) for things to work well. + */ +#define TCP_WND (1000 * TCP_MSS) + +/** + * TCP sender buffer space (bytes). To achieve good performance, this + * should be at least 2 * TCP_MSS. + */ +#define TCP_SND_BUF TCP_WND + +/** + * TCP writable space (bytes). This must be less than TCP_SND_BUF. It is + * the amount of space which must be available in the TCP snd_buf for + * select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#define TCP_SNDLOWAT TCP_MSS + +/** + * TCP will support sending selective acknowledgements (SACKs). + */ +#define LWIP_TCP_SACK_OUT 1 + +/** + * Set LWIP_WND_SCALE to 1 to enable window scaling. + */ +#define LWIP_WND_SCALE 1 + +/** + * Set TCP_RCV_SCALE to the desired scaling factor (shift count in the + * range of [0..14]). + * When LWIP_WND_SCALE is enabled but TCP_RCV_SCALE is 0, we can use a large + * send window while having a small receive window only. + */ +#define TCP_RCV_SCALE 12 + +/** + * Support the TCP timestamp option. + */ +#define LWIP_TCP_TIMESTAMPS 1 + +/** + * The number of buffers in the pbuf pool. + */ +#define PBUF_POOL_SIZE 1000 + +/* + * Streams can hang around in FIN_WAIT state for a + * while after closing. Increase the max number of concurrent streams to allow + * for a few of these while the next benchmark runs. + */ +#define MEMP_NUM_TCP_PCB 100 + +/** + * The number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#define MEMP_NUM_PBUF (10 * TCP_SND_QUEUELEN) + +/** + * The number of simultaneously queued TCP segments. + */ +#define MEMP_NUM_TCP_SEG (10 * TCP_SND_QUEUELEN) + +/** + * The number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_PCB_LISTEN MEMP_NUM_TCP_PCB + +/** + * Enable statistics collection in lwip_stats. Set this to 0 for performance. + */ +#define LWIP_STATS 0 + +/* Debugging options */ +#define LWIP_DEBUG +/* Change this to LWIP_DBG_LEVEL_ALL to see a trace */ +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_SERIOUS + +#define DHCP_DEBUG LWIP_DBG_ON +#define UDP_DEBUG LWIP_DBG_ON +#define ETHARP_DEBUG LWIP_DBG_ON +#define PBUF_DEBUG LWIP_DBG_ON +#define IP_DEBUG LWIP_DBG_ON +#define TCPIP_DEBUG LWIP_DBG_ON +#define DHCP_DEBUG LWIP_DBG_ON +#define UDP_DEBUG LWIP_DBG_ON diff --git a/examples/backtrace_test/meta.py b/examples/backtrace_test/meta.py new file mode 100644 index 000000000..b19656d13 --- /dev/null +++ b/examples/backtrace_test/meta.py @@ -0,0 +1,48 @@ +# Copyright 2026, UNSW +# SPDX-License-Identifier: BSD-2-Clause +import argparse +from dataclasses import dataclass +from typing import List +from sdfgen import SystemDescription, Sddf, DeviceTree, LionsOs +from importlib.metadata import version +from board import BOARDS + +assert version("sdfgen").split(".")[1] == "28", "Unexpected sdfgen version" + +ProtectionDomain = SystemDescription.ProtectionDomain +MemoryRegion = SystemDescription.MemoryRegion +Map = SystemDescription.Map +Channel = SystemDescription.Channel + + +def generate(sdf_path: str, output_dir: str): + faulter_pd = ProtectionDomain("faulter", "faulter.elf", priority=1) + + pds = [ + faulter_pd + ] + backtracer = ProtectionDomain("backtracer", "backtracer.elf", priority=128, stack_size=0x100000) + + for pd in pds: + backtracer.add_child_pd(pd) + sdf.add_pd(backtracer) + + with open(f"{output_dir}/{sdf_path}", "w+") as f: + f.write(sdf.render()) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--sddf", required=True) + parser.add_argument("--board", required=True, choices=[b.name for b in BOARDS]) + parser.add_argument("--output", required=True) + parser.add_argument("--sdf", required=True) + + args = parser.parse_args() + + board = next(filter(lambda b: b.name == args.board, BOARDS)) + + sdf = SystemDescription(board.arch, board.paddr_top) + sddf = Sddf(args.sddf) + + generate(args.sdf, args.output) diff --git a/examples/backtrace_test/posix_test.mk b/examples/backtrace_test/posix_test.mk new file mode 100644 index 000000000..b15d44668 --- /dev/null +++ b/examples/backtrace_test/posix_test.mk @@ -0,0 +1,122 @@ +# +# Copyright 2026, UNSW +# +# SPDX-License-Identifier: BSD-2-Clause +# + +TOOLCHAIN ?= clang +SUPPORTED_BOARDS := \ + qemu_virt_aarch64 \ + maaxboard + +IMAGES := \ + faulter.elf \ + backtracer.elf + +TOOLCHAIN ?= clang +MICROKIT_TOOL ?= $(MICROKIT_SDK)/bin/microkit +BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG) +SDDF := $(LIONSOS)/dep/sddf +LWIP := $(SDDF)/network/ipstacks/lwip/src +LIBMICROKITCO_PATH := $(LIONSOS)/dep/libmicrokitco +LIBUNWIND := $(LIONSOS)/dep/llvm-project/libunwind +SYSTEM_FILE := posix_test.system +IMAGE_FILE := posix_test.img +REPORT_FILE := report.txt + +all: ${IMAGE_FILE} + +include ${SDDF}/tools/make/board/common.mk + +METAPROGRAM := $(POSIX_TEST_DIR)/meta.py + +FAT := $(LIONSOS)/components/fs/fat + +CFLAGS += \ + -Wno-bitwise-op-parentheses \ + -Wno-shift-op-parentheses \ + -Wno-unused-function \ + -Wno-tautological-constant-out-of-range-compare \ + -I$(LIONSOS)/include \ + -I$(SDDF)/include \ + -I$(SDDF)/include/microkit \ + -I$(LIBMICROKITCO_PATH) \ + -I$(LWIP)/include \ + -I$(LIBUNWIND)/include \ + -DMAX_FDS=8 \ + -funwind-tables + +include $(LIONSOS)/lib/libc/libc.mk + +LDFLAGS := --eh-frame-hdr -L$(BOARD_DIR)/lib -L$(LIONS_LIBC)/lib -L$(POSIX_TEST_DIR)/build +LIBS := -lmicrokit -Tmicrokit.ld libsddf_util_debug.a -lc -T$(POSIX_TEST_DIR)/unwind.ld -lunwind + +BLK_DRIVER := $(SDDF)/drivers/blk/${BLK_DRIV_DIR} +BLK_COMPONENTS := $(SDDF)/blk/components + +SDDF_LIBC_INCLUDE := $(LIONS_LIBC)/include +include ${SDDF}/util/util.mk +include ${SDDF}/drivers/timer/${TIMER_DRIV_DIR}/timer_driver.mk +include ${SDDF}/drivers/serial/${UART_DRIV_DIR}/serial_driver.mk +include ${SDDF}/drivers/network/${NET_DRIV_DIR}/eth_driver.mk +include ${SDDF}/serial/components/serial_components.mk +include ${SDDF}/network/components/network_components.mk + +LIB_SDDF_LWIP_CFLAGS := -I${POSIX_TEST_DIR}/lwip_include +include ${SDDF}/network/lib_sddf_lwip/lib_sddf_lwip.mk + +include ${SDDF}/libco/libco.mk +include ${BLK_DRIVER}/blk_driver.mk +include ${BLK_COMPONENTS}/blk_components.mk + +FAT_LIBC_LIB := $(LIONS_LIBC)/lib/libc.a +FAT_LIBC_INCLUDE := $(LIONS_LIBC)/include +include $(LIONSOS)/components/fs/fat/fat.mk + +LIBMICROKITCO_CFLAGS_posix_test := -I$(POSIX_TEST_DIR) +LIBMICROKITCO_LIBC_INCLUDE := $(LIONS_LIBC)/include +include $(LIBMICROKITCO_PATH)/libmicrokitco.mk + +${IMAGES}: $(LIONS_LIBC)/lib/libc.a libsddf_util_debug.a + +# for libmicrokitco_opts.h and lwipopts.h +backtracer.o: $(POSIX_TEST_DIR)/backtracer.c | $(LIONS_LIBC)/include + ${CC} ${CFLAGS} -c -o $@ $< + +backtracer.elf: backtracer.o libunwind.a + ${LD} ${LDFLAGS} -o $@ $^ ${LIBS} + +faulter.o: $(POSIX_TEST_DIR)/faulter.c | $(LIONS_LIBC)/include + ${CC} ${CFLAGS} -c -o $@ $< + +faulter.elf: faulter.o libunwind.a + ${LD} ${LDFLAGS} -o $@ $^ ${LIBS} + +FORCE: + +$(SYSTEM_FILE): $(METAPROGRAM) $(IMAGES) $(DTB) + PYTHONPATH=${SDDF}/tools/meta:$$PYTHONPATH $(PYTHON) $(METAPROGRAM) --sddf $(SDDF) --board $(MICROKIT_BOARD) --output . --sdf $(SYSTEM_FILE) + # Add the unwind table to the memory region specified. + +$(IMAGE_FILE) $(REPORT_FILE): $(IMAGES) $(SYSTEM_FILE) + $(MICROKIT_TOOL) $(SYSTEM_FILE) --search-path $(BUILD_DIR) --board $(MICROKIT_BOARD) --config $(MICROKIT_CONFIG) -o $(IMAGE_FILE) -r $(REPORT_FILE) + +qemu_disk: + $(SDDF)/tools/mkvirtdisk $@ 1 512 16777216 GPT + +qemu: ${IMAGE_FILE} qemu_disk + $(QEMU) -machine virt,virtualization=on \ + -cpu cortex-a53 \ + -serial mon:stdio \ + -device loader,file=$(IMAGE_FILE),addr=0x70000000,cpu-num=0 \ + -m size=2G \ + -nographic \ + -global virtio-mmio.force-legacy=false \ + -d guest_errors \ + -drive file=qemu_disk,if=none,format=raw,id=hd \ + -device virtio-blk-device,drive=hd,bus=virtio-mmio-bus.1 \ + -device virtio-net-device,netdev=netdev0,bus=virtio-mmio-bus.0 \ + -netdev user,id=netdev0,hostfwd=tcp::5560-10.0.2.15:5560,hostfwd=tcp::5561-10.0.2.15:5561 \ + +libunwind.a: + echo "Please paste libunwind.a in here!" diff --git a/examples/backtrace_test/unwind.ld b/examples/backtrace_test/unwind.ld new file mode 100644 index 000000000..7a25425a9 --- /dev/null +++ b/examples/backtrace_test/unwind.ld @@ -0,0 +1,40 @@ +/* + * Copyright 2019, Data61 + * Commonwealth Scientific and Industrial Research Organisation (CSIRO) + * ABN 41 687 119 230. + * + * This software may be distributed and modified according to the terms of + * the GNU General Public License version 2. Note that NO WARRANTY is provided. + * See "LICENSE_GPLv2.txt" for details. + * + * @TAG(DATA61_GPL) + */ +SECTIONS +{ + /* stolen from config.h in libunwind llvm */ + .eh_frame : + { + __eh_frame_start = .; + KEEP(*(.eh_frame)) + __eh_frame_end = .; + } + .eh_frame_hdr : + { + KEEP(*(.eh_frame_hdr)) + } + __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; + __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; +} + +/* OLD + .eh_frame : + { + PROVIDE (__eh_frame_start = .); + KEEP (*(.eh_frame)) *(.eh_frame.*) + PROVIDE (__eh_frame_end = .); + PROVIDE (__eh_frame_hdr_start = .); + KEEP (*(.eh_frame_hdr)) *(.eh_frame_hdr.*) + PROVIDE (__eh_frame_hdr_end = .); + } +*/ +INSERT AFTER .text; From 295d6d028401fcc4b7c0aa0f7cf4310076e71bb8 Mon Sep 17 00:00:00 2001 From: 0aids Date: Mon, 8 Jun 2026 21:02:11 +1000 Subject: [PATCH 02/27] backtracing works Signed-off-by: 0aids --- examples/backtrace_test/backtracer.c | 22 ++++++++++++++++++---- examples/backtrace_test/meta.py | 4 ++-- examples/backtrace_test/posix_test.mk | 4 ++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/examples/backtrace_test/backtracer.c b/examples/backtrace_test/backtracer.c index 1940c9eec..f95f71e02 100644 --- a/examples/backtrace_test/backtracer.c +++ b/examples/backtrace_test/backtracer.c @@ -1,10 +1,13 @@ #include -#include +#include + #define UNW_LOCAL_ONLY #include void show_backtrace (void) { - unw_cursor_t cursor; unw_context_t uc; + microkit_dbg_puts("BACKTRACER | BEGIN_SHOW_BACKTRACE\n"); + unw_cursor_t cursor; + unw_context_t uc; unw_word_t ip, sp; unw_getcontext(&uc); @@ -12,19 +15,30 @@ void show_backtrace (void) { while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); - printf ("ip = %lx, sp = %lx\n", (long) ip, (long) sp); + sddf_printf("ip = %lx, sp = %lx\n", (long) ip, (long) sp); } + microkit_dbg_puts("BACKTRACER | END_SHOW_BACKTRACE\n"); +} + +void increase_stackdepth(int size) +{ + if (size > 0) + increase_stackdepth(size - 1); + else show_backtrace(); } void init() { microkit_dbg_puts("BACKTRACER | Backtracer initialised!\n"); - show_backtrace(); + sddf_printf("BACKTRACER | Printf test! %d\n", 10); + increase_stackdepth(5); } + seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) { microkit_dbg_puts("BACKTRACER | Fault received!\n"); return 0; } + void notified(microkit_channel ch) {} microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) {} diff --git a/examples/backtrace_test/meta.py b/examples/backtrace_test/meta.py index b19656d13..cbbbf3632 100644 --- a/examples/backtrace_test/meta.py +++ b/examples/backtrace_test/meta.py @@ -23,8 +23,8 @@ def generate(sdf_path: str, output_dir: str): ] backtracer = ProtectionDomain("backtracer", "backtracer.elf", priority=128, stack_size=0x100000) - for pd in pds: - backtracer.add_child_pd(pd) + # for pd in pds: + # backtracer.add_child_pd(pd) sdf.add_pd(backtracer) with open(f"{output_dir}/{sdf_path}", "w+") as f: diff --git a/examples/backtrace_test/posix_test.mk b/examples/backtrace_test/posix_test.mk index b15d44668..7486d80a4 100644 --- a/examples/backtrace_test/posix_test.mk +++ b/examples/backtrace_test/posix_test.mk @@ -44,7 +44,7 @@ CFLAGS += \ -I$(LWIP)/include \ -I$(LIBUNWIND)/include \ -DMAX_FDS=8 \ - -funwind-tables + -funwind-tables -O0 include $(LIONSOS)/lib/libc/libc.mk @@ -119,4 +119,4 @@ qemu: ${IMAGE_FILE} qemu_disk -netdev user,id=netdev0,hostfwd=tcp::5560-10.0.2.15:5560,hostfwd=tcp::5561-10.0.2.15:5561 \ libunwind.a: - echo "Please paste libunwind.a in here!" + $(error "Please paste libunwind.a in here!") From 49178b0de487d7299f557579289d35d20e5391a1 Mon Sep 17 00:00:00 2001 From: 0aids Date: Tue, 9 Jun 2026 16:40:05 +1000 Subject: [PATCH 03/27] fix build for libunwind and child backtracing working Signed-off-by: 0aids --- examples/backtrace_test/backtracer.c | 91 ++++++++++++++++-------- examples/backtrace_test/default.nix | 76 ++++++++++++++++++++ examples/backtrace_test/faulter.c | 25 ++++++- examples/backtrace_test/meta.py | 6 +- examples/backtrace_test/posix_test.mk | 41 +++++++++-- examples/backtrace_test/unwind_helpers.c | 27 +++++++ 6 files changed, 225 insertions(+), 41 deletions(-) create mode 100644 examples/backtrace_test/default.nix create mode 100644 examples/backtrace_test/unwind_helpers.c diff --git a/examples/backtrace_test/backtracer.c b/examples/backtrace_test/backtracer.c index f95f71e02..1fac672b6 100644 --- a/examples/backtrace_test/backtracer.c +++ b/examples/backtrace_test/backtracer.c @@ -1,43 +1,78 @@ #include #include +#define LOG(...) sddf_printf("BACKTRACER | " __VA_ARGS__) +#define FAULTS \ + X(seL4_Fault_CapFault) \ + X(seL4_Fault_VMFault) \ + X(seL4_Fault_UnknownSyscall) \ + X(seL4_Fault_UserException) \ + X(seL4_Fault_NullFault) \ + X(seL4_Fault_VPPIEvent) \ + X(seL4_Fault_VCPUFault) + // X(seL4_Fault_TimeoutFault) + // X(seL4_Fault_VGICMaintenence) + // X(seL4_Fault_DebugException) -#define UNW_LOCAL_ONLY -#include - -void show_backtrace (void) { - microkit_dbg_puts("BACKTRACER | BEGIN_SHOW_BACKTRACE\n"); - unw_cursor_t cursor; - unw_context_t uc; - unw_word_t ip, sp; - - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); - while (unw_step(&cursor) > 0) { - unw_get_reg(&cursor, UNW_REG_IP, &ip); - unw_get_reg(&cursor, UNW_REG_SP, &sp); - sddf_printf("ip = %lx, sp = %lx\n", (long) ip, (long) sp); - } - microkit_dbg_puts("BACKTRACER | END_SHOW_BACKTRACE\n"); -} +#define BASE_PD_TCB_CAP 202 +#define TEST_FUNC_ADDR 0x20001c -void increase_stackdepth(int size) +static void aarch64_print_vm_fault() { - if (size > 0) - increase_stackdepth(size - 1); - else show_backtrace(); + seL4_Word ip = seL4_GetMR(seL4_VMFault_IP); + seL4_Word fault_addr = seL4_GetMR(seL4_VMFault_Addr); + seL4_Word is_instruction = seL4_GetMR(seL4_VMFault_PrefetchFault); + seL4_Word fsr = seL4_GetMR(seL4_VMFault_FSR); + sddf_printf("MON|ERROR: VMFault: ip=%0llx fault_addr=%0llx fsr=%0llx, %s\n", ip, fault_addr, fsr, is_instruction ? "(instruction fault)" : "(data fault)"); } + void init() { - microkit_dbg_puts("BACKTRACER | Backtracer initialised!\n"); - sddf_printf("BACKTRACER | Printf test! %d\n", 10); - increase_stackdepth(5); + LOG("Backtracer initialised!\n"); + LOG("Printf test! %d\n", 100); +} + +void printFaultType(seL4_Word label) +{ + LOG("Fault type: "); + switch (label) + { + #define X(value) case value: sddf_printf(#value "\n"); break; + FAULTS + #undef X + } + + if (label == seL4_Fault_VMFault) + { + aarch64_print_vm_fault(); + } +} + +// modifies ctxt +void aarch64_callConvention_prologue(seL4_UserContext* ctxt, uintptr_t funcAddr) +{ + // Store x29, x30 to address sp-16, sp-8 respectively + // stp x29, x30, [sp, #-16]! + // mov x29, sp + LOG("Pre jump PC: %p\n", (void*) ctxt->pc); + // Set the link register to old PC + ctxt->x30 = ctxt->pc; + // Set the PC to the next function + ctxt->pc = funcAddr; + LOG("Post jump PC: %p\n", (void*) ctxt->pc); } seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) { - - microkit_dbg_puts("BACKTRACER | Fault received!\n"); - return 0; + LOG("BEGIN Fault received!\n"); + uint64_t label = microkit_msginfo_get_label(msginfo); + uint64_t count = microkit_msginfo_get_count(msginfo); + printFaultType(label); + seL4_UserContext ctxt = {0}; + LOG("read registers return: %d\n", seL4_TCB_ReadRegisters(BASE_PD_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt)); + aarch64_callConvention_prologue(&ctxt, TEST_FUNC_ADDR); + LOG("write registers return: %d\n", seL4_TCB_WriteRegisters(BASE_PD_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt)); + LOG("END Fault received!\n"); + return seL4_True; } void notified(microkit_channel ch) {} diff --git a/examples/backtrace_test/default.nix b/examples/backtrace_test/default.nix new file mode 100644 index 000000000..6e9d76493 --- /dev/null +++ b/examples/backtrace_test/default.nix @@ -0,0 +1,76 @@ +let + nixpkgs = builtins.fetchTarball { + name = "source"; + url = "https://github.com/nixos/nixpkgs/archive/da044451c6a70518db5b730fe277b70f494188f1.tar.gz"; + sha256 = "sha256:11z08fa0s7r9hryllhjj7kyn4z6bsixlqz7iwgsmf1k4p3hcl692"; + }; + +in + +{ pkgs ? (import nixpkgs { + overlays = [ + (self: super: { + python3 = super.python3.override { + packageOverrides = _: pySuper: { + pyfdt = pySuper.buildPythonPackage rec { + name = "pyfdt"; + src = pySuper.fetchPypi { + pname = name; + version = "0.3"; + sha256 = "sha256-YWAcIAX/OUolpshMbaIIi7+IgygDhADSfk7rGwS59PA="; + }; + }; + }; + }; + }) + ]; + }) +}: + +pkgs.mkShellNoCC { + name = "time-protection-sel4"; + + nativeBuildInputs = with pkgs; [ + qemu + cacert + cmake + cpio + dtc + gdb + ubootTools + # (pkgsCross.riscv64-embedded.stdenv.cc.cc.override { enableMultilib = true; }) + # pkgsCross.riscv64-embedded.stdenv.cc.cc + # pkgsCross.riscv64-embedded.stdenv.cc.bintools.bintools + pkgsCross.aarch64-embedded.stdenv.cc.cc + pkgsCross.aarch64-embedded.stdenv.cc.bintools.bintools + # pkgsCross.arm-embedded.stdenv.cc.cc + # pkgsCross.arm-embedded.stdenv.cc.bintools.bintools + libxml2 + ninja + # camkes. not this doesn't like nix so needs gmp installed + pkgs.stack + # cheshire + pkgs.gptfdisk + pkgs.openfpgaloader + + (pkgs.stdenv.mkDerivation rec { + pname = "bender"; + version = "v0.29.0"; + + src = pkgs.fetchzip { + url = "https://github.com/pulp-platform/bender/releases/download/v0.29.0/bender-0.29.0-x86_64-linux-gnu.tar.gz"; + hash = "sha256-ssVqe1d8a3XtFDMAZJHomY34IAu/tGFuvLxdaTh/R2M="; + }; + + installPhase = '' + mkdir -p $out/bin + cp $src/bender $out/bin/ + ''; + }) + + # openjdk # leakiest + ]; + + env.CMAKE_EXPORT_COMPILE_COMMANDS = "1"; +} + diff --git a/examples/backtrace_test/faulter.c b/examples/backtrace_test/faulter.c index 233e0c534..2050ea545 100644 --- a/examples/backtrace_test/faulter.c +++ b/examples/backtrace_test/faulter.c @@ -1,12 +1,31 @@ #include #include #include +#include +#define LOG(...) sddf_printf("FAULTER | " __VA_ARGS__) +extern void show_backtrace(); +void anotherFunc () { + volatile int a = 1; +} + +void testFunc() { + LOG("Test\n"); + anotherFunc(); + show_backtrace(); + while (1); +} void init() { - microkit_dbg_puts("FAULTER | Faulter initialised!\n"); + LOG("Faulter initialised!\n"); // Cause a fault immediately volatile int* happy = (void*)UINTPTR_MAX; volatile int notHappy = *happy; + LOG("After dereference\n"); +} +void notified(microkit_channel ch) { + LOG("Notified!\n"); +} +microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) { + + LOG("Protected!\n"); } -void notified(microkit_channel ch) {} -microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) {} diff --git a/examples/backtrace_test/meta.py b/examples/backtrace_test/meta.py index cbbbf3632..db10d44a8 100644 --- a/examples/backtrace_test/meta.py +++ b/examples/backtrace_test/meta.py @@ -16,15 +16,15 @@ def generate(sdf_path: str, output_dir: str): - faulter_pd = ProtectionDomain("faulter", "faulter.elf", priority=1) + faulter_pd = ProtectionDomain("faulter", "faulter.elf", priority=1, stack_size=0x100000) pds = [ faulter_pd ] backtracer = ProtectionDomain("backtracer", "backtracer.elf", priority=128, stack_size=0x100000) - # for pd in pds: - # backtracer.add_child_pd(pd) + for pd in pds: + backtracer.add_child_pd(pd) sdf.add_pd(backtracer) with open(f"{output_dir}/{sdf_path}", "w+") as f: diff --git a/examples/backtrace_test/posix_test.mk b/examples/backtrace_test/posix_test.mk index 7486d80a4..fed9d3175 100644 --- a/examples/backtrace_test/posix_test.mk +++ b/examples/backtrace_test/posix_test.mk @@ -13,7 +13,7 @@ IMAGES := \ faulter.elf \ backtracer.elf -TOOLCHAIN ?= clang +TOOLCHAIN ?= $(CC) MICROKIT_TOOL ?= $(MICROKIT_SDK)/bin/microkit BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG) SDDF := $(LIONSOS)/dep/sddf @@ -49,7 +49,7 @@ CFLAGS += \ include $(LIONSOS)/lib/libc/libc.mk LDFLAGS := --eh-frame-hdr -L$(BOARD_DIR)/lib -L$(LIONS_LIBC)/lib -L$(POSIX_TEST_DIR)/build -LIBS := -lmicrokit -Tmicrokit.ld libsddf_util_debug.a -lc -T$(POSIX_TEST_DIR)/unwind.ld -lunwind +LIBS := --start-group -T$(POSIX_TEST_DIR)/unwind.ld -lmicrokit -Tmicrokit.ld libsddf_util_debug.a -lc -lunwind --end-group BLK_DRIVER := $(SDDF)/drivers/blk/${BLK_DRIV_DIR} BLK_COMPONENTS := $(SDDF)/blk/components @@ -79,17 +79,20 @@ include $(LIBMICROKITCO_PATH)/libmicrokitco.mk ${IMAGES}: $(LIONS_LIBC)/lib/libc.a libsddf_util_debug.a +unwind_helpers.o: $(POSIX_TEST_DIR)/unwind_helpers.c | $(LIONS_LIBC)/include + ${CC} ${CFLAGS} -c -o $@ $< + # for libmicrokitco_opts.h and lwipopts.h backtracer.o: $(POSIX_TEST_DIR)/backtracer.c | $(LIONS_LIBC)/include ${CC} ${CFLAGS} -c -o $@ $< -backtracer.elf: backtracer.o libunwind.a +backtracer.elf: backtracer.o libunwind.a unwind_helpers.o ${LD} ${LDFLAGS} -o $@ $^ ${LIBS} faulter.o: $(POSIX_TEST_DIR)/faulter.c | $(LIONS_LIBC)/include ${CC} ${CFLAGS} -c -o $@ $< -faulter.elf: faulter.o libunwind.a +faulter.elf: faulter.o libunwind.a unwind_helpers.o ${LD} ${LDFLAGS} -o $@ $^ ${LIBS} FORCE: @@ -117,6 +120,30 @@ qemu: ${IMAGE_FILE} qemu_disk -device virtio-blk-device,drive=hd,bus=virtio-mmio-bus.1 \ -device virtio-net-device,netdev=netdev0,bus=virtio-mmio-bus.0 \ -netdev user,id=netdev0,hostfwd=tcp::5560-10.0.2.15:5560,hostfwd=tcp::5561-10.0.2.15:5561 \ - -libunwind.a: - $(error "Please paste libunwind.a in here!") +# -S -s + +libunwind.a: | $(LIONS_LIBC)/include + cmake -B $(BUILD_DIR)/libunwind -S $(LIBUNWIND) \ + -DCMAKE_SYSTEM_NAME=Generic\ + -DCMAKE_C_COMPILER_TARGET=${TARGET}\ + -DCMAKE_CXX_COMPILER_TARGET=${TARGET}\ + -DCMAKE_ASM_COMPILER_TARGET=${TARGET}\ + -DLIBUNWIND_IS_BAREMETAL=ON\ + -DLIBUNWIND_ENABLE_SHARED=OFF\ + -DLIBUNWIND_ENABLE_THREADS=OFF\ + -DLIBUNWIND_USE_COMPILER_RT=ON\ + -DLIBUNWIND_ENABLE_PEDANTIC=OFF\ + -DLIBUNWIND_ENABLE_ASSERTIONS=OFF\ + -DCMAKE_BUILD_TYPE=Debug\ + -DLIBUNWIND_ENABLE_STATIC=ON\ + -DCMAKE_C_COMPILER=$(CC)\ + -DCMAKE_CXX_COMPILER=$(CXX)\ + -DCMAKE_ASM_COMPILER=$(CC)\ + -DCMAKE_C_FLAGS="-I$(LIONS_LIBC)/include"\ + -DCMAKE_CXX_FLAGS="-I$(LIONS_LIBC)/include -fno-exceptions"\ + -DCMAKE_C_COMPILER_WORKS=ON\ + -DCMAKE_CXX_COMPILER_WORKS=ON\ + -DCMAKE_ASM_COMPILER_WORKS=ON + + cmake --build $(BUILD_DIR)/libunwind + ln -sr $(BUILD_DIR)/libunwind/lib/libunwind.a $@ diff --git a/examples/backtrace_test/unwind_helpers.c b/examples/backtrace_test/unwind_helpers.c new file mode 100644 index 000000000..6c09ba6b7 --- /dev/null +++ b/examples/backtrace_test/unwind_helpers.c @@ -0,0 +1,27 @@ +#include +#include +#define UNW_LOCAL_ONLY +#include + +void show_backtrace (void) { + microkit_dbg_puts("SHOW_BACKTRACE | BEGIN_SHOW_BACKTRACE\n"); + unw_cursor_t cursor; + unw_context_t uc; + unw_word_t ip, sp; + + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + while (unw_step(&cursor) > 0) { + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + sddf_printf("ip = %lx, sp = %lx\n", (long) ip, (long) sp); + } + microkit_dbg_puts("SHOW_BACKTRACE | END_SHOW_BACKTRACE\n"); +} + +void increase_stackdepth(int size) +{ + if (size > 0) + increase_stackdepth(size - 1); + else show_backtrace(); +} From 5f893b0ae8c89d97638c2a26b7c01c29302183ac Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 10 Jun 2026 18:13:06 +1000 Subject: [PATCH 04/27] wip meta.py functions and addr inserting Signed-off-by: 0aids --- examples/backtrace_test/backtracer.c | 53 +++++++++++++----------- examples/backtrace_test/faulter.c | 11 ----- examples/backtrace_test/meta.py | 27 ++++++++---- examples/backtrace_test/posix_test.mk | 12 +++--- examples/backtrace_test/unwind_helpers.c | 8 +--- 5 files changed, 55 insertions(+), 56 deletions(-) diff --git a/examples/backtrace_test/backtracer.c b/examples/backtrace_test/backtracer.c index 1fac672b6..fba09da3d 100644 --- a/examples/backtrace_test/backtracer.c +++ b/examples/backtrace_test/backtracer.c @@ -13,22 +13,14 @@ // X(seL4_Fault_VGICMaintenence) // X(seL4_Fault_DebugException) -#define BASE_PD_TCB_CAP 202 -#define TEST_FUNC_ADDR 0x20001c - -static void aarch64_print_vm_fault() -{ - seL4_Word ip = seL4_GetMR(seL4_VMFault_IP); - seL4_Word fault_addr = seL4_GetMR(seL4_VMFault_Addr); - seL4_Word is_instruction = seL4_GetMR(seL4_VMFault_PrefetchFault); - seL4_Word fsr = seL4_GetMR(seL4_VMFault_FSR); - sddf_printf("MON|ERROR: VMFault: ip=%0llx fault_addr=%0llx fsr=%0llx, %s\n", ip, fault_addr, fsr, is_instruction ? "(instruction fault)" : "(data fault)"); -} +#define BASE_PD_TCB_CAP 202 +#ifndef SHOW_BACKTRACE_FUNC_ADDR +#error "Please define SHOW_BACKTRACE_FUNC_ADDR to be the address of the show_backtrace function" +#endif void init() { - LOG("Backtracer initialised!\n"); - LOG("Printf test! %d\n", 100); + LOG("Initialised!"); } void printFaultType(seL4_Word label) @@ -40,15 +32,11 @@ void printFaultType(seL4_Word label) FAULTS #undef X } - - if (label == seL4_Fault_VMFault) - { - aarch64_print_vm_fault(); - } } +#if defined(__aarch64__) // modifies ctxt -void aarch64_callConvention_prologue(seL4_UserContext* ctxt, uintptr_t funcAddr) +void callConvention_prologue(seL4_UserContext* ctxt, uintptr_t funcAddr) { // Store x29, x30 to address sp-16, sp-8 respectively // stp x29, x30, [sp, #-16]! @@ -60,18 +48,33 @@ void aarch64_callConvention_prologue(seL4_UserContext* ctxt, uintptr_t funcAddr) ctxt->pc = funcAddr; LOG("Post jump PC: %p\n", (void*) ctxt->pc); } +#elif defined(__riscv) +#error "Unimplemented backtracer for riscv" +#elif defined(__x86_64__) +#error "Unimplemented backtracer for x86_64" +#else +#error "Unsupported architecture for backtracing" +#endif seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) { - LOG("BEGIN Fault received!\n"); + LOG("Fault received! Setting up backtrace...\n"); uint64_t label = microkit_msginfo_get_label(msginfo); - uint64_t count = microkit_msginfo_get_count(msginfo); printFaultType(label); seL4_UserContext ctxt = {0}; - LOG("read registers return: %d\n", seL4_TCB_ReadRegisters(BASE_PD_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt)); - aarch64_callConvention_prologue(&ctxt, TEST_FUNC_ADDR); - LOG("write registers return: %d\n", seL4_TCB_WriteRegisters(BASE_PD_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt)); - LOG("END Fault received!\n"); + int readRegResult = seL4_TCB_ReadRegisters(BASE_PD_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); + if (readRegResult != 0) + { + LOG("Failed to read registers for setting up backtrace jump! Got %d, expected %d\n", readRegResult, 0); + return seL4_False; + } + callConvention_prologue(&ctxt, SHOW_BACKTRACE_FUNC_ADDR); + int writeRegResult = seL4_TCB_WriteRegisters(BASE_PD_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); + if (writeRegResult != 0) + { + LOG("Failed to write registers for setting up backtrace jump! Got %d, expected %d\n", writeRegResult, 0); + return seL4_False; + } return seL4_True; } diff --git a/examples/backtrace_test/faulter.c b/examples/backtrace_test/faulter.c index 2050ea545..63bd1d7e2 100644 --- a/examples/backtrace_test/faulter.c +++ b/examples/backtrace_test/faulter.c @@ -3,17 +3,6 @@ #include #include #define LOG(...) sddf_printf("FAULTER | " __VA_ARGS__) -extern void show_backtrace(); -void anotherFunc () { - volatile int a = 1; -} - -void testFunc() { - LOG("Test\n"); - anotherFunc(); - show_backtrace(); - while (1); -} void init() { LOG("Faulter initialised!\n"); diff --git a/examples/backtrace_test/meta.py b/examples/backtrace_test/meta.py index db10d44a8..cc05caad5 100644 --- a/examples/backtrace_test/meta.py +++ b/examples/backtrace_test/meta.py @@ -10,21 +10,32 @@ assert version("sdfgen").split(".")[1] == "28", "Unexpected sdfgen version" ProtectionDomain = SystemDescription.ProtectionDomain +ProtectionDomain.PRIORITY_MAX = 254 + MemoryRegion = SystemDescription.MemoryRegion Map = SystemDescription.Map Channel = SystemDescription.Channel +def enableBacktracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr = 0xb00000): + """ + Wrap an array or single pd as children into a backtracer parent, + capable of catching faults and then forcing prints of the backtrace + Remember to compile each of the children with "backtrace.o" + """ + backtracer = ProtectionDomain("backtracer", "backtracer.elf", priority=ProtectionDomain.PRIORITY_MAX, stack_size=0x10000); + if isinstance(array_of_pds_or_single_pd, list): + for child_pd in array_of_pds_or_single_pd: + backtracer.add_child_pd(child_pd) + else: + backtracer.add_child_pd(array_of_pds_or_single_pd) + + # Create a memory region at the predefined address, as an array + # func_list_mr = MemoryRegion("backtracer_ + return backtracer def generate(sdf_path: str, output_dir: str): faulter_pd = ProtectionDomain("faulter", "faulter.elf", priority=1, stack_size=0x100000) - - pds = [ - faulter_pd - ] - backtracer = ProtectionDomain("backtracer", "backtracer.elf", priority=128, stack_size=0x100000) - - for pd in pds: - backtracer.add_child_pd(pd) + backtracer = enableBacktracing(faulter_pd) sdf.add_pd(backtracer) with open(f"{output_dir}/{sdf_path}", "w+") as f: diff --git a/examples/backtrace_test/posix_test.mk b/examples/backtrace_test/posix_test.mk index fed9d3175..d09ffc52b 100644 --- a/examples/backtrace_test/posix_test.mk +++ b/examples/backtrace_test/posix_test.mk @@ -19,7 +19,8 @@ BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG) SDDF := $(LIONSOS)/dep/sddf LWIP := $(SDDF)/network/ipstacks/lwip/src LIBMICROKITCO_PATH := $(LIONSOS)/dep/libmicrokitco -LIBUNWIND := $(LIONSOS)/dep/llvm-project/libunwind +LLVM := $(LIONSOS)/dep/llvm-project/ +LIBUNWIND := $(LLVM)/libunwind SYSTEM_FILE := posix_test.system IMAGE_FILE := posix_test.img REPORT_FILE := report.txt @@ -82,9 +83,9 @@ ${IMAGES}: $(LIONS_LIBC)/lib/libc.a libsddf_util_debug.a unwind_helpers.o: $(POSIX_TEST_DIR)/unwind_helpers.c | $(LIONS_LIBC)/include ${CC} ${CFLAGS} -c -o $@ $< -# for libmicrokitco_opts.h and lwipopts.h -backtracer.o: $(POSIX_TEST_DIR)/backtracer.c | $(LIONS_LIBC)/include - ${CC} ${CFLAGS} -c -o $@ $< +# Seems a bit fragile... +backtracer.o: $(POSIX_TEST_DIR)/backtracer.c faulter.elf | $(LIONS_LIBC)/include + ${CC} ${CFLAGS} -c -o $@ $< -DSHOW_BACKTRACE_FUNC_ADDR='0x$(shell nm faulter.elf | grep "show_backtrace" | cut --delimiter=" " -f 1)' backtracer.elf: backtracer.o libunwind.a unwind_helpers.o ${LD} ${LDFLAGS} -o $@ $^ ${LIBS} @@ -123,7 +124,8 @@ qemu: ${IMAGE_FILE} qemu_disk # -S -s libunwind.a: | $(LIONS_LIBC)/include - cmake -B $(BUILD_DIR)/libunwind -S $(LIBUNWIND) \ + cmake -B $(BUILD_DIR)/libunwind -S $(LLVM)/runtimes \ + -DLLVM_ENABLE_RUNTIMES=libunwind\ -DCMAKE_SYSTEM_NAME=Generic\ -DCMAKE_C_COMPILER_TARGET=${TARGET}\ -DCMAKE_CXX_COMPILER_TARGET=${TARGET}\ diff --git a/examples/backtrace_test/unwind_helpers.c b/examples/backtrace_test/unwind_helpers.c index 6c09ba6b7..8cf1e3704 100644 --- a/examples/backtrace_test/unwind_helpers.c +++ b/examples/backtrace_test/unwind_helpers.c @@ -11,6 +11,7 @@ void show_backtrace (void) { unw_getcontext(&uc); unw_init_local(&cursor, &uc); + // TODO: print the backtrace depth, and possibly find the culprit function address? while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); @@ -18,10 +19,3 @@ void show_backtrace (void) { } microkit_dbg_puts("SHOW_BACKTRACE | END_SHOW_BACKTRACE\n"); } - -void increase_stackdepth(int size) -{ - if (size > 0) - increase_stackdepth(size - 1); - else show_backtrace(); -} From d9d5676dd0619032c0489efe8e23a9c414e7654e Mon Sep 17 00:00:00 2001 From: 0aids Date: Thu, 11 Jun 2026 12:31:57 +1000 Subject: [PATCH 05/27] wip meta.py for mapping functions of backtracing Signed-off-by: 0aids --- .gitmodules | 3 --- dep/libunwind | 1 - examples/backtrace_test/backtracer.c | 6 ++---- examples/backtrace_test/meta.py | 7 +++++-- flake.lock | 25 ++++++++++++------------- flake.nix | 2 +- 6 files changed, 20 insertions(+), 24 deletions(-) delete mode 160000 dep/libunwind diff --git a/.gitmodules b/.gitmodules index 154ebccaf..7ddfb0378 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,6 +25,3 @@ [submodule "dep/wasm-micro-runtime"] path = dep/wasm-micro-runtime url = https://github.com/au-ts/wasm-micro-runtime -[submodule "dep/libunwind"] - path = dep/libunwind - url = https://github.com/libunwind/libunwind.git diff --git a/dep/libunwind b/dep/libunwind deleted file mode 160000 index 473b1da68..000000000 --- a/dep/libunwind +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 473b1da68ee145e887f7a39150208f252e9a3a7a diff --git a/examples/backtrace_test/backtracer.c b/examples/backtrace_test/backtracer.c index fba09da3d..ea6e0e6e2 100644 --- a/examples/backtrace_test/backtracer.c +++ b/examples/backtrace_test/backtracer.c @@ -14,6 +14,8 @@ // X(seL4_Fault_DebugException) +void (*backtraceFunctions[])() = {NULL}; + #define BASE_PD_TCB_CAP 202 #ifndef SHOW_BACKTRACE_FUNC_ADDR #error "Please define SHOW_BACKTRACE_FUNC_ADDR to be the address of the show_backtrace function" @@ -35,12 +37,8 @@ void printFaultType(seL4_Word label) } #if defined(__aarch64__) -// modifies ctxt void callConvention_prologue(seL4_UserContext* ctxt, uintptr_t funcAddr) { - // Store x29, x30 to address sp-16, sp-8 respectively - // stp x29, x30, [sp, #-16]! - // mov x29, sp LOG("Pre jump PC: %p\n", (void*) ctxt->pc); // Set the link register to old PC ctxt->x30 = ctxt->pc; diff --git a/examples/backtrace_test/meta.py b/examples/backtrace_test/meta.py index cc05caad5..23bea6aae 100644 --- a/examples/backtrace_test/meta.py +++ b/examples/backtrace_test/meta.py @@ -7,7 +7,7 @@ from importlib.metadata import version from board import BOARDS -assert version("sdfgen").split(".")[1] == "28", "Unexpected sdfgen version" +# assert version("sdfgen").split(".")[1] == "28", "Unexpected sdfgen version" ProtectionDomain = SystemDescription.ProtectionDomain ProtectionDomain.PRIORITY_MAX = 254 @@ -30,7 +30,10 @@ def enableBacktracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr = backtracer.add_child_pd(array_of_pds_or_single_pd) # Create a memory region at the predefined address, as an array - # func_list_mr = MemoryRegion("backtracer_ + func_list_mr = MemoryRegion(sdf, "backtracerFunctions", prefill_path="test.txt") + sdf.add_mr(func_list_mr) + func_list_map = Map(func_list_mr, vaddr=0x20000, perms="r", setvar_vaddr="backtraceFunctions") + backtracer.add_map(func_list_map) return backtracer def generate(sdf_path: str, output_dir: str): diff --git a/flake.lock b/flake.lock index 77bb57fac..49540c996 100644 --- a/flake.lock +++ b/flake.lock @@ -132,18 +132,17 @@ "zig-overlay": "zig-overlay" }, "locked": { - "lastModified": 1764823094, - "narHash": "sha256-Eeef5J0y31NH/F5Z0fayJ+4mroYfb8JPadu3cw6cNhc=", - "owner": "au-ts", - "repo": "microkit_sdf_gen", - "rev": "13686a373b9189c7b1d778cd749d7d8bbd8a63f6", - "type": "github" + "lastModified": 1781144170, + "narHash": "sha256-KcJ9hHnpG5Ho6gCxmhoU5iVonjLdB/OaA+L6CfYQeIQ=", + "ref": "refs/heads/mr_prefill_support", + "rev": "32e356aeaecbcd819c9b944fb55e37fad834c76c", + "revCount": 822, + "type": "git", + "url": "file:///home/aids/git/ToR/microkit_sdf_gen" }, "original": { - "owner": "au-ts", - "ref": "0.28.1", - "repo": "microkit_sdf_gen", - "type": "github" + "type": "git", + "url": "file:///home/aids/git/ToR/microkit_sdf_gen" } }, "systems": { @@ -216,11 +215,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1739707935, - "narHash": "sha256-YE+Zn03AWqDBmgxNrM50s7tpH+7fQYu1n9ZvXUWhznE=", + "lastModified": 1756037521, + "narHash": "sha256-nLOxILJqZtVCPCWppiDcEodTyguC6/EWvOprRuVoH4Q=", "owner": "mitchellh", "repo": "zig-overlay", - "rev": "18c6ec3d906c8f7e611687ca71705d6130e754c4", + "rev": "25d6cdf56abecb2b6a8e59905948ef41892aa371", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index c6c2fcdb2..3a7c66c2e 100644 --- a/flake.nix +++ b/flake.nix @@ -8,7 +8,7 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; zig-overlay.url = "github:mitchellh/zig-overlay"; - sdfgen.url = "github:au-ts/microkit_sdf_gen/0.28.1"; + sdfgen.url = "git+file:///home/aids/git/ToR/microkit_sdf_gen"; sdfgen.inputs.nixpkgs.follows = "nixpkgs"; }; From 581cd0cb271d980408a6329bf106c22a088cd014 Mon Sep 17 00:00:00 2001 From: 0aids Date: Thu, 11 Jun 2026 15:03:09 +1000 Subject: [PATCH 06/27] wip got multi-child fault and backtracing partially working Signed-off-by: 0aids --- examples/backtrace_test/backtracer.c | 10 +++--- examples/backtrace_test/meta.py | 45 ++++++++++++++++++++++-- examples/backtrace_test/unwind_helpers.c | 2 ++ 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/examples/backtrace_test/backtracer.c b/examples/backtrace_test/backtracer.c index ea6e0e6e2..4b7fe3e2d 100644 --- a/examples/backtrace_test/backtracer.c +++ b/examples/backtrace_test/backtracer.c @@ -14,15 +14,13 @@ // X(seL4_Fault_DebugException) -void (*backtraceFunctions[])() = {NULL}; +void (**backtraceFunctions)() = NULL; #define BASE_PD_TCB_CAP 202 -#ifndef SHOW_BACKTRACE_FUNC_ADDR -#error "Please define SHOW_BACKTRACE_FUNC_ADDR to be the address of the show_backtrace function" -#endif void init() { - LOG("Initialised!"); + LOG("Initialised!\n"); + LOG("Backtracer table pointer value: %p\n", backtraceFunctions); } void printFaultType(seL4_Word label) @@ -66,7 +64,7 @@ seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, LOG("Failed to read registers for setting up backtrace jump! Got %d, expected %d\n", readRegResult, 0); return seL4_False; } - callConvention_prologue(&ctxt, SHOW_BACKTRACE_FUNC_ADDR); + callConvention_prologue(&ctxt, (uintptr_t)(backtraceFunctions[child])); int writeRegResult = seL4_TCB_WriteRegisters(BASE_PD_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); if (writeRegResult != 0) { diff --git a/examples/backtrace_test/meta.py b/examples/backtrace_test/meta.py index 23bea6aae..f2c880967 100644 --- a/examples/backtrace_test/meta.py +++ b/examples/backtrace_test/meta.py @@ -6,6 +6,8 @@ from sdfgen import SystemDescription, Sddf, DeviceTree, LionsOs from importlib.metadata import version from board import BOARDS +from subprocess import run +from copy import deepcopy # assert version("sdfgen").split(".")[1] == "28", "Unexpected sdfgen version" @@ -16,6 +18,15 @@ Map = SystemDescription.Map Channel = SystemDescription.Channel +def getArchitecturePointerAlignment(arch: SystemDescription.Arch): + match arch: + case SystemDescription.Arch.AARCH64 | SystemDescription.Arch.RISCV64 | SystemDescription.Arch.X86_64: + return 8 + case SystemDescription.Arch.AARCH32 | SystemDescription.Arch.RISCV32 | SystemDescription.Arch.X86: + return 8 + case _: + raise Exception(f"Archicture '{arch}' is not supported") + def enableBacktracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr = 0xb00000): """ Wrap an array or single pd as children into a backtracer parent, @@ -23,22 +34,50 @@ def enableBacktracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr = Remember to compile each of the children with "backtrace.o" """ backtracer = ProtectionDomain("backtracer", "backtracer.elf", priority=ProtectionDomain.PRIORITY_MAX, stack_size=0x10000); + pd_elf_paths = []; if isinstance(array_of_pds_or_single_pd, list): for child_pd in array_of_pds_or_single_pd: backtracer.add_child_pd(child_pd) + pd_elf_paths.append(child_pd.program_image) else: backtracer.add_child_pd(array_of_pds_or_single_pd) + pd_elf_paths.append(array_of_pds_or_single_pd.program_image) # Create a memory region at the predefined address, as an array - func_list_mr = MemoryRegion(sdf, "backtracerFunctions", prefill_path="test.txt") + # Extract each of the addresses of the children's show_backtrace function + pd_show_backtrace_addrs = [] + for elf_path in pd_elf_paths: + shell_output = run("set -o pipefail && nm faulter.elf | grep \"show_backtrace\" | cut --delimiter=\" \" -f 1", + capture_output=True, shell=True, text=True) + if shell_output.returncode != 0: + raise Exception(f"Failed to get addresses of 'show_backtrace' for file {elf_path}\n" + + f"stderr: {shell_output.stderr}\n" + + f"stdout: {shell_output.stdout}\n" + + f"exit code: {shell_output.returncode}\n") + show_backtrace_addr = int(shell_output.stdout.strip(), 16); + print(f"'{elf_path}':show_backtrace @ {hex(show_backtrace_addr)}") + pd_show_backtrace_addrs.append(show_backtrace_addr) + + # now write a .data file containing the files spaced out by architectures pointer size. + alignment = getArchitecturePointerAlignment(board.arch) + print(f"Alignment for architecture {board.arch.name}: {alignment}") + frame = b"" + for backtrace_addr in pd_show_backtrace_addrs: + frame += bytes(backtrace_addr.to_bytes(alignment, "little")) + BACKTRACER_FUNCTION_DATA_PATH = "backtrace_functions.data" + with open(BACKTRACER_FUNCTION_DATA_PATH, "wb") as dataFile: + dataFile.write(frame) + func_list_mr = MemoryRegion(sdf, "backtracerFunctions", prefill_path=BACKTRACER_FUNCTION_DATA_PATH) sdf.add_mr(func_list_mr) func_list_map = Map(func_list_mr, vaddr=0x20000, perms="r", setvar_vaddr="backtraceFunctions") backtracer.add_map(func_list_map) return backtracer def generate(sdf_path: str, output_dir: str): - faulter_pd = ProtectionDomain("faulter", "faulter.elf", priority=1, stack_size=0x100000) - backtracer = enableBacktracing(faulter_pd) + domains = [ + ProtectionDomain(f"faulter{i}", "faulter.elf", priority=i, stack_size=0x100000) for i in range(5) + ] + backtracer = enableBacktracing(domains) sdf.add_pd(backtracer) with open(f"{output_dir}/{sdf_path}", "w+") as f: diff --git a/examples/backtrace_test/unwind_helpers.c b/examples/backtrace_test/unwind_helpers.c index 8cf1e3704..fd0e55d00 100644 --- a/examples/backtrace_test/unwind_helpers.c +++ b/examples/backtrace_test/unwind_helpers.c @@ -18,4 +18,6 @@ void show_backtrace (void) { sddf_printf("ip = %lx, sp = %lx\n", (long) ip, (long) sp); } microkit_dbg_puts("SHOW_BACKTRACE | END_SHOW_BACKTRACE\n"); + // while (1) + // seL4_Yield(); } From bec9681992bc0f88dfdcad552366f2244c1ca87c Mon Sep 17 00:00:00 2001 From: 0aids Date: Thu, 11 Jun 2026 16:47:15 +1000 Subject: [PATCH 07/27] implemented multi-child PD fault backtracing Signed-off-by: 0aids --- examples/backtrace_test/backtracer.c | 12 +++++++----- examples/backtrace_test/meta.py | 25 ++++++++++++++++-------- examples/backtrace_test/unwind_helpers.c | 10 +++++++--- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/examples/backtrace_test/backtracer.c b/examples/backtrace_test/backtracer.c index 4b7fe3e2d..582baab0e 100644 --- a/examples/backtrace_test/backtracer.c +++ b/examples/backtrace_test/backtracer.c @@ -16,8 +16,6 @@ void (**backtraceFunctions)() = NULL; -#define BASE_PD_TCB_CAP 202 - void init() { LOG("Initialised!\n"); LOG("Backtracer table pointer value: %p\n", backtraceFunctions); @@ -58,14 +56,15 @@ seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, uint64_t label = microkit_msginfo_get_label(msginfo); printFaultType(label); seL4_UserContext ctxt = {0}; - int readRegResult = seL4_TCB_ReadRegisters(BASE_PD_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); + // BASE_TCB_CAP is from microkit.h. Not sure if completely portable? + int readRegResult = seL4_TCB_ReadRegisters(BASE_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); if (readRegResult != 0) { LOG("Failed to read registers for setting up backtrace jump! Got %d, expected %d\n", readRegResult, 0); return seL4_False; } callConvention_prologue(&ctxt, (uintptr_t)(backtraceFunctions[child])); - int writeRegResult = seL4_TCB_WriteRegisters(BASE_PD_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); + int writeRegResult = seL4_TCB_WriteRegisters(BASE_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); if (writeRegResult != 0) { LOG("Failed to write registers for setting up backtrace jump! Got %d, expected %d\n", writeRegResult, 0); @@ -75,4 +74,7 @@ seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, } void notified(microkit_channel ch) {} -microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) {} +microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) { + microkit_pd_stop(ch); + return msginfo; +} diff --git a/examples/backtrace_test/meta.py b/examples/backtrace_test/meta.py index f2c880967..70318850d 100644 --- a/examples/backtrace_test/meta.py +++ b/examples/backtrace_test/meta.py @@ -35,13 +35,22 @@ def enableBacktracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr = """ backtracer = ProtectionDomain("backtracer", "backtracer.elf", priority=ProtectionDomain.PRIORITY_MAX, stack_size=0x10000); pd_elf_paths = []; - if isinstance(array_of_pds_or_single_pd, list): - for child_pd in array_of_pds_or_single_pd: - backtracer.add_child_pd(child_pd) - pd_elf_paths.append(child_pd.program_image) - else: - backtracer.add_child_pd(array_of_pds_or_single_pd) - pd_elf_paths.append(array_of_pds_or_single_pd.program_image) + if not isinstance(array_of_pds_or_single_pd, list): + array_of_pds_or_single_pd = [array_of_pds_or_single_pd] + + for i, child_pd in enumerate(array_of_pds_or_single_pd): + # Also add a channel for allowing a thread to pause completely + newChannel = Channel( + child_pd, + backtracer, + a_id = 10 + i, + b_id = i, + pp_a = True, + pd_a_setvar_id="channel_to_backtrace" + ) + sdf.add_channel(newChannel) + backtracer.add_child_pd(child_pd) + pd_elf_paths.append(child_pd.program_image) # Create a memory region at the predefined address, as an array # Extract each of the addresses of the children's show_backtrace function @@ -76,7 +85,7 @@ def enableBacktracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr = def generate(sdf_path: str, output_dir: str): domains = [ ProtectionDomain(f"faulter{i}", "faulter.elf", priority=i, stack_size=0x100000) for i in range(5) - ] + ] backtracer = enableBacktracing(domains) sdf.add_pd(backtracer) diff --git a/examples/backtrace_test/unwind_helpers.c b/examples/backtrace_test/unwind_helpers.c index fd0e55d00..cfdbf58ce 100644 --- a/examples/backtrace_test/unwind_helpers.c +++ b/examples/backtrace_test/unwind_helpers.c @@ -3,8 +3,12 @@ #define UNW_LOCAL_ONLY #include +#define INPUT_CAP 1 +static seL4_MessageInfo_t empty_msg = {0}; +uintptr_t channel_to_backtrace = 0; + void show_backtrace (void) { - microkit_dbg_puts("SHOW_BACKTRACE | BEGIN_SHOW_BACKTRACE\n"); + sddf_printf("SHOW_BACKTRACE | BEGIN_SHOW_BACKTRACE for '%s'\n", microkit_name); unw_cursor_t cursor; unw_context_t uc; unw_word_t ip, sp; @@ -18,6 +22,6 @@ void show_backtrace (void) { sddf_printf("ip = %lx, sp = %lx\n", (long) ip, (long) sp); } microkit_dbg_puts("SHOW_BACKTRACE | END_SHOW_BACKTRACE\n"); - // while (1) - // seL4_Yield(); + microkit_ppcall(channel_to_backtrace, empty_msg); + microkit_dbg_puts("You're not supposed to see this\n"); } From 66dcec72c2cd2f962179f50ba9d6df06f650eeae Mon Sep 17 00:00:00 2001 From: 0aids Date: Sun, 14 Jun 2026 12:49:40 +1000 Subject: [PATCH 08/27] fixed incorrect alignment and unnecessary channel ID incrementing Signed-off-by: 0aids --- examples/backtrace_test/meta.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/backtrace_test/meta.py b/examples/backtrace_test/meta.py index 70318850d..594209c18 100644 --- a/examples/backtrace_test/meta.py +++ b/examples/backtrace_test/meta.py @@ -23,7 +23,7 @@ def getArchitecturePointerAlignment(arch: SystemDescription.Arch): case SystemDescription.Arch.AARCH64 | SystemDescription.Arch.RISCV64 | SystemDescription.Arch.X86_64: return 8 case SystemDescription.Arch.AARCH32 | SystemDescription.Arch.RISCV32 | SystemDescription.Arch.X86: - return 8 + return 4 case _: raise Exception(f"Archicture '{arch}' is not supported") @@ -43,7 +43,7 @@ def enableBacktracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr = newChannel = Channel( child_pd, backtracer, - a_id = 10 + i, + a_id = 61, b_id = i, pp_a = True, pd_a_setvar_id="channel_to_backtrace" From 496f5e97c168df87e34a95cf22eec8729c31e80a Mon Sep 17 00:00:00 2001 From: 0aids Date: Mon, 15 Jun 2026 14:44:34 +1000 Subject: [PATCH 09/27] cleaned up backtrace printing Signed-off-by: 0aids --- examples/backtrace_test/backtracer.c | 40 +- examples/backtrace_test/faulter.c | 19 +- .../backtrace_test/lwip_include/arch/cc.h | 70 -- .../backtrace_test/lwip_include/lwipopts.h | 208 ----- examples/backtrace_test/monitor.h | 859 ++++++++++++++++++ examples/backtrace_test/posix_test.mk | 5 +- examples/backtrace_test/unwind_helpers.c | 5 +- examples/backtrace_test/util.h | 92 ++ 8 files changed, 980 insertions(+), 318 deletions(-) delete mode 100644 examples/backtrace_test/lwip_include/arch/cc.h delete mode 100644 examples/backtrace_test/lwip_include/lwipopts.h create mode 100644 examples/backtrace_test/monitor.h create mode 100644 examples/backtrace_test/util.h diff --git a/examples/backtrace_test/backtracer.c b/examples/backtrace_test/backtracer.c index 582baab0e..8465c9227 100644 --- a/examples/backtrace_test/backtracer.c +++ b/examples/backtrace_test/backtracer.c @@ -1,48 +1,24 @@ #include #include +#include "monitor.h" #define LOG(...) sddf_printf("BACKTRACER | " __VA_ARGS__) -#define FAULTS \ - X(seL4_Fault_CapFault) \ - X(seL4_Fault_VMFault) \ - X(seL4_Fault_UnknownSyscall) \ - X(seL4_Fault_UserException) \ - X(seL4_Fault_NullFault) \ - X(seL4_Fault_VPPIEvent) \ - X(seL4_Fault_VCPUFault) - // X(seL4_Fault_TimeoutFault) - // X(seL4_Fault_VGICMaintenence) - // X(seL4_Fault_DebugException) - void (**backtraceFunctions)() = NULL; void init() { - LOG("Initialised!\n"); - LOG("Backtracer table pointer value: %p\n", backtraceFunctions); -} - -void printFaultType(seL4_Word label) -{ - LOG("Fault type: "); - switch (label) - { - #define X(value) case value: sddf_printf(#value "\n"); break; - FAULTS - #undef X - } + LOG("Backtracer initialised!\n"); + LOG("Backtracer table starting address: %p\n", backtraceFunctions); } #if defined(__aarch64__) -void callConvention_prologue(seL4_UserContext* ctxt, uintptr_t funcAddr) +static void callConvention_prologue(seL4_UserContext* ctxt, uintptr_t funcAddr) { - LOG("Pre jump PC: %p\n", (void*) ctxt->pc); // Set the link register to old PC ctxt->x30 = ctxt->pc; // Set the PC to the next function ctxt->pc = funcAddr; - LOG("Post jump PC: %p\n", (void*) ctxt->pc); } -#elif defined(__riscv) +#elif defined(__riscv__) #error "Unimplemented backtracer for riscv" #elif defined(__x86_64__) #error "Unimplemented backtracer for x86_64" @@ -52,9 +28,8 @@ void callConvention_prologue(seL4_UserContext* ctxt, uintptr_t funcAddr) seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) { - LOG("Fault received! Setting up backtrace...\n"); - uint64_t label = microkit_msginfo_get_label(msginfo); - printFaultType(label); + LOG("Child '%d' Faulted!\n", child); + print_fault_error(child, msginfo); seL4_UserContext ctxt = {0}; // BASE_TCB_CAP is from microkit.h. Not sure if completely portable? int readRegResult = seL4_TCB_ReadRegisters(BASE_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); @@ -63,6 +38,7 @@ seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, LOG("Failed to read registers for setting up backtrace jump! Got %d, expected %d\n", readRegResult, 0); return seL4_False; } + print_tcb_registers(&ctxt); callConvention_prologue(&ctxt, (uintptr_t)(backtraceFunctions[child])); int writeRegResult = seL4_TCB_WriteRegisters(BASE_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); if (writeRegResult != 0) diff --git a/examples/backtrace_test/faulter.c b/examples/backtrace_test/faulter.c index 63bd1d7e2..5de224a08 100644 --- a/examples/backtrace_test/faulter.c +++ b/examples/backtrace_test/faulter.c @@ -4,17 +4,28 @@ #include #define LOG(...) sddf_printf("FAULTER | " __VA_ARGS__) +const char* timestamp = __TIMESTAMP__; +// Get a random-ish pointer to low-ish memory +uintptr_t happy = 0; + +void recurseFault(int depth) +{ + if (depth == 0) + { + *(volatile int*)happy; + return; + } + recurseFault(--depth); +} + void init() { LOG("Faulter initialised!\n"); - // Cause a fault immediately - volatile int* happy = (void*)UINTPTR_MAX; - volatile int notHappy = *happy; + recurseFault(4); LOG("After dereference\n"); } void notified(microkit_channel ch) { LOG("Notified!\n"); } microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) { - LOG("Protected!\n"); } diff --git a/examples/backtrace_test/lwip_include/arch/cc.h b/examples/backtrace_test/lwip_include/arch/cc.h deleted file mode 100644 index ef493c8f5..000000000 --- a/examples/backtrace_test/lwip_include/arch/cc.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - */ -#pragma once - -#include -#include -#include - -typedef uint8_t u8_t; -typedef uint16_t u16_t; -typedef uint32_t u32_t; -typedef uint64_t u64_t; - -typedef int8_t s8_t; -typedef int16_t s16_t; -typedef int32_t s32_t; -typedef int64_t s64_t; - -typedef uintptr_t mem_ptr_t; - -#define U16_F "u" -#define S16_F "d" -#define X16_F "x" -#define U32_F "u" -#define S32_F "d" -#define X32_F "x" -#define SZT_F "lu" - -// BYTE_ORDER might be defined by the architecture -#ifndef BYTE_ORDER -#if defined(__BYTE_ORDER__) -#define BYTE_ORDER __BYTE_ORDER__ -#elif defined(__BIG_ENDIAN) -#define BYTE_ORDER BIG_ENDIAN -#elif defined(__LITTLE_ENDIAN) -#define BYTE_ORDER LITTLE_ENDIAN -#else -#error Unable to detemine system endianess -#endif -#endif - -#define LWIP_CHKSUM_ALGORITHM 3 - -#define PACK_STRUCT_STRUCT __attribute__((packed)) -#define PACK_STRUCT_BEGIN -#define PACK_STRUCT_END - -#define LWIP_PLATFORM_BYTESWAP 1 -#define LWIP_PLATFORM_HTONS(x) ( (((u16_t)(x))>>8) | (((x)&0xFF)<<8) ) -#define LWIP_PLATFORM_HTONL(x) ( (((u32_t)(x))>>24) | (((x)&0xFF0000)>>8) \ - | (((x)&0xFF00)<<8) | (((x)&0xFF)<<24) ) - -#define LWIP_RAND rand - -/* Plaform specific diagnostic output */ -#define LWIP_PLATFORM_DIAG(x) \ - do { \ - sddf_dprintf x ; \ - } while(0) - -#define LWIP_PLATFORM_ASSERT(x) \ - do { \ - if (!x) { \ - sddf_dprintf("assertion violated: %s : %s:%d:%s\n", \ - #x, __FILE__, __LINE__, __FUNCTION__); \ - while(1); \ - } \ - } while(0) diff --git a/examples/backtrace_test/lwip_include/lwipopts.h b/examples/backtrace_test/lwip_include/lwipopts.h deleted file mode 100644 index 3df69029a..000000000 --- a/examples/backtrace_test/lwip_include/lwipopts.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright 2022, UNSW - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -#if defined(CONFIG_PLAT_QEMU_ARM_VIRT) || defined(CONFIG_PLAT_QEMU_RISCV_VIRT) -// We don't need to do any address conflict detection on QEMU -// as it creates it's own isolated network. -// -// Disabling this option drastically decreases the time to -// complete DHCP on QEMU. -#define LWIP_DHCP_DOES_ACD_CHECK 0 -#endif - -/** - * Use lwIP without OS-awareness (no thread, semaphores, mutexes or mboxes). - */ -#define NO_SYS 1 - -/** - * Enable Netconn API (require to use api_lib.c). - */ -#define LWIP_NETCONN 0 - -/** - * Enable Socket API (require to use sockets.c). - */ -#define LWIP_SOCKET 0 - -/** - * Enable IGMP module inside the IP stack. - */ -#define LWIP_IGMP 1 - -/** - * Turn on DNS module. UDP must be available for DNS transport. - */ -#define LWIP_DNS 1 - -/** - * Enable DHCP module. - */ -#define LWIP_DHCP 1 - -/** - * Should be set to the alignment of the CPU. - */ -#define MEM_ALIGNMENT 4 - -/** - * The size of the heap memory. If the application will send - * a lot of data that needs to be copied, this should be set high. - */ -#define MEM_SIZE 0x30000 - -/** - * Enable code to support static ARP table entries (using - * etharp_add_static_entry/etharp_remove_static_entry). - */ -#define ETHARP_SUPPORT_STATIC_ENTRIES 1 - -/** - * Enable inter-task protection (and task-vs-interrupt protection) - * for certain critical regions during buffer allocation, deallocation - * and memory allocation and deallocation. - */ -#define SYS_LIGHTWEIGHT_PROT 0 - -/** - * Support a callback function whenever an interface changes its - * up/down status (i.e., due to DHCP IP acquisition). - */ -#define LWIP_NETIF_STATUS_CALLBACK 1 - -/** - * Set options to 1 to enable checking of checksums in software for incoming - * packets. We leave the checksum checking on RX to hardware. - */ -#define CHECKSUM_CHECK_IP 0 -#define CHECKSUM_CHECK_UDP 0 -#define CHECKSUM_CHECK_TCP 0 -#define CHECKSUM_CHECK_ICMP 0 -#define CHECKSUM_CHECK_ICMP6 0 - -/** - * Set options to 1 to generate checksums in software for outgoing packets. - */ -#ifdef NETWORK_HW_HAS_CHECKSUM - -/* Leave the checksum checking on tx to hw */ -#define CHECKSUM_GEN_IP 0 -#define CHECKSUM_GEN_UDP 0 -#define CHECKSUM_GEN_TCP 0 -#define CHECKSUM_GEN_ICMP 0 -#define CHECKSUM_GEN_ICMP6 0 - -#else - -#define CHECKSUM_GEN_IP 1 -#define CHECKSUM_GEN_UDP 1 -#define CHECKSUM_GEN_TCP 1 -#define CHECKSUM_GEN_ICMP 1 -#define CHECKSUM_GEN_ICMP6 1 - -#endif - -/** - * TCP Maximum segment size. For the receive side, this MSS is advertised - * to the remote side when opening a connection. For the transmit size, this - * MSS sets an upper limit on the MSS advertised by the remote host. - */ -#define TCP_MSS 1460 - -/** - * The size of a TCP window - Maximum data we can receive at once. This - * must be at least (2 * TCP_MSS) for things to work well. - */ -#define TCP_WND (1000 * TCP_MSS) - -/** - * TCP sender buffer space (bytes). To achieve good performance, this - * should be at least 2 * TCP_MSS. - */ -#define TCP_SND_BUF TCP_WND - -/** - * TCP writable space (bytes). This must be less than TCP_SND_BUF. It is - * the amount of space which must be available in the TCP snd_buf for - * select to return writable (combined with TCP_SNDQUEUELOWAT). - */ -#define TCP_SNDLOWAT TCP_MSS - -/** - * TCP will support sending selective acknowledgements (SACKs). - */ -#define LWIP_TCP_SACK_OUT 1 - -/** - * Set LWIP_WND_SCALE to 1 to enable window scaling. - */ -#define LWIP_WND_SCALE 1 - -/** - * Set TCP_RCV_SCALE to the desired scaling factor (shift count in the - * range of [0..14]). - * When LWIP_WND_SCALE is enabled but TCP_RCV_SCALE is 0, we can use a large - * send window while having a small receive window only. - */ -#define TCP_RCV_SCALE 12 - -/** - * Support the TCP timestamp option. - */ -#define LWIP_TCP_TIMESTAMPS 1 - -/** - * The number of buffers in the pbuf pool. - */ -#define PBUF_POOL_SIZE 1000 - -/* - * Streams can hang around in FIN_WAIT state for a - * while after closing. Increase the max number of concurrent streams to allow - * for a few of these while the next benchmark runs. - */ -#define MEMP_NUM_TCP_PCB 100 - -/** - * The number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). - * If the application sends a lot of data out of ROM (or other static memory), - * this should be set high. - */ -#define MEMP_NUM_PBUF (10 * TCP_SND_QUEUELEN) - -/** - * The number of simultaneously queued TCP segments. - */ -#define MEMP_NUM_TCP_SEG (10 * TCP_SND_QUEUELEN) - -/** - * The number of listening TCP connections. - * (requires the LWIP_TCP option) - */ -#define MEMP_NUM_TCP_PCB_LISTEN MEMP_NUM_TCP_PCB - -/** - * Enable statistics collection in lwip_stats. Set this to 0 for performance. - */ -#define LWIP_STATS 0 - -/* Debugging options */ -#define LWIP_DEBUG -/* Change this to LWIP_DBG_LEVEL_ALL to see a trace */ -#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_SERIOUS - -#define DHCP_DEBUG LWIP_DBG_ON -#define UDP_DEBUG LWIP_DBG_ON -#define ETHARP_DEBUG LWIP_DBG_ON -#define PBUF_DEBUG LWIP_DBG_ON -#define IP_DEBUG LWIP_DBG_ON -#define TCPIP_DEBUG LWIP_DBG_ON -#define DHCP_DEBUG LWIP_DBG_ON -#define UDP_DEBUG LWIP_DBG_ON diff --git a/examples/backtrace_test/monitor.h b/examples/backtrace_test/monitor.h new file mode 100644 index 000000000..07aec3238 --- /dev/null +++ b/examples/backtrace_test/monitor.h @@ -0,0 +1,859 @@ +#pragma once +/* + * Copyright 2021, Breakaway Consulting Pty. Ltd. + * + * SPDX-License-Identifier: BSD-2-Clause + */ +/* + * The Microkit Monitor. + * + * The monitor is the highest priority Protection Domain + * exclusively in a Microkit system. It fulfills one purpose: + * + * Acting as the fault handler for protection domains. + */ + +#include +#include +#include + +#include "util.h" + +#define MAX_VMS 64 +#define MAX_PDS 64 +#define MAX_NAME_LEN 64 + +#define FAULT_EP_CAP 1 +#define REPLY_CAP 2 +#define BASE_PD_TCB_CAP 10 +#define BASE_SCHED_CONTEXT_CAP 138 +#define BASE_NOTIFICATION_CAP 202 + +extern seL4_IPCBuffer __sel4_ipc_buffer_obj; + +char pd_names[MAX_PDS][MAX_NAME_LEN]; +seL4_Word pd_names_len; +char vm_names[MAX_VMS][MAX_NAME_LEN] __attribute__((unused)); +seL4_Word vm_names_len; + +/* For reporting potential stack overflows, keep track of the stack regions for each PD. */ +seL4_Word pd_stack_bottom_addrs[MAX_PDS]; + +/* Sanity check that the architecture specific macro have been set. */ +#if defined(ARCH_aarch64) +#elif defined(ARCH_x86_64) +#elif defined(ARCH_riscv64) +#else +#error "No architecture flag was defined, double check your CC flags" +#endif + +#ifdef ARCH_riscv64 +/* + * Convert the fault status register given by the kernel into a string describing + * what fault happened. The FSR is the 'scause' register. + */ +static char *riscv_fsr_to_string(seL4_Word fsr) +{ + switch (fsr) { + case 0: + return "Instruction address misaligned"; + case 1: + return "Instruction access fault"; + case 2: + return "Illegal instruction"; + case 3: + return "Breakpoint"; + case 4: + return "Load address misaligned"; + case 5: + return "Load access fault"; + case 6: + return "Store/AMO address misaligned"; + case 7: + return "Store/AMO access fault"; + case 8: + return "Environment call from U-mode"; + case 9: + return "Environment call from S-mode"; + case 12: + return "Instruction page fault"; + case 13: + return "Load page fault"; + case 15: + return "Store/AMO page fault"; + case 18: + return "Software check"; + case 19: + return "Hardware error"; + default: + return ""; + } +} +#endif + +#ifdef ARCH_aarch64 +static char *ec_to_string(uintptr_t ec) +{ + switch (ec) { + case 0: + return "Unknown reason"; + case 1: + return "Trapped WFI or WFE instruction execution"; + case 3: + return "Trapped MCR or MRC access with (coproc==0b1111) this is not reported using EC 0b000000"; + case 4: + return "Trapped MCRR or MRRC access with (coproc==0b1111) this is not reported using EC 0b000000"; + case 5: + return "Trapped MCR or MRC access with (coproc==0b1110)"; + case 6: + return "Trapped LDC or STC access"; + case 7: + return "Access to SVC, Advanced SIMD or floating-point functionality trapped"; + case 12: + return "Trapped MRRC access with (coproc==0b1110)"; + case 13: + return "Branch Target Exception"; + case 17: + return "SVC instruction execution in AArch32 state"; + case 21: + return "SVC instruction execution in AArch64 state"; + case 24: + return "Trapped MSR, MRS or System instruction exuection in AArch64 state, this is not reported using EC 0xb000000, 0b000001 or 0b000111"; + case 25: + return "Access to SVE functionality trapped"; + case 28: + return "Exception from a Pointer Authentication instruction authentication failure"; + case 32: + return "Instruction Abort from a lower Exception level"; + case 33: + return "Instruction Abort taken without a change in Exception level"; + case 34: + return "PC alignment fault exception"; + case 36: + return "Data Abort from a lower Exception level"; + case 37: + return "Data Abort taken without a change in Exception level"; + case 38: + return "SP alignment faultr exception"; + case 40: + return "Trapped floating-point exception taken from AArch32 state"; + case 44: + return "Trapped floating-point exception taken from AArch64 state"; + case 47: + return "SError interrupt"; + case 48: + return "Breakpoint exception from a lower Exception level"; + case 49: + return "Breakpoint exception taken without a change in Exception level"; + case 50: + return "Software Step exception from a lower Exception level"; + case 51: + return "Software Step exception taken without a change in Exception level"; + case 52: + return "Watchpoint exception from a lower Exception level"; + case 53: + return "Watchpoint exception taken without a change in Exception level"; + case 56: + return "BKPT instruction execution in AArch32 state"; + case 60: + return "BRK instruction execution in AArch64 state"; + } + return ""; +} + +static char *data_abort_dfsc_to_string(uintptr_t dfsc) +{ + switch (dfsc) { + case 0x00: + return "address size fault, level 0"; + case 0x01: + return "address size fault, level 1"; + case 0x02: + return "address size fault, level 2"; + case 0x03: + return "address size fault, level 3"; + case 0x04: + return "translation fault, level 0"; + case 0x05: + return "translation fault, level 1"; + case 0x06: + return "translation fault, level 2"; + case 0x07: + return "translation fault, level 3"; + case 0x09: + return "access flag fault, level 1"; + case 0x0a: + return "access flag fault, level 2"; + case 0x0b: + return "access flag fault, level 3"; + case 0x0d: + return "permission fault, level 1"; + case 0x0e: + return "permission fault, level 2"; + case 0x0f: + return "permission fault, level 3"; + case 0x10: + return "synchronuos external abort"; + case 0x11: + return "synchronous tag check fault"; + case 0x14: + return "synchronous external abort, level 0"; + case 0x15: + return "synchronous external abort, level 1"; + case 0x16: + return "synchronous external abort, level 2"; + case 0x17: + return "synchronous external abort, level 3"; + case 0x18: + return "synchronous parity or ECC error"; + case 0x1c: + return "synchronous parity or ECC error, level 0"; + case 0x1d: + return "synchronous parity or ECC error, level 1"; + case 0x1e: + return "synchronous parity or ECC error, level 2"; + case 0x1f: + return "synchronous parity or ECC error, level 3"; + case 0x21: + return "alignment fault"; + case 0x30: + return "tlb conflict abort"; + case 0x31: + return "unsupported atomic hardware update fault"; + } + return ""; +} +#endif + +#ifdef ARCH_x86_64 +static char *page_fault_to_string(seL4_Word fsr) +{ + // https://wiki.osdev.org/Exceptions#Page_Fault + switch (fsr) { + case 0 | 4: + return "read to a non-present page at ring 3"; + case 1 | 4: + return "page-protection violation from read at ring 3"; + case 2 | 4: + return "write to a non-present page at ring 3"; + case 3 | 4: + return "page-protection violation from write at ring 3"; + case 16: + // Note that seL4 currently does not implement the NX/XD bit + // to mark a page as non-executable so we will never see the below message. + return "instruction fetch from non-executable page"; + default: + return "invalid FSR or unimplemented decoding"; + } +} +#endif + +/* UBSAN decoding related functionality */ +#define UBSAN_ARM64_BRK_IMM 0x5500 +#define UBSAN_ARM64_BRK_MASK 0x00ff +#define ESR_COMMENT_MASK ((1 << 16) - 1) +#define ARM64_BRK_EC 60 + +/* + * ABI defined by Clang's UBSAN enum SanitizerHandler: + * https://github.com/llvm/llvm-project/blob/release/16.x/clang/lib/CodeGen/CodeGenFunction.h#L113 + */ +enum UBSAN_CHECKS { + UBSAN_ADD_OVERFLOW, + UBSAN_BUILTIN_UNREACHABLE, + UBSAN_CFI_CHECK_FAIL, + UBSAN_DIVREM_OVERFLOW, + UBSAN_DYNAMIC_TYPE_CACHE_MISS, + UBSAN_FLOAT_CAST_OVERFLOW, + UBSAN_FUNCTION_TYPE_MISMATCH, + UBSAN_IMPLICIT_CONVERSION, + UBSAN_INVALID_BUILTIN, + UBSAN_INVALID_OBJC_CAST, + UBSAN_LOAD_INVALID_VALUE, + UBSAN_MISSING_RETURN, + UBSAN_MUL_OVERFLOW, + UBSAN_NEGATE_OVERFLOW, + UBSAN_NULLABILITY_ARG, + UBSAN_NULLABILITY_RETURN, + UBSAN_NONNULL_ARG, + UBSAN_NONNULL_RETURN, + UBSAN_OUT_OF_BOUNDS, + UBSAN_POINTER_OVERFLOW, + UBSAN_SHIFT_OUT_OF_BOUNDS, + UBSAN_SUB_OVERFLOW, + UBSAN_TYPE_MISMATCH, + UBSAN_ALIGNMENT_ASSUMPTION, + UBSAN_VLA_BOUND_NOT_POSITIVE, +}; + +#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT +static char *usban_code_to_string(seL4_Word code) +{ + switch (code) { + case UBSAN_ADD_OVERFLOW: + return "add overflow"; + case UBSAN_BUILTIN_UNREACHABLE: + return "builtin unreachable"; + case UBSAN_CFI_CHECK_FAIL: + return "control-flow-integrity check fail"; + case UBSAN_DIVREM_OVERFLOW: + return "division remainder overflow"; + case UBSAN_DYNAMIC_TYPE_CACHE_MISS: + return "dynamic type cache miss"; + case UBSAN_FLOAT_CAST_OVERFLOW: + return "float case overflow"; + case UBSAN_FUNCTION_TYPE_MISMATCH: + return "function type mismatch"; + case UBSAN_IMPLICIT_CONVERSION: + return "implicit conversion"; + case UBSAN_INVALID_BUILTIN: + return "invalid builtin"; + case UBSAN_INVALID_OBJC_CAST: + return "invalid objc cast"; + case UBSAN_LOAD_INVALID_VALUE: + return "load invalid value"; + case UBSAN_MISSING_RETURN: + return "missing return"; + case UBSAN_MUL_OVERFLOW: + return "multiplication overflow"; + case UBSAN_NEGATE_OVERFLOW: + return "negate overflow"; + case UBSAN_NULLABILITY_ARG: + return "nullability argument"; + case UBSAN_NULLABILITY_RETURN: + return "nullability return"; + case UBSAN_NONNULL_ARG: + return "non-null argument"; + case UBSAN_NONNULL_RETURN: + return "non-null return"; + case UBSAN_OUT_OF_BOUNDS: + return "out of bounds access"; + case UBSAN_POINTER_OVERFLOW: + return "pointer overflow"; + case UBSAN_SHIFT_OUT_OF_BOUNDS: + return "shift out of bounds"; + case UBSAN_SUB_OVERFLOW: + return "subtraction overflow"; + case UBSAN_TYPE_MISMATCH: + return "type mismatch"; + case UBSAN_ALIGNMENT_ASSUMPTION: + return "alignment assumption"; + case UBSAN_VLA_BOUND_NOT_POSITIVE: + return "variable-length-array bound not positive"; + default: + return "unknown reason"; + } +} +#endif + +static void print_tcb_registers(seL4_UserContext *regs) +{ +#if defined(ARCH_riscv64) + puts("BACKTRACER | Registers: \n"); + puts("BACKTRACER | pc : "); + puthex64(regs->pc); + puts("\n"); + puts("BACKTRACER | ra : "); + puthex64(regs->ra); + puts("\n"); + puts("BACKTRACER | s0 : "); + puthex64(regs->s0); + puts("\n"); + puts("BACKTRACER | s1 : "); + puthex64(regs->s1); + puts("\n"); + puts("BACKTRACER | s2 : "); + puthex64(regs->s2); + puts("\n"); + puts("BACKTRACER | s3 : "); + puthex64(regs->s3); + puts("\n"); + puts("BACKTRACER | s4 : "); + puthex64(regs->s4); + puts("\n"); + puts("BACKTRACER | s5 : "); + puthex64(regs->s5); + puts("\n"); + puts("BACKTRACER | s6 : "); + puthex64(regs->s6); + puts("\n"); + puts("BACKTRACER | s7 : "); + puthex64(regs->s7); + puts("\n"); + puts("BACKTRACER | s8 : "); + puthex64(regs->s8); + puts("\n"); + puts("BACKTRACER | s9 : "); + puthex64(regs->s9); + puts("\n"); + puts("BACKTRACER | s10 : "); + puthex64(regs->s10); + puts("\n"); + puts("BACKTRACER | s11 : "); + puthex64(regs->s11); + puts("\n"); + puts("BACKTRACER | a0 : "); + puthex64(regs->a0); + puts("\n"); + puts("BACKTRACER | a1 : "); + puthex64(regs->a1); + puts("\n"); + puts("BACKTRACER | a2 : "); + puthex64(regs->a2); + puts("\n"); + puts("BACKTRACER | a3 : "); + puthex64(regs->a3); + puts("\n"); + puts("BACKTRACER | a4 : "); + puthex64(regs->a4); + puts("\n"); + puts("BACKTRACER | a5 : "); + puthex64(regs->a5); + puts("\n"); + puts("BACKTRACER | a6 : "); + puthex64(regs->a6); + puts("\n"); + puts("BACKTRACER | t0 : "); + puthex64(regs->t0); + puts("\n"); + puts("BACKTRACER | t1 : "); + puthex64(regs->t1); + puts("\n"); + puts("BACKTRACER | t2 : "); + puthex64(regs->t2); + puts("\n"); + puts("BACKTRACER | t3 : "); + puthex64(regs->t3); + puts("\n"); + puts("BACKTRACER | t4 : "); + puthex64(regs->t4); + puts("\n"); + puts("BACKTRACER | t5 : "); + puthex64(regs->t5); + puts("\n"); + puts("BACKTRACER | t6 : "); + puthex64(regs->t6); + puts("\n"); + puts("BACKTRACER | tp : "); + puthex64(regs->tp); + puts("\n"); +#elif defined(ARCH_aarch64) + puts("BACKTRACER | Registers: \n"); + puts("BACKTRACER | pc : "); + puthex64(regs->pc); + puts("\n"); + puts("BACKTRACER | sp: "); + puthex64(regs->sp); + puts("\n"); + puts("BACKTRACER | spsr : "); + puthex64(regs->spsr); + puts("\n"); + puts("BACKTRACER | x0 : "); + puthex64(regs->x0); + puts("\n"); + puts("BACKTRACER | x1 : "); + puthex64(regs->x1); + puts("\n"); + puts("BACKTRACER | x2 : "); + puthex64(regs->x2); + puts("\n"); + puts("BACKTRACER | x3 : "); + puthex64(regs->x3); + puts("\n"); + puts("BACKTRACER | x4 : "); + puthex64(regs->x4); + puts("\n"); + puts("BACKTRACER | x5 : "); + puthex64(regs->x5); + puts("\n"); + puts("BACKTRACER | x6 : "); + puthex64(regs->x6); + puts("\n"); + puts("BACKTRACER | x7 : "); + puthex64(regs->x7); + puts("\n"); + puts("BACKTRACER | x8 : "); + puthex64(regs->x8); + puts("\n"); + puts("BACKTRACER | x16 : "); + puthex64(regs->x16); + puts("\n"); + puts("BACKTRACER | x17 : "); + puthex64(regs->x17); + puts("\n"); + puts("BACKTRACER | x18 : "); + puthex64(regs->x18); + puts("\n"); + puts("BACKTRACER | x29 : "); + puthex64(regs->x29); + puts("\n"); + puts("BACKTRACER | x30 : "); + puthex64(regs->x30); + puts("\n"); + puts("BACKTRACER | x9 : "); + puthex64(regs->x9); + puts("\n"); + puts("BACKTRACER | x10 : "); + puthex64(regs->x10); + puts("\n"); + puts("BACKTRACER | x11 : "); + puthex64(regs->x11); + puts("\n"); + puts("BACKTRACER | x12 : "); + puthex64(regs->x12); + puts("\n"); + puts("BACKTRACER | x13 : "); + puthex64(regs->x13); + puts("\n"); + puts("BACKTRACER | x14 : "); + puthex64(regs->x14); + puts("\n"); + puts("BACKTRACER | x15 : "); + puthex64(regs->x15); + puts("\n"); + puts("BACKTRACER | x19 : "); + puthex64(regs->x19); + puts("\n"); + puts("BACKTRACER | x20 : "); + puthex64(regs->x20); + puts("\n"); + puts("BACKTRACER | x21 : "); + puthex64(regs->x21); + puts("\n"); + puts("BACKTRACER | x22 : "); + puthex64(regs->x22); + puts("\n"); + puts("BACKTRACER | x23 : "); + puthex64(regs->x23); + puts("\n"); + puts("BACKTRACER | x24 : "); + puthex64(regs->x24); + puts("\n"); + puts("BACKTRACER | x25 : "); + puthex64(regs->x25); + puts("\n"); + puts("BACKTRACER | x26 : "); + puthex64(regs->x26); + puts("\n"); + puts("BACKTRACER | x27 : "); + puthex64(regs->x27); + puts("\n"); + puts("BACKTRACER | x28 : "); + puthex64(regs->x28); + puts("\n"); + puts("BACKTRACER | tpidr_el0 : "); + puthex64(regs->tpidr_el0); + puts("\n"); + puts("BACKTRACER | tpidrro_el0 : "); + puthex64(regs->tpidrro_el0); + puts("\n"); +#elif ARCH_x86_64 + puts("BACKTRACER | Registers: \n"); + puts("BACKTRACER | rip : "); + puthex64(regs->rip); + puts("\n"); + puts("BACKTRACER | rsp : "); + puthex64(regs->rsp); + puts("\n"); + puts("BACKTRACER | rflags : "); + puthex64(regs->rflags); + puts("\n"); + puts("BACKTRACER | rax : "); + puthex64(regs->rax); + puts("\n"); + puts("BACKTRACER | rbx : "); + puthex64(regs->rbx); + puts("\n"); + puts("BACKTRACER | rcx : "); + puthex64(regs->rcx); + puts("\n"); + puts("BACKTRACER | rdx : "); + puthex64(regs->rdx); + puts("\n"); + puts("BACKTRACER | rsi : "); + puthex64(regs->rsi); + puts("\n"); + puts("BACKTRACER | rdi : "); + puthex64(regs->rdi); + puts("\n"); + puts("BACKTRACER | rbp : "); + puthex64(regs->rbp); + puts("\n"); + puts("BACKTRACER | r8 : "); + puthex64(regs->r8); + puts("\n"); + puts("BACKTRACER | r9 : "); + puthex64(regs->r9); + puts("\n"); + puts("BACKTRACER | r10 : "); + puthex64(regs->r10); + puts("\n"); + puts("BACKTRACER | r11 : "); + puthex64(regs->r11); + puts("\n"); + puts("BACKTRACER | r12 : "); + puthex64(regs->r12); + puts("\n"); + puts("BACKTRACER | r13 : "); + puthex64(regs->r13); + puts("\n"); + puts("BACKTRACER | r14 : "); + puthex64(regs->r14); + puts("\n"); + puts("BACKTRACER | r15 : "); + puthex64(regs->r15); + puts("\n"); + puts("BACKTRACER | fs_base : "); + puthex64(regs->fs_base); + puts("\n"); + puts("BACKTRACER | gs_base : "); + puthex64(regs->gs_base); + puts("\n"); +#endif +} + +#ifdef ARCH_riscv64 +static void riscv_print_vm_fault() +{ + seL4_Word ip = seL4_GetMR(seL4_VMFault_IP); + seL4_Word fault_addr = seL4_GetMR(seL4_VMFault_Addr); + seL4_Word is_instruction = seL4_GetMR(seL4_VMFault_PrefetchFault); + seL4_Word fsr = seL4_GetMR(seL4_VMFault_FSR); + puts("BACKTRACER | VMFault: ip="); + puthex64(ip); + puts(" fault_addr="); + puthex64(fault_addr); + puts(" fsr="); + puthex64(fsr); + puts(" "); + puts(is_instruction ? "(instruction fault)" : "(data fault)"); + puts("\n"); + puts("BACKTRACER | description of fault: "); + puts(riscv_fsr_to_string(fsr)); + puts("\n"); +} +#endif + +#if ARCH_x86_64 +static void x86_64_print_vm_fault() +{ + seL4_Word ip = seL4_GetMR(seL4_VMFault_IP); + seL4_Word fault_addr = seL4_GetMR(seL4_VMFault_Addr); + seL4_Word is_instruction = seL4_GetMR(seL4_VMFault_PrefetchFault); + seL4_Word fsr = seL4_GetMR(seL4_VMFault_FSR); + puts("BACKTRACER | VMFault: ip="); + puthex64(ip); + puts(" fault_addr="); + puthex64(fault_addr); + puts(" fsr="); + puthex64(fsr); + puts(" "); + puts(is_instruction ? "(instruction fault)" : "(data fault)"); + puts("\n"); + + puts("BACKTRACER | description of fault: "); + puts(page_fault_to_string(fsr)); + puts("\n"); +} +#endif + +#ifdef ARCH_aarch64 +static void aarch64_print_vm_fault() +{ + seL4_Word ip = seL4_GetMR(seL4_VMFault_IP); + seL4_Word fault_addr = seL4_GetMR(seL4_VMFault_Addr); + seL4_Word is_instruction = seL4_GetMR(seL4_VMFault_PrefetchFault); + seL4_Word fsr = seL4_GetMR(seL4_VMFault_FSR); + seL4_Word ec = fsr >> 26; + seL4_Word il = fsr >> 25 & 1; + seL4_Word iss = fsr & 0x1ffffffUL; + puts("BACKTRACER | VMFault: ip="); + puthex64(ip); + puts(" fault_addr="); + puthex64(fault_addr); + puts(" fsr="); + puthex64(fsr); + puts(" "); + puts(is_instruction ? "(instruction fault)" : "(data fault)"); + puts("\n"); + puts("BACKTRACER | ec: "); + puthex32(ec); + puts(" "); + puts(ec_to_string(ec)); + puts(" il: "); + puts(il ? "1" : "0"); + puts(" iss: "); + puthex32(iss); + puts("\n"); + + if (ec == 0x24) { + /* FIXME: Note, this is not a complete decoding of the fault! Just some of the more + common fields! + */ + seL4_Word dfsc = iss & 0x3f; + bool ea = (iss >> 9) & 1; + bool cm = (iss >> 8) & 1; + bool s1ptw = (iss >> 7) & 1; + bool wnr = (iss >> 6) & 1; + puts("BACKTRACER | dfsc = "); + puts(data_abort_dfsc_to_string(dfsc)); + puts(" ("); + puthex32(dfsc); + puts(")"); + if (ea) { + puts(" -- external abort"); + } + if (cm) { + puts(" -- cache maint"); + } + if (s1ptw) { + puts(" -- stage 2 fault for stage 1 page table walk"); + } + if (wnr) { + puts(" -- write not read"); + } + puts("\n"); + } +} +#endif + +static void print_fault_error(microkit_child child, microkit_msginfo msginfo) +{ + seL4_Word tcb_cap = BASE_PD_TCB_CAP + child; + seL4_Word label = microkit_msginfo_get_label(msginfo); + seL4_Word err = {0}; + seL4_Word badge = child + 1; + + if (label == seL4_Fault_NullFault && child < MAX_PDS) { + /* This is a request from our PD to become passive */ + err = seL4_SchedContext_Bind(BASE_SCHED_CONTEXT_CAP + child, BASE_NOTIFICATION_CAP + child); + if (err != seL4_NoError) { + puts("BACKTRACER | could not bind scheduling context to notification object\n"); + } else { + puts("MON|INFO: PD '"); + puts(pd_names[child]); + puts("' is now passive!\n"); + } + + return; + } + + puts("BACKTRACER | received message "); + puthex32(label); + puts(" badge: "); + puthex64(badge); + puts(" tcb cap: "); + puthex64(tcb_cap); + puts("\n"); + + switch (label) { + case seL4_Fault_CapFault: { + seL4_Word ip = seL4_GetMR(seL4_CapFault_IP); + seL4_Word fault_addr = seL4_GetMR(seL4_CapFault_Addr); + seL4_Word in_recv_phase = seL4_GetMR(seL4_CapFault_InRecvPhase); + seL4_Word lookup_failure_type = seL4_GetMR(seL4_CapFault_LookupFailureType); + seL4_Word bits_left = seL4_GetMR(seL4_CapFault_BitsLeft); + seL4_Word depth_bits_found = seL4_GetMR(seL4_CapFault_DepthMismatch_BitsFound); + seL4_Word guard_found = seL4_GetMR(seL4_CapFault_GuardMismatch_GuardFound); + seL4_Word guard_bits_found = seL4_GetMR(seL4_CapFault_GuardMismatch_BitsFound); + + puts("BACKTRACER | CapFault: ip="); + puthex64(ip); + puts(" fault_addr="); + puthex64(fault_addr); + puts(" in_recv_phase="); + puts(in_recv_phase == 0 ? "false" : "true"); + puts(" lookup_failure_type="); + + switch (lookup_failure_type) { + case seL4_NoFailure: + puts("seL4_NoFailure"); + break; + case seL4_InvalidRoot: + puts("seL4_InvalidRoot"); + break; + case seL4_MissingCapability: + puts("seL4_MissingCapability"); + break; + case seL4_DepthMismatch: + puts("seL4_DepthMismatch"); + break; + case seL4_GuardMismatch: + puts("seL4_GuardMismatch"); + break; + default: + puthex64(lookup_failure_type); + } + + if ( + lookup_failure_type == seL4_MissingCapability || + lookup_failure_type == seL4_DepthMismatch || + lookup_failure_type == seL4_GuardMismatch) { + puts(" bits_left="); + puthex64(bits_left); + } + if (lookup_failure_type == seL4_DepthMismatch) { + puts(" depth_bits_found="); + puthex64(depth_bits_found); + } + if (lookup_failure_type == seL4_GuardMismatch) { + puts(" guard_found="); + puthex64(guard_found); + puts(" guard_bits_found="); + puthex64(guard_bits_found); + } + puts("\n"); + break; + } + case seL4_Fault_UserException: { + puts("BACKTRACER | UserException\n"); + break; + } + case seL4_Fault_VMFault: { +#if defined(ARCH_aarch64) + aarch64_print_vm_fault(); +#elif defined(ARCH_riscv64) + riscv_print_vm_fault(); +#elif defined(ARCH_x86_64) + x86_64_print_vm_fault(); +#else +#error "Unknown architecture to print a VM fault for" +#endif + + seL4_Word fault_addr = seL4_GetMR(seL4_VMFault_Addr); + seL4_Word stack_addr = pd_stack_bottom_addrs[child]; + if (fault_addr < stack_addr && fault_addr >= stack_addr - 0x1000) { + puts("BACKTRACER | potential stack overflow, fault address within one page outside of stack region\n"); + } + + break; + } +#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT + case seL4_Fault_VCPUFault: { + seL4_Word esr = seL4_GetMR(seL4_VCPUFault_HSR); + seL4_Word ec = esr >> 26; + + puts("BACKTRACER | received vCPU fault with ESR: "); + puthex64(esr); + puts("\n"); + + seL4_Word esr_comment = esr & ESR_COMMENT_MASK; + if (ec == ARM64_BRK_EC && ((esr_comment & ~UBSAN_ARM64_BRK_MASK) == UBSAN_ARM64_BRK_IMM)) { + /* We likely have a UBSAN check going off from a brk instruction */ + seL4_Word ubsan_code = esr_comment & UBSAN_ARM64_BRK_MASK; + puts("BACKTRACER | potential undefined behaviour detected by UBSAN for: '"); + puts(usban_code_to_string(ubsan_code)); + puts("'\n"); + } else { + puts("BACKTRACER | Unknown vCPU fault\n"); + } + break; + } +#endif + default: + puts("BACKTRACER | Unknown fault\n"); + puthex64(label); + break; + } +} + diff --git a/examples/backtrace_test/posix_test.mk b/examples/backtrace_test/posix_test.mk index d09ffc52b..b00676da4 100644 --- a/examples/backtrace_test/posix_test.mk +++ b/examples/backtrace_test/posix_test.mk @@ -45,7 +45,8 @@ CFLAGS += \ -I$(LWIP)/include \ -I$(LIBUNWIND)/include \ -DMAX_FDS=8 \ - -funwind-tables -O0 + -funwind-tables -O0 \ + -DARCH_aarch64 include $(LIONSOS)/lib/libc/libc.mk @@ -85,7 +86,7 @@ unwind_helpers.o: $(POSIX_TEST_DIR)/unwind_helpers.c | $(LIONS_LIBC)/include # Seems a bit fragile... backtracer.o: $(POSIX_TEST_DIR)/backtracer.c faulter.elf | $(LIONS_LIBC)/include - ${CC} ${CFLAGS} -c -o $@ $< -DSHOW_BACKTRACE_FUNC_ADDR='0x$(shell nm faulter.elf | grep "show_backtrace" | cut --delimiter=" " -f 1)' + ${CC} ${CFLAGS} -c -o $@ $< backtracer.elf: backtracer.o libunwind.a unwind_helpers.o ${LD} ${LDFLAGS} -o $@ $^ ${LIBS} diff --git a/examples/backtrace_test/unwind_helpers.c b/examples/backtrace_test/unwind_helpers.c index cfdbf58ce..c23cfc8d2 100644 --- a/examples/backtrace_test/unwind_helpers.c +++ b/examples/backtrace_test/unwind_helpers.c @@ -15,11 +15,12 @@ void show_backtrace (void) { unw_getcontext(&uc); unw_init_local(&cursor, &uc); - // TODO: print the backtrace depth, and possibly find the culprit function address? + + seL4_Word depth = 0; while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); - sddf_printf("ip = %lx, sp = %lx\n", (long) ip, (long) sp); + sddf_printf("SHOW_BACKTRACE | #%d: ip = %p, sp = %p\n", (int)depth++, (void*) ip, (void*) sp); } microkit_dbg_puts("SHOW_BACKTRACE | END_SHOW_BACKTRACE\n"); microkit_ppcall(channel_to_backtrace, empty_msg); diff --git a/examples/backtrace_test/util.h b/examples/backtrace_test/util.h new file mode 100644 index 000000000..c1423c423 --- /dev/null +++ b/examples/backtrace_test/util.h @@ -0,0 +1,92 @@ +#pragma once +/* + * Copyright 2021, Breakaway Consulting Pty. Ltd. + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#include +#include + +static void putc(uint8_t ch) +{ +#if defined(CONFIG_PRINTING) + seL4_DebugPutChar(ch); +#endif +} + +static void puts(const char *s) +{ + while (*s) { + putc(*s); + s++; + } +} + +static char hexchar(unsigned int v) +{ + return v < 10 ? '0' + v : ('a' - 10) + v; +} + +static void puthex32(uint32_t val) +{ + char buffer[8 + 3]; + buffer[0] = '0'; + buffer[1] = 'x'; + buffer[8 + 3 - 1] = 0; + for (unsigned i = 8 + 1; i > 1; i--) { + buffer[i] = hexchar(val & 0xf); + val >>= 4; + } + puts(buffer); +} + +static void puthex64(uint64_t val) +{ + char buffer[16 + 3]; + buffer[0] = '0'; + buffer[1] = 'x'; + buffer[16 + 3 - 1] = 0; + for (unsigned i = 16 + 1; i > 1; i--) { + buffer[i] = hexchar(val & 0xf); + val >>= 4; + } + puts(buffer); +} + +static void fail(char *s) +{ + puts("FAIL: "); + puts(s); + puts("\n"); + for (;;) {} +} + +static char *sel4_strerror(seL4_Word err) +{ + switch (err) { + case seL4_NoError: + return "seL4_NoError"; + case seL4_InvalidArgument: + return "seL4_InvalidArgument"; + case seL4_InvalidCapability: + return "seL4_InvalidCapability"; + case seL4_IllegalOperation: + return "seL4_IllegalOperation"; + case seL4_RangeError: + return "seL4_RangeError"; + case seL4_AlignmentError: + return "seL4_AlignmentError"; + case seL4_FailedLookup: + return "seL4_FailedLookup"; + case seL4_TruncatedMessage: + return "seL4_TruncatedMessage"; + case seL4_DeleteFirst: + return "seL4_DeleteFirst"; + case seL4_RevokeFirst: + return "seL4_RevokeFirst"; + case seL4_NotEnoughMemory: + return "seL4_NotEnoughMemory"; + } + + return ""; +} From ae841973f38a43d72722b4e2f16d8cbb1abc3f53 Mon Sep 17 00:00:00 2001 From: 0aids Date: Mon, 15 Jun 2026 16:14:27 +1000 Subject: [PATCH 10/27] feat: added backtrace component and works with backtrace example Signed-off-by: 0aids --- components/backtracer/LionsOS_Backtracer.py | 85 +++++++++++++++++ .../backtracer}/backtracer.c | 0 components/backtracer/backtracer.mk | 63 +++++++++++++ .../backtracer}/monitor.h | 0 .../backtracer}/unwind.ld | 0 components/backtracer/unwind_helpers.c | 28 ++++++ components/backtracer/util.h | 92 +++++++++++++++++++ examples/backtrace_test/Makefile | 12 +-- .../{posix_test.mk => backtrace_test.mk} | 90 ++++++++---------- examples/backtrace_test/default.nix | 76 --------------- 10 files changed, 312 insertions(+), 134 deletions(-) create mode 100644 components/backtracer/LionsOS_Backtracer.py rename {examples/backtrace_test => components/backtracer}/backtracer.c (100%) create mode 100644 components/backtracer/backtracer.mk rename {examples/backtrace_test => components/backtracer}/monitor.h (100%) rename {examples/backtrace_test => components/backtracer}/unwind.ld (100%) create mode 100644 components/backtracer/unwind_helpers.c create mode 100644 components/backtracer/util.h rename examples/backtrace_test/{posix_test.mk => backtrace_test.mk} (57%) delete mode 100644 examples/backtrace_test/default.nix diff --git a/components/backtracer/LionsOS_Backtracer.py b/components/backtracer/LionsOS_Backtracer.py new file mode 100644 index 000000000..6f877009a --- /dev/null +++ b/components/backtracer/LionsOS_Backtracer.py @@ -0,0 +1,85 @@ +# Copyright 2026, UNSW +# SPDX-License-Identifier: BSD-2-Clause +import argparse +from dataclasses import dataclass +from typing import List +from sdfgen import SystemDescription, Sddf, DeviceTree, LionsOs +from importlib.metadata import version +from board import BOARDS +from subprocess import run +from copy import deepcopy + +# assert version("sdfgen").split(".")[1] == "28", "Unexpected sdfgen version" + +ProtectionDomain = SystemDescription.ProtectionDomain +ProtectionDomain.PRIORITY_MAX = 254 + +MemoryRegion = SystemDescription.MemoryRegion +Map = SystemDescription.Map +Channel = SystemDescription.Channel + +def get_architecture_pointer_alignment(arch: SystemDescription.Arch): + match arch: + case SystemDescription.Arch.AARCH64 | SystemDescription.Arch.RISCV64 | SystemDescription.Arch.X86_64: + return 8 + case SystemDescription.Arch.AARCH32 | SystemDescription.Arch.RISCV32 | SystemDescription.Arch.X86: + return 4 + case _: + raise Exception(f"Alignment of architecture {arch} is unknown.") + +def enable_backtracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr = 0xb00000): + """ + Wrap an array or single pd as children into a backtracer parent, + capable of catching faults and then forcing prints of the backtrace + Remember to compile each of the children with "backtrace.o" + """ + backtracer = ProtectionDomain("backtracer", "backtracer.elf", priority=ProtectionDomain.PRIORITY_MAX, stack_size=0x10000); + pd_elf_paths = []; + if not isinstance(array_of_pds_or_single_pd, list): + array_of_pds_or_single_pd = [array_of_pds_or_single_pd] + + for i, child_pd in enumerate(array_of_pds_or_single_pd): + # Also add a channel for allowing a thread to pause completely + newChannel = Channel( + child_pd, + backtracer, + a_id = 61, + b_id = i, + pp_a = True, + pd_a_setvar_id="channel_to_backtrace" + ) + sdf.add_channel(newChannel) + backtracer.add_child_pd(child_pd) + pd_elf_paths.append(child_pd.program_image) + + # Create a memory region at the predefined address, as an array + # Extract each of the addresses of the children's show_backtrace function + pd_show_backtrace_addrs = [] + for elf_path in pd_elf_paths: + shell_output = run("set -o pipefail && nm faulter.elf | grep \"show_backtrace\" | cut --delimiter=\" \" -f 1", + capture_output=True, shell=True, text=True) + if shell_output.returncode != 0: + raise Exception(f"Failed to get addresses of 'show_backtrace' for file {elf_path}\n" + + f"stderr: {shell_output.stderr}\n" + + f"stdout: {shell_output.stdout}\n" + + f"exit code: {shell_output.returncode}\n") + show_backtrace_addr = int(shell_output.stdout.strip(), 16); + print(f"'{elf_path}':show_backtrace @ {hex(show_backtrace_addr)}") + pd_show_backtrace_addrs.append(show_backtrace_addr) + + # now write a .data file containing the files spaced out by architectures pointer size. + alignment = getArchitecturePointerAlignment(board.arch) + print(f"Alignment for architecture {board.arch.name}: {alignment}") + frame = b"" + for backtrace_addr in pd_show_backtrace_addrs: + frame += bytes(backtrace_addr.to_bytes(alignment, "little")) + BACKTRACER_FUNCTION_DATA_PATH = "backtrace_functions.data" + with open(BACKTRACER_FUNCTION_DATA_PATH, "wb") as dataFile: + dataFile.write(frame) + func_list_mr = MemoryRegion(sdf, "backtracerFunctions", prefill_path=BACKTRACER_FUNCTION_DATA_PATH) + sdf.add_mr(func_list_mr) + func_list_map = Map(func_list_mr, vaddr=0x20000, perms="r", setvar_vaddr="backtraceFunctions") + backtracer.add_map(func_list_map) + return backtracer + + diff --git a/examples/backtrace_test/backtracer.c b/components/backtracer/backtracer.c similarity index 100% rename from examples/backtrace_test/backtracer.c rename to components/backtracer/backtracer.c diff --git a/components/backtracer/backtracer.mk b/components/backtracer/backtracer.mk new file mode 100644 index 000000000..cbc26249b --- /dev/null +++ b/components/backtracer/backtracer.mk @@ -0,0 +1,63 @@ +BACKTRACER_DIR := $(LIONSOS)/components/backtracer +LLVM := $(LIONSOS)/dep/llvm-project + +CFLAGS_backtracer := \ + -target $(TARGET) \ + -I$(LIONSOS)/include \ + -I$(SDDF)/include \ + -I$(SDDF)/include/microkit \ + -I$(LIBUNWIND)/include \ + -I$(BOARD_DIR)/include \ + -I$(LIONS_LIBC)/include \ + -funwind-tables -O0 \ + -DARCH_aarch64 + +LDFLAGS_backtracer := -L$(BOARD_DIR)/lib -L$(LIONS_LIBC)/lib +LIBS_backtracer := -lmicrokit -Tmicrokit.ld libsddf_util_debug.a -lc + + +LLVM_CMAKE_FLAGS := \ + -DLLVM_ENABLE_RUNTIMES=libunwind\ + -DCMAKE_SYSTEM_NAME=Generic\ + -DCMAKE_C_COMPILER_TARGET=$(TARGET)\ + -DCMAKE_CXX_COMPILER_TARGET=$(TARGET)\ + -DCMAKE_ASM_COMPILER_TARGET=$(TARGET)\ + -DLIBUNWIND_IS_BAREMETAL=ON\ + -DLIBUNWIND_ENABLE_SHARED=OFF\ + -DLIBUNWIND_ENABLE_THREADS=OFF\ + -DLIBUNWIND_USE_COMPILER_RT=ON\ + -DLIBUNWIND_ENABLE_PEDANTIC=OFF\ + -DLIBUNWIND_ENABLE_ASSERTIONS=OFF\ + -DCMAKE_BUILD_TYPE=Debug\ + -DLIBUNWIND_ENABLE_STATIC=ON\ + -DCMAKE_C_COMPILER=$(CC)\ + -DCMAKE_CXX_COMPILER=$(CXX)\ + -DCMAKE_ASM_COMPILER=$(CC)\ + -DCMAKE_C_FLAGS="-I$(LIONS_LIBC)/include"\ + -DCMAKE_CXX_FLAGS="-I$(LIONS_LIBC)/include -fno-exceptions"\ + -DCMAKE_C_COMPILER_WORKS=ON\ + -DCMAKE_CXX_COMPILER_WORKS=ON\ + -DCMAKE_ASM_COMPILER_WORKS=ON + +backtracer: + mkdir -p $@ + +unwind_helpers.o: $(BACKTRACER_DIR)/unwind_helpers.c | $(LIONS_LIBC)/include backtracer + ${CC} ${CFLAGS_backtracer} -c -o $@ $< + +backtracer/backtracer.o: $(BACKTRACER_DIR)/backtracer.c | $(LIONS_LIBC)/include backtracer + ${CC} ${CFLAGS_backtracer} -c -o $@ $< + +backtracer.elf: backtracer/backtracer.o libunwind.a | backtracer + ${LD} ${LDFLAGS_backtracer} -o $@ $^ ${LIBS_backtracer} + +libunwind.a: | $(LIONS_LIBC)/include backtracer + cmake -B $(BUILD_DIR)/libunwind -S $(LLVM)/runtimes \ + $(LLVM_CMAKE_FLAGS) + + cmake --build $(BUILD_DIR)/libunwind + cp $(BUILD_DIR)/libunwind/lib/libunwind.a $@ + +export PYTHONPATH := "$(BACKTRACER_DIR):$$PYTHONPATH:$(PYTHONPATH)" + +LDFLAGS += -L$(BACKTRACER_DIR) diff --git a/examples/backtrace_test/monitor.h b/components/backtracer/monitor.h similarity index 100% rename from examples/backtrace_test/monitor.h rename to components/backtracer/monitor.h diff --git a/examples/backtrace_test/unwind.ld b/components/backtracer/unwind.ld similarity index 100% rename from examples/backtrace_test/unwind.ld rename to components/backtracer/unwind.ld diff --git a/components/backtracer/unwind_helpers.c b/components/backtracer/unwind_helpers.c new file mode 100644 index 000000000..c23cfc8d2 --- /dev/null +++ b/components/backtracer/unwind_helpers.c @@ -0,0 +1,28 @@ +#include +#include +#define UNW_LOCAL_ONLY +#include + +#define INPUT_CAP 1 +static seL4_MessageInfo_t empty_msg = {0}; +uintptr_t channel_to_backtrace = 0; + +void show_backtrace (void) { + sddf_printf("SHOW_BACKTRACE | BEGIN_SHOW_BACKTRACE for '%s'\n", microkit_name); + unw_cursor_t cursor; + unw_context_t uc; + unw_word_t ip, sp; + + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + + seL4_Word depth = 0; + while (unw_step(&cursor) > 0) { + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + sddf_printf("SHOW_BACKTRACE | #%d: ip = %p, sp = %p\n", (int)depth++, (void*) ip, (void*) sp); + } + microkit_dbg_puts("SHOW_BACKTRACE | END_SHOW_BACKTRACE\n"); + microkit_ppcall(channel_to_backtrace, empty_msg); + microkit_dbg_puts("You're not supposed to see this\n"); +} diff --git a/components/backtracer/util.h b/components/backtracer/util.h new file mode 100644 index 000000000..c1423c423 --- /dev/null +++ b/components/backtracer/util.h @@ -0,0 +1,92 @@ +#pragma once +/* + * Copyright 2021, Breakaway Consulting Pty. Ltd. + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#include +#include + +static void putc(uint8_t ch) +{ +#if defined(CONFIG_PRINTING) + seL4_DebugPutChar(ch); +#endif +} + +static void puts(const char *s) +{ + while (*s) { + putc(*s); + s++; + } +} + +static char hexchar(unsigned int v) +{ + return v < 10 ? '0' + v : ('a' - 10) + v; +} + +static void puthex32(uint32_t val) +{ + char buffer[8 + 3]; + buffer[0] = '0'; + buffer[1] = 'x'; + buffer[8 + 3 - 1] = 0; + for (unsigned i = 8 + 1; i > 1; i--) { + buffer[i] = hexchar(val & 0xf); + val >>= 4; + } + puts(buffer); +} + +static void puthex64(uint64_t val) +{ + char buffer[16 + 3]; + buffer[0] = '0'; + buffer[1] = 'x'; + buffer[16 + 3 - 1] = 0; + for (unsigned i = 16 + 1; i > 1; i--) { + buffer[i] = hexchar(val & 0xf); + val >>= 4; + } + puts(buffer); +} + +static void fail(char *s) +{ + puts("FAIL: "); + puts(s); + puts("\n"); + for (;;) {} +} + +static char *sel4_strerror(seL4_Word err) +{ + switch (err) { + case seL4_NoError: + return "seL4_NoError"; + case seL4_InvalidArgument: + return "seL4_InvalidArgument"; + case seL4_InvalidCapability: + return "seL4_InvalidCapability"; + case seL4_IllegalOperation: + return "seL4_IllegalOperation"; + case seL4_RangeError: + return "seL4_RangeError"; + case seL4_AlignmentError: + return "seL4_AlignmentError"; + case seL4_FailedLookup: + return "seL4_FailedLookup"; + case seL4_TruncatedMessage: + return "seL4_TruncatedMessage"; + case seL4_DeleteFirst: + return "seL4_DeleteFirst"; + case seL4_RevokeFirst: + return "seL4_RevokeFirst"; + case seL4_NotEnoughMemory: + return "seL4_NotEnoughMemory"; + } + + return ""; +} diff --git a/examples/backtrace_test/Makefile b/examples/backtrace_test/Makefile index eea066f56..9ba2138af 100644 --- a/examples/backtrace_test/Makefile +++ b/examples/backtrace_test/Makefile @@ -10,12 +10,12 @@ endif override MICROKIT_SDK:=$(abspath ${MICROKIT_SDK}) export LIONSOS ?= $(abspath ../..) -export POSIX_TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +export BACKTRACE_TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) export MICROKIT_CONFIG ?= debug export BUILD_DIR ?= $(abspath build) export MICROKIT_BOARD ?= qemu_virt_aarch64 -IMAGE_FILE := $(BUILD_DIR)/posix_test.img +IMAGE_FILE := $(BUILD_DIR)/backtrace_test.img REPORT_FILE := $(BUILD_DIR)/report.txt all: ${IMAGE_FILE} @@ -23,16 +23,16 @@ all: ${IMAGE_FILE} qemu qemu-gdb ${IMAGE_FILE} ${REPORT_FILE} clean clobber libunwind.a: ${BUILD_DIR}/Makefile FORCE ${MAKE} -C ${BUILD_DIR} MICROKIT_SDK=${MICROKIT_SDK} $(notdir $@) -${BUILD_DIR}/Makefile: posix_test.mk Makefile +${BUILD_DIR}/Makefile: backtrace_test.mk Makefile mkdir -p ${BUILD_DIR} - cp posix_test.mk $@ + cp backtrace_test.mk $@ echo "export LIONSOS ?= ${LIONSOS}" > $@ - echo "export POSIX_TEST_DIR ?= ${POSIX_TEST_DIR}" >> $@ + echo "export BACKTRACE_TEST_DIR ?= ${BACKTRACE_TEST_DIR}" >> $@ echo "export BUILD_DIR := ${BUILD_DIR}" >> $@ echo "export MICROKIT_BOARD ?= ${MICROKIT_BOARD}" >> $@ echo "export MICROKIT_SDK ?= ${MICROKIT_SDK}" >> $@ echo "export MICROKIT_CONFIG ?= ${MICROKIT_CONFIG}" >> $@ - cat posix_test.mk >> $@ + cat backtrace_test.mk >> $@ submodules: git submodule update --init $(LIONSOS)/dep/sddf diff --git a/examples/backtrace_test/posix_test.mk b/examples/backtrace_test/backtrace_test.mk similarity index 57% rename from examples/backtrace_test/posix_test.mk rename to examples/backtrace_test/backtrace_test.mk index b00676da4..7533c9449 100644 --- a/examples/backtrace_test/posix_test.mk +++ b/examples/backtrace_test/backtrace_test.mk @@ -10,26 +10,25 @@ SUPPORTED_BOARDS := \ maaxboard IMAGES := \ - faulter.elf \ - backtracer.elf + faulter.elf TOOLCHAIN ?= $(CC) MICROKIT_TOOL ?= $(MICROKIT_SDK)/bin/microkit BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG) SDDF := $(LIONSOS)/dep/sddf LWIP := $(SDDF)/network/ipstacks/lwip/src -LIBMICROKITCO_PATH := $(LIONSOS)/dep/libmicrokitco LLVM := $(LIONSOS)/dep/llvm-project/ LIBUNWIND := $(LLVM)/libunwind -SYSTEM_FILE := posix_test.system -IMAGE_FILE := posix_test.img +SYSTEM_FILE := backtrace_test.system +IMAGE_FILE := backtrace_test.img REPORT_FILE := report.txt +BACKTRACER := $(LIONSOS)/components/backtracer all: ${IMAGE_FILE} include ${SDDF}/tools/make/board/common.mk -METAPROGRAM := $(POSIX_TEST_DIR)/meta.py +METAPROGRAM := $(BACKTRACE_TEST_DIR)/meta.py FAT := $(LIONSOS)/components/fs/fat @@ -41,7 +40,6 @@ CFLAGS += \ -I$(LIONSOS)/include \ -I$(SDDF)/include \ -I$(SDDF)/include/microkit \ - -I$(LIBMICROKITCO_PATH) \ -I$(LWIP)/include \ -I$(LIBUNWIND)/include \ -DMAX_FDS=8 \ @@ -50,8 +48,8 @@ CFLAGS += \ include $(LIONSOS)/lib/libc/libc.mk -LDFLAGS := --eh-frame-hdr -L$(BOARD_DIR)/lib -L$(LIONS_LIBC)/lib -L$(POSIX_TEST_DIR)/build -LIBS := --start-group -T$(POSIX_TEST_DIR)/unwind.ld -lmicrokit -Tmicrokit.ld libsddf_util_debug.a -lc -lunwind --end-group +LDFLAGS := --eh-frame-hdr -L$(BOARD_DIR)/lib -L$(LIONS_LIBC)/lib -L$(BACKTRACE_TEST_DIR)/build +LIBS := --start-group -Tunwind.ld -lmicrokit -Tmicrokit.ld libsddf_util_debug.a -lc -lunwind --end-group BLK_DRIVER := $(SDDF)/drivers/blk/${BLK_DRIV_DIR} BLK_COMPONENTS := $(SDDF)/blk/components @@ -64,7 +62,7 @@ include ${SDDF}/drivers/network/${NET_DRIV_DIR}/eth_driver.mk include ${SDDF}/serial/components/serial_components.mk include ${SDDF}/network/components/network_components.mk -LIB_SDDF_LWIP_CFLAGS := -I${POSIX_TEST_DIR}/lwip_include +LIB_SDDF_LWIP_CFLAGS := -I${BACKTRACE_TEST_DIR}/lwip_include include ${SDDF}/network/lib_sddf_lwip/lib_sddf_lwip.mk include ${SDDF}/libco/libco.mk @@ -75,23 +73,11 @@ FAT_LIBC_LIB := $(LIONS_LIBC)/lib/libc.a FAT_LIBC_INCLUDE := $(LIONS_LIBC)/include include $(LIONSOS)/components/fs/fat/fat.mk -LIBMICROKITCO_CFLAGS_posix_test := -I$(POSIX_TEST_DIR) -LIBMICROKITCO_LIBC_INCLUDE := $(LIONS_LIBC)/include -include $(LIBMICROKITCO_PATH)/libmicrokitco.mk +include $(BACKTRACER)/backtracer.mk ${IMAGES}: $(LIONS_LIBC)/lib/libc.a libsddf_util_debug.a -unwind_helpers.o: $(POSIX_TEST_DIR)/unwind_helpers.c | $(LIONS_LIBC)/include - ${CC} ${CFLAGS} -c -o $@ $< - -# Seems a bit fragile... -backtracer.o: $(POSIX_TEST_DIR)/backtracer.c faulter.elf | $(LIONS_LIBC)/include - ${CC} ${CFLAGS} -c -o $@ $< - -backtracer.elf: backtracer.o libunwind.a unwind_helpers.o - ${LD} ${LDFLAGS} -o $@ $^ ${LIBS} - -faulter.o: $(POSIX_TEST_DIR)/faulter.c | $(LIONS_LIBC)/include +faulter.o: $(BACKTRACE_TEST_DIR)/faulter.c | $(LIONS_LIBC)/include ${CC} ${CFLAGS} -c -o $@ $< faulter.elf: faulter.o libunwind.a unwind_helpers.o @@ -99,8 +85,8 @@ faulter.elf: faulter.o libunwind.a unwind_helpers.o FORCE: -$(SYSTEM_FILE): $(METAPROGRAM) $(IMAGES) $(DTB) - PYTHONPATH=${SDDF}/tools/meta:$$PYTHONPATH $(PYTHON) $(METAPROGRAM) --sddf $(SDDF) --board $(MICROKIT_BOARD) --output . --sdf $(SYSTEM_FILE) +$(SYSTEM_FILE): $(METAPROGRAM) $(IMAGES) $(DTB) backtracer.elf + PYTHONPATH="${SDDF}/tools/meta:$$PYTHONPATH:$(PYTHONPATH)" $(PYTHON) $(METAPROGRAM) --sddf $(SDDF) --board $(MICROKIT_BOARD) --output . --sdf $(SYSTEM_FILE) # Add the unwind table to the memory region specified. $(IMAGE_FILE) $(REPORT_FILE): $(IMAGES) $(SYSTEM_FILE) @@ -124,29 +110,29 @@ qemu: ${IMAGE_FILE} qemu_disk -netdev user,id=netdev0,hostfwd=tcp::5560-10.0.2.15:5560,hostfwd=tcp::5561-10.0.2.15:5561 \ # -S -s -libunwind.a: | $(LIONS_LIBC)/include - cmake -B $(BUILD_DIR)/libunwind -S $(LLVM)/runtimes \ - -DLLVM_ENABLE_RUNTIMES=libunwind\ - -DCMAKE_SYSTEM_NAME=Generic\ - -DCMAKE_C_COMPILER_TARGET=${TARGET}\ - -DCMAKE_CXX_COMPILER_TARGET=${TARGET}\ - -DCMAKE_ASM_COMPILER_TARGET=${TARGET}\ - -DLIBUNWIND_IS_BAREMETAL=ON\ - -DLIBUNWIND_ENABLE_SHARED=OFF\ - -DLIBUNWIND_ENABLE_THREADS=OFF\ - -DLIBUNWIND_USE_COMPILER_RT=ON\ - -DLIBUNWIND_ENABLE_PEDANTIC=OFF\ - -DLIBUNWIND_ENABLE_ASSERTIONS=OFF\ - -DCMAKE_BUILD_TYPE=Debug\ - -DLIBUNWIND_ENABLE_STATIC=ON\ - -DCMAKE_C_COMPILER=$(CC)\ - -DCMAKE_CXX_COMPILER=$(CXX)\ - -DCMAKE_ASM_COMPILER=$(CC)\ - -DCMAKE_C_FLAGS="-I$(LIONS_LIBC)/include"\ - -DCMAKE_CXX_FLAGS="-I$(LIONS_LIBC)/include -fno-exceptions"\ - -DCMAKE_C_COMPILER_WORKS=ON\ - -DCMAKE_CXX_COMPILER_WORKS=ON\ - -DCMAKE_ASM_COMPILER_WORKS=ON - - cmake --build $(BUILD_DIR)/libunwind - ln -sr $(BUILD_DIR)/libunwind/lib/libunwind.a $@ +# libunwind.a: | $(LIONS_LIBC)/include +# cmake -B $(BUILD_DIR)/libunwind -S $(LLVM)/runtimes \ +# -DLLVM_ENABLE_RUNTIMES=libunwind\ +# -DCMAKE_SYSTEM_NAME=Generic\ +# -DCMAKE_C_COMPILER_TARGET=${TARGET}\ +# -DCMAKE_CXX_COMPILER_TARGET=${TARGET}\ +# -DCMAKE_ASM_COMPILER_TARGET=${TARGET}\ +# -DLIBUNWIND_IS_BAREMETAL=ON\ +# -DLIBUNWIND_ENABLE_SHARED=OFF\ +# -DLIBUNWIND_ENABLE_THREADS=OFF\ +# -DLIBUNWIND_USE_COMPILER_RT=ON\ +# -DLIBUNWIND_ENABLE_PEDANTIC=OFF\ +# -DLIBUNWIND_ENABLE_ASSERTIONS=OFF\ +# -DCMAKE_BUILD_TYPE=Debug\ +# -DLIBUNWIND_ENABLE_STATIC=ON\ +# -DCMAKE_C_COMPILER=$(CC)\ +# -DCMAKE_CXX_COMPILER=$(CXX)\ +# -DCMAKE_ASM_COMPILER=$(CC)\ +# -DCMAKE_C_FLAGS="-I$(LIONS_LIBC)/include"\ +# -DCMAKE_CXX_FLAGS="-I$(LIONS_LIBC)/include -fno-exceptions"\ +# -DCMAKE_C_COMPILER_WORKS=ON\ +# -DCMAKE_CXX_COMPILER_WORKS=ON\ +# -DCMAKE_ASM_COMPILER_WORKS=ON + +# cmake --build $(BUILD_DIR)/libunwind +# ln -sr $(BUILD_DIR)/libunwind/lib/libunwind.a $@ diff --git a/examples/backtrace_test/default.nix b/examples/backtrace_test/default.nix deleted file mode 100644 index 6e9d76493..000000000 --- a/examples/backtrace_test/default.nix +++ /dev/null @@ -1,76 +0,0 @@ -let - nixpkgs = builtins.fetchTarball { - name = "source"; - url = "https://github.com/nixos/nixpkgs/archive/da044451c6a70518db5b730fe277b70f494188f1.tar.gz"; - sha256 = "sha256:11z08fa0s7r9hryllhjj7kyn4z6bsixlqz7iwgsmf1k4p3hcl692"; - }; - -in - -{ pkgs ? (import nixpkgs { - overlays = [ - (self: super: { - python3 = super.python3.override { - packageOverrides = _: pySuper: { - pyfdt = pySuper.buildPythonPackage rec { - name = "pyfdt"; - src = pySuper.fetchPypi { - pname = name; - version = "0.3"; - sha256 = "sha256-YWAcIAX/OUolpshMbaIIi7+IgygDhADSfk7rGwS59PA="; - }; - }; - }; - }; - }) - ]; - }) -}: - -pkgs.mkShellNoCC { - name = "time-protection-sel4"; - - nativeBuildInputs = with pkgs; [ - qemu - cacert - cmake - cpio - dtc - gdb - ubootTools - # (pkgsCross.riscv64-embedded.stdenv.cc.cc.override { enableMultilib = true; }) - # pkgsCross.riscv64-embedded.stdenv.cc.cc - # pkgsCross.riscv64-embedded.stdenv.cc.bintools.bintools - pkgsCross.aarch64-embedded.stdenv.cc.cc - pkgsCross.aarch64-embedded.stdenv.cc.bintools.bintools - # pkgsCross.arm-embedded.stdenv.cc.cc - # pkgsCross.arm-embedded.stdenv.cc.bintools.bintools - libxml2 - ninja - # camkes. not this doesn't like nix so needs gmp installed - pkgs.stack - # cheshire - pkgs.gptfdisk - pkgs.openfpgaloader - - (pkgs.stdenv.mkDerivation rec { - pname = "bender"; - version = "v0.29.0"; - - src = pkgs.fetchzip { - url = "https://github.com/pulp-platform/bender/releases/download/v0.29.0/bender-0.29.0-x86_64-linux-gnu.tar.gz"; - hash = "sha256-ssVqe1d8a3XtFDMAZJHomY34IAu/tGFuvLxdaTh/R2M="; - }; - - installPhase = '' - mkdir -p $out/bin - cp $src/bender $out/bin/ - ''; - }) - - # openjdk # leakiest - ]; - - env.CMAKE_EXPORT_COMPILE_COMMANDS = "1"; -} - From f86abeb09fc92b8428544830d5d475307424c21e Mon Sep 17 00:00:00 2001 From: 0aids Date: Mon, 15 Jun 2026 16:42:51 +1000 Subject: [PATCH 11/27] fix: backtraces not showing and cleaned up makefiles Signed-off-by: 0aids --- components/backtracer/backtracer.c | 1 + components/backtracer/backtracer.mk | 9 ++-- components/backtracer/monitor.h | 33 +++++++------- components/backtracer/unwind.ld | 12 ------ examples/backtrace_test/backtrace_test.mk | 52 +++-------------------- 5 files changed, 27 insertions(+), 80 deletions(-) diff --git a/components/backtracer/backtracer.c b/components/backtracer/backtracer.c index 8465c9227..2f3b758cd 100644 --- a/components/backtracer/backtracer.c +++ b/components/backtracer/backtracer.c @@ -17,6 +17,7 @@ static void callConvention_prologue(seL4_UserContext* ctxt, uintptr_t funcAddr) ctxt->x30 = ctxt->pc; // Set the PC to the next function ctxt->pc = funcAddr; + LOG("Old PC: %p, New PC: %p\n", (void*)ctxt->x30, (void*)funcAddr); } #elif defined(__riscv__) #error "Unimplemented backtracer for riscv" diff --git a/components/backtracer/backtracer.mk b/components/backtracer/backtracer.mk index cbc26249b..2cdb1c779 100644 --- a/components/backtracer/backtracer.mk +++ b/components/backtracer/backtracer.mk @@ -8,14 +8,11 @@ CFLAGS_backtracer := \ -I$(SDDF)/include/microkit \ -I$(LIBUNWIND)/include \ -I$(BOARD_DIR)/include \ - -I$(LIONS_LIBC)/include \ - -funwind-tables -O0 \ - -DARCH_aarch64 + -I$(LIONS_LIBC)/include -O0 -ggdb -funwind-tables LDFLAGS_backtracer := -L$(BOARD_DIR)/lib -L$(LIONS_LIBC)/lib LIBS_backtracer := -lmicrokit -Tmicrokit.ld libsddf_util_debug.a -lc - LLVM_CMAKE_FLAGS := \ -DLLVM_ENABLE_RUNTIMES=libunwind\ -DCMAKE_SYSTEM_NAME=Generic\ @@ -58,6 +55,10 @@ libunwind.a: | $(LIONS_LIBC)/include backtracer cmake --build $(BUILD_DIR)/libunwind cp $(BUILD_DIR)/libunwind/lib/libunwind.a $@ +clean:: + ${RM} -rf backtracer backtracer.elf unwind_helpers.o libunwind.a libunwind export PYTHONPATH := "$(BACKTRACER_DIR):$$PYTHONPATH:$(PYTHONPATH)" LDFLAGS += -L$(BACKTRACER_DIR) + +# TODO: add dep files. diff --git a/components/backtracer/monitor.h b/components/backtracer/monitor.h index 07aec3238..3ee3c985d 100644 --- a/components/backtracer/monitor.h +++ b/components/backtracer/monitor.h @@ -16,7 +16,6 @@ #include #include #include - #include "util.h" #define MAX_VMS 64 @@ -40,14 +39,14 @@ seL4_Word vm_names_len; seL4_Word pd_stack_bottom_addrs[MAX_PDS]; /* Sanity check that the architecture specific macro have been set. */ -#if defined(ARCH_aarch64) -#elif defined(ARCH_x86_64) -#elif defined(ARCH_riscv64) +#if defined(__aarch64__) +#elif defined(__x86_64__) +#elif defined(__riscv64__) #else -#error "No architecture flag was defined, double check your CC flags" +#error "Unknown or unsupported architecture for backtracing" #endif -#ifdef ARCH_riscv64 +#ifdef __riscv64__ /* * Convert the fault status register given by the kernel into a string describing * what fault happened. The FSR is the 'scause' register. @@ -91,7 +90,7 @@ static char *riscv_fsr_to_string(seL4_Word fsr) } #endif -#ifdef ARCH_aarch64 +#ifdef __aarch64__ static char *ec_to_string(uintptr_t ec) { switch (ec) { @@ -225,7 +224,7 @@ static char *data_abort_dfsc_to_string(uintptr_t dfsc) } #endif -#ifdef ARCH_x86_64 +#ifdef __x86_64__ static char *page_fault_to_string(seL4_Word fsr) { // https://wiki.osdev.org/Exceptions#Page_Fault @@ -348,7 +347,7 @@ static char *usban_code_to_string(seL4_Word code) static void print_tcb_registers(seL4_UserContext *regs) { -#if defined(ARCH_riscv64) +#if defined(__riscv64__) puts("BACKTRACER | Registers: \n"); puts("BACKTRACER | pc : "); puthex64(regs->pc); @@ -437,7 +436,7 @@ static void print_tcb_registers(seL4_UserContext *regs) puts("BACKTRACER | tp : "); puthex64(regs->tp); puts("\n"); -#elif defined(ARCH_aarch64) +#elif defined(__aarch64__) puts("BACKTRACER | Registers: \n"); puts("BACKTRACER | pc : "); puthex64(regs->pc); @@ -547,7 +546,7 @@ static void print_tcb_registers(seL4_UserContext *regs) puts("BACKTRACER | tpidrro_el0 : "); puthex64(regs->tpidrro_el0); puts("\n"); -#elif ARCH_x86_64 +#elif defined(__x86_64__) puts("BACKTRACER | Registers: \n"); puts("BACKTRACER | rip : "); puthex64(regs->rip); @@ -612,7 +611,7 @@ static void print_tcb_registers(seL4_UserContext *regs) #endif } -#ifdef ARCH_riscv64 +#ifdef __riscv64__ static void riscv_print_vm_fault() { seL4_Word ip = seL4_GetMR(seL4_VMFault_IP); @@ -634,7 +633,7 @@ static void riscv_print_vm_fault() } #endif -#if ARCH_x86_64 +#ifdef __x86_64__ static void x86_64_print_vm_fault() { seL4_Word ip = seL4_GetMR(seL4_VMFault_IP); @@ -657,7 +656,7 @@ static void x86_64_print_vm_fault() } #endif -#ifdef ARCH_aarch64 +#ifdef __aarch64__ static void aarch64_print_vm_fault() { seL4_Word ip = seL4_GetMR(seL4_VMFault_IP); @@ -810,11 +809,11 @@ static void print_fault_error(microkit_child child, microkit_msginfo msginfo) break; } case seL4_Fault_VMFault: { -#if defined(ARCH_aarch64) +#if defined(__aarch64__) aarch64_print_vm_fault(); -#elif defined(ARCH_riscv64) +#elif defined(__riscv64__) riscv_print_vm_fault(); -#elif defined(ARCH_x86_64) +#elif defined(__x86_64__) x86_64_print_vm_fault(); #else #error "Unknown architecture to print a VM fault for" diff --git a/components/backtracer/unwind.ld b/components/backtracer/unwind.ld index 7a25425a9..d32ae1822 100644 --- a/components/backtracer/unwind.ld +++ b/components/backtracer/unwind.ld @@ -25,16 +25,4 @@ SECTIONS __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; } - -/* OLD - .eh_frame : - { - PROVIDE (__eh_frame_start = .); - KEEP (*(.eh_frame)) *(.eh_frame.*) - PROVIDE (__eh_frame_end = .); - PROVIDE (__eh_frame_hdr_start = .); - KEEP (*(.eh_frame_hdr)) *(.eh_frame_hdr.*) - PROVIDE (__eh_frame_hdr_end = .); - } -*/ INSERT AFTER .text; diff --git a/examples/backtrace_test/backtrace_test.mk b/examples/backtrace_test/backtrace_test.mk index 7533c9449..0f55b0fac 100644 --- a/examples/backtrace_test/backtrace_test.mk +++ b/examples/backtrace_test/backtrace_test.mk @@ -16,7 +16,6 @@ TOOLCHAIN ?= $(CC) MICROKIT_TOOL ?= $(MICROKIT_SDK)/bin/microkit BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG) SDDF := $(LIONSOS)/dep/sddf -LWIP := $(SDDF)/network/ipstacks/lwip/src LLVM := $(LIONSOS)/dep/llvm-project/ LIBUNWIND := $(LLVM)/libunwind SYSTEM_FILE := backtrace_test.system @@ -43,31 +42,15 @@ CFLAGS += \ -I$(LWIP)/include \ -I$(LIBUNWIND)/include \ -DMAX_FDS=8 \ - -funwind-tables -O0 \ - -DARCH_aarch64 + -funwind-tables -O0 -ggdb include $(LIONSOS)/lib/libc/libc.mk LDFLAGS := --eh-frame-hdr -L$(BOARD_DIR)/lib -L$(LIONS_LIBC)/lib -L$(BACKTRACE_TEST_DIR)/build LIBS := --start-group -Tunwind.ld -lmicrokit -Tmicrokit.ld libsddf_util_debug.a -lc -lunwind --end-group -BLK_DRIVER := $(SDDF)/drivers/blk/${BLK_DRIV_DIR} -BLK_COMPONENTS := $(SDDF)/blk/components - SDDF_LIBC_INCLUDE := $(LIONS_LIBC)/include include ${SDDF}/util/util.mk -include ${SDDF}/drivers/timer/${TIMER_DRIV_DIR}/timer_driver.mk -include ${SDDF}/drivers/serial/${UART_DRIV_DIR}/serial_driver.mk -include ${SDDF}/drivers/network/${NET_DRIV_DIR}/eth_driver.mk -include ${SDDF}/serial/components/serial_components.mk -include ${SDDF}/network/components/network_components.mk - -LIB_SDDF_LWIP_CFLAGS := -I${BACKTRACE_TEST_DIR}/lwip_include -include ${SDDF}/network/lib_sddf_lwip/lib_sddf_lwip.mk - -include ${SDDF}/libco/libco.mk -include ${BLK_DRIVER}/blk_driver.mk -include ${BLK_COMPONENTS}/blk_components.mk FAT_LIBC_LIB := $(LIONS_LIBC)/lib/libc.a FAT_LIBC_INCLUDE := $(LIONS_LIBC)/include @@ -107,32 +90,7 @@ qemu: ${IMAGE_FILE} qemu_disk -drive file=qemu_disk,if=none,format=raw,id=hd \ -device virtio-blk-device,drive=hd,bus=virtio-mmio-bus.1 \ -device virtio-net-device,netdev=netdev0,bus=virtio-mmio-bus.0 \ - -netdev user,id=netdev0,hostfwd=tcp::5560-10.0.2.15:5560,hostfwd=tcp::5561-10.0.2.15:5561 \ -# -S -s - -# libunwind.a: | $(LIONS_LIBC)/include -# cmake -B $(BUILD_DIR)/libunwind -S $(LLVM)/runtimes \ -# -DLLVM_ENABLE_RUNTIMES=libunwind\ -# -DCMAKE_SYSTEM_NAME=Generic\ -# -DCMAKE_C_COMPILER_TARGET=${TARGET}\ -# -DCMAKE_CXX_COMPILER_TARGET=${TARGET}\ -# -DCMAKE_ASM_COMPILER_TARGET=${TARGET}\ -# -DLIBUNWIND_IS_BAREMETAL=ON\ -# -DLIBUNWIND_ENABLE_SHARED=OFF\ -# -DLIBUNWIND_ENABLE_THREADS=OFF\ -# -DLIBUNWIND_USE_COMPILER_RT=ON\ -# -DLIBUNWIND_ENABLE_PEDANTIC=OFF\ -# -DLIBUNWIND_ENABLE_ASSERTIONS=OFF\ -# -DCMAKE_BUILD_TYPE=Debug\ -# -DLIBUNWIND_ENABLE_STATIC=ON\ -# -DCMAKE_C_COMPILER=$(CC)\ -# -DCMAKE_CXX_COMPILER=$(CXX)\ -# -DCMAKE_ASM_COMPILER=$(CC)\ -# -DCMAKE_C_FLAGS="-I$(LIONS_LIBC)/include"\ -# -DCMAKE_CXX_FLAGS="-I$(LIONS_LIBC)/include -fno-exceptions"\ -# -DCMAKE_C_COMPILER_WORKS=ON\ -# -DCMAKE_CXX_COMPILER_WORKS=ON\ -# -DCMAKE_ASM_COMPILER_WORKS=ON - -# cmake --build $(BUILD_DIR)/libunwind -# ln -sr $(BUILD_DIR)/libunwind/lib/libunwind.a $@ + -netdev user,id=netdev0,hostfwd=tcp::5560-10.0.2.15:5560,hostfwd=tcp::5561-10.0.2.15:5561 + +clean:: + ${RM} -rf ${IMAGES} faulter.o faulter.elf From 02c6ffb8dcbdd35c4ca848fff274f05b1c63c894 Mon Sep 17 00:00:00 2001 From: 0aids Date: Mon, 15 Jun 2026 16:44:37 +1000 Subject: [PATCH 12/27] chore: removed unnecessary files from backtrace_test example Signed-off-by: 0aids --- examples/backtrace_test/unwind_helpers.c | 28 -------- examples/backtrace_test/util.h | 92 ------------------------ 2 files changed, 120 deletions(-) delete mode 100644 examples/backtrace_test/unwind_helpers.c delete mode 100644 examples/backtrace_test/util.h diff --git a/examples/backtrace_test/unwind_helpers.c b/examples/backtrace_test/unwind_helpers.c deleted file mode 100644 index c23cfc8d2..000000000 --- a/examples/backtrace_test/unwind_helpers.c +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include -#define UNW_LOCAL_ONLY -#include - -#define INPUT_CAP 1 -static seL4_MessageInfo_t empty_msg = {0}; -uintptr_t channel_to_backtrace = 0; - -void show_backtrace (void) { - sddf_printf("SHOW_BACKTRACE | BEGIN_SHOW_BACKTRACE for '%s'\n", microkit_name); - unw_cursor_t cursor; - unw_context_t uc; - unw_word_t ip, sp; - - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); - - seL4_Word depth = 0; - while (unw_step(&cursor) > 0) { - unw_get_reg(&cursor, UNW_REG_IP, &ip); - unw_get_reg(&cursor, UNW_REG_SP, &sp); - sddf_printf("SHOW_BACKTRACE | #%d: ip = %p, sp = %p\n", (int)depth++, (void*) ip, (void*) sp); - } - microkit_dbg_puts("SHOW_BACKTRACE | END_SHOW_BACKTRACE\n"); - microkit_ppcall(channel_to_backtrace, empty_msg); - microkit_dbg_puts("You're not supposed to see this\n"); -} diff --git a/examples/backtrace_test/util.h b/examples/backtrace_test/util.h deleted file mode 100644 index c1423c423..000000000 --- a/examples/backtrace_test/util.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once -/* - * Copyright 2021, Breakaway Consulting Pty. Ltd. - * - * SPDX-License-Identifier: BSD-2-Clause - */ -#include -#include - -static void putc(uint8_t ch) -{ -#if defined(CONFIG_PRINTING) - seL4_DebugPutChar(ch); -#endif -} - -static void puts(const char *s) -{ - while (*s) { - putc(*s); - s++; - } -} - -static char hexchar(unsigned int v) -{ - return v < 10 ? '0' + v : ('a' - 10) + v; -} - -static void puthex32(uint32_t val) -{ - char buffer[8 + 3]; - buffer[0] = '0'; - buffer[1] = 'x'; - buffer[8 + 3 - 1] = 0; - for (unsigned i = 8 + 1; i > 1; i--) { - buffer[i] = hexchar(val & 0xf); - val >>= 4; - } - puts(buffer); -} - -static void puthex64(uint64_t val) -{ - char buffer[16 + 3]; - buffer[0] = '0'; - buffer[1] = 'x'; - buffer[16 + 3 - 1] = 0; - for (unsigned i = 16 + 1; i > 1; i--) { - buffer[i] = hexchar(val & 0xf); - val >>= 4; - } - puts(buffer); -} - -static void fail(char *s) -{ - puts("FAIL: "); - puts(s); - puts("\n"); - for (;;) {} -} - -static char *sel4_strerror(seL4_Word err) -{ - switch (err) { - case seL4_NoError: - return "seL4_NoError"; - case seL4_InvalidArgument: - return "seL4_InvalidArgument"; - case seL4_InvalidCapability: - return "seL4_InvalidCapability"; - case seL4_IllegalOperation: - return "seL4_IllegalOperation"; - case seL4_RangeError: - return "seL4_RangeError"; - case seL4_AlignmentError: - return "seL4_AlignmentError"; - case seL4_FailedLookup: - return "seL4_FailedLookup"; - case seL4_TruncatedMessage: - return "seL4_TruncatedMessage"; - case seL4_DeleteFirst: - return "seL4_DeleteFirst"; - case seL4_RevokeFirst: - return "seL4_RevokeFirst"; - case seL4_NotEnoughMemory: - return "seL4_NotEnoughMemory"; - } - - return ""; -} From c64d3e0d251448aec94ade06bc08c2f75f8f9d26 Mon Sep 17 00:00:00 2001 From: 0aids Date: Mon, 15 Jun 2026 16:59:11 +1000 Subject: [PATCH 13/27] feat: separate out backtracer related python functions into component Signed-off-by: 0aids --- components/backtracer/LionsOS_Backtracer.py | 8 +-- examples/backtrace_test/meta.py | 69 ++------------------- 2 files changed, 7 insertions(+), 70 deletions(-) diff --git a/components/backtracer/LionsOS_Backtracer.py b/components/backtracer/LionsOS_Backtracer.py index 6f877009a..69ed452b9 100644 --- a/components/backtracer/LionsOS_Backtracer.py +++ b/components/backtracer/LionsOS_Backtracer.py @@ -27,7 +27,7 @@ def get_architecture_pointer_alignment(arch: SystemDescription.Arch): case _: raise Exception(f"Alignment of architecture {arch} is unknown.") -def enable_backtracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr = 0xb00000): +def enable_backtracing(sdf, arch, array_of_pds_or_single_pd, show_backtrace_func_list_addr = 0xb00000): """ Wrap an array or single pd as children into a backtracer parent, capable of catching faults and then forcing prints of the backtrace @@ -68,8 +68,8 @@ def enable_backtracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr pd_show_backtrace_addrs.append(show_backtrace_addr) # now write a .data file containing the files spaced out by architectures pointer size. - alignment = getArchitecturePointerAlignment(board.arch) - print(f"Alignment for architecture {board.arch.name}: {alignment}") + alignment = get_architecture_pointer_alignment(arch) + print(f"Alignment for architecture {arch.name}: {alignment}") frame = b"" for backtrace_addr in pd_show_backtrace_addrs: frame += bytes(backtrace_addr.to_bytes(alignment, "little")) @@ -81,5 +81,3 @@ def enable_backtracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr func_list_map = Map(func_list_mr, vaddr=0x20000, perms="r", setvar_vaddr="backtraceFunctions") backtracer.add_map(func_list_map) return backtracer - - diff --git a/examples/backtrace_test/meta.py b/examples/backtrace_test/meta.py index 594209c18..c59b85feb 100644 --- a/examples/backtrace_test/meta.py +++ b/examples/backtrace_test/meta.py @@ -8,85 +8,24 @@ from board import BOARDS from subprocess import run from copy import deepcopy +import LionsOS_Backtracer # assert version("sdfgen").split(".")[1] == "28", "Unexpected sdfgen version" ProtectionDomain = SystemDescription.ProtectionDomain -ProtectionDomain.PRIORITY_MAX = 254 MemoryRegion = SystemDescription.MemoryRegion Map = SystemDescription.Map Channel = SystemDescription.Channel +board = 0 +sdf = 0 -def getArchitecturePointerAlignment(arch: SystemDescription.Arch): - match arch: - case SystemDescription.Arch.AARCH64 | SystemDescription.Arch.RISCV64 | SystemDescription.Arch.X86_64: - return 8 - case SystemDescription.Arch.AARCH32 | SystemDescription.Arch.RISCV32 | SystemDescription.Arch.X86: - return 4 - case _: - raise Exception(f"Archicture '{arch}' is not supported") - -def enableBacktracing(array_of_pds_or_single_pd, show_backtrace_func_list_addr = 0xb00000): - """ - Wrap an array or single pd as children into a backtracer parent, - capable of catching faults and then forcing prints of the backtrace - Remember to compile each of the children with "backtrace.o" - """ - backtracer = ProtectionDomain("backtracer", "backtracer.elf", priority=ProtectionDomain.PRIORITY_MAX, stack_size=0x10000); - pd_elf_paths = []; - if not isinstance(array_of_pds_or_single_pd, list): - array_of_pds_or_single_pd = [array_of_pds_or_single_pd] - - for i, child_pd in enumerate(array_of_pds_or_single_pd): - # Also add a channel for allowing a thread to pause completely - newChannel = Channel( - child_pd, - backtracer, - a_id = 61, - b_id = i, - pp_a = True, - pd_a_setvar_id="channel_to_backtrace" - ) - sdf.add_channel(newChannel) - backtracer.add_child_pd(child_pd) - pd_elf_paths.append(child_pd.program_image) - - # Create a memory region at the predefined address, as an array - # Extract each of the addresses of the children's show_backtrace function - pd_show_backtrace_addrs = [] - for elf_path in pd_elf_paths: - shell_output = run("set -o pipefail && nm faulter.elf | grep \"show_backtrace\" | cut --delimiter=\" \" -f 1", - capture_output=True, shell=True, text=True) - if shell_output.returncode != 0: - raise Exception(f"Failed to get addresses of 'show_backtrace' for file {elf_path}\n" + - f"stderr: {shell_output.stderr}\n" + - f"stdout: {shell_output.stdout}\n" + - f"exit code: {shell_output.returncode}\n") - show_backtrace_addr = int(shell_output.stdout.strip(), 16); - print(f"'{elf_path}':show_backtrace @ {hex(show_backtrace_addr)}") - pd_show_backtrace_addrs.append(show_backtrace_addr) - - # now write a .data file containing the files spaced out by architectures pointer size. - alignment = getArchitecturePointerAlignment(board.arch) - print(f"Alignment for architecture {board.arch.name}: {alignment}") - frame = b"" - for backtrace_addr in pd_show_backtrace_addrs: - frame += bytes(backtrace_addr.to_bytes(alignment, "little")) - BACKTRACER_FUNCTION_DATA_PATH = "backtrace_functions.data" - with open(BACKTRACER_FUNCTION_DATA_PATH, "wb") as dataFile: - dataFile.write(frame) - func_list_mr = MemoryRegion(sdf, "backtracerFunctions", prefill_path=BACKTRACER_FUNCTION_DATA_PATH) - sdf.add_mr(func_list_mr) - func_list_map = Map(func_list_mr, vaddr=0x20000, perms="r", setvar_vaddr="backtraceFunctions") - backtracer.add_map(func_list_map) - return backtracer def generate(sdf_path: str, output_dir: str): domains = [ ProtectionDomain(f"faulter{i}", "faulter.elf", priority=i, stack_size=0x100000) for i in range(5) ] - backtracer = enableBacktracing(domains) + backtracer = LionsOS_Backtracer.enable_backtracing(sdf, board.arch, domains) sdf.add_pd(backtracer) with open(f"{output_dir}/{sdf_path}", "w+") as f: From ef889b4dab54c3daa65ceda19897688b74f2944c Mon Sep 17 00:00:00 2001 From: 0aids Date: Mon, 15 Jun 2026 17:03:12 +1000 Subject: [PATCH 14/27] fix: hardcoded paths in backtracing python tool and LDFLAGS manipulation in mk Signed-off-by: 0aids --- components/backtracer/LionsOS_Backtracer.py | 3 ++- components/backtracer/backtracer.mk | 2 -- examples/backtrace_test/backtrace_test.mk | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/components/backtracer/LionsOS_Backtracer.py b/components/backtracer/LionsOS_Backtracer.py index 69ed452b9..d8ad39176 100644 --- a/components/backtracer/LionsOS_Backtracer.py +++ b/components/backtracer/LionsOS_Backtracer.py @@ -56,7 +56,8 @@ def enable_backtracing(sdf, arch, array_of_pds_or_single_pd, show_backtrace_func # Extract each of the addresses of the children's show_backtrace function pd_show_backtrace_addrs = [] for elf_path in pd_elf_paths: - shell_output = run("set -o pipefail && nm faulter.elf | grep \"show_backtrace\" | cut --delimiter=\" \" -f 1", + # Not very stable but good enough for now. + shell_output = run(f"set -o pipefail && nm {elf_path} | grep \"show_backtrace\" | cut --delimiter=\" \" -f 1", capture_output=True, shell=True, text=True) if shell_output.returncode != 0: raise Exception(f"Failed to get addresses of 'show_backtrace' for file {elf_path}\n" + diff --git a/components/backtracer/backtracer.mk b/components/backtracer/backtracer.mk index 2cdb1c779..a5f362bcb 100644 --- a/components/backtracer/backtracer.mk +++ b/components/backtracer/backtracer.mk @@ -59,6 +59,4 @@ clean:: ${RM} -rf backtracer backtracer.elf unwind_helpers.o libunwind.a libunwind export PYTHONPATH := "$(BACKTRACER_DIR):$$PYTHONPATH:$(PYTHONPATH)" -LDFLAGS += -L$(BACKTRACER_DIR) - # TODO: add dep files. diff --git a/examples/backtrace_test/backtrace_test.mk b/examples/backtrace_test/backtrace_test.mk index 0f55b0fac..7769cef78 100644 --- a/examples/backtrace_test/backtrace_test.mk +++ b/examples/backtrace_test/backtrace_test.mk @@ -46,7 +46,7 @@ CFLAGS += \ include $(LIONSOS)/lib/libc/libc.mk -LDFLAGS := --eh-frame-hdr -L$(BOARD_DIR)/lib -L$(LIONS_LIBC)/lib -L$(BACKTRACE_TEST_DIR)/build +LDFLAGS := --eh-frame-hdr -L$(BOARD_DIR)/lib -L$(LIONS_LIBC)/lib -L$(BACKTRACE_TEST_DIR)/build -L$(BACKTRACER) LIBS := --start-group -Tunwind.ld -lmicrokit -Tmicrokit.ld libsddf_util_debug.a -lc -lunwind --end-group SDDF_LIBC_INCLUDE := $(LIONS_LIBC)/include From 6133d9ad0c0c89d7a068d65af01b3bc061b34170 Mon Sep 17 00:00:00 2001 From: 0aids Date: Tue, 16 Jun 2026 18:17:00 +1000 Subject: [PATCH 15/27] chore: some more docs Signed-off-by: 0aids --- components/backtracer/README.md | 14 ++++++++++++++ components/backtracer/backtracer.mk | 4 ++-- examples/backtrace_test/backtrace_test.mk | 2 +- flake.lock | 13 +++++++------ flake.nix | 2 +- 5 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 components/backtracer/README.md diff --git a/components/backtracer/README.md b/components/backtracer/README.md new file mode 100644 index 000000000..1c0e4bd64 --- /dev/null +++ b/components/backtracer/README.md @@ -0,0 +1,14 @@ +# Usage +1. Include `backtracer.mk` file. +2. For all targets to be backtraced: + 1. Add `libunwind.a` and `unwind_helpers.o` as targets and add them to be compiled with the target. + 3. Add `-funwind-tables` to `CFLAGS` + 4. Add `--eh-frame-hdr -L{Directory of backtracer}` to `LDFLAGS` + 5. Add `-Tunwind.ld -lunwind` to `LIBS` + 6. Optionally add `--start-group` and `--end-group` to the beginning and end of `LIBS` respectively. +3. For `meta.py`, make sure to add the path to this directory in to `PYTHONPATH` + +# Dependencies +- `libc` for ... +- llvm-project's `libunwind` +- `sddf` or some implementation of `printf` diff --git a/components/backtracer/backtracer.mk b/components/backtracer/backtracer.mk index a5f362bcb..639ca38d7 100644 --- a/components/backtracer/backtracer.mk +++ b/components/backtracer/backtracer.mk @@ -48,7 +48,7 @@ backtracer/backtracer.o: $(BACKTRACER_DIR)/backtracer.c | $(LIONS_LIBC)/include backtracer.elf: backtracer/backtracer.o libunwind.a | backtracer ${LD} ${LDFLAGS_backtracer} -o $@ $^ ${LIBS_backtracer} -libunwind.a: | $(LIONS_LIBC)/include backtracer +libunwind.a: | $(LIONS_LIBC)/include backtracer $(LLVM) cmake -B $(BUILD_DIR)/libunwind -S $(LLVM)/runtimes \ $(LLVM_CMAKE_FLAGS) @@ -57,6 +57,6 @@ libunwind.a: | $(LIONS_LIBC)/include backtracer clean:: ${RM} -rf backtracer backtracer.elf unwind_helpers.o libunwind.a libunwind -export PYTHONPATH := "$(BACKTRACER_DIR):$$PYTHONPATH:$(PYTHONPATH)" +# export PYTHONPATH := "$(BACKTRACER_DIR):$$PYTHONPATH:$(PYTHONPATH)" # TODO: add dep files. diff --git a/examples/backtrace_test/backtrace_test.mk b/examples/backtrace_test/backtrace_test.mk index 7769cef78..ff10cef64 100644 --- a/examples/backtrace_test/backtrace_test.mk +++ b/examples/backtrace_test/backtrace_test.mk @@ -69,7 +69,7 @@ faulter.elf: faulter.o libunwind.a unwind_helpers.o FORCE: $(SYSTEM_FILE): $(METAPROGRAM) $(IMAGES) $(DTB) backtracer.elf - PYTHONPATH="${SDDF}/tools/meta:$$PYTHONPATH:$(PYTHONPATH)" $(PYTHON) $(METAPROGRAM) --sddf $(SDDF) --board $(MICROKIT_BOARD) --output . --sdf $(SYSTEM_FILE) + PYTHONPATH="${SDDF}/tools/meta:${BACKTRACER}:$$PYTHONPATH:$(PYTHONPATH)" $(PYTHON) $(METAPROGRAM) --sddf $(SDDF) --board $(MICROKIT_BOARD) --output . --sdf $(SYSTEM_FILE) # Add the unwind table to the memory region specified. $(IMAGE_FILE) $(REPORT_FILE): $(IMAGES) $(SYSTEM_FILE) diff --git a/flake.lock b/flake.lock index 49540c996..f24903676 100644 --- a/flake.lock +++ b/flake.lock @@ -134,15 +134,16 @@ "locked": { "lastModified": 1781144170, "narHash": "sha256-KcJ9hHnpG5Ho6gCxmhoU5iVonjLdB/OaA+L6CfYQeIQ=", - "ref": "refs/heads/mr_prefill_support", + "owner": "au-ts", + "repo": "microkit_sdf_gen", "rev": "32e356aeaecbcd819c9b944fb55e37fad834c76c", - "revCount": 822, - "type": "git", - "url": "file:///home/aids/git/ToR/microkit_sdf_gen" + "type": "github" }, "original": { - "type": "git", - "url": "file:///home/aids/git/ToR/microkit_sdf_gen" + "owner": "au-ts", + "ref": "mr_prefill_support", + "repo": "microkit_sdf_gen", + "type": "github" } }, "systems": { diff --git a/flake.nix b/flake.nix index 3a7c66c2e..6399df1b1 100644 --- a/flake.nix +++ b/flake.nix @@ -8,7 +8,7 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; zig-overlay.url = "github:mitchellh/zig-overlay"; - sdfgen.url = "git+file:///home/aids/git/ToR/microkit_sdf_gen"; + sdfgen.url = "github:au-ts/microkit_sdf_gen/mr_prefill_support"; sdfgen.inputs.nixpkgs.follows = "nixpkgs"; }; From 3f45c1c8eba4bfacf9a0f35cfd6239c7dc426f6b Mon Sep 17 00:00:00 2001 From: 0aids Date: Tue, 16 Jun 2026 18:30:50 +1000 Subject: [PATCH 16/27] fix: llvm as submodule Signed-off-by: 0aids --- .gitmodules | 3 +++ dep/llvm-project | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 7ddfb0378..4296f35da 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule "dep/wasm-micro-runtime"] path = dep/wasm-micro-runtime url = https://github.com/au-ts/wasm-micro-runtime +[submodule "dep/llvm-project"] + path = dep/llvm-project + url = https://github.com/llvm/llvm-project.git diff --git a/dep/llvm-project b/dep/llvm-project index 7da29bc52..a255c1ed3 160000 --- a/dep/llvm-project +++ b/dep/llvm-project @@ -1 +1 @@ -Subproject commit 7da29bc529d74d327804ad25e49e0cdeccfed263 +Subproject commit a255c1ed36a1d06f79bd2633ba9f8d900153007c From 739aa5d6ee3e277db2de3606a3e7f57621638a6d Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 17 Jun 2026 13:07:09 +1000 Subject: [PATCH 17/27] chore: remove llvm-project as a submodule in favour of wget Having llvm-project as a submodule was causing problems with shallow cloning. Signed-off-by: 0aids --- .gitmodules | 3 --- components/backtracer/README.md | 4 ++++ components/backtracer/backtracer.mk | 15 +++++++++++++-- dep/llvm-project | 1 - examples/backtrace_test/backtrace_test.mk | 2 -- 5 files changed, 17 insertions(+), 8 deletions(-) delete mode 160000 dep/llvm-project diff --git a/.gitmodules b/.gitmodules index 4296f35da..7ddfb0378 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,6 +25,3 @@ [submodule "dep/wasm-micro-runtime"] path = dep/wasm-micro-runtime url = https://github.com/au-ts/wasm-micro-runtime -[submodule "dep/llvm-project"] - path = dep/llvm-project - url = https://github.com/llvm/llvm-project.git diff --git a/components/backtracer/README.md b/components/backtracer/README.md index 1c0e4bd64..eee866c74 100644 --- a/components/backtracer/README.md +++ b/components/backtracer/README.md @@ -12,3 +12,7 @@ - `libc` for ... - llvm-project's `libunwind` - `sddf` or some implementation of `printf` + +# Pros +- Larger binary sizes +- Depending on `llvm-project` (sorry) diff --git a/components/backtracer/backtracer.mk b/components/backtracer/backtracer.mk index 639ca38d7..ad4ef369d 100644 --- a/components/backtracer/backtracer.mk +++ b/components/backtracer/backtracer.mk @@ -1,5 +1,10 @@ +TAR ?= tar + BACKTRACER_DIR := $(LIONSOS)/components/backtracer -LLVM := $(LIONSOS)/dep/llvm-project +LLVM := llvm-project-22.1.8.src +LLVM_TAR := llvm-project-22.1.8.src.tar.xz +LLVM_URL := https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.8/llvm-project-22.1.8.src.tar.xz +LIBUNWIND := $(LLVM)/libunwind CFLAGS_backtracer := \ -target $(TARGET) \ @@ -39,7 +44,7 @@ LLVM_CMAKE_FLAGS := \ backtracer: mkdir -p $@ -unwind_helpers.o: $(BACKTRACER_DIR)/unwind_helpers.c | $(LIONS_LIBC)/include backtracer +unwind_helpers.o: $(BACKTRACER_DIR)/unwind_helpers.c | $(LIONS_LIBC)/include backtracer $(LLVM) ${CC} ${CFLAGS_backtracer} -c -o $@ $< backtracer/backtracer.o: $(BACKTRACER_DIR)/backtracer.c | $(LIONS_LIBC)/include backtracer @@ -48,6 +53,12 @@ backtracer/backtracer.o: $(BACKTRACER_DIR)/backtracer.c | $(LIONS_LIBC)/include backtracer.elf: backtracer/backtracer.o libunwind.a | backtracer ${LD} ${LDFLAGS_backtracer} -o $@ $^ ${LIBS_backtracer} +$(LLVM_TAR): + wget $(LLVM_URL) + +$(LLVM): $(LLVM_TAR) + tar xvf $< $@/{libunwind,runtimes,cmake,utils,third-party} $@/llvm/{cmake,utils} + libunwind.a: | $(LIONS_LIBC)/include backtracer $(LLVM) cmake -B $(BUILD_DIR)/libunwind -S $(LLVM)/runtimes \ $(LLVM_CMAKE_FLAGS) diff --git a/dep/llvm-project b/dep/llvm-project deleted file mode 160000 index a255c1ed3..000000000 --- a/dep/llvm-project +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a255c1ed36a1d06f79bd2633ba9f8d900153007c diff --git a/examples/backtrace_test/backtrace_test.mk b/examples/backtrace_test/backtrace_test.mk index ff10cef64..75b4b9836 100644 --- a/examples/backtrace_test/backtrace_test.mk +++ b/examples/backtrace_test/backtrace_test.mk @@ -3,7 +3,6 @@ # # SPDX-License-Identifier: BSD-2-Clause # - TOOLCHAIN ?= clang SUPPORTED_BOARDS := \ qemu_virt_aarch64 \ @@ -17,7 +16,6 @@ MICROKIT_TOOL ?= $(MICROKIT_SDK)/bin/microkit BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG) SDDF := $(LIONSOS)/dep/sddf LLVM := $(LIONSOS)/dep/llvm-project/ -LIBUNWIND := $(LLVM)/libunwind SYSTEM_FILE := backtrace_test.system IMAGE_FILE := backtrace_test.img REPORT_FILE := report.txt From 23bb77daa4ceee4481d47d0ef76cee08b150afe0 Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 17 Jun 2026 13:36:21 +1000 Subject: [PATCH 18/27] backtracer/docs: more information on backtracer usage and deps Signed-off-by: 0aids --- components/backtracer/README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/components/backtracer/README.md b/components/backtracer/README.md index eee866c74..a335fef97 100644 --- a/components/backtracer/README.md +++ b/components/backtracer/README.md @@ -6,13 +6,21 @@ 4. Add `--eh-frame-hdr -L{Directory of backtracer}` to `LDFLAGS` 5. Add `-Tunwind.ld -lunwind` to `LIBS` 6. Optionally add `--start-group` and `--end-group` to the beginning and end of `LIBS` respectively. -3. For `meta.py`, make sure to add the path to this directory in to `PYTHONPATH` +3. For `meta.py`: + 1. Make sure to add the path to this directory in to `PYTHONPATH` + 2. Import `LionsOS_Backtracer` + 3. For all PDs to be traced, add them to a list and pass them to the `enable_backtracing` function. + This function returns a parent PD containing all of the children given. + The function prototype is `enable_backtracing(sdf, architecture, PD_list) -> PD` + +See the `backtrace_test` example for more details. # Dependencies -- `libc` for ... +- `libc` for `libunwind` - llvm-project's `libunwind` - `sddf` or some implementation of `printf` +- patched `sdfgen` with Memory region prefilling capabilities (updated sdfgen) -# Pros +# Cons - Larger binary sizes - Depending on `llvm-project` (sorry) From 702658640e1d1b39aed2c72769d25c922f5c4cf1 Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 17 Jun 2026 14:40:03 +1000 Subject: [PATCH 19/27] chore: formatting Signed-off-by: 0aids --- components/backtracer/LionsOS_Backtracer.py | 63 +++-- components/backtracer/backtracer.c | 56 ++-- components/backtracer/monitor.h | 278 ++++++++++---------- components/backtracer/unwind_helpers.c | 35 +-- examples/backtrace_test/faulter.c | 20 +- examples/backtrace_test/meta.py | 5 +- 6 files changed, 251 insertions(+), 206 deletions(-) diff --git a/components/backtracer/LionsOS_Backtracer.py b/components/backtracer/LionsOS_Backtracer.py index d8ad39176..7a3d3a17a 100644 --- a/components/backtracer/LionsOS_Backtracer.py +++ b/components/backtracer/LionsOS_Backtracer.py @@ -18,23 +18,40 @@ Map = SystemDescription.Map Channel = SystemDescription.Channel + def get_architecture_pointer_alignment(arch: SystemDescription.Arch): match arch: - case SystemDescription.Arch.AARCH64 | SystemDescription.Arch.RISCV64 | SystemDescription.Arch.X86_64: + case ( + SystemDescription.Arch.AARCH64 + | SystemDescription.Arch.RISCV64 + | SystemDescription.Arch.X86_64 + ): return 8 - case SystemDescription.Arch.AARCH32 | SystemDescription.Arch.RISCV32 | SystemDescription.Arch.X86: + case ( + SystemDescription.Arch.AARCH32 + | SystemDescription.Arch.RISCV32 + | SystemDescription.Arch.X86 + ): return 4 case _: raise Exception(f"Alignment of architecture {arch} is unknown.") -def enable_backtracing(sdf, arch, array_of_pds_or_single_pd, show_backtrace_func_list_addr = 0xb00000): + +def enable_backtracing( + sdf, arch, array_of_pds_or_single_pd, show_backtrace_func_list_addr=0xB00000 +): """ Wrap an array or single pd as children into a backtracer parent, capable of catching faults and then forcing prints of the backtrace Remember to compile each of the children with "backtrace.o" """ - backtracer = ProtectionDomain("backtracer", "backtracer.elf", priority=ProtectionDomain.PRIORITY_MAX, stack_size=0x10000); - pd_elf_paths = []; + backtracer = ProtectionDomain( + "backtracer", + "backtracer.elf", + priority=ProtectionDomain.PRIORITY_MAX, + stack_size=0x10000, + ) + pd_elf_paths = [] if not isinstance(array_of_pds_or_single_pd, list): array_of_pds_or_single_pd = [array_of_pds_or_single_pd] @@ -43,10 +60,10 @@ def enable_backtracing(sdf, arch, array_of_pds_or_single_pd, show_backtrace_func newChannel = Channel( child_pd, backtracer, - a_id = 61, - b_id = i, - pp_a = True, - pd_a_setvar_id="channel_to_backtrace" + a_id=61, + b_id=i, + pp_a=True, + pd_a_setvar_id="channel_to_backtrace", ) sdf.add_channel(newChannel) backtracer.add_child_pd(child_pd) @@ -57,14 +74,20 @@ def enable_backtracing(sdf, arch, array_of_pds_or_single_pd, show_backtrace_func pd_show_backtrace_addrs = [] for elf_path in pd_elf_paths: # Not very stable but good enough for now. - shell_output = run(f"set -o pipefail && nm {elf_path} | grep \"show_backtrace\" | cut --delimiter=\" \" -f 1", - capture_output=True, shell=True, text=True) + shell_output = run( + f'set -o pipefail && nm {elf_path} | grep "show_backtrace" | cut --delimiter=" " -f 1', + capture_output=True, + shell=True, + text=True, + ) if shell_output.returncode != 0: - raise Exception(f"Failed to get addresses of 'show_backtrace' for file {elf_path}\n" + - f"stderr: {shell_output.stderr}\n" + - f"stdout: {shell_output.stdout}\n" + - f"exit code: {shell_output.returncode}\n") - show_backtrace_addr = int(shell_output.stdout.strip(), 16); + raise Exception( + f"Failed to get addresses of 'show_backtrace' for file {elf_path}\n" + + f"stderr: {shell_output.stderr}\n" + + f"stdout: {shell_output.stdout}\n" + + f"exit code: {shell_output.returncode}\n" + ) + show_backtrace_addr = int(shell_output.stdout.strip(), 16) print(f"'{elf_path}':show_backtrace @ {hex(show_backtrace_addr)}") pd_show_backtrace_addrs.append(show_backtrace_addr) @@ -77,8 +100,12 @@ def enable_backtracing(sdf, arch, array_of_pds_or_single_pd, show_backtrace_func BACKTRACER_FUNCTION_DATA_PATH = "backtrace_functions.data" with open(BACKTRACER_FUNCTION_DATA_PATH, "wb") as dataFile: dataFile.write(frame) - func_list_mr = MemoryRegion(sdf, "backtracerFunctions", prefill_path=BACKTRACER_FUNCTION_DATA_PATH) + func_list_mr = MemoryRegion( + sdf, "backtracerFunctions", prefill_path=BACKTRACER_FUNCTION_DATA_PATH + ) sdf.add_mr(func_list_mr) - func_list_map = Map(func_list_mr, vaddr=0x20000, perms="r", setvar_vaddr="backtraceFunctions") + func_list_map = Map( + func_list_mr, vaddr=0x20000, perms="r", setvar_vaddr="backtraceFunctions" + ) backtracer.add_map(func_list_map) return backtracer diff --git a/components/backtracer/backtracer.c b/components/backtracer/backtracer.c index 2f3b758cd..bf2ce83b5 100644 --- a/components/backtracer/backtracer.c +++ b/components/backtracer/backtracer.c @@ -1,23 +1,24 @@ +#include "monitor.h" #include #include -#include "monitor.h" #define LOG(...) sddf_printf("BACKTRACER | " __VA_ARGS__) void (**backtraceFunctions)() = NULL; -void init() { +void init() +{ LOG("Backtracer initialised!\n"); LOG("Backtracer table starting address: %p\n", backtraceFunctions); } #if defined(__aarch64__) -static void callConvention_prologue(seL4_UserContext* ctxt, uintptr_t funcAddr) +static void callConvention_prologue(seL4_UserContext *ctxt, uintptr_t funcAddr) { - // Set the link register to old PC + // Set the link register to old PC ctxt->x30 = ctxt->pc; - // Set the PC to the next function + // Set the PC to the next function ctxt->pc = funcAddr; - LOG("Old PC: %p, New PC: %p\n", (void*)ctxt->x30, (void*)funcAddr); + LOG("Old PC: %p, New PC: %p\n", (void *)ctxt->x30, (void *)funcAddr); } #elif defined(__riscv__) #error "Unimplemented backtracer for riscv" @@ -27,31 +28,38 @@ static void callConvention_prologue(seL4_UserContext* ctxt, uintptr_t funcAddr) #error "Unsupported architecture for backtracing" #endif -seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, - microkit_msginfo *reply_msginfo) { - LOG("Child '%d' Faulted!\n", child); - print_fault_error(child, msginfo); - seL4_UserContext ctxt = {0}; - // BASE_TCB_CAP is from microkit.h. Not sure if completely portable? - int readRegResult = seL4_TCB_ReadRegisters(BASE_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); - if (readRegResult != 0) - { - LOG("Failed to read registers for setting up backtrace jump! Got %d, expected %d\n", readRegResult, 0); +seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) +{ + LOG("Child '%d' Faulted!\n", child); + print_fault_error(child, msginfo); + seL4_UserContext ctxt = { 0 }; + // BASE_TCB_CAP is from microkit.h. Not sure if completely portable? + int readRegResult = seL4_TCB_ReadRegisters(BASE_TCB_CAP + child, seL4_True, 0, + sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); + if (readRegResult != 0) { + LOG("Failed to read registers for setting up backtrace jump! Got %d, " + "expected %d\n", + readRegResult, 0); return seL4_False; } - print_tcb_registers(&ctxt); - callConvention_prologue(&ctxt, (uintptr_t)(backtraceFunctions[child])); - int writeRegResult = seL4_TCB_WriteRegisters(BASE_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); - if (writeRegResult != 0) - { - LOG("Failed to write registers for setting up backtrace jump! Got %d, expected %d\n", writeRegResult, 0); + print_tcb_registers(&ctxt); + callConvention_prologue(&ctxt, (uintptr_t)(backtraceFunctions[child])); + int writeRegResult = seL4_TCB_WriteRegisters(BASE_TCB_CAP + child, seL4_True, 0, + sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); + if (writeRegResult != 0) { + LOG("Failed to write registers for setting up backtrace jump! Got %d, " + "expected %d\n", + writeRegResult, 0); return seL4_False; } return seL4_True; } -void notified(microkit_channel ch) {} -microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) { +void notified(microkit_channel ch) +{ +} +microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) +{ microkit_pd_stop(ch); return msginfo; } diff --git a/components/backtracer/monitor.h b/components/backtracer/monitor.h index 3ee3c985d..a7f52053f 100644 --- a/components/backtracer/monitor.h +++ b/components/backtracer/monitor.h @@ -13,10 +13,10 @@ * Acting as the fault handler for protection domains. */ +#include "util.h" +#include #include #include -#include -#include "util.h" #define MAX_VMS 64 #define MAX_PDS 64 @@ -35,7 +35,8 @@ seL4_Word pd_names_len; char vm_names[MAX_VMS][MAX_NAME_LEN] __attribute__((unused)); seL4_Word vm_names_len; -/* For reporting potential stack overflows, keep track of the stack regions for each PD. */ +/* For reporting potential stack overflows, keep track of the stack regions for + * each PD. */ seL4_Word pd_stack_bottom_addrs[MAX_PDS]; /* Sanity check that the architecture specific macro have been set. */ @@ -48,8 +49,8 @@ seL4_Word pd_stack_bottom_addrs[MAX_PDS]; #ifdef __riscv64__ /* - * Convert the fault status register given by the kernel into a string describing - * what fault happened. The FSR is the 'scause' register. + * Convert the fault status register given by the kernel into a string + * describing what fault happened. The FSR is the 'scause' register. */ static char *riscv_fsr_to_string(seL4_Word fsr) { @@ -99,15 +100,18 @@ static char *ec_to_string(uintptr_t ec) case 1: return "Trapped WFI or WFE instruction execution"; case 3: - return "Trapped MCR or MRC access with (coproc==0b1111) this is not reported using EC 0b000000"; + return "Trapped MCR or MRC access with (coproc==0b1111) this is not " + "reported using EC 0b000000"; case 4: - return "Trapped MCRR or MRRC access with (coproc==0b1111) this is not reported using EC 0b000000"; + return "Trapped MCRR or MRRC access with (coproc==0b1111) this is not " + "reported using EC 0b000000"; case 5: return "Trapped MCR or MRC access with (coproc==0b1110)"; case 6: return "Trapped LDC or STC access"; case 7: - return "Access to SVC, Advanced SIMD or floating-point functionality trapped"; + return "Access to SVC, Advanced SIMD or floating-point functionality " + "trapped"; case 12: return "Trapped MRRC access with (coproc==0b1110)"; case 13: @@ -117,11 +121,13 @@ static char *ec_to_string(uintptr_t ec) case 21: return "SVC instruction execution in AArch64 state"; case 24: - return "Trapped MSR, MRS or System instruction exuection in AArch64 state, this is not reported using EC 0xb000000, 0b000001 or 0b000111"; + return "Trapped MSR, MRS or System instruction exuection in AArch64 state, " + "this is not reported using EC 0xb000000, 0b000001 or 0b000111"; case 25: return "Access to SVE functionality trapped"; case 28: - return "Exception from a Pointer Authentication instruction authentication failure"; + return "Exception from a Pointer Authentication instruction authentication " + "failure"; case 32: return "Instruction Abort from a lower Exception level"; case 33: @@ -227,7 +233,7 @@ static char *data_abort_dfsc_to_string(uintptr_t dfsc) #ifdef __x86_64__ static char *page_fault_to_string(seL4_Word fsr) { - // https://wiki.osdev.org/Exceptions#Page_Fault + // https://wiki.osdev.org/Exceptions#Page_Fault switch (fsr) { case 0 | 4: return "read to a non-present page at ring 3"; @@ -238,8 +244,8 @@ static char *page_fault_to_string(seL4_Word fsr) case 3 | 4: return "page-protection violation from write at ring 3"; case 16: - // Note that seL4 currently does not implement the NX/XD bit - // to mark a page as non-executable so we will never see the below message. + // Note that seL4 currently does not implement the NX/XD bit + // to mark a page as non-executable so we will never see the below message. return "instruction fetch from non-executable page"; default: return "invalid FSR or unimplemented decoding"; @@ -686,9 +692,9 @@ static void aarch64_print_vm_fault() puts("\n"); if (ec == 0x24) { - /* FIXME: Note, this is not a complete decoding of the fault! Just some of the more - common fields! - */ + /* FIXME: Note, this is not a complete decoding of the fault! Just some of + the more common fields! + */ seL4_Word dfsc = iss & 0x3f; bool ea = (iss >> 9) & 1; bool cm = (iss >> 8) & 1; @@ -718,141 +724,141 @@ static void aarch64_print_vm_fault() static void print_fault_error(microkit_child child, microkit_msginfo msginfo) { - seL4_Word tcb_cap = BASE_PD_TCB_CAP + child; - seL4_Word label = microkit_msginfo_get_label(msginfo); - seL4_Word err = {0}; - seL4_Word badge = child + 1; - - if (label == seL4_Fault_NullFault && child < MAX_PDS) { - /* This is a request from our PD to become passive */ - err = seL4_SchedContext_Bind(BASE_SCHED_CONTEXT_CAP + child, BASE_NOTIFICATION_CAP + child); - if (err != seL4_NoError) { - puts("BACKTRACER | could not bind scheduling context to notification object\n"); - } else { - puts("MON|INFO: PD '"); - puts(pd_names[child]); - puts("' is now passive!\n"); - } - - return; + seL4_Word tcb_cap = BASE_PD_TCB_CAP + child; + seL4_Word label = microkit_msginfo_get_label(msginfo); + seL4_Word err = { 0 }; + seL4_Word badge = child + 1; + + if (label == seL4_Fault_NullFault && child < MAX_PDS) { + /* This is a request from our PD to become passive */ + err = seL4_SchedContext_Bind(BASE_SCHED_CONTEXT_CAP + child, BASE_NOTIFICATION_CAP + child); + if (err != seL4_NoError) { + puts("BACKTRACER | could not bind scheduling context to notification " + "object\n"); + } else { + puts("MON|INFO: PD '"); + puts(pd_names[child]); + puts("' is now passive!\n"); } - puts("BACKTRACER | received message "); - puthex32(label); - puts(" badge: "); - puthex64(badge); - puts(" tcb cap: "); - puthex64(tcb_cap); - puts("\n"); + return; + } - switch (label) { - case seL4_Fault_CapFault: { - seL4_Word ip = seL4_GetMR(seL4_CapFault_IP); - seL4_Word fault_addr = seL4_GetMR(seL4_CapFault_Addr); - seL4_Word in_recv_phase = seL4_GetMR(seL4_CapFault_InRecvPhase); - seL4_Word lookup_failure_type = seL4_GetMR(seL4_CapFault_LookupFailureType); - seL4_Word bits_left = seL4_GetMR(seL4_CapFault_BitsLeft); - seL4_Word depth_bits_found = seL4_GetMR(seL4_CapFault_DepthMismatch_BitsFound); - seL4_Word guard_found = seL4_GetMR(seL4_CapFault_GuardMismatch_GuardFound); - seL4_Word guard_bits_found = seL4_GetMR(seL4_CapFault_GuardMismatch_BitsFound); - - puts("BACKTRACER | CapFault: ip="); - puthex64(ip); - puts(" fault_addr="); - puthex64(fault_addr); - puts(" in_recv_phase="); - puts(in_recv_phase == 0 ? "false" : "true"); - puts(" lookup_failure_type="); - - switch (lookup_failure_type) { - case seL4_NoFailure: - puts("seL4_NoFailure"); - break; - case seL4_InvalidRoot: - puts("seL4_InvalidRoot"); - break; - case seL4_MissingCapability: - puts("seL4_MissingCapability"); - break; - case seL4_DepthMismatch: - puts("seL4_DepthMismatch"); - break; - case seL4_GuardMismatch: - puts("seL4_GuardMismatch"); - break; - default: - puthex64(lookup_failure_type); - } - - if ( - lookup_failure_type == seL4_MissingCapability || - lookup_failure_type == seL4_DepthMismatch || - lookup_failure_type == seL4_GuardMismatch) { - puts(" bits_left="); - puthex64(bits_left); - } - if (lookup_failure_type == seL4_DepthMismatch) { - puts(" depth_bits_found="); - puthex64(depth_bits_found); - } - if (lookup_failure_type == seL4_GuardMismatch) { - puts(" guard_found="); - puthex64(guard_found); - puts(" guard_bits_found="); - puthex64(guard_bits_found); - } - puts("\n"); + puts("BACKTRACER | received message "); + puthex32(label); + puts(" badge: "); + puthex64(badge); + puts(" tcb cap: "); + puthex64(tcb_cap); + puts("\n"); + + switch (label) { + case seL4_Fault_CapFault: { + seL4_Word ip = seL4_GetMR(seL4_CapFault_IP); + seL4_Word fault_addr = seL4_GetMR(seL4_CapFault_Addr); + seL4_Word in_recv_phase = seL4_GetMR(seL4_CapFault_InRecvPhase); + seL4_Word lookup_failure_type = seL4_GetMR(seL4_CapFault_LookupFailureType); + seL4_Word bits_left = seL4_GetMR(seL4_CapFault_BitsLeft); + seL4_Word depth_bits_found = seL4_GetMR(seL4_CapFault_DepthMismatch_BitsFound); + seL4_Word guard_found = seL4_GetMR(seL4_CapFault_GuardMismatch_GuardFound); + seL4_Word guard_bits_found = seL4_GetMR(seL4_CapFault_GuardMismatch_BitsFound); + + puts("BACKTRACER | CapFault: ip="); + puthex64(ip); + puts(" fault_addr="); + puthex64(fault_addr); + puts(" in_recv_phase="); + puts(in_recv_phase == 0 ? "false" : "true"); + puts(" lookup_failure_type="); + + switch (lookup_failure_type) { + case seL4_NoFailure: + puts("seL4_NoFailure"); break; - } - case seL4_Fault_UserException: { - puts("BACKTRACER | UserException\n"); + case seL4_InvalidRoot: + puts("seL4_InvalidRoot"); + break; + case seL4_MissingCapability: + puts("seL4_MissingCapability"); + break; + case seL4_DepthMismatch: + puts("seL4_DepthMismatch"); break; + case seL4_GuardMismatch: + puts("seL4_GuardMismatch"); + break; + default: + puthex64(lookup_failure_type); + } + + if (lookup_failure_type == seL4_MissingCapability || lookup_failure_type == seL4_DepthMismatch + || lookup_failure_type == seL4_GuardMismatch) { + puts(" bits_left="); + puthex64(bits_left); } - case seL4_Fault_VMFault: { + if (lookup_failure_type == seL4_DepthMismatch) { + puts(" depth_bits_found="); + puthex64(depth_bits_found); + } + if (lookup_failure_type == seL4_GuardMismatch) { + puts(" guard_found="); + puthex64(guard_found); + puts(" guard_bits_found="); + puthex64(guard_bits_found); + } + puts("\n"); + break; + } + case seL4_Fault_UserException: { + puts("BACKTRACER | UserException\n"); + break; + } + case seL4_Fault_VMFault: { #if defined(__aarch64__) - aarch64_print_vm_fault(); + aarch64_print_vm_fault(); #elif defined(__riscv64__) - riscv_print_vm_fault(); + riscv_print_vm_fault(); #elif defined(__x86_64__) - x86_64_print_vm_fault(); + x86_64_print_vm_fault(); #else #error "Unknown architecture to print a VM fault for" #endif - seL4_Word fault_addr = seL4_GetMR(seL4_VMFault_Addr); - seL4_Word stack_addr = pd_stack_bottom_addrs[child]; - if (fault_addr < stack_addr && fault_addr >= stack_addr - 0x1000) { - puts("BACKTRACER | potential stack overflow, fault address within one page outside of stack region\n"); - } - - break; + seL4_Word fault_addr = seL4_GetMR(seL4_VMFault_Addr); + seL4_Word stack_addr = pd_stack_bottom_addrs[child]; + if (fault_addr < stack_addr && fault_addr >= stack_addr - 0x1000) { + puts("BACKTRACER | potential stack overflow, fault address within one " + "page outside of stack region\n"); } + + break; + } #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT - case seL4_Fault_VCPUFault: { - seL4_Word esr = seL4_GetMR(seL4_VCPUFault_HSR); - seL4_Word ec = esr >> 26; - - puts("BACKTRACER | received vCPU fault with ESR: "); - puthex64(esr); - puts("\n"); - - seL4_Word esr_comment = esr & ESR_COMMENT_MASK; - if (ec == ARM64_BRK_EC && ((esr_comment & ~UBSAN_ARM64_BRK_MASK) == UBSAN_ARM64_BRK_IMM)) { - /* We likely have a UBSAN check going off from a brk instruction */ - seL4_Word ubsan_code = esr_comment & UBSAN_ARM64_BRK_MASK; - puts("BACKTRACER | potential undefined behaviour detected by UBSAN for: '"); - puts(usban_code_to_string(ubsan_code)); - puts("'\n"); - } else { - puts("BACKTRACER | Unknown vCPU fault\n"); - } - break; + case seL4_Fault_VCPUFault: { + seL4_Word esr = seL4_GetMR(seL4_VCPUFault_HSR); + seL4_Word ec = esr >> 26; + + puts("BACKTRACER | received vCPU fault with ESR: "); + puthex64(esr); + puts("\n"); + + seL4_Word esr_comment = esr & ESR_COMMENT_MASK; + if (ec == ARM64_BRK_EC && ((esr_comment & ~UBSAN_ARM64_BRK_MASK) == UBSAN_ARM64_BRK_IMM)) { + /* We likely have a UBSAN check going off from a brk instruction */ + seL4_Word ubsan_code = esr_comment & UBSAN_ARM64_BRK_MASK; + puts("BACKTRACER | potential undefined behaviour detected by UBSAN for: " + "'"); + puts(usban_code_to_string(ubsan_code)); + puts("'\n"); + } else { + puts("BACKTRACER | Unknown vCPU fault\n"); } + break; + } #endif - default: - puts("BACKTRACER | Unknown fault\n"); - puthex64(label); - break; - } + default: + puts("BACKTRACER | Unknown fault\n"); + puthex64(label); + break; + } } - diff --git a/components/backtracer/unwind_helpers.c b/components/backtracer/unwind_helpers.c index c23cfc8d2..50253d1a1 100644 --- a/components/backtracer/unwind_helpers.c +++ b/components/backtracer/unwind_helpers.c @@ -4,25 +4,26 @@ #include #define INPUT_CAP 1 -static seL4_MessageInfo_t empty_msg = {0}; +static seL4_MessageInfo_t empty_msg = { 0 }; uintptr_t channel_to_backtrace = 0; -void show_backtrace (void) { - sddf_printf("SHOW_BACKTRACE | BEGIN_SHOW_BACKTRACE for '%s'\n", microkit_name); - unw_cursor_t cursor; - unw_context_t uc; - unw_word_t ip, sp; +void show_backtrace(void) +{ + sddf_printf("SHOW_BACKTRACE | BEGIN_SHOW_BACKTRACE for '%s'\n", microkit_name); + unw_cursor_t cursor; + unw_context_t uc; + unw_word_t ip, sp; - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); - seL4_Word depth = 0; - while (unw_step(&cursor) > 0) { - unw_get_reg(&cursor, UNW_REG_IP, &ip); - unw_get_reg(&cursor, UNW_REG_SP, &sp); - sddf_printf("SHOW_BACKTRACE | #%d: ip = %p, sp = %p\n", (int)depth++, (void*) ip, (void*) sp); - } - microkit_dbg_puts("SHOW_BACKTRACE | END_SHOW_BACKTRACE\n"); - microkit_ppcall(channel_to_backtrace, empty_msg); - microkit_dbg_puts("You're not supposed to see this\n"); + seL4_Word depth = 0; + while (unw_step(&cursor) > 0) { + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + sddf_printf("SHOW_BACKTRACE | #%d: ip = %p, sp = %p\n", (int)depth++, (void *)ip, (void *)sp); + } + microkit_dbg_puts("SHOW_BACKTRACE | END_SHOW_BACKTRACE\n"); + microkit_ppcall(channel_to_backtrace, empty_msg); + microkit_dbg_puts("You're not supposed to see this\n"); } diff --git a/examples/backtrace_test/faulter.c b/examples/backtrace_test/faulter.c index 5de224a08..047c94ed8 100644 --- a/examples/backtrace_test/faulter.c +++ b/examples/backtrace_test/faulter.c @@ -1,31 +1,33 @@ #include -#include -#include #include +#include +#include #define LOG(...) sddf_printf("FAULTER | " __VA_ARGS__) -const char* timestamp = __TIMESTAMP__; +const char *timestamp = __TIMESTAMP__; // Get a random-ish pointer to low-ish memory uintptr_t happy = 0; void recurseFault(int depth) { - if (depth == 0) - { - *(volatile int*)happy; + if (depth == 0) { + *(volatile int *)happy; return; } recurseFault(--depth); } -void init() { +void init() +{ LOG("Faulter initialised!\n"); recurseFault(4); LOG("After dereference\n"); } -void notified(microkit_channel ch) { +void notified(microkit_channel ch) +{ LOG("Notified!\n"); } -microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) { +microkit_msginfo protected(microkit_channel ch, microkit_msginfo msginfo) +{ LOG("Protected!\n"); } diff --git a/examples/backtrace_test/meta.py b/examples/backtrace_test/meta.py index c59b85feb..2b0cf9396 100644 --- a/examples/backtrace_test/meta.py +++ b/examples/backtrace_test/meta.py @@ -22,8 +22,9 @@ def generate(sdf_path: str, output_dir: str): - domains = [ - ProtectionDomain(f"faulter{i}", "faulter.elf", priority=i, stack_size=0x100000) for i in range(5) + domains = [ + ProtectionDomain(f"faulter{i}", "faulter.elf", priority=i, stack_size=0x100000) + for i in range(5) ] backtracer = LionsOS_Backtracer.enable_backtracing(sdf, board.arch, domains) sdf.add_pd(backtracer) From 8ed5aad41b735dd23936a87aceea4c996b17798d Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 17 Jun 2026 15:14:14 +1000 Subject: [PATCH 20/27] fix: missing include in monitor Signed-off-by: 0aids --- components/backtracer/monitor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/components/backtracer/monitor.h b/components/backtracer/monitor.h index a7f52053f..a57d44553 100644 --- a/components/backtracer/monitor.h +++ b/components/backtracer/monitor.h @@ -13,6 +13,7 @@ * Acting as the fault handler for protection domains. */ +#include #include "util.h" #include #include From c21a6bb480d470803719addf1acb76b51e040bd4 Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 17 Jun 2026 15:14:39 +1000 Subject: [PATCH 21/27] chore: clean up makefiles with dependency tracking Signed-off-by: 0aids --- components/backtracer/backtracer.mk | 19 ++++++++++--------- examples/backtrace_test/Makefile | 5 ----- examples/backtrace_test/backtrace_test.mk | 3 +-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/components/backtracer/backtracer.mk b/components/backtracer/backtracer.mk index ad4ef369d..2b0e607ac 100644 --- a/components/backtracer/backtracer.mk +++ b/components/backtracer/backtracer.mk @@ -5,15 +5,16 @@ LLVM := llvm-project-22.1.8.src LLVM_TAR := llvm-project-22.1.8.src.tar.xz LLVM_URL := https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.8/llvm-project-22.1.8.src.tar.xz LIBUNWIND := $(LLVM)/libunwind +LIBUNWIND_BUILD_DIR := ./libunwind CFLAGS_backtracer := \ - -target $(TARGET) \ + $(CFLAGS)\ -I$(LIONSOS)/include \ -I$(SDDF)/include \ -I$(SDDF)/include/microkit \ -I$(LIBUNWIND)/include \ -I$(BOARD_DIR)/include \ - -I$(LIONS_LIBC)/include -O0 -ggdb -funwind-tables + -I$(LIONS_LIBC)/include -funwind-tables LDFLAGS_backtracer := -L$(BOARD_DIR)/lib -L$(LIONS_LIBC)/lib LIBS_backtracer := -lmicrokit -Tmicrokit.ld libsddf_util_debug.a -lc @@ -57,17 +58,17 @@ $(LLVM_TAR): wget $(LLVM_URL) $(LLVM): $(LLVM_TAR) - tar xvf $< $@/{libunwind,runtimes,cmake,utils,third-party} $@/llvm/{cmake,utils} + ${TAR} xvf $< $@/{libunwind,runtimes,cmake,utils,third-party} $@/llvm/{cmake,utils} -libunwind.a: | $(LIONS_LIBC)/include backtracer $(LLVM) - cmake -B $(BUILD_DIR)/libunwind -S $(LLVM)/runtimes \ +$(LIBUNWIND_BUILD_DIR): | $(LLVM) $(LIONS_LIBC)/include + cmake -B $(LIBUNWIND_BUILD_DIR) -S $(LLVM)/runtimes \ $(LLVM_CMAKE_FLAGS) - cmake --build $(BUILD_DIR)/libunwind - cp $(BUILD_DIR)/libunwind/lib/libunwind.a $@ +libunwind.a: | $(LIONS_LIBC)/include $(LIBUNWIND_BUILD_DIR) + ${MAKE} -C $(LIBUNWIND_BUILD_DIR) + cp $(LIBUNWIND_BUILD_DIR)/lib/libunwind.a $@ clean:: ${RM} -rf backtracer backtracer.elf unwind_helpers.o libunwind.a libunwind -# export PYTHONPATH := "$(BACKTRACER_DIR):$$PYTHONPATH:$(PYTHONPATH)" -# TODO: add dep files. +-include unwind_helpers.d backtrace/backtracer.d diff --git a/examples/backtrace_test/Makefile b/examples/backtrace_test/Makefile index 9ba2138af..c9553c6a0 100644 --- a/examples/backtrace_test/Makefile +++ b/examples/backtrace_test/Makefile @@ -34,9 +34,4 @@ ${BUILD_DIR}/Makefile: backtrace_test.mk Makefile echo "export MICROKIT_CONFIG ?= ${MICROKIT_CONFIG}" >> $@ cat backtrace_test.mk >> $@ -submodules: - git submodule update --init $(LIONSOS)/dep/sddf - git submodule update --init $(LIONSOS)/dep/libmicrokitco - git submodule update --init $(LIONSOS)/dep/libunwind - FORCE: diff --git a/examples/backtrace_test/backtrace_test.mk b/examples/backtrace_test/backtrace_test.mk index 75b4b9836..472fe5229 100644 --- a/examples/backtrace_test/backtrace_test.mk +++ b/examples/backtrace_test/backtrace_test.mk @@ -3,7 +3,6 @@ # # SPDX-License-Identifier: BSD-2-Clause # -TOOLCHAIN ?= clang SUPPORTED_BOARDS := \ qemu_virt_aarch64 \ maaxboard @@ -11,7 +10,7 @@ SUPPORTED_BOARDS := \ IMAGES := \ faulter.elf -TOOLCHAIN ?= $(CC) +TOOLCHAIN ?= clang MICROKIT_TOOL ?= $(MICROKIT_SDK)/bin/microkit BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG) SDDF := $(LIONSOS)/dep/sddf From 426f71eb16cfc6f5083917fadc8f8d38de7a8dbe Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 17 Jun 2026 15:37:48 +1000 Subject: [PATCH 22/27] chore: clean up python files Signed-off-by: 0aids --- components/backtracer/LionsOS_Backtracer.py | 12 +++++++----- components/backtracer/unwind_helpers.c | 4 ++-- examples/backtrace_test/meta.py | 2 -- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/components/backtracer/LionsOS_Backtracer.py b/components/backtracer/LionsOS_Backtracer.py index 7a3d3a17a..2e639037c 100644 --- a/components/backtracer/LionsOS_Backtracer.py +++ b/components/backtracer/LionsOS_Backtracer.py @@ -38,7 +38,8 @@ def get_architecture_pointer_alignment(arch: SystemDescription.Arch): def enable_backtracing( - sdf, arch, array_of_pds_or_single_pd, show_backtrace_func_list_addr=0xB00000 + sdf, arch, array_of_pds_or_single_pd, *, show_backtrace_func_list_addr=0xB00000, backtracer_stack_size=0x10000, + pd_callback_channel_id=61, endianness="little" ): """ Wrap an array or single pd as children into a backtracer parent, @@ -49,8 +50,9 @@ def enable_backtracing( "backtracer", "backtracer.elf", priority=ProtectionDomain.PRIORITY_MAX, - stack_size=0x10000, + stack_size=backtracer_stack_size, ) + pd_elf_paths = [] if not isinstance(array_of_pds_or_single_pd, list): array_of_pds_or_single_pd = [array_of_pds_or_single_pd] @@ -60,10 +62,10 @@ def enable_backtracing( newChannel = Channel( child_pd, backtracer, - a_id=61, + a_id=pd_callback_channel_id, b_id=i, pp_a=True, - pd_a_setvar_id="channel_to_backtrace", + pd_a_setvar_id="unwind_helper_channel_to_backtracer", ) sdf.add_channel(newChannel) backtracer.add_child_pd(child_pd) @@ -96,7 +98,7 @@ def enable_backtracing( print(f"Alignment for architecture {arch.name}: {alignment}") frame = b"" for backtrace_addr in pd_show_backtrace_addrs: - frame += bytes(backtrace_addr.to_bytes(alignment, "little")) + frame += bytes(backtrace_addr.to_bytes(alignment, endianness)) BACKTRACER_FUNCTION_DATA_PATH = "backtrace_functions.data" with open(BACKTRACER_FUNCTION_DATA_PATH, "wb") as dataFile: dataFile.write(frame) diff --git a/components/backtracer/unwind_helpers.c b/components/backtracer/unwind_helpers.c index 50253d1a1..787d2be61 100644 --- a/components/backtracer/unwind_helpers.c +++ b/components/backtracer/unwind_helpers.c @@ -5,7 +5,7 @@ #define INPUT_CAP 1 static seL4_MessageInfo_t empty_msg = { 0 }; -uintptr_t channel_to_backtrace = 0; +uintptr_t unwind_helper_channel_to_backtracer = 0; void show_backtrace(void) { @@ -24,6 +24,6 @@ void show_backtrace(void) sddf_printf("SHOW_BACKTRACE | #%d: ip = %p, sp = %p\n", (int)depth++, (void *)ip, (void *)sp); } microkit_dbg_puts("SHOW_BACKTRACE | END_SHOW_BACKTRACE\n"); - microkit_ppcall(channel_to_backtrace, empty_msg); + microkit_ppcall(unwind_helper_channel_to_backtracer, empty_msg); microkit_dbg_puts("You're not supposed to see this\n"); } diff --git a/examples/backtrace_test/meta.py b/examples/backtrace_test/meta.py index 2b0cf9396..cfbfe4d3d 100644 --- a/examples/backtrace_test/meta.py +++ b/examples/backtrace_test/meta.py @@ -17,8 +17,6 @@ MemoryRegion = SystemDescription.MemoryRegion Map = SystemDescription.Map Channel = SystemDescription.Channel -board = 0 -sdf = 0 def generate(sdf_path: str, output_dir: str): From 694cfe1feea291047cd173bc2903c709bc9df8ff Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 17 Jun 2026 15:39:10 +1000 Subject: [PATCH 23/27] chore: clean up c files and licensing Signed-off-by: 0aids --- components/backtracer/backtracer.c | 3 +-- components/backtracer/unwind.ld | 16 ++++------------ 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/components/backtracer/backtracer.c b/components/backtracer/backtracer.c index bf2ce83b5..b9ca7d54c 100644 --- a/components/backtracer/backtracer.c +++ b/components/backtracer/backtracer.c @@ -33,7 +33,6 @@ seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo LOG("Child '%d' Faulted!\n", child); print_fault_error(child, msginfo); seL4_UserContext ctxt = { 0 }; - // BASE_TCB_CAP is from microkit.h. Not sure if completely portable? int readRegResult = seL4_TCB_ReadRegisters(BASE_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); if (readRegResult != 0) { @@ -47,7 +46,7 @@ seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo int writeRegResult = seL4_TCB_WriteRegisters(BASE_TCB_CAP + child, seL4_True, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), &ctxt); if (writeRegResult != 0) { - LOG("Failed to write registers for setting up backtrace jump! Got %d, " + LOG("Failed to write registers for setting up backtrace jump! Got error value %d, " "expected %d\n", writeRegResult, 0); return seL4_False; diff --git a/components/backtracer/unwind.ld b/components/backtracer/unwind.ld index d32ae1822..0e8eaaca4 100644 --- a/components/backtracer/unwind.ld +++ b/components/backtracer/unwind.ld @@ -1,17 +1,9 @@ /* - * Copyright 2019, Data61 - * Commonwealth Scientific and Industrial Research Organisation (CSIRO) - * ABN 41 687 119 230. - * - * This software may be distributed and modified according to the terms of - * the GNU General Public License version 2. Note that NO WARRANTY is provided. - * See "LICENSE_GPLv2.txt" for details. - * - * @TAG(DATA61_GPL) + * Copyright 2026, UNSW + * SPDX-License-Identifier: BSD-2-Clause */ SECTIONS { - /* stolen from config.h in libunwind llvm */ .eh_frame : { __eh_frame_start = .; @@ -20,9 +12,9 @@ SECTIONS } .eh_frame_hdr : { + __eh_frame_hdr_start = .; KEEP(*(.eh_frame_hdr)) + __eh_frame_hdr_end = .; } - __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; - __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; } INSERT AFTER .text; From 31c87730ef5548a1c681f2f82ecc484d9fa9bfe7 Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 17 Jun 2026 15:48:41 +1000 Subject: [PATCH 24/27] chore: remove unused vars and better names Signed-off-by: 0aids --- components/backtracer/unwind_helpers.c | 1 - examples/backtrace_test/faulter.c | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/components/backtracer/unwind_helpers.c b/components/backtracer/unwind_helpers.c index 787d2be61..85ddb0bf3 100644 --- a/components/backtracer/unwind_helpers.c +++ b/components/backtracer/unwind_helpers.c @@ -3,7 +3,6 @@ #define UNW_LOCAL_ONLY #include -#define INPUT_CAP 1 static seL4_MessageInfo_t empty_msg = { 0 }; uintptr_t unwind_helper_channel_to_backtracer = 0; diff --git a/examples/backtrace_test/faulter.c b/examples/backtrace_test/faulter.c index 047c94ed8..f11921faf 100644 --- a/examples/backtrace_test/faulter.c +++ b/examples/backtrace_test/faulter.c @@ -4,14 +4,12 @@ #include #define LOG(...) sddf_printf("FAULTER | " __VA_ARGS__) -const char *timestamp = __TIMESTAMP__; -// Get a random-ish pointer to low-ish memory -uintptr_t happy = 0; +uintptr_t faulty_ptr = 0; void recurseFault(int depth) { if (depth == 0) { - *(volatile int *)happy; + *(volatile int *)faulty_ptr; return; } recurseFault(--depth); From 96e462965572c71c8e00a70f3adc273be49072bb Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 17 Jun 2026 15:52:29 +1000 Subject: [PATCH 25/27] chore: add relevant licensing Signed-off-by: 0aids --- components/backtracer/README.md | 4 ++++ components/backtracer/backtracer.c | 4 ++++ components/backtracer/backtracer.mk | 5 +++++ components/backtracer/unwind_helpers.c | 4 ++++ examples/backtrace_test/faulter.c | 4 ++++ 5 files changed, 21 insertions(+) diff --git a/components/backtracer/README.md b/components/backtracer/README.md index a335fef97..963c3acb5 100644 --- a/components/backtracer/README.md +++ b/components/backtracer/README.md @@ -1,3 +1,7 @@ + # Usage 1. Include `backtracer.mk` file. 2. For all targets to be backtraced: diff --git a/components/backtracer/backtracer.c b/components/backtracer/backtracer.c index b9ca7d54c..f6e910d70 100644 --- a/components/backtracer/backtracer.c +++ b/components/backtracer/backtracer.c @@ -1,3 +1,7 @@ +/* + * Copyright 2025, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ #include "monitor.h" #include #include diff --git a/components/backtracer/backtracer.mk b/components/backtracer/backtracer.mk index 2b0e607ac..ea1c203ea 100644 --- a/components/backtracer/backtracer.mk +++ b/components/backtracer/backtracer.mk @@ -1,3 +1,8 @@ +# +# Copyright 2026, UNSW +# +# SPDX-License-Identifier: BSD-2-Clause +# TAR ?= tar BACKTRACER_DIR := $(LIONSOS)/components/backtracer diff --git a/components/backtracer/unwind_helpers.c b/components/backtracer/unwind_helpers.c index 85ddb0bf3..dae1fb9ee 100644 --- a/components/backtracer/unwind_helpers.c +++ b/components/backtracer/unwind_helpers.c @@ -1,3 +1,7 @@ +/* + * Copyright 2025, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ #include #include #define UNW_LOCAL_ONLY diff --git a/examples/backtrace_test/faulter.c b/examples/backtrace_test/faulter.c index f11921faf..53107e3fe 100644 --- a/examples/backtrace_test/faulter.c +++ b/examples/backtrace_test/faulter.c @@ -1,3 +1,7 @@ +/* + * Copyright 2025, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ #include #include #include From c08a4a841d5300bf14e139161548c1b4cd57ad7b Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 17 Jun 2026 15:55:17 +1000 Subject: [PATCH 26/27] chore: use updated sddf for CXX var in make Signed-off-by: 0aids --- dep/sddf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dep/sddf b/dep/sddf index d1f5252ea..e689f1d97 160000 --- a/dep/sddf +++ b/dep/sddf @@ -1 +1 @@ -Subproject commit d1f5252ea64edab6087552eb4220e23c019c2fbe +Subproject commit e689f1d97d5ef151906862683620132034082f62 From 919a5d4655abb6352b6bab875d81df877e0aaf3b Mon Sep 17 00:00:00 2001 From: 0aids Date: Wed, 17 Jun 2026 17:42:58 +1000 Subject: [PATCH 27/27] chore: clean up excess headers Signed-off-by: 0aids --- components/backtracer/backtracer.c | 1 - components/backtracer/monitor.h | 496 ++++++++--------------------- components/backtracer/util.h | 92 ------ 3 files changed, 126 insertions(+), 463 deletions(-) delete mode 100644 components/backtracer/util.h diff --git a/components/backtracer/backtracer.c b/components/backtracer/backtracer.c index f6e910d70..3830d4c3f 100644 --- a/components/backtracer/backtracer.c +++ b/components/backtracer/backtracer.c @@ -5,7 +5,6 @@ #include "monitor.h" #include #include -#define LOG(...) sddf_printf("BACKTRACER | " __VA_ARGS__) void (**backtraceFunctions)() = NULL; diff --git a/components/backtracer/monitor.h b/components/backtracer/monitor.h index a57d44553..86ea8c2fb 100644 --- a/components/backtracer/monitor.h +++ b/components/backtracer/monitor.h @@ -4,42 +4,21 @@ * * SPDX-License-Identifier: BSD-2-Clause */ -/* - * The Microkit Monitor. - * - * The monitor is the highest priority Protection Domain - * exclusively in a Microkit system. It fulfills one purpose: - * - * Acting as the fault handler for protection domains. - */ - #include -#include "util.h" #include #include #include +#include +#include + +#define LOG(...) sddf_printf("BACKTRACER | " __VA_ARGS__) -#define MAX_VMS 64 #define MAX_PDS 64 -#define MAX_NAME_LEN 64 -#define FAULT_EP_CAP 1 -#define REPLY_CAP 2 #define BASE_PD_TCB_CAP 10 #define BASE_SCHED_CONTEXT_CAP 138 #define BASE_NOTIFICATION_CAP 202 -extern seL4_IPCBuffer __sel4_ipc_buffer_obj; - -char pd_names[MAX_PDS][MAX_NAME_LEN]; -seL4_Word pd_names_len; -char vm_names[MAX_VMS][MAX_NAME_LEN] __attribute__((unused)); -seL4_Word vm_names_len; - -/* For reporting potential stack overflows, keep track of the stack regions for - * each PD. */ -seL4_Word pd_stack_bottom_addrs[MAX_PDS]; - /* Sanity check that the architecture specific macro have been set. */ #if defined(__aarch64__) #elif defined(__x86_64__) @@ -355,266 +334,96 @@ static char *usban_code_to_string(seL4_Word code) static void print_tcb_registers(seL4_UserContext *regs) { #if defined(__riscv64__) - puts("BACKTRACER | Registers: \n"); - puts("BACKTRACER | pc : "); - puthex64(regs->pc); - puts("\n"); - puts("BACKTRACER | ra : "); - puthex64(regs->ra); - puts("\n"); - puts("BACKTRACER | s0 : "); - puthex64(regs->s0); - puts("\n"); - puts("BACKTRACER | s1 : "); - puthex64(regs->s1); - puts("\n"); - puts("BACKTRACER | s2 : "); - puthex64(regs->s2); - puts("\n"); - puts("BACKTRACER | s3 : "); - puthex64(regs->s3); - puts("\n"); - puts("BACKTRACER | s4 : "); - puthex64(regs->s4); - puts("\n"); - puts("BACKTRACER | s5 : "); - puthex64(regs->s5); - puts("\n"); - puts("BACKTRACER | s6 : "); - puthex64(regs->s6); - puts("\n"); - puts("BACKTRACER | s7 : "); - puthex64(regs->s7); - puts("\n"); - puts("BACKTRACER | s8 : "); - puthex64(regs->s8); - puts("\n"); - puts("BACKTRACER | s9 : "); - puthex64(regs->s9); - puts("\n"); - puts("BACKTRACER | s10 : "); - puthex64(regs->s10); - puts("\n"); - puts("BACKTRACER | s11 : "); - puthex64(regs->s11); - puts("\n"); - puts("BACKTRACER | a0 : "); - puthex64(regs->a0); - puts("\n"); - puts("BACKTRACER | a1 : "); - puthex64(regs->a1); - puts("\n"); - puts("BACKTRACER | a2 : "); - puthex64(regs->a2); - puts("\n"); - puts("BACKTRACER | a3 : "); - puthex64(regs->a3); - puts("\n"); - puts("BACKTRACER | a4 : "); - puthex64(regs->a4); - puts("\n"); - puts("BACKTRACER | a5 : "); - puthex64(regs->a5); - puts("\n"); - puts("BACKTRACER | a6 : "); - puthex64(regs->a6); - puts("\n"); - puts("BACKTRACER | t0 : "); - puthex64(regs->t0); - puts("\n"); - puts("BACKTRACER | t1 : "); - puthex64(regs->t1); - puts("\n"); - puts("BACKTRACER | t2 : "); - puthex64(regs->t2); - puts("\n"); - puts("BACKTRACER | t3 : "); - puthex64(regs->t3); - puts("\n"); - puts("BACKTRACER | t4 : "); - puthex64(regs->t4); - puts("\n"); - puts("BACKTRACER | t5 : "); - puthex64(regs->t5); - puts("\n"); - puts("BACKTRACER | t6 : "); - puthex64(regs->t6); - puts("\n"); - puts("BACKTRACER | tp : "); - puthex64(regs->tp); - puts("\n"); + LOG("BACKTRACER | Registers: \n"); + LOG("BACKTRACER | pc : %#016lx\n", regs->pc); + LOG("ra : %#016lx\n", regs->ra); + LOG("s0 : %#016lx\n", regs->s0); + LOG("s1 : %#016lx\n", regs->s1); + LOG("s2 : %#016lx\n", regs->s2); + LOG("s3 : %#016lx\n", regs->s3); + LOG("s4 : %#016lx\n", regs->s4); + LOG("s5 : %#016lx\n", regs->s5); + LOG("s6 : %#016lx\n", regs->s6); + LOG("s7 : %#016lx\n", regs->s7); + LOG("s8 : %#016lx\n", regs->s8); + LOG("s9 : %#016lx\n", regs->s9); + LOG("s10 : %#016lx\n", regs->s10); + LOG("s11 : %#016lx\n", regs->s11); + LOG("a0 : %#016lx\n", regs->a0); + LOG("a1 : %#016lx\n", regs->a1); + LOG("a2 : %#016lx\n", regs->a2); + LOG("a3 : %#016lx\n", regs->a3); + LOG("a4 : %#016lx\n", regs->a4); + LOG("a5 : %#016lx\n", regs->a5); + LOG("a6 : %#016lx\n", regs->a6); + LOG("t0 : %#016lx\n", regs->t0); + LOG("t1 : %#016lx\n", regs->t1); + LOG("t2 : %#016lx\n", regs->t2); + LOG("t3 : %#016lx\n", regs->t3); + LOG("t4 : %#016lx\n", regs->t4); + LOG("t5 : %#016lx\n", regs->t5); + LOG("t6 : %#016lx\n", regs->t6); + LOG("tp : %#016lx\n", regs->tp); #elif defined(__aarch64__) - puts("BACKTRACER | Registers: \n"); - puts("BACKTRACER | pc : "); - puthex64(regs->pc); - puts("\n"); - puts("BACKTRACER | sp: "); - puthex64(regs->sp); - puts("\n"); - puts("BACKTRACER | spsr : "); - puthex64(regs->spsr); - puts("\n"); - puts("BACKTRACER | x0 : "); - puthex64(regs->x0); - puts("\n"); - puts("BACKTRACER | x1 : "); - puthex64(regs->x1); - puts("\n"); - puts("BACKTRACER | x2 : "); - puthex64(regs->x2); - puts("\n"); - puts("BACKTRACER | x3 : "); - puthex64(regs->x3); - puts("\n"); - puts("BACKTRACER | x4 : "); - puthex64(regs->x4); - puts("\n"); - puts("BACKTRACER | x5 : "); - puthex64(regs->x5); - puts("\n"); - puts("BACKTRACER | x6 : "); - puthex64(regs->x6); - puts("\n"); - puts("BACKTRACER | x7 : "); - puthex64(regs->x7); - puts("\n"); - puts("BACKTRACER | x8 : "); - puthex64(regs->x8); - puts("\n"); - puts("BACKTRACER | x16 : "); - puthex64(regs->x16); - puts("\n"); - puts("BACKTRACER | x17 : "); - puthex64(regs->x17); - puts("\n"); - puts("BACKTRACER | x18 : "); - puthex64(regs->x18); - puts("\n"); - puts("BACKTRACER | x29 : "); - puthex64(regs->x29); - puts("\n"); - puts("BACKTRACER | x30 : "); - puthex64(regs->x30); - puts("\n"); - puts("BACKTRACER | x9 : "); - puthex64(regs->x9); - puts("\n"); - puts("BACKTRACER | x10 : "); - puthex64(regs->x10); - puts("\n"); - puts("BACKTRACER | x11 : "); - puthex64(regs->x11); - puts("\n"); - puts("BACKTRACER | x12 : "); - puthex64(regs->x12); - puts("\n"); - puts("BACKTRACER | x13 : "); - puthex64(regs->x13); - puts("\n"); - puts("BACKTRACER | x14 : "); - puthex64(regs->x14); - puts("\n"); - puts("BACKTRACER | x15 : "); - puthex64(regs->x15); - puts("\n"); - puts("BACKTRACER | x19 : "); - puthex64(regs->x19); - puts("\n"); - puts("BACKTRACER | x20 : "); - puthex64(regs->x20); - puts("\n"); - puts("BACKTRACER | x21 : "); - puthex64(regs->x21); - puts("\n"); - puts("BACKTRACER | x22 : "); - puthex64(regs->x22); - puts("\n"); - puts("BACKTRACER | x23 : "); - puthex64(regs->x23); - puts("\n"); - puts("BACKTRACER | x24 : "); - puthex64(regs->x24); - puts("\n"); - puts("BACKTRACER | x25 : "); - puthex64(regs->x25); - puts("\n"); - puts("BACKTRACER | x26 : "); - puthex64(regs->x26); - puts("\n"); - puts("BACKTRACER | x27 : "); - puthex64(regs->x27); - puts("\n"); - puts("BACKTRACER | x28 : "); - puthex64(regs->x28); - puts("\n"); - puts("BACKTRACER | tpidr_el0 : "); - puthex64(regs->tpidr_el0); - puts("\n"); - puts("BACKTRACER | tpidrro_el0 : "); - puthex64(regs->tpidrro_el0); - puts("\n"); + LOG("Registers: \n"); + LOG("pc : %#016lx\n", regs->pc); + LOG("sp: %#016lx\n", regs->sp); + LOG("spsr : %#016lx\n", regs->spsr); + LOG("x0 : %#016lx\n", regs->x0); + LOG("x1 : %#016lx\n", regs->x1); + LOG("x2 : %#016lx\n", regs->x2); + LOG("x3 : %#016lx\n", regs->x3); + LOG("x4 : %#016lx\n", regs->x4); + LOG("x5 : %#016lx\n", regs->x5); + LOG("x6 : %#016lx\n", regs->x6); + LOG("x7 : %#016lx\n", regs->x7); + LOG("x8 : %#016lx\n", regs->x8); + LOG("x16 : %#016lx\n", regs->x16); + LOG("x17 : %#016lx\n", regs->x17); + LOG("x18 : %#016lx\n", regs->x18); + LOG("x29 : %#016lx\n", regs->x29); + LOG("x30 : %#016lx\n", regs->x30); + LOG("x9 : %#016lx\n", regs->x9); + LOG("x10 : %#016lx\n", regs->x10); + LOG("x11 : %#016lx\n", regs->x11); + LOG("x12 : %#016lx\n", regs->x12); + LOG("x13 : %#016lx\n", regs->x13); + LOG("x14 : %#016lx\n", regs->x14); + LOG("x15 : %#016lx\n", regs->x15); + LOG("x19 : %#016lx\n", regs->x19); + LOG("x20 : %#016lx\n", regs->x20); + LOG("x21 : %#016lx\n", regs->x21); + LOG("x22 : %#016lx\n", regs->x22); + LOG("x23 : %#016lx\n", regs->x23); + LOG("x24 : %#016lx\n", regs->x24); + LOG("x25 : %#016lx\n", regs->x25); + LOG("x26 : %#016lx\n", regs->x26); + LOG("x27 : %#016lx\n", regs->x27); + LOG("x28 : %#016lx\n", regs->x28); + LOG("tpidr_el0 : %#016lx\n", regs->tpidr_el0); + LOG("tpidrro_el0 : %#016lx\n", regs->tpidrro_el0); #elif defined(__x86_64__) - puts("BACKTRACER | Registers: \n"); - puts("BACKTRACER | rip : "); - puthex64(regs->rip); - puts("\n"); - puts("BACKTRACER | rsp : "); - puthex64(regs->rsp); - puts("\n"); - puts("BACKTRACER | rflags : "); - puthex64(regs->rflags); - puts("\n"); - puts("BACKTRACER | rax : "); - puthex64(regs->rax); - puts("\n"); - puts("BACKTRACER | rbx : "); - puthex64(regs->rbx); - puts("\n"); - puts("BACKTRACER | rcx : "); - puthex64(regs->rcx); - puts("\n"); - puts("BACKTRACER | rdx : "); - puthex64(regs->rdx); - puts("\n"); - puts("BACKTRACER | rsi : "); - puthex64(regs->rsi); - puts("\n"); - puts("BACKTRACER | rdi : "); - puthex64(regs->rdi); - puts("\n"); - puts("BACKTRACER | rbp : "); - puthex64(regs->rbp); - puts("\n"); - puts("BACKTRACER | r8 : "); - puthex64(regs->r8); - puts("\n"); - puts("BACKTRACER | r9 : "); - puthex64(regs->r9); - puts("\n"); - puts("BACKTRACER | r10 : "); - puthex64(regs->r10); - puts("\n"); - puts("BACKTRACER | r11 : "); - puthex64(regs->r11); - puts("\n"); - puts("BACKTRACER | r12 : "); - puthex64(regs->r12); - puts("\n"); - puts("BACKTRACER | r13 : "); - puthex64(regs->r13); - puts("\n"); - puts("BACKTRACER | r14 : "); - puthex64(regs->r14); - puts("\n"); - puts("BACKTRACER | r15 : "); - puthex64(regs->r15); - puts("\n"); - puts("BACKTRACER | fs_base : "); - puthex64(regs->fs_base); - puts("\n"); - puts("BACKTRACER | gs_base : "); - puthex64(regs->gs_base); - puts("\n"); + LOG("Registers: \n"); + LOG("rip : %#016lx\n", regs->rip); + LOG("rsp : %#016lx\n", regs->rsp); + LOG("rflags : %#016lx\n", regs->rflags); + LOG("rax : %#016lx\n", regs->rax); + LOG("rbx : %#016lx\n", regs->rbx); + LOG("rcx : %#016lx\n", regs->rcx); + LOG("rdx : %#016lx\n", regs->rdx); + LOG("rsi : %#016lx\n", regs->rsi); + LOG("rdi : %#016lx\n", regs->rdi); + LOG("rbp : %#016lx\n", regs->rbp); + LOG("r8 : %#016lx\n", regs->r8); + LOG("r9 : %#016lx\n", regs->r9); + LOG("r10 : %#016lx\n", regs->r10); + LOG("r11 : %#016lx\n", regs->r11); + LOG("r12 : %#016lx\n", regs->r12); + LOG("r13 : %#016lx\n", regs->r13); + LOG("r14 : %#016lx\n", regs->r14); + LOG("r15 : %#016lx\n", regs->r15); + LOG("fs_base : %#016lx\n", regs->fs_base); + LOG("gs_base : %#016lx\n", regs->gs_base); #endif } @@ -625,13 +434,9 @@ static void riscv_print_vm_fault() seL4_Word fault_addr = seL4_GetMR(seL4_VMFault_Addr); seL4_Word is_instruction = seL4_GetMR(seL4_VMFault_PrefetchFault); seL4_Word fsr = seL4_GetMR(seL4_VMFault_FSR); - puts("BACKTRACER | VMFault: ip="); - puthex64(ip); - puts(" fault_addr="); + LOG("BACKTRACER | VMFault: ip=%#016lx\n", ip); puthex64(fault_addr); - puts(" fsr="); - puthex64(fsr); - puts(" "); + puts(" fsr=%#016lx\n", fsr); puts(is_instruction ? "(instruction fault)" : "(data fault)"); puts("\n"); puts("BACKTRACER | description of fault: "); @@ -673,24 +478,10 @@ static void aarch64_print_vm_fault() seL4_Word ec = fsr >> 26; seL4_Word il = fsr >> 25 & 1; seL4_Word iss = fsr & 0x1ffffffUL; - puts("BACKTRACER | VMFault: ip="); - puthex64(ip); - puts(" fault_addr="); - puthex64(fault_addr); - puts(" fsr="); - puthex64(fsr); - puts(" "); - puts(is_instruction ? "(instruction fault)" : "(data fault)"); - puts("\n"); - puts("BACKTRACER | ec: "); - puthex32(ec); - puts(" "); - puts(ec_to_string(ec)); - puts(" il: "); - puts(il ? "1" : "0"); - puts(" iss: "); - puthex32(iss); - puts("\n"); + LOG("VMFault: ip=%#016lx fault_addr=%#016lx\n", ip, fault_addr); + LOG(" fsr=%#016lx %s\n", fsr, is_instruction ? "(instruction fault)" : "(data fault)"); + LOG(" ec: %#08lx %s\n", ec, ec_to_string(ec)); + LOG(" il: %s iss: %#08lx\n", il ? "1" : "0", iss); if (ec == 0x24) { /* FIXME: Note, this is not a complete decoding of the fault! Just some of @@ -701,24 +492,20 @@ static void aarch64_print_vm_fault() bool cm = (iss >> 8) & 1; bool s1ptw = (iss >> 7) & 1; bool wnr = (iss >> 6) & 1; - puts("BACKTRACER | dfsc = "); - puts(data_abort_dfsc_to_string(dfsc)); - puts(" ("); - puthex32(dfsc); - puts(")"); + LOG(" dfsc = %s (%#08lx)", data_abort_dfsc_to_string(dfsc), dfsc); if (ea) { - puts(" -- external abort"); + sddf_printf(" -- external abort"); } if (cm) { - puts(" -- cache maint"); + sddf_printf(" -- cache maint"); } if (s1ptw) { - puts(" -- stage 2 fault for stage 1 page table walk"); + sddf_printf(" -- stage 2 fault for stage 1 page table walk"); } if (wnr) { - puts(" -- write not read"); + sddf_printf(" -- write not read"); } - puts("\n"); + sddf_printf("\n"); } } #endif @@ -734,24 +521,15 @@ static void print_fault_error(microkit_child child, microkit_msginfo msginfo) /* This is a request from our PD to become passive */ err = seL4_SchedContext_Bind(BASE_SCHED_CONTEXT_CAP + child, BASE_NOTIFICATION_CAP + child); if (err != seL4_NoError) { - puts("BACKTRACER | could not bind scheduling context to notification " + LOG("could not bind scheduling context to notification " "object\n"); } else { - puts("MON|INFO: PD '"); - puts(pd_names[child]); - puts("' is now passive!\n"); + LOG("PD id: '%d' is now passive!\n", child); } - return; } - puts("BACKTRACER | received message "); - puthex32(label); - puts(" badge: "); - puthex64(badge); - puts(" tcb cap: "); - puthex64(tcb_cap); - puts("\n"); + LOG("received message %#08lx badge: %#016lx tcb cap: %#016lx\n", label, badge, tcb_cap); switch (label) { case seL4_Fault_CapFault: { @@ -764,54 +542,45 @@ static void print_fault_error(microkit_child child, microkit_msginfo msginfo) seL4_Word guard_found = seL4_GetMR(seL4_CapFault_GuardMismatch_GuardFound); seL4_Word guard_bits_found = seL4_GetMR(seL4_CapFault_GuardMismatch_BitsFound); - puts("BACKTRACER | CapFault: ip="); - puthex64(ip); - puts(" fault_addr="); - puthex64(fault_addr); - puts(" in_recv_phase="); - puts(in_recv_phase == 0 ? "false" : "true"); - puts(" lookup_failure_type="); + LOG("CapFault: ip=%#016lx fault_addr=%#016lx in_recv_phase=%s", ip, fault_addr, in_recv_phase == 0 ? "false" : "true"); + sddf_printf(" lookup_failure_type="); switch (lookup_failure_type) { case seL4_NoFailure: - puts("seL4_NoFailure"); + sddf_printf("seL4_NoFailure"); break; case seL4_InvalidRoot: - puts("seL4_InvalidRoot"); + sddf_printf("seL4_InvalidRoot"); break; case seL4_MissingCapability: - puts("seL4_MissingCapability"); + sddf_printf("seL4_MissingCapability"); break; case seL4_DepthMismatch: - puts("seL4_DepthMismatch"); + sddf_printf("seL4_DepthMismatch"); break; case seL4_GuardMismatch: - puts("seL4_GuardMismatch"); + sddf_printf("seL4_GuardMismatch"); break; default: - puthex64(lookup_failure_type); + sddf_printf("%#016lx", lookup_failure_type); } if (lookup_failure_type == seL4_MissingCapability || lookup_failure_type == seL4_DepthMismatch || lookup_failure_type == seL4_GuardMismatch) { - puts(" bits_left="); - puthex64(bits_left); + sddf_printf(" bits_left=%#016lx", bits_left); } if (lookup_failure_type == seL4_DepthMismatch) { - puts(" depth_bits_found="); - puthex64(depth_bits_found); + sddf_printf(" depth_bits_found=%#016lx", depth_bits_found); } if (lookup_failure_type == seL4_GuardMismatch) { - puts(" guard_found="); - puthex64(guard_found); - puts(" guard_bits_found="); - puthex64(guard_bits_found); + sddf_printf(" guard_found=%#016lx", guard_found); + sddf_printf(" guard_bits_found=%#016lx", guard_bits_found); } - puts("\n"); + sddf_printf("\n"); break; } case seL4_Fault_UserException: { - puts("BACKTRACER | UserException\n"); + LOG("UserException\n"); break; } case seL4_Fault_VMFault: { @@ -824,14 +593,6 @@ static void print_fault_error(microkit_child child, microkit_msginfo msginfo) #else #error "Unknown architecture to print a VM fault for" #endif - - seL4_Word fault_addr = seL4_GetMR(seL4_VMFault_Addr); - seL4_Word stack_addr = pd_stack_bottom_addrs[child]; - if (fault_addr < stack_addr && fault_addr >= stack_addr - 0x1000) { - puts("BACKTRACER | potential stack overflow, fault address within one " - "page outside of stack region\n"); - } - break; } #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT @@ -839,27 +600,22 @@ static void print_fault_error(microkit_child child, microkit_msginfo msginfo) seL4_Word esr = seL4_GetMR(seL4_VCPUFault_HSR); seL4_Word ec = esr >> 26; - puts("BACKTRACER | received vCPU fault with ESR: "); - puthex64(esr); - puts("\n"); + LOG("received vCPU fault with ESR: %#016lx\n", esr); seL4_Word esr_comment = esr & ESR_COMMENT_MASK; if (ec == ARM64_BRK_EC && ((esr_comment & ~UBSAN_ARM64_BRK_MASK) == UBSAN_ARM64_BRK_IMM)) { /* We likely have a UBSAN check going off from a brk instruction */ seL4_Word ubsan_code = esr_comment & UBSAN_ARM64_BRK_MASK; - puts("BACKTRACER | potential undefined behaviour detected by UBSAN for: " - "'"); - puts(usban_code_to_string(ubsan_code)); - puts("'\n"); + LOG("potential undefined behaviour detected by UBSAN for: " + "'%s'\n", usban_code_to_string(ubsan_code)); } else { - puts("BACKTRACER | Unknown vCPU fault\n"); + LOG("Unknown vCPU fault\n"); } break; } #endif default: - puts("BACKTRACER | Unknown fault\n"); - puthex64(label); + LOG("Unknown fault: %#016lx\n", label); break; } } diff --git a/components/backtracer/util.h b/components/backtracer/util.h deleted file mode 100644 index c1423c423..000000000 --- a/components/backtracer/util.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once -/* - * Copyright 2021, Breakaway Consulting Pty. Ltd. - * - * SPDX-License-Identifier: BSD-2-Clause - */ -#include -#include - -static void putc(uint8_t ch) -{ -#if defined(CONFIG_PRINTING) - seL4_DebugPutChar(ch); -#endif -} - -static void puts(const char *s) -{ - while (*s) { - putc(*s); - s++; - } -} - -static char hexchar(unsigned int v) -{ - return v < 10 ? '0' + v : ('a' - 10) + v; -} - -static void puthex32(uint32_t val) -{ - char buffer[8 + 3]; - buffer[0] = '0'; - buffer[1] = 'x'; - buffer[8 + 3 - 1] = 0; - for (unsigned i = 8 + 1; i > 1; i--) { - buffer[i] = hexchar(val & 0xf); - val >>= 4; - } - puts(buffer); -} - -static void puthex64(uint64_t val) -{ - char buffer[16 + 3]; - buffer[0] = '0'; - buffer[1] = 'x'; - buffer[16 + 3 - 1] = 0; - for (unsigned i = 16 + 1; i > 1; i--) { - buffer[i] = hexchar(val & 0xf); - val >>= 4; - } - puts(buffer); -} - -static void fail(char *s) -{ - puts("FAIL: "); - puts(s); - puts("\n"); - for (;;) {} -} - -static char *sel4_strerror(seL4_Word err) -{ - switch (err) { - case seL4_NoError: - return "seL4_NoError"; - case seL4_InvalidArgument: - return "seL4_InvalidArgument"; - case seL4_InvalidCapability: - return "seL4_InvalidCapability"; - case seL4_IllegalOperation: - return "seL4_IllegalOperation"; - case seL4_RangeError: - return "seL4_RangeError"; - case seL4_AlignmentError: - return "seL4_AlignmentError"; - case seL4_FailedLookup: - return "seL4_FailedLookup"; - case seL4_TruncatedMessage: - return "seL4_TruncatedMessage"; - case seL4_DeleteFirst: - return "seL4_DeleteFirst"; - case seL4_RevokeFirst: - return "seL4_RevokeFirst"; - case seL4_NotEnoughMemory: - return "seL4_NotEnoughMemory"; - } - - return ""; -}