cxx/lyra/lyra.h (84 lines of code) (raw):

/* * Copyright (c) Facebook, Inc. and its affiliates. * * 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. */ #pragma once #include <iomanip> #include <string> #include <vector> namespace facebook { namespace lyra { constexpr size_t kDefaultLimit = 64; using InstructionPointer = const void*; class StackTraceElement { public: StackTraceElement(InstructionPointer absoluteProgramCounter, InstructionPointer libraryBase, InstructionPointer functionAddress, std::string libraryName, std::string functionName) : absoluteProgramCounter_{absoluteProgramCounter}, libraryBase_{libraryBase}, functionAddress_{functionAddress}, libraryName_{std::move(libraryName)}, functionName_{std::move(functionName)}, hasBuildId_{false}, buildId_{} {} InstructionPointer libraryBase() const noexcept { return libraryBase_; } InstructionPointer functionAddress() const noexcept { return functionAddress_; } InstructionPointer absoluteProgramCounter() const noexcept { return absoluteProgramCounter_; } const std::string& libraryName() const noexcept { return libraryName_; } const std::string& functionName() const noexcept { return functionName_; } /** * The offset of the program counter to the base of the library (i.e. the * address that addr2line takes as input> */ std::ptrdiff_t libraryOffset() const noexcept { auto absoluteLibrary = static_cast<const char*>(libraryBase_); auto absoluteabsoluteProgramCounter = static_cast<const char*>(absoluteProgramCounter_); return absoluteabsoluteProgramCounter - absoluteLibrary; } /** * The offset within the current function */ int functionOffset() const noexcept { auto absoluteSymbol = static_cast<const char*>(functionAddress_); auto absoluteabsoluteProgramCounter = static_cast<const char*>(absoluteProgramCounter_); return absoluteabsoluteProgramCounter - absoluteSymbol; } std::string buildId() const; private: const InstructionPointer absoluteProgramCounter_; const InstructionPointer libraryBase_; const InstructionPointer functionAddress_; const std::string libraryName_; const std::string functionName_; mutable bool hasBuildId_; mutable std::string buildId_; }; /** * If a library identifier function is set, it is passed a libraryName * for the frame, and returns a library build id string, which will be * included in the logged stack trace. The most common use for this * will be correlating stack traces with breakpad identifiers. */ typedef std::string (*LibraryIdentifierFunctionType)(const std::string&); void setLibraryIdentifierFunction(LibraryIdentifierFunctionType func); /** * Populate the vector with the current stack trace * * Note that this trace needs to be symbolicated to get the library offset even * if it is to be symbolicated off-line. * * Beware of a bug on some platforms, which makes the trace loop until the * buffer is full when it reaches a noexpr function. It seems to be fixed in * newer versions of gcc. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56846 * * @param stackTrace The vector that will receive the stack trace. Before * filling the vector it will be cleared. The vector will never grow so the * number of frames captured is limited by the capacity of it. * * @param skip The number of frames to skip before capturing the trace */ void getStackTrace(std::vector<InstructionPointer>& stackTrace, size_t skip = 0); /** * Creates a vector and populates it with the current stack trace * * Note that this trace needs to be symbolicated to get the library offset even * if it is to be symbolicated off-line. * * Beware of a bug on some platforms, which makes the trace loop until the * buffer is full when it reaches a noexpr function. It seems to be fixed in * newer versions of gcc. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56846 * * @param skip The number of frames to skip before capturing the trace * * @limit The maximum number of frames captured */ inline std::vector<InstructionPointer> getStackTrace( size_t skip = 0, size_t limit = kDefaultLimit) { auto stackTrace = std::vector<InstructionPointer>{}; stackTrace.reserve(limit); getStackTrace(stackTrace, skip + 1); return stackTrace; } /** * Symbolicates a stack trace into a given vector * * @param symbols The vector to receive the output. The vector is cleared and * enough room to keep the frames are reserved. * * @param stackTrace The input stack trace */ void getStackTraceSymbols(std::vector<StackTraceElement>& symbols, const std::vector<InstructionPointer>& trace); /** * Symbolicates a stack trace into a new vector * * @param stackTrace The input stack trace */ inline std::vector<StackTraceElement> getStackTraceSymbols( const std::vector<InstructionPointer>& trace) { auto symbols = std::vector<StackTraceElement>{}; getStackTraceSymbols(symbols, trace); return symbols; } /** * Captures and symbolicates a stack trace * * Beware of a bug on some platforms, which makes the trace loop until the * buffer is full when it reaches a noexpr function. It seems to be fixed in * newer versions of gcc. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56846 * * @param skip The number of frames before capturing the trace * * @param limit The maximum number of frames captured */ inline std::vector<StackTraceElement> getStackTraceSymbols( size_t skip = 0, size_t limit = kDefaultLimit) { return getStackTraceSymbols(getStackTrace(skip + 1, limit)); } /** * Formatting a stack trace element */ std::ostream& operator<<(std::ostream& out, const StackTraceElement& elm); /** * Formatting a stack trace */ std::ostream& operator<<(std::ostream& out, const std::vector<StackTraceElement>& trace); /** * Log stack trace * * Makes it possible to log a trace without using a temporary stream when the * underlying log API is not stream based. */ void logStackTrace(const std::vector<StackTraceElement>& trace); } }