"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/gallium/auxiliary/util/u_debug_stack.c" (16 Sep 2020, 8906 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "u_debug_stack.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20.1.5_vs_20.2.0-rc1.

    1 /**************************************************************************
    2  * 
    3  * Copyright 2009 VMware, Inc.
    4  * All Rights Reserved.
    5  *
    6  * Permission is hereby granted, free of charge, to any person obtaining a
    7  * copy of this software and associated documentation files (the
    8  * "Software"), to deal in the Software without restriction, including
    9  * without limitation the rights to use, copy, modify, merge, publish,
   10  * distribute, sub license, and/or sell copies of the Software, and to
   11  * permit persons to whom the Software is furnished to do so, subject to
   12  * the following conditions:
   13  *
   14  * The above copyright notice and this permission notice (including the
   15  * next paragraph) shall be included in all copies or substantial portions
   16  * of the Software.
   17  *
   18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
   21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
   22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   25  *
   26  **************************************************************************/
   27 
   28 /**
   29  * @file
   30  * Stack backtracing.
   31  *
   32  * @author Jose Fonseca <jfonseca@vmware.com>
   33  */
   34 
   35 #include "util/u_debug.h"
   36 #include "u_debug_symbol.h"
   37 #include "u_debug_stack.h"
   38 
   39 #if defined(HAVE_LIBUNWIND)
   40 
   41 #ifndef _GNU_SOURCE
   42 #define _GNU_SOURCE
   43 #endif
   44 #include <dlfcn.h>
   45 
   46 #include "os/os_thread.h"
   47 #include "u_hash_table.h"
   48 
   49 static struct hash_table* symbols_hash;
   50 static mtx_t symbols_mutex = _MTX_INITIALIZER_NP;
   51 
   52 /* TODO with some refactoring we might be able to re-use debug_symbol_name_cached()
   53  * instead.. otoh if using libunwind I think u_debug_symbol could just be excluded
   54  * from build?
   55  */
   56 static const char *
   57 symbol_name_cached(unw_cursor_t *cursor, unw_proc_info_t *pip)
   58 {
   59    void *addr = (void *)(uintptr_t)pip->start_ip;
   60    char *name;
   61 
   62    mtx_lock(&symbols_mutex);
   63    if(!symbols_hash)
   64       symbols_hash = util_hash_table_create_ptr_keys();
   65    name = util_hash_table_get(symbols_hash, addr);
   66    if(!name)
   67    {
   68       char procname[256];
   69       unw_word_t off;
   70       int ret;
   71 
   72       ret = unw_get_proc_name(cursor, procname, sizeof(procname), &off);
   73       if (ret && ret != -UNW_ENOMEM) {
   74          procname[0] = '?';
   75          procname[1] = 0;
   76       }
   77 
   78       if (asprintf(&name, "%s%s", procname, ret == -UNW_ENOMEM ? "..." : "") == -1) 
   79          name = "??";
   80       _mesa_hash_table_insert(symbols_hash, addr, (void*)name);
   81    }
   82    mtx_unlock(&symbols_mutex);
   83 
   84    return name;
   85 }
   86 
   87 void
   88 debug_backtrace_capture(struct debug_stack_frame *backtrace,
   89                         unsigned start_frame,
   90                         unsigned nr_frames)
   91 {
   92    unw_cursor_t cursor;
   93    unw_context_t context;
   94    unw_proc_info_t pip;
   95    unsigned i = 0;
   96 
   97    pip.unwind_info = NULL;
   98 
   99    unw_getcontext(&context);
  100    unw_init_local(&cursor, &context);
  101 
  102    while ((start_frame > 0) && (unw_step(&cursor) > 0))
  103       start_frame--;
  104 
  105    while ((i < nr_frames) && (unw_step(&cursor) > 0)) {
  106       unw_word_t ip;
  107 
  108       unw_get_reg(&cursor, UNW_REG_IP, &ip);
  109       unw_get_proc_info(&cursor, &pip);
  110 
  111       backtrace[i].start_ip = pip.start_ip;
  112       backtrace[i].off      = ip - pip.start_ip;
  113       backtrace[i].procname = symbol_name_cached(&cursor, &pip);
  114 
  115       i++;
  116    }
  117 
  118    while (i < nr_frames) {
  119       backtrace[i].start_ip = 0;
  120       i++;
  121    }
  122 }
  123 
  124 static const void *
  125 frame_ip(const struct debug_stack_frame *frame)
  126 {
  127    return (void *)(uintptr_t)(frame->start_ip + frame->off);
  128 }
  129 
  130 static const char *
  131 frame_info(const struct debug_stack_frame *frame, unsigned *offset)
  132 {
  133    Dl_info dlinfo;
  134    const void *addr = frame_ip(frame);
  135 
  136 
  137    if (dladdr(addr, &dlinfo) && dlinfo.dli_fname &&
  138            *dlinfo.dli_fname) {
  139       *offset = (unsigned)((uintptr_t)addr - (uintptr_t)dlinfo.dli_fbase);
  140       return dlinfo.dli_fname;
  141    }
  142 
  143    *offset = 0;
  144    return "?";
  145 }
  146 
  147 void
  148 debug_backtrace_dump(const struct debug_stack_frame *backtrace,
  149                      unsigned nr_frames)
  150 {
  151    unsigned i, offset;
  152    const char *filename;
  153 
  154    for (i = 0; i < nr_frames; ++i) {
  155       if (!backtrace[i].start_ip)
  156          break;
  157       filename = frame_info(&backtrace[i], &offset);
  158       debug_printf("\t%s(+0x%x) (%s+0x%x) [%p]\n", filename, offset,
  159             backtrace[i].procname, backtrace[i].off,
  160             frame_ip(&backtrace[i]));
  161    }
  162 }
  163 
  164 void
  165 debug_backtrace_print(FILE *f,
  166                       const struct debug_stack_frame *backtrace,
  167                       unsigned nr_frames)
  168 {
  169    unsigned i, offset;
  170    const char *filename;
  171 
  172    for (i = 0; i < nr_frames; ++i) {
  173       if (!backtrace[i].start_ip)
  174          break;
  175       filename = frame_info(&backtrace[i], &offset);
  176       fprintf(f, "\t%s(+0x%x) (%s+0x%x) [%p]\n", filename, offset,
  177             backtrace[i].procname, backtrace[i].off,
  178             frame_ip(&backtrace[i]));
  179    }
  180 }
  181 #elif defined(ANDROID)
  182    /* Not implemented here; see u_debug_stack_android.cpp */
  183 #else /* ! HAVE_LIBUNWIND */
  184 
  185 #if defined(PIPE_OS_WINDOWS)
  186 #include <windows.h>
  187 #endif
  188 
  189 
  190 /**
  191  * Capture stack backtrace.
  192  *
  193  * NOTE: The implementation of this function is quite big, but it is important
  194  * not to break it down in smaller functions to avoid adding new frames to the
  195  * calling stack.
  196  */
  197 void
  198 debug_backtrace_capture(struct debug_stack_frame *backtrace,
  199                         unsigned start_frame,
  200                         unsigned nr_frames)
  201 {
  202    const void **frame_pointer = NULL;
  203    unsigned i = 0;
  204 
  205    if (!nr_frames) {
  206       return;
  207    }
  208 
  209    /*
  210     * On Windows try obtaining the stack backtrace via CaptureStackBackTrace.
  211     *
  212     * It works reliably both for x86 for x86_64.
  213     */
  214 #if defined(PIPE_OS_WINDOWS)
  215    {
  216       typedef USHORT (WINAPI *PFNCAPTURESTACKBACKTRACE)(ULONG, ULONG,
  217                                                         PVOID *, PULONG);
  218       static PFNCAPTURESTACKBACKTRACE pfnCaptureStackBackTrace = NULL;
  219 
  220       if (!pfnCaptureStackBackTrace) {
  221          static HMODULE hModule = NULL;
  222          if (!hModule) {
  223             hModule = LoadLibraryA("kernel32");
  224             assert(hModule);
  225          }
  226          if (hModule) {
  227             pfnCaptureStackBackTrace =
  228                (PFNCAPTURESTACKBACKTRACE)GetProcAddress(hModule,
  229                                                 "RtlCaptureStackBackTrace");
  230          }
  231       }
  232       if (pfnCaptureStackBackTrace) {
  233          /*
  234           * Skip this (debug_backtrace_capture) function's frame.
  235           */
  236 
  237          start_frame += 1;
  238 
  239          assert(start_frame + nr_frames < 63);
  240          i = pfnCaptureStackBackTrace(start_frame, nr_frames,
  241                                       (PVOID *) &backtrace->function, NULL);
  242 
  243          /* Pad remaing requested frames with NULL */
  244          while (i < nr_frames) {
  245             backtrace[i++].function = NULL;
  246          }
  247 
  248          return;
  249       }
  250    }
  251 #endif
  252 
  253 #if defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION > 404) || defined(__clang__)
  254 #pragma GCC diagnostic push
  255 #pragma GCC diagnostic ignored "-Wframe-address"
  256    frame_pointer = ((const void **)__builtin_frame_address(1));
  257 #pragma GCC diagnostic pop
  258 #elif defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86)
  259    __asm {
  260       mov frame_pointer, ebp
  261    }
  262    frame_pointer = (const void **)frame_pointer[0];
  263 #else
  264    frame_pointer = NULL;
  265 #endif
  266 
  267 #ifdef PIPE_ARCH_X86
  268    while (nr_frames) {
  269       const void **next_frame_pointer;
  270 
  271       if (!frame_pointer)
  272          break;
  273 
  274       if (start_frame)
  275          --start_frame;
  276       else {
  277          backtrace[i++].function = frame_pointer[1];
  278          --nr_frames;
  279       }
  280 
  281       next_frame_pointer = (const void **)frame_pointer[0];
  282 
  283       /* Limit the stack walk to avoid referencing undefined memory */
  284       if ((uintptr_t)next_frame_pointer <= (uintptr_t)frame_pointer ||
  285           (uintptr_t)next_frame_pointer > (uintptr_t)frame_pointer + 64*1024)
  286          break;
  287 
  288       frame_pointer = next_frame_pointer;
  289    }
  290 #else
  291    (void) frame_pointer;
  292 #endif
  293 
  294    while (nr_frames) {
  295       backtrace[i++].function = NULL;
  296       --nr_frames;
  297    }
  298 }
  299 
  300 
  301 void
  302 debug_backtrace_dump(const struct debug_stack_frame *backtrace,
  303                      unsigned nr_frames)
  304 {
  305    unsigned i;
  306 
  307    for (i = 0; i < nr_frames; ++i) {
  308       if (!backtrace[i].function)
  309          break;
  310       debug_symbol_print(backtrace[i].function);
  311    }
  312 }
  313 
  314 
  315 void
  316 debug_backtrace_print(FILE *f,
  317                       const struct debug_stack_frame *backtrace,
  318                       unsigned nr_frames)
  319 {
  320    unsigned i;
  321 
  322    for (i = 0; i < nr_frames; ++i) {
  323       const char *symbol;
  324       if (!backtrace[i].function)
  325          break;
  326       symbol = debug_symbol_name_cached(backtrace[i].function);
  327       if (symbol)
  328          fprintf(f, "%s\n", symbol);
  329    }
  330 }
  331 
  332 #endif /* HAVE_LIBUNWIND */