Skip to content

Commit e68ba40

Browse files
break up win impl
1 parent f8c37b2 commit e68ba40

File tree

7 files changed

+283
-36
lines changed

7 files changed

+283
-36
lines changed

libcxx/src/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ set(LIBCXX_SOURCES
4646
stacktrace/to_string.cpp
4747
stacktrace/tools.cpp
4848
stacktrace/unwind.cpp
49-
stacktrace/windows.cpp
49+
stacktrace/win/dll.cpp
50+
stacktrace/win/impl.cpp
5051
stdexcept.cpp
5152
string.cpp
5253
support/runtime/exception_fallback.ipp

libcxx/src/stacktrace/builder.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616
#include "stacktrace/macos.h"
1717
#include "stacktrace/tools.h"
1818
#include "stacktrace/unwind.h"
19-
#include "stacktrace/utils.h"
20-
#include "stacktrace/windows.h"
19+
#include "stacktrace/utils/debug.h"
20+
#include "stacktrace/utils/failed.h"
21+
#include "stacktrace/utils/fd.h"
22+
#include "stacktrace/win/dll.h"
23+
#include "stacktrace/win/impl.h"
2124

2225
_LIBCPP_BEGIN_NAMESPACE_STD
2326

libcxx/src/stacktrace/config.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,4 @@
3333
# define _LIBCPP_STACKTRACE_CAN_SPAWN_TOOLS
3434
#endif
3535

36-
#if defined(_LIBCPP_WIN32API)
37-
# define _LIBCPP_STACKTRACE_WINDOWS
38-
#endif
39-
4036
#endif // _LIBCPP_STACKTRACE_CONFIG_H

libcxx/src/stacktrace/windows.cpp renamed to libcxx/src/stacktrace/win/dll.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include "stacktrace/config.h"
9+
#include <__config>
1010

11-
#if defined(_LIBCPP_STACKTRACE_WINDOWS)
11+
#if defined(_LIBCPP_WIN32API)
1212

1313
# include <__stacktrace/base.h>
1414

1515
# include "stacktrace/alloc.h"
1616
# include "stacktrace/config.h"
1717
# include "stacktrace/utils.h"
18-
# include "stacktrace/windows.h"
18+
# include "stacktrace/win/dll.h"
19+
# include "stacktrace/win/impl.h"
1920

2021
_LIBCPP_BEGIN_NAMESPACE_STD
2122
namespace __stacktrace {
@@ -243,4 +244,4 @@ if (!getFunc(&EnumProcessModules, "EnumProcessModules")) { return; }
243244
} // namespace __stacktrace
244245
_LIBCPP_END_NAMESPACE_STD
245246

246-
#endif // _LIBCPP_STACKTRACE_WINDOWS
247+
#endif // _LIBCPP_WIN32API

libcxx/src/stacktrace/windows.h renamed to libcxx/src/stacktrace/win/dll.h

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,31 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#ifndef _LIBCPP_STACKTRACE_WIN_IMPL_H
10-
#define _LIBCPP_STACKTRACE_WIN_IMPL_H
9+
#ifndef _LIBCPP_STACKTRACE_WIN_DLL
10+
#define _LIBCPP_STACKTRACE_WIN_DLL
1111

12-
#include "stacktrace/config.h"
12+
#include <__config>
13+
#if defined(_LIBCPP_WIN32API)
1314

14-
#if defined(_LIBCPP_STACKTRACE_WINDOWS)
1515
// windows.h must be first
1616
# include <windows.h>
1717
// other windows-specific headers
1818
# include <dbghelp.h>
1919
# define PSAPI_VERSION 1
2020
# include <psapi.h>
21-
#endif
2221

23-
#include <__config>
24-
#include <__config_site>
25-
#include <cstddef>
26-
#include <cstdlib>
27-
#include <mutex>
22+
# include <__config_site>
23+
# include <cstddef>
24+
# include <cstdlib>
25+
# include <mutex>
26+
# include <stacktrace>
2827

29-
#include <__stacktrace/base.h>
28+
# include "stacktrace/utils/debug.h"
3029

3130
_LIBCPP_BEGIN_NAMESPACE_STD
3231
namespace __stacktrace {
3332

34-
struct win_impl {
35-
builder& builder_;
36-
std::lock_guard<std::mutex> guard_;
37-
win_impl(builder& trace);
38-
~win_impl();
39-
40-
void collect(size_t skip, size_t max_depth);
41-
void ident_modules();
42-
void symbolize();
43-
void resolve_lines();
44-
};
45-
46-
#if defined(_LIBCPP_STACKTRACE_WINDOWS)
33+
# if defined(_LIBCPP_WIN32API)
4734

4835
// clang-format off
4936

@@ -130,4 +117,5 @@ struct psapi_dll final : dll {
130117
} // namespace __stacktrace
131118
_LIBCPP_END_NAMESPACE_STD
132119

133-
#endif // _LIBCPP_STACKTRACE_WIN_IMPL_H
120+
#endif // _LIBCPP_WIN32API
121+
#endif // _LIBCPP_STACKTRACE_WIN_DLL

libcxx/src/stacktrace/win/impl.cpp

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

libcxx/src/stacktrace/win/impl.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP_STACKTRACE_WIN_IMPL_H
10+
#define _LIBCPP_STACKTRACE_WIN_IMPL_H
11+
12+
#include <__config>
13+
#include <__config_site>
14+
#include <cstddef>
15+
#include <cstdlib>
16+
#include <mutex>
17+
18+
_LIBCPP_BEGIN_NAMESPACE_STD
19+
namespace __stacktrace {
20+
21+
struct builder;
22+
23+
struct win_impl {
24+
builder& builder_;
25+
std::lock_guard<std::mutex> guard_;
26+
win_impl(builder& trace);
27+
~win_impl();
28+
29+
void collect(size_t skip, size_t max_depth);
30+
void ident_modules();
31+
void symbolize();
32+
void resolve_lines();
33+
};
34+
35+
} // namespace __stacktrace
36+
_LIBCPP_END_NAMESPACE_STD
37+
38+
#endif // _LIBCPP_STACKTRACE_WIN_IMPL_H

0 commit comments

Comments
 (0)