Skip to content

Commit d46d50a

Browse files
mujacicaclaude
andcommitted
Add debug_file and fix code_id format for Windows native backend
The native backend on Windows was causing symbolicator to fail with "internal server error" because it was missing the debug_file field that minidump events include. This prevented proper symbolication. Changes: - Add pdb_name field to sentry_module_info_t struct - Extract PDB filename from PE CodeView debug directory - Set debug_file field on PE images in native crash events - Fix code_id format to use lowercase hex (matching minidump format) The debug_file field is essential for Sentry's symbolicator to know where to look for PDB files when symbolicating Windows crash events. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 0304e9f commit d46d50a

2 files changed

Lines changed: 44 additions & 11 deletions

File tree

src/backends/native/sentry_crash_context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ typedef struct {
133133
char name[SENTRY_CRASH_MAX_PATH];
134134
uint8_t uuid[16]; // Module UUID for symbolication
135135
uint32_t pdb_age; // PDB age (Windows PE only, appended to debug_id)
136+
char pdb_name[SENTRY_CRASH_MAX_PATH]; // PDB filename (Windows PE only)
136137
} sentry_module_info_t;
137138

138139
#if defined(SENTRY_PLATFORM_LINUX) || defined(SENTRY_PLATFORM_ANDROID)

src/backends/native/sentry_crash_daemon.c

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,22 +1326,27 @@ struct CodeViewRecord70 {
13261326
};
13271327

13281328
/**
1329-
* Extract PDB debug info (GUID and age) from a module in another process
1330-
* Uses ReadProcessMemory to read PE headers from the crashed process
1329+
* Extract PDB debug info (GUID, age, and filename) from a module in another
1330+
* process. Uses ReadProcessMemory to read PE headers from the crashed process.
13311331
*
13321332
* @param hProcess Handle to the crashed process
13331333
* @param module_base Base address of the module in the crashed process
13341334
* @param uuid Output: 16-byte PDB GUID (set to zeros on failure)
13351335
* @param pdb_age Output: PDB age value (set to 0 on failure)
1336+
* @param pdb_name Output: PDB filename buffer (set to empty on failure)
1337+
* @param pdb_name_size Size of pdb_name buffer
13361338
* @return true if PDB info was successfully extracted
13371339
*/
13381340
static bool
1339-
extract_pdb_info_from_process(
1340-
HANDLE hProcess, uint64_t module_base, uint8_t *uuid, uint32_t *pdb_age)
1341+
extract_pdb_info_from_process(HANDLE hProcess, uint64_t module_base,
1342+
uint8_t *uuid, uint32_t *pdb_age, char *pdb_name, size_t pdb_name_size)
13411343
{
1342-
// Initialize outputs to zero
1344+
// Initialize outputs to zero/empty
13431345
memset(uuid, 0, 16);
13441346
*pdb_age = 0;
1347+
if (pdb_name && pdb_name_size > 0) {
1348+
pdb_name[0] = '\0';
1349+
}
13451350

13461351
if (!module_base) {
13471352
return false;
@@ -1418,7 +1423,28 @@ extract_pdb_info_from_process(
14181423
// Extract age (bytes 20-23)
14191424
memcpy(pdb_age, cv_header + 20, sizeof(*pdb_age));
14201425

1421-
SENTRY_DEBUGF("Extracted PDB info: age=%u", *pdb_age);
1426+
// Extract PDB filename (variable length, null-terminated, starts at
1427+
// byte 24) The filename can be up to (SizeOfData - 24) bytes
1428+
if (pdb_name && pdb_name_size > 0) {
1429+
size_t max_filename_len = pdb_name_size - 1;
1430+
if (debug_entry.SizeOfData > 24) {
1431+
size_t available = debug_entry.SizeOfData - 24;
1432+
if (available < max_filename_len) {
1433+
max_filename_len = available;
1434+
}
1435+
}
1436+
uint64_t filename_addr = cv_addr + 24;
1437+
SIZE_T filename_read;
1438+
if (ReadProcessMemory(hProcess, (LPCVOID)(uintptr_t)filename_addr,
1439+
pdb_name, max_filename_len, &filename_read)) {
1440+
pdb_name[filename_read] = '\0';
1441+
// Ensure null termination within buffer
1442+
pdb_name[pdb_name_size - 1] = '\0';
1443+
}
1444+
}
1445+
1446+
SENTRY_DEBUGF("Extracted PDB info: age=%u, pdb=%s", *pdb_age,
1447+
pdb_name ? pdb_name : "(null)");
14221448
return true;
14231449
}
14241450

@@ -1476,9 +1502,9 @@ capture_modules_from_process(sentry_crash_context_t *ctx)
14761502
strncpy(mod->name, modName, sizeof(mod->name) - 1);
14771503
mod->name[sizeof(mod->name) - 1] = '\0';
14781504

1479-
// Extract PDB GUID and age from PE debug directory
1480-
extract_pdb_info_from_process(
1481-
hProcess, mod->base_address, mod->uuid, &mod->pdb_age);
1505+
// Extract PDB GUID, age, and filename from PE debug directory
1506+
extract_pdb_info_from_process(hProcess, mod->base_address, mod->uuid,
1507+
&mod->pdb_age, mod->pdb_name, sizeof(mod->pdb_name));
14821508

14831509
SENTRY_DEBUGF("Captured module: %s base=0x%llx size=0x%llx pdb_age=%u",
14841510
mod->name, (unsigned long long)mod->base_address,
@@ -1775,12 +1801,12 @@ build_native_crash_event(const sentry_crash_context_t *ctx,
17751801

17761802
#if defined(SENTRY_PLATFORM_WINDOWS)
17771803
// Set code_id for PE modules (TimeDateStamp + SizeOfImage)
1778-
// This helps Sentry identify the module without full debug info
1804+
// Format: lowercase hex to match minidump format
17791805
if (mod->name[0]) {
17801806
DWORD timestamp = get_pe_timestamp(mod->name);
17811807
if (timestamp != 0) {
17821808
char code_id_buf[32];
1783-
snprintf(code_id_buf, sizeof(code_id_buf), "%08X%x",
1809+
snprintf(code_id_buf, sizeof(code_id_buf), "%x%x",
17841810
(unsigned int)timestamp, (unsigned int)mod->size);
17851811
sentry_value_set_by_key(
17861812
image, "code_id", sentry_value_new_string(code_id_buf));
@@ -1805,6 +1831,12 @@ build_native_crash_event(const sentry_crash_context_t *ctx,
18051831
sentry_value_set_by_key(
18061832
image, "debug_id", sentry_value_new_string(debug_id_buf));
18071833
}
1834+
1835+
// Set debug_file (path to PDB file for symbolication)
1836+
if (mod->pdb_name[0]) {
1837+
sentry_value_set_by_key(image, "debug_file",
1838+
sentry_value_new_string(mod->pdb_name));
1839+
}
18081840
#else
18091841
// Set debug_id from UUID (macOS/Linux)
18101842
sentry_uuid_t uuid

0 commit comments

Comments
 (0)