From a3f411ddd42fc9486e9ac697f21e1d8899cded67 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 7 Jun 2024 13:45:26 -0700 Subject: [PATCH] more progress on rdi parsing library high-level composite helpers; update breakpad_from_pdb to new format/maker changes --- src/lib_rdi_format/rdi_format_parse.c | 86 +++++++++ src/lib_rdi_format/rdi_format_parse.h | 44 ++++- .../rdi_breakpad_from_pdb_main.c | 165 ++++++++---------- 3 files changed, 203 insertions(+), 92 deletions(-) diff --git a/src/lib_rdi_format/rdi_format_parse.c b/src/lib_rdi_format/rdi_format_parse.c index b7d7f825..87ccf1bc 100644 --- a/src/lib_rdi_format/rdi_format_parse.c +++ b/src/lib_rdi_format/rdi_format_parse.c @@ -525,6 +525,12 @@ rdi_procedure_from_name_cstr(RDI_Parsed *rdi, char *cstr) return result; } +RDI_PROC RDI_U8 * +rdi_name_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure, RDI_U64 *len_out) +{ + return rdi_string_from_idx(rdi, procedure->name_string_idx, len_out); +} + RDI_PROC RDI_Scope * rdi_root_scope_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure) { @@ -548,6 +554,14 @@ rdi_opl_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure) return result; } +RDI_PROC RDI_Procedure * +rdi_procedure_from_voff(RDI_Parsed *rdi, RDI_U64 voff) +{ + RDI_Scope *scope = rdi_scope_from_voff(rdi, voff); + RDI_Procedure *procedure = rdi_procedure_from_scope(rdi, scope); + return procedure; +} + //- scopes RDI_PROC RDI_U64 @@ -566,6 +580,21 @@ rdi_opl_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope) return result; } +RDI_PROC RDI_Scope * +rdi_scope_from_voff(RDI_Parsed *rdi, RDI_U64 voff) +{ + RDI_U32 idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff); + RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, idx); + return scope; +} + +RDI_PROC RDI_Procedure * +rdi_procedure_from_scope(RDI_Parsed *rdi, RDI_Scope *scope) +{ + RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, scope->proc_idx); + return procedure; +} + //- units RDI_PROC RDI_Unit * @@ -617,6 +646,31 @@ rdi_source_file_from_line(RDI_Parsed *rdi, RDI_Line *line) //- source files +RDI_PROC RDI_SourceFile * +rdi_source_file_from_normal_path(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size) +{ + RDI_NameMap *map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_NormalSourcePaths); + RDI_ParsedNameMap map_parsed = {0}; + rdi_parsed_from_name_map(rdi, map, &map_parsed); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map_parsed, name, name_size); + RDI_U32 id_count = 0; + RDI_U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); + RDI_U32 file_idx = 0; + if(id_count > 0) + { + file_idx = ids[0]; + } + RDI_SourceFile *file = rdi_element_from_name_idx(rdi, SourceFiles, file_idx); + return file; +} + +RDI_PROC RDI_SourceFile * +rdi_source_file_from_normal_path_cstr(RDI_Parsed *rdi, char *cstr) +{ + RDI_SourceFile *result = rdi_source_file_from_normal_path(rdi, (RDI_U8 *)cstr, rdi_cstring_length(cstr)); + return result; +} + RDI_PROC RDI_U8 * rdi_normal_path_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U64 *len_out) { @@ -630,6 +684,38 @@ rdi_file_path_node_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file) return result; } +RDI_PROC RDI_SourceLineMap * +rdi_source_line_map_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file) +{ + RDI_SourceLineMap *result = rdi_element_from_name_idx(rdi, SourceLineMaps, src_file->source_line_map_idx); + return result; +} + +RDI_PROC RDI_U64 +rdi_first_voff_from_source_file_line_num(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U32 line_num) +{ + RDI_SourceLineMap *source_line_map = rdi_source_line_map_from_source_file(rdi, src_file); + RDI_U64 voff = rdi_first_voff_from_source_line_map_num(rdi, source_line_map, line_num); + return voff; +} + +//- source line maps + +RDI_PROC RDI_U64 +rdi_first_voff_from_source_line_map_num(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_U32 line_num) +{ + RDI_ParsedSourceLineMap parsed = {0}; + rdi_parsed_from_source_line_map(rdi, map, &parsed); + RDI_U32 all_voffs_count = 0; + RDI_U64 *all_voffs = rdi_line_voffs_from_num(&parsed, line_num, &all_voffs_count); + RDI_U64 voff = 0; + if(all_voffs_count != 0) + { + voff = all_voffs[0]; + } + return voff; +} + //- file path nodes RDI_PROC RDI_FilePathNode * diff --git a/src/lib_rdi_format/rdi_format_parse.h b/src/lib_rdi_format/rdi_format_parse.h index f75ae369..1e0c097a 100644 --- a/src/lib_rdi_format/rdi_format_parse.h +++ b/src/lib_rdi_format/rdi_format_parse.h @@ -7,6 +7,37 @@ // Defines helper types and functions for extracting data from // RDI files. +//////////////////////////////////////////////////////////////// +//~ Usage Samples +// +#if 0 +// Procedure Name -> Line +{ + RDI_Parsed *rdi = ...; + char *name = "mule_main"; + RDI_Procedure *procedure = rdi_procedure_from_name_cstr(rdi, name); // 1. name -> procedure + RDI_U64 procedure_first_voff = rdi_first_voff_from_procedure(rdi, procedure); // 2. procedure -> virtual offset + RDI_Line line = rdi_line_from_voff(rdi, procedure_first_voff); // 3. virtual offset -> line + RDI_SourceFile *file = rdi_source_file_from_line(rdi, &line); // 4. line -> source file + RDI_U64 file_path_size = 0; // 5. source file -> path + RDI_U8 *file_path = rdi_normal_path_from_source_file(rdi, file, &file_path_size); + printf("%s is at %.*s:%u\n", name, (int)file_path_size, file_path, line.line_num); +} + +// Line -> Procedure Name +{ + RDI_Parsed *rdi = ...; + char *path = "c:/devel/raddebugger/src/mule/mule_main.cpp"; + RDI_U32 line_num = 2557; + RDI_SourceFile *file = rdi_source_file_from_normal_path_cstr(rdi, path); // 1. path -> source file + RDI_U64 voff = rdi_first_voff_from_source_file_line_num(rdi, file, line_num); // 2. (source file, line) -> virtual offset + RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); // 3. virtual offset -> procedure + RDI_U64 name_size = 0; // 4. procedure -> name + RDI_U8 *name = rdi_name_from_procedure(rdi, procedure, &name_size); + printf("%s:%u is inside %.*s\n", path, line_num, (int)name_size, name); +} +#endif + #ifndef RDI_FORMAT_PARSE_H #define RDI_FORMAT_PARSE_H @@ -147,26 +178,37 @@ RDI_PROC RDI_U32 *rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node //- procedures RDI_PROC RDI_Procedure *rdi_procedure_from_name(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size); RDI_PROC RDI_Procedure *rdi_procedure_from_name_cstr(RDI_Parsed *rdi, char *cstr); +RDI_PROC RDI_U8 *rdi_name_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure, RDI_U64 *len_out); RDI_PROC RDI_Scope *rdi_root_scope_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure); RDI_PROC RDI_U64 rdi_first_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure); RDI_PROC RDI_U64 rdi_opl_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure); +RDI_PROC RDI_Procedure *rdi_procedure_from_voff(RDI_Parsed *rdi, RDI_U64 voff); //- scopes RDI_PROC RDI_U64 rdi_first_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope); RDI_PROC RDI_U64 rdi_opl_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope); +RDI_PROC RDI_Scope *rdi_scope_from_voff(RDI_Parsed *rdi, RDI_U64 voff); +RDI_PROC RDI_Procedure *rdi_procedure_from_scope(RDI_Parsed *rdi, RDI_Scope *scope); //- units RDI_PROC RDI_Unit *rdi_unit_from_voff(RDI_Parsed *rdi, RDI_U64 voff); RDI_PROC RDI_LineTable *rdi_line_table_from_unit(RDI_Parsed *rdi, RDI_Unit *unit); -//- line info +//- line tables RDI_PROC RDI_Line rdi_line_from_voff(RDI_Parsed *rdi, RDI_U64 voff); RDI_PROC RDI_Line rdi_line_from_line_table_voff(RDI_Parsed *rdi, RDI_LineTable *line_table, RDI_U64 voff); RDI_PROC RDI_SourceFile *rdi_source_file_from_line(RDI_Parsed *rdi, RDI_Line *line); //- source files +RDI_PROC RDI_SourceFile *rdi_source_file_from_normal_path(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size); +RDI_PROC RDI_SourceFile *rdi_source_file_from_normal_path_cstr(RDI_Parsed *rdi, char *cstr); RDI_PROC RDI_U8 *rdi_normal_path_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U64 *len_out); RDI_PROC RDI_FilePathNode *rdi_file_path_node_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file); +RDI_PROC RDI_SourceLineMap *rdi_source_line_map_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file); +RDI_PROC RDI_U64 rdi_first_voff_from_source_file_line_num(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U32 line_num); + +//- source line maps +RDI_PROC RDI_U64 rdi_first_voff_from_source_line_map_num(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_U32 line_num); //- file path nodes RDI_PROC RDI_FilePathNode *rdi_parent_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode *node); diff --git a/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c index b1578399..9a32b06e 100644 --- a/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c +++ b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c @@ -59,61 +59,27 @@ struct P2B_BakeUnitVMapIn RDIM_UnitChunkList *units; }; -typedef struct P2B_BakeUnitVMapOut P2B_BakeUnitVMapOut; -struct P2B_BakeUnitVMapOut -{ - RDI_VMapEntry *vmap_entries; - RDI_U64 vmap_entries_count; -}; - internal TS_TASK_FUNCTION_DEF(p2b_bake_unit_vmap_task__entry_point) { P2B_BakeUnitVMapIn *in = (P2B_BakeUnitVMapIn *)p; - P2B_BakeUnitVMapOut *out = push_array(arena, P2B_BakeUnitVMapOut, 1); - RDIM_UnitVMapBakeResult bake = rdim_bake_unit_vmap(arena, in->units); - out->vmap_entries = bake.vmap.vmap; - out->vmap_entries_count = bake.vmap.count+1; + RDIM_UnitVMapBakeResult *out = push_array(arena, RDIM_UnitVMapBakeResult, 1); + *out = rdim_bake_unit_vmap(arena, in->units); return out; } -//- rjf: per-unit baking +//- rjf: line table baking -typedef struct P2B_BakeUnitIn P2B_BakeUnitIn; -struct P2B_BakeUnitIn +typedef struct P2B_BakeLineTablesIn P2B_BakeLineTablesIn; +struct P2B_BakeLineTablesIn { - RDIM_Unit *unit; + RDIM_LineTableChunkList *line_tables; }; -typedef struct P2B_BakeUnitOut P2B_BakeUnitOut; -struct P2B_BakeUnitOut +internal TS_TASK_FUNCTION_DEF(p2b_bake_line_table_task__entry_point) { - U64 unit_line_count; - U64 *unit_line_voffs; - RDI_Line *unit_lines; -}; - -internal TS_TASK_FUNCTION_DEF(p2b_bake_unit_task__entry_point) -{ - P2B_BakeUnitIn *in = (P2B_BakeUnitIn *)p; - P2B_BakeUnitOut *out = push_array(arena, P2B_BakeUnitOut, 1); - RDIM_BakeSectionList sections = rdim_bake_section_list_from_unit(arena, in->unit); - RDIM_BakeSection *voffs_section = 0; - RDIM_BakeSection *lines_section = 0; - for(RDIM_BakeSectionNode *n = sections.first; n != 0; n = n->next) - { - switch(n->v.tag) - { - default:{}break; - case RDI_SectionKind_LineInfoVoffs:{voffs_section = &n->v;}break; - case RDI_SectionKind_LineInfoData: {lines_section = &n->v;}break; - } - } - if(voffs_section != 0 && lines_section != 0) - { - out->unit_line_count = lines_section->unpacked_size/sizeof(RDI_Line); - out->unit_line_voffs = (U64 *)voffs_section->data; - out->unit_lines = (RDI_Line *)lines_section->data; - } + P2B_BakeLineTablesIn *in = (P2B_BakeLineTablesIn *)p; + RDIM_LineTableBakeResult *out = push_array(arena, RDIM_LineTableBakeResult, 1); + *out = rdim_bake_line_tables(arena, in->line_tables); return out; } @@ -124,8 +90,9 @@ struct P2B_DumpProcChunkIn { RDI_VMapEntry *unit_vmap; U32 unit_vmap_count; - P2B_BakeUnitOut **bake_units_out; - U64 bake_units_out_count; + U32 *unit_line_table_idxs; + U64 unit_count; + RDIM_LineTableBakeResult *line_tables_bake; RDIM_SymbolChunkNode *chunk; }; @@ -133,6 +100,12 @@ internal TS_TASK_FUNCTION_DEF(p2b_dump_proc_chunk_task__entry_point) { P2B_DumpProcChunkIn *in = (P2B_DumpProcChunkIn *)p; String8List *out = push_array(arena, String8List, 1); + RDI_LineTable *line_tables = in->line_tables_bake->line_tables; + RDI_U64 line_tables_count = in->line_tables_bake->line_tables_count; + RDI_U64 *line_table_voffs = in->line_tables_bake->line_table_voffs; + RDI_U64 line_table_voffs_count = in->line_tables_bake->line_table_voffs_count; + RDI_Line *line_table_lines = in->line_tables_bake->line_table_lines; + RDI_U64 line_table_lines_count = in->line_tables_bake->line_table_lines_count; for(U64 idx = 0; idx < in->chunk->count; idx += 1) { // NOTE(rjf): breakpad does not support multiple voff ranges per procedure. @@ -146,34 +119,45 @@ internal TS_TASK_FUNCTION_DEF(p2b_dump_proc_chunk_task__entry_point) // 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) + if(0 < unit_idx && unit_idx <= in->unit_count) { - // rjf: unpack unit line info - P2B_BakeUnitOut *bake_unit_out = in->bake_units_out[unit_idx]; - RDI_ParsedLineTable 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;) + U32 line_table_idx = in->unit_line_table_idxs[unit_idx]; + if(0 < line_table_idx && line_table_idx <= line_tables_count) { - RDI_U64 line_info_idx = rdi_line_info_idx_from_voff(&line_info, voff); - if(line_info_idx < line_info.count) + // rjf: unpack unit line info + RDI_LineTable *line_table = &line_tables[line_table_idx]; + RDI_ParsedLineTable line_info = { - 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]; - if(line->file_idx != 0) + line_table_voffs + line_table->voffs_base_idx, + line_table_lines + line_table->lines_base_idx, + 0, + line_table->lines_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) { - 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); + 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]; + if(line->file_idx != 0) + { + 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; } - last_voff = voff; - voff = line_voff_opl; - } - else - { - break; } } } @@ -236,20 +220,23 @@ entry_point(CmdLine *cmdline) RDIM_BakeParams *params = &convert2bake->bake_params; //- rjf: kick off unit vmap baking - P2B_BakeUnitVMapIn bake_unit_vmap_in = {params}; + P2B_BakeUnitVMapIn bake_unit_vmap_in = {¶ms->units}; TS_Ticket bake_unit_vmap_ticket = ts_kickoff(p2b_bake_unit_vmap_task__entry_point, 0, &bake_unit_vmap_in); - //- rjf: kick off per-line-table baking - P2B_BakeUnitIn *bake_units_in = push_array(arena, P2B_BakeUnitIn, params->units.total_count+1); - TS_Ticket *bake_units_tickets = push_array(arena, TS_Ticket, params->units.total_count+1); + //- rjf: kick off line-table baking + P2B_BakeLineTablesIn bake_line_tables_in = {¶ms->line_tables}; + TS_Ticket bake_line_tables_ticket = ts_kickoff(p2b_bake_line_table_task__entry_point, 0, &bake_line_tables_in); + + //- rjf: build unit -> line table idx array + U64 unit_count = params->units.total_count; + U32 *unit_line_table_idxs = push_array(arena, U32, unit_count+1); { - U64 idx = 1; + U64 dst_idx = 1; for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) { - for(U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, idx += 1) + for(U64 n_idx = 0; n_idx < n->count; n_idx += 1, dst_idx += 1) { - bake_units_in[chunk_idx].unit = &n->v[chunk_idx]; - bake_units_tickets[idx] = ts_kickoff(p2b_bake_unit_task__entry_point, 0, &bake_units_in[chunk_idx]); + unit_line_table_idxs[dst_idx] = rdim_idx_from_line_table(n->v[n_idx].line_table); } } } @@ -273,20 +260,15 @@ 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); + RDIM_UnitVMapBakeResult *bake_unit_vmap_out = ts_join_struct(bake_unit_vmap_ticket, max_U64, RDIM_UnitVMapBakeResult); + RDI_VMapEntry *unit_vmap = bake_unit_vmap_out->vmap.vmap; + U32 unit_vmap_count = bake_unit_vmap_out->vmap.count; ProfEnd(); - //- rjf: join units - P2B_BakeUnitOut **bake_units_out = push_array(arena, P2B_BakeUnitOut*, params->units.total_count+1); - ProfScope("join units") - { - 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: join line tables + ProfBegin("join line table"); + RDIM_LineTableBakeResult *bake_line_tables_out = ts_join_struct(bake_line_tables_ticket, max_U64, RDIM_LineTableBakeResult); + ProfEnd(); //- rjf: kick off FUNC & line record dump tasks P2B_DumpProcChunkIn *dump_proc_chunk_in = push_array(arena, P2B_DumpProcChunkIn, params->procedures.chunk_count); @@ -298,8 +280,9 @@ entry_point(CmdLine *cmdline) { 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].unit_line_table_idxs = unit_line_table_idxs; + dump_proc_chunk_in[task_idx].unit_count = unit_count; + dump_proc_chunk_in[task_idx].line_tables_bake = bake_line_tables_out; 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]); }