eliminate standalone programs for pdb -> rdi; dwarf -> rdi; pdb -> breakpad; sketch out 'radbin', unified cli frontend for dumping/converting/etc., plug in pdb -> rdi, pdb -> breakpad, & stub out dumper/dwarf

This commit is contained in:
Ryan Fleury
2025-06-09 15:40:48 -07:00
parent 4926f6cfc8
commit 79bf3d8639
32 changed files with 1241 additions and 2201 deletions
+50 -87
View File
@@ -40,11 +40,12 @@ p2r_hash_from_voff(U64 voff)
////////////////////////////////
//~ rjf: Command Line -> Conversion Inputs
internal P2R_User2Convert *
#if 0
internal P2R_ConvertParams *
p2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline)
{
P2R_User2Convert *result = push_array(arena, P2R_User2Convert, 1);
P2R_ConvertParams *result = push_array(arena, P2R_ConvertParams, 1);
//- rjf: get input pdb
{
@@ -152,7 +153,8 @@ Case("source_path_name_map",NormalSourcePathNameMap)\
#undef FlagNameMapXList
return result;
}
}
#endif
////////////////////////////////
//~ rjf: COFF <-> RDI Canonical Conversions
@@ -503,7 +505,7 @@ p2r_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDI
ASYNC_WORK_DEF(p2r_exe_hash_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_EXEHashIn *in = (P2R_EXEHashIn *)input;
U64 *out = push_array(arena, U64, 1);
ProfScope("hash exe") *out = rdi_hash(in->exe_data.str, in->exe_data.size);
@@ -514,7 +516,7 @@ ASYNC_WORK_DEF(p2r_exe_hash_work)
ASYNC_WORK_DEF(p2r_tpi_hash_parse_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_TPIHashParseIn *in = (P2R_TPIHashParseIn *)input;
void *out = 0;
ProfScope("parse tpi hash") out = pdb_tpi_hash_from_data(arena, in->strtbl, in->tpi, in->hash_data, in->aux_data);
@@ -525,7 +527,7 @@ ASYNC_WORK_DEF(p2r_tpi_hash_parse_work)
ASYNC_WORK_DEF(p2r_tpi_leaf_parse_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_TPILeafParseIn *in = (P2R_TPILeafParseIn *)input;
void *out = 0;
ProfScope("parse tpi leaf") out = cv_leaf_from_data(arena, in->leaf_data, in->itype_first);
@@ -536,7 +538,7 @@ ASYNC_WORK_DEF(p2r_tpi_leaf_parse_work)
ASYNC_WORK_DEF(p2r_symbol_stream_parse_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_SymbolStreamParseIn *in = (P2R_SymbolStreamParseIn *)input;
void *out = 0;
ProfScope("parse symbol stream") out = cv_sym_from_data(arena, in->data, 4);
@@ -547,7 +549,7 @@ ASYNC_WORK_DEF(p2r_symbol_stream_parse_work)
ASYNC_WORK_DEF(p2r_c13_stream_parse_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_C13StreamParseIn *in = (P2R_C13StreamParseIn *)input;
void *out = 0;
ProfScope("parse c13 stream") out = cv_c13_parsed_from_data(arena, in->data, in->strtbl, in->coff_sections);
@@ -558,7 +560,7 @@ ASYNC_WORK_DEF(p2r_c13_stream_parse_work)
ASYNC_WORK_DEF(p2r_comp_unit_parse_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_CompUnitParseIn *in = (P2R_CompUnitParseIn *)input;
void *out = 0;
ProfScope("parse comp units") out = pdb_comp_unit_array_from_data(arena, in->data);
@@ -569,7 +571,7 @@ ASYNC_WORK_DEF(p2r_comp_unit_parse_work)
ASYNC_WORK_DEF(p2r_comp_unit_contributions_parse_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_CompUnitContributionsParseIn *in = (P2R_CompUnitContributionsParseIn *)input;
void *out = 0;
ProfScope("parse comp unit contributions") out = pdb_comp_unit_contribution_array_from_data(arena, in->data, in->coff_sections);
@@ -580,7 +582,7 @@ ASYNC_WORK_DEF(p2r_comp_unit_contributions_parse_work)
ASYNC_WORK_DEF(p2r_comp_unit_contributions_bucket_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_CompUnitContributionsBucketIn *in = (P2R_CompUnitContributionsBucketIn *)input;
P2R_CompUnitContributionsBucketOut *out = push_array(arena, P2R_CompUnitContributionsBucketOut, 1);
{
@@ -605,7 +607,7 @@ ASYNC_WORK_DEF(p2r_comp_unit_contributions_bucket_work)
ASYNC_WORK_DEF(p2r_gather_unit_src_file_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
Temp scratch = scratch_begin(&arena, 1);
P2R_GatherUnitSrcFilesIn *in = (P2R_GatherUnitSrcFilesIn *)input;
P2R_GatherUnitSrcFilesOut *out = push_array(arena, P2R_GatherUnitSrcFilesOut, 1);
@@ -856,7 +858,7 @@ ASYNC_WORK_DEF(p2r_gather_unit_src_file_work)
ASYNC_WORK_DEF(p2r_unit_convert_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
Temp scratch = scratch_begin(&arena, 1);
P2R_UnitConvertIn *in = (P2R_UnitConvertIn *)input;
P2R_UnitConvertOut *out = push_array(arena, P2R_UnitConvertOut, 1);
@@ -1208,7 +1210,7 @@ ASYNC_WORK_DEF(p2r_unit_convert_work)
ASYNC_WORK_DEF(p2r_src_file_seq_equip_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_SrcFileSeqEquipIn *in = (P2R_SrcFileSeqEquipIn *)input;
for(RDIM_LineTableChunkNode *line_table_chunk_n = in->line_tables.first; line_table_chunk_n != 0; line_table_chunk_n = line_table_chunk_n->next)
{
@@ -1231,7 +1233,7 @@ ASYNC_WORK_DEF(p2r_src_file_seq_equip_work)
ASYNC_WORK_DEF(p2r_link_name_map_build_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_LinkNameMapBuildIn *in = (P2R_LinkNameMapBuildIn *)input;
CV_RecRange *rec_ranges_first = in->sym->sym_ranges.ranges;
CV_RecRange *rec_ranges_opl = rec_ranges_first + in->sym->sym_ranges.count;
@@ -1289,7 +1291,7 @@ ASYNC_WORK_DEF(p2r_link_name_map_build_work)
ASYNC_WORK_DEF(p2r_itype_fwd_map_fill_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_ITypeFwdMapFillIn *in = (P2R_ITypeFwdMapFillIn *)input;
ProfScope("fill itype fwd map") for(CV_TypeId itype = in->itype_first; itype < in->itype_opl; itype += 1)
{
@@ -1419,7 +1421,7 @@ ASYNC_WORK_DEF(p2r_itype_fwd_map_fill_work)
ASYNC_WORK_DEF(p2r_itype_chain_build_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
Temp scratch = scratch_begin(&arena, 1);
P2R_ITypeChainBuildIn *in = (P2R_ITypeChainBuildIn *)input;
ProfScope("dependency itype chain build")
@@ -1722,7 +1724,7 @@ ASYNC_WORK_DEF(p2r_itype_chain_build_work)
ASYNC_WORK_DEF(p2r_udt_convert_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
P2R_UDTConvertIn *in = (P2R_UDTConvertIn *)input;
#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);
@@ -2359,7 +2361,7 @@ ASYNC_WORK_DEF(p2r_udt_convert_work)
ASYNC_WORK_DEF(p2r_symbol_stream_convert_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
Arena *arena = async_root_thread_arena(p2r_async_root);
Temp scratch = scratch_begin(&arena, 1);
P2R_SymbolStreamConvertIn *in = (P2R_SymbolStreamConvertIn *)input;
#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)
@@ -3226,7 +3228,11 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work)
U8 *name_ptr = val_ptr + val.encoded_size;
String8 name = str8_cstring_capped(name_ptr, sym_data_opl);
String8 val_data = str8_struct(&val64);
U64 container_name_opl = p2r_end_of_cplusplus_container_name(type->name);
U64 container_name_opl = 0;
if(type != 0)
{
container_name_opl = p2r_end_of_cplusplus_container_name(type->name);
}
String8 name_qualified = name;
if(container_name_opl != 0)
{
@@ -3269,11 +3275,12 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work)
////////////////////////////////
//~ rjf: Top-Level Conversion Entry Point
internal P2R_Convert2Bake *
p2r_convert(Arena *arena, P2R_User2Convert *in)
internal RDIM_BakeParams
p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in)
{
Temp scratch = scratch_begin(&arena, 1);
p2r_async_root = async_root;
//////////////////////////////////////////////////////////////
//- rjf: parse MSF structure
//
@@ -3569,7 +3576,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in)
top_level_info.exe_name = str8_skip_last_slash(in->input_exe_name);
top_level_info.exe_hash = exe_hash;
top_level_info.voff_max = exe_voff_max;
if(!(in->flags & P2R_ConvertFlag_Deterministic))
if(in->deterministic)
{
top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL);
}
@@ -3742,7 +3749,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in)
CV_TypeId *itype_fwd_map = 0;
CV_TypeId itype_first = 0;
CV_TypeId itype_opl = 0;
if(tpi_leaf != 0 && in->flags & P2R_ConvertFlag_Types) ProfScope("types pass 1: produce type forward resolution map")
if(tpi_leaf != 0 && in->subset_flags & RDIM_SubsetFlag_Types) ProfScope("types pass 1: produce type forward resolution map")
{
//- rjf: allocate forward resolution map
itype_first = tpi_leaf->itype_first;
@@ -3783,7 +3790,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in)
// as such, always show up *earlier* in the actually built types.
//
P2R_TypeIdChain **itype_chains = 0;
if(tpi_leaf != 0 && in->flags & P2R_ConvertFlag_Types) ProfScope("types pass 2: produce per-itype itype chain (for producing dependent types first)")
if(tpi_leaf != 0 && in->subset_flags & RDIM_SubsetFlag_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);
@@ -3821,7 +3828,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in)
RDIM_Type **itype_type_ptrs = 0;
RDIM_TypeChunkList all_types = rdim_init_type_chunk_list(arena, top_level_info.arch);
#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")
if(in->subset_flags & RDIM_SubsetFlag_Types) ProfScope("types pass 3: construct all root/stub types from TPI")
{
itype_type_ptrs = push_array(arena, RDIM_Type *, (U64)(itype_opl));
@@ -4341,7 +4348,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);
ASYNC_Task **udt_tasks = push_array(scratch.arena, ASYNC_Task *, udt_tasks_count);
if(in->flags & P2R_ConvertFlag_UDTs) ProfScope("types pass 4: kick off UDT build")
if(in->subset_flags & RDIM_SubsetFlag_UDTs) ProfScope("types pass 4: kick off UDT build")
{
for(U64 idx = 0; idx < udt_tasks_count; idx += 1)
{
@@ -4475,71 +4482,27 @@ p2r_convert(Arena *arena, P2R_User2Convert *in)
//////////////////////////////////////////////////////////////
//- rjf: fill output
//
P2R_Convert2Bake *out = push_array(arena, P2R_Convert2Bake, 1);
RDIM_BakeParams out = {0};
{
out->bake_params.top_level_info = top_level_info;
out->bake_params.binary_sections = binary_sections;
out->bake_params.units = all_units;
out->bake_params.types = all_types;
out->bake_params.udts = all_udts;
out->bake_params.src_files = all_src_files;
out->bake_params.line_tables = all_line_tables;
out->bake_params.global_variables = all_global_variables;
out->bake_params.thread_variables = all_thread_variables;
out->bake_params.constants = all_constants;
out->bake_params.procedures = all_procedures;
out->bake_params.scopes = all_scopes;
out->bake_params.inline_sites = all_inline_sites;
out.top_level_info = top_level_info;
out.binary_sections = binary_sections;
out.units = all_units;
out.types = all_types;
out.udts = all_udts;
out.src_files = all_src_files;
out.line_tables = all_line_tables;
out.global_variables = all_global_variables;
out.thread_variables = all_thread_variables;
out.constants = all_constants;
out.procedures = all_procedures;
out.scopes = all_scopes;
out.inline_sites = all_inline_sites;
}
scratch_end(scratch);
return out;
}
////////////////////////////////
//~ rjf: Top-Level Initialization
internal void
p2r_init(void)
{
Arena *arena = arena_alloc();
p2r_state = push_array(arena, P2R_State, 1);
p2r_state->arena = arena;
p2r_state->work_thread_arenas_count = async_thread_count();
p2r_state->work_thread_arenas = push_array(arena, Arena *, p2r_state->work_thread_arenas_count);
for EachIndex(idx, p2r_state->work_thread_arenas_count)
{
p2r_state->work_thread_arenas[idx] = arena_alloc();
}
}
////////////////////////////////
//~ rjf: Top-Level Baking Entry Point
internal P2R_Bake2Serialize *
p2r_bake(Arena *arena, P2R_Convert2Bake *in)
{
RDIM_LocalState local_state = {0};
local_state.arena = p2r_state->arena;
local_state.work_thread_arenas_count = p2r_state->work_thread_arenas_count;
local_state.work_thread_arenas = p2r_state->work_thread_arenas;
P2R_Bake2Serialize *result = push_array(arena, P2R_Bake2Serialize, 1);
result->bake_results = rdim_bake(&local_state, &in->bake_params);
return result;
}
////////////////////////////////
//~ rjf: Top-Level Compression Entry Point
internal P2R_Serialize2File *
p2r_compress(Arena *arena, P2R_Serialize2File *in)
{
P2R_Serialize2File *out = push_array(arena, P2R_Serialize2File, 1);
out->bundle = rdim_compress(arena, &in->bundle);
return out;
}
////////////////////////////////
internal B32
+9 -80
View File
@@ -4,65 +4,18 @@
#ifndef RDI_FROM_PDB_H
#define RDI_FROM_PDB_H
////////////////////////////////
//~ rjf: Export Artifact Flags
typedef U32 P2R_ConvertFlags;
enum
{
P2R_ConvertFlag_Strings = (1<<0),
P2R_ConvertFlag_IndexRuns = (1<<1),
P2R_ConvertFlag_BinarySections = (1<<2),
P2R_ConvertFlag_Units = (1<<3),
P2R_ConvertFlag_Procedures = (1<<4),
P2R_ConvertFlag_GlobalVariables = (1<<5),
P2R_ConvertFlag_ThreadVariables = (1<<6),
P2R_ConvertFlag_Scopes = (1<<7),
P2R_ConvertFlag_Locals = (1<<8),
P2R_ConvertFlag_Types = (1<<9),
P2R_ConvertFlag_UDTs = (1<<10),
P2R_ConvertFlag_LineInfo = (1<<11),
P2R_ConvertFlag_GlobalVariableNameMap = (1<<12),
P2R_ConvertFlag_ThreadVariableNameMap = (1<<13),
P2R_ConvertFlag_ProcedureNameMap = (1<<14),
P2R_ConvertFlag_TypeNameMap = (1<<15),
P2R_ConvertFlag_LinkNameProcedureNameMap= (1<<16),
P2R_ConvertFlag_NormalSourcePathNameMap = (1<<17),
P2R_ConvertFlag_Deterministic = (1<<18),
P2R_ConvertFlag_All = 0xffffffff,
};
////////////////////////////////
//~ rjf: Conversion Stage Inputs/Outputs
typedef struct P2R_User2Convert P2R_User2Convert;
struct P2R_User2Convert
typedef struct P2R_ConvertParams P2R_ConvertParams;
struct P2R_ConvertParams
{
String8 input_pdb_name;
String8 input_pdb_data;
String8 input_exe_name;
String8 input_exe_data;
String8 output_name;
P2R_ConvertFlags flags;
String8List errors;
};
typedef struct P2R_Convert2Bake P2R_Convert2Bake;
struct P2R_Convert2Bake
{
RDIM_BakeParams bake_params;
};
typedef struct P2R_Bake2Serialize P2R_Bake2Serialize;
struct P2R_Bake2Serialize
{
RDIM_BakeResults bake_results;
};
typedef struct P2R_Serialize2File P2R_Serialize2File;
struct P2R_Serialize2File
{
RDIM_SerializedSectionBundle bundle;
RDIM_SubsetFlags subset_flags;
B32 deterministic;
};
////////////////////////////////
@@ -319,21 +272,10 @@ struct P2R_SymbolStreamConvertOut
RDIM_TypeChunkList typedefs;
};
////////////////////////////////
//~ rjf: Top-Level State
typedef struct P2R_State P2R_State;
struct P2R_State
{
Arena *arena;
U64 work_thread_arenas_count;
Arena **work_thread_arenas;
};
////////////////////////////////
//~ rjf: Globals
global P2R_State *p2r_state = 0;
global ASYNC_Root *p2r_async_root = 0;
////////////////////////////////
//~ rjf: Basic Helpers
@@ -344,7 +286,9 @@ internal U64 p2r_hash_from_voff(U64 voff);
////////////////////////////////
//~ rjf: Command Line -> Conversion Inputs
internal P2R_User2Convert *p2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline);
#if 0
internal P2R_ConvertParams *p2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline);
#endif
////////////////////////////////
//~ rjf: COFF => RDI Canonical Conversions
@@ -417,22 +361,7 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work);
////////////////////////////////
//~ rjf: Top-Level Conversion Entry Point
internal P2R_Convert2Bake *p2r_convert(Arena *arena, P2R_User2Convert *in);
////////////////////////////////
//~ rjf: Top-Level Initialization
internal void p2r_init(void);
////////////////////////////////
//~ rjf: Top-Level Baking Entry Point
internal P2R_Bake2Serialize *p2r_bake(Arena *arena, P2R_Convert2Bake *in);
////////////////////////////////
//~ rjf: Top-Level Compression Entry Point
internal P2R_Serialize2File *p2r_compress(Arena *arena, P2R_Serialize2File *in);
internal RDIM_BakeParams p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in);
////////////////////////////////
-136
View File
@@ -1,136 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Build Options
#define BUILD_TITLE "rdi_from_pdb"
#define BUILD_CONSOLE_INTERFACE 1
////////////////////////////////
//~ rjf: Includes
//- rjf: [lib]
#include "lib_rdi_format/rdi_format.h"
#include "lib_rdi_format/rdi_format.c"
#include "third_party/rad_lzb_simple/rad_lzb_simple.h"
#include "third_party/rad_lzb_simple/rad_lzb_simple.c"
//- rjf: [h]
#include "base/base_inc.h"
#include "os/os_inc.h"
#include "path/path.h"
#include "async/async.h"
#include "rdi_make/rdi_make_local.h"
#include "coff/coff.h"
#include "coff/coff_parse.h"
#include "codeview/codeview.h"
#include "codeview/codeview_parse.h"
#include "msf/msf.h"
#include "msf/msf_parse.h"
#include "pdb/pdb.h"
#include "pdb/pdb_parse.h"
#include "pdb/pdb_stringize.h"
#include "rdi_from_pdb.h"
//- rjf: [c]
#include "base/base_inc.c"
#include "os/os_inc.c"
#include "path/path.c"
#include "async/async.c"
#include "rdi_make/rdi_make_local.c"
#include "coff/coff.c"
#include "coff/coff_parse.c"
#include "codeview/codeview.c"
#include "codeview/codeview_parse.c"
#include "msf/msf.c"
#include "msf/msf_parse.c"
#include "pdb/pdb.c"
#include "pdb/pdb_parse.c"
#include "pdb/pdb_stringize.c"
#include "rdi_from_pdb.c"
////////////////////////////////
//~ rjf: Entry Point
internal void
entry_point(CmdLine *cmdline)
{
//- rjf: initialize state, unpack command line
Arena *arena = arena_alloc();
B32 do_help = (cmd_line_has_flag(cmdline, str8_lit("help")) ||
cmd_line_has_flag(cmdline, str8_lit("h")) ||
cmd_line_has_flag(cmdline, str8_lit("?")));
P2R_User2Convert *user2convert = p2r_user2convert_from_cmdln(arena, cmdline);
//- rjf: display help
if(do_help || user2convert->errors.node_count != 0)
{
fprintf(stderr, "--- rdi_from_pdb --------------------------------------------------------------\n\n");
fprintf(stderr, "This utility converts debug information from PDBs into the RAD Debug Info\n");
fprintf(stderr, "format. The following arguments are accepted:\n\n");
fprintf(stderr, "--exe:<path> [optional] Specifies the path of the executable file for which the\n");
fprintf(stderr, " debug info was generated.\n");
fprintf(stderr, "--pdb:<path> Specifies the path of the PDB debug info file to\n");
fprintf(stderr, " convert.\n");
fprintf(stderr, "--out:<path> Specifies the path at which the output Breakpad debug\n");
fprintf(stderr, " info will be written.\n\n");
if(!do_help)
{
for(String8Node *n = user2convert->errors.first; n != 0; n = n->next)
{
fprintf(stderr, "error(input): %.*s\n", str8_varg(n->string));
}
}
os_abort(0);
}
//- rjf: convert
P2R_Convert2Bake *convert2bake = 0;
ProfScope("convert")
{
convert2bake = p2r_convert(arena, user2convert);
}
//- rjf: bake
P2R_Bake2Serialize *bake2srlz = 0;
ProfScope("bake")
{
bake2srlz = p2r_bake(arena, convert2bake);
}
//- rjf: serialize
P2R_Serialize2File *srlz2file = 0;
ProfScope("serialize")
{
srlz2file = push_array(arena, P2R_Serialize2File, 1);
srlz2file->bundle = rdim_serialized_section_bundle_from_bake_results(&bake2srlz->bake_results);
}
//- rjf: compress
P2R_Serialize2File *srlz2file_compressed = srlz2file;
if(cmd_line_has_flag(cmdline, str8_lit("compress"))) ProfScope("compress")
{
srlz2file_compressed = push_array(arena, P2R_Serialize2File, 1);
srlz2file_compressed = p2r_compress(arena, srlz2file);
}
//- rjf: serialize
String8List blobs = rdim_file_blobs_from_section_bundle(arena, &srlz2file_compressed->bundle);
//- rjf: write
ProfScope("write")
{
OS_Handle output_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, user2convert->output_name);
U64 off = 0;
for(String8Node *n = blobs.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);
}
}