Skip to content

Commit a901e3c

Browse files
Clean up windows impl
1 parent 4f80088 commit a901e3c

File tree

2 files changed

+80
-146
lines changed

2 files changed

+80
-146
lines changed

libcxx/include/__stacktrace/basic_stacktrace.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,14 @@ class basic_stacktrace : private __stacktrace::_Trace {
131131
// Creation and assignment [stacktrace.basic.cons]
132132

133133
_LIBCPP_ALWAYS_INLINE // Omit this function from the trace
134-
static basic_stacktrace current(const allocator_type& __alloc = allocator_type()) noexcept {
134+
static basic_stacktrace
135+
current(const allocator_type& __alloc = allocator_type()) noexcept {
135136
return current(0, __default_max_depth, __alloc);
136137
}
137138

138139
_LIBCPP_ALWAYS_INLINE // Omit this function from the trace
139-
static basic_stacktrace current(size_type __skip, const allocator_type& __alloc = allocator_type()) noexcept {
140+
static basic_stacktrace
141+
current(size_type __skip, const allocator_type& __alloc = allocator_type()) noexcept {
140142
return current(__skip, __default_max_depth, __alloc);
141143
}
142144

@@ -148,7 +150,7 @@ class basic_stacktrace : private __stacktrace::_Trace {
148150
basic_stacktrace __ret{__alloc};
149151

150152
if (__max_depth) {
151-
# if defined(WIN32)
153+
# if defined(_WIN32)
152154
__ret.windows_impl(__skip, __max_depth);
153155
# else
154156
__ret.populate_addrs(__skip, __max_depth);

libcxx/src/stacktrace/windows_impl.cpp

Lines changed: 75 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -15,188 +15,124 @@
1515
# include <psapi.h>
1616
//
1717
# include <cstring>
18-
# include <iostream>
1918
# include <mutex>
2019
# include <stacktrace>
2120

21+
# pragma comment(lib, "dbghelp.lib")
22+
# pragma comment(lib, "psapi.lib")
23+
2224
_LIBCPP_BEGIN_NAMESPACE_STD
2325
namespace __stacktrace {
2426

2527
namespace {
2628

27-
struct _DLL {
28-
HMODULE module_{};
29-
bool loaded_{};
30-
31-
explicit _DLL(char const* name) : module_(LoadLibraryA(name)) {}
32-
33-
~_DLL() {
34-
if (module_) {
35-
FreeLibrary(module_);
36-
}
37-
}
38-
39-
template <typename F>
40-
bool get_func(F** func, char const* name) {
41-
return ((*func = (F*)(void*)GetProcAddress(module_, name)) != nullptr);
42-
}
43-
};
44-
45-
// clang-format off
46-
47-
struct _Dbghelp_DLL final : _DLL {
48-
IMAGE_NT_HEADERS* (*ImageNtHeader)(void*);
49-
bool (WINAPI *SymCleanup) (HANDLE);
50-
DWORD (WINAPI *SymGetOptions) ();
51-
bool (WINAPI *SymGetSearchPath) (HANDLE, char const*, DWORD);
52-
bool (WINAPI *SymInitialize) (HANDLE, char const*, bool);
53-
DWORD (WINAPI *SymSetOptions) (DWORD);
54-
bool (WINAPI *SymSetSearchPath) (HANDLE, char const*);
55-
bool (WINAPI *StackWalk64) (DWORD, HANDLE, HANDLE, STACKFRAME64*, void*, void*, void*, void*, void*);
56-
void* (WINAPI *SymFunctionTableAccess64)(HANDLE, DWORD64);
57-
bool (WINAPI *SymGetLineFromAddr64)(HANDLE, DWORD64, DWORD*, IMAGEHLP_LINE64*);
58-
DWORD64 (WINAPI *SymGetModuleBase64) (HANDLE, DWORD64);
59-
bool (WINAPI *SymGetModuleInfo64) (HANDLE, DWORD64, IMAGEHLP_MODULE64*);
60-
bool (WINAPI *SymGetSymFromAddr64)(HANDLE, DWORD64, DWORD64*, IMAGEHLP_SYMBOL64*);
61-
DWORD64 (WINAPI *SymLoadModule64) (HANDLE, HANDLE, char const*, char const*, void*, DWORD);
62-
63-
_Dbghelp_DLL() : _DLL("dbghelp.dll") {
64-
loaded_ = true
65-
&& get_func(&ImageNtHeader, "ImageNtHeader")
66-
&& get_func(&SymCleanup, "SymCleanup")
67-
&& get_func(&SymGetOptions, "SymGetOptions")
68-
&& get_func(&SymGetSearchPath, "SymGetSearchPath")
69-
&& get_func(&SymInitialize, "SymInitialize")
70-
&& get_func(&SymSetOptions, "SymSetOptions")
71-
&& get_func(&SymSetSearchPath, "SymSetSearchPath")
72-
&& get_func(&StackWalk64, "StackWalk64")
73-
&& get_func(&SymFunctionTableAccess64, "SymFunctionTableAccess64")
74-
&& get_func(&SymGetLineFromAddr64, "SymGetLineFromAddr64")
75-
&& get_func(&SymGetModuleBase64, "SymGetModuleBase64")
76-
&& get_func(&SymGetModuleInfo64, "SymGetModuleInfo64")
77-
&& get_func(&SymGetSymFromAddr64, "SymGetSymFromAddr64")
78-
&& get_func(&SymLoadModule64, "SymLoadModule64")
79-
;
80-
}
81-
};
82-
83-
struct _Psapi_DLL final : _DLL {
84-
bool (WINAPI *EnumProcessModules) (HANDLE, HMODULE*, DWORD, DWORD*);
85-
bool (WINAPI *GetModuleInformation) (HANDLE, HMODULE, MODULEINFO*, DWORD);
86-
DWORD (WINAPI *GetModuleBaseName) (HANDLE, HMODULE, char**, DWORD);
87-
88-
_Psapi_DLL() : _DLL("psapi.dll") {
89-
loaded_ = true
90-
&& get_func(&EnumProcessModules, "EnumProcessModules")
91-
&& get_func(&GetModuleInformation, "GetModuleInformation")
92-
&& get_func(&GetModuleBaseName, "GetModuleBaseNameA")
93-
;
94-
}
95-
};
96-
9729
struct _Sym_Init_Scope {
98-
_Dbghelp_DLL& dbghelp_;
9930
HANDLE proc_;
10031

101-
_Sym_Init_Scope(_Dbghelp_DLL& dbghelp, HANDLE proc)
102-
: dbghelp_(dbghelp), proc_(proc) {
103-
(*dbghelp_.SymInitialize)(proc_, nullptr, true);
104-
}
105-
~_Sym_Init_Scope() {
106-
(*dbghelp_.SymCleanup)(proc_);
107-
}
32+
explicit _Sym_Init_Scope(HANDLE proc) : proc_(proc) { SymInitialize(proc_, nullptr, true); }
33+
~_Sym_Init_Scope() { SymCleanup(proc_); }
10834
};
10935

110-
} // namespace
36+
} // namespace
11137

112-
_LIBCPP_EXPORTED_FROM_ABI void
113-
_Trace::windows_impl(size_t skip, size_t max_depth) {
114-
if (!max_depth) [[unlikely]] {
38+
_LIBCPP_EXPORTED_FROM_ABI void _Trace::windows_impl(size_t skip, size_t max_depth) {
39+
if (!max_depth) {
11540
return;
11641
}
11742

118-
static _Psapi_DLL psapi;
119-
static _Dbghelp_DLL dbghelp;
120-
if (!psapi.loaded_ || !dbghelp.loaded_) { return; }
43+
// Use the Windows Debug Help and Process Status libraries to get a stacktrace.
44+
// https://learn.microsoft.com/en-us/windows/win32/debug/debug-help-library
45+
// https://learn.microsoft.com/en-us/windows/win32/psapi/process-status-helper
12146

122-
// Not thread-safe according to docs
47+
// These APIs are not thread-safe, according to docs.
12348
static std::mutex api_mutex;
12449
std::lock_guard<std::mutex> api_guard(api_mutex);
12550

12651
HANDLE proc = GetCurrentProcess();
12752
HMODULE exe = GetModuleHandle(nullptr);
128-
if (!exe) { return; }
53+
if (!exe) {
54+
return;
55+
}
12956

130-
_Sym_Init_Scope symscope(dbghelp, proc);
57+
_Sym_Init_Scope symscope(proc);
13158

132-
char sym_path[MAX_PATH * 4]; // arbitrary
133-
if (!(*dbghelp.SymGetSearchPath)(proc, sym_path, sizeof(sym_path))) { return; }
59+
// Allow space for a handful of paths
60+
char sym_path[MAX_PATH * 4];
61+
if (!SymGetSearchPath(proc, sym_path, sizeof(sym_path))) {
62+
return;
63+
}
13464

13565
char exe_dir[MAX_PATH];
136-
if (!GetModuleFileNameA(nullptr, exe_dir, sizeof(exe_dir))) { return; }
66+
if (!GetModuleFileNameA(nullptr, exe_dir, sizeof(exe_dir))) {
67+
return;
68+
}
13769
size_t exe_dir_len = strlen(exe_dir);
138-
while (exe_dir_len > 0 && exe_dir[exe_dir_len - 1] != '\\') { exe_dir[--exe_dir_len] = 0; }
139-
if (exe_dir_len > 0) { exe_dir[--exe_dir_len] = 0; } // strip last backslash
70+
while (exe_dir_len > 0 && exe_dir[exe_dir_len - 1] != '\\') {
71+
exe_dir[--exe_dir_len] = 0;
72+
}
73+
if (exe_dir_len > 0) {
74+
exe_dir[--exe_dir_len] = 0;
75+
} // strip last backslash
14076

14177
if (!strstr(sym_path, exe_dir)) {
142-
(void) strncat(sym_path, ";", sizeof(sym_path) - 1);
143-
(void) strncat(sym_path, exe_dir, sizeof(sym_path) - 1);
144-
if (!(*dbghelp.SymSetSearchPath)(proc, sym_path)) { return; }
78+
(void)strncat(sym_path, ";", sizeof(sym_path) - 1);
79+
(void)strncat(sym_path, exe_dir, sizeof(sym_path) - 1);
80+
if (!SymSetSearchPath(proc, sym_path)) {
81+
return;
82+
}
14583
}
14684

14785
IMAGE_NT_HEADERS* nt_headers;
148-
if (!(nt_headers = (*dbghelp.ImageNtHeader)(exe))) { return; }
86+
if (!(nt_headers = ImageNtHeader(exe))) {
87+
return;
88+
}
14989

150-
(*dbghelp.SymSetOptions)(
151-
(*dbghelp.SymGetOptions)()
152-
| SYMOPT_LOAD_LINES
153-
| SYMOPT_UNDNAME);
90+
SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
15491

155-
auto thread = GetCurrentThread();
156-
auto machine = nt_headers->FileHeader.Machine;
92+
HANDLE thread = GetCurrentThread();
93+
int machine = nt_headers->FileHeader.Machine;
15794

15895
CONTEXT ccx;
15996
RtlCaptureContext(&ccx);
16097

161-
STACKFRAME64 frame;
98+
STACKFRAME frame;
16299
memset(&frame, 0, sizeof(frame));
163-
frame.AddrPC.Mode = AddrModeFlat;
164-
frame.AddrStack.Mode = AddrModeFlat;
165-
frame.AddrFrame.Mode = AddrModeFlat;
166-
#if defined(_M_AMD64)
100+
frame.AddrPC.Mode = AddrModeFlat;
101+
frame.AddrStack.Mode = AddrModeFlat;
102+
frame.AddrFrame.Mode = AddrModeFlat;
103+
# if defined(_M_AMD64)
167104
frame.AddrPC.Offset = ccx.Rip;
168105
frame.AddrStack.Offset = ccx.Rsp;
169106
frame.AddrFrame.Offset = ccx.Rbp;
170-
#elif defined(_M_ARM64)
107+
# elif defined(_M_ARM64)
171108
frame.AddrPC.Offset = ccx.Pc;
172109
frame.AddrStack.Offset = ccx.Sp;
173110
frame.AddrFrame.Offset = ccx.Fp;
174-
#elif defined(_M_IX86)
111+
# elif defined(_M_IX86)
175112
frame.AddrPC.Offset = ccx.Eip;
176113
frame.AddrStack.Offset = ccx.Esp;
177114
frame.AddrFrame.Offset = ccx.Ebp;
178-
#else
179-
# warning unrecognized architecture; returned stacktraces will be empty
115+
# else
116+
# warning unrecognized architecture; returned stacktraces will be empty
180117
return;
181-
#endif
118+
# endif
182119

183120
// Skip call to this `current_impl` func
184121
++skip;
185-
186-
while (max_depth) {
187122

188-
if (!(*dbghelp.StackWalk64)(
189-
machine, proc, thread, &frame, &ccx, nullptr,
190-
(void*) dbghelp.SymFunctionTableAccess64,
191-
(void*) dbghelp.SymGetModuleBase64,
192-
nullptr)) {
123+
while (max_depth) {
124+
if (!StackWalk(machine, proc, thread, &frame, &ccx, nullptr, SymFunctionTableAccess, SymGetModuleBase, nullptr)) {
193125
break;
194126
}
195127

196-
if (skip && skip--) { continue; }
197-
if (!frame.AddrPC.Offset) { break; }
128+
if (skip && skip--) {
129+
continue;
130+
}
131+
if (!frame.AddrPC.Offset) {
132+
break;
133+
}
198134

199-
auto& entry = this->__entry_append_();
135+
_Entry& entry = this->__entry_append_();
200136

201137
// Note: can't differentiate between a signal / exception, or a normal function call.
202138
// This assumes the more common (presumably) case of normal function calls, so we'll
@@ -207,39 +143,35 @@ _Trace::windows_impl(size_t skip, size_t max_depth) {
207143
// itself or a DLL. This is used in place of the source filename, if the source filename
208144
// cannot be found (missing PDB, etc.). If the source file can be determined this will
209145
// be overwritten.
210-
IMAGEHLP_MODULE64 mod_info;
146+
IMAGEHLP_MODULE mod_info;
211147
memset(&mod_info, 0, sizeof(mod_info));
212148
mod_info.SizeOfStruct = sizeof(mod_info);
213-
if ((*dbghelp.SymGetModuleInfo64)(proc, frame.AddrPC.Offset, &mod_info)) {
149+
if (SymGetModuleInfo(proc, frame.AddrPC.Offset, &mod_info)) {
214150
entry.__file_.assign(mod_info.LoadedImageName);
215151
}
216152

217153
--max_depth;
218154
}
219155

220156
DWORD need_bytes = 0;
221-
HMODULE module_handles[1024] {0};
222-
if (!(*psapi.EnumProcessModules)(
223-
proc, module_handles, sizeof(module_handles), LPDWORD(&need_bytes))) {
157+
HMODULE module_handles[1024]{0};
158+
if (!EnumProcessModules(proc, module_handles, sizeof(module_handles), LPDWORD(&need_bytes))) {
224159
return;
225160
}
226161

227-
// Symbols longer than this will be truncated.
228-
static constexpr size_t kMaxSymName = 256;
229-
230-
for (auto& entry : __entry_iters_()) {
231-
char space[sizeof(IMAGEHLP_SYMBOL64) + kMaxSymName + 1];
232-
auto* sym = (IMAGEHLP_SYMBOL64*)space;
233-
sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
234-
sym->MaxNameLength = kMaxSymName;
235-
uint64_t symdisp{0};
162+
for (_Entry& entry : __entry_iters_()) {
163+
char space[sizeof(IMAGEHLP_SYMBOL) + _Entry::__max_sym_len + 1];
164+
IMAGEHLP_SYMBOL* sym = reinterpret_cast<IMAGEHLP_SYMBOL*>(space);
165+
sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
166+
sym->MaxNameLength = _Entry::__max_sym_len;
167+
uintptr_t symdisp{0};
236168
DWORD linedisp{0};
237-
IMAGEHLP_LINE64 line;
238-
if ((*dbghelp.SymGetSymFromAddr64)(proc, entry.__addr_, &symdisp, sym)) {
169+
IMAGEHLP_LINE line;
170+
if (SymGetSymFromAddr(proc, entry.__addr_, &symdisp, sym)) {
239171
entry.__desc_.assign(sym->Name);
240172
}
241-
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
242-
if ((*dbghelp.SymGetLineFromAddr64)(proc, entry.__addr_, &linedisp, &line)) {
173+
line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
174+
if (SymGetLineFromAddr(proc, entry.__addr_, &linedisp, &line)) {
243175
entry.__file_.assign(line.FileName);
244176
entry.__line_ = line.LineNumber;
245177
}
@@ -249,4 +181,4 @@ _Trace::windows_impl(size_t skip, size_t max_depth) {
249181
} // namespace __stacktrace
250182
_LIBCPP_END_NAMESPACE_STD
251183

252-
#endif // _WIN32
184+
#endif // _WIN32

0 commit comments

Comments
 (0)