Skip to content

Commit dbe1a60

Browse files
committed
implement direct stack tracing
1 parent a65acc5 commit dbe1a60

File tree

3 files changed

+60
-67
lines changed

3 files changed

+60
-67
lines changed

include/c_minilib_error.h

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,26 @@
1212
// We are staticly restricting fields to create only one memory allocation for
1313
// whole error. Mallocs are pretty expensive and errors can be created and
1414
// destroyed very frequently.
15+
#ifdef CME_ENABLE_BACKTRACE
1516
#define CME_STACK_MAX 16
17+
#else
18+
#define CME_STACK_MAX 1
19+
#endif
20+
1621
#define CME_STR_MAX 255
1722

18-
// Because we want to hit cpu hot cache when operating on error
19-
// error should be less than 32kib, as this is most common
20-
// 64bit system L1 cache these days.
23+
struct cme_StackSymbol {
24+
const char *source_file;
25+
const char *source_func;
26+
uint32_t source_line;
27+
};
28+
2129
struct __attribute__((aligned(8))) cme_Error {
22-
uint32_t code; // 32/8 = 4 bytes
23-
char msg[CME_STR_MAX]; // 1*256 = 256 bytes
24-
char source_file[CME_STR_MAX]; // 1*256 = 256 bytes
25-
char source_func[CME_STR_MAX]; // 1*256 = 256 bytes
26-
uint32_t source_line; // 32/8 = 4 bytes
27-
#ifdef CME_ENABLE_BACKTRACE
28-
uint32_t stack_length; // 32/8 = 4 bytes
29-
void *stack_symbols[CME_STACK_MAX]; // (64/8) * 16 = 128 bytes
30-
#else
31-
uint32_t stack_length; // 32/8 = 4 bytes
32-
void **stack_symbols; // 64/8 = 8 bytes
33-
#endif
30+
uint32_t code;
31+
char msg[CME_STR_MAX];
32+
uint32_t stack_length;
33+
struct cme_StackSymbol stack_symbols[CME_STACK_MAX];
3434
};
35-
// If CME_ENABLED_BACKTRACE defined we have 4+256*3+8+4+4+128 = 916 bytes.
36-
// If not we have 4+256*3+8+8+4+4+8 = 804 bytes.
37-
// Because 916%8!=0 nor 804%8!=0 we need to align our struct to 8 bytes
38-
// via compiler `aligned` attribute.
3935

4036
typedef struct cme_Error *cme_error_t;
4137

