Improved backtrace on platforms without glibc. Added $$frameaddress and $$returnaddress properly.

This commit is contained in:
Christoffer Lerno
2023-11-18 14:18:09 +01:00
committed by Christoffer Lerno
parent 00019f9d76
commit 87fdb5956e
11 changed files with 347 additions and 16 deletions

View File

@@ -6,7 +6,7 @@ module std::core::mem::allocator;
import std::collections::map;
import std::collections::list;
const MAX_BACKTRACE = 8;
const MAX_BACKTRACE = 16;
struct Allocation
{
void* ptr;
@@ -104,7 +104,7 @@ fn void*! TrackingAllocator.resize(&self, void* old_pointer, usz size, usz align
}
if (data)
{
void*[8] bt;
void*[MAX_BACKTRACE] bt;
backtrace::capture_current(&bt);
self.map.set((uptr)data, { data, size, bt });
self.mem_total += size;
@@ -115,8 +115,14 @@ fn void*! TrackingAllocator.resize(&self, void* old_pointer, usz size, usz align
fn void TrackingAllocator.release(&self, void* old_pointer, bool is_aligned) @dynamic
{
if (old_pointer)
{
if (catch self.map.remove((uptr)old_pointer))
{
assert(false, "Attempt to release untracked pointer %p, this is likely a bug.", old_pointer);
}
}
self.inner_allocator.release(old_pointer, is_aligned);
if (old_pointer) self.map.remove((uptr)old_pointer);
}
fn void TrackingAllocator.clear(&self)
@@ -205,7 +211,17 @@ fn void! TrackingAllocator.fprint_report(&self, OutStream* out)
io::fprintfn(out, "Allocation %d (%d bytes): ", i + 1, allocation.size)!;
foreach (trace : list)
{
io::fprintfn(out, " %s", trace);
if (trace.has_file())
{
io::fprintfn(out, " %s (in %s:%d)", trace.function, trace.file, trace.line);
continue;
}
if (trace.is_unknown())
{
io::fprintfn(out, " ??? (in unknown)");
continue;
}
io::fprintfn(out, " %s (source unavailable)", trace.function);
}
}
}

View File

@@ -331,6 +331,289 @@ macro uint String.hash(String c) => (uint)fnv32a::encode(c);
macro uint char[].hash(char[] c) => (uint)fnv32a::encode(c);
macro uint void*.hash(void* ptr) => ((ulong)(uptr)ptr).hash();
const MAX_FRAMEADDRESS = 128;
/**
* @require n >= 0
**/
macro void* get_frameaddress(int n)
{
if (n > MAX_FRAMEADDRESS) return null;
switch (n)
{
case 0: return $$frameaddress(0);
case 1: return $$frameaddress(1);
case 2: return $$frameaddress(2);
case 3: return $$frameaddress(3);
case 4: return $$frameaddress(4);
case 5: return $$frameaddress(5);
case 6: return $$frameaddress(6);
case 7: return $$frameaddress(7);
case 8: return $$frameaddress(8);
case 9: return $$frameaddress(9);
case 10: return $$frameaddress(10);
case 11: return $$frameaddress(11);
case 12: return $$frameaddress(12);
case 13: return $$frameaddress(13);
case 14: return $$frameaddress(14);
case 15: return $$frameaddress(15);
case 16: return $$frameaddress(16);
case 17: return $$frameaddress(17);
case 18: return $$frameaddress(18);
case 19: return $$frameaddress(19);
case 20: return $$frameaddress(20);
case 21: return $$frameaddress(21);
case 22: return $$frameaddress(22);
case 23: return $$frameaddress(23);
case 24: return $$frameaddress(24);
case 25: return $$frameaddress(25);
case 26: return $$frameaddress(26);
case 27: return $$frameaddress(27);
case 28: return $$frameaddress(28);
case 29: return $$frameaddress(29);
case 30: return $$frameaddress(30);
case 31: return $$frameaddress(31);
case 32: return $$frameaddress(32);
case 33: return $$frameaddress(33);
case 34: return $$frameaddress(34);
case 35: return $$frameaddress(35);
case 36: return $$frameaddress(36);
case 37: return $$frameaddress(37);
case 38: return $$frameaddress(38);
case 39: return $$frameaddress(39);
case 40: return $$frameaddress(40);
case 41: return $$frameaddress(41);
case 42: return $$frameaddress(42);
case 43: return $$frameaddress(43);
case 44: return $$frameaddress(44);
case 45: return $$frameaddress(45);
case 46: return $$frameaddress(46);
case 47: return $$frameaddress(47);
case 48: return $$frameaddress(48);
case 49: return $$frameaddress(49);
case 50: return $$frameaddress(50);
case 51: return $$frameaddress(51);
case 52: return $$frameaddress(52);
case 53: return $$frameaddress(53);
case 54: return $$frameaddress(54);
case 55: return $$frameaddress(55);
case 56: return $$frameaddress(56);
case 57: return $$frameaddress(57);
case 58: return $$frameaddress(58);
case 59: return $$frameaddress(59);
case 60: return $$frameaddress(60);
case 61: return $$frameaddress(61);
case 62: return $$frameaddress(62);
case 63: return $$frameaddress(63);
case 64: return $$frameaddress(64);
case 65: return $$frameaddress(65);
case 66: return $$frameaddress(66);
case 67: return $$frameaddress(67);
case 68: return $$frameaddress(68);
case 69: return $$frameaddress(69);
case 70: return $$frameaddress(70);
case 71: return $$frameaddress(71);
case 72: return $$frameaddress(72);
case 73: return $$frameaddress(73);
case 74: return $$frameaddress(74);
case 75: return $$frameaddress(75);
case 76: return $$frameaddress(76);
case 77: return $$frameaddress(77);
case 78: return $$frameaddress(78);
case 79: return $$frameaddress(79);
case 80: return $$frameaddress(80);
case 81: return $$frameaddress(81);
case 82: return $$frameaddress(82);
case 83: return $$frameaddress(83);
case 84: return $$frameaddress(84);
case 85: return $$frameaddress(85);
case 86: return $$frameaddress(86);
case 87: return $$frameaddress(87);
case 88: return $$frameaddress(88);
case 89: return $$frameaddress(89);
case 90: return $$frameaddress(90);
case 91: return $$frameaddress(91);
case 92: return $$frameaddress(92);
case 93: return $$frameaddress(93);
case 94: return $$frameaddress(94);
case 95: return $$frameaddress(95);
case 96: return $$frameaddress(96);
case 97: return $$frameaddress(97);
case 98: return $$frameaddress(98);
case 99: return $$frameaddress(99);
case 100: return $$frameaddress(100);
case 101: return $$frameaddress(101);
case 102: return $$frameaddress(102);
case 103: return $$frameaddress(103);
case 104: return $$frameaddress(104);
case 105: return $$frameaddress(105);
case 106: return $$frameaddress(106);
case 107: return $$frameaddress(107);
case 108: return $$frameaddress(108);
case 109: return $$frameaddress(109);
case 110: return $$frameaddress(110);
case 111: return $$frameaddress(111);
case 112: return $$frameaddress(112);
case 113: return $$frameaddress(113);
case 114: return $$frameaddress(114);
case 115: return $$frameaddress(115);
case 116: return $$frameaddress(116);
case 117: return $$frameaddress(117);
case 118: return $$frameaddress(118);
case 119: return $$frameaddress(119);
case 120: return $$frameaddress(120);
case 121: return $$frameaddress(121);
case 122: return $$frameaddress(122);
case 123: return $$frameaddress(123);
case 124: return $$frameaddress(124);
case 125: return $$frameaddress(125);
case 126: return $$frameaddress(126);
case 127: return $$frameaddress(127);
case 128: return $$frameaddress(128);
default: unreachable();
}
}
/**
* @require n >= 0
**/
macro void* get_returnaddress(int n)
{
if (n > MAX_FRAMEADDRESS) return null;
switch (n)
{
case 0: return $$returnaddress(0);
case 1: return $$returnaddress(1);
case 2: return $$returnaddress(2);
case 3: return $$returnaddress(3);
case 4: return $$returnaddress(4);
case 5: return $$returnaddress(5);
case 6: return $$returnaddress(6);
case 7: return $$returnaddress(7);
case 8: return $$returnaddress(8);
case 9: return $$returnaddress(9);
case 10: return $$returnaddress(10);
case 11: return $$returnaddress(11);
case 12: return $$returnaddress(12);
case 13: return $$returnaddress(13);
case 14: return $$returnaddress(14);
case 15: return $$returnaddress(15);
case 16: return $$returnaddress(16);
case 17: return $$returnaddress(17);
case 18: return $$returnaddress(18);
case 19: return $$returnaddress(19);
case 20: return $$returnaddress(20);
case 21: return $$returnaddress(21);
case 22: return $$returnaddress(22);
case 23: return $$returnaddress(23);
case 24: return $$returnaddress(24);
case 25: return $$returnaddress(25);
case 26: return $$returnaddress(26);
case 27: return $$returnaddress(27);
case 28: return $$returnaddress(28);
case 29: return $$returnaddress(29);
case 30: return $$returnaddress(30);
case 31: return $$returnaddress(31);
case 32: return $$returnaddress(32);
case 33: return $$returnaddress(33);
case 34: return $$returnaddress(34);
case 35: return $$returnaddress(35);
case 36: return $$returnaddress(36);
case 37: return $$returnaddress(37);
case 38: return $$returnaddress(38);
case 39: return $$returnaddress(39);
case 40: return $$returnaddress(40);
case 41: return $$returnaddress(41);
case 42: return $$returnaddress(42);
case 43: return $$returnaddress(43);
case 44: return $$returnaddress(44);
case 45: return $$returnaddress(45);
case 46: return $$returnaddress(46);
case 47: return $$returnaddress(47);
case 48: return $$returnaddress(48);
case 49: return $$returnaddress(49);
case 50: return $$returnaddress(50);
case 51: return $$returnaddress(51);
case 52: return $$returnaddress(52);
case 53: return $$returnaddress(53);
case 54: return $$returnaddress(54);
case 55: return $$returnaddress(55);
case 56: return $$returnaddress(56);
case 57: return $$returnaddress(57);
case 58: return $$returnaddress(58);
case 59: return $$returnaddress(59);
case 60: return $$returnaddress(60);
case 61: return $$returnaddress(61);
case 62: return $$returnaddress(62);
case 63: return $$returnaddress(63);
case 64: return $$returnaddress(64);
case 65: return $$returnaddress(65);
case 66: return $$returnaddress(66);
case 67: return $$returnaddress(67);
case 68: return $$returnaddress(68);
case 69: return $$returnaddress(69);
case 70: return $$returnaddress(70);
case 71: return $$returnaddress(71);
case 72: return $$returnaddress(72);
case 73: return $$returnaddress(73);
case 74: return $$returnaddress(74);
case 75: return $$returnaddress(75);
case 76: return $$returnaddress(76);
case 77: return $$returnaddress(77);
case 78: return $$returnaddress(78);
case 79: return $$returnaddress(79);
case 80: return $$returnaddress(80);
case 81: return $$returnaddress(81);
case 82: return $$returnaddress(82);
case 83: return $$returnaddress(83);
case 84: return $$returnaddress(84);
case 85: return $$returnaddress(85);
case 86: return $$returnaddress(86);
case 87: return $$returnaddress(87);
case 88: return $$returnaddress(88);
case 89: return $$returnaddress(89);
case 90: return $$returnaddress(90);
case 91: return $$returnaddress(91);
case 92: return $$returnaddress(92);
case 93: return $$returnaddress(93);
case 94: return $$returnaddress(94);
case 95: return $$returnaddress(95);
case 96: return $$returnaddress(96);
case 97: return $$returnaddress(97);
case 98: return $$returnaddress(98);
case 99: return $$returnaddress(99);
case 100: return $$returnaddress(100);
case 101: return $$returnaddress(101);
case 102: return $$returnaddress(102);
case 103: return $$returnaddress(103);
case 104: return $$returnaddress(104);
case 105: return $$returnaddress(105);
case 106: return $$returnaddress(106);
case 107: return $$returnaddress(107);
case 108: return $$returnaddress(108);
case 109: return $$returnaddress(109);
case 110: return $$returnaddress(110);
case 111: return $$returnaddress(111);
case 112: return $$returnaddress(112);
case 113: return $$returnaddress(113);
case 114: return $$returnaddress(114);
case 115: return $$returnaddress(115);
case 116: return $$returnaddress(116);
case 117: return $$returnaddress(117);
case 118: return $$returnaddress(118);
case 119: return $$returnaddress(119);
case 120: return $$returnaddress(120);
case 121: return $$returnaddress(121);
case 122: return $$returnaddress(122);
case 123: return $$returnaddress(123);
case 124: return $$returnaddress(124);
case 125: return $$returnaddress(125);
case 126: return $$returnaddress(126);
case 127: return $$returnaddress(127);
case 128: return $$returnaddress(128);
default: unreachable();
}
}
module std::core::builtin @if((env::LINUX || env::DARWIN) && env::COMPILER_SAFE_MODE && env::DEBUG_SYMBOLS);
import libc;
@@ -385,3 +668,4 @@ fn void install_signal_handlers() @init(101) @local
install_signal_handler(libc::SIGBUS, &sig_bus_error);
install_signal_handler(libc::SIGSEGV, &sig_segmentation_fault);
}

