mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-07-09 19:11:38 -07:00
produce image layout map
This commit is contained in:
+177
-1
@@ -3139,6 +3139,169 @@ LNK_CHUNK_VISITOR_SIG(lnk_max_tls_align)
|
||||
return 0;
|
||||
}
|
||||
|
||||
global LNK_Section **g_rad_sort_sect_id_map = 0;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U64 off;
|
||||
LNK_Chunk *chunk;
|
||||
} LNK_ChunkOffPair;
|
||||
|
||||
internal int
|
||||
lnk_map_sort_on_chunk_file_off(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_Chunk **a = raw_a;
|
||||
LNK_Chunk **b = raw_b;
|
||||
|
||||
U64 a_file_off = lnk_virt_off_from_chunk_ref(g_rad_sort_sect_id_map, (*a)->ref);
|
||||
U64 b_file_off = lnk_virt_off_from_chunk_ref(g_rad_sort_sect_id_map, (*b)->ref);
|
||||
|
||||
int is_before = a_file_off < b_file_off;
|
||||
return is_before;
|
||||
}
|
||||
|
||||
internal int
|
||||
lnk_map_sort_on_chunk_off(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_ChunkOffPair *a = raw_a;
|
||||
LNK_ChunkOffPair *b = raw_b;
|
||||
|
||||
int is_before = a->off < b->off;
|
||||
return is_before;
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_chunk_off_pair_array_bsearch(LNK_ChunkOffPair *arr, U64 count, U64 value)
|
||||
{
|
||||
if(count > 1 && arr[0].off <= value && value < arr[count-1].off)
|
||||
{
|
||||
U64 l = 0;
|
||||
U64 r = count - 1;
|
||||
for(; l <= r; )
|
||||
{
|
||||
U64 m = l + (r - l) / 2;
|
||||
if(arr[m].off == value)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
else if(arr[m].off < value)
|
||||
{
|
||||
l = m + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = m - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (count == 1 && arr[0].off == value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return max_U64;
|
||||
}
|
||||
|
||||
internal String8List
|
||||
lnk_build_rad_chunk_map(Arena *arena, String8 image_data, U64 thread_count, LNK_ObjList objs, LNK_SectionTable *st, LNK_SymbolTable *symtab)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st);
|
||||
|
||||
String8List map = {0};
|
||||
|
||||
str8_list_pushf(arena, &map, "# CHUNKS\n");
|
||||
for (LNK_SectionNode *sect_n = st->list.first; sect_n != 0; sect_n = sect_n->next) {
|
||||
LNK_Section *sect = §_n->data;
|
||||
if (sect->has_layout) {
|
||||
LNK_Chunk **chunks = push_array_no_zero(scratch.arena, LNK_Chunk *, sect->layout.total_count);
|
||||
MemoryCopyTyped(chunks, sect->layout.chunk_ptr_array, sect->layout.total_count);
|
||||
|
||||
g_rad_sort_sect_id_map = sect_id_map;
|
||||
radsort(chunks, sect->layout.total_count, lnk_map_sort_on_chunk_file_off);
|
||||
|
||||
str8_list_pushf(arena, &map, "%S\n", sect->name);
|
||||
str8_list_pushf(arena, &map, "%-16s %-8s %-8s %-16s %-8s %s\n", "Sect:Offset", "VirtSize", "FileSize", "Blake3", "ChunkRef", "Source");
|
||||
for (U64 chunk_idx = 0; chunk_idx < sect->layout.total_count; ++chunk_idx) {
|
||||
LNK_Chunk *chunk = chunks[chunk_idx];
|
||||
if (chunk->type == LNK_Chunk_Leaf && chunk != g_null_chunk_ptr) {
|
||||
Temp temp = temp_begin(scratch.arena);
|
||||
|
||||
ISectOff sc = lnk_sc_from_chunk_ref(sect_id_map, chunk->ref);
|
||||
U64 virt_size = lnk_virt_size_from_chunk_ref(sect_id_map, chunk->ref);
|
||||
U64 file_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk->ref);
|
||||
String8 chunk_data = lnk_data_from_chunk_ref(sect_id_map, image_data, chunk->ref);
|
||||
|
||||
U128 chunk_hash = {0};
|
||||
if (~sect->flags & COFF_SectionFlag_CntUninitializedData) {
|
||||
blake3_hasher hasher; blake3_hasher_init(&hasher);
|
||||
blake3_hasher_update(&hasher, chunk_data.str, chunk_data.size);
|
||||
blake3_hasher_finalize(&hasher, (U8 *)&chunk_hash, sizeof(chunk_hash));
|
||||
}
|
||||
|
||||
String8 address_str = push_str8f(temp.arena, "%04x:%08x", sc.isect, sc.off);
|
||||
String8 virt_size_str = push_str8f(temp.arena, "%08x", virt_size);
|
||||
String8 file_size_str = push_str8f(temp.arena, "%08x", file_size);
|
||||
String8 chunk_hash_str = push_str8f(temp.arena, "%08x%08x", chunk_hash.u64[0], chunk_hash.u64[1]);
|
||||
String8 chunk_ref_str = push_str8f(temp.arena, "{%llx,%llx}", chunk->ref.sect_id, chunk->ref.chunk_id);
|
||||
String8 source_str = str8_lit("\?\?\?");
|
||||
if (chunk->obj) {
|
||||
if (chunk->obj->lib_path.size) {
|
||||
String8 lib_name = chunk->obj->lib_path;
|
||||
lib_name = str8_skip_last_slash(lib_name);
|
||||
lib_name = str8_chop_last_dot(lib_name);
|
||||
|
||||
String8 obj_name = chunk->obj->path;
|
||||
obj_name = str8_skip_last_slash(obj_name);
|
||||
|
||||
source_str = push_str8f(temp.arena, "%S:%S", lib_name, obj_name);
|
||||
} else {
|
||||
source_str = push_str8f(temp.arena, "%S", chunk->obj->path);
|
||||
}
|
||||
}
|
||||
|
||||
str8_list_pushf(arena, &map, "%-16S %-8S %-8S %-16S %-8S %S\n", address_str, virt_size_str, file_size_str, chunk_hash_str, chunk_ref_str, source_str);
|
||||
|
||||
temp_end(temp);
|
||||
}
|
||||
}
|
||||
str8_list_pushf(arena, &map, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
str8_list_pushf(arena, &map, "# SYMBOLS\n");
|
||||
str8_list_pushf(arena, &map, "%-8s %s\n", "ChunkRef", "Symbol");
|
||||
for (LNK_ObjNode *obj_n = objs.first; obj_n != 0; obj_n = obj_n->next) {
|
||||
LNK_Obj *obj = &obj_n->data;
|
||||
for (LNK_SymbolNode *symbol_n = obj->symbol_list.first; symbol_n != 0; symbol_n = symbol_n->next) {
|
||||
LNK_Symbol *symbol = symbol_n->data;
|
||||
if (LNK_Symbol_IsDefined(symbol->type)) {
|
||||
if (symbol->u.defined.value_type == LNK_DefinedSymbolValue_Chunk) {
|
||||
LNK_Chunk *chunk = symbol->u.defined.u.chunk;
|
||||
String8 chunk_ref_str = push_str8f(scratch.arena, "{%llx,%llx}", chunk->ref.sect_id, chunk->ref.chunk_id);
|
||||
|
||||
String8 lib_name = obj->lib_path;
|
||||
lib_name = str8_skip_last_slash(lib_name);
|
||||
lib_name = str8_chop_last_dot(lib_name);
|
||||
|
||||
String8 obj_name = obj->path;
|
||||
obj_name = str8_skip_last_slash(obj_name);
|
||||
|
||||
str8_list_pushf(arena, &map, "%-8S (%S%s%S) %S\n",
|
||||
chunk_ref_str,
|
||||
lib_name, lib_name.size ? ":" : "", obj_name,
|
||||
symbol->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//str8_list_pushf(arena, &map, "%16s %30s %23s %10s\n\n", "Address", "Publics by Value", "Rva+Base", "Lib:Object");
|
||||
|
||||
scratch_end(scratch);
|
||||
return map;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_run(int argc, char **argv)
|
||||
{
|
||||
@@ -3167,6 +3330,7 @@ lnk_run(int argc, char **argv)
|
||||
State_BuildBaseRelocs,
|
||||
State_FinalizeImage,
|
||||
State_BuildImpLib,
|
||||
State_BuildRadChunkMap,
|
||||
State_BuildDebugInfo,
|
||||
};
|
||||
struct StateNode {
|
||||
@@ -3254,10 +3418,11 @@ lnk_run(int argc, char **argv)
|
||||
B32 report_unresolved_symbols = 1;
|
||||
B32 check_unused_delay_loads = !!(config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll);
|
||||
B32 build_imp_lib = config->build_imp_lib;
|
||||
B32 build_rad_chunk_map = (config->rad_chunk_map == LNK_SwitchState_Yes);
|
||||
LNK_ObjList obj_list = {0};
|
||||
LNK_LibList lib_index[LNK_InputSource_Count] = {0};
|
||||
String8 image_data = str8_zero();
|
||||
OS_Handle image_write_thread = {0};
|
||||
OS_Handle image_write_thread = {0};
|
||||
|
||||
// init state machine
|
||||
struct StateList state_list = {0};
|
||||
@@ -4121,6 +4286,12 @@ lnk_run(int argc, char **argv)
|
||||
lnk_timer_end(LNK_Timer_Lib);
|
||||
ProfEnd();
|
||||
} break;
|
||||
case State_BuildRadChunkMap: {
|
||||
ProfBegin("RAD Chunk Map");
|
||||
String8List map = lnk_build_rad_chunk_map(scratch.arena, image_data, config->worker_count, obj_list, st, symtab);
|
||||
lnk_write_data_list_to_file_path(config->rad_chunk_map_name, config->temp_rad_chunk_map_name, map);
|
||||
ProfEnd();
|
||||
} break;
|
||||
case State_BuildDebugInfo: {
|
||||
ProfBegin("Debug Info");
|
||||
lnk_timer_begin(LNK_Timer_Debug);
|
||||
@@ -4319,6 +4490,11 @@ lnk_run(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (build_rad_chunk_map) {
|
||||
build_rad_chunk_map = 0;
|
||||
state_list_push(scratch.arena, state_list, State_BuildRadChunkMap);
|
||||
continue;
|
||||
}
|
||||
if (build_debug_info) {
|
||||
build_debug_info = 0;
|
||||
state_list_push(scratch.arena, state_list, State_BuildDebugInfo);
|
||||
|
||||
@@ -40,6 +40,7 @@ typedef struct LNK_Chunk
|
||||
struct LNK_ChunkList *list;
|
||||
struct LNK_ChunkArray *arr;
|
||||
} u;
|
||||
struct LNK_Obj *obj;
|
||||
#if LNK_DEBUG_CHUNKS
|
||||
String8 debug;
|
||||
#endif
|
||||
@@ -115,7 +116,7 @@ typedef struct LNK_ChunkPadArrayNode
|
||||
} LNK_ChunkPadArrayNode;
|
||||
typedef struct LNK_ChunkPadArrayList
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
LNK_ChunkPadArrayNode *first;
|
||||
LNK_ChunkPadArrayNode *last;
|
||||
} LNK_ChunkPadArrayList;
|
||||
|
||||
+10
-3
@@ -132,6 +132,7 @@ global read_only struct
|
||||
{ LNK_CmdSwitch_Rad_Age, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." },
|
||||
{ LNK_CmdSwitch_Rad_BuildInfo, "RAD_BUILD_INFO", "", "Print build info and exit." },
|
||||
{ LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_ChunkMap, "RAD_CHUNK_MAP", ":FILENAME", "Emit file with the output image's layout description." },
|
||||
{ LNK_CmdSwitch_Rad_Debug, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." },
|
||||
{ LNK_CmdSwitch_Rad_DebugAltPath, "RAD_DEBUGALTPATH", "", "" },
|
||||
{ LNK_CmdSwitch_Rad_DebugName, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." },
|
||||
@@ -1522,6 +1523,11 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
|
||||
lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_CheckUnusedDelayLoadDll);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_ChunkMap: {
|
||||
lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->rad_chunk_map_name);
|
||||
config->rad_chunk_map = LNK_SwitchState_Yes;
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_Debug: {
|
||||
lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &config->rad_debug);
|
||||
} break;
|
||||
@@ -2060,9 +2066,10 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
|
||||
// create temporary files names
|
||||
if (config->write_temp_files == LNK_SwitchState_Yes) {
|
||||
config->temp_image_name = push_str8f(arena, "%S.tmp%x", config->image_name, config->time_stamp);
|
||||
config->temp_pdb_name = push_str8f(arena, "%S.tmp%x", config->pdb_name, config->time_stamp);
|
||||
config->temp_rad_debug_name = push_str8f(arena, "%S.tmp%x", config->rad_debug_name, config->time_stamp);
|
||||
config->temp_rad_chunk_map_name = push_str8f(arena, "%S.tmp%x", config->rad_chunk_map_name, config->time_stamp);
|
||||
config->temp_image_name = push_str8f(arena, "%S.tmp%x", config->image_name, config->time_stamp);
|
||||
config->temp_pdb_name = push_str8f(arena, "%S.tmp%x", config->pdb_name, config->time_stamp);
|
||||
config->temp_rad_debug_name = push_str8f(arena, "%S.tmp%x", config->rad_debug_name, config->time_stamp);
|
||||
}
|
||||
|
||||
if (lnk_get_log_status(LNK_Log_Debug)) {
|
||||
|
||||
@@ -128,6 +128,7 @@ typedef enum
|
||||
LNK_CmdSwitch_Rad_Age,
|
||||
LNK_CmdSwitch_Rad_BuildInfo,
|
||||
LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll,
|
||||
LNK_CmdSwitch_Rad_ChunkMap,
|
||||
LNK_CmdSwitch_Rad_Debug,
|
||||
LNK_CmdSwitch_Rad_DebugName,
|
||||
LNK_CmdSwitch_Rad_DebugAltPath,
|
||||
@@ -355,6 +356,8 @@ typedef struct LNK_Config
|
||||
String8 manifest_ui_access;
|
||||
String8List manifest_dependency_list;
|
||||
LNK_SwitchState rad_debug;
|
||||
LNK_SwitchState rad_chunk_map;
|
||||
String8 rad_chunk_map_name;
|
||||
String8 rad_debug_name;
|
||||
String8 rad_debug_alt_path;
|
||||
String8List include_symbol_list;
|
||||
@@ -369,6 +372,7 @@ typedef struct LNK_Config
|
||||
String8 temp_image_name;
|
||||
String8 temp_pdb_name;
|
||||
String8 temp_rad_debug_name;
|
||||
String8 temp_rad_chunk_map_name;
|
||||
} LNK_Config;
|
||||
|
||||
typedef enum
|
||||
|
||||
@@ -410,6 +410,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
|
||||
chunk->input_idx = LNK_MakeChunkInputIdx(obj_idx, sect_idx);
|
||||
chunk->flags = coff_sect->flags;
|
||||
chunk->u.leaf = data;
|
||||
chunk->obj = obj;
|
||||
lnk_chunk_set_debugf(arena, chunk, "%S: name: %S, obj_idx: 0x%llX isect: 0x%llX", cached_path, sect_name_arr[sect_idx], obj_idx, sect_idx);
|
||||
}
|
||||
|
||||
@@ -425,6 +426,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
|
||||
master_common_block->flags = LNK_BSS_SECTION_FLAGS;
|
||||
master_common_block->associate = 0;
|
||||
master_common_block->u.list = push_array(arena, LNK_ChunkList, 1);
|
||||
master_common_block->obj = obj;
|
||||
lnk_chunk_set_debugf(arena, master_common_block, "%S: master common block", cached_path);
|
||||
|
||||
LNK_ChunkPtr *chunk_ptr_arr = push_array_no_zero(arena, LNK_ChunkPtr, chunk_count);
|
||||
@@ -787,6 +789,7 @@ lnk_symbol_array_from_coff(Arena *arena,
|
||||
chunk_list->input_idx = chunk->input_idx;
|
||||
chunk_list->flags = chunk->flags;
|
||||
chunk_list->u.list = push_array(arena, LNK_ChunkList, 1);
|
||||
chunk_list->obj = obj;
|
||||
lnk_chunk_set_debugf(arena, chunk_list, "%S: function chunk list for %S", obj_path, symbol.name);
|
||||
|
||||
// update properties on first chunk
|
||||
@@ -834,6 +837,7 @@ lnk_symbol_array_from_coff(Arena *arena,
|
||||
split_chunk->is_discarded = current->data->is_discarded;
|
||||
split_chunk->flags = current->data->flags;
|
||||
split_chunk->u.leaf = right_data;
|
||||
split_chunk->obj = obj;
|
||||
lnk_chunk_set_debugf(arena, split_chunk, "%S: chunk split on function %S SECT%x SPLIT_POS %#llx", obj_path, symbol.name, symbol.section_number, split_pos);
|
||||
|
||||
LNK_ChunkNode *split_node = push_array(arena, LNK_ChunkNode, 1);
|
||||
@@ -985,6 +989,7 @@ lnk_symbol_array_from_coff(Arena *arena,
|
||||
chunk->type = LNK_Chunk_Leaf;
|
||||
chunk->flags = master_common_block->flags;
|
||||
chunk->u.leaf = str8(0, parsed_symbol.value);
|
||||
chunk->obj = obj;
|
||||
lnk_chunk_set_debugf(arena, chunk, "%S: common block %S", obj_path, parsed_symbol.name);
|
||||
lnk_chunk_list_push(arena, master_common_block->u.list, chunk);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user