git: f0d88ce88589 - stable/13 - Store core dump notes for all valid register sets for FreeBSD processes.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 12 May 2022 22:56:36 UTC
The branch stable/13 has been updated by jhb:
URL: https://cgit.FreeBSD.org/src/commit/?id=f0d88ce885897efe90db2a7c81207379e4d4d8b1
commit f0d88ce885897efe90db2a7c81207379e4d4d8b1
Author: John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2022-03-10 23:40:19 +0000
Commit: John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-05-12 22:13:00 +0000
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
(cherry picked from commit 6b71405bfe8dc76834603f8f9e48346c3f49eae0)
Note that this does not remove NT_ARM_ADDR_MASK from the arm64 hook
on stable/13 as NT_ARM_ADDR_MASK is not present in stable/13.
---
sys/kern/imgact_elf.c | 110 +++++++++++++++++++++++++++++++++-----------------
1 file changed, 72 insertions(+), 38 deletions(-)
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index c39a865dcf05..f81f565cacc9 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -102,6 +102,8 @@ static boolean_t __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,
@@ -1505,6 +1507,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. */
@@ -1524,9 +1527,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 *);
@@ -1819,7 +1820,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
@@ -1829,10 +1831,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,
@@ -1952,6 +1951,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)
@@ -2050,7 +2077,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;
@@ -2222,24 +2258,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)
@@ -2284,21 +2302,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