Skip to content

Commit

Permalink
c/debug: StackTrace
Browse files Browse the repository at this point in the history
  • Loading branch information
visualfc committed Nov 30, 2024
1 parent 67f9580 commit 7b6b8b0
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 0 deletions.
26 changes: 26 additions & 0 deletions c/debug/_demo/stacktrace/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"unsafe"

"github.com/goplus/llgo/c/debug"
)

type T struct {
n int
}

func (t *T) Demo() {
println(t.n)
debug.StackTrace(0, func(fr *debug.Frame) bool {
var info debug.Info
debug.Addrinfo(unsafe.Pointer(fr.PC), &info)
println("[", fr.PC, "]", fr.Name, "+", fr.Offset, ", SP =", fr.SP)
return true
})
}

func main() {
t := &T{100}
t.Demo()
}
24 changes: 24 additions & 0 deletions c/debug/_wrap/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#endif

#include <dlfcn.h>
#include <libunwind.h>

void *llgo_address() {
return __builtin_return_address(0);
Expand All @@ -12,3 +13,26 @@ void *llgo_address() {
int llgo_addrinfo(void *addr, Dl_info *info) {
return dladdr(addr, info);
}

void llgo_stacktrace(int skip, void *ctx, int (*fn)(void *ctx, void *pc, void *offset, void *sp, char *name)) {
unw_cursor_t cursor;
unw_context_t context;
unw_word_t offset, pc, sp;
char fname[256];
unw_getcontext(&context);
unw_init_local(&cursor, &context);
int depth = 0;
while (unw_step(&cursor) > 0) {
if (depth < skip) {
depth++;
continue;
}
if (unw_get_reg(&cursor, UNW_REG_IP, &pc) == 0) {
unw_get_proc_name(&cursor, fname, sizeof(fname), &offset);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
if (fn(ctx, (void*)pc, (void*)offset, (void*)sp, fname) == 0) {
return;
}
}
}
}
20 changes: 20 additions & 0 deletions c/debug/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,23 @@ func Address() unsafe.Pointer

//go:linkname Addrinfo C.llgo_addrinfo
func Addrinfo(addr unsafe.Pointer, info *Info) c.Int

//go:linkname stacktrace C.llgo_stacktrace
func stacktrace(skip c.Int, ctx unsafe.Pointer, fn func(ctx, pc, offset, sp unsafe.Pointer, name *c.Char) c.Int)

type Frame struct {
PC uintptr
Offset uintptr
SP unsafe.Pointer
Name string
}

func StackTrace(skip int, fn func(fr *Frame) bool) {
stacktrace(c.Int(1+skip), unsafe.Pointer(&fn), func(ctx, pc, offset, sp unsafe.Pointer, name *c.Char) c.Int {
fn := *(*func(fr *Frame) bool)(ctx)
if !fn(&Frame{uintptr(pc), uintptr(offset), sp, c.GoString(name)}) {
return 0
}
return 1
})
}

0 comments on commit 7b6b8b0

Please sign in to comment.