View File

@@ -45,7 +45,7 @@ extern fn CInt get_system_info(SystemInfo*) @extern("GetSystemInfo");
// Aliases to simplify libc use
macro Tm* localtime_r(Time_t* timer, Tm* buf) => _localtime64_s(buf, timer);
macro CInt setjmp(JmpBuf* buffer) => _setjmp($$frameaddress(), buffer);
macro CInt setjmp(JmpBuf* buffer) => _setjmp($$frameaddress(0), buffer);
macro Tm* gmtime_r(Time_t* timer, Tm* buf) => _gmtime64_s(buf, timer);
macro isz read(Fd fd, void* buffer, usz buffer_size) => _read(fd, buffer, (CUInt)buffer_size);
macro isz write(Fd fd, void* buffer, usz count) => _write(fd, buffer, (CUInt)count);

View File

@@ -37,7 +37,6 @@ def spawn = posix_spawn;
extern fn CInt kill(Pid_t pid, CInt sig);
extern fn Pid_t waitpid(Pid_t pid, CInt* stat_loc, int options);
extern fn CInt raise(CInt sig);
extern fn CInt backtrace(void **buffer, CInt size);
extern fn ZString* backtrace_symbols(void** buffer, CInt size);
extern fn void backtrace_symbols_fd(void** buffer, CInt size, CInt fd);
macro CInt wEXITSTATUS(CInt status) => (status & 0xff00) >> 8;
@@ -55,3 +54,17 @@ const CInt __W_CONTINUED = 0xffff;
const CInt WNOHANG = 1;
const CInt WUNTRACES = 2;
extern fn CInt backtrace(void** buffer, CInt size) @if(env::DARWIN);
fn CInt backtrace(void** buffer, CInt size) @if(!env::DARWIN)
{
if (size < 1) return 0;
void*[128] buffer_first;
CInt i;
for (i = 0; (uptr)builtin::get_frameaddress(i + 1) > 1 && i < size; i++)
{
buffer[i] = builtin::get_returnaddress(i);
if (!buffer[i]) break;
}
return i;
}

