Skip to content

Commit

Permalink
[coredump] Avoid Hardcoding x86/x64 Logic
Browse files Browse the repository at this point in the history
While I was working on fixing up `darling-coredump` for ARM64 support, I noticed that there is some x86 code that doesn't really need to be hardcoded at compile time.

If there aren't any other unexpected issues, this should also allow one (in theory) to process a x86 core dump on a non-x86 device.
  • Loading branch information
CuriousTommy committed Dec 13, 2023
1 parent 3435165 commit 4b8daad
Showing 1 changed file with 90 additions and 50 deletions.
140 changes: 90 additions & 50 deletions src/hosttools/src/coredump/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@

#include <linux/time_types.h>

#if __x86_64__
#include <coredump/x86_64.h>
#else
#error Not implemented
#endif

#include <darling-config.h>

Expand Down Expand Up @@ -238,6 +234,10 @@ static const union nt_file_entry* nt_file_get_entry(const struct coredump_params
return (const union nt_file_entry*)((const char*)header + nt_file_header_size(cprm) + (nt_file_entry_size(cprm) * index));
};

static uint16_t get_elf_machine_type(const struct coredump_params* cprm) {
return cprm->universal_header->e_machine;
}

// first tries to open the file directly, then tries to open the file in the lower layer of the overlay
// (because if we're outside the container, the overlay won't be mounted, but the core dump paths would refer to it)
static int open_file(struct coredump_params* cprm, const char* filename, size_t filename_length) {
Expand Down Expand Up @@ -342,7 +342,7 @@ int main(int argc, char** argv) {
return 1;
}

switch (cprm.universal_header->e_machine) {
switch (get_elf_machine_type(&cprm)) {
case EM_X86_64:
case EM_386:
cprm.input_header = cprm.input_corefile_mapping;
Expand Down Expand Up @@ -681,7 +681,7 @@ struct thread_flavor
};

static
void fill_thread_state32(x86_thread_state32_t* state, const struct thread_info* info)
void fill_x86_thread_state32(x86_thread_state32_t* state, const struct thread_info* info)
{
state->eax = info->prstatus->elf32.general_registers.i386.eax;
state->ebx = info->prstatus->elf32.general_registers.i386.ebx;
Expand All @@ -702,14 +702,14 @@ void fill_thread_state32(x86_thread_state32_t* state, const struct thread_info*
}

static
void fill_float_state32(x86_float_state32_t* state, const struct thread_info* info)
void fill_x86_float_state32(x86_float_state32_t* state, const struct thread_info* info)
{
// TODO
memset(state, 0, sizeof(*state));
}

static
void fill_thread_state64(x86_thread_state64_t* state, const struct thread_info* info)
void fill_x86_thread_state64(x86_thread_state64_t* state, const struct thread_info* info)
{
state->rax = info->prstatus->elf64.general_registers.x86_64.ax;
state->rbx = info->prstatus->elf64.general_registers.x86_64.bx;
Expand All @@ -735,7 +735,7 @@ void fill_thread_state64(x86_thread_state64_t* state, const struct thread_info*
}

static
void fill_float_state64(x86_float_state64_t* state, const struct thread_info* info)
void fill_x86_float_state64(x86_float_state64_t* state, const struct thread_info* info)
{
// TODO
memset(state, 0, sizeof(*state));
Expand All @@ -744,6 +744,8 @@ void fill_float_state64(x86_float_state64_t* state, const struct thread_info* in
static
bool macho_dump_headers32(struct coredump_params* cprm)
{
uint16_t machine_type = get_elf_machine_type(cprm);

// Count memory segments and threads
unsigned int segs = cprm->vm_area_count;
unsigned int threads = cprm->thread_info_count;
Expand All @@ -760,16 +762,25 @@ bool macho_dump_headers32(struct coredump_params* cprm)
}

mh.magic = MH_MAGIC;
#ifdef __x86_64__
mh.cputype = CPU_TYPE_X86;
mh.cpusubtype = CPU_SUBTYPE_X86_ALL;
#else
#warning Missing code for this arch
#endif
mh.filetype = MH_CORE;
mh.ncmds = segs + threads;

const int statesize = sizeof(x86_thread_state32_t) + (DUMP_FLOAT_STATE ? sizeof(x86_float_state32_t) : 0) + sizeof(struct thread_flavor) * (DUMP_FLOAT_STATE ? 2 : 1);
int statesize;
switch (machine_type)
{
case EM_386:
mh.cputype = CPU_TYPE_X86;
mh.cpusubtype = CPU_SUBTYPE_X86_ALL;

statesize = sizeof(struct thread_flavor) + sizeof(x86_thread_state32_t);
statesize += (DUMP_FLOAT_STATE ? sizeof(struct thread_flavor) + sizeof(x86_float_state32_t) : 0);
break;

default:
// Missing code for this arch
abort();
}

mh.sizeofcmds = segs * sizeof(struct segment_command) + threads * (sizeof(struct thread_command) + statesize);
mh.flags = 0;

Expand Down Expand Up @@ -837,25 +848,34 @@ bool macho_dump_headers32(struct coredump_params* cprm)
for (size_t i = 0; i < cprm->thread_info_count; ++i) {
const struct thread_info* thread_info = &cprm->thread_infos[i];
struct thread_command* tc = (struct thread_command*) buffer;
struct thread_flavor* tf = (struct thread_flavor*)(tc+1);
struct thread_flavor* tf;

tc->cmd = LC_THREAD;
tc->cmdsize = memsize;

// General registers
tf->flavor = x86_THREAD_STATE32;
tf->count = x86_THREAD_STATE32_COUNT;

fill_thread_state32((x86_thread_state32_t*)tf->state, thread_info);
switch (machine_type)
{
case EM_386:
// General registers
tf = (struct thread_flavor*)(tc+1);
tf->flavor = x86_THREAD_STATE32;
tf->count = x86_THREAD_STATE32_COUNT;
fill_x86_thread_state32((x86_thread_state32_t*)tf->state, thread_info);

// Float registers
if (DUMP_FLOAT_STATE) {
tf = (struct thread_flavor*) (tf->state + sizeof(x86_thread_state32_t));
tf->flavor = x86_FLOAT_STATE32;
tf->count = x86_FLOAT_STATE32_COUNT;
fill_x86_float_state32((x86_float_state32_t*)tf->state, thread_info);
}

#if DUMP_FLOAT_STATE
// Float registers
tf = (struct thread_flavor*) (tf->state + sizeof(x86_thread_state32_t));
tf->flavor = x86_FLOAT_STATE32;
tf->count = x86_FLOAT_STATE32_COUNT;
break;

fill_float_state32((x86_float_state32_t*)tf->state, thread_info);
#endif
default:
// Missing code for this arch
abort();
}

if (!dump_emit(cprm, buffer, memsize))
{
Expand All @@ -873,6 +893,8 @@ bool macho_dump_headers32(struct coredump_params* cprm)
static
bool macho_dump_headers64(struct coredump_params* cprm)
{
uint16_t machine_type = get_elf_machine_type(cprm);

// Count memory segments and threads
unsigned int segs = cprm->vm_area_count;
unsigned int threads = cprm->thread_info_count;
Expand All @@ -889,16 +911,25 @@ bool macho_dump_headers64(struct coredump_params* cprm)
}

mh.magic = MH_MAGIC_64;
#ifdef __x86_64__
mh.cputype = CPU_TYPE_X86_64;
mh.cpusubtype = CPU_SUBTYPE_X86_64_ALL;
#else
#warning Missing code for this arch
#endif
mh.filetype = MH_CORE;
mh.ncmds = segs + threads;

const int statesize = sizeof(x86_thread_state64_t) + (DUMP_FLOAT_STATE ? sizeof(x86_float_state64_t) : 0) + sizeof(struct thread_flavor) * (DUMP_FLOAT_STATE ? 2 : 1);
int statesize;
switch (machine_type)
{
case EM_X86_64:
mh.cputype = CPU_TYPE_X86_64;
mh.cpusubtype = CPU_SUBTYPE_X86_64_ALL;

statesize = sizeof(struct thread_flavor) + sizeof(x86_thread_state64_t);
statesize += (DUMP_FLOAT_STATE ? sizeof(struct thread_flavor) + sizeof(x86_float_state64_t) : 0);
break;

default:
// Missing code for this arch
abort();
}

mh.sizeofcmds = segs * sizeof(struct segment_command_64) + threads * (sizeof(struct thread_command) + statesize);
mh.flags = 0;
mh.reserved = 0;
Expand Down Expand Up @@ -965,25 +996,34 @@ bool macho_dump_headers64(struct coredump_params* cprm)
for (size_t i = 0; i < cprm->thread_info_count; ++i) {
const struct thread_info* thread_info = &cprm->thread_infos[i];
struct thread_command* tc = (struct thread_command*) buffer;
struct thread_flavor* tf = (struct thread_flavor*)(tc+1);
struct thread_flavor* tf;

tc->cmd = LC_THREAD;
tc->cmdsize = memsize;

// General registers
tf->flavor = x86_THREAD_STATE64;
tf->count = x86_THREAD_STATE64_COUNT;

fill_thread_state64((x86_thread_state64_t*)tf->state, thread_info);

#if DUMP_FLOAT_STATE
// Float registers
tf = (struct thread_flavor*) (tf->state + sizeof(x86_thread_state64_t));
tf->flavor = x86_FLOAT_STATE64;
tf->count = x86_FLOAT_STATE64_COUNT;
switch (machine_type)
{
case EM_X86_64:
// General registers
tf = (struct thread_flavor*)(tc+1);
tf->flavor = x86_THREAD_STATE64;
tf->count = x86_THREAD_STATE64_COUNT;
fill_x86_thread_state64((x86_thread_state64_t*)tf->state, thread_info);

// Float registers
if (DUMP_FLOAT_STATE) {
tf = (struct thread_flavor*) (tf->state + sizeof(x86_thread_state64_t));
tf->flavor = x86_FLOAT_STATE64;
tf->count = x86_FLOAT_STATE64_COUNT;
fill_x86_float_state64((x86_float_state64_t*)tf->state, thread_info);
}

fill_float_state64((x86_float_state64_t*)tf->state, thread_info);
#endif
break;

default:
// Missing code for this arch
abort();
}

if (!dump_emit(cprm, buffer, memsize))
{
Expand Down

0 comments on commit 4b8daad

Please sign in to comment.