Skip to content

Commit 06aad7e

Browse files
committed
Crash handler: Always log registers (creating a full .dmp can fail)
1 parent 5e2e2c5 commit 06aad7e

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed

Client/core/CCrashDumpWriter.cpp

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,181 @@ constexpr DWORD Milliseconds(std::chrono::milliseconds duration)
8282

8383
class CClientBase;
8484

85+
// Record crash registers in scenario that a failure to create .dmp is likely
86+
namespace EmergencyCrashLogging
87+
{
88+
// Result codes for SEH-protected read operations
89+
enum class ReadResult : int
90+
{
91+
Success = 1,
92+
NullPointer = 0,
93+
AccessFault = -1
94+
};
95+
96+
static void DoAddReportLog(int id, const char* msg)
97+
{
98+
SharedUtil::AddReportLog(id, msg);
99+
}
100+
101+
static bool TryAddReportLog(int id, const char* msg)
102+
{
103+
__try
104+
{
105+
DoAddReportLog(id, msg);
106+
return true;
107+
}
108+
__except (EXCEPTION_EXECUTE_HANDLER)
109+
{
110+
return false;
111+
}
112+
}
113+
114+
static void SafeEmergencyLog(const char* msg)
115+
{
116+
// Always output to debugger first (guaranteed crash-safe)
117+
OutputDebugStringA(msg);
118+
OutputDebugStringA("\n");
119+
120+
TryAddReportLog(9800, msg);
121+
}
122+
123+
// SEH-isolated reader for exception record
124+
#pragma warning(push)
125+
#pragma warning(disable: 4702)
126+
static ReadResult TryReadExceptionRecord(const _EXCEPTION_POINTERS* pException,
127+
char* buf, size_t bufSize)
128+
{
129+
ReadResult result = ReadResult::AccessFault;
130+
__try
131+
{
132+
if (pException->ExceptionRecord != nullptr)
133+
{
134+
sprintf_s(buf, bufSize, "Code=0x%08lX Addr=0x%08lX ThreadId=%lu",
135+
static_cast<unsigned long>(pException->ExceptionRecord->ExceptionCode),
136+
static_cast<unsigned long>(reinterpret_cast<uintptr_t>(
137+
pException->ExceptionRecord->ExceptionAddress)),
138+
static_cast<unsigned long>(GetCurrentThreadId()));
139+
result = ReadResult::Success;
140+
}
141+
else
142+
{
143+
result = ReadResult::NullPointer;
144+
}
145+
}
146+
__except (EXCEPTION_EXECUTE_HANDLER)
147+
{
148+
result = ReadResult::AccessFault;
149+
}
150+
return result;
151+
}
152+
153+
// SEH-isolated reader for context record
154+
static ReadResult TryReadContextRecord(const _EXCEPTION_POINTERS* pException,
155+
char* buf1, size_t buf1Size,
156+
char* buf2, size_t buf2Size)
157+
{
158+
ReadResult result = ReadResult::AccessFault;
159+
__try
160+
{
161+
if (pException->ContextRecord != nullptr)
162+
{
163+
const CONTEXT* ctx = pException->ContextRecord;
164+
165+
sprintf_s(buf1, buf1Size, "EAX=0x%08lX EBX=0x%08lX ECX=0x%08lX EDX=0x%08lX",
166+
ctx->Eax, ctx->Ebx, ctx->Ecx, ctx->Edx);
167+
168+
sprintf_s(buf2, buf2Size, "ESI=0x%08lX EDI=0x%08lX EBP=0x%08lX ESP=0x%08lX EIP=0x%08lX EFL=0x%08lX",
169+
ctx->Esi, ctx->Edi, ctx->Ebp, ctx->Esp, ctx->Eip, ctx->EFlags);
170+
171+
result = ReadResult::Success;
172+
}
173+
else
174+
{
175+
result = ReadResult::NullPointer;
176+
}
177+
}
178+
__except (EXCEPTION_EXECUTE_HANDLER)
179+
{
180+
result = ReadResult::AccessFault;
181+
}
182+
return result;
183+
}
184+
#pragma warning(pop)
185+
186+
} // namespace EmergencyCrashLogging
187+
188+
// Call SEH-isolated readers
189+
static void LogEmergencyExceptionRecord(const _EXCEPTION_POINTERS* pException)
190+
{
191+
using namespace EmergencyCrashLogging;
192+
193+
std::array<char, 128> buf{};
194+
195+
const auto result = TryReadExceptionRecord(pException, buf.data(), buf.size());
196+
197+
switch (result)
198+
{
199+
case ReadResult::Success:
200+
SafeEmergencyLog(buf.data());
201+
break;
202+
case ReadResult::NullPointer:
203+
SafeEmergencyLog("[!] ExceptionRecord is NULL");
204+
break;
205+
case ReadResult::AccessFault:
206+
SafeEmergencyLog("[!] Fault reading ExceptionRecord");
207+
break;
208+
default:
209+
SafeEmergencyLog("[!] Unknown result reading ExceptionRecord");
210+
break;
211+
}
212+
}
213+
214+
static void LogEmergencyContextRecord(const _EXCEPTION_POINTERS* pException)
215+
{
216+
using namespace EmergencyCrashLogging;
217+
218+
std::array<char, 128> buf1{};
219+
std::array<char, 128> buf2{};
220+
221+
const auto result = TryReadContextRecord(pException,
222+
buf1.data(), buf1.size(),
223+
buf2.data(), buf2.size());
224+
225+
switch (result)
226+
{
227+
case ReadResult::Success:
228+
SafeEmergencyLog(buf1.data());
229+
SafeEmergencyLog(buf2.data());
230+
break;
231+
case ReadResult::NullPointer:
232+
SafeEmergencyLog("[!] ContextRecord is NULL");
233+
break;
234+
case ReadResult::AccessFault:
235+
SafeEmergencyLog("[!] Fault reading context");
236+
break;
237+
default:
238+
SafeEmergencyLog("[!] Unknown result reading ContextRecord");
239+
break;
240+
}
241+
}
242+
243+
static void LogEmergencyCrashContext(const _EXCEPTION_POINTERS* pException)
244+
{
245+
using namespace EmergencyCrashLogging;
246+
247+
SafeEmergencyLog("=== EMERGENCY CRASH CONTEXT ===");
248+
249+
if (pException == nullptr)
250+
{
251+
SafeEmergencyLog("[!] pException is NULL");
252+
return;
253+
}
254+
255+
LogEmergencyExceptionRecord(pException);
256+
257+
LogEmergencyContextRecord(pException);
258+
}
259+
85260
static bool SafeReadGameByte(uintptr_t address, unsigned char& outValue)
86261
{
87262
__try
@@ -1267,6 +1442,11 @@ long WINAPI CCrashDumpWriter::HandleExceptionGlobal(_EXCEPTION_POINTERS* pExcept
12671442
// This is critical for diagnosing exceptions that may fault during handling
12681443
OutputDebugStringSafe("CCrashDumpWriter::HandleExceptionGlobal - EMERGENCY ENTRY MARKER\n");
12691444

1445+
// Log exception code and registers immediately - ensures crash context is captured
1446+
// even if subsequent processing fails and no dump is generated (stale artifact scenario)
1447+
// Uses SafeEmergencyLog internally which is SEH-protected
1448+
LogEmergencyCrashContext(pException);
1449+
12701450
SAFE_DEBUG_OUTPUT("========================================\n");
12711451
SAFE_DEBUG_OUTPUT("CCrashDumpWriter::HandleExceptionGlobal - ENTRY\n");
12721452
SAFE_DEBUG_OUTPUT("========================================\n");

0 commit comments

Comments
 (0)