Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:49:30

0001 #pragma once
0002 
0003 /**
0004 SBacktrace
0005 ===========
0006 
0007 
0008 
0009 https://oroboro.com/stack-trace-on-crash/
0010 https://panthema.net/2008/0901-stacktrace-demangled/cxa_demangle.html
0011 
0012 https://eli.thegreenplace.net/2015/programmatic-access-to-the-call-stack-in-c/
0013 
0014    suggests libunwind
0015 
0016 
0017 Utilities for dumping process backtraces.
0018 
0019 Using the addresses in the debugger::
0020 
0021 
0022     (lldb) source list -a 0x0000000101f1be26
0023     /usr/local/opticks_externals/g4_1042/lib/libG4tracking.dylib`G4SteppingManager::DefinePhysicalStepLength() + 1334 at /usr/local/opticks_externals/g4_1042.build/geant4.10.04.p02/source/tracking/src/G4SteppingManager2.cc:251
0024        246                                      &fGPILSelection );
0025        247  #ifdef G4VERBOSE
0026        248                           // !!!!! Verbose
0027        249       if(verboseLevel>0) fVerbose->DPSLAlongStep();
0028        250  #endif
0029     -> 251       if(physIntLength < PhysicalStep){
0030        252         PhysicalStep = physIntLength;
0031        253
0032        254         // Check if the process wants to be the GPIL winner. For example,
0033        255         // multi-scattering proposes Step limit, but won't be the winner.
0034        256         if(fGPILSelection==CandidateForSelection){
0035     (lldb)
0036 
0037 
0038 
0039 
0040 **/
0041 
0042 
0043 #include "SYSRAP_API_EXPORT.hh"
0044 #include <ostream>
0045 
0046 struct SYSRAP_API SBacktrace
0047 {
0048     static void Dump();
0049     static void DumpCaller();
0050     static void DumpSummary();
0051 
0052     static void Dump(std::ostream& out) ;
0053     static void DumpCaller(std::ostream& out) ;
0054     static void DumpSummary(std::ostream& out) ;
0055 
0056     static bool SummaryMatch(const char* x_summary);
0057     static char* Summary();
0058 
0059     static const char* CallSite(const char* call="::flat()" , bool addr=true );
0060 };
0061 
0062 
0063 
0064 
0065 #include <cstdio>
0066 #include <cstdlib>
0067 #include <string.h>
0068 #include <ostream>
0069 #include <iostream>
0070 #include <sstream>
0071 
0072 #include "SStackFrame.h"
0073 
0074 #include <execinfo.h>
0075 #include <errno.h>
0076 
0077 inline void SBacktrace::Dump()
0078 {
0079     std::ostream& out = std::cout ;
0080     Dump(out);
0081 }
0082 inline void SBacktrace::DumpCaller()
0083 {
0084     std::ostream& out = std::cout ;
0085     DumpCaller(out);
0086 }
0087 inline void SBacktrace::DumpSummary()
0088 {
0089     std::ostream& out = std::cout ;
0090     DumpSummary(out);
0091 }
0092 
0093 
0094 
0095 
0096 
0097 
0098 inline void SBacktrace::Dump(std::ostream& out)
0099 {
0100    enum { max_frames = 63 };
0101    void* addrlist[max_frames+1];
0102    unsigned addrlen = backtrace( addrlist, sizeof(addrlist)/sizeof(void*));
0103 
0104    out << "SBacktrace::Dump"
0105        << " addrlen " << addrlen
0106        << std::endl
0107        ;
0108 
0109    if(addrlen == 0) return;
0110 
0111    char** symbollist = backtrace_symbols( addrlist, addrlen );
0112 
0113    bool raw = false ;
0114    if(raw) for ( unsigned i = 0 ; i < addrlen; i++ )
0115        out << symbollist[i]
0116            << " : "
0117            << addrlist[i]
0118            << std::endl
0119            ;
0120 
0121    out << "SStackFrames..\n" ;
0122 
0123    for ( unsigned i = 0 ; i < addrlen; i++ )
0124    {
0125        SStackFrame f(symbollist[i]) ;
0126        f.dump(out);
0127    }
0128 
0129    free(symbollist);
0130 }
0131 
0132 
0133 /**
0134 SBacktrace::SummaryMatch
0135 --------------------------
0136 
0137 String matching with SBacktrace::Summary
0138 NB a complete match is not required it is only
0139 necessary for the *q_summary* to appear inside the
0140 backtrace summary. NB as the *q_summary* will normally
0141 contain newlines to delimit different levels of
0142 the callstack it is necessary to remove all trailing
0143 blanks. Use "set list" in vim to check the literal
0144 test *q_summary* strings.
0145 
0146 **/
0147 
0148 inline bool SBacktrace::SummaryMatch(const char* q_summary)
0149 {
0150     char* summary = Summary();
0151     return strstr( summary, q_summary ) != nullptr ;
0152 }
0153 
0154 /**
0155 SBacktrace::Summary
0156 --------------------
0157 
0158 For ease of use the Summary chops the arguments from stack frame signatures
0159 by terminating the signatire at the first '('
0160 
0161 **/
0162 
0163 inline char* SBacktrace::Summary()
0164 {
0165    enum { max_frames = 63 };
0166    void* addrlist[max_frames+1];
0167    unsigned addrlen = backtrace( addrlist, sizeof(addrlist)/sizeof(void*));
0168    if(addrlen == 0) return nullptr ;
0169 
0170    std::stringstream ss ;
0171    char** symbollist = backtrace_symbols( addrlist, addrlen );
0172    for ( unsigned i = 0 ; i < addrlen; i++ )
0173    {
0174        SStackFrame f(symbollist[i]) ;
0175        if(f.smry) ss << f.smry << std::endl ;
0176    }
0177    free(symbollist);
0178    std::string s = ss.str();
0179    return strdup(s.c_str());
0180 }
0181 
0182 inline void SBacktrace::DumpSummary(std::ostream& out)
0183 {
0184     char* summary = Summary();
0185     out << summary << std::endl ;
0186 }
0187 
0188 inline void SBacktrace::DumpCaller(std::ostream& out)
0189 {
0190     const char* caller = CallSite("::flat") ;
0191     out << "SBacktrace::DumpCaller " << caller << std::endl ;
0192 }
0193 
0194 
0195 
0196 /**
0197 SBacktrace::CallSite
0198 ---------------------
0199 
0200 For a call stack like the below with call "::flat()" return the line starting with 3::
0201 
0202     SStackFrames..
0203     0   libSysRap.dylib                     0x000000010b991662 SBacktrace::Dump()                                                                                   + 114
0204     1   libCFG4.dylib                       0x000000010026909d CMixMaxRng::flat()                                                                                   + 445
0205     2   libCFG4.dylib                       0x0000000100269169 non-virtual thunk to CMixMaxRng::flat()                                                              + 25
0206     3   libG4processes.dylib                0x0000000102ba3ee5 G4VEmProcess::PostStepGetPhysicalInteractionLength(G4Track const&, double, G4ForceCondition*)        + 661
0207     4   libG4tracking.dylib                 0x00000001023e8ff0 G4VProcess::PostStepGPIL(G4Track const&, double, G4ForceCondition*)                                  + 80
0208     5   libG4tracking.dylib                 0x00000001023e8a1a G4SteppingManager::DefinePhysicalStepLength()                                                        + 298
0209     6   libG4tracking.dylib                 0x00000001023e5c3a G4SteppingManager::Stepping()                                                                        + 394
0210 
0211 
0212 **/
0213 
0214 inline const char* SBacktrace::CallSite(const char* call, bool addr )
0215 {
0216    const char* site = NULL ;
0217    enum { max_frames = 63 };
0218    void* addrlist[max_frames+1];
0219    unsigned addrlen = backtrace( addrlist, sizeof(addrlist)/sizeof(void*));
0220    if(addrlen == 0) return site ;
0221 
0222    char** symbollist = backtrace_symbols( addrlist, addrlen );
0223    int state = -1 ;
0224    for ( unsigned i = 0 ; i < addrlen; i++ )
0225    {
0226        SStackFrame f(symbollist[i]) ;
0227        //f.dump();
0228 
0229        char* p = f.func ? strstr( f.func, call ) : NULL ;
0230        if(p) state++ ;
0231 
0232        if(!p && state > -1 )    // pick first line without call string following a line with it
0233        {
0234            char out[256];
0235            if(addr)
0236            {
0237                snprintf( out, 256, "%16p %10s %s", addrlist[i], f.offset, f.func ) ;
0238                // addresses different for each executable so not good for comparisons, but real handy
0239                // for looking up source line in debugger with :
0240                //      (lldb) source list  -a 0x000...
0241            }
0242            else
0243            {
0244                snprintf( out, 256, " %10s %s", f.offset, f.func ) ;
0245            }
0246            site = strdup(out) ;
0247            break ;
0248        }
0249    }
0250 
0251    free(symbollist);
0252    return site ;
0253 }
0254 
0255 
0256