mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 10:40:00 +00:00
更好的panic+kdbg
This commit is contained in:
@@ -12,6 +12,7 @@ set(USER_CC "cc" CACHE STRING "User-space C compiler")
|
||||
set(USER_LD "ld" CACHE STRING "User-space linker")
|
||||
set(RUSTC "rustc" CACHE STRING "Rust compiler")
|
||||
set(NM "nm" CACHE STRING "nm executable")
|
||||
set(ADDR2LINE "addr2line" CACHE STRING "addr2line executable")
|
||||
|
||||
set(XORRISO "xorriso" CACHE STRING "xorriso executable")
|
||||
set(TAR "tar" CACHE STRING "tar executable")
|
||||
@@ -102,6 +103,7 @@ resolve_tool_with_fallback(LD ld.lld ld)
|
||||
resolve_tool_with_fallback(USER_CC cc gcc clang)
|
||||
resolve_tool_with_fallback(USER_LD ld.lld ld)
|
||||
resolve_tool_with_fallback(NM llvm-nm x86_64-elf-nm nm)
|
||||
resolve_tool_with_fallback(ADDR2LINE llvm-addr2line x86_64-elf-addr2line addr2line)
|
||||
resolve_tool_with_fallback(OBJCOPY_FOR_TARGET llvm-objcopy x86_64-linux-gnu-objcopy objcopy)
|
||||
resolve_tool_with_fallback(OBJDUMP_FOR_TARGET llvm-objdump x86_64-linux-gnu-objdump objdump)
|
||||
resolve_tool_with_fallback(READELF_FOR_TARGET llvm-readelf x86_64-linux-gnu-readelf readelf)
|
||||
@@ -121,6 +123,7 @@ set(CFLAGS_COMMON
|
||||
-ffreestanding
|
||||
-fno-stack-protector
|
||||
-fno-builtin
|
||||
-g
|
||||
-Wall
|
||||
-Wextra
|
||||
-Werror
|
||||
@@ -339,6 +342,7 @@ add_custom_command(
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${BUILD_ROOT}"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"-DNM_TOOL=${NM}"
|
||||
"-DADDR2LINE_TOOL=${ADDR2LINE}"
|
||||
"-DKERNEL_ELF=${KERNEL_ELF}"
|
||||
"-DOUT_SYMBOL_FILE=${KERNEL_SYMBOLS_FILE}"
|
||||
-P "${CMAKE_SOURCE_DIR}/cmake/gen_kernel_symbols.cmake"
|
||||
@@ -382,7 +386,7 @@ set(USER_SHELL_COMMAND_APPS
|
||||
help args ls cat grep head tail wc cut uniq sort pwd cd exec pid spawn wait sleep yield
|
||||
bg fg jobs kill ps top
|
||||
shutdown restart exit clear ansi ansitest wavplay fastfetch memstat fsstat taskstat userstat
|
||||
shstat stats tty dmesg kbdstat mkdir touch write append cp mv rm
|
||||
shstat stats tty dmesg kbdstat mkdir touch write append cp mv rm kdbg
|
||||
)
|
||||
|
||||
foreach(SRC IN LISTS USER_APP_MAIN_SOURCES)
|
||||
@@ -546,6 +550,7 @@ add_custom_target(setup-tools
|
||||
"-DOBJDUMP_TOOL=${OBJDUMP_FOR_TARGET}"
|
||||
"-DREADELF_TOOL=${READELF_FOR_TARGET}"
|
||||
"-DNM_TOOL=${NM}"
|
||||
"-DADDR2LINE_TOOL=${ADDR2LINE}"
|
||||
"-DUSER_CC_TOOL=${USER_CC}"
|
||||
"-DUSER_LD_TOOL=${USER_LD}"
|
||||
"-DRUSTC_TOOL=${RUSTC}"
|
||||
|
||||
@@ -31,6 +31,7 @@ static int ush_cmd_help(void) {
|
||||
ush_writeln(" wait <pid> / fg [pid]");
|
||||
ush_writeln(" kill <pid> [signal]");
|
||||
ush_writeln(" jobs [-a] / ps [-a] [-u] / top [--once] [-n loops] [-d ticks]");
|
||||
ush_writeln(" kdbg sym <addr> / kdbg bt <rbp> <rip> / kdbg regs");
|
||||
ush_writeln(" sleep <ticks>");
|
||||
ush_writeln(" spin (busy loop test for Alt+Ctrl+C)");
|
||||
ush_writeln(" yield");
|
||||
|
||||
269
cleonos/c/apps/kdbg_main.c
Normal file
269
cleonos/c/apps/kdbg_main.c
Normal file
@@ -0,0 +1,269 @@
|
||||
#include "cmd_runtime.h"
|
||||
|
||||
#define USH_KDBG_TEXT_MAX 2048ULL
|
||||
|
||||
static int ush_kdbg_is_hex(char ch) {
|
||||
if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 ush_kdbg_hex_value(char ch) {
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
return (u64)(ch - '0');
|
||||
}
|
||||
|
||||
if (ch >= 'a' && ch <= 'f') {
|
||||
return 10ULL + (u64)(ch - 'a');
|
||||
}
|
||||
|
||||
return 10ULL + (u64)(ch - 'A');
|
||||
}
|
||||
|
||||
static int ush_kdbg_parse_u64(const char *text, u64 *out_value) {
|
||||
u64 value = 0ULL;
|
||||
u64 i = 0ULL;
|
||||
int is_hex = 0;
|
||||
|
||||
if (text == (const char *)0 || out_value == (u64 *)0 || text[0] == '\0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) {
|
||||
i = 2ULL;
|
||||
is_hex = 1;
|
||||
} else if (text[0] == 'x' || text[0] == 'X') {
|
||||
i = 1ULL;
|
||||
is_hex = 1;
|
||||
}
|
||||
|
||||
if (is_hex != 0) {
|
||||
if (text[i] == '\0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (text[i] != '\0') {
|
||||
u64 digit;
|
||||
|
||||
if (ush_kdbg_is_hex(text[i]) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
digit = ush_kdbg_hex_value(text[i]);
|
||||
|
||||
if (value > ((0xFFFFFFFFFFFFFFFFULL - digit) >> 4U)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = (value << 4U) | digit;
|
||||
i++;
|
||||
}
|
||||
|
||||
*out_value = value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ush_parse_u64_dec(text, out_value);
|
||||
}
|
||||
|
||||
static int ush_kdbg_next_token(const char **io_cursor, char *out, u64 out_size) {
|
||||
const char *p;
|
||||
u64 n = 0ULL;
|
||||
|
||||
if (io_cursor == (const char **)0 || out == (char *)0 || out_size == 0ULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = *io_cursor;
|
||||
out[0] = '\0';
|
||||
|
||||
if (p == (const char *)0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*p != '\0' && ush_is_space(*p) != 0) {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p == '\0') {
|
||||
*io_cursor = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*p != '\0' && ush_is_space(*p) == 0) {
|
||||
if (n + 1ULL < out_size) {
|
||||
out[n++] = *p;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
out[n] = '\0';
|
||||
*io_cursor = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ush_kdbg_has_more_tokens(const char *cursor) {
|
||||
if (cursor == (const char *)0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*cursor != '\0') {
|
||||
if (ush_is_space(*cursor) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
cursor++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ush_kdbg_usage(void) {
|
||||
ush_writeln("usage:");
|
||||
ush_writeln(" kdbg sym <addr>");
|
||||
ush_writeln(" kdbg bt <rbp> <rip>");
|
||||
ush_writeln(" kdbg regs");
|
||||
}
|
||||
|
||||
static int ush_cmd_kdbg(const char *arg) {
|
||||
const char *cursor = arg;
|
||||
char subcmd[USH_CMD_MAX];
|
||||
char tok0[USH_PATH_MAX];
|
||||
char tok1[USH_PATH_MAX];
|
||||
char out[USH_KDBG_TEXT_MAX];
|
||||
u64 got;
|
||||
u64 value0;
|
||||
u64 value1;
|
||||
|
||||
if (ush_kdbg_next_token(&cursor, subcmd, (u64)sizeof(subcmd)) == 0) {
|
||||
ush_kdbg_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ush_streq(subcmd, "sym") != 0) {
|
||||
if (ush_kdbg_next_token(&cursor, tok0, (u64)sizeof(tok0)) == 0 || ush_kdbg_has_more_tokens(cursor) != 0) {
|
||||
ush_kdbg_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ush_kdbg_parse_u64(tok0, &value0) == 0) {
|
||||
ush_writeln("kdbg: invalid addr");
|
||||
return 0;
|
||||
}
|
||||
|
||||
got = cleonos_sys_kdbg_sym(value0, out, (u64)sizeof(out));
|
||||
|
||||
if (got == 0ULL) {
|
||||
ush_writeln("kdbg: sym failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
out[(u64)sizeof(out) - 1ULL] = '\0';
|
||||
ush_writeln(out);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ush_streq(subcmd, "bt") != 0) {
|
||||
if (ush_kdbg_next_token(&cursor, tok0, (u64)sizeof(tok0)) == 0 ||
|
||||
ush_kdbg_next_token(&cursor, tok1, (u64)sizeof(tok1)) == 0 ||
|
||||
ush_kdbg_has_more_tokens(cursor) != 0) {
|
||||
ush_kdbg_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ush_kdbg_parse_u64(tok0, &value0) == 0 || ush_kdbg_parse_u64(tok1, &value1) == 0) {
|
||||
ush_writeln("kdbg: invalid rbp/rip");
|
||||
return 0;
|
||||
}
|
||||
|
||||
got = cleonos_sys_kdbg_bt(value0, value1, out, (u64)sizeof(out));
|
||||
|
||||
if (got == 0ULL) {
|
||||
ush_writeln("kdbg: bt failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
out[(u64)sizeof(out) - 1ULL] = '\0';
|
||||
ush_write(out);
|
||||
if (got > (u64)sizeof(out) - 1ULL) {
|
||||
got = (u64)sizeof(out) - 1ULL;
|
||||
}
|
||||
if (got > 0ULL && out[got - 1ULL] != '\n') {
|
||||
ush_write_char('\n');
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ush_streq(subcmd, "regs") != 0) {
|
||||
if (ush_kdbg_has_more_tokens(cursor) != 0) {
|
||||
ush_kdbg_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
got = cleonos_sys_kdbg_regs(out, (u64)sizeof(out));
|
||||
|
||||
if (got == 0ULL) {
|
||||
ush_writeln("kdbg: regs failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
out[(u64)sizeof(out) - 1ULL] = '\0';
|
||||
ush_write(out);
|
||||
if (got > (u64)sizeof(out) - 1ULL) {
|
||||
got = (u64)sizeof(out) - 1ULL;
|
||||
}
|
||||
if (got > 0ULL && out[got - 1ULL] != '\n') {
|
||||
ush_write_char('\n');
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
ush_kdbg_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cleonos_app_main(void) {
|
||||
ush_cmd_ctx ctx;
|
||||
ush_cmd_ret ret;
|
||||
ush_state sh;
|
||||
char initial_cwd[USH_PATH_MAX];
|
||||
int has_context = 0;
|
||||
int success = 0;
|
||||
const char *arg = "";
|
||||
|
||||
ush_zero(&ctx, (u64)sizeof(ctx));
|
||||
ush_zero(&ret, (u64)sizeof(ret));
|
||||
ush_init_state(&sh);
|
||||
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
|
||||
|
||||
if (ush_command_ctx_read(&ctx) != 0) {
|
||||
if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "kdbg") != 0) {
|
||||
has_context = 1;
|
||||
arg = ctx.arg;
|
||||
if (ctx.cwd[0] == '/') {
|
||||
ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd);
|
||||
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
success = ush_cmd_kdbg(arg);
|
||||
|
||||
if (has_context != 0) {
|
||||
if (ush_streq(sh.cwd, initial_cwd) == 0) {
|
||||
ret.flags |= USH_CMD_RET_FLAG_CWD;
|
||||
ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd);
|
||||
}
|
||||
|
||||
if (sh.exit_requested != 0) {
|
||||
ret.flags |= USH_CMD_RET_FLAG_EXIT;
|
||||
ret.exit_code = sh.exit_code;
|
||||
}
|
||||
|
||||
(void)ush_command_ret_write(&ret);
|
||||
}
|
||||
|
||||
return (success != 0) ? 0 : 1;
|
||||
}
|
||||
@@ -156,6 +156,7 @@ static int ush_cmd_help(void) {
|
||||
ush_writeln(" wait <pid> / fg [pid]");
|
||||
ush_writeln(" kill <pid> [signal]");
|
||||
ush_writeln(" jobs [-a] / ps [-a] [-u] / top [--once] [-n loops] [-d ticks]");
|
||||
ush_writeln(" kdbg sym <addr> / kdbg bt <rbp> <rip> / kdbg regs");
|
||||
ush_writeln(" sleep <ticks>");
|
||||
ush_writeln(" yield");
|
||||
ush_writeln(" shutdown / restart");
|
||||
|
||||
@@ -100,6 +100,9 @@ typedef struct cleonos_proc_snapshot {
|
||||
#define CLEONOS_SYSCALL_PROC_PID_AT 62ULL
|
||||
#define CLEONOS_SYSCALL_PROC_SNAPSHOT 63ULL
|
||||
#define CLEONOS_SYSCALL_PROC_KILL 64ULL
|
||||
#define CLEONOS_SYSCALL_KDBG_SYM 65ULL
|
||||
#define CLEONOS_SYSCALL_KDBG_BT 66ULL
|
||||
#define CLEONOS_SYSCALL_KDBG_REGS 67ULL
|
||||
|
||||
u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
||||
u64 cleonos_sys_log_write(const char *message, u64 length);
|
||||
@@ -166,5 +169,8 @@ u64 cleonos_sys_proc_count(void);
|
||||
u64 cleonos_sys_proc_pid_at(u64 index, u64 *out_pid);
|
||||
u64 cleonos_sys_proc_snapshot(u64 pid, cleonos_proc_snapshot *out_snapshot, u64 out_size);
|
||||
u64 cleonos_sys_proc_kill(u64 pid, u64 signal);
|
||||
u64 cleonos_sys_kdbg_sym(u64 addr, char *out_line, u64 out_size);
|
||||
u64 cleonos_sys_kdbg_bt(u64 rbp, u64 rip, char *out_text, u64 out_size);
|
||||
u64 cleonos_sys_kdbg_regs(char *out_text, u64 out_size);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -268,3 +268,29 @@ u64 cleonos_sys_proc_snapshot(u64 pid, cleonos_proc_snapshot *out_snapshot, u64
|
||||
u64 cleonos_sys_proc_kill(u64 pid, u64 signal) {
|
||||
return cleonos_syscall(CLEONOS_SYSCALL_PROC_KILL, pid, signal, 0ULL);
|
||||
}
|
||||
|
||||
struct cleonos_kdbg_bt_req {
|
||||
u64 rbp;
|
||||
u64 rip;
|
||||
u64 out_ptr;
|
||||
u64 out_size;
|
||||
};
|
||||
|
||||
u64 cleonos_sys_kdbg_sym(u64 addr, char *out_line, u64 out_size) {
|
||||
return cleonos_syscall(CLEONOS_SYSCALL_KDBG_SYM, addr, (u64)out_line, out_size);
|
||||
}
|
||||
|
||||
u64 cleonos_sys_kdbg_bt(u64 rbp, u64 rip, char *out_text, u64 out_size) {
|
||||
struct cleonos_kdbg_bt_req req;
|
||||
|
||||
req.rbp = rbp;
|
||||
req.rip = rip;
|
||||
req.out_ptr = (u64)out_text;
|
||||
req.out_size = out_size;
|
||||
|
||||
return cleonos_syscall(CLEONOS_SYSCALL_KDBG_BT, (u64)&req, 0ULL, 0ULL);
|
||||
}
|
||||
|
||||
u64 cleonos_sys_kdbg_regs(char *out_text, u64 out_size) {
|
||||
return cleonos_syscall(CLEONOS_SYSCALL_KDBG_REGS, (u64)out_text, out_size, 0ULL);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,9 @@
|
||||
#define CLKS_SYSCALL_PROC_PID_AT 62ULL
|
||||
#define CLKS_SYSCALL_PROC_SNAPSHOT 63ULL
|
||||
#define CLKS_SYSCALL_PROC_KILL 64ULL
|
||||
#define CLKS_SYSCALL_KDBG_SYM 65ULL
|
||||
#define CLKS_SYSCALL_KDBG_BT 66ULL
|
||||
#define CLKS_SYSCALL_KDBG_REGS 67ULL
|
||||
|
||||
void clks_syscall_init(void);
|
||||
u64 clks_syscall_dispatch(void *frame_ptr);
|
||||
|
||||
@@ -229,14 +229,19 @@ static clks_bool clks_panic_parse_symbol_line(const char *line,
|
||||
usize len,
|
||||
u64 *out_addr,
|
||||
const char **out_name,
|
||||
usize *out_name_len) {
|
||||
usize *out_name_len,
|
||||
const char **out_source,
|
||||
usize *out_source_len) {
|
||||
usize i = 0U;
|
||||
u64 addr = 0ULL;
|
||||
u32 digits = 0U;
|
||||
usize name_start;
|
||||
usize name_end;
|
||||
usize source_start;
|
||||
usize source_end;
|
||||
|
||||
if (line == CLKS_NULL || out_addr == CLKS_NULL || out_name == CLKS_NULL || out_name_len == CLKS_NULL) {
|
||||
if (line == CLKS_NULL || out_addr == CLKS_NULL || out_name == CLKS_NULL || out_name_len == CLKS_NULL ||
|
||||
out_source == CLKS_NULL || out_source_len == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
@@ -267,20 +272,34 @@ static clks_bool clks_panic_parse_symbol_line(const char *line,
|
||||
}
|
||||
|
||||
name_start = i;
|
||||
name_end = len;
|
||||
|
||||
while (name_end > name_start &&
|
||||
(line[name_end - 1U] == ' ' || line[name_end - 1U] == '\t' || line[name_end - 1U] == '\r')) {
|
||||
name_end--;
|
||||
while (i < len && line[i] != ' ' && line[i] != '\t' && line[i] != '\r') {
|
||||
i++;
|
||||
}
|
||||
|
||||
name_end = i;
|
||||
|
||||
if (name_end <= name_start) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
while (i < len && (line[i] == ' ' || line[i] == '\t')) {
|
||||
i++;
|
||||
}
|
||||
|
||||
source_start = i;
|
||||
source_end = len;
|
||||
|
||||
while (source_end > source_start &&
|
||||
(line[source_end - 1U] == ' ' || line[source_end - 1U] == '\t' || line[source_end - 1U] == '\r')) {
|
||||
source_end--;
|
||||
}
|
||||
|
||||
*out_addr = addr;
|
||||
*out_name = &line[name_start];
|
||||
*out_name_len = name_end - name_start;
|
||||
*out_source = (source_end > source_start) ? &line[source_start] : CLKS_NULL;
|
||||
*out_source_len = (source_end > source_start) ? (source_end - source_start) : 0U;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
@@ -309,22 +328,32 @@ static clks_bool clks_panic_symbols_ready(void) {
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_panic_lookup_symbol(u64 addr, const char **out_name, usize *out_name_len, u64 *out_base) {
|
||||
static clks_bool clks_panic_lookup_symbol(u64 addr,
|
||||
const char **out_name,
|
||||
usize *out_name_len,
|
||||
u64 *out_base,
|
||||
const char **out_source,
|
||||
usize *out_source_len) {
|
||||
const char *data;
|
||||
const char *end;
|
||||
const char *line;
|
||||
const char *best_name = CLKS_NULL;
|
||||
const char *best_source = CLKS_NULL;
|
||||
usize best_len = 0U;
|
||||
usize best_source_len = 0U;
|
||||
u64 best_addr = 0ULL;
|
||||
clks_bool found = CLKS_FALSE;
|
||||
|
||||
if (out_name == CLKS_NULL || out_name_len == CLKS_NULL || out_base == CLKS_NULL) {
|
||||
if (out_name == CLKS_NULL || out_name_len == CLKS_NULL || out_base == CLKS_NULL || out_source == CLKS_NULL ||
|
||||
out_source_len == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_name = CLKS_NULL;
|
||||
*out_name_len = 0U;
|
||||
*out_base = 0ULL;
|
||||
*out_source = CLKS_NULL;
|
||||
*out_source_len = 0U;
|
||||
|
||||
if (clks_panic_symbols_ready() == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
@@ -337,6 +366,8 @@ static clks_bool clks_panic_lookup_symbol(u64 addr, const char **out_name, usize
|
||||
u64 line_addr;
|
||||
const char *line_name;
|
||||
usize line_name_len;
|
||||
const char *line_source;
|
||||
usize line_source_len;
|
||||
usize line_len = 0U;
|
||||
|
||||
line = data;
|
||||
@@ -350,7 +381,13 @@ static clks_bool clks_panic_lookup_symbol(u64 addr, const char **out_name, usize
|
||||
data++;
|
||||
}
|
||||
|
||||
if (clks_panic_parse_symbol_line(line, line_len, &line_addr, &line_name, &line_name_len) == CLKS_FALSE) {
|
||||
if (clks_panic_parse_symbol_line(line,
|
||||
line_len,
|
||||
&line_addr,
|
||||
&line_name,
|
||||
&line_name_len,
|
||||
&line_source,
|
||||
&line_source_len) == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -358,6 +395,8 @@ static clks_bool clks_panic_lookup_symbol(u64 addr, const char **out_name, usize
|
||||
best_addr = line_addr;
|
||||
best_name = line_name;
|
||||
best_len = line_name_len;
|
||||
best_source = line_source;
|
||||
best_source_len = line_source_len;
|
||||
found = CLKS_TRUE;
|
||||
}
|
||||
}
|
||||
@@ -369,6 +408,8 @@ static clks_bool clks_panic_lookup_symbol(u64 addr, const char **out_name, usize
|
||||
*out_name = best_name;
|
||||
*out_name_len = best_len;
|
||||
*out_base = best_addr;
|
||||
*out_source = best_source;
|
||||
*out_source_len = best_source_len;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
@@ -376,13 +417,15 @@ static void clks_panic_emit_bt_entry(struct clks_panic_console *console, u32 ind
|
||||
char index_dec[12];
|
||||
char rip_hex[19];
|
||||
const char *sym_name = CLKS_NULL;
|
||||
const char *sym_source = CLKS_NULL;
|
||||
usize sym_name_len = 0U;
|
||||
usize sym_source_len = 0U;
|
||||
u64 sym_base = 0ULL;
|
||||
clks_bool has_symbol;
|
||||
|
||||
clks_panic_u32_to_dec(index, index_dec, sizeof(index_dec));
|
||||
clks_panic_u64_to_hex(rip, rip_hex);
|
||||
has_symbol = clks_panic_lookup_symbol(rip, &sym_name, &sym_name_len, &sym_base);
|
||||
has_symbol = clks_panic_lookup_symbol(rip, &sym_name, &sym_name_len, &sym_base, &sym_source, &sym_source_len);
|
||||
|
||||
clks_serial_write("[PANIC][BT] #");
|
||||
clks_serial_write(index_dec);
|
||||
@@ -398,6 +441,11 @@ static void clks_panic_emit_bt_entry(struct clks_panic_console *console, u32 ind
|
||||
clks_panic_serial_write_n(sym_name, sym_name_len);
|
||||
clks_serial_write("+");
|
||||
clks_serial_write(off_hex);
|
||||
|
||||
if (sym_source != CLKS_NULL && sym_source_len > 0U) {
|
||||
clks_serial_write(" @ ");
|
||||
clks_panic_serial_write_n(sym_source, sym_source_len);
|
||||
}
|
||||
}
|
||||
|
||||
clks_serial_write("\n");
|
||||
@@ -420,6 +468,11 @@ static void clks_panic_emit_bt_entry(struct clks_panic_console *console, u32 ind
|
||||
clks_panic_console_write_n(console, sym_name, sym_name_len);
|
||||
clks_panic_console_write(console, "+");
|
||||
clks_panic_console_write(console, off_hex);
|
||||
|
||||
if (sym_source != CLKS_NULL && sym_source_len > 0U) {
|
||||
clks_panic_console_write(console, " @ ");
|
||||
clks_panic_console_write_n(console, sym_source, sym_source_len);
|
||||
}
|
||||
}
|
||||
|
||||
clks_panic_console_write(console, "\n");
|
||||
|
||||
@@ -27,6 +27,11 @@
|
||||
#define CLKS_SYSCALL_ITEM_MAX 128U
|
||||
#define CLKS_SYSCALL_PROCFS_TEXT_MAX 2048U
|
||||
#define CLKS_SYSCALL_USER_TRACE_BUDGET 128ULL
|
||||
#define CLKS_SYSCALL_KDBG_TEXT_MAX 2048U
|
||||
#define CLKS_SYSCALL_KDBG_BT_MAX_FRAMES 16U
|
||||
#define CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES (128ULL * 1024ULL)
|
||||
#define CLKS_SYSCALL_KERNEL_SYMBOL_FILE "/system/kernel.sym"
|
||||
#define CLKS_SYSCALL_KERNEL_ADDR_BASE 0xFFFF800000000000ULL
|
||||
|
||||
struct clks_syscall_frame {
|
||||
u64 rax;
|
||||
@@ -53,9 +58,21 @@ struct clks_syscall_frame {
|
||||
u64 ss;
|
||||
};
|
||||
|
||||
struct clks_syscall_kdbg_bt_req {
|
||||
u64 rbp;
|
||||
u64 rip;
|
||||
u64 out_ptr;
|
||||
u64 out_size;
|
||||
};
|
||||
|
||||
static clks_bool clks_syscall_ready = CLKS_FALSE;
|
||||
static clks_bool clks_syscall_user_trace_active = CLKS_FALSE;
|
||||
static u64 clks_syscall_user_trace_budget = 0ULL;
|
||||
static struct clks_syscall_frame clks_syscall_last_frame;
|
||||
static clks_bool clks_syscall_last_frame_valid = CLKS_FALSE;
|
||||
static clks_bool clks_syscall_symbols_checked = CLKS_FALSE;
|
||||
static const char *clks_syscall_symbols_data = CLKS_NULL;
|
||||
static u64 clks_syscall_symbols_size = 0ULL;
|
||||
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
static inline void clks_syscall_outb(u16 port, u8 value) {
|
||||
@@ -104,6 +121,24 @@ static clks_bool clks_syscall_copy_user_optional_string(u64 src_addr, char *dst,
|
||||
return clks_syscall_copy_user_string(src_addr, dst, dst_size);
|
||||
}
|
||||
|
||||
static u64 clks_syscall_copy_text_to_user(u64 dst_addr, u64 dst_size, const char *src, usize src_len) {
|
||||
usize copy_len;
|
||||
|
||||
if (dst_addr == 0ULL || dst_size == 0ULL || src == CLKS_NULL) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
copy_len = src_len;
|
||||
|
||||
if (copy_len + 1U > (usize)dst_size) {
|
||||
copy_len = (usize)dst_size - 1U;
|
||||
}
|
||||
|
||||
clks_memcpy((void *)dst_addr, src, copy_len);
|
||||
((char *)dst_addr)[copy_len] = '\0';
|
||||
return (u64)copy_len;
|
||||
}
|
||||
|
||||
static u64 clks_syscall_log_write(u64 arg0, u64 arg1) {
|
||||
const char *src = (const char *)arg0;
|
||||
u64 len = arg1;
|
||||
@@ -336,6 +371,461 @@ static usize clks_syscall_procfs_append_u64_hex(char *out, usize out_size, usize
|
||||
return pos;
|
||||
}
|
||||
|
||||
static usize clks_syscall_procfs_append_n(char *out, usize out_size, usize pos, const char *text, usize text_len) {
|
||||
usize i = 0U;
|
||||
|
||||
if (text == CLKS_NULL) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
while (i < text_len) {
|
||||
pos = clks_syscall_procfs_append_char(out, out_size, pos, text[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static clks_bool clks_syscall_is_hex(char ch) {
|
||||
if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
static u8 clks_syscall_hex_value(char ch) {
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
return (u8)(ch - '0');
|
||||
}
|
||||
|
||||
if (ch >= 'a' && ch <= 'f') {
|
||||
return (u8)(10 + (ch - 'a'));
|
||||
}
|
||||
|
||||
return (u8)(10 + (ch - 'A'));
|
||||
}
|
||||
|
||||
static clks_bool clks_syscall_parse_symbol_line(const char *line,
|
||||
usize len,
|
||||
u64 *out_addr,
|
||||
const char **out_name,
|
||||
usize *out_name_len,
|
||||
const char **out_source,
|
||||
usize *out_source_len) {
|
||||
usize i = 0U;
|
||||
u64 addr = 0ULL;
|
||||
u32 digits = 0U;
|
||||
usize name_start;
|
||||
usize name_end;
|
||||
usize source_start;
|
||||
usize source_end;
|
||||
|
||||
if (line == CLKS_NULL || out_addr == CLKS_NULL || out_name == CLKS_NULL || out_name_len == CLKS_NULL ||
|
||||
out_source == CLKS_NULL || out_source_len == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (len == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (len >= 2U && line[0] == '0' && (line[1] == 'X' || line[1] == 'x')) {
|
||||
i = 2U;
|
||||
}
|
||||
|
||||
while (i < len && clks_syscall_is_hex(line[i]) == CLKS_TRUE) {
|
||||
addr = (addr << 4) | (u64)clks_syscall_hex_value(line[i]);
|
||||
digits++;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (digits == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
while (i < len && (line[i] == ' ' || line[i] == '\t')) {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i >= len) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
name_start = i;
|
||||
|
||||
while (i < len && line[i] != ' ' && line[i] != '\t' && line[i] != '\r') {
|
||||
i++;
|
||||
}
|
||||
|
||||
name_end = i;
|
||||
|
||||
if (name_end <= name_start) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
while (i < len && (line[i] == ' ' || line[i] == '\t')) {
|
||||
i++;
|
||||
}
|
||||
|
||||
source_start = i;
|
||||
source_end = len;
|
||||
|
||||
while (source_end > source_start &&
|
||||
(line[source_end - 1U] == ' ' || line[source_end - 1U] == '\t' || line[source_end - 1U] == '\r')) {
|
||||
source_end--;
|
||||
}
|
||||
|
||||
*out_addr = addr;
|
||||
*out_name = &line[name_start];
|
||||
*out_name_len = name_end - name_start;
|
||||
*out_source = (source_end > source_start) ? &line[source_start] : CLKS_NULL;
|
||||
*out_source_len = (source_end > source_start) ? (source_end - source_start) : 0U;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_syscall_symbols_ready(void) {
|
||||
const void *data;
|
||||
u64 size = 0ULL;
|
||||
|
||||
if (clks_syscall_symbols_checked == CLKS_TRUE) {
|
||||
return (clks_syscall_symbols_data != CLKS_NULL && clks_syscall_symbols_size > 0ULL) ? CLKS_TRUE : CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_syscall_symbols_checked = CLKS_TRUE;
|
||||
|
||||
if (clks_fs_is_ready() == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
data = clks_fs_read_all(CLKS_SYSCALL_KERNEL_SYMBOL_FILE, &size);
|
||||
|
||||
if (data == CLKS_NULL || size == 0ULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_syscall_symbols_data = (const char *)data;
|
||||
clks_syscall_symbols_size = size;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_syscall_lookup_symbol(u64 addr,
|
||||
const char **out_name,
|
||||
usize *out_name_len,
|
||||
u64 *out_base,
|
||||
const char **out_source,
|
||||
usize *out_source_len) {
|
||||
const char *data;
|
||||
const char *end;
|
||||
const char *line;
|
||||
const char *best_name = CLKS_NULL;
|
||||
const char *best_source = CLKS_NULL;
|
||||
usize best_name_len = 0U;
|
||||
usize best_source_len = 0U;
|
||||
u64 best_addr = 0ULL;
|
||||
clks_bool found = CLKS_FALSE;
|
||||
|
||||
if (out_name == CLKS_NULL || out_name_len == CLKS_NULL || out_base == CLKS_NULL || out_source == CLKS_NULL ||
|
||||
out_source_len == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_name = CLKS_NULL;
|
||||
*out_name_len = 0U;
|
||||
*out_base = 0ULL;
|
||||
*out_source = CLKS_NULL;
|
||||
*out_source_len = 0U;
|
||||
|
||||
if (clks_syscall_symbols_ready() == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
data = clks_syscall_symbols_data;
|
||||
end = clks_syscall_symbols_data + clks_syscall_symbols_size;
|
||||
|
||||
while (data < end) {
|
||||
u64 line_addr;
|
||||
const char *line_name;
|
||||
usize line_name_len;
|
||||
const char *line_source;
|
||||
usize line_source_len;
|
||||
usize line_len = 0U;
|
||||
|
||||
line = data;
|
||||
|
||||
while (data < end && *data != '\n') {
|
||||
data++;
|
||||
line_len++;
|
||||
}
|
||||
|
||||
if (data < end && *data == '\n') {
|
||||
data++;
|
||||
}
|
||||
|
||||
if (clks_syscall_parse_symbol_line(line,
|
||||
line_len,
|
||||
&line_addr,
|
||||
&line_name,
|
||||
&line_name_len,
|
||||
&line_source,
|
||||
&line_source_len) == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line_addr <= addr && (found == CLKS_FALSE || line_addr >= best_addr)) {
|
||||
best_addr = line_addr;
|
||||
best_name = line_name;
|
||||
best_name_len = line_name_len;
|
||||
best_source = line_source;
|
||||
best_source_len = line_source_len;
|
||||
found = CLKS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_name = best_name;
|
||||
*out_name_len = best_name_len;
|
||||
*out_base = best_addr;
|
||||
*out_source = best_source;
|
||||
*out_source_len = best_source_len;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static usize clks_syscall_kdbg_format_symbol_into(char *out, usize out_size, usize pos, u64 addr) {
|
||||
const char *sym_name = CLKS_NULL;
|
||||
const char *sym_source = CLKS_NULL;
|
||||
usize sym_name_len = 0U;
|
||||
usize sym_source_len = 0U;
|
||||
u64 sym_base = 0ULL;
|
||||
clks_bool has_symbol;
|
||||
|
||||
pos = clks_syscall_procfs_append_u64_hex(out, out_size, pos, addr);
|
||||
has_symbol = clks_syscall_lookup_symbol(addr, &sym_name, &sym_name_len, &sym_base, &sym_source, &sym_source_len);
|
||||
|
||||
if (has_symbol == CLKS_TRUE) {
|
||||
pos = clks_syscall_procfs_append_char(out, out_size, pos, ' ');
|
||||
pos = clks_syscall_procfs_append_n(out, out_size, pos, sym_name, sym_name_len);
|
||||
pos = clks_syscall_procfs_append_char(out, out_size, pos, '+');
|
||||
pos = clks_syscall_procfs_append_u64_hex(out, out_size, pos, addr - sym_base);
|
||||
|
||||
if (sym_source != CLKS_NULL && sym_source_len > 0U) {
|
||||
pos = clks_syscall_procfs_append_text(out, out_size, pos, " @ ");
|
||||
pos = clks_syscall_procfs_append_n(out, out_size, pos, sym_source, sym_source_len);
|
||||
}
|
||||
} else {
|
||||
pos = clks_syscall_procfs_append_text(out, out_size, pos, " <no-symbol>");
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static usize clks_syscall_kdbg_append_bt_frame(char *out, usize out_size, usize pos, u64 index, u64 rip) {
|
||||
pos = clks_syscall_procfs_append_char(out, out_size, pos, '#');
|
||||
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, index);
|
||||
pos = clks_syscall_procfs_append_char(out, out_size, pos, ' ');
|
||||
pos = clks_syscall_kdbg_format_symbol_into(out, out_size, pos, rip);
|
||||
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
|
||||
return pos;
|
||||
}
|
||||
|
||||
static clks_bool clks_syscall_kdbg_stack_ptr_valid(u64 ptr, u64 stack_low, u64 stack_high) {
|
||||
if ((ptr & 0x7ULL) != 0ULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (ptr < stack_low || ptr + 16ULL > stack_high) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (ptr < CLKS_SYSCALL_KERNEL_ADDR_BASE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static u64 clks_syscall_kdbg_sym(u64 arg0, u64 arg1, u64 arg2) {
|
||||
char text[CLKS_SYSCALL_KDBG_TEXT_MAX];
|
||||
usize len;
|
||||
|
||||
if (arg1 == 0ULL || arg2 == 0ULL) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
text[0] = '\0';
|
||||
len = clks_syscall_kdbg_format_symbol_into(text, sizeof(text), 0U, arg0);
|
||||
return clks_syscall_copy_text_to_user(arg1, arg2, text, len);
|
||||
}
|
||||
|
||||
static u64 clks_syscall_kdbg_regs(u64 arg0, u64 arg1) {
|
||||
char text[CLKS_SYSCALL_KDBG_TEXT_MAX];
|
||||
usize pos = 0U;
|
||||
const struct clks_syscall_frame *frame = &clks_syscall_last_frame;
|
||||
|
||||
if (arg0 == 0ULL || arg1 == 0ULL) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
text[0] = '\0';
|
||||
|
||||
if (clks_syscall_last_frame_valid == CLKS_FALSE) {
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "NO REG SNAPSHOT\n");
|
||||
return clks_syscall_copy_text_to_user(arg0, arg1, text, pos);
|
||||
}
|
||||
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "RAX=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rax);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RBX=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rbx);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RCX=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rcx);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RDX=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rdx);
|
||||
pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n');
|
||||
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "RSI=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rsi);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RDI=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rdi);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RBP=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rbp);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RSP=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rsp);
|
||||
pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n');
|
||||
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "R8 =");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r8);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R9 =");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r9);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R10=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r10);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R11=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r11);
|
||||
pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n');
|
||||
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "R12=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r12);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R13=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r13);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R14=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r14);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R15=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r15);
|
||||
pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n');
|
||||
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "RIP=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rip);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " CS=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->cs);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RFLAGS=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rflags);
|
||||
pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n');
|
||||
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "VECTOR=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->vector);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " ERROR=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->error_code);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " SS=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->ss);
|
||||
pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n');
|
||||
|
||||
return clks_syscall_copy_text_to_user(arg0, arg1, text, pos);
|
||||
}
|
||||
|
||||
static u64 clks_syscall_kdbg_bt(u64 arg0) {
|
||||
struct clks_syscall_kdbg_bt_req req;
|
||||
char text[CLKS_SYSCALL_KDBG_TEXT_MAX];
|
||||
usize pos = 0U;
|
||||
u64 frame_index = 0ULL;
|
||||
|
||||
if (arg0 == 0ULL) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
clks_memcpy(&req, (const void *)arg0, sizeof(req));
|
||||
|
||||
if (req.out_ptr == 0ULL || req.out_size == 0ULL) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
text[0] = '\0';
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "BT RBP=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, req.rbp);
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RIP=");
|
||||
pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, req.rip);
|
||||
pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n');
|
||||
|
||||
if (req.rip != 0ULL) {
|
||||
pos = clks_syscall_kdbg_append_bt_frame(text, sizeof(text), pos, frame_index, req.rip);
|
||||
frame_index++;
|
||||
}
|
||||
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
{
|
||||
u64 current_rbp = req.rbp;
|
||||
u64 current_rsp = 0ULL;
|
||||
u64 stack_low;
|
||||
u64 stack_high;
|
||||
|
||||
__asm__ volatile("mov %%rsp, %0" : "=r"(current_rsp));
|
||||
|
||||
stack_low = (current_rsp > CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES)
|
||||
? (current_rsp - CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES)
|
||||
: CLKS_SYSCALL_KERNEL_ADDR_BASE;
|
||||
stack_high = current_rsp + CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES;
|
||||
|
||||
if (stack_high < current_rsp) {
|
||||
stack_high = 0xFFFFFFFFFFFFFFFFULL;
|
||||
}
|
||||
|
||||
if (stack_low < CLKS_SYSCALL_KERNEL_ADDR_BASE) {
|
||||
stack_low = CLKS_SYSCALL_KERNEL_ADDR_BASE;
|
||||
}
|
||||
|
||||
if (clks_syscall_kdbg_stack_ptr_valid(current_rbp, stack_low, stack_high) == CLKS_TRUE) {
|
||||
while (frame_index < CLKS_SYSCALL_KDBG_BT_MAX_FRAMES) {
|
||||
const u64 *frame_ptr;
|
||||
u64 next_rbp;
|
||||
u64 ret_rip;
|
||||
|
||||
frame_ptr = (const u64 *)(usize)current_rbp;
|
||||
next_rbp = frame_ptr[0];
|
||||
ret_rip = frame_ptr[1];
|
||||
|
||||
if (ret_rip == 0ULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
pos = clks_syscall_kdbg_append_bt_frame(text, sizeof(text), pos, frame_index, ret_rip);
|
||||
frame_index++;
|
||||
|
||||
if (next_rbp <= current_rbp) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (clks_syscall_kdbg_stack_ptr_valid(next_rbp, stack_low, stack_high) == CLKS_FALSE) {
|
||||
break;
|
||||
}
|
||||
|
||||
current_rbp = next_rbp;
|
||||
}
|
||||
} else {
|
||||
pos = clks_syscall_procfs_append_text(text,
|
||||
sizeof(text),
|
||||
pos,
|
||||
"NOTE: stack walk skipped (rbp not in current kernel stack window)\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "NOTE: stack walk unsupported on this arch\n");
|
||||
#endif
|
||||
|
||||
return clks_syscall_copy_text_to_user(req.out_ptr, req.out_size, text, pos);
|
||||
}
|
||||
|
||||
static clks_bool clks_syscall_procfs_snapshot_for_path(const char *path, struct clks_exec_proc_snapshot *out_snap) {
|
||||
u64 pid;
|
||||
|
||||
@@ -1043,6 +1533,11 @@ void clks_syscall_init(void) {
|
||||
clks_syscall_ready = CLKS_TRUE;
|
||||
clks_syscall_user_trace_active = CLKS_FALSE;
|
||||
clks_syscall_user_trace_budget = 0ULL;
|
||||
clks_memset(&clks_syscall_last_frame, 0, sizeof(clks_syscall_last_frame));
|
||||
clks_syscall_last_frame_valid = CLKS_FALSE;
|
||||
clks_syscall_symbols_checked = CLKS_FALSE;
|
||||
clks_syscall_symbols_data = CLKS_NULL;
|
||||
clks_syscall_symbols_size = 0ULL;
|
||||
clks_log(CLKS_LOG_INFO, "SYSCALL", "INT80 FRAMEWORK ONLINE");
|
||||
}
|
||||
|
||||
@@ -1054,6 +1549,9 @@ u64 clks_syscall_dispatch(void *frame_ptr) {
|
||||
return (u64)-1;
|
||||
}
|
||||
|
||||
clks_memcpy(&clks_syscall_last_frame, frame, sizeof(clks_syscall_last_frame));
|
||||
clks_syscall_last_frame_valid = CLKS_TRUE;
|
||||
|
||||
id = frame->rax;
|
||||
clks_syscall_trace_user_program(id);
|
||||
|
||||
@@ -1195,6 +1693,12 @@ u64 clks_syscall_dispatch(void *frame_ptr) {
|
||||
return clks_syscall_audio_play_tone(frame->rbx, frame->rcx);
|
||||
case CLKS_SYSCALL_AUDIO_STOP:
|
||||
return clks_syscall_audio_stop();
|
||||
case CLKS_SYSCALL_KDBG_SYM:
|
||||
return clks_syscall_kdbg_sym(frame->rbx, frame->rcx, frame->rdx);
|
||||
case CLKS_SYSCALL_KDBG_BT:
|
||||
return clks_syscall_kdbg_bt(frame->rbx);
|
||||
case CLKS_SYSCALL_KDBG_REGS:
|
||||
return clks_syscall_kdbg_regs(frame->rbx, frame->rcx);
|
||||
default:
|
||||
return (u64)-1;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ require_tool("${OBJCOPY_TOOL}")
|
||||
require_tool("${OBJDUMP_TOOL}")
|
||||
require_tool("${READELF_TOOL}")
|
||||
require_tool("${NM_TOOL}")
|
||||
require_tool("${ADDR2LINE_TOOL}")
|
||||
require_tool("${USER_CC_TOOL}")
|
||||
require_tool("${USER_LD_TOOL}")
|
||||
require_tool("${RUSTC_TOOL}")
|
||||
|
||||
@@ -4,6 +4,10 @@ if(NOT DEFINED NM_TOOL OR "${NM_TOOL}" STREQUAL "")
|
||||
message(FATAL_ERROR "NM_TOOL is required")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED ADDR2LINE_TOOL OR "${ADDR2LINE_TOOL}" STREQUAL "")
|
||||
message(FATAL_ERROR "ADDR2LINE_TOOL is required")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED KERNEL_ELF OR "${KERNEL_ELF}" STREQUAL "")
|
||||
message(FATAL_ERROR "KERNEL_ELF is required")
|
||||
endif()
|
||||
@@ -27,7 +31,9 @@ string(REPLACE "\r\n" "\n" _nm_output "${_nm_output}")
|
||||
string(REPLACE "\r" "\n" _nm_output "${_nm_output}")
|
||||
string(REPLACE "\n" ";" _nm_lines "${_nm_output}")
|
||||
|
||||
set(_out_text "CLEONOS_KERNEL_SYMBOLS_V1\n")
|
||||
set(_symbol_addrs_upper)
|
||||
set(_symbol_addrs_query)
|
||||
set(_symbol_names)
|
||||
|
||||
foreach(_line IN LISTS _nm_lines)
|
||||
string(STRIP "${_line}" _line)
|
||||
@@ -45,8 +51,55 @@ foreach(_line IN LISTS _nm_lines)
|
||||
endif()
|
||||
|
||||
string(TOUPPER "${_addr}" _addr_upper)
|
||||
set(_out_text "${_out_text}0X${_addr_upper} ${_name}\n")
|
||||
list(APPEND _symbol_addrs_upper "${_addr_upper}")
|
||||
list(APPEND _symbol_addrs_query "0x${_addr_upper}")
|
||||
list(APPEND _symbol_names "${_name}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(_out_text "CLEONOS_KERNEL_SYMBOLS_V2\n")
|
||||
|
||||
list(LENGTH _symbol_addrs_query _symbol_count)
|
||||
|
||||
if(_symbol_count GREATER 0)
|
||||
execute_process(
|
||||
COMMAND "${ADDR2LINE_TOOL}" -f -C -e "${KERNEL_ELF}" ${_symbol_addrs_query}
|
||||
RESULT_VARIABLE _a2l_result
|
||||
OUTPUT_VARIABLE _a2l_output
|
||||
ERROR_VARIABLE _a2l_error
|
||||
)
|
||||
|
||||
if(NOT _a2l_result EQUAL 0)
|
||||
message(FATAL_ERROR "failed to run addr2line (${_a2l_result}): ${_a2l_error}")
|
||||
endif()
|
||||
|
||||
string(REPLACE "\r\n" "\n" _a2l_output "${_a2l_output}")
|
||||
string(REPLACE "\r" "\n" _a2l_output "${_a2l_output}")
|
||||
string(REPLACE "\n" ";" _a2l_lines "${_a2l_output}")
|
||||
list(LENGTH _a2l_lines _a2l_line_count)
|
||||
|
||||
math(EXPR _last_index "${_symbol_count} - 1")
|
||||
foreach(_idx RANGE 0 ${_last_index})
|
||||
math(EXPR _src_idx "${_idx} * 2 + 1")
|
||||
|
||||
list(GET _symbol_addrs_upper ${_idx} _addr_upper)
|
||||
list(GET _symbol_names ${_idx} _name)
|
||||
|
||||
if(_src_idx LESS _a2l_line_count)
|
||||
list(GET _a2l_lines ${_src_idx} _src_line)
|
||||
else()
|
||||
set(_src_line "??:0")
|
||||
endif()
|
||||
|
||||
string(STRIP "${_src_line}" _src_line)
|
||||
|
||||
if("${_src_line}" STREQUAL "")
|
||||
set(_src_line "??:0")
|
||||
endif()
|
||||
|
||||
string(REPLACE "\t" " " _src_line "${_src_line}")
|
||||
set(_out_text "${_out_text}0X${_addr_upper}\t${_name}\t${_src_line}\n")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
file(WRITE "${OUT_SYMBOL_FILE}" "${_out_text}")
|
||||
|
||||
Reference in New Issue
Block a user