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
2325namespace __stacktrace {
2426
2527namespace {
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-
9729struct _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