gcore: Use PT_GETREGSET to fetch NT_PRSTATUS and NT_FPREGSET.
Add a elf_putregnote() helper to build the ELF note for a register set. Once nice result of this approach is that this reuses the kernel's support for generating 32-bit register sets for 32-bit processes avoiding the need to duplicate that logic in elf32core.c. Reviewed by: markj Sponsored by: University of Cambridge, Google, Inc. Differential Revision: https://reviews.freebsd.org/D34447
This commit is contained in:
parent
6b71405bfe
commit
4965ac059d
@ -12,65 +12,6 @@
|
||||
#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;
|
||||
#elif defined(__aarch64__)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 13; i++)
|
||||
rd->r[i] = rs->x[i];
|
||||
rd->r_sp = rs->x[13];
|
||||
rd->r_lr = rs->x[14];
|
||||
rd->r_pc = rs->elr;
|
||||
rd->r_cpsr = rs->spsr;
|
||||
#elif defined(__powerpc64__)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
rd->fixreg[i] = rs->fixreg[i];
|
||||
rd->lr = rs->lr;
|
||||
rd->cr = rs->cr;
|
||||
rd->xer = rs->xer;
|
||||
rd->ctr = rs->ctr;
|
||||
rd->pc = rs->pc;
|
||||
#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));
|
||||
#elif defined(__aarch64__)
|
||||
/* ARM64TODO */
|
||||
#elif defined(__powerpc64__)
|
||||
memcpy(rd, rs, sizeof(*rd));
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
elf_convert_siginfo(struct siginfo32 *sid, siginfo_t *sis)
|
||||
{
|
||||
|
@ -89,8 +89,6 @@ typedef struct reg32 elfcore_gregset_t;
|
||||
typedef struct prpsinfo32 elfcore_prpsinfo_t;
|
||||
typedef struct prstatus32 elfcore_prstatus_t;
|
||||
typedef struct ptrace_lwpinfo32 elfcore_lwpinfo_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);
|
||||
static void elf_convert_lwpinfo(struct ptrace_lwpinfo32 *pld,
|
||||
struct ptrace_lwpinfo *pls);
|
||||
#else
|
||||
@ -99,8 +97,6 @@ typedef gregset_t elfcore_gregset_t;
|
||||
typedef prpsinfo_t elfcore_prpsinfo_t;
|
||||
typedef prstatus_t elfcore_prstatus_t;
|
||||
typedef struct ptrace_lwpinfo elfcore_lwpinfo_t;
|
||||
#define elf_convert_gregset(d,s) *d = *s
|
||||
#define elf_convert_fpregset(d,s) *d = *s
|
||||
#define elf_convert_lwpinfo(d,s) *d = *s
|
||||
#endif
|
||||
|
||||
@ -111,9 +107,7 @@ static void cb_size_segment(struct map_entry *, void *);
|
||||
static void each_dumpable_segment(struct map_entry *, segment_callback,
|
||||
void *closure);
|
||||
static void elf_detach(void); /* atexit() handler. */
|
||||
static void *elf_note_fpregset(void *, size_t *);
|
||||
static void *elf_note_prpsinfo(void *, size_t *);
|
||||
static void *elf_note_prstatus(void *, size_t *);
|
||||
static void *elf_note_thrmisc(void *, size_t *);
|
||||
static void *elf_note_ptlwpinfo(void *, size_t *);
|
||||
#if defined(__arm__)
|
||||
@ -139,6 +133,7 @@ static void elf_puthdr(int, pid_t, struct map_entry *, void *, size_t, size_t,
|
||||
size_t, int);
|
||||
static void elf_putnote(int, notefunc_t, void *, struct sbuf *);
|
||||
static void elf_putnotes(pid_t, struct sbuf *, size_t *);
|
||||
static void elf_putregnote(int, lwpid_t, struct sbuf *);
|
||||
static void freemap(struct map_entry *);
|
||||
static struct map_entry *readmap(pid_t);
|
||||
static void *procstat_sysctl(void *, int, size_t, size_t *sizep);
|
||||
@ -376,8 +371,8 @@ elf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep)
|
||||
elf_putnote(NT_PRPSINFO, elf_note_prpsinfo, &pid, sb);
|
||||
|
||||
for (i = 0; i < threads; ++i) {
|
||||
elf_putnote(NT_PRSTATUS, elf_note_prstatus, tids + i, sb);
|
||||
elf_putnote(NT_FPREGSET, elf_note_fpregset, tids + i, sb);
|
||||
elf_putregnote(NT_PRSTATUS, tids[i], sb);
|
||||
elf_putregnote(NT_FPREGSET, tids[i], sb);
|
||||
elf_putnote(NT_THRMISC, elf_note_thrmisc, tids + i, sb);
|
||||
elf_putnote(NT_PTLWPINFO, elf_note_ptlwpinfo, tids + i, sb);
|
||||
#if defined(__arm__)
|
||||
@ -414,6 +409,40 @@ elf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep)
|
||||
*sizep = size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit one register set note section to sbuf.
|
||||
*/
|
||||
static void
|
||||
elf_putregnote(int type, lwpid_t tid, struct sbuf *sb)
|
||||
{
|
||||
Elf_Note note;
|
||||
struct iovec iov;
|
||||
ssize_t old_len;
|
||||
|
||||
iov.iov_base = NULL;
|
||||
iov.iov_len = 0;
|
||||
if (ptrace(PT_GETREGSET, tid, (void *)&iov, type) != 0)
|
||||
return;
|
||||
iov.iov_base = calloc(1, iov.iov_len);
|
||||
if (iov.iov_base == NULL)
|
||||
errx(1, "out of memory");
|
||||
if (ptrace(PT_GETREGSET, tid, (void *)&iov, type) != 0)
|
||||
errx(1, "failed to fetch register set %d", type);
|
||||
|
||||
note.n_namesz = 8; /* strlen("FreeBSD") + 1 */
|
||||
note.n_descsz = iov.iov_len;
|
||||
note.n_type = type;
|
||||
|
||||
sbuf_bcat(sb, ¬e, sizeof(note));
|
||||
sbuf_start_section(sb, &old_len);
|
||||
sbuf_bcat(sb, "FreeBSD", note.n_namesz);
|
||||
sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
|
||||
sbuf_start_section(sb, &old_len);
|
||||
sbuf_bcat(sb, iov.iov_base, iov.iov_len);
|
||||
sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
|
||||
free(iov.iov_base);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit one note section to sbuf.
|
||||
*/
|
||||
@ -654,48 +683,6 @@ elf_note_prpsinfo(void *arg, size_t *sizep)
|
||||
return (psinfo);
|
||||
}
|
||||
|
||||
static void *
|
||||
elf_note_prstatus(void *arg, size_t *sizep)
|
||||
{
|
||||
lwpid_t tid;
|
||||
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(*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 *)&greg, 0);
|
||||
elf_convert_gregset(&status->pr_reg, &greg);
|
||||
|
||||
*sizep = sizeof(*status);
|
||||
return (status);
|
||||
}
|
||||
|
||||
static void *
|
||||
elf_note_fpregset(void *arg, size_t *sizep)
|
||||
{
|
||||
lwpid_t tid;
|
||||
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 *)&fpreg, 0);
|
||||
elf_convert_fpregset(fpregset, &fpreg);
|
||||
|
||||
*sizep = sizeof(*fpregset);
|
||||
return (fpregset);
|
||||
}
|
||||
|
||||
static void *
|
||||
elf_note_thrmisc(void *arg, size_t *sizep)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user