Skip to content

Commit e2c7ec6

Browse files
authored
Merge pull request swiftlang#75108 from al45tair/eng/PR-130992923
[Runtime][Win32] Fix fatalError() backtraces.
2 parents c345ba9 + a72c167 commit e2c7ec6

File tree

4 files changed

+195
-36
lines changed

4 files changed

+195
-36
lines changed

stdlib/public/runtime/Errors.cpp

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -102,25 +102,31 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName,
102102
// providing failure status instead of just returning the original string like
103103
// swift demangle.
104104
#if defined(_WIN32)
105-
char szUndName[1024];
106-
DWORD dwResult;
107-
dwResult = _swift_win32_withDbgHelpLibrary([&] (HANDLE hProcess) -> DWORD {
108-
if (!hProcess) {
109-
return 0;
110-
}
111-
112-
DWORD dwFlags = UNDNAME_COMPLETE;
105+
const char *szSymbolName = syminfo.getSymbolName();
106+
107+
// UnDecorateSymbolName() will not fail for Swift symbols, so detect them
108+
// up-front and let Swift handle them.
109+
if (!Demangle::isMangledName(szSymbolName)) {
110+
char szUndName[1024];
111+
DWORD dwResult;
112+
dwResult = _swift_win32_withDbgHelpLibrary([&] (HANDLE hProcess) -> DWORD {
113+
if (!hProcess) {
114+
return 0;
115+
}
116+
117+
DWORD dwFlags = UNDNAME_COMPLETE;
113118
#if !defined(_WIN64)
114-
dwFlags |= UNDNAME_32_BIT_DECODE;
119+
dwFlags |= UNDNAME_32_BIT_DECODE;
115120
#endif
116121

117-
return UnDecorateSymbolName(syminfo.getSymbolName(), szUndName,
118-
sizeof(szUndName), dwFlags);
119-
});
122+
return UnDecorateSymbolName(szSymbolName, szUndName,
123+
sizeof(szUndName), dwFlags);
124+
});
120125

121-
if (dwResult) {
122-
symbolName += szUndName;
123-
return true;
126+
if (dwResult) {
127+
symbolName += szUndName;
128+
return true;
129+
}
124130
}
125131
#else
126132
int status;
@@ -151,6 +157,9 @@ void swift::dumpStackTraceEntry(unsigned index, void *framePC,
151157
#if SWIFT_STDLIB_SUPPORTS_BACKTRACE_REPORTING && SWIFT_STDLIB_HAS_DLADDR
152158
auto syminfo = SymbolInfo::lookup(framePC);
153159
if (!syminfo.has_value()) {
160+
constexpr const char *format = "%-4u %-34s 0x%0.16tx\n";
161+
fprintf(stderr, format, index, "<unknown>",
162+
reinterpret_cast<uintptr_t>(framePC));
154163
return;
155164
}
156165

@@ -159,7 +168,12 @@ void swift::dumpStackTraceEntry(unsigned index, void *framePC,
159168
// is not provided in the header so that it requires linking with
160169
// libSupport.a.
161170
llvm::StringRef libraryName{syminfo->getFilename()};
171+
172+
#ifdef _WIN32
173+
libraryName = libraryName.substr(libraryName.rfind('\\')).substr(1);
174+
#else
162175
libraryName = libraryName.substr(libraryName.rfind('/')).substr(1);
176+
#endif
163177

164178
// Next we get the symbol name that we are going to use in our backtrace.
165179
std::string symbolName;
@@ -179,6 +193,11 @@ void swift::dumpStackTraceEntry(unsigned index, void *framePC,
179193
symbolName = "<unavailable>";
180194
}
181195

196+
const char *libraryNameStr = libraryName.data();
197+
198+
if (!libraryNameStr)
199+
libraryNameStr = "<unknown>";
200+
182201
// We do not use %p here for our pointers since the format is implementation
183202
// defined. This makes it logically impossible to check the output. Forcing
184203
// hexadecimal solves this issue.
@@ -187,11 +206,11 @@ void swift::dumpStackTraceEntry(unsigned index, void *framePC,
187206
// This gives enough info to reconstruct identical debugging target after
188207
// this process terminates.
189208
if (shortOutput) {
190-
fprintf(stderr, "%s`%s + %td", libraryName.data(), symbolName.c_str(),
209+
fprintf(stderr, "%s`%s + %td", libraryNameStr, symbolName.c_str(),
191210
offset);
192211
} else {
193212
constexpr const char *format = "%-4u %-34s 0x%0.16" PRIxPTR " %s + %td\n";
194-
fprintf(stderr, format, index, libraryName.data(), symbolAddr,
213+
fprintf(stderr, format, index, libraryNameStr, symbolAddr,
195214
symbolName.c_str(), offset);
196215
}
197216
#else

stdlib/public/runtime/ImageInspectionCOFF.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ using namespace swift;
3131
#if defined(_WIN32)
3232
static LazyMutex mutex;
3333
static HANDLE dbgHelpHandle = nullptr;
34+
static bool isDbgHelpInitialized = false;
3435

3536
void _swift_win32_withDbgHelpLibrary(
3637
void (* body)(HANDLE hProcess, void *context), void *context) {
@@ -54,8 +55,7 @@ void _swift_win32_withDbgHelpLibrary(
5455
}
5556

5657
// If we have not previously initialized the Debug Help library, do so now.
57-
bool isDbgHelpInitialized = false;
58-
if (dbgHelpHandle) {
58+
if (dbgHelpHandle && !isDbgHelpInitialized) {
5959
isDbgHelpInitialized = SymInitialize(dbgHelpHandle, nullptr, true);
6060
}
6161

stdlib/public/runtime/SymbolInfo.cpp

Lines changed: 92 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define NOMINMAX
1818
#include <Windows.h>
1919
#include <DbgHelp.h>
20+
#include <psapi.h>
2021
#elif SWIFT_STDLIB_HAS_DLADDR
2122
#include <dlfcn.h>
2223
#endif
@@ -29,7 +30,7 @@ using namespace swift;
2930

3031
const char *SymbolInfo::getFilename() const {
3132
#if defined(_WIN32) && !defined(__CYGWIN__)
32-
return nullptr;
33+
return _moduleFileName;
3334
#elif SWIFT_STDLIB_HAS_DLADDR
3435
return _info.dli_fname;
3536
#else
@@ -39,7 +40,7 @@ const char *SymbolInfo::getFilename() const {
3940

4041
const void *SymbolInfo::getBaseAddress() const {
4142
#if defined(_WIN32) && !defined(__CYGWIN__)
42-
return reinterpret_cast<const void *>(_package.si.ModBase);
43+
return _moduleBaseAddress;
4344
#elif SWIFT_STDLIB_HAS_DLADDR
4445
return _info.dli_fbase;
4546
#else
@@ -49,7 +50,7 @@ const void *SymbolInfo::getBaseAddress() const {
4950

5051
const char *SymbolInfo::getSymbolName() const {
5152
#if defined(_WIN32) && !defined(__CYGWIN__)
52-
return _package.si.Name;
53+
return _symbolName;
5354
#elif SWIFT_STDLIB_HAS_DLADDR
5455
return _info.dli_sname;
5556
#else
@@ -59,42 +60,117 @@ const char *SymbolInfo::getSymbolName() const {
5960

6061
const void *SymbolInfo::getSymbolAddress() const {
6162
#if defined(_WIN32) && !defined(__CYGWIN__)
62-
return reinterpret_cast<const void *>(_package.si.Address);
63+
return _symbolAddress;
6364
#elif SWIFT_STDLIB_HAS_DLADDR
6465
return _info.dli_saddr;
6566
#else
6667
return nullptr;
6768
#endif
6869
}
6970

70-
std::optional<SymbolInfo> SymbolInfo::lookup(const void *address) {
71-
std::optional<SymbolInfo> result;
71+
#if defined(_WIN32) && !defined(__CYGWIN__)
72+
struct Win32ModuleInfo {
73+
const char *name;
74+
const void *base;
75+
};
76+
77+
// Get the filename and base of the module that contains the specified
78+
// address. N.B. This returns a `malloc`-ed copy of the filename in the
79+
// Win32ModuleInfo struct; you are responsible for freeing that.
80+
static Win32ModuleInfo moduleInfoFromAddress(const void *address) {
81+
HMODULE hModule;
82+
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
83+
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
84+
(LPCTSTR)address,
85+
&hModule)) {
86+
MODULEINFO mi;
87+
88+
if (!GetModuleInformation(GetCurrentProcess(), hModule,
89+
&mi, sizeof(mi))) {
90+
ZeroMemory(&mi, sizeof(mi));
91+
}
92+
93+
WCHAR wszBuffer[256];
94+
LPWSTR pwszFileName = wszBuffer;
95+
DWORD dwCapacity = sizeof(wszBuffer) / sizeof(*wszBuffer);
96+
DWORD dwRet = GetModuleFileNameW(hModule, pwszFileName, dwCapacity);
7297

98+
if (dwRet == dwCapacity) {
99+
dwCapacity = 512;
100+
101+
pwszFileName = (LPWSTR)::malloc(sizeof(WCHAR) * dwCapacity);
102+
while (true) {
103+
dwRet = GetModuleFileNameW(hModule, pwszFileName, dwCapacity);
104+
if (dwRet != dwCapacity)
105+
break;
106+
107+
dwCapacity *= 2;
108+
109+
pwszFileName = (LPWSTR)::realloc(pwszFileName,
110+
sizeof(WCHAR) * dwCapacity);
111+
}
112+
}
113+
114+
if (dwRet == 0) {
115+
if (pwszFileName != wszBuffer)
116+
::free(pwszFileName);
117+
118+
return { ::strdup("<unknown>"), mi.lpBaseOfDll };
119+
}
120+
121+
const char *result = _swift_win32_copyUTF8FromWide(pwszFileName);
122+
123+
if (pwszFileName != wszBuffer)
124+
::free((void *)pwszFileName);
125+
126+
return { result, mi.lpBaseOfDll };
127+
} else {
128+
return { ::strdup("<unknown>"), nullptr };
129+
}
130+
}
131+
#endif
132+
133+
std::optional<SymbolInfo> SymbolInfo::lookup(const void *address) {
73134
#if defined(__wasm__)
74135
// Currently, Wasm doesn't have a standard stable ABI for exporting address <->
75136
// symbol table, it's work in progress. Also, there is no API to access such
76137
// information from Wasm binary side. It's accessible only from host VM.
77138
// See https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
78139
#elif defined(_WIN32) && !defined(__CYGWIN__)
140+
Win32ModuleInfo moduleInfo = moduleInfoFromAddress(address);
141+
SYMBOL_INFO_PACKAGE package;
142+
BOOL bRet;
143+
144+
package.si.SizeOfStruct = sizeof(SYMBOL_INFO);
145+
package.si.MaxNameLen = MAX_SYM_NAME;
146+
79147
_swift_win32_withDbgHelpLibrary([&] (HANDLE hProcess) {
80148
if (!hProcess) {
81-
return;
149+
bRet = false;
150+
return;
82151
}
83152

84-
SymbolInfo info;
85-
info._package.si.SizeOfStruct = sizeof(SYMBOL_INFO);
86-
info._package.si.MaxNameLen = MAX_SYM_NAME;
87-
if (SymFromAddr(hProcess, reinterpret_cast<const DWORD64>(address),
88-
nullptr, &info._package.si)) {
89-
result = info;
90-
}
153+
bRet = SymFromAddr(hProcess, reinterpret_cast<const DWORD64>(address),
154+
nullptr, &package.si);
91155
});
156+
157+
if (bRet) {
158+
return SymbolInfo((const void *)package.si.Address,
159+
::strdup(package.si.Name),
160+
moduleInfo.name,
161+
moduleInfo.base);
162+
} else {
163+
return SymbolInfo(address,
164+
nullptr,
165+
moduleInfo.name,
166+
moduleInfo.base);
167+
}
92168
#elif SWIFT_STDLIB_HAS_DLADDR
93169
SymbolInfo info;
94170
if (dladdr(address, &info._info)) {
95-
result = info;
171+
return info;
96172
}
97173
#endif
98174

99-
return result;
175+
return {};
100176
}

stdlib/public/runtime/SymbolInfo.h

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,77 @@ namespace swift {
4343
struct SymbolInfo {
4444
private:
4545
#if defined(_WIN32) && !defined(__CYGWIN__)
46-
SYMBOL_INFO_PACKAGE _package;
46+
const void *_symbolAddress;
47+
const char *_symbolName;
48+
const char *_moduleFileName;
49+
const void *_moduleBaseAddress;
4750
#elif SWIFT_STDLIB_HAS_DLADDR
4851
Dl_info _info;
4952
#endif
5053

54+
#if defined(_WIN32) && !defined(__CYGWIN__)
55+
SymbolInfo(const void *symbolAddress,
56+
const char *symbolName,
57+
const char *moduleFileName,
58+
const void *moduleBaseAddress)
59+
: _symbolAddress(symbolAddress),
60+
_symbolName(symbolName),
61+
_moduleFileName(moduleFileName),
62+
_moduleBaseAddress(moduleBaseAddress)
63+
{}
64+
65+
void initializeFrom(const SymbolInfo &other) {
66+
_symbolAddress = other._symbolAddress;
67+
_symbolName = ::strdup(other._symbolName);
68+
_moduleFileName = ::strdup(other._moduleFileName);
69+
_moduleBaseAddress = other._moduleBaseAddress;
70+
}
71+
72+
void deinitialize() {
73+
::free((void *)_moduleFileName);
74+
::free((void *)_symbolName);
75+
_moduleFileName = nullptr;
76+
_symbolName = nullptr;
77+
}
78+
#endif
79+
5180
public:
81+
#if defined(_WIN32) && !defined(__CYGWIN__)
82+
SymbolInfo() : _symbolName(nullptr), _moduleFileName(nullptr) {}
83+
84+
SymbolInfo(const SymbolInfo &other) {
85+
initializeFrom(other);
86+
}
87+
SymbolInfo(SymbolInfo &&other) {
88+
*this = std::move(other);
89+
}
90+
~SymbolInfo() {
91+
deinitialize();
92+
}
93+
94+
SymbolInfo &operator=(const SymbolInfo &other) {
95+
if (this != &other) {
96+
deinitialize();
97+
initializeFrom(other);
98+
}
99+
100+
return *this;
101+
}
102+
SymbolInfo &operator=(SymbolInfo &&other) {
103+
if (this != &other) {
104+
_symbolAddress = other._symbolAddress;
105+
_symbolName = other._symbolName;
106+
other._symbolName = nullptr;
107+
_moduleFileName = other._moduleFileName;
108+
other._moduleFileName = nullptr;
109+
_moduleBaseAddress = other._moduleBaseAddress;
110+
}
111+
112+
return *this;
113+
}
114+
#else
52115
SymbolInfo() {}
116+
#endif
53117

54118
/// Get the file name of the image where the symbol was found.
55119
///

0 commit comments

Comments
 (0)