Back to index

glibc  2.9
backtrace.c
Go to the documentation of this file.
00001 /* Return backtrace of current program state.
00002    Copyright (C) 1998, 2000, 2003-2005, 2007 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <bits/libc-lock.h>
00022 #include <dlfcn.h>
00023 #include <execinfo.h>
00024 #include <stdlib.h>
00025 #include <unwind.h>
00026 
00027 struct trace_arg
00028 {
00029   void **array;
00030   int cnt, size;
00031   void *lastebp, *lastesp;
00032 };
00033 
00034 #ifdef SHARED
00035 static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
00036 static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
00037 static _Unwind_Ptr (*unwind_getcfa) (struct _Unwind_Context *);
00038 static _Unwind_Ptr (*unwind_getgr) (struct _Unwind_Context *, int);
00039 static void *libgcc_handle;
00040 
00041 static void
00042 init (void)
00043 {
00044   libgcc_handle = __libc_dlopen ("libgcc_s.so.1");
00045 
00046   if (libgcc_handle == NULL)
00047     return;
00048 
00049   unwind_backtrace = __libc_dlsym (libgcc_handle, "_Unwind_Backtrace");
00050   unwind_getip = __libc_dlsym (libgcc_handle, "_Unwind_GetIP");
00051   unwind_getcfa = __libc_dlsym (libgcc_handle, "_Unwind_GetCFA");
00052   unwind_getgr = __libc_dlsym (libgcc_handle, "_Unwind_GetGR");
00053   if (unwind_getip == NULL || unwind_getgr == NULL || unwind_getcfa == NULL)
00054     {
00055       unwind_backtrace = NULL;
00056       __libc_dlclose (libgcc_handle);
00057       libgcc_handle = NULL;
00058     }
00059 }
00060 #else
00061 # define unwind_backtrace _Unwind_Backtrace
00062 # define unwind_getip _Unwind_GetIP
00063 # define unwind_getcfa _Unwind_GetCFA
00064 # define unwind_getgr _Unwind_GetGR
00065 #endif
00066 
00067 static _Unwind_Reason_Code
00068 backtrace_helper (struct _Unwind_Context *ctx, void *a)
00069 {
00070   struct trace_arg *arg = a;
00071 
00072   /* We are first called with address in the __backtrace function.
00073      Skip it.  */
00074   if (arg->cnt != -1)
00075     arg->array[arg->cnt] = (void *) unwind_getip (ctx);
00076   if (++arg->cnt == arg->size)
00077     return _URC_END_OF_STACK;
00078 
00079   /* %ebp is DWARF2 register 5 on IA-32.  */
00080   arg->lastebp = (void *) unwind_getgr (ctx, 5);
00081   arg->lastesp = (void *) unwind_getcfa (ctx);
00082   return _URC_NO_REASON;
00083 }
00084 
00085 
00086 /* This is a global variable set at program start time.  It marks the
00087    highest used stack address.  */
00088 extern void *__libc_stack_end;
00089 
00090 
00091 /* This is the stack layout we see with every stack frame
00092    if not compiled without frame pointer.
00093 
00094             +-----------------+        +-----------------+
00095     %ebp -> | %ebp last frame--------> | %ebp last frame--->...
00096             |                 |        |                 |
00097             | return address  |        | return address  |
00098             +-----------------+        +-----------------+
00099 
00100    First try as far to get as far as possible using
00101    _Unwind_Backtrace which handles -fomit-frame-pointer
00102    as well, but requires .eh_frame info.  Then fall back to
00103    walking the stack manually.  */
00104 
00105 struct layout
00106 {
00107   struct layout *ebp;
00108   void *ret;
00109 };
00110 
00111 
00112 int
00113 __backtrace (array, size)
00114      void **array;
00115      int size;
00116 {
00117   struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
00118 #ifdef SHARED
00119   __libc_once_define (static, once);
00120 
00121   __libc_once (once, init);
00122   if (unwind_backtrace == NULL)
00123     return 0;
00124 #endif
00125 
00126   if (size >= 1)
00127     unwind_backtrace (backtrace_helper, &arg);
00128 
00129   if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
00130     --arg.cnt;
00131   else if (arg.cnt < size)
00132     {
00133       struct layout *ebp = (struct layout *) arg.lastebp;
00134 
00135       while (arg.cnt < size)
00136        {
00137          /* Check for out of range.  */
00138          if ((void *) ebp < arg.lastesp || (void *) ebp > __libc_stack_end
00139              || ((long) ebp & 3))
00140            break;
00141 
00142          array[arg.cnt++] = ebp->ret;
00143          ebp = ebp->ebp;
00144        }
00145     }
00146   return arg.cnt != -1 ? arg.cnt : 0;
00147 }
00148 weak_alias (__backtrace, backtrace)
00149 libc_hidden_def (__backtrace)
00150 
00151 
00152 #ifdef SHARED
00153 /* Free all resources if necessary.  */
00154 libc_freeres_fn (free_mem)
00155 {
00156   unwind_backtrace = NULL;
00157   if (libgcc_handle != NULL)
00158     {
00159       __libc_dlclose (libgcc_handle);
00160       libgcc_handle = NULL;
00161     }
00162 }
00163 #endif