mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-15 08:32:22 -07:00
571 lines
19 KiB
C
571 lines
19 KiB
C
// Copyright (c) 2024 Epic Games Tools
|
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
|
|
////////////////////////////////
|
|
//~ RADDBG Parse API
|
|
|
|
RDI_PROC RDI_ParseStatus
|
|
rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out)
|
|
{
|
|
RDI_ParseStatus result = RDI_ParseStatus_Good;
|
|
|
|
// out header
|
|
RDI_Header *hdr = 0;
|
|
{
|
|
if (sizeof(*hdr) <= size){
|
|
hdr = (RDI_Header*)data;
|
|
}
|
|
|
|
// (errors)
|
|
if (hdr == 0 || hdr->magic != RDI_MAGIC_CONSTANT){
|
|
hdr = 0;
|
|
result = RDI_ParseStatus_HeaderDoesNotMatch;
|
|
}
|
|
if (hdr != 0 && hdr->encoding_version != 1){
|
|
hdr = 0;
|
|
result = RDI_ParseStatus_UnsupportedVersionNumber;
|
|
}
|
|
}
|
|
|
|
// out data sections
|
|
RDI_DataSection *dsecs = 0;
|
|
RDI_U32 dsec_count = 0;
|
|
if (hdr != 0){
|
|
RDI_U64 opl = (RDI_U64)hdr->data_section_off + (RDI_U64)hdr->data_section_count*sizeof(*dsecs);
|
|
if (opl <= size){
|
|
dsecs = (RDI_DataSection*)(data + hdr->data_section_off);
|
|
dsec_count = hdr->data_section_count;
|
|
}
|
|
|
|
// (errors)
|
|
if (dsecs == 0){
|
|
result = RDI_ParseStatus_InvalidDataSecionLayout;
|
|
}
|
|
}
|
|
|
|
// extract primary data section indexes
|
|
RDI_U32 dsec_idx[RDI_DataSectionTag_PRIMARY_COUNT] = {0};
|
|
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){
|
|
dsec_idx[sec_ptr->tag] = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// fill out data block (part 1)
|
|
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){
|
|
out->dsec_idx[i] = dsec_idx[i];
|
|
}
|
|
}
|
|
|
|
// out string table
|
|
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);
|
|
|
|
RDI_U64 table_entry_count = 0;
|
|
rdi_parse__extract_primary(out, string_offs, &table_entry_count,
|
|
RDI_DataSectionTag_StringTable);
|
|
if (table_entry_count > 0){
|
|
string_count = table_entry_count - 1;
|
|
}
|
|
|
|
// (errors)
|
|
if (string_data == 0){
|
|
result = RDI_ParseStatus_MissingStringDataSection;
|
|
}
|
|
else if (string_offs == 0){
|
|
result = RDI_ParseStatus_MissingStringTableSection;
|
|
}
|
|
}
|
|
|
|
// out index runs
|
|
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){
|
|
result = RDI_ParseStatus_MissingIndexRunSection;
|
|
}
|
|
}
|
|
|
|
if (result == RDI_ParseStatus_Good){
|
|
// fill out primary data structures (part 2)
|
|
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;
|
|
rdi_parse__extract_primary(out, tli, &dummy, RDI_DataSectionTag_TopLevelInfo);
|
|
if (dummy != 1){
|
|
tli = 0;
|
|
}
|
|
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->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){
|
|
if (out->name_maps_by_kind[name_map_ptr->kind] == 0){
|
|
out->name_maps_by_kind[name_map_ptr->kind] = name_map_ptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if !defined(RDI_DISABLE_NILS)
|
|
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; }
|
|
if(out->units == 0) { out->units = &rdi_unit_nil; out->units_count = 1; }
|
|
if(out->unit_vmap == 0) { out->unit_vmap = &rdi_vmap_entry_nil; out->unit_vmap_count = 1; }
|
|
if(out->type_nodes == 0) { out->type_nodes = &rdi_type_node_nil; out->type_nodes_count = 1; }
|
|
if(out->udts == 0) { out->udts = &rdi_udt_nil; out->udts_count = 1; }
|
|
if(out->members == 0) { out->members = &rdi_member_nil; out->members_count = 1; }
|
|
if(out->enum_members == 0) { out->enum_members = &rdi_enum_member_nil; out->enum_members_count = 1; }
|
|
if(out->global_variables == 0) { out->global_variables = &rdi_global_variable_nil; out->global_variables_count = 1; }
|
|
if(out->global_vmap == 0) { out->global_vmap = &rdi_vmap_entry_nil; out->global_vmap_count = 1; }
|
|
if(out->thread_variables == 0) { out->thread_variables = &rdi_thread_variable_nil; out->thread_variables_count = 1; }
|
|
if(out->procedures == 0) { out->procedures = &rdi_procedure_nil; out->procedures_count = 1; }
|
|
if(out->scopes == 0) { out->scopes = &rdi_scope_nil; out->scopes_count = 1; }
|
|
if(out->scope_voffs == 0) { out->scope_voffs = &rdi_voff_nil; out->scope_voffs_count = 1; }
|
|
if(out->scope_vmap == 0) { out->scope_vmap = &rdi_vmap_entry_nil; out->scope_vmap_count = 1; }
|
|
if(out->locals == 0) { out->locals = &rdi_local_nil; out->locals_count = 1; }
|
|
if(out->location_blocks == 0) { out->location_blocks = &rdi_location_block_nil; out->location_blocks_count = 1; }
|
|
#endif
|
|
|
|
return(result);
|
|
}
|
|
|
|
RDI_PROC RDI_U64
|
|
rdi_decompressed_size_from_parsed(RDI_Parsed *rdi)
|
|
{
|
|
RDI_U64 decompressed_size = rdi->raw_data_size;
|
|
for(RDI_U64 dsec_idx = 0; dsec_idx < rdi->dsec_count; dsec_idx += 1)
|
|
{
|
|
decompressed_size += (rdi->dsecs[dsec_idx].unpacked_size - rdi->dsecs[dsec_idx].encoded_size);
|
|
}
|
|
return decompressed_size;
|
|
}
|
|
|
|
RDI_PROC RDI_U8*
|
|
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){
|
|
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);
|
|
RDI_U32 off = rdi_parse__min(off_raw, opl);
|
|
result = parsed->string_data + off;
|
|
len_result = opl - off;
|
|
}
|
|
*len_out = len_result;
|
|
return(result);
|
|
}
|
|
|
|
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_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){
|
|
result = parsed->idx_run_data + first;
|
|
}
|
|
*n_out = opl - first;
|
|
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_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);
|
|
|
|
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;
|
|
}
|
|
|
|
RDI_PROC RDI_U64
|
|
rdi_line_info_idx_from_voff(RDI_ParsedLineInfo *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]){
|
|
// 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 (;;){
|
|
RDI_U32 mid = (first + opl)/2;
|
|
if (line_info->voffs[mid] < voff){
|
|
first = mid;
|
|
}
|
|
else if (line_info->voffs[mid] > voff){
|
|
opl = mid;
|
|
}
|
|
else{
|
|
first = mid;
|
|
break;
|
|
}
|
|
if (opl - first <= 1){
|
|
break;
|
|
}
|
|
}
|
|
result = (RDI_U64)first;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
RDI_PROC void
|
|
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_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_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_U32 count_a = (range_count > 0)?(range_count - 1):0;
|
|
RDI_U32 count_b = rdi_parse__min(count_a, num_count);
|
|
RDI_U32 count = rdi_parse__min(count_b, srcfile->line_map_count);
|
|
|
|
out->nums = nums;
|
|
out->ranges = ranges;
|
|
out->voffs = voffs;
|
|
out->count = count;
|
|
out->voff_count = voff_count;
|
|
}
|
|
|
|
RDI_PROC RDI_U64*
|
|
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){
|
|
// 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 (;;){
|
|
RDI_U32 mid = (first + opl)/2;
|
|
if (nums[mid] < linenum){
|
|
first = mid;
|
|
}
|
|
else if (nums[mid] > linenum){
|
|
opl = mid;
|
|
}
|
|
else{
|
|
first = mid;
|
|
break;
|
|
}
|
|
if (opl - first <= 1){
|
|
break;
|
|
}
|
|
}
|
|
closest_i = first;
|
|
}
|
|
|
|
// round up instead of down if possible
|
|
if (closest_i + 1 < map->count &&
|
|
map->nums[closest_i] < linenum){
|
|
closest_i += 1;
|
|
}
|
|
|
|
// set result if possible
|
|
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){
|
|
result = map->voffs + first;
|
|
*n_out = opl - first;
|
|
}
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
|
|
//- vmaps
|
|
|
|
RDI_PROC RDI_U64
|
|
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){
|
|
// 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 (;;){
|
|
RDI_U32 mid = (first + opl)/2;
|
|
if (vmap[mid].voff < voff){
|
|
first = mid;
|
|
}
|
|
else if (vmap[mid].voff > voff){
|
|
opl = mid;
|
|
}
|
|
else{
|
|
first = mid;
|
|
break;
|
|
}
|
|
if (opl - first <= 1){
|
|
break;
|
|
}
|
|
}
|
|
result = (RDI_U64)vmap[first].idx;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
//- name maps
|
|
|
|
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){
|
|
result = p->name_maps_by_kind[kind];
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
RDI_PROC void
|
|
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);
|
|
}
|
|
}
|
|
|
|
RDI_PROC RDI_NameMapNode*
|
|
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){
|
|
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){
|
|
// 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){
|
|
RDI_U8 *a = str;
|
|
RDI_U8 *aopl = str + len;
|
|
RDI_U8 *b = nstr;
|
|
for (;a < aopl && *a == *b; a += 1, b += 1);
|
|
match = (a == aopl);
|
|
}
|
|
|
|
// stop with a matching node in result
|
|
if (match){
|
|
result = node;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
RDI_PROC RDI_U32*
|
|
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){
|
|
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);
|
|
}
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
//- common helpers
|
|
|
|
RDI_PROC RDI_U64
|
|
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){
|
|
RDI_Procedure *proc = p->procedures + proc_id;
|
|
RDI_U32 scope_id = proc->root_scope_idx;
|
|
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){
|
|
result = p->scope_voffs[scope->voff_range_first];
|
|
}
|
|
}
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
////////////////////////////////
|
|
//~ RADDBG Parsing 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)
|
|
{
|
|
void *result = 0;
|
|
RDI_U32 count_result = 0;
|
|
if(0 < idx && idx < parsed->dsec_count)
|
|
{
|
|
RDI_DataSection *ds = parsed->dsecs + idx;
|
|
if(ds->tag == expected_tag)
|
|
{
|
|
RDI_U64 encoded_opl = ds->off + ds->encoded_size;
|
|
if(encoded_opl <= parsed->raw_data_size)
|
|
{
|
|
count_result = ds->unpacked_size/item_size;
|
|
result = (parsed->raw_data + ds->off);
|
|
}
|
|
}
|
|
}
|
|
*count_out = count_result;
|
|
return(result);
|
|
}
|