master
c 91 lines 2.59 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "stacktrace-array.h"
4 #include "stacktrace-common.h"
5
6 // Initialize a stacktrace array
7 void stacktrace_array_init(STACKTRACE_ARRAY *array) {
8 if (unlikely(!array))
9 return;
10
11 spinlock_init(&array->spinlock);
12 array->num_stacktraces = 0;
13 memset(array->stacktraces, 0, sizeof(array->stacktraces));
14 }
15
16 // Add a stacktrace to an array (captures current stacktrace)
17 NEVER_INLINE
18 bool stacktrace_array_add(STACKTRACE_ARRAY *array, int skip_frames) {
19 if (unlikely(!array))
20 return false;
21
22 // Get current stacktrace
23 STACKTRACE current = stacktrace_get(skip_frames + 1); // +1 to skip this function
24 if (!current)
25 return false;
26
27 bool added = false;
28
29 // Protect the stacktraces array with a spinlock
30 spinlock_lock(&array->spinlock);
31
32 // Check if this stacktrace already exists in the array
33 bool found = false;
34 for (int i = 0; i < array->num_stacktraces; i++) {
35 if (array->stacktraces[i] == current) {
36 found = true;
37 break;
38 }
39 }
40
41 // Add the stacktrace if it's unique and there's room
42 if (!found && array->num_stacktraces < STACKTRACE_ARRAY_MAX_TRACES) {
43 array->stacktraces[array->num_stacktraces++] = current;
44 added = true;
45 }
46
47 spinlock_unlock(&array->spinlock);
48
49 return added;
50 }
51
52 // Report stacktraces to a buffer
53 size_t stacktrace_array_to_buffer(STACKTRACE_ARRAY *array, BUFFER *wb, size_t *total_count, const char *prefix, bool brief_output) {
54 if (unlikely(!array || !wb))
55 return 0;
56
57 if (!prefix)
58 prefix = "STACKTRACE";
59
60 size_t reported = 0;
61
62 // Lock the array while we're operating on it
63 spinlock_lock(&array->spinlock);
64
65 // Update total count if requested
66 if (total_count)
67 *total_count = array->num_stacktraces;
68
69 // If brief output is requested, just report the number of stacktraces
70 if (brief_output) {
71 buffer_sprintf(wb, "%s: %d stacktraces captured\n", prefix, array->num_stacktraces);
72 spinlock_unlock(&array->spinlock);
73 return array->num_stacktraces;
74 }
75
76 // Report each stacktrace in the array
77 for (int i = 0; i < array->num_stacktraces; i++) {
78 if (array->stacktraces[i]) {
79 if (i > 0)
80 buffer_strcat(wb, "\n");
81
82 buffer_sprintf(wb, "%s #%d:\n", prefix, i+1);
83 stacktrace_to_buffer(array->stacktraces[i], wb);
84 reported++;
85 }
86 }
87
88 spinlock_unlock(&array->spinlock);
89
90 return reported;
91 }