mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-14 17:28:07 +00:00
move GNU and ELF specific struct readers to appropriate layers
This commit is contained in:
+281
-463
@@ -120,7 +120,8 @@ dmn_lnx_read_string(Arena *arena, int memory_fd, U64 vaddr)
|
|||||||
internal
|
internal
|
||||||
MACHINE_OP_MEM_READ(dmn_lnx_machine_op_mem_read)
|
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
|
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));
|
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
|
//- rjf: pid => info extraction
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
@@ -353,260 +168,6 @@ dmn_lnx_exe_path_from_pid(Arena *arena, pid_t pid)
|
|||||||
return result;
|
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
|
internal String8
|
||||||
dmn_lnx_dl_path_from_pid(Arena *arena, pid_t pid, U64 auxv_base)
|
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;
|
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
|
//~ SDT Probes
|
||||||
|
|
||||||
@@ -690,11 +504,11 @@ dmn_lnx_read_probes(Arena *arena, int fd, U64 offset, U64 image_base)
|
|||||||
DMN_LNX_ProbeList probes = {0};
|
DMN_LNX_ProbeList probes = {0};
|
||||||
|
|
||||||
ELF_Hdr64 ehdr = {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;
|
U64 strtab_shdr_offset = offset + ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize;
|
||||||
ELF_Shdr64 strtab_shdr = {0};
|
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 = 0;
|
||||||
B32 found_probes_base = 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 < shdr_opl;
|
||||||
shdr_off += ehdr.e_shentsize) {
|
shdr_off += ehdr.e_shentsize) {
|
||||||
ELF_Shdr64 shdr = {0};
|
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)
|
if(shdr.sh_type == ELF_ShType_Note)
|
||||||
{
|
{
|
||||||
@@ -956,6 +770,7 @@ internal B32
|
|||||||
dmn_lnx_thread_read_reg_block(DMN_LNX_Entity *thread)
|
dmn_lnx_thread_read_reg_block(DMN_LNX_Entity *thread)
|
||||||
{
|
{
|
||||||
AssertAlways(dmn_lnx_state->tracer_tid == gettid());
|
AssertAlways(dmn_lnx_state->tracer_tid == gettid());
|
||||||
|
AssertAlways(thread->thread_state == DMN_LNX_ThreadState_Stopped);
|
||||||
|
|
||||||
B32 result = 0;
|
B32 result = 0;
|
||||||
switch(thread->arch)
|
switch(thread->arch)
|
||||||
@@ -1178,6 +993,7 @@ internal B32
|
|||||||
dmn_lnx_thread_write_reg_block(DMN_LNX_Entity *thread)
|
dmn_lnx_thread_write_reg_block(DMN_LNX_Entity *thread)
|
||||||
{
|
{
|
||||||
AssertAlways(dmn_lnx_state->tracer_tid == thread->parent->tracer_tid);
|
AssertAlways(dmn_lnx_state->tracer_tid == thread->parent->tracer_tid);
|
||||||
|
AssertAlways(thread->thread_state == DMN_LNX_ThreadState_Stopped);
|
||||||
|
|
||||||
B32 result = 0;
|
B32 result = 0;
|
||||||
switch(thread->arch)
|
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 rdebug_brk_vaddr = rdebug_vaddr + gnu_r_brk_offset_from_arch(arch);
|
||||||
U64 base_vaddr = (auxv.phdr & ~(auxv.pagesz-1));
|
U64 base_vaddr = (auxv.phdr & ~(auxv.pagesz-1));
|
||||||
U64 rebase = exe_ehdr.e_type == ELF_Type_Dyn ? base_vaddr : 0;
|
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();
|
Arena *process_arena = arena_alloc();
|
||||||
|
|
||||||
ELF_Class dl_class;
|
ELF_Class dl_class;
|
||||||
{
|
{
|
||||||
ELF_Hdr64 ehdr = {0};
|
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];
|
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->module = dmn_lnx_handle_from_entity(module);
|
||||||
e->arch = process->arch;
|
e->arch = process->arch;
|
||||||
e->address = base_vaddr;
|
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->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_vrange = r1u64(auxv.phdr, auxv.phdr + auxv.phent * auxv.phnum);
|
||||||
e->elf_phdr_entsize = auxv.phent;
|
e->elf_phdr_entsize = auxv.phent;
|
||||||
@@ -1721,12 +1537,12 @@ dmn_lnx_load_module(Arena *arena, DMN_EventList *events, DMN_LNX_Entity *process
|
|||||||
|
|
||||||
// parse out module's ELF header
|
// parse out module's ELF header
|
||||||
ELF_Hdr64 module_ehdr = {0};
|
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
|
// gather info about module
|
||||||
U64 module_rebase = module_ehdr.e_type == ELF_Type_Dyn ? base_vaddr : 0;
|
U64 module_rebase = module_ehdr.e_type == ELF_Type_Dyn ? base_vaddr : 0;
|
||||||
U64 module_phdr_vaddr = module_rebase + module_ehdr.e_phoff;
|
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);
|
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);
|
String8 module_name = dmn_lnx_read_string(process->arena, process->fd, module_name_vaddr);
|
||||||
|
|
||||||
// read TLS index and TLS offset
|
// read TLS index and TLS offset
|
||||||
@@ -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->module = dmn_lnx_handle_from_entity(module);
|
||||||
e->arch = arch_from_elf_machine(module_ehdr.e_machine);
|
e->arch = arch_from_elf_machine(module_ehdr.e_machine);
|
||||||
e->address = base_vaddr;
|
e->address = base_vaddr;
|
||||||
e->size = dim_1u64(module_phdr_info.range);
|
e->size = dim_1u64(module_vrange);
|
||||||
e->string = module_name;
|
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_vrange = r1u64(module_phdr_vaddr, module_phdr_vaddr + module_ehdr.e_phentsize * module_ehdr.e_phnum);
|
||||||
e->elf_phdr_entsize = module_ehdr.e_phentsize;
|
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)
|
for(U64 map_vaddr = new_link_map_vaddr; map_vaddr != 0; map_vaddr = map.next_vaddr)
|
||||||
{
|
{
|
||||||
// read out new link map item
|
// 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?
|
// was module with this base already registered?
|
||||||
DMN_LNX_Entity *module = hash_table_search_u64_raw(process->loaded_modules_ht, map.addr_vaddr);
|
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
|
// mark live modules
|
||||||
B32 is_64bit = process->dl_class == ELF_Class_64;
|
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) {
|
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) {
|
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);
|
DMN_LNX_Entity *module = hash_table_search_u64_raw(process->loaded_modules_ht, link_map_n->v.addr_vaddr);
|
||||||
module->is_live = 1;
|
module->is_live = 1;
|
||||||
@@ -1889,7 +1705,7 @@ 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; }
|
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};
|
GNU_RDebugInfo64 rdebug = {0};
|
||||||
if(!dmn_lnx_read_r_debug(process->fd, rdebug_addr, process->arch, &rdebug)) { 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; }
|
if(rdebug.r_version < 1) { goto init_complete_exit; }
|
||||||
|
|
||||||
dmn_lnx_handle_load_module(arena, events, process, name_space_id, rdebug.r_map);
|
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
|
// extract modules from r_debug
|
||||||
B32 is_64bit = process->dl_class == ELF_Class_64;
|
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;
|
U64 name_space_id = 0;
|
||||||
for EachNode(rdebug_n, GNU_RDebugInfoNode, rdebug_list.first)
|
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 *thread = dmn_lnx_thread_from_pid(wait_id);
|
||||||
DMN_LNX_Entity *process = thread->parent;
|
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)
|
if(thread->thread_state == DMN_LNX_ThreadState_PendingCreation)
|
||||||
{
|
{
|
||||||
// finish thread init
|
// 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);
|
AssertAlways(dmn_lnx_state->threads_pending_creation > 0);
|
||||||
dmn_lnx_state->threads_pending_creation -= 1;
|
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;
|
}break;
|
||||||
default: { Assert(0 && "unexpected ptrace code"); } break;
|
default: { Assert(0 && "unexpected ptrace code"); } break;
|
||||||
}
|
}
|
||||||
@@ -3130,3 +2947,4 @@ dmn_process_iter_end(DMN_ProcessIter *iter)
|
|||||||
}
|
}
|
||||||
MemoryZeroStruct(iter);
|
MemoryZeroStruct(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,13 +136,6 @@ struct DMN_LNX_ProcessAuxv
|
|||||||
U64 pagesz;
|
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;
|
typedef struct DMN_LNX_DynamicInfo DMN_LNX_DynamicInfo;
|
||||||
struct DMN_LNX_DynamicInfo
|
struct DMN_LNX_DynamicInfo
|
||||||
{
|
{
|
||||||
@@ -343,42 +336,29 @@ internal DMN_LNX_EntityNode * dmn_lnx_entity_list_push(Arena *arena, DMN_LNX_Ent
|
|||||||
//- rjf: file descriptor memory reading/writing helpers
|
//- rjf: file descriptor memory reading/writing helpers
|
||||||
internal U64 dmn_lnx_read(int memory_fd, Rng1U64 range, void *dst);
|
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 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 String8 dmn_lnx_read_string_capped(Arena *arena, int memory_fd, U64 base_vaddr, U64 cap_size);
|
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);
|
internal String8 dmn_lnx_read_string(Arena *arena, int memory_fd, U64 base_vaddr);
|
||||||
|
#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))
|
||||||
//~ 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);
|
|
||||||
|
|
||||||
//- rjf: pid => info extraction
|
//- rjf: pid => info extraction
|
||||||
internal String8 dmn_lnx_exe_path_from_pid(Arena *arena, pid_t pid);
|
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 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);
|
internal DMN_LNX_ProcessAuxv dmn_lnx_auxv_from_pid(pid_t pid, ELF_Class elf_class);
|
||||||
|
|
||||||
//- ELF/GNU info from memory
|
//- 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 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 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);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Entity Functions
|
//~ rjf: Entity Functions
|
||||||
|
|
||||||
internal DMN_LNX_Entity *dmn_lnx_entity_alloc(DMN_LNX_Entity *parent, DMN_LNX_EntityKind kind);
|
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 void dmn_lnx_entity_release(DMN_LNX_Entity *entity);
|
||||||
internal DMN_Handle dmn_lnx_handle_from_entity(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_entity_from_handle(DMN_Handle handle);
|
||||||
internal DMN_LNX_Entity *dmn_lnx_thread_from_pid(pid_t pid);
|
internal DMN_LNX_Entity * dmn_lnx_thread_from_pid(pid_t pid);
|
||||||
|
|
||||||
//- Process
|
//- Process
|
||||||
internal void dmn_lnx_process_install_probes();
|
internal void dmn_lnx_process_install_probes();
|
||||||
@@ -390,9 +370,6 @@ 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 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_read_reg_block(DMN_LNX_Entity *thread);
|
||||||
internal B32 dmn_lnx_thread_write_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_set_single_step_flag(DMN_LNX_Entity *thread, B32 is_on);
|
||||||
|
|
||||||
#endif // DEMON_CORE_LINUX_H
|
#endif // DEMON_CORE_LINUX_H
|
||||||
|
|||||||
+112
@@ -179,3 +179,115 @@ elf_dyn_size_from_class(ELF_Class elf_class)
|
|||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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_phdr_size_from_class(ELF_Class elf_class);
|
||||||
internal U64 elf_dyn_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
|
#endif // ELF_H
|
||||||
|
|||||||
@@ -276,3 +276,40 @@ gnu_string_from_property_flags_x86(Arena *arena, GNU_PropertyX86 prop, U32 flags
|
|||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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_note_type(GNU_NoteType note_type);
|
||||||
internal String8 gnu_string_from_property_x86(GNU_PropertyX86 prop);
|
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
|
#endif // GNU_H
|
||||||
|
|||||||
Reference in New Issue
Block a user