mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-10-06 07:55:42 +00:00
215 lines
6.4 KiB
C
215 lines
6.4 KiB
C
// Copyright (c) Epic Games Tools
|
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
|
|
//- rjf: top-level binary parsing
|
|
|
|
internal ELF_Bin
|
|
elf_bin_from_data(Arena *arena, String8 data)
|
|
{
|
|
ELF_Bin bin = {0};
|
|
if(str8_match(str8_prefix(data, elf_magic_string.size), elf_magic_string, 0) &&
|
|
data.size >= ELF_Identifier_Max)
|
|
{
|
|
//- rjf: parse sig/header
|
|
U8 sig[ELF_Identifier_Max] = {0};
|
|
str8_deserial_read(data, 0, &sig[0], sizeof(sig), 1);
|
|
switch(sig[ELF_Identifier_Class])
|
|
{
|
|
default:
|
|
case ELF_Class_None:{}break;
|
|
case ELF_Class_32:
|
|
{
|
|
ELF_Hdr32 hdr32 = {0};
|
|
U64 hdr_size = str8_deserial_read_struct(data, 0, &hdr32);
|
|
if(hdr_size == sizeof(hdr32))
|
|
{
|
|
bin.hdr = elf_hdr64_from_hdr32(hdr32);
|
|
U64 shstr_off = hdr32.e_shoff + hdr32.e_shentsize*hdr32.e_shstrndx;
|
|
ELF_Shdr32 shdr = {0};
|
|
U64 shdr_size = str8_deserial_read_struct(data, shstr_off, &shdr);
|
|
if(shdr_size == sizeof(shdr))
|
|
{
|
|
bin.sh_name_range = rng_1u64(shdr.sh_offset, shdr.sh_offset + shdr.sh_size);
|
|
}
|
|
}
|
|
}break;
|
|
case ELF_Class_64:
|
|
{
|
|
ELF_Hdr64 hdr64 = {0};
|
|
U64 hdr_size = str8_deserial_read_struct(data, 0, &hdr64);
|
|
if(hdr_size == sizeof(hdr64))
|
|
{
|
|
bin.hdr = hdr64;
|
|
U64 shstr_off = hdr64.e_shoff + hdr64.e_shentsize*hdr64.e_shstrndx;
|
|
ELF_Shdr64 shdr = {0};
|
|
U64 shdr_size = str8_deserial_read_struct(data, shstr_off, &shdr);
|
|
if(shdr_size == sizeof(shdr))
|
|
{
|
|
bin.sh_name_range = rng_1u64(shdr.sh_offset, shdr.sh_offset + shdr.sh_size);
|
|
}
|
|
}
|
|
}break;
|
|
}
|
|
|
|
//- rjf: gather all shdrs
|
|
{
|
|
ELF_Hdr64 *hdr = &bin.hdr;
|
|
bin.shdrs.count = hdr->e_shnum;
|
|
bin.shdrs.v = push_array(arena, ELF_Shdr64, hdr->e_shnum);
|
|
Rng1U64 shdr_range = rng_1u64(hdr->e_shoff, hdr->e_shoff + hdr->e_shentsize*hdr->e_shnum);
|
|
String8 shdr_data = str8_substr(data, shdr_range);
|
|
for EachIndex(shdr_idx, hdr->e_shnum)
|
|
{
|
|
switch(hdr->e_ident[ELF_Identifier_Class])
|
|
{
|
|
default:
|
|
case ELF_Class_None:
|
|
{}break;
|
|
case ELF_Class_32:
|
|
{
|
|
ELF_Shdr32 shdr32 = {0};
|
|
str8_deserial_read_struct(shdr_data, shdr_idx * sizeof(ELF_Shdr32), &shdr32);
|
|
bin.shdrs.v[shdr_idx] = elf_shdr64_from_shdr32(shdr32);
|
|
}break;
|
|
case ELF_Class_64:
|
|
{
|
|
str8_deserial_read_struct(shdr_data, shdr_idx * sizeof(ELF_Shdr64), &bin.shdrs.v[shdr_idx]);
|
|
}break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//- rjf: gather all phdrs
|
|
{
|
|
ELF_Hdr64 *hdr = &bin.hdr;
|
|
bin.phdrs.count = hdr->e_phnum;
|
|
bin.phdrs.v = push_array(arena, ELF_Phdr64, hdr->e_phnum);
|
|
Rng1U64 phdr_range = rng_1u64(hdr->e_phoff, hdr->e_phoff + hdr->e_phentsize*hdr->e_phnum);
|
|
String8 phdr_data = str8_substr(data, phdr_range);
|
|
for EachIndex(phdr_idx, hdr->e_phnum)
|
|
{
|
|
switch(hdr->e_ident[ELF_Identifier_Class])
|
|
{
|
|
default:
|
|
case ELF_Class_None:
|
|
{}break;
|
|
case ELF_Class_32:
|
|
{
|
|
ELF_Phdr32 phdr32 = {0};
|
|
str8_deserial_read_struct(phdr_data, phdr_idx * sizeof(ELF_Phdr32), &phdr32);
|
|
bin.phdrs.v[phdr_idx] = elf_phdr64_from_phdr32(phdr32);
|
|
}break;
|
|
case ELF_Class_64:
|
|
{
|
|
str8_deserial_read_struct(phdr_data, phdr_idx * sizeof(ELF_Phdr64), &bin.phdrs.v[phdr_idx]);
|
|
}break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return bin;
|
|
}
|
|
|
|
//- rjf: extra bin info extraction
|
|
|
|
internal String8
|
|
elf_name_from_shdr64(String8 data, ELF_Bin *bin, ELF_Shdr64 *shdr)
|
|
{
|
|
String8 sh_names = str8_substr(data, bin->sh_name_range);
|
|
String8 name = {0};
|
|
str8_deserial_read_cstr(sh_names, shdr->sh_name, &name);
|
|
return name;
|
|
}
|
|
|
|
internal U64
|
|
elf_base_addr_from_bin(ELF_Bin *bin)
|
|
{
|
|
U64 base_vaddr = 0;
|
|
if(bin->hdr.e_type != ELF_Type_Dyn)
|
|
{
|
|
for EachIndex(phdr_idx, bin->phdrs.count)
|
|
{
|
|
ELF_Phdr64 *phdr = &bin->phdrs.v[phdr_idx];
|
|
if(phdr->p_type == ELF_PType_Load &&
|
|
(base_vaddr == 0 || phdr->p_vaddr < base_vaddr))
|
|
{
|
|
base_vaddr = phdr->p_vaddr;
|
|
}
|
|
}
|
|
}
|
|
return base_vaddr;
|
|
}
|
|
|
|
internal ELF_GnuDebugLink
|
|
elf_gnu_debug_link_from_bin(String8 raw_data, ELF_Bin *bin)
|
|
{
|
|
ELF_GnuDebugLink result = {0};
|
|
for EachIndex(idx, bin->shdrs.count)
|
|
{
|
|
ELF_Shdr64 *shdr = &bin->shdrs.v[idx];
|
|
String8 name = elf_name_from_shdr64(raw_data, bin, shdr);
|
|
if(str8_match(name, str8_lit(".gnu_debuglink"), 0))
|
|
{
|
|
Rng1U64 raw_data_range = rng_1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size);
|
|
String8 data = str8_substr(raw_data, raw_data_range);
|
|
String8 path = {0};
|
|
U32 checksum = 0;
|
|
{
|
|
U64 cursor = 0;
|
|
cursor += str8_deserial_read_cstr(data, cursor, &path);
|
|
cursor = AlignPow2(cursor, 4);
|
|
cursor += str8_deserial_read_struct(data, cursor, &checksum);
|
|
}
|
|
result.path = path;
|
|
result.checksum = checksum;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal ELF_NoteList
|
|
elf_parse_note(Arena *arena, String8 raw_note, ELF_Class elf_class, ELF_MachineKind e_machine)
|
|
{
|
|
ELF_NoteList result = {0};
|
|
|
|
for (U64 cursor = 0; cursor < raw_note.size; ) {
|
|
U32 owner_size;
|
|
U64 owner_size_size = str8_deserial_read_struct(raw_note, cursor, &owner_size);
|
|
if (owner_size_size == 0) { goto exit; }
|
|
cursor += owner_size_size;
|
|
|
|
U32 desc_size;
|
|
U64 desc_size_size = str8_deserial_read_struct(raw_note, cursor, &desc_size);
|
|
if (desc_size_size == 0) { goto exit; }
|
|
cursor += desc_size_size;
|
|
|
|
ELF_NoteType type;
|
|
U64 type_size = str8_deserial_read_struct(raw_note, cursor, &type);
|
|
if (type_size == 0) { goto exit; }
|
|
cursor += type_size;
|
|
|
|
if (cursor + owner_size > raw_note.size) { goto exit; }
|
|
String8 owner = str8_cstring_capped(raw_note.str + cursor, raw_note.str + cursor + owner_size);
|
|
cursor += owner_size;
|
|
|
|
if (cursor + desc_size > raw_note.size) { goto exit; }
|
|
String8 desc = str8_substr(raw_note, r1u64(cursor, cursor + desc_size));
|
|
cursor += desc_size;
|
|
cursor = AlignPow2(cursor, 4);
|
|
|
|
ELF_NoteNode *n = push_array(arena, ELF_NoteNode, 1);
|
|
n->v.owner = owner;
|
|
n->v.desc = desc;
|
|
n->v.type = type;
|
|
|
|
SLLQueuePush(result.first, result.last, n);
|
|
result.count += 1;
|
|
}
|
|
|
|
exit:;
|
|
return result;
|
|
}
|
|
|
|
|