Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ARM64 and musl and fix few mistakes #3

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 64 additions & 15 deletions src/elfcore.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ extern "C" {
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#if defined(__GLIBC__) || defined(__UCLIBC__)
#include <sys/poll.h>
#else
#include <poll.h>
#endif
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/time.h>
Expand Down Expand Up @@ -149,18 +153,29 @@ typedef struct fpregs {
uint32_t fir;
} fpregs;
#define regs mips_regs
#elif defined(__aarch64__)
typedef struct fpxregs { /* No extended FPU registers on Aarch64 */
} fpxregs;
typedef struct fpregs { /* FPU registers */
__uint128_t vregs[32];
unsigned int fpsr;
unsigned int fpcr;
} fpregs;
#define regs aarch64_regs /* General purpose registers */
#endif

typedef struct elf_timeval { /* Time value with microsecond resolution */
long tv_sec; /* Seconds */
long tv_usec; /* Microseconds */
} elf_timeval;

#if !defined(__aarch64__)
typedef struct elf_siginfo { /* Information about signal (unused) */
int32_t si_signo; /* Signal number */
int32_t si_code; /* Extra code */
int32_t si_errno; /* Errno */
} elf_siginfo;
#endif

typedef struct prstatus { /* Information about thread; includes CPU reg*/
elf_siginfo pr_info; /* Info associated with signal */
Expand All @@ -185,7 +200,7 @@ typedef struct prpsinfo { /* Information about process */
unsigned char pr_zomb; /* Zombie */
signed char pr_nice; /* Nice val */
unsigned long pr_flag; /* Flags */
#if defined(__x86_64__) || defined(__mips__)
#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__)
uint32_t pr_uid; /* User ID */
uint32_t pr_gid; /* Group ID */
#else
Expand Down Expand Up @@ -255,6 +270,8 @@ typedef struct core_user { /* Ptrace returns this data for thread state */
#define ELF_ARCH EM_ARM
#elif defined(__mips__)
#define ELF_ARCH EM_MIPS
#elif defined(__aarch64__)
#define ELF_ARCH EM_AARCH64
#endif

/* Wrap a class around system calls, in order to give us access to
Expand Down Expand Up @@ -690,24 +707,24 @@ static Ehdr *SanitizeVDSO(Ehdr *ehdr, size_t start, size_t end) {
/* Phdr[] is not "covered" by expected region. */
return NULL;
}
if (phdr[0].p_type != PT_LOAD || phdr[0].p_vaddr != start || phdr[0].p_vaddr + phdr[0].p_memsz >= end) {
/* Something goofy. */
return NULL;
}
for (i = 1; i < ehdr->e_phnum; i++) {
int pt_load_hdrs = 0;
for (i = 0; i < ehdr->e_phnum; i++) {
if (phdr[i].p_type == PT_LOAD) {
/* Only a single PT_LOAD at index 0 is expected */
return NULL;
pt_load_hdrs++;
}
if (phdr[i].p_vaddr & (sizeof(size_t) - 1)) {
if ((start + phdr[i].p_vaddr) & (phdr[i].p_align - 1)) {
/* Phdr data not properly aligned */
return NULL;
}
if (phdr[i].p_vaddr <= start || end <= phdr[i].p_vaddr + phdr[i].p_filesz) {
if (start + phdr[i].p_vaddr + phdr[i].p_filesz >= end) {
/* The data isn't in the expected range */
return NULL;
}
}
if (pt_load_hdrs != 1) {
/* There should be one and only one PT_LOAD segment */
return NULL;
}
return ehdr;
}

Expand Down Expand Up @@ -965,6 +982,11 @@ static int CreateElfCore(void *handle, ssize_t (*writer)(void *, const void *, s
for (i = 0; i < vdso.ehdr->e_phnum; i++) {
if (vdso_phdr[i].p_type == PT_LOAD) {
/* This will be written as "normal" mapping */
} else if (vdso_phdr[i].p_type == PT_NOTE) {
/* Skip PT_NOTE segment obtained from vdso.
* There should be just one PT_NOTE instance in a core file.
* As otherwise gdb identify such core file as corrupted.
*/
} else {
num_extra_phdrs++;
}
Expand Down Expand Up @@ -1053,7 +1075,7 @@ static int CreateElfCore(void *handle, ssize_t (*writer)(void *, const void *, s
Phdr *vdso_phdr = (Phdr *)(vdso.address + vdso.ehdr->e_phoff);
for (i = 0; i < vdso.ehdr->e_phnum; i++) {
Phdr *p = vdso_phdr + i;
if (p->p_type != PT_LOAD) {
if (p->p_type != PT_LOAD && p->p_type != PT_NOTE) {
vdso_size += p->p_filesz;
}
}
Expand Down Expand Up @@ -1112,7 +1134,7 @@ static int CreateElfCore(void *handle, ssize_t (*writer)(void *, const void *, s
if (vdso.ehdr) {
Phdr *vdso_phdr = (Phdr *)(vdso.address + vdso.ehdr->e_phoff);
for (i = 0; i < vdso.ehdr->e_phnum; i++) {
if (vdso_phdr[i].p_type != PT_LOAD) {
if (vdso_phdr[i].p_type != PT_LOAD && vdso_phdr[i].p_type != PT_NOTE) {
memcpy(&phdr, vdso_phdr + i, sizeof(Phdr));
offset += filesz;
filesz = phdr.p_filesz;
Expand Down Expand Up @@ -1255,7 +1277,9 @@ static int CreateElfCore(void *handle, ssize_t (*writer)(void *, const void *, s
/* This segment has already been dumped, because it is one of
* the mappings[].
*/
} else if (writer(handle, (void *)p->p_vaddr, p->p_filesz) != p->p_filesz) {
} else if (p->p_type == PT_NOTE) {
/* Skip PT_NOTE section obtained from vdso */
} else if (writer(handle, (void *)(p->p_vaddr + vdso.address), p->p_filesz) != p->p_filesz) {
goto done;
}
}
Expand Down Expand Up @@ -1528,13 +1552,25 @@ static inline int GetParentRegs(void *frame, regs *cpu, fpregs *fp, fpxregs *fpx
int rc = 0;
char scratch[4096];
pid_t pid = getppid();
if (sys_ptrace(PTRACE_ATTACH, pid, (void *)0, (void *)0) == 0 && waitpid(pid, (void *)0, __WALL) >= 0) {
if (sys_ptrace(PTRACE_ATTACH, pid, (void *)0, (void *)0) == 0 && waitpid(pid, (int *)0, __WALL) >= 0) {
memset(scratch, 0xFF, sizeof(scratch));
#if defined(__aarch64__)
struct iovec iovec;
iovec.iov_base = scratch;
iovec.iov_len = sizeof(struct regs);
if (sys_ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, &iovec) == 0) {
#else
if (sys_ptrace(PTRACE_GETREGS, pid, scratch, scratch) == 0) {
#endif
memcpy(cpu, scratch, sizeof(struct regs));
SET_FRAME(*(Frame *)frame, *cpu);
memset(scratch, 0xFF, sizeof(scratch));
#if defined(__aarch64__)
iovec.iov_len = sizeof(struct fpregs);
if (sys_ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRFPREG, &iovec) == 0) {
#else
if (sys_ptrace(PTRACE_GETFPREGS, pid, scratch, scratch) == 0) {
#endif
memcpy(fp, scratch, sizeof(struct fpregs));
memset(scratch, 0xFF, sizeof(scratch));
#if defined(__i386__) && !defined(__x86_64__)
Expand Down Expand Up @@ -1664,13 +1700,26 @@ int InternalGetCoreDump(void *frame, int num_threads, pid_t *pids,
hasSSE = 0;
#else
memset(scratch, 0xFF, sizeof(scratch));
#if defined(__aarch64__)
struct iovec iovec;
iovec.iov_base = scratch;
iovec.iov_len = sizeof(struct regs);
if (sys_ptrace(PTRACE_GETREGSET, pids[i], (void *)NT_PRSTATUS, &iovec) == 0) {
#else
if (sys_ptrace(PTRACE_GETREGS, pids[i], scratch, scratch) == 0) {
#endif
memcpy(thread_regs + i, scratch, sizeof(struct regs));
if (main_pid == pids[i]) {
SET_FRAME(*(Frame *)frame, thread_regs[i]);
}
memset(scratch, 0xFF, sizeof(scratch));
#if defined(__aarch64__)
iovec.iov_base = scratch;
iovec.iov_len = sizeof(struct fpregs);
if (sys_ptrace(PTRACE_GETREGSET, pids[i], (void *)NT_PRFPREG, &iovec) == 0) {
#else
if (sys_ptrace(PTRACE_GETFPREGS, pids[i], scratch, scratch) == 0) {
#endif
memcpy(thread_fpregs + i, scratch, sizeof(struct fpregs));
memset(scratch, 0xFF, sizeof(scratch));
#if defined(__i386__) && !defined(__x86_64__)
Expand Down Expand Up @@ -1928,7 +1977,7 @@ int InternalGetCoreDump(void *frame, int num_threads, pid_t *pids,
} else if (rc > 0) {
#ifndef THREADS
/* Child will double-fork, so reap the process, now. */
sys_waitpid(rc, (void *)0, __WALL);
sys_waitpid(rc, (int *)0, __WALL);
#endif
}

Expand Down
54 changes: 53 additions & 1 deletion src/elfcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ extern "C" {
/* We currently only support x86-32, x86-64, ARM, and MIPS on Linux.
* Porting to other related platforms should not be difficult.
*/
#if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || defined(__mips__)) && defined(__linux)
#if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || defined(__mips__) || defined(__aarch64__)) && defined(__linux)

#include <stdarg.h>
#include <stdint.h>
Expand Down Expand Up @@ -105,6 +105,13 @@ typedef struct mips_regs {
unsigned long cp0_cause;
unsigned long unused;
} mips_regs;
#elif defined(__aarch64__)
typedef struct aarch64_regs { /* General purpose registers */
unsigned long long uregs[31];
unsigned long long sp;
unsigned long long pc;
unsigned long long pstate;
} aarch64_regs;
#endif

#if defined(__i386__) && defined(__GNUC__)
Expand Down Expand Up @@ -332,6 +339,51 @@ typedef struct Frame {
(r).lo = (f).mips_regs.lo; \
(r).cp0_epc = (f).mips_regs.cp0_epc; \
} while (0)
#elif defined(__aarch64__)
typedef struct Frame {
struct aarch64_regs aarch64_regs;
int errno_;
pid_t tid;
} Frame;

#define FRAME(f) \
Frame f; \
uint64_t tmp; \
do { \
f.errno_ = errno; \
f.tid = sys_gettid(); \
__asm__ __volatile__ ( \
"stp x0, x1, [%1, #16 * 0]\n" \
"stp x2, x3, [%1, #16 * 1]\n" \
"stp x4, x5, [%1, #16 * 2]\n" \
"stp x6, x7, [%1, #16 * 3]\n" \
"stp x8, x9, [%1, #16 * 4]\n" \
"stp x10, x11, [%1, #16 * 5]\n" \
"stp x12, x13, [%1, #16 * 6]\n" \
"stp x14, x15, [%1, #16 * 7]\n" \
"stp x16, x17, [%1, #16 * 8]\n" \
"stp x18, x19, [%1, #16 * 9]\n" \
"stp x20, x21, [%1, #16 * 10]\n" \
"stp x22, x23, [%1, #16 * 11]\n" \
"stp x24, x25, [%1, #16 * 12]\n" \
"stp x26, x27, [%1, #16 * 13]\n" \
"stp x28, x29, [%1, #16 * 14]\n" \
"mov %0, sp\n" \
"stp x30, %0, [%1, #16 * 15]\n" \
"adr %0, 1f\n" \
"1:\n" \
"stp %0, %0, [%1, #16 * 16]\n" \
: "=&r" (tmp) \
: "r" (&f.aarch64_regs) \
: "memory"); \
} while (0)

#define SET_FRAME(f, r) \
do { \
errno = (f).errno_; \
(r) = (f).aarch64_regs; \
} while (0)

#else
/* If we do not have a hand-optimized assembly version of the FRAME()
* macro, we cannot reliably unroll the stack. So, we show a few additional
Expand Down
Loading