-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathstack_trace.h
More file actions
179 lines (153 loc) · 6.86 KB
/
stack_trace.h
File metadata and controls
179 lines (153 loc) · 6.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#pragma once
/**
* Stack tracing and traced exceptions, Copyright (c) 2017-2018, Jorma Rebane
* Distributed under MIT Software License
*/
#include "config.h"
#include "strview.h"
#include <stdexcept>
#include <string>
#include <vector>
#include <cstdint>
namespace rpp
{
/**
* @brief Represents a single entry in a callstack and provides file, line and function name information
*/
struct RPPAPI CallstackEntry
{
uint64_t addr = 0; // if 0, we have no valid entry
int line = 0;
std::string name; // function name
std::string file; // if empty, we have no valid file info, try using module name instead
std::string module;
explicit CallstackEntry(uint64_t addr) noexcept : addr{addr} {}
CallstackEntry() noexcept = default; // required for std::vector<CallstackEntry>
/** @return short file or module path from long `file` path */
const char* short_path() const noexcept;
/** @return clean function name from long symbolicated name */
std::string clean_name() const noexcept;
/**
* @return A string representation of this callstack entry
* "[file]:[line] in [function]"
*/
std::string to_string() const noexcept;
};
/**
* @brief Performs lookup for address information
* @brief addr Address to lookup
*/
RPPAPI CallstackEntry get_address_info(uint64_t addr) noexcept;
// absolute limit for callstack depth
static inline constexpr size_t CALLSTACK_MAX_DEPTH = 256u;
/**
* @brief Walks the stack and returns a list of callstack addresses.
* You can then use get_address_info() to get more information about each address,
* or use format_trace() to get a formatted stack trace.
* @param maxDepth Maximum number of stack frames to trace
* @param entriesToSkip Number of initial entries to skip in order to hide stack tracing internals
* @param threadId Thread to get callstack from, only implemented for WIN32
* @return List of callstack addresses
*/
RPPAPI std::vector<uint64_t> get_callstack(size_t maxDepth = 32, size_t entriesToSkip = 0, uint64_t threadId = 0) noexcept;
/**
* @brief Walks the stack and returns a list of callstack addresses.
* You can then use get_address_info() to get more information about each address,
* or use format_trace() to get a formatted stack trace.
* @param callstack [out] Pre-allocated buffer for callstack addresses
* @param maxDepth Maximum number of stack frames to trace
* @param entriesToSkip Number of initial entries to skip in order to hide stack tracing internals
* @return Number of callstack entries written to the buffer
*/
RPPAPI int get_callstack(uint64_t* callstack, size_t maxDepth, size_t entriesToSkip = 0) noexcept;
struct ThreadCallstack
{
std::vector<uint64_t> callstack;
rpp::uint64 thread_id = 0;
};
/**
* @brief Enumerates threads of the current process and returns list of callstacks.
* @param maxDepth Maximum number of stack frames to trace per thread
* @param entriesToSkip Number of initial entries to skip on the calling thread
* @return List of callstacks along with thread ids
*/
RPPAPI std::vector<ThreadCallstack> get_all_callstacks(size_t maxDepth = 32, size_t entriesToSkip = 0);
/**
* Prepends an error message before formatting the stack trace
* @param message Message to prepend to stack trace
* @param callstack [in] Pre-walked callstack
* @param depth Number of entries in the callstack
* @return Formatted stack trace with available debug information. Line information is not always available.
*/
RPPAPI std::string format_trace(rpp::strview message, const uint64_t* callstack, size_t depth) noexcept;
/**
* @brief Generic implementation of stack trace, taking a pre-walked callstack
* @param callstack [in] Pre-walked callstack
* @return Formatted stack trace with available debug information. Line information is not always available.
*/
inline std::string format_trace(const std::vector<uint64_t>& callstack) noexcept
{
return rpp::format_trace(rpp::strview{}, callstack.data(), callstack.size());
}
/**
* Prepends an error message before formatting the stack trace
* @param message Message to prepend to stack trace
* @param callstack [in] Pre-walked callstack
* @return Formatted stack trace with available debug information. Line information is not always available.
*/
inline std::string format_trace(rpp::strview message, const std::vector<uint64_t>& callstack) noexcept
{
return rpp::format_trace(message, callstack.data(), callstack.size());
}
/**
* Base implementation of stack trace. Only needed if you're implementing custom abstractions
* @param message [nullable] Message to prepend to stack trace
* @param messageLen Length of the message (or 0)
* @param maxDepth Maximum number of stack frames to trace
* @param entriesToSkip Number of initial entries to skip in order to hide stack tracing internals
* @return Stack trace with available debug information. Line information is not always available.
* @note
* On linux you must compile with -rdynamic, otherwise internal symbols won't be visible
* @endnote
*/
RPPAPI std::string stack_trace(rpp::strview message, size_t maxDepth = 32,
size_t entriesToSkip = 2) noexcept;
/**
* Prepares stack trace
*/
inline std::string stack_trace(size_t maxDepth = 32) noexcept
{
return rpp::stack_trace(rpp::strview{}, maxDepth, 2);
}
/**
* Prints stack trace to STDERR
*/
RPPAPI void print_trace(size_t maxDepth = 32) noexcept;
/**
* Prints stack trace to STDERR WITH error message
*/
RPPAPI void print_trace(rpp::strview message, size_t maxDepth = 32) noexcept;
/**
* @return Prepared runtime_error with error message and stack trace
*/
RPPAPI std::runtime_error error_with_trace(rpp::strview message, size_t maxDepth = 32) noexcept;
/**
* Traced exception forms a complete [message]\\n[stacktrace] string
* which can be retrieved via runtime_error::what()
*/
struct RPPAPI traced_exception : std::runtime_error
{
explicit traced_exception(rpp::strview message) noexcept;
};
/**
* Installs a default handler for SIGSEGV which will
* throw a traced_exception instead of quietly terminating
* @note Will cause std::terminate if SIGSEGV happens in noexcept context
*/
RPPAPI void register_segfault_tracer() noexcept;
/**
* Installs a default handler for SIGSEGV which will
* prints stack trace to stderr and then calls std::terminate
*/
RPPAPI void register_segfault_tracer(std::nothrow_t nothrow) noexcept;
}