Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

StackTrace.cc

Go to the documentation of this file.
00001 #include "StackTrace.h"
00002 #include <stdio.h>
00003 
00004 #if defined(HAVE_BFD) && HAVE_BFD!=0
00005 #  include <bfd.h>
00006 #  include "libiberty.h"
00007 #  include "demangle.h"
00008 #  include <sys/stat.h>
00009 #  include <string.h>
00010 #endif
00011 
00012 #ifdef ST_UNUSED 
00013 #elif defined(__GNUC__) && __GNUC__>3
00014 //! portable access to compiler hint not to warn if a function argument is ignored (goes in argument list)
00015 # define ST_UNUSED(x) UNUSED_##x __attribute__((unused)) 
00016 //! portable access to compiler hint not to warn if a function argument is ignored (goes at beginning of function body)
00017 # define ST_BODY_UNUSED(x) /*no body necessary*/
00018 
00019 #elif defined(__LCLINT__) 
00020 //! portable access to compiler hint not to warn if a function argument is ignored (goes in argument list)
00021 # define ST_UNUSED(x) /*@unused@*/ x 
00022 //! portable access to compiler hint not to warn if a function argument is ignored (goes at beginning of function body)
00023 # define ST_BODY_UNUSED(x) /*no body necessary*/
00024 
00025 #else 
00026 //! portable access to compiler hint not to warn if a function argument is ignored (goes in argument list)
00027 # define ST_UNUSED(x) UNUSED_##x 
00028 //! portable access to compiler hint not to warn if a function argument is ignored (goes at beginning of function body)
00029 # define ST_BODY_UNUSED(x) (void)UNUSED_##x /* ugly hack to avoid warning */
00030 #endif
00031 
00032 #ifdef __cplusplus
00033 namespace stacktrace {
00034 #endif /* __cplusplus */
00035 
00036 #if defined(HAVE_BFD) && HAVE_BFD!=0
00037 char * bfd_objfile=NULL;
00038 #endif
00039 
00040 //! target string to use when opening symbol files if host architecture can't be detected
00041 const char * BFD_DEFAULT_TARGET="powerpc-apple-darwin8.5.0";
00042 //const char * BFD_DEFAULT_TARGET="i686-pc-linux-gnu";
00043 
00044 #if defined(HAVE_BFD) && HAVE_BFD!=0
00045 int loadStackTraceSymbols(const char* objfile) {
00046   static int bfdInited=0;
00047   if(!bfdInited) {
00048     bfd_init();
00049     if(!bfd_set_default_target(BFD_DEFAULT_TARGET)) {
00050       bfd_error_type err=bfd_get_error();
00051       fprintf(stderr,"can't set BFD default target to `%s': %s\n",BFD_DEFAULT_TARGET,bfd_errmsg(err));
00052       fprintf(stderr,"stacktrace::loadStackTraceSymbols(%s) failed\n",objfile);
00053       return err;
00054     }
00055     bfdInited=1;
00056   }
00057   /*const char ** tgt=bfd_target_list();
00058   while(*tgt)
00059     printf("%s\n",*tgt++);
00060   free(bfd_objfile);
00061   if(objfile==NULL) {
00062     bfd_objfile=NULL;
00063     return 0;
00064   }
00065   struct stat sb;
00066   if(stat(objfile,&sb)) {
00067     char msg[128];
00068     snprintf(msg,128,"stacktrace::loadStackTraceSymbols(%s): stat",objfile);
00069     perror(msg);
00070     return -1;
00071   }
00072   bfd * abfd = bfd_openr(objfile, NULL);
00073   if(abfd==NULL) {
00074     bfd_error_type err=bfd_get_error();
00075     fprintf(stderr,"Can't open object file `%s': %s\n",objfile,bfd_errmsg(err));
00076     fprintf(stderr,"stacktrace::loadStackTraceSymbols(%s) failed\n",objfile);
00077     return err;
00078   }
00079   if(!bfd_close(abfd)) {
00080     bfd_error_type err=bfd_get_error();
00081     fprintf(stderr,"Can't close object file `%s': %s\n",objfile,bfd_errmsg(err));
00082     fprintf(stderr,"stacktrace::loadStackTraceSymbols(%s) failed\n",objfile);
00083     return err;
00084     }*/
00085   bfd_objfile=strdup(objfile);
00086   return 0;
00087 }
00088 #else
00089 int loadStackTraceSymbols(const char* ST_UNUSED(objfile)) {
00090   ST_BODY_UNUSED(objfile);
00091   return 0;
00092 }
00093 #endif
00094 
00095 int unrollStackFrame(struct StackFrame* curFrame, struct StackFrame* nextFrame) {
00096   void* nsp=NULL;
00097   machineInstruction * nra=NULL;
00098 
00099 #if defined(__i386__) || defined(__x86_64__) || defined(__amd64__)
00100   if(curFrame==NULL)
00101     return 0;
00102   curFrame->caller=NULL;
00103   if(nextFrame==NULL)
00104     return 0;
00105   if(curFrame->sp==NULL)
00106     return 0;
00107   if(((void**)curFrame->sp)-1==NULL)
00108     return 0;
00109   nsp=((void***)curFrame->sp)[-1];
00110   if(nsp==NULL)
00111     return 0;
00112   nsp=(void**)nsp+1; //move from frame pointer to stack pointer of previous frame
00113   nra=*((machineInstruction**)curFrame->sp);
00114   if(nsp<=curFrame->sp) {
00115     fprintf(stderr,"stacktrace::unrollStackFrame(sp=%p,ra=%p) directed to invalid next frame: (sp=%p,ra=%p)\n",curFrame->sp,curFrame->ra,nsp,nra);
00116     return 0;
00117   }
00118 #  ifdef DEBUG_STACKTRACE
00119   if(curFrame->debug)
00120     printf("( %p %p ) -> { %p %p }\n",curFrame->sp,curFrame->ra,nsp,nra);
00121   nextFrame->debug=curFrame->debug;
00122 #  endif
00123   nextFrame->sp=nsp;
00124   nextFrame->ra=nra;
00125   curFrame->caller=nextFrame;
00126   return 1;
00127 #endif
00128 #ifdef __POWERPC__
00129   if(curFrame==NULL)
00130     return 0;
00131   curFrame->caller=NULL;
00132   if(nextFrame==NULL)
00133     return 0;
00134   if(curFrame->sp==NULL)
00135     return 0;
00136   if(*(void**)curFrame->sp==NULL)
00137     return 0;
00138   nsp=*(void**)curFrame->sp;
00139   nra=((machineInstruction**)nsp)[2];
00140   if(nsp<=curFrame->sp) {
00141     fprintf(stderr,"stacktrace::unrollStackFrame(sp=%p,ra=%p) directed to invalid next frame: (sp=%p,ra=%p)\n",curFrame->sp,curFrame->ra,nsp,nra);
00142     return 0;
00143   }
00144 #  ifdef DEBUG_STACKTRACE
00145   if(curFrame->debug)
00146     printf("( %p %p ) -> { %p %p }\n",curFrame->sp,curFrame->ra,nsp,nra);
00147   nextFrame->debug=curFrame->debug;
00148 #  endif
00149   nextFrame->sp=nsp;
00150   nextFrame->ra=nra;
00151   curFrame->caller=nextFrame;
00152   return 1;
00153 #endif
00154 #if defined(__MIPSEL__) || defined(__MIPS__) /* we're running on PLATFORM_APERIOS */
00155   /* Have to scan through intructions being executed because stack pointer is not stored directly on the stack */
00156   machineInstruction * ins;
00157   const machineInstruction * INS_BASE=(const machineInstruction *)0x2000; // lowest valid memory address?
00158   if(curFrame==NULL)
00159     return 0;
00160   curFrame->caller=NULL;
00161   if(nextFrame==NULL || curFrame==NULL || curFrame->sp==NULL)
00162     return 0;
00163   
00164 #ifdef __pic__
00165   ins = reinterpret_cast<machineInstruction*>(curFrame->gp-curFrame->ra);
00166 #else
00167   ins = curFrame->ra;
00168 #endif
00169   // find previous return address
00170   for(; ins>=INS_BASE; ins--) {
00171     // gcc will always save the return address with the instruction
00172     //     sw ra, offset(sp)
00173     // 
00174     // the high word in this case is sw sp ra
00175     if ( ( *ins & 0xffff0000 ) == 0xafbf0000 )
00176     {
00177       // the low word is the offset from sp
00178       int offset = *ins & 0x000ffff;
00179       
00180       // in case things went horribly awry, don't deref the non-aligned ptr
00181       if (offset & 0x3)
00182         return 0;
00183       
00184       nra = *reinterpret_cast<machineInstruction**>((char*)curFrame->sp + offset);
00185       break; // now search for stack pointer
00186     }
00187     
00188     //it appears the aperios stub entry functions always begin with "ori  t0,ra,0x0"
00189     //if we hit one of these, return 0, because we can't unroll any more
00190     //(or at least, I don't know how it returns from these... there's no return statements!)
00191     if ( *ins  == 0x37e80000 ) {
00192 #  ifdef DEBUG_STACKTRACE
00193       if(curFrame->debug)
00194         printf("( %p %p %p ) -> { kernel? }\n",curFrame->sp,curFrame->ra,curFrame->gp);
00195 #  endif
00196       return 0;
00197     }
00198   }
00199   // find previous stack pointer
00200   for(; ins>=INS_BASE; ins--) {
00201     // gcc will always change the stack frame with the instruction
00202     //     addiu sp,sp,offset
00203     //
00204     // at the beginning of the function the offset will be negative since the stack grows 
00205     // from high to low addresses
00206     //
00207     // first check the high word which will be instruction + regs in this case (I-type)
00208     if ( ( *ins & 0xffff0000 ) == 0x27bd0000 ) {
00209       // the offset is in the low word. since we're finding occurrence at the start of the function,
00210       // it will be negative (increase stack size), so sign extend it
00211       int offset = ( *ins & 0x0000ffff ) | 0xffff0000;
00212 
00213       // in case things went horribly awry, don't deref the non-aligned ptr
00214       if (offset & 0x3)
00215         return 0;
00216       
00217       nsp = (char*)curFrame->sp - offset;
00218       break;
00219     }
00220   }
00221   
00222   
00223   if(ins>=INS_BASE) {
00224     if(nsp<=curFrame->sp) {
00225 #ifdef __pic__
00226       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]));
00227 #else
00228       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);
00229 #endif
00230       return 0;
00231     }
00232 
00233 #ifdef __pic__
00234 #  ifdef DEBUG_STACKTRACE
00235     if(curFrame->debug)
00236       printf("( %p %p %p ) -> { %p %p %p }\n",curFrame->sp,curFrame->ra,curFrame->gp,nsp,nra,reinterpret_cast<size_t*>(nsp)[4]);
00237     nextFrame->debug=curFrame->debug;
00238 #  endif
00239     // I'm not actually sure this is a valid stop criteria, but in testing,
00240     // after this it seems to cross into some kind of kernel code.
00241     // (We get a really low gp (0x106), although a fairly normal nra, and then go bouncing
00242     // around in memory until we hit sp=0x80808080, ra=0x2700, which seems to be the 'real' last frame)
00243     //if(reinterpret_cast<size_t>(nra)>reinterpret_cast<size_t*>(nsp)[4])
00244     //return 0;
00245     //instead of this however, now we check for the ori t0,ra,0 statement, and reuse previous gp below
00246     
00247     nextFrame->sp=nsp;
00248     //not sure how valid this is either:
00249     if(reinterpret_cast<size_t>(nra)>reinterpret_cast<size_t*>(nsp)[4]) {
00250       nextFrame->gp = curFrame->gp;
00251     } else {
00252       nextFrame->gp = reinterpret_cast<size_t*>(nsp)[4]; // gp is stored 4 words from stack pointer
00253     }
00254     nextFrame->ra = nextFrame->gp-reinterpret_cast<size_t>(nra);
00255 #else
00256 #  ifdef DEBUG_STACKTRACE
00257     if(curFrame->debug)
00258       printf("( %p %p ) -> { %p %p }\n",curFrame->sp,curFrame->ra,nsp,nra);
00259     nextFrame->debug=curFrame->debug;
00260 #  endif
00261     nextFrame->sp=nsp;
00262     nextFrame->ra=nra;
00263 #endif /* __pic__ */
00264     curFrame->caller=nextFrame;
00265     return 1;
00266   }
00267 #ifdef __pic__
00268 #  ifdef DEBUG_STACKTRACE
00269   if(curFrame->debug)
00270     printf("( %p %p %p ) -> { %p %p --- }\n",curFrame->sp,curFrame->ra,curFrame->gp,nsp,nra);
00271 #  endif
00272 #else
00273 #  ifdef DEBUG_STACKTRACE
00274   if(curFrame->debug)
00275     printf("( %p %p ) -> { %p %p }\n",curFrame->sp,curFrame->ra,nsp,nra);
00276 #  endif
00277 #endif
00278   return 0;
00279 #endif
00280 }
00281 
00282 void getCurrentStackFrame(struct StackFrame* frame) {
00283   void** csp=NULL;
00284   machineInstruction* cra=NULL;
00285 
00286 #ifdef __POWERPC__
00287   __asm __volatile__ ("mr %0,r1" : "=r"(csp) ); // get the current stack pointer
00288   __asm __volatile__ ("mflr %0" : "=r"(cra) );  // get the current return address
00289 #endif /* __POWERPC__ */
00290   
00291 #if defined(__MIPSEL__) || defined(__MIPS__)
00292 #ifdef __pic__
00293   size_t cgp=0;
00294   __asm __volatile__ ("move %0,$gp" : "=r"(cgp) ); //get the gp register so we can compute link addresses
00295 #endif /* __pic__ */
00296   __asm __volatile__ ("move %0,$sp" : "=r"(csp) ); // get the current stack pointer
00297   __asm __volatile__ ("jal readepc; nop; readepc: move %0,$ra" : "=r"(cra) ); // get the current return address
00298 #endif /* __MIPSEL__ */
00299   
00300 #if defined(__i386__) || defined(__x86_64__) || defined(__amd64__)
00301   __asm __volatile__ ("movl %%ebp,%0" : "=m"(csp) ); // get the caller's stack pointer
00302   csp++; //go back one to really be a stack pointer
00303   //__asm __volatile__ ("movl (%%esp),%0" : "=r"(cra) ); // get the caller's address
00304   cra=*((machineInstruction**)csp);
00305   csp=((void***)csp)[-1]+1;
00306 #endif /* __i386__ */
00307 
00308   frame->sp=csp;
00309 #ifdef __pic__
00310   frame->ra=cgp-reinterpret_cast<size_t>(cra);
00311   frame->gp=cgp;
00312 #else
00313   frame->ra=cra;
00314 #endif /* __pic__ */
00315 
00316 #if !defined(__i386__) && !defined(__x86_64__) && !defined(__amd64__)
00317   //with ia-32 it was more convenient to directly provide caller, so don't need to unroll
00318   //otherwise we actually want to return *caller's* frame, so unroll once
00319   unrollStackFrame(frame,frame);
00320 #endif /* not __i386__ */
00321 }
00322 
00323 void freeStackTrace(struct StackFrame* frame) {
00324   while(frame!=NULL) {
00325     struct StackFrame * next=frame->caller;
00326     free(frame);
00327     if(frame==next)
00328       return;
00329     frame=next;
00330   }
00331 }
00332 
00333 struct StackFrame* allocateStackTrace(unsigned int size) {
00334   struct StackFrame * frame=NULL;
00335   while(size--!=0) {
00336     struct StackFrame * prev = (struct StackFrame *)malloc(sizeof(struct StackFrame));
00337     prev->caller=frame;
00338     frame=prev;
00339   }
00340   return frame;
00341 }
00342 
00343 
00344 struct StackFrame * recordStackTrace(unsigned int limit/*=-1U*/, unsigned int skip/*=0*/) {
00345   struct StackFrame cur;
00346 #ifdef DEBUG_STACKTRACE
00347   cur.debug=0;
00348 #endif
00349   if(limit==0)
00350     return NULL;
00351   getCurrentStackFrame(&cur);
00352   for(; skip!=0; skip--)
00353     if(!unrollStackFrame(&cur,&cur))
00354       return NULL;
00355   struct StackFrame * prev = (struct StackFrame *)malloc(sizeof(struct StackFrame));
00356 #ifdef DEBUG_STACKTRACE
00357   prev->debug=0;
00358 #endif
00359   unrollStackFrame(&cur,prev); //unroll once more for the current frame
00360   for(; limit!=0; limit--) {
00361     struct StackFrame * next = (struct StackFrame *)malloc(sizeof(struct StackFrame));
00362 #ifdef DEBUG_STACKTRACE
00363     next->debug=0;
00364 #endif
00365     if(!unrollStackFrame(prev,next)) {
00366       // reached end of trace
00367       free(next);
00368       prev->caller=NULL; //denotes end was reached
00369       return cur.caller;
00370     }
00371     prev=next;
00372   }
00373   // reaching here implies limit was reached
00374   prev->caller=prev; //denotes limit was reached
00375   return cur.caller;
00376 }
00377 
00378 struct StackFrame * recordOverStackTrace(struct StackFrame* frame, unsigned int skip) {
00379   struct StackFrame cur;
00380 #ifdef DEBUG_STACKTRACE
00381   cur.debug=0;
00382 #endif
00383   if(frame==NULL)
00384     return frame;
00385   getCurrentStackFrame(&cur);
00386   for(; skip!=0; skip--)
00387     if(!unrollStackFrame(&cur,&cur))
00388       return frame;
00389   unrollStackFrame(&cur,frame); //unroll once more for the current frame
00390   for(; frame->caller!=NULL && frame->caller!=frame; frame=frame->caller) {
00391     cur.caller=frame->caller; //don't lose remainder of free list if we hit the end
00392     if(!unrollStackFrame(frame,frame->caller))
00393       return cur.caller; // reached end of trace
00394   }
00395   // reaching here implies limit was reached
00396   frame->caller=frame; //denotes limit was reached
00397   return cur.caller;
00398 }
00399 
00400 #if defined(HAVE_BFD) && HAVE_BFD!=0
00401 bfd * abfd = NULL;
00402 static asymbol **syms;    /* Symbol table.  */
00403 #endif
00404 
00405 //! attempts to read symbol information and displays stack trace header
00406 void beginDisplay() {
00407 #if defined(HAVE_BFD) && HAVE_BFD!=0
00408   const char* consolation=", try addr2line or trace_lookup";
00409   if(bfd_objfile==NULL) {
00410     fprintf(stderr,"No symbols are loaded%s.\n",consolation);
00411     return;
00412   }
00413   abfd = bfd_openr(bfd_objfile, NULL);
00414   if(abfd==NULL) {
00415     bfd_error_type err=bfd_get_error();
00416     fprintf(stderr,"Can't open object file `%s': %s\n",bfd_objfile,bfd_errmsg(err));
00417     fprintf(stderr,"stacktrace::beginDisplay() failed%s.\n",consolation);
00418     return;
00419   }
00420   if(bfd_check_format (abfd, bfd_archive)) {
00421     bfd_error_type err=bfd_get_error();
00422     fprintf(stderr,"Can't get addresses from archive `%s': %s\n",bfd_objfile,bfd_errmsg(err));
00423     if(!bfd_close(abfd))
00424       fprintf(stderr,"Can't close object file `%s': %s\n",bfd_objfile,bfd_errmsg(bfd_get_error()));
00425     fprintf(stderr,"stacktrace::beginDisplay() failed%s.\n",consolation);
00426     abfd=NULL;
00427     return;
00428   }
00429   {
00430     char **matching;
00431     if(!bfd_check_format_matches(abfd, bfd_object, &matching)) {
00432       bfd_error_type err=bfd_get_error();
00433       fprintf(stderr,"Can't get archive `%s' format doesn't match bfd_object: %s\n",bfd_objfile,bfd_errmsg(err));
00434       if (err == bfd_error_file_ambiguously_recognized) {
00435         char** p=matching;
00436         fprintf(stderr,"Matching formats:");
00437         while (*p)
00438           fprintf (stderr, " %s", *p++);
00439         fputc ('\n', stderr);
00440         free (matching);
00441       }
00442       if(!bfd_close(abfd))
00443         fprintf(stderr,"Can't close object file `%s': %s\n",bfd_objfile,bfd_errmsg(bfd_get_error()));
00444       fprintf(stderr,"stacktrace::beginDisplay() failed%s.\n",consolation);
00445       abfd=NULL;
00446     }
00447   }
00448   {
00449     long symcount;
00450     unsigned int size;
00451     
00452     if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0)
00453       return;
00454     
00455     symcount = bfd_read_minisymbols (abfd, FALSE, (void *) &syms, &size);
00456     if (symcount == 0)
00457       symcount = bfd_read_minisymbols (abfd, TRUE /* dynamic */, (void *) &syms, &size);
00458     
00459     if (symcount < 0) {
00460       bfd_error_type err=bfd_get_error();
00461       fprintf(stderr,"Can't read minisymbols from `%s': %s\n",bfd_get_filename (abfd),bfd_errmsg(err));
00462       if(!bfd_close(abfd))
00463         fprintf(stderr,"Can't close object file `%s': %s\n",bfd_objfile,bfd_errmsg(bfd_get_error()));
00464       fprintf(stderr,"stacktrace::beginDisplay() failed%s.\n",consolation);
00465       abfd=NULL;
00466     }
00467     if(abfd!=NULL) {
00468       fprintf(stderr,"Stack trace:\n");
00469       return;
00470     }
00471   }
00472   fprintf(stderr,"Stack trace:");
00473 #else
00474 # ifdef PLATFORM_APERIOS
00475   fprintf(stderr,"Run trace_lookup:");
00476 #  else
00477   const char* consolation=", try addr2line or trace_lookup";
00478   fprintf(stderr,"libBFD unavaible%s:\n",consolation);
00479   fprintf(stderr,"Stack trace:");
00480 #  endif
00481 #endif
00482 }
00483 
00484 #if defined(HAVE_BFD) && HAVE_BFD!=0
00485 //! from binutils' budemangle
00486 /*! Wrapper around cplus_demangle.   Strips leading underscores and
00487  *  other such chars that would otherwise confuse the demangler.   */
00488 char * demangle (const char *name) {
00489   char *res, *alloc;
00490   const char *pre, *suf;
00491   size_t pre_len;
00492 
00493   if (abfd != NULL && bfd_get_symbol_leading_char (abfd) == name[0])
00494     ++name;
00495 
00496   /* This is a hack for better error reporting on XCOFF, PowerPC64-ELF
00497      or the MS PE format.  These formats have a number of leading '.'s
00498      on at least some symbols, so we remove all dots to avoid
00499      confusing the demangler.  */
00500   pre = name;
00501   while (*name == '.')
00502     ++name;
00503   pre_len = name - pre;
00504 
00505   alloc = NULL;
00506   suf = strchr (name, '@');
00507   if (suf != NULL)
00508     {
00509       alloc = xmalloc (suf - name + 1);
00510       memcpy (alloc, name, suf - name);
00511       alloc[suf - name] = '\0';
00512       name = alloc;
00513     }
00514 
00515   res = cplus_demangle (name, DMGL_ANSI | DMGL_PARAMS);
00516   if (res != NULL)
00517     {
00518       /* Now put back any suffix, or stripped dots.  */
00519       if (pre_len != 0 || suf != NULL)
00520         {
00521           size_t len;
00522           size_t suf_len;
00523           char *final;
00524 
00525           if (alloc != NULL)
00526             free (alloc);
00527 
00528           len = strlen (res);
00529           if (suf == NULL)
00530             suf = res + len;
00531           suf_len = strlen (suf) + 1;
00532           final = xmalloc (pre_len + len + suf_len);
00533 
00534           memcpy (final, pre, pre_len);
00535           memcpy (final + pre_len, res, len);
00536           memcpy (final + pre_len + len, suf, suf_len);
00537           free (res);
00538           res = final;
00539         }
00540 
00541       return res;
00542     }
00543 
00544   if (alloc != NULL)
00545     free (alloc);
00546 
00547   return xstrdup (pre);
00548 }
00549 
00550 struct AddrLookupInfo {
00551   bfd_vma addr;
00552   const char *filename;
00553   const char *functionname;
00554   unsigned int line;
00555   bfd_boolean found;
00556 };
00557 
00558 /*! Look for an address in a section. This is called via bfd_map_over_sections.  */
00559 static void stackTraceFindAddress (bfd *fabfd, asection *section, void *data) {
00560   struct AddrLookupInfo * info=(struct AddrLookupInfo *)data;
00561   bfd_vma vma;
00562   bfd_size_type size;
00563   
00564 #ifdef bfd_get_section_size
00565   printf("searching %p: %s %x-%x\n",info->addr,section->name,bfd_get_section_vma (fabfd, section),bfd_get_section_vma (fabfd, section)+bfd_get_section_size (section));
00566 #else
00567   printf("searching %p: %s %x-%x\n",info->addr,section->name,bfd_get_section_vma (fabfd, section),bfd_get_section_vma (fabfd, section)+bfd_get_section_size_before_reloc (section));
00568 #endif
00569   
00570   if (info->found)
00571     return;
00572   if ((bfd_get_section_flags (fabfd, section) & SEC_ALLOC) == 0)
00573     return;
00574 
00575   vma = bfd_get_section_vma (fabfd, section);
00576   if (info->addr < vma)
00577     return;
00578 #ifdef bfd_get_section_size
00579   size = bfd_get_section_size (section);
00580 #else
00581   size = bfd_get_section_size_before_reloc (section);
00582 #endif
00583   if (info->addr >= vma + size)
00584     return;
00585   
00586   info->found = bfd_find_nearest_line (fabfd, section, syms, info->addr - vma, &info->filename, &info->functionname, &info->line);
00587   printf("found %d\n",info->found);
00588 }
00589 #endif /* HAVE_BFD */
00590 
00591 #if defined(HAVE_BFD) && HAVE_BFD!=0
00592 void displayStackFrame(unsigned int depth, const struct StackFrame* frame) {
00593   if(abfd!=NULL) {
00594     struct AddrLookupInfo info={(bfd_vma)frame->ra,NULL,NULL,0,FALSE};
00595     asection *p;
00596     for (p = abfd->sections; p != NULL; p = p->next)
00597       stackTraceFindAddress(abfd, p, &info);
00598     //bfd_map_over_sections (abfd, stackTraceFindAddress, &info);
00599     if (!info.found) {
00600       printf("%u: %p ????\n",depth,frame->ra);
00601     } else {
00602       const char *name=info.functionname;
00603       char *alloc = NULL;
00604       if (name == NULL || *name == '\0')
00605         name = "??";
00606       else {
00607         alloc = demangle(name);
00608         name = alloc;
00609       }
00610       
00611       printf ("%u: %p %s", depth, frame->ra, name);
00612       if (alloc != NULL) {
00613         free (alloc);
00614         alloc=NULL;
00615       }
00616   
00617       if(info.filename)
00618         printf(" (%s:%u)\n", info.filename, info.line);
00619       else
00620         printf(" (??:?)\n");
00621     }
00622     return;
00623   }
00624   fprintf(stderr," %p",frame->ra);
00625 }
00626 #else
00627 void displayStackFrame(unsigned int ST_UNUSED(depth), const struct StackFrame* frame) {
00628   ST_BODY_UNUSED(depth);
00629   fprintf(stderr," %p",(void*)frame->ra);
00630 }
00631 #endif
00632 
00633 //! releases symbol information used during display
00634 void completeDisplay(int isend) {
00635 #if defined(HAVE_BFD) && HAVE_BFD!=0
00636   if (syms != NULL) {
00637     free(syms);
00638     syms = NULL;
00639   }
00640   if(abfd!=NULL) {
00641     if(!bfd_close(abfd)) {
00642       bfd_error_type err=bfd_get_error();
00643       fprintf(stderr,"Can't close object file `%s': %s\n",bfd_get_filename (abfd),bfd_errmsg(err));
00644       fprintf(stderr,"stacktrace::completeDisplay() failed");
00645     }
00646     abfd=NULL;
00647     if(!isend)
00648       fprintf(stderr," ...\n");
00649     return;
00650   }
00651 #endif
00652   if(!isend)
00653     fprintf(stderr," ...");
00654   fprintf(stderr,"\n");
00655 }
00656 
00657 void displayCurrentStackTrace(unsigned int limit/*=-1U*/, unsigned int skip/*=0*/) {
00658   struct StackFrame cur;
00659 #ifdef DEBUG_STACKTRACE
00660   cur.debug=0;
00661 #endif
00662   unsigned int i;
00663   int more;
00664   if(limit==0)
00665     return;
00666   getCurrentStackFrame(&cur);
00667   //printf(" initial (%p\t%p\t%p)\n",cur.ra,cur.sp,*(void**)cur.sp);
00668   beginDisplay();
00669   for(; skip!=0; skip--) {
00670     if(!unrollStackFrame(&cur,&cur)) {
00671       completeDisplay(1);
00672       return;
00673     }
00674     //printf(" skip (%p\t%p\t%p)\n",cur.ra,cur.sp,*(void**)cur.sp);
00675   }
00676   for(i=0; (more=unrollStackFrame(&cur,&cur)) && i<limit; i++) {
00677     //printf(" out (%p\t%p\t%p)\n",cur.ra,cur.sp,*(void**)cur.sp);
00678     displayStackFrame(i,&cur);
00679   }
00680   completeDisplay(!more);
00681 }
00682 
00683 void displayStackTrace(const struct StackFrame* frame) {
00684   int i;
00685   beginDisplay();
00686   for(i=0; frame!=NULL && frame->caller!=frame; i++) {
00687     displayStackFrame(i,frame);
00688     frame=frame->caller;
00689   }
00690   if(frame!=NULL)
00691     displayStackFrame(i+1,frame);
00692   completeDisplay(frame==NULL);
00693 }
00694 
00695 
00696 #ifdef __cplusplus
00697 }
00698 #endif /* __cplusplus */
00699 
00700 /*! @file
00701  * @brief Implements functionality for performing stack traces
00702  * @author ejt (Generalized and implementation for non-MIPS platforms)
00703  * @author Stuart Scandrett (original inspiration, Aperios/MIPS stack operations)
00704  *
00705  * $Author: ejt $
00706  * $Name: tekkotsu-4_0 $
00707  * $Revision: 1.14 $
00708  * $State: Exp $
00709  * $Date: 2007/11/13 04:16:03 $
00710  */

Tekkotsu v4.0
Generated Thu Nov 22 00:54:56 2007 by Doxygen 1.5.4