Last active
February 12, 2026 22:39
-
-
Save bullno1/1045776c12dee6aa69b8bffc70f1cde6 to your computer and use it in GitHub Desktop.
bstacktrace.h on MacOS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #elif defined(__APPLE__) | |
| // macOS {{{ | |
| #include <string.h> | |
| #include <dlfcn.h> | |
| #include <mach/mach.h> | |
| #include <execinfo.h> | |
| // CoreSymbolication {{{ | |
| // CoreSymbolication is a private framework, so we declare the types ourselves | |
| typedef struct _CSTypeRef { | |
| void* csCppData; | |
| void* csCppObj; | |
| } CSTypeRef; | |
| typedef CSTypeRef CSSymbolicatorRef; | |
| typedef CSTypeRef CSSymbolRef; | |
| typedef CSTypeRef CSSymbolOwnerRef; | |
| typedef CSTypeRef CSSourceInfoRef; | |
| #define kCSNow 0x80000000u | |
| // Declare the functions we'll dynamically load | |
| CSSymbolicatorRef CSSymbolicatorCreateWithTask(task_t task); | |
| CSSymbolRef CSSymbolicatorGetSymbolWithAddressAtTime(CSSymbolicatorRef symbolicator, mach_vm_address_t address, uint64_t time); | |
| const char* CSSymbolGetName(CSSymbolRef symbol); | |
| CSSymbolOwnerRef CSSymbolGetSymbolOwner(CSSymbolRef symbol); | |
| const char* CSSymbolOwnerGetPath(CSSymbolOwnerRef owner); | |
| CSSourceInfoRef CSSymbolGetSourceInfo(CSSymbolRef symbol); | |
| const char* CSSourceInfoGetPath(CSSourceInfoRef info); | |
| int CSSourceInfoGetLineNumber(CSSourceInfoRef info); | |
| int CSSourceInfoGetColumn(CSSourceInfoRef info); | |
| int CSIsNull(CSTypeRef ref); | |
| void CSRelease(CSTypeRef ref); | |
| #define BSTACKTRACE_HAS_CORESYMBOLICATION | |
| #define BSTACKTRACE_CORESYM_FN(X) \ | |
| X(CSSymbolicatorCreateWithTask) \ | |
| X(CSSymbolicatorGetSymbolWithAddressAtTime) \ | |
| X(CSSymbolGetName) \ | |
| X(CSSymbolGetSymbolOwner) \ | |
| X(CSSymbolOwnerGetPath) \ | |
| X(CSSymbolGetSourceInfo) \ | |
| X(CSSourceInfoGetPath) \ | |
| X(CSSourceInfoGetLineNumber) \ | |
| X(CSSourceInfoGetColumn) \ | |
| X(CSIsNull) \ | |
| X(CSRelease) | |
| #if __STDC_VERSION__ >= 202311L | |
| # define BSTACKTRACE_TYPEOF(EXP) typeof(EXP) | |
| #elif defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER) | |
| # define BSTACKTRACE_TYPEOF(EXP) __typeof__(EXP) | |
| #endif | |
| #define BSTACKTRACE_DECLARE_FN_PTR(NAME) BSTACKTRACE_TYPEOF(&NAME) NAME; | |
| typedef struct { | |
| void* handle; | |
| BSTACKTRACE_CORESYM_FN(BSTACKTRACE_DECLARE_FN_PTR) | |
| } bstacktrace_coresym_t; | |
| typedef CSSymbolicatorRef bstacktrace_coresym_session_t; | |
| static void | |
| bstacktrace_coresym_load(bstacktrace_coresym_t* lib) { | |
| lib->handle = dlopen("/System/Library/PrivateFrameworks/CoreSymbolication.framework/CoreSymbolication", | |
| RTLD_NOW | RTLD_LOCAL); | |
| if (lib->handle == NULL) { | |
| return; | |
| } | |
| #define BSTACKTRACE_LOAD_SYM(NAME) lib->NAME = (BSTACKTRACE_TYPEOF(lib->NAME))dlsym(lib->handle, #NAME); | |
| BSTACKTRACE_CORESYM_FN(BSTACKTRACE_LOAD_SYM) | |
| } | |
| static void | |
| bstacktrace_coresym_unload(bstacktrace_coresym_t* lib) { | |
| if (lib->handle != NULL) { | |
| dlclose(lib->handle); | |
| } | |
| } | |
| static void | |
| bstacktrace_coresym_session_begin(bstacktrace_coresym_t* lib, bstacktrace_coresym_session_t* session_ptr) { | |
| *session_ptr = (CSSymbolicatorRef){ 0 }; | |
| if (lib->handle == NULL) { return; } | |
| CSSymbolicatorRef symbolicator = lib->CSSymbolicatorCreateWithTask(mach_task_self()); | |
| if (lib->CSIsNull(symbolicator)) { return; } | |
| *session_ptr = symbolicator; | |
| } | |
| static void | |
| bstacktrace_coresym_session_end(bstacktrace_coresym_t* lib, bstacktrace_coresym_session_t* session_ptr) { | |
| CSSymbolicatorRef symbolicator = *session_ptr; | |
| if (lib->CSIsNull(symbolicator)) { return; } | |
| lib->CSRelease(symbolicator); | |
| *session_ptr = (CSSymbolicatorRef){ 0 }; | |
| } | |
| static void | |
| bstacktrace_coresym_resolve( | |
| bstacktrace_coresym_t* lib, | |
| bstacktrace_coresym_session_t symbolicator, | |
| uintptr_t pc, | |
| bstacktrace_resolve_flags_t flags, | |
| bstacktrace_info_t* info | |
| ) { | |
| if (lib->handle == NULL) { return; } | |
| if (lib->CSIsNull(symbolicator)) { return; } | |
| CSSymbolRef symbol = lib->CSSymbolicatorGetSymbolWithAddressAtTime( | |
| symbolicator, pc, kCSNow); | |
| if (lib->CSIsNull(symbol)) { return; } | |
| if (flags & BSTACKTRACE_RESOLVE_FUNCTION) { | |
| info->function = lib->CSSymbolGetName(symbol); | |
| } | |
| if (flags & BSTACKTRACE_RESOLVE_MODULE) { | |
| CSSymbolOwnerRef owner = lib->CSSymbolGetSymbolOwner(symbol); | |
| if (!lib->CSIsNull(owner)) { | |
| info->module = lib->CSSymbolOwnerGetPath(owner); | |
| } | |
| } | |
| if (flags & (BSTACKTRACE_RESOLVE_FILENAME | BSTACKTRACE_RESOLVE_LINE | BSTACKTRACE_RESOLVE_COLUMN)) { | |
| CSSourceInfoRef sourceInfo = lib->CSSymbolGetSourceInfo(symbol); | |
| if (!lib->CSIsNull(sourceInfo)) { | |
| info->filename = lib->CSSourceInfoGetPath(sourceInfo); | |
| info->line = lib->CSSourceInfoGetLineNumber(sourceInfo); | |
| info->column = lib->CSSourceInfoGetColumn(sourceInfo); | |
| } | |
| } | |
| } | |
| // }}} | |
| struct bstacktrace_s { | |
| void* memctx; | |
| bstacktrace_coresym_t coresym; | |
| bstacktrace_coresym_session_t coresym_session; | |
| }; | |
| bstacktrace_t* | |
| bstacktrace_init(void* memctx) { | |
| bstacktrace_t* ctx = BSTACKTRACE_REALLOC(NULL, sizeof(bstacktrace_t), memctx); | |
| *ctx = (bstacktrace_t){ | |
| .memctx = memctx, | |
| }; | |
| bstacktrace_coresym_load(&ctx->coresym); | |
| bstacktrace_coresym_session_begin(&ctx->coresym, &ctx->coresym_session); | |
| return ctx; | |
| } | |
| void | |
| bstacktrace_cleanup(bstacktrace_t* ctx) { | |
| bstacktrace_coresym_session_end(&ctx->coresym, &ctx->coresym_session); | |
| bstacktrace_coresym_unload(&ctx->coresym); | |
| BSTACKTRACE_REALLOC(ctx, 0, ctx->memctx); | |
| } | |
| void | |
| bstacktrace_refresh(bstacktrace_t* ctx) { | |
| bstacktrace_coresym_session_end(&ctx->coresym, &ctx->coresym_session); | |
| bstacktrace_coresym_session_begin(&ctx->coresym, &ctx->coresym_session); | |
| } | |
| BSTACKTRACE_NOINLINE void | |
| bstacktrace_walk( | |
| bstacktrace_t* ctx, | |
| bstacktrace_callback_fn_t callback, | |
| void* userdata | |
| ) { | |
| void* frames[128]; | |
| int count = backtrace(frames, 128); | |
| // Skip the first frame (this function) | |
| for (int i = 1; i < count; ++i) { | |
| if (!callback((uintptr_t)frames[i], userdata)) { | |
| break; | |
| } | |
| } | |
| } | |
| bstacktrace_info_t | |
| bstacktrace_resolve(bstacktrace_t* ctx, uintptr_t address, bstacktrace_resolve_flags_t flags) { | |
| bstacktrace_info_t info = { 0 }; | |
| bstacktrace_coresym_resolve(&ctx->coresym, ctx->coresym_session, address, flags, &info); | |
| return info; | |
| } | |
| // }}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment