mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-14 09:18:09 +00:00
WIP process attaching
This commit is contained in:
@@ -117,6 +117,17 @@ dmn_lnx_read_string(Arena *arena, int memory_fd, U64 vaddr)
|
||||
return dmn_lnx_read_string_capped(arena, memory_fd, vaddr, 4096);
|
||||
}
|
||||
|
||||
internal int
|
||||
dmn_lnx_ptrace_seize(pid_t pid)
|
||||
{
|
||||
// ensure tracer ops are issued on thread that sizes processes
|
||||
if(dmn_lnx_state->tracer_tid == 0) { dmn_lnx_state->tracer_tid = gettid(); }
|
||||
AssertAlways(dmn_lnx_state->tracer_tid == gettid());
|
||||
|
||||
// TODO: PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE
|
||||
return OS_LNX_RETRY_ON_EINTR(ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_TRACEEXEC | PTRACE_O_EXITKILL | PTRACE_O_TRACECLONE));
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Runtime Struct Helpers
|
||||
|
||||
@@ -491,7 +502,7 @@ dmn_lnx_dynamic_info_from_memory(int memory_fd, ELF_Class elf_class, U64 rebase,
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_lnx_rdebug_vaddr_from_memory(int memory_fd, U64 loader_vbase)
|
||||
dmn_lnx_rdebug_vaddr_from_memory(int memory_fd, U64 loader_vbase, B32 is_rebased)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
@@ -521,7 +532,8 @@ dmn_lnx_rdebug_vaddr_from_memory(int memory_fd, U64 loader_vbase)
|
||||
}
|
||||
|
||||
// extract necessary info out of dynamic program header
|
||||
DMN_LNX_DynamicInfo dynamic_info = dmn_lnx_dynamic_info_from_memory(memory_fd, elf_class, rebase, dynamic_vaddr);
|
||||
U64 dynamic_info_rebase = is_rebased ? 0 : rebase;
|
||||
DMN_LNX_DynamicInfo dynamic_info = dmn_lnx_dynamic_info_from_memory(memory_fd, elf_class, dynamic_info_rebase, dynamic_vaddr);
|
||||
|
||||
// extract symbol table count from available options
|
||||
U64 symbol_count = 0;
|
||||
@@ -660,6 +672,12 @@ dmn_lnx_dl_path_from_pid(Arena *arena, pid_t pid, U64 auxv_base)
|
||||
return dl_path;
|
||||
}
|
||||
|
||||
internal
|
||||
GNU_MEM_READ(dmn_lnx_gnu_mem_read)
|
||||
{
|
||||
return dmn_lnx_read(((DMN_LNX_Entity *)ud)->fd, r1u64(addr, addr + size), buffer);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ SDT Probes
|
||||
|
||||
@@ -1409,6 +1427,8 @@ dmn_lnx_handle_not_attached(Arena *arena, DMN_EventList *events)
|
||||
e->error_kind = DMN_ErrorKind_NotAttached;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal DMN_LNX_Entity *
|
||||
dmn_lnx_handle_create_thread(Arena *arena, DMN_EventList *events, DMN_LNX_Entity *process, pid_t tid)
|
||||
{
|
||||
@@ -1445,16 +1465,18 @@ dmn_lnx_handle_create_thread(Arena *arena, DMN_EventList *events, DMN_LNX_Entity
|
||||
return thread;
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_lnx_handle_create_process(Arena *arena, DMN_EventList *events, B32 debug_subprocesses, pid_t pid)
|
||||
internal DMN_LNX_Entity *
|
||||
dmn_lnx_handle_create_process(Arena *arena, DMN_EventList *events, B32 debug_subprocesses, B32 is_rebased, pid_t pid)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
DMN_LNX_Entity *process = 0;
|
||||
|
||||
ELF_Hdr64 exe_ehdr = dmn_lnx_ehdr_from_pid(pid);
|
||||
int memory_fd = open((char*)str8f(scratch.arena, "/proc/%d/mem", pid).str, O_RDWR);
|
||||
DMN_LNX_ProcessAuxv auxv = dmn_lnx_auxv_from_pid(pid, exe_ehdr.e_ident[ELF_Identifier_Class]);
|
||||
Arch arch = arch_from_elf_machine(exe_ehdr.e_machine);
|
||||
U64 rdebug_vaddr = dmn_lnx_rdebug_vaddr_from_memory(memory_fd, auxv.base);
|
||||
U64 rdebug_vaddr = dmn_lnx_rdebug_vaddr_from_memory(memory_fd, auxv.base, is_rebased);
|
||||
U64 rdebug_brk_vaddr = rdebug_vaddr + gnu_r_brk_offset_from_arch(arch);
|
||||
U64 base_vaddr = (auxv.phdr & ~(auxv.pagesz-1));
|
||||
U64 rebase = exe_ehdr.e_type == ELF_Type_Dyn ? base_vaddr : 0;
|
||||
@@ -1536,7 +1558,7 @@ dmn_lnx_handle_create_process(Arena *arena, DMN_EventList *events, B32 debug_sub
|
||||
//
|
||||
// init process
|
||||
//
|
||||
DMN_LNX_Entity *process = dmn_lnx_entity_alloc(dmn_lnx_state->entities_base, DMN_LNX_EntityKind_Process);
|
||||
process = dmn_lnx_entity_alloc(dmn_lnx_state->entities_base, DMN_LNX_EntityKind_Process);
|
||||
process->id = pid;
|
||||
process->arch = arch;
|
||||
process->fd = memory_fd;
|
||||
@@ -1615,6 +1637,7 @@ dmn_lnx_handle_create_process(Arena *arena, DMN_EventList *events, B32 debug_sub
|
||||
dmn_lnx_state->active_process_count += 1;
|
||||
|
||||
scratch_end(scratch);
|
||||
return process;
|
||||
}
|
||||
|
||||
internal void
|
||||
@@ -1665,7 +1688,7 @@ dmn_lnx_handle_exit_thread(Arena *arena, DMN_EventList *events, pid_t tid, U64 e
|
||||
DMN_LNX_Entity *process = thread->parent;
|
||||
|
||||
// store main thread's exit code
|
||||
if(thread->is_main_thread)
|
||||
if(thread->id == process->id)
|
||||
{
|
||||
process->main_thread_exit_code = exit_code;
|
||||
}
|
||||
@@ -1753,41 +1776,31 @@ internal void
|
||||
dmn_lnx_hanlde_unload_module(Arena *arena, DMN_EventList *events, DMN_LNX_Entity *process, U64 name_space_id, U64 rdebug_vaddr)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
B32 is_unmap_complete_finished = 0;
|
||||
|
||||
GNU_RDebugInfo64 rdebug = {0};
|
||||
if(!dmn_lnx_read_r_debug(process->fd, rdebug_vaddr, process->arch, &rdebug)) { goto exit; }
|
||||
if(rdebug.r_version != 1) { goto exit; }
|
||||
|
||||
// flag every module as inactive
|
||||
for(DMN_LNX_Entity *module = process->first; module != dmn_lnx_nil_entity; module = module->next)
|
||||
{
|
||||
if(module->kind != DMN_LNX_EntityKind_Module) {continue;}
|
||||
if(module->kind != DMN_LNX_EntityKind_Module) { continue; }
|
||||
module->is_live = 0;
|
||||
}
|
||||
|
||||
// loop over modules in the link map and mark live modules
|
||||
GNU_LinkMap64 map = {0};
|
||||
for(U64 map_vaddr = rdebug.r_map; map_vaddr != 0; map_vaddr = map.next_vaddr)
|
||||
{
|
||||
if(dmn_lnx_read_linkmap(process->fd, map_vaddr, process->dl_class, &map))
|
||||
{
|
||||
DMN_LNX_Entity *module = hash_table_search_u64_raw(process->loaded_modules_ht, map.addr_vaddr);
|
||||
if(module)
|
||||
{
|
||||
module->is_live = 1;
|
||||
}
|
||||
else { Assert(0 && "unknown module is being unloaded"); }
|
||||
// mark live modules
|
||||
B32 is_64bit = process->dl_class == ELF_Class_64;
|
||||
GNU_RDebugInfoList rdebug_list = gnu_parse_rdebug(scratch.arena, is_64bit, rdebug_vaddr, dmn_lnx_gnu_mem_read, process);
|
||||
for EachNode(rdebug_n, GNU_RDebugInfoNode, rdebug_list.first) {
|
||||
GNU_LinkMapList link_map_list = gnu_parse_link_map_list(scratch.arena, is_64bit, rdebug_n->v.r_map, dmn_lnx_gnu_mem_read, process);
|
||||
for EachNode(link_map_n, GNU_LinkMapNode, link_map_list.first) {
|
||||
DMN_LNX_Entity *module = hash_table_search_u64_raw(process->loaded_modules_ht, link_map_n->v.addr_vaddr);
|
||||
module->is_live = 1;
|
||||
}
|
||||
else { Assert(0 && "unable to read Link Map"); }
|
||||
}
|
||||
|
||||
// collect unloaded modules
|
||||
DMN_HandleList to_release = {0};
|
||||
for(DMN_LNX_Entity *module = process->first; module != dmn_lnx_nil_entity; module = module->next)
|
||||
{
|
||||
if(module->kind != DMN_LNX_EntityKind_Module) {continue;}
|
||||
if(module->is_live) {continue;}
|
||||
if(module->kind != DMN_LNX_EntityKind_Module) { continue; }
|
||||
if(module->is_live) { continue; }
|
||||
dmn_handle_list_push(scratch.arena, &to_release, dmn_lnx_handle_from_entity(module));
|
||||
}
|
||||
|
||||
@@ -1807,9 +1820,6 @@ dmn_lnx_hanlde_unload_module(Arena *arena, DMN_EventList *events, DMN_LNX_Entity
|
||||
dmn_lnx_entity_release(module);
|
||||
}
|
||||
|
||||
is_unmap_complete_finished = 1;
|
||||
exit:;
|
||||
Assert(is_unmap_complete_finished);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
@@ -1845,7 +1855,7 @@ dmn_lnx_handle_breakpoint(Arena *arena, DMN_EventList *events, HashTable *active
|
||||
|
||||
GNU_RDebugInfo64 rdebug = {0};
|
||||
if(!dmn_lnx_read_r_debug(process->fd, rdebug_addr, process->arch, &rdebug)) { goto init_complete_exit; }
|
||||
if(rdebug.r_version != 1 && rdebug.r_version != 2) { goto init_complete_exit; }
|
||||
if(rdebug.r_version < 1) { goto init_complete_exit; }
|
||||
|
||||
dmn_lnx_handle_load_module(arena, events, process, name_space_id, rdebug.r_map);
|
||||
|
||||
@@ -2006,6 +2016,66 @@ dmn_lnx_handle_exception(Arena *arena, DMN_EventList *events, pid_t tid, U64 sig
|
||||
}
|
||||
}
|
||||
|
||||
internal DMN_LNX_Entity *
|
||||
dmn_lnx_handle_attach(Arena *arena, DMN_EventList *events, pid_t pid)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
DMN_LNX_Entity *process = 0;
|
||||
|
||||
String8 task_path = push_str8f(scratch.arena, "/proc/%d/task", pid);
|
||||
DIR *task_dirp = opendir((char *)task_path.str);
|
||||
if(task_dirp)
|
||||
{
|
||||
// create process
|
||||
process = dmn_lnx_handle_create_process(arena, events, 1, 1, pid);
|
||||
|
||||
// extract threads from /proc/pid/task
|
||||
for(;;)
|
||||
{
|
||||
struct dirent *dirent = readdir(task_dirp);
|
||||
if(dirent == 0) { break; }
|
||||
|
||||
String8 tid_str = str8_cstring_capped(dirent->d_name, dirent->d_name + NAME_MAX);
|
||||
if(str8_match(tid_str, str8_lit(".."), 0) || str8_match(tid_str, str8_lit("."), 0)) { continue; }
|
||||
U64 tid_64 = u64_from_str8(tid_str, 10);
|
||||
pid_t tid = (pid_t)tid_64;
|
||||
AssertAlways(tid == tid_64);
|
||||
|
||||
if(tid == pid) { continue; } // main thread was created during create process sequence
|
||||
dmn_lnx_handle_create_thread(arena, events, process, tid);
|
||||
}
|
||||
|
||||
// extract modules from r_debug
|
||||
B32 is_64bit = process->dl_class == ELF_Class_64;
|
||||
GNU_RDebugInfoList rdebug_list = gnu_parse_rdebug(scratch.arena, is_64bit, process->rdebug_vaddr, dmn_lnx_gnu_mem_read, process);
|
||||
U64 name_space_id = 0;
|
||||
for EachNode(rdebug_n, GNU_RDebugInfoNode, rdebug_list.first)
|
||||
{
|
||||
dmn_lnx_handle_load_module(arena, events, process, name_space_id, rdebug_n->v.r_map);
|
||||
name_space_id += 1;
|
||||
}
|
||||
|
||||
OS_LNX_RETRY_ON_EINTR(closedir(task_dirp));
|
||||
}
|
||||
|
||||
//
|
||||
// handshake complete
|
||||
//
|
||||
{
|
||||
DMN_LNX_Entity *main_thread = dmn_lnx_thread_from_pid(pid);
|
||||
|
||||
DMN_Event *e = dmn_event_list_push(arena, events);
|
||||
e->kind = DMN_EventKind_HandshakeComplete;
|
||||
e->process = dmn_lnx_handle_from_entity(process);
|
||||
e->thread = dmn_lnx_handle_from_entity(main_thread);
|
||||
e->arch = process->arch;
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return process;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS)
|
||||
|
||||
@@ -2133,13 +2203,7 @@ dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params)
|
||||
B32 failed_to_seize = 1;
|
||||
|
||||
// try to seize child process
|
||||
//
|
||||
// TODO: PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE
|
||||
if(OS_LNX_RETRY_ON_EINTR(ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_TRACEEXEC | PTRACE_O_EXITKILL | PTRACE_O_TRACECLONE) < 0)) { goto parent_exit; }
|
||||
|
||||
// ensure tracer ops are issued on thread that sizes processes
|
||||
if(dmn_lnx_state->tracer_tid == 0) { dmn_lnx_state->tracer_tid = gettid(); }
|
||||
AssertAlways(dmn_lnx_state->tracer_tid == gettid());
|
||||
if(dmn_lnx_ptrace_seize(pid) < 0) { goto parent_exit; }
|
||||
|
||||
// alloc pending process node
|
||||
DMN_LNX_ProcessLaunch *pending_proc = dmn_lnx_state->free_pids.first;
|
||||
@@ -2170,7 +2234,28 @@ dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params)
|
||||
internal B32
|
||||
dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid)
|
||||
{
|
||||
return 0;
|
||||
B32 is_attached = 0;
|
||||
|
||||
if(dmn_lnx_ptrace_seize(pid) >= 0)
|
||||
{
|
||||
if(OS_LNX_RETRY_ON_EINTR(kill(pid, SIGSTOP)) >= 0)
|
||||
{
|
||||
DMN_LNX_ProcessLaunch *pending_proc = dmn_lnx_state->free_pids.first;
|
||||
if(pending_proc) { dmn_lnx_process_launch_list_remove(&dmn_lnx_state->free_pids, pending_proc); }
|
||||
else { pending_proc = push_array(dmn_lnx_state->arena, DMN_LNX_ProcessLaunch, 1); }
|
||||
|
||||
*pending_proc = (DMN_LNX_ProcessLaunch){ 1, pid, DMN_LNX_ProcessLaunchState_Attach };
|
||||
dmn_lnx_process_launch_list_push_node(&dmn_lnx_state->pending_procs, pending_proc);
|
||||
|
||||
is_attached = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
OS_LNX_RETRY_ON_EINTR(ptrace(PTRACE_DETACH, pid, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
return is_attached;
|
||||
}
|
||||
|
||||
internal B32
|
||||
@@ -2430,7 +2515,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
dmn_lnx_process_launch_list_push_node(&dmn_lnx_state->free_pids, pending_proc);
|
||||
|
||||
// push create process events
|
||||
dmn_lnx_handle_create_process(arena, &events, pending_proc->debug_subprocesses, wait_id);
|
||||
dmn_lnx_handle_create_process(arena, &events, pending_proc->debug_subprocesses, 0, wait_id);
|
||||
|
||||
// override event code so the main code path does not create another process
|
||||
event_code = PTRACE_EVENT_STOP;
|
||||
@@ -2443,6 +2528,17 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if(pending_proc->state == DMN_LNX_ProcessLaunchState_Attach)
|
||||
{
|
||||
// move pending process node to the free list
|
||||
dmn_lnx_process_launch_list_remove(&dmn_lnx_state->pending_procs, pending_proc);
|
||||
dmn_lnx_process_launch_list_push_node(&dmn_lnx_state->free_pids, pending_proc);
|
||||
|
||||
dmn_lnx_handle_attach(arena, &events, wait_id);
|
||||
|
||||
// override event code
|
||||
event_code = PTRACE_EVENT_STOP;
|
||||
}
|
||||
else if(pending_proc->state == DMN_LNX_ProcessLaunchState_Exit)
|
||||
{
|
||||
// move pending process node to the free list
|
||||
@@ -2565,7 +2661,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
if(process->debug_subprocesses)
|
||||
{
|
||||
dmn_lnx_handle_exit_thread(arena, &events, wait_id, 0);
|
||||
dmn_lnx_handle_create_process(arena, &events, 1, wait_id);
|
||||
dmn_lnx_handle_create_process(arena, &events, 1, 0, wait_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -215,7 +215,6 @@ struct DMN_LNX_Entity
|
||||
// thread
|
||||
void *reg_block;
|
||||
B32 expecting_dummy_sigstop;
|
||||
B32 is_main_thread;
|
||||
B32 is_reg_block_dirty;
|
||||
B32 pass_through_signal;
|
||||
U64 pass_through_signo;
|
||||
@@ -253,6 +252,7 @@ enum
|
||||
{
|
||||
DMN_LNX_ProcessLaunchState_Null,
|
||||
DMN_LNX_ProcessLaunchState_Exec,
|
||||
DMN_LNX_ProcessLaunchState_Attach,
|
||||
DMN_LNX_ProcessLaunchState_Exit,
|
||||
};
|
||||
|
||||
@@ -359,7 +359,7 @@ internal DMN_LNX_ProcessAuxv dmn_lnx_auxv_from_pid(pid_t pid, ELF_Class elf_clas
|
||||
//- ELF/GNU info from memory
|
||||
internal DMN_LNX_PhdrInfo dmn_lnx_phdr_info_from_memory(int memory_fd, ELF_Class elf_class, U64 rebase, U64 e_phaddr, U64 e_phentsize, U64 e_phnum);
|
||||
internal DMN_LNX_DynamicInfo dmn_lnx_dynamic_info_from_memory(int memory_fd, ELF_Class elf_Class, U64 rebase, U64 dynamic_vaddr);
|
||||
internal U64 dmn_lnx_rdebug_vaddr_from_memory(int memory_fd, U64 loader_vaddr);
|
||||
internal U64 dmn_lnx_rdebug_vaddr_from_memory(int memory_fd, U64 loader_vaddr, B32 is_rebased);
|
||||
|
||||
internal String8 dmn_lnx_dl_path_from_pid(Arena *arena, pid_t pid, U64 auxv_base);
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal GNU_RDebugInfoList
|
||||
gnu_parse_rdebug(Arena *arena, B32 is_64bit, U64 first_rdebug_vaddr, GNU_MemRead *mem_read_func, void *mem_read_ud)
|
||||
{
|
||||
GNU_RDebugInfoList result = {0};
|
||||
|
||||
for (U64 rdebug_vaddr = first_rdebug_vaddr, rdebug_next = 0; rdebug_vaddr != 0; rdebug_vaddr = rdebug_next) {
|
||||
GNU_RDebugInfo64 rdebug;
|
||||
if (is_64bit) {
|
||||
U64 rdebug_read_size = mem_read_func(rdebug_vaddr, sizeof(rdebug), &rdebug, mem_read_ud);
|
||||
if (rdebug_read_size != sizeof(rdebug)) { goto exit; }
|
||||
} else {
|
||||
GNU_RDebugInfo32 rdebug32;
|
||||
U64 rdebug_read_size = mem_read_func(rdebug_vaddr, sizeof(rdebug32), &rdebug32, mem_read_ud);
|
||||
if (rdebug_read_size != sizeof(rdebug32)) { goto exit; }
|
||||
}
|
||||
if (rdebug.r_version < 1) { goto exit; }
|
||||
|
||||
if (rdebug.r_version > 1) {
|
||||
U64 r_next_size = mem_read_func(rdebug_vaddr + sizeof(rdebug), sizeof(rdebug_next), &rdebug_next, mem_read_ud);
|
||||
if (r_next_size != sizeof(rdebug_next)) { goto exit; }
|
||||
}
|
||||
|
||||
GNU_RDebugInfoNode *rdebug_n = push_array(arena, GNU_RDebugInfoNode, 1);
|
||||
rdebug_n->v = rdebug;
|
||||
SLLQueuePush(result.first, result.last, rdebug_n);
|
||||
result.count += 1;
|
||||
}
|
||||
|
||||
exit:;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal GNU_LinkMapList
|
||||
gnu_parse_link_map_list(Arena *arena, B32 is_64bit, U64 first_link_map_vaddr, GNU_MemRead *mem_read_func, void *mem_read_ud)
|
||||
{
|
||||
GNU_LinkMapList result = {0};
|
||||
|
||||
GNU_LinkMap64 link_map = {0};
|
||||
for (U64 link_map_vaddr = first_link_map_vaddr; link_map_vaddr != 0; link_map_vaddr = link_map.next_vaddr) {
|
||||
if (is_64bit) {
|
||||
U64 link_map_size = mem_read_func(link_map_vaddr, sizeof(link_map), &link_map, mem_read_ud);
|
||||
if (link_map_size != sizeof(link_map)) { goto exit; }
|
||||
} else {
|
||||
GNU_LinkMap32 link_map32 = {0};
|
||||
U64 link_map_size = mem_read_func(link_map_vaddr, sizeof(link_map32), &link_map32, mem_read_ud);
|
||||
if (link_map_size != sizeof(link_map32)) { goto exit; }
|
||||
gnu_linkmap64_from_linkmap32(link_map32);
|
||||
}
|
||||
|
||||
GNU_LinkMapNode *n = push_array(arena, GNU_LinkMapNode, 1);
|
||||
n->v = link_map;
|
||||
SLLQueuePush(result.first, result.last, n);
|
||||
result.count += 1;
|
||||
}
|
||||
|
||||
exit:;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef GNU_PARSE_H
|
||||
#define GNU_PARSE_H
|
||||
|
||||
typedef struct GNU_LinkMapNode
|
||||
{
|
||||
GNU_LinkMap64 v;
|
||||
struct GNU_LinkMapNode *next;
|
||||
} GNU_LinkMapNode;
|
||||
|
||||
typedef struct GNU_LinkMapList
|
||||
{
|
||||
U64 count;
|
||||
GNU_LinkMapNode *first;
|
||||
GNU_LinkMapNode *last;
|
||||
} GNU_LinkMapList;
|
||||
|
||||
typedef struct GNU_RDebugInfoNode
|
||||
{
|
||||
GNU_RDebugInfo64 v;
|
||||
struct GNU_RDebugInfoNode *next;
|
||||
} GNU_RDebugInfoNode;
|
||||
|
||||
typedef struct GNU_RDebugInfoList
|
||||
{
|
||||
U64 count;
|
||||
GNU_RDebugInfoNode *first;
|
||||
GNU_RDebugInfoNode *last;
|
||||
} GNU_RDebugInfoList;
|
||||
|
||||
#define GNU_MEM_READ(name) U64 name(U64 addr, U64 size, void *buffer, void *ud)
|
||||
typedef GNU_MEM_READ(GNU_MemRead);
|
||||
|
||||
////////////////////////////////
|
||||
internal GNU_RDebugInfoList gnu_parse_rdebug(Arena *arena, B32 is_64bit, U64 first_rdebug_vaddr, GNU_MemRead *mem_read_func, void *mem_read_ud);
|
||||
internal GNU_LinkMapList gnu_parse_link_map_list(Arena *arena, B32 is_64bit, U64 first_link_map_vaddr, GNU_MemRead *mem_read_func, void *mem_read_ud);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
#include "pe/pe.h"
|
||||
#include "elf/elf.h"
|
||||
#include "gnu/gnu.h"
|
||||
#include "gnu/gnu_parse.h"
|
||||
#include "elf/elf_parse.h"
|
||||
#include "elf/elf_dump.h"
|
||||
#include "codeview/codeview.h"
|
||||
@@ -262,6 +263,7 @@
|
||||
#include "pe/pe.c"
|
||||
#include "elf/elf.c"
|
||||
#include "gnu/gnu.c"
|
||||
#include "gnu/gnu_parse.c"
|
||||
#include "elf/elf_parse.c"
|
||||
#include "elf/elf_dump.c"
|
||||
#include "codeview/codeview.c"
|
||||
|
||||
Reference in New Issue
Block a user