32#include <XPLMUtilities.h>
39#define DATE_FMT "%Y-%m-%d %H:%M:%S"
40#define PREFIX_FMT "%s %s[%s:%d]: ", timedate, log_prefix, filename, line
42#define MAX_STACK_FRAMES 128
43#define MAX_MODULES 1024
44#define BACKTRACE_STR "Backtrace is:\n"
45#if defined(__GNUC__) || defined(__clang__)
46#define BACKTRACE_STRLEN __builtin_strlen(BACKTRACE_STR)
48#define BACKTRACE_STRLEN strlen(BACKTRACE_STR)
57#define MAX_SYM_NAME_LEN 4096
58#define MAX_BACKTRACE_LEN (64 * 1024)
59static char backtrace_buf[MAX_BACKTRACE_LEN] = { 0 };
60static char symbol_buf[
sizeof (SYMBOL_INFO) +
61 MAX_SYM_NAME_LEN *
sizeof (TCHAR)];
62static char line_buf[
sizeof (IMAGEHLP_LINE64)];
66static HMODULE modules[MAX_MODULES];
67static MODULEINFO mi[MAX_MODULES];
68static DWORD num_modules;
70#define SYMNAME_MAXLEN 4095
73static logfunc_t log_func = NULL;
74static char *log_prefix = NULL;
100 if (func == NULL || prefix == NULL)
140log_impl(
const char *filename,
int line,
const char *fmt, ...)
153log_impl_v(
const char *filename,
int line,
const char *fmt, va_list ap)
158 size_t prefix_len, len;
164 VERIFY(strftime(timedate,
sizeof (timedate), DATE_FMT, tm) != 0);
167 if (log_func == NULL || log_prefix == NULL)
170 prefix_len = snprintf(NULL, 0, PREFIX_FMT);
171 va_copy(ap_copy, ap);
172 len = vsnprintf(NULL, 0, fmt, ap_copy);
174 buf = (
char *)malloc(prefix_len + len + 2);
176 (void) snprintf(buf, prefix_len + 1, PREFIX_FMT);
177 (void) vsnprintf(&buf[prefix_len], len + 1, fmt, ap);
178 (void) sprintf(&buf[strlen(buf)],
"\n");
237find_symbol(
const char *filename,
void *addr,
char *symname,
246 static char symstxtname[MAX_PATH];
247 static char prevsym[SYMNAME_MAXLEN + 1];
248 static const char *sep;
250 static void *prevptr = NULL;
255 sep = strrchr(filename, DIRSEP);
258 lacf_strlcpy(symstxtname, filename, MIN((uintptr_t)(sep - filename) + 1,
259 sizeof (symstxtname)));
260 strncat(symstxtname, DIRSEP_S
"syms.txt",
sizeof (symstxtname));
261 fp = fopen(symstxtname,
"rb");
266 static char unused_c;
268 static char sym[SYMNAME_MAXLEN + 1];
270 if (fscanf(fp,
"%p %c %" SCANF_STR_AUTOLEN(SYMNAME_MAXLEN)
"s",
271 &ptr, &unused_c, sym) != 3) {
280 }
while (c !=
'\n' && c !=
'\r' && c != EOF);
287 if (addr >= prevptr && addr < ptr) {
288 snprintf(symname, symname_cap,
"%s+%x", prevsym,
289 (
unsigned)(addr - prevptr));
299find_module(LPVOID pc, DWORD64 *module_base)
302 for (i = 0; i < num_modules; i++) {
303 static LPVOID start, end;
304 start = mi[i].lpBaseOfDll;
305 end = start + mi[i].SizeOfImage;
306 if (start <= pc && end > pc) {
307 *module_base = (DWORD64)start;
316gather_module_info(
void)
318 HANDLE process = GetCurrentProcess();
320 EnumProcessModules(process, modules,
sizeof (HMODULE) * MAX_MODULES,
322 num_modules = MIN(num_modules, MAX_MODULES);
323 for (DWORD i = 0; i < num_modules; i++)
324 GetModuleInformation(process, modules[i], &mi[i],
sizeof (*mi));
330 static unsigned frames;
331 static void *stack[MAX_STACK_FRAMES];
332 static SYMBOL_INFO *symbol;
333 static HANDLE process;
334 static DWORD displacement;
335 static IMAGEHLP_LINE64 *line;
336 static char filename[MAX_PATH];
340 frames = RtlCaptureStackBackTrace(skip_frames + 1, MAX_STACK_FRAMES,
343 process = GetCurrentProcess();
345 SymInitialize(process, NULL, TRUE);
346 SymSetOptions(SYMOPT_LOAD_LINES);
348 gather_module_info();
350 memset(symbol_buf, 0,
sizeof (symbol_buf));
351 memset(line_buf, 0,
sizeof (line_buf));
353 symbol = (SYMBOL_INFO *)symbol_buf;
354 symbol->MaxNameLen = MAX_SYM_NAME_LEN - 1;
355 symbol->SizeOfStruct =
sizeof (SYMBOL_INFO);
357 line = (IMAGEHLP_LINE64 *)line_buf;
358 line->SizeOfStruct =
sizeof (*line);
360 backtrace_buf[0] =
'\0';
361 lacf_strlcpy(backtrace_buf, BACKTRACE_STR,
sizeof (backtrace_buf));
363 for (
unsigned frame_nr = 0; frame_nr < frames; frame_nr++) {
364 static DWORD64 address;
367 address = (DWORD64)(uintptr_t)stack[frame_nr];
368 fill = strlen(backtrace_buf);
370 memset(symbol_buf, 0,
sizeof (symbol_buf));
374 if (!SymFromAddr(process, address, 0, symbol)) {
375 static DWORD64 start;
376 static HMODULE
module;
378 module = find_module((void *)address, &start);
379 if (module != NULL) {
380 static char symname[SYMNAME_MAXLEN + 1];
382 GetModuleFileNameA(module, filename,
384 find_symbol(filename, stack[frame_nr] - start,
385 symname,
sizeof (symname));
386 fill += snprintf(&backtrace_buf[fill],
387 sizeof (backtrace_buf) - fill,
388 "%d %p %s+%p (%s)\n", frame_nr,
389 stack[frame_nr], filename,
390 stack[frame_nr] - start, symname);
392 fill += snprintf(&backtrace_buf[fill],
393 sizeof (backtrace_buf) - fill,
394 "%d %p <unknown module>\n", frame_nr,
403 if (SymGetLineFromAddr64(process, address, &displacement,
405 snprintf(&backtrace_buf[fill],
sizeof (backtrace_buf) -
406 fill,
"%d: %s (0x%lx) [%s:%d]\n", frame_nr,
407 symbol->Name, (
unsigned long)symbol->Address,
408 line->FileName, (
int)line->LineNumber);
410 snprintf(&backtrace_buf[fill],
sizeof (backtrace_buf) -
411 fill,
"%d: %s - 0x%lx\n", frame_nr, symbol->Name,
412 (
unsigned long)symbol->Address);
416 if (log_func == NULL)
418 log_func(backtrace_buf);
419 fputs(backtrace_buf, stderr);
427log_backtrace_sw64(PCONTEXT ctx)
429 static char filename[MAX_PATH];
430 static DWORD64 pcs[MAX_STACK_FRAMES];
431 static unsigned num_stack_frames;
432 static STACKFRAME64 sf;
433 static HANDLE process, thread;
434 static DWORD machine;
438 process = GetCurrentProcess();
439 thread = GetCurrentThread();
441 SymInitialize(process, NULL, TRUE);
442 SymSetOptions(SYMOPT_LOAD_LINES);
444 gather_module_info();
446 memset(&sf, 0,
sizeof (sf));
447 sf.AddrPC.Mode = AddrModeFlat;
448 sf.AddrStack.Mode = AddrModeFlat;
449 sf.AddrFrame.Mode = AddrModeFlat;
451 machine = IMAGE_FILE_MACHINE_I386;
452 sf.AddrPC.Offset = ctx->Eip;
453 sf.AddrStack.Offset = ctx->Esp;
454 sf.AddrFrame.Offset = ctx->Ebp;
456 machine = IMAGE_FILE_MACHINE_AMD64;
457 sf.AddrPC.Offset = ctx->Rip;
458 sf.AddrStack.Offset = ctx->Rsp;
459 sf.AddrFrame.Offset = ctx->Rbp;
460#elif defined(_M_IA64)
461 machine = IMAGE_FILE_MACHINE_IA64;
462 sf.AddrPC.Offset = ctx->StIIP;
463 sf.AddrFrame.Offset = ctx->IntSp;
464 sf.AddrBStore.Offset = ctx->RsBSP;
465 sf.AddrBStore.Mode = AddrModeFlat;
466 sf.AddrStack.Offset = ctx->IntSp;
468#error "Unsupported architecture"
471 for (num_stack_frames = 0; num_stack_frames < MAX_STACK_FRAMES;
472 num_stack_frames++) {
473 if (!StackWalk64(machine, process, thread, &sf, ctx, NULL,
474 SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
477 pcs[num_stack_frames] = sf.AddrPC.Offset;
480 backtrace_buf[0] =
'\0';
481 lacf_strlcpy(backtrace_buf, BACKTRACE_STR,
sizeof (backtrace_buf));
483 for (
unsigned i = 0; i < num_stack_frames; i++) {
486 static char symname[SYMNAME_MAXLEN + 1];
487 static HMODULE
module;
488 static DWORD64 mbase;
490 fill = strlen(backtrace_buf);
493 module = find_module((LPVOID)pc, &mbase);
494 GetModuleFileNameA(module, filename,
sizeof (filename));
495 find_symbol(filename, (
void *)(pc - mbase),
496 symname,
sizeof (symname));
497 fill += snprintf(&backtrace_buf[fill],
498 sizeof (backtrace_buf) - fill,
499 "%d %p %s+%p (%s)\n", i, (
void *)pc, filename,
500 (
void *)(pc - mbase), symname);
503 if (log_func == NULL)
505 log_func(backtrace_buf);
506 fputs(backtrace_buf, stderr);
519 static size_t msg_len;
520 static void *trace[MAX_STACK_FRAMES];
521 static size_t i, j, sz;
522 static char **fnames;
524 sz = backtrace(trace, MAX_STACK_FRAMES);
525 fnames = backtrace_symbols(trace, sz);
527 for (i = 1 + skip_frames, msg_len = BACKTRACE_STRLEN; i < sz; i++)
528 msg_len += snprintf(NULL, 0,
"%s\n", fnames[i]);
530 msg = (
char *)malloc(msg_len + 1);
531 strcpy(msg, BACKTRACE_STR);
532 for (i = 1 + skip_frames, j = BACKTRACE_STRLEN; i < sz; i++)
533 j += sprintf(&msg[j],
"%s\n", fnames[i]);
535 if (log_func == NULL)
void lacf_strlcpy(char *dest, const char *src, size_t cap)
void log_impl_v(const char *filename, int line, const char *fmt, va_list ap)
void log_impl(const char *filename, int line, const char *fmt,...)
void log_init(logfunc_t func, const char *prefix)
void log_backtrace(int skip_frames)
logfunc_t log_get_logfunc(void)
static char * safe_strdup(const char *str2)
static void mutex_destroy(mutex_t *mtx)
static void mutex_enter(mutex_t *mtx)
static void mutex_exit(mutex_t *mtx)
static void mutex_init(mutex_t *mtx)