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-13 15:18:28 -07:00
parent f7ce1b73bc
commit 44868c0e85
17 changed files with 1355 additions and 705 deletions
+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