clean up pdb -> raddbgi converter parameters; extend conversion parameterization with optional type/udt disabling; use in breakpad converter

This commit is contained in:
Ryan Fleury
2024-02-26 14:11:26 -08:00
parent 1c2c82cc58
commit 3b7a4f3331
4 changed files with 131 additions and 170 deletions
+94 -49
View File
@@ -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);
}
}
}
+26 -101
View File
@@ -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:<output_path>'");
}
}
//- 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)
{
+10 -19
View File
@@ -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
+1 -1
View File
@@ -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)
{