00001 #if !defined(__APPLE__) && !defined(_GNU_SOURCE)
00002 # define _GNU_SOURCE // enable dladdr and getline
00003 #endif
00004
00005 #include "StackTrace.h"
00006 #include <unistd.h>
00007
00008 #if defined(__APPLE__) // need atos
00009 # if defined(STACKTRACE_USE_BACKTRACE)
00010 # include <execinfo.h>
00011 # endif
00012
00013 # include </usr/include/util.h>
00014 # include <termios.h>
00015 # include <sys/select.h>
00016
00017 #elif defined(STACKTRACE_USE_BACKTRACE)
00018 # include <execinfo.h>
00019
00020 # include <dlfcn.h>
00021 # include <sys/param.h>
00022 # include <errno.h>
00023 # if defined(__GNUC__) && defined(__cplusplus)
00024 # include <cxxabi.h>
00025 # include <string>
00026 # endif
00027 # if defined(__linux__)
00028 # include <sys/stat.h>
00029 # endif
00030 #endif
00031
00032 #ifdef __cplusplus
00033 # include <cstdio>
00034 # include <cstdlib>
00035 # include <cstring>
00036 #else
00037 # include <stdio.h>
00038 # include <stdlib.h>
00039 # include <string.h>
00040 #endif
00041
00042 #ifdef ST_UNUSED
00043 #elif defined(__GNUC__) && __GNUC__>3
00044
00045 # define ST_UNUSED(x) UNUSED_##x __attribute__((unused))
00046
00047 # define ST_BODY_UNUSED(x)
00048
00049 #elif defined(__LCLINT__)
00050
00051 # define ST_UNUSED(x) x
00052
00053 # define ST_BODY_UNUSED(x)
00054
00055 #else
00056
00057 # define ST_UNUSED(x) UNUSED_##x
00058
00059 # define ST_BODY_UNUSED(x) (void)UNUSED_##x
00060 #endif
00061
00062 #ifdef __cplusplus
00063 namespace stacktrace {
00064 #endif
00065
00066 int unrollStackFrame(struct StackFrame* curFrame, struct StackFrame* nextFrame) {
00067 if(curFrame==NULL)
00068 return 0;
00069 curFrame->caller=NULL;
00070 if(nextFrame==NULL)
00071 return 0;
00072
00073
00074 #ifdef STACKTRACE_USE_BACKTRACE
00075
00076 if(curFrame->packedRA==NULL)
00077 return 0;
00078 if(*curFrame->packedRAUsed<=curFrame->depth+1) {
00079
00080 if(curFrame!=nextFrame) {
00081 nextFrame->packedRA = NULL;
00082 nextFrame->packedRAUsed = nextFrame->packedRACap = NULL;
00083 }
00084 return 0;
00085 }
00086 if(curFrame!=nextFrame) {
00087 nextFrame->packedRA = curFrame->packedRA;
00088 nextFrame->packedRAUsed = curFrame->packedRAUsed;
00089 nextFrame->packedRACap = curFrame->packedRACap;
00090 nextFrame->depth = curFrame->depth;
00091 }
00092 nextFrame->ra = (*nextFrame->packedRA)[++(nextFrame->depth)];
00093 curFrame->caller=nextFrame;
00094 return 1;
00095
00096 #else
00097
00098 void* nsp=NULL;
00099 machineInstruction * nra=NULL;
00100
00101 #if defined(__i386__) || defined(__x86_64__) || defined(__amd64__)
00102 if(curFrame->sp==NULL)
00103 return 0;
00104 if(((void**)curFrame->sp)-1==NULL)
00105 return 0;
00106 nsp=((void***)curFrame->sp)[-1];
00107 if(nsp==NULL)
00108 return 0;
00109 nsp=(void**)nsp+1;
00110 nra=*((machineInstruction**)curFrame->sp);
00111 if(nsp<=curFrame->sp) {
00112 fprintf(stderr,"stacktrace::unrollStackFrame(sp=%p,ra=%p) directed to invalid next frame: (sp=%p,ra=%p)\n",curFrame->sp,curFrame->ra,nsp,nra);
00113 return 0;
00114 }
00115 # ifdef DEBUG_STACKTRACE
00116 if(curFrame->debug)
00117 printf("( %p %p ) -> { %p %p }\n",curFrame->sp,curFrame->ra,nsp,nra);
00118 nextFrame->debug=curFrame->debug;
00119 # endif
00120 nextFrame->sp=nsp;
00121 nextFrame->ra=nra;
00122 curFrame->caller=nextFrame;
00123 return 1;
00124 #endif
00125 #ifdef __POWERPC__
00126 if(curFrame->sp==NULL)
00127 return 0;
00128 if(*(void**)curFrame->sp==NULL)
00129 return 0;
00130 nsp=*(void**)curFrame->sp;
00131 nra=((machineInstruction**)nsp)[2];
00132 if(nsp<=curFrame->sp) {
00133 fprintf(stderr,"stacktrace::unrollStackFrame(sp=%p,ra=%p) directed to invalid next frame: (sp=%p,ra=%p)\n",curFrame->sp,curFrame->ra,nsp,nra);
00134 return 0;
00135 }
00136 # ifdef DEBUG_STACKTRACE
00137 if(curFrame->debug)
00138 printf("( %p %p ) -> { %p %p }\n",curFrame->sp,curFrame->ra,nsp,nra);
00139 nextFrame->debug=curFrame->debug;
00140 # endif
00141 nextFrame->sp=nsp;
00142 nextFrame->ra=nra;
00143 curFrame->caller=nextFrame;
00144 return 1;
00145 #endif
00146 #if defined(__MIPSEL__) || defined(__MIPS__)
00147 if(curFrame->sp==NULL)
00148 return 0;
00149
00150 machineInstruction * ins;
00151 const machineInstruction * INS_BASE=(const machineInstruction *)0x2000;
00152
00153 #ifdef __PIC__
00154 ins = reinterpret_cast<machineInstruction*>(curFrame->gp-curFrame->ra);
00155 #else
00156 ins = curFrame->ra;
00157 #endif
00158
00159 for(; ins>=INS_BASE; ins--) {
00160
00161
00162
00163
00164 if ( ( *ins & 0xffff0000 ) == 0xafbf0000 )
00165 {
00166
00167 int offset = *ins & 0x000ffff;
00168
00169
00170 if (offset & 0x3)
00171 return 0;
00172
00173 nra = *reinterpret_cast<machineInstruction**>((char*)curFrame->sp + offset);
00174 break;
00175 }
00176
00177
00178
00179
00180 if ( *ins == 0x37e80000 ) {
00181 # ifdef DEBUG_STACKTRACE
00182 if(curFrame->debug)
00183 printf("( %p %p %p ) -> { kernel? }\n",curFrame->sp,curFrame->ra,curFrame->gp);
00184 # endif
00185 return 0;
00186 }
00187 }
00188
00189 for(; ins>=INS_BASE; ins--) {
00190
00191
00192
00193
00194
00195
00196
00197 if ( ( *ins & 0xffff0000 ) == 0x27bd0000 ) {
00198
00199
00200 int offset = ( *ins & 0x0000ffff ) | 0xffff0000;
00201
00202
00203 if (offset & 0x3)
00204 return 0;
00205
00206 nsp = (char*)curFrame->sp - offset;
00207 break;
00208 }
00209 }
00210
00211
00212 if(ins>=INS_BASE) {
00213 if(nsp<=curFrame->sp) {
00214 #ifdef __PIC__
00215 fprintf(stderr,"stacktrace::unrollStackFrame(sp=%p,ra=%p,gp=%p) directed to invalid next frame: (sp=%p,ra=%p,gp=%p)\n",curFrame->sp,(void*)curFrame->ra,(void*)curFrame->gp,nsp,nra,(void*)(reinterpret_cast<size_t*>(nsp)[4]));
00216 #else
00217 fprintf(stderr,"stacktrace::unrollStackFrame(sp=%p,ra=%p) directed to invalid next frame: (sp=%p,ra=%p)\n",curFrame->sp,(void*)curFrame->ra,nsp,nra);
00218 #endif
00219 return 0;
00220 }
00221
00222 #ifdef __PIC__
00223 # ifdef DEBUG_STACKTRACE
00224 if(curFrame->debug)
00225 printf("( %p %p %p ) -> { %p %p %p }\n",curFrame->sp,curFrame->ra,curFrame->gp,nsp,nra,reinterpret_cast<size_t*>(nsp)[4]);
00226 nextFrame->debug=curFrame->debug;
00227 # endif
00228
00229
00230
00231
00232
00233
00234
00235
00236 nextFrame->sp=nsp;
00237
00238 if(reinterpret_cast<size_t>(nra)>reinterpret_cast<size_t*>(nsp)[4]) {
00239 nextFrame->gp = curFrame->gp;
00240 } else {
00241 nextFrame->gp = reinterpret_cast<size_t*>(nsp)[4];
00242 }
00243 nextFrame->ra = nextFrame->gp-reinterpret_cast<size_t>(nra);
00244 #else
00245 # ifdef DEBUG_STACKTRACE
00246 if(curFrame->debug)
00247 printf("( %p %p ) -> { %p %p }\n",curFrame->sp,curFrame->ra,nsp,nra);
00248 nextFrame->debug=curFrame->debug;
00249 # endif
00250 nextFrame->sp=nsp;
00251 nextFrame->ra=nra;
00252 #endif
00253 curFrame->caller=nextFrame;
00254 return 1;
00255 }
00256 #ifdef __PIC__
00257 # ifdef DEBUG_STACKTRACE
00258 if(curFrame->debug)
00259 printf("( %p %p %p ) -> { %p %p --- }\n",curFrame->sp,curFrame->ra,curFrame->gp,nsp,nra);
00260 # endif
00261 #else
00262 # ifdef DEBUG_STACKTRACE
00263 if(curFrame->debug)
00264 printf("( %p %p ) -> { %p %p }\n",curFrame->sp,curFrame->ra,nsp,nra);
00265 # endif
00266 #endif
00267 return 0;
00268 #endif
00269 #endif
00270 }
00271
00272 #ifdef STACKTRACE_USE_BACKTRACE
00273 static int growAlloc(struct StackFrame* frame) {
00274 void** r = (void**)realloc(*frame->packedRA, *frame->packedRACap * sizeof(void*) * 2);
00275 if(r==NULL)
00276 return 0;
00277 *frame->packedRACap *= 2;
00278 *frame->packedRA = r;
00279 return 1;
00280 }
00281 #endif
00282
00283 #ifdef STACKTRACE_USE_BACKTRACE
00284 const size_t MIN_CAP=50;
00285 static void allocBacktraceRegion(struct StackFrame* frame, size_t cap) {
00286 if(cap < MIN_CAP)
00287 cap=MIN_CAP;
00288 frame->packedRACap = (size_t*)malloc(sizeof(size_t));
00289 *frame->packedRACap = MIN_CAP;
00290 frame->packedRAUsed = (size_t*)malloc(sizeof(size_t));
00291 *frame->packedRAUsed = 0;
00292 frame->packedRA = (void***)malloc(sizeof(void**));
00293 *frame->packedRA = (void**)malloc(*frame->packedRACap * sizeof(void*));
00294
00295 }
00296
00297 static void freeBacktraceRegion(struct StackFrame* frame) {
00298
00299 free(frame->packedRACap);
00300 frame->packedRACap = NULL;
00301 free(frame->packedRAUsed);
00302 frame->packedRAUsed = NULL;
00303 free(*frame->packedRA);
00304 *frame->packedRA=NULL;
00305 free(frame->packedRA);
00306 frame->packedRA=NULL;
00307 }
00308 #endif
00309
00310 void getCurrentStackFrame(struct StackFrame* frame) {
00311 #ifdef STACKTRACE_USE_BACKTRACE
00312
00313
00314 if(frame->packedRA==NULL)
00315 allocBacktraceRegion(frame,MIN_CAP);
00316
00317
00318 do {
00319 *frame->packedRAUsed = backtrace(*frame->packedRA, *frame->packedRACap);
00320 } while(*frame->packedRAUsed==*frame->packedRACap && growAlloc(frame));
00321
00322
00323 if(*frame->packedRACap > *frame->packedRAUsed*2 && *frame->packedRACap>MIN_CAP) {
00324 unsigned int newsize = *frame->packedRAUsed * 3 / 2;
00325 if(newsize < MIN_CAP)
00326 newsize = MIN_CAP;
00327 void** r = (void**)realloc(*frame->packedRA, newsize * sizeof(void*) * 2);
00328 if(r!=NULL) {
00329 *frame->packedRACap = newsize;
00330 *frame->packedRA = r;
00331 }
00332 }
00333 frame->depth=1;
00334
00335 #else
00336
00337 void** csp=NULL;
00338 machineInstruction* cra=NULL;
00339
00340 #ifdef __POWERPC__
00341 __asm __volatile__ ("mr %0,r1" : "=r"(csp) );
00342 __asm __volatile__ ("mflr %0" : "=r"(cra) );
00343 #endif
00344
00345 #if defined(__MIPSEL__) || defined(__MIPS__)
00346 #ifdef __PIC__
00347 size_t cgp=0;
00348 __asm __volatile__ ("move %0,$gp" : "=r"(cgp) );
00349 #endif
00350 __asm __volatile__ ("move %0,$sp" : "=r"(csp) );
00351 __asm __volatile__ ("jal readepc; nop; readepc: move %0,$ra" : "=r"(cra) );
00352 #endif
00353
00354 #if defined(__i386__)
00355 __asm __volatile__ ("movl %%ebp,%0" : "=m"(csp) );
00356 csp++;
00357
00358 cra=*((machineInstruction**)csp);
00359 csp=((void***)csp)[-1]+1;
00360 #endif
00361
00362
00363 #if defined(__x86_64__) || defined(__amd64__)
00364 __asm __volatile__ ("movq %%rbp,%0" : "=m"(csp) );
00365 csp++;
00366
00367 cra=*((machineInstruction**)csp);
00368 csp=((void***)csp)[-1]+1;
00369 #endif
00370
00371 frame->sp=csp;
00372 #if defined(__PIC__) && (defined(__MIPSEL__) || defined(__MIPS__))
00373 frame->ra=cgp-reinterpret_cast<size_t>(cra);
00374 frame->gp=cgp;
00375 #else
00376 frame->ra=cra;
00377 #endif
00378
00379 #if !defined(__i386__) && !defined(__x86_64__) && !defined(__amd64__)
00380
00381
00382 unrollStackFrame(frame,frame);
00383 #endif
00384 #endif
00385 }
00386
00387 void freeStackTrace(struct StackFrame* frame) {
00388 #ifdef STACKTRACE_USE_BACKTRACE
00389 if(frame!=NULL && frame->packedRA!=NULL) {
00390 freeBacktraceRegion(frame);
00391 }
00392 #endif
00393 while(frame!=NULL) {
00394 struct StackFrame * next=frame->caller;
00395 free(frame);
00396 if(frame==next)
00397 return;
00398 frame=next;
00399 }
00400 }
00401
00402 struct StackFrame* allocateStackTrace(unsigned int size) {
00403 struct StackFrame * frame=NULL;
00404 while(size--!=0) {
00405 struct StackFrame * prev = (struct StackFrame *)malloc(sizeof(struct StackFrame));
00406 memset(prev, 0, sizeof(*prev));
00407 #ifdef STACKTRACE_USE_BACKTRACE
00408 if(frame==NULL) {
00409 allocBacktraceRegion(prev,size);
00410 } else {
00411 prev->packedRA = frame->packedRA;
00412 prev->packedRAUsed = frame->packedRAUsed;
00413 prev->packedRACap = frame->packedRACap;
00414 }
00415 prev->depth = size-1;
00416 #endif
00417 prev->caller=frame;
00418 frame=prev;
00419 }
00420 return frame;
00421 }
00422
00423
00424 struct StackFrame * recordStackTrace(unsigned int limit, unsigned int skip) {
00425 if(limit==0)
00426 return NULL;
00427 struct StackFrame * cur = allocateStackTrace(1);
00428 #ifdef DEBUG_STACKTRACE
00429 cur->debug=0;
00430 #endif
00431 getCurrentStackFrame(cur);
00432 for(; skip!=0; skip--)
00433 if(!unrollStackFrame(cur,cur)) {
00434 freeStackTrace(cur);
00435 return NULL;
00436 }
00437 struct StackFrame * prev = (struct StackFrame *)malloc(sizeof(struct StackFrame));
00438 memset(prev, 0, sizeof(*prev));
00439 #ifdef DEBUG_STACKTRACE
00440 prev->debug=0;
00441 #endif
00442
00443
00444 if(!unrollStackFrame(cur,prev)) {
00445 freeStackTrace(cur);
00446 return NULL;
00447 }
00448 #ifdef STACKTRACE_USE_BACKTRACE
00449 memset(cur,0,sizeof(*cur));
00450 #else
00451 cur->caller=NULL;
00452 #endif
00453 freeStackTrace(cur);
00454 cur=prev;
00455
00456 for(--limit; limit!=0; limit--) {
00457 struct StackFrame * next = (struct StackFrame *)malloc(sizeof(struct StackFrame));
00458 memset(next, 0, sizeof(*next));
00459 #ifdef DEBUG_STACKTRACE
00460 next->debug=0;
00461 #endif
00462 if(!unrollStackFrame(prev,next)) {
00463
00464 free(next);
00465 prev->caller=NULL;
00466 return cur;
00467 }
00468 prev=next;
00469 }
00470
00471 prev->caller=prev;
00472 return cur;
00473 }
00474
00475 struct StackFrame * recordOverStackTrace(struct StackFrame* frame, unsigned int skip) {
00476 struct StackFrame * cur = allocateStackTrace(1);
00477 #ifdef DEBUG_STACKTRACE
00478 cur->debug=0;
00479 #endif
00480 if(frame==NULL)
00481 return frame;
00482 getCurrentStackFrame(cur);
00483 for(; skip!=0; skip--)
00484 if(!unrollStackFrame(cur,cur)) {
00485 freeStackTrace(cur);
00486 return frame;
00487 }
00488 #ifdef STACKTRACE_USE_BACKTRACE
00489 if(frame->packedRA!=NULL)
00490 freeBacktraceRegion(frame);
00491 #endif
00492
00493
00494 if(!unrollStackFrame(cur,frame)) {
00495 freeStackTrace(cur);
00496 return NULL;
00497 }
00498 #ifdef STACKTRACE_USE_BACKTRACE
00499 memset(cur,0,sizeof(*cur));
00500 #else
00501 cur->caller=NULL;
00502 #endif
00503 freeStackTrace(cur);
00504
00505 struct StackFrame * ans;
00506 for(; frame->caller!=NULL && frame->caller!=frame; frame=frame->caller) {
00507 ans=frame->caller;
00508 if(!unrollStackFrame(frame,frame->caller)) {
00509 return ans;
00510 }
00511 }
00512
00513 frame->caller=frame;
00514 return NULL;
00515 }
00516
00517
00518 #ifdef __APPLE__
00519
00520
00521
00522
00523
00524
00525 static void atosLookup(unsigned int depth, void* ra) {
00526 static int fd=-1;
00527 int isfirst=0;
00528
00529 if(fd==-1) {
00530 struct termios opts;
00531 cfmakeraw(&opts);
00532 pid_t child = forkpty(&fd,NULL,&opts,NULL);
00533 if(child<0) {
00534 perror("Could not forkpty for atos call");
00535 return;
00536 }
00537 if(child==0) {
00538
00539 char pidstr[50];
00540 snprintf(pidstr,50,"%d",getppid());
00541 execlp("atos","atos","-p",pidstr,(char*)0);
00542
00543
00544 fprintf(stderr,"Could not exec atos for stack trace!\n");
00545 _exit(1);
00546 }
00547 isfirst=1;
00548 }
00549
00550 {
00551 char q[50];
00552 size_t qlen = snprintf(q,50,"%p\n",ra);
00553
00554 write(fd,q,qlen);
00555 }
00556
00557 if(isfirst) {
00558
00559
00560 int err;
00561 struct timeval tv = {3,0};
00562 fd_set fds;
00563 FD_ZERO(&fds);
00564 FD_SET(fd,&fds);
00565 err = select(fd+1,&fds,NULL,NULL,&tv);
00566 if(err<0)
00567 perror("select for atos output");
00568 if(err==0)
00569 printf("Generating... first call takes some time for 'atos' to cache the symbol table.\n");
00570 }
00571
00572 {
00573 const unsigned int MAXLINE=1024;
00574 char line[MAXLINE];
00575 size_t nread=0;
00576 char c='x';
00577 while(c!='\n' && nread<MAXLINE) {
00578 if(read(fd,&c,1)<=0) {
00579 fprintf(stderr,"Lost atos connection for stacktrace\n");
00580 close(fd);
00581 fd=-1;
00582 break;
00583 }
00584
00585 if(c!='\r')
00586 line[nread++]=c;
00587 }
00588 if(nread<MAXLINE)
00589 line[nread++]='\0';
00590 fprintf(stderr,"%4d %.*s",depth,MAXLINE,line);
00591 }
00592 }
00593
00594 #elif defined(STACKTRACE_USE_BACKTRACE)
00595
00596 # if defined(__GNUC__) && defined(__cplusplus)
00597 static std::string demangle(const std::string& name)
00598 {
00599 int status = 0;
00600 char *d = 0;
00601 std::string ret = name;
00602 try { if ((d = abi::__cxa_demangle(name.c_str(), 0, 0, &status))) ret = d; }
00603 catch(...) { }
00604 std::free(d);
00605 return ret;
00606 }
00607 # endif
00608
00609 # ifndef __linux__
00610
00611 static int getline(char** s, size_t* len, FILE* f) {
00612 size_t _len;
00613 char * _s = fgetln(f,&_len);
00614 if(_s==NULL)
00615 return -1;
00616 if(*len<_len+1) {
00617 char * ns = (char*)realloc(*s,_len+1);
00618 if(ns==NULL)
00619 return -1;
00620 *s=ns;
00621 }
00622 memcpy(*s,_s,_len);
00623 (*s)[_len]='\0';
00624 return _len;
00625 }
00626 # endif
00627
00628 static int addr2lineLookup(const char* const ex, const void* const off, char** srcfile, size_t* srcfilelen, char** func, size_t* funclen) {
00629 const char * cmdfmt = "addr2line -fe '%s' %p";
00630 const size_t cmdlen = snprintf(NULL,0,cmdfmt,ex,off)+1;
00631 char * cmd = (char*)malloc(cmdlen*sizeof(char));
00632 if(cmd==NULL) {
00633 fprintf(stderr,"[ERR Could not malloc addr2line command]\n");
00634 return -1;
00635 }
00636 const int cmdused = snprintf(cmd,cmdlen,cmdfmt,ex,off);
00637 if(cmdused<0) {
00638 perror("snprintf for addr2line command");
00639 free(cmd);
00640 return -1;
00641 }
00642 if((size_t)cmdused>=cmdlen) {
00643 fprintf(stderr, "[ERR addr2line command grew? %d vs %lu]\n",cmdused,(unsigned long)cmdlen);
00644 free(cmd);
00645 return -1;
00646 }
00647 FILE* look=popen(cmd,"r");
00648 free(cmd);
00649 if(look==NULL) {
00650 fprintf(stderr, "[Missing addr2line]\n");
00651 return -1;
00652 }
00653 if(getline(func,funclen,look)<=0) {
00654 pclose(look);
00655 return -1;
00656 }
00657 if(getline(srcfile,srcfilelen,look)<=0) {
00658 pclose(look);
00659 return -1;
00660 }
00661 pclose(look);
00662 char* nl = strrchr(*func,'\n');
00663 if(nl!=NULL)
00664 *nl='\0';
00665 nl = strrchr(*srcfile,'\n');
00666 if(nl!=NULL)
00667 *nl='\0';
00668 return 0;
00669 }
00670
00671 static void displayRelPath(FILE* os, const char * wd, const char* path) {
00672 unsigned int same=0,i=0;
00673 for(i=0; path[i]!='\0'; ++i) {
00674 if(wd[i]=='/')
00675 same=i+1;
00676 else if(wd[i]=='\0') {
00677 same=i;
00678 break;
00679 } else if(wd[i]!=path[i])
00680 break;
00681 }
00682 if(wd[same]=='\0')
00683 ++same;
00684 else if(same>1) {
00685
00686
00687
00688
00689
00690 }
00691 fprintf(os,"%s",&path[same]);
00692 }
00693 #endif
00694
00695
00696 static void beginDisplay() {
00697 #ifdef STACKTRACE_USE_BACKTRACE
00698
00699 #elif defined(PLATFORM_APERIOS)
00700 fprintf(stderr,"Run trace_lookup:");
00701 #elif defined(__APPLE__)
00702 fprintf(stderr,"backtrace_symbols() unavailable, try 'atos' to make human-readable backtrace (-p %d):",getpid());
00703 #else
00704 fprintf(stderr,"backtrace_symbols() unavailable, try addr2line or tools/trace_lookup to make human-readable backtrace:");
00705 #endif
00706 }
00707
00708 #ifdef __APPLE__
00709 static void displayStackFrame(unsigned int depth, const struct StackFrame* frame) {
00710 atosLookup(depth,(void*)frame->ra);
00711 }
00712 #elif defined(STACKTRACE_USE_BACKTRACE)
00713 static void displayStackFrame(unsigned int depth, const struct StackFrame* frame) {
00714 void* ra = (void*)frame->ra;
00715 Dl_info sym;
00716 memset(&sym,0,sizeof(Dl_info));
00717 int dlres = dladdr(frame->ra, &sym);
00718
00719 int isExe = (sym.dli_fname==NULL);
00720 # ifdef __linux__
00721
00722 if(!isExe && sym.dli_fname[0]!='\0') {
00723 struct stat exeStat;
00724 struct stat libStat;
00725 if(stat("/proc/self/exe",&exeStat)!=0) {
00726 perror(" stat /proc/self/exe");
00727 } else if(stat(sym.dli_fname,&libStat)!=0) {
00728 perror(" stat lib");
00729 } else {
00730 isExe = (exeStat.st_dev==libStat.st_dev && exeStat.st_ino==libStat.st_ino);
00731 }
00732 }
00733 # endif
00734
00735 if(dlres==0 || sym.dli_sname==NULL) {
00736 if(sym.dli_fname==NULL || sym.dli_fname[0]=='\0') {
00737 fprintf(stderr,"%4d [non-dynamic symbol @ %p]",depth,ra);
00738 fprintf(stderr," (has offset %p in unknown library)\n",sym.dli_fbase);
00739 } else {
00740
00741 const void* const off = (isExe) ? ra : (void*)((size_t)ra-(size_t)sym.dli_fbase);
00742 char* srcfile=NULL, *func=NULL;
00743 size_t srcfilelen=0, funclen=0;
00744 if(addr2lineLookup(sym.dli_fname,off,&srcfile,&srcfilelen,&func,&funclen)==0) {
00745 fprintf(stderr,"%4d %s",depth,(strlen(func)==0) ? "[unknown symbol]" : func);
00746 if(!isExe) {
00747 const char * base = strrchr(sym.dli_fname,'/');
00748 fprintf(stderr," (%s)",(base==NULL)?sym.dli_fname:base+1);
00749 }
00750 if(strcmp(srcfile,"??:0")!=0) {
00751 fprintf(stderr," ");
00752 char * wd = getcwd(NULL,0);
00753 if(wd==NULL) {
00754 perror("getcwd");
00755 return;
00756 }
00757 fprintf(stderr,"(");
00758 displayRelPath(stderr,wd,srcfile);
00759 fprintf(stderr,")");
00760 free(wd);
00761 }
00762 fprintf(stderr,"\n");
00763 }
00764 free(srcfile);
00765 free(func);
00766 }
00767 return;
00768 } else {
00769 const char * dispFmt="%4d %s +%#lx";
00770 # ifdef __cplusplus
00771 fprintf(stderr,dispFmt,depth,demangle(sym.dli_sname).c_str(),(size_t)ra-(size_t)sym.dli_saddr);
00772 # else
00773 fprintf(stderr,dispFmt,depth,sym.dli_sname,(size_t)ra-(size_t)sym.dli_saddr);
00774 # endif
00775 }
00776
00777 if(sym.dli_fname==NULL || sym.dli_fname[0]=='\0') {
00778 fprintf(stderr," (%p, offset %p in unknown lib)\n",ra,sym.dli_fbase);
00779 return;
00780 } else if(isExe) {
00781
00782
00783
00784 } else {
00785
00786
00787 const char * base = strrchr(sym.dli_fname,'/');
00788 fprintf(stderr," (%s)",(base==NULL)?sym.dli_fname:base+1);
00789 }
00790
00791
00792 const void* const off = (isExe) ? ra : (void*)((size_t)ra-(size_t)sym.dli_fbase);
00793 char* srcfile=NULL, *func=NULL;
00794 size_t srcfilelen=0, funclen=0;
00795 if(addr2lineLookup(sym.dli_fname,off,&srcfile,&srcfilelen,&func,&funclen)==0 && strcmp(srcfile,"??:0")!=0) {
00796 fprintf(stderr," ");
00797 char * wd = getcwd(NULL,0);
00798 if(wd==NULL) {
00799 perror("getcwd");
00800 return;
00801 }
00802 fprintf(stderr,"(");
00803 displayRelPath(stderr,wd,srcfile);
00804 fprintf(stderr,")");
00805 free(wd);
00806 }
00807 fprintf(stderr,"\n");
00808 free(srcfile);
00809 free(func);
00810 }
00811 #else
00812 static void displayStackFrame(unsigned int ST_UNUSED(depth), const struct StackFrame* frame) {
00813 ST_BODY_UNUSED(depth);
00814 fprintf(stderr," %p",(void*)frame->ra);
00815 }
00816 #endif
00817
00818
00819 static void completeDisplay(int isend) {
00820 #if defined(STACKTRACE_USE_BACKTRACE)
00821 #endif
00822 if(!isend)
00823 fprintf(stderr," ...\n");
00824 }
00825
00826 void displayCurrentStackTrace(unsigned int limit, unsigned int skip) {
00827 struct StackFrame * cur = allocateStackTrace(1);
00828 #ifdef DEBUG_STACKTRACE
00829 cur->debug=0;
00830 #endif
00831 unsigned int i;
00832 int more;
00833 if(limit==0)
00834 return;
00835 getCurrentStackFrame(cur);
00836
00837 beginDisplay();
00838 for(; skip!=0; skip--) {
00839 if(!unrollStackFrame(cur,cur)) {
00840 completeDisplay(1);
00841 return;
00842 }
00843
00844 }
00845 for(i=0; (more=unrollStackFrame(cur,cur)) && i<limit; i++) {
00846
00847 displayStackFrame(i,cur);
00848 }
00849 completeDisplay(!more);
00850 freeStackTrace(cur);
00851 }
00852
00853 void displayStackTrace(const struct StackFrame* frame) {
00854 int i;
00855 beginDisplay();
00856 for(i=0; frame!=NULL && frame->caller!=frame; i++) {
00857 displayStackFrame(i,frame);
00858 frame=frame->caller;
00859 }
00860 if(frame!=NULL)
00861 displayStackFrame(i+1,frame);
00862 completeDisplay(frame==NULL);
00863 }
00864
00865
00866 #ifdef __cplusplus
00867 }
00868 #endif
00869
00870
00871
00872
00873
00874