mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-12 23:31:38 -07:00
WIP RAD debug info converter
This commit is contained in:
@@ -107,6 +107,7 @@ if not "%no_meta%"=="1" (
|
||||
pushd build
|
||||
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1
|
||||
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %link_natvis%"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1
|
||||
if "%radcon%"=="1" set didbuild=1 && %compile% ..\src\radcon\radcon_main.c %compile_link% %out%radcon.exe || exit /b 1
|
||||
if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1
|
||||
if "%rdi_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1
|
||||
if "%rdi_from_dwarf%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf_main.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1
|
||||
|
||||
@@ -0,0 +1,454 @@
|
||||
internal String8
|
||||
rc_data_from_file_path(Arena *arena, String8 path)
|
||||
{
|
||||
String8 data = os_data_from_file_path(arena, path);
|
||||
if (data.size == 0) {
|
||||
fprintf(stderr, "error: unable to read file %.*s\n", str8_varg(path));
|
||||
os_abort(1);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
internal RC_Context
|
||||
rc_context_from_cmd_line(Arena *arena, CmdLine *cmdl)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
if (cmdl->inputs.node_count > 2) {
|
||||
fprintf(stderr, "error: too many input files on the command line.\n");
|
||||
os_abort(1);
|
||||
}
|
||||
|
||||
B32 is_pe_present = 0;
|
||||
B32 is_pdb_present = 0;
|
||||
B32 is_elf_present = 0;
|
||||
B32 is_elf_debug_present = 0;
|
||||
String8 pe_name = {0};
|
||||
String8 pe_data = {0};
|
||||
String8 pdb_name = {0};
|
||||
String8 pdb_data = {0};
|
||||
String8 elf_name = {0};
|
||||
String8 elf_data = {0};
|
||||
String8 elf_debug_name = {0};
|
||||
String8 elf_debug_data = {0};
|
||||
|
||||
//
|
||||
// Set typed inputs
|
||||
//
|
||||
if (cmd_line_has_flag(cmdl, str8_lit("pe"))) {
|
||||
pe_name = cmd_line_string(cmdl, str8_lit("pe"));
|
||||
pe_data = rc_data_from_file_path(arena, pe_name);
|
||||
if (!pe_check_magic(pe_data)) {
|
||||
fprintf(stderr, "error: -pe:%.*s is not of PE format\n", str8_varg(pe_name));
|
||||
os_abort(1);
|
||||
}
|
||||
is_pe_present = 1;
|
||||
}
|
||||
if (cmd_line_has_flag(cmdl, str8_lit("pdb"))) {
|
||||
pdb_name = cmd_line_string(cmdl, str8_lit("pdb"));
|
||||
pdb_data = rc_data_from_file_path(arena, pdb_name);
|
||||
if (!msf_check_magic_20(pdb_data) && !msf_check_magic_70(pdb_data)) {
|
||||
fprintf(stderr, "error: -pdb:%.*s is not of PDB format\n", str8_varg(pdb_name));
|
||||
os_abort(1);
|
||||
}
|
||||
is_pdb_present = 1;
|
||||
}
|
||||
if (cmd_line_has_flag(cmdl, str8_lit("elf"))) {
|
||||
elf_name = cmd_line_string(cmdl, str8_lit("elf"));
|
||||
elf_data = rc_data_from_file_path(arena, elf_name);
|
||||
if (!elf_check_magic(elf_data)) {
|
||||
fprintf(stderr, "error: -elf:%.*s is not of ELF format\n", str8_varg(elf_name));
|
||||
os_abort(1);
|
||||
}
|
||||
is_elf_present = 1;
|
||||
}
|
||||
if (cmd_line_has_flag(cmdl, str8_lit("elf_debug"))) {
|
||||
elf_debug_name = cmd_line_string(cmdl, str8_lit("elf_debug"));
|
||||
elf_debug_data = rc_data_from_file_path(arena, elf_debug_name);
|
||||
if (!elf_check_magic(elf_debug_data)) {
|
||||
fprintf(stderr, "error: -elf_debug:%.*s is not of ELF format\n", str8_varg(elf_debug_name));
|
||||
os_abort(1);
|
||||
}
|
||||
is_elf_debug_present = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Load inputs
|
||||
//
|
||||
for (String8Node *input_n = cmdl->inputs.first; input_n != 0; input_n = input_n->next) {
|
||||
String8 input_data = os_data_from_file_path(arena, input_n->string);
|
||||
|
||||
if (input_data.size == 0) {
|
||||
fprintf(stderr, "unable to read input %.*s\n", str8_varg(input_n->string));
|
||||
os_abort(1);
|
||||
}
|
||||
|
||||
if (pe_check_magic(input_data)) {
|
||||
if (is_pe_present) {
|
||||
fprintf(stderr, "error: too many PE files are specified on the command line\n");
|
||||
fprintf(stderr, " selected: %.*s\n", str8_varg(pe_name));
|
||||
fprintf(stderr, " current: %.*s\n", str8_varg(input_n->string));
|
||||
os_abort(1);
|
||||
}
|
||||
pe_data = input_data;
|
||||
pe_name = input_n->string;
|
||||
is_pe_present = 1;
|
||||
} else if (elf_check_magic(input_data)) {
|
||||
ELF_BinInfo elf = elf_bin_from_data(input_data);
|
||||
B32 is_dwarf_present = dw_is_dwarf_present_elf_section_table(input_data, &elf);
|
||||
if (is_dwarf_present) {
|
||||
if (is_elf_debug_present) {
|
||||
fprintf(stderr, "error: ambiguous input, both ELFs have DWARF debug sections, please use --elf:<path> --elf_debug:<path> to clarify inputs.\n");
|
||||
os_abort(1);
|
||||
}
|
||||
elf_debug_name = input_n->string;
|
||||
elf_debug_data = input_data;
|
||||
is_elf_debug_present = 1;
|
||||
} else {
|
||||
elf_name = input_n->string;
|
||||
elf_data = input_data;
|
||||
is_elf_present = 1;
|
||||
}
|
||||
} else if (msf_check_magic_20(input_data) || msf_check_magic_70(input_data)) {
|
||||
if (is_pdb_present) {
|
||||
fprintf(stderr, "error: too many PDB files are specified on the command line\n");
|
||||
fprintf(stderr, " selected: %.*s\n", str8_varg(pdb_name));
|
||||
fprintf(stderr, " current: %.*s\n", str8_varg(input_n->string));
|
||||
continue;
|
||||
}
|
||||
pdb_name = input_n->string;
|
||||
pdb_data = input_data;
|
||||
is_pdb_present = 1;
|
||||
} else {
|
||||
fprintf(stderr, "error: unknown file format %.*s\n", str8_varg(input_n->string));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Validate input combos
|
||||
//
|
||||
if ((is_pe_present || is_pdb_present) && (is_elf_present || is_elf_debug_present)) {
|
||||
fprintf(stderr, "error: invalid combination of inputs provided, we convert only (PE|PDB) or (ELF|ELF_DEBUG) at a time.\n");
|
||||
if (is_pe_present) {
|
||||
fprintf(stderr, " PE: %.*s\n", str8_varg(pe_name));
|
||||
}
|
||||
if (is_pdb_present) {
|
||||
fprintf(stderr, " PDB: %.*s\n", str8_varg(pdb_name));
|
||||
}
|
||||
if (is_elf_present) {
|
||||
fprintf(stderr, " ELF: %.*s\n", str8_varg(elf_name));
|
||||
}
|
||||
if (is_elf_debug_present) {
|
||||
fprintf(stderr, " ELF Debug: %.*s\n", str8_varg(elf_debug_name));
|
||||
}
|
||||
os_abort(1);
|
||||
}
|
||||
|
||||
//
|
||||
// Pick conversion driver
|
||||
//
|
||||
RC_Driver driver = RC_Driver_Null;
|
||||
if (cmd_line_has_flag(cmdl, str8_lit("driver"))) {
|
||||
String8 driver_name = cmd_line_string(cmdl, str8_lit("driver"));
|
||||
if (str8_match(driver_name, str8_lit("dwarf"), StringMatchFlag_CaseInsensitive)) {
|
||||
driver = RC_Driver_Dwarf;
|
||||
} else if (str8_match(driver_name, str8_lit("pdb"), StringMatchFlag_CaseInsensitive)) {
|
||||
driver = RC_Driver_Pdb;
|
||||
} else {
|
||||
fprintf(stderr, "error: unknown driver %.*s\n", str8_varg(driver_name));
|
||||
os_abort(1);
|
||||
}
|
||||
}
|
||||
|
||||
ImageType image = Image_Null;
|
||||
String8 image_name = {0};
|
||||
String8 image_data = {0};
|
||||
String8 debug_name = {0};
|
||||
String8 debug_data = {0};
|
||||
|
||||
//
|
||||
// Input is PE/COFF
|
||||
//
|
||||
B32 check_guid = 0;
|
||||
Guid pe_pdb_guid = {0};
|
||||
if (is_pe_present) {
|
||||
PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, pe_data);
|
||||
|
||||
String8 raw_debug_dir = str8_substr(pe_data, pe.data_dir_franges[PE_DataDirectoryIndex_DEBUG]);
|
||||
PE_DebugInfoList debug_dir = pe_parse_debug_directory(scratch.arena, pe_data, raw_debug_dir);
|
||||
for (PE_DebugInfoNode *debug_n = debug_dir.first; debug_n != 0; debug_n = debug_n->next) {
|
||||
PE_DebugInfo *debug = &debug_n->v;
|
||||
if (debug->header.type == PE_DebugDirectoryType_CODEVIEW) {
|
||||
if (debug->u.codeview.magic == PE_CODEVIEW_PDB70_MAGIC) {
|
||||
check_guid = 1;
|
||||
pe_pdb_guid = debug->u.codeview.pdb70.header.guid;
|
||||
|
||||
if (!is_pdb_present) {
|
||||
pdb_name = debug->u.codeview.pdb70.path;
|
||||
pdb_data = rc_data_from_file_path(arena, pdb_name);
|
||||
is_pdb_present = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (driver == RC_Driver_Dwarf || driver == RC_Driver_Null) {
|
||||
String8 raw_sections = str8_substr(pe_data, rng_1u64(pe.section_array_off, pe.section_array_off+sizeof(COFF_SectionHeader)*pe.section_count));
|
||||
U64 section_count = raw_sections.size / sizeof(COFF_SectionHeader);
|
||||
COFF_SectionHeader *section_array = (COFF_SectionHeader *)raw_sections.str;
|
||||
if (dw_is_dwarf_present_coff_section_table(pe_data, pe.string_table_off, section_count, section_array)) {
|
||||
driver = RC_Driver_Dwarf;
|
||||
image = Image_CoffPe;
|
||||
image_name = pe_name;
|
||||
image_data = pe_data;
|
||||
debug_name = pe_name;
|
||||
debug_data = pe_data;
|
||||
goto driver_found;
|
||||
} else {
|
||||
if (driver == RC_Driver_Dwarf) {
|
||||
fprintf(stderr, "error: image doesn't have DWARF debug sections.\n");
|
||||
os_abort(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Input is PDB
|
||||
//
|
||||
if (driver == RC_Driver_Null && is_pdb_present) {
|
||||
if (is_pe_present) {
|
||||
image = Image_CoffPe;
|
||||
image_name = pe_name;
|
||||
image_data = pe_data;
|
||||
}
|
||||
driver = RC_Driver_Pdb;
|
||||
debug_name = pdb_name;
|
||||
debug_data = pdb_data;
|
||||
goto driver_found;
|
||||
}
|
||||
|
||||
B32 elf_has_debug_link = 0;
|
||||
ELF_GnuDebugLink debug_link = {0};
|
||||
if (is_elf_present || is_elf_debug_present) {
|
||||
if (driver != RC_Driver_Null && driver != RC_Driver_Dwarf) {
|
||||
fprintf(stderr, "ELF inputs are only supported when using DWARF driver.\n");
|
||||
os_abort(1);
|
||||
}
|
||||
|
||||
//
|
||||
// Load image ELF
|
||||
//
|
||||
ELF_BinInfo elf = elf_bin_from_data(elf_data);
|
||||
B32 has_elf_dwarf = dw_is_dwarf_present_elf_section_table(elf_data, &elf);
|
||||
|
||||
//
|
||||
// ELF doesn't have debug info and no .debug was specified on command line,
|
||||
// try to load .debug via debug link
|
||||
//
|
||||
if (is_elf_present && !is_elf_debug_present) {
|
||||
elf_has_debug_link = elf_parse_debug_link(elf_data, &elf, &debug_link);
|
||||
}
|
||||
if (elf_has_debug_link) {
|
||||
elf_debug_data = rc_data_from_file_path(arena, debug_link.path);
|
||||
is_elf_debug_present = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Load .debug ELF
|
||||
//
|
||||
ELF_BinInfo elf_debug = elf_bin_from_data(elf_debug_data);
|
||||
B32 has_elf_debug_dwarf = dw_is_dwarf_present_elf_section_table(elf_debug_data, &elf_debug);
|
||||
|
||||
//
|
||||
// Input is image ELF and .debug ELF
|
||||
//
|
||||
B32 is_split_elf = is_elf_present && is_elf_debug_present && !has_elf_dwarf && has_elf_debug_dwarf;
|
||||
if (is_split_elf) {
|
||||
driver = RC_Driver_Dwarf;
|
||||
image = ELF_HdrIs64Bit(elf.hdr.e_ident) ? Image_Elf64 : Image_Elf32;
|
||||
image_name = elf_name;
|
||||
image_data = elf_data;
|
||||
debug_name = elf_debug_name;
|
||||
debug_data = elf_debug_data;
|
||||
goto driver_found;
|
||||
}
|
||||
|
||||
//
|
||||
// Input ELF is image with debug info
|
||||
//
|
||||
B32 is_monolithic_elf = is_elf_present && !is_elf_debug_present && has_elf_dwarf;
|
||||
if (is_monolithic_elf) {
|
||||
driver = RC_Driver_Dwarf;
|
||||
image = ELF_HdrIs64Bit(elf.hdr.e_ident) ? Image_Elf64 : Image_Elf32;
|
||||
image_name = elf_name;
|
||||
image_data = elf_data;
|
||||
debug_name = elf_name;
|
||||
debug_data = elf_data;
|
||||
goto driver_found;
|
||||
}
|
||||
|
||||
//
|
||||
// Input ELF is .debug
|
||||
//
|
||||
B32 is_debug_elf = !is_elf_present && is_elf_debug_present && has_elf_debug_dwarf;
|
||||
if (is_debug_elf) {
|
||||
driver = RC_Driver_Dwarf;
|
||||
image = ELF_HdrIs64Bit(elf_debug.hdr.e_ident) ? Image_Elf64 : Image_Elf32;
|
||||
debug_name = elf_debug_name;
|
||||
debug_data = elf_debug_data;
|
||||
goto driver_found;
|
||||
}
|
||||
}
|
||||
|
||||
driver_found:;
|
||||
|
||||
//
|
||||
// Handle -out param
|
||||
//
|
||||
String8 out_name = {0};
|
||||
if (cmd_line_has_flag(cmdl, str8_lit("out"))) {
|
||||
out_name = cmd_line_string(cmdl, str8_lit("out"));
|
||||
if (out_name.size == 0) {
|
||||
fprintf(stderr, "error: -out parameter doesn't have a value\n");
|
||||
os_abort(1);
|
||||
}
|
||||
} else {
|
||||
if (image_name.size) {
|
||||
out_name = path_replace_file_extension(arena, image_name, str8_lit("rdi"));
|
||||
} else {
|
||||
out_name = path_replace_file_extension(arena, debug_name, str8_lit("rdi"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Validate driver input
|
||||
//
|
||||
if (driver == RC_Driver_Pdb &&
|
||||
!is_pdb_present && (is_elf_present || is_elf_debug_present)) {
|
||||
fprintf(stderr, "error: DWARF is an invalid input for PDB driver\n");
|
||||
os_abort(1);
|
||||
}
|
||||
|
||||
|
||||
RC_Context ctx = {0};
|
||||
ctx.driver = driver;
|
||||
ctx.image = image;
|
||||
ctx.image_name = image_name;
|
||||
ctx.image_data = image_data;
|
||||
ctx.debug_name = debug_name;
|
||||
ctx.debug_data = debug_data;
|
||||
if (check_guid) {
|
||||
ctx.flags |= RC_Flag_CheckPdbGuid;
|
||||
ctx.guid = pe_pdb_guid;
|
||||
}
|
||||
if (elf_has_debug_link) {
|
||||
ctx.flags |= RC_Flag_CheckElfChecksum;
|
||||
ctx.debug_link = debug_link;
|
||||
}
|
||||
ctx.out_name = out_name;
|
||||
|
||||
scratch_end(scratch);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
internal String8List
|
||||
rc_run(Arena *arena, RC_Context *rc)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
ProfBegin("Convert");
|
||||
RDIM_HelpState *help_state = rdim_help_init();
|
||||
RDIM_BakeParams *convert2bake = 0;
|
||||
switch (rc->driver) {
|
||||
case RC_Driver_Null: break;
|
||||
case RC_Driver_Dwarf: convert2bake = d2r_convert(scratch.arena, help_state, rc); break;
|
||||
case RC_Driver_Pdb: convert2bake = p2r_convert(scratch.arena, help_state, rc); break;
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
if (rc->errors.node_count) {
|
||||
NotImplemented;
|
||||
}
|
||||
|
||||
ProfBegin("Bake");
|
||||
RDIM_BakeResults bake2srlz = rdim_bake(help_state, convert2bake);
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("Serialize Bake");
|
||||
RDIM_SerializedSectionBundle srlz2file = rdim_serialized_section_bundle_from_bake_results(&bake2srlz);
|
||||
ProfEnd();
|
||||
|
||||
RDIM_SerializedSectionBundle srlz2file_compressed = srlz2file;
|
||||
if (rc->flags & RC_Flag_Compress) {
|
||||
ProfBegin("Compress");
|
||||
srlz2file_compressed = rdim_compress(scratch.arena, &srlz2file);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
ProfBegin("Serialize");
|
||||
String8List raw_rdi = rdim_file_blobs_from_section_bundle(scratch.arena, &srlz2file_compressed);
|
||||
ProfEnd();
|
||||
|
||||
scratch_end(scratch);
|
||||
return raw_rdi;
|
||||
}
|
||||
|
||||
internal String8
|
||||
rc_rdi_from_cmd_line(Arena *arena, CmdLine *cmdl)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
RC_Context rc = rc_context_from_cmd_line(scratch.arena, cmdl);
|
||||
String8List raw_rdi = rc_run(scratch.arena, &rc);
|
||||
String8 result = str8_list_join(arena, &raw_rdi, 0);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
rc_main(CmdLine *cmdl)
|
||||
{
|
||||
B32 do_help = (cmd_line_has_flag(cmdl, str8_lit("help")) ||
|
||||
cmd_line_has_flag(cmdl, str8_lit("h")) ||
|
||||
cmd_line_has_flag(cmdl, str8_lit("?")) ||
|
||||
cmdl->argc == 1);
|
||||
if (do_help) {
|
||||
fprintf(stderr, "--- Help ---------------------------------------------------------------------\n");
|
||||
fprintf(stderr, " %s\n\n", BUILD_TITLE_STRING_LITERAL);
|
||||
fprintf(stderr, " Usage: radcon [Options] [Files]\n\n");
|
||||
fprintf(stderr, " Options:\n");
|
||||
fprintf(stderr, " -pe:<path> Path to Win32 executable image\n");
|
||||
fprintf(stderr, " -pdb:<path> Path to PDB\n");
|
||||
fprintf(stderr, " -elf:<path> Path to ELF\n");
|
||||
fprintf(stderr, " -elf_debug:<path> Path to ELF with debug info\n");
|
||||
fprintf(stderr, " -out:<path> Path at which the output RDI debug info will be written\n");
|
||||
fprintf(stderr, " -driver:<PDB|DWARF> Sets converter for debug info\n");
|
||||
} else {
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
// make converter context
|
||||
RC_Context rc = rc_context_from_cmd_line(scratch.arena, cmdl);
|
||||
|
||||
// make RDI from context
|
||||
String8List raw_rdi = rc_run(scratch.arena, &rc);
|
||||
|
||||
// output RDI
|
||||
if (rc.errors.node_count == 0) {
|
||||
if (!os_write_data_list_to_file_path(rc.out_name, raw_rdi)) {
|
||||
str8_list_pushf(scratch.arena, &rc.errors, "no write access to path %.*s", str8_varg(rc.out_name));
|
||||
}
|
||||
}
|
||||
|
||||
// report any errors
|
||||
for (String8Node *error_n = rc.errors.first; error_n != 0; error_n = error_n->next) {
|
||||
fprintf(stderr, "error: %.*s\n", str8_varg(error_n->string));
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RADCON_H
|
||||
#define RADCON_H
|
||||
|
||||
typedef U32 RC_Flags;
|
||||
enum
|
||||
{
|
||||
RC_Flag_Strings = (1 << 0),
|
||||
RC_Flag_IndexRuns = (1 << 1),
|
||||
RC_Flag_BinarySections = (1 << 2),
|
||||
RC_Flag_Units = (1 << 3),
|
||||
RC_Flag_Procedures = (1 << 4),
|
||||
RC_Flag_GlobalVariables = (1 << 5),
|
||||
RC_Flag_ThreadVariables = (1 << 6),
|
||||
RC_Flag_Scopes = (1 << 7),
|
||||
RC_Flag_Locals = (1 << 8),
|
||||
RC_Flag_Types = (1 << 9),
|
||||
RC_Flag_UDTs = (1 << 10),
|
||||
RC_Flag_LineInfo = (1 << 11),
|
||||
RC_Flag_GlobalVariableNameMap = (1 << 12),
|
||||
RC_Flag_ThreadVariableNameMap = (1 << 13),
|
||||
RC_Flag_ProcedureNameMap = (1 << 14),
|
||||
RC_Flag_TypeNameMap = (1 << 15),
|
||||
RC_Flag_LinkNameProcedureNameMap= (1 << 16),
|
||||
RC_Flag_NormalSourcePathNameMap = (1 << 17),
|
||||
RC_Flag_Compress = (1 << 18),
|
||||
RC_Flag_StrictDwarfParse = (1 << 19),
|
||||
RC_Flag_Deterministic = (1 << 20),
|
||||
RC_Flag_CheckPdbGuid = (1 << 21),
|
||||
RC_Flag_CheckElfChecksum = (1 << 22),
|
||||
RC_Flag_All = 0xffffffff,
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RC_Driver_Null,
|
||||
RC_Driver_Dwarf,
|
||||
RC_Driver_Pdb,
|
||||
} RC_Driver;
|
||||
|
||||
typedef struct RC_Context
|
||||
{
|
||||
ImageType image;
|
||||
RC_Driver driver;
|
||||
String8 image_name;
|
||||
String8 image_data;
|
||||
String8 debug_name;
|
||||
String8 debug_data;
|
||||
String8 out_name;
|
||||
RC_Flags flags;
|
||||
Guid guid;
|
||||
ELF_GnuDebugLink debug_link;
|
||||
String8List errors;
|
||||
} RC_Context;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal RC_Context rc_context_from_cmd_line(Arena *arena, CmdLine *cmdl);
|
||||
internal String8List rc_run(Arena *arena, RC_Context *rc);
|
||||
internal String8 rc_rdi_from_cmd_line(Arena *arena, CmdLine *cmdl);
|
||||
internal void rc_main(CmdLine *cmdl);
|
||||
|
||||
#endif // RADCON_H
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal RDI_Arch
|
||||
c2r_rdi_arch_from_coff_machine(COFF_MachineType machine)
|
||||
{
|
||||
switch (machine) {
|
||||
case COFF_Machine_X86: return RDI_Arch_X86;
|
||||
case COFF_Machine_X64: return RDI_Arch_X64;
|
||||
|
||||
case COFF_Machine_Unknown:
|
||||
case COFF_Machine_Am33:
|
||||
case COFF_Machine_Arm:
|
||||
case COFF_Machine_Arm64:
|
||||
case COFF_Machine_ArmNt:
|
||||
case COFF_Machine_Ebc:
|
||||
case COFF_Machine_Ia64:
|
||||
case COFF_Machine_M32R:
|
||||
case COFF_Machine_Mips16:
|
||||
case COFF_Machine_MipsFpu:
|
||||
case COFF_Machine_MipsFpu16:
|
||||
case COFF_Machine_PowerPc:
|
||||
case COFF_Machine_PowerPcFp:
|
||||
case COFF_Machine_R4000:
|
||||
case COFF_Machine_RiscV32:
|
||||
case COFF_Machine_RiscV64:
|
||||
case COFF_Machine_Sh3:
|
||||
case COFF_Machine_Sh3Dsp:
|
||||
case COFF_Machine_Sh4:
|
||||
case COFF_Machine_Sh5:
|
||||
case COFF_Machine_Thumb:
|
||||
case COFF_Machine_WceMipsV2:
|
||||
NotImplemented;
|
||||
default:
|
||||
return RDI_Arch_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
internal RDI_BinarySectionFlags
|
||||
c2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags)
|
||||
{
|
||||
RDI_BinarySectionFlags result = 0;
|
||||
if(flags & COFF_SectionFlag_MemRead)
|
||||
{
|
||||
result |= RDI_BinarySectionFlag_Read;
|
||||
}
|
||||
if(flags & COFF_SectionFlag_MemWrite)
|
||||
{
|
||||
result |= RDI_BinarySectionFlag_Write;
|
||||
}
|
||||
if(flags & COFF_SectionFlag_MemExecute)
|
||||
{
|
||||
result |= RDI_BinarySectionFlag_Execute;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal RDIM_BinarySectionList
|
||||
c2r_rdi_binary_sections_from_coff_sections(Arena *arena, String8 image_data, U64 string_table_off, U64 sectab_count, COFF_SectionHeader *sectab)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
RDIM_BinarySectionList binary_sections = {0};
|
||||
|
||||
for (U64 isec = 0; isec < sectab_count; ++isec) {
|
||||
COFF_SectionHeader *coff_sec = §ab[isec];
|
||||
RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections);
|
||||
|
||||
sec->name = coff_name_from_section_header(image_data, coff_sec, string_table_off);
|
||||
sec->flags = c2r_rdi_binary_section_flags_from_coff_section_flags(coff_sec->flags);
|
||||
sec->voff_first = coff_sec->voff;
|
||||
sec->voff_opl = coff_sec->voff + coff_sec->vsize;
|
||||
sec->foff_first = coff_sec->foff;
|
||||
sec->foff_opl = coff_sec->foff + coff_sec->fsize;
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
return binary_sections;
|
||||
}
|
||||
|
||||
internal RDIM_TopLevelInfo
|
||||
c2r_make_rdim_top_level_info(String8 image_name, RDI_Arch arch, U64 exe_hash, U64 sectab_count, COFF_SectionHeader *sectab)
|
||||
{
|
||||
U64 exe_voff_max = 0;
|
||||
{
|
||||
COFF_SectionHeader *coff_sec_ptr = sectab;
|
||||
COFF_SectionHeader *coff_ptr_opl = sectab + sectab_count;
|
||||
for (;coff_sec_ptr < coff_ptr_opl; coff_sec_ptr += 1) {
|
||||
U64 sec_voff_max = coff_sec_ptr->voff + coff_sec_ptr->vsize;
|
||||
exe_voff_max = Max(exe_voff_max, sec_voff_max);
|
||||
}
|
||||
}
|
||||
|
||||
RDIM_TopLevelInfo top_level_info = {0};
|
||||
top_level_info.arch = arch;
|
||||
top_level_info.exe_name = str8_skip_last_slash(image_name);
|
||||
top_level_info.exe_hash = exe_hash;
|
||||
top_level_info.voff_max = exe_voff_max;
|
||||
top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL);
|
||||
|
||||
return top_level_info;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RADCON_COFF_H
|
||||
#define RADCON_COFF_H
|
||||
|
||||
internal RDI_Arch c2r_rdi_arch_from_coff_machine(COFF_MachineType machine);
|
||||
internal RDI_BinarySectionFlags c2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags);
|
||||
internal RDIM_BinarySectionList c2r_rdi_binary_sections_from_coff_sections(Arena *arena, String8 image_data, U64 string_table_off, U64 sectab_count, COFF_SectionHeader *sectab);
|
||||
internal RDIM_TopLevelInfo c2r_make_rdim_top_level_info(String8 image_name, RDI_Arch arch, U64 exe_hash, U64 sectab_count, COFF_SectionHeader *sectab);
|
||||
|
||||
#endif // RADCON_COFF_H
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: CodeView <-> RDI Canonical Conversions
|
||||
|
||||
internal RDI_Arch
|
||||
cv2r_rdi_arch_from_cv_arch(CV_Arch cv_arch)
|
||||
{
|
||||
RDI_Arch result = 0;
|
||||
switch(cv_arch)
|
||||
{
|
||||
case CV_Arch_8086: result = RDI_Arch_X86; break;
|
||||
case CV_Arch_X64: result = RDI_Arch_X64; break;
|
||||
//case CV_Arch_8080: break;
|
||||
//case CV_Arch_80286: break;
|
||||
//case CV_Arch_80386: break;
|
||||
//case CV_Arch_80486: break;
|
||||
//case CV_Arch_PENTIUM: break;
|
||||
//case CV_Arch_PENTIUMII: break;
|
||||
//case CV_Arch_PENTIUMIII: break;
|
||||
//case CV_Arch_MIPS: break;
|
||||
//case CV_Arch_MIPS16: break;
|
||||
//case CV_Arch_MIPS32: break;
|
||||
//case CV_Arch_MIPS64: break;
|
||||
//case CV_Arch_MIPSI: break;
|
||||
//case CV_Arch_MIPSII: break;
|
||||
//case CV_Arch_MIPSIII: break;
|
||||
//case CV_Arch_MIPSIV: break;
|
||||
//case CV_Arch_MIPSV: break;
|
||||
//case CV_Arch_M68000: break;
|
||||
//case CV_Arch_M68010: break;
|
||||
//case CV_Arch_M68020: break;
|
||||
//case CV_Arch_M68030: break;
|
||||
//case CV_Arch_M68040: break;
|
||||
//case CV_Arch_ALPHA: break;
|
||||
//case CV_Arch_ALPHA_21164: break;
|
||||
//case CV_Arch_ALPHA_21164A: break;
|
||||
//case CV_Arch_ALPHA_21264: break;
|
||||
//case CV_Arch_ALPHA_21364: break;
|
||||
//case CV_Arch_PPC601: break;
|
||||
//case CV_Arch_PPC603: break;
|
||||
//case CV_Arch_PPC604: break;
|
||||
//case CV_Arch_PPC620: break;
|
||||
//case CV_Arch_PPCFP: break;
|
||||
//case CV_Arch_PPCBE: break;
|
||||
//case CV_Arch_SH3: break;
|
||||
//case CV_Arch_SH3E: break;
|
||||
//case CV_Arch_SH3DSP: break;
|
||||
//case CV_Arch_SH4: break;
|
||||
//case CV_Arch_SHMEDIA: break;
|
||||
//case CV_Arch_ARM3: break;
|
||||
//case CV_Arch_ARM4: break;
|
||||
//case CV_Arch_ARM4T: break;
|
||||
//case CV_Arch_ARM5: break;
|
||||
//case CV_Arch_ARM5T: break;
|
||||
//case CV_Arch_ARM6: break;
|
||||
//case CV_Arch_ARM_XMAC: break;
|
||||
//case CV_Arch_ARM_WMMX: break;
|
||||
//case CV_Arch_ARM7: break;
|
||||
//case CV_Arch_OMNI: break;
|
||||
//case CV_Arch_IA64_1: break;
|
||||
//case CV_Arch_IA64_2: break;
|
||||
//case CV_Arch_CEE: break;
|
||||
//case CV_Arch_AM33: break;
|
||||
//case CV_Arch_M32R: break;
|
||||
//case CV_Arch_TRICORE: break;
|
||||
//case CV_Arch_EBC: break;
|
||||
//case CV_Arch_THUMB: break;
|
||||
//case CV_Arch_ARMNT: break;
|
||||
//case CV_Arch_ARM64: break;
|
||||
//case CV_Arch_D3D11_SHADER: break;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal RDI_RegCode
|
||||
cv2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code)
|
||||
{
|
||||
RDI_RegCode result = 0;
|
||||
switch(arch)
|
||||
{
|
||||
case RDI_Arch_X86:
|
||||
{
|
||||
switch(reg_code)
|
||||
{
|
||||
#define X(CVN,C,RDN,BP,BZ) case C: result = RDI_RegCodeX86_##RDN; break;
|
||||
CV_Reg_X86_XList(X)
|
||||
#undef X
|
||||
}
|
||||
}break;
|
||||
case RDI_Arch_X64:
|
||||
{
|
||||
switch(reg_code)
|
||||
{
|
||||
#define X(CVN,C,RDN,BP,BZ) case C: result = RDI_RegCodeX64_##RDN; break;
|
||||
CV_Reg_X64_XList(X)
|
||||
#undef X
|
||||
}
|
||||
}break;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal RDI_Language
|
||||
cv2r_rdi_language_from_cv_language(CV_Language cv_language)
|
||||
{
|
||||
RDI_Language result = 0;
|
||||
switch(cv_language)
|
||||
{
|
||||
case CV_Language_C: result = RDI_Language_C; break;
|
||||
case CV_Language_CXX: result = RDI_Language_CPlusPlus; break;
|
||||
//case CV_Language_FORTRAN: result = ; break;
|
||||
//case CV_Language_MASM: result = ; break;
|
||||
//case CV_Language_PASCAL: result = ; break;
|
||||
//case CV_Language_BASIC: result = ; break;
|
||||
//case CV_Language_COBOL: result = ; break;
|
||||
//case CV_Language_LINK: result = ; break;
|
||||
//case CV_Language_CVTRES: result = ; break;
|
||||
//case CV_Language_CVTPGD: result = ; break;
|
||||
//case CV_Language_CSHARP: result = ; break;
|
||||
//case CV_Language_VB: result = ; break;
|
||||
//case CV_Language_ILASM: result = ; break;
|
||||
//case CV_Language_JAVA: result = ; break;
|
||||
//case CV_Language_JSCRIPT: result = ; break;
|
||||
//case CV_Language_MSIL: result = ; break;
|
||||
//case CV_Language_HLSL: result = ; break;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal RDI_RegCode
|
||||
cv2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg)
|
||||
{
|
||||
RDI_RegCode result = 0;
|
||||
switch(arch)
|
||||
{
|
||||
case RDI_Arch_X86:
|
||||
{
|
||||
switch(encoded_reg)
|
||||
{
|
||||
case CV_EncodedFramePtrReg_StackPtr:
|
||||
{
|
||||
// TODO(allen): support CV_AllReg_VFRAME
|
||||
// TODO(allen): error
|
||||
}break;
|
||||
case CV_EncodedFramePtrReg_FramePtr:
|
||||
{
|
||||
result = RDI_RegCodeX86_ebp;
|
||||
}break;
|
||||
case CV_EncodedFramePtrReg_BasePtr:
|
||||
{
|
||||
result = RDI_RegCodeX86_ebx;
|
||||
}break;
|
||||
}
|
||||
}break;
|
||||
case RDI_Arch_X64:
|
||||
{
|
||||
switch(encoded_reg)
|
||||
{
|
||||
case CV_EncodedFramePtrReg_StackPtr:
|
||||
{
|
||||
result = RDI_RegCodeX64_rsp;
|
||||
}break;
|
||||
case CV_EncodedFramePtrReg_FramePtr:
|
||||
{
|
||||
result = RDI_RegCodeX64_rbp;
|
||||
}break;
|
||||
case CV_EncodedFramePtrReg_BasePtr:
|
||||
{
|
||||
result = RDI_RegCodeX64_r13;
|
||||
}break;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
internal RDI_TypeKind
|
||||
cv2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type)
|
||||
{
|
||||
RDI_TypeKind result = RDI_TypeKind_NULL;
|
||||
switch(basic_type)
|
||||
{
|
||||
case CV_BasicType_VOID: {result = RDI_TypeKind_Void;}break;
|
||||
case CV_BasicType_HRESULT: {result = RDI_TypeKind_HResult;}break;
|
||||
|
||||
case CV_BasicType_RCHAR:
|
||||
case CV_BasicType_CHAR:
|
||||
case CV_BasicType_CHAR8:
|
||||
{result = RDI_TypeKind_Char8;}break;
|
||||
|
||||
case CV_BasicType_UCHAR: {result = RDI_TypeKind_UChar8;}break;
|
||||
case CV_BasicType_WCHAR: {result = RDI_TypeKind_UChar16;}break;
|
||||
case CV_BasicType_CHAR16: {result = RDI_TypeKind_Char16;}break;
|
||||
case CV_BasicType_CHAR32: {result = RDI_TypeKind_Char32;}break;
|
||||
|
||||
case CV_BasicType_BOOL8:
|
||||
case CV_BasicType_INT8:
|
||||
{result = RDI_TypeKind_S8;}break;
|
||||
|
||||
case CV_BasicType_BOOL16:
|
||||
case CV_BasicType_INT16:
|
||||
case CV_BasicType_SHORT:
|
||||
{result = RDI_TypeKind_S16;}break;
|
||||
|
||||
case CV_BasicType_BOOL32:
|
||||
case CV_BasicType_INT32:
|
||||
case CV_BasicType_LONG:
|
||||
{result = RDI_TypeKind_S32;}break;
|
||||
|
||||
case CV_BasicType_BOOL64:
|
||||
case CV_BasicType_INT64:
|
||||
case CV_BasicType_QUAD:
|
||||
{result = RDI_TypeKind_S64;}break;
|
||||
|
||||
case CV_BasicType_INT128:
|
||||
case CV_BasicType_OCT:
|
||||
{result = RDI_TypeKind_S128;}break;
|
||||
|
||||
case CV_BasicType_UINT8: {result = RDI_TypeKind_U8;}break;
|
||||
|
||||
case CV_BasicType_UINT16:
|
||||
case CV_BasicType_USHORT:
|
||||
{result = RDI_TypeKind_U16;}break;
|
||||
|
||||
case CV_BasicType_UINT32:
|
||||
case CV_BasicType_ULONG:
|
||||
{result = RDI_TypeKind_U32;}break;
|
||||
|
||||
case CV_BasicType_UINT64:
|
||||
case CV_BasicType_UQUAD:
|
||||
{result = RDI_TypeKind_U64;}break;
|
||||
|
||||
case CV_BasicType_UINT128:
|
||||
case CV_BasicType_UOCT:
|
||||
{result = RDI_TypeKind_U128;}break;
|
||||
|
||||
case CV_BasicType_FLOAT16:{result = RDI_TypeKind_F16;}break;
|
||||
case CV_BasicType_FLOAT32:{result = RDI_TypeKind_F32;}break;
|
||||
case CV_BasicType_FLOAT32PP:{result = RDI_TypeKind_F32PP;}break;
|
||||
case CV_BasicType_FLOAT48:{result = RDI_TypeKind_F48;}break;
|
||||
case CV_BasicType_FLOAT64:{result = RDI_TypeKind_F64;}break;
|
||||
case CV_BasicType_FLOAT80:{result = RDI_TypeKind_F80;}break;
|
||||
case CV_BasicType_FLOAT128:{result = RDI_TypeKind_F128;}break;
|
||||
case CV_BasicType_COMPLEX32:{result = RDI_TypeKind_ComplexF32;}break;
|
||||
case CV_BasicType_COMPLEX64:{result = RDI_TypeKind_ComplexF64;}break;
|
||||
case CV_BasicType_COMPLEX80:{result = RDI_TypeKind_ComplexF80;}break;
|
||||
case CV_BasicType_COMPLEX128:{result = RDI_TypeKind_ComplexF128;}break;
|
||||
case CV_BasicType_PTR:{result = RDI_TypeKind_Handle;}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: CodeView => RDI Canonical Conversions
|
||||
|
||||
internal RDI_Arch cv2r_rdi_arch_from_cv_arch(CV_Arch arch);
|
||||
internal RDI_RegCode cv2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code);
|
||||
internal RDI_Language cv2r_rdi_language_from_cv_language(CV_Language language);
|
||||
internal RDI_RegCode cv2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg);
|
||||
internal RDI_TypeKind cv2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RADCON_DWARF_H
|
||||
#define RADCON_DWARF_H
|
||||
|
||||
typedef struct D2R_TypeTable
|
||||
{
|
||||
HashTable *ht;
|
||||
RDIM_TypeChunkList *types;
|
||||
U64 type_chunk_cap;
|
||||
RDIM_Type *void_type;
|
||||
RDIM_Type *varg_type;
|
||||
} D2R_TypeTable;
|
||||
|
||||
typedef struct D2R_TagNode
|
||||
{
|
||||
struct D2R_TagNode *next;
|
||||
DW_TagNode *cur_node;
|
||||
RDIM_Type *type;
|
||||
RDIM_Scope *scope;
|
||||
} D2R_TagNode;
|
||||
|
||||
typedef struct D2R_CompUnitContribMap
|
||||
{
|
||||
U64 count;
|
||||
U64 *info_off_arr;
|
||||
RDIM_Rng1U64List *voff_range_arr;
|
||||
} D2R_CompUnitContribMap;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal RDIM_BakeParams * d2r_convert(Arena *arena, RDIM_HelpState *help_state, RC_Context *in);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal RDI_Language rdi_language_from_dw_language(DW_Language v);
|
||||
internal RDI_RegCodeX86 rdi_reg_from_dw_reg_x86(DW_RegX86 v);
|
||||
internal B32 rdi_reg_from_dw_reg_x64(DW_RegX64 v, RDI_RegCodeX64 *code_out, U64 *off_out, U64 *size_out);
|
||||
internal B32 rdi_reg_from_dw_reg(Arch arch, DW_Reg v, RDI_RegCode *code_out, U64 *off_out, U64 *size_out);
|
||||
|
||||
#endif // RADCON_DWARF_H
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal RDIM_BinarySectionList
|
||||
e2r_rdi_binary_sections_from_elf_section_table(Arena *arena, ELF_Shdr64Array shdrs)
|
||||
{
|
||||
RDIM_BinarySectionList result = {0};
|
||||
return result;
|
||||
}
|
||||
|
||||
internal RDIM_TopLevelInfo
|
||||
e2r_make_rdim_top_level_info(String8 image_name, RDI_Arch arch, ELF_Shdr64Array shdrs)
|
||||
{
|
||||
RDIM_TopLevelInfo top_level_info = {0};
|
||||
return top_level_info;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RADCON_ELF_H
|
||||
#define RADCON_ELF_H
|
||||
|
||||
internal RDIM_BinarySectionList e2r_rdi_binary_sections_from_elf_section_table(Arena *arena, ELF_Shdr64Array shdrs);
|
||||
internal RDIM_TopLevelInfo e2r_make_rdim_top_level_info(String8 image_name, RDI_Arch arch, ELF_Shdr64Array shdrs);
|
||||
|
||||
#endif // RADCON_ELF_H
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#define BUILD_TITLE "Epic Games Tools (R) RAD Debug Info Converter"
|
||||
#define BUILD_CONSOLE_INTERFACE 1
|
||||
|
||||
////////////////////////////////
|
||||
// Third Party
|
||||
|
||||
#include "third_party/rad_lzb_simple/rad_lzb_simple.h"
|
||||
#include "third_party/rad_lzb_simple/rad_lzb_simple.c"
|
||||
#define XXH_STATIC_LINKING_ONLY
|
||||
#include "third_party/xxHash/xxhash.c"
|
||||
#include "third_party/xxHash/xxhash.h"
|
||||
#define SINFL_IMPLEMENTATION
|
||||
#include "third_party/sinfl/sinfl.h"
|
||||
|
||||
////////////////////////////////
|
||||
// RDI Format Library
|
||||
|
||||
#include "lib_rdi_format/rdi_format.h"
|
||||
#include "lib_rdi_format/rdi_format.c"
|
||||
|
||||
////////////////////////////////
|
||||
// Headers
|
||||
|
||||
#include "base/base_inc.h"
|
||||
#include "os/os_inc.h"
|
||||
#include "async/async.h"
|
||||
#include "path/path.h"
|
||||
#include "rdi_make/rdi_make_local.h"
|
||||
#include "rdi_make/rdi_make_help.h"
|
||||
#include "linker/hash_table.h"
|
||||
#include "coff/coff.h"
|
||||
#include "coff/coff_parse.h"
|
||||
#include "pe/pe.h"
|
||||
#include "elf/elf.h"
|
||||
#include "elf/elf_parse.h"
|
||||
#include "codeview/codeview.h"
|
||||
#include "codeview/codeview_parse.h"
|
||||
#include "dwarf/dwarf.h"
|
||||
#include "dwarf/dwarf_parse.h"
|
||||
#include "dwarf/dwarf_coff.h"
|
||||
#include "dwarf/dwarf_elf.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 "radcon.h"
|
||||
#include "radcon_coff.h"
|
||||
#include "radcon_elf.h"
|
||||
#include "radcon_cv.h"
|
||||
#include "radcon_dwarf.h"
|
||||
#include "radcon_pdb.h"
|
||||
|
||||
////////////////////////////////
|
||||
// Implementations
|
||||
|
||||
#include "base/base_inc.c"
|
||||
#include "os/os_inc.c"
|
||||
#include "async/async.c"
|
||||
#include "path/path.c"
|
||||
#include "rdi_make/rdi_make_local.c"
|
||||
#include "rdi_make/rdi_make_help.c"
|
||||
#include "linker/hash_table.c"
|
||||
#include "coff/coff.c"
|
||||
#include "coff/coff_parse.c"
|
||||
#include "pe/pe.c"
|
||||
#include "elf/elf.c"
|
||||
#include "elf/elf_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 "dwarf/dwarf.c"
|
||||
#include "dwarf/dwarf_parse.c"
|
||||
#include "dwarf/dwarf_coff.c"
|
||||
#include "dwarf/dwarf_elf.c"
|
||||
#include "radcon.c"
|
||||
#include "radcon_coff.c"
|
||||
#include "radcon_elf.c"
|
||||
#include "radcon_cv.c"
|
||||
#include "radcon_dwarf.c"
|
||||
#include "radcon_pdb.c"
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void
|
||||
entry_point(CmdLine *cmdl)
|
||||
{
|
||||
rc_main(cmdl);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,238 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RADCON_PDB_H
|
||||
#define RADCON_PDB_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Initial PDB Information Extraction & Conversion Preparation Task Types
|
||||
|
||||
//- rjf: tpi hash parsing
|
||||
|
||||
typedef struct P2R_TPIHashParseIn P2R_TPIHashParseIn;
|
||||
struct P2R_TPIHashParseIn
|
||||
{
|
||||
PDB_Strtbl *strtbl;
|
||||
PDB_TpiParsed *tpi;
|
||||
String8 hash_data;
|
||||
String8 aux_data;
|
||||
};
|
||||
|
||||
//- rjf: tpi leaves parsing
|
||||
|
||||
typedef struct P2R_TPILeafParseIn P2R_TPILeafParseIn;
|
||||
struct P2R_TPILeafParseIn
|
||||
{
|
||||
String8 leaf_data;
|
||||
CV_TypeId itype_first;
|
||||
};
|
||||
|
||||
//- rjf: exe hashing
|
||||
|
||||
typedef struct P2R_EXEHashIn P2R_EXEHashIn;
|
||||
struct P2R_EXEHashIn
|
||||
{
|
||||
String8 exe_data;
|
||||
};
|
||||
|
||||
//- rjf: symbol stream parsing
|
||||
|
||||
typedef struct P2R_SymbolStreamParseIn P2R_SymbolStreamParseIn;
|
||||
struct P2R_SymbolStreamParseIn
|
||||
{
|
||||
String8 data;
|
||||
};
|
||||
|
||||
//- rjf: c13 line info stream parsing
|
||||
|
||||
typedef struct P2R_C13StreamParseIn P2R_C13StreamParseIn;
|
||||
struct P2R_C13StreamParseIn
|
||||
{
|
||||
String8 data;
|
||||
String8 strtbl;
|
||||
COFF_SectionHeaderArray coff_sections;
|
||||
};
|
||||
|
||||
//- rjf: comp unit parsing
|
||||
|
||||
typedef struct P2R_CompUnitParseIn P2R_CompUnitParseIn;
|
||||
struct P2R_CompUnitParseIn
|
||||
{
|
||||
String8 data;
|
||||
};
|
||||
|
||||
//- rjf: comp unit contribution table parsing
|
||||
|
||||
typedef struct P2R_CompUnitContributionsParseIn P2R_CompUnitContributionsParseIn;
|
||||
struct P2R_CompUnitContributionsParseIn
|
||||
{
|
||||
String8 data;
|
||||
COFF_SectionHeaderArray coff_sections;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Conversion Data Structure & Task Types
|
||||
|
||||
//- rjf: link name map (voff -> string)
|
||||
|
||||
typedef struct P2R_LinkNameNode P2R_LinkNameNode;
|
||||
struct P2R_LinkNameNode
|
||||
{
|
||||
P2R_LinkNameNode *next;
|
||||
U64 voff;
|
||||
String8 name;
|
||||
};
|
||||
|
||||
typedef struct P2R_LinkNameMap P2R_LinkNameMap;
|
||||
struct P2R_LinkNameMap
|
||||
{
|
||||
P2R_LinkNameNode **buckets;
|
||||
U64 buckets_count;
|
||||
U64 bucket_collision_count;
|
||||
U64 link_name_count;
|
||||
};
|
||||
|
||||
//- rjf: normalized file path -> source file map
|
||||
|
||||
typedef struct P2R_SrcFileNode P2R_SrcFileNode;
|
||||
struct P2R_SrcFileNode
|
||||
{
|
||||
P2R_SrcFileNode *next;
|
||||
RDIM_SrcFile *src_file;
|
||||
};
|
||||
|
||||
typedef struct P2R_SrcFileMap P2R_SrcFileMap;
|
||||
struct P2R_SrcFileMap
|
||||
{
|
||||
P2R_SrcFileNode **slots;
|
||||
U64 slots_count;
|
||||
};
|
||||
|
||||
//- rjf: unit conversion tasks
|
||||
|
||||
typedef struct P2R_UnitConvertIn P2R_UnitConvertIn;
|
||||
struct P2R_UnitConvertIn
|
||||
{
|
||||
PDB_Strtbl *pdb_strtbl;
|
||||
COFF_SectionHeaderArray coff_sections;
|
||||
PDB_CompUnitArray *comp_units;
|
||||
PDB_CompUnitContributionArray *comp_unit_contributions;
|
||||
CV_SymParsed **comp_unit_syms;
|
||||
CV_C13Parsed **comp_unit_c13s;
|
||||
};
|
||||
|
||||
typedef struct P2R_UnitConvertOut P2R_UnitConvertOut;
|
||||
struct P2R_UnitConvertOut
|
||||
{
|
||||
RDIM_UnitChunkList units;
|
||||
RDIM_SrcFileChunkList src_files;
|
||||
RDIM_LineTableChunkList line_tables;
|
||||
RDIM_LineTable **units_first_inline_site_line_tables;
|
||||
};
|
||||
|
||||
//- rjf: link name map building tasks
|
||||
|
||||
typedef struct P2R_LinkNameMapBuildIn P2R_LinkNameMapBuildIn;
|
||||
struct P2R_LinkNameMapBuildIn
|
||||
{
|
||||
CV_SymParsed *sym;
|
||||
COFF_SectionHeaderArray coff_sections;
|
||||
P2R_LinkNameMap *link_name_map;
|
||||
};
|
||||
|
||||
//- rjf: udt conversion
|
||||
|
||||
typedef struct P2R_UDTConvertIn P2R_UDTConvertIn;
|
||||
struct P2R_UDTConvertIn
|
||||
{
|
||||
CV_LeafParsed *tpi_leaf;
|
||||
CV_TypeId itype_first;
|
||||
CV_TypeId itype_opl;
|
||||
RDIM_Type **itype_type_ptrs;
|
||||
};
|
||||
|
||||
//- rjf: symbol stream conversion
|
||||
|
||||
typedef struct P2R_SymbolStreamConvertIn P2R_SymbolStreamConvertIn;
|
||||
struct P2R_SymbolStreamConvertIn
|
||||
{
|
||||
RDI_Arch arch;
|
||||
COFF_SectionHeaderArray coff_sections;
|
||||
PDB_TpiHashParsed *tpi_hash;
|
||||
CV_LeafParsed *tpi_leaf;
|
||||
CV_LeafParsed *ipi_leaf;
|
||||
CV_SymParsed *sym;
|
||||
U64 sym_ranges_first;
|
||||
U64 sym_ranges_opl;
|
||||
RDIM_Type **itype_type_ptrs;
|
||||
P2R_LinkNameMap *link_name_map;
|
||||
RDIM_LineTable *first_inline_site_line_table;
|
||||
};
|
||||
|
||||
typedef struct P2R_SymbolStreamConvertOut P2R_SymbolStreamConvertOut;
|
||||
struct P2R_SymbolStreamConvertOut
|
||||
{
|
||||
RDIM_SymbolChunkList procedures;
|
||||
RDIM_SymbolChunkList global_variables;
|
||||
RDIM_SymbolChunkList thread_variables;
|
||||
RDIM_ScopeChunkList scopes;
|
||||
RDIM_InlineSiteChunkList inline_sites;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 p2r_end_of_cplusplus_container_name(String8 str);
|
||||
internal U64 p2r_hash_from_voff(U64 voff);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Location Info Building Helpers
|
||||
|
||||
internal RDIM_Location *p2r_location_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection);
|
||||
internal RDI_RegCode p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg);
|
||||
internal void p2r_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Location *location, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Initial Parsing & Preparation Pass Tasks
|
||||
|
||||
ASYNC_WORK_DEF(p2r_exe_hash_work);
|
||||
ASYNC_WORK_DEF(p2r_tpi_hash_parse_work);
|
||||
ASYNC_WORK_DEF(p2r_tpi_leaf_work);
|
||||
ASYNC_WORK_DEF(p2r_symbol_stream_parse_work);
|
||||
ASYNC_WORK_DEF(p2r_c13_stream_parse_work);
|
||||
ASYNC_WORK_DEF(p2r_comp_unit_parse_work);
|
||||
ASYNC_WORK_DEF(p2r_comp_unit_contributions_parse_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unit Conversion Tasks
|
||||
|
||||
ASYNC_WORK_DEF(p2r_units_convert_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Link Name Map Building Tasks
|
||||
|
||||
ASYNC_WORK_DEF(p2r_link_name_map_build_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UDT Conversion Tasks
|
||||
|
||||
ASYNC_WORK_DEF(p2r_udt_convert_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Symbol Stream Conversion Tasks
|
||||
|
||||
ASYNC_WORK_DEF(p2r_symbol_stream_convert_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Conversion Entry Point
|
||||
|
||||
internal RDIM_BakeParams *p2r_convert(Arena *arena, RDIM_HelpState *help_state, RC_Context *in);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal B32 p2r_has_symbol_ref(String8 msf_data, String8List symbol_list, MSF_RawStreamTable *st);
|
||||
internal B32 p2r_has_file_ref(String8 msf_data, String8List file_list, MSF_RawStreamTable *st);
|
||||
internal B32 p2r_has_symbol_or_file_ref(String8 msf_data, String8List symbol_list, String8List file_list);
|
||||
|
||||
#endif // RADCON_PDB_H
|
||||
|
||||
+10
-67
@@ -42,78 +42,21 @@ rd_stderr(char *fmt, ...)
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal String8
|
||||
rd_invoke_rdi_converter(Arena *arena, String8 exe_name, String8 exe_data, String8 pdb_path)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
P2R_User2Convert user2convert = {0};
|
||||
user2convert.input_pdb_name = pdb_path;
|
||||
user2convert.input_pdb_data = os_data_from_file_path(scratch.arena, pdb_path);
|
||||
user2convert.input_exe_name = exe_name;
|
||||
user2convert.input_exe_data = exe_data;
|
||||
user2convert.output_name = str8_zero();
|
||||
user2convert.flags = P2R_ConvertFlag_All;
|
||||
|
||||
P2R_Convert2Bake *convert2bake = p2r_convert(scratch.arena, &user2convert);
|
||||
P2R_Bake2Serialize *bake2srlz = p2r_bake(scratch.arena, convert2bake);
|
||||
RDIM_SerializedSectionBundle bundle = rdim_serialized_section_bundle_from_bake_results(&bake2srlz->bake_results);
|
||||
String8List rdi_blobs = rdim_file_blobs_from_section_bundle(scratch.arena, &bundle);
|
||||
String8 raw_rdi = str8_list_join(arena, &rdi_blobs, 0);
|
||||
|
||||
scratch_end(scratch);
|
||||
return raw_rdi;
|
||||
}
|
||||
|
||||
internal RDI_Parsed *
|
||||
rd_rdi_from_pe(Arena *arena, String8 data_path, String8 raw_data)
|
||||
rd_rdi_from_pe(Arena *arena, String8 pe_path)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// make command line for converter
|
||||
String8List cmdl_string = {0};
|
||||
str8_list_pushf(scratch.arena, &cmdl_string, "-pe:%S", pe_path);
|
||||
CmdLine cmdl = cmd_line_from_string_list(scratch.arena, cmdl_string);
|
||||
|
||||
// run converter
|
||||
String8 raw_rdi = rc_rdi_from_cmd_line(scratch.arena, &cmdl);
|
||||
|
||||
// load RDI
|
||||
RDI_Parsed *rdi = 0;
|
||||
|
||||
PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, raw_data);
|
||||
String8 raw_debug_dir = str8_substr(raw_data, pe.data_dir_franges[PE_DataDirectoryIndex_DEBUG]);
|
||||
PE_DebugInfoList dbg_list = pe_parse_debug_directory(scratch.arena, raw_data, raw_debug_dir);
|
||||
|
||||
String8 raw_rdi = {0};
|
||||
Guid rdi_guid = {0};
|
||||
for (PE_DebugInfoNode *n = dbg_list.first; n != 0; n = n->next) {
|
||||
PE_DebugInfo *v = &n->v;
|
||||
if (v->header.type == PE_DebugDirectoryType_CODEVIEW) {
|
||||
if (v->u.codeview.magic == PE_CODEVIEW_RDI_MAGIC) {
|
||||
if (raw_rdi.size) {
|
||||
rd_warningf("multiple RDI paths defined in %S");
|
||||
} else {
|
||||
raw_rdi = os_data_from_file_path(arena, v->u.codeview.rdi.path);
|
||||
rdi_guid = v->u.codeview.rdi.header.guid;
|
||||
if (raw_rdi.size == 0) {
|
||||
rd_errorf("unable to open RDI: %S", v->u.codeview.rdi.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!raw_rdi.size) {
|
||||
String8 pdb_path = str8_zero();
|
||||
Guid pdb_guid = {0};
|
||||
B32 convert_pdb = 0;
|
||||
for (PE_DebugInfoNode *n = dbg_list.first; n != 0; n = n->next) {
|
||||
PE_DebugInfo *v = &n->v;
|
||||
if (v->header.type == PE_DebugDirectoryType_CODEVIEW) {
|
||||
pdb_path = v->u.codeview.pdb70.path;
|
||||
pdb_guid = v->u.codeview.pdb70.header.guid;
|
||||
convert_pdb = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (convert_pdb) {
|
||||
raw_rdi = rd_invoke_rdi_converter(scratch.arena, data_path, raw_data, pdb_path);
|
||||
}
|
||||
}
|
||||
|
||||
if (raw_rdi.size) {
|
||||
rdi = push_array(arena, RDI_Parsed, 1);
|
||||
|
||||
|
||||
@@ -53,8 +53,12 @@
|
||||
#include "dwarf/dwarf_coff.h"
|
||||
#include "dwarf/dwarf_elf.h"
|
||||
#include "dwarf/dwarf_enum.h"
|
||||
#include "rdi_from_pdb/rdi_from_pdb.h"
|
||||
#include "rdi_from_dwarf/rdi_from_dwarf.h"
|
||||
#include "radcon/radcon.h"
|
||||
#include "radcon/radcon_coff.h"
|
||||
#include "radcon/radcon_cv.h"
|
||||
#include "radcon/radcon_elf.h"
|
||||
#include "radcon/radcon_pdb.h"
|
||||
#include "radcon/radcon_dwarf.h"
|
||||
|
||||
#include "base/base_inc.c"
|
||||
#include "linker/base_ext/base_inc.c"
|
||||
@@ -87,8 +91,12 @@
|
||||
#include "dwarf/dwarf_coff.c"
|
||||
#include "dwarf/dwarf_elf.c"
|
||||
#include "dwarf/dwarf_enum.c"
|
||||
#include "rdi_from_pdb/rdi_from_pdb.c"
|
||||
#include "rdi_from_dwarf/rdi_from_dwarf.c"
|
||||
#include "radcon/radcon_coff.c"
|
||||
#include "radcon/radcon_cv.c"
|
||||
#include "radcon/radcon_elf.c"
|
||||
#include "radcon/radcon_pdb.c"
|
||||
#include "radcon/radcon_dwarf.c"
|
||||
#include "radcon/radcon.c"
|
||||
|
||||
#include "linker/thread_pool/thread_pool.h"
|
||||
#include "linker/thread_pool/thread_pool.c"
|
||||
@@ -288,7 +296,7 @@ entry_point(CmdLine *cmdline)
|
||||
} else if (pe_check_magic(raw_data)) {
|
||||
RDI_Parsed *rdi = 0;
|
||||
if (!(opts & RD_Option_NoRdi)) {
|
||||
rdi = rd_rdi_from_pe(arena, file_path, raw_data);
|
||||
rdi = rd_rdi_from_pe(arena, file_path);
|
||||
}
|
||||
pe_print(arena, out, indent, raw_data, opts, rdi);
|
||||
} else if (pe_is_res(raw_data)) {
|
||||
|
||||
Reference in New Issue
Block a user