Skip to content

Commit 53173e4

Browse files
mujacicaclaude
andcommitted
Add PE code_id for Windows modules in native crash events
Extract PE TimeDateStamp from module files on disk and include code_id (timestamp + size) in debug_meta images. This helps Sentry identify Windows PE modules even without full PDB debug info. The code_id format is "{TimeDateStamp:08X}{SizeOfImage:x}" which matches the Windows symbol server convention. Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent e68b2b5 commit 53173e4

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

src/backends/native/sentry_crash_daemon.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,53 @@ enumerate_threads_from_proc(sentry_crash_context_t *ctx)
10371037
# include <psapi.h>
10381038
# include <tlhelp32.h>
10391039

1040+
/**
1041+
* Extract PE TimeDateStamp from a module file for code_id
1042+
* Returns 0 on failure
1043+
*/
1044+
static DWORD
1045+
get_pe_timestamp(const char *module_path)
1046+
{
1047+
HANDLE hFile = CreateFileA(module_path, GENERIC_READ, FILE_SHARE_READ, NULL,
1048+
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1049+
if (hFile == INVALID_HANDLE_VALUE) {
1050+
return 0;
1051+
}
1052+
1053+
// Read DOS header
1054+
IMAGE_DOS_HEADER dos_header;
1055+
DWORD bytes_read;
1056+
if (!ReadFile(hFile, &dos_header, sizeof(dos_header), &bytes_read, NULL)
1057+
|| bytes_read != sizeof(dos_header) || dos_header.e_magic != 0x5A4D) {
1058+
CloseHandle(hFile);
1059+
return 0;
1060+
}
1061+
1062+
// Seek to PE header
1063+
if (SetFilePointer(hFile, dos_header.e_lfanew, NULL, FILE_BEGIN)
1064+
== INVALID_SET_FILE_POINTER) {
1065+
CloseHandle(hFile);
1066+
return 0;
1067+
}
1068+
1069+
// Read PE signature and COFF header
1070+
DWORD pe_sig;
1071+
IMAGE_FILE_HEADER coff_header;
1072+
if (!ReadFile(hFile, &pe_sig, sizeof(pe_sig), &bytes_read, NULL)
1073+
|| bytes_read != sizeof(pe_sig) || pe_sig != 0x00004550) {
1074+
CloseHandle(hFile);
1075+
return 0;
1076+
}
1077+
if (!ReadFile(hFile, &coff_header, sizeof(coff_header), &bytes_read, NULL)
1078+
|| bytes_read != sizeof(coff_header)) {
1079+
CloseHandle(hFile);
1080+
return 0;
1081+
}
1082+
1083+
CloseHandle(hFile);
1084+
return coff_header.TimeDateStamp;
1085+
}
1086+
10401087
/**
10411088
* Capture modules from the crashed process for debug_meta on Windows
10421089
*/
@@ -1384,6 +1431,21 @@ build_native_crash_event(const sentry_crash_context_t *ctx,
13841431
sentry_value_set_by_key(image, "image_size",
13851432
sentry_value_new_double((double)mod->size));
13861433

1434+
#if defined(SENTRY_PLATFORM_WINDOWS)
1435+
// Set code_id for PE modules (TimeDateStamp + SizeOfImage)
1436+
// This helps Sentry identify the module without full debug info
1437+
if (mod->name[0]) {
1438+
DWORD timestamp = get_pe_timestamp(mod->name);
1439+
if (timestamp != 0) {
1440+
char code_id_buf[32];
1441+
snprintf(code_id_buf, sizeof(code_id_buf), "%08X%x",
1442+
timestamp, (unsigned int)mod->size);
1443+
sentry_value_set_by_key(
1444+
image, "code_id", sentry_value_new_string(code_id_buf));
1445+
}
1446+
}
1447+
#endif
1448+
13871449
// Set debug_id from UUID
13881450
sentry_uuid_t uuid
13891451
= sentry_uuid_from_bytes((const char *)mod->uuid);

0 commit comments

Comments
 (0)