From 3b7a4f33318d4e3943c5d529c56682b6d53c539f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 26 Feb 2024 14:11:26 -0800 Subject: [PATCH] clean up pdb -> raddbgi converter parameters; extend conversion parameterization with optional type/udt disabling; use in breakpad converter --- .../breakpad_from_pdb_main.c | 143 ++++++++++++------ src/raddbgi_from_pdb/raddbgi_from_pdb.c | 127 ++++------------ src/raddbgi_from_pdb/raddbgi_from_pdb.h | 29 ++-- src/raddbgi_from_pdb/raddbgi_from_pdb_main.c | 2 +- 4 files changed, 131 insertions(+), 170 deletions(-) diff --git a/src/breakpad_from_pdb/breakpad_from_pdb_main.c b/src/breakpad_from_pdb/breakpad_from_pdb_main.c index 4c0c35b2..64df40c2 100644 --- a/src/breakpad_from_pdb/breakpad_from_pdb_main.c +++ b/src/breakpad_from_pdb/breakpad_from_pdb_main.c @@ -126,6 +126,69 @@ p2b_bake_unit_task__entry_point(Arena *arena, void *p) return out; } +//- rjf: per-procedure chunk dumping + +typedef struct P2B_DumpProcChunkIn P2B_DumpProcChunkIn; +struct P2B_DumpProcChunkIn +{ + RDI_VMapEntry *unit_vmap; + U32 unit_vmap_count; + P2B_BakeUnitOut **bake_units_out; + U64 bake_units_out_count; + RDIM_SymbolChunkNode *chunk; +}; + +internal void * +p2b_dump_proc_chunk_task__entry_point(Arena *arena, void *p) +{ + P2B_DumpProcChunkIn *in = (P2B_DumpProcChunkIn *)p; + String8List *out = push_array(arena, String8List, 1); + for(U64 idx = 0; idx < in->chunk->count; idx += 1) + { + // NOTE(rjf): breakpad does not support multiple voff ranges per procedure. + RDIM_Symbol *proc = &in->chunk->v[idx]; + RDIM_Scope *root_scope = proc->root_scope; + if(root_scope != 0 && root_scope->voff_ranges.first != 0) + { + // rjf: dump function record + RDIM_Rng1U64 voff_range = root_scope->voff_ranges.first->v; + str8_list_pushf(arena, out, "FUNC %I64x %I64x %I64x %S\n", voff_range.min, voff_range.max-voff_range.min, 0ull, proc->name); + + // rjf: dump function lines + U64 unit_idx = rdi_vmap_idx_from_voff(in->unit_vmap, in->unit_vmap_count, voff_range.min); + if(0 < unit_idx && unit_idx <= in->bake_units_out_count) + { + // rjf: unpack unit line info + P2B_BakeUnitOut *bake_unit_out = in->bake_units_out[unit_idx]; + RDI_ParsedLineInfo line_info = {bake_unit_out->unit_line_voffs, bake_unit_out->unit_lines, 0, bake_unit_out->unit_line_count, 0}; + for(U64 voff = voff_range.min, last_voff = 0; + voff < voff_range.max && voff > last_voff;) + { + RDI_U64 line_info_idx = rdi_line_info_idx_from_voff(&line_info, voff); + if(line_info_idx < line_info.count) + { + RDI_Line *line = &line_info.lines[line_info_idx]; + U64 line_voff_min = line_info.voffs[line_info_idx]; + U64 line_voff_opl = line_info.voffs[line_info_idx+1]; + str8_list_pushf(arena, out, "%I64x %I64x %I64u %I64u\n", + line_voff_min, + line_voff_opl-line_voff_min, + (U64)line->line_num, + (U64)line->file_idx); + last_voff = voff; + voff = line_voff_opl; + } + else + { + break; + } + } + } + } + } + return out; +} + //////////////////////////////// //~ rjf: Entry Point @@ -135,9 +198,10 @@ entry_point(CmdLine *cmdline) //- rjf: initialize state, unpack command line Arena *arena = arena_alloc(); P2R_User2Convert *user2convert = p2r_user2convert_from_cmdln(arena, cmdline); + user2convert->flags &= ~(P2R_ConvertFlag_Types|P2R_ConvertFlag_UDTs); //- rjf: display errors with input - if(user2convert->errors.node_count > 0 && !user2convert->hide_errors.input) + if(user2convert->errors.node_count > 0) { for(String8Node *n = user2convert->errors.first; n != 0; n = n->next) { @@ -195,65 +259,46 @@ entry_point(CmdLine *cmdline) } //- rjf: join unit vmap + ProfBegin("join unit vmap"); P2B_BakeUnitVMapOut *bake_unit_vmap_out = ts_join_struct(bake_unit_vmap_ticket, max_U64, P2B_BakeUnitVMapOut); RDI_VMapEntry *unit_vmap = bake_unit_vmap_out->vmap_entries; U32 unit_vmap_count = (U32)(bake_unit_vmap_out->vmap_entries_count); + ProfEnd(); //- rjf: join units P2B_BakeUnitOut **bake_units_out = push_array(arena, P2B_BakeUnitOut*, params->units.total_count+1); - for(U64 idx = 1; idx < params->units.total_count+1; idx += 1) + ProfScope("join units") { - bake_units_out[idx] = ts_join_struct(bake_units_tickets[idx], max_U64, P2B_BakeUnitOut); + for(U64 idx = 1; idx < params->units.total_count+1; idx += 1) + { + bake_units_out[idx] = ts_join_struct(bake_units_tickets[idx], max_U64, P2B_BakeUnitOut); + } } - //- rjf: dump FUNC & line records - ProfScope("dump FUNC & line records") + //- rjf: kick off FUNC & line record dump tasks + P2B_DumpProcChunkIn *dump_proc_chunk_in = push_array(arena, P2B_DumpProcChunkIn, params->procedures.chunk_count); + TS_Ticket *dump_proc_chunk_tickets = push_array(arena, TS_Ticket, params->procedures.chunk_count); + ProfScope("kick off FUNC & line record dump tasks") { - for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next) + U64 task_idx = 0; + for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next, task_idx += 1) { - for(U64 idx = 0; idx < n->count; idx += 1) - { - // NOTE(rjf): breakpad does not support multiple voff ranges per procedure. - RDIM_Symbol *proc = &n->v[idx]; - RDIM_Scope *root_scope = proc->root_scope; - if(root_scope != 0 && root_scope->voff_ranges.first != 0) - { - // rjf: dump function record - RDIM_Rng1U64 voff_range = root_scope->voff_ranges.first->v; - str8_list_pushf(arena, &dump, "FUNC %I64x %I64x %I64x %S\n", voff_range.min, voff_range.max-voff_range.min, 0ull, proc->name); - - // rjf: dump function lines - U64 unit_idx = rdi_vmap_idx_from_voff(unit_vmap, unit_vmap_count, voff_range.min); - if(0 < unit_idx && unit_idx <= params->units.total_count) - { - // rjf: unpack unit line info - P2B_BakeUnitOut *bake_unit_out = bake_units_out[unit_idx]; - RDI_ParsedLineInfo line_info = {bake_unit_out->unit_line_voffs, bake_unit_out->unit_lines, 0, bake_unit_out->unit_line_count, 0}; - for(U64 voff = voff_range.min, last_voff = 0; - voff < voff_range.max && voff > last_voff;) - { - RDI_U64 line_info_idx = rdi_line_info_idx_from_voff(&line_info, voff); - if(line_info_idx < line_info.count) - { - RDI_Line *line = &line_info.lines[line_info_idx]; - U64 line_voff_min = line_info.voffs[line_info_idx]; - U64 line_voff_opl = line_info.voffs[line_info_idx+1]; - str8_list_pushf(arena, &dump, "%I64x %I64x %I64u %I64u\n", - line_voff_min, - line_voff_opl-line_voff_min, - (U64)line->line_num, - (U64)line->file_idx); - last_voff = voff; - voff = line_voff_opl; - } - else - { - break; - } - } - } - } - } + dump_proc_chunk_in[task_idx].unit_vmap = unit_vmap; + dump_proc_chunk_in[task_idx].unit_vmap_count = unit_vmap_count; + dump_proc_chunk_in[task_idx].bake_units_out = bake_units_out; + dump_proc_chunk_in[task_idx].bake_units_out_count = params->units.total_count+1; + dump_proc_chunk_in[task_idx].chunk = n; + dump_proc_chunk_tickets[task_idx] = ts_kickoff(p2b_dump_proc_chunk_task__entry_point, 0, &dump_proc_chunk_in[task_idx]); + } + } + + //- rjf: join FUNC & line record dump tasks + ProfScope("join FUNC & line record dump tasks") + { + for(U64 idx = 0; idx < params->procedures.chunk_count; idx += 1) + { + String8List *out = ts_join_struct(dump_proc_chunk_tickets[idx], max_U64, String8List); + str8_list_concat_in_place(&dump, out); } } } diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.c b/src/raddbgi_from_pdb/raddbgi_from_pdb.c index b68fc952..b9951804 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb.c +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb.c @@ -84,97 +84,15 @@ p2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline) //- rjf: get output name { result->output_name = cmd_line_string(cmdline, str8_lit("out")); - } - - //- rjf: error options - if(cmd_line_has_flag(cmdline, str8_lit("hide_errors"))) - { - String8List vals = cmd_line_strings(cmdline, str8_lit("hide_errors")); - - // if no values - set all to hidden - if(vals.node_count == 0) + if(result->output_name.size == 0) { - B8 *ptr = (B8*)&result->hide_errors; - B8 *opl = ptr + sizeof(result->hide_errors); - for(;ptr < opl; ptr += 1) - { - *ptr = 1; - } - } - - // for each explicit value set the corresponding flag to hidden - for(String8Node *node = vals.first; node != 0; node = node->next) - { - if(str8_match(node->string, str8_lit("input"), 0)) - { - result->hide_errors.input = 1; - } - else if(str8_match(node->string, str8_lit("output"), 0)) - { - result->hide_errors.output = 1; - } - else if(str8_match(node->string, str8_lit("parsing"), 0)) - { - result->hide_errors.parsing = 1; - } - else if(str8_match(node->string, str8_lit("converting"), 0)) - { - result->hide_errors.converting = 1; - } + str8_list_pushf(arena, &result->errors, "Missing required parameter: '--out:'"); } } - //- rjf: dump options - if(cmd_line_has_flag(cmdline, str8_lit("dump"))) + //- rjf: get flags { - result->dump = 1; - String8List vals = cmd_line_strings(cmdline, str8_lit("dump")); - if(vals.first == 0) - { - B8 *ptr = &result->dump__first; - for(;ptr < &result->dump__last; ptr += 1) - { - *ptr = 1; - } - } - else - { - for(String8Node *node = vals.first; node != 0; node = node->next) - { - if(str8_match(node->string, str8_lit("coff_sections"), 0)) - { - result->dump_coff_sections = 1; - } - else if(str8_match(node->string, str8_lit("msf"), 0)) - { - result->dump_msf = 1; - } - else if(str8_match(node->string, str8_lit("sym"), 0)) - { - result->dump_sym = 1; - } - else if(str8_match(node->string, str8_lit("tpi_hash"), 0)) - { - result->dump_tpi_hash = 1; - } - else if(str8_match(node->string, str8_lit("leaf"), 0)) - { - result->dump_leaf = 1; - } - else if(str8_match(node->string, str8_lit("c13"), 0)) - { - result->dump_c13 = 1; - } - else if(str8_match(node->string, str8_lit("contributions"), 0)) - { - result->dump_contributions = 1; - } - else if(str8_match(node->string, str8_lit("table_diagnostics"), 0)) - { - result->dump_table_diagnostics = 1; - } - } - } + result->flags = P2R_ConvertFlag_All; } return result; @@ -184,7 +102,7 @@ p2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline) //~ rjf: COFF <-> RADDBGI Canonical Conversions internal RDI_BinarySectionFlags -rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags) +p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags) { RDI_BinarySectionFlags result = 0; if(flags & COFF_SectionFlag_MEM_READ) @@ -1218,7 +1136,7 @@ internal void * p2r_udt_convert_task__entry_point(Arena *arena, void *p) { P2R_UDTConvertIn *in = (P2R_UDTConvertIn *)p; -#define p2r_type_ptr_from_itype(itype) (((itype) < in->tpi_leaf->itype_opl) ? (in->itype_type_ptrs[(in->itype_fwd_map[(itype)] ? in->itype_fwd_map[(itype)] : (itype))]) : 0) +#define p2r_type_ptr_from_itype(itype) ((in->itype_type_ptrs && (itype) < in->tpi_leaf->itype_opl) ? (in->itype_type_ptrs[(in->itype_fwd_map[(itype)] ? in->itype_fwd_map[(itype)] : (itype))]) : 0) RDIM_UDTChunkList *udts = push_array(arena, RDIM_UDTChunkList, 1); RDI_U64 udts_chunk_cap = 1024; ProfScope("convert UDT info") @@ -1844,7 +1762,7 @@ p2r_symbol_stream_convert_task__entry_point(Arena *arena, void *p) { Temp scratch = scratch_begin(&arena, 1); P2R_SymbolStreamConvertIn *in = (P2R_SymbolStreamConvertIn *)p; -#define p2r_type_ptr_from_itype(itype) (((itype) < in->tpi_leaf->itype_opl) ? (in->itype_type_ptrs[(in->itype_fwd_map[(itype)] ? in->itype_fwd_map[(itype)] : (itype))]) : 0) +#define p2r_type_ptr_from_itype(itype) ((in->itype_type_ptrs && (itype) < in->tpi_leaf->itype_opl) ? (in->itype_type_ptrs[(in->itype_fwd_map[(itype)] ? in->itype_fwd_map[(itype)] : (itype))]) : 0) ////////////////////////// //- rjf: set up outputs for this sym stream @@ -2223,6 +2141,7 @@ p2r_symbol_stream_convert_task__entry_point(Arena *arena, void *p) local->type = type; // rjf: add location info to local + if(type != 0) { // rjf: determine if we need an extra indirection to the value B32 extra_indirection_to_value = 0; @@ -2665,45 +2584,49 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) //- rjf: kickoff TPI hash parse // P2R_TPIHashParseIn tpi_hash_in = {0}; + TS_Ticket tpi_hash_ticket = {0}; { tpi_hash_in.strtbl = strtbl; tpi_hash_in.tpi = tpi; tpi_hash_in.hash_data = msf_data_from_stream(msf, tpi->hash_sn); tpi_hash_in.aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); + tpi_hash_ticket = ts_kickoff(p2r_tpi_hash_parse_task__entry_point, 0, &tpi_hash_in); } - TS_Ticket tpi_hash_ticket = ts_kickoff(p2r_tpi_hash_parse_task__entry_point, 0, &tpi_hash_in); ////////////////////////////////////////////////////////////// //- rjf: kickoff TPI leaf parse // P2R_TPILeafParseIn tpi_leaf_in = {0}; + TS_Ticket tpi_leaf_ticket = {0}; { tpi_leaf_in.leaf_data = pdb_leaf_data_from_tpi(tpi); tpi_leaf_in.itype_first = tpi->itype_first; + tpi_leaf_ticket = ts_kickoff(p2r_tpi_leaf_parse_task__entry_point, 0, &tpi_leaf_in); } - TS_Ticket tpi_leaf_ticket = ts_kickoff(p2r_tpi_leaf_parse_task__entry_point, 0, &tpi_leaf_in); ////////////////////////////////////////////////////////////// //- rjf: kickoff IPI hash parse // P2R_TPIHashParseIn ipi_hash_in = {0}; + TS_Ticket ipi_hash_ticket = {0}; { ipi_hash_in.strtbl = strtbl; ipi_hash_in.tpi = ipi; ipi_hash_in.hash_data = msf_data_from_stream(msf, ipi->hash_sn); ipi_hash_in.aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); + ipi_hash_ticket = ts_kickoff(p2r_tpi_hash_parse_task__entry_point, 0, &ipi_hash_in); } - TS_Ticket ipi_hash_ticket = ts_kickoff(p2r_tpi_hash_parse_task__entry_point, 0, &ipi_hash_in); ////////////////////////////////////////////////////////////// //- rjf: kickoff IPI leaf parse // P2R_TPILeafParseIn ipi_leaf_in = {0}; + TS_Ticket ipi_leaf_ticket = {0}; { ipi_leaf_in.leaf_data = pdb_leaf_data_from_tpi(ipi); ipi_leaf_in.itype_first = ipi->itype_first; + ipi_leaf_ticket = ts_kickoff(p2r_tpi_leaf_parse_task__entry_point, 0, &ipi_leaf_in); } - TS_Ticket ipi_leaf_ticket = ts_kickoff(p2r_tpi_leaf_parse_task__entry_point, 0, &ipi_leaf_in); ////////////////////////////////////////////////////////////// //- rjf: kickoff top-level global symbol stream parse @@ -2840,7 +2763,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) char *name_opl = name_first + sizeof(coff_ptr->name); RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); sec->name = str8_cstring_capped(name_first, name_opl); - sec->flags = rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); + sec->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); sec->voff_first = coff_ptr->voff; sec->voff_opl = coff_ptr->voff+coff_ptr->vsize; sec->foff_first = coff_ptr->foff; @@ -2922,11 +2845,13 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) // possible, and so this map can be used to do that in subsequent stages. // CV_TypeId *itype_fwd_map = 0; - CV_TypeId itype_first = tpi_leaf->itype_first; - CV_TypeId itype_opl = tpi_leaf->itype_opl; - ProfScope("types pass 1: produce type forward resolution map") + CV_TypeId itype_first = 0; + CV_TypeId itype_opl = 0; + if(in->flags & P2R_ConvertFlag_Types) ProfScope("types pass 1: produce type forward resolution map") { //- rjf: allocate forward resolution map + itype_first = tpi_leaf->itype_first; + itype_opl = tpi_leaf->itype_opl; itype_fwd_map = push_array(arena, CV_TypeId, (U64)itype_opl); //- rjf: kick off tasks to fill forward resolution map @@ -2963,7 +2888,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) // as such, always show up *earlier* in the actually built types. // P2R_TypeIdChain **itype_chains = 0; - ProfScope("types pass 2: produce per-itype itype chain (for producing dependent types first)") + if(in->flags & P2R_ConvertFlag_Types) ProfScope("types pass 2: produce per-itype itype chain (for producing dependent types first)") { //- rjf: allocate itype chain table itype_chains = push_array(arena, P2R_TypeIdChain *, (U64)itype_opl); @@ -3000,8 +2925,8 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) // RDIM_Type **itype_type_ptrs = 0; RDIM_TypeChunkList all_types = {0}; -#define p2r_type_ptr_from_itype(itype) (((itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) - ProfScope("types pass 3: construct all root/stub types from TPI") +#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) + if(in->flags & P2R_ConvertFlag_Types) ProfScope("types pass 3: construct all root/stub types from TPI") { itype_type_ptrs = push_array(arena, RDIM_Type *, (U64)(itype_opl)); for(CV_TypeId root_itype = 0; root_itype < itype_opl; root_itype += 1) @@ -3425,7 +3350,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) U64 udt_tasks_count = ((U64)itype_opl+(udt_task_size_itypes-1))/udt_task_size_itypes; P2R_UDTConvertIn *udt_tasks_inputs = push_array(scratch.arena, P2R_UDTConvertIn, udt_tasks_count); TS_Ticket *udt_tasks_tickets = push_array(scratch.arena, TS_Ticket, udt_tasks_count); - ProfScope("types pass 4: kick off UDT build") + if(in->flags & P2R_ConvertFlag_UDTs) ProfScope("types pass 4: kick off UDT build") { for(U64 idx = 0; idx < udt_tasks_count; idx += 1) { diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.h b/src/raddbgi_from_pdb/raddbgi_from_pdb.h index 9384bcb1..ff385d2d 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb.h +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb.h @@ -7,6 +7,14 @@ //////////////////////////////// //~ rjf: Conversion Stage Inputs/Outputs +typedef U32 P2R_ConvertFlags; +enum +{ + P2R_ConvertFlag_Types = (1<<0), + P2R_ConvertFlag_UDTs = (1<<1), + P2R_ConvertFlag_All = 0xffffffff, +}; + typedef struct P2R_User2Convert P2R_User2Convert; struct P2R_User2Convert { @@ -15,24 +23,7 @@ struct P2R_User2Convert String8 input_exe_name; String8 input_exe_data; String8 output_name; - struct - { - B8 input; - B8 output; - B8 parsing; - B8 converting; - } hide_errors; - B8 dump; - B8 dump__first; - B8 dump_coff_sections; - B8 dump_msf; - B8 dump_sym; - B8 dump_tpi_hash; - B8 dump_leaf; - B8 dump_c13; - B8 dump_contributions; - B8 dump_table_diagnostics; - B8 dump__last; + P2R_ConvertFlags flags; String8List errors; }; @@ -392,7 +383,7 @@ internal P2R_User2Convert *p2r_user2convert_from_cmdln(Arena *arena, CmdLine *cm //////////////////////////////// //~ rjf: COFF => RADDBGI Canonical Conversions -internal RDI_BinarySectionFlags rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags); +internal RDI_BinarySectionFlags p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags); //////////////////////////////// //~ rjf: CodeView => RADDBGI Canonical Conversions diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c b/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c index 42ed46b5..b44b8657 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c @@ -55,7 +55,7 @@ entry_point(CmdLine *cmdline) P2R_User2Convert *user2convert = p2r_user2convert_from_cmdln(arena, cmdline); //- rjf: display errors with input - if(user2convert->errors.node_count > 0 && !user2convert->hide_errors.input) + if(user2convert->errors.node_count > 0) { for(String8Node *n = user2convert->errors.first; n != 0; n = n->next) {