From fd6c3ef0e0d486bded796797d29ed9aeab0cbe3c Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 28 Dec 2025 01:16:55 -0800 Subject: [PATCH] move GNU and ELF specific struct readers to appropriate layers --- src/demon/linux/demon_core_linux.c | 752 +++++++++++------------------ src/demon/linux/demon_core_linux.h | 57 +-- src/elf/elf.c | 112 +++++ src/elf/elf.h | 9 + src/gnu/gnu.c | 37 ++ src/gnu/gnu.h | 6 + 6 files changed, 466 insertions(+), 507 deletions(-) diff --git a/src/demon/linux/demon_core_linux.c b/src/demon/linux/demon_core_linux.c index 87028bcc..2ead00fb 100644 --- a/src/demon/linux/demon_core_linux.c +++ b/src/demon/linux/demon_core_linux.c @@ -120,7 +120,8 @@ dmn_lnx_read_string(Arena *arena, int memory_fd, U64 vaddr) internal MACHINE_OP_MEM_READ(dmn_lnx_machine_op_mem_read) { - return dmn_lnx_read(((DMN_LNX_Entity *)ud)->fd, r1u64(addr, addr + buffer_size), buffer); + U64 read_size = dmn_lnx_read(*(int *)ud, r1u64(addr, addr + buffer_size), buffer); + return read_size == buffer_size ? MachineOpResult_Ok : MachineOpResult_Fail; } internal int @@ -134,192 +135,6 @@ dmn_lnx_ptrace_seize(pid_t pid) return OS_LNX_RETRY_ON_EINTR(ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_TRACEEXEC | PTRACE_O_EXITKILL | PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE)); } -//////////////////////////////// -//~ Runtime Struct Helpers - -internal B32 -dmn_lnx_read_ehdr(int memory_fd, U64 addr, ELF_Hdr64 *ehdr_out) -{ - B32 is_read = 0; - U8 e_ident[ELF_Identifier_Max] = {0}; - U64 e_ident_size = dmn_lnx_read(memory_fd, r1u64(addr, addr + sizeof(e_ident)), &e_ident); - if(e_ident_size == sizeof(e_ident)) - { - if(str8_match(str8_prefix(str8_array_fixed(e_ident), elf_magic_string.size), elf_magic_string, 0)) - { - switch(e_ident[ELF_Identifier_Class]) - { - default:{InvalidPath;}break; - case ELF_Class_None: {}break; - case ELF_Class_32: - { - ELF_Hdr32 ehdr32 = {0}; - if(dmn_lnx_read_struct(memory_fd, addr, &ehdr32)) - { - *ehdr_out = elf_hdr64_from_hdr32(ehdr32); - is_read = 1; - } - }break; - case ELF_Class_64: - { - is_read = dmn_lnx_read_struct(memory_fd, addr, ehdr_out); - }break; - } - } - } - return is_read; -} - -internal B32 -dmn_lnx_read_phdr(int memory_fd, U64 addr, ELF_Class elf_class, ELF_Phdr64 *phdr_out) -{ - B32 is_read = 0; - switch (elf_class) - { - case ELF_Class_None: break; - case ELF_Class_32: - { - ELF_Phdr32 phdr32 = {0}; - if(dmn_lnx_read_struct(memory_fd, addr, &phdr32)) - { - *phdr_out = elf_phdr64_from_phdr32(phdr32); - is_read = 1; - } - }break; - case ELF_Class_64: - { - is_read = dmn_lnx_read_struct(memory_fd, addr, phdr_out); - }break; - default:{NotImplemented;}break; - } - return is_read; -} - -internal B32 -dmn_lnx_read_shdr(int memory_fd, U64 addr, ELF_Class elf_class, ELF_Shdr64 *shdr_out) -{ - B32 is_read = 0; - switch (elf_class) - { - case ELF_Class_None: break; - case ELF_Class_32: - { - ELF_Shdr32 shdr32 = {0}; - if(dmn_lnx_read_struct(memory_fd, addr, &shdr32)) - { - *shdr_out = elf_shdr64_from_shdr32(shdr32); - is_read = 1; - } - }break; - case ELF_Class_64: - { - is_read = dmn_lnx_read_struct(memory_fd, addr, shdr_out); - }break; - default:{NotImplemented;}break; - } - return is_read; -} - -internal B32 -dmn_lnx_read_linkmap(int memory_fd, U64 addr, ELF_Class elf_class, GNU_LinkMap64 *linkmap_out) -{ - B32 is_read = 0; - switch(elf_class) - { - case ELF_Class_None: {}break; - case ELF_Class_32: - { - GNU_LinkMap32 linkmap32 = {0}; - if(dmn_lnx_read_struct(memory_fd, addr, &linkmap32)) - { - *linkmap_out = gnu_linkmap64_from_linkmap32(linkmap32); - is_read = 1; - } - }break; - case ELF_Class_64: - { - is_read = dmn_lnx_read_struct(memory_fd, addr, linkmap_out); - }break; - default:{NotImplemented;}break; - } - return is_read; -} - -internal B32 -dmn_lnx_read_dynamic(int memory_fd, U64 addr, ELF_Class elf_class, ELF_Dyn64 *dyn_out) -{ - B32 is_read = 0; - switch(elf_class) - { - case ELF_Class_None:{}break; - case ELF_Class_32: - { - ELF_Dyn32 dyn32 = {0}; - if(dmn_lnx_read_struct(memory_fd, addr, &dyn32)) - { - *dyn_out = elf_dyn64_from_dyn32(dyn32); - is_read = 1; - } - }break; - case ELF_Class_64: - { - is_read = dmn_lnx_read_struct(memory_fd, addr, dyn_out); - }break; - default:{NotImplemented;}break; - } - return is_read; -} - -internal B32 -dmn_lnx_read_symbol(int memory_fd, U64 addr, ELF_Class elf_class, ELF_Sym64 *symbol_out) -{ - B32 is_read = 0; - switch(elf_class) - { - case ELF_Class_None:{}break; - case ELF_Class_32: - { - ELF_Sym32 symbol32 = {0}; - if(dmn_lnx_read_struct(memory_fd, addr, &symbol32)) - { - *symbol_out = elf_sym64_from_sym32(symbol32); - is_read = 1; - } - }break; - case ELF_Class_64: - { - is_read = dmn_lnx_read_struct(memory_fd, addr, symbol_out); - }break; - default:{NotImplemented;}break; - } - return is_read; -} - -internal B32 -dmn_lnx_read_r_debug(int memory_fd, U64 addr, Arch arch, GNU_RDebugInfo64 *rdebug_out) -{ - B32 is_read = 0; - switch(gnu_rdebug_info_size_from_arch(arch)) - { - case 0: {} break; - case sizeof(GNU_RDebugInfo32): { - GNU_RDebugInfo32 rdebug32 = {0}; - if(dmn_lnx_read_struct(memory_fd, addr, &rdebug32)) - { - *rdebug_out = gnu_rdebug_info64_from_rdebug_info32(rdebug32); - is_read = 1; - } - }break; - case sizeof(GNU_RDebugInfo64): - { - is_read = dmn_lnx_read_struct(memory_fd, addr, rdebug_out); - }break; - default:{InvalidPath;}break; - } - Assert(is_read); - return is_read; -} - //- rjf: pid => info extraction internal String8 @@ -353,260 +168,6 @@ dmn_lnx_exe_path_from_pid(Arena *arena, pid_t pid) return result; } -internal ELF_Hdr64 -dmn_lnx_ehdr_from_pid(pid_t pid) -{ - Temp scratch = scratch_begin(0, 0); - B32 is_read = 0; - ELF_Hdr64 exe = {0}; - String8 exe_path = dmn_lnx_exe_path_from_pid(scratch.arena, pid); - if(exe_path.size != 0) - { - int exe_fd = OS_LNX_RETRY_ON_EINTR(open((char *)exe_path.str, O_RDONLY)); - if(exe_fd != -1) - { - is_read = dmn_lnx_read_ehdr(exe_fd, 0, &exe); - close(exe_fd); - } - } - Assert(is_read); - scratch_end(scratch); - return exe; -} - -internal DMN_LNX_ProcessAuxv -dmn_lnx_auxv_from_pid(pid_t pid, ELF_Class elf_class) -{ - Temp scratch = scratch_begin(0, 0); - DMN_LNX_ProcessAuxv result = {0}; - - // rjf: open aux data - String8 auxv_path = push_str8f(scratch.arena, "/proc/%d/auxv", pid); - int auxv_fd = OS_LNX_RETRY_ON_EINTR(open((char*)auxv_path.str, O_RDONLY)); - - // rjf: scan aux data - if(auxv_fd >= 0) - { - for(;;) - { - // rjf: read next aux - ELF_Auxv64 auxv = {0}; - switch(elf_class) - { - case ELF_Class_None:{}break; - case ELF_Class_32: - { - ELF_Auxv32 auxv32 = {0}; - if(read(auxv_fd, &auxv32, sizeof(auxv32)) != sizeof(auxv32)) { goto brkloop; } - auxv = elf_auxv64_from_auxv32(auxv32); - }break; - case ELF_Class_64: - { - if(read(auxv_fd, &auxv, sizeof(auxv)) != sizeof(auxv)) { goto brkloop; } - }break; - default:{NotImplemented;}break; - } - - // rjf: fill result - switch(auxv.a_type) - { - default:{}break; - case ELF_AuxType_Null: goto brkloop; break; - case ELF_AuxType_Base: result.base = auxv.a_val; break; - case ELF_AuxType_Phnum: result.phnum = auxv.a_val; break; - case ELF_AuxType_Phent: result.phent = auxv.a_val; break; - case ELF_AuxType_Phdr: result.phdr = auxv.a_val; break; - case ELF_AuxType_ExecFn: result.execfn = auxv.a_val; break; - case ELF_AuxType_Pagesz: result.pagesz = auxv.a_val; break; - } - } - brkloop:; - close(auxv_fd); - } - - scratch_end(scratch); - return result; -} - -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) -{ - DMN_LNX_PhdrInfo result = { .range.min = max_U64 }; - - // rjf: scan table - for(U64 ph_cursor = e_phaddr, ph_opl = (e_phaddr + e_phentsize * e_phnum); - ph_cursor < ph_opl; - ph_cursor += e_phentsize) - { - ELF_Phdr64 phdr = {0}; - if(!dmn_lnx_read_phdr(memory_fd, ph_cursor, elf_class, &phdr)) - { - Assert(0 && "unable to read a program header"); - } - - // rjf: save - switch(phdr.p_type) - { - default:{}break; - case ELF_PType_Dynamic: - { - result.dynamic = rebase + phdr.p_vaddr; - }break; - case ELF_PType_Load: - { - U64 min = rebase + phdr.p_vaddr; - U64 max = rebase + phdr.p_vaddr + phdr.p_memsz; - result.range.min = Min(result.range.min, min); - result.range.max = Max(result.range.max, max); - }break; - } - } - - return result; -} - -internal DMN_LNX_DynamicInfo -dmn_lnx_dynamic_info_from_memory(int memory_fd, ELF_Class elf_class, U64 rebase, U64 dynamic_vaddr) -{ - DMN_LNX_DynamicInfo dynamic_info = {0}; - for(U64 dynamic_cursor = dynamic_vaddr; ; dynamic_cursor += elf_dyn_size_from_class(elf_class)) - { - // rjf: read next dyn entry - ELF_Dyn64 dyn = {0}; - if(!dmn_lnx_read_dynamic(memory_fd, dynamic_cursor, elf_class, &dyn)) { Assert(0 && "unable to read dynamic"); } - - // rjf: break on zero - if(dyn.tag == ELF_DynTag_Null) { break; } - - // extract reuiqred values out of dynamic section - if(dyn.tag == ELF_DynTag_Strtab) - { - dynamic_info.strtab_vaddr = rebase + dyn.val; - } - else if(dyn.tag == ELF_DynTag_Strsz) - { - dynamic_info.strtab_size = dyn.val; - } - else if(dyn.tag == ELF_DynTag_Symtab) - { - dynamic_info.symtab_vaddr = rebase + dyn.val; - } - else if(dyn.tag == ELF_DynTag_Syment) - { - dynamic_info.symtab_entry_size = dyn.val; - } - else if(dyn.tag == ELF_DynTag_Hash) - { - dynamic_info.hash_vaddr = rebase + dyn.val; - } - else if(dyn.tag == ELF_DynTag_GNU_Hash) - { - dynamic_info.gnu_hash_vaddr = rebase + dyn.val; - } - } - return dynamic_info; -} - -internal U64 -dmn_lnx_rdebug_vaddr_from_memory(int memory_fd, U64 loader_vbase, B32 is_rebased) -{ - Temp scratch = scratch_begin(0, 0); - - U64 rdebug_vaddr = 0; - - // load DL's header - ELF_Hdr64 ehdr = {0}; - if(!dmn_lnx_read_ehdr(memory_fd, loader_vbase, &ehdr)) { Assert(0 && "failed to read interp's header"); goto exit; } - - U64 rebase = ehdr.e_type == ELF_Type_Dyn ? loader_vbase : 0; - ELF_Class elf_class = ehdr.e_ident[ELF_Identifier_Class]; - - // find dynamic program header - U64 dynamic_vaddr = max_U64; - for EachIndex(phdr_idx, ehdr.e_phnum) - { - U64 phdr_vaddr = loader_vbase + ehdr.e_phoff + phdr_idx * ehdr.e_phentsize; - - ELF_Phdr64 phdr = {0}; - if(!dmn_lnx_read_phdr(memory_fd, phdr_vaddr, elf_class, &phdr)) { Assert(0 && "failed to read program header"); goto exit; } - - if(phdr.p_type == ELF_PType_Dynamic) - { - dynamic_vaddr = rebase + phdr.p_vaddr; - break; - } - } - - // extract necessary info out of dynamic program header - 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; - if(dynamic_info.hash_vaddr) - { - U64 hash_entry_size = 4; - if(elf_class == ELF_Class_64 && (ehdr.e_machine == ELF_MachineKind_ALPHA || ehdr.e_machine == ELF_MachineKind_S390 || ehdr.e_machine == ELF_MachineKind_S390_OLD)) - { - hash_entry_size = 8; - } - - U64 chain_count = 0; - if(dmn_lnx_read(memory_fd, r1u64(dynamic_info.hash_vaddr, dynamic_info.hash_vaddr + hash_entry_size), &chain_count) == hash_entry_size) - { - symbol_count = chain_count; - } - else - { - Assert(0 && "failed to read hash table's chain count out of HASH"); - } - } - else - { - // TODO: extract count from GNU_HASH - NotImplemented; - } - - // scan symbol table for the rendezvous symbol - if(dynamic_info.symtab_vaddr && dynamic_info.symtab_entry_size && symbol_count) - { - for EachIndex(symbol_idx, symbol_count) - { - ELF_Sym64 symbol = {0}; - if(!dmn_lnx_read_symbol(memory_fd, dynamic_info.symtab_vaddr + symbol_idx * dynamic_info.symtab_entry_size, elf_class, &symbol)) - { - Assert(0 && "failed to read symbol table"); - break; - } - - Temp temp = temp_begin(scratch.arena); - - String8 symbol_name = {0}; - if(symbol.st_name < dynamic_info.strtab_size) - { - U64 cap = dynamic_info.strtab_size - symbol.st_name; - symbol_name = dmn_lnx_read_string_capped(temp.arena, memory_fd, dynamic_info.strtab_vaddr + symbol.st_name, cap); - } - - if(str8_match(symbol_name, str8_lit("_r_debug"), 0)) - { - ELF_SymType symbol_type = ELF_ST_TYPE(symbol.st_info); - if(symbol_type == ELF_SymType_Object && symbol.st_size > 0) - { - rdebug_vaddr = rebase + symbol.st_value; - break; - } - } - - temp_end(temp); - } - } - -exit:; - scratch_end(scratch); - return rdebug_vaddr; -} - internal String8 dmn_lnx_dl_path_from_pid(Arena *arena, pid_t pid, U64 auxv_base) { @@ -679,6 +240,259 @@ dmn_lnx_dl_path_from_pid(Arena *arena, pid_t pid, U64 auxv_base) return dl_path; } +internal ELF_Hdr64 +dmn_lnx_ehdr_from_pid(pid_t pid) +{ + Temp scratch = scratch_begin(0, 0); + B32 is_read = 0; + ELF_Hdr64 exe = {0}; + String8 exe_path = dmn_lnx_exe_path_from_pid(scratch.arena, pid); + if(exe_path.size != 0) + { + int exe_fd = OS_LNX_RETRY_ON_EINTR(open((char *)exe_path.str, O_RDONLY)); + if(exe_fd != -1) + { + is_read = elf_read_ehdr(dmn_lnx_machine_op_mem_read, &exe_fd, 0, &exe); + close(exe_fd); + } + } + Assert(is_read); + scratch_end(scratch); + return exe; +} + +internal DMN_LNX_ProcessAuxv +dmn_lnx_auxv_from_pid(pid_t pid, ELF_Class elf_class) +{ + Temp scratch = scratch_begin(0, 0); + DMN_LNX_ProcessAuxv result = {0}; + + // rjf: open aux data + String8 auxv_path = push_str8f(scratch.arena, "/proc/%d/auxv", pid); + int auxv_fd = OS_LNX_RETRY_ON_EINTR(open((char*)auxv_path.str, O_RDONLY)); + + // rjf: scan aux data + if(auxv_fd >= 0) + { + for(;;) + { + // rjf: read next aux + ELF_Auxv64 auxv = {0}; + switch(elf_class) + { + case ELF_Class_None:{}break; + case ELF_Class_32: + { + ELF_Auxv32 auxv32 = {0}; + if(read(auxv_fd, &auxv32, sizeof(auxv32)) != sizeof(auxv32)) { goto brkloop; } + auxv = elf_auxv64_from_auxv32(auxv32); + }break; + case ELF_Class_64: + { + if(read(auxv_fd, &auxv, sizeof(auxv)) != sizeof(auxv)) { goto brkloop; } + }break; + default:{NotImplemented;}break; + } + + // rjf: fill result + switch(auxv.a_type) + { + default:{}break; + case ELF_AuxType_Null: goto brkloop; break; + case ELF_AuxType_Base: result.base = auxv.a_val; break; + case ELF_AuxType_Phnum: result.phnum = auxv.a_val; break; + case ELF_AuxType_Phent: result.phent = auxv.a_val; break; + case ELF_AuxType_Phdr: result.phdr = auxv.a_val; break; + case ELF_AuxType_ExecFn: result.execfn = auxv.a_val; break; + case ELF_AuxType_Pagesz: result.pagesz = auxv.a_val; break; + } + } + brkloop:; + close(auxv_fd); + } + + scratch_end(scratch); + return result; +} + +internal Rng1U64 +dmn_lnx_compute_image_vrange(int memory_fd, ELF_Class elf_class, U64 rebase, U64 e_phaddr, U64 e_phentsize, U64 e_phnum) +{ + Rng1U64 result = { .min = max_U64 }; + + for(U64 ph_cursor = e_phaddr, ph_opl = (e_phaddr + e_phentsize * e_phnum); ph_cursor < ph_opl; ph_cursor += e_phentsize) + { + ELF_Phdr64 phdr = {0}; + if(elf_read_phdr(dmn_lnx_machine_op_mem_read, &memory_fd, ph_cursor, elf_class, &phdr) != MachineOpResult_Ok) + { + Assert(0 && "unable to read a program header"); + } + + if(phdr.p_type == ELF_PType_Load) + { + U64 min = rebase + phdr.p_vaddr; + U64 max = rebase + phdr.p_vaddr + phdr.p_memsz; + result.min = Min(result.min, min); + result.max = Max(result.max, max); + } + } + + return result; +} + +internal U64 +dmn_lnx_find_dynamic_phdr(int memory_fd, ELF_Class elf_class, U64 rebase, U64 e_phaddr, U64 e_phentsize, U64 e_phnum) +{ + U64 result = max_U64; + + for(U64 ph_cursor = e_phaddr, ph_opl = (e_phaddr + e_phentsize * e_phnum); ph_cursor < ph_opl; ph_cursor += e_phentsize) + { + ELF_Phdr64 phdr = {0}; + if(elf_read_phdr(dmn_lnx_machine_op_mem_read, &memory_fd, ph_cursor, elf_class, &phdr) != MachineOpResult_Ok) + { + Assert(0 && "unable to read a program header"); + } + + if(phdr.p_type == ELF_PType_Dynamic) + { + result = rebase + phdr.p_vaddr; + break; + } + } + + return result; +} + +internal DMN_LNX_DynamicInfo +dmn_lnx_dynamic_info_from_memory(int memory_fd, ELF_Class elf_class, U64 rebase, U64 dynamic_vaddr) +{ + DMN_LNX_DynamicInfo dynamic_info = {0}; + for(U64 dynamic_cursor = dynamic_vaddr; ; dynamic_cursor += elf_dyn_size_from_class(elf_class)) + { + // rjf: read next dyn entry + ELF_Dyn64 dyn = {0}; + if(elf_read_dyn(dmn_lnx_machine_op_mem_read, &memory_fd, dynamic_cursor, elf_class, &dyn) != MachineOpResult_Ok) { Assert(0 && "unable to read dynamic"); } + + // rjf: break on zero + if(dyn.tag == ELF_DynTag_Null) { break; } + + // extract reuiqred values out of dynamic section + if(dyn.tag == ELF_DynTag_Strtab) + { + dynamic_info.strtab_vaddr = rebase + dyn.val; + } + else if(dyn.tag == ELF_DynTag_Strsz) + { + dynamic_info.strtab_size = dyn.val; + } + else if(dyn.tag == ELF_DynTag_Symtab) + { + dynamic_info.symtab_vaddr = rebase + dyn.val; + } + else if(dyn.tag == ELF_DynTag_Syment) + { + dynamic_info.symtab_entry_size = dyn.val; + } + else if(dyn.tag == ELF_DynTag_Hash) + { + dynamic_info.hash_vaddr = rebase + dyn.val; + } + else if(dyn.tag == ELF_DynTag_GNU_Hash) + { + dynamic_info.gnu_hash_vaddr = rebase + dyn.val; + } + } + return dynamic_info; +} + +internal U64 +dmn_lnx_rdebug_vaddr_from_memory(int memory_fd, U64 loader_vbase, B32 is_rebased) +{ + Temp scratch = scratch_begin(0, 0); + + U64 rdebug_vaddr = 0; + + // load DL's header + ELF_Hdr64 ehdr = {0}; + if(elf_read_ehdr(dmn_lnx_machine_op_mem_read, &memory_fd, loader_vbase, &ehdr) != MachineOpResult_Ok) { Assert(0 && "failed to read interp's header"); goto exit; } + + U64 rebase = ehdr.e_type == ELF_Type_Dyn ? loader_vbase : 0; + ELF_Class elf_class = ehdr.e_ident[ELF_Identifier_Class]; + + // find dynamic program header + U64 phdr_vaddr = loader_vbase + ehdr.e_phoff; + U64 dynamic_vaddr = dmn_lnx_find_dynamic_phdr(memory_fd, elf_class, rebase, phdr_vaddr, ehdr.e_phentsize, ehdr.e_phentsize); + + // extract necessary info out of dynamic program header + 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; + if(dynamic_info.hash_vaddr) + { + U64 hash_entry_size = 4; + if(elf_class == ELF_Class_64 && (ehdr.e_machine == ELF_MachineKind_ALPHA || ehdr.e_machine == ELF_MachineKind_S390 || ehdr.e_machine == ELF_MachineKind_S390_OLD)) + { + hash_entry_size = 8; + } + + U64 chain_count = 0; + if(dmn_lnx_read(memory_fd, r1u64(dynamic_info.hash_vaddr, dynamic_info.hash_vaddr + hash_entry_size), &chain_count) == hash_entry_size) + { + symbol_count = chain_count; + } + else + { + Assert(0 && "failed to read hash table's chain count out of HASH"); + } + } + else + { + // TODO: extract count from GNU_HASH + NotImplemented; + } + + // scan symbol table for the rendezvous symbol + if(dynamic_info.symtab_vaddr && dynamic_info.symtab_entry_size && symbol_count) + { + for EachIndex(symbol_idx, symbol_count) + { + ELF_Sym64 symbol = {0}; + if(elf_read_symbol(dmn_lnx_machine_op_mem_read, &memory_fd, dynamic_info.symtab_vaddr + symbol_idx * dynamic_info.symtab_entry_size, elf_class, &symbol) != MachineOpResult_Ok) + { + Assert(0 && "failed to read symbol table"); + break; + } + + Temp temp = temp_begin(scratch.arena); + + String8 symbol_name = {0}; + if(symbol.st_name < dynamic_info.strtab_size) + { + U64 cap = dynamic_info.strtab_size - symbol.st_name; + symbol_name = dmn_lnx_read_string_capped(temp.arena, memory_fd, dynamic_info.strtab_vaddr + symbol.st_name, cap); + } + + if(str8_match(symbol_name, str8_lit("_r_debug"), 0)) + { + ELF_SymType symbol_type = ELF_ST_TYPE(symbol.st_info); + if(symbol_type == ELF_SymType_Object && symbol.st_size > 0) + { + rdebug_vaddr = rebase + symbol.st_value; + break; + } + } + + temp_end(temp); + } + } + +exit:; + scratch_end(scratch); + return rdebug_vaddr; +} + //////////////////////////////// //~ SDT Probes @@ -690,11 +504,11 @@ dmn_lnx_read_probes(Arena *arena, int fd, U64 offset, U64 image_base) DMN_LNX_ProbeList probes = {0}; ELF_Hdr64 ehdr = {0}; - if(!dmn_lnx_read_ehdr(fd, offset, &ehdr)) { goto exit; } + if(elf_read_ehdr(dmn_lnx_machine_op_mem_read, &fd, offset, &ehdr) != MachineOpResult_Ok) { goto exit; } U64 strtab_shdr_offset = offset + ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize; ELF_Shdr64 strtab_shdr = {0}; - if(!dmn_lnx_read_shdr(fd, strtab_shdr_offset, ehdr.e_ident[ELF_Identifier_Class], &strtab_shdr)) { goto exit; } + if(elf_read_shdr(dmn_lnx_machine_op_mem_read, &fd, strtab_shdr_offset, ehdr.e_ident[ELF_Identifier_Class], &strtab_shdr) != MachineOpResult_Ok) { goto exit; } B32 found_probes = 0; B32 found_probes_base = 0; @@ -705,7 +519,7 @@ dmn_lnx_read_probes(Arena *arena, int fd, U64 offset, U64 image_base) shdr_off < shdr_opl; shdr_off += ehdr.e_shentsize) { ELF_Shdr64 shdr = {0}; - if(!dmn_lnx_read_shdr(fd, shdr_off, ehdr.e_ident[ELF_Identifier_Class], &shdr)) { goto exit; } + if(elf_read_shdr(dmn_lnx_machine_op_mem_read, &fd, shdr_off, ehdr.e_ident[ELF_Identifier_Class], &shdr) != MachineOpResult_Ok) { goto exit; } if(shdr.sh_type == ELF_ShType_Note) { @@ -956,6 +770,7 @@ internal B32 dmn_lnx_thread_read_reg_block(DMN_LNX_Entity *thread) { AssertAlways(dmn_lnx_state->tracer_tid == gettid()); + AssertAlways(thread->thread_state == DMN_LNX_ThreadState_Stopped); B32 result = 0; switch(thread->arch) @@ -1178,6 +993,7 @@ internal B32 dmn_lnx_thread_write_reg_block(DMN_LNX_Entity *thread) { AssertAlways(dmn_lnx_state->tracer_tid == thread->parent->tracer_tid); + AssertAlways(thread->thread_state == DMN_LNX_ThreadState_Stopped); B32 result = 0; switch(thread->arch) @@ -1486,13 +1302,13 @@ dmn_lnx_handle_create_process(Arena *arena, DMN_EventList *events, B32 debug_sub 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; - DMN_LNX_PhdrInfo phdr_info = dmn_lnx_phdr_info_from_memory(memory_fd, exe_ehdr.e_ident[ELF_Identifier_Class], rebase, auxv.phdr, auxv.phent, auxv.phnum); + Rng1U64 image_vrange = dmn_lnx_compute_image_vrange(memory_fd, exe_ehdr.e_ident[ELF_Identifier_Class], rebase, auxv.phdr, auxv.phent, auxv.phnum); Arena *process_arena = arena_alloc(); ELF_Class dl_class; { ELF_Hdr64 ehdr = {0}; - if(!dmn_lnx_read_ehdr(memory_fd, auxv.base, &ehdr)) { Assert(0 && "failed to read interp's header"); } + if(elf_read_ehdr(dmn_lnx_machine_op_mem_read, &memory_fd, auxv.base, &ehdr) != MachineOpResult_Ok) { Assert(0 && "failed to read interp's header"); } dl_class = ehdr.e_ident[ELF_Identifier_Class]; } @@ -1618,7 +1434,7 @@ dmn_lnx_handle_create_process(Arena *arena, DMN_EventList *events, B32 debug_sub e->module = dmn_lnx_handle_from_entity(module); e->arch = process->arch; e->address = base_vaddr; - e->size = dim_1u64(phdr_info.range); + e->size = dim_1u64(image_vrange); e->string = dmn_lnx_read_string(arena, process->fd, auxv.execfn); e->elf_phdr_vrange = r1u64(auxv.phdr, auxv.phdr + auxv.phent * auxv.phnum); e->elf_phdr_entsize = auxv.phent; @@ -1721,13 +1537,13 @@ dmn_lnx_load_module(Arena *arena, DMN_EventList *events, DMN_LNX_Entity *process // parse out module's ELF header ELF_Hdr64 module_ehdr = {0}; - if(!dmn_lnx_read_ehdr(process->fd, base_vaddr, &module_ehdr)) { goto exit; } + if(elf_read_ehdr(dmn_lnx_machine_op_mem_read, &process->fd, base_vaddr, &module_ehdr) != MachineOpResult_Ok) { goto exit; } // gather info about module - U64 module_rebase = module_ehdr.e_type == ELF_Type_Dyn ? base_vaddr : 0; - U64 module_phdr_vaddr = module_rebase + module_ehdr.e_phoff; - DMN_LNX_PhdrInfo module_phdr_info = dmn_lnx_phdr_info_from_memory(process->fd, module_ehdr.e_ident[ELF_Identifier_Class], module_rebase, module_phdr_vaddr, module_ehdr.e_phentsize, module_ehdr.e_phnum); - String8 module_name = dmn_lnx_read_string(process->arena, process->fd, module_name_vaddr); + U64 module_rebase = module_ehdr.e_type == ELF_Type_Dyn ? base_vaddr : 0; + U64 module_phdr_vaddr = module_rebase + module_ehdr.e_phoff; + Rng1U64 module_vrange = dmn_lnx_compute_image_vrange(process->fd, module_ehdr.e_ident[ELF_Identifier_Class], module_rebase, module_phdr_vaddr, module_ehdr.e_phentsize, module_ehdr.e_phnum); + String8 module_name = dmn_lnx_read_string(process->arena, process->fd, module_name_vaddr); // read TLS index and TLS offset U64 tls_index = max_U64; @@ -1757,7 +1573,7 @@ dmn_lnx_load_module(Arena *arena, DMN_EventList *events, DMN_LNX_Entity *process e->module = dmn_lnx_handle_from_entity(module); e->arch = arch_from_elf_machine(module_ehdr.e_machine); e->address = base_vaddr; - e->size = dim_1u64(module_phdr_info.range); + e->size = dim_1u64(module_vrange); e->string = module_name; e->elf_phdr_vrange = r1u64(module_phdr_vaddr, module_phdr_vaddr + module_ehdr.e_phentsize * module_ehdr.e_phnum); e->elf_phdr_entsize = module_ehdr.e_phentsize; @@ -1775,7 +1591,7 @@ dmn_lnx_handle_load_module(Arena *arena, DMN_EventList *events, DMN_LNX_Entity * for(U64 map_vaddr = new_link_map_vaddr; map_vaddr != 0; map_vaddr = map.next_vaddr) { // read out new link map item - if(!dmn_lnx_read_linkmap(process->fd, map_vaddr, process->dl_class, &map)) { break; } + if(gnu_read_link_map(dmn_lnx_machine_op_mem_read, &process->fd, map_vaddr, process->dl_class, &map) != MachineOpResult_Ok) { break; } // was module with this base already registered? DMN_LNX_Entity *module = hash_table_search_u64_raw(process->loaded_modules_ht, map.addr_vaddr); @@ -1804,9 +1620,9 @@ dmn_lnx_handle_unload_module(Arena *arena, DMN_EventList *events, DMN_LNX_Entity // 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_machine_op_mem_read, process); + GNU_RDebugInfoList rdebug_list = gnu_parse_rdebug(scratch.arena, is_64bit, rdebug_vaddr, dmn_lnx_machine_op_mem_read, &process->fd); 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_machine_op_mem_read, process); + GNU_LinkMapList link_map_list = gnu_parse_link_map_list(scratch.arena, is_64bit, rdebug_n->v.r_map, dmn_lnx_machine_op_mem_read, &process->fd); 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; @@ -1889,8 +1705,8 @@ dmn_lnx_handle_breakpoint(Arena *arena, DMN_EventList *events, DMN_ActiveTrap *u if(!stap_read_arg_u(probe->args.v[1], process->arch, thread->reg_block, dmn_lnx_stap_memory_read, process, &rdebug_addr)) { goto init_complete_exit; } 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) { goto init_complete_exit; } + if(gnu_read_r_debug(dmn_lnx_machine_op_mem_read, &process->fd, rdebug_addr, process->arch, &rdebug) != MachineOpResult_Ok) { 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); @@ -2083,7 +1899,7 @@ dmn_lnx_handle_attach(Arena *arena, DMN_EventList *events, pid_t pid) // 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_machine_op_mem_read, process); + GNU_RDebugInfoList rdebug_list = gnu_parse_rdebug(scratch.arena, is_64bit, process->rdebug_vaddr, dmn_lnx_machine_op_mem_read, &process->fd); U64 name_space_id = 0; for EachNode(rdebug_n, GNU_RDebugInfoNode, rdebug_list.first) { @@ -2794,6 +2610,15 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) DMN_LNX_Entity *thread = dmn_lnx_thread_from_pid(wait_id); DMN_LNX_Entity *process = thread->parent; + AssertAlways(thread->thread_state == DMN_LNX_ThreadState_PendingCreation || thread->thread_state == DMN_LNX_ThreadState_Stopped); + + if(process->expect_user_interrupt) + { + process->expect_user_interrupt = 0; + dmn_lnx_handle_halt(arena, &events); + break; + } + if(thread->thread_state == DMN_LNX_ThreadState_PendingCreation) { // finish thread init @@ -2803,14 +2628,6 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) AssertAlways(dmn_lnx_state->threads_pending_creation > 0); dmn_lnx_state->threads_pending_creation -= 1; } - else - { - if(process->expect_user_interrupt) - { - process->expect_user_interrupt = 0; - dmn_lnx_handle_halt(arena, &events); - } - } }break; default: { Assert(0 && "unexpected ptrace code"); } break; } @@ -3130,3 +2947,4 @@ dmn_process_iter_end(DMN_ProcessIter *iter) } MemoryZeroStruct(iter); } + diff --git a/src/demon/linux/demon_core_linux.h b/src/demon/linux/demon_core_linux.h index 44f499b4..6bb67868 100644 --- a/src/demon/linux/demon_core_linux.h +++ b/src/demon/linux/demon_core_linux.h @@ -136,13 +136,6 @@ struct DMN_LNX_ProcessAuxv U64 pagesz; }; -typedef struct DMN_LNX_PhdrInfo DMN_LNX_PhdrInfo; -struct DMN_LNX_PhdrInfo -{ - Rng1U64 range; - U64 dynamic; -}; - typedef struct DMN_LNX_DynamicInfo DMN_LNX_DynamicInfo; struct DMN_LNX_DynamicInfo { @@ -341,58 +334,42 @@ read_only global DMN_LNX_Entity *dmn_lnx_nil_entity = &dmn_lnx_nil_entity_; internal DMN_LNX_EntityNode * dmn_lnx_entity_list_push(Arena *arena, DMN_LNX_EntityList *list, DMN_LNX_Entity *v); //- rjf: file descriptor memory reading/writing helpers -internal U64 dmn_lnx_read(int memory_fd, Rng1U64 range, void *dst); -internal B32 dmn_lnx_write(int memory_fd, Rng1U64 range, void *src); -#define dmn_lnx_read_struct(fd, vaddr, ptr) dmn_lnx_read((fd), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr)) -#define dmn_lnx_write_struct(fd, vaddr, ptr) dmn_lnx_write((fd), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr)) +internal U64 dmn_lnx_read(int memory_fd, Rng1U64 range, void *dst); +internal B32 dmn_lnx_write(int memory_fd, Rng1U64 range, void *src); internal String8 dmn_lnx_read_string_capped(Arena *arena, int memory_fd, U64 base_vaddr, U64 cap_size); internal String8 dmn_lnx_read_string(Arena *arena, int memory_fd, U64 base_vaddr); - -//////////////////////////////// -//~ Runtime Struct Helpers - -internal B32 dmn_lnx_read_ehdr(int memory_fd, U64 addr, ELF_Hdr64 *ehdr_out); -internal B32 dmn_lnx_read_phdr(int memory_fd, U64 addr, ELF_Class elf_class, ELF_Phdr64 *phdr_out); -internal B32 dmn_lnx_read_shdr(int memory_fd, U64 addr, ELF_Class elf_class, ELF_Shdr64 *shdr_out); -internal B32 dmn_lnx_read_linkmap(int memory_fd, U64 addr, ELF_Class elf_class, GNU_LinkMap64 *link_map_out); -internal B32 dmn_lnx_read_dynamic(int memory_fd, U64 addr, ELF_Class elf_class, ELF_Dyn64 *dyn_out); -internal B32 dmn_lnx_read_symbol(int memory_fd, U64 addr, ELF_Class elf_class, ELF_Sym64 *symbol_out); -internal B32 dmn_lnx_read_r_debug(int memory_fd, U64 addr, Arch arch, GNU_RDebugInfo64 *rdebug_out); +#define dmn_lnx_read_struct(fd, vaddr, ptr) dmn_lnx_read((fd), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr)) +#define dmn_lnx_write_struct(fd, vaddr, ptr) dmn_lnx_write((fd), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr)) //- rjf: pid => info extraction internal String8 dmn_lnx_exe_path_from_pid(Arena *arena, pid_t pid); +internal String8 dmn_lnx_dl_path_from_pid(Arena *arena, pid_t pid, U64 auxv_base); internal ELF_Hdr64 dmn_lnx_ehdr_from_pid(pid_t pid); internal DMN_LNX_ProcessAuxv dmn_lnx_auxv_from_pid(pid_t pid, ELF_Class elf_class); //- 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, B32 is_rebased); - -internal String8 dmn_lnx_dl_path_from_pid(Arena *arena, pid_t pid, U64 auxv_base); +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, B32 is_rebased); //////////////////////////////// //~ rjf: Entity Functions -internal DMN_LNX_Entity *dmn_lnx_entity_alloc(DMN_LNX_Entity *parent, DMN_LNX_EntityKind kind); -internal void dmn_lnx_entity_release(DMN_LNX_Entity *entity); -internal DMN_Handle dmn_lnx_handle_from_entity(DMN_LNX_Entity *entity); -internal DMN_LNX_Entity *dmn_lnx_entity_from_handle(DMN_Handle handle); -internal DMN_LNX_Entity *dmn_lnx_thread_from_pid(pid_t pid); +internal DMN_LNX_Entity * dmn_lnx_entity_alloc(DMN_LNX_Entity *parent, DMN_LNX_EntityKind kind); +internal void dmn_lnx_entity_release(DMN_LNX_Entity *entity); +internal DMN_Handle dmn_lnx_handle_from_entity(DMN_LNX_Entity *entity); +internal DMN_LNX_Entity * dmn_lnx_entity_from_handle(DMN_Handle handle); +internal DMN_LNX_Entity * dmn_lnx_thread_from_pid(pid_t pid); //- Process internal void dmn_lnx_process_install_probes(); //- Thread -internal U64 dmn_lnx_thread_read_ip(DMN_LNX_Entity *thread); -internal U64 dmn_lnx_thread_read_sp(DMN_LNX_Entity *thread); +internal U64 dmn_lnx_thread_read_ip(DMN_LNX_Entity *thread); +internal U64 dmn_lnx_thread_read_sp(DMN_LNX_Entity *thread); internal void dmn_lnx_thread_write_ip(DMN_LNX_Entity *thread, U64 ip); internal void dmn_lnx_thread_write_sp(DMN_LNX_Entity *thread, U64 sp); -internal B32 dmn_lnx_thread_read_reg_block(DMN_LNX_Entity *thread); -internal B32 dmn_lnx_thread_write_reg_block(DMN_LNX_Entity *thread); - -//////////////////////////////// - -internal B32 dmn_lnx_set_single_step_flag(DMN_LNX_Entity *thread, B32 is_on); +internal B32 dmn_lnx_thread_read_reg_block(DMN_LNX_Entity *thread); +internal B32 dmn_lnx_thread_write_reg_block(DMN_LNX_Entity *thread); +internal B32 dmn_lnx_set_single_step_flag(DMN_LNX_Entity *thread, B32 is_on); #endif // DEMON_CORE_LINUX_H diff --git a/src/elf/elf.c b/src/elf/elf.c index 0925a428..e9e67346 100644 --- a/src/elf/elf.c +++ b/src/elf/elf.c @@ -179,3 +179,115 @@ elf_dyn_size_from_class(ELF_Class elf_class) return result; } +//////////////////////////////// + +internal MachineOpResult +elf_read_ehdr(MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, ELF_Hdr64 *ehdr_out) +{ + U8 e_ident[ELF_Identifier_Max] = {0}; + MachineOpResult result = mem_read(addr, &e_ident, sizeof(e_ident), mem_read_ud); + if (result == MachineOpResult_Ok) { + if (str8_match(str8_prefix(str8_array_fixed(e_ident), elf_magic_string.size), elf_magic_string, 0)) { + switch (e_ident[ELF_Identifier_Class]) { + default: { InvalidPath; }break; + case ELF_Class_None: { }break; + case ELF_Class_32: { + ELF_Hdr32 ehdr32 = {0}; + result = mem_read(addr, &ehdr32, sizeof(ehdr32), mem_read_ud); + if (result == MachineOpResult_Ok) { + *ehdr_out = elf_hdr64_from_hdr32(ehdr32); + } + } break; + case ELF_Class_64: { + result = mem_read(addr, ehdr_out, sizeof(*ehdr_out), mem_read_ud); + } break; + } + } + } + return result; +} + +internal MachineOpResult +elf_read_phdr(MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, ELF_Class elf_class, ELF_Phdr64 *phdr_out) +{ + MachineOpResult result = MachineOpResult_Fail; + switch (elf_class) { + case ELF_Class_None: break; + case ELF_Class_32: { + ELF_Phdr32 phdr32 = {0}; + result = mem_read(addr, &phdr32, sizeof(phdr32), mem_read_ud); + if (result == MachineOpResult_Ok) { + *phdr_out = elf_phdr64_from_phdr32(phdr32); + } + } break; + case ELF_Class_64: { + result = mem_read(addr, phdr_out, sizeof(*phdr_out), mem_read_ud); + } break; + default: { NotImplemented; } break; + } + return result; +} + +internal MachineOpResult +elf_read_shdr(MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, ELF_Class elf_class, ELF_Shdr64 *shdr_out) +{ + MachineOpResult result = MachineOpResult_Fail; + switch (elf_class) { + case ELF_Class_None: break; + case ELF_Class_32: { + ELF_Shdr32 shdr32 = {0}; + result = mem_read(addr, &shdr32, sizeof(shdr32), mem_read_ud); + if (result == MachineOpResult_Ok) { + *shdr_out = elf_shdr64_from_shdr32(shdr32); + } + } break; + case ELF_Class_64: { + result = mem_read(addr, shdr_out, sizeof(*shdr_out), mem_read_ud); + } break; + default: { NotImplemented; } break; + } + return result; +} + +internal MachineOpResult +elf_read_dyn(MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, ELF_Class elf_class, ELF_Dyn64 *dyn_out) +{ + MachineOpResult result = MachineOpResult_Fail; + switch (elf_class) { + case ELF_Class_None: {} break; + case ELF_Class_32: { + ELF_Dyn32 dyn32 = {0}; + result = mem_read(addr, &dyn32, sizeof(dyn32), mem_read_ud); + if (result == MachineOpResult_Fail) { + *dyn_out = elf_dyn64_from_dyn32(dyn32); + } + } break; + case ELF_Class_64: { + result = mem_read(addr, dyn_out, sizeof(*dyn_out), mem_read_ud); + } break; + default: { NotImplemented; } break; + } + return result; +} + +internal MachineOpResult +elf_read_symbol(MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, ELF_Class elf_class, ELF_Sym64 *symbol_out) +{ + MachineOpResult result = MachineOpResult_Fail; + switch (elf_class) { + case ELF_Class_None: {} break; + case ELF_Class_32: { + ELF_Sym32 symbol32 = {0}; + result = mem_read(addr, &symbol32, sizeof(symbol32), mem_read_ud); + if (result == MachineOpResult_Ok) { + *symbol_out = elf_sym64_from_sym32(symbol32); + } + }break; + case ELF_Class_64: { + result = mem_read(addr, symbol_out, sizeof(*symbol_out), mem_read_ud); + }break; + default: { NotImplemented; } break; + } + return result; +} + diff --git a/src/elf/elf.h b/src/elf/elf.h index 2c15aa15..1a32fbce 100644 --- a/src/elf/elf.h +++ b/src/elf/elf.h @@ -841,4 +841,13 @@ internal Arch arch_from_elf_machine(ELF_MachineKind machine); internal U64 elf_phdr_size_from_class(ELF_Class elf_class); internal U64 elf_dyn_size_from_class(ELF_Class elf_class); +//////////////////////////////// +//~ Compat Readers + +internal MachineOpResult elf_read_ehdr (MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, ELF_Hdr64 *ehdr_out); +internal MachineOpResult elf_read_phdr (MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, ELF_Class elf_class, ELF_Phdr64 *phdr_out); +internal MachineOpResult elf_read_shdr (MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, ELF_Class elf_class, ELF_Shdr64 *shdr_out); +internal MachineOpResult elf_read_dyn (MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, ELF_Class elf_class, ELF_Dyn64 *dyn_out); +internal MachineOpResult elf_read_symbol(MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, ELF_Class elf_class, ELF_Sym64 *symbol_out); + #endif // ELF_H diff --git a/src/gnu/gnu.c b/src/gnu/gnu.c index 814d786f..9586fa32 100644 --- a/src/gnu/gnu.c +++ b/src/gnu/gnu.c @@ -276,3 +276,40 @@ gnu_string_from_property_flags_x86(Arena *arena, GNU_PropertyX86 prop, U32 flags return result; } +internal MachineOpResult +gnu_read_link_map(MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, B32 is_64bit, GNU_LinkMap64 *link_map_out) +{ + MachineOpResult result = MachineOpResult_Fail; + if (is_64bit) { + result = mem_read(addr, link_map_out, sizeof(*link_map_out), mem_read_ud); + } else { + GNU_LinkMap32 link_map_32 = {0}; + result = mem_read(addr, &link_map_32, sizeof(link_map_32), mem_read_ud); + if (result == MachineOpResult_Ok) { + *link_map_out = gnu_linkmap64_from_linkmap32(link_map_32); + } + } + return result; +} + +internal MachineOpResult +gnu_read_r_debug(MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, Arch arch, GNU_RDebugInfo64 *rdebug_out) +{ + MachineOpResult result = MachineOpResult_Fail; + switch (gnu_rdebug_info_size_from_arch(arch)) { + case 0: {} break; + case sizeof(GNU_RDebugInfo32): { + GNU_RDebugInfo32 rdebug32 = {0}; + result = mem_read(addr, &rdebug32, sizeof(rdebug32), mem_read_ud); + if (result == MachineOpResult_Ok) { + *rdebug_out = gnu_rdebug_info64_from_rdebug_info32(rdebug32); + } + } break; + case sizeof(GNU_RDebugInfo64): { + result = mem_read(addr, rdebug_out, sizeof(*rdebug_out), mem_read_ud); + } break; + default: { InvalidPath; } break; + } + return result; +} + diff --git a/src/gnu/gnu.h b/src/gnu/gnu.h index 37f15007..22ba9aaf 100644 --- a/src/gnu/gnu.h +++ b/src/gnu/gnu.h @@ -201,4 +201,10 @@ internal String8 gnu_string_from_abi_tag(GNU_AbiTag abi_tag); internal String8 gnu_string_from_note_type(GNU_NoteType note_type); internal String8 gnu_string_from_property_x86(GNU_PropertyX86 prop); +//////////////////////////////// +//~ Compat Readers + +internal MachineOpResult gnu_read_link_map(MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, B32 is_64bit, GNU_LinkMap64 *link_map_out); +internal MachineOpResult gnu_read_r_debug (MachineOp_MemRead *mem_read, void *mem_read_ud, U64 addr, Arch arch, GNU_RDebugInfo64 *rdebug_out); + #endif // GNU_H