diff options
-rw-r--r-- | src/nvim/README.md | 19 | ||||
-rw-r--r-- | src/nvim/log.c | 47 | ||||
-rw-r--r-- | src/nvim/log.h | 4 |
3 files changed, 64 insertions, 6 deletions
diff --git a/src/nvim/README.md b/src/nvim/README.md index 660e3d1010..1c1c3c364e 100644 --- a/src/nvim/README.md +++ b/src/nvim/README.md @@ -1,13 +1,20 @@ +Nvim core source +================ -Module-specific details are documented at the top of each module (e.g. -terminal.c, screen.c). +Module-specific details are documented at the top of each module (`terminal.c`, +`screen.c`, ...). -See also `:help development`. +See `:help development` for more guidelines. -UI Debugging ------------- +Logs +---- -At `DEBUG_LOG_LEVEL`, all UI events are logged. +Low-level log messages sink to `$NVIM_LOG_FILE`. + +You can use `LOG_CALLSTACK()` anywhere in the source to log the current +stacktrace. (Currently Linux-only.) + +UI events are logged at level 0 (`DEBUG_LOG_LEVEL`). rm -rf build/ make CMAKE_EXTRA_FLAGS="-DMIN_LOG_LEVEL=0" diff --git a/src/nvim/log.c b/src/nvim/log.c index f1dbe61dda..252fe5438d 100644 --- a/src/nvim/log.c +++ b/src/nvim/log.c @@ -173,6 +173,53 @@ FILE *open_log_file(void) return stderr; } +#if defined(__linux__) +# include <execinfo.h> +void log_callstack(const char *const func_name, const int line_num) +{ + void *trace[100]; + int trace_size = backtrace(trace, ARRAY_SIZE(trace)); + + char exepath[MAXPATHL] = { 0 }; + size_t exepathlen = MAXPATHL; + if (os_exepath(exepath, &exepathlen) != 0) { + abort(); + } + assert(24 + exepathlen < IOSIZE); // Must fit in `cmdbuf` below. + + do_log(DEBUG_LOG_LEVEL, func_name, line_num, true, "trace:"); + + char cmdbuf[IOSIZE + (20 * ARRAY_SIZE(trace))]; + snprintf(cmdbuf, sizeof(cmdbuf), "addr2line -e %s -f -p", exepath); + for (int i = 1; i < trace_size; i++) { + char buf[20]; // 64-bit pointer 0xNNNNNNNNNNNNNNNN with leading space. + snprintf(buf, sizeof(buf), " %p", trace[i]); + xstrlcat(cmdbuf, buf, sizeof(cmdbuf)); + } + // Now we have a command string like: + // addr2line -e /path/to/exe -f -p 0x123 0x456 ... + + log_lock(); + FILE *log_file = open_log_file(); + if (log_file == NULL) { + goto end; + } + + FILE *fp = popen(cmdbuf, "r"); + char linebuf[IOSIZE]; + while (fgets(linebuf, sizeof(linebuf) - 1, fp) != NULL) { + fprintf(log_file, " %s", linebuf); + } + pclose(fp); + + if (log_file != stderr && log_file != stdout) { + fclose(log_file); + } +end: + log_unlock(); +} +#endif + static bool do_log_to_file(FILE *log_file, int log_level, const char *func_name, int line_num, bool eol, const char* fmt, ...) diff --git a/src/nvim/log.h b/src/nvim/log.h index 221f0bbaf6..2bd18f5776 100644 --- a/src/nvim/log.h +++ b/src/nvim/log.h @@ -61,6 +61,10 @@ __VA_ARGS__) #endif +#if defined(__linux__) +# define LOG_CALLSTACK() log_callstack(__func__, __LINE__) +#endif + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "log.h.generated.h" #endif |