Store core dump notes for all valid register sets for FreeBSD processes.
In particular, use a generic wrapper around struct regset rather than requiring per-regset helpers. This helper replaces the MI __elfN(note_prstatus) and __elfN(note_fpregset) helpers. It also removes the need to explicitly dump NT_ARM_ADDR_MASK in the arm64 __elfN(dump_thread). Reviewed by: markj, emaste Sponsored by: University of Cambridge, Google, Inc. Differential Revision: https://reviews.freebsd.org/D34446
This commit is contained in:
parent
a6db407f15
commit
6b71405bfe
@ -143,25 +143,9 @@ static struct regset regset_arm64_addr_mask = {
|
||||
ELF_REGSET(regset_arm64_addr_mask);
|
||||
|
||||
void
|
||||
elf64_dump_thread(struct thread *td, void *dst, size_t *off)
|
||||
elf64_dump_thread(struct thread *td __unused, void *dst __unused,
|
||||
size_t *off __unused)
|
||||
{
|
||||
struct arm64_addr_mask addr_mask;
|
||||
size_t len, mask_size;
|
||||
|
||||
len = 0;
|
||||
if (dst != NULL) {
|
||||
mask_size = sizeof(addr_mask);
|
||||
get_arm64_addr_mask(®set_arm64_addr_mask, td, &addr_mask,
|
||||
&mask_size);
|
||||
|
||||
len += elf64_populate_note(NT_ARM_ADDR_MASK, &addr_mask, dst,
|
||||
sizeof(addr_mask), NULL);
|
||||
} else {
|
||||
len += elf64_populate_note(NT_ARM_ADDR_MASK, NULL, NULL,
|
||||
sizeof(addr_mask), NULL);
|
||||
}
|
||||
|
||||
*off += len;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -102,6 +102,8 @@ static bool __elfN(check_note)(struct image_params *imgp,
|
||||
uint32_t *fctl0);
|
||||
static vm_prot_t __elfN(trans_prot)(Elf_Word);
|
||||
static Elf_Word __elfN(untrans_prot)(vm_prot_t);
|
||||
static size_t __elfN(prepare_register_notes)(struct thread *td,
|
||||
struct note_info_list *list, struct thread *target_td);
|
||||
|
||||
SYSCTL_NODE(_kern, OID_AUTO, __CONCAT(elf, __ELF_WORD_SIZE),
|
||||
CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
|
||||
@ -1519,6 +1521,7 @@ struct phdr_closure {
|
||||
|
||||
struct note_info {
|
||||
int type; /* Note type. */
|
||||
struct regset *regset; /* Register set. */
|
||||
outfunc_t outfunc; /* Output function. */
|
||||
void *outarg; /* Argument for the output function. */
|
||||
size_t outsize; /* Output size. */
|
||||
@ -1538,9 +1541,7 @@ static int __elfN(corehdr)(struct coredump_params *, int, void *, size_t,
|
||||
struct note_info_list *, size_t, int);
|
||||
static void __elfN(putnote)(struct thread *td, struct note_info *, struct sbuf *);
|
||||
|
||||
static void __elfN(note_fpregset)(void *, struct sbuf *, size_t *);
|
||||
static void __elfN(note_prpsinfo)(void *, struct sbuf *, size_t *);
|
||||
static void __elfN(note_prstatus)(void *, struct sbuf *, size_t *);
|
||||
static void __elfN(note_threadmd)(void *, struct sbuf *, size_t *);
|
||||
static void __elfN(note_thrmisc)(void *, struct sbuf *, size_t *);
|
||||
static void __elfN(note_ptlwpinfo)(void *, struct sbuf *, size_t *);
|
||||
@ -1833,7 +1834,8 @@ __elfN(prepare_notes)(struct thread *td, struct note_info_list *list,
|
||||
p = td->td_proc;
|
||||
size = 0;
|
||||
|
||||
size += __elfN(register_note)(td, list, NT_PRPSINFO, __elfN(note_prpsinfo), p);
|
||||
size += __elfN(register_note)(td, list, NT_PRPSINFO,
|
||||
__elfN(note_prpsinfo), p);
|
||||
|
||||
/*
|
||||
* To have the debugger select the right thread (LWP) as the initial
|
||||
@ -1843,10 +1845,7 @@ __elfN(prepare_notes)(struct thread *td, struct note_info_list *list,
|
||||
*/
|
||||
thr = td;
|
||||
while (thr != NULL) {
|
||||
size += __elfN(register_note)(td, list, NT_PRSTATUS,
|
||||
__elfN(note_prstatus), thr);
|
||||
size += __elfN(register_note)(td, list, NT_FPREGSET,
|
||||
__elfN(note_fpregset), thr);
|
||||
size += __elfN(prepare_register_notes)(td, list, thr);
|
||||
size += __elfN(register_note)(td, list, NT_THRMISC,
|
||||
__elfN(note_thrmisc), thr);
|
||||
size += __elfN(register_note)(td, list, NT_PTLWPINFO,
|
||||
@ -1968,6 +1967,34 @@ __elfN(puthdr)(struct thread *td, void *hdr, size_t hdrsize, int numsegs,
|
||||
each_dumpable_segment(td, cb_put_phdr, &phc, flags);
|
||||
}
|
||||
|
||||
static size_t
|
||||
__elfN(register_regset_note)(struct thread *td, struct note_info_list *list,
|
||||
struct regset *regset, struct thread *target_td)
|
||||
{
|
||||
const struct sysentvec *sv;
|
||||
struct note_info *ninfo;
|
||||
size_t size, notesize;
|
||||
|
||||
size = 0;
|
||||
if (!regset->get(regset, target_td, NULL, &size) || size == 0)
|
||||
return (0);
|
||||
|
||||
ninfo = malloc(sizeof(*ninfo), M_TEMP, M_ZERO | M_WAITOK);
|
||||
ninfo->type = regset->note;
|
||||
ninfo->regset = regset;
|
||||
ninfo->outarg = target_td;
|
||||
ninfo->outsize = size;
|
||||
TAILQ_INSERT_TAIL(list, ninfo, link);
|
||||
|
||||
sv = td->td_proc->p_sysent;
|
||||
notesize = sizeof(Elf_Note) + /* note header */
|
||||
roundup2(strlen(sv->sv_elf_core_abi_vendor) + 1, ELF_NOTE_ROUNDSIZE) +
|
||||
/* note name */
|
||||
roundup2(size, ELF_NOTE_ROUNDSIZE); /* note description */
|
||||
|
||||
return (notesize);
|
||||
}
|
||||
|
||||
size_t
|
||||
__elfN(register_note)(struct thread *td, struct note_info_list *list,
|
||||
int type, outfunc_t out, void *arg)
|
||||
@ -2066,7 +2093,16 @@ __elfN(putnote)(struct thread *td, struct note_info *ninfo, struct sbuf *sb)
|
||||
if (note.n_descsz == 0)
|
||||
return;
|
||||
sbuf_start_section(sb, &old_len);
|
||||
ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize);
|
||||
if (ninfo->regset != NULL) {
|
||||
struct regset *regset = ninfo->regset;
|
||||
void *buf;
|
||||
|
||||
buf = malloc(ninfo->outsize, M_TEMP, M_ZERO | M_WAITOK);
|
||||
(void)regset->get(regset, ninfo->outarg, buf, &ninfo->outsize);
|
||||
sbuf_bcat(sb, buf, ninfo->outsize);
|
||||
free(buf, M_TEMP);
|
||||
} else
|
||||
ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize);
|
||||
sect_len = sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0);
|
||||
if (sect_len < 0)
|
||||
return;
|
||||
@ -2237,24 +2273,6 @@ static struct regset __elfN(regset_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));
|
||||
free(status, M_TEMP);
|
||||
}
|
||||
*sizep = sizeof(*status);
|
||||
}
|
||||
|
||||
static bool
|
||||
__elfN(get_fpregset)(struct regset *rs, struct thread *td, void *buf,
|
||||
size_t *sizep)
|
||||
@ -2299,21 +2317,37 @@ static struct regset __elfN(regset_fpregset) = {
|
||||
};
|
||||
ELF_REGSET(__elfN(regset_fpregset));
|
||||
|
||||
static void
|
||||
__elfN(note_fpregset)(void *arg, struct sbuf *sb, size_t *sizep)
|
||||
static size_t
|
||||
__elfN(prepare_register_notes)(struct thread *td, struct note_info_list *list,
|
||||
struct thread *target_td)
|
||||
{
|
||||
struct thread *td;
|
||||
elf_prfpregset_t *fpregset;
|
||||
struct sysentvec *sv = td->td_proc->p_sysent;
|
||||
struct regset **regsetp, **regset_end, *regset;
|
||||
size_t size;
|
||||
|
||||
td = arg;
|
||||
if (sb != NULL) {
|
||||
KASSERT(*sizep == sizeof(*fpregset), ("invalid size"));
|
||||
fpregset = malloc(sizeof(*fpregset), M_TEMP, M_ZERO | M_WAITOK);
|
||||
__elfN(get_fpregset)(NULL, td, fpregset, sizep);
|
||||
sbuf_bcat(sb, fpregset, sizeof(*fpregset));
|
||||
free(fpregset, M_TEMP);
|
||||
size = 0;
|
||||
|
||||
/* NT_PRSTATUS must be the first register set note. */
|
||||
size += __elfN(register_regset_note)(td, list, &__elfN(regset_prstatus),
|
||||
target_td);
|
||||
|
||||
regsetp = sv->sv_regset_begin;
|
||||
if (regsetp == NULL) {
|
||||
/* XXX: This shouldn't be true for any FreeBSD ABIs. */
|
||||
size += __elfN(register_regset_note)(td, list,
|
||||
&__elfN(regset_fpregset), target_td);
|
||||
return (size);
|
||||
}
|
||||
*sizep = sizeof(*fpregset);
|
||||
regset_end = sv->sv_regset_end;
|
||||
MPASS(regset_end != NULL);
|
||||
for (; regsetp < regset_end; regsetp++) {
|
||||
regset = *regsetp;
|
||||
if (regset->note == NT_PRSTATUS)
|
||||
continue;
|
||||
size += __elfN(register_regset_note)(td, list, regset,
|
||||
target_td);
|
||||
}
|
||||
return (size);
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user