summaryrefslogtreecommitdiff
path: root/libgcompat/backtrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgcompat/backtrace.c')
-rw-r--r--libgcompat/backtrace.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/libgcompat/backtrace.c b/libgcompat/backtrace.c
new file mode 100644
index 0000000..2ceb334
--- /dev/null
+++ b/libgcompat/backtrace.c
@@ -0,0 +1,44 @@
+#include <dlfcn.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#define _frame_level(addr_buf, curr, frame, size) \
+ if(__builtin_frame_address(frame) != NULL && (curr = __builtin_return_address(frame)) > 0x1000 && frame <= size) addr_buf[frame] = curr; \
+ else return size;
+
+int backtrace(void **addr_buf, int size)
+{
+ void *curr;
+ _frame_level(addr_buf, curr, 0, size)
+ _frame_level(addr_buf, curr, 1, size)
+ _frame_level(addr_buf, curr, 2, size)
+ _frame_level(addr_buf, curr, 3, size)
+ _frame_level(addr_buf, curr, 4, size)
+ _frame_level(addr_buf, curr, 5, size)
+ _frame_level(addr_buf, curr, 6, size)
+ _frame_level(addr_buf, curr, 7, size)
+ _frame_level(addr_buf, curr, 8, size)
+ _frame_level(addr_buf, curr, 9, size)
+ return 9;
+}
+
+char **backtrace_symbols(void * const *addr_buf, int size)
+{
+ char **result = calloc(sizeof(char *), size);
+ if(result == NULL) return result;
+
+ for(int next = 0; next < size; next++)
+ {
+ Dl_info info;
+ int err = dladdr(addr_buf[next], &info);
+
+ if(err != 0)
+ {
+ result[next] = "??:0";
+ } else {
+ result[next] = info.dli_sname;
+ }
+ }
+
+ return result;
+}