Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/imgact_elf.c
Show First 20 Lines • Show All 2,173 Lines • ▼ Show 20 Lines | if (sb != NULL) { | ||||
} | } | ||||
psinfo->pr_pid = p->p_pid; | psinfo->pr_pid = p->p_pid; | ||||
sbuf_bcat(sb, psinfo, sizeof(*psinfo)); | sbuf_bcat(sb, psinfo, sizeof(*psinfo)); | ||||
free(psinfo, M_TEMP); | free(psinfo, M_TEMP); | ||||
} | } | ||||
*sizep = sizeof(*psinfo); | *sizep = sizeof(*psinfo); | ||||
} | } | ||||
static void | static bool | ||||
__elfN(note_prstatus)(void *arg, struct sbuf *sb, size_t *sizep) | __elfN(get_prstatus)(struct regset *rs, struct thread *td, void *buf, | ||||
size_t *sizep) | |||||
{ | { | ||||
struct thread *td; | |||||
elf_prstatus_t *status; | elf_prstatus_t *status; | ||||
td = arg; | if (buf != NULL) { | ||||
if (sb != NULL) { | KASSERT(*sizep == sizeof(*status), ("%s: invalid size", | ||||
KASSERT(*sizep == sizeof(*status), ("invalid size")); | __func__)); | ||||
status = malloc(sizeof(*status), M_TEMP, M_ZERO | M_WAITOK); | status = buf; | ||||
status->pr_version = PRSTATUS_VERSION; | status->pr_version = PRSTATUS_VERSION; | ||||
status->pr_statussz = sizeof(elf_prstatus_t); | status->pr_statussz = sizeof(elf_prstatus_t); | ||||
status->pr_gregsetsz = sizeof(elf_gregset_t); | status->pr_gregsetsz = sizeof(elf_gregset_t); | ||||
status->pr_fpregsetsz = sizeof(elf_fpregset_t); | status->pr_fpregsetsz = sizeof(elf_fpregset_t); | ||||
status->pr_osreldate = osreldate; | status->pr_osreldate = osreldate; | ||||
status->pr_cursig = td->td_proc->p_sig; | status->pr_cursig = td->td_proc->p_sig; | ||||
status->pr_pid = td->td_tid; | status->pr_pid = td->td_tid; | ||||
#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32 | #if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32 | ||||
fill_regs32(td, &status->pr_reg); | fill_regs32(td, &status->pr_reg); | ||||
#else | #else | ||||
fill_regs(td, &status->pr_reg); | fill_regs(td, &status->pr_reg); | ||||
#endif | #endif | ||||
} | |||||
*sizep = sizeof(*status); | |||||
return (true); | |||||
} | |||||
static bool | |||||
__elfN(set_prstatus)(struct regset *rs, struct thread *td, void *buf, | |||||
size_t size) | |||||
{ | |||||
elf_prstatus_t *status; | |||||
KASSERT(size == sizeof(*status), ("%s: invalid size", __func__)); | |||||
status = buf; | |||||
#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32 | |||||
set_regs32(td, &status->pr_reg); | |||||
#else | |||||
set_regs(td, &status->pr_reg); | |||||
#endif | |||||
return (true); | |||||
} | |||||
static struct regset __elfN(regset_prstatus) = { | |||||
.note = NT_PRSTATUS, | |||||
.size = sizeof(elf_prstatus_t), | |||||
.get = __elfN(get_prstatus), | |||||
.set = __elfN(set_prstatus), | |||||
}; | |||||
ELF_REGSET(__elfN(regset_prstatus)); | |||||
static void | |||||
__elfN(note_prstatus)(void *arg, struct sbuf *sb, size_t *sizep) | |||||
{ | |||||
struct thread *td; | |||||
elf_prstatus_t *status; | |||||
td = arg; | |||||
if (sb != NULL) { | |||||
KASSERT(*sizep == sizeof(*status), ("%s: invalid size", | |||||
__func__)); | |||||
status = malloc(sizeof(*status), M_TEMP, M_ZERO | M_WAITOK); | |||||
__elfN(get_prstatus)(NULL, td, status, sizep); | |||||
sbuf_bcat(sb, status, sizeof(*status)); | sbuf_bcat(sb, status, sizeof(*status)); | ||||
free(status, M_TEMP); | free(status, M_TEMP); | ||||
} | } | ||||
*sizep = sizeof(*status); | *sizep = sizeof(*status); | ||||
} | } | ||||
static bool | |||||
__elfN(get_fpregset)(struct regset *rs, struct thread *td, void *buf, | |||||
size_t *sizep) | |||||
{ | |||||
elf_prfpregset_t *fpregset; | |||||
if (buf != NULL) { | |||||
KASSERT(*sizep == sizeof(*fpregset), ("%s: invalid size", | |||||
__func__)); | |||||
fpregset = buf; | |||||
#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32 | |||||
fill_fpregs32(td, fpregset); | |||||
#else | |||||
fill_fpregs(td, fpregset); | |||||
#endif | |||||
} | |||||
*sizep = sizeof(fpregset); | |||||
return (true); | |||||
} | |||||
static bool | |||||
__elfN(set_fpregset)(struct regset *rs, struct thread *td, void *buf, | |||||
size_t size) | |||||
{ | |||||
elf_prfpregset_t *fpregset; | |||||
fpregset = buf; | |||||
KASSERT(size == sizeof(*fpregset), ("%s: invalid size", __func__)); | |||||
#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32 | |||||
set_fpregs32(td, fpregset); | |||||
#else | |||||
set_fpregs(td, fpregset); | |||||
#endif | |||||
return (true); | |||||
} | |||||
static struct regset __elfN(regset_fpregset) = { | |||||
.note = NT_FPREGSET, | |||||
.size = sizeof(elf_prfpregset_t), | |||||
.get = __elfN(get_fpregset), | |||||
.set = __elfN(set_fpregset), | |||||
}; | |||||
ELF_REGSET(__elfN(regset_fpregset)); | |||||
static void | static void | ||||
__elfN(note_fpregset)(void *arg, struct sbuf *sb, size_t *sizep) | __elfN(note_fpregset)(void *arg, struct sbuf *sb, size_t *sizep) | ||||
{ | { | ||||
struct thread *td; | struct thread *td; | ||||
elf_prfpregset_t *fpregset; | elf_prfpregset_t *fpregset; | ||||
td = arg; | td = arg; | ||||
if (sb != NULL) { | if (sb != NULL) { | ||||
KASSERT(*sizep == sizeof(*fpregset), ("invalid size")); | KASSERT(*sizep == sizeof(*fpregset), ("invalid size")); | ||||
fpregset = malloc(sizeof(*fpregset), M_TEMP, M_ZERO | M_WAITOK); | fpregset = malloc(sizeof(*fpregset), M_TEMP, M_ZERO | M_WAITOK); | ||||
#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32 | __elfN(get_fpregset)(NULL, td, fpregset, sizep); | ||||
jhb: Eventually what we'd like to do I think is to add a hook which iterates over the linker set and… | |||||
Done Inline ActionsI tried this, however found it started to get very complex. We might be able to use the same scheme for all the per-thread data, however the per-proc data expect to take a sbuf where the size may not be known ahead of time. Because of this they may extend the size to fit breaking when called from ptrace. XSAVE would work (as the earlier version of this patch shows) because, while it's dynamic, the size can be fixed during the boot process. andrew: I tried this, however found it started to get very complex. We might be able to use the same… | |||||
Not Done Inline ActionsEh, I was only suggesting this for the per-thread register set notes. For example, note_fpregset here should be fully replaceable by this scheme. jhb: Eh, I was only suggesting this for the per-thread register set notes. For example… | |||||
fill_fpregs32(td, fpregset); | |||||
#else | |||||
fill_fpregs(td, fpregset); | |||||
#endif | |||||
sbuf_bcat(sb, fpregset, sizeof(*fpregset)); | sbuf_bcat(sb, fpregset, sizeof(*fpregset)); | ||||
free(fpregset, M_TEMP); | free(fpregset, M_TEMP); | ||||
} | } | ||||
*sizep = sizeof(*fpregset); | *sizep = sizeof(*fpregset); | ||||
} | } | ||||
static void | static void | ||||
__elfN(note_thrmisc)(void *arg, struct sbuf *sb, size_t *sizep) | __elfN(note_thrmisc)(void *arg, struct sbuf *sb, size_t *sizep) | ||||
▲ Show 20 Lines • Show All 546 Lines • Show Last 20 Lines |
Eventually what we'd like to do I think is to add a hook which iterates over the linker set and writes out core dump notes for each regset making use of the 'get_regset' hook. The one trick is that NT_PRSTATUS has to come first, but we could use this hook to retire this custom function and also the custom dumping of register sets for VFP, XSAVE, etc. Not sure if you were already planning on doing that as a followup to this?