// // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #ifndef PXR_BASE_ARCH_STACK_TRACE_H #define PXR_BASE_ARCH_STACK_TRACE_H /// \file arch/stackTrace.h /// \ingroup group_arch_Diagnostics /// Architecture-specific call-stack tracing routines. #include "pxr/pxr.h" #include "pxr/base/arch/api.h" #include "pxr/base/arch/defines.h" #include #include #include #include #include #include PXR_NAMESPACE_OPEN_SCOPE /// \addtogroup group_arch_Diagnostics ///@{ /// Dumps call-stack info to a file, and prints an informative message. /// /// The reason for the trace should be supplied in \p reason. This routine /// can be slow and is intended to be called for a fatal error, such as a /// caught coredump signal, but may be called at any time. An additional /// message may be provided in \p message. If \p reason is \c NULL then this /// function only writes \p message to the banner (if any). /// /// This function is implemented by calling an external program. This is /// suitable for times where the current process may be corrupted. In other /// cases, using \c ArchPrintStackTrace() or other related functions would be /// much faster. /// /// Note the use of \c char* as opposed to \c string: this is intentional, /// because we are trying to use only async-safe function from here on and /// malloc() is not async-safe. ARCH_API void ArchLogPostMortem( const char* reason, const char* message = nullptr, const char* extraLogMsg = nullptr); /// Sets the command line that gathers call-stack info. /// /// This function sets the command line to execute to gather and log /// call-stack info. \p argv must be NULL terminated. \p command and/or \p /// argv may be NULL to suppress execution. Otherwise argv[0] must be the /// full path to the program to execute, typically \p command or "$cmd" as /// described below. /// /// \p command and \p argv are not copied and must remain valid until the next /// call to \c ArchSetPostMortem. /// /// Simple substitution is supported on argv elements: /// \li $cmd: Substitutes the command pathname, or $ARCH_POSTMORTEM if set /// \li $pid: Substitutes the process id /// \li $log: Substitutes the log pathname /// \li $time: Substitutes the user time (if available, else wall time) /// /// \sa ArchLogPostMortem ARCH_API void ArchSetPostMortem(const char* command, const char *const argv[]); /// Log session info. /// /// Optionally indicate that this is due to a crash by providing /// the path to a file containing a stack trace in \p crashStackTrace. /// ARCH_API void ArchLogSessionInfo(const char *crashStackTrace=NULL); /// Sets the command line to log sessions. /// /// This function sets the command line to execute to log session info. \p /// argv is used if no crash stack trace is provided, otherwise \p crashArgv /// is used. Both must be NULL terminated. If \p command or \p argv is NULL /// then non-crashes are not logged; if \p command or \p crashArgv is NULL /// then crashes are not logged. If not NULL then argv[0] and crashArgv[0] /// must be full path to the program to execute, typically \p command or /// "$cmd" as described below. /// /// \p command, \p argv, and \p crashArgv are not copied and must remain valid /// until the next call to \c ArchSetLogSession. /// /// Simple substitution is supported on argv elements: /// \li $cmd: Substitutes the command pathname, or $ARCH_LOGSESSION if set /// \li $prog Substitutes the program name /// \li $pid: Substitutes the process id /// \li $time: Substitutes the user time (if available, else wall time) /// \li $stack: Substitutes the crash stack string (only in crashArgv) /// /// \sa ArchLogSessionInfo ARCH_API void ArchSetLogSession(const char* command, const char* const argv[], const char* const crashArgv[]); /// Register the callback to invoke logging at end of a successful session. /// /// This function registers ArchLogSessionInfo() and records the current /// timestamp, to send up-time to the DB upon exiting. ARCH_API void ArchEnableSessionLogging(); /// Print a stack trace to the given FILE pointer. ARCH_API void ArchPrintStackTrace(FILE *fout, const std::string& programName, const std::string& reason); /// Print a stack trace to the given FILE pointer. /// This function uses ArchGetProgramInfoForErrors as the \c programName. /// \overload ARCH_API void ArchPrintStackTrace(FILE *fout, const std::string& reason); /// Print a stack trace to the given ostream. /// \overload ARCH_API void ArchPrintStackTrace(std::ostream& out, const std::string& programName, const std::string& reason); /// Print a stack trace to the given ostream. /// This function uses ArchGetProgramInfoForErrors as the \c programName. /// \overload ARCH_API void ArchPrintStackTrace(std::ostream& out, const std::string& reason); /// A callback to get a symbolic representation of an address. typedef std::function ArchStackTraceCallback; /// Sets a callback to get a symbolic representation of an address. /// /// The callback returns a string for an address in a stack trace, typically /// including the name of the function containing the address. \p cb may be \c /// NULL to use a default implementation. ARCH_API void ArchSetStackTraceCallback(const ArchStackTraceCallback& cb); /// Returns the callback to get a symbolic representation of an address. /// \sa ArchSetStackTraceCallback ARCH_API void ArchGetStackTraceCallback(ArchStackTraceCallback* cb); /// Returns the set value for the application's launch time. /// The timestamp for this value is set when the arch library is initialized. ARCH_API time_t ArchGetAppLaunchTime(); /// Enables or disables the automatic logging of crash information. /// /// This function controls whether the stack trace and build information is /// automatically caught and stored to an internal database when a fatal crash /// occurs. ARCH_API void ArchSetFatalStackLogging(bool flag); /// Returns whether automatic logging of fatal crashes is enabled /// This is set to false by default. /// \see ArchSetFatalStackLogging ARCH_API bool ArchGetFatalStackLogging(); /// Sets the program name to be used in diagnostic output /// /// The default value is initialized to ArchGetExecutablePath(). ARCH_API void ArchSetProgramNameForErrors(const char * progName); /// Returns the currently set program name for reporting errors. /// Defaults to ArchGetExecutablePath(). ARCH_API const char * ArchGetProgramNameForErrors(); /// Sets additional program info to be reported to the terminal in case of a /// fatal error. ARCH_API void ArchSetProgramInfoForErrors( const std::string& key, const std::string& value ); /// Returns currently set program info. /// \see ArchSetExtraLogInfoForErrors ARCH_API std::string ArchGetProgramInfoForErrors(const std::string& key); /// Stores (or removes if \p lines is nullptr) a pointer to additional log data /// that will be output in the stack trace log in case of a fatal error. Note /// that the pointer \p lines is copied, not the pointed-to data. In addition, /// Arch might read the data pointed to by \p lines concurrently at any time. /// Thus it is the caller's responsibility to ensure that \p lines is both valid /// and not mutated until replacing or removing it by invoking this function /// again with the same \p key and different \p lines. ARCH_API void ArchSetExtraLogInfoForErrors(const std::string &key, std::vector const *lines); /// Logs a stack trace to a file in /var/tmp. /// /// This function is similar to \c ArchLogPostMortem(), but will not fork an /// external process and only reports a stack trace. A file in /var/tmp is /// created with the name \c st_APPNAME.XXXXXX, where \c mktemp is used to /// make a unique extension for the file. If \c sessionLog is specified, then /// it will be appended to this file. A message is printed to \c stderr /// reporting that a stack trace has been taken and what file it has been /// written to. And if \c fatal is true, then the stack trace will be added /// to the stack_trace database table. ARCH_API void ArchLogStackTrace(const std::string& progName, const std::string& reason, bool fatal = false, const std::string& sessionLog = ""); /// Logs a stack trace to a file in /var/tmp. /// /// This function is similar to \c ArchLogPostMortem(), but will not fork an /// external process and only reports a stack trace. A file in /var/tmp is /// created with the name \c st_APPNAME.XXXXXX, where \c mktemp is used to /// make a unique extension for the file. If \c sessionLog is specified, /// then it will be appended to this file. A message is printed to \c stderr /// reporting that a stack trace has been taken and what file it has been /// written to. And if \c fatal is true, then the stack trace will be added /// to the stack_trace database table. ARCH_API void ArchLogStackTrace(const std::string& reason, bool fatal = false, const std::string& sessionLog = ""); /// Return stack trace. /// /// This function will return a vector of strings containing the current /// stack. The vector will be of maximum size \p maxDepth. ARCH_API std::vector ArchGetStackTrace(size_t maxDepth); /// Save frames of current stack /// /// This function saves at maximum \c maxDepth frames of the current stack /// into the vector \c frames. ARCH_API void ArchGetStackFrames(size_t maxDepth, std::vector *frames); /// Save frames of current stack. /// /// This function saves at maximum \p maxDepth frames of the current stack /// into the vector \p frames, skipping the first \p numFramesToSkipAtTop /// frames. The first frame will be at depth \p numFramesToSkipAtTop and the /// last at depth \p numFramesToSkipAtTop + \p maxDepth - 1. ARCH_API void ArchGetStackFrames(size_t maxDepth, size_t numFramesToSkipAtTop, std::vector *frames); /// Print stack frames to the given ostream. ARCH_API void ArchPrintStackFrames(std::ostream& out, const std::vector &frames); /// Callback for handling crashes. /// \see ArchCrashHandlerSystemv typedef void (*ArchCrashHandlerSystemCB)(void* userData); /// Replacement for 'system' safe for a crash handler /// /// This function is a substitute for system() which does not allocate or free /// any data, and times out after \c timeout seconds if the operation in \c /// argv is not complete. Unlike system, it takes the full \c pathname of the /// program to run, and won't search the path. Also unlike system, \c argv[] /// are the separated arguments, starting with the program's name, as for /// execv. \c callback is called every second. \c userData is passed to \c /// callback. \c callback can be used, for example, to print a '.' repeatedly /// to show progress. The alarm used in this function could interfere with /// setitimer or other calls to alarm, and this function uses non-locking fork /// and exec if available so should not generally be used except following a /// catastrophe. ARCH_API int ArchCrashHandlerSystemv(const char* pathname, char *const argv[], int timeout, ArchCrashHandlerSystemCB callback, void* userData); /// Crash, to test crash behavior. /// /// This function causes the calling program to crash by doing bad malloc /// and free things. If \c spawnthread is true, it spawns a thread which /// remains alive during the crash. It aborts if it fails to crash. /// /// \private ARCH_API void ArchTestCrash(bool spawnthread); #if defined(ARCH_OS_DARWIN) // macOS has no ETIME. ECANCELED seems to have about the closest meaning to // the actual error here. The operation is timing out, not being explicitly // canceled, but it is canceled. #ifndef ETIME #define ETIME ECANCELED #endif // end ETIME #endif // end ARCH_OS_DARWIN ///@} PXR_NAMESPACE_CLOSE_SCOPE #endif // PXR_BASE_ARCH_STACK_TRACE_H