From 270d73220f2316fb406114184b103851843f5042 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 16 Apr 2026 16:46:45 -0700 Subject: [PATCH] test GSI --- src/linker/codeview_ext/codeview.c | 37 +++++++++++++++++ src/linker/codeview_ext/codeview.h | 17 ++++---- src/torture/torture_radlink.c | 64 +++++++++++++++++++++++++----- 3 files changed, 100 insertions(+), 18 deletions(-) diff --git a/src/linker/codeview_ext/codeview.c b/src/linker/codeview_ext/codeview.c index a065f069..198d6675 100644 --- a/src/linker/codeview_ext/codeview.c +++ b/src/linker/codeview_ext/codeview.c @@ -397,6 +397,43 @@ cv_make_end(Arena *arena) return str8_zero(); } +internal String8 +cv_make_data32(Arena *arena, CV_SymData32 data, String8 name) +{ + U64 buf_size = sizeof(data) + name.size + 1; + U8 *buf = push_array(arena, U8, buf_size); + CV_SymData32 *data_dst = (CV_SymData32 *)buf; + MemoryCopy(data_dst, &data, sizeof(data)); + MemoryCopy(data_dst + 1, name.str, name.size); + buf[sizeof(data) + name.size] = 0; + return str8(buf, buf_size); +} + +internal String8 +cv_make_const(Arena *arena, CV_SymConstant v, U16 value, String8 name) +{ + U64 buf_size = sizeof(v) + sizeof(value) + name.size + 1; + U8 *buf = push_array(arena, U8, buf_size); + CV_SymConstant *data_dst = (CV_SymConstant *)buf; + MemoryCopy(buf, &v, sizeof(v)); + MemoryCopy(buf + sizeof(v), &value, sizeof(value)); + MemoryCopy(buf + sizeof(v) + sizeof(value), name.str, name.size); + buf[sizeof(v) + sizeof(value) + name.size] = 0; + return str8(buf, buf_size); +} + +internal String8 +cv_make_udt(Arena *arena, CV_SymUDT v, String8 name) +{ + U64 buf_size = sizeof(v) + name.size + 1; + U8 *buf = push_array(arena, U8, buf_size); + CV_SymUDT *data_dst = (CV_SymUDT *)buf; + MemoryCopy(data_dst, &v, sizeof(v)); + MemoryCopy(data_dst + 1, name.str, name.size); + buf[sizeof(v) + name.size] = 0; + return str8(buf, buf_size); +} + internal String8 cv_make_inline_site(Arena *arena, CV_SymInlineSite inline_site, String8 annots) { diff --git a/src/linker/codeview_ext/codeview.h b/src/linker/codeview_ext/codeview.h index 6c0219c6..985f2dce 100644 --- a/src/linker/codeview_ext/codeview.h +++ b/src/linker/codeview_ext/codeview.h @@ -353,13 +353,16 @@ internal CV_Symbol cv_symbol_from_ptr(U8 *ptr); internal String8 cv_raw_from_symbol(void *ptr); internal B32 cv_symbol_match(CV_Symbol a, CV_Symbol b); -internal String8 cv_make_symbol(Arena *arena, CV_SymKind kind, String8 data); -internal String8 cv_make_obj_name(Arena *arena, String8 obj_path, U32 sig); -internal String8 cv_make_comp3(Arena *arena, CV_Compile3Flags flags, CV_Language lang, CV_Arch arch, U16 ver_fe_major, U16 ver_fe_minor, U16 ver_fe_build, U16 ver_feqfe, U16 ver_major, U16 ver_minor, U16 ver_build, U16 ver_qfe, String8 version_string); -internal String8 cv_make_envblock(Arena *arena, String8List string_list); -internal String8 cv_make_end(Arena *arena); -internal CV_Symbol cv_make_proc_ref(Arena *arena, CV_ModIndex imod, U32 stream_offset, String8 name, B32 is_local); -internal CV_Symbol cv_make_pub32(Arena *arena, CV_Pub32Flags flags, U32 off, U16 isect, String8 name); +internal String8 cv_make_symbol(Arena *arena, CV_SymKind kind, String8 data); +internal String8 cv_make_obj_name(Arena *arena, String8 obj_path, U32 sig); +internal String8 cv_make_comp3(Arena *arena, CV_Compile3Flags flags, CV_Language lang, CV_Arch arch, U16 ver_fe_major, U16 ver_fe_minor, U16 ver_fe_build, U16 ver_feqfe, U16 ver_major, U16 ver_minor, U16 ver_build, U16 ver_qfe, String8 version_string); +internal String8 cv_make_envblock(Arena *arena, String8List string_list); +internal String8 cv_make_end(Arena *arena); +internal String8 cv_make_data32(Arena *arena, CV_SymData32 data, String8 name); +internal String8 cv_make_const(Arena *arena, CV_SymConstant v, U16 value, String8 name); +internal String8 cv_make_udt(Arena *arena, CV_SymUDT v, String8 name); +internal CV_Symbol cv_make_proc_ref(Arena *arena, CV_ModIndex imod, U32 stream_offset, String8 name, B32 is_local); +internal CV_Symbol cv_make_pub32(Arena *arena, CV_Pub32Flags flags, U32 off, U16 isect, String8 name); 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); diff --git a/src/torture/torture_radlink.c b/src/torture/torture_radlink.c index 107aeb25..55ad47be 100644 --- a/src/torture/torture_radlink.c +++ b/src/torture/torture_radlink.c @@ -4630,6 +4630,25 @@ TEST(get_msf_stream_pages) msf_release(msf); } +internal String8 +data_from_pdb(Arena *arena, PDB_Context *pdb) +{ + TP_Context *tp = tp_alloc(arena, 1, 1, str8_lit("foo")); + TP_Arena *tp_arena = tp_arena_alloc(tp); + pdb_build(tp, tp_arena, pdb, (CV_StringHashTable){0}, 1, 0); + + AssertAlways(msf_build(pdb->msf) == MSF_Error_OK); + String8List raw_msf_list = msf_get_page_data_nodes(arena, pdb->msf); + AssertAlways(t_write_file_list(str8_lit("test.pdb"), raw_msf_list)); + + String8 data = str8_list_join(arena, &raw_msf_list, 0); + + tp_arena_release(&tp_arena); + tp_release(tp); + + return data; +} + TEST(validate_info_stream) { COFF_TimeStamp time_stamp = 123; @@ -4644,16 +4663,8 @@ TEST(validate_info_stream) stream_numbers[i] = pdb_push_named_stream(&pdb->info->named_stream_ht, pdb->msf, str8_cstring(stream_names[i])); T_Ok(stream_numbers[i] != MSF_INVALID_STREAM_NUMBER); } - - TP_Context *tp = tp_alloc(arena, 1, 1, str8_lit("foo")); - TP_Arena *tp_arena = tp_arena_alloc(tp); - pdb_build(tp, tp_arena, pdb, (CV_StringHashTable){0}, 1, 0); - - T_Ok(msf_build(pdb->msf) == MSF_Error_OK); - String8List raw_msf_list = msf_get_page_data_nodes(arena, pdb->msf); - T_Ok(t_write_file_list(str8_lit("test.pdb"), raw_msf_list)); - String8 raw_msf = t_read_file(arena, str8_lit("test.pdb")); + String8 raw_msf = data_from_pdb(arena, pdb); MSF_Parsed *msf_parsed = msf_parsed_from_data(arena, raw_msf); String8 info_data = msf_data_from_stream(msf_parsed, PDB_FixedStream_Info); @@ -4677,8 +4688,39 @@ TEST(validate_info_stream) T_Ok(str8_match(info_data, str8_array_fixed(expected_info_data), 0)); pdb_release(pdb); - tp_arena_release(&tp_arena); - tp_release(tp); +} + +TEST(validate_gsi) +{ + PDB_Context *pdb = pdb_alloc(MSF_DEFAULT_PAGE_SIZE, COFF_MachineType_X64, 123, 1, (Guid){ .data1 = max_U32, .data2 = max_U16 - 1, .data3 = max_U16 - 2, .data4 = { 1, 2, 3, 4, 5, 6, 7, 8 } }); + CV_Symbol symbols[] = { + cv_symbol_from_ptr(cv_make_symbol(arena, CV_SymKind_GDATA32, cv_make_data32(arena, (CV_SymData32){ .itype = 0x41bd, .off = 0x25440, .sec = 2 }, str8_lit("__newclmap"))).str), + cv_symbol_from_ptr(cv_make_symbol(arena, CV_SymKind_CONSTANT, cv_make_const(arena, (CV_SymConstant){ .itype = 0x2348 }, 263, str8_lit("CV_SymKind_BLOCK16"))).str), + cv_symbol_from_ptr(cv_make_symbol(arena, CV_SymKind_GDATA32, cv_make_data32(arena, (CV_SymData32){ .itype = 0, .off = 123, .sec = 1 }, str8_lit("coffeebabe"))).str), + cv_symbol_from_ptr(cv_make_symbol(arena, CV_SymKind_GDATA32, cv_make_data32(arena, (CV_SymData32){ .itype = 0, .off = 123, .sec = 1 }, str8_lit("deadbeef"))).str), + }; + for EachElement(i, symbols) { gsi_push(pdb->gsi, &symbols[i]); } + + String8 raw_pdb = data_from_pdb(arena, 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 gsi_data = msf_data_from_stream(msf, dbi->gsi_sn); + PDB_GsiParsed *gsi = pdb_gsi_from_data(arena, gsi_data); + String8 symbol_data = msf_data_from_stream(msf, dbi->sym_sn); + + for EachElement(i, symbols) { + String8 string = cv_name_from_symbol(symbols[i].kind, symbols[i].data); + U64 symbol_off = pdb_gsi_symbol_from_string(gsi, symbol_data, string); + T_Ok(symbol_off < symbol_data.size); + + 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])); + } + + pdb_release(pdb); } TEST(patch_cv_symbol_tree)