@@ -46,6 +42,7 @@ cme_error_t cme_error_create(int code, char *source_file, char *source_func,
4642
// Destroy error
4743
void cme_error_destroy(cme_error_t);
4844

45+
// Handy macro
4946
#define cme_errorf(code, fmt, ...) \
5047
cme_error_create((code), __FILE__, (char *)__func__, __LINE__, \
5148
(char *)(fmt), ##__VA_ARGS__)
@@ -56,7 +53,11 @@ int cme_error_dump_to_file(cme_error_t err, char *file_path);
5653
// Dump error to string
5754
int cme_error_dump_to_str(cme_error_t err, uint32_t n, char *buffer);
5855

59-
// Return wrapper
60-
cme_error_t cme_return(cme_error_t err);
56+
// Add symbol to error stack
57+
cme_error_t cme_error_push_symbol(cme_error_t err, const char *file,
58+
const char *func, int line);
59+
// Handy macro
60+
#define cme_return(ERR) \
61+
cme_error_push_symbol((ERR), __FILE__, __func__, __LINE__)
6162

6263
#endif // C_MINILIB_CONFIG_ERROR_H

src/c_minilib_error.c

Lines changed: 38 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
static struct cme_Error generic_error = {0};
1818

1919
#define CREATE_GENERIC_ERROR(status_code, err_msg) \
20-
generic_error.stack_length = 0; \
21-
generic_error.code = (status_code); \
22-
generic_error.source_line = __LINE__; \
2320
snprintf(generic_error.msg, CME_STR_MAX, "%s", (err_msg)); \
24-
snprintf(generic_error.source_func, CME_STR_MAX, "%s", __func__);
21+
generic_error.code = (status_code); \
22+
generic_error.stack_length = 1; \
23+
generic_error.stack_symbols[0].source_file = __FILE__; \
24+
generic_error.stack_symbols[0].source_func = __func__; \
25+
generic_error.stack_symbols[0].source_line = __LINE__;
2526

2627
cme_error_t cme_error_create(int code, char *source_file, char *source_func,
2728
int source_line, char *fmt, ...) {
@@ -32,17 +33,11 @@ cme_error_t cme_error_create(int code, char *source_file, char *source_func,
3233
return &generic_error;
3334
}
3435

35-
err->stack_length = 0;
3636
err->code = code;
37-
err->source_line = source_line;
38-
39-
if (source_file) {
40-
snprintf(err->source_file, CME_STR_MAX, "%s", source_file);
41-
}
42-
43-
if (source_func) {
44-
snprintf(err->source_func, CME_STR_MAX, "%s", source_func);
45-
}
37+
err->stack_length = 1;
38+
err->stack_symbols[0].source_func = source_func;
39+
err->stack_symbols[0].source_file = source_file;
40+
err->stack_symbols[0].source_line = source_line;
4641

4742
if (fmt) {
4843
va_list args;
@@ -72,40 +67,33 @@ int cme_error_dump_to_str(cme_error_t err, uint32_t n, char *buffer) {
7267
size_t offset = 0;
7368
int written;
7469

75-
/* 1) Common fields */
7670
written = cme_sprintf(buffer + offset, n - offset,
7771
"====== ERROR DUMP ======\n"
7872
"Error code: %d\n"
79-
"Error message: %s\n"
80-
"Src file: %s\n"
81-
"Src line: %d\n"
82-
"Src func: %s\n",
83-
err->code, err->msg, err->source_file, err->source_line,
84-
err->source_func);
73+
"Error message: %s\n",
74+
err->code, err->msg);
8575
if (written < 0) {
8676
return ENOBUFS;
8777
}
78+
79+
offset += (size_t)written;
80+
81+
written =
82+
cme_sprintf(buffer + offset, n - offset, "------------------------\n");
83+
if (written < 0)
84+
return ENOBUFS;
8885
offset += (size_t)written;
8986

90-
#ifdef CME_ENABLE_BACKTRACE
91-
if (err->stack_length > 0) {
92-
written =
93-
cme_sprintf(buffer + offset, n - offset, "------------------------\n");
94-
if (written < 0) {
87+
for (uint32_t i = 0; i < err->stack_length; ++i) {
88+
const struct cme_StackSymbol *sym = &err->stack_symbols[i];
89+
written = cme_sprintf(buffer + offset, n - offset, "%u:%s:%s:%u\n", i,
90+
sym->source_func ? sym->source_func : "??",
91+
sym->source_file ? sym->source_file : "??",
92+
sym->source_line);
93+
if (written < 0)
9594
return ENOBUFS;
96-
}
9795
offset += (size_t)written;
98-
99-
for (int i = 0; i < err->stack_length; ++i) {
100-
written = cme_sprintf(buffer + offset, n - offset, "[%p]\n",
101-
err->stack_symbols[i]);
102-
if (written < 0) {
103-
return ENOBUFS;
104-
}
105-
offset += (size_t)written;
106-
}
10796
}
108-
#endif
10997

11098
return 0;
11199
}
@@ -124,19 +112,23 @@ int cme_error_dump_to_file(cme_error_t err, char *path) {
124112
return 0;
125113
}
126114

127-
cme_error_t cme_return(cme_error_t err) {
115+
cme_error_t cme_error_push_symbol(cme_error_t err, const char *file,
116+
const char *func, int line) {
128117
#ifndef CME_ENABLE_BACKTRACE
118+
(void)file;
119+
(void)func;
120+
(void)line;
129121
return err;
130122
#else
131-
if (!err) {
123+
if (!err)
124+
return err;
125+
if (err->stack_length >= CME_STACK_MAX)
132126
return err;
133-
}
134-
135-
if (err->stack_length < CME_STACK_MAX) {
136-
err->stack_symbols[err->stack_length++] =
137-
__builtin_extract_return_addr(__builtin_return_address(0));
138-
}
139127

128+
struct cme_StackSymbol *f = &err->stack_symbols[err->stack_length++];
129+
f->source_file = file;
130+
f->source_func = func;
131+
f->source_line = line;
140132
return err;
141133
#endif
142-
};
134+
}

0 commit comments

Comments
 (0)