View File

@@ -919,6 +919,7 @@ typedef enum
BUILTIN_REDUCE_OR,
BUILTIN_REDUCE_XOR,
BUILTIN_REVERSE,
BUILTIN_RETURNADDRESS,
BUILTIN_RINT,
BUILTIN_ROUND,
BUILTIN_ROUNDEVEN,

View File

@@ -702,6 +702,7 @@ static void llvm_codegen_setup()
intrinsic_id.powi = lookup_intrinsic("llvm.powi");
intrinsic_id.prefetch = lookup_intrinsic("llvm.prefetch");
intrinsic_id.readcyclecounter = lookup_intrinsic("llvm.readcyclecounter");
intrinsic_id.returnaddress = lookup_intrinsic("llvm.returnaddress");
intrinsic_id.rint = lookup_intrinsic("llvm.rint");
intrinsic_id.round = lookup_intrinsic("llvm.round");
intrinsic_id.roundeven = lookup_intrinsic("llvm.roundeven");

View File

@@ -794,11 +794,20 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
llvm_emit_compare_exchange(c, result_value, expr);
return;
case BUILTIN_FRAMEADDRESS:
{
llvm_emit_expr(c, result_value, expr->call_expr.arguments[0]);
llvm_value_rvalue(c, result_value);
LLVMValueRef res = llvm_emit_call_intrinsic(c, func == BUILTIN_FRAMEADDRESS ? intrinsic_id.frameaddress : intrinsic_id.returnaddress, &c->ptr_type, 1, &result_value->value, 1);
llvm_value_set(result_value, res, expr->type);
return;
}
case BUILTIN_RETURNADDRESS:
{
LLVMTypeRef type[2] = { c->ptr_type, llvm_get_type(c, type_int) };
LLVMValueRef value = LLVMConstNull(type[1]);
value = llvm_emit_call_intrinsic(c, intrinsic_id.frameaddress, type, 1, &value, 1);
llvm_value_set(result_value, value, expr->type);
llvm_emit_expr(c, result_value, expr->call_expr.arguments[0]);
llvm_value_rvalue(c, result_value);
LLVMTypeRef type = LLVMTypeOf(result_value->value);
LLVMValueRef res = llvm_emit_call_intrinsic(c, func == BUILTIN_FRAMEADDRESS ? intrinsic_id.frameaddress : intrinsic_id.returnaddress, NULL, 0, &result_value->value, 1);
llvm_value_set(result_value, res, expr->type);
return;
}
case BUILTIN_SELECT:

