diff --git a/src/linker/codeview_ext/codeview.c b/src/linker/codeview_ext/codeview.c index 198d6675..dc1e7d88 100644 --- a/src/linker/codeview_ext/codeview.c +++ b/src/linker/codeview_ext/codeview.c @@ -196,11 +196,13 @@ cv_write_symbol_buf(String8Node *buf, U64 *buf_pos, CV_Symbol *symbol, U64 align { CV_SymbolHeader header = { .size = sizeof(CV_SymKind) + symbol->data.size, .kind = symbol->kind }; U64 pad_size = AlignPadPow2(header.size + sizeof(CV_SymSize), align); + header.size += pad_size; + U64 write_size = 0; write_size += str8_buffer_write(buf, buf_pos, str8_struct(&header)); write_size += str8_buffer_write(buf, buf_pos, symbol->data); write_size += str8_buffer_write_zeroes(buf, buf_pos, pad_size); - Assert(write_size == header.size + sizeof(CV_SymSize) + pad_size); + return write_size; } diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 9c65833d..7d8b1917 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -5320,7 +5320,8 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) if (symbol.kind == CV_SymKind_SKIP) { continue; } if (cv_is_lproc(symbol)) { proc_count += 1; - proc_size += AlignPow2(symbol.data.size, CV_SymbolAlign); + proc_size += AlignPow2(sizeof(CV_SymbolHeader) + symbol.data.size, CV_SymbolAlign); + proc_size += AlignPow2(sizeof(CV_SymbolHeader), CV_SymbolAlign); // S_END } } section += 1; @@ -5329,7 +5330,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) 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; + U64 buffer_size = proc_size; U8 *buffer = push_array(scratch.arena, U8, buffer_size); U64 buffer_cursor = 0; @@ -5339,13 +5340,10 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) 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 }; - + CV_SymProc32 *src_proc = str8_deserial_get_raw_ptr(symbol.data, 0, sizeof(*src_proc)); + memory_write32(&src_proc->itype, 0); // strip type index 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); + buffer_cursor += cv_write_symbol(buffer, buffer_cursor, buffer_size, &(CV_Symbol){ .kind = CV_SymKind_END }, CV_SymbolAlign); } } } diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 2cdef26f..7a66c940 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -2411,18 +2411,19 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config cv_string_hash_table_assign_buffer_offsets(tp, task.string_ht); ProfEnd(); - ProfScope ("Alloc Modules") for EachIndex(obj_idx, cv->obj_count) { task.mod_arr[obj_idx] = dbi_push_module(task.pdb->dbi, cv->obj_arr[obj_idx]->path, lnk_obj_get_lib_path(cv->obj_arr[obj_idx])); } - ProfScope("Move Global Symbols") tp_for_parallel(tp, 0, tp->worker_count, lnk_move_global_symbols_to_gsi, &task); - { - PDB_Context *pdb = task.pdb; - PDB_DbiContext *dbi = pdb->dbi; - dbi->globals_sn = msf_stream_alloc(pdb->msf); - dbi->publics_sn = msf_stream_alloc(pdb->msf); - dbi->symbols_sn = msf_stream_alloc(pdb->msf); - psi_build(tp, pdb->psi, pdb->msf, dbi->publics_sn, dbi->symbols_sn); - gsi_build(tp, pdb->gsi, pdb->msf, dbi->globals_sn, dbi->symbols_sn); - } - ProfScope("Write Modules") tp_for_parallel(tp, 0, tp->worker_count, lnk_write_pdb_modules, &task); + ProfScope ("Alloc Modules") + for EachIndex(obj_idx, cv->obj_count) { + task.mod_arr[obj_idx] = dbi_push_module(task.pdb->dbi, cv->obj_arr[obj_idx]->path, lnk_obj_get_lib_path(cv->obj_arr[obj_idx])); + } + + ProfScope("Move Global Symbols") + tp_for_parallel(tp, 0, tp->worker_count, lnk_move_global_symbols_to_gsi, &task); + + ProfScope("Build GSI and PSI") + pdb_build_gsi_psi(tp, task.pdb); + + ProfScope("Write Modules") + tp_for_parallel(tp, 0, tp->worker_count, lnk_write_pdb_modules, &task); ProfBegin("Add string tables"); pdb_strtab_add_cv_string_hash_table(&task.pdb->info->strtab, task.string_ht); diff --git a/src/linker/pdb_ext/pdb_builder.c b/src/linker/pdb_ext/pdb_builder.c index 56cb02c5..f7de6cdb 100644 --- a/src/linker/pdb_ext/pdb_builder.c +++ b/src/linker/pdb_ext/pdb_builder.c @@ -3134,6 +3134,24 @@ pdb_get_guid(PDB_Context *pdb) return pdb->info->guid; } +internal void +pdb_build_gsi_psi(TP_Context *tp, PDB_Context *pdb) +{ + PDB_DbiContext *dbi = pdb->dbi; + + if (pdb->psi->gsi->symbol_count) { + if (dbi->publics_sn == MSF_INVALID_STREAM_NUMBER) { dbi->publics_sn = msf_stream_alloc(pdb->msf); } + if (dbi->symbols_sn == MSF_INVALID_STREAM_NUMBER) { dbi->symbols_sn = msf_stream_alloc(pdb->msf); } + psi_build(tp, pdb->psi, pdb->msf, dbi->publics_sn, dbi->symbols_sn); + } + + if (pdb->gsi->symbol_count) { + if (dbi->globals_sn == MSF_INVALID_STREAM_NUMBER) { dbi->globals_sn = msf_stream_alloc(pdb->msf); } + if (dbi->symbols_sn == MSF_INVALID_STREAM_NUMBER) { dbi->symbols_sn = msf_stream_alloc(pdb->msf); } + gsi_build(tp, pdb->gsi, pdb->msf, dbi->globals_sn, dbi->symbols_sn); + } +} + internal void pdb_build(TP_Context *tp, TP_Arena *pool_temp, PDB_Context *pdb, CV_StringHashTable string_ht, B32 build_gsi, B32 is_stripped) { @@ -3151,17 +3169,7 @@ pdb_build(TP_Context *tp, TP_Arena *pool_temp, PDB_Context *pdb, CV_StringHashTa } if (build_gsi) { - if (dbi->globals_sn == MSF_INVALID_STREAM_NUMBER) { - dbi->globals_sn = msf_stream_alloc(pdb->msf); - } - if (dbi->publics_sn == MSF_INVALID_STREAM_NUMBER) { - dbi->publics_sn = msf_stream_alloc(pdb->msf); - } - if (dbi->symbols_sn == MSF_INVALID_STREAM_NUMBER) { - dbi->symbols_sn = msf_stream_alloc(pdb->msf); - } - psi_build(tp, pdb->psi, pdb->msf, dbi->publics_sn, dbi->symbols_sn); - gsi_build(tp, pdb->gsi, pdb->msf, dbi->globals_sn, dbi->symbols_sn); + pdb_build_gsi_psi(tp, pdb); } dbi_build(tp, pdb->dbi, pdb->msf, PDB_FixedStream_Dbi, string_ht, is_stripped); diff --git a/src/torture/torture_radlink.c b/src/torture/torture_radlink.c index 8fdf9eb1..d9beebde 100644 --- a/src/torture/torture_radlink.c +++ b/src/torture/torture_radlink.c @@ -4687,9 +4687,9 @@ TEST(validate_info_stream) 0x6f, 0x00, 0x74, 0x68, 0x72, 0x65, 0x65, 0x00, 0x66, 0x6f, 0x75, 0x72, 0x00, 0x66, 0x69, 0x76, 0x65, 0x00, 0x2f, 0x4c, 0x69, 0x6e, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, - 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x51, 0x33, 0x01 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x51, 0x33, 0x01, }; T_Ok(str8_match(info_data, str8_array_fixed(expected_info_data), 0)); @@ -4742,7 +4742,9 @@ TEST(validate_gsi) CV_Symbol test_symbol = {0}; U64 test_symbol_size = cv_read_symbol(str8_skip(symbol_data, symbol_off), 0, 1, &test_symbol); T_Ok(test_symbol_size > 0); - T_Ok(cv_symbol_match(test_symbol, symbols[i])); + + String8 test_symbol_name = cv_name_from_symbol(test_symbol.kind, test_symbol.data); + T_Ok(str8_match(test_symbol_name, string, 0)); } } @@ -4904,6 +4906,106 @@ TEST(validate_psi) T_Ok(pub32_count > 0); } +TEST(pdbstripped) +{ + String8 debug_obj; + { + String8 raw_symbols[] = { + cv_make_symbol(arena, CV_SymKind_OBJNAME, cv_make_obj_name(arena, str8_lit("debug.obj"), 0x123)), + cv_make_symbol(arena, CV_SymKind_GPROC32_ID, cv_make_proc32(arena, (CV_SymProc32){0}, str8_lit("global_proc"))), + cv_make_symbol(arena, CV_SymKind_PROC_ID_END, cv_make_end(arena)), + + cv_make_symbol(arena, CV_SymKind_UDT, cv_make_udt(arena, (CV_SymUDT){0}, str8_lit("global_typedef"))), + + cv_make_symbol(arena, CV_SymKind_LPROC32_ID, cv_make_proc32(arena, (CV_SymProc32){0}, str8_lit("local_proc"))), + cv_make_symbol(arena, CV_SymKind_UDT, cv_make_udt(arena, (CV_SymUDT){0}, str8_lit("local_typedef"))), + cv_make_symbol(arena, CV_SymKind_PROC_ID_END, cv_make_end(arena)), + }; + + CV_Symbol symbols[ArrayCount(raw_symbols)] = {0}; + for EachElement(i, raw_symbols) { symbols[i] = cv_symbol_from_ptr(raw_symbols[i].str); } + + CV_DebugS debug_s = {0}; + for EachElement(i, symbols) { str8_list_push(arena, &debug_s.data_list[CV_C13SubSectionIdxKind_Symbols], cv_data_from_symbol(arena, &symbols[i], CV_SymbolAlign)); } + String8List raw_debug_s_list = cv_data_from_debug_s_c13(arena, &debug_s, 1); + String8 raw_debug_s = str8_list_join(arena, &raw_debug_s_list, 0); + + COFF_ObjWriter *cow = coff_obj_writer_alloc(0, COFF_MachineType_X64); + t_push_debug_s_section(cow, raw_debug_s); + debug_obj = coff_obj_writer_serialize(arena, cow); + coff_obj_writer_release(&cow); + } + + String8 pub_obj; + { + COFF_ObjWriter *cow = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSection *text = coff_obj_writer_push_section(cow, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_lit("FOOBAR")); + COFF_ObjSection *data = coff_obj_writer_push_section(cow, str8_lit(".data"), PE_DATA_SECTION_FLAGS, str8_lit("QWE")); + coff_obj_writer_push_symbol_extern_func(cow, str8_lit("global_func"), 1, text); + coff_obj_writer_push_symbol_extern(cow, str8_lit("global_var"), 1, data); + coff_obj_writer_push_symbol_static(cow, str8_lit("static_var"), 1, data); + pub_obj = coff_obj_writer_serialize(arena, cow); + coff_obj_writer_release(&cow); + } + + T_Ok(t_write_file(str8_lit("debug.obj"), debug_obj)); + T_Ok(t_write_file(str8_lit("pub.obj"), pub_obj)); + T_Ok(t_write_entry_obj()); + t_invoke_linkerf("/subsystem:console /entry:entry /debug:full /out:a.exe /pdbstripped:a.stripped.pdb entry.obj pub.obj debug.obj"); + T_Ok(g_last_exit_code == 0); + + String8 raw_pdb = t_read_file(arena, str8_lit("a.stripped.pdb")); + MSF_Parsed *msf = msf_parsed_from_data(arena, raw_pdb); + String8 dbi_data = msf_data_from_stream(msf, PDB_FixedStream_Dbi); + PDB_DbiParsed *dbi = pdb_dbi_from_data(arena, dbi_data); + + String8 mods_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo); + PDB_CompUnitArray *mods = pdb_comp_unit_array_from_data(arena, mods_data); + T_Ok(mods->count > 0); + + // modules must contain only stubs for static procs + for EachIndex(i, mods->count) { + PDB_CompUnit *mod = mods->units[i]; + U64 sym_data_size = mod->range_off[PDB_DbiCompUnitRange_Symbols + 1] - mod->range_off[PDB_DbiCompUnitRange_Symbols]; + U64 c11_data_size = mod->range_off[PDB_DbiCompUnitRange_C11 + 1] - mod->range_off[PDB_DbiCompUnitRange_C11]; + U64 c13_data_size = mod->range_off[PDB_DbiCompUnitRange_C13 + 1] - mod->range_off[PDB_DbiCompUnitRange_C13]; + T_Ok(c11_data_size == 0); + T_Ok(c13_data_size == 0); + if (str8_match(str8_skip_last_slash(mod->obj_name), str8_lit("debug.obj"), 0)) { + T_Ok(sym_data_size > 0); + } else { + T_Ok(sym_data_size == 0); + } + + String8 mod_data = msf_data_from_stream(msf, mod->sn); + String8 sym_data = str8_substr(mod_data, r1u64(mod->range_off[PDB_DbiCompUnitRange_Symbols], mod->range_off[PDB_DbiCompUnitRange_Symbols + 1])); + for (U64 cursor = 0; cursor < sym_data_size; ) { + CV_Symbol symbol = {0}; + U64 read_size = cv_read_symbol(sym_data, cursor, PDB_SYMBOL_ALIGN, &symbol); + T_Ok(read_size > 0); + cursor += read_size; + T_Ok(symbol.kind == CV_SymKind_LPROC32 || symbol.kind == CV_SymKind_END); + } + } + + // global symbol stream must have public and references to the static stubs + String8 symbol_data = msf_data_from_stream(msf, dbi->sym_sn); + for (U64 cursor = 0; cursor < symbol_data.size; ) { + CV_Symbol symbol = {0}; + U64 read_size = cv_read_symbol(symbol_data, cursor, PDB_SYMBOL_ALIGN, &symbol); + T_Ok(read_size > 0); + cursor += read_size; + T_Ok(symbol.kind == CV_SymKind_PUB32 || + symbol.kind == CV_SymKind_LPROCREF); + } + + // types must be stripped + String8 tpi = msf_data_from_stream(msf, PDB_FixedStream_Tpi); + T_Ok(tpi.size == sizeof(PDB_TpiHeader)); + String8 ipi = msf_data_from_stream(msf, PDB_FixedStream_Ipi); + T_Ok(ipi.size == sizeof(PDB_TpiHeader)); +} + TEST(patch_cv_symbol_tree) { String8List raw_symbols = {0};