Page MenuHomeFreeBSD

D30019.1776486620.diff
No OneTemporary

Size
33 KB
Referenced Files
None
Subscribers
None

D30019.1776486620.diff

Index: sys/amd64/linux/linux.h
===================================================================
--- sys/amd64/linux/linux.h
+++ sys/amd64/linux/linux.h
@@ -445,4 +445,40 @@
l_uintptr_t pending_list;
};
+/* This corresponds to 'struct user_regs_struct' in Linux. */
+struct linux_pt_regset {
+ l_ulong r15;
+ l_ulong r14;
+ l_ulong r13;
+ l_ulong r12;
+ l_ulong rbp;
+ l_ulong rbx;
+ l_ulong r11;
+ l_ulong r10;
+ l_ulong r9;
+ l_ulong r8;
+ l_ulong rax;
+ l_ulong rcx;
+ l_ulong rdx;
+ l_ulong rsi;
+ l_ulong rdi;
+ l_ulong orig_rax;
+ l_ulong rip;
+ l_ulong cs;
+ l_ulong eflags;
+ l_ulong rsp;
+ l_ulong ss;
+ l_ulong fs_base;
+ l_ulong gs_base;
+ l_ulong ds;
+ l_ulong es;
+ l_ulong fs;
+ l_ulong gs;
+};
+
+struct reg;
+
+void bsd_to_linux_regset(struct reg *b_reg,
+ struct linux_pt_regset *l_regset);
+
#endif /* !_AMD64_LINUX_H_ */
Index: sys/amd64/linux/linux_ptrace.c
===================================================================
--- sys/amd64/linux/linux_ptrace.c
+++ sys/amd64/linux/linux_ptrace.c
@@ -173,36 +173,6 @@
l_ulong ss;
};
-struct linux_pt_regset {
- l_ulong r15;
- l_ulong r14;
- l_ulong r13;
- l_ulong r12;
- l_ulong rbp;
- l_ulong rbx;
- l_ulong r11;
- l_ulong r10;
- l_ulong r9;
- l_ulong r8;
- l_ulong rax;
- l_ulong rcx;
- l_ulong rdx;
- l_ulong rsi;
- l_ulong rdi;
- l_ulong orig_rax;
- l_ulong rip;
- l_ulong cs;
- l_ulong eflags;
- l_ulong rsp;
- l_ulong ss;
- l_ulong fs_base;
- l_ulong gs_base;
- l_ulong ds;
- l_ulong es;
- l_ulong fs;
- l_ulong gs;
-};
-
/*
* Translate amd64 ptrace registers between Linux and FreeBSD formats.
* The translation is pretty straighforward, for all registers but
@@ -235,9 +205,8 @@
l_reg->ss = b_reg->r_ss;
}
-static void
-map_regs_to_linux_regset(struct reg *b_reg, unsigned long fs_base,
- unsigned long gs_base, struct linux_pt_regset *l_regset)
+void
+bsd_to_linux_regset(struct reg *b_reg, struct linux_pt_regset *l_regset)
{
l_regset->r15 = b_reg->r_r15;
@@ -261,8 +230,8 @@
l_regset->eflags = b_reg->r_rflags;
l_regset->rsp = b_reg->r_rsp;
l_regset->ss = b_reg->r_ss;
- l_regset->fs_base = fs_base;
- l_regset->gs_base = gs_base;
+ l_regset->fs_base = 0;
+ l_regset->gs_base = 0;
l_regset->ds = b_reg->r_ds;
l_regset->es = b_reg->r_es;
l_regset->fs = b_reg->r_fs;
@@ -477,7 +446,6 @@
struct linux_pt_regset l_regset;
struct iovec iov;
struct pcb *pcb;
- unsigned long fsbase, gsbase;
size_t len;
int error;
@@ -494,10 +462,10 @@
pcb = td->td_pcb;
if (td == curthread)
update_pcb_bases(pcb);
- fsbase = pcb->pcb_fsbase;
- gsbase = pcb->pcb_gsbase;
- map_regs_to_linux_regset(&b_reg, fsbase, gsbase, &l_regset);
+ bsd_to_linux_regset(&b_reg, &l_regset);
+ l_regset.fs_base = pcb->pcb_fsbase;
+ l_regset.gs_base = pcb->pcb_gsbase;
error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
if (error != 0) {
Index: sys/amd64/linux/linux_sysvec.c
===================================================================
--- sys/amd64/linux/linux_sysvec.c
+++ sys/amd64/linux/linux_sysvec.c
@@ -739,7 +739,7 @@
.sv_sigcode = &_binary_linux_locore_o_start,
.sv_szsigcode = &linux_szsigcode,
.sv_name = "Linux ELF64",
- .sv_coredump = elf64_coredump,
+ .sv_coredump = linux64_coredump,
.sv_imgact_try = linux_exec_imgact_try,
.sv_minsigstksz = LINUX_MINSIGSTKSZ,
.sv_minuser = VM_MIN_ADDRESS,
Index: sys/amd64/linux32/linux.h
===================================================================
--- sys/amd64/linux32/linux.h
+++ sys/amd64/linux32/linux.h
@@ -630,4 +630,30 @@
l_uintptr_t pending_list;
};
+/* This corresponds to 'struct user_regs_struct32' in Linux. */
+struct linux_pt_regset32 {
+ l_uint ebx;
+ l_uint ecx;
+ l_uint edx;
+ l_uint esi;
+ l_uint edi;
+ l_uint ebp;
+ l_uint eax;
+ l_uint ds;
+ l_uint es;
+ l_uint fs;
+ l_uint gs;
+ l_uint orig_eax;
+ l_uint eip;
+ l_uint cs;
+ l_uint eflags;
+ l_uint esp;
+ l_uint ss;
+};
+
+struct reg32;
+
+void bsd_to_linux_regset32(struct reg32 *b_reg,
+ struct linux_pt_regset32 *l_regset);
+
#endif /* !_AMD64_LINUX_H_ */
Index: sys/amd64/linux32/linux32_machdep.c
===================================================================
--- sys/amd64/linux32/linux32_machdep.c
+++ sys/amd64/linux32/linux32_machdep.c
@@ -61,6 +61,7 @@
#include <machine/md_var.h>
#include <machine/pcb.h>
#include <machine/psl.h>
+#include <machine/reg.h>
#include <machine/segments.h>
#include <machine/specialreg.h>
#include <x86/ifunc.h>
@@ -721,6 +722,29 @@
return (0);
}
+void
+bsd_to_linux_regset32(struct reg32 *b_reg, struct linux_pt_regset32 *l_regset)
+{
+
+ l_regset->ebx = b_reg->r_ebx;
+ l_regset->ecx = b_reg->r_ecx;
+ l_regset->edx = b_reg->r_edx;
+ l_regset->esi = b_reg->r_esi;
+ l_regset->edi = b_reg->r_edi;
+ l_regset->ebp = b_reg->r_ebp;
+ l_regset->eax = b_reg->r_eax;
+ l_regset->ds = b_reg->r_ds;
+ l_regset->es = b_reg->r_es;
+ l_regset->fs = b_reg->r_fs;
+ l_regset->gs = b_reg->r_gs;
+ l_regset->orig_eax = b_reg->r_eax;
+ l_regset->eip = b_reg->r_eip;
+ l_regset->cs = b_reg->r_cs;
+ l_regset->eflags = b_reg->r_eflags;
+ l_regset->esp = b_reg->r_esp;
+ l_regset->ss = b_reg->r_ss;
+}
+
int futex_xchgl_nosmap(int oparg, uint32_t *uaddr, int *oldval);
int futex_xchgl_smap(int oparg, uint32_t *uaddr, int *oldval);
DEFINE_IFUNC(, int, futex_xchgl, (int, uint32_t *, int *))
Index: sys/amd64/linux32/linux32_sysvec.c
===================================================================
--- sys/amd64/linux32/linux32_sysvec.c
+++ sys/amd64/linux32/linux32_sysvec.c
@@ -906,7 +906,7 @@
.sv_sigcode = &_binary_linux32_locore_o_start,
.sv_szsigcode = &linux_szsigcode,
.sv_name = "Linux ELF32",
- .sv_coredump = elf32_coredump,
+ .sv_coredump = linux32_coredump,
.sv_imgact_try = linux_exec_imgact_try,
.sv_minsigstksz = LINUX_MINSIGSTKSZ,
.sv_minuser = VM_MIN_ADDRESS,
Index: sys/compat/linux/linux_elf.h
===================================================================
--- /dev/null
+++ sys/compat/linux/linux_elf.h
@@ -0,0 +1,57 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Chuck Tuffli
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _COMPAT_LINUX_ELF_H_
+#define _COMPAT_LINUX_ELF_H_
+
+struct l_elf_siginfo {
+ l_int si_signo;
+ l_int si_code;
+ l_int si_errno;
+};
+
+typedef struct linux_pt_regset l_elf_gregset_t;
+
+struct linux_elf_prstatus {
+ struct l_elf_siginfo pr_info;
+ l_short pr_cursig;
+ l_ulong pr_sigpend;
+ l_ulong pr_sighold;
+ l_pid_t pr_pid;
+ l_pid_t pr_ppid;
+ l_pid_t pr_pgrp;
+ l_pid_t pr_sid;
+ l_timeval pr_utime;
+ l_timeval pr_stime;
+ l_timeval pr_cutime;
+ l_timeval pr_cstime;
+ l_elf_gregset_t pr_reg;
+ l_int pr_fpvalid;
+};
+
+#endif
Index: sys/compat/linux/linux_elf.c
===================================================================
--- /dev/null
+++ sys/compat/linux/linux_elf.c
@@ -0,0 +1,531 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2021 Edward Tomasz Napierala <trasz@FreeBSD.org>
+ * Copyright (c) 2018 Chuck Tuffli
+ * Copyright (c) 2017 Dell EMC
+ * Copyright (c) 2000 David O'Brien
+ * Copyright (c) 1995-1996 Søren Schmidt
+ * Copyright (c) 1996 Peter Wemm
+ * All rights reserved.
+ *
+ * This software was developed by the University of Cambridge Computer
+ * Laboratory as part of the CHERI for Hypervisors and Operating Systems
+ * (CHaOS) project, funded by EPSRC grant EP/V000292/1.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Mostly stolen from sys/kern/imgact_elf.c but modified to write
+ * Linux style core files.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/imgact_elf.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+#include <sys/ptrace.h>
+#include <sys/racct.h>
+#include <sys/sbuf.h>
+#include <sys/syslog.h>
+#include <sys/user.h>
+#include <sys/vnode.h>
+
+#include <machine/elf.h>
+
+#if defined(COMPAT_LINUX32) && __ELF_WORD_SIZE == 32
+#define linux_pt_regset linux_pt_regset32
+#define bsd_to_linux_regset bsd_to_linux_regset32
+#include <machine/../linux32/linux.h>
+#else
+#include <machine/../linux/linux.h>
+#endif
+#include <compat/linux/linux_elf.h>
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_misc.h>
+
+#define __linuxN(x) __CONCAT(__CONCAT(__CONCAT(linux,__ELF_WORD_SIZE),_),x)
+
+#define ELF_NOTE_ROUNDSIZE 4
+#define CORE_BUF_SIZE (16 * 1024)
+
+#define LINUX_NT_AUXV 6
+
+/* Linux core notes are labeled "CORE" */
+static const char LINUX_ABI_VENDOR[] = "CORE";
+
+/*
+ * Code for generating ELF core dumps.
+ */
+
+typedef void (*outfunc_t)(void *, struct sbuf *, size_t *);
+
+struct note_info {
+ int type; /* Note type. */
+ outfunc_t outfunc; /* Output function. */
+ void *outarg; /* Argument for the output function. */
+ size_t outsize; /* Output size. */
+ TAILQ_ENTRY(note_info) link; /* Link to the next note info. */
+};
+
+TAILQ_HEAD(note_info_list, note_info);
+
+static int corehdr(struct coredump_params *, int, void *, size_t,
+ struct note_info_list *, size_t);
+static void prepare_notes(struct thread *, struct note_info_list *,
+ size_t *);
+static void putnote(struct note_info *, struct sbuf *);
+static size_t register_note(struct note_info_list *, int, outfunc_t, void *);
+
+static void note_fpregset(void *, struct sbuf *, size_t *);
+static void note_prpsinfo(void *, struct sbuf *, size_t *);
+static void note_prstatus(void *, struct sbuf *, size_t *);
+static void note_threadmd(void *, struct sbuf *, size_t *);
+static void note_linux_nt_auxv(void *, struct sbuf *, size_t *);
+
+int
+__linuxN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
+{
+ struct ucred *cred = td->td_ucred;
+ int error = 0;
+ struct sseg_closure seginfo;
+ struct note_info_list notelst;
+ struct coredump_params params;
+ struct note_info *ninfo;
+ void *hdr, *tmpbuf;
+ size_t hdrsize, notesz, coresize;
+
+ hdr = NULL;
+ tmpbuf = NULL;
+ TAILQ_INIT(&notelst);
+
+ /* Size the program segments. */
+ __elfN(size_segments)(td, &seginfo);
+
+ /*
+ * Collect info about the core file header area.
+ */
+ hdrsize = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * (1 + seginfo.count);
+ if (seginfo.count + 1 >= PN_XNUM)
+ hdrsize += sizeof(Elf_Shdr);
+ prepare_notes(td, &notelst, &notesz);
+ coresize = round_page(hdrsize + notesz) + seginfo.size;
+
+ /* Set up core dump parameters. */
+ params.offset = 0;
+ params.active_cred = cred;
+ params.file_cred = NOCRED;
+ params.td = td;
+ params.vp = vp;
+ params.comp = NULL;
+
+#ifdef RACCT
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ error = racct_add(td->td_proc, RACCT_CORE, coresize);
+ PROC_UNLOCK(td->td_proc);
+ if (error != 0) {
+ error = EFAULT;
+ goto done;
+ }
+ }
+#endif
+ if (coresize >= limit) {
+ error = EFAULT;
+ goto done;
+ }
+
+ /*
+ * Allocate memory for building the header, fill it up,
+ * and write it out following the notes.
+ */
+ hdr = malloc(hdrsize, M_TEMP, M_WAITOK);
+ error = corehdr(&params, seginfo.count, hdr, hdrsize, &notelst,
+ notesz);
+
+ /* Write the contents of all of the writable segments. */
+ if (error == 0) {
+ Elf_Phdr *php;
+ off_t offset;
+ int i;
+
+ php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1;
+ offset = round_page(hdrsize + notesz);
+ for (i = 0; i < seginfo.count; i++) {
+ error = __elfN(core_output)((caddr_t)(uintptr_t)php->p_vaddr,
+ php->p_filesz, offset, &params, tmpbuf);
+ if (error != 0)
+ break;
+ offset += php->p_filesz;
+ php++;
+ }
+ }
+ if (error) {
+ log(LOG_WARNING,
+ "Failed to write core file for process %s (error %d)\n",
+ curproc->p_comm, error);
+ }
+
+done:
+ while ((ninfo = TAILQ_FIRST(&notelst)) != NULL) {
+ TAILQ_REMOVE(&notelst, ninfo, link);
+ free(ninfo, M_TEMP);
+ }
+ if (hdr != NULL)
+ free(hdr, M_TEMP);
+
+ return (error);
+}
+
+/*
+ * Write the core file header to the file, including padding up to
+ * the page boundary.
+ */
+static int
+corehdr(struct coredump_params *p, int numsegs, void *hdr,
+ size_t hdrsize, struct note_info_list *notelst, size_t notesz)
+{
+ struct note_info *ninfo;
+ struct sbuf *sb;
+ int error;
+
+ /* Fill in the header. */
+ bzero(hdr, hdrsize);
+ __elfN(puthdr)(p->td, hdr, hdrsize, numsegs, notesz, ELFOSABI_NONE);
+
+ sb = sbuf_new(NULL, NULL, CORE_BUF_SIZE, SBUF_FIXEDLEN);
+ sbuf_set_drain(sb, __elfN(sbuf_drain_core_output), p);
+ sbuf_start_section(sb, NULL);
+ sbuf_bcat(sb, hdr, hdrsize);
+ TAILQ_FOREACH(ninfo, notelst, link)
+ putnote(ninfo, sb);
+ /* Align up to a page boundary for the program segments. */
+ sbuf_end_section(sb, -1, PAGE_SIZE, 0);
+ error = sbuf_finish(sb);
+ sbuf_delete(sb);
+
+ return (error);
+}
+
+static void
+prepare_notes(struct thread *td, struct note_info_list *list,
+ size_t *sizep)
+{
+ struct proc *p;
+ struct thread *thr;
+ size_t size;
+
+ p = td->td_proc;
+ size = 0;
+
+ /*
+ * To have the debugger select the right thread (LWP) as the initial
+ * thread, we dump the state of the thread passed to us in td first.
+ * This is the thread that causes the core dump and thus likely to
+ * be the right thread one wants to have selected in the debugger.
+ */
+ thr = td;
+ while (thr != NULL) {
+ size += register_note(list, NT_PRSTATUS, note_prstatus, thr);
+ size += register_note(list, NT_PRPSINFO, note_prpsinfo, p);
+ size += register_note(list, LINUX_NT_AUXV, note_linux_nt_auxv, p);
+ size += register_note(list, NT_FPREGSET, note_fpregset, thr);
+ size += register_note(list, -1,
+ note_threadmd, thr);
+
+ thr = (thr == td) ? TAILQ_FIRST(&p->p_threads) :
+ TAILQ_NEXT(thr, td_plist);
+ if (thr == td)
+ thr = TAILQ_NEXT(thr, td_plist);
+ }
+
+ *sizep = size;
+}
+
+static size_t
+register_note(struct note_info_list *list, int type, outfunc_t out, void *arg)
+{
+ struct note_info *ninfo;
+ size_t size, notesize;
+
+ size = 0;
+ out(arg, NULL, &size);
+ ninfo = malloc(sizeof(*ninfo), M_TEMP, M_ZERO | M_WAITOK);
+ ninfo->type = type;
+ ninfo->outfunc = out;
+ ninfo->outarg = arg;
+ ninfo->outsize = size;
+ TAILQ_INSERT_TAIL(list, ninfo, link);
+
+ if (type == -1)
+ return (size);
+
+ notesize = sizeof(Elf_Note) + /* note header */
+ roundup2(sizeof(LINUX_ABI_VENDOR), ELF_NOTE_ROUNDSIZE) +
+ /* note name */
+ roundup2(size, ELF_NOTE_ROUNDSIZE); /* note description */
+
+ return (notesize);
+}
+
+static void
+putnote(struct note_info *ninfo, struct sbuf *sb)
+{
+ Elf_Note note;
+ ssize_t old_len, sect_len;
+ size_t new_len, descsz, i;
+
+ if (ninfo->type == -1) {
+ ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize);
+ return;
+ }
+
+ note.n_namesz = sizeof(LINUX_ABI_VENDOR);
+ note.n_descsz = ninfo->outsize;
+ note.n_type = ninfo->type;
+
+ sbuf_bcat(sb, &note, sizeof(note));
+ sbuf_start_section(sb, &old_len);
+ sbuf_bcat(sb, LINUX_ABI_VENDOR, sizeof(LINUX_ABI_VENDOR));
+ sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0);
+ if (note.n_descsz == 0)
+ return;
+ sbuf_start_section(sb, &old_len);
+ ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize);
+ sect_len = sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0);
+ if (sect_len < 0)
+ return;
+
+ new_len = (size_t)sect_len;
+ descsz = roundup(note.n_descsz, ELF_NOTE_ROUNDSIZE);
+ if (new_len < descsz) {
+ /*
+ * It is expected that individual note emitters will correctly
+ * predict their expected output size and fill up to that size
+ * themselves, padding in a format-specific way if needed.
+ * However, in case they don't, just do it here with zeros.
+ */
+ for (i = 0; i < descsz - new_len; i++)
+ sbuf_putc(sb, 0);
+ } else if (new_len > descsz) {
+ /*
+ * We can't always truncate sb -- we may have drained some
+ * of it already.
+ */
+ KASSERT(new_len == descsz, ("%s: Note type %u changed as we "
+ "read it (%zu > %zu). Since it is longer than "
+ "expected, this coredump's notes are corrupt. THIS "
+ "IS A BUG in the note_procstat routine for type %u.\n",
+ __func__, (unsigned)note.n_type, new_len, descsz,
+ (unsigned)note.n_type));
+ }
+}
+
+/*
+ * Miscellaneous note out functions.
+ */
+
+#if defined(COMPAT_LINUX32) && __ELF_WORD_SIZE == 32
+typedef struct linux_elf_prstatus elf_prstatus_t;
+typedef struct prpsinfo32 elf_prpsinfo_t;
+typedef struct fpreg32 elf_prfpregset_t;
+#else
+typedef struct linux_elf_prstatus elf_prstatus_t;
+typedef prpsinfo_t elf_prpsinfo_t;
+typedef prfpregset_t elf_prfpregset_t;
+#endif
+
+static void
+note_prpsinfo(void *arg, struct sbuf *sb, size_t *sizep)
+{
+ struct sbuf sbarg;
+ size_t len;
+ char *cp, *end;
+ struct proc *p;
+ elf_prpsinfo_t *psinfo;
+ int error;
+
+ p = (struct proc *)arg;
+ if (sb != NULL) {
+ KASSERT(*sizep == sizeof(*psinfo), ("invalid size"));
+ psinfo = malloc(sizeof(*psinfo), M_TEMP, M_ZERO | M_WAITOK);
+ psinfo->pr_version = PRPSINFO_VERSION;
+ psinfo->pr_psinfosz = sizeof(elf_prpsinfo_t);
+ strlcpy(psinfo->pr_fname, p->p_comm, sizeof(psinfo->pr_fname));
+ PROC_LOCK(p);
+ if (p->p_args != NULL) {
+ len = sizeof(psinfo->pr_psargs) - 1;
+ if (len > p->p_args->ar_length)
+ len = p->p_args->ar_length;
+ memcpy(psinfo->pr_psargs, p->p_args->ar_args, len);
+ PROC_UNLOCK(p);
+ error = 0;
+ } else {
+ _PHOLD(p);
+ PROC_UNLOCK(p);
+ sbuf_new(&sbarg, psinfo->pr_psargs,
+ sizeof(psinfo->pr_psargs), SBUF_FIXEDLEN);
+ error = proc_getargv(curthread, p, &sbarg);
+ PRELE(p);
+ if (sbuf_finish(&sbarg) == 0)
+ len = sbuf_len(&sbarg) - 1;
+ else
+ len = sizeof(psinfo->pr_psargs) - 1;
+ sbuf_delete(&sbarg);
+ }
+ if (error || len == 0)
+ strlcpy(psinfo->pr_psargs, p->p_comm,
+ sizeof(psinfo->pr_psargs));
+ else {
+ KASSERT(len < sizeof(psinfo->pr_psargs),
+ ("len is too long: %zu vs %zu", len,
+ sizeof(psinfo->pr_psargs)));
+ cp = psinfo->pr_psargs;
+ end = cp + len - 1;
+ for (;;) {
+ cp = memchr(cp, '\0', end - cp);
+ if (cp == NULL)
+ break;
+ *cp = ' ';
+ }
+ }
+ psinfo->pr_pid = p->p_pid;
+ sbuf_bcat(sb, psinfo, sizeof(*psinfo));
+ free(psinfo, M_TEMP);
+ }
+ *sizep = sizeof(*psinfo);
+}
+
+static void
+note_prstatus(void *arg, struct sbuf *sb, size_t *sizep)
+{
+ struct thread *td;
+ elf_prstatus_t *status;
+#if defined(COMPAT_LINUX32) && __ELF_WORD_SIZE == 32
+ struct reg32 pr_reg;
+#else
+ struct reg pr_reg;
+#endif
+
+ td = (struct thread *)arg;
+ if (sb != NULL) {
+ KASSERT(*sizep == sizeof(*status), ("invalid size"));
+ status = malloc(sizeof(*status), M_TEMP, M_ZERO | M_WAITOK);
+
+ /*
+ * XXX: Some fields missing.
+ */
+ status->pr_cursig = td->td_proc->p_sig;
+ status->pr_pid = td->td_tid;
+
+#if defined(COMPAT_LINUX32) && __ELF_WORD_SIZE == 32
+ fill_regs32(td, &pr_reg);
+#else
+ fill_regs(td, &pr_reg);
+#endif
+ bsd_to_linux_regset(&pr_reg, &status->pr_reg);
+ sbuf_bcat(sb, status, sizeof(*status));
+ free(status, M_TEMP);
+ }
+ *sizep = sizeof(*status);
+}
+
+static void
+note_fpregset(void *arg, struct sbuf *sb, size_t *sizep)
+{
+ struct thread *td;
+ elf_prfpregset_t *fpregset;
+
+ td = (struct thread *)arg;
+ if (sb != NULL) {
+ KASSERT(*sizep == sizeof(*fpregset), ("invalid size"));
+ fpregset = malloc(sizeof(*fpregset), M_TEMP, M_ZERO | M_WAITOK);
+#if defined(COMPAT_LINUX32) && __ELF_WORD_SIZE == 32
+ fill_fpregs32(td, fpregset);
+#else
+ fill_fpregs(td, fpregset);
+#endif
+ sbuf_bcat(sb, fpregset, sizeof(*fpregset));
+ free(fpregset, M_TEMP);
+ }
+ *sizep = sizeof(*fpregset);
+}
+
+/*
+ * Allow for MD specific notes, as well as any MD
+ * specific preparations for writing MI notes.
+ */
+static void
+note_threadmd(void *arg, struct sbuf *sb, size_t *sizep)
+{
+ struct thread *td;
+ void *buf;
+ size_t size;
+
+ td = (struct thread *)arg;
+ size = *sizep;
+ if (size != 0 && sb != NULL)
+ buf = malloc(size, M_TEMP, M_ZERO | M_WAITOK);
+ else
+ buf = NULL;
+ size = 0;
+ __elfN(dump_thread)(td, buf, &size);
+ KASSERT(sb == NULL || *sizep == size, ("invalid size"));
+ if (size != 0 && sb != NULL)
+ sbuf_bcat(sb, buf, size);
+ free(buf, M_TEMP);
+ *sizep = size;
+}
+
+static void
+note_linux_nt_auxv(void *arg, struct sbuf *sb, size_t *sizep)
+{
+ struct proc *p;
+ size_t size;
+
+ p = (struct proc *)arg;
+ if (sb == NULL) {
+ size = 0;
+ sb = sbuf_new(NULL, NULL, 320, SBUF_FIXEDLEN);
+ sbuf_set_drain(sb, sbuf_count_drain, &size);
+ PHOLD(p);
+ proc_getauxv(curthread, p, sb);
+ PRELE(p);
+ sbuf_finish(sb);
+ sbuf_delete(sb);
+ *sizep = size;
+ } else {
+ PHOLD(p);
+ proc_getauxv(curthread, p, sb);
+ PRELE(p);
+ }
+}
Index: sys/compat/linux/linux_elf32.c
===================================================================
--- /dev/null
+++ sys/compat/linux/linux_elf32.c
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Edward Tomasz Napierala <trasz@FreeBSD.org>
+ * Copyright (c) 2002 Doug Rabson
+ * All rights reserved.
+ *
+ * This software was developed by the University of Cambridge Computer
+ * Laboratory as part of the CHERI for Hypervisors and Operating Systems
+ * (CHaOS) project, funded by EPSRC grant EP/V000292/1.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __ELF_WORD_SIZE 32
+#include <compat/linux/linux_elf.c>
Index: sys/compat/linux/linux_elf64.c
===================================================================
--- /dev/null
+++ sys/compat/linux/linux_elf64.c
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Edward Tomasz Napierala <trasz@FreeBSD.org>
+ * Copyright (c) 2002 Doug Rabson
+ * All rights reserved.
+ *
+ * This software was developed by the University of Cambridge Computer
+ * Laboratory as part of the CHERI for Hypervisors and Operating Systems
+ * (CHaOS) project, funded by EPSRC grant EP/V000292/1.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __ELF_WORD_SIZE 64
+#include <compat/linux/linux_elf.c>
Index: sys/compat/linux/linux_emul.h
===================================================================
--- sys/compat/linux/linux_emul.h
+++ sys/compat/linux/linux_emul.h
@@ -58,6 +58,8 @@
void linux_thread_dtor(struct thread *);
void linux_thread_detach(struct thread *);
int linux_common_execve(struct thread *, struct image_args *);
+int linux32_coredump(struct thread *, struct vnode *, off_t, int);
+int linux64_coredump(struct thread *, struct vnode *, off_t, int);
/* process emuldata flags */
#define LINUX_XDEPR_REQUEUEOP 0x00000001 /* uses deprecated
Index: sys/kern/imgact_elf.c
===================================================================
--- sys/kern/imgact_elf.c
+++ sys/kern/imgact_elf.c
@@ -1436,12 +1436,6 @@
Elf_Off offset; /* Offset of segment in core file */
};
-/* Closure for cb_size_segment(). */
-struct sseg_closure {
- int count; /* Count of writable segments. */
- size_t size; /* Total size of all writable segments. */
-};
-
typedef void (*outfunc_t)(void *, struct sbuf *, size_t *);
struct note_info {
@@ -1454,16 +1448,6 @@
TAILQ_HEAD(note_info_list, note_info);
-/* Coredump output parameters. */
-struct coredump_params {
- off_t offset;
- struct ucred *active_cred;
- struct ucred *file_cred;
- struct thread *td;
- struct vnode *vp;
- struct compressor *comp;
-};
-
extern int compress_user_cores;
extern int compress_user_cores_level;
@@ -1476,10 +1460,8 @@
struct note_info_list *, size_t);
static void __elfN(prepare_notes)(struct thread *, struct note_info_list *,
size_t *);
-static void __elfN(puthdr)(struct thread *, void *, size_t, int, size_t);
static void __elfN(putnote)(struct note_info *, struct sbuf *);
static size_t register_note(struct note_info_list *, int, outfunc_t, void *);
-static int sbuf_drain_core_output(void *, const char *, int);
static void __elfN(note_fpregset)(void *, struct sbuf *, size_t *);
static void __elfN(note_prpsinfo)(void *, struct sbuf *, size_t *);
@@ -1543,8 +1525,8 @@
p->active_cred, p->file_cred, resid, p->td));
}
-static int
-core_output(char *base, size_t len, off_t offset, struct coredump_params *p,
+int
+__elfN(core_output)(char *base, size_t len, off_t offset, struct coredump_params *p,
void *tmpbuf)
{
vm_map_t map;
@@ -1618,8 +1600,8 @@
/*
* Drain into a core file.
*/
-static int
-sbuf_drain_core_output(void *arg, const char *data, int len)
+int
+__elfN(sbuf_drain_core_output)(void *arg, const char *data, int len)
{
struct coredump_params *p;
int error, locked;
@@ -1667,9 +1649,7 @@
TAILQ_INIT(&notelst);
/* Size the program segments. */
- seginfo.count = 0;
- seginfo.size = 0;
- each_dumpable_segment(td, cb_size_segment, &seginfo);
+ __elfN(size_segments)(td, &seginfo);
/*
* Collect info about the core file header area.
@@ -1733,7 +1713,7 @@
php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1;
offset = round_page(hdrsize + notesz);
for (i = 0; i < seginfo.count; i++) {
- error = core_output((char *)(uintptr_t)php->p_vaddr,
+ error = __elfN(core_output)((char *)(uintptr_t)php->p_vaddr,
php->p_filesz, offset, &params, tmpbuf);
if (error != 0)
break;
@@ -1800,6 +1780,15 @@
ssc->size += entry->end - entry->start;
}
+void
+__elfN(size_segments)(struct thread *td, struct sseg_closure *seginfo)
+{
+ seginfo->count = 0;
+ seginfo->size = 0;
+
+ each_dumpable_segment(td, cb_size_segment, seginfo);
+}
+
/*
* For each writable segment in the process's memory map, call the given
* function with a pointer to the map entry and some arbitrary
@@ -1875,10 +1864,10 @@
/* Fill in the header. */
bzero(hdr, hdrsize);
- __elfN(puthdr)(p->td, hdr, hdrsize, numsegs, notesz);
+ __elfN(puthdr)(p->td, hdr, hdrsize, numsegs, notesz, ELFOSABI_FREEBSD);
sb = sbuf_new(NULL, NULL, CORE_BUF_SIZE, SBUF_FIXEDLEN);
- sbuf_set_drain(sb, sbuf_drain_core_output, p);
+ sbuf_set_drain(sb, __elfN(sbuf_drain_core_output), p);
sbuf_start_section(sb, NULL);
sbuf_bcat(sb, hdr, hdrsize);
TAILQ_FOREACH(ninfo, notelst, link)
@@ -1951,9 +1940,9 @@
*sizep = size;
}
-static void
+void
__elfN(puthdr)(struct thread *td, void *hdr, size_t hdrsize, int numsegs,
- size_t notesz)
+ size_t notesz, int osabi)
{
Elf_Ehdr *ehdr;
Elf_Phdr *phdr;
@@ -1969,7 +1958,7 @@
ehdr->e_ident[EI_CLASS] = ELF_CLASS;
ehdr->e_ident[EI_DATA] = ELF_DATA;
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
- ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
+ ehdr->e_ident[EI_OSABI] = osabi;
ehdr->e_ident[EI_ABIVERSION] = 0;
ehdr->e_ident[EI_PAD] = 0;
ehdr->e_type = ET_CORE;
Index: sys/modules/linux/Makefile
===================================================================
--- sys/modules/linux/Makefile
+++ sys/modules/linux/Makefile
@@ -13,7 +13,7 @@
VDSO= linux${SFX}_vdso
KMOD= linux
-SRCS= linux_fork.c linux${SFX}_dummy_machdep.c linux_file.c linux_event.c \
+SRCS= linux_elf32.c linux_fork.c linux${SFX}_dummy_machdep.c linux_file.c linux_event.c \
linux_futex.c linux_getcwd.c linux_ioctl.c linux_ipc.c \
linux${SFX}_machdep.c linux_misc.c linux_signal.c \
linux_socket.c linux_stats.c linux_sysctl.c linux${SFX}_sysent.c \
Index: sys/modules/linux64/Makefile
===================================================================
--- sys/modules/linux64/Makefile
+++ sys/modules/linux64/Makefile
@@ -8,7 +8,7 @@
VDSO= linux_vdso
KMOD= linux64
-SRCS= linux_fork.c linux_dummy_machdep.c linux_file.c linux_event.c \
+SRCS= linux_elf64.c linux_fork.c linux_dummy_machdep.c linux_file.c linux_event.c \
linux_futex.c linux_getcwd.c linux_ioctl.c linux_ipc.c \
linux_machdep.c linux_misc.c linux_ptrace.c linux_signal.c \
linux_socket.c linux_stats.c linux_sysctl.c linux_sysent.c \
Index: sys/sys/imgact_elf.h
===================================================================
--- sys/sys/imgact_elf.h
+++ sys/sys/imgact_elf.h
@@ -100,6 +100,25 @@
#define MAX_BRANDS 8
+/*
+ * Structures used for core dumping code.
+ */
+
+struct coredump_params {
+ off_t offset;
+ struct ucred *active_cred;
+ struct ucred *file_cred;
+ struct thread *td;
+ struct vnode *vp;
+ struct compressor *comp;
+};
+
+/* Closure for cb_size_segment(). */
+struct sseg_closure {
+ int count; /* Count of writable segments. */
+ size_t size; /* Total size of all writable segments. */
+};
+
int __elfN(brand_inuse)(Elf_Brandinfo *entry);
int __elfN(insert_brand_entry)(Elf_Brandinfo *entry);
int __elfN(remove_brand_entry)(Elf_Brandinfo *entry);
@@ -108,6 +127,12 @@
size_t __elfN(populate_note)(int, void *, void *, size_t, void **);
void __elfN(stackgap)(struct image_params *, uintptr_t *);
int __elfN(freebsd_copyout_auxargs)(struct image_params *, uintptr_t);
+int __elfN(core_output)(char *base, size_t len, off_t offset,
+ struct coredump_params *p, void *tmpbuf);
+int __elfN(sbuf_drain_core_output)(void *, const char *, int);
+void __elfN(puthdr)(struct thread *, void *, size_t, int, size_t, int);
+void __elfN(size_segments)(struct thread *td, struct sseg_closure *seginfo);
+
/* Machine specific function to dump per-thread information. */
void __elfN(dump_thread)(struct thread *, void *, size_t *);

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 18, 4:30 AM (8 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28373037
Default Alt Text
D30019.1776486620.diff (33 KB)

Event Timeline