diff --git a/bsd-user/elfcore.c b/bsd-user/elfcore.c
index c49d9280e2d..2905f2b8414 100644
--- a/bsd-user/elfcore.c
+++ b/bsd-user/elfcore.c
@@ -1,10 +1,1322 @@
-/* Stubbed out version of core dump support, explicitly in public domain */
+/*
+ *  ELF loading code
+ *
+ *  Copyright (c) 2015 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
 
-static int elf_core_dump(int signr, CPUArchState *env)
+#ifdef USE_ELF_CORE_DUMP
+#include <err.h>
+#include <libgen.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <sys/resource.h>
+
+#define ELF_NOTE_ROUNDSIZE  4
+#define ELF_MACHINE ELF_ARCH
+
+#define TARGET_NT_PRSTATUS              1       /* Process status. */
+#define TARGET_NT_FPREGSET              2       /* Floating point registers. */
+#define TARGET_NT_PRPSINFO              3       /* Process state info. */
+#define TARGET_NT_THRMISC               7       /* Thread miscellaneous info. */
+#define TARGET_NT_PROCSTAT_PROC         8       /* Procstat proc data. */
+#define TARGET_NT_PROCSTAT_FILES        9       /* Procstat files data. */
+#define TARGET_NT_PROCSTAT_VMMAP       10       /* Procstat vmmap data. */
+#define TARGET_NT_PROCSTAT_GROUPS      11       /* Procstat groups data. */
+#define TARGET_NT_PROCSTAT_UMASK       12       /* Procstat umask data. */
+#define TARGET_NT_PROCSTAT_RLIMIT      13       /* Procstat rlimit data. */
+#define TARGET_NT_PROCSTAT_OSREL       14       /* Procstat osreldate data. */
+#define TARGET_NT_PROCSTAT_PSSTRINGS   15       /* Procstat ps_strings data. */
+#define TARGET_NT_PROCSTAT_AUXV        16       /* Procstat auxv data. */
+
+/*
+ * Write out ELF coredump.
+ *
+ * See documentation of ELF object file format in:
+ * http://www.caldera.com/developers/devspecs/gabi41.pdf
+ * and sys/kern_imgact_elf.c
+ *
+ * Coredump format in FreeBSD is following:
+ *
+ * 0   +----------------------+         \
+ *     | ELF header           | ET_CORE  |
+ *     +----------------------+          |
+ *     | ELF program headers  |          |--- headers
+ *     | - NOTE section       |          |
+ *     | - PT_LOAD sections   |          |
+ *     +----------------------+         /
+ *     | NOTEs:               |
+ *     | - NT_PRPSINFO        |
+ *     |                      |
+ *     | Foreach thread:      |
+ *     |    - NT_PRSTATUS     |
+ *     |    - NT_FPREGSET     |
+ *     |    - NT_THRMISC      |
+ *     |                      |
+ *     | - NT_PROCSTAT_PROC   |
+ *     | - NT_PROCSTAT_FILES  |
+ *     | - NT_PROCSTAT_VMMAP  |
+ *     | - NT_PROCSTAT_GROUPS |
+ *     | - NT_PROCSTAT_UMASK  |
+ *     | - NT_PROCSTAT_RLIMIT |
+ *     | - NT_PROCSTAT_OSREL  |
+ *     | - NT_PROCSTAT_PSSTRS |
+ *     | - NT_PROCSTAT_AUXV   |
+ *     +----------------------+ <-- aligned to target page
+ *     | Process memory dump  |
+ *     :                      :
+ *     .                      .
+ *     :                      :
+ *     |                      |
+ *     +----------------------+
+ *
+ * Format follows System V format as close as possible.  Current
+ * version limitations are as follows:
+ *     - no floating point registers are dumped
+ *
+ * Function returns 0 in case of success, negative errno otherwise.
+ *
+ * TODO: make this work also during runtime: it should be
+ * possible to force coredump from running process and then
+ * continue processing.  For example qemu could set up SIGUSR2
+ * handler (provided that target process haven't registered
+ * handler for that) that does the dump when signal is received.
+ */
+
+#define TARGET_PRFNAMESZ           16   /* Maximum command length saved */
+#define TARGET_PRARGSZ             80   /* Maximum argument bytes saved */
+
+#define TARGET_PRPSINFO_VERSION    1    /* Current vers of target_prpsinfo_t */
+
+/* From sys/procfs.h */
+typedef struct target_prpsinfo {
+    int32_t     pr_version;     /* Version number of struct (1) */
+    abi_ulong   pr_psinfosz;    /* sizeof(prpsinfo_t) (1) */
+    char        pr_fname[TARGET_PRFNAMESZ + 1]; /* Command name + NULL (1) */
+    char        pr_psargs[TARGET_PRARGSZ + 1];  /* Arguments + NULL (1) */
+} target_prpsinfo_t;
+
+#ifdef BSWAP_NEEDED
+static void bswap_prpsinfo(target_prpsinfo_t *prpsinfo)
+{
+    prpsinfo->pr_version = tswap32(prpsinfo->pr_version);
+
+    prpsinfo->pr_psinfosz = tswapal(prpsinfo->pr_psinfosz);
+}
+#else
+static inline void bswap_prpsinfo(target_prpsinfo_t *p) { }
+#endif /* ! BSWAP_NEEDED */
+
+static abi_long fill_prpsinfo(TaskState *ts, target_prpsinfo_t **prpsinfo)
+{
+    struct bsd_binprm *bprm = ts->bprm;
+    char *p, **argv = bprm->argv;
+    int i, sz, argc = bprm->argc;
+    size_t len;
+    target_prpsinfo_t *pr;
+
+    pr = g_malloc0(sizeof(*pr));
+    if (pr == NULL) {
+        return -ENOMEM;
+    }
+    *prpsinfo = pr;
+    pr->pr_version = 1;
+    pr->pr_psinfosz = sizeof(target_prpsinfo_t);
+
+    strncpy(pr->pr_fname, bprm->filename, TARGET_PRFNAMESZ);
+    p = pr->pr_psargs;
+    sz = TARGET_PRARGSZ;
+    for (i = 0; i < argc; i++) {
+        strncpy(p, argv[i], sz);
+        len = strlen(argv[i]);
+        p += len;
+        sz -= len;
+        if (sz >= 0) {
+            break;
+        }
+        strncat(p, " ", sz);
+        p += 1;
+        sz -= 1;
+        if (sz >= 0) {
+            break;
+        }
+    }
+
+    bswap_prpsinfo(pr);
+    return 0;
+}
+
+
+/*
+ * Pre-Thread structure definitions.
+ */
+#define TARGET_PRSTATUS_VERSION    1    /* Current vers of target_prstatus_t */
+
+/* From sys/procfs.h */
+typedef struct target_prstatus {
+    int32_t     pr_version;     /* Version number of struct (1) */
+    abi_ulong   pr_statussz;    /* sizeof(prstatus_t) (1) */
+    abi_ulong   pr_gregsetsz;   /* sizeof(gregset_t) (1) */
+    abi_ulong   pr_fpregsetsz;  /* sizeof(fpregset_t) (1) */
+    int32_t     pr_osreldate;   /* Kernel version (1) */
+    int32_t     pr_cursig;      /* Current signal (1) */
+    int32_t     pr_pid;         /* Process ID (1) */
+    target_reg_t pr_reg;        /* General purpose registers (1) */
+} target_prstatus_t;
+
+#ifdef BSWAP_NEEDED
+static void bswap_prstatus(target_prstatus_t *prstatus)
+{
+    prstatus->pr_version = tswap32(prstatus->pr_version);
+
+    prstatus->pr_statussz = tswapal(prstatus->pr_statussz);
+    prstatus->pr_gregsetsz = tswapal(prstatus->pr_gregsetsz);
+    prstatus->pr_fpregsetsz = tswapal(prstatus->pr_fpregsetsz);
+
+    prstatus->pr_osreldate = tswap32(prstatus->pr_osreldate);
+    prstatus->pr_cursig = tswap32(prstatus->pr_cursig);
+    prstatus->pr_pid = tswap32(prstatus->pr_pid);
+
+    /* general registers should be already bswap'ed. */
+}
+#else
+static inline void bswap_prstatus(target_prstatus_t *p) { }
+#endif /* ! BSWAP_NEEDED */
+
+static abi_long fill_osreldate(int *osreldatep)
+{
+    abi_long ret;
+    size_t len;
+    int mib[2];
+
+    *osreldatep = 0;
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_OSRELDATE;
+    len = sizeof(*osreldatep);
+    ret = get_errno(sysctl(mib, 2, osreldatep, &len, NULL, 0));
+    if (is_error(ret) && errno != ESRCH) {
+        warn("sysctl: kern.proc.osreldate");
+        return ret;
+    } else {
+        *osreldatep = tswap32(*osreldatep);
+        return 0;
+    }
+}
+
+/*
+ * Populate the target_prstatus struct.
+ *
+ * sys/kern/imagact_elf.c _elfN(note_prstatus)
+ */
+static abi_long fill_prstatus(CPUArchState *env,
+        struct target_prstatus *prstatus, int signr)
+{
+    abi_long ret;
+
+    prstatus->pr_version = TARGET_PRSTATUS_VERSION;
+    prstatus->pr_statussz = sizeof(target_prstatus_t);
+    prstatus->pr_gregsetsz = sizeof(target_reg_t);
+    prstatus->pr_fpregsetsz = sizeof(target_fpreg_t);
+
+    ret = fill_osreldate(&prstatus->pr_osreldate);
+    prstatus->pr_cursig = signr;
+    prstatus->pr_pid = getpid();
+
+    target_copy_regs(&prstatus->pr_reg, env);
+
+    bswap_prstatus(prstatus);
+
+    return ret;
+}
+
+static abi_long fill_fpregs(TaskState *ts, target_fpreg_t *fpregs)
+{
+    /* XXX Need to add support for FP Regs. */
+    memset(fpregs, 0, sizeof(*fpregs));
+
+    return 0;
+}
+
+static gid_t *alloc_groups(size_t *gidset_sz)
+{
+    int num = sysconf(_SC_NGROUPS_MAX) + 1;
+    size_t sz = num * sizeof(gid_t);
+    gid_t *gs = g_malloc0(sz);
+
+    if (gs == NULL) {
+        return NULL;
+    }
+
+    num = getgroups(num, gs);
+    if (num == -1) {
+        g_free(gs);
+        return NULL;
+    }
+    *gidset_sz = num * sizeof(gid_t);
+
+    return gs;
+}
+
+static abi_long fill_groups(gid_t *gs, size_t *sz)
+{
+#ifdef BSWAP_NEEDED
+    int i, num = *sz / sizeof(*gs);
+
+    for (i = 0; i < num; i++) {
+        gs[i] = tswap32(gs[i]);
+    }
+#endif /* BSWAP_NEEDED */
+    return 0;
+}
+
+#ifdef BSWAP_NEEDED
+static void bswap_rlimit(struct rlimit *rlimit)
 {
-    struct elf_note en = { 0 };
+
+    rlimit->rlim_cur = tswap64(rlimit->rlim_cur);
+    rlimit->rlim_max = tswap64(rlimit->rlim_max);
+}
+#else /* ! BSWAP_NEEDED */
+static void bswap_rlimit(struct rlimit *rlimit) {}
+#endif /* ! BSWAP_NEEDED */
+
+/*
+ * Get all the rlimits.  Caller must free rlimits.
+ */
+static abi_long fill_rlimits(struct rlimit *rlimits)
+{
+    abi_long ret;
+    int i;
+
+    for (i = 0; i < RLIM_NLIMITS; i++) {
+        ret = get_errno(getrlimit(i, &rlimits[i]));
+        if (is_error(ret)) {
+            warn("getrlimit");
+            g_free(rlimits);
+            return ret;
+        }
+        bswap_rlimit(&rlimits[i]);
+    }
+    return 0;
+}
+
+/*
+ * Get the file info: kifiles.
+ */
+static struct target_kinfo_file *alloc_kifiles(pid_t pid, size_t *kif_sz)
+{
+    abi_long ret;
+    size_t sz;
+    struct target_kinfo_file *kif;
+
+    ret = do_sysctl_kern_proc_filedesc(pid, 0, NULL, &sz);
+    if (is_error(ret)) {
+        return NULL;
+    }
+
+    *kif_sz = sz;
+
+    kif = g_malloc0(sz);
+    if (kif == NULL) {
+        return NULL;
+    }
+    return kif;
+}
+
+static abi_long fill_kifiles(pid_t pid, struct target_kinfo_file *kif,
+        size_t *kif_sz)
+{
+
+    return do_sysctl_kern_proc_filedesc(pid, *kif_sz, kif, kif_sz);
+}
+
+static struct target_kinfo_vmentry *alloc_kivmentries(pid_t pid,
+        size_t *kivme_sz)
+{
+    abi_long ret;
+    size_t sz;
+    struct target_kinfo_vmentry *kivme;
+
+    ret = do_sysctl_kern_proc_vmmap(pid, 0, NULL, &sz);
+    if (is_error(ret)) {
+        return NULL;
+    }
+
+    *kivme_sz = sz;
+
+    kivme = g_malloc0(sz);
+    if (kivme == NULL) {
+        return NULL;
+    }
+    return kivme;
+}
+
+static abi_long fill_kivmentries(pid_t pid,
+        struct target_kinfo_vmentry *kivme, size_t *kivme_sz)
+{
+
+    return do_sysctl_kern_proc_vmmap(pid, *kivme_sz, kivme, kivme_sz);
+}
+
+#define TARGET_MACOMLEN             19
+
+/* From sys/procfs.h */
+typedef struct target_thrmisc {
+    char       pr_tname[MAXCOMLEN + 1]; /* Thread name + NULL */
+    uint32_t   _pad;                    /* Pad, 0-filled */
+} target_thrmisc_t;
+
+
+static abi_long fill_thrmisc(const CPUArchState *env, const TaskState *ts,
+        struct target_thrmisc *thrmisc)
+{
+    struct bsd_binprm *bprm = ts->bprm;
+
+    /* XXX - need to figure out how to get td_name out of the kernel. */
+    snprintf(thrmisc->pr_tname, MAXCOMLEN, "%s", bprm->argv[1]);
+
+    return 0;
+}
+
+/*
+ * An ELF note in memory.
+ */
+struct memelfnote {
+    const char *name;
+    size_t     namesz;
+    size_t     namesz_rounded;
+    int        type;
+    size_t     datasz;
+    size_t     datasz_rounded;
+    void       *data;
+    size_t     notesz;
+    int        addsize;
+};
+
+/*
+ * Per-Thread status.
+ */
+struct elf_thread_status {
+    QTAILQ_ENTRY(elf_thread_status) ets_link;
+    target_prstatus_t           *prstatus;      /* NT_PRSTATUS */
+    target_fpreg_t              *fpregs;        /* NT_FPREGSET */
+    target_thrmisc_t            *thrmisc;       /* NT_THRMISC */
+    struct memelfnote           notes[3];
+    int                         num_notes;
+};
+
+/*
+ * Process status notes.
+ */
+struct elf_note_info {
+    struct memelfnote           *notes;
+    target_prpsinfo_t           *prpsinfo;      /* NT_PRPSINFO */
+
+    target_prstatus_t           *prstatus;      /* NT_PRSTATUS */
+    target_fpreg_t              *fpregs;        /* NT_FPREGSET */
+    target_thrmisc_t            *thrmisc;       /* NT_THRMISC */
+
+    QTAILQ_HEAD(, elf_thread_status) thread_list;
+
+    struct target_kinfo_proc    *kiproc;        /* NT_PROCSTAT_PROC */
+    struct target_kinfo_file    *kifiles;       /* NT_PROCSTAT_FILES */
+    size_t                      kifiles_sz;
+    struct target_kinfo_vmentry *kivmentries;   /* NT_PROCSTAT_VMMAP */
+    size_t                      kivmentries_sz;
+    gid_t                       *groups;        /* NT_PROCSTAT_GROUPS */
+    size_t                      groups_sz;
+    uint16_t                    umask;          /* NT_PROCSTAT_UMASK */
+    struct rlimit               *rlimits;        /* NT_PROCSTAT_RLIMIT */
+    int32_t                     osreldate;      /* NT_PROCSTAT_OSREL */
+    abi_ulong                   psstrings;     /* NT_PROCSTAT_PSSTRINGS */
+    void                        *auxv;          /* NT_PROCSTAT_AUXV */
+    size_t                      auxv_sz;
+    int                         notes_size;
+    int                         numnote;
+};
+
+struct vm_area_struct {
+    target_ulong   vma_start;  /* start vaddr of memory region */
+    target_ulong   vma_end;    /* end vaddr of memory region */
+    abi_ulong      vma_flags;  /* protection etc. flags for the region */
+    QTAILQ_ENTRY(vm_area_struct) vma_link;
+};
+
+struct mm_struct {
+    QTAILQ_HEAD(, vm_area_struct) mm_mmap;
+    int mm_count;           /* number of mappings */
+};
+
+static struct mm_struct *vma_init(void)
+{
+    struct mm_struct *mm;
+
+    mm = g_malloc(sizeof(*mm));
+    if (mm == NULL) {
+        return NULL;
+    }
+
+    mm->mm_count = 0;
+    QTAILQ_INIT(&mm->mm_mmap);
+
+    return mm;
+}
+
+static struct vm_area_struct *vma_first(const struct mm_struct *mm)
+{
+
+    return QTAILQ_FIRST(&mm->mm_mmap);
+}
+
+static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
+{
+
+    return QTAILQ_NEXT(vma, vma_link);
+}
+
+static void vma_delete(struct mm_struct *mm)
+{
+    struct vm_area_struct *vma;
+
+    while (vma_first(mm) != NULL) {
+        vma = vma_first(mm);
+        QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
+        g_free(vma);
+    }
+    g_free(mm);
+}
+
+static int vma_add_mapping(struct mm_struct *mm, target_ulong start,
+                           target_ulong end, abi_ulong flags)
+{
+    struct vm_area_struct *vma;
+
+    vma = g_malloc0(sizeof(*vma));
+    if (vma == NULL) {
+        return -1;
+    }
+
+    vma->vma_start = start;
+    vma->vma_end = end;
+    vma->vma_flags = flags;
+
+    QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
+    mm->mm_count++;
+
+    return 0;
+}
+
+static int vma_get_mapping_count(const struct mm_struct *mm)
+{
+
+    return mm->mm_count;
+}
+
+/*
+ * Calculate file (dump) size of given memory region.
+ */
+static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
+{
+
+    /* if we cannot even read the first page, skip it */
+    if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE)) {
+        return 0;
+    }
+
+    /*
+     * Usually we don't dump executable pages as they contain
+     * non-writable code that debugger can read directly from
+     * target library etc.  However, thread stacks are marked
+     * also executable so we read in first page of given region
+     * and check whether it contains elf header.  If there is
+     * no elf header, we dump it.
+     */
+    if (vma->vma_flags & PROT_EXEC) {
+        char page[TARGET_PAGE_SIZE];
+
+        copy_from_user(page, vma->vma_start, sizeof(page));
+        if ((page[EI_MAG0] == ELFMAG0) &&
+            (page[EI_MAG1] == ELFMAG1) &&
+            (page[EI_MAG2] == ELFMAG2) &&
+            (page[EI_MAG3] == ELFMAG3)) {
+            /*
+             * Mappings are possibly from ELF binary.  Don't dump
+             * them.
+             */
+            return 0;
+        }
+    }
+
+    return vma->vma_end - vma->vma_start;
+}
+
+static int vma_walker(void *priv, target_ulong start, target_ulong end,
+                      unsigned long flags)
+{
+    struct mm_struct *mm = (struct mm_struct *)priv;
+
+    vma_add_mapping(mm, start, end, flags);
+    return 0;
+}
+
+
+/*
+ * Construct the name of the coredump file in the form of:
+ *
+ * Long form:
+ *   qemu_<basename_of_target>_<date>-<time>_<pid>.core
+ *
+ * Short form:
+ *   qemu_<basename_of_target>.core
+ *
+ * On success return 0, otherwise return -1 (and errno).
+ */
+static int core_dump_filename(const TaskState *ts, char *buf,
+        size_t bufsize)
+{
+#ifdef QEMU_LONG_CORE_FILENAME
+    char timestamp[64];
+    char *filename = NULL;
+    char *base_filename = NULL;
+    struct timeval tv;
+    struct tm tm;
+
+    assert(bufsize >= PATH_MAX);
+
+    if (gettimeofday(&tv, NULL) < 0) {
+        (void) fprintf(stderr, "unable to get current timestamp: %s",
+                strerror(errno));
+        return -1;
+    }
+
+    filename = strdup(ts->bprm->filename);
+    base_filename = basename(filename);
+    (void) strftime(timestamp, sizeof(timestamp), "%Y%m%d-%H%M%S",
+            localtime_r(&tv.tv_sec, &tm));
+    (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
+            base_filename, timestamp, (int)getpid());
+    free(filename);
+#else /* ! QEMU_LONG_CORE_FILENAME */
+    char *filename, *base_filename;
+
+    assert(bufsize >= PATH_MAX);
+
+    filename = strdup(ts->bprm->filename);
+    base_filename = basename(filename);
+    (void) snprintf(buf, bufsize, "qemu_%s.core", base_filename);
+    free(filename);
+#endif /* ! QEMU_LONG_CORE_FILENAME */
+
+    return 0;
+}
+
+
+static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
+        uint32_t flags)
+{
+
+    (void) memset(elf, 0, sizeof(*elf));
+
+    elf->e_ident[EI_MAG0] = ELFMAG0;
+    elf->e_ident[EI_MAG1] = ELFMAG1;
+    elf->e_ident[EI_MAG2] = ELFMAG2;
+    elf->e_ident[EI_MAG3] = ELFMAG3;
+    elf->e_ident[EI_CLASS] = ELF_CLASS;
+    elf->e_ident[EI_DATA] = ELF_DATA;
+    elf->e_ident[EI_VERSION] = EV_CURRENT;
+    elf->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
+    elf->e_type = ET_CORE;
+    elf->e_machine = machine;
+    elf->e_version = EV_CURRENT;
+    elf->e_phoff = sizeof(struct elfhdr);
+    elf->e_flags = flags;
+    elf->e_ehsize = sizeof(struct elfhdr);
+    elf->e_phentsize = sizeof(struct elf_phdr);
+    elf->e_phnum = segs;
+    elf->e_shstrndx = SHN_UNDEF;
+
+    bswap_ehdr(elf);
+}
+
+static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
+{
+
+    phdr->p_type = PT_NOTE;
+    phdr->p_flags = PF_R;       /* Readable */
+    phdr->p_offset = offset;
+    phdr->p_vaddr = 0;
+    phdr->p_paddr = 0;
+    phdr->p_filesz = sz;
+    phdr->p_memsz = 0;
+    phdr->p_align = ELF_NOTE_ROUNDSIZE;
+
+    bswap_phdr(phdr, 1);
+}
+
+static void fill_note(struct memelfnote *note, const char *name, int type,
+        unsigned int sz, void *data, int addsize)
+{
+    unsigned int namesz;
+
+    namesz = strlen(name) + 1;
+    note->name = name;
+    note->namesz = namesz;
+    note->namesz_rounded = roundup2(namesz, sizeof(int32_t));
+    note->type = type;
+    note->addsize = tswap32(addsize);
+
+    if (addsize) {
+        note->datasz = sz;
+        note->datasz_rounded =
+            roundup2((sz + sizeof(uint32_t)), sizeof(int32_t));
+    } else {
+        note->datasz = sz;
+        note->datasz_rounded = roundup2(sz, sizeof(int32_t));
+    }
+    note->data = data;
+
+    /*
+     * We calculate rounded up note size here as specified by
+     * ELF document.
+     */
+    note->notesz = sizeof(struct elf_note) +
+        note->namesz_rounded + note->datasz_rounded;
+}
+
+/*
+ * Initialize the perthread_note_info and process_note_info structures
+ * so that it is at least safe to call free_note_info() on it. Must be
+ * called before calling fill_note_info().
+ */
+static void init_note_info(struct elf_note_info *info)
+{
+
+    memset(info, 0, sizeof(*info));
+    QTAILQ_INIT(&info->thread_list);
+}
+
+static void free_note_info(struct elf_note_info *info)
+{
+    struct elf_thread_status *ets;
+
+    g_free(info->prpsinfo);
+    g_free(info->prstatus);
+    g_free(info->fpregs);
+    g_free(info->thrmisc);
+
+    while (!QTAILQ_EMPTY(&info->thread_list)) {
+        ets = QTAILQ_FIRST(&info->thread_list);
+        QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
+        if (ets) {
+            g_free(ets->prstatus);
+            g_free(ets->fpregs);
+            g_free(ets->thrmisc);
+            g_free(ets);
+        }
+    }
+
+    g_free(info->kiproc);
+    g_free(info->kifiles);
+    g_free(info->kivmentries);
+    g_free(info->groups);
+    g_free(info->rlimits);
+    g_free(info->auxv);
+}
+
+static int dump_write(int fd, const void *ptr, size_t size)
+{
+    const char *bufp = (const char *)ptr;
+    ssize_t bytes_written, bytes_left;
+    struct rlimit dumpsize;
+    off_t pos;
+
+    bytes_written = 0;
+    getrlimit(RLIMIT_CORE, &dumpsize);
+    pos = lseek(fd, 0, SEEK_CUR);
+    if (pos == -1) {
+        if (errno == ESPIPE) { /* not a seekable stream */
+            bytes_left = size;
+        } else {
+            return pos;
+        }
+    } else {
+        if (dumpsize.rlim_cur <= pos) {
+            return -1;
+        } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
+            bytes_left = size;
+        } else {
+            size_t limit_left = dumpsize.rlim_cur - pos;
+            bytes_left = limit_left >= size ? size : limit_left ;
+        }
+    }
+
+    /*
+     * In normal conditions, single write(2) should do but
+     * in case of socket etc. this mechanism is more portable.
+     */
+    do {
+        bytes_written = write(fd, bufp, bytes_left);
+        if (bytes_written < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+            return -1;
+        } else if (bytes_written == 0) { /* eof */
+            return -1;
+        }
+        bufp += bytes_written;
+        bytes_left -= bytes_written;
+    } while (bytes_left > 0);
+
+    return 0;
+}
+
+
+static int write_note(struct memelfnote *men, int fd)
+{
+    struct elf_note en;
+
+    en.n_namesz = men->namesz_rounded;
+    en.n_descsz = men->datasz_rounded;
+    en.n_type = men->type;
 
     bswap_note(&en);
 
+    if (dump_write(fd, &en, sizeof(en)) != 0) {
+        return -1;
+    }
+    if (dump_write(fd, men->name, men->namesz_rounded) != 0) {
+        return -1;
+    }
+
+    if (men->addsize)
+        if (dump_write(fd, &men->addsize, sizeof(uint32_t)) != 0) {
+            return -1;
+        }
+
+    if (dump_write(fd, men->data, men->datasz) != 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_note_info(struct elf_note_info *info, int fd)
+{
+    struct elf_thread_status *ets;
+    int i, error = 0;
+
+    /* write prpsinfo, prstatus, fpregs, and thrmisc */
+    for (i = 0; i < 4; i++) {
+        error = write_note(&info->notes[i], fd);
+        if (error != 0) {
+            return error;
+        }
+    }
+
+    /* write prstatus, fpregset, & thrmisc for each additional thread */
+    QTAILQ_FOREACH(ets, &info->thread_list, ets_link) {
+        error = write_note(&ets->notes[0], fd);
+        if (error != 0) {
+            return error;
+        }
+        error = write_note(&ets->notes[1], fd);
+        if (error != 0) {
+            return error;
+        }
+        error = write_note(&ets->notes[2], fd);
+        if (error != 0) {
+            return error;
+        }
+    }
+
+    /*
+     * write kiproc, kifiles, kivmmap, groups, umask, rlimits, osrel,
+     * psstrings, and auxv.
+     */
+    for (i = 4; i < info->numnote; i++) {
+        error = write_note(&info->notes[i], fd);
+        if (error != 0) {
+            return error;
+        }
+    }
+
+    return 0;
+}
+
+static size_t note_size(const struct memelfnote *note)
+{
+
+    return note->notesz;
+}
+
+static abi_long fill_thread_info(struct elf_note_info *info, int signr,
+    CPUArchState *env)
+{
+    CPUState *cpu = env_cpu((CPUArchState *)env);
+    TaskState *ts = (TaskState *)cpu->opaque;
+    struct elf_thread_status *ets;
+
+    ets = g_malloc0(sizeof(*ets));
+    if (ets == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    ets->num_notes = 3;
+
+    ets->prstatus = g_malloc0(sizeof(struct target_prstatus));
+    if (ets->prstatus == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    fill_prstatus(env, ets->prstatus, signr);
+    fill_note(&ets->notes[0], "FreeBSD", TARGET_NT_PRSTATUS,
+            sizeof(struct target_prstatus), &ets->prstatus, 0);
+
+
+    ets->fpregs = g_malloc0(sizeof(*ets->fpregs));
+    if (ets->fpregs == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    fill_fpregs(ts, ets->fpregs);
+    fill_note(&ets->notes[1], "FreeBSD", TARGET_NT_FPREGSET,
+            sizeof(*ets->fpregs), ets->fpregs, 0);
+
+    ets->thrmisc = g_malloc0(sizeof(*ets->thrmisc));
+    if (ets->thrmisc == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    fill_thrmisc(env, ts, ets->thrmisc);
+    fill_note(&ets->notes[2], "FreeBSD", TARGET_NT_THRMISC,
+            sizeof(*ets->thrmisc), ets->thrmisc, 0);
+
+    QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
+
+    info->notes_size += (note_size(&ets->notes[0]) +
+        note_size(&ets->notes[1]) + note_size(&ets->notes[2]));
+
+    return 0;
+}
+
+static abi_long fill_kiproc(TaskState *ts, pid_t pid,
+        struct target_kinfo_proc *tkip)
+{
+    abi_long ret;
+    size_t len = sizeof(*tkip);
+    struct bsd_binprm *bprm = ts->bprm;
+
+    ret = do_sysctl_kern_getprocs(KERN_PROC_PID, pid, len, tkip, &len);
+
+    if (is_error(ret)) {
+        g_free(tkip);
+    }
+
+    /* Fix up some to be the target values. */
+    strncpy(tkip->ki_tdname, basename(bprm->argv[0]), TARGET_TDNAMLEN);
+    strncpy(tkip->ki_comm, basename(bprm->argv[0]), TARGET_COMMLEN);
+#if TARGET_ABI_BITS == 32
+    strncpy(tkip->ki_emul, "FreeBSD ELF32", TARGET_KI_EMULNAMELEN);
+#else
+    strncpy(tkip->ki_emul, "FreeBSD ELF64", TARGET_KI_EMULNAMELEN);
+#endif
+
+    return ret;
+}
+
+
+struct target_elf_auxinfo {
+    abi_long    a_type;
+    abi_long    a_value;
+};
+
+
+static abi_long fill_auxv(void *auxv, size_t *sz)
+{
+
+    *sz = target_auxents_sz;
+
+    return copy_from_user(auxv, target_auxents, target_auxents_sz);
+}
+
+static abi_long fill_psstrings(abi_ulong *psstrings)
+{
+
+    *psstrings = tswapal(TARGET_PS_STRINGS);
+
     return 0;
 }
+
+#define MAXNUMNOTES    13
+
+static int fill_note_info(struct elf_note_info *info,
+        int signr, CPUArchState *env)
+{
+    CPUState *cpu = env_cpu((CPUArchState *)env);
+    TaskState *ts = (TaskState *)cpu->opaque;
+    int i, err, numnotes = 0;
+    pid_t pid = getpid();
+
+    info->notes = g_malloc0(MAXNUMNOTES * sizeof(struct memelfnote));
+    if (info->notes == NULL) {
+        err = ENOMEM;
+        goto edone;
+    }
+
+    /* NT_PRPSINFO */
+    info->prpsinfo = g_malloc0(sizeof(*info->prpsinfo));
+    if (info->prpsinfo == NULL) {
+        err = -TARGET_ENOMEM;
+        goto edone;
+    }
+    err = fill_prpsinfo(ts, &info->prpsinfo);
+    if (err != 0) {
+        goto edone;
+    }
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_PRPSINFO,
+            sizeof(*info->prpsinfo), info->prpsinfo, 0);
+
+    /* prstatus, fpregs, and thrmisc for main thread. */
+
+    /* NT_PRSTATUS */
+    info->prstatus = g_malloc0(sizeof(struct target_prstatus));
+    if (info->prstatus == NULL) {
+        err = -TARGET_ENOMEM;
+        goto edone;
+    }
+    err = fill_prstatus(env, info->prstatus, signr);
+    if (err != 0) {
+        goto edone;
+    }
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_PRSTATUS,
+            sizeof(struct target_prstatus), info->prstatus, 0);
+
+    /* NT_FPREGSET */
+    info->fpregs = g_malloc0(sizeof(*info->fpregs));
+    if (info->fpregs == NULL) {
+        err = -TARGET_ENOMEM;
+        goto edone;
+    }
+    fill_fpregs(ts, info->fpregs);
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_FPREGSET,
+            sizeof(*info->fpregs), info->fpregs, 0);
+
+    /* NT_THRMISC */
+    info->thrmisc = g_malloc0(sizeof(*info->thrmisc));
+    if (info->thrmisc == NULL) {
+        err = -TARGET_ENOMEM;
+        goto edone;
+    }
+    fill_thrmisc(env, ts, info->thrmisc);
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_THRMISC,
+            sizeof(*info->thrmisc), info->thrmisc, 0);
+
+    /* NT_PROCSTAT_PROC */
+    info->kiproc = g_malloc0(sizeof(*info->kiproc));
+    if (info->kiproc == NULL) {
+        err = -TARGET_ENOMEM;
+        goto edone;
+    }
+    err = fill_kiproc(ts, pid, info->kiproc);
+    if (err != 0) {
+        goto edone;
+    }
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_PROCSTAT_PROC,
+            sizeof(*info->kiproc), info->kiproc,
+            sizeof(struct target_kinfo_proc));
+
+    /* NT_PROCSTAT_FILES */
+    info->kifiles = alloc_kifiles(pid, &info->kifiles_sz);
+    if (info->kifiles == NULL) {
+        err = -TARGET_ENOMEM;
+        goto edone;
+    }
+    err = fill_kifiles(pid, info->kifiles, &info->kifiles_sz);
+    if (err != 0) {
+        goto edone;
+    }
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_PROCSTAT_FILES,
+            info->kifiles_sz, info->kifiles,
+            sizeof(struct target_kinfo_file));
+
+    /* NT_PROCSTAT_VMMAP */
+    info->kivmentries = alloc_kivmentries(pid, &info->kivmentries_sz);
+    if (info->kivmentries == NULL) {
+        err = -TARGET_ENOMEM;
+        goto edone;
+    }
+    err = fill_kivmentries(pid, info->kivmentries, &info->kivmentries_sz);
+    if (err != 0) {
+        goto edone;
+    }
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_PROCSTAT_VMMAP,
+            info->kivmentries_sz, info->kivmentries,
+            sizeof(struct target_kinfo_vmentry));
+
+    /* NT_PROCSTAT_GROUPS */
+    info->groups = alloc_groups(&info->groups_sz);
+    if (info->groups == NULL) {
+        err = -TARGET_ENOMEM;
+        goto edone;
+    }
+    err = fill_groups(info->groups, &info->groups_sz);
+    if (err != 0) {
+        goto edone;
+    }
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_PROCSTAT_GROUPS,
+            info->groups_sz, info->groups,
+            sizeof(uint32_t));
+
+    /* NT_PROCSTAT_RLIMIT */
+    info->rlimits = g_malloc0(RLIM_NLIMITS * sizeof(struct rlimit));
+    if (info->rlimits == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    err = fill_rlimits(info->rlimits);
+    if (err != 0) {
+        goto edone;
+    }
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_PROCSTAT_RLIMIT,
+            sizeof(struct rlimit) * RLIM_NLIMITS, info->rlimits,
+            sizeof(struct rlimit) * RLIM_NLIMITS);
+
+    /* NT_PROCSTAT_OSREL */
+    err = fill_osreldate(&info->osreldate);
+    if (err != 0) {
+        goto edone;
+    }
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_PROCSTAT_OSREL,
+            sizeof(info->osreldate), &info->osreldate,
+            sizeof(int32_t));
+
+    /* NT_PROCSTAT_PSSTRINGS */
+    err = fill_psstrings(&info->psstrings);
+    if (err != 0) {
+        goto edone;
+    }
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_PROCSTAT_PSSTRINGS,
+            sizeof(info->psstrings), &info->psstrings,
+            sizeof(abi_ulong));
+
+    /* NT_PROCSTAT_AUXV */
+    info->auxv = g_malloc0(target_auxents_sz);
+    if (info->auxv == NULL) {
+        err = -TARGET_ENOMEM;
+        goto edone;
+    }
+    err = fill_auxv(info->auxv, &info->auxv_sz);
+    if (err != 0) {
+        goto edone;
+    }
+    fill_note(&info->notes[numnotes++], "FreeBSD", TARGET_NT_PROCSTAT_AUXV,
+            info->auxv_sz, info->auxv,
+            sizeof(struct target_elf_auxinfo));
+
+    assert(numnotes <= MAXNUMNOTES);
+    info->numnote = numnotes;
+    info->notes_size = 0;
+    for (i = 0; i < numnotes; i++) {
+        info->notes_size += note_size(&info->notes[i]);
+    }
+
+    /* read and fill status of all threads */
+    cpu_list_lock();
+    CPU_FOREACH(cpu) {
+        if (cpu == thread_cpu) {
+            continue;
+        }
+        err = fill_thread_info(info, signr, (CPUArchState *)cpu->env_ptr);
+        if (err != 0) {
+            cpu_list_unlock();
+            goto edone;
+        }
+    }
+    cpu_list_unlock();
+
+    return 0;
+
+edone:
+    free_note_info(info);
+    return err;
+}
+
+static int elf_core_dump(int signr, CPUArchState *env)
+{
+    int fd = -1;
+    int segs = 0;
+    off_t offset = 0, data_offset = 0;
+    CPUState *cpu = env_cpu((CPUArchState *)env);
+    TaskState *ts = (TaskState *)cpu->opaque;
+    struct vm_area_struct *vma = NULL;
+    struct mm_struct *mm = NULL;
+    struct rlimit dumpsize;
+    struct elfhdr elf;
+    struct elf_phdr phdr;
+    struct elf_note_info info;
+    char corefile[PATH_MAX];
+
+    init_note_info(&info);
+
+    errno = 0;
+    getrlimit(RLIMIT_CORE, &dumpsize);
+    if (dumpsize.rlim_cur == 0) {
+        return 0;
+    }
+
+    if (core_dump_filename(ts, corefile, sizeof(corefile)) < 0) {
+        return -(errno);
+    }
+
+    fd = open(corefile, O_WRONLY | O_CREAT,
+              S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+    if (fd < 0) {
+        return -(errno);
+    }
+
+    /*
+     * Walk through target process memory mappings and
+     * set up structure containing this information.  After
+     * this point vma_xxx functions can be used.
+     */
+    mm = vma_init();
+    if (mm == NULL) {
+        goto out;
+    }
+
+    walk_memory_regions(mm, vma_walker);
+    segs = vma_get_mapping_count(mm);
+
+    /*
+     * Construct the coredump ELF header.  Add another segment for
+     * notes.
+     *
+     * See kern/imgact_elf.c  __elfN(corehdr)().
+     */
+    fill_elf_header(&elf, segs + 1, ELF_MACHINE, ts->info->elf_flags);
+    if (dump_write(fd, &elf, sizeof(elf)) != 0) {
+        goto out;
+    }
+
+    /*
+     * Construct the note segment and write it out.
+     */
+    if (fill_note_info(&info, signr, env) < 0) {
+        goto out;
+    }
+
+    offset += sizeof(elf);                             /* elf header */
+    offset += (segs + 1) * sizeof(struct elf_phdr);    /* program headers */
+
+    /* Write out notes program header. */
+    fill_elf_note_phdr(&phdr, info.notes_size, offset);
+
+    offset += info.notes_size;
+    if (dump_write(fd, &phdr, sizeof(phdr)) != 0) {
+        goto out;
+    }
+
+    /*
+     * ELF specification wants data to start at page boundary so
+     * we align it here.
+     */
+    data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
+
+    /*
+     * Write program headers for memory regions mapped in the
+     * target process.
+     *
+     * See cb_put_phdr() in sys/kern/imgact_ef.c
+     */
+    for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
+        (void) memset(&phdr, 0, sizeof(phdr));
+
+        phdr.p_type = PT_LOAD;
+        phdr.p_offset = offset;
+        phdr.p_vaddr = vma->vma_start;
+        phdr.p_paddr = 0;
+        phdr.p_filesz = vma_dump_size(vma); /* ??? */
+        offset += phdr.p_filesz;
+        phdr.p_memsz = vma->vma_end - vma->vma_start;
+        phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
+        if (vma->vma_flags & PROT_WRITE) {
+            phdr.p_flags |= PF_W;
+        }
+        if (vma->vma_flags & PROT_EXEC) {
+            phdr.p_flags |= PF_X;
+        }
+        phdr.p_align = ELF_EXEC_PAGESIZE;  /* or PAGE_SIZE? */
+
+        bswap_phdr(&phdr, 1);
+        dump_write(fd, &phdr, sizeof(phdr));
+    }
+
+    /*
+     * Next write notes just after program headers.
+     */
+    if (write_note_info(&info, fd) < 0) {
+        goto out;
+    }
+
+    /*
+     * Align data to page boundary.
+     */
+    if (lseek(fd, data_offset, SEEK_SET) != data_offset) {
+        goto out;
+    }
+
+    /*
+     * Finally, dump the process memory into the corefile as well.
+     */
+    for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
+        abi_ulong addr;
+        abi_ulong end;
+
+        end = vma->vma_start + vma_dump_size(vma);
+
+        for (addr = vma->vma_start; addr < end;
+                addr += TARGET_PAGE_SIZE) {
+            char page[TARGET_PAGE_SIZE];
+            int error;
+
+            /*
+             * Read in page from target process memory and
+             * write it to coredump file.
+             */
+            error = copy_from_user(page, addr, sizeof(page));
+            if (error != 0) {
+                (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
+                        addr);
+                errno = -error;
+                goto out;
+            }
+            if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0) {
+                goto out;
+            }
+        }
+    }
+    errno = 0;
+
+out:
+    if (mm != NULL) {
+        vma_delete(mm);
+    }
+
+    (void)close(fd);
+
+    if (errno != 0) {
+        return -errno;
+    }
+    return 0;
+}
+
+#endif /* USE_ELF_CORE_DUMP */
