dependency('cutils'),
dependency('hardware'),
dependency('sync'),
+ dependency('backtrace')
]
- if with_gallium
- dep_android += dependency('backtrace')
- endif
if get_option('platform-sdk-version') >= 26
dep_android += dependency('nativewindow')
endif
'util/u_debug_image.h',
'util/u_debug_refcnt.c',
'util/u_debug_refcnt.h',
- 'util/u_debug_stack.h',
- 'util/u_debug_symbol.c',
- 'util/u_debug_symbol.h',
'util/u_dirty_flags.h',
'util/u_dirty_surfaces.h',
'util/u_dl.c',
'nir/nir_draw_helpers.h',
)
-if with_platform_android
- files_libgallium += files(
- 'util/u_debug_stack_android.cpp',
- )
-else
- files_libgallium += files(
- 'util/u_debug_stack.c',
- )
-endif
-
if dep_libdrm.found()
files_libgallium += files(
'renderonly/renderonly.c',
cpp_args : [cpp_msvc_compat_args],
gnu_symbol_visibility : 'hidden',
dependencies : [
- dep_libdrm, dep_llvm, dep_unwind, dep_dl, dep_m, dep_thread, dep_lmsensors,
+ dep_libdrm, dep_llvm, dep_dl, dep_m, dep_thread, dep_lmsensors,
idep_nir, idep_nir_headers, idep_mesautil,
],
build_by_default : false
+++ /dev/null
-/**************************************************************************
- *
- * 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@vmware.com>
- */
-
-#include "util/u_debug.h"
-#include "u_debug_symbol.h"
-#include "u_debug_stack.h"
-#include "pipe/p_config.h"
-
-#if defined(HAVE_LIBUNWIND)
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-#include <dlfcn.h>
-
-#include "os/os_thread.h"
-#include "util/hash_table.h"
-
-static struct hash_table* symbols_hash;
-static mtx_t symbols_mutex = _MTX_INITIALIZER_NP;
-
-/* TODO with some refactoring we might be able to re-use debug_symbol_name_cached()
- * instead.. otoh if using libunwind I think u_debug_symbol could just be excluded
- * from build?
- */
-static const char *
-symbol_name_cached(unw_cursor_t *cursor, unw_proc_info_t *pip)
-{
- void *addr = (void *)(uintptr_t)pip->start_ip;
- char *name;
-
- mtx_lock(&symbols_mutex);
- if(!symbols_hash)
- symbols_hash = _mesa_pointer_hash_table_create(NULL);
- struct hash_entry *entry = _mesa_hash_table_search(symbols_hash, addr);
- if (!entry) {
- 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;
- }
-
- if (asprintf(&name, "%s%s", procname, ret == -UNW_ENOMEM ? "..." : "") == -1)
- name = "??";
- entry = _mesa_hash_table_insert(symbols_hash, addr, (void*)name);
- }
- mtx_unlock(&symbols_mutex);
-
- return entry->data;
-}
-
-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 "?";
-}
-
-void
-debug_backtrace_dump(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);
- debug_printf("\t%s(+0x%x) (%s+0x%x) [%p]\n", filename, offset,
- backtrace[i].procname, backtrace[i].off,
- frame_ip(&backtrace[i]));
- }
-}
-
-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]));
- }
-}
-#elif defined(ANDROID)
- /* Not implemented here; see u_debug_stack_android.cpp */
-#else /* ! HAVE_LIBUNWIND */
-
-#if defined(PIPE_OS_WINDOWS)
-#include <windows.h>
-#endif
-
-
-/**
- * Capture stack backtrace.
- *
- * NOTE: The implementation of this function is quite big, but it is important
- * not to break it down in smaller functions to avoid adding new frames to the
- * calling stack.
- */
-void
-debug_backtrace_capture(struct debug_stack_frame *backtrace,
- unsigned start_frame,
- unsigned nr_frames)
-{
- const void **frame_pointer = NULL;
- unsigned i = 0;
-
- if (!nr_frames) {
- return;
- }
-
- /*
- * On Windows try obtaining the stack backtrace via CaptureStackBackTrace.
- *
- * It works reliably both for x86 for x86_64.
- */
-#if defined(PIPE_OS_WINDOWS)
- {
- typedef USHORT (WINAPI *PFNCAPTURESTACKBACKTRACE)(ULONG, ULONG,
- PVOID *, PULONG);
- static PFNCAPTURESTACKBACKTRACE pfnCaptureStackBackTrace = NULL;
-
- if (!pfnCaptureStackBackTrace) {
- static HMODULE hModule = NULL;
- if (!hModule) {
- hModule = LoadLibraryA("kernel32");
- assert(hModule);
- }
- if (hModule) {
- pfnCaptureStackBackTrace =
- (PFNCAPTURESTACKBACKTRACE)GetProcAddress(hModule,
- "RtlCaptureStackBackTrace");
- }
- }
- if (pfnCaptureStackBackTrace) {
- /*
- * Skip this (debug_backtrace_capture) function's frame.
- */
-
- start_frame += 1;
-
- assert(start_frame + nr_frames < 63);
- i = pfnCaptureStackBackTrace(start_frame, nr_frames,
- (PVOID *) &backtrace->function, NULL);
-
- /* Pad remaing requested frames with NULL */
- while (i < nr_frames) {
- backtrace[i++].function = NULL;
- }
-
- return;
- }
- }
-#endif
-
-#if defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION > 404) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wframe-address"
- frame_pointer = ((const void **)__builtin_frame_address(1));
-#pragma GCC diagnostic pop
-#elif defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86)
- __asm {
- mov frame_pointer, ebp
- }
- frame_pointer = (const void **)frame_pointer[0];
-#else
- frame_pointer = NULL;
-#endif
-
-#ifdef PIPE_ARCH_X86
- while (nr_frames) {
- const void **next_frame_pointer;
-
- if (!frame_pointer)
- break;
-
- if (start_frame)
- --start_frame;
- else {
- backtrace[i++].function = frame_pointer[1];
- --nr_frames;
- }
-
- next_frame_pointer = (const void **)frame_pointer[0];
-
- /* Limit the stack walk to avoid referencing undefined memory */
- if ((uintptr_t)next_frame_pointer <= (uintptr_t)frame_pointer ||
- (uintptr_t)next_frame_pointer > (uintptr_t)frame_pointer + 64*1024)
- break;
-
- frame_pointer = next_frame_pointer;
- }
-#else
- (void) frame_pointer;
-#endif
-
- while (nr_frames) {
- backtrace[i++].function = NULL;
- --nr_frames;
- }
-}
-
-
-void
-debug_backtrace_dump(const struct debug_stack_frame *backtrace,
- unsigned nr_frames)
-{
- unsigned i;
-
- for (i = 0; i < nr_frames; ++i) {
- if (!backtrace[i].function)
- break;
- debug_symbol_print(backtrace[i].function);
- }
-}
-
-
-void
-debug_backtrace_print(FILE *f,
- const struct debug_stack_frame *backtrace,
- unsigned nr_frames)
-{
- unsigned i;
-
- for (i = 0; i < nr_frames; ++i) {
- const char *symbol;
- if (!backtrace[i].function)
- break;
- symbol = debug_symbol_name_cached(backtrace[i].function);
- if (symbol)
- fprintf(f, "%s\n", symbol);
- }
-}
-
-#endif /* HAVE_LIBUNWIND */
+++ /dev/null
-/**************************************************************************
- *
- * 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.
- *
- **************************************************************************/
-
-#ifndef U_DEBUG_STACK_H_
-#define U_DEBUG_STACK_H_
-
-#include <stdio.h>
-
-#ifdef HAVE_LIBUNWIND
-#define UNW_LOCAL_ONLY
-#include <libunwind.h>
-#endif
-
-/**
- * @file
- * Stack backtracing.
- *
- * @author Jose Fonseca <jfonseca@vmware.com>
- */
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/**
- * Represent a frame from a stack backtrace.
- *
-#if defined(PIPE_OS_WINDOWS) && !defined(HAVE_LIBUNWIND)
- * XXX: Do not change this. (passed to Windows' CaptureStackBackTrace())
-#endif
- *
- * TODO: This should be refactored as a void * typedef.
- */
-struct debug_stack_frame
-{
-#ifdef HAVE_LIBUNWIND
- unw_word_t start_ip;
- unsigned int off;
- const char *procname;
-#else
- const void *function;
-#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);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* U_DEBUG_STACK_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2018 Stefan Schake <stschake@gmail.com>
- *
- * 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.
- */
-
-#include <backtrace/Backtrace.h>
-
-#include "util/u_debug.h"
-#include "u_debug_stack.h"
-#include "util/hash_table.h"
-#include "os/os_thread.h"
-
-static hash_table *backtrace_table;
-static mtx_t table_mutex = _MTX_INITIALIZER_NP;
-
-void
-debug_backtrace_capture(debug_stack_frame *mesa_backtrace,
- unsigned start_frame,
- unsigned nr_frames)
-{
- hash_entry *backtrace_entry;
- Backtrace *backtrace;
- pid_t tid = gettid();
-
- if (!nr_frames)
- return;
-
- /* We keep an Android Backtrace handler around for each thread */
- mtx_lock(&table_mutex);
- if (!backtrace_table)
- backtrace_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
- _mesa_key_pointer_equal);
-
- backtrace_entry = _mesa_hash_table_search(backtrace_table, (void*) (uintptr_t)tid);
- if (!backtrace_entry) {
- backtrace = Backtrace::Create(getpid(), tid);
- _mesa_hash_table_insert(backtrace_table, (void*) (uintptr_t)tid, backtrace);
- } else {
- backtrace = (Backtrace *) backtrace_entry->data;
- }
- mtx_unlock(&table_mutex);
-
- /* Add one to exclude this call. Unwind already ignores itself. */
- backtrace->Unwind(start_frame + 1);
-
- /* Store the Backtrace handler in the first mesa frame for reference.
- * Unwind will generally return less frames than nr_frames specified
- * but we have no good way of storing the real count otherwise.
- * The Backtrace handler only stores the results until the next Unwind,
- * but that is how u_debug_stack is used anyway.
- */
- mesa_backtrace->function = backtrace;
-}
-
-void
-debug_backtrace_dump(const debug_stack_frame *mesa_backtrace,
- unsigned nr_frames)
-{
- Backtrace *backtrace = (Backtrace *) mesa_backtrace->function;
- size_t i;
-
- if (!nr_frames)
- return;
-
- if (nr_frames > backtrace->NumFrames())
- nr_frames = backtrace->NumFrames();
- for (i = 0; i < nr_frames; i++) {
- /* There is no prescribed format and this isn't interpreted further,
- * so we simply use the default Android format.
- */
- const std::string& frame_line = backtrace->FormatFrameData(i);
- debug_printf("%s\n", frame_line.c_str());
- }
-}
-
-void
-debug_backtrace_print(FILE *f,
- const debug_stack_frame *mesa_backtrace,
- unsigned nr_frames)
-{
- Backtrace *backtrace = (Backtrace *) mesa_backtrace->function;
- size_t i;
-
- if (!nr_frames)
- return;
-
- if (nr_frames > backtrace->NumFrames())
- nr_frames = backtrace->NumFrames();
- for (i = 0; i < nr_frames; i++) {
- const std::string& frame_line = backtrace->FormatFrameData(i);
- fprintf(f, "%s\n", frame_line.c_str());
- }
-}
+++ /dev/null
-/**************************************************************************
- *
- * 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
- * Symbol lookup.
- *
- * @author Jose Fonseca <jfonseca@vmware.com>
- */
-
-#include "pipe/p_compiler.h"
-#include "os/os_thread.h"
-#include "util/u_string.h"
-
-#include "util/u_debug.h"
-#include "u_debug_symbol.h"
-#include "util/hash_table.h"
-
-
-#if defined(PIPE_OS_WINDOWS)
-
-#include <windows.h>
-#include <stddef.h>
-
-#include "dbghelp.h"
-
-
-/**
- * SymInitialize() must be called once for each process (in this case, the
- * current process), before any of the other functions can be called.
- */
-static BOOL g_bSymInitialized = FALSE;
-
-
-/**
- * Lookup the address of a DbgHelp function.
- */
-static FARPROC WINAPI
-getDbgHelpProcAddress(LPCSTR lpProcName)
-{
- static HMODULE hModule = NULL;
-
- if (!hModule) {
- static boolean bail = FALSE;
-
- if (bail) {
- return NULL;
- }
-
-#ifdef PIPE_CC_GCC
- /*
- * DbgHelp does not understand the debug information generated by MinGW toolchain.
- *
- * mgwhelp.dll is a dbghelp.dll look-alike replacement, which is able to
- * understand MinGW symbols, including on 64-bit builds.
- */
- if (!hModule) {
- hModule = LoadLibraryA("mgwhelp.dll");
- if (!hModule) {
- _debug_printf("warning: mgwhelp.dll not found: symbol names will not be resolved\n"
- "warning: download it from https://github.com/jrfonseca/drmingw/#mgwhelp\n");
- }
- }
-#endif
-
- /*
- * Fallback to the real DbgHelp.
- */
- if (!hModule) {
- hModule = LoadLibraryA("dbghelp.dll");
- }
-
- if (!hModule) {
- bail = TRUE;
- return NULL;
- }
- }
-
- return GetProcAddress(hModule, lpProcName);
-}
-
-
-/**
- * Generic macro to dispatch a DbgHelp functions.
- */
-#define DBGHELP_DISPATCH(_name, _ret_type, _ret_default, _arg_types, _arg_names) \
- static _ret_type WINAPI \
- j_##_name _arg_types \
- { \
- typedef BOOL (WINAPI *PFN) _arg_types; \
- static PFN pfn = NULL; \
- if (!pfn) { \
- pfn = (PFN) getDbgHelpProcAddress(#_name); \
- if (!pfn) { \
- return _ret_default; \
- } \
- } \
- return pfn _arg_names; \
- }
-
-DBGHELP_DISPATCH(SymInitialize,
- BOOL, 0,
- (HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess),
- (hProcess, UserSearchPath, fInvadeProcess))
-
-DBGHELP_DISPATCH(SymSetOptions,
- DWORD, FALSE,
- (DWORD SymOptions),
- (SymOptions))
-
-DBGHELP_DISPATCH(SymFromAddr,
- BOOL, FALSE,
- (HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol),
- (hProcess, Address, Displacement, Symbol))
-
-DBGHELP_DISPATCH(SymGetLineFromAddr64,
- BOOL, FALSE,
- (HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line),
- (hProcess, dwAddr, pdwDisplacement, Line))
-
-
-#undef DBGHELP_DISPATCH
-
-
-static inline boolean
-debug_symbol_name_dbghelp(const void *addr, char* buf, unsigned size)
-{
- DWORD64 dwAddr = (DWORD64)(uintptr_t)addr;
- HANDLE hProcess = GetCurrentProcess();
-
- /* General purpose buffer, to back pSymbol and other temporary stuff.
- * Must not be too memory hungry here to avoid stack overflows.
- */
- CHAR buffer[512];
-
- PSYMBOL_INFO pSymbol = (PSYMBOL_INFO) buffer;
- DWORD64 dwDisplacement = 0; /* Displacement of the input address, relative to the start of the symbol */
- DWORD dwLineDisplacement = 0;
- IMAGEHLP_LINE64 Line;
-
- memset(pSymbol, 0, sizeof *pSymbol);
- pSymbol->SizeOfStruct = sizeof buffer;
- pSymbol->MaxNameLen = sizeof buffer - offsetof(SYMBOL_INFO, Name);
-
- if (!g_bSymInitialized) {
- j_SymSetOptions(/* SYMOPT_UNDNAME | */ SYMOPT_LOAD_LINES);
- if (j_SymInitialize(hProcess, NULL, TRUE)) {
- g_bSymInitialized = TRUE;
- }
- }
-
- /* Lookup symbol name */
- if (!g_bSymInitialized ||
- !j_SymFromAddr(hProcess, dwAddr, &dwDisplacement, pSymbol)) {
- /*
- * We couldn't obtain symbol information. At least tell which module the address belongs.
- */
-
- HMODULE hModule = NULL;
-
- if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
- (LPCTSTR)addr,
- &hModule)) {
- return FALSE;
- }
-
- if (GetModuleFileNameA(hModule, buffer, sizeof buffer) == sizeof buffer) {
- return FALSE;
- }
- snprintf(buf, size, "%p at %s+0x%lx",
- addr, buffer,
- (unsigned long)((uintptr_t)addr - (uintptr_t)hModule));
-
- return TRUE;
- }
-
- /*
- * Try to get filename and line number.
- */
- memset(&Line, 0, sizeof Line);
- Line.SizeOfStruct = sizeof Line;
- if (!j_SymGetLineFromAddr64(hProcess, dwAddr, &dwLineDisplacement, &Line)) {
- Line.FileName = NULL;
- }
-
- if (Line.FileName) {
- snprintf(buf, size, "%s at %s:%lu", pSymbol->Name, Line.FileName, Line.LineNumber);
- } else {
- snprintf(buf, size, "%s", pSymbol->Name);
- }
-
- return TRUE;
-}
-
-#endif /* PIPE_OS_WINDOWS */
-
-
-#if defined(HAVE_EXECINFO_H)
-
-#include <execinfo.h>
-
-/* This can only provide dynamic symbols, or binary offsets into a file.
- *
- * To fix this, post-process the output with tools/addr2line.sh
- */
-static inline boolean
-debug_symbol_name_glibc(const void *addr, char* buf, unsigned size)
-{
- char** syms = backtrace_symbols((void**)&addr, 1);
- if (!syms) {
- return FALSE;
- }
- strncpy(buf, syms[0], size - 1);
- buf[size - 1] = 0;
- free(syms);
- return TRUE;
-}
-
-#endif /* defined(HAVE_EXECINFO_H) */
-
-
-void
-debug_symbol_name(const void *addr, char* buf, unsigned size)
-{
-#if defined(PIPE_OS_WINDOWS)
- if (debug_symbol_name_dbghelp(addr, buf, size)) {
- return;
- }
-#endif
-
-#if defined(HAVE_EXECINFO_H)
- if (debug_symbol_name_glibc(addr, buf, size)) {
- return;
- }
-#endif /* defined(HAVE_EXECINFO_H) */
-
- snprintf(buf, size, "%p", addr);
- buf[size - 1] = 0;
-}
-
-void
-debug_symbol_print(const void *addr)
-{
- char buf[1024];
- debug_symbol_name(addr, buf, sizeof(buf));
- debug_printf("\t%s\n", buf);
-}
-
-static struct hash_table* symbols_hash;
-#ifdef PIPE_OS_WINDOWS
-static mtx_t symbols_mutex;
-#else
-static mtx_t symbols_mutex = _MTX_INITIALIZER_NP;
-#endif
-
-const char*
-debug_symbol_name_cached(const void *addr)
-{
- const char* name;
-#ifdef PIPE_OS_WINDOWS
- static boolean first = TRUE;
-
- if (first) {
- (void) mtx_init(&symbols_mutex, mtx_plain);
- first = FALSE;
- }
-#endif
-
- mtx_lock(&symbols_mutex);
- if(!symbols_hash)
- symbols_hash = _mesa_pointer_hash_table_create(NULL);
- struct hash_entry *entry = _mesa_hash_table_search(symbols_hash, addr);
- if (!entry) {
- char buf[1024];
- debug_symbol_name(addr, buf, sizeof(buf));
- name = strdup(buf);
-
- entry = _mesa_hash_table_insert(symbols_hash, addr, (void*)name);
- }
- mtx_unlock(&symbols_mutex);
- return entry->data;
-}
+++ /dev/null
-/**************************************************************************
- *
- * 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.
- *
- **************************************************************************/
-
-#ifndef U_DEBUG_SYMBOL_H_
-#define U_DEBUG_SYMBOL_H_
-
-
-/**
- * @file
- * Symbol lookup.
- *
- * @author Jose Fonseca <jfonseca@vmware.com>
- */
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-void
-debug_symbol_name(const void *addr, char* buf, unsigned size);
-
-const char*
-debug_symbol_name_cached(const void *addr);
-
-void
-debug_symbol_print(const void *addr);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* U_DEBUG_SYMBOL_H_ */
dep_m,
dep_valgrind,
dep_zstd,
+ dep_dl,
+ dep_unwind,
]
if with_platform_android
deps_for_libmesa_util += dep_android
+ files_debug_stack = files('u_debug_stack_android.cpp')
+ else
+ files_debug_stack = files(
+ 'u_debug_stack.c',
+ 'u_debug_symbol.c',
+ 'u_debug_symbol.h',
+ )
endif
_libmesa_util = static_library(
'mesa_util',
- [files_mesa_util, format_srgb],
+ [files_mesa_util, files_debug_stack, format_srgb],
include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux],
dependencies : deps_for_libmesa_util,
link_with: libmesa_format,
--- /dev/null
+/**************************************************************************
+ *
+ * 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@vmware.com>
+ */
+
+#include "util/u_debug.h"
+#include "u_debug_symbol.h"
+#include "u_debug_stack.h"
+#include "pipe/p_config.h"
+
+#if defined(HAVE_LIBUNWIND)
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <dlfcn.h>
+
+#include "os/os_thread.h"
+#include "util/hash_table.h"
+
+static struct hash_table* symbols_hash;
+static mtx_t symbols_mutex = _MTX_INITIALIZER_NP;
+
+/* TODO with some refactoring we might be able to re-use debug_symbol_name_cached()
+ * instead.. otoh if using libunwind I think u_debug_symbol could just be excluded
+ * from build?
+ */
+static const char *
+symbol_name_cached(unw_cursor_t *cursor, unw_proc_info_t *pip)
+{
+ void *addr = (void *)(uintptr_t)pip->start_ip;
+ char *name;
+
+ mtx_lock(&symbols_mutex);
+ if(!symbols_hash)
+ symbols_hash = _mesa_pointer_hash_table_create(NULL);
+ struct hash_entry *entry = _mesa_hash_table_search(symbols_hash, addr);
+ if (!entry) {
+ 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;
+ }
+
+ if (asprintf(&name, "%s%s", procname, ret == -UNW_ENOMEM ? "..." : "") == -1)
+ name = "??";
+ entry = _mesa_hash_table_insert(symbols_hash, addr, (void*)name);
+ }
+ mtx_unlock(&symbols_mutex);
+
+ return entry->data;
+}
+
+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 "?";
+}
+
+void
+debug_backtrace_dump(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);
+ debug_printf("\t%s(+0x%x) (%s+0x%x) [%p]\n", filename, offset,
+ backtrace[i].procname, backtrace[i].off,
+ frame_ip(&backtrace[i]));
+ }
+}
+
+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]));
+ }
+}
+#elif defined(ANDROID)
+ /* Not implemented here; see u_debug_stack_android.cpp */
+#else /* ! HAVE_LIBUNWIND */
+
+#if defined(PIPE_OS_WINDOWS)
+#include <windows.h>
+#endif
+
+
+/**
+ * Capture stack backtrace.
+ *
+ * NOTE: The implementation of this function is quite big, but it is important
+ * not to break it down in smaller functions to avoid adding new frames to the
+ * calling stack.
+ */
+void
+debug_backtrace_capture(struct debug_stack_frame *backtrace,
+ unsigned start_frame,
+ unsigned nr_frames)
+{
+ const void **frame_pointer = NULL;
+ unsigned i = 0;
+
+ if (!nr_frames) {
+ return;
+ }
+
+ /*
+ * On Windows try obtaining the stack backtrace via CaptureStackBackTrace.
+ *
+ * It works reliably both for x86 for x86_64.
+ */
+#if defined(PIPE_OS_WINDOWS)
+ {
+ typedef USHORT (WINAPI *PFNCAPTURESTACKBACKTRACE)(ULONG, ULONG,
+ PVOID *, PULONG);
+ static PFNCAPTURESTACKBACKTRACE pfnCaptureStackBackTrace = NULL;
+
+ if (!pfnCaptureStackBackTrace) {
+ static HMODULE hModule = NULL;
+ if (!hModule) {
+ hModule = LoadLibraryA("kernel32");
+ assert(hModule);
+ }
+ if (hModule) {
+ pfnCaptureStackBackTrace =
+ (PFNCAPTURESTACKBACKTRACE)GetProcAddress(hModule,
+ "RtlCaptureStackBackTrace");
+ }
+ }
+ if (pfnCaptureStackBackTrace) {
+ /*
+ * Skip this (debug_backtrace_capture) function's frame.
+ */
+
+ start_frame += 1;
+
+ assert(start_frame + nr_frames < 63);
+ i = pfnCaptureStackBackTrace(start_frame, nr_frames,
+ (PVOID *) &backtrace->function, NULL);
+
+ /* Pad remaing requested frames with NULL */
+ while (i < nr_frames) {
+ backtrace[i++].function = NULL;
+ }
+
+ return;
+ }
+ }
+#endif
+
+#if defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION > 404) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-address"
+ frame_pointer = ((const void **)__builtin_frame_address(1));
+#pragma GCC diagnostic pop
+#elif defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86)
+ __asm {
+ mov frame_pointer, ebp
+ }
+ frame_pointer = (const void **)frame_pointer[0];
+#else
+ frame_pointer = NULL;
+#endif
+
+#ifdef PIPE_ARCH_X86
+ while (nr_frames) {
+ const void **next_frame_pointer;
+
+ if (!frame_pointer)
+ break;
+
+ if (start_frame)
+ --start_frame;
+ else {
+ backtrace[i++].function = frame_pointer[1];
+ --nr_frames;
+ }
+
+ next_frame_pointer = (const void **)frame_pointer[0];
+
+ /* Limit the stack walk to avoid referencing undefined memory */
+ if ((uintptr_t)next_frame_pointer <= (uintptr_t)frame_pointer ||
+ (uintptr_t)next_frame_pointer > (uintptr_t)frame_pointer + 64*1024)
+ break;
+
+ frame_pointer = next_frame_pointer;
+ }
+#else
+ (void) frame_pointer;
+#endif
+
+ while (nr_frames) {
+ backtrace[i++].function = NULL;
+ --nr_frames;
+ }
+}
+
+
+void
+debug_backtrace_dump(const struct debug_stack_frame *backtrace,
+ unsigned nr_frames)
+{
+ unsigned i;
+
+ for (i = 0; i < nr_frames; ++i) {
+ if (!backtrace[i].function)
+ break;
+ debug_symbol_print(backtrace[i].function);
+ }
+}
+
+
+void
+debug_backtrace_print(FILE *f,
+ const struct debug_stack_frame *backtrace,
+ unsigned nr_frames)
+{
+ unsigned i;
+
+ for (i = 0; i < nr_frames; ++i) {
+ const char *symbol;
+ if (!backtrace[i].function)
+ break;
+ symbol = debug_symbol_name_cached(backtrace[i].function);
+ if (symbol)
+ fprintf(f, "%s\n", symbol);
+ }
+}
+
+#endif /* HAVE_LIBUNWIND */
--- /dev/null
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#ifndef U_DEBUG_STACK_H_
+#define U_DEBUG_STACK_H_
+
+#include <stdio.h>
+
+#ifdef HAVE_LIBUNWIND
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#endif
+
+/**
+ * @file
+ * Stack backtracing.
+ *
+ * @author Jose Fonseca <jfonseca@vmware.com>
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Represent a frame from a stack backtrace.
+ *
+#if defined(PIPE_OS_WINDOWS) && !defined(HAVE_LIBUNWIND)
+ * XXX: Do not change this. (passed to Windows' CaptureStackBackTrace())
+#endif
+ *
+ * TODO: This should be refactored as a void * typedef.
+ */
+struct debug_stack_frame
+{
+#ifdef HAVE_LIBUNWIND
+ unw_word_t start_ip;
+ unsigned int off;
+ const char *procname;
+#else
+ const void *function;
+#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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* U_DEBUG_STACK_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2018 Stefan Schake <stschake@gmail.com>
+ *
+ * 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.
+ */
+
+#include <backtrace/Backtrace.h>
+
+#include "util/u_debug.h"
+#include "u_debug_stack.h"
+#include "util/hash_table.h"
+#include "os/os_thread.h"
+
+static hash_table *backtrace_table;
+static mtx_t table_mutex = _MTX_INITIALIZER_NP;
+
+void
+debug_backtrace_capture(debug_stack_frame *mesa_backtrace,
+ unsigned start_frame,
+ unsigned nr_frames)
+{
+ hash_entry *backtrace_entry;
+ Backtrace *backtrace;
+ pid_t tid = gettid();
+
+ if (!nr_frames)
+ return;
+
+ /* We keep an Android Backtrace handler around for each thread */
+ mtx_lock(&table_mutex);
+ if (!backtrace_table)
+ backtrace_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+
+ backtrace_entry = _mesa_hash_table_search(backtrace_table, (void*) (uintptr_t)tid);
+ if (!backtrace_entry) {
+ backtrace = Backtrace::Create(getpid(), tid);
+ _mesa_hash_table_insert(backtrace_table, (void*) (uintptr_t)tid, backtrace);
+ } else {
+ backtrace = (Backtrace *) backtrace_entry->data;
+ }
+ mtx_unlock(&table_mutex);
+
+ /* Add one to exclude this call. Unwind already ignores itself. */
+ backtrace->Unwind(start_frame + 1);
+
+ /* Store the Backtrace handler in the first mesa frame for reference.
+ * Unwind will generally return less frames than nr_frames specified
+ * but we have no good way of storing the real count otherwise.
+ * The Backtrace handler only stores the results until the next Unwind,
+ * but that is how u_debug_stack is used anyway.
+ */
+ mesa_backtrace->function = backtrace;
+}
+
+void
+debug_backtrace_dump(const debug_stack_frame *mesa_backtrace,
+ unsigned nr_frames)
+{
+ Backtrace *backtrace = (Backtrace *) mesa_backtrace->function;
+ size_t i;
+
+ if (!nr_frames)
+ return;
+
+ if (nr_frames > backtrace->NumFrames())
+ nr_frames = backtrace->NumFrames();
+ for (i = 0; i < nr_frames; i++) {
+ /* There is no prescribed format and this isn't interpreted further,
+ * so we simply use the default Android format.
+ */
+ const std::string& frame_line = backtrace->FormatFrameData(i);
+ debug_printf("%s\n", frame_line.c_str());
+ }
+}
+
+void
+debug_backtrace_print(FILE *f,
+ const debug_stack_frame *mesa_backtrace,
+ unsigned nr_frames)
+{
+ Backtrace *backtrace = (Backtrace *) mesa_backtrace->function;
+ size_t i;
+
+ if (!nr_frames)
+ return;
+
+ if (nr_frames > backtrace->NumFrames())
+ nr_frames = backtrace->NumFrames();
+ for (i = 0; i < nr_frames; i++) {
+ const std::string& frame_line = backtrace->FormatFrameData(i);
+ fprintf(f, "%s\n", frame_line.c_str());
+ }
+}
--- /dev/null
+/**************************************************************************
+ *
+ * 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
+ * Symbol lookup.
+ *
+ * @author Jose Fonseca <jfonseca@vmware.com>
+ */
+
+#include "pipe/p_compiler.h"
+#include "os/os_thread.h"
+#include "util/u_string.h"
+
+#include "util/u_debug.h"
+#include "u_debug_symbol.h"
+#include "util/hash_table.h"
+
+
+#if defined(PIPE_OS_WINDOWS)
+
+#include <windows.h>
+#include <stddef.h>
+
+#include "dbghelp.h"
+
+
+/**
+ * SymInitialize() must be called once for each process (in this case, the
+ * current process), before any of the other functions can be called.
+ */
+static BOOL g_bSymInitialized = FALSE;
+
+
+/**
+ * Lookup the address of a DbgHelp function.
+ */
+static FARPROC WINAPI
+getDbgHelpProcAddress(LPCSTR lpProcName)
+{
+ static HMODULE hModule = NULL;
+
+ if (!hModule) {
+ static boolean bail = FALSE;
+
+ if (bail) {
+ return NULL;
+ }
+
+#ifdef PIPE_CC_GCC
+ /*
+ * DbgHelp does not understand the debug information generated by MinGW toolchain.
+ *
+ * mgwhelp.dll is a dbghelp.dll look-alike replacement, which is able to
+ * understand MinGW symbols, including on 64-bit builds.
+ */
+ if (!hModule) {
+ hModule = LoadLibraryA("mgwhelp.dll");
+ if (!hModule) {
+ _debug_printf("warning: mgwhelp.dll not found: symbol names will not be resolved\n"
+ "warning: download it from https://github.com/jrfonseca/drmingw/#mgwhelp\n");
+ }
+ }
+#endif
+
+ /*
+ * Fallback to the real DbgHelp.
+ */
+ if (!hModule) {
+ hModule = LoadLibraryA("dbghelp.dll");
+ }
+
+ if (!hModule) {
+ bail = TRUE;
+ return NULL;
+ }
+ }
+
+ return GetProcAddress(hModule, lpProcName);
+}
+
+
+/**
+ * Generic macro to dispatch a DbgHelp functions.
+ */
+#define DBGHELP_DISPATCH(_name, _ret_type, _ret_default, _arg_types, _arg_names) \
+ static _ret_type WINAPI \
+ j_##_name _arg_types \
+ { \
+ typedef BOOL (WINAPI *PFN) _arg_types; \
+ static PFN pfn = NULL; \
+ if (!pfn) { \
+ pfn = (PFN) getDbgHelpProcAddress(#_name); \
+ if (!pfn) { \
+ return _ret_default; \
+ } \
+ } \
+ return pfn _arg_names; \
+ }
+
+DBGHELP_DISPATCH(SymInitialize,
+ BOOL, 0,
+ (HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess),
+ (hProcess, UserSearchPath, fInvadeProcess))
+
+DBGHELP_DISPATCH(SymSetOptions,
+ DWORD, FALSE,
+ (DWORD SymOptions),
+ (SymOptions))
+
+DBGHELP_DISPATCH(SymFromAddr,
+ BOOL, FALSE,
+ (HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol),
+ (hProcess, Address, Displacement, Symbol))
+
+DBGHELP_DISPATCH(SymGetLineFromAddr64,
+ BOOL, FALSE,
+ (HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line),
+ (hProcess, dwAddr, pdwDisplacement, Line))
+
+
+#undef DBGHELP_DISPATCH
+
+
+static inline boolean
+debug_symbol_name_dbghelp(const void *addr, char* buf, unsigned size)
+{
+ DWORD64 dwAddr = (DWORD64)(uintptr_t)addr;
+ HANDLE hProcess = GetCurrentProcess();
+
+ /* General purpose buffer, to back pSymbol and other temporary stuff.
+ * Must not be too memory hungry here to avoid stack overflows.
+ */
+ CHAR buffer[512];
+
+ PSYMBOL_INFO pSymbol = (PSYMBOL_INFO) buffer;
+ DWORD64 dwDisplacement = 0; /* Displacement of the input address, relative to the start of the symbol */
+ DWORD dwLineDisplacement = 0;
+ IMAGEHLP_LINE64 Line;
+
+ memset(pSymbol, 0, sizeof *pSymbol);
+ pSymbol->SizeOfStruct = sizeof buffer;
+ pSymbol->MaxNameLen = sizeof buffer - offsetof(SYMBOL_INFO, Name);
+
+ if (!g_bSymInitialized) {
+ j_SymSetOptions(/* SYMOPT_UNDNAME | */ SYMOPT_LOAD_LINES);
+ if (j_SymInitialize(hProcess, NULL, TRUE)) {
+ g_bSymInitialized = TRUE;
+ }
+ }
+
+ /* Lookup symbol name */
+ if (!g_bSymInitialized ||
+ !j_SymFromAddr(hProcess, dwAddr, &dwDisplacement, pSymbol)) {
+ /*
+ * We couldn't obtain symbol information. At least tell which module the address belongs.
+ */
+
+ HMODULE hModule = NULL;
+
+ if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ (LPCTSTR)addr,
+ &hModule)) {
+ return FALSE;
+ }
+
+ if (GetModuleFileNameA(hModule, buffer, sizeof buffer) == sizeof buffer) {
+ return FALSE;
+ }
+ snprintf(buf, size, "%p at %s+0x%lx",
+ addr, buffer,
+ (unsigned long)((uintptr_t)addr - (uintptr_t)hModule));
+
+ return TRUE;
+ }
+
+ /*
+ * Try to get filename and line number.
+ */
+ memset(&Line, 0, sizeof Line);
+ Line.SizeOfStruct = sizeof Line;
+ if (!j_SymGetLineFromAddr64(hProcess, dwAddr, &dwLineDisplacement, &Line)) {
+ Line.FileName = NULL;
+ }
+
+ if (Line.FileName) {
+ snprintf(buf, size, "%s at %s:%lu", pSymbol->Name, Line.FileName, Line.LineNumber);
+ } else {
+ snprintf(buf, size, "%s", pSymbol->Name);
+ }
+
+ return TRUE;
+}
+
+#endif /* PIPE_OS_WINDOWS */
+
+
+#if defined(HAVE_EXECINFO_H)
+
+#include <execinfo.h>
+
+/* This can only provide dynamic symbols, or binary offsets into a file.
+ *
+ * To fix this, post-process the output with tools/addr2line.sh
+ */
+static inline boolean
+debug_symbol_name_glibc(const void *addr, char* buf, unsigned size)
+{
+ char** syms = backtrace_symbols((void**)&addr, 1);
+ if (!syms) {
+ return FALSE;
+ }
+ strncpy(buf, syms[0], size - 1);
+ buf[size - 1] = 0;
+ free(syms);
+ return TRUE;
+}
+
+#endif /* defined(HAVE_EXECINFO_H) */
+
+
+void
+debug_symbol_name(const void *addr, char* buf, unsigned size)
+{
+#if defined(PIPE_OS_WINDOWS)
+ if (debug_symbol_name_dbghelp(addr, buf, size)) {
+ return;
+ }
+#endif
+
+#if defined(HAVE_EXECINFO_H)
+ if (debug_symbol_name_glibc(addr, buf, size)) {
+ return;
+ }
+#endif /* defined(HAVE_EXECINFO_H) */
+
+ snprintf(buf, size, "%p", addr);
+ buf[size - 1] = 0;
+}
+
+void
+debug_symbol_print(const void *addr)
+{
+ char buf[1024];
+ debug_symbol_name(addr, buf, sizeof(buf));
+ debug_printf("\t%s\n", buf);
+}
+
+static struct hash_table* symbols_hash;
+#ifdef PIPE_OS_WINDOWS
+static mtx_t symbols_mutex;
+#else
+static mtx_t symbols_mutex = _MTX_INITIALIZER_NP;
+#endif
+
+const char*
+debug_symbol_name_cached(const void *addr)
+{
+ const char* name;
+#ifdef PIPE_OS_WINDOWS
+ static boolean first = TRUE;
+
+ if (first) {
+ (void) mtx_init(&symbols_mutex, mtx_plain);
+ first = FALSE;
+ }
+#endif
+
+ mtx_lock(&symbols_mutex);
+ if(!symbols_hash)
+ symbols_hash = _mesa_pointer_hash_table_create(NULL);
+ struct hash_entry *entry = _mesa_hash_table_search(symbols_hash, addr);
+ if (!entry) {
+ char buf[1024];
+ debug_symbol_name(addr, buf, sizeof(buf));
+ name = strdup(buf);
+
+ entry = _mesa_hash_table_insert(symbols_hash, addr, (void*)name);
+ }
+ mtx_unlock(&symbols_mutex);
+ return entry->data;
+}
--- /dev/null
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#ifndef U_DEBUG_SYMBOL_H_
+#define U_DEBUG_SYMBOL_H_
+
+
+/**
+ * @file
+ * Symbol lookup.
+ *
+ * @author Jose Fonseca <jfonseca@vmware.com>
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void
+debug_symbol_name(const void *addr, char* buf, unsigned size);
+
+const char*
+debug_symbol_name_cached(const void *addr);
+
+void
+debug_symbol_print(const void *addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* U_DEBUG_SYMBOL_H_ */