Skip to content

Instantly share code, notes, and snippets.

@lpereira

lpereira/error-codes.c

Last active Jan 6, 2021
Embed
What would you like to do?
#include <stdio.h>
struct error_code {
int code;
};
struct error_context {
const struct error_code *code;
const char *msg;
const char *file;
int line;
};
#ifndef NDEBUG
#define _ERROR_NEW(msg_) \
static struct error_code __attribute__((__used__)) \
__attribute__((__section__("error_code"))) __error_code__ = {.code = 0}; \
static const struct error_context __attribute__((__used__)) \
__attribute__((__section__("error_context"))) \
__error_context__ = {.msg = msg_, \
.file = __FILE__, \
.line = __LINE__, \
.code = &__error_code__};
#else
#define _ERROR_NEW(msg_) \
static struct error_code __attribute__((__used__)) \
__attribute__((__section__("error_code"))) __error_code__ = {.code = 0};
#endif
#define ERROR_NEW(msg_) \
({ \
_ERROR_NEW(msg_) \
__error_code__.code; \
})
__attribute__((__constructor__)) static void error_init(void) {
extern struct error_code __start_error_code[], __stop_error_code[];
struct error_code *c;
int counter = 0;
for (c = __start_error_code; c < __stop_error_code; c++) {
c->code = counter++;
}
}
const struct error_code *error_find(int code) {
extern struct error_code __start_error_code[], __stop_error_code[];
const struct error_code *c;
for (c = __start_error_code; c < __stop_error_code; c++) {
if (c->code == code)
return c;
}
return NULL;
}
const struct error_context *error_find_context(int code) {
extern struct error_context __start_error_context[], __stop_error_context[];
const struct error_context *ctx;
const struct error_code *c = error_find(code);
if (!c)
return NULL;
for (ctx = __start_error_context; ctx < __stop_error_context; ctx++) {
if (ctx->code == c)
return ctx;
}
return NULL;
}
int main() {
int error_code_1 = ERROR_NEW("foo");
int error_code_2 = ERROR_NEW("bar");
int error_code_3 = ERROR_NEW("baz");
int error_code_4 = ERROR_NEW("aaa");
int error_code_5 = ERROR_NEW("bbb");
int error_code_6 = ERROR_NEW("ccc");
int error_code_7 = ERROR_NEW("ddd");
printf("%d %d\n", error_code_1, error_code_2);
printf("%d %d\n", error_code_3, error_code_4);
printf("%d %d\n", error_code_5, error_code_6);
printf("%d\n", error_code_7);
const struct error_context *ctx = error_find_context(error_code_1);
if (!ctx) {
printf("context not found; maybe it was stripped?\n");
} else {
printf("error code %d defined with message '%s' on file '%s' at line %d\n",
error_code_1, ctx->msg, ctx->file, ctx->line);
}
}
$ make error-codes
cc error-codes.c -o error-codes
$ ./error-codes
0 1
2 3
4 5
6
error code 0 defined with message 'foo' on file 'error-codes.c' at line 73
$ objcopy --remove-section error_context ./error-codes
$ ./error-codes
0 1
2 3
4 5
6
context not found; maybe it was stripped?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment