aboutsummaryrefslogtreecommitdiff
path: root/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib')
-rw-r--r--stdlib/functiontype.c4
-rw-r--r--stdlib/stdlib.c67
2 files changed, 57 insertions, 14 deletions
diff --git a/stdlib/functiontype.c b/stdlib/functiontype.c
index dc4d0c94..b02739a2 100644
--- a/stdlib/functiontype.c
+++ b/stdlib/functiontype.c
@@ -52,13 +52,13 @@ PUREFUNC static func_info_t *get_function_info(void *fn)
return info;
}
-PUREFUNC public Text_t get_function_name(void *fn)
+PUREFUNC public OptionalText_t get_function_name(void *fn)
{
func_info_t *info = get_function_info(fn);
return info ? info->name : NONE_TEXT;
}
-PUREFUNC public Text_t get_function_filename(void *fn)
+PUREFUNC public OptionalText_t get_function_filename(void *fn)
{
func_info_t *info = get_function_info(fn);
return info ? info->filename : NONE_TEXT;
diff --git a/stdlib/stdlib.c b/stdlib/stdlib.c
index c97dbfa3..d07fa68e 100644
--- a/stdlib/stdlib.c
+++ b/stdlib/stdlib.c
@@ -383,26 +383,69 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
}
#pragma GCC diagnostic pop
+static void print_stack_line(FILE *out, OptionalText_t fn_name, const char *filename, int64_t line_num)
+{
+ // NOTE: this function is a bit inefficient. Each time we print a line, we
+ // do a linear scan through the whole file. However, performance shouldn't
+ // really matter if we only print stack lines when there's a crash.
+ if (filename) {
+ fprintf(out, "\033[34mFile\033[m \033[35;1m%s\033[m", filename);
+ if (line_num >= 1)
+ fprintf(out, "\033[34m line\033[m \033[35;1m%ld\033[m", line_num);
+ }
+ if (fn_name.length > 0) {
+ fprintf(out, filename ? "\033[34m, in \033[m \033[36;1m%k\033[m" : "\033[36;1m%k\033[m", &fn_name);
+ }
+ fprintf(out, "\n");
+
+ FILE *f = fopen(filename, "r");
+ char *line = NULL;
+ size_t size = 0;
+ ssize_t nread;
+ int64_t cur_line = 1;
+ while ((nread = getline(&line, &size, f)) != -1) {
+ if (line[strlen(line)-1] == '\n')
+ line[strlen(line)-1] = '\0';
+
+ if (cur_line >= line_num)
+ fprintf(out, "\033[33;1m%s\033[m\n", line);
+
+ cur_line += 1;
+ if (cur_line > line_num)
+ break;
+ }
+ if (line) free(line);
+ fclose(f);
+}
+
void print_stack_trace(FILE *out, int start, int stop)
{
// Print stack trace:
- fprintf(out, "\x1b[34m");
- fflush(out);
- void *array[1024];
- int64_t size = (int64_t)backtrace(array, sizeof(array)/sizeof(array[0]));
- char **strings = strings = backtrace_symbols(array, size);
+ void *stack[1024];
+ int64_t size = (int64_t)backtrace(stack, sizeof(stack)/sizeof(stack[0]));
+ char **strings = strings = backtrace_symbols(stack, size);
for (int64_t i = start; i < size - stop; i++) {
char *filename = strings[i];
- const char *cmd = heap_strf("addr2line -e %.*s -fisp | sed 's/^_\\$//;s/\\$/./g;s/ at /() at /' >&2", strcspn(filename, "("), filename);
- FILE *fp = popen(cmd, "w");
+ char *paren = strchrnul(strings[i], '(');
+ char *addr_end = paren + 1 + strcspn(paren + 1, ")");
+ ptrdiff_t offset = strtol(paren + 1, &addr_end, 16) - 1;
+ const char *cmd = heap_strf("addr2line -e %.*s -is +0x%x", strcspn(filename, "("), filename, offset);
+ FILE *fp = popen(cmd, "r");
+ OptionalText_t fn_name = get_function_name(stack[i]);
+ const char *src_filename = NULL;
+ int64_t line_number = 0;
if (fp) {
- char *paren = strchrnul(strings[i], '(');
- fprintf(fp, "%.*s\n", strcspn(paren + 1, ")"), paren + 1);
+ char buf[PATH_MAX + 10] = {};
+ if (fgets(buf, sizeof(buf), fp)) {
+ char *saveptr, *line_num_str;
+ if ((src_filename=strtok_r(buf, ":", &saveptr))
+ && (line_num_str=strtok_r(NULL, ":", &saveptr)))
+ line_number = atoi(line_num_str);
+ }
+ pclose(fp);
}
- pclose(fp);
+ print_stack_line(out, fn_name, src_filename, line_number);
}
- fprintf(out, "\x1b[m");
- fflush(out);
}
__attribute__((format(printf, 1, 2)))