[Mesa-dev] [PATCH] util: Add backtrace support based on gallium u_debug_stack
Jordan Justen
jordan.l.justen at intel.com
Fri Dec 1 23:08:39 UTC 2017
Only the libunwind support is retained from u_debug_stack.
Signed-off-by: Jordan Justen <jordan.l.justen at intel.com>
---
src/util/Makefile.am | 4 +-
src/util/Makefile.sources | 2 +
src/util/backtrace.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/backtrace.h | 55 ++++++++++++
src/util/meson.build | 2 +
5 files changed, 285 insertions(+), 1 deletion(-)
create mode 100644 src/util/backtrace.c
create mode 100644 src/util/backtrace.h
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index a5241ad27ba..25ed47ab248 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -42,6 +42,7 @@ libmesautil_la_CPPFLAGS = \
-I$(top_srcdir)/src/gallium/include \
-I$(top_srcdir)/src/gallium/auxiliary \
$(VISIBILITY_CFLAGS) \
+ $(LIBUNWIND_CFLAGS) \
$(MSVC2013_COMPAT_CFLAGS) \
$(ZLIB_CFLAGS)
@@ -52,7 +53,8 @@ libmesautil_la_SOURCES = \
libmesautil_la_LIBADD = \
$(CLOCK_LIB) \
$(ZLIB_LIBS) \
- $(LIBATOMIC_LIBS)
+ $(LIBATOMIC_LIBS) \
+ $(LIBUNWIND_LIBS)
libxmlconfig_la_SOURCES = $(XMLCONFIG_FILES)
libxmlconfig_la_CFLAGS = \
diff --git a/src/util/Makefile.sources b/src/util/Makefile.sources
index 104ecae8ed3..39e67bd6f44 100644
--- a/src/util/Makefile.sources
+++ b/src/util/Makefile.sources
@@ -1,4 +1,6 @@
MESA_UTIL_FILES := \
+ backtrace.c \
+ backtrace.h \
bitscan.c \
bitscan.h \
bitset.h \
diff --git a/src/util/backtrace.c b/src/util/backtrace.c
new file mode 100644
index 00000000000..df629c877ac
--- /dev/null
+++ b/src/util/backtrace.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * Stack backtracing.
+ *
+ * @author Jose Fonseca <jfonseca at vmware.com>
+ */
+
+#include "backtrace.h"
+
+#if defined(HAVE_LIBUNWIND)
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+
+/**
+ * Represent a frame from a stack backtrace.
+ */
+#ifdef HAVE_LIBUNWIND
+struct debug_stack_frame
+{
+ unw_word_t start_ip;
+ unsigned int off;
+ const char *procname;
+};
+#else
+struct debug_stack_frame;
+#endif
+
+
+// void
+// debug_backtrace_capture(struct debug_stack_frame *backtrace,
+// unsigned start_frame,
+// unsigned nr_frames);
+
+// void
+// debug_backtrace_dump(const struct debug_stack_frame *backtrace,
+// unsigned nr_frames);
+
+// void
+// debug_backtrace_print(FILE *f,
+// const struct debug_stack_frame *backtrace,
+// unsigned nr_frames);
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <dlfcn.h>
+
+#include "u_thread.h"
+#include "hash_table.h"
+
+static struct hash_table* symbols_hash = NULL;;
+static mtx_t symbols_mutex = _MTX_INITIALIZER_NP;
+
+static const char *
+symbol_name_cached(unw_cursor_t *cursor, unw_proc_info_t *pip)
+{
+ void *addr = (void *)(uintptr_t)pip->start_ip;
+ struct hash_entry *entry;
+ char *name;
+
+ mtx_lock(&symbols_mutex);
+ if(!symbols_hash)
+ symbols_hash = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+ entry = _mesa_hash_table_search(symbols_hash, addr);
+ if(entry) {
+ name = entry->data;
+ } else {
+ char procname[256];
+ unw_word_t off;
+ int ret;
+
+ ret = unw_get_proc_name(cursor, procname, sizeof(procname), &off);
+ if (ret && ret != -UNW_ENOMEM) {
+ procname[0] = '?';
+ procname[1] = 0;
+ }
+
+ asprintf(&name, "%s%s", procname, ret == -UNW_ENOMEM ? "..." : "");
+
+ _mesa_hash_table_insert(symbols_hash, addr, name);
+ }
+ mtx_unlock(&symbols_mutex);
+
+ return name;
+}
+
+static void
+debug_backtrace_capture(struct debug_stack_frame *backtrace,
+ unsigned start_frame,
+ unsigned nr_frames)
+{
+ unw_cursor_t cursor;
+ unw_context_t context;
+ unw_proc_info_t pip;
+ unsigned i = 0;
+
+ pip.unwind_info = NULL;
+
+ unw_getcontext(&context);
+ unw_init_local(&cursor, &context);
+
+ while ((start_frame > 0) && (unw_step(&cursor) > 0))
+ start_frame--;
+
+ while ((i < nr_frames) && (unw_step(&cursor) > 0)) {
+ unw_word_t ip;
+
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
+ unw_get_proc_info(&cursor, &pip);
+
+ backtrace[i].start_ip = pip.start_ip;
+ backtrace[i].off = ip - pip.start_ip;
+ backtrace[i].procname = symbol_name_cached(&cursor, &pip);
+
+ i++;
+ }
+
+ while (i < nr_frames) {
+ backtrace[i].start_ip = 0;
+ i++;
+ }
+}
+
+static const void *
+frame_ip(const struct debug_stack_frame *frame)
+{
+ return (void *)(uintptr_t)(frame->start_ip + frame->off);
+}
+
+static const char *
+frame_info(const struct debug_stack_frame *frame, unsigned *offset)
+{
+ Dl_info dlinfo;
+ const void *addr = frame_ip(frame);
+
+
+ if (dladdr(addr, &dlinfo) && dlinfo.dli_fname &&
+ *dlinfo.dli_fname) {
+ *offset = (unsigned)((uintptr_t)addr - (uintptr_t)dlinfo.dli_fbase);
+ return dlinfo.dli_fname;
+ }
+
+ *offset = 0;
+ return "?";
+}
+
+static void
+debug_backtrace_print(FILE *f,
+ const struct debug_stack_frame *backtrace,
+ unsigned nr_frames)
+{
+ unsigned i, offset;
+ const char *filename;
+
+ for (i = 0; i < nr_frames; ++i) {
+ if (!backtrace[i].start_ip)
+ break;
+ filename = frame_info(&backtrace[i], &offset);
+ fprintf(f, "\t%s(+0x%x) (%s+0x%x) [%p]\n", filename, offset,
+ backtrace[i].procname, backtrace[i].off,
+ frame_ip(&backtrace[i]));
+ }
+}
+
+bool
+backtrace_available(void)
+{
+ return true;
+}
+
+void
+fput_backtrace(FILE *f, unsigned max_frames)
+{
+ if (max_frames == 0)
+ max_frames = 100;
+
+ struct debug_stack_frame *frames = calloc(max_frames, sizeof(*frames));
+ debug_backtrace_capture(frames, 1, max_frames);
+ debug_backtrace_print(f, frames, max_frames);
+ free(frames);
+}
+
+#else /* ! HAVE_LIBUNWIND */
+
+bool
+backtrace_available(void)
+{
+ return false;
+}
+
+void
+fput_backtrace(FILE *f, unsigned max_frames)
+{
+}
+
+#endif /* HAVE_LIBUNWIND */
diff --git a/src/util/backtrace.h b/src/util/backtrace.h
new file mode 100644
index 00000000000..7b8b6a3bb00
--- /dev/null
+++ b/src/util/backtrace.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef BACKTRACE_H_INCLUDED
+#define BACKTRACE_H_INCLUDED
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Returns `true` if a backtrace can be captured.
+ */
+bool
+backtrace_available(void);
+
+/**
+ * Write a maximum of `max_frames` backtrace frames to file `f`.
+ *
+ * If `max_frames` is 0, then all frames will be written.
+ *
+ * If `backtrace_available` returns false, this function will have no effect
+ * if called.
+ */
+void
+fput_backtrace(FILE *f, unsigned max_frames);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BACKTRACE_H_INCLUDED */
diff --git a/src/util/meson.build b/src/util/meson.build
index b54c20796ff..c59cd964735 100644
--- a/src/util/meson.build
+++ b/src/util/meson.build
@@ -23,6 +23,8 @@ inc_util = include_directories('.')
subdir('xmlpool')
files_mesa_util = files(
+ 'backtrace.c',
+ 'backtrace.h',
'bitscan.c',
'bitscan.h',
'bitset.h',
--
2.15.0
More information about the mesa-dev
mailing list