stage0 支持类gdb的调试vm手段
This commit is contained in:
103
stage0/spl_vm.c
103
stage0/spl_vm.c
@@ -81,15 +81,17 @@ static int spl_type_size(spl_type_t t) {
|
||||
return -1; \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_ADDR(addr, label) do { \
|
||||
if (vm->debug_addr && (uintptr_t)(addr) < 0x1000) { \
|
||||
fprintf(stderr, "vm: %s at ip=%zd: LOW ADDR=%p sp=%zd fp=%zd\n", \
|
||||
label, vm->ip - 1, (void*)(uintptr_t)(addr), vm->sp, vm->fp); \
|
||||
spl_vm_stackdump(vm, vm->sp); \
|
||||
spl_vm_backtrace(vm, vm->fp); \
|
||||
vm->exit_code = 1; return -1; \
|
||||
} \
|
||||
} while(0)
|
||||
#define CHECK_ADDR(addr, label) \
|
||||
do { \
|
||||
if (vm->debug_addr && (uintptr_t)(addr) < 0x1000) { \
|
||||
fprintf(stderr, "vm: %s at ip=%zd: LOW ADDR=%p sp=%zd fp=%zd\n", label, vm->ip - 1, \
|
||||
(void *)(uintptr_t)(addr), vm->sp, vm->fp); \
|
||||
spl_vm_stackdump(vm, vm->sp); \
|
||||
spl_vm_backtrace(vm, vm->fp); \
|
||||
vm->exit_code = 1; \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* ================================================================
|
||||
* Stack push/pop (stacks.data is pre-allocated in init)
|
||||
@@ -553,12 +555,15 @@ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth) {
|
||||
vec_realloc(vm->stacks, (usize)vm->config.max_stack_depth);
|
||||
vec_init(vm->frames);
|
||||
vec_realloc(vm->frames, (usize)vm->config.max_call_depth);
|
||||
vec_init(vm->breakpoints);
|
||||
vec_init(vm->fn_breakpoints);
|
||||
|
||||
vm->sp = vm->fp = vm->ip = vm->cp = vm->gp = 0;
|
||||
vm->prog = NULL;
|
||||
vm->trace = 0;
|
||||
vm->debug = 1;
|
||||
vm->debug_addr = 0;
|
||||
vm->skip_bp = 0;
|
||||
vm->exit_code = 0;
|
||||
}
|
||||
|
||||
@@ -569,6 +574,68 @@ void spl_vm_drop(spl_vm_t *vm) {
|
||||
return;
|
||||
vec_free(vm->stacks);
|
||||
vec_free(vm->frames);
|
||||
for (usize i = 0; i < vec_size(vm->fn_breakpoints); i++)
|
||||
free(vm->fn_breakpoints.data[i]);
|
||||
vec_free(vm->fn_breakpoints);
|
||||
vec_free(vm->breakpoints);
|
||||
}
|
||||
|
||||
void spl_vm_add_breakpoint(spl_vm_t *vm, usize ip) {
|
||||
if (!vm)
|
||||
return;
|
||||
for (usize i = 0; i < vec_size(vm->breakpoints); i++)
|
||||
if (vm->breakpoints.data[i] == ip)
|
||||
return;
|
||||
vec_push(vm->breakpoints, ip);
|
||||
}
|
||||
|
||||
void spl_vm_add_breakpoint_fn(spl_vm_t *vm, const char *name) {
|
||||
if (!vm || !name)
|
||||
return;
|
||||
for (usize i = 0; i < vec_size(vm->fn_breakpoints); i++)
|
||||
if (strcmp(vm->fn_breakpoints.data[i], name) == 0)
|
||||
return;
|
||||
vec_push(vm->fn_breakpoints, strdup(name));
|
||||
}
|
||||
|
||||
void spl_vm_clear_breakpoints(spl_vm_t *vm) {
|
||||
if (!vm)
|
||||
return;
|
||||
vm->breakpoints.size = 0;
|
||||
for (usize i = 0; i < vec_size(vm->fn_breakpoints); i++)
|
||||
free(vm->fn_breakpoints.data[i]);
|
||||
vm->fn_breakpoints.size = 0;
|
||||
}
|
||||
|
||||
void spl_vm_skip_breakpoint(spl_vm_t *vm) {
|
||||
if (vm)
|
||||
vm->skip_bp = 1;
|
||||
}
|
||||
|
||||
/* 前向声明(定义在文件尾部 dump 区域) */
|
||||
static const char *func_name_by_ip(spl_prog_t *prog, spl_val_t ip);
|
||||
|
||||
/* 函数名断点命中:addr 所在函数名是否在断点表 */
|
||||
static int fn_breakpoint_hit(spl_vm_t *vm, spl_val_t addr) {
|
||||
if (!vm || !vm->prog || !vec_size(vm->fn_breakpoints))
|
||||
return 0;
|
||||
const char *fn = func_name_by_ip(vm->prog, addr);
|
||||
if (!fn)
|
||||
return 0;
|
||||
for (usize i = 0; i < vec_size(vm->fn_breakpoints); i++)
|
||||
if (strcmp(vm->fn_breakpoints.data[i], fn) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ip 断点命中:vm->ip(即将执行的指令)在断点表 */
|
||||
static int ip_breakpoint_hit(spl_vm_t *vm) {
|
||||
if (!vm || !vec_size(vm->breakpoints))
|
||||
return 0;
|
||||
for (usize i = 0; i < vec_size(vm->breakpoints); i++)
|
||||
if (vm->breakpoints.data[i] == (usize)vm->ip)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
@@ -678,6 +745,16 @@ int spl_vm_run_once(spl_vm_t *vm) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 断点:即将执行的指令命中 ip 断点 → 暂停(返回 2)。
|
||||
* skip_bp 置位时执行当前指令(continue 越过当前断点)。 */
|
||||
if (ip_breakpoint_hit(vm)) {
|
||||
if (vm->skip_bp) {
|
||||
vm->skip_bp = 0;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
ins = &vec_at(prog->insns, vm->ip);
|
||||
vm->ip++;
|
||||
|
||||
@@ -870,14 +947,20 @@ int spl_vm_run_once(spl_vm_t *vm) {
|
||||
case SPL_CALL: {
|
||||
spl_val_t _nargs = ins->imm;
|
||||
spl_val_t _addr = POP();
|
||||
int _hit = fn_breakpoint_hit(vm, _addr);
|
||||
spl_vm_call(vm, _addr, _nargs);
|
||||
if (_hit)
|
||||
return 2; /* 已进入函数,暂停在函数入口 */
|
||||
break;
|
||||
}
|
||||
|
||||
case SPL_CALLI: {
|
||||
spl_val_t _addr = POP();
|
||||
spl_val_t _nargs = POP();
|
||||
int _hit = fn_breakpoint_hit(vm, _addr);
|
||||
spl_vm_call(vm, _addr, _nargs);
|
||||
if (_hit)
|
||||
return 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1053,7 +1136,7 @@ int spl_vm_run_once(spl_vm_t *vm) {
|
||||
}
|
||||
|
||||
case SPL_BK: {
|
||||
return 0; /* breakpoint: pause execution */
|
||||
return 2; /* breakpoint: pause execution */
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user