mirror of
https://git.sr.ht/~lattis/muon
synced 2026-01-26 08:07:51 +00:00
add optional native backtrace printing
This commit is contained in:
parent
43c18b047c
commit
45ab272c61
26
include/platform/backtrace.h
Normal file
26
include/platform/backtrace.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Stone Tickle <lattis@mochiro.moe>
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
#ifndef MUON_PLATFORM_BACKTRACE_H
|
||||
#define MUON_PLATFORM_BACKTRACE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "datastructures/arr.h"
|
||||
|
||||
struct platform_backtrace_frame {
|
||||
void *addr, *symbol;
|
||||
const char *symbol_name, *file_name;
|
||||
ptrdiff_t offset;
|
||||
};
|
||||
|
||||
struct platform_backtrace {
|
||||
struct arr frames;
|
||||
};
|
||||
|
||||
void platform_backtrace_capture(struct arena *a, struct platform_backtrace *bt);
|
||||
|
||||
extern bool have_platform_backtrace_capture;
|
||||
#endif
|
||||
@ -106,16 +106,18 @@ foreach native : [false, true]
|
||||
'-Wno-missing-field-initializers',
|
||||
'-Wno-unused-parameter',
|
||||
'-Wold-style-definition',
|
||||
'-Wno-frame-address',
|
||||
'-Woverflow',
|
||||
'-Wstrict-aliasing=2',
|
||||
'-Wstrict-prototypes',
|
||||
'-Wundef',
|
||||
'-Wvla',
|
||||
'-fstrict-aliasing',
|
||||
'-std=c99',
|
||||
'-fno-omit-frame-pointer',
|
||||
'-fmacro-prefix-map=@0@/='.format(
|
||||
fs.relative_to(meson.current_source_dir(), meson.current_build_dir()),
|
||||
),
|
||||
'-std=c99',
|
||||
]
|
||||
endif
|
||||
|
||||
@ -139,6 +141,7 @@ foreach native : [false, true]
|
||||
endforeach
|
||||
|
||||
include_dir = [include_directories('include')]
|
||||
muon_export_dynamic = false
|
||||
|
||||
subdir('tools')
|
||||
subdir('src')
|
||||
@ -195,6 +198,7 @@ muon = executable(
|
||||
c_args: muon_c_args,
|
||||
cpp_args: muon_c_args,
|
||||
install: true,
|
||||
export_dynamic: muon_export_dynamic,
|
||||
)
|
||||
|
||||
subdir('tests')
|
||||
|
||||
@ -55,6 +55,13 @@ option(
|
||||
description: 'select readline implementation',
|
||||
)
|
||||
|
||||
option(
|
||||
'native_backtrace',
|
||||
type: 'feature',
|
||||
value: 'auto',
|
||||
description: 'enable native backtrace capture',
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# build settings
|
||||
################################################################################
|
||||
|
||||
@ -117,6 +117,7 @@
|
||||
#include "platform/assert.c"
|
||||
#include "platform/filesystem.c"
|
||||
#include "platform/mem.c"
|
||||
#include "platform/null/backtrace.c"
|
||||
#include "platform/os.c"
|
||||
#include "platform/path.c"
|
||||
#include "platform/run_cmd.c"
|
||||
|
||||
13
src/main.c
13
src/main.c
@ -36,6 +36,7 @@
|
||||
#include "options.h"
|
||||
#include "opts.h"
|
||||
#include "platform/assert.h"
|
||||
#include "platform/backtrace.h"
|
||||
#include "platform/init.h"
|
||||
#include "platform/os.h"
|
||||
#include "platform/path.h"
|
||||
@ -1324,6 +1325,7 @@ cmd_version(struct workspace *wk, uint32_t argc, uint32_t argi, char *const argv
|
||||
#ifdef __SANITIZE_MEMORY__
|
||||
{ "msan", true },
|
||||
#endif
|
||||
{ "native backtrace", have_platform_backtrace_capture },
|
||||
};
|
||||
|
||||
uint32_t i;
|
||||
@ -1467,6 +1469,16 @@ signal_handler(int signal, const char *signal_name, void *_ctx)
|
||||
|
||||
LOG_I("caught signal %d (%s)", signal, signal_name);
|
||||
|
||||
struct platform_backtrace bt = { 0 };
|
||||
platform_backtrace_capture(wk->a, &bt);
|
||||
|
||||
LOG_I("native backtrace (%d frames):", bt.frames.len);
|
||||
for (uint32_t i = 0; i < bt.frames.len; i++) {
|
||||
const struct platform_backtrace_frame *frame = arr_get(&bt.frames, i);
|
||||
LOG_I("%p <%s+%d> at %s", frame->addr, frame->symbol_name, (int)frame->offset, frame->file_name);
|
||||
}
|
||||
|
||||
log_flush();
|
||||
|
||||
if (wk->vm.run) {
|
||||
vm_error(wk, "encountered unhandled runtime error");
|
||||
@ -1475,6 +1487,7 @@ signal_handler(int signal, const char *signal_name, void *_ctx)
|
||||
backend_print_stack(wk);
|
||||
}
|
||||
|
||||
log_flush();
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@ -31,6 +31,7 @@ if host_machine.system() == 'windows'
|
||||
platform_sources += files(
|
||||
'windows/rpath_fixer.c',
|
||||
'windows/win32_error.c',
|
||||
'null/backtrace.c',
|
||||
)
|
||||
endif
|
||||
|
||||
@ -40,4 +41,26 @@ if platform == 'posix'
|
||||
else
|
||||
platform_sources += files('posix/rpath_fixer.c')
|
||||
endif
|
||||
|
||||
native_backtrace = get_option('native_backtrace').enabled()
|
||||
if get_option('native_backtrace').auto()
|
||||
libdl = cc.find_library('dl', required: false)
|
||||
|
||||
native_backtrace = (
|
||||
cc.has_function('dladdr', prefix: '#include <dlfcn.h>', args: ['-D_BSD_SOURCE'], dependencies: libdl)
|
||||
and cc.has_function('__builtin_frame_address')
|
||||
and cc.has_function('__builtin_return_address')
|
||||
)
|
||||
|
||||
if native_backtrace and libdl.found()
|
||||
deps += libdl
|
||||
endif
|
||||
endif
|
||||
|
||||
if native_backtrace
|
||||
muon_export_dynamic = true
|
||||
platform_sources += files('posix/backtrace.c')
|
||||
else
|
||||
platform_sources += files('null/backtrace.c')
|
||||
endif
|
||||
endif
|
||||
|
||||
13
src/platform/null/backtrace.c
Normal file
13
src/platform/null/backtrace.c
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Stone Tickle <lattis@mochiro.moe>
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
#include "platform/backtrace.h"
|
||||
|
||||
bool have_platform_backtrace_capture = false;
|
||||
|
||||
void
|
||||
platform_backtrace_capture(struct arena *a, struct platform_backtrace *bt)
|
||||
{
|
||||
}
|
||||
320
src/platform/posix/backtrace.c
Normal file
320
src/platform/posix/backtrace.c
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Stone Tickle <lattis@mochiro.moe>
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
// dladdr requires _GNU_SOURCE or _BSD_SOURCE
|
||||
#undef _POSIX_C_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "platform/backtrace.h"
|
||||
|
||||
bool have_platform_backtrace_capture = true;
|
||||
|
||||
static void *
|
||||
backtrace_getreturnaddr(uint8_t level)
|
||||
{
|
||||
switch (level) {
|
||||
case 0: return __builtin_return_address(1);
|
||||
case 1: return __builtin_return_address(2);
|
||||
case 2: return __builtin_return_address(3);
|
||||
case 3: return __builtin_return_address(4);
|
||||
case 4: return __builtin_return_address(5);
|
||||
case 5: return __builtin_return_address(6);
|
||||
case 6: return __builtin_return_address(7);
|
||||
case 7: return __builtin_return_address(8);
|
||||
case 8: return __builtin_return_address(9);
|
||||
case 9: return __builtin_return_address(10);
|
||||
case 10: return __builtin_return_address(11);
|
||||
case 11: return __builtin_return_address(12);
|
||||
case 12: return __builtin_return_address(13);
|
||||
case 13: return __builtin_return_address(14);
|
||||
case 14: return __builtin_return_address(15);
|
||||
case 15: return __builtin_return_address(16);
|
||||
case 16: return __builtin_return_address(17);
|
||||
case 17: return __builtin_return_address(18);
|
||||
case 18: return __builtin_return_address(19);
|
||||
case 19: return __builtin_return_address(20);
|
||||
case 20: return __builtin_return_address(21);
|
||||
case 21: return __builtin_return_address(22);
|
||||
case 22: return __builtin_return_address(23);
|
||||
case 23: return __builtin_return_address(24);
|
||||
case 24: return __builtin_return_address(25);
|
||||
case 25: return __builtin_return_address(26);
|
||||
case 26: return __builtin_return_address(27);
|
||||
case 27: return __builtin_return_address(28);
|
||||
case 28: return __builtin_return_address(29);
|
||||
case 29: return __builtin_return_address(30);
|
||||
case 30: return __builtin_return_address(31);
|
||||
case 31: return __builtin_return_address(32);
|
||||
case 32: return __builtin_return_address(33);
|
||||
case 33: return __builtin_return_address(34);
|
||||
case 34: return __builtin_return_address(35);
|
||||
case 35: return __builtin_return_address(36);
|
||||
case 36: return __builtin_return_address(37);
|
||||
case 37: return __builtin_return_address(38);
|
||||
case 38: return __builtin_return_address(39);
|
||||
case 39: return __builtin_return_address(40);
|
||||
case 40: return __builtin_return_address(41);
|
||||
case 41: return __builtin_return_address(42);
|
||||
case 42: return __builtin_return_address(43);
|
||||
case 43: return __builtin_return_address(44);
|
||||
case 44: return __builtin_return_address(45);
|
||||
case 45: return __builtin_return_address(46);
|
||||
case 46: return __builtin_return_address(47);
|
||||
case 47: return __builtin_return_address(48);
|
||||
case 48: return __builtin_return_address(49);
|
||||
case 49: return __builtin_return_address(50);
|
||||
case 50: return __builtin_return_address(51);
|
||||
case 51: return __builtin_return_address(52);
|
||||
case 52: return __builtin_return_address(53);
|
||||
case 53: return __builtin_return_address(54);
|
||||
case 54: return __builtin_return_address(55);
|
||||
case 55: return __builtin_return_address(56);
|
||||
case 56: return __builtin_return_address(57);
|
||||
case 57: return __builtin_return_address(58);
|
||||
case 58: return __builtin_return_address(59);
|
||||
case 59: return __builtin_return_address(60);
|
||||
case 60: return __builtin_return_address(61);
|
||||
case 61: return __builtin_return_address(62);
|
||||
case 62: return __builtin_return_address(63);
|
||||
case 63: return __builtin_return_address(64);
|
||||
case 64: return __builtin_return_address(65);
|
||||
case 65: return __builtin_return_address(66);
|
||||
case 66: return __builtin_return_address(67);
|
||||
case 67: return __builtin_return_address(68);
|
||||
case 68: return __builtin_return_address(69);
|
||||
case 69: return __builtin_return_address(70);
|
||||
case 70: return __builtin_return_address(71);
|
||||
case 71: return __builtin_return_address(72);
|
||||
case 72: return __builtin_return_address(73);
|
||||
case 73: return __builtin_return_address(74);
|
||||
case 74: return __builtin_return_address(75);
|
||||
case 75: return __builtin_return_address(76);
|
||||
case 76: return __builtin_return_address(77);
|
||||
case 77: return __builtin_return_address(78);
|
||||
case 78: return __builtin_return_address(79);
|
||||
case 79: return __builtin_return_address(80);
|
||||
case 80: return __builtin_return_address(81);
|
||||
case 81: return __builtin_return_address(82);
|
||||
case 82: return __builtin_return_address(83);
|
||||
case 83: return __builtin_return_address(84);
|
||||
case 84: return __builtin_return_address(85);
|
||||
case 85: return __builtin_return_address(86);
|
||||
case 86: return __builtin_return_address(87);
|
||||
case 87: return __builtin_return_address(88);
|
||||
case 88: return __builtin_return_address(89);
|
||||
case 89: return __builtin_return_address(90);
|
||||
case 90: return __builtin_return_address(91);
|
||||
case 91: return __builtin_return_address(92);
|
||||
case 92: return __builtin_return_address(93);
|
||||
case 93: return __builtin_return_address(94);
|
||||
case 94: return __builtin_return_address(95);
|
||||
case 95: return __builtin_return_address(96);
|
||||
case 96: return __builtin_return_address(97);
|
||||
case 97: return __builtin_return_address(98);
|
||||
case 98: return __builtin_return_address(99);
|
||||
case 99: return __builtin_return_address(100);
|
||||
case 100: return __builtin_return_address(101);
|
||||
case 101: return __builtin_return_address(102);
|
||||
case 102: return __builtin_return_address(103);
|
||||
case 103: return __builtin_return_address(104);
|
||||
case 104: return __builtin_return_address(105);
|
||||
case 105: return __builtin_return_address(106);
|
||||
case 106: return __builtin_return_address(107);
|
||||
case 107: return __builtin_return_address(108);
|
||||
case 108: return __builtin_return_address(109);
|
||||
case 109: return __builtin_return_address(110);
|
||||
case 110: return __builtin_return_address(111);
|
||||
case 111: return __builtin_return_address(112);
|
||||
case 112: return __builtin_return_address(113);
|
||||
case 113: return __builtin_return_address(114);
|
||||
case 114: return __builtin_return_address(115);
|
||||
case 115: return __builtin_return_address(116);
|
||||
case 116: return __builtin_return_address(117);
|
||||
case 117: return __builtin_return_address(118);
|
||||
case 118: return __builtin_return_address(119);
|
||||
case 119: return __builtin_return_address(120);
|
||||
case 120: return __builtin_return_address(121);
|
||||
case 121: return __builtin_return_address(122);
|
||||
case 122: return __builtin_return_address(123);
|
||||
case 123: return __builtin_return_address(124);
|
||||
case 124: return __builtin_return_address(125);
|
||||
case 125: return __builtin_return_address(126);
|
||||
case 126: return __builtin_return_address(127);
|
||||
case 127: return __builtin_return_address(128);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
backtrace_getframeaddr(uint8_t level)
|
||||
{
|
||||
switch (level) {
|
||||
case 0: return __builtin_frame_address(1);
|
||||
case 1: return __builtin_frame_address(2);
|
||||
case 2: return __builtin_frame_address(3);
|
||||
case 3: return __builtin_frame_address(4);
|
||||
case 4: return __builtin_frame_address(5);
|
||||
case 5: return __builtin_frame_address(6);
|
||||
case 6: return __builtin_frame_address(7);
|
||||
case 7: return __builtin_frame_address(8);
|
||||
case 8: return __builtin_frame_address(9);
|
||||
case 9: return __builtin_frame_address(10);
|
||||
case 10: return __builtin_frame_address(11);
|
||||
case 11: return __builtin_frame_address(12);
|
||||
case 12: return __builtin_frame_address(13);
|
||||
case 13: return __builtin_frame_address(14);
|
||||
case 14: return __builtin_frame_address(15);
|
||||
case 15: return __builtin_frame_address(16);
|
||||
case 16: return __builtin_frame_address(17);
|
||||
case 17: return __builtin_frame_address(18);
|
||||
case 18: return __builtin_frame_address(19);
|
||||
case 19: return __builtin_frame_address(20);
|
||||
case 20: return __builtin_frame_address(21);
|
||||
case 21: return __builtin_frame_address(22);
|
||||
case 22: return __builtin_frame_address(23);
|
||||
case 23: return __builtin_frame_address(24);
|
||||
case 24: return __builtin_frame_address(25);
|
||||
case 25: return __builtin_frame_address(26);
|
||||
case 26: return __builtin_frame_address(27);
|
||||
case 27: return __builtin_frame_address(28);
|
||||
case 28: return __builtin_frame_address(29);
|
||||
case 29: return __builtin_frame_address(30);
|
||||
case 30: return __builtin_frame_address(31);
|
||||
case 31: return __builtin_frame_address(32);
|
||||
case 32: return __builtin_frame_address(33);
|
||||
case 33: return __builtin_frame_address(34);
|
||||
case 34: return __builtin_frame_address(35);
|
||||
case 35: return __builtin_frame_address(36);
|
||||
case 36: return __builtin_frame_address(37);
|
||||
case 37: return __builtin_frame_address(38);
|
||||
case 38: return __builtin_frame_address(39);
|
||||
case 39: return __builtin_frame_address(40);
|
||||
case 40: return __builtin_frame_address(41);
|
||||
case 41: return __builtin_frame_address(42);
|
||||
case 42: return __builtin_frame_address(43);
|
||||
case 43: return __builtin_frame_address(44);
|
||||
case 44: return __builtin_frame_address(45);
|
||||
case 45: return __builtin_frame_address(46);
|
||||
case 46: return __builtin_frame_address(47);
|
||||
case 47: return __builtin_frame_address(48);
|
||||
case 48: return __builtin_frame_address(49);
|
||||
case 49: return __builtin_frame_address(50);
|
||||
case 50: return __builtin_frame_address(51);
|
||||
case 51: return __builtin_frame_address(52);
|
||||
case 52: return __builtin_frame_address(53);
|
||||
case 53: return __builtin_frame_address(54);
|
||||
case 54: return __builtin_frame_address(55);
|
||||
case 55: return __builtin_frame_address(56);
|
||||
case 56: return __builtin_frame_address(57);
|
||||
case 57: return __builtin_frame_address(58);
|
||||
case 58: return __builtin_frame_address(59);
|
||||
case 59: return __builtin_frame_address(60);
|
||||
case 60: return __builtin_frame_address(61);
|
||||
case 61: return __builtin_frame_address(62);
|
||||
case 62: return __builtin_frame_address(63);
|
||||
case 63: return __builtin_frame_address(64);
|
||||
case 64: return __builtin_frame_address(65);
|
||||
case 65: return __builtin_frame_address(66);
|
||||
case 66: return __builtin_frame_address(67);
|
||||
case 67: return __builtin_frame_address(68);
|
||||
case 68: return __builtin_frame_address(69);
|
||||
case 69: return __builtin_frame_address(70);
|
||||
case 70: return __builtin_frame_address(71);
|
||||
case 71: return __builtin_frame_address(72);
|
||||
case 72: return __builtin_frame_address(73);
|
||||
case 73: return __builtin_frame_address(74);
|
||||
case 74: return __builtin_frame_address(75);
|
||||
case 75: return __builtin_frame_address(76);
|
||||
case 76: return __builtin_frame_address(77);
|
||||
case 77: return __builtin_frame_address(78);
|
||||
case 78: return __builtin_frame_address(79);
|
||||
case 79: return __builtin_frame_address(80);
|
||||
case 80: return __builtin_frame_address(81);
|
||||
case 81: return __builtin_frame_address(82);
|
||||
case 82: return __builtin_frame_address(83);
|
||||
case 83: return __builtin_frame_address(84);
|
||||
case 84: return __builtin_frame_address(85);
|
||||
case 85: return __builtin_frame_address(86);
|
||||
case 86: return __builtin_frame_address(87);
|
||||
case 87: return __builtin_frame_address(88);
|
||||
case 88: return __builtin_frame_address(89);
|
||||
case 89: return __builtin_frame_address(90);
|
||||
case 90: return __builtin_frame_address(91);
|
||||
case 91: return __builtin_frame_address(92);
|
||||
case 92: return __builtin_frame_address(93);
|
||||
case 93: return __builtin_frame_address(94);
|
||||
case 94: return __builtin_frame_address(95);
|
||||
case 95: return __builtin_frame_address(96);
|
||||
case 96: return __builtin_frame_address(97);
|
||||
case 97: return __builtin_frame_address(98);
|
||||
case 98: return __builtin_frame_address(99);
|
||||
case 99: return __builtin_frame_address(100);
|
||||
case 100: return __builtin_frame_address(101);
|
||||
case 101: return __builtin_frame_address(102);
|
||||
case 102: return __builtin_frame_address(103);
|
||||
case 103: return __builtin_frame_address(104);
|
||||
case 104: return __builtin_frame_address(105);
|
||||
case 105: return __builtin_frame_address(106);
|
||||
case 106: return __builtin_frame_address(107);
|
||||
case 107: return __builtin_frame_address(108);
|
||||
case 108: return __builtin_frame_address(109);
|
||||
case 109: return __builtin_frame_address(110);
|
||||
case 110: return __builtin_frame_address(111);
|
||||
case 111: return __builtin_frame_address(112);
|
||||
case 112: return __builtin_frame_address(113);
|
||||
case 113: return __builtin_frame_address(114);
|
||||
case 114: return __builtin_frame_address(115);
|
||||
case 115: return __builtin_frame_address(116);
|
||||
case 116: return __builtin_frame_address(117);
|
||||
case 117: return __builtin_frame_address(118);
|
||||
case 118: return __builtin_frame_address(119);
|
||||
case 119: return __builtin_frame_address(120);
|
||||
case 120: return __builtin_frame_address(121);
|
||||
case 121: return __builtin_frame_address(122);
|
||||
case 122: return __builtin_frame_address(123);
|
||||
case 123: return __builtin_frame_address(124);
|
||||
case 124: return __builtin_frame_address(125);
|
||||
case 125: return __builtin_frame_address(126);
|
||||
case 126: return __builtin_frame_address(127);
|
||||
case 127: return __builtin_frame_address(128);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
platform_backtrace_resolve(struct platform_backtrace *bt)
|
||||
{
|
||||
for (uint32_t i = 0; i < bt->frames.len; i++) {
|
||||
struct platform_backtrace_frame *frame = arr_get(&bt->frames, i);
|
||||
Dl_info info = { 0 };
|
||||
if (dladdr(frame->addr, &info) != 0) {
|
||||
frame->symbol_name = info.dli_sname;
|
||||
frame->file_name = info.dli_fname;
|
||||
frame->symbol = info.dli_saddr ? info.dli_saddr : frame->addr;
|
||||
frame->offset = (char *)frame->addr - (char *)frame->symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
platform_backtrace_capture(struct arena *a, struct platform_backtrace *bt)
|
||||
{
|
||||
*bt = (struct platform_backtrace){ 0 };
|
||||
|
||||
arr_init(a, &bt->frames, 32, struct platform_backtrace_frame);
|
||||
|
||||
for (uint32_t i = 1; backtrace_getframeaddr(i + 1); i++) {
|
||||
void *returnaddr = backtrace_getreturnaddr(i);
|
||||
if (!returnaddr) {
|
||||
break;
|
||||
}
|
||||
arr_push(a, &bt->frames, &(struct platform_backtrace_frame){ .addr = returnaddr });
|
||||
}
|
||||
platform_backtrace_resolve(bt);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user