aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/log.c
diff options
context:
space:
mode:
authorJames McCoy <jamessan@jamessan.com>2018-03-28 21:52:06 -0400
committerJames McCoy <jamessan@jamessan.com>2018-03-28 21:54:39 -0400
commit79f9c2d9c650ceab27cdc6707fd6d7fa1de29fc1 (patch)
tree4e0589d75801f3ff6a9678f84f5009102766661e /src/nvim/log.c
parent4403864da3c48412595d439f36458d1e6ccfc49f (diff)
parent3f3de9b1a95d273463a87516365510dbffcaf3d2 (diff)
downloadrneovim-79f9c2d9c650ceab27cdc6707fd6d7fa1de29fc1.tar.gz
rneovim-79f9c2d9c650ceab27cdc6707fd6d7fa1de29fc1.tar.bz2
rneovim-79f9c2d9c650ceab27cdc6707fd6d7fa1de29fc1.zip
Merge branch 'master' into yagebu/option-fixes
Diffstat (limited to 'src/nvim/log.c')
-rw-r--r--src/nvim/log.c97
1 files changed, 83 insertions, 14 deletions
diff --git a/src/nvim/log.c b/src/nvim/log.c
index f1dbe61dda..7bfe5c4089 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -25,6 +25,10 @@ static uv_mutex_t mutex;
# include "log.c.generated.h"
#endif
+#ifdef HAVE_EXECINFO_BACKTRACE
+# include <execinfo.h>
+#endif
+
static bool log_try_create(char *fname)
{
if (fname == NULL || fname[0] == '\0') {
@@ -91,8 +95,12 @@ void log_unlock(void)
uv_mutex_unlock(&mutex);
}
-bool do_log(int log_level, const char *func_name, int line_num, bool eol,
- const char* fmt, ...) FUNC_ATTR_UNUSED
+/// @param context description of a shared context or subsystem
+/// @param func_name function name, or NULL
+/// @param line_num source line number, or -1
+bool do_log(int log_level, const char *context, const char *func_name,
+ int line_num, bool eol, const char *fmt, ...)
+ FUNC_ATTR_UNUSED
{
if (log_level < MIN_LOG_LEVEL) {
return false;
@@ -108,8 +116,8 @@ bool do_log(int log_level, const char *func_name, int line_num, bool eol,
va_list args;
va_start(args, fmt);
- ret = v_do_log_to_file(log_file, log_level, func_name, line_num, eol,
- fmt, args);
+ ret = v_do_log_to_file(log_file, log_level, context, func_name, line_num,
+ eol, fmt, args);
va_end(args);
if (log_file != stderr && log_file != stdout) {
@@ -147,7 +155,7 @@ FILE *open_log_file(void)
static bool opening_log_file = false;
// check if it's a recursive call
if (opening_log_file) {
- do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true,
+ do_log_to_file(stderr, ERROR_LOG_LEVEL, NULL, __func__, __LINE__, true,
"Cannot LOG() recursively.");
return stderr;
}
@@ -167,33 +175,87 @@ FILE *open_log_file(void)
// - LOG() is called before early_init()
// - Directory does not exist
// - File is not writable
- do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true,
+ do_log_to_file(stderr, ERROR_LOG_LEVEL, NULL, __func__, __LINE__, true,
"Logging to stderr, failed to open $" LOG_FILE_ENV ": %s",
log_file_path);
return stderr;
}
-static bool do_log_to_file(FILE *log_file, int log_level,
+#ifdef HAVE_EXECINFO_BACKTRACE
+void log_callstack_to_file(FILE *log_file, 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.
+
+ 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 ...
+
+ do_log_to_file(log_file, DEBUG_LOG_LEVEL, NULL, func_name, line_num, true,
+ "trace:");
+ 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);
+ }
+}
+
+void log_callstack(const char *const func_name, const int line_num)
+{
+ log_lock();
+ FILE *log_file = open_log_file();
+ if (log_file == NULL) {
+ goto end;
+ }
+
+ log_callstack_to_file(log_file, func_name, line_num);
+
+end:
+ log_unlock();
+}
+#endif
+
+static bool do_log_to_file(FILE *log_file, int log_level, const char *context,
const char *func_name, int line_num, bool eol,
const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
- bool ret = v_do_log_to_file(log_file, log_level, func_name, line_num, eol,
- fmt, args);
+ bool ret = v_do_log_to_file(log_file, log_level, context, func_name,
+ line_num, eol, fmt, args);
va_end(args);
return ret;
}
static bool v_do_log_to_file(FILE *log_file, int log_level,
- const char *func_name, int line_num, bool eol,
- const char* fmt, va_list args)
+ const char *context, const char *func_name,
+ int line_num, bool eol, const char *fmt,
+ va_list args)
{
static const char *log_levels[] = {
[DEBUG_LOG_LEVEL] = "DEBUG",
[INFO_LOG_LEVEL] = "INFO ",
- [WARNING_LOG_LEVEL] = "WARN ",
+ [WARN_LOG_LEVEL] = "WARN ",
[ERROR_LOG_LEVEL] = "ERROR",
};
assert(log_level >= DEBUG_LOG_LEVEL && log_level <= ERROR_LOG_LEVEL);
@@ -211,8 +273,15 @@ static bool v_do_log_to_file(FILE *log_file, int log_level,
// print the log message prefixed by the current timestamp and pid
int64_t pid = os_get_pid();
- if (fprintf(log_file, "%s %s %" PRId64 "/%s:%d: ", date_time,
- log_levels[log_level], pid, func_name, line_num) < 0) {
+ int rv = (line_num == -1 || func_name == NULL)
+ ? fprintf(log_file, "%s %s %" PRId64 " %s", date_time,
+ log_levels[log_level], pid,
+ (context == NULL ? "?:" : context))
+ : fprintf(log_file, "%s %s %" PRId64 " %s%s:%d: ", date_time,
+ log_levels[log_level], pid,
+ (context == NULL ? "" : context),
+ func_name, line_num);
+ if (rv < 0) {
return false;
}
if (vfprintf(log_file, fmt, args) < 0) {