WIP stripped PDB

This commit is contained in:
Nikita Smith
2026-04-10 17:02:04 -07:00
parent b4bbc38ab2
commit 89a5acba2c
7 changed files with 152 additions and 40 deletions
+17
View File
@@ -466,6 +466,23 @@ cv_make_pub32(Arena *arena, CV_Pub32Flags flags, U32 off, U16 isect, String8 nam
return symbol;
}
internal B32
cv_is_gproc(CV_Symbol symbol)
{
return symbol.kind == CV_SymKind_GPROC32 ||
symbol.kind == CV_SymKind_GPROCMIPS ||
symbol.kind == CV_SymKind_GPROCIA64 ||
symbol.kind == CV_SymKind_GPROC32_ID ||
symbol.kind == CV_SymKind_GPROCMIPS_ID ||
symbol.kind == CV_SymKind_GPROCIA64_ID ||
symbol.kind == CV_SymKind_GPROC16 ||
symbol.kind == CV_SymKind_GPROC32_16t ||
symbol.kind == CV_SymKind_GPROCMIPS_16t ||
symbol.kind == CV_SymKind_GPROC32_ST ||
symbol.kind == CV_SymKind_GPROCMIPS_ST ||
symbol.kind == CV_SymKind_GPROCIA64_ST;
}
internal B32
cv_is_lproc(CV_Symbol symbol)
{
+1
View File
@@ -364,6 +364,7 @@ internal CV_Symbol cv_make_pub32(Arena *arena, CV_Pub32Flags flags, U32 off,
internal U64 cv_read_symbol(String8 raw_data, U64 off, U64 align, CV_Symbol *symbol_out);
internal CV_Symbol cv_symbol_from_string(String8 raw_data);
internal B32 cv_is_gproc(CV_Symbol symbol);
internal B32 cv_is_lproc(CV_Symbol symbol);
internal B32 cv_is_obj_info(CV_Symbol symbol);
internal CV_ObjInfo cv_obj_info_from_symbol(CV_Symbol symbol);
+72 -1
View File
@@ -2123,7 +2123,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
}
ProfBegin("Build * Debug Directories *");
if (config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null) {
if (lnk_do_debug_info(config)) {
String8 pdb_dir_obj = pe_make_debug_directory_pdb_obj(arena->v[0], config->machine, config->guid, config->age, config->time_stamp, config->pdb_alt_path);
lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Debug Directory PDB *"), pdb_dir_obj);
}
@@ -5298,6 +5298,77 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config)
lnk_timer_end(LNK_Timer_Pdb);
}
//
// stripped PDB
//
if (config->pdb_stripped_name.size != 0) {
CV_DebugS *debug_s_arr = push_array(scratch.arena, CV_DebugS, cv.obj_count);
for EachIndex(obj_idx, cv.obj_count) {
CV_DebugS *debug_s_dst = &debug_s_arr[obj_idx];
CV_DebugS *debug_s_src = &cv.debug_s_arr[obj_idx];
String8List *dst = &debug_s_dst->data_list[CV_C13SubSectionIdxKind_Symbols];
String8List *src = &debug_s_src->data_list[CV_C13SubSectionIdxKind_Symbols];
U64 proc_count = 0;
U64 proc_size = 0;
U64 section = 0;
for EachNode(n, String8Node, src->first) {
for (U64 cursor = 0; cursor < n->string.size; ) {
U64 c = cursor;
CV_Symbol symbol = {0};
TryReadBreak(cv_read_symbol(n->string, cursor, CV_SymbolAlign, &symbol), cursor);
if (symbol.kind == CV_SymKind_SKIP) { continue; }
if (cv_is_lproc(symbol)) {
proc_count += 1;
proc_size += AlignPow2(symbol.data.size, CV_SymbolAlign);
}
}
section += 1;
}
if (proc_count) {
U64 end_count = proc_count;
U64 symbol_count = proc_count + end_count;
U64 buffer_size = proc_size + sizeof(CV_SymbolHeader) * symbol_count;
U8 *buffer = push_array(scratch.arena, U8, buffer_size);
U64 buffer_cursor = 0;
for EachNode(n, String8Node, src->first) {
for (U64 cursor = 0; cursor < n->string.size; ) {
CV_Symbol symbol = {0};
TryReadBreak(cv_read_symbol(n->string, cursor, CV_SymbolAlign, &symbol), cursor);
if (symbol.kind == CV_SymKind_SKIP) { continue; }
if (cv_is_lproc(symbol)) {
CV_SymProc32 *src_proc = (CV_SymProc32 *)symbol.data.str;
src_proc->itype = 0;
CV_Symbol end_symbol = { .kind = CV_SymKind_END };
buffer_cursor += cv_write_symbol(buffer, buffer_cursor, buffer_size, &symbol, CV_SymbolAlign);
buffer_cursor += cv_write_symbol(buffer, buffer_cursor, buffer_size, &end_symbol, CV_SymbolAlign);
}
}
}
Assert(buffer_cursor == buffer_size);
str8_list_push(scratch.arena, dst, str8(buffer, buffer_size));
}
}
LNK_CodeViewInput stripped_cv = {0};
stripped_cv.io_flags = config->io_flags;
stripped_cv.is_stripped = 1;
stripped_cv.obj_arr = cv.obj_arr;
stripped_cv.obj_count = cv.obj_count;
stripped_cv.count = cv.obj_count;
stripped_cv.debug_s_arr = debug_s_arr;
stripped_cv.symbol_input_ranges = push_array(scratch.arena, Rng1U64, tp->worker_count);
String8List pdb_data = lnk_build_pdb(tp, arena, image_ctx.image_data, config, symtab, &stripped_cv, (LNK_MergedTypes){0});
lnk_write_data_list_to_file_path(config->pdb_stripped_name, str8f(scratch.arena, "%S.tmp", config->pdb_stripped_name), pdb_data);
}
lnk_timer_end(LNK_Timer_Debug);
ProfEnd();
}
+8
View File
@@ -53,6 +53,7 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] =
{ LNK_CmdSwitch_Pdb, 0, "PDB", ":FILENAME", "File name of the output PDB." },
{ LNK_CmdSwitch_PdbAltPath, 0, "PDBALTPATH", ":PATH", "Alternative output path for the PDB." },
{ LNK_CmdSwitch_PdbPageSize, 0, "PDBPAGESIZE", ":#", "Page size must be power of two." },
{ LNK_CmdSwitch_PdbStripped, 0, "PDBSTRIPPED", ":FILENAME", "Create a stripped PDB containing public symbols, a section map, and a list of object files." },
{ LNK_CmdSwitch_Release, 1, "RELEASE", "", "Write image checksum." },
{ LNK_CmdSwitch_Stack, 1, "STACK", ":RESERVE[,COMMIT]", "Set reserve and commit size for the stack." },
{ LNK_CmdSwitch_SubSystem, 1, "SUBSYSTEM", ":{CONSOLE|NATIVE|WINDOWS}[,#[.##]]", "Set subsystem for the image." },
@@ -1721,6 +1722,13 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
}
} break;
case LNK_CmdSwitch_PdbStripped: {
String8 file_name;
if (lnk_cmd_switch_parse_string(obj, cmd_switch, value_strings, &file_name)) {
config->pdb_stripped_name = str8_copy(config->arena, file_name);
}
} break;
case LNK_CmdSwitch_Release: {
if (value_strings.node_count == 0) {
config->flags |= LNK_ConfigFlag_WriteImageChecksum;
+3 -1
View File
@@ -50,8 +50,8 @@ typedef enum
LNK_CmdSwitch_FailIfMismatch,
LNK_CmdSwitch_FileAlign,
LNK_CmdSwitch_Fixed,
LNK_CmdSwitch_FunctionPadMin,
LNK_CmdSwitch_Force,
LNK_CmdSwitch_FunctionPadMin,
LNK_CmdSwitch_Heap,
LNK_CmdSwitch_HighEntropyVa,
LNK_CmdSwitch_Ignore,
@@ -79,6 +79,7 @@ typedef enum
LNK_CmdSwitch_Pdb,
LNK_CmdSwitch_PdbAltPath,
LNK_CmdSwitch_PdbPageSize,
LNK_CmdSwitch_PdbStripped,
LNK_CmdSwitch_Release,
LNK_CmdSwitch_Stack,
LNK_CmdSwitch_SubSystem,
@@ -312,6 +313,7 @@ typedef struct LNK_Config
String8List raw_cmd_line;
String8 pdb_name;
String8 pdb_alt_path;
String8 pdb_stripped_name;
String8 mt_path;
LNK_TypeNameHashMode pdb_hash_type_names;
String8 pdb_hash_type_name_map;
+50 -38
View File
@@ -2046,30 +2046,33 @@ lnk_write_debug_s_to_pdb_module(PDB_DbiModule *mod, CV_DebugS debug_s, String8No
mod->c13_data_size = 0;
mod->globrefs_size = 0;
// signature
U64 sig_size = str8_buffer_write_u32(buf, buf_pos, CV_Signature_C13);
mod->sym_data_size += sig_size;
mod_cursor += sig_size;
// write symbols
String8List symbols = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_Symbols);
U64 scope_depth = 0;
for EachNode(n, String8Node, symbols.first) {
for (U64 cursor = 0; cursor + sizeof(CV_SymbolHeader) <= n->string.size; ) {
CV_Symbol symbol = {0};
TryReadBreak(cv_read_symbol(n->string, cursor, CV_SymbolAlign, &symbol), cursor);
if (symbol.kind == CV_SymKind_SKIP) { continue; }
if (cv_is_global_symbol(symbol.kind)) { continue; }
else if (cv_is_typedef(symbol.kind) && scope_depth == 0) { continue; }
else if (symbol.kind == 0x1176) { continue; }
if (symbols.total_size) {
// signature
U64 sig_size = str8_buffer_write_u32(buf, buf_pos, CV_Signature_C13);
mod->sym_data_size += sig_size;
mod_cursor += sig_size;
if (cv_is_scope_symbol(symbol.kind)) { scope_depth += 1; }
else if (cv_is_end_symbol(symbol.kind)) { scope_depth -= 1; }
// write symbols
U64 scope_depth = 0;
for EachNode(n, String8Node, symbols.first) {
for (U64 cursor = 0; cursor + sizeof(CV_SymbolHeader) <= n->string.size; ) {
CV_Symbol symbol = {0};
TryReadBreak(cv_read_symbol(n->string, cursor, CV_SymbolAlign, &symbol), cursor);
if (symbol.kind == CV_SymKind_SKIP) { continue; }
U64 symbol_size = cv_write_symbol_buf(buf, buf_pos, &symbol, PDB_SYMBOL_ALIGN);
mod_cursor += symbol_size;
mod->sym_data_size += symbol_size;
if (cv_is_global_symbol(symbol.kind)) { continue; }
else if (cv_is_typedef(symbol.kind) && scope_depth == 0) { continue; }
else if (symbol.kind == 0x1176) { continue; }
if (cv_is_scope_symbol(symbol.kind)) { scope_depth += 1; }
else if (cv_is_end_symbol(symbol.kind)) { scope_depth -= 1; }
U64 symbol_size = cv_write_symbol_buf(buf, buf_pos, &symbol, PDB_SYMBOL_ALIGN);
mod_cursor += symbol_size;
mod->sym_data_size += symbol_size;
}
}
}
@@ -2112,10 +2115,12 @@ lnk_write_debug_s_to_pdb_module(PDB_DbiModule *mod, CV_DebugS debug_s, String8No
}
// write global refs
String8List globrefs = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_GlobalRefs);
mod->globrefs_size += str8_buffer_write_u32(buf, buf_pos, safe_cast_u32(globrefs.total_size));
mod->globrefs_size += str8_buffer_write_string_list(buf, buf_pos, globrefs);
mod_cursor += mod->globrefs_size;
if (mod->sym_data_size) {
String8List globrefs = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_GlobalRefs);
mod->globrefs_size += str8_buffer_write_u32(buf, buf_pos, safe_cast_u32(globrefs.total_size));
mod->globrefs_size += str8_buffer_write_string_list(buf, buf_pos, globrefs);
mod_cursor += mod->globrefs_size;
}
return mod_cursor;
}
@@ -2153,6 +2158,9 @@ THREAD_POOL_TASK_FUNC(lnk_write_pdb_modules)
U64 obj_idx = obj_indices.v[i];
PDB_DbiModule *mod = task->mod_arr[obj_idx];
if (mod->sn == MSF_INVALID_STREAM_NUMBER) { continue; }
CV_DebugS debug_s = task->cv->debug_s_arr[obj_idx];
String8List mod_data = msf_data_from_sn(temp.arena, task->pdb->msf, mod->sn);
@@ -2162,10 +2170,12 @@ THREAD_POOL_TASK_FUNC(lnk_write_pdb_modules)
lnk_write_debug_s_to_pdb_module(mod, debug_s, &buf, &pos);
// sub range symbol data pages and patch symbol tree offsets
Rng1U64 sym_data_range = r1u64(sizeof(CV_Signature), mod->sym_data_size);
String8List mod_symbols = str8_list_substr(temp.arena, mod_data, sym_data_range);
Assert(mod_symbols.total_size == dim_1u64(sym_data_range));
cv_patch_symbol_tree_offsets(mod_symbols, sizeof(CV_Signature), PDB_SYMBOL_ALIGN);
if (mod->sym_data_size) {
Rng1U64 sym_data_range = r1u64(sizeof(CV_Signature), mod->sym_data_size);
String8List mod_symbols = str8_list_substr(temp.arena, mod_data, sym_data_range);
Assert(mod_symbols.total_size == dim_1u64(sym_data_range));
cv_patch_symbol_tree_offsets(mod_symbols, sizeof(CV_Signature), PDB_SYMBOL_ALIGN);
}
}
temp_end(temp);
@@ -2204,11 +2214,14 @@ THREAD_POOL_TASK_FUNC(lnk_write_pdb_modules)
for EachIndex(i, obj_indices.count) {
Temp temp = temp_begin(scratch.arena);
U64 obj_idx = obj_indices.v[i];
PDB_DbiModule *mod = task->mod_arr[obj_idx];
String8List mod_data = msf_data_from_sn(temp.arena, task->pdb->msf, mod->sn);
Rng1U64 c13_data_range = r1u64(mod->sym_data_size + mod->c11_data_size, mod->sym_data_size + mod->c11_data_size + mod->c13_data_size);
String8List c13_data = str8_list_substr(temp.arena, mod_data, c13_data_range);
U64 obj_idx = obj_indices.v[i];
PDB_DbiModule *mod = task->mod_arr[obj_idx];
if (mod->sn == MSF_INVALID_STREAM_NUMBER) { continue; }
String8List mod_data = msf_data_from_sn(temp.arena, task->pdb->msf, mod->sn);
Rng1U64 c13_data_range = r1u64(mod->sym_data_size + mod->c11_data_size, mod->sym_data_size + mod->c11_data_size + mod->c13_data_size);
String8List c13_data = str8_list_substr(temp.arena, mod_data, c13_data_range);
CV_DebugS debug_s = task->cv->debug_s_arr[obj_idx];
String8 string_table = cv_string_table_from_debug_s(debug_s);
@@ -2359,9 +2372,11 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
.image_section_virt_ranges.v = push_array(scratch.arena, Rng1U64, task.image_section_table_count),
.image_section_file_ranges.v = push_array(scratch.arena, Rng1U64, task.image_section_table_count),
};
// set min type indices
for EachElement(ti_source, cv_types.min_type_indices) { task.pdb->type_servers[ti_source]->ti_lo = cv_types.min_type_indices[ti_source]; }
// per worker obj indices
{
U64 objs_per_worker = CeilIntegerDiv(cv->obj_count, tp->worker_count);
task.obj_indices = push_array(scratch.arena, U32Array, tp->worker_count);
@@ -2372,10 +2387,7 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
}
}
// move patched type data
//
// leaf data is stored in g_file_arena which has linker's life-time
// and this way we skip redundant leaf copy to the type server to make things faster
// push types
pdb_type_server_push_parallel(tp, task.pdb->type_servers[CV_TypeIndexSource_IPI], cv_types.count[CV_TypeIndexSource_IPI], cv_types.v[CV_TypeIndexSource_IPI]);
pdb_type_server_push_parallel(tp, task.pdb->type_servers[CV_TypeIndexSource_TPI], cv_types.count[CV_TypeIndexSource_TPI], cv_types.v[CV_TypeIndexSource_TPI]);
@@ -2453,7 +2465,7 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
}
ProfEnd();
pdb_build(tp, tp_arena, task.pdb, task.string_ht, 0);
pdb_build(tp, tp_arena, task.pdb, task.string_ht, 0, cv->is_stripped);
MSF_Error msf_err = msf_build(task.pdb->msf);
if (msf_err != MSF_Error_OK) {
+1
View File
@@ -27,6 +27,7 @@ typedef struct
{
LNK_IO_Flags io_flags;
U64 obj_count;
B32 is_stripped;
U64 count;
LNK_Obj **obj_arr;