Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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