// balst_stacktraceresolverimpl_xcoff.h -*-C++-*- // ---------------------------------------------------------------------------- // NOTICE // // This component is not up to date with current BDE coding standards, and // should not be used as an example for new development. // ---------------------------------------------------------------------------- #ifndef INCLUDED_BALST_STACKTRACERESOLVERIMPL_XCOFF #define INCLUDED_BALST_STACKTRACERESOLVERIMPL_XCOFF #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a mechanism to resolve xcoff symbols in a stack trace. // //@CLASSES: // balst::StackTraceResolverImpl<Xcoff>: symbol resolution for Xcoff objects // //@SEE_ALSO: balst_stacktraceresolverimpl_elf, // balst_stacktraceresolverimpl_windows // //@DESCRIPTION: This component provides a class, // balst::StackTraceResolver<Xcoff>, that, given a vector of // 'balst::StackTraceFrame's that have only their 'address' fields set, // resolves all other fields in those frames. Xcoff objects are used on AIX // platforms. // ///Inline Functions ///---------------- // Inline functions and template functions that are, in fact, called out of // line are handled properly. Functions that are inlined are not represented // in the stack trace, and the stack frames of the functions that called them // do not have their line number information populated. // ///Usage ///----- // This component is an implementation detail of 'balst' and is *not* intended // for direct client use. It is subject to change without notice. As such, a // usage example is not provided. #include <balscm_version.h> #include <balst_objectfileformat.h> #if defined(BALST_OBJECTFILEFORMAT_RESOLVER_XCOFF) #include <balst_stacktrace.h> #include <balst_stacktraceframe.h> #include <balst_stacktraceresolver_filehelper.h> #include <bslmt_qlock.h> #include <bdlma_heapbypassallocator.h> #include <bdls_filesystemutil.h> #include <bsls_assert.h> #include <bsls_types.h> #include <bslma_allocator.h> struct syment; // defined in imp by included file '<syms.h>' union auxent; // defined in imp by included file '<syms.h>' namespace BloombergLP { namespace balst { template <typename RESOLVER_POLICY> class StackTraceResolverImpl; // ===================================================== // class StackTraceResolverImpl<ObjectFileFormat::Xcoff> // ===================================================== template <> class StackTraceResolverImpl<ObjectFileFormat::Xcoff> { // This class is for resolving symbols in Xcoff executables. Given a // vector of 'StackTraceFrame's that have only their 'address' fields // set, it resolves all other fields in those frames. Xcoff objects are // used on AIX platforms. Note that all methods, including the // constructor, are private except for that static method 'resolve' which // constructs and destroys the object. public: // PUBLIC TYPES typedef bsls::Types::IntPtr IntPtr; // 32 bit signed on 32 bit, 64 bit // signed on 64 bit typedef bsls::Types::UintPtr UintPtr; // 32 bit unsigned on 32 bit, 64 bit // unsigned on 64 bit typedef bsls::Types::Int64 Int64; typedef bsls::Types::Uint64 Uint64; typedef bdls::FilesystemUtil::Offset // Usually used for offsets in a Offset; // file, absolute or relative. private: // TYPES struct AuxInfo; // Internal -- fleshed out in the // implementation file struct LoadAuxInfosInfo; // Internal -- fleshed out in the // implementation file enum FindIncludeFileFlags { // flags returned by 'findIncludeFile' k_USE_INCLUDE_SOURCE_FILE_NAME = 0x1, k_SUPPRESS_LINE_NUMBER = 0x2 }; // DATA StackTraceResolver_FileHelper *d_helper; // helper for reading files StackTrace *d_stackTrace_p; // pointer to stack trace object // to be populated by resolution. // Note only the 'address' fields // are initialized at the start, // our goal is to initialize all // the other fields. Held, not // owned. StackTraceFrame **d_segFramePtrs_p; // pointers to stack trace frames // contained in 'd_stackTrace_p' // listing only those frames // whose 'address' fields point // into the current segment const void **d_segAddresses_p; // the 'address' fields from // 'd_segFramePtrs_p' in 1-1 // correspondence, note this // duplication of information is // a performance optimization AuxInfo *d_segAuxInfos_p; // array of aux infos (AuxInfo is // a struct private to this // class, defined in the imp) in // 1-1 correspondence with the // entries of 'd_segFramePtrs_p' int d_numCurrAddresses;// number of 'address' fields in // 'd_stackTrace_p' that point // into the current segment, also // the length of // 'd_segFramePtrs_p', // 'd_segAddresses_p', and // 'd_segAuxInfos_p', note all 3 // are allocated to have // 'd_stackTrace_p->length()' // (worst case) length char *d_scratchBuf_p; // scratch buffer char *d_symbolBuf_p; // buffer for reading symbols Offset d_virtualToPhysicalOffset; // translation from an address // given in the file to an // address in memory for the // current segment Offset d_archiveMemberOffset; // archive member offset, or 0 if // the segment is not an archive // member Offset d_archiveMemberSize; // archive member size, or size // of the whole file if the // segment is not an archive // member Offset d_symTableOffset; // absolute offset of symbol // table in the current file Offset d_stringTableOffset; // absolute offset of string // table in the current file bool d_demangle; // flag indicating whether // demangling is to be done bdlma::HeapBypassAllocator d_hbpAlloc; // heap bypass allocator, all // memory allocated by this // object will be freed when this // allocator is destroyed. static bslmt::QLock s_demangleQLock; // 'QLock' to guard access to // the non-thread-safe 'Demangle' // function. private: // NOT IMPLEMENTED StackTraceResolverImpl(const StackTraceResolverImpl&); StackTraceResolverImpl& operator=(const StackTraceResolverImpl&); // PRIVATE CREATORS StackTraceResolverImpl(StackTrace *stackTrace, bool demangle); // Create an stack trace reolver that can populate other fields of the // specified 'stackFrames' object given previously populated 'address' // fields. Specify 'demangle', which indicates whether demangling of // symbols is to occur, and 'basicAllocator', which is to be used for // memory allocation. Note that the behavior is undefined if // 'basicAllocator' is 0 or unspecified, the intention is that it // should be of type 'bdema::HeapByPassAllocator'. ~StackTraceResolverImpl(); // Destroy this stack trace resolver object. // PRIVATE MANIPULATORS bslma::Allocator *allocator(); // Return a pointer to this object's heap bypass allocator. int findArchiveMember(const char *memberName); // Locate the archive member with the specified 'memberName' in the // current archive file and save the member's offset from the beginning // of the archive and the member's size. Return zero on success, and a // negative value otherwise. Note that this is never called on an // executable, only on archives. Offset findCsectIndex(const char *symbolAddress, const char *csectEndAddress, Offset primarySymIndex); // Iterate through all the addresses in d_segAddresses_p, returning the // specified 'primarySymIndex', which is the index of the current // symbol, if any of them are in the range // '[symbolAddress, csectEndAddress)' and 'UintPtr(-1)' otherwise. int findIncludeFile(syment *includeSymEnt, Offset firstLineNumberOffset, Offset lineNumberOffset, Offset symStartIndex, Offset symEndIndex); // Read the portion of the symbol table of the current segment starting // at the specified 'symStartIndex' and ending at the specified // 'symEndIndex' to determine if the specified 'lineNumberOffset' is in // an include file. Return a positive value which is a bitwise or of // the appropriate 'FindIncludeFileFlags' if found, 0 if not found, and // a negative value if an error is encountered. The positive value // returned on success is a bitwise or of the flags defined by enum // 'FindIncludeFileFlags' defined in the class, indicating whether the // file was found, and whether the line number we have (which is not // passed to this routine) is absolute or relative. Note that the line // numbers corresponding to include files are sometimes absolute, while // other line numbers are relative to the beginning of the function in // which they occur. Also note that this routine is called immediately // after 'findLineNumber'. int findLineNumber(int *outLineNumber_p, Offset *outLineNumberOffset_p, Offset lineBufStartOffset, const void *segAddress); // Find a line number and line number offset of the source that refers // to the specified 'address', and load the results into the specified // '*outLineNumber_p' and '*outLineNumberOffset_p'. Begin the search // at the specified 'lineBufStartOffset' in the file and end either at // the end of that function, at the end of the archive member, or the // end of the file. Return zero on success, and a nonzero value // otherwise. Note that the line number may be either relative to the // beginning of the function, or absolute (see 'findIncludeFile'). // Note that 'lineBufStartOffset' points to the beginning of line // number records describing the function containing the code // 'segAddress' refers to. void loadAuxInfos(const LoadAuxInfosInfo *laiInfo, const char *functionBeginAddress, const char *functionEndAddress); // Iterate through 'd_segAddresses_p' and, for each address that refers // to code in the function specified by 'functionBeginAddress' and // 'functionEndAddress', initialize the 'offsetFromSymbol' field of the // corresponding stack trace frame, and initialize the corresponding // 'AuxInfo' struct with information from variables local to the // calling 'loadSymbols' function accessed through pointers in the // specified 'laiInfo' struct. int loadSymbols(Offset numSyms, int textSectionNum); // Read the specified 'numSym' symbols from the symbol table associated // with this segment, skipping those symbols not associated with the // text section indicated by the specified 'textSectionNum'. Return 0 // on success and a non-zero value otherwise. const char *getSourceName(const auxent *sourceAuxent); // Allocate memory for, and return a pointer to, a string containing // the name of the source file referred to by the specified // 'sourceAuxent'. const char *getSymbolName(const syment *sourceSyment); // Allocate memory for, and return a pointer to, a string containing // the name of the symbol defined by the specified 'sourceSyment'. // Note the symbol is sometimes a function name, sometimes a source // file name. int resolveSegment(void *segmentPtr, UintPtr segmentSize, const char *libraryFileName, const char *displayFileName, const char *archiveMemberName); // Populate those stack trace frames whose 'address' fields reside // within the segment specfied by 'segmentPtr' and 'segmentSize'. The // segment is in the specified 'libraryFileName', with the specified // 'archiveMemberName'. Specify the 'displayFileName' used to identify // the library file name in the stack trace. Note that // 'displayFileName' may be different from 'libraryFileName' because // AIX truncates the filename of the executable file to be 32 chars // long, so we use another means to open the executable file. Note // that if 'archiveMemberName' is unspecified, the whole library file // has a single segment. public: // PUBLIC CLASS METHODS static int resolve(StackTrace *stackTrace, bool demangle); // Populate information for the specified 'stackFrames', a vector of // stack trace frames in a stack trace object. Specify 'demangle', to // determine whether demangling is to occur, and 'basicAllocator', // which is to be used for memory allocation. The behavior is // undefined unless all the 'address' field in 'stackFrames' are valid // and other fields are invalid, and 'basicAllocator != 0'. static inline int testFunc(); // For testing only. Do some random garbage and return a line number // from within the routine. }; // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // ---------------------------- // class StackTraceResolverImpl // ---------------------------- // PRIVATE MANIPULATORS inline bslma::Allocator *StackTraceResolverImpl<ObjectFileFormat::Xcoff>::allocator() { return &d_hbpAlloc; } // CLASS METHODS inline int StackTraceResolverImpl<ObjectFileFormat::Xcoff>::testFunc() { // Do some random garbage to generate some code, then return a line number // within this routine int line = 0, lineCopy = 0; for (int i = 0; true; ++i) { BSLS_ASSERT_OPT(line == lineCopy); const int loopGuard = 0x8edf0000; // garbage with a lot of trailing // 0's. const int mask = 0xa72c3dca; // pure garbage enum { k_LINE = __LINE__ }; for (int i = 0; !(i & loopGuard); ++i) { line ^= (i & mask); } // The above loop will leave the value of 'line' unchanged. BSLS_ASSERT_OPT(line == lineCopy); if (line != 0) { break; } line = k_LINE; lineCopy = line; } return line; } } // close package namespace } // close enterprise namespace #endif #endif // ---------------------------------------------------------------------------- // Copyright 2015 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------