Home | History | Annotate | Download | only in util
      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 (at) vmware.com>
     33  */
     34 
     35 #include "u_debug.h"
     36 #include "u_debug_symbol.h"
     37 #include "u_debug_stack.h"
     38 
     39 #if defined(PIPE_OS_WINDOWS)
     40 #include <windows.h>
     41 #endif
     42 
     43 
     44 /**
     45  * Capture stack backtrace.
     46  *
     47  * NOTE: The implementation of this function is quite big, but it is important
     48  * not to break it down in smaller functions to avoid adding new frames to the
     49  * calling stack.
     50  */
     51 void
     52 debug_backtrace_capture(struct debug_stack_frame *backtrace,
     53                         unsigned start_frame,
     54                         unsigned nr_frames)
     55 {
     56    const void **frame_pointer = NULL;
     57    unsigned i = 0;
     58 
     59    if (!nr_frames) {
     60       return;
     61    }
     62 
     63    /*
     64     * On Windows try obtaining the stack backtrace via CaptureStackBackTrace.
     65     *
     66     * It works reliably both for x86 for x86_64.
     67     */
     68 #if defined(PIPE_OS_WINDOWS)
     69    {
     70       typedef USHORT (WINAPI *PFNCAPTURESTACKBACKTRACE)(ULONG, ULONG,
     71                                                         PVOID *, PULONG);
     72       static PFNCAPTURESTACKBACKTRACE pfnCaptureStackBackTrace = NULL;
     73 
     74       if (!pfnCaptureStackBackTrace) {
     75          static HMODULE hModule = NULL;
     76          if (!hModule) {
     77             hModule = LoadLibraryA("kernel32");
     78             assert(hModule);
     79          }
     80          if (hModule) {
     81             pfnCaptureStackBackTrace =
     82                (PFNCAPTURESTACKBACKTRACE)GetProcAddress(hModule,
     83                                                 "RtlCaptureStackBackTrace");
     84          }
     85       }
     86       if (pfnCaptureStackBackTrace) {
     87          /*
     88           * Skip this (debug_backtrace_capture) function's frame.
     89           */
     90 
     91          start_frame += 1;
     92 
     93          assert(start_frame + nr_frames < 63);
     94          i = pfnCaptureStackBackTrace(start_frame, nr_frames,
     95                                       (PVOID *) &backtrace->function, NULL);
     96 
     97          /* Pad remaing requested frames with NULL */
     98          while (i < nr_frames) {
     99             backtrace[i++].function = NULL;
    100          }
    101 
    102          return;
    103       }
    104    }
    105 #endif
    106 
    107 #if defined(PIPE_CC_GCC)
    108    frame_pointer = ((const void **)__builtin_frame_address(1));
    109 #elif defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86)
    110    __asm {
    111       mov frame_pointer, ebp
    112    }
    113    frame_pointer = (const void **)frame_pointer[0];
    114 #else
    115    frame_pointer = NULL;
    116 #endif
    117 
    118 #ifdef PIPE_ARCH_X86
    119    while (nr_frames) {
    120       const void **next_frame_pointer;
    121 
    122       if (!frame_pointer)
    123          break;
    124 
    125       if (start_frame)
    126          --start_frame;
    127       else {
    128          backtrace[i++].function = frame_pointer[1];
    129          --nr_frames;
    130       }
    131 
    132       next_frame_pointer = (const void **)frame_pointer[0];
    133 
    134       /* Limit the stack walk to avoid referencing undefined memory */
    135       if ((uintptr_t)next_frame_pointer <= (uintptr_t)frame_pointer ||
    136           (uintptr_t)next_frame_pointer > (uintptr_t)frame_pointer + 64*1024)
    137          break;
    138 
    139       frame_pointer = next_frame_pointer;
    140    }
    141 #else
    142    (void) frame_pointer;
    143 #endif
    144 
    145    while (nr_frames) {
    146       backtrace[i++].function = NULL;
    147       --nr_frames;
    148    }
    149 }
    150 
    151 
    152 void
    153 debug_backtrace_dump(const struct debug_stack_frame *backtrace,
    154                      unsigned nr_frames)
    155 {
    156    unsigned i;
    157 
    158    for (i = 0; i < nr_frames; ++i) {
    159       if (!backtrace[i].function)
    160          break;
    161       debug_symbol_print(backtrace[i].function);
    162    }
    163 }
    164 
    165