yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Jay KwakFix intermittent failure of slang-unit-test-tool/ReplayRecord (#6981)1b539d890

master
5.8 KiB203 linesraw
1#include "common.h"
2
3#include <inttypes.h>
4#include <string>
5#include <vector>
6#include <windows.h>
7
8// dbghelp.h needs to be included after windows.h
9#include <dbghelp.h>
10
11#define SLANG_EXAMPLE_LOG_ERROR(...)                      \
12    fprintf(file, "error: %s: %d: ", __FILE__, __LINE__); \
13    print(file, __VA_ARGS__);                             \
14    fprintf(file, "\n");
15
16static void print(FILE* /* file */) {}
17static void print(FILE* file, unsigned int n)
18{
19    fprintf(file, "%u", n);
20}
21
22
23static bool getModuleFileNameAtAddress(FILE* file, DWORD64 const address, std::string& fileName)
24{
25    HMODULE module = NULL;
26    {
27        BOOL result = GetModuleHandleEx(
28            GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
29            (LPCTSTR)address,
30            &module);
31        if (result == 0)
32        {
33            SLANG_EXAMPLE_LOG_ERROR(GetLastError());
34            return false;
35        }
36        if (module == NULL)
37        {
38            SLANG_EXAMPLE_LOG_ERROR();
39            return false;
40        }
41    }
42
43    std::vector<char> buffer(1U << 8U);
44    uint32_t constexpr maxBufferSize = 1U << 20;
45    while (buffer.size() < maxBufferSize)
46    {
47        DWORD result = GetModuleFileNameA(module, buffer.data(), buffer.size());
48        if (result == 0)
49        {
50            SLANG_EXAMPLE_LOG_ERROR(GetLastError());
51            return false;
52        }
53        else if (result == ERROR_INSUFFICIENT_BUFFER)
54        {
55            buffer.resize(buffer.size() << 1U);
56        }
57        else
58        {
59            break;
60        }
61    }
62    if (buffer.size() == maxBufferSize)
63    {
64        SLANG_EXAMPLE_LOG_ERROR();
65        return false;
66    }
67
68    fileName = std::string(buffer.data(), buffer.data() + buffer.size());
69    return true;
70}
71
72// NOTE: This function is not thread-safe, due to usage of StackWalk64 and static buffers.
73static bool printStack(FILE* file, HANDLE process, HANDLE thread, CONTEXT const& context)
74{
75#if defined(_M_AMD64)
76    DWORD constexpr machineType = IMAGE_FILE_MACHINE_AMD64;
77#elif defined(_M_ARM64)
78    DWORD constexpr machineType = IMAGE_FILE_MACHINE_ARM64;
79#else
80#error Unsupported machine type
81#endif
82
83    static char symbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
84
85    // StackWalk64 may modify the context record
86    CONTEXT contextCopy;
87    memcpy(&contextCopy, &context, sizeof(CONTEXT));
88
89    STACKFRAME64 frame = {};
90    constexpr uint32_t maxFrameCount = 1U << 10;
91    uint32_t frameIndex = 0U;
92    while (frameIndex < maxFrameCount)
93    {
94        // Use the default routine
95        PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryRoutine = NULL;
96        // Not sure what this is for, but documentation says most callers can pass NULL
97        PTRANSLATE_ADDRESS_ROUTINE64 translateAddressRoutine = NULL;
98        {
99            BOOL result = StackWalk64(
100                machineType,
101                process,
102                thread,
103                &frame,
104                &contextCopy,
105                readMemoryRoutine,
106                SymFunctionTableAccess64,
107                SymGetModuleBase64,
108                translateAddressRoutine);
109            if (result == FALSE)
110                break;
111        }
112
113        PSYMBOL_INFO maybeSymbol = (PSYMBOL_INFO)symbolBuffer;
114        {
115            maybeSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
116            maybeSymbol->MaxNameLen = MAX_SYM_NAME;
117            DWORD64 address = frame.AddrPC.Offset;
118            // Not required, we want to look up the symbol exactly at the address
119            PDWORD64 displacement = NULL;
120            BOOL result = SymFromAddr(process, address, displacement, maybeSymbol);
121            if (result == FALSE)
122            {
123                SLANG_EXAMPLE_LOG_ERROR(GetLastError());
124                maybeSymbol = NULL;
125            }
126        }
127
128        fprintf(file, "%u", frameIndex);
129
130        std::string moduleFileName;
131        if (getModuleFileNameAtAddress(file, frame.AddrPC.Offset, moduleFileName))
132            fprintf(file, ": %s", moduleFileName.c_str());
133
134        if (maybeSymbol)
135        {
136            PSYMBOL_INFO& symbol = maybeSymbol;
137
138            IMAGEHLP_LINE64 line = {};
139            line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
140
141            DWORD displacement;
142            if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &displacement, &line))
143            {
144                fprintf(file, ": %s: %s: %lu", symbol->Name, line.FileName, line.LineNumber);
145            }
146            else
147            {
148                fprintf(file, ": %s", symbol->Name);
149            }
150
151            fprintf(file, ": 0x%.16" PRIXPTR, symbol->Address);
152        }
153        fprintf(file, "\n");
154
155        frameIndex++;
156    }
157
158    return frameIndex < maxFrameCount;
159}
160
161int exceptionFilter(FILE* logFile, _EXCEPTION_POINTERS* exception)
162{
163    FILE* file = logFile ? logFile : stdout;
164    fprintf(
165        file,
166        "error: Exception 0x%lx occurred. Stack trace:\n",
167        exception->ExceptionRecord->ExceptionCode);
168
169    HANDLE process = GetCurrentProcess();
170    HANDLE thread = GetCurrentThread();
171
172    bool symbolsLoaded = false;
173    {
174        // The default search paths should suffice
175        PCSTR symbolFileSearchPath = NULL;
176        BOOL loadSymbolsOfLoadedModules = TRUE;
177        BOOL result = SymInitialize(process, symbolFileSearchPath, loadSymbolsOfLoadedModules);
178        if (result == FALSE)
179        {
180            fprintf(file, "warning: Failed to load symbols\n");
181        }
182        else
183        {
184            symbolsLoaded = true;
185        }
186    }
187
188    if (!printStack(file, process, thread, *exception->ContextRecord))
189    {
190        fprintf(file, "warning: Failed to print complete stack trace!\n");
191    }
192
193    if (symbolsLoaded)
194    {
195        BOOL result = SymCleanup(process);
196        if (result == FALSE)
197        {
198            SLANG_EXAMPLE_LOG_ERROR(GetLastError());
199        }
200    }
201
202    return EXCEPTION_EXECUTE_HANDLER;
203}