master
c 159 lines 4.66 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "stacktrace-common.h"
4
5 #if defined(USE_BACKTRACE)
6 #include <execinfo.h>
7
8 const char *stacktrace_backend(void) {
9 return "backtrace";
10 }
11
12 bool stacktrace_available(void) {
13 return true;
14 }
15
16 void impl_stacktrace_init(void) {
17 // Nothing to initialize for backtrace backend
18 }
19
20 void stacktrace_flush(void) {
21 // Nothing to flush
22 }
23
24 bool stacktrace_capture_is_async_signal_safe(void) {
25 return false;
26 }
27
28 NEVER_INLINE
29 void stacktrace_capture(BUFFER *wb) {
30 void *array[50];
31 char **messages;
32 int size, i;
33
34 root_cause_function[0] = '\0';
35
36 size = backtrace(array, _countof(array));
37 messages = backtrace_symbols(array, size);
38
39 if (!messages) {
40 buffer_strcat(wb, NO_STACK_TRACE_PREFIX "backtrace() reports no symbols");
41 return;
42 }
43
44 size_t added = 0;
45 bool found_signal_handler = false;
46
47 // Format the stack trace (removing the address part)
48 // Skip the first frame (stacktrace_capture itself)
49 for (i = 1; i < size; i++) {
50 if(messages[i] && *messages[i]) {
51 // Check if we found the signal handler frame
52 if (!found_signal_handler && stacktrace_contains_signal_handler_function(messages[i])) {
53 // We found the signal handler, reset the buffer
54 buffer_flush(wb);
55 added = 0;
56 found_signal_handler = true;
57 continue; // Skip adding the signal handler itself
58 }
59
60 // Check for logging functions, but only if we haven't found a signal handler yet
61 if (!found_signal_handler && stacktrace_contains_logging_function(messages[i])) {
62 // Found a logging function, reset the buffer
63 buffer_flush(wb);
64 added = 0;
65 // continue to add the function to the stack trace
66 }
67
68 if(added)
69 buffer_putc(wb, '\n');
70
71 buffer_putc(wb, '#');
72 buffer_print_uint64(wb, added);
73 buffer_putc(wb, ' ');
74 buffer_strcat(wb, messages[i]);
75 added++;
76 }
77 }
78
79 if(!added)
80 buffer_strcat(wb, NO_STACK_TRACE_PREFIX "backtrace() reports no frames");
81
82 free(messages);
83 }
84
85 // Implementation-specific function to collect stack trace frames
86 int impl_stacktrace_get_frames(void **frames, int max_frames, int skip_frames) {
87 if (!frames || max_frames <= 0)
88 return 0;
89
90 // Add 1 to skip_frames to also skip this function itself
91 skip_frames += 1;
92
93 // Collect all stack frames without skipping at this level
94 void *array[100 + 50]; // Use a larger array to account for skipped frames (100) plus the max we need (50)
95 int size = backtrace(array, _countof(array));
96
97 if (size <= skip_frames) // Not enough frames after skipping
98 return 0;
99
100 // Apply skip_frames here, in the aftermath of backtrace, not during capture
101 // This ensures we're not skipping inlined functions
102 int available_frames = size - skip_frames;
103 int frames_to_copy = available_frames < max_frames ? available_frames : max_frames;
104
105 // Copy the frames, skipping the requested number of frames
106 memcpy(frames, array + skip_frames, frames_to_copy * sizeof(void *));
107
108 return frames_to_copy;
109 }
110
111 // Implementation-specific function to convert a stacktrace to a buffer
112 void impl_stacktrace_to_buffer(STACKTRACE trace, BUFFER *wb) {
113 struct stacktrace *st = (struct stacktrace *)trace;
114
115 // Convert to text representation
116 char **messages = backtrace_symbols(st->frames, st->frame_count);
117
118 if (!messages) {
119 buffer_strcat(wb, NO_STACK_TRACE_PREFIX "backtrace_symbols() failed");
120 return;
121 }
122
123 bool found_signal_handler = false;
124 int added = 0;
125
126 for (int i = 0; i < st->frame_count; i++) {
127 if (!messages[i] || !*messages[i])
128 continue;
129
130 // Handle filtering
131 if (!found_signal_handler && stacktrace_contains_signal_handler_function(messages[i])) {
132 buffer_flush(wb);
133 added = 0;
134 found_signal_handler = true;
135 continue;
136 }
137
138 if (!found_signal_handler && stacktrace_contains_logging_function(messages[i])) {
139 buffer_flush(wb);
140 added = 0;
141 }
142
143 if (added > 0)
144 buffer_putc(wb, '\n');
145
146 buffer_putc(wb, '#');
147 buffer_print_uint64(wb, added);
148 buffer_putc(wb, ' ');
149 buffer_strcat(wb, messages[i]);
150 added++;
151 }
152
153 free(messages);
154
155 if (added == 0)
156 buffer_strcat(wb, NO_STACK_TRACE_PREFIX "no valid frames");
157 }
158
159 #endif // USE_BACKTRACE