00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #ifdef HAVE_LIBCTRACE
00026 #include <execinfo.h>
00027 #endif
00028
00029 #include <isc/backtrace.h>
00030 #include <isc/result.h>
00031 #include <isc/util.h>
00032
00033 #ifdef ISC_PLATFORM_USEBACKTRACE
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #ifdef HAVE_LIBCTRACE
00051 #define BACKTRACE_LIBC
00052 #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__ia64__))
00053 #define BACKTRACE_GCC
00054 #elif defined(WIN32)
00055 #define BACKTRACE_WIN32
00056 #elif defined(__x86_64__) || defined(__i386__)
00057 #define BACKTRACE_X86STACK
00058 #else
00059 #define BACKTRACE_DISABLED
00060 #endif
00061 #else
00062 #define BACKTRACE_DISABLED
00063 #endif
00064
00065 #ifdef BACKTRACE_LIBC
00066 isc_result_t
00067 isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
00068 int n;
00069
00070
00071
00072
00073
00074 if (addrs == NULL || nframes == NULL)
00075 return (ISC_R_FAILURE);
00076
00077
00078
00079
00080
00081 n = backtrace(addrs, maxaddrs);
00082 if (n < 2)
00083 return (ISC_R_NOTFOUND);
00084 n--;
00085 memmove(addrs, &addrs[1], sizeof(void *) * n);
00086 *nframes = n;
00087 return (ISC_R_SUCCESS);
00088 }
00089 #elif defined(BACKTRACE_GCC)
00090 extern int _Unwind_Backtrace(void* fn, void* a);
00091 extern void* _Unwind_GetIP(void* ctx);
00092
00093 typedef struct {
00094 void **result;
00095 int max_depth;
00096 int skip_count;
00097 int count;
00098 } trace_arg_t;
00099
00100 static int
00101 btcallback(void *uc, void *opq) {
00102 trace_arg_t *arg = (trace_arg_t *)opq;
00103
00104 if (arg->skip_count > 0)
00105 arg->skip_count--;
00106 else
00107 arg->result[arg->count++] = (void *)_Unwind_GetIP(uc);
00108 if (arg->count == arg->max_depth)
00109 return (5);
00110
00111 return (0);
00112 }
00113
00114 isc_result_t
00115 isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
00116 trace_arg_t arg;
00117
00118
00119 if (addrs == NULL || nframes == NULL)
00120 return (ISC_R_FAILURE);
00121
00122 arg.skip_count = 1;
00123 arg.result = addrs;
00124 arg.max_depth = maxaddrs;
00125 arg.count = 0;
00126 _Unwind_Backtrace(btcallback, &arg);
00127
00128 *nframes = arg.count;
00129
00130 return (ISC_R_SUCCESS);
00131 }
00132 #elif defined(BACKTRACE_WIN32)
00133 isc_result_t
00134 isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
00135 unsigned long ftc = (unsigned long)maxaddrs;
00136
00137 *nframes = (int)CaptureStackBackTrace(1, ftc, addrs, NULL);
00138 return ISC_R_SUCCESS;
00139 }
00140 #elif defined(BACKTRACE_X86STACK)
00141 #ifdef __x86_64__
00142 static unsigned long
00143 getrbp(void) {
00144 __asm("movq %rbp, %rax\n");
00145 }
00146 #endif
00147
00148 static void **
00149 getnextframeptr(void **sp) {
00150 void **newsp = (void **)*sp;
00151
00152
00153
00154
00155
00156
00157
00158 if (newsp <= sp)
00159 return (NULL);
00160
00161
00162 if ((char *)newsp - (char *)sp > 100000)
00163 return (NULL);
00164
00165
00166
00167
00168
00169
00170
00171 return (newsp);
00172 }
00173
00174 isc_result_t
00175 isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
00176 int i = 0;
00177 void **sp;
00178
00179
00180 if (addrs == NULL || nframes == NULL)
00181 return (ISC_R_FAILURE);
00182
00183 #ifdef __x86_64__
00184 sp = (void **)getrbp();
00185 if (sp == NULL)
00186 return (ISC_R_NOTFOUND);
00187
00188
00189
00190
00191 sp = getnextframeptr(sp);
00192 #else
00193
00194
00195
00196
00197
00198 sp = (void **)&addrs - 2;
00199 #endif
00200
00201 while (sp != NULL && i < maxaddrs) {
00202 addrs[i++] = *(sp + 1);
00203 sp = getnextframeptr(sp);
00204 }
00205
00206 *nframes = i;
00207
00208 return (ISC_R_SUCCESS);
00209 }
00210 #elif defined(BACKTRACE_DISABLED)
00211 isc_result_t
00212 isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
00213
00214 if (addrs == NULL || nframes == NULL)
00215 return (ISC_R_FAILURE);
00216
00217 UNUSED(maxaddrs);
00218
00219 return (ISC_R_NOTIMPLEMENTED);
00220 }
00221 #endif
00222
00223 isc_result_t
00224 isc_backtrace_getsymbolfromindex(int idx, const void **addrp,
00225 const char **symbolp)
00226 {
00227 REQUIRE(addrp != NULL && *addrp == NULL);
00228 REQUIRE(symbolp != NULL && *symbolp == NULL);
00229
00230 if (idx < 0 || idx >= isc__backtrace_nsymbols)
00231 return (ISC_R_RANGE);
00232
00233 *addrp = isc__backtrace_symtable[idx].addr;
00234 *symbolp = isc__backtrace_symtable[idx].symbol;
00235 return (ISC_R_SUCCESS);
00236 }
00237
00238 static int
00239 symtbl_compare(const void *addr, const void *entryarg) {
00240 const isc_backtrace_symmap_t *entry = entryarg;
00241 const isc_backtrace_symmap_t *end =
00242 &isc__backtrace_symtable[isc__backtrace_nsymbols - 1];
00243
00244 if (isc__backtrace_nsymbols == 1 || entry == end) {
00245 if (addr >= entry->addr) {
00246
00247
00248
00249
00250
00251 return (0);
00252 }
00253 return (-1);
00254 }
00255
00256
00257 if (addr < entry->addr)
00258 return (-1);
00259 else if (addr >= (entry + 1)->addr)
00260 return (1);
00261 return (0);
00262 }
00263
00264 isc_result_t
00265 isc_backtrace_getsymbol(const void *addr, const char **symbolp,
00266 unsigned long *offsetp)
00267 {
00268 isc_result_t result = ISC_R_SUCCESS;
00269 isc_backtrace_symmap_t *found;
00270
00271
00272
00273
00274
00275 if (symbolp == NULL || *symbolp != NULL || offsetp == NULL)
00276 return (ISC_R_FAILURE);
00277
00278 if (isc__backtrace_nsymbols < 1)
00279 return (ISC_R_NOTFOUND);
00280
00281
00282
00283
00284
00285 found = bsearch(addr, isc__backtrace_symtable, isc__backtrace_nsymbols,
00286 sizeof(isc__backtrace_symtable[0]), symtbl_compare);
00287 if (found == NULL)
00288 result = ISC_R_NOTFOUND;
00289 else {
00290 *symbolp = found->symbol;
00291 *offsetp = (unsigned long) ((const char *)addr -
00292 (char *)found->addr);
00293 }
00294
00295 return (result);
00296 }