rdi, rdi_make, rdi_from_pdb, rdi_dump, df, dasm, etc: extract line tables from per-unit data sections, have top-level line info tables with units referring to line tables, and line tables just referring to sub-ranges of top-level sections; fix off-by-one string index in rdi generation

This commit is contained in:
Ryan Fleury
2024-06-03 15:32:14 -07:00
parent fcb839b788
commit 44fbbc24ee
17 changed files with 1355 additions and 705 deletions
+218 -38
View File
@@ -45,7 +45,7 @@ typedef int64_t RDI_S64;
// \"raddbg\0\0\"
#define RDI_MAGIC_CONSTANT 0x0000676264646172
#define RDI_ENCODING_VERSION 1
#define RDI_ENCODING_VERSION 2
////////////////////////////////////////////////////////////////
//~ Format Types & Functions
@@ -61,33 +61,35 @@ RDI_DataSectionTag_IndexRuns = 0x0004,
RDI_DataSectionTag_BinarySections = 0x0005,
RDI_DataSectionTag_FilePathNodes = 0x0006,
RDI_DataSectionTag_SourceFiles = 0x0007,
RDI_DataSectionTag_Units = 0x0008,
RDI_DataSectionTag_UnitVmap = 0x0009,
RDI_DataSectionTag_TypeNodes = 0x000A,
RDI_DataSectionTag_UDTs = 0x000B,
RDI_DataSectionTag_Members = 0x000C,
RDI_DataSectionTag_EnumMembers = 0x000D,
RDI_DataSectionTag_GlobalVariables = 0x000E,
RDI_DataSectionTag_GlobalVmap = 0x000F,
RDI_DataSectionTag_ThreadVariables = 0x0010,
RDI_DataSectionTag_Procedures = 0x0011,
RDI_DataSectionTag_Scopes = 0x0012,
RDI_DataSectionTag_ScopeVoffData = 0x0013,
RDI_DataSectionTag_ScopeVmap = 0x0014,
RDI_DataSectionTag_Locals = 0x0015,
RDI_DataSectionTag_LocationBlocks = 0x0016,
RDI_DataSectionTag_LocationData = 0x0017,
RDI_DataSectionTag_NameMaps = 0x0018,
RDI_DataSectionTag_PRIMARY_COUNT = 0x0019,
RDI_DataSectionTag_LineTables = 0x0008,
RDI_DataSectionTag_LineInfoVoffs = 0x0009,
RDI_DataSectionTag_LineInfoLines = 0x000A,
RDI_DataSectionTag_LineInfoColumns = 0x000B,
RDI_DataSectionTag_Units = 0x000C,
RDI_DataSectionTag_UnitVmap = 0x000D,
RDI_DataSectionTag_TypeNodes = 0x000E,
RDI_DataSectionTag_UDTs = 0x000F,
RDI_DataSectionTag_Members = 0x0010,
RDI_DataSectionTag_EnumMembers = 0x0011,
RDI_DataSectionTag_GlobalVariables = 0x0012,
RDI_DataSectionTag_GlobalVmap = 0x0013,
RDI_DataSectionTag_ThreadVariables = 0x0014,
RDI_DataSectionTag_Procedures = 0x0015,
RDI_DataSectionTag_Scopes = 0x0016,
RDI_DataSectionTag_ScopeVoffData = 0x0017,
RDI_DataSectionTag_ScopeVmap = 0x0018,
RDI_DataSectionTag_InlineSites = 0x0019,
RDI_DataSectionTag_Locals = 0x001A,
RDI_DataSectionTag_LocationBlocks = 0x001B,
RDI_DataSectionTag_LocationData = 0x001C,
RDI_DataSectionTag_NameMaps = 0x001D,
RDI_DataSectionTag_PRIMARY_COUNT = 0x001E,
RDI_DataSectionTag_SECONDARY = 0x80000000,
RDI_DataSectionTag_LineInfoVoffs = RDI_DataSectionTag_SECONDARY|0x0001,
RDI_DataSectionTag_LineInfoData = RDI_DataSectionTag_SECONDARY|0x0002,
RDI_DataSectionTag_LineInfoColumns = RDI_DataSectionTag_SECONDARY|0x0003,
RDI_DataSectionTag_LineMapNumbers = RDI_DataSectionTag_SECONDARY|0x0004,
RDI_DataSectionTag_LineMapRanges = RDI_DataSectionTag_SECONDARY|0x0005,
RDI_DataSectionTag_LineMapVoffs = RDI_DataSectionTag_SECONDARY|0x0006,
RDI_DataSectionTag_NameMapBuckets = RDI_DataSectionTag_SECONDARY|0x0007,
RDI_DataSectionTag_NameMapNodes = RDI_DataSectionTag_SECONDARY|0x0008,
RDI_DataSectionTag_LineMapNumbers = RDI_DataSectionTag_SECONDARY|0x0001,
RDI_DataSectionTag_LineMapRanges = RDI_DataSectionTag_SECONDARY|0x0002,
RDI_DataSectionTag_LineMapVoffs = RDI_DataSectionTag_SECONDARY|0x0003,
RDI_DataSectionTag_NameMapBuckets = RDI_DataSectionTag_SECONDARY|0x0004,
RDI_DataSectionTag_NameMapNodes = RDI_DataSectionTag_SECONDARY|0x0005,
} RDI_DataSectionTagEnum;
typedef RDI_U32 RDI_DataSectionEncoding;
@@ -485,6 +487,12 @@ RDI_NameMapKind_NormalSourcePaths = 6,
RDI_NameMapKind_COUNT = 7,
} RDI_NameMapKindEnum;
#define RDI_Header_XList \
X(RDI_U64, magic)\
X(RDI_U32, encoding_version)\
X(RDI_U32, data_section_off)\
X(RDI_U32, data_section_count)\
#define RDI_DataSectionTag_XList \
X(NULL)\
X(TopLevelInfo)\
@@ -494,6 +502,10 @@ X(IndexRuns)\
X(BinarySections)\
X(FilePathNodes)\
X(SourceFiles)\
X(LineTables)\
X(LineInfoVoffs)\
X(LineInfoLines)\
X(LineInfoColumns)\
X(Units)\
X(UnitVmap)\
X(TypeNodes)\
@@ -507,15 +519,13 @@ X(Procedures)\
X(Scopes)\
X(ScopeVoffData)\
X(ScopeVmap)\
X(InlineSites)\
X(Locals)\
X(LocationBlocks)\
X(LocationData)\
X(NameMaps)\
X(PRIMARY_COUNT)\
X(SECONDARY)\
X(LineInfoVoffs)\
X(LineInfoData)\
X(LineInfoColumns)\
X(LineMapNumbers)\
X(LineMapRanges)\
X(LineMapVoffs)\
@@ -526,15 +536,80 @@ X(NameMapNodes)\
X(Unpacked)\
X(LZB)\
#define RDI_DataSection_XList \
X(RDI_DataSectionTag, tag)\
X(RDI_DataSectionEncoding, encoding)\
X(RDI_U64, off)\
X(RDI_U64, encoded_size)\
X(RDI_U64, unpacked_size)\
#define RDI_VMapEntry_XList \
X(RDI_U64, voff)\
X(RDI_U64, idx)\
#define RDI_Arch_XList \
X(NULL)\
X(X86)\
X(X64)\
#define RDI_TopLevelInfo_XList \
X(RDI_Arch, arch)\
X(RDI_U32, exe_name_string_idx)\
X(RDI_U64, exe_hash)\
X(RDI_U64, voff_max)\
#define RDI_BinarySectionFlags_XList \
X(NULL)\
X(X86)\
X(X64)\
X(Read)\
X(Write)\
X(Execute)\
#define RDI_BinarySection_XList \
X(RDI_U32, name_string_idx)\
X(RDI_BinarySectionFlags, flags)\
X(RDI_U64, voff_first)\
X(RDI_U64, voff_opl)\
X(RDI_U64, foff_first)\
X(RDI_U64, foff_opl)\
#define RDI_FilePathNode_XList \
X(RDI_U32, name_string_idx)\
X(RDI_U32, parent_path_node)\
X(RDI_U32, first_child)\
X(RDI_U32, next_sibling)\
X(RDI_U32, source_file_idx)\
#define RDI_SourceFile_XList \
X(RDI_U32, file_path_node_idx)\
X(RDI_U32, normal_full_path_string_idx)\
X(RDI_U32, line_map_count)\
X(RDI_U32, line_map_nums_data_idx)\
X(RDI_U32, line_map_range_data_idx)\
X(RDI_U32, line_map_voff_data_idx)\
#define RDI_Unit_XList \
X(RDI_U32, unit_name_string_idx)\
X(RDI_U32, compiler_name_string_idx)\
X(RDI_U32, source_file_path_node)\
X(RDI_U32, object_file_path_node)\
X(RDI_U32, archive_file_path_node)\
X(RDI_U32, build_path_node)\
X(RDI_Language, language)\
X(RDI_U32, line_table_idx)\
#define RDI_LineTable_XList \
X(RDI_U32, voffs_base_idx)\
X(RDI_U32, lines_base_idx)\
X(RDI_U32, cols_base_idx)\
X(RDI_U32, lines_count)\
X(RDI_U32, cols_count)\
#define RDI_Line_XList \
X(RDI_U32, file_idx)\
X(RDI_U32, line_num)\
#define RDI_Column_XList \
X(RDI_U16, col_first)\
X(RDI_U16, col_opl)\
#define RDI_Language_XList \
X(NULL)\
@@ -602,9 +677,23 @@ X(Variadic)\
X(Const)\
X(Volatile)\
#define RDI_UDTFlag_XList \
#define RDI_TypeNode_XList \
X(RDI_TypeKind, kind)\
X(RDI_U16, flags)\
X(RDI_U32, byte_size)\
#define RDI_UDTFlags_XList \
X(EnumMembers)\
#define RDI_UDT_XList \
X(RDI_U32, self_type_idx)\
X(RDI_UDTFlags, flags)\
X(RDI_U32, member_first)\
X(RDI_U32, member_count)\
X(RDI_U32, file_idx)\
X(RDI_U32, line)\
X(RDI_U32, col)\
#define RDI_MemberKind_XList \
X(NULL)\
X(DataField)\
@@ -617,6 +706,18 @@ X(Base)\
X(VirtualBase)\
X(NestedType)\
#define RDI_Member_XList \
X(RDI_MemberKind, kind)\
X(RDI_U16, pad)\
X(RDI_U32, name_string_idx)\
X(RDI_U32, type_idx)\
X(RDI_U32, off)\
#define RDI_EnumMember_XList \
X(RDI_U32, name_string_idx)\
X(RDI_U32, pad)\
X(RDI_U64, val)\
#define RDI_LinkFlags_XList \
X(External)\
X(TypeScoped)\
@@ -635,6 +736,74 @@ X(AddrRegPlusU16)\
X(AddrAddrRegPlusU16)\
X(ValReg)\
#define RDI_GlobalVariable_XList \
X(RDI_U32, name_string_idx)\
X(RDI_LinkFlags, link_flags)\
X(RDI_U64, voff)\
X(RDI_U32, type_idx)\
X(RDI_U32, container_idx)\
#define RDI_ThreadVariable_XList \
X(RDI_U32, name_string_idx)\
X(RDI_LinkFlags, link_flags)\
X(RDI_U32, tls_off)\
X(RDI_U32, type_idx)\
X(RDI_U32, container_idx)\
#define RDI_Procedure_XList \
X(RDI_U32, name_string_idx)\
X(RDI_U32, link_name_string_idx)\
X(RDI_LinkFlags, link_flags)\
X(RDI_U32, type_idx)\
X(RDI_U32, root_scope_idx)\
X(RDI_U32, container_idx)\
#define RDI_Scope_XList \
X(RDI_U32, proc_idx)\
X(RDI_U32, parent_scope_idx)\
X(RDI_U32, first_child_scope_idx)\
X(RDI_U32, next_sibling_scope_idx)\
X(RDI_U32, voff_range_first)\
X(RDI_U32, voff_range_opl)\
X(RDI_U32, local_first)\
X(RDI_U32, local_count)\
X(RDI_U32, static_local_idx_run_first)\
X(RDI_U32, static_local_count)\
#define RDI_InlineSite_XList \
X(RDI_U32, name_string_idx)\
X(RDI_U32, call_src_file_idx)\
X(RDI_U32, call_line_num)\
X(RDI_U32, call_col_num)\
X(RDI_U32, type_idx)\
X(RDI_U32, owner_type_idx)\
X(RDI_U32, line_table_idx)\
#define RDI_Local_XList \
X(RDI_LocalKind, kind)\
X(RDI_U32, name_string_idx)\
X(RDI_U32, type_idx)\
X(RDI_U32, pad)\
X(RDI_U32, location_first)\
X(RDI_U32, location_opl)\
#define RDI_LocationBlock_XList \
X(RDI_U32, scope_off_first)\
X(RDI_U32, scope_off_opl)\
X(RDI_U32, location_data_off)\
#define RDI_LocationBytecodeStream_XList \
X(RDI_LocationKind, kind)\
#define RDI_LocationRegPlusU16_XList \
X(RDI_LocationKind, kind)\
X(RDI_RegCode, reg_code)\
X(RDI_U16, offset)\
#define RDI_LocationReg_XList \
X(RDI_LocationKind, kind)\
X(RDI_RegCode, reg_code)\
#define RDI_EvalOp_XList \
X(Stop)\
X(Noop)\
@@ -708,6 +877,20 @@ X(LinkNameProcedures)\
X(NormalSourcePaths)\
X(COUNT)\
#define RDI_NameMap_XList \
X(RDI_NameMapKind, kind)\
X(RDI_U32, bucket_data_idx)\
X(RDI_U32, node_data_idx)\
#define RDI_NameMapBucket_XList \
X(RDI_U32, first_node)\
X(RDI_U32, node_count)\
#define RDI_NameMapNode_XList \
X(RDI_U32, string_idx)\
X(RDI_U32, match_count)\
X(RDI_U32, match_idx_or_idx_run_first)\
#define RDI_EVAL_CTRLBITS(decodeN,popN,pushN) ((decodeN) | ((popN) << 4) | ((pushN) << 6))
#define RDI_DECODEN_FROM_CTRLBITS(ctrlbits) ((ctrlbits) & 0xf)
#define RDI_POPN_FROM_CTRLBITS(ctrlbits) (((ctrlbits) >> 4) & 0x3)
@@ -791,10 +974,7 @@ RDI_U32 object_file_path_node;
RDI_U32 archive_file_path_node;
RDI_U32 build_path_node;
RDI_Language language;
RDI_U32 line_info_voffs_data_idx;
RDI_U32 line_info_data_idx;
RDI_U32 line_info_col_data_idx;
RDI_U32 line_info_count;
RDI_U32 line_table_idx;
};
typedef struct RDI_LineTable RDI_LineTable;
+243 -226
View File
@@ -2,116 +2,136 @@
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ RADDBG Parse API
//~ Top-Level Parsing API
RDI_PROC RDI_ParseStatus
rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out)
{
RDI_ParseStatus result = RDI_ParseStatus_Good;
// out header
//////////////////////////////
//- rjf: extract header
//
RDI_Header *hdr = 0;
if(result == RDI_ParseStatus_Good)
{
if (sizeof(*hdr) <= size){
if(sizeof(*hdr) <= size)
{
hdr = (RDI_Header*)data;
}
// (errors)
if (hdr == 0 || hdr->magic != RDI_MAGIC_CONSTANT){
if(hdr == 0 || hdr->magic != RDI_MAGIC_CONSTANT)
{
hdr = 0;
result = RDI_ParseStatus_HeaderDoesNotMatch;
}
if (hdr != 0 && hdr->encoding_version != 1){
if(hdr != 0 && hdr->encoding_version != RDI_ENCODING_VERSION)
{
hdr = 0;
result = RDI_ParseStatus_UnsupportedVersionNumber;
}
}
// out data sections
//////////////////////////////
//- rjf: extract data sections
//
RDI_DataSection *dsecs = 0;
RDI_U32 dsec_count = 0;
if (hdr != 0){
if(result == RDI_ParseStatus_Good)
{
RDI_U64 opl = (RDI_U64)hdr->data_section_off + (RDI_U64)hdr->data_section_count*sizeof(*dsecs);
if (opl <= size){
if(opl <= size)
{
dsecs = (RDI_DataSection*)(data + hdr->data_section_off);
dsec_count = hdr->data_section_count;
}
// (errors)
if (dsecs == 0){
if(dsecs == 0)
{
result = RDI_ParseStatus_InvalidDataSecionLayout;
}
}
// extract primary data section indexes
//////////////////////////////
//- rjf: extract primary data section indexes
//
RDI_U32 dsec_idx[RDI_DataSectionTag_PRIMARY_COUNT] = {0};
if (result == RDI_ParseStatus_Good){
if(result == RDI_ParseStatus_Good)
{
RDI_DataSection *sec_ptr = dsecs;
for (RDI_U32 i = 0; i < dsec_count; i += 1, sec_ptr += 1){
if (sec_ptr->tag < RDI_DataSectionTag_PRIMARY_COUNT){
for(RDI_U32 i = 0; i < dsec_count; i += 1, sec_ptr += 1)
{
if(sec_ptr->tag < RDI_DataSectionTag_PRIMARY_COUNT)
{
dsec_idx[sec_ptr->tag] = i;
}
}
}
// fill out data block (part 1)
if (result == RDI_ParseStatus_Good){
//////////////////////////////
//- rjf: fill out raw data info
//
if(result == RDI_ParseStatus_Good)
{
out->raw_data = data;
out->raw_data_size = size;
out->dsecs = dsecs;
out->dsec_count = dsec_count;
for (RDI_U32 i = 0; i < RDI_DataSectionTag_PRIMARY_COUNT; i += 1){
for(RDI_U32 i = 0; i < RDI_DataSectionTag_PRIMARY_COUNT; i += 1)
{
out->dsec_idx[i] = dsec_idx[i];
}
}
// out string table
//////////////////////////////
//- rjf: extract string table info
//
RDI_U8 *string_data = 0;
RDI_U64 string_opl = 0;
RDI_U32 *string_offs = 0;
RDI_U64 string_count = 0;
if (result == RDI_ParseStatus_Good){
rdi_parse__extract_primary(out, string_data, &string_opl,
RDI_DataSectionTag_StringData);
if(result == RDI_ParseStatus_Good)
{
RDI_U64 table_entry_count = 0;
rdi_parse__extract_primary(out, string_offs, &table_entry_count,
RDI_DataSectionTag_StringTable);
if (table_entry_count > 0){
rdi_parse__extract_primary(out, string_offs, &table_entry_count, RDI_DataSectionTag_StringTable);
rdi_parse__extract_primary(out, string_data, &string_opl, RDI_DataSectionTag_StringData);
if(table_entry_count > 0)
{
string_count = table_entry_count - 1;
}
// (errors)
if (string_data == 0){
if(string_data == 0)
{
result = RDI_ParseStatus_MissingStringDataSection;
}
else if (string_offs == 0){
else if (string_offs == 0)
{
result = RDI_ParseStatus_MissingStringTableSection;
}
}
// out index runs
//////////////////////////////
//- rjf: extract index run table info
//
RDI_U32 *idx_run_data = 0;
RDI_U64 idx_run_count = 0;
if (result == RDI_ParseStatus_Good){
rdi_parse__extract_primary(out, idx_run_data, &idx_run_count,
RDI_DataSectionTag_IndexRuns);
// (errors)
if (idx_run_data == 0){
if(result == RDI_ParseStatus_Good)
{
rdi_parse__extract_primary(out, idx_run_data, &idx_run_count, RDI_DataSectionTag_IndexRuns);
if(idx_run_data == 0)
{
result = RDI_ParseStatus_MissingIndexRunSection;
}
}
if (result == RDI_ParseStatus_Good){
// fill out primary data structures (part 2)
//////////////////////////////
//- rjf: extract info tables
//
if(result == RDI_ParseStatus_Good)
{
out->string_data = string_data;
out->string_offs = string_offs;
out->string_data_size = string_opl;
out->string_count = string_count;
out->idx_run_data = idx_run_data;
out->idx_run_count = idx_run_count;
{
RDI_TopLevelInfo *tli = 0;
RDI_U64 dummy = 0;
@@ -121,71 +141,32 @@ rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out)
}
out->top_level_info = tli;
}
rdi_parse__extract_primary(out, out->binary_sections, &out->binary_sections_count,
RDI_DataSectionTag_BinarySections);
rdi_parse__extract_primary(out, out->file_paths, &out->file_paths_count,
RDI_DataSectionTag_FilePathNodes);
rdi_parse__extract_primary(out, out->source_files, &out->source_files_count,
RDI_DataSectionTag_SourceFiles);
rdi_parse__extract_primary(out, out->units, &out->units_count,
RDI_DataSectionTag_Units);
rdi_parse__extract_primary(out, out->unit_vmap, &out->unit_vmap_count,
RDI_DataSectionTag_UnitVmap);
rdi_parse__extract_primary(out, out->unit_vmap, &out->unit_vmap_count,
RDI_DataSectionTag_UnitVmap);
rdi_parse__extract_primary(out, out->type_nodes, &out->type_nodes_count,
RDI_DataSectionTag_TypeNodes);
rdi_parse__extract_primary(out, out->udts, &out->udts_count,
RDI_DataSectionTag_UDTs);
rdi_parse__extract_primary(out, out->members, &out->members_count,
RDI_DataSectionTag_Members);
rdi_parse__extract_primary(out, out->enum_members, &out->enum_members_count,
RDI_DataSectionTag_EnumMembers);
rdi_parse__extract_primary(out, out->global_variables, &out->global_variables_count,
RDI_DataSectionTag_GlobalVariables);
rdi_parse__extract_primary(out, out->global_vmap, &out->global_vmap_count,
RDI_DataSectionTag_GlobalVmap);
rdi_parse__extract_primary(out, out->thread_variables, &out->thread_variables_count,
RDI_DataSectionTag_ThreadVariables);
rdi_parse__extract_primary(out, out->procedures, &out->procedures_count,
RDI_DataSectionTag_Procedures);
rdi_parse__extract_primary(out, out->scopes, &out->scopes_count,
RDI_DataSectionTag_Scopes);
rdi_parse__extract_primary(out, out->scope_voffs, &out->scope_voffs_count,
RDI_DataSectionTag_ScopeVoffData);
rdi_parse__extract_primary(out, out->scope_vmap, &out->scope_vmap_count,
RDI_DataSectionTag_ScopeVmap);
rdi_parse__extract_primary(out, out->locals, &out->locals_count,
RDI_DataSectionTag_Locals);
rdi_parse__extract_primary(out, out->location_blocks, &out->location_blocks_count,
RDI_DataSectionTag_LocationBlocks);
rdi_parse__extract_primary(out, out->location_data, &out->location_data_size,
RDI_DataSectionTag_LocationData);
rdi_parse__extract_primary(out, out->binary_sections, &out->binary_sections_count, RDI_DataSectionTag_BinarySections);
rdi_parse__extract_primary(out, out->file_paths, &out->file_paths_count, RDI_DataSectionTag_FilePathNodes);
rdi_parse__extract_primary(out, out->source_files, &out->source_files_count, RDI_DataSectionTag_SourceFiles);
rdi_parse__extract_primary(out, out->line_tables, &out->line_tables_count, RDI_DataSectionTag_LineTables);
rdi_parse__extract_primary(out, out->line_info_voffs, &out->line_info_voffs_count, RDI_DataSectionTag_LineInfoVoffs);
rdi_parse__extract_primary(out, out->line_info_lines, &out->line_info_lines_count, RDI_DataSectionTag_LineInfoLines);
rdi_parse__extract_primary(out, out->line_info_columns, &out->line_info_columns_count, RDI_DataSectionTag_LineInfoColumns);
rdi_parse__extract_primary(out, out->units, &out->units_count, RDI_DataSectionTag_Units);
rdi_parse__extract_primary(out, out->unit_vmap, &out->unit_vmap_count, RDI_DataSectionTag_UnitVmap);
rdi_parse__extract_primary(out, out->unit_vmap, &out->unit_vmap_count, RDI_DataSectionTag_UnitVmap);
rdi_parse__extract_primary(out, out->type_nodes, &out->type_nodes_count, RDI_DataSectionTag_TypeNodes);
rdi_parse__extract_primary(out, out->udts, &out->udts_count, RDI_DataSectionTag_UDTs);
rdi_parse__extract_primary(out, out->members, &out->members_count, RDI_DataSectionTag_Members);
rdi_parse__extract_primary(out, out->enum_members, &out->enum_members_count, RDI_DataSectionTag_EnumMembers);
rdi_parse__extract_primary(out, out->global_variables, &out->global_variables_count, RDI_DataSectionTag_GlobalVariables);
rdi_parse__extract_primary(out, out->global_vmap, &out->global_vmap_count, RDI_DataSectionTag_GlobalVmap);
rdi_parse__extract_primary(out, out->thread_variables, &out->thread_variables_count, RDI_DataSectionTag_ThreadVariables);
rdi_parse__extract_primary(out, out->procedures, &out->procedures_count, RDI_DataSectionTag_Procedures);
rdi_parse__extract_primary(out, out->scopes, &out->scopes_count, RDI_DataSectionTag_Scopes);
rdi_parse__extract_primary(out, out->scope_voffs, &out->scope_voffs_count, RDI_DataSectionTag_ScopeVoffData);
rdi_parse__extract_primary(out, out->scope_vmap, &out->scope_vmap_count, RDI_DataSectionTag_ScopeVmap);
rdi_parse__extract_primary(out, out->locals, &out->locals_count, RDI_DataSectionTag_Locals);
rdi_parse__extract_primary(out, out->location_blocks, &out->location_blocks_count, RDI_DataSectionTag_LocationBlocks);
rdi_parse__extract_primary(out, out->location_data, &out->location_data_size, RDI_DataSectionTag_LocationData);
rdi_parse__extract_primary(out, out->name_maps, &out->name_maps_count, RDI_DataSectionTag_NameMaps);
{
rdi_parse__extract_primary(out, out->name_maps, &out->name_maps_count,
RDI_DataSectionTag_NameMaps);
RDI_NameMap *name_map_ptr = out->name_maps;
RDI_NameMap *name_map_opl = out->name_maps + out->name_maps_count;
for (; name_map_ptr < name_map_opl; name_map_ptr += 1){
@@ -196,8 +177,11 @@ rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out)
}
}
//////////////////////////////
//- rjf: fill any missing tables with nil elements
//
#if !defined(RDI_DISABLE_NILS)
if(out->top_level_info == 0) { out->top_level_info = &rdi_top_level_info_nil; }
if(out->top_level_info == 0) { out->top_level_info = &rdi_top_level_info_nil; }
if(out->binary_sections == 0) { out->binary_sections = &rdi_binary_section_nil; out->binary_sections_count = 1; }
if(out->file_paths == 0) { out->file_paths = &rdi_file_path_node_nil; out->file_paths_count = 1; }
if(out->source_files == 0) { out->source_files = &rdi_source_file_nil; out->source_files_count = 1; }
@@ -218,9 +202,14 @@ rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out)
if(out->location_blocks == 0) { out->location_blocks = &rdi_location_block_nil; out->location_blocks_count = 1; }
#endif
return(result);
return result;
}
////////////////////////////////
//~ Parsed Info Extraction Helpers
//- top-level info
RDI_PROC RDI_U64
rdi_decompressed_size_from_parsed(RDI_Parsed *rdi)
{
@@ -232,11 +221,15 @@ rdi_decompressed_size_from_parsed(RDI_Parsed *rdi)
return decompressed_size;
}
//- strings
RDI_PROC RDI_U8*
rdi_string_from_idx(RDI_Parsed *parsed, RDI_U32 idx, RDI_U64 *len_out){
rdi_string_from_idx(RDI_Parsed *parsed, RDI_U32 idx, RDI_U64 *len_out)
{
RDI_U8 *result = 0;
RDI_U64 len_result = 0;
if (idx < parsed->string_count){
if(idx < parsed->string_count)
{
RDI_U32 off_raw = parsed->string_offs[idx];
RDI_U32 opl_raw = parsed->string_offs[idx + 1];
RDI_U32 opl = rdi_parse__min(opl_raw, parsed->string_data_size);
@@ -245,108 +238,113 @@ rdi_string_from_idx(RDI_Parsed *parsed, RDI_U32 idx, RDI_U64 *len_out){
len_result = opl - off;
}
*len_out = len_result;
return(result);
return result;
}
//- index runs
RDI_PROC RDI_U32*
rdi_idx_run_from_first_count(RDI_Parsed *parsed,
RDI_U32 raw_first, RDI_U32 raw_count,
RDI_U32 *n_out){
rdi_idx_run_from_first_count(RDI_Parsed *parsed, RDI_U32 raw_first, RDI_U32 raw_count, RDI_U32 *n_out)
{
RDI_U32 raw_opl = raw_first + raw_count;
RDI_U32 opl = rdi_parse__min(raw_opl, parsed->idx_run_count);
RDI_U32 first = rdi_parse__min(raw_first, opl);
RDI_U32 *result = 0;
if (first < parsed->idx_run_count){
if(first < parsed->idx_run_count)
{
result = parsed->idx_run_data + first;
}
*n_out = opl - first;
return(result);
return result;
}
//- line info
RDI_PROC void
rdi_line_info_from_unit(RDI_Parsed *p, RDI_Unit *unit, RDI_ParsedLineInfo *out){
RDI_U64 line_info_voff_count = 0;
RDI_U64 *voffs = (RDI_U64*)
rdi_data_from_dsec(p, unit->line_info_voffs_data_idx, sizeof(RDI_U64),
RDI_DataSectionTag_LineInfoVoffs,
&line_info_voff_count);
rdi_parsed_from_line_table(RDI_Parsed *p, RDI_LineTable *line_table, RDI_ParsedLineTable *out)
{
//- rjf: extract top-level line info tables
RDI_U64 all_voffs_count = 0;
RDI_U64 *all_voffs = (RDI_U64 *)rdi_data_from_dsec(p, p->dsec_idx[RDI_DataSectionTag_LineInfoVoffs], sizeof(RDI_U64), RDI_DataSectionTag_LineInfoVoffs, &all_voffs_count);
RDI_U64 *all_voffs_opl = all_voffs + all_voffs_count;
RDI_U64 all_lines_count = 0;
RDI_Line *all_lines = (RDI_Line *)rdi_data_from_dsec(p, p->dsec_idx[RDI_DataSectionTag_LineInfoLines], sizeof(RDI_Line), RDI_DataSectionTag_LineInfoLines, &all_lines_count);
RDI_Line *all_lines_opl = all_lines + all_lines_count;
RDI_U64 all_cols_count = 0;
RDI_Column *all_cols = (RDI_Column *)rdi_data_from_dsec(p, p->dsec_idx[RDI_DataSectionTag_LineInfoColumns], sizeof(RDI_Column), RDI_DataSectionTag_LineInfoColumns, &all_cols_count);
RDI_Column *all_cols_opl = all_cols + all_cols_count;
RDI_U64 line_info_count_raw = 0;
RDI_Line *lines = (RDI_Line*)
rdi_data_from_dsec(p, unit->line_info_data_idx, sizeof(RDI_Line),
RDI_DataSectionTag_LineInfoData,
&line_info_count_raw);
//- rjf: extract ranges of top-level tables belonging to this line table
RDI_U64 *lt_voffs = all_voffs + line_table->voffs_base_idx;
RDI_Line *lt_lines = all_lines + line_table->lines_base_idx;
RDI_Column *lt_cols = all_cols + line_table->cols_base_idx;
RDI_U64 lines_count = line_table->lines_count;
RDI_U64 cols_count = line_table->cols_count;
if(lt_voffs >= all_voffs_opl) {lt_voffs = all_voffs; lines_count = 0;}
if(lt_lines >= all_lines_opl) {lt_lines = all_lines; lines_count = 0;}
if(lt_cols >= all_cols_opl) {lt_cols = all_cols; cols_count = 0;}
RDI_U64 column_info_count_raw = 0;
RDI_Column *cols = (RDI_Column*)
rdi_data_from_dsec(p, unit->line_info_col_data_idx, sizeof(RDI_Column),
RDI_DataSectionTag_LineInfoColumns,
&column_info_count_raw);
RDI_U32 line_info_count_a = (line_info_voff_count > 0)?line_info_voff_count - 1:0;
RDI_U32 line_info_count = rdi_parse__min(line_info_count_a, line_info_count_raw);
RDI_U32 column_info_count = rdi_parse__min(column_info_count_raw, line_info_count);
out->voffs = voffs;
out->lines = lines;
out->cols = cols;
out->count = line_info_count;
out->col_count = column_info_count;
//- rjf: fill result
out->voffs = lt_voffs;
out->lines = lt_lines;
out->cols = lt_cols;
out->count = lines_count;
out->col_count = cols_count;
}
RDI_PROC RDI_U64
rdi_line_info_idx_from_voff(RDI_ParsedLineInfo *line_info, RDI_U64 voff)
rdi_line_info_idx_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff)
{
RDI_U64 result = 0;
if (line_info->count > 0 && line_info->voffs[0] <= voff && voff < line_info->voffs[line_info->count - 1]){
if(line_info->count > 0 && line_info->voffs[0] <= voff && voff < line_info->voffs[line_info->count - 1])
{
// assuming: (i < j) -> (vmap[i].voff < vmap[j].voff)
// find i such that: (vmap[i].voff <= voff) && (voff < vmap[i + 1].voff)
RDI_U32 first = 0;
RDI_U32 opl = line_info->count;
for (;;){
for(;;)
{
RDI_U32 mid = (first + opl)/2;
if (line_info->voffs[mid] < voff){
if(line_info->voffs[mid] < voff)
{
first = mid;
}
else if (line_info->voffs[mid] > voff){
else if(line_info->voffs[mid] > voff)
{
opl = mid;
}
else{
else
{
first = mid;
break;
}
if (opl - first <= 1){
if(opl - first <= 1)
{
break;
}
}
result = (RDI_U64)first;
}
return(result);
return result;
}
RDI_PROC void
rdi_line_map_from_source_file(RDI_Parsed *p, RDI_SourceFile *srcfile,
RDI_ParsedLineMap *out){
rdi_line_map_from_source_file(RDI_Parsed *p, RDI_SourceFile *srcfile, RDI_ParsedLineMap *out)
{
RDI_U64 num_count = 0;
RDI_U32 *nums = (RDI_U32*)
rdi_data_from_dsec(p, srcfile->line_map_nums_data_idx, sizeof(RDI_U32),
RDI_DataSectionTag_LineMapNumbers,
&num_count);
RDI_U32 *nums = (RDI_U32*)rdi_data_from_dsec(p, srcfile->line_map_nums_data_idx, sizeof(RDI_U32),
RDI_DataSectionTag_LineMapNumbers,
&num_count);
RDI_U64 range_count = 0;
RDI_U32 *ranges = (RDI_U32*)
rdi_data_from_dsec(p, srcfile->line_map_range_data_idx, sizeof(RDI_U32),
RDI_DataSectionTag_LineMapRanges,
&range_count);
RDI_U32 *ranges = (RDI_U32*)rdi_data_from_dsec(p, srcfile->line_map_range_data_idx, sizeof(RDI_U32),
RDI_DataSectionTag_LineMapRanges,
&range_count);
RDI_U64 voff_count = 0;
RDI_U64 *voffs = (RDI_U64*)
rdi_data_from_dsec(p, srcfile->line_map_voff_data_idx, sizeof(RDI_U64),
RDI_DataSectionTag_LineMapVoffs,
&voff_count);
RDI_U64 *voffs = (RDI_U64*)rdi_data_from_dsec(p, srcfile->line_map_voff_data_idx, sizeof(RDI_U64),
RDI_DataSectionTag_LineMapVoffs,
&voff_count);
RDI_U32 count_a = (range_count > 0)?(range_count - 1):0;
RDI_U32 count_b = rdi_parse__min(count_a, num_count);
@@ -360,30 +358,36 @@ rdi_line_map_from_source_file(RDI_Parsed *p, RDI_SourceFile *srcfile,
}
RDI_PROC RDI_U64*
rdi_line_voffs_from_num(RDI_ParsedLineMap *map, RDI_U32 linenum, RDI_U32 *n_out){
rdi_line_voffs_from_num(RDI_ParsedLineMap *map, RDI_U32 linenum, RDI_U32 *n_out)
{
RDI_U64 *result = 0;
*n_out = 0;
RDI_U32 closest_i = 0;
if (map->count > 0 && map->nums[0] <= linenum){
if(map->count > 0 && map->nums[0] <= linenum)
{
// assuming: (i < j) -> (nums[i] < nums[j])
// find i such that: (nums[i] <= linenum) && (linenum < nums[i + 1])
RDI_U32 *nums = map->nums;
RDI_U32 first = 0;
RDI_U32 opl = map->count;
for (;;){
for(;;)
{
RDI_U32 mid = (first + opl)/2;
if (nums[mid] < linenum){
if(nums[mid] < linenum)
{
first = mid;
}
else if (nums[mid] > linenum){
else if(nums[mid] > linenum)
{
opl = mid;
}
else{
else
{
first = mid;
break;
}
if (opl - first <= 1){
if(opl - first <= 1)
{
break;
}
}
@@ -391,54 +395,62 @@ rdi_line_voffs_from_num(RDI_ParsedLineMap *map, RDI_U32 linenum, RDI_U32 *n_out)
}
// round up instead of down if possible
if (closest_i + 1 < map->count &&
map->nums[closest_i] < linenum){
if(closest_i + 1 < map->count && map->nums[closest_i] < linenum)
{
closest_i += 1;
}
// set result if possible
if (closest_i < map->count){
if(closest_i < map->count)
{
RDI_U32 first = map->ranges[closest_i];
RDI_U32 opl = map->ranges[closest_i + 1];
if (opl < map->voff_count){
if(opl < map->voff_count)
{
result = map->voffs + first;
*n_out = opl - first;
}
}
return(result);
return result;
}
//- vmaps
//- vmap lookups
RDI_PROC RDI_U64
rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U32 vmap_count, RDI_U64 voff){
rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U32 vmap_count, RDI_U64 voff)
{
RDI_U64 result = 0;
if (vmap_count > 0 && vmap[0].voff <= voff && voff < vmap[vmap_count - 1].voff){
if(vmap_count > 0 && vmap[0].voff <= voff && voff < vmap[vmap_count - 1].voff)
{
// assuming: (i < j) -> (vmap[i].voff < vmap[j].voff)
// find i such that: (vmap[i].voff <= voff) && (voff < vmap[i + 1].voff)
RDI_U32 first = 0;
RDI_U32 opl = vmap_count;
for (;;){
for(;;)
{
RDI_U32 mid = (first + opl)/2;
if (vmap[mid].voff < voff){
if(vmap[mid].voff < voff)
{
first = mid;
}
else if (vmap[mid].voff > voff){
else if(vmap[mid].voff > voff)
{
opl = mid;
}
else{
else
{
first = mid;
break;
}
if (opl - first <= 1){
if(opl - first <= 1)
{
break;
}
}
result = (RDI_U64)vmap[first].idx;
}
return(result);
return result;
}
//- name maps
@@ -446,47 +458,48 @@ rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U32 vmap_count, RDI_U64 voff){
RDI_PROC RDI_NameMap*
rdi_name_map_from_kind(RDI_Parsed *p, RDI_NameMapKind kind){
RDI_NameMap *result = 0;
if (0 < kind && kind < RDI_NameMapKind_COUNT){
if(0 < kind && kind < RDI_NameMapKind_COUNT)
{
result = p->name_maps_by_kind[kind];
}
return(result);
return result;
}
RDI_PROC void
rdi_name_map_parse(RDI_Parsed *p, RDI_NameMap *mapptr, RDI_ParsedNameMap *out){
rdi_name_map_parse(RDI_Parsed *p, RDI_NameMap *mapptr, RDI_ParsedNameMap *out)
{
out->buckets = 0;
out->bucket_count = 0;
if (mapptr != 0){
out->buckets = (RDI_NameMapBucket*)
rdi_data_from_dsec(p, mapptr->bucket_data_idx, sizeof(RDI_NameMapBucket),
RDI_DataSectionTag_NameMapBuckets, &out->bucket_count);
out->nodes = (RDI_NameMapNode*)
rdi_data_from_dsec(p, mapptr->node_data_idx, sizeof(RDI_NameMapNode),
RDI_DataSectionTag_NameMapNodes, &out->node_count);
if(mapptr != 0)
{
out->buckets = (RDI_NameMapBucket*)rdi_data_from_dsec(p, mapptr->bucket_data_idx, sizeof(RDI_NameMapBucket), RDI_DataSectionTag_NameMapBuckets, &out->bucket_count);
out->nodes = (RDI_NameMapNode*)rdi_data_from_dsec(p, mapptr->node_data_idx, sizeof(RDI_NameMapNode), RDI_DataSectionTag_NameMapNodes, &out->node_count);
}
}
RDI_PROC RDI_NameMapNode*
rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map,
RDI_U8 *str, RDI_U64 len){
rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map, RDI_U8 *str, RDI_U64 len)
{
RDI_NameMapNode *result = 0;
if (map->bucket_count > 0){
if(map->bucket_count > 0)
{
RDI_NameMapBucket *buckets = map->buckets;
RDI_U64 bucket_count = map->bucket_count;
RDI_U64 hash = rdi_hash(str, len);
RDI_U64 bucket_index = hash%bucket_count;
RDI_NameMapBucket *bucket = map->buckets + bucket_index;
RDI_NameMapNode *node = map->nodes + bucket->first_node;
RDI_NameMapNode *node_opl = node + bucket->node_count;
for (;node < node_opl; node += 1){
for(;node < node_opl; node += 1)
{
// extract a string from this node
RDI_U64 nlen = 0;
RDI_U8 *nstr = rdi_string_from_idx(p, node->string_idx, &nlen);
// compare this to the needle string
RDI_S32 match = 0;
if (nlen == len){
if(nlen == len)
{
RDI_U8 *a = str;
RDI_U8 *aopl = str + len;
RDI_U8 *b = nstr;
@@ -495,60 +508,64 @@ rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map,
}
// stop with a matching node in result
if (match){
if(match)
{
result = node;
break;
}
}
}
return(result);
return result;
}
RDI_PROC RDI_U32*
rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node,
RDI_U32 *n_out){
rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node, RDI_U32 *n_out)
{
RDI_U32 *result = 0;
*n_out = 0;
if (node != 0){
if (node->match_count == 1){
if(node != 0)
{
if(node->match_count == 1)
{
result = &node->match_idx_or_idx_run_first;
*n_out = 1;
}
else{
result = rdi_idx_run_from_first_count(p, node->match_idx_or_idx_run_first,
node->match_count, n_out);
else
{
result = rdi_idx_run_from_first_count(p, node->match_idx_or_idx_run_first, node->match_count, n_out);
}
}
return(result);
return result;
}
//- common helpers
//- procedures
RDI_PROC RDI_U64
rdi_first_voff_from_proc(RDI_Parsed *p, RDI_U32 proc_id){
rdi_first_voff_from_proc(RDI_Parsed *p, RDI_U32 proc_id)
{
RDI_U64 result = 0;
if (0 < proc_id && proc_id < p->procedures_count){
if(0 < proc_id && proc_id < p->procedures_count)
{
RDI_Procedure *proc = p->procedures + proc_id;
RDI_U32 scope_id = proc->root_scope_idx;
if (0 < scope_id && scope_id < p->scopes_count){
if(0 < scope_id && scope_id < p->scopes_count)
{
RDI_Scope *scope = p->scopes + scope_id;
if (scope->voff_range_first < scope->voff_range_opl &&
scope->voff_range_first < p->scope_voffs_count){
if(scope->voff_range_first < scope->voff_range_opl && scope->voff_range_first < p->scope_voffs_count)
{
result = p->scope_voffs[scope->voff_range_first];
}
}
}
return(result);
return result;
}
////////////////////////////////
//~ RADDBG Parsing Helpers
//~ Parser Helpers
RDI_PROC void*
rdi_data_from_dsec(RDI_Parsed *parsed, RDI_U32 idx, RDI_U32 item_size,
RDI_DataSectionTag expected_tag,
RDI_U64 *count_out)
rdi_data_from_dsec(RDI_Parsed *parsed, RDI_U32 idx, RDI_U32 item_size, RDI_DataSectionTag expected_tag, RDI_U64 *count_out)
{
void *result = 0;
RDI_U32 count_result = 0;
@@ -566,5 +583,5 @@ rdi_data_from_dsec(RDI_Parsed *parsed, RDI_U32 idx, RDI_U32 item_size,
}
}
*count_out = count_result;
return(result);
return result;
}
+92 -102
View File
@@ -1,23 +1,41 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef RDI_PARSE_H
#define RDI_PARSE_H
////////////////////////////////////////////////////////////////
//~ RAD Debug Info, (R)AD(D)BG(I) Format Parsing Library
//
// Defines helper types and functions for extracting data from
// RDI files.
////////////////////////////////
//~ RADDBG Parsing Helpers
#ifndef RDI_FORMAT_PARSE_H
#define RDI_FORMAT_PARSE_H
typedef struct RDI_Parsed{
// raw data & data sections (part 1)
////////////////////////////////////////////////////////////////
//~ Parsed Information Types
typedef enum RDI_ParseStatus
{
RDI_ParseStatus_Good = 0,
RDI_ParseStatus_HeaderDoesNotMatch = 1,
RDI_ParseStatus_UnsupportedVersionNumber = 2,
RDI_ParseStatus_InvalidDataSecionLayout = 3,
RDI_ParseStatus_MissingStringDataSection = 4,
RDI_ParseStatus_MissingStringTableSection = 5,
RDI_ParseStatus_MissingIndexRunSection = 6,
}
RDI_ParseStatus;
typedef struct RDI_Parsed RDI_Parsed;
struct RDI_Parsed
{
// raw data & primary data sections
RDI_U8 *raw_data;
RDI_U64 raw_data_size;
RDI_DataSection *dsecs;
RDI_U64 dsec_count;
RDI_U32 dsec_idx[RDI_DataSectionTag_PRIMARY_COUNT];
// primary data structures (part 2)
// handled by helper APIs
// parsed universal data structures (strings, index runs)
RDI_U8* string_data;
RDI_U64 string_data_size;
RDI_U32* string_offs;
@@ -25,16 +43,22 @@ typedef struct RDI_Parsed{
RDI_U32* idx_run_data;
RDI_U32 idx_run_count;
// directly readable by users
// (any of these may be empty and null even in a successful parse)
RDI_TopLevelInfo* top_level_info;
// extracted info & tables (any of these may be empty or null, even with a successful parse)
RDI_TopLevelInfo* top_level_info;
RDI_BinarySection* binary_sections;
RDI_U64 binary_sections_count;
RDI_FilePathNode* file_paths;
RDI_U64 file_paths_count;
RDI_SourceFile* source_files;
RDI_U64 source_files_count;
RDI_LineTable* line_tables;
RDI_U64 line_tables_count;
RDI_U64* line_info_voffs;
RDI_U64 line_info_voffs_count;
RDI_Line* line_info_lines;
RDI_U64 line_info_lines_count;
RDI_Column* line_info_columns;
RDI_U64 line_info_columns_count;
RDI_Unit* units;
RDI_U64 units_count;
RDI_VMapEntry* unit_vmap;
@@ -69,37 +93,26 @@ typedef struct RDI_Parsed{
RDI_U64 location_data_size;
RDI_NameMap* name_maps;
RDI_U64 name_maps_count;
// other helpers
RDI_NameMap* name_maps_by_kind[RDI_NameMapKind_COUNT];
} RDI_Parsed;
};
typedef enum{
RDI_ParseStatus_Good = 0,
RDI_ParseStatus_HeaderDoesNotMatch = 1,
RDI_ParseStatus_UnsupportedVersionNumber = 2,
RDI_ParseStatus_InvalidDataSecionLayout = 3,
RDI_ParseStatus_MissingStringDataSection = 4,
RDI_ParseStatus_MissingStringTableSection = 5,
RDI_ParseStatus_MissingIndexRunSection = 6,
} RDI_ParseStatus;
typedef struct RDI_ParsedLineInfo{
typedef struct RDI_ParsedLineTable RDI_ParsedLineTable;
struct RDI_ParsedLineTable
{
// NOTE: Mapping VOFF -> LINE_INFO
//
// * [ voff[i], voff[i + 1] ) forms the voff range
// * for the line info at lines[i] (and cols[i] if i < col_count)
RDI_U64* voffs; // [count + 1] sorted
RDI_Line* lines; // [count]
RDI_Column* cols; // [col_count]
RDI_U64 count;
RDI_U64 col_count;
} RDI_ParsedLineInfo;
};
typedef struct RDI_ParsedLineMap{
typedef struct RDI_ParsedLineMap RDI_ParsedLineMap;
struct RDI_ParsedLineMap
{
// NOTE: Mapping LINE_NUMBER -> VOFFs
//
// * nums[i] gives a line number
@@ -108,21 +121,21 @@ typedef struct RDI_ParsedLineMap{
// * to find all associated voffs for the line number nums[i] :
// * let k span over the range [ ranges[i], ranges[i + 1] )
// * voffs[k] gives the associated voffs
RDI_U32* nums; // [count] sorted
RDI_U32* ranges; // [count + 1]
RDI_U64* voffs; // [voff_count]
RDI_U64 count;
RDI_U64 voff_count;
} RDI_ParsedLineMap;
};
typedef struct RDI_ParsedNameMap{
typedef struct RDI_ParsedNameMap RDI_ParsedNameMap;
struct RDI_ParsedNameMap
{
RDI_NameMapBucket *buckets;
RDI_NameMapNode *nodes;
RDI_U64 bucket_count;
RDI_U64 node_count;
} RDI_ParsedNameMap;
};
////////////////////////////////
//~ Global Nils
@@ -132,6 +145,9 @@ static RDI_TopLevelInfo rdi_top_level_info_nil = {0};
static RDI_BinarySection rdi_binary_section_nil = {0};
static RDI_FilePathNode rdi_file_path_node_nil = {0};
static RDI_SourceFile rdi_source_file_nil = {0};
static RDI_LineTable rdi_line_table_nil = {0};
static RDI_Line rdi_line_nil = {0};
static RDI_Column rdi_column_nil = {0};
static RDI_Unit rdi_unit_nil = {0};
static RDI_VMapEntry rdi_vmap_entry_nil = {0};
static RDI_TypeNode rdi_type_node_nil = {0};
@@ -148,76 +164,50 @@ static RDI_Local rdi_local_nil = {0};
#endif
////////////////////////////////
//~ RADDBG Parse API
RDI_PROC RDI_ParseStatus
rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out);
RDI_PROC RDI_U64
rdi_decompressed_size_from_parsed(RDI_Parsed *rdi);
RDI_PROC RDI_U8*
rdi_string_from_idx(RDI_Parsed *parsed, RDI_U32 idx, RDI_U64 *len_out);
RDI_PROC RDI_U32*
rdi_idx_run_from_first_count(RDI_Parsed *parsed, RDI_U32 first, RDI_U32 raw_count,
RDI_U32 *n_out);
//- table lookups
#define rdi_element_from_idx(parsed, name, idx) ((0 <= (idx) && (idx) < (parsed)->name##_count) ? &(parsed)->name[idx] : (parsed)->name ? &(parsed)->name[0] : 0)
//- line info
RDI_PROC void
rdi_line_info_from_unit(RDI_Parsed *p, RDI_Unit *unit, RDI_ParsedLineInfo *out);
RDI_PROC RDI_U64
rdi_line_info_idx_from_voff(RDI_ParsedLineInfo *line_info, RDI_U64 voff);
RDI_PROC void
rdi_line_map_from_source_file(RDI_Parsed *p, RDI_SourceFile *srcfile,
RDI_ParsedLineMap *out);
RDI_PROC RDI_U64*
rdi_line_voffs_from_num(RDI_ParsedLineMap *map, RDI_U32 linenum, RDI_U32 *n_out);
//- vmaps
RDI_PROC RDI_U64
rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U32 vmap_count, RDI_U64 voff);
//- name maps
RDI_PROC RDI_NameMap*
rdi_name_map_from_kind(RDI_Parsed *p, RDI_NameMapKind kind);
RDI_PROC void
rdi_name_map_parse(RDI_Parsed* p, RDI_NameMap *mapptr, RDI_ParsedNameMap *out);
RDI_PROC RDI_NameMapNode*
rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map,
RDI_U8 *str, RDI_U64 len);
RDI_PROC RDI_U32*
rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node, RDI_U32 *n_out);
//- common helpers
RDI_PROC RDI_U64
rdi_first_voff_from_proc(RDI_Parsed *p, RDI_U32 proc_id);
//~ Top-Level Parsing API
RDI_PROC RDI_ParseStatus rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out);
////////////////////////////////
//~ RADDBG Parsing Helpers
//~ Parsed Info Extraction Helpers
//- element extractor
#define rdi_element_from_idx(parsed, name, idx) ((0 <= (idx) && (idx) < (parsed)->name##_count) ? &(parsed)->name[idx] : (parsed)->name ? &(parsed)->name[0] : 0)
//- top-level info
RDI_PROC RDI_U64 rdi_decompressed_size_from_parsed(RDI_Parsed *rdi);
//- strings
RDI_PROC RDI_U8 *rdi_string_from_idx(RDI_Parsed *parsed, RDI_U32 idx, RDI_U64 *len_out);
//- index runs
RDI_PROC RDI_U32 *rdi_idx_run_from_first_count(RDI_Parsed *parsed, RDI_U32 first, RDI_U32 raw_count, RDI_U32 *n_out);
//- line info
RDI_PROC void rdi_parsed_from_line_table(RDI_Parsed *p, RDI_LineTable *line_table, RDI_ParsedLineTable *out);
RDI_PROC RDI_U64 rdi_line_info_idx_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff);
RDI_PROC void rdi_line_map_from_source_file(RDI_Parsed *p, RDI_SourceFile *srcfile, RDI_ParsedLineMap *out);
RDI_PROC RDI_U64 *rdi_line_voffs_from_num(RDI_ParsedLineMap *map, RDI_U32 linenum, RDI_U32 *n_out);
//- vmap lookups
RDI_PROC RDI_U64 rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U32 vmap_count, RDI_U64 voff);
//- name maps
RDI_PROC RDI_NameMap *rdi_name_map_from_kind(RDI_Parsed *p, RDI_NameMapKind kind);
RDI_PROC void rdi_name_map_parse(RDI_Parsed* p, RDI_NameMap *mapptr, RDI_ParsedNameMap *out);
RDI_PROC RDI_NameMapNode *rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map, RDI_U8 *str, RDI_U64 len);
RDI_PROC RDI_U32 *rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node, RDI_U32 *n_out);
//- procedures
RDI_PROC RDI_U64 rdi_first_voff_from_proc(RDI_Parsed *p, RDI_U32 proc_id);
////////////////////////////////
//~ Parser Helpers
#define rdi_parse__min(a,b) (((a)<(b))?(a):(b))
#define rdi_parse__extract_primary(p,outptr,outn,pritag) \
( (*(void**)&(outptr)) = \
rdi_data_from_dsec((p),(p)->dsec_idx[pritag],sizeof(*(outptr)),(pritag),(outn)) )
RDI_PROC void *rdi_data_from_dsec(RDI_Parsed *p, RDI_U32 idx, RDI_U32 item_size, RDI_DataSectionTag expected_tag, RDI_U64 *n_out);
RDI_PROC void*
rdi_data_from_dsec(RDI_Parsed *p, RDI_U32 idx, RDI_U32 item_size,
RDI_DataSectionTag expected_tag, RDI_U64 *n_out);
#define rdi_parse__min(a,b) (((a)<(b))?(a):(b))
#endif // RDI_PARSE_H
#endif // RDI_FORMAT_PARSE_H