// balst_stacktraceframe.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_STACKTRACEFRAME #define INCLUDED_BALST_STACKTRACEFRAME #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide an attribute class describing an execution stack frame. // //@CLASSES: // balst::StackTraceFrame: a description of one frame of an execution stack // //@SEE_ALSO: balst_stacktrace // //@DESCRIPTION: This component provides a single, simply-constrained // (value-semantic) attribute class, 'balst::StackTraceFrame', that describes // a stack frame from the execution stack of a function call. Additional // methods are provided to indicate whether a given attribute is considered // "unknown". // ///Attributes ///---------- //.. // Name Type Default Constraint // ----------------- ----------- ---------- ---------- // address const void * 0 none // libraryFileName bsl::string "" none // lineNumber int -1 'lineNumber >= -1' // mangledSymbolName bsl::string "" none // offsetFromSymbol bsl::size_t (size_t)-1 none // sourceFileName bsl::string "" none // symbolName bsl::string "" none //.. //: o address: the return address in the *parent* (calling) function //: on return from the *child* (called) function. //: //: o libraryFileName: the executable or shared-library file name //: containing the parent function. //: //: o lineNumber: the source line number in the parent function corresponding, //: corresponding to a call to the child function. //: //: o mangledSymbolName: mangled symbol name of the parent function (in C code, //: the "mangled" name matches the symbol name.) //: //: o offsetFromSymbol: offset from the start of the parent function to the //: call to the child function. //: //: o sourceFileName: Name of the source file of the parent function. //: //: o symbolName: unmangled symbol name of the parent function (in C, code //: symbol name matches the mangled symbol name.) // ///Unknown Values ///-------------- // For each attribute, a particular value is reserved to designate that the // attribute value is "unknown". Default constructed objects are created with // the designated "unknown" value for each attribute. // ///Supplementary Methods ///--------------------- // In addition to the usual setters and getters, the 'balst::StackTraceFrame' // attribute class provides also provides a suite of non-'static', // (boolean-valued) *predicate* methods, of the form 'is<attributeName>Known'. // Each of these return 'true' if the object attribute named by the method does // *not* contain the designated "unknown" value for that attribute, and 'false' // otherwise. // ///Usage ///----- // In this example, we create two 'balst::StackTraceFrame' objects, modify // their properties, and compare them. First, we create the objects 'a' and // 'b': //.. // balst::StackTraceFrame a, b; // assert(a == b); //.. // Then, we verify all values are initialized by the constructor to "unknown" // values: //.. // assert(false == a.isAddressKnown()); // assert(false == a.isLibraryFileNameKnown()); // assert(false == a.isLineNumberKnown()); // assert(false == a.isMangledSymbolNameKnown()); // assert(false == a.isOffsetFromSymbolKnown()); // assert(false == a.isSourceFileNameKnown()); // assert(false == a.isSymbolNameKnown()); //.. // Next, we assign a value to the 'lineNumber' attribute of 'a' and verify: //.. // a.setLineNumber(5); // assert(true == a.isLineNumberKnown()); // assert(5 == a.lineNumber()); // assert(a != b); //.. // Next, make the same change to 'b' and thereby restore it's equality to 'a': //.. // b.setLineNumber(5); // assert(true == b.isLineNumberKnown()); // assert(5 == b.lineNumber()); // assert(a == b); //.. // Next, we update the 'address' attribute of 'a' and use the 'address' // accessor method to obtain the new value for the update of 'b': //.. // a.setAddress((char *) 0x12345678); // assert(a != b); // // b.setAddress(a.address()); // assert(true == a.isAddressKnown()); // assert(true == b.isAddressKnown()); // assert((char *) 0x12345678 == a.address()); // assert((char *) 0x12345678 == b.address()); // assert(a.address() == b.address()); // assert(a == b); //.. // Finally, we exercise this sequence of operations for two other attributes, // 'symbolName' and 'sourceFileName': //.. // a.setSymbolName("woof"); // assert(a != b); // // b.setSymbolName(a.symbolName()); // assert(true == a.isSymbolNameKnown()); // assert(true == b.isSymbolNameKnown()); // assert(0 == bsl::strcmp("woof", a.symbolName().c_str())); // assert(0 == bsl::strcmp("woof", b.symbolName().c_str())); // assert(a == b); // // a.setSourceFileName("woof.cpp"); // assert(a != b); // b.setSourceFileName(a.sourceFileName()); // assert(a.isSourceFileNameKnown()); // assert(b.isSourceFileNameKnown()); // assert(0 == bsl::strcmp("woof.cpp", a.sourceFileName().c_str())); // assert(0 == bsl::strcmp("woof.cpp", b.sourceFileName().c_str())); // assert(a == b); //.. #include <balscm_version.h> #include <bslalg_swaputil.h> #include <bslma_allocator.h> #include <bslma_usesbslmaallocator.h> #include <bslmf_nestedtraitdeclaration.h> #include <bsls_assert.h> #include <bsls_review.h> #include <bsl_cstddef.h> // bsl::size_t #include <bsl_iosfwd.h> #include <bsl_string.h> #ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #include <bslalg_typetraits.h> #include <bsl_algorithm.h> #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES namespace BloombergLP { namespace balst { // ===================== // class StackTraceFrame // ===================== class StackTraceFrame { // This simply constrained (value-semantic) attribute class describes a // call frame created on the execution stack when a *parent* function calls // a *child* function. Supplementary predicate methods indicate whether a // given attribute value is considered "unknown". See the Attributes // section under @DESCRIPTION in the component-level documentation. Note // that the class invariants are identically the constraints on the // individual attributes. private: // DATA const void *d_address; // return address in the parent // on completion of the child // function, if known, and 0 // otherwise bsl::string d_libraryFileName; // name of the executable file or // shared library, where the code // referred to by 'd_address' // resides, if known, and "" // otherwise int d_lineNumber; // line number in the source file // corresponding to 'd_address', // if known, and -1 otherwise bsl::string d_mangledSymbolName; // mangled name of the parent // function, if known, and "" // otherwise bsl::size_t d_offsetFromSymbol; // offset (in bytes) of 'd_address' // from the start of the parent // function, if known, and // '(bsl::size_t)-1' otherwise. bsl::string d_sourceFileName; // name of the source file of the // parent function, if known, and "" // otherwise bsl::string d_symbolName; // name of the parent function, if // known, and "" otherwise public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(StackTraceFrame, bslma::UsesBslmaAllocator); // CREATORS explicit StackTraceFrame(bslma::Allocator *basicAllocator = 0); // Create a 'StackTraceFrame' object having the (default) // attribute values: //.. // address == 0 // libraryFileName == "" // lineNumber == -1 // mangledSymbolName == "" // offsetFromSymbol == (size_t)-1 // sourceFileName == "" // symbolName == "" //.. // Optionally specify a 'basicAllocator' used to supply memory. If // 'basicAllocator' is 0, the currently installed default allocator is // used. StackTraceFrame(const void *address, const bsl::string_view& libraryFileName, int lineNumber, const bsl::string_view& mangledSymbolName, bsl::size_t offsetFromSymbol, const bsl::string_view& sourceFileName, const bsl::string_view& symbolName, bslma::Allocator *basicAllocator = 0); // Create a local time descriptor object having the specified // 'address', 'libraryFileName', 'lineNumber', 'mangledSymbolName', // 'offsetFromSymbol', 'sourceFileName', and 'symbolName' attribute // values. Optionally specify a 'basicAllocator' used to supply // memory. If 'basicAllocator' is 0, the currently installed default // allocator is used. The behavior is undefined unless // '-1 <= lineNumber'. StackTraceFrame(const StackTraceFrame& original, bslma::Allocator *basicAllocator = 0); // Create a 'StackTraceFrame' object having the same value as the // specified 'original' object. Optionally specify a 'basicAllocator' // used to supply memory. If 'basicAllocator' is 0, the currently // installed default allocator is used. ~StackTraceFrame(); // Destroy this object. // MANIPULATORS StackTraceFrame& operator=(const StackTraceFrame& rhs); // Assign to this object the value of the specified 'rhs' object, and // return a reference providing modifiable access to this object. void setAddress(const void *value); // Set the 'address' attribute of this object to the specified 'value'. // Note that the value '(void *)0)' indicates that 'address' is // "unknown". void setLibraryFileName(const bsl::string_view& value); // Set the 'libraryFileName' attribute of this object to the specified // 'value'. Note that the empty string indicates the 'libraryFileName' // is "unknown". void setLineNumber(int value); // Set the 'lineNumber' attribute of this object to the specified // 'value'. The behavior is undefined unless '-1 <= value'. Note that // the value -1 indicates the 'lineNumber' is "unknown". void setMangledSymbolName(const bsl::string_view& value); // Set the 'mangledSymbolName' attribute of this object to the // specified 'value'. Note that the empty string indicates that the // 'mangledSymbolName' is "unknown". void setOffsetFromSymbol(bsl::size_t value); // Set the 'offsetFromSymbol' attribute of this object to the specified // 'value'. Note that the value '(bsl::size_t)-1' indicates that // 'offsetFromSymbol' is "unknown". void setSourceFileName(const bsl::string_view& value); // Set the 'sourceFileName' attribute of this object to the specified // 'value'. Note that the empty string indicates that 'sourceFileName' // is "unknown". void setSymbolName(const bsl::string_view& value); // Set the 'symbolName' attribute of this object to the specified // 'value'. Note that the empty string indicates that 'symbolName' is // "unknown". // Aspects void swap(StackTraceFrame& other); // Efficiently exchange the value of this object with the value of the // specified 'other' object. This method provides the no-throw // exception-safety guarantee. The behavior is undefined unless this // object was created with the same allocator as 'other'. // ACCESSORS const void *address() const; // Return the value of 'address' attribute of this object. Note that // '(void *)0' indicates that the 'address' is "unknown". const bsl::string& libraryFileName() const; // Return a reference providing non-modifiable access to the // 'libraryFileName' attribute of this object. Note the empty string // indicates that the 'libraryFileName' is "unknown". int lineNumber() const; // Return the value of the 'lineNumber' attribute of this object. Note // that -1 indicates that 'lineNumber' is "unknown". const bsl::string& mangledSymbolName() const; // Return a reference providing non-modifiable access to the // 'mangledSymbolName' attribute of this object. Note that the empty // string indicates that 'mangledSymbolName' is "unknown". bsl::size_t offsetFromSymbol() const; // Return the value of the 'offsetFromSymbol' attribute of this object. // Note that '(bsl::size_t)-1' indicates that 'lineNumber' is not // known. const bsl::string& sourceFileName() const; // Return a reference providing non-modifiable access to the // 'sourceFileName' attribute of this object. Note that the empty // string indicates that 'sourceFileName' is "unknown". const bsl::string& symbolName() const; // Return a reference providing non-modifiable access to the // 'symbolName' attribute of this object. Note that the empty string // indicates that 'symbolName' is "unknown". // Predicates bool isAddressKnown() const; // Return 'true' if the 'setAddress' attribute of this object is not // the "unknown" value for that attribute, and 'false' otherwise. bool isLibraryFileNameKnown() const; // Return 'true' if the 'libraryFileName' attribute of this object is // not the "unknown" value for that attribute, and 'false' otherwise. bool isLineNumberKnown() const; // Return 'true' if the 'lineNumber' attribute of this object is not // the "unknown" value for that attribute, and 'false' otherwise. bool isMangledSymbolNameKnown() const; // Return 'true' if the 'mangledSymbolName' attribute of this object is // not the "unknown" value for that attribute, and 'false' otherwise. bool isOffsetFromSymbolKnown() const; // Return 'true' if the 'offsetFromSymbol' attribute of this object is // not the "unknown" value for that attribute, and 'false' otherwise. bool isSourceFileNameKnown() const; // Return 'true' if the 'sourceFileName' attribute of this object is // not the "unknown" value for that attribute, and 'false' otherwise. bool isSymbolNameKnown() const; // Return 'true' if the 'symbolName' attribute of this object is not // the "unknown" value for that attribute, and 'false' otherwise. // Aspects bslma::Allocator *allocator() const; // Return the allocator used by this object to supply memory. Note // that if no allocator was supplied at construction the currently // installed default allocator is used. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Write the value of this object to the specified output 'stream' in a // human-readable format, and return a reference to 'stream'. // Optionally specify an initial indentation 'level', whose absolute // value is incremented recursively for nested objects. If 'level' is // specified, optionally specify 'spacesPerLevel', whose absolute value // indicates the number of spaces per indentation level for this and // all of its nested objects. If 'level' is negative, suppress // indentation of the first line. If 'spacesPerLevel' is negative, // format the entire output on one line, suppressing all but the // initial indentation (as governed by 'level'). If 'stream' is not // valid on entry, this operation has no effect. Note that the format // is not fully specified, and can change without notice. }; // FREE OPERATORS bool operator==(const StackTraceFrame& lhs, const StackTraceFrame& rhs); // Return 'true' if the specified 'lhs' and 'rhs' objects have the same // value, and 'false' otherwise. Two 'StackTraceFrame' objects // have the same value if the corresponding values of their 'address', // 'libraryFileName', 'lineNumber', 'mangledSymbolName', // 'offsetFromSymbol', 'sourceFileName', and 'symbolName' attributes are // the same. bool operator!=(const StackTraceFrame& lhs, const StackTraceFrame& rhs); // Return 'true' if the specified 'lhs' and 'rhs' objects do not have the // same value, and 'false' otherwise. Two 'StackTraceFrame' // objects do not have the same value if the corresponding values // of their 'address', 'libraryFileName', 'lineNumber', // 'mangledSymbolName', 'offsetFromSymbol', 'sourceFileName', or // 'symbolName' attributes are the not same. bsl::ostream& operator<<(bsl::ostream& stream, const StackTraceFrame& object); // Write the value of the specified 'object' to the specified output // 'stream' in a single-line format, and return a reference to 'stream'. // If 'stream' is not valid on entry, this operation has no effect. Note // that this human-readable format is not fully specified and can change // without notice. Also note that this method has the same behavior as // 'object.print(stream, 0, -1)', but with the attribute names elided. // FREE FUNCTIONS void swap(StackTraceFrame& a, StackTraceFrame& b); // Exchange the values of the specified 'a' and 'b' objects. This function // provides the no-throw exception-safety guarantee if the two objects were // created with the same allocator and the basic guarantee otherwise. // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // --------------------- // class StackTraceFrame // --------------------- // CREATORS inline StackTraceFrame::StackTraceFrame(bslma::Allocator *basicAllocator) : d_address(0) , d_libraryFileName(basicAllocator) , d_lineNumber(-1) , d_mangledSymbolName(basicAllocator) , d_offsetFromSymbol((bsl::size_t)-1) , d_sourceFileName(basicAllocator) , d_symbolName(basicAllocator) { } inline StackTraceFrame::StackTraceFrame(const void *address, const bsl::string_view& libraryFileName, int lineNumber, const bsl::string_view& mangledSymbolName, bsl::size_t offsetFromSymbol, const bsl::string_view& sourceFileName, const bsl::string_view& symbolName, bslma::Allocator *basicAllocator) : d_address(address) , d_libraryFileName(libraryFileName.begin(), libraryFileName.end(), basicAllocator) , d_lineNumber(lineNumber) , d_mangledSymbolName(mangledSymbolName.begin(), mangledSymbolName.end(), basicAllocator) , d_offsetFromSymbol(offsetFromSymbol) , d_sourceFileName(sourceFileName.begin(), sourceFileName.end(), basicAllocator) , d_symbolName(symbolName.begin(), symbolName.end(), basicAllocator) { BSLS_ASSERT(0 != libraryFileName.data()); BSLS_ASSERT(-1 <= lineNumber); BSLS_ASSERT(0 != mangledSymbolName.data()); BSLS_ASSERT(0 != sourceFileName.data()); BSLS_ASSERT(0 != symbolName.data()); } inline StackTraceFrame::StackTraceFrame(const StackTraceFrame& original, bslma::Allocator *basicAllocator) : d_address(original.d_address) , d_libraryFileName(original.d_libraryFileName, basicAllocator) , d_lineNumber(original.d_lineNumber) , d_mangledSymbolName(original.d_mangledSymbolName, basicAllocator) , d_offsetFromSymbol(original.d_offsetFromSymbol) , d_sourceFileName(original.d_sourceFileName, basicAllocator) , d_symbolName(original.d_symbolName, basicAllocator) { } inline StackTraceFrame::~StackTraceFrame() { BSLS_ASSERT(-1 <= d_lineNumber); } // MANIPULATORS inline StackTraceFrame& StackTraceFrame::operator=(const StackTraceFrame& rhs) { if (rhs == *this) { return *this; // RETURN } bslma::Allocator *allocator_p = d_symbolName.get_allocator().mechanism(); StackTraceFrame(rhs, allocator_p).swap(*this); return *this; } inline void StackTraceFrame::setAddress(const void *value) { d_address = value; } inline void StackTraceFrame::setLibraryFileName(const bsl::string_view& value) { BSLS_ASSERT(0 != value.data()); d_libraryFileName.assign(value.begin(), value.end()); } inline void StackTraceFrame::setLineNumber(int value) { BSLS_ASSERT(-1 <= value); d_lineNumber = value; } inline void StackTraceFrame::setMangledSymbolName(const bsl::string_view& value) { BSLS_ASSERT(0 != value.data()); d_mangledSymbolName.assign(value.begin(), value.end()); } inline void StackTraceFrame::setOffsetFromSymbol(bsl::size_t value) { d_offsetFromSymbol = value; } inline void StackTraceFrame::setSourceFileName(const bsl::string_view& value) { BSLS_ASSERT(0 != value.data()); d_sourceFileName.assign(value.begin(), value.end()); } inline void StackTraceFrame::setSymbolName(const bsl::string_view& value) { BSLS_ASSERT(0 != value.data()); d_symbolName.assign(value.begin(), value.end()); } // ACCESSORS inline const void *StackTraceFrame::address() const { return d_address; } inline const bsl::string& StackTraceFrame::libraryFileName() const { return d_libraryFileName; } inline int StackTraceFrame::lineNumber() const { return d_lineNumber; } inline bsl::size_t StackTraceFrame::offsetFromSymbol() const { return d_offsetFromSymbol; } inline const bsl::string& StackTraceFrame::mangledSymbolName() const { return d_mangledSymbolName; } inline const bsl::string& StackTraceFrame::sourceFileName() const { return d_sourceFileName; } inline const bsl::string& StackTraceFrame::symbolName() const { return d_symbolName; } // Predicates inline bool StackTraceFrame::isAddressKnown() const { return 0 != d_address; } inline bool StackTraceFrame::isLibraryFileNameKnown() const { return !d_libraryFileName.empty(); } inline bool StackTraceFrame::isLineNumberKnown() const { return d_lineNumber > 0; } inline bool StackTraceFrame::isMangledSymbolNameKnown() const { return !d_mangledSymbolName.empty(); } inline bool StackTraceFrame::isOffsetFromSymbolKnown() const { return (bsl::size_t)-1 != d_offsetFromSymbol; } inline bool StackTraceFrame::isSourceFileNameKnown() const { return !d_sourceFileName.empty(); } inline bool StackTraceFrame::isSymbolNameKnown() const { return !d_symbolName.empty(); } // Aspects inline bslma::Allocator *StackTraceFrame::allocator() const { return d_symbolName.get_allocator().mechanism(); } } // close package namespace // FREE OPERATORS inline bool balst::operator==(const StackTraceFrame& lhs, const StackTraceFrame& rhs) { return lhs.address() == rhs.address() && lhs.libraryFileName() == rhs.libraryFileName() && lhs.lineNumber() == rhs.lineNumber() && lhs.mangledSymbolName() == rhs.mangledSymbolName() && lhs.offsetFromSymbol() == rhs.offsetFromSymbol() && lhs.sourceFileName() == rhs.sourceFileName() && lhs.symbolName() == rhs.symbolName(); } inline bool balst::operator!=(const StackTraceFrame& lhs, const StackTraceFrame& rhs) { return lhs.address() != rhs.address() || lhs.libraryFileName() != rhs.libraryFileName() || lhs.lineNumber() != rhs.lineNumber() || lhs.mangledSymbolName() != rhs.mangledSymbolName() || lhs.offsetFromSymbol() != rhs.offsetFromSymbol() || lhs.sourceFileName() != rhs.sourceFileName() || lhs.symbolName() != rhs.symbolName(); } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2018 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 ----------------------------------