00001
00002
00003 #ifndef _GSYMLOOKUP_H_
00004 #define _GSYMLOOKUP_H_
00005
00006 #include <dlfcn.h>
00007 #include <mach/vm_types.h>
00008 #include <sys/uio.h>
00009
00010 #include <cxxabi.h>
00011 #include "GProcess.h"
00012
00013 #include <stdlib.h>
00014 #include <stdio.h>
00015 #include <string.h>
00016
00017 #ifdef _POSIX_C_SOURCE
00018 #error "This shouldn't be defined."
00019 #endif
00020 #ifndef _DLFCN_H_
00021 #error "Include dlfcn.h"
00022 #endif
00023
00024 #if __LP64__
00025 #define _BACKTRACE_FORMAT "%-4d%-35s 0x%016x %s + %u"
00026 #define _BACKTRACE_FORMAT_SIZE 82
00027 #else
00028 #define _BACKTRACE_FORMAT "%-4d%-35s 0x%08x %s + %u"
00029 #define _BACKTRACE_FORMAT_SIZE 65
00030 #endif
00031
00032 #if defined(__i386__) || defined(__x86_64__)
00033 #define FP_LINK_OFFSET 1
00034 #elif defined(__ppc__) || defined(__ppc64__)
00035 #define FP_LINK_OFFSET 2
00036 #else
00037 #error ********** Unimplemented architecture
00038 #endif
00039
00040 #define INSTACK(a) ((a) >= stackbot && (a) <= stacktop)
00041 #if defined(__ppc__) || defined(__ppc64__) || defined(__x86_64__)
00042 #define ISALIGNED(a) ((((uintptr_t)(a)) & 0xf) == 0)
00043 #elif defined(__i386__)
00044 #define ISALIGNED(a) ((((uintptr_t)(a)) & 0xf) == 8)
00045 #endif
00046
00048 class GSymLookup
00049 {
00050 public:
00051 typedef void *Addr;
00052
00053 private:
00054 __attribute__((noinline))
00055 void
00056 _thread_stack_pcs(vm_address_t *buffer, unsigned max, unsigned *nb, unsigned skip)
00057 {
00058 void *frame, *next;
00059 pthread_t self = pthread_self();
00060 void *stacktop = pthread_get_stackaddr_np(self);
00061 void *stackbot = (char*)stacktop - pthread_get_stacksize_np(self);
00062
00063 *nb = 0;
00064
00065
00066 (char*&)stacktop -= (FP_LINK_OFFSET + 1) * sizeof(void *);
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 #if defined(__i386__) || defined(__x86_64__)
00077 frame = __builtin_frame_address(0);
00078 #elif defined(__ppc__) || defined(__ppc64__)
00079
00080 __asm__ volatile("mr %0, r1" : "=r" (frame));
00081 #endif
00082 if(!INSTACK(frame) || !ISALIGNED(frame))
00083 return;
00084 #if defined(__ppc__) || defined(__ppc64__)
00085
00086 next = *(void **)frame;
00087 if(!INSTACK(next) || !ISALIGNED(next) || next <= frame)
00088 return;
00089 frame = next;
00090 #endif
00091 while (skip--) {
00092 next = *(void **)frame;
00093 if(!INSTACK(next) || !ISALIGNED(next) || next <= frame)
00094 return;
00095 frame = next;
00096 }
00097 while (max--) {
00098 buffer[*nb] = *(vm_address_t *)(((void **)frame) + FP_LINK_OFFSET);
00099 (*nb)++;
00100 next = *(void **)frame;
00101 if(!INSTACK(next) || !ISALIGNED(next) || next <= frame)
00102 return;
00103 frame = next;
00104 }
00105 }
00106
00107
00108 int
00109 _backtrace_snprintf(char* buf, size_t size, int frame, const void* addr, const Dl_info* info)
00110 {
00111 char symbuf[19];
00112 const char* image = "???";
00113 const char* symbol = symbuf;
00114
00115 if (info->dli_fname) {
00116 image = strrchr(info->dli_fname, '/') + 1;
00117 if (image == NULL) image = info->dli_fname;
00118 }
00119
00120 if (info->dli_sname) {
00121 symbol = info->dli_sname;
00122 } else {
00123 snprintf(symbuf, sizeof(symbuf), "0x%x", (int)info->dli_saddr);
00124 }
00125
00126 return snprintf(buf, size,
00127 _BACKTRACE_FORMAT,
00128 frame,
00129 image,
00130 (unsigned) addr,
00131 symbol,
00132 (char*)addr - (char*)info->dli_saddr) + 1;
00133 }
00134
00135 char**
00136 backtrace_symbols(Addr* buffer, int size)
00137 {
00138 int i;
00139 size_t total_bytes;
00140 char** result;
00141 char** ptrs;
00142 intptr_t strs;
00143 Dl_info* info = (Dl_info*) calloc(size, sizeof (Dl_info));
00144
00145 if (info == NULL)
00146 return NULL;
00147
00148
00149
00150
00151 total_bytes = sizeof(char*) * size;
00152
00153
00154 for (i = 0 ; i < size; ++i) {
00155 dladdr(buffer[i], &info[i]);
00156 total_bytes += _BACKTRACE_FORMAT_SIZE + 1;
00157 if (info[i].dli_sname) total_bytes += strlen(info[i].dli_sname);
00158 }
00159
00160 result = (char**)malloc(total_bytes);
00161 if (result == NULL) {
00162 free(info);
00163 return NULL;
00164 }
00165
00166
00167
00168
00169 ptrs = result;
00170 strs = ((intptr_t)result) + sizeof(char*) * size;
00171
00172 for (i = 0; i < size; ++i) {
00173 ptrs[i] = (char*)strs;
00174 strs += _backtrace_snprintf((char*)strs, total_bytes, i, buffer[i], &info[i]);
00175 }
00176
00177 free(info);
00178
00179 return result;
00180 }
00181
00182 void backtrace_symbols_fd(void* const* buffer, int size, int fd)
00183 {
00184 int i;
00185 char buf[BUFSIZ];
00186 Dl_info info;
00187 struct iovec iov[2];
00188
00189 iov[0].iov_base = buf;
00190
00191 iov[1].iov_base = (void*)"\n";
00192 iov[1].iov_len = 1;
00193
00194 for (i = 0; i < size; ++i) {
00195 memset(&info, 0, sizeof(info));
00196 dladdr(buffer[i], &info);
00197
00198 iov[0].iov_len = _backtrace_snprintf(buf, sizeof(buf), i, buffer[i], &info);
00199
00200 writev(fd, iov, 2);
00201 }
00202 }
00203
00204
00205 public:
00206 GSymLookup()
00207 {
00208 }
00209
00210 ~GSymLookup()
00211 {
00212 }
00213
00214 bool GetStatus()
00215 {
00216 return true;
00217 }
00218
00221 bool Lookup
00222 (
00224 char *buf,
00226 int buflen,
00228 Addr *Ip,
00230 int IpLen
00231 )
00232 {
00233 #if 0
00234
00235 Dl_info dli;
00236 if (dladdr(Ip, &dli))
00237 {
00238
00239 ptrdiff_t offset;
00240 int c = 0;
00241
00242 if (dli.dli_fname && dli.dli_fbase)
00243 {
00244 offset = (ptrdiff_t)Ip - (ptrdiff_t)dli.dli_fbase;
00245 c = snprintf(buf, buflen, "%s+0x%x", dli.dli_fname, offset );
00246 }
00247 if (dli.dli_sname && dli.dli_saddr)
00248 {
00249 offset = (ptrdiff_t)Ip - (ptrdiff_t)dli.dli_saddr;
00250 c += snprintf(buf+c, buflen-c, "(%s+0x%x)", dli.dli_sname, offset );
00251 }
00252
00253 if (c > 0)
00254 {
00255 snprintf(buf+c, buflen-c, " [%p]", Ip);
00256 }
00257
00258 return true;
00259 }
00260 else printf("%s:%i - dladdr failed for %p\n", _FL, Ip);
00261 return false;
00262
00263 #else
00264
00265 char Ws[] = " \t\r\n";
00266 char **Syms = backtrace_symbols(Ip, IpLen);
00267 if (!Syms)
00268 return false;
00269
00270 for (int i=0; i<IpLen; i++)
00271 {
00272 char *Sym = Syms[i];
00273 int Ch = 0;
00274
00275 if (0)
00276 {
00277 char *c = Sym;
00278 char Binary[256];
00279 GAutoString Method;
00280 char *End = 0;
00281 int Idx = 0;
00282
00283 for (int i=0; *c; i++)
00284 {
00285 char *Start = c;
00286 while (*c && !strchr(Ws, *c)) c++;
00287
00288 switch (i)
00289 {
00290 case 0:
00291 {
00292 Idx = atoi(Start);
00293 break;
00294 }
00295 case 1:
00296 {
00297 memcpy(Binary, Start, c-Start);
00298 Binary[c-Start] = 0;
00299 break;
00300 }
00301 case 3:
00302 {
00303 char Args[256];
00304 sprintf(Args, "-n %.*s", c-Start, Start);
00305 GProcess p;
00306 GStringPipe Out;
00307 if (p.Run("c++filt", Args, 0, true, 0, &Out) &&
00308 Method.Reset(Out.NewStr()))
00309 {
00310 char *e = Method + strlen(Method);
00311 while (e > Method && strchr(Ws, e[-1]))
00312 *--e = 0;
00313 }
00314 else
00315 {
00316 Method.Reset(NewStr(Start, c-Start));
00317 }
00318
00319 End = c;
00320 break;
00321 }
00322 }
00323
00324 while (*c && strchr(Ws, *c)) c++;
00325 }
00326
00327 Ch = snprintf(buf, buflen, "\t%i\t%s\t%s%s\n", Idx, Binary, Method.Get(), End);
00328 }
00329 else
00330 {
00331 Ch = snprintf(buf, buflen, "%s\n", Sym);
00332 }
00333 buf += Ch;
00334 buflen -= Ch;
00335 }
00336
00337 free(Syms);
00338 return true;
00339
00340 #endif
00341 }
00342
00344 int BackTrace(long Eip, long Ebp, Addr *buffer, int max_frames)
00345 {
00346 #if 0
00347
00348 void **frame = (void **)__builtin_frame_address(0);
00349 void **bp = ( void **)(*frame);
00350 void *ip = frame[1];
00351 int i;
00352
00353 for ( i = 0; bp && ip && i < max_frames; i++ )
00354 {
00355 *(buffer++) = ip;
00356 ip = bp[1];
00357 bp = (void**)(bp[0]);
00358 }
00359
00360 return i;
00361
00362 #else
00363
00364 unsigned int num_frames;
00365 _thread_stack_pcs((vm_address_t*)buffer, max_frames, &num_frames, 1);
00366 while (num_frames >= 1 && buffer[num_frames-1] == NULL)
00367 num_frames -= 1;
00368
00369 return num_frames;
00370 #endif
00371 }
00372 };
00373
00374 #endif