From 3c719de3f5cc1493ac9e008bdbdd68a2f756dda9 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 20 Aug 2026 17:44:29 -0700 Subject: [PATCH] use callee info to disambiguate overlapping sibling inline sites --- src/linker/lnk.c | 2 +- src/linker/lnk_obj.c | 52 +++++++++++++++++++++++++++++++++++++++++--- src/linker/lnk_obj.h | 16 ++++++++------ 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 77d5c2e5..dcec56e0 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2409,7 +2409,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer LNK_ObjLineMap *line_map = line_maps[obj->input_idx]; // is reference inline site? - LNK_InlineSite *inline_site = lnk_inline_site_from_section_offset(line_map, safe_cast_u32(section_number), reloc->apply_off); + LNK_InlineSite *inline_site = lnk_inline_site_from_section_offset(line_map, safe_cast_u32(section_number), reloc->apply_off, symbol); if (inline_site && inline_site->name.size) { CV_Line *line_inline = lnk_line_from_inline_site(inline_site, reloc->apply_off); if (line_inline) { diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index e8c168bc..20ee52f8 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -1349,6 +1349,20 @@ lnk_line_map_from_obj(Arena *arena, LNK_Obj *obj) radsort(inline_site->lines, inline_site->line_count, cv_c13_voff_map_is_before); } } + } else if (symbol.kind == CV_SymKind_CALLEES) { + if (inline_site_stack_count && symbol.data.size >= sizeof(CV_SymFunctionList)) { + CV_SymFunctionList *func_list = (CV_SymFunctionList *)symbol.data.str; + U64 callee_count = Min(func_list->count, (symbol.data.size - sizeof(*func_list)) / sizeof(CV_ItemId)); + CV_ItemId *callees = (CV_ItemId *)(func_list + 1); + + LNK_InlineSite *inline_site = &map->inline_sites[inline_site_stack[inline_site_stack_count - 1]]; + inline_site->callee_count = callee_count; + inline_site->callee_names = push_array(arena, String8, callee_count); + for EachIndex(callee_idx, callee_count) { + String8 *callee_name = hash_map_search_u64_string(&inlinee_hm, callees[callee_idx]); + inline_site->callee_names[callee_idx] = callee_name ? *callee_name : str8_zero(); + } + } } else if (symbol.kind == CV_SymKind_INLINESITE_END) { if (inline_site_stack_count > 0) { inline_site_stack_count -= 1; @@ -1449,10 +1463,11 @@ lnk_lines_from_section_offset(LNK_ObjLineMap *map, U32 section_number, U32 offse } internal LNK_InlineSite * -lnk_inline_site_from_section_offset(LNK_ObjLineMap *map, U32 section_number, U32 offset) +lnk_inline_site_from_section_offset(LNK_ObjLineMap *map, U32 section_number, U32 offset, LNK_Symbol *callee_symbol) { U64 key = Compose64Bit(section_number, offset); + // find upper bound U64 min = 0; U64 opl = map->inline_range_count; while (min < opl) { @@ -1464,21 +1479,52 @@ lnk_inline_site_from_section_offset(LNK_ObjLineMap *map, U32 section_number, U32 } } - LNK_InlineSite *site = 0; + // hacky demangle + String8 callee_name = callee_symbol ? callee_symbol->name : str8_zero(); + if (str8_starts_with(callee_name, str8_lit("__imp_"))) { + callee_name = str8_skip(callee_name, 6); + } + if (str8_starts_with(callee_name, str8_lit("?"))) { + U64 name_opl = str8_find_needle(callee_name, 1, str8_lit("@"), 0); + callee_name = str8_substr(callee_name, r1u64(1, name_opl)); + } + + // scan back to the lower bound and match inline sites + LNK_InlineSite *site = 0; + LNK_InlineSite *callee_site = 0; + B32 callee_site_is_ambiguous = 0; while (min > 0) { LNK_InlineRange *range = &map->inline_ranges[--min]; if (key < range->key_max) { LNK_InlineSite *candidate = &map->inline_sites[range->site_idx]; + if (site == 0 || site->depth < candidate->depth) { site = candidate; } + + for EachIndex(callee_idx, candidate->callee_count) { + String8 pdb_callee_name = candidate->callee_names[callee_idx]; + if (str8_match(callee_name, pdb_callee_name, 0)) { + + // candidate matches callee + if (callee_site == 0 || callee_site->depth < candidate->depth) { + callee_site = candidate; + callee_site_is_ambiguous = 0; + } else if (candidate->depth == callee_site->depth && candidate != callee_site) { + callee_site_is_ambiguous = 1; + } + + break; + } + } } + if (min == 0 || map->inline_ranges[min - 1].prefix_max <= key) { break; } } - return site; + return (callee_site && !callee_site_is_ambiguous) ? callee_site : site; } internal CV_Line * diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index 9b74e4a2..d93ad522 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -115,12 +115,14 @@ typedef struct LNK_LineTable typedef struct LNK_InlineSite { - U32 parent_idx_plus_one; - U32 depth; - CV_ItemId inlinee; - String8 name; - U64 line_count; - CV_Line *lines; + U32 parent_idx_plus_one; + U32 depth; + CV_ItemId inlinee; + String8 name; + U64 callee_count; + String8 *callee_names; + U64 line_count; + CV_Line *lines; } LNK_InlineSite; typedef struct LNK_InlineRange @@ -254,6 +256,6 @@ internal U32 lnk_symbol_from_section_offset(LNK_ObjSymbolMap *map // CodeView map internal LNK_ObjLineMap * lnk_line_map_from_obj(Arena *arena, LNK_Obj *obj); internal CV_Line * lnk_lines_from_section_offset(LNK_ObjLineMap *map, U32 section_number, U32 offset, U64 *line_count_out); -internal LNK_InlineSite * lnk_inline_site_from_section_offset(LNK_ObjLineMap *map, U32 section_number, U32 offset); +internal LNK_InlineSite * lnk_inline_site_from_section_offset(LNK_ObjLineMap *map, U32 section_number, U32 offset, LNK_Symbol *callee_symbol); internal CV_Line * lnk_line_from_inline_site(LNK_InlineSite *site, U32 offset);