mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-06 22:08:41 +00:00
breakpad_from_pdb per-function line info writing
This commit is contained in:
+1
-1
@@ -47,7 +47,7 @@ commands =
|
|||||||
{
|
{
|
||||||
.rjf_f1 =
|
.rjf_f1 =
|
||||||
{
|
{
|
||||||
.win = "build raddbgi_from_pdb telemetry",
|
.win = "build breakpad_from_pdb telemetry release",
|
||||||
.linux = "",
|
.linux = "",
|
||||||
.out = "*compilation*",
|
.out = "*compilation*",
|
||||||
.footer_panel = true,
|
.footer_panel = true,
|
||||||
|
|||||||
@@ -13,7 +13,9 @@
|
|||||||
|
|
||||||
//- rjf: [lib]
|
//- rjf: [lib]
|
||||||
#include "lib_raddbgi_format/raddbgi_format.h"
|
#include "lib_raddbgi_format/raddbgi_format.h"
|
||||||
|
#include "lib_raddbgi_format/raddbgi_format_parse.h"
|
||||||
#include "lib_raddbgi_format/raddbgi_format.c"
|
#include "lib_raddbgi_format/raddbgi_format.c"
|
||||||
|
#include "lib_raddbgi_format/raddbgi_format_parse.c"
|
||||||
|
|
||||||
//- rjf: [h]
|
//- rjf: [h]
|
||||||
#include "base/base_inc.h"
|
#include "base/base_inc.h"
|
||||||
@@ -41,6 +43,89 @@
|
|||||||
#include "pdb/pdb_stringize.c"
|
#include "pdb/pdb_stringize.c"
|
||||||
#include "raddbgi_from_pdb/raddbgi_from_pdb.c"
|
#include "raddbgi_from_pdb/raddbgi_from_pdb.c"
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Baking Tasks
|
||||||
|
|
||||||
|
//- rjf: unit vmap baking
|
||||||
|
|
||||||
|
typedef struct P2B_BakeUnitVMapIn P2B_BakeUnitVMapIn;
|
||||||
|
struct P2B_BakeUnitVMapIn
|
||||||
|
{
|
||||||
|
RDIM_BakeParams *params;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct P2B_BakeUnitVMapOut P2B_BakeUnitVMapOut;
|
||||||
|
struct P2B_BakeUnitVMapOut
|
||||||
|
{
|
||||||
|
RDI_VMapEntry *vmap_entries;
|
||||||
|
RDI_U64 vmap_entries_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
p2b_bake_unit_vmap_task__entry_point(Arena *arena, void *p)
|
||||||
|
{
|
||||||
|
P2B_BakeUnitVMapIn *in = (P2B_BakeUnitVMapIn *)p;
|
||||||
|
P2B_BakeUnitVMapOut *out = push_array(arena, P2B_BakeUnitVMapOut, 1);
|
||||||
|
RDIM_BakeSectionList sections = rdim_bake_unit_vmap_section_list_from_params(arena, in->params);
|
||||||
|
RDIM_BakeSection *vmap_section = 0;
|
||||||
|
for(RDIM_BakeSectionNode *n = sections.first; n != 0 && vmap_section == 0; n = n->next)
|
||||||
|
{
|
||||||
|
switch(n->v.tag)
|
||||||
|
{
|
||||||
|
default:{}break;
|
||||||
|
case RDI_DataSectionTag_UnitVmap:{vmap_section = &n->v;}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(vmap_section != 0)
|
||||||
|
{
|
||||||
|
out->vmap_entries = (RDI_VMapEntry *)vmap_section->data;
|
||||||
|
out->vmap_entries_count = vmap_section->size/sizeof(RDI_VMapEntry);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: per-unit baking
|
||||||
|
|
||||||
|
typedef struct P2B_BakeUnitIn P2B_BakeUnitIn;
|
||||||
|
struct P2B_BakeUnitIn
|
||||||
|
{
|
||||||
|
RDIM_Unit *unit;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct P2B_BakeUnitOut P2B_BakeUnitOut;
|
||||||
|
struct P2B_BakeUnitOut
|
||||||
|
{
|
||||||
|
U64 unit_line_count;
|
||||||
|
U64 *unit_line_voffs;
|
||||||
|
RDI_Line *unit_lines;
|
||||||
|
};
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
p2b_bake_unit_task__entry_point(Arena *arena, void *p)
|
||||||
|
{
|
||||||
|
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_DataSectionTag_LineInfoVoffs:{voffs_section = &n->v;}break;
|
||||||
|
case RDI_DataSectionTag_LineInfoData: {lines_section = &n->v;}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(voffs_section != 0 && lines_section != 0)
|
||||||
|
{
|
||||||
|
out->unit_line_count = lines_section->size/sizeof(RDI_Line);
|
||||||
|
out->unit_line_voffs = (U64 *)voffs_section->data;
|
||||||
|
out->unit_lines = (RDI_Line *)lines_section->data;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Entry Point
|
//~ rjf: Entry Point
|
||||||
|
|
||||||
@@ -73,10 +158,31 @@ entry_point(CmdLine *cmdline)
|
|||||||
{
|
{
|
||||||
RDIM_BakeParams *params = &convert2bake->bake_params;
|
RDIM_BakeParams *params = &convert2bake->bake_params;
|
||||||
|
|
||||||
|
//- rjf: kick off unit vmap baking
|
||||||
|
P2B_BakeUnitVMapIn bake_unit_vmap_in = {params};
|
||||||
|
TS_Ticket bake_unit_vmap_ticket = ts_kickoff(p2b_bake_unit_vmap_task__entry_point, 0, &bake_unit_vmap_in);
|
||||||
|
|
||||||
|
//- rjf: kick off per-unit 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);
|
||||||
|
{
|
||||||
|
U64 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)
|
||||||
|
{
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//- rjf: dump MODULE record
|
//- rjf: dump MODULE record
|
||||||
str8_list_pushf(arena, &dump, "MODULE windows x86_64 %I64x %S\n", params->top_level_info.exe_hash, params->top_level_info.exe_name);
|
str8_list_pushf(arena, &dump, "MODULE windows x86_64 %I64x %S\n", params->top_level_info.exe_hash, params->top_level_info.exe_name);
|
||||||
|
|
||||||
//- rjf: dump FILE records
|
//- rjf: dump FILE records
|
||||||
|
ProfScope("dump FILE records")
|
||||||
|
{
|
||||||
for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next)
|
for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next)
|
||||||
{
|
{
|
||||||
for(U64 idx = 0; idx < n->count; idx += 1)
|
for(U64 idx = 0; idx < n->count; idx += 1)
|
||||||
@@ -86,33 +192,84 @@ entry_point(CmdLine *cmdline)
|
|||||||
str8_list_pushf(arena, &dump, "FILE %I64u %S\n", file_idx, src_path);
|
str8_list_pushf(arena, &dump, "FILE %I64u %S\n", file_idx, src_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//- rjf: dump FUNC records
|
//- rjf: 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);
|
||||||
|
|
||||||
|
//- 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)
|
||||||
|
{
|
||||||
|
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")
|
||||||
|
{
|
||||||
for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next)
|
for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next)
|
||||||
{
|
{
|
||||||
for(U64 idx = 0; idx < n->count; 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_Symbol *proc = &n->v[idx];
|
||||||
RDIM_Scope *root_scope = proc->root_scope;
|
RDIM_Scope *root_scope = proc->root_scope;
|
||||||
if(root_scope != 0 && root_scope->voff_ranges.first != 0)
|
if(root_scope != 0 && root_scope->voff_ranges.first != 0)
|
||||||
{
|
{
|
||||||
|
// rjf: dump function record
|
||||||
RDIM_Rng1U64 voff_range = root_scope->voff_ranges.first->v;
|
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);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: bake
|
||||||
|
String8 baked = {0};
|
||||||
|
ProfScope("bake")
|
||||||
|
{
|
||||||
|
baked = str8_list_join(arena, &dump, 0);
|
||||||
|
}
|
||||||
|
|
||||||
//- rjf: write
|
//- rjf: write
|
||||||
ProfScope("write")
|
ProfScope("write")
|
||||||
{
|
{
|
||||||
OS_Handle output_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, user2convert->output_name);
|
OS_Handle output_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, user2convert->output_name);
|
||||||
U64 off = 0;
|
os_file_write(output_file, r1u64(0, baked.size), baked.str);
|
||||||
for(String8Node *n = dump.first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
os_file_write(output_file, r1u64(off, off+n->string.size), n->string.str);
|
|
||||||
off += n->string.size;
|
|
||||||
}
|
|
||||||
os_file_close(output_file);
|
os_file_close(output_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3744,14 +3744,17 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in)
|
|||||||
//- rjf: kick off pass 1 tasks
|
//- rjf: kick off pass 1 tasks
|
||||||
P2R_BakeUnitIn *bake_units_in = push_array(scratch.arena, P2R_BakeUnitIn, params->units.total_count);
|
P2R_BakeUnitIn *bake_units_in = push_array(scratch.arena, P2R_BakeUnitIn, params->units.total_count);
|
||||||
TS_Ticket *bake_units_tickets = push_array(scratch.arena, TS_Ticket, params->units.total_count);
|
TS_Ticket *bake_units_tickets = push_array(scratch.arena, TS_Ticket, params->units.total_count);
|
||||||
|
{
|
||||||
|
U64 idx = 0;
|
||||||
for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next)
|
for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next)
|
||||||
{
|
{
|
||||||
for(U64 idx = 0; idx < n->count; idx += 1)
|
for(U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, idx += 1)
|
||||||
{
|
{
|
||||||
bake_units_in[idx].unit = &n->v[idx];
|
bake_units_in[idx].unit = &n->v[chunk_idx];
|
||||||
bake_units_tickets[idx] = ts_kickoff(p2r_bake_unit_task__entry_point, 0, &bake_units_in[idx]);
|
bake_units_tickets[idx] = ts_kickoff(p2r_bake_unit_task__entry_point, 0, &bake_units_in[idx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
P2R_BuildBakeStringMapIn build_bake_string_map_in = {path_tree, params};
|
P2R_BuildBakeStringMapIn build_bake_string_map_in = {path_tree, params};
|
||||||
TS_Ticket build_bake_string_map_ticket = ts_kickoff(p2r_build_bake_string_map_task__entry_point, 0, &build_bake_string_map_in);
|
TS_Ticket build_bake_string_map_ticket = ts_kickoff(p2r_build_bake_string_map_task__entry_point, 0, &build_bake_string_map_in);
|
||||||
P2R_BuildBakeNameMapIn build_bake_name_map_in[RDI_NameMapKind_COUNT] = {0};
|
P2R_BuildBakeNameMapIn build_bake_name_map_in[RDI_NameMapKind_COUNT] = {0};
|
||||||
|
|||||||
Reference in New Issue
Block a user