Skip to content

Instantly share code, notes, and snippets.

@bullno1
Last active February 12, 2026 22:39
Show Gist options
  • Select an option

  • Save bullno1/1045776c12dee6aa69b8bffc70f1cde6 to your computer and use it in GitHub Desktop.

Select an option

Save bullno1/1045776c12dee6aa69b8bffc70f1cde6 to your computer and use it in GitHub Desktop.
bstacktrace.h on MacOS
#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