traces.ha (1404B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use hash; 5 use hash::fnv; 6 use rt; 7 8 def TRACE_BUCKETS = 65535; 9 10 let traces: [TRACE_BUCKETS][]trace = [[]...]; 11 12 export type trace = struct { 13 id: u64, 14 frames: *stackframe, 15 }; 16 17 // Retrives a stack trace by its ID. 18 export fn trace_by_id(id: u64) (stackframe | void) = { 19 let bucket = &traces[id % TRACE_BUCKETS]; 20 for (let trace &.. bucket) { 21 if (trace.id == id) { 22 return *trace.frames; 23 }; 24 }; 25 }; 26 27 // Stores a stack trace and returns its ID. Stored stack traces are hashed and 28 // de-duplicated in a global stack list. 29 export fn trace_store(frame: stackframe) u64 = { 30 static let pc: []uintptr = []; 31 pc = pc[..0]; 32 33 const prev_heap = begin_altheap(); 34 defer end_altheap(prev_heap); 35 36 const hash = fnv::fnv64a(); 37 for (true) { 38 hash::write(&hash, &frame_pc(frame): *[size(uintptr)]u8); 39 append(pc, frame_pc(frame))!; 40 41 match (next(frame)) { 42 case let next: stackframe => 43 frame = next; 44 case done => break; 45 }; 46 }; 47 48 const id = fnv::sum64(&hash); 49 let bucket = &traces[id % TRACE_BUCKETS]; 50 for (let trace &.. bucket) { 51 if (trace.id == id) { 52 return id; 53 }; 54 }; 55 56 let frames: []stackframe = alloc([stackframe { ... }...], len(pc) + 1)!; 57 for (let i = 0z; i < len(pc); i += 1) { 58 frames[i] = mkframe(&frames[i + 1], pc[i]); 59 }; 60 61 append(bucket, trace { 62 id = id, 63 frames = &frames[0], 64 })!; 65 66 return id; 67 };