Changeset 20773

Show
Ignore:
Timestamp:
09/06/07 14:01:06 (1 year ago)
Author:
patrick
Message:

Implemented stack trace printing on Mac OS X.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • juggler/trunk/modules/vapor/ChangeLog

    r20758 r20773  
    11DATE       AUTHOR   CHANGE 
    22---------- -------- ----------------------------------------------------------- 
     32007-09-06 patrick  Implemented stack trace printing on Mac OS X. 
    342007-09-04 patrick  Set VPR_BASE_DIR automatically on all platforms. 
    452007-08-21 patrick  Removed support for SPROC. 
  • juggler/trunk/modules/vapor/vpr/SystemBase.cpp

    r20463 r20773  
    4141#  include <execinfo.h> 
    4242#  include <sstream> 
     43#elif defined(VPR_OS_Darwin) 
     44#  include <iomanip> 
     45#  include <sstream> 
     46#  include <vector> 
     47 
     48extern "C" 
     49{ 
     50 
     51#  include <mach-o/dyld.h> 
     52#  include <mach-o/loader.h> 
     53#  include <mach-o/nlist.h> 
     54#  include <mach-o/stab.h> 
     55 
     56} 
     57 
    4358#elif defined(VPR_OS_Windows) 
    4459#  if _MSC_VER >= 1400 
     
    8095namespace 
    8196{ 
     97 
    8298#if defined(VPR_OS_Windows) && defined(VPR_DEBUG) 
    8399#if _MSC_VER >= 1400 
     
    230246      { 
    231247//         std::cerr << "vpr::SystemBase::demangleTraceString: mangled_name " 
    232 //                   << "is not a valid name under the C++ ABI mangling ' 
     248//                   << "is not a valid name under the C++ ABI mangling " 
    233249//                   << "rules.\n"; 
    234250      } 
     
    248264#endif 
    249265} 
     266 
     267#if defined(VPR_OS_Darwin) 
     268struct CrawlFrame 
     269{ 
     270   unsigned int pc; 
     271   size_t frame; 
     272   std::string name; 
     273   unsigned int offset; 
     274}; 
     275 
     276const mach_header* findOwnerOfPC(const unsigned int pc) 
     277{ 
     278   const unsigned int count = _dyld_image_count(); 
     279   for ( unsigned int index = 0; index < count; ++index ) 
     280   { 
     281      const mach_header* header = _dyld_get_image_header(index); 
     282      const unsigned int offset = _dyld_get_image_vmaddr_slide(index); 
     283      const load_command* cmd = 
     284         reinterpret_cast<const load_command*>( 
     285            reinterpret_cast<const char*>(header) + sizeof(mach_header) 
     286         ); 
     287 
     288      for ( unsigned int cmdex = 0; 
     289            cmdex < header->ncmds; 
     290            ++cmdex, cmd = reinterpret_cast<const load_command*>(reinterpret_cast<const char*>(cmd) + cmd->cmdsize)) 
     291      { 
     292         switch (cmd->cmd) 
     293         { 
     294            case LC_SEGMENT: 
     295               { 
     296                  const segment_command* seg = 
     297                     reinterpret_cast<const segment_command*>(cmd); 
     298                  if ( pc >= (seg->vmaddr + offset) && 
     299                       pc < (seg->vmaddr + offset + seg->vmsize) ) 
     300                  { 
     301                     return header; 
     302                  } 
     303               } 
     304               break; 
     305         } 
     306      } 
     307   } 
     308 
     309   return NULL; 
     310} 
     311 
     312std::string getFunctionName(const unsigned int pc, unsigned int* offset) 
     313{ 
     314   const mach_header* header = findOwnerOfPC(pc); 
     315   if ( header != NULL ) 
     316   { 
     317      const segment_command* seg_linkedit(NULL); 
     318      const segment_command* seg_text(NULL); 
     319      const symtab_command* symtab(NULL); 
     320 
     321      const load_command* cmd = 
     322         reinterpret_cast<const load_command*>( 
     323            reinterpret_cast<const char*>(header) + sizeof(mach_header) 
     324         ); 
     325 
     326      for ( unsigned int index = 0; 
     327            index < header->ncmds; 
     328            ++index, cmd = reinterpret_cast<const load_command*>(reinterpret_cast<const char*>(cmd) + cmd->cmdsize) ) 
     329      { 
     330         switch (cmd->cmd) 
     331         { 
     332            case LC_SEGMENT: 
     333               if ( ! strncmp(reinterpret_cast<const segment_command*>(cmd)->segname, SEG_TEXT, 16) ) 
     334               { 
     335                  seg_text = reinterpret_cast<const segment_command*>(cmd); 
     336               } 
     337               else if ( ! strncmp(reinterpret_cast<const segment_command*>(cmd)->segname, SEG_LINKEDIT, 16) ) 
     338               { 
     339                  seg_linkedit = reinterpret_cast<const segment_command*>(cmd); 
     340               } 
     341               break; 
     342             
     343            case LC_SYMTAB: 
     344               symtab = reinterpret_cast<const symtab_command*>(cmd); 
     345               break; 
     346         } 
     347      } 
     348       
     349      if ( seg_text == NULL || seg_linkedit == NULL || symtab == NULL ) 
     350      { 
     351         *offset = 0; 
     352         return NULL; 
     353      } 
     354 
     355      size_t vm_slide = reinterpret_cast<size_t>(header) - seg_text->vmaddr; 
     356      const size_t file_slide = (seg_linkedit->vmaddr - seg_text->vmaddr) - 
     357                                   seg_linkedit->fileoff; 
     358      struct nlist* symbase = 
     359         reinterpret_cast<struct nlist*>( 
     360            reinterpret_cast<size_t>(header) + symtab->symoff + file_slide 
     361         ); 
     362      char* strings = 
     363         reinterpret_cast<char*>( 
     364            reinterpret_cast<size_t>(header) + symtab->stroff + file_slide 
     365         ); 
     366       
     367      // Look for a global symbol. 
     368      unsigned int index; 
     369      struct nlist* sym(NULL); 
     370      for ( index = 0, sym = symbase; index < symtab->nsyms; ++index, ++sym ) 
     371      { 
     372         if ( sym->n_type != N_FUN ) 
     373         { 
     374            continue; 
     375         } 
     376 
     377         char* name = sym->n_un.n_strx ? (strings + sym->n_un.n_strx) : NULL; 
     378         const unsigned int base = sym->n_value + vm_slide; 
     379 
     380         for ( index += 1, sym += 1; index < symtab->nsyms; ++index, ++sym ) 
     381         { 
     382            if ( sym->n_type == N_FUN ) 
     383            { 
     384               break; 
     385            } 
     386         } 
     387 
     388         if ( pc >= base  &&  pc <= (base + sym->n_value) && name != NULL && 
     389              std::strlen(name) > 0 ) 
     390         { 
     391            *offset = pc - base; 
     392            return std::string(name); 
     393         } 
     394      } 
     395 
     396      // Look for a reasonably close private symbol. 
     397      char* name; 
     398      unsigned int base; 
     399      for ( name = NULL, base = 0xFFFFFFFF, index = 0, sym = symbase; 
     400            index < symtab->nsyms; 
     401            ++index, ++sym ) 
     402      { 
     403         if ( (sym->n_type & 0x0E) != 0x0E ) 
     404         { 
     405            continue; 
     406         } 
     407 
     408         if ( (sym->n_value + vm_slide) > pc ) 
     409         { 
     410            continue; 
     411         } 
     412 
     413         if ( base != 0xFFFFFFFF && 
     414              (pc - (sym->n_value + vm_slide)) >= (pc - base) ) 
     415         { 
     416            continue; 
     417         } 
     418 
     419         name = sym->n_un.n_strx ? (strings + sym->n_un.n_strx) : NULL; 
     420         base = sym->n_value + vm_slide; 
     421      } 
     422 
     423      *offset = pc - base; 
     424      return (name != NULL) ? std::string(name) : std::string(); 
     425   } 
     426    
     427   *offset = 0; 
     428   return std::string(); 
     429} 
     430#endif  /* VPR_OS_Darwin */ 
    250431 
    251432} 
     
    263444   char** strings; 
    264445 
    265    pid_t cur_pid = getpid(); 
    266446   size = backtrace(trace_syms, 100); 
    267447   strings = backtrace_symbols(trace_syms, size); 
    268448 
    269449   std::ostringstream trace_stream; 
    270    trace_stream << "Stack trace: thread: " << cur_pid << std::endl; 
     450   trace_stream << "Stack trace for process: " << getpid() << std::endl; 
    271451 
    272452   for (size_t i = 0; i < size; ++i) 
     
    277457 
    278458   free(strings); 
     459 
     460   ret_stack = trace_stream.str(); 
     461#elif defined(VPR_OS_Darwin) 
     462#if defined(__ppc__) || defined(__ppc64__) 
     463   struct StackFrame 
     464   { 
     465      unsigned int savedSP; 
     466      unsigned int savedCR; 
     467      unsigned int savedLR; 
     468      unsigned int reserved[2]; 
     469      unsigned int savedRTOC; 
     470   }; 
     471#elif defined(__i386__) 
     472   struct StackFrame 
     473   { 
     474      unsigned int savedSP; 
     475      unsigned int savedLR; 
     476   }; 
     477#else 
     478#error Unknown platform 
     479#endif 
     480 
     481   std::ostringstream trace_stream; 
     482   trace_stream << "Stack trace for process: " << getpid() << std::endl; 
     483 
     484   std::vector<CrawlFrame> stack; 
     485   StackFrame* frame(NULL); 
     486 
     487#if defined(__ppc__) || defined(__ppc64__) 
     488   frame = *(StackFrame**) __builtin_frame_address(0); 
     489#elif defined(__i386__) 
     490   frame = (StackFrame*) __builtin_frame_address(0); 
     491#endif 
     492 
     493   for ( ; frame != NULL; frame = (StackFrame*) frame->savedSP) 
     494   { 
     495      if ( (frame->savedLR & ~3) == 0 || (~(frame->savedLR) & ~3) == 0 ) 
     496      { 
     497         break; 
     498      } 
     499 
     500      CrawlFrame cur_frame; 
     501      cur_frame.pc    = frame->savedLR; 
     502      cur_frame.frame = reinterpret_cast<size_t>(frame); 
     503      cur_frame.name  = getFunctionName(frame->savedLR, &cur_frame.offset); 
     504 
     505      if ( cur_frame.pc != 0 ) 
     506      { 
     507         cur_frame.pc -= 4; 
     508      } 
     509 
     510      stack.push_back(cur_frame); 
     511   } 
     512 
     513   typedef std::vector<CrawlFrame>::reverse_iterator iter_type; 
     514   for ( iter_type i = stack.rbegin(); i != stack.rend(); ++i ) 
     515   { 
     516      std::string func_name("(unknown)"); 
     517 
     518      if ( ! (*i).name.empty() ) 
     519      { 
     520         typedef std::string::size_type size_type; 
     521         const size_type name_len((*i).name.size()); 
     522         for ( size_type j = 0; j < name_len; ++j ) 
     523         { 
     524            bool objc(false); 
     525            if ( j == 1  &&  (*i).name[j] == '[' ) 
     526            { 
     527               objc = true; 
     528            } 
     529 
     530            if ( objc && (*i).name[j] == ']' ) 
     531            { 
     532               objc = false; 
     533            } 
     534 
     535            if ( ! objc && (*i).name[j] == ':' ) 
     536            { 
     537               break; 
     538            } 
     539         } 
     540 
     541         std::ostringstream func_stream; 
     542         func_stream << (*i).name << "+" << std::hex << (*i).offset; 
     543         func_name = func_stream.str(); 
     544      } 
     545 
     546      const char fill_char(trace_stream.fill()); 
     547      const std::ios::fmtflags fmt_flags(trace_stream.flags()); 
     548      trace_stream.fill('0'); 
     549      trace_stream.setf(std::ios::uppercase); 
     550      trace_stream.setf(std::ios::hex | std::ios::right, 
     551                        std::ios::adjustfield | std::ios::basefield); 
     552      trace_stream << "  " << std::setw(sizeof(void*) * 2) << (*i).frame 
     553                   << "  " << std::setw(sizeof(void*) * 2) << (*i).pc; 
     554      trace_stream.flags(fmt_flags); 
     555      trace_stream.fill(fill_char); 
     556      trace_stream << "  " << func_name << std::endl; 
     557   } 
    279558 
    280559   ret_stack = trace_stream.str();