12
12
13
13
# include < __stacktrace/base.h>
14
14
15
- # include " stacktrace/base.h"
16
- # include " stacktrace/config.h"
17
- # include " stacktrace/utils.h"
18
15
# include " stacktrace/windows/dll.h"
19
16
# include " stacktrace/windows/impl.h"
20
17
@@ -23,188 +20,29 @@ namespace __stacktrace {
23
20
24
21
namespace {
25
22
26
- /*
27
- Global objects, shared among all threads and among all stacktrace operations.
28
- The `dbghelp` APIs are not safe to call concurrently (according to their docs)
29
- so we claim a lock in the `WinDebugAPIs` constructor.
30
- */
31
-
32
- // Statically-initialized
33
- std::mutex gWindowsAPILock ;
34
- DbgHelpDLL dbg;
35
- PSAPIDLL ps;
36
-
37
- // Initialized once, in first WinDebugAPIs construction;
38
- // protected by the above mutex.
23
+ // Initialized once, in first `win_impl` construction.
24
+ // Protected by mutex within the `win_impl` constructor.
39
25
HANDLE proc;
40
26
HMODULE exe;
41
27
IMAGE_NT_HEADERS* ntHeaders;
42
28
bool globalInitialized{false };
43
29
44
30
// Globals used across invocations of the functions below.
45
- // Also guarded by the above mutex .
31
+ // Protected by mutex within the `win_impl` constructor .
46
32
bool symsInitialized{false };
47
33
HMODULE moduleHandles[1024 ];
48
34
size_t moduleCount; // 0 IFF module enumeration failed
49
35
50
36
} // namespace
51
37
52
- win_impl::WinDebugAPIs (base& trace) : base_(trace), guard_(gWindowsAPILock ) {
53
- if (!globalInitialized) {
54
- // Cannot proceed without these DLLs:
55
- if (!dbg) {
56
- return ;
57
- }
58
- if (!ps) {
59
- return ;
60
- }
61
- proc = GetCurrentProcess ();
62
- if (!(exe = GetModuleHandle (nullptr ))) {
63
- return ;
64
- }
65
- if (!(ntHeaders = (*dbg.ImageNtHeader )(exe))) {
66
- return ;
67
- }
68
-
69
- globalInitialized = true ;
70
- }
71
-
72
- // Initialize symbol machinery.
73
- // Presumably the symbols in this process's space can change between
74
- // stacktraces, so we'll do this each time we take a trace.
75
- // The final `true` means we want the runtime to enumerate all this
76
- // process's modules' symbol tables.
77
- symsInitialized = (*dbg.SymInitialize )(proc, nullptr , true );
78
- DWORD symOptions = (*dbg.SymGetOptions )();
79
- symOptions |= SYMOPT_LOAD_LINES | SYMOPT_UNDNAME;
80
- (*dbg.SymSetOptions )(symOptions);
81
- }
82
-
83
- win_impl::~WinDebugAPIs () {
84
- if (symsInitialized) {
85
- (*dbg.SymCleanup )(proc);
86
- symsInitialized = false ;
87
- }
88
- }
89
-
90
- void win_impl::ident_modules () {
91
- if (!globalInitialized) {
92
- return ;
93
- }
94
- DWORD needBytes;
95
- auto enumMods = (*ps.EnumProcessModules )(proc, moduleHandles, sizeof (moduleHandles), LPDWORD (&needBytes));
96
- if (enumMods) {
97
- moduleCount = needBytes / sizeof (HMODULE);
98
- } else {
99
- moduleCount = 0 ;
100
- Debug () << " EnumProcessModules failed: " << GetLastError () << ' \n ' ;
101
- }
102
- }
103
-
104
- void win_impl::symbolize () {
105
- // Very long symbols longer than this amount will be truncated.
106
- static constexpr size_t kMaxSymName = 256 ;
107
- if (!globalInitialized) {
108
- return ;
109
- }
110
-
111
- for (auto & entry : base_.__entries_ ) {
112
- char space[sizeof (IMAGEHLP_SYMBOL64) + kMaxSymName ];
113
- auto * sym = (IMAGEHLP_SYMBOL64*)space;
114
- sym->SizeOfStruct = sizeof (IMAGEHLP_SYMBOL64);
115
- sym->MaxNameLength = kMaxSymName ;
116
- uint64_t disp{0 };
117
- if ((*dbg.SymGetSymFromAddr64 )(proc, entry.__addr_actual_ , &disp, sym)) {
118
- // Copy chars into the destination string which uses the caller-provided allocator.
119
- ((entry_base&)entry).__desc_ = {sym->Name };
120
- } else {
121
- Debug () << " SymGetSymFromAddr64 failed: " << GetLastError () << ' \n ' ;
122
- }
123
- }
124
- }
125
-
126
- void win_impl::resolve_lines () {
127
- if (!globalInitialized) {
128
- return ;
129
- }
130
-
131
- for (auto & entry : base_.__entries_ ) {
132
- DWORD disp{0 };
133
- IMAGEHLP_LINE64 line;
134
- line.SizeOfStruct = sizeof (IMAGEHLP_LINE64);
135
- if ((*dbg.SymGetLineFromAddr64 )(proc, entry.__addr_actual_ , &disp, &line)) {
136
- // Copy chars into the destination string which uses the caller-provided allocator.
137
- entry.__file_ = line.FileName ;
138
- entry.__line_ = line.LineNumber ;
139
- } else {
140
- Debug () << " SymGetLineFromAddr64 failed: " << GetLastError () << ' \n ' ;
141
- }
142
- }
143
- }
144
-
145
- /*
146
- Inlining is disabled from here on;
147
- this is to ensure `collect` below doesn't get merged into its caller
148
- and mess around with the top of the stack (making `skip` inaccurate).
149
- */
150
- # pragma auto_inline(off)
151
-
152
- _LIBCPP_NO_TAIL_CALLS _LIBCPP_NOINLINE void win_impl::collect (size_t skip, size_t max_depth) {
153
- if (!globalInitialized) {
154
- return ;
155
- }
156
-
157
- auto thread = GetCurrentThread ();
158
- auto machine = ntHeaders->FileHeader .Machine ;
159
-
160
- CONTEXT ccx;
161
- RtlCaptureContext (&ccx);
162
-
163
- STACKFRAME64 frame;
164
- memset (&frame, 0 , sizeof (frame));
165
- frame.AddrPC .Mode = AddrModeFlat;
166
- frame.AddrStack .Mode = AddrModeFlat;
167
- frame.AddrFrame .Mode = AddrModeFlat;
168
- frame.AddrPC .Offset = ctrace.Rip ;
169
- frame.AddrStack .Offset = ctrace.Rsp ;
170
- frame.AddrFrame .Offset = ctrace.Rbp ;
171
-
172
- while (max_depth &&
173
- (*dbg.StackWalk64 )(
174
- machine,
175
- proc,
176
- thread,
177
- &frame,
178
- &ccx,
179
- nullptr ,
180
- dbg.SymFunctionTableAccess64 ,
181
- dbg.SymGetModuleBase64 ,
182
- nullptr )) {
183
- if (skip) {
184
- --skip;
185
- continue ;
186
- }
187
- --max_depth;
188
- auto & entry = base_.__entries_ .emplace_back ();
189
- // We don't need to compute the un-slid addr; windbg only needs the actual addresses.
190
- // Assume address is of the instruction after a call instruction, since we can't
191
- // differentiate between a signal, SEH exception handler, or a normal function call.
192
- entry.__addr_actual_ = frame.AddrPC .Offset - 1 ; // Back up 1 byte to get into prev insn range
193
- }
194
- }
195
-
196
38
dll::~dll () { FreeLibrary (module_); }
197
39
198
- dll::dll (char const * name) : name_(name), module_(LoadLibrary(name)) {
199
- if (!module_) {
200
- debug () << " LoadLibrary failed: " << name_ << " : " << GetLastError () << ' \n ' ;
201
- }
202
- }
40
+ dll::dll (char const * name) : name_(name), module_(LoadLibrary(name)) {}
203
41
204
42
dbghelp_dll::~dbghelp_dll () = default ;
205
43
206
44
dbghelp_dll& dbghelp_dll::get () {
207
- dbghelp_dll ret;
45
+ static dbghelp_dll ret;
208
46
return ret;
209
47
}
210
48
@@ -228,15 +66,15 @@ if (!get_func(&ImageNtHeader, "ImageNtHeader")) { return; }
228
66
psapi_dll::~psapi_dll () = default ;
229
67
230
68
psapi_dll& psapi_dll::get () {
231
- psapi_dll ret;
69
+ static psapi_dll ret;
232
70
return ret;
233
71
}
234
72
235
- psapi_dll () : dll(" psapi.dll" ) {
73
+ psapi_dll::psapi_dll () : dll(" psapi.dll" ) {
236
74
// clang-format off
237
- if (!getFunc (&EnumProcessModules, " EnumProcessModules" )) { return ; }
238
- if (!getFunc (&GetModuleInformation, " GetModuleInformation" )) { return ; }
239
- if (!getFunc (&GetModuleBaseName, " GetModuleBaseNameA" )) { return ; }
75
+ if (!get_func (&EnumProcessModules, " EnumProcessModules" )) { return ; }
76
+ if (!get_func (&GetModuleInformation, " GetModuleInformation" )) { return ; }
77
+ if (!get_func (&GetModuleBaseName, " GetModuleBaseNameA" )) { return ; }
240
78
valid_ = true ;
241
79
// clang-format on
242
80
}
0 commit comments