From c3c1906d43fb72a50c3339aba356a55b17ef57ce Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 15 Feb 2024 15:44:24 -0800 Subject: [PATCH] first pass over raddbgi make baking phase rewrite/cleanup pass, getting off of old cons API --- project.4coder | 2 +- src/lib_raddbgi_make/raddbgi_make.c | 897 ++++++++++++++++--- src/lib_raddbgi_make/raddbgi_make.h | 237 ++++- src/raddbgi_from_pdb/raddbgi_from_pdb.c | 111 ++- src/raddbgi_from_pdb/raddbgi_from_pdb.h | 35 +- src/raddbgi_from_pdb/raddbgi_from_pdb_main.c | 89 +- 6 files changed, 1141 insertions(+), 230 deletions(-) diff --git a/project.4coder b/project.4coder index 21a2732d..afc8e60c 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { .rjf_f1 = { - .win = "build raddbg telemetry", + .win = "build raddbgi_from_pdb telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, diff --git a/src/lib_raddbgi_make/raddbgi_make.c b/src/lib_raddbgi_make/raddbgi_make.c index 6e092c64..53926748 100644 --- a/src/lib_raddbgi_make/raddbgi_make.c +++ b/src/lib_raddbgi_make/raddbgi_make.c @@ -44,31 +44,34 @@ RDI_PROC RDIM_Arena * rdim_arena_alloc_fallback(void) { RDIM_Arena *arena = 0; + // TODO(rjf) return arena; } RDI_PROC void rdim_arena_release_fallback(RDIM_Arena *arena) { - + // TODO(rjf) } RDI_PROC RDI_U64 rdim_arena_pos_fallback(RDIM_Arena *arena) { + // TODO(rjf) return 0; } RDI_PROC void * rdim_arena_push_fallback(RDIM_Arena *arena, RDI_U64 size) { + // TODO(rjf) return 0; } RDI_PROC void rdim_arena_pop_to_fallback(RDIM_Arena *arena, RDI_U64 pos) { - + // TODO(rjf) } #endif @@ -205,6 +208,19 @@ rdim_str8_list_push(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 stri list->RDIM_String8List_TotalSizeMember += string.RDIM_String8_SizeMember; } +RDI_PROC void +rdim_str8_list_push_align(RDIM_Arena *arena, RDIM_String8List *list, RDI_U64 align) +{ + RDI_U64 total_size_pre_align = list->total_size; + RDI_U64 total_size_post_align = (total_size_pre_align + (align-1))&(~(align-1)); + RDI_U64 needed_size = total_size_post_align - total_size_pre_align; + if(needed_size != 0) + { + RDI_U8 *padding = rdim_push_array(arena, RDI_U8, needed_size); + rdim_str8_list_push(arena, list, rdim_str8(padding, needed_size)); + } +} + RDI_PROC RDIM_String8 rdim_str8_list_join(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 sep) { @@ -236,7 +252,7 @@ rdim_str8_list_join(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 sep) //- rjf: sortable range sorting -RDI_PROC RDIM_SortKey* +RDI_PROC RDIM_SortKey * rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count) { // This sort is designed to take advantage of lots of pre-existing sorted ranges. @@ -387,7 +403,8 @@ rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count) #if 0 // assert sortedness - for(RDI_U64 i = 1; i < count; i += 1){ + for(RDI_U64 i = 1; i < count; i += 1) + { rdim_assert(result[i - 1].key <= result[i].key); } #endif @@ -396,9 +413,6 @@ rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count) return result; } -//////////////////////////////// -//~ rjf: Auxiliary Data Structure Functions - //- rjf: rng1u64 list RDI_PROC void @@ -414,104 +428,6 @@ rdim_rng1u64_list_push(RDIM_Arena *arena, RDIM_Rng1U64List *list, RDIM_Rng1U64 r } } -//- rjf: u64 -> ptr map - -RDI_PROC void -rdim_u64toptr_map_init(RDIM_Arena *arena, RDIM_U64ToPtrMap *map, RDI_U64 bucket_count) -{ - rdim_assert(IsPow2OrZero(bucket_count) && bucket_count > 0); - map->buckets = rdim_push_array(arena, RDIM_U64ToPtrNode*, bucket_count); - map->buckets_count = bucket_count; -} - -RDI_PROC void -rdim_u64toptr_map_lookup(RDIM_U64ToPtrMap *map, RDI_U64 key, RDI_U64 hash, RDIM_U64ToPtrLookup *lookup_out) -{ - RDI_U64 bucket_idx = hash&(map->buckets_count - 1); - RDIM_U64ToPtrNode *check_node = map->buckets[bucket_idx]; - for(;check_node != 0; check_node = check_node->next){ - for(RDI_U32 k = 0; k < ArrayCount(check_node->key); k += 1){ - if(check_node->ptr[k] == 0){ - lookup_out->fill_node = check_node; - lookup_out->fill_k = k; - break; - } - else if(check_node->key[k] == key){ - lookup_out->match = check_node->ptr[k]; - break; - } - } - } -} - -RDI_PROC void -rdim_u64toptr_map_insert(RDIM_Arena *arena, RDIM_U64ToPtrMap *map, RDI_U64 key, RDI_U64 hash, RDIM_U64ToPtrLookup *lookup, void *ptr) -{ - if(lookup->fill_node != 0) - { - RDIM_U64ToPtrNode *node = lookup->fill_node; - RDI_U32 k = lookup->fill_k; - node->key[k] = key; - node->ptr[k] = ptr; - } - else - { - RDI_U64 bucket_idx = hash&(map->buckets_count - 1); - - RDIM_U64ToPtrNode *node = rdim_push_array(arena, RDIM_U64ToPtrNode, 1); - SLLStackPush(map->buckets[bucket_idx], node); - node->key[0] = key; - node->ptr[0] = ptr; - - lookup->fill_node = node; - lookup->fill_k = 0; - - map->pair_count += 1; - map->bucket_collision_count += (node->next != 0); - } -} - -//- rjf: string8 -> ptr map - -RDI_PROC void -rdim_str8toptr_map_init(RDIM_Arena *arena, RDIM_Str8ToPtrMap *map, RDI_U64 bucket_count) -{ - map->buckets_count = bucket_count; - map->buckets = rdim_push_array(arena, RDIM_Str8ToPtrNode*, map->buckets_count); -} - -RDI_PROC void* -rdim_str8toptr_map_lookup(RDIM_Str8ToPtrMap *map, RDIM_String8 key, RDI_U64 hash) -{ - void *result = 0; - RDI_U64 bucket_idx = hash%map->buckets_count; - for(RDIM_Str8ToPtrNode *node = map->buckets[bucket_idx]; - node != 0; - node = node->next) - { - if(node->hash == hash && rdim_str8_match(node->key, key, 0)) - { - result = node->ptr; - break; - } - } - return result; -} - -RDI_PROC void -rdim_str8toptr_map_insert(RDIM_Arena *arena, RDIM_Str8ToPtrMap *map, RDIM_String8 key, RDI_U64 hash, void *ptr) -{ - RDI_U64 bucket_idx = hash%map->buckets_count; - RDIM_Str8ToPtrNode *node = rdim_push_array(arena, RDIM_Str8ToPtrNode, 1); - SLLStackPush(map->buckets[bucket_idx], node); - - node->key = rdim_str8_copy(arena, key); - node->hash = hash; - node->ptr = ptr; - map->bucket_collision_count += (node->next != 0); - map->pair_count += 1; -} - //////////////////////////////// //~ rjf: Binary Section List Building @@ -546,6 +462,35 @@ rdim_unit_chunk_list_push(RDIM_Arena *arena, RDIM_UnitChunkList *list) return unit; } +RDI_PROC void +rdim_unit_chunk_list_push_array(RDIM_Arena *arena, RDIM_UnitChunkList *list, RDIM_UnitArray *array) +{ + RDIM_UnitChunkNode *n = rdim_push_array(arena, RDIM_UnitChunkNode, 1); + RDIM_SLLQueuePush(list->first, list->last, n); + n->count = array->count; + n->cap = array->count; + n->v = array->v; + list->total_count += n->count; + list->chunk_count += 1; +} + +RDI_PROC void +rdim_unit_chunk_list_concat_in_place(RDIM_UnitChunkList *dst, RDIM_UnitChunkList *to_push) +{ + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + RDI_PROC RDIM_LineSequence * rdim_line_sequence_list_push(RDIM_Arena *arena, RDIM_LineSequenceList *list) { @@ -591,6 +536,35 @@ rdim_type_chunk_list_push(RDIM_Arena *arena, RDIM_TypeChunkList *list, RDI_U64 c return result; } +RDI_PROC void +rdim_type_chunk_list_push_array(RDIM_Arena *arena, RDIM_TypeChunkList *list, RDIM_TypeArray *array) +{ + RDIM_TypeChunkNode *n = rdim_push_array(arena, RDIM_TypeChunkNode, 1); + RDIM_SLLQueuePush(list->first, list->last, n); + n->count = array->count; + n->cap = array->count; + n->v = array->v; + list->total_count += n->count; + list->chunk_count += 1; +} + +RDI_PROC void +rdim_type_chunk_list_concat_in_place(RDIM_TypeChunkList *dst, RDIM_TypeChunkList *to_push) +{ + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + RDI_PROC RDIM_UDT * rdim_udt_chunk_list_push(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDI_U64 cap) { @@ -609,6 +583,23 @@ rdim_udt_chunk_list_push(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDI_U64 cap return result; } +RDI_PROC void +rdim_udt_chunk_list_concat_in_place(RDIM_UDTChunkList *dst, RDIM_UDTChunkList *to_push) +{ + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + RDI_PROC RDIM_UDTMember * rdim_udt_push_member(RDIM_Arena *arena, RDIM_UDT *udt) { @@ -731,6 +722,23 @@ rdim_symbol_chunk_list_push(RDIM_Arena *arena, RDIM_SymbolChunkList *list, RDI_U return result; } +RDI_PROC void +rdim_symbol_chunk_list_concat_in_place(RDIM_SymbolChunkList *dst, RDIM_SymbolChunkList *to_push) +{ + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + //////////////////////////////// //~ rjf: Scope Info Building @@ -752,6 +760,23 @@ rdim_scope_chunk_list_push(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDI_U64 return result; } +RDI_PROC void +rdim_scope_chunk_list_concat_in_place(RDIM_ScopeChunkList *dst, RDIM_ScopeChunkList *to_push) +{ + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + RDI_PROC RDIM_Local * rdim_scope_push_local(RDIM_Arena *arena, RDIM_Scope *scope) { @@ -825,10 +850,672 @@ rdim_location_set_push_case(RDIM_Arena *arena, RDIM_LocationSet *locset, RDIM_Rn location_case->location = location; } +//////////////////////////////// +//~ rjf: Baking + +//- rjf: data section list building helpers + +RDI_PROC RDIM_BakeSection * +rdim_bake_section_list_push(RDIM_Arena *arena, RDIM_BakeSectionList *list) +{ + RDIM_BakeSectionNode *n = rdim_push_array(arena, RDIM_BakeSectionNode, 1); + RDIM_SLLQueuePush(list->first, list->last, n); + list->count += 1; + RDIM_BakeSection *result = &n->v; + return result; +} + +RDI_PROC RDIM_BakeSection * +rdim_bake_section_list_push_new(RDIM_Arena *arena, RDIM_BakeSectionList *list, void *data, RDI_U64 size, RDI_DataSectionTag tag) +{ + RDIM_BakeSection *section = rdim_bake_section_list_push(arena, list); + section->data = data; + section->size = size; + section->tag = tag; + return section; +} + +//- rjf: interned string building + +RDI_PROC RDI_U32 +rdim_bake_string(RDIM_Arena *arena, RDIM_BakeStringMap *map, RDIM_String8 string) +{ + RDI_U64 hash = rdi_hash(string.RDIM_String8_BaseMember, string.RDIM_String8_SizeMember); + RDI_U64 slot_idx = hash%map->slots_count; + + // rjf: find existing node + RDIM_BakeStringNode *node = 0; + for(RDIM_BakeStringNode *n = map->slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->hash == hash && rdim_str8_match(n->string, string, 0)) + { + node = n; + break; + } + } + + // rjf: no node -> make new node + if(node == 0) + { + node = rdim_push_array_no_zero(arena, RDIM_BakeStringNode, 1); + node->string = rdim_str8_copy(arena, string); + node->hash = hash; + node->idx = map->count; + map->count += 1; + RDIM_SLLQueuePush_N(map->order_first, map->order_last, node, order_next); + RDIM_SLLStackPush_N(map->slots[slot_idx], node, hash_next); + map->slot_collision_count += (node->hash_next != 0); + } + + // rjf: node -> index + RDI_U32 result = node->idx; + return result; +} + +//- rjf: interned index run building + +RDI_PROC RDI_U64 +rdim_hash_from_idx_run(RDI_U32 *idx_run, RDI_U32 count) +{ + RDI_U64 hash = 5381; + RDI_U32 *ptr = idx_run; + RDI_U32 *opl = idx_run + count; + for(;ptr < opl; ptr += 1) + { + hash = ((hash << 5) + hash) + (*ptr); + } + return hash; +} + +RDI_PROC RDI_U32 +rdim_bake_idx_run(RDIM_Arena *arena, RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count) +{ + RDI_U64 hash = rdim_hash_from_idx_run(idx_run, count); + RDI_U64 slot_idx = hash%map->slots_count; + + // rjf: find existing node + RDIM_BakeIdxRunNode *node = 0; + for(RDIM_BakeIdxRunNode *n = map->slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->hash == hash) + { + RDI_S32 is_match = 1; + RDI_U32 *n_idx = n->idx_run; + for(RDI_U32 i = 0; i < count; i += 1) + { + if(n_idx[i] != idx_run[i]) + { + is_match = 0; + break; + } + } + if(is_match) + { + node = n; + break; + } + } + } + + // rjf: no node -> make new node + if(node == 0) + { + node = rdim_push_array_no_zero(arena, RDIM_BakeIdxRunNode, 1); + RDI_U32 *idx_run_copy = rdim_push_array_no_zero(arena, RDI_U32, count); + for(RDI_U32 i = 0; i < count; i += 1) + { + idx_run_copy[i] = idx_run[i]; + } + node->idx_run = idx_run_copy; + node->hash = hash; + node->count = count; + node->first_idx = map->idx_count; + map->count += 1; + map->idx_count += count; + RDIM_SLLQueuePush_N(map->order_first, map->order_last, node, order_next); + RDIM_SLLStackPush_N(map->slots[slot_idx], node, hash_next); + map->slot_collision_count += (node->hash_next != 0); + } + + // rjf: node -> index + RDI_U32 result = node->first_idx; + return result; +} + +//- rjf: interned path/file building + +RDI_PROC RDIM_String8 +rdim_normal_string_from_bake_path_node(RDIM_Arena *arena, RDIM_BakePathNode *node) +{ + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + RDIM_String8List list = {0}; + for(RDIM_BakePathNode *n = node; n != 0; n = n->parent) + { + if(n->name.size != 0) + { + rdim_str8_list_push(scratch.arena, &list, n->name); + } + } + RDIM_String8 result = rdim_str8_list_join(arena, &list, rdim_str8_lit("/")); + { + RDI_U8 *ptr = result.str; + RDI_U8 *opl = result.str + result.size; + for(;ptr < opl; ptr += 1) + { + RDI_U8 c = *ptr; + if('A' <= c && c <= 'Z') { c += 'a' - 'A'; } + *ptr = c; + } + } + scratch_end(scratch); + return result; +} + +RDI_PROC RDIM_BakePathNode * +rdim_bake_path_node_from_string(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_String8 string) +{ + RDIM_BakePathNode *node = &tree->root; + RDI_U8 *ptr = string.str; + RDI_U8 *opl = string.str + string.size; + for(;ptr < opl;) + { + // rjf: skip past slashes + for(;ptr < opl && (*ptr == '/' || *ptr == '\\'); ptr += 1); + + // rjf: save beginning of non-slash range + RDI_U8 *range_first = ptr; + + // rjf: skip past non-slashes + for(;ptr < opl && !(*ptr == '/' || *ptr == '\\'); ptr += 1); + + // rjf: empty range -> continue + if(range_first >= ptr) + { + continue; + } + + // rjf: range -> sub-directory string + RDIM_String8 sub_dir = rdim_str8(range_first, (RDI_U64)(ptr-range_first)); + + // rjf: sub-directory string -> find child of node + RDIM_BakePathNode *sub_dir_node = 0; + for(RDIM_BakePathNode *child = node->first_child; child != 0; child = child->next_sibling) + { + if(rdim_str8_match(child->name, sub_dir, RDIM_StringMatchFlag_CaseInsensitive)) + { + sub_dir_node = child; + } + } + + // rjf: no child -> make one + if(sub_dir_node == 0) + { + sub_dir_node = rdim_push_array(arena, RDIM_BakePathNode, 1); + RDIM_SLLQueuePush_N(tree->first, tree->last, sub_dir_node, next_order); + sub_dir_node->parent = node; + RDIM_SLLQueuePush_N(node->first_child, node->last_child, sub_dir_node, next_sibling); + sub_dir_node->name = rdim_str8_copy(arena, sub_dir); + sub_dir_node->idx = tree->count; + tree->count += 1; + } + + // rjf: descend to child + node = sub_dir_node; + } + return node; +} + +RDI_PROC RDIM_BakeSrcNode * +rdim_bake_src_node_from_path_node(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_BakePathNode *path_node) +{ + RDIM_BakeSrcNode *src_node = path_node->src_file; + if(src_node == 0) + { + src_node = rdim_push_array(arena, RDIM_BakeSrcNode, 1); + path_node->src_file = src_node; + src_node->path_node = path_node; + src_node->normal_full_path = rdim_normal_string_from_bake_path_node(arena, path_node); + src_node->idx = tree->src_count; + tree->src_count += 1; + RDIM_SLLQueuePush(tree->src_first, tree->src_last, src_node); + } + return src_node; +} + +RDI_PROC RDI_U32 +rdim_bake_path(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_String8 string) +{ + RDIM_BakePathNode *path_node = rdim_bake_path_node_from_string(arena, tree, string); + return path_node->idx; +} + +//- rjf: main baking entry point + +RDI_PROC RDIM_String8List +rdim_bake(RDIM_Arena *arena, RDIM_BakeParams *params) +{ + RDIM_String8List blobs; + rdim_memzero_struct(&blobs); + + ////////////////////////////// + //- rjf: set up intermediate baking data structures + // + RDIM_BakeSectionList sections = {0}; + RDIM_BakeStringMap strings = {0}; + RDIM_BakeIdxRunMap idx_runs = {0}; + RDIM_BakePathTree path_tree = {0}; + { + rdim_bake_section_list_push_new(arena, §ions, 0, 0, RDI_DataSectionTag_NULL); + strings.slots_count = 65536; + strings.slots = rdim_push_array(arena, RDIM_BakeStringNode *, strings.slots_count); + idx_runs.slots_count = 65536; + idx_runs.slots = rdim_push_array(arena, RDIM_BakeIdxRunNode *, idx_runs.slots_count); + } + + ////////////////////////////// + //- rjf: build section for top-level-info + // + ProfScope("build section for top-level-info") + { + RDI_TopLevelInfo *dst_tli = rdim_push_array(arena, RDI_TopLevelInfo, 1); + RDIM_TopLevelInfo *src_tli = ¶ms->top_level_info; + dst_tli->architecture = src_tli->arch; + dst_tli->exe_name_string_idx = rdim_bake_string(arena, &strings, src_tli->exe_name); + dst_tli->exe_hash = src_tli->exe_hash; + dst_tli->voff_max = src_tli->voff_max; + rdim_bake_section_list_push_new(arena, §ions, dst_tli, sizeof(*dst_tli), RDI_DataSectionTag_TopLevelInfo); + } + + ////////////////////////////// + //- rjf: build section for binary sections + // + ProfScope("build section for binary sections") + { + RDIM_BinarySectionList *src_list = ¶ms->binary_sections; + RDI_BinarySection *dst_base = rdim_push_array(arena, RDI_BinarySection, src_list->count); + U64 dst_idx = 0; + for(RDIM_BinarySectionNode *src_n = src_list->first; src_n != 0; src_n = src_n->next, dst_idx += 1) + { + RDIM_BinarySection *src = &src_n->v; + RDI_BinarySection *dst = &dst_base[dst_idx]; + dst->name_string_idx = rdim_bake_string(arena, &strings, src->name); + dst->flags = src->flags; + dst->voff_first = src->voff_first; + dst->voff_opl = src->voff_opl; + dst->foff_first = src->foff_first; + dst->foff_opl = src->foff_opl; + } + rdim_bake_section_list_push_new(arena, §ions, dst_base, sizeof(*dst_base)*dst_idx, RDI_DataSectionTag_BinarySections); + } + + ////////////////////////////// + //- rjf: build sections for units + // + ProfScope("build sections for units") + { + RDIM_UnitChunkList *src_list = ¶ms->units; + RDI_Unit *dst_base = rdim_push_array(arena, RDI_Unit, src_list->total_count); + RDI_U64 dst_idx = 0; + for(RDIM_UnitChunkNode *src_n = src_list->first; src_n != 0; src_n = src_n->next) + { + for(RDI_U64 src_chunk_idx = 0; src_chunk_idx < src_n->count; src_chunk_idx += 1, dst_idx += 1) + { + RDIM_Unit *src = &src_n->v[src_chunk_idx]; + RDI_Unit *dst = &dst_base[dst_idx]; + + //////////////////////// + //- rjf: produce combined unit line info + // + RDI_U64 *unit_voffs = 0; + RDI_Line *unit_lines = 0; + RDI_U16 *unit_cols = 0; + RDI_U32 unit_line_count = 0; + { + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + + //- rjf: gather up all line info into two arrays: + // + // [1] keys: sortable array; pairs voffs with line info records; null records are sequence enders + // [2] recs: contains all the source coordinates for a range of voffs + // + typedef struct RDIM_LineRec RDIM_LineRec; + struct RDIM_LineRec + { + RDI_U32 file_id; + RDI_U32 line_num; + RDI_U16 col_first; + RDI_U16 col_opl; + }; + RDI_U64 line_count = 0; + RDI_U64 seq_count = 0; + for(RDIM_LineSequenceNode *seq_n = src->line_sequences.first; seq_n != 0; seq_n = seq_n->next) + { + seq_count += 1; + line_count += seq_n->v.line_count; + } + RDI_U64 key_count = line_count + seq_count; + RDIM_SortKey *line_keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, key_count); + RDIM_LineRec *line_recs = rdim_push_array_no_zero(scratch.arena, RDIM_LineRec, line_count); + { + RDIM_SortKey *key_ptr = line_keys; + RDIM_LineRec *rec_ptr = line_recs; + for(RDIM_LineSequenceNode *seq_n = src->line_sequences.first; seq_n != 0; seq_n = seq_n->next) + { + RDIM_LineSequence *seq = &seq_n->v; + RDIM_BakePathNode *src_path = rdim_bake_path_node_from_string(arena, &path_tree, seq->file_name); + RDIM_BakeSrcNode *src_file = rdim_bake_src_node_from_path_node(arena, &path_tree, src_path); + for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) + { + key_ptr->key = seq->voffs[line_idx]; + key_ptr->val = rec_ptr; + key_ptr += 1; + rec_ptr->file_id = src_file->idx; + rec_ptr->line_num = seq->line_nums[line_idx]; + if(seq->col_nums != 0) + { + rec_ptr->col_first = seq->col_nums[line_idx*2]; + rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; + } + rec_ptr += 1; + } + key_ptr->key = seq->voffs[seq->line_count]; + key_ptr->val = 0; + key_ptr += 1; + + RDIM_BakeLineMapFragment *fragment = rdim_push_array(arena, RDIM_BakeLineMapFragment, 1); + RDIM_SLLQueuePush(src_file->first_fragment, src_file->last_fragment, fragment); + fragment->seq = seq; + } + } + + //- rjf: sort + RDIM_SortKey *sorted_line_keys = rdim_sort_key_array(scratch.arena, line_keys, key_count); + + // TODO(rjf): do a pass over sorted keys to make sure duplicate keys + // are sorted with null record first, and no more than one null + // record and one non-null record + + //- rjf: arrange output + RDI_U64 *arranged_voffs = rdim_push_array_no_zero(arena, RDI_U64, key_count + 1); + RDI_Line *arranged_lines = rdim_push_array_no_zero(arena, RDI_Line, key_count); + for(RDI_U64 i = 0; i < key_count; i += 1) + { + arranged_voffs[i] = sorted_line_keys[i].key; + } + arranged_voffs[key_count] = ~0ull; + for(RDI_U64 i = 0; i < key_count; i += 1) + { + RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[i].val; + if(rec != 0) + { + arranged_lines[i].file_idx = rec->file_id; + arranged_lines[i].line_num = rec->line_num; + } + else + { + arranged_lines[i].file_idx = 0; + arranged_lines[i].line_num = 0; + } + } + + //- rjf: fill output + unit_voffs = arranged_voffs; + unit_lines = arranged_lines; + unit_cols = 0; + unit_line_count = key_count; + scratch_end(scratch); + } + + //////////////////////// + //- rjf: build line info sections + // + RDI_U32 line_info_voffs_data_idx = (RDI_U32)sections.count; + RDI_U32 line_info_data_idx = line_info_voffs_data_idx+1; + RDI_U32 line_info_col_data_idx = unit_cols ? line_info_voffs_data_idx+2 : 0; + rdim_bake_section_list_push_new(arena, §ions, unit_voffs, sizeof(RDI_U64)*(unit_line_count+1), RDI_DataSectionTag_LineInfoVoffs); + rdim_bake_section_list_push_new(arena, §ions, unit_lines, sizeof(RDI_Line)*unit_line_count, RDI_DataSectionTag_LineInfoData); + if(unit_cols != 0) + { + rdim_bake_section_list_push_new(arena, §ions, unit_cols, sizeof(RDI_Column)*unit_line_count, RDI_DataSectionTag_LineInfoColumns); + } + + //////////////////////// + //- rjf: fill output + // + dst->unit_name_string_idx = rdim_bake_string(arena, &strings, src->unit_name); + dst->compiler_name_string_idx = rdim_bake_string(arena, &strings, src->compiler_name); + dst->source_file_path_node = rdim_bake_path(arena, &path_tree, src->source_file); + dst->object_file_path_node = rdim_bake_path(arena, &path_tree, src->object_file); + dst->archive_file_path_node = rdim_bake_path(arena, &path_tree, src->archive_file); + dst->build_path_node = rdim_bake_path(arena, &path_tree, src->build_path); + dst->language = src->language; + dst->line_info_voffs_data_idx = line_info_voffs_data_idx; + dst->line_info_data_idx = line_info_data_idx; + dst->line_info_col_data_idx = line_info_col_data_idx; + } + } + rdim_bake_section_list_push_new(arena, §ions, dst_base, sizeof(*dst_base)*dst_idx, RDI_DataSectionTag_Units); + } + + ////////////////////////////// + //- rjf: build section for per-source-file line info + // + ProfScope("build section for per-source-file line info") + { + + } + + ////////////////////////////// + //- rjf: build section for unit vmap + // + ProfScope("build section for unit vmap") + { + + } + + ////////////////////////////// + //- rjf: build sections for type info + // + ProfScope("build sections for type info") + { + + } + + ////////////////////////////// + //- rjf: build sections for symbol info + // + ProfScope("build sections for type info") + { + + } + + ////////////////////////////// + //- rjf: build sections for name maps + // + ProfScope("build sections for name maps") + { + + } + + ////////////////////////////// + //- rjf: build sections for file paths + // + ProfScope("build sections for file paths") + { + + } + + ////////////////////////////// + //- rjf: build sections for source files + // + ProfScope("build sections for source files") + { + + } + + ////////////////////////////// + //- rjf: build sections for strings + // + ProfScope("build sections for strings") + { + + } + + ////////////////////////////// + //- rjf: build section for index runs + // + ProfScope("build section for index runs") + { + + } + + ////////////////////////////// + //- rjf: build blob strings for header & all sections + // + ProfScope("build blob strings for header & all sections") + { + // rjf: push empty header & data section table + RDI_Header *baked_rdi_header = rdim_push_array(arena, RDI_Header, 1); + RDI_DataSection *baked_rdi_sections = rdim_push_array(arena, RDI_DataSection, sections.count); + rdim_str8_list_push(arena, &blobs, rdim_str8_struct(baked_rdi_header)); + rdim_str8_list_push_align(arena, &blobs, 8); + U32 data_section_off = (U32)blobs.total_size; + rdim_str8_list_push(arena, &blobs, rdim_str8((RDI_U8 *)baked_rdi_sections, sizeof(RDI_DataSection)*sections.count)); + + // rjf: fill baked header + { + baked_rdi_header->magic = RDI_MAGIC_CONSTANT; + baked_rdi_header->encoding_version = RDI_ENCODING_VERSION; + baked_rdi_header->data_section_off = data_section_off; + baked_rdi_header->data_section_count = sections.count; + } + + // rjf: fill baked data section table + U64 dst_idx = 0; + for(RDIM_BakeSectionNode *src_n = sections.first; src_n != 0; src_n = src_n->next, dst_idx += 1) + { + RDIM_BakeSection *src = &src_n->v; + RDI_DataSection *dst = baked_rdi_sections + dst_idx; + U64 data_section_off = 0; + if(src->size != 0) + { + rdim_str8_list_push_align(arena, &blobs, 8); + data_section_off = blobs.total_size; + rdim_str8_list_push(arena, &blobs, rdim_str8((RDI_U8 *)src->data, src->size)); + } + dst->tag = src->tag; + dst->encoding = RDI_DataSectionEncoding_Unpacked; + dst->off = data_section_off; + dst->encoded_size = src->size; + dst->unpacked_size = src->size; + } + } + + return blobs; +} + #if 0 //////////////////////////////// //~ rjf: Loose Debug Info Construction (Anything -> Loose) Functions +//- rjf: u64 -> ptr map + +RDI_PROC void +rdim_u64toptr_map_init(RDIM_Arena *arena, RDIM_U64ToPtrMap *map, RDI_U64 bucket_count) +{ + rdim_assert(IsPow2OrZero(bucket_count) && bucket_count > 0); + map->buckets = rdim_push_array(arena, RDIM_U64ToPtrNode*, bucket_count); + map->buckets_count = bucket_count; +} + +RDI_PROC void +rdim_u64toptr_map_lookup(RDIM_U64ToPtrMap *map, RDI_U64 key, RDI_U64 hash, RDIM_U64ToPtrLookup *lookup_out) +{ + RDI_U64 bucket_idx = hash&(map->buckets_count - 1); + RDIM_U64ToPtrNode *check_node = map->buckets[bucket_idx]; + for(;check_node != 0; check_node = check_node->next){ + for(RDI_U32 k = 0; k < ArrayCount(check_node->key); k += 1){ + if(check_node->ptr[k] == 0){ + lookup_out->fill_node = check_node; + lookup_out->fill_k = k; + break; + } + else if(check_node->key[k] == key){ + lookup_out->match = check_node->ptr[k]; + break; + } + } + } +} + +RDI_PROC void +rdim_u64toptr_map_insert(RDIM_Arena *arena, RDIM_U64ToPtrMap *map, RDI_U64 key, RDI_U64 hash, RDIM_U64ToPtrLookup *lookup, void *ptr) +{ + if(lookup->fill_node != 0) + { + RDIM_U64ToPtrNode *node = lookup->fill_node; + RDI_U32 k = lookup->fill_k; + node->key[k] = key; + node->ptr[k] = ptr; + } + else + { + RDI_U64 bucket_idx = hash&(map->buckets_count - 1); + + RDIM_U64ToPtrNode *node = rdim_push_array(arena, RDIM_U64ToPtrNode, 1); + SLLStackPush(map->buckets[bucket_idx], node); + node->key[0] = key; + node->ptr[0] = ptr; + + lookup->fill_node = node; + lookup->fill_k = 0; + + map->pair_count += 1; + map->bucket_collision_count += (node->next != 0); + } +} + +//- rjf: string8 -> ptr map + +RDI_PROC void +rdim_str8toptr_map_init(RDIM_Arena *arena, RDIM_Str8ToPtrMap *map, RDI_U64 bucket_count) +{ + map->buckets_count = bucket_count; + map->buckets = rdim_push_array(arena, RDIM_Str8ToPtrNode*, map->buckets_count); +} + +RDI_PROC void* +rdim_str8toptr_map_lookup(RDIM_Str8ToPtrMap *map, RDIM_String8 key, RDI_U64 hash) +{ + void *result = 0; + RDI_U64 bucket_idx = hash%map->buckets_count; + for(RDIM_Str8ToPtrNode *node = map->buckets[bucket_idx]; + node != 0; + node = node->next) + { + if(node->hash == hash && rdim_str8_match(node->key, key, 0)) + { + result = node->ptr; + break; + } + } + return result; +} + +RDI_PROC void +rdim_str8toptr_map_insert(RDIM_Arena *arena, RDIM_Str8ToPtrMap *map, RDIM_String8 key, RDI_U64 hash, void *ptr) +{ + RDI_U64 bucket_idx = hash%map->buckets_count; + RDIM_Str8ToPtrNode *node = rdim_push_array(arena, RDIM_Str8ToPtrNode, 1); + SLLStackPush(map->buckets[bucket_idx], node); + + node->key = rdim_str8_copy(arena, key); + node->hash = hash; + node->ptr = ptr; + map->bucket_collision_count += (node->next != 0); + map->pair_count += 1; +} + //- rjf: root creation RDI_PROC RDIM_Root * diff --git a/src/lib_raddbgi_make/raddbgi_make.h b/src/lib_raddbgi_make/raddbgi_make.h index 8d64b762..3ce7351a 100644 --- a/src/lib_raddbgi_make/raddbgi_make.h +++ b/src/lib_raddbgi_make/raddbgi_make.h @@ -762,6 +762,162 @@ struct RDIM_NameMap RDI_U64 name_count; }; +//////////////////////////////// +//~ rjf: Baking Types + +//- rjf: bake parameters + +typedef struct RDIM_BakeParams RDIM_BakeParams; +struct RDIM_BakeParams +{ + RDIM_TopLevelInfo top_level_info; + RDIM_BinarySectionList binary_sections; + RDIM_UnitChunkList units; + RDIM_TypeChunkList types; + RDIM_SymbolChunkList global_variables; + RDIM_SymbolChunkList thread_variables; + RDIM_SymbolChunkList procedures; + RDIM_ScopeChunkList scopes; +}; + +//- rjf: data sections + +typedef struct RDIM_BakeSection RDIM_BakeSection; +struct RDIM_BakeSection +{ + void *data; + RDI_U64 size; + RDI_DataSectionTag tag; +}; + +typedef struct RDIM_BakeSectionNode RDIM_BakeSectionNode; +struct RDIM_BakeSectionNode +{ + RDIM_BakeSectionNode *next; + RDIM_BakeSection v; +}; + +typedef struct RDIM_BakeSectionList RDIM_BakeSectionList; +struct RDIM_BakeSectionList +{ + RDIM_BakeSectionNode *first; + RDIM_BakeSectionNode *last; + RDI_U64 count; +}; + +//- rjf: interned strings + +typedef struct RDIM_BakeStringNode RDIM_BakeStringNode; +struct RDIM_BakeStringNode +{ + RDIM_BakeStringNode *hash_next; + RDIM_BakeStringNode *order_next; + RDIM_String8 string; + RDI_U64 hash; + RDI_U32 idx; +}; + +typedef struct RDIM_BakeStringMap RDIM_BakeStringMap; +struct RDIM_BakeStringMap +{ + RDIM_BakeStringNode *order_first; + RDIM_BakeStringNode *order_last; + RDIM_BakeStringNode **slots; + RDI_U64 slots_count; + RDI_U64 slot_collision_count; + RDI_U32 count; +}; + +//- rjf: index runs + +typedef struct RDIM_BakeIdxRunNode RDIM_BakeIdxRunNode; +struct RDIM_BakeIdxRunNode +{ + RDIM_BakeIdxRunNode *hash_next; + RDIM_BakeIdxRunNode *order_next; + RDI_U32 *idx_run; + RDI_U64 hash; + RDI_U32 count; + RDI_U32 first_idx; +}; + +typedef struct RDIM_BakeIdxRunMap RDIM_BakeIdxRunMap; +struct RDIM_BakeIdxRunMap +{ + RDIM_BakeIdxRunNode *order_first; + RDIM_BakeIdxRunNode *order_last; + RDIM_BakeIdxRunNode **slots; + RDI_U64 slots_count; + RDI_U64 slot_collision_count; + RDI_U32 count; + RDI_U32 idx_count; +}; + +//- rjf: line info + +typedef struct RDIM_LineRec RDIM_LineRec; +struct RDIM_LineRec +{ + RDI_U32 file_id; + RDI_U32 line_num; + RDI_U16 col_first; + RDI_U16 col_opl; +}; + +//- rjf: source info & path tree + +typedef struct RDIM_BakePathNode RDIM_BakePathNode; +struct RDIM_BakePathNode +{ + RDIM_BakePathNode *next_order; + RDIM_BakePathNode *parent; + RDIM_BakePathNode *first_child; + RDIM_BakePathNode *last_child; + RDIM_BakePathNode *next_sibling; + RDIM_String8 name; + struct RDIM_BakeSrcNode *src_file; + RDI_U32 idx; +}; + +typedef struct RDIM_BakeLineMapFragment RDIM_BakeLineMapFragment; +struct RDIM_BakeLineMapFragment +{ + RDIM_BakeLineMapFragment *next; + RDIM_LineSequence *seq; +}; + +typedef struct RDIM_BakeSrcNode RDIM_BakeSrcNode; +struct RDIM_BakeSrcNode +{ + RDIM_BakeSrcNode *next; + RDIM_BakePathNode *path_node; + RDI_U32 idx; + RDIM_String8 normal_full_path; + + // rjf: line info attached to this src file + RDIM_BakeLineMapFragment *first_fragment; + RDIM_BakeLineMapFragment *last_fragment; + + // rjf: final baked version of this file's line map + RDI_U32 line_map_nums_data_idx; + RDI_U32 line_map_range_data_idx; + RDI_U32 line_map_count; + RDI_U32 line_map_voff_data_idx; +}; + +typedef struct RDIM_BakePathTree RDIM_BakePathTree; +struct RDIM_BakePathTree +{ + RDIM_BakePathNode *first; + RDIM_BakePathNode *last; + RDI_U32 count; + RDIM_BakePathNode root; + RDIM_BakeSrcNode *src_first; + RDIM_BakeSrcNode *src_last; + RDI_U32 src_count; +}; + +#if 0 //////////////////////////////// //~ rjf: Root Construction Bundle Types @@ -950,15 +1106,6 @@ struct RDIM_PathTree //- rjf: line info baking data structures -typedef struct RDIM_LineRec RDIM_LineRec; -struct RDIM_LineRec -{ - RDI_U32 file_id; - RDI_U32 line_num; - RDI_U16 col_first; - RDI_U16 col_opl; -}; - typedef struct RDIM_UnitLinesCombined RDIM_UnitLinesCombined; struct RDIM_UnitLinesCombined { @@ -1114,6 +1261,7 @@ struct RDIM_BakeCtx RDIM_IdxRuns idxs; RDIM_PathTree *tree; }; +#endif //////////////////////////////// //~ rjf: Basic Helpers @@ -1157,27 +1305,15 @@ RDI_PROC RDI_S32 rdim_str8_match(RDIM_String8 a, RDIM_String8 b, RDIM_StringMatc //- rjf: string lists RDI_PROC void rdim_str8_list_push(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 string); +RDI_PROC void rdim_str8_list_push_align(RDIM_Arena *arena, RDIM_String8List *list, RDI_U64 align); RDI_PROC RDIM_String8 rdim_str8_list_join(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 sep); //- rjf: sortable range sorting -RDI_PROC RDIM_SortKey* rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count); - -//////////////////////////////// -//~ rjf: Auxiliary Data Structure Functions +RDI_PROC RDIM_SortKey *rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count); //- rjf: rng1u64 list RDI_PROC void rdim_rng1u64_list_push(RDIM_Arena *arena, RDIM_Rng1U64List *list, RDIM_Rng1U64 r); -//- rjf: u64 -> ptr map -RDI_PROC void rdim_u64toptr_map_init(RDIM_Arena *arena, RDIM_U64ToPtrMap *map, RDI_U64 bucket_count); -RDI_PROC void rdim_u64toptr_map_lookup(RDIM_U64ToPtrMap *map, RDI_U64 key, RDI_U64 hash, RDIM_U64ToPtrLookup *lookup_out); -RDI_PROC void rdim_u64toptr_map_insert(RDIM_Arena *arena, RDIM_U64ToPtrMap *map, RDI_U64 key, RDI_U64 hash, RDIM_U64ToPtrLookup *lookup, void *ptr); - -//- rjf: string8 -> ptr map -RDI_PROC void rdim_str8toptr_map_init(RDIM_Arena *arena, RDIM_Str8ToPtrMap *map, RDI_U64 bucket_count); -RDI_PROC void*rdim_str8toptr_map_lookup(RDIM_Str8ToPtrMap *map, RDIM_String8 key, RDI_U64 hash); -RDI_PROC void rdim_str8toptr_map_insert(RDIM_Arena *arena, RDIM_Str8ToPtrMap *map, RDIM_String8 key, RDI_U64 hash, void *ptr); - //////////////////////////////// //~ rjf: Binary Section Info Building @@ -1187,6 +1323,8 @@ RDI_PROC RDIM_BinarySection *rdim_binary_section_list_push(RDIM_Arena *arena, RD //~ rjf: Unit Info Building RDI_PROC RDIM_Unit *rdim_unit_chunk_list_push(RDIM_Arena *arena, RDIM_UnitChunkList *list); +RDI_PROC void rdim_unit_chunk_list_push_array(RDIM_Arena *arena, RDIM_UnitChunkList *list, RDIM_UnitArray *array); +RDI_PROC void rdim_unit_chunk_list_concat_in_place(RDIM_UnitChunkList *dst, RDIM_UnitChunkList *to_push); RDI_PROC RDIM_LineSequence *rdim_line_sequence_list_push(RDIM_Arena *arena, RDIM_LineSequenceList *list); RDI_PROC RDIM_UnitArray rdim_unit_array_from_chunk_list(RDIM_Arena *arena, RDIM_UnitChunkList *list); @@ -1194,7 +1332,10 @@ RDI_PROC RDIM_UnitArray rdim_unit_array_from_chunk_list(RDIM_Arena *arena, RDIM_ //~ rjf: Type Info & UDT Building RDI_PROC RDIM_Type *rdim_type_chunk_list_push(RDIM_Arena *arena, RDIM_TypeChunkList *list, RDI_U64 cap); +RDI_PROC void rdim_type_chunk_list_push_array(RDIM_Arena *arena, RDIM_TypeChunkList *list, RDIM_TypeArray *array); +RDI_PROC void rdim_type_chunk_list_concat_in_place(RDIM_TypeChunkList *dst, RDIM_TypeChunkList *to_push); RDI_PROC RDIM_UDT *rdim_udt_chunk_list_push(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDI_U64 cap); +RDI_PROC void rdim_udt_chunk_list_concat_in_place(RDIM_UDTChunkList *dst, RDIM_UDTChunkList *to_push); RDI_PROC RDIM_UDTMember *rdim_udt_push_member(RDIM_Arena *arena, RDIM_UDT *udt); RDI_PROC RDIM_UDTEnumVal *rdim_udt_push_enum_val(RDIM_Arena *arena, RDIM_UDT *udt); @@ -1210,11 +1351,13 @@ RDI_PROC void rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_Ev //~ rjf: Symbol Info Building RDI_PROC RDIM_Symbol *rdim_symbol_chunk_list_push(RDIM_Arena *arena, RDIM_SymbolChunkList *list, RDI_U64 cap); +RDI_PROC void rdim_symbol_chunk_list_concat_in_place(RDIM_SymbolChunkList *dst, RDIM_SymbolChunkList *to_push); //////////////////////////////// //~ rjf: Scope Info Building RDI_PROC RDIM_Scope *rdim_scope_chunk_list_push(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDI_U64 cap); +RDI_PROC void rdim_scope_chunk_list_concat_in_place(RDIM_ScopeChunkList *dst, RDIM_ScopeChunkList *to_push); RDI_PROC RDIM_Local *rdim_scope_push_local(RDIM_Arena *arena, RDIM_Scope *scope); //////////////////////////////// @@ -1230,11 +1373,44 @@ RDI_PROC RDIM_Location *rdim_push_location_val_reg(RDIM_Arena *arena, RDI_U8 reg //- rjf: location sets RDI_PROC void rdim_location_set_push_case(RDIM_Arena *arena, RDIM_LocationSet *locset, RDIM_Rng1U64 voff_range, RDIM_Location *location); +//////////////////////////////// +//~ rjf: Baking + +//- rjf: data section list building helpers +RDI_PROC RDIM_BakeSection *rdim_bake_section_list_push(RDIM_Arena *arena, RDIM_BakeSectionList *list); +RDI_PROC RDIM_BakeSection *rdim_bake_section_list_push_new(RDIM_Arena *arena, RDIM_BakeSectionList *list, void *data, RDI_U64 size, RDI_DataSectionTag tag); + +//- rjf: interned string building +RDI_PROC RDI_U32 rdim_bake_string(RDIM_Arena *arena, RDIM_BakeStringMap *map, RDIM_String8 string); + +//- rjf: interned index run building +RDI_PROC RDI_U64 rdim_hash_from_idx_run(RDI_U32 *idx_run, RDI_U32 count); +RDI_PROC RDI_U32 rdim_bake_idx_run(RDIM_Arena *arena, RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count); + +//- rjf: interned path/file building +RDI_PROC RDIM_String8 rdim_normal_string_from_bake_path_node(RDIM_Arena *arena, RDIM_BakePathNode *node); +RDI_PROC RDIM_BakePathNode *rdim_bake_path_node_from_string(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_String8 string); +RDI_PROC RDIM_BakeSrcNode *rdim_bake_src_node_from_path_node(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_BakePathNode *path_node); +RDI_PROC RDI_U32 rdim_bake_path(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_String8 string); + +//- rjf: main baking entry point +RDI_PROC RDIM_String8List rdim_bake(RDIM_Arena *arena, RDIM_BakeParams *params); + #if 0 //////////////////////////////// //~ rjf: Loose Debug Info Construction (Anything -> Loose) Functions +//- rjf: u64 -> ptr map +RDI_PROC void rdim_u64toptr_map_init(RDIM_Arena *arena, RDIM_U64ToPtrMap *map, RDI_U64 bucket_count); +RDI_PROC void rdim_u64toptr_map_lookup(RDIM_U64ToPtrMap *map, RDI_U64 key, RDI_U64 hash, RDIM_U64ToPtrLookup *lookup_out); +RDI_PROC void rdim_u64toptr_map_insert(RDIM_Arena *arena, RDIM_U64ToPtrMap *map, RDI_U64 key, RDI_U64 hash, RDIM_U64ToPtrLookup *lookup, void *ptr); + +//- rjf: string8 -> ptr map +RDI_PROC void rdim_str8toptr_map_init(RDIM_Arena *arena, RDIM_Str8ToPtrMap *map, RDI_U64 bucket_count); +RDI_PROC void*rdim_str8toptr_map_lookup(RDIM_Str8ToPtrMap *map, RDIM_String8 key, RDI_U64 hash); +RDI_PROC void rdim_str8toptr_map_insert(RDIM_Arena *arena, RDIM_Str8ToPtrMap *map, RDIM_String8 key, RDI_U64 hash, void *ptr); + //- rjf: root creation RDI_PROC RDIM_Root* rdim_root_alloc(RDIM_RootParams *params); RDI_PROC void rdim_root_release(RDIM_Root *root); @@ -1334,14 +1510,13 @@ RDI_PROC RDI_U32 rdim_idx_run(RDIM_BakeCtx *bctx, RDI_U32 *idx_run, RDI_U32 coun RDI_PROC RDI_U32 rdim_dsection(RDIM_Arena *arena, RDIM_DSections *dss, void *data, RDI_U64 size, RDI_DataSectionTag tag); //- rjf: paths baking -RDI_PROC RDIM_String8 rdim_normal_string_from_path_node(RDIM_Arena *arena, RDIM_PathNode *node); -RDI_PROC void rdim_normal_string_from_path_node_build(RDIM_Arena *arena, RDIM_PathNode *node, RDIM_String8List *out); -RDI_PROC RDIM_PathNode* rdim_paths_new_node(RDIM_BakeCtx *bctx); -RDI_PROC RDIM_PathNode* rdim_paths_sub_path(RDIM_BakeCtx *bctx, RDIM_PathNode *dir, RDIM_String8 sub_dir); -RDI_PROC RDIM_PathNode* rdim_paths_node_from_path(RDIM_BakeCtx *bctx, RDIM_String8 path); -RDI_PROC RDI_U32 rdim_paths_idx_from_path(RDIM_BakeCtx *bctx, RDIM_String8 path); -RDI_PROC RDIM_SrcNode* rdim_paths_new_src_node(RDIM_BakeCtx *bctx); -RDI_PROC RDIM_SrcNode* rdim_paths_src_node_from_path_node(RDIM_BakeCtx *bctx, RDIM_PathNode *path_node); +RDI_PROC RDIM_String8 rdim_normal_string_from_path_node(RDIM_Arena *arena, RDIM_PathNode *node); +RDI_PROC RDIM_BakePathNode *rdim_bake_path_tree_push_path_node(RDIM_Arena *arena, RDIM_BakePathTree *tree); +RDI_PROC RDIM_BakePathNode *rdim_paths_sub_path(RDIM_BakeCtx *bctx, RDIM_PathNode *dir, RDIM_String8 sub_dir); +RDI_PROC RDIM_BakePathNode *rdim_paths_node_from_path(RDIM_BakeCtx *bctx, RDIM_String8 path); +RDI_PROC RDI_U32 rdim_paths_idx_from_path(RDIM_BakeCtx *bctx, RDIM_String8 path); +RDI_PROC RDIM_BakeSrcNode * rdim_paths_new_src_node(RDIM_BakeCtx *bctx); +RDI_PROC RDIM_BakeSrcNode * rdim_paths_src_node_from_path_node(RDIM_BakeCtx *bctx, RDIM_PathNode *path_node); //- rjf: per-unit line info baking RDI_PROC RDIM_UnitLinesCombined* rdim_unit_combine_lines(RDIM_Arena *arena, RDIM_BakeCtx *bctx, RDIM_LineSequenceNode *first_seq); diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.c b/src/raddbgi_from_pdb/raddbgi_from_pdb.c index b96ccaef..6a2ae202 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb.c +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb.c @@ -25,15 +25,16 @@ p2r_end_of_cplusplus_container_name(String8 str) } return(result); } -//////////////////////////////// -//~ rjf: Command Line -> Conversion Parameters -internal P2R_Params* -p2r_params_from_cmd_line(Arena *arena, CmdLine *cmdline) +//////////////////////////////// +//~ rjf: Command Line -> Conversion Inputs + +internal P2R_ConvertIn * +p2r_convert_in_from_cmd_line(Arena *arena, CmdLine *cmdline) { - P2R_Params *result = push_array(arena, P2R_Params, 1); + P2R_ConvertIn *result = push_array(arena, P2R_ConvertIn, 1); - // get input pdb + //- rjf: get input pdb { String8 input_name = cmd_line_string(cmdline, str8_lit("pdb")); if(input_name.size == 0) @@ -55,7 +56,7 @@ p2r_params_from_cmd_line(Arena *arena, CmdLine *cmdline) } } - // get input exe + //- rjf: get input exe { String8 input_name = cmd_line_string(cmdline, str8_lit("exe")); if(input_name.size > 0) @@ -73,12 +74,12 @@ p2r_params_from_cmd_line(Arena *arena, CmdLine *cmdline) } } - // get output name + //- rjf: get output name { result->output_name = cmd_line_string(cmdline, str8_lit("out")); } - // error options + //- rjf: error options if(cmd_line_has_flag(cmdline, str8_lit("hide_errors"))) { String8List vals = cmd_line_strings(cmdline, str8_lit("hide_errors")); @@ -116,7 +117,7 @@ p2r_params_from_cmd_line(Arena *arena, CmdLine *cmdline) } } - // dump options + //- rjf: dump options if(cmd_line_has_flag(cmdline, str8_lit("dump"))) { result->dump = 1; @@ -169,7 +170,7 @@ p2r_params_from_cmd_line(Arena *arena, CmdLine *cmdline) } } - return(result); + return result; } //////////////////////////////// @@ -3433,20 +3434,18 @@ p2r_link_name_find(P2R_LinkNameMap *map, U64 voff) //////////////////////////////// //~ rjf: Top-Level Conversion Entry Point -internal P2R_Out * -p2r_convert(Arena *arena, P2R_Params *params) +internal P2R_ConvertOut * +p2r_convert(Arena *arena, P2R_ConvertIn *in) { Temp scratch = scratch_begin(&arena, 1); - P2R_Out *out = push_array(arena, P2R_Out, 1); - out->good_parse = 1; ////////////////////////////////////////////////////////////// //- rjf: parse MSF structure // MSF_Parsed *msf = 0; - if(params->errors.node_count == 0) ProfScope("parse MSF structure") + if(in->input_pdb_data.size != 0) ProfScope("parse MSF structure") { - msf = msf_parsed_from_data(arena, params->input_pdb_data); + msf = msf_parsed_from_data(arena, in->input_pdb_data); } ////////////////////////////////////////////////////////////// @@ -3651,9 +3650,9 @@ p2r_convert(Arena *arena, P2R_Params *params) //- rjf: hash exe // U64 exe_hash = 0; - if(params->input_exe_data.size > 0) ProfScope("hash exe") + if(in->input_exe_data.size > 0) ProfScope("hash exe") { - exe_hash = rdi_hash(params->input_exe_data.str, params->input_exe_data.size); + exe_hash = rdi_hash(in->input_exe_data.str, in->input_exe_data.size); } ////////////////////////////////////////////////////////////// @@ -3708,7 +3707,7 @@ p2r_convert(Arena *arena, P2R_Params *params) RDIM_TopLevelInfo top_level_info = {0}; { top_level_info.arch = arch; - top_level_info.exe_name = params->input_exe_name; + top_level_info.exe_name = in->input_exe_name; top_level_info.exe_hash = exe_hash; top_level_info.voff_max = exe_voff_max; } @@ -3844,11 +3843,11 @@ p2r_convert(Arena *arena, P2R_Params *params) // U64 type_fwd_map_count = 0; CV_TypeId *type_fwd_map = 0; + CV_TypeId itype_first = 0; + CV_TypeId itype_opl = tpi_leaf->itype_opl; ProfScope("types pass 1: produce type forward resolution map") { - CV_TypeId itype_first = tpi_leaf->itype_first; - CV_TypeId itype_opl = tpi_leaf->itype_opl; - type_fwd_map_count = (U64)(itype_opl-itype_first); + type_fwd_map_count = (U64)itype_opl; type_fwd_map = push_array(arena, CV_TypeId, type_fwd_map_count); for(CV_TypeId itype = itype_first; itype < itype_opl; itype += 1) { @@ -3985,8 +3984,6 @@ p2r_convert(Arena *arena, P2R_Params *params) }; P2R_TypeIdRevisitTask *first_itype_revisit_task = 0; P2R_TypeIdRevisitTask *last_itype_revisit_task = 0; - CV_TypeId itype_first = tpi_leaf->itype_first; - CV_TypeId itype_opl = tpi_leaf->itype_opl; RDIM_TypeArray itype_types = {0}; // root type for per-TPI-itype RDIM_TypeChunkList extra_types = {0}; // extra supplementary types we build, which do not have any itypes ProfScope("types pass 2: construct all root/stub types from TPI") @@ -4384,8 +4381,6 @@ p2r_convert(Arena *arena, P2R_Params *params) ProfScope("types pass 3: attach cross-itype-relationship data to all types, build UDTs") { RDI_U64 udts_chunk_cap = 1024; - CV_TypeId itype_first = tpi_leaf->itype_first; - CV_TypeId itype_opl = tpi_leaf->itype_opl; #define p2r_type_ptr_from_itype(itype) ((itype_first <= (itype) && (itype) < itype_opl) ? (&itype_types.v[(type_fwd_map[(itype)-itype_first] ? type_fwd_map[(itype)-itype_first] : (itype))-itype_first]) : 0) for(P2R_TypeIdRevisitTask *task = first_itype_revisit_task; task != 0; task = task->next) { @@ -4483,7 +4478,7 @@ p2r_convert(Arena *arena, P2R_Params *params) //- rjf: arrays -> calculate array count based on direct type size // case RDI_TypeKind_Array: - if(dst_type->direct_type != 0) + if(dst_type->direct_type != 0 && dst_type->direct_type->byte_size != 0) { dst_type->count = dst_type->byte_size/dst_type->direct_type->byte_size; }break; @@ -5086,6 +5081,10 @@ p2r_convert(Arena *arena, P2R_Params *params) ////////////////////////////////////////////////////////////// //- rjf: produce symbols from all sym streams // + RDIM_SymbolChunkList all_procedures = {0}; + RDIM_SymbolChunkList all_global_variables = {0}; + RDIM_SymbolChunkList all_thread_variables = {0}; + RDIM_ScopeChunkList all_scopes = {0}; ProfScope("produce symbols from all sym streams") { #define p2r_type_ptr_from_itype(itype) ((itype_first <= (itype) && (itype) < itype_opl) ? (&itype_types.v[(type_fwd_map[(itype)-itype_first] ? type_fwd_map[(itype)-itype_first] : (itype))-itype_first]) : 0) @@ -5239,8 +5238,11 @@ p2r_convert(Arena *arena, P2R_Params *params) case CV_SymKind_END: { P2R_ScopeNode *n = top_scope_node; - SLLStackPop(top_scope_node); - SLLStackPush(free_scope_node, n); + if(n != 0) + { + SLLStackPop(top_scope_node); + SLLStackPush(free_scope_node, n); + } defrange_target = 0; defrange_target_is_param = 0; }break; @@ -5785,19 +5787,42 @@ p2r_convert(Arena *arena, P2R_Params *params) } } + ////////////////////////// + //- rjf: merge this stream's outputs with collated list + // + rdim_symbol_chunk_list_concat_in_place(&all_procedures, &sym_procedures); + rdim_symbol_chunk_list_concat_in_place(&all_global_variables, &sym_global_variables); + rdim_symbol_chunk_list_concat_in_place(&all_thread_variables, &sym_thread_variables); + rdim_scope_chunk_list_concat_in_place(&all_scopes, &sym_scopes); + scratch_end(scratch); } #undef p2r_type_ptr_from_itype } + ////////////////////////////////////////////////////////////// + //- rjf: fill output + // + P2R_ConvertOut *out = push_array(arena, P2R_ConvertOut, 1); + { + out->top_level_info = top_level_info; + out->binary_sections = binary_sections; + rdim_unit_chunk_list_push_array(arena, &out->units, &units); + rdim_type_chunk_list_push_array(arena, &out->types, &itype_types); + rdim_type_chunk_list_concat_in_place(&out->types, &extra_types); + out->global_variables = all_global_variables; + out->thread_variables = all_thread_variables; + out->procedures = all_procedures; + out->scopes = all_scopes; + } //~ TODO(rjf): OLD vvvvvvvvvvvvvvvvvvv #if 0 // output generation P2R_Ctx *p2r_ctx = 0; - if(params->output_name.size > 0) + if(in->output_name.size > 0) { // setup root RDIM_RootParams root_params = {0}; @@ -5830,7 +5855,7 @@ p2r_convert(Arena *arena, P2R_Params *params) // set top level info RDIM_TopLevelInfo tli = {0}; tli.architecture = architecture; - tli.exe_name = params->input_exe_name; + tli.exe_name = in->input_exe_name; tli.exe_hash = exe_hash; tli.voff_max = voff_max; @@ -5977,7 +6002,7 @@ p2r_convert(Arena *arena, P2R_Params *params) } // conversion errors - if(!params->hide_errors.converting) + if(!in->hide_errors.converting) { for(RDIM_Msg *msg = rdim_first_msg_from_root(root); msg != 0; @@ -5989,7 +6014,7 @@ p2r_convert(Arena *arena, P2R_Params *params) } // dump - if(params->dump) ProfScope("dump") + if(in->dump) ProfScope("dump") { String8List dump = {0}; @@ -6007,7 +6032,7 @@ p2r_convert(Arena *arena, P2R_Params *params) } // MSF - if(params->dump_msf) + if(in->dump_msf) { if(msf != 0) { @@ -6033,7 +6058,7 @@ p2r_convert(Arena *arena, P2R_Params *params) } // DBI - if(params->dump_sym) + if(in->dump_sym) { if(sym != 0) { @@ -6047,7 +6072,7 @@ p2r_convert(Arena *arena, P2R_Params *params) } // TPI - if(params->dump_tpi_hash) + if(in->dump_tpi_hash) { if(tpi_hash != 0) { @@ -6071,7 +6096,7 @@ p2r_convert(Arena *arena, P2R_Params *params) } // LEAF - if(params->dump_leaf) + if(in->dump_leaf) { if(tpi_leaf != 0) { @@ -6095,7 +6120,7 @@ p2r_convert(Arena *arena, P2R_Params *params) } // BINARY SECTIONS - if(params->dump_coff_sections) + if(in->dump_coff_sections) { if(coff_sections != 0) { @@ -6130,8 +6155,8 @@ p2r_convert(Arena *arena, P2R_Params *params) // UNITS if(comp_units != 0) { - B32 dump_sym = params->dump_sym; - B32 dump_c13 = params->dump_c13; + B32 dump_sym = in->dump_sym; + B32 dump_c13 = in->dump_c13; B32 dump_units = (dump_sym || dump_c13); @@ -6163,7 +6188,7 @@ p2r_convert(Arena *arena, P2R_Params *params) // UNIT CONTRIBUTIONS if(comp_unit_contributions != 0) { - if(params->dump_contributions) + if(in->dump_contributions) { str8_list_push(arena, &dump, str8_lit("################################" @@ -6181,7 +6206,7 @@ p2r_convert(Arena *arena, P2R_Params *params) } // rjf: dump table diagnostics - if(params->dump_table_diagnostics) + if(in->dump_table_diagnostics) { str8_list_push(arena, &dump, str8_lit("################################" diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.h b/src/raddbgi_from_pdb/raddbgi_from_pdb.h index 22ebf9fd..7d1943f3 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb.h +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb.h @@ -5,10 +5,10 @@ #define RDI_FROM_PDB_H //////////////////////////////// -//~ rjf: Conversion Parameters Type +//~ rjf: Conversion Inputs/Outputs -typedef struct P2R_Params P2R_Params; -struct P2R_Params +typedef struct P2R_ConvertIn P2R_ConvertIn; +struct P2R_ConvertIn { String8 input_pdb_name; String8 input_pdb_data; @@ -39,6 +39,19 @@ struct P2R_Params String8List errors; }; +typedef struct P2R_ConvertOut P2R_ConvertOut; +struct P2R_ConvertOut +{ + RDIM_TopLevelInfo top_level_info; + RDIM_BinarySectionList binary_sections; + RDIM_UnitChunkList units; + RDIM_TypeChunkList types; + RDIM_SymbolChunkList global_variables; + RDIM_SymbolChunkList thread_variables; + RDIM_SymbolChunkList procedures; + RDIM_ScopeChunkList scopes; +}; + //////////////////////////////// //~ rjf: Conversion Data Structure Types @@ -217,7 +230,6 @@ struct P2R_Ctx P2R_KnownGlobalSet known_globals; P2R_LinkNameMap link_names; }; -#endif //////////////////////////////// //~ Conversion Output Type @@ -230,6 +242,7 @@ struct P2R_Out String8List dump; String8List errors; }; +#endif //////////////////////////////// //~ rjf: Basic Helpers @@ -237,9 +250,9 @@ struct P2R_Out internal U64 p2r_end_of_cplusplus_container_name(String8 str); //////////////////////////////// -//~ rjf: Command Line -> Conversion Parameters +//~ rjf: Command Line -> Conversion Inputs -internal P2R_Params *p2r_params_from_cmd_line(Arena *arena, CmdLine *cmdline); +internal P2R_ConvertIn *p2r_convert_in_from_cmd_line(Arena *arena, CmdLine *cmdline); //////////////////////////////// //~ rjf: COFF => RADDBGI Canonical Conversions @@ -263,6 +276,11 @@ internal RDI_RegisterCode p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, C internal void p2r_location_over_lvar_addr_range(Arena *arena, RDIM_LocationSet *locset, RDIM_Location *location, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); +//////////////////////////////// +//~ rjf: Top-Level Conversion Entry Point + +internal P2R_ConvertOut *p2r_convert(Arena *arena, P2R_ConvertIn *in); + #if 0 //////////////////////////////// @@ -371,9 +389,4 @@ internal String8 p2r_link_name_find(P2R_LinkNameMap *map, U64 voff); #endif -//////////////////////////////// -//~ rjf: Top-Level Conversion Entry Point - -internal P2R_Out *p2r_convert(Arena *arena, P2R_Params *params); - #endif // RDI_FROM_PDB_H diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c b/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c index 9468bddb..1c183fb0 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c @@ -1,9 +1,11 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//- rjf: [lib] #include "lib_raddbgi_format/raddbgi_format.h" #include "lib_raddbgi_format/raddbgi_format.c" +//- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" #include "raddbgi_make_local/raddbgi_make_local.h" @@ -13,9 +15,9 @@ #include "msf/msf.h" #include "pdb/pdb.h" #include "pdb/pdb_stringize.h" - #include "raddbgi_from_pdb.h" +//- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" #include "raddbgi_make_local/raddbgi_make_local.c" @@ -25,11 +27,13 @@ #include "msf/msf.c" #include "pdb/pdb.c" #include "pdb/pdb_stringize.c" - #include "raddbgi_from_pdb.c" +//- rjf: entry point + int -main(int argc, char **argv){ +main(int argc, char **argv) +{ local_persist TCTX main_thread_tctx = {0}; tctx_init_and_equip(&main_thread_tctx); #if PROFILE_TELEMETRY @@ -40,69 +44,76 @@ main(int argc, char **argv){ tmSetMaxThreadCount(1024); tmInitialize(tm_data_size, tm_data); #endif - ThreadName("[main]"); + //- rjf: initialize dependencies + os_init(argc, argv); + + //- rjf: initialize state, parse command line Arena *arena = arena_alloc(); String8List args = os_string_list_from_argcv(arena, argc, argv); CmdLine cmdline = cmd_line_from_string_list(arena, args); + B32 should_capture = cmd_line_has_flag(&cmdline, str8_lit("capture")); + P2R_ConvertIn *convert_in = p2r_convert_in_from_cmd_line(arena, &cmdline); - ProfBeginCapture("raddbgi_from_pdb"); - - //- rjf: parse arguments - P2R_Params *params = p2r_params_from_cmd_line(arena, &cmdline); - - //- rjf: show input errors - if (params->errors.node_count > 0 && - !params->hide_errors.input){ - for (String8Node *node = params->errors.first; - node != 0; - node = node->next){ - fprintf(stderr, "error(input): %.*s\n", str8_varg(node->string)); - } + //- rjf: begin capture + if(should_capture) + { + ProfBeginCapture(argv[0]); } - //- rjf: open output file - String8 output_name = push_str8_copy(arena, params->output_name); - FILE *out_file = fopen((char*)output_name.str, "wb"); - if(out_file == 0 && !params->hide_errors.output) + //- rjf: display errors with input + if(convert_in->errors.node_count > 0 && !convert_in->hide_errors.input) { - fprintf(stderr, "error(output): could not open output file\n"); + for(String8Node *n = convert_in->errors.first; n != 0; n = n->next) + { + fprintf(stderr, "error(input): %.*s\n", str8_varg(n->string)); + } } //- rjf: convert - P2R_Out *out = 0; - if(out_file != 0) + P2R_ConvertOut *convert_out = 0; + ProfScope("convert") { - out = p2r_convert(arena, params); + convert_out = p2r_convert(arena, convert_in); } - //- rjf: print dump - if(out != 0) + //- rjf: bake + String8List bake_strings = {0}; + ProfScope("bake") { - for(String8Node *node = out->dump.first; node != 0; node = node->next) + RDIM_BakeParams bake_params = {0}; { - fwrite(node->string.str, 1, node->string.size, stdout); + bake_params.top_level_info = convert_out->top_level_info; + bake_params.binary_sections = convert_out->binary_sections; + bake_params.types = convert_out->types; + bake_params.global_variables = convert_out->global_variables; + bake_params.thread_variables = convert_out->thread_variables; + bake_params.procedures = convert_out->procedures; + bake_params.scopes = convert_out->scopes; } + bake_strings = rdim_bake(arena, &bake_params); } - //- rjf: bake file - if(out != 0 && out->good_parse && params->output_name.size > 0 && out->good_parse) + //- rjf: write + ProfScope("write") { - String8List baked = {0}; - rdim_bake_file(arena, out->root, &baked); - for(String8Node *node = baked.first; node != 0; node = node->next) + OS_Handle output_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, convert_in->output_name); + U64 off = 0; + for(String8Node *n = bake_strings.first; n != 0; n = n->next) { - fwrite(node->string.str, node->string.size, 1, out_file); + os_file_write(output_file, r1u64(off, off+n->string.size), n->string.str); + off += n->string.size; } + os_file_close(output_file); } - //- rjf: close output file - if(out_file != 0) + + //- rjf: end capture + if(should_capture) { - fclose(out_file); + ProfEndCapture(); } - ProfEndCapture(); return(0); }