From 195fb4cb45c3f7a3541eb8f592fa51ec7b5b2f2a Mon Sep 17 00:00:00 2001 From: marcel Date: Sat, 26 Jul 2014 16:45:11 +0000 Subject: [PATCH] Create 32-bit core files for 32-bit processes on 64-bit machines. The 64-bit machine supported right now is amd64, but it's not too hard to add powerpc64. Obtained from: Juniper Networks, Inc. --- usr.bin/gcore/Makefile | 4 +++ usr.bin/gcore/elf32core.c | 66 +++++++++++++++++++++++++++++++++++++ usr.bin/gcore/elfcore.c | 68 ++++++++++++++++++++++++++++++--------- 3 files changed, 123 insertions(+), 15 deletions(-) create mode 100644 usr.bin/gcore/elf32core.c diff --git a/usr.bin/gcore/Makefile b/usr.bin/gcore/Makefile index 0f37281e42ff..7fff5403e50e 100644 --- a/usr.bin/gcore/Makefile +++ b/usr.bin/gcore/Makefile @@ -6,6 +6,10 @@ SRCS= elfcore.c gcore.c DPADD= ${LIBSBUF} ${LIBUTIL} LDADD= -lsbuf -lutil +.if ${MACHINE_ARCH} == "amd64" +SRCS+= elf32core.c +.endif + WARNS?= 1 .include diff --git a/usr.bin/gcore/elf32core.c b/usr.bin/gcore/elf32core.c new file mode 100644 index 000000000000..de48500a1f71 --- /dev/null +++ b/usr.bin/gcore/elf32core.c @@ -0,0 +1,66 @@ +/* $FreeBSD$ */ +#ifndef __LP64__ +#error "this file must be compiled for LP64." +#endif + +#define __ELF_WORD_SIZE 32 +#define _MACHINE_ELF_WANT_32BIT + +#include + +struct prpsinfo32 { + int pr_version; + u_int pr_psinfosz; + char pr_fname[PRFNAMESZ+1]; + char pr_psargs[PRARGSZ+1]; +}; + +struct prstatus32 { + int pr_version; + u_int pr_statussz; + u_int pr_gregsetsz; + u_int pr_fpregsetsz; + int pr_osreldate; + int pr_cursig; + pid_t pr_pid; + struct reg32 pr_reg; +}; + +#define ELFCORE_COMPAT_32 1 +#include "elfcore.c" + +static void +elf_convert_gregset(elfcore_gregset_t *rd, struct reg *rs) +{ +#ifdef __amd64__ + rd->r_gs = rs->r_gs; + rd->r_fs = rs->r_fs; + rd->r_es = rs->r_es; + rd->r_ds = rs->r_ds; + rd->r_edi = rs->r_rdi; + rd->r_esi = rs->r_rsi; + rd->r_ebp = rs->r_rbp; + rd->r_ebx = rs->r_rbx; + rd->r_edx = rs->r_rdx; + rd->r_ecx = rs->r_rcx; + rd->r_eax = rs->r_rax; + rd->r_eip = rs->r_rip; + rd->r_cs = rs->r_cs; + rd->r_eflags = rs->r_rflags; + rd->r_esp = rs->r_rsp; + rd->r_ss = rs->r_ss; +#else +#error Unsupported architecture +#endif +} + +static void +elf_convert_fpregset(elfcore_fpregset_t *rd, struct fpreg *rs) +{ +#ifdef __amd64__ + /* XXX this is wrong... */ + memcpy(rd, rs, sizeof(*rd)); +#else +#error Unsupported architecture +#endif +} diff --git a/usr.bin/gcore/elfcore.c b/usr.bin/gcore/elfcore.c index 20e801a4f531..f857dcfb709a 100644 --- a/usr.bin/gcore/elfcore.c +++ b/usr.bin/gcore/elfcore.c @@ -28,6 +28,7 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include #include @@ -73,6 +74,22 @@ struct sseg_closure { size_t size; /* Total size of all writable segments. */ }; +#ifdef ELFCORE_COMPAT_32 +typedef struct fpreg32 elfcore_fpregset_t; +typedef struct reg32 elfcore_gregset_t; +typedef struct prpsinfo32 elfcore_prpsinfo_t; +typedef struct prstatus32 elfcore_prstatus_t; +static void elf_convert_gregset(elfcore_gregset_t *rd, struct reg *rs); +static void elf_convert_fpregset(elfcore_fpregset_t *rd, struct fpreg *rs); +#else +typedef fpregset_t elfcore_fpregset_t; +typedef gregset_t elfcore_gregset_t; +typedef prpsinfo_t elfcore_prpsinfo_t; +typedef prstatus_t elfcore_prstatus_t; +#define elf_convert_gregset(d,s) *d = *s +#define elf_convert_fpregset(d,s) *d = *s +#endif + typedef void* (*notefunc_t)(void *, size_t *); static void cb_put_phdr(vm_map_entry_t, void *); @@ -108,13 +125,28 @@ elf_ident(int efd, pid_t pid __unused, char *binfile __unused) { Elf_Ehdr hdr; int cnt; + uint16_t machine; cnt = read(efd, &hdr, sizeof(hdr)); if (cnt != sizeof(hdr)) return (0); - if (IS_ELF(hdr)) - return (1); - return (0); + if (!IS_ELF(hdr)) + return (0); + switch (hdr.e_ident[EI_DATA]) { + case ELFDATA2LSB: + machine = le16toh(hdr.e_machine); + break; + case ELFDATA2MSB: + machine = be16toh(hdr.e_machine); + break; + default: + return (0); + } + if (!ELF_MACHINE_OK(machine)) + return (0); + + /* Looks good. */ + return (1); } static void @@ -194,7 +226,7 @@ elf_coredump(int efd __unused, int fd, pid_t pid) uintmax_t nleft = php->p_filesz; iorequest.piod_op = PIOD_READ_D; - iorequest.piod_offs = (caddr_t)php->p_vaddr; + iorequest.piod_offs = (caddr_t)(uintptr_t)php->p_vaddr; while (nleft > 0) { char buf[8*1024]; size_t nwant; @@ -311,6 +343,7 @@ elf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep) elf_putnote(NT_THRMISC, elf_note_thrmisc, tids + i, sb); } +#ifndef ELFCORE_COMPAT_32 elf_putnote(NT_PROCSTAT_PROC, elf_note_procstat_proc, &pid, sb); elf_putnote(NT_PROCSTAT_FILES, elf_note_procstat_files, &pid, sb); elf_putnote(NT_PROCSTAT_VMMAP, elf_note_procstat_vmmap, &pid, sb); @@ -321,6 +354,7 @@ elf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep) elf_putnote(NT_PROCSTAT_PSSTRINGS, elf_note_procstat_psstrings, &pid, sb); elf_putnote(NT_PROCSTAT_AUXV, elf_note_procstat_auxv, &pid, sb); +#endif size = sbuf_end_section(sb, old_len, 1, 0); if (size == -1) @@ -491,7 +525,7 @@ static void * elf_note_prpsinfo(void *arg, size_t *sizep) { pid_t pid; - prpsinfo_t *psinfo; + elfcore_prpsinfo_t *psinfo; struct kinfo_proc kip; size_t len; int name[4]; @@ -501,7 +535,7 @@ elf_note_prpsinfo(void *arg, size_t *sizep) if (psinfo == NULL) errx(1, "out of memory"); psinfo->pr_version = PRPSINFO_VERSION; - psinfo->pr_psinfosz = sizeof(prpsinfo_t); + psinfo->pr_psinfosz = sizeof(*psinfo); name[0] = CTL_KERN; name[1] = KERN_PROC; @@ -523,19 +557,21 @@ static void * elf_note_prstatus(void *arg, size_t *sizep) { lwpid_t tid; - prstatus_t *status; + elfcore_prstatus_t *status; + struct reg greg; tid = *(lwpid_t *)arg; status = calloc(1, sizeof(*status)); if (status == NULL) errx(1, "out of memory"); status->pr_version = PRSTATUS_VERSION; - status->pr_statussz = sizeof(prstatus_t); - status->pr_gregsetsz = sizeof(gregset_t); - status->pr_fpregsetsz = sizeof(fpregset_t); + status->pr_statussz = sizeof(*status); + status->pr_gregsetsz = sizeof(elfcore_gregset_t); + status->pr_fpregsetsz = sizeof(elfcore_fpregset_t); status->pr_osreldate = __FreeBSD_version; status->pr_pid = tid; - ptrace(PT_GETREGS, tid, (void *)&status->pr_reg, 0); + ptrace(PT_GETREGS, tid, (void *)&greg, 0); + elf_convert_gregset(&status->pr_reg, &greg); *sizep = sizeof(*status); return (status); @@ -545,13 +581,15 @@ static void * elf_note_fpregset(void *arg, size_t *sizep) { lwpid_t tid; - prfpregset_t *fpregset; + elfcore_fpregset_t *fpregset; + fpregset_t fpreg; tid = *(lwpid_t *)arg; fpregset = calloc(1, sizeof(*fpregset)); if (fpregset == NULL) errx(1, "out of memory"); - ptrace(PT_GETFPREGS, tid, (void *)fpregset, 0); + ptrace(PT_GETFPREGS, tid, (void *)&fpreg, 0); + elf_convert_fpregset(fpregset, &fpreg); *sizep = sizeof(*fpregset); return (fpregset); @@ -700,5 +738,5 @@ elf_note_procstat_rlimit(void *arg, size_t *sizep) return (buf); } -struct dumpers elfdump = { elf_ident, elf_coredump }; -TEXT_SET(dumpset, elfdump); +struct dumpers __elfN(dump) = { elf_ident, elf_coredump }; +TEXT_SET(dumpset, __elfN(dump));