View File

@@ -178,6 +178,7 @@ typedef struct
unsigned powi;
unsigned prefetch;
unsigned readcyclecounter;
unsigned returnaddress;
unsigned rint;
unsigned round;
unsigned roundeven;

View File

@@ -338,9 +338,6 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
case BUILTIN_GET_ROUNDING_MODE:
expr->type = type_int;
return true;
case BUILTIN_FRAMEADDRESS:
expr->type = type_voidptr;
return true;
case BUILTIN_COMPARE_EXCHANGE:
return sema_expr_analyse_compare_exchange(context, expr);
default:
@@ -514,6 +511,14 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
arg_count)) return false;
rtype = args[0]->type;
break;
case BUILTIN_FRAMEADDRESS:
case BUILTIN_RETURNADDRESS:
assert(arg_count);
if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_INTEGER }, arg_count)) return false;
if (!cast_implicit(context, args[0], type_int)) return false;
if (!expr_is_const_int(args[0])) RETURN_SEMA_ERROR(args[0], "Expected a compile time constant integer.");
rtype = type_voidptr;
break;
case BUILTIN_WASM_MEMORY_SIZE:
assert(arg_count == 1);
if (!cast_implicit(context, args[0], type_uint)) return false;
@@ -865,7 +870,6 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
}
case BUILTIN_NONE:
case BUILTIN_COMPARE_EXCHANGE:
case BUILTIN_FRAMEADDRESS:
case BUILTIN_GET_ROUNDING_MODE:
case BUILTIN_SWIZZLE:
case BUILTIN_SWIZZLE2:
@@ -892,7 +896,6 @@ static inline int builtin_expected_args(BuiltinFunction func)
case BUILTIN_SYSCLOCK:
case BUILTIN_TRAP:
case BUILTIN_UNREACHABLE:
case BUILTIN_FRAMEADDRESS:
return 0;
case BUILTIN_ABS:
case BUILTIN_BITREVERSE:
@@ -931,6 +934,8 @@ static inline int builtin_expected_args(BuiltinFunction func)
case BUILTIN_REDUCE_MIN:
case BUILTIN_SET_ROUNDING_MODE:
case BUILTIN_WASM_MEMORY_SIZE:
case BUILTIN_FRAMEADDRESS:
case BUILTIN_RETURNADDRESS:
return 1;
case BUILTIN_COPYSIGN:
case BUILTIN_EXACT_ADD:

View File

@@ -265,6 +265,7 @@ void symtab_init(uint32_t capacity)
builtin_list[BUILTIN_REDUCE_OR] = KW_DEF("reduce_or");
builtin_list[BUILTIN_REDUCE_XOR] = KW_DEF("reduce_xor");
builtin_list[BUILTIN_REVERSE] = KW_DEF("reverse");
builtin_list[BUILTIN_RETURNADDRESS] = KW_DEF("returnaddress");
builtin_list[BUILTIN_RINT] = KW_DEF("rint");
builtin_list[BUILTIN_ROUND] = KW_DEF("round");
builtin_list[BUILTIN_ROUNDEVEN] = KW_DEF("roundeven");

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.706"
#define COMPILER_VERSION "0.4.707"