Skip to content

Commit 1d91e7d

Browse files
authored
Merge pull request #75236 from al45tair/eng/PR-130992923-6.0
[Runtime][Win32] Fix fatalError() backtraces.
2 parents 935c99b + c6e40a9 commit 1d91e7d

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
@@ -100,25 +100,31 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName,
100100
// providing failure status instead of just returning the original string like
101101
// swift demangle.
102102
#if defined(_WIN32)
103-
char szUndName[1024];
104-
DWORD dwResult;
105-
dwResult = _swift_win32_withDbgHelpLibrary([&] (HANDLE hProcess) -> DWORD {
106-
if (!hProcess) {
107-
return 0;
108-
}
109-
110-
DWORD dwFlags = UNDNAME_COMPLETE;
103+
const char *szSymbolName = syminfo.getSymbolName();
104+
105+
// UnDecorateSymbolName() will not fail for Swift symbols, so detect them
106+
// up-front and let Swift handle them.
107+
if (!Demangle::isMangledName(szSymbolName)) {
108+
char szUndName[1024];
109+
DWORD dwResult;
110+
dwResult = _swift_win32_withDbgHelpLibrary([&] (HANDLE hProcess) -> DWORD {
111+
if (!hProcess) {
112+
return 0;
113+
}
114+
115+
DWORD dwFlags = UNDNAME_COMPLETE;
111116
#if !defined(_WIN64)
112-
dwFlags |= UNDNAME_32_BIT_DECODE;
117+
dwFlags |= UNDNAME_32_BIT_DECODE;
113118
#endif
114119

115-
return UnDecorateSymbolName(syminfo.getSymbolName(), szUndName,
116-
sizeof(szUndName), dwFlags);
117-
});
120+
return UnDecorateSymbolName(szSymbolName, szUndName,
121+
sizeof(szUndName), dwFlags);
122+
});
118123

119-
if (dwResult) {
120-
symbolName += szUndName;
121-
return true;
124+
if (dwResult) {
125+
symbolName += szUndName;
126+
return true;
127+
}
122128
}
123129
#else
124130
int status;
@@ -149,6 +155,9 @@ void swift::dumpStackTraceEntry(unsigned index, void *framePC,
149155
#if SWIFT_STDLIB_SUPPORTS_BACKTRACE_REPORTING && SWIFT_STDLIB_HAS_DLADDR
150156
auto syminfo = SymbolInfo::lookup(framePC);
151157
if (!syminfo.has_value()) {
158+
constexpr const char *format = "%-4u %-34s 0x%0.16tx\n";
159+
fprintf(stderr, format, index, "<unknown>",
160+
reinterpret_cast<uintptr_t>(framePC));
152161
return;
153162
}
154163

@@ -157,7 +166,12 @@ void swift::dumpStackTraceEntry(unsigned index, void *framePC,
157166
// is not provided in the header so that it requires linking with
158167
// libSupport.a.
159168
llvm::StringRef libraryName{syminfo->getFilename()};
169+
170+
#ifdef _WIN32
171+
libraryName = libraryName.substr(libraryName.rfind('\\')).substr(1);
172+
#else
160173
libraryName = libraryName.substr(libraryName.rfind('/')).substr(1);
174+
#endif
161175

162176
// Next we get the symbol name that we are going to use in our backtrace.
163177
std::string symbolName;
@@ -177,6 +191,11 @@ void swift::dumpStackTraceEntry(unsigned index, void *framePC,
177191
symbolName = "<unavailable>";
178192
}
179193

194+
const char *libraryNameStr = libraryName.data();
195+
196+
if (!libraryNameStr)
197+
libraryNameStr = "<unknown>";
198+
180199
// We do not use %p here for our pointers since the format is implementation
181200
// defined. This makes it logically impossible to check the output. Forcing
182201
// hexadecimal solves this issue.
@@ -185,11 +204,11 @@ void swift::dumpStackTraceEntry(unsigned index, void *framePC,
185204
// This gives enough info to reconstruct identical debugging target after
186205
// this process terminates.
187206
if (shortOutput) {
188-
fprintf(stderr, "%s`%s + %td", libraryName.data(), symbolName.c_str(),
207+
fprintf(stderr, "%s`%s + %td", libraryNameStr, symbolName.c_str(),
189208
offset);
190209
} else {
191210
constexpr const char *format = "%-4u %-34s 0x%0.16" PRIxPTR " %s + %td\n";
192-
fprintf(stderr, format, index, libraryName.data(), symbolAddr,
211+
fprintf(stderr, format, index, libraryNameStr, symbolAddr,
193212
symbolName.c_str(), offset);
194213
}
195214
#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)