2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#define _STRUCTURED_PROC 1
2N/A
2N/A#include <stdlib.h>
2N/A#include <ctype.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <errno.h>
2N/A#include <procfs.h>
2N/A#include <priv.h>
2N/A#include <sys/elf.h>
2N/A#include <sys/machelf.h>
2N/A#include <sys/sysmacros.h>
2N/A#include <sys/systeminfo.h>
2N/A#include <sys/proc.h>
2N/A#include <sys/utsname.h>
2N/A
2N/A#include <sys/old_procfs.h>
2N/A
2N/A#include "Pcontrol.h"
2N/A#include "P32ton.h"
2N/A
2N/Atypedef enum {
2N/A STR_NONE,
2N/A STR_CTF,
2N/A STR_SYMTAB,
2N/A STR_DYNSYM,
2N/A STR_STRTAB,
2N/A STR_DYNSTR,
2N/A STR_SHSTRTAB,
2N/A STR_NUM
2N/A} shstrtype_t;
2N/A
2N/Astatic const char *shstrtab_data[] = {
2N/A "",
2N/A ".SUNW_ctf",
2N/A ".symtab",
2N/A ".dynsym",
2N/A ".strtab",
2N/A ".dynstr",
2N/A ".shstrtab"
2N/A};
2N/A
2N/Atypedef struct shstrtab {
2N/A int sst_ndx[STR_NUM];
2N/A int sst_cur;
2N/A} shstrtab_t;
2N/A
2N/Atypedef struct {
2N/A struct ps_prochandle *P;
2N/A int pgc_fd;
2N/A off64_t *pgc_poff;
2N/A off64_t *pgc_soff;
2N/A off64_t *pgc_doff;
2N/A core_content_t pgc_content;
2N/A void *pgc_chunk;
2N/A size_t pgc_chunksz;
2N/A
2N/A shstrtab_t pgc_shstrtab;
2N/A} pgcore_t;
2N/A
2N/Astatic void
2N/Ashstrtab_init(shstrtab_t *s)
2N/A{
2N/A bzero(&s->sst_ndx, sizeof (s->sst_ndx));
2N/A s->sst_cur = 1;
2N/A}
2N/A
2N/Astatic int
2N/Ashstrtab_ndx(shstrtab_t *s, shstrtype_t type)
2N/A{
2N/A int ret;
2N/A
2N/A if ((ret = s->sst_ndx[type]) != 0 || type == STR_NONE)
2N/A return (ret);
2N/A
2N/A ret = s->sst_ndx[type] = s->sst_cur;
2N/A s->sst_cur += strlen(shstrtab_data[type]) + 1;
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/Astatic size_t
2N/Ashstrtab_size(const shstrtab_t *s)
2N/A{
2N/A return (s->sst_cur);
2N/A}
2N/A
2N/Aint
2N/APgcore(struct ps_prochandle *P, const char *fname, core_content_t content)
2N/A{
2N/A int fd;
2N/A int err;
2N/A
2N/A if ((fd = creat64(fname, 0666)) < 0)
2N/A return (-1);
2N/A
2N/A if ((err = Pfgcore(P, fd, content)) != 0) {
2N/A (void) close(fd);
2N/A (void) unlink(fname);
2N/A return (err);
2N/A }
2N/A
2N/A return (close(fd));
2N/A}
2N/A
2N/A/*
2N/A * Since we don't want to use the old-school procfs interfaces, we use the
2N/A * new-style data structures we already have to construct the old-style
2N/A * data structures. We include these data structures in core files for
2N/A * backward compatibility.
2N/A */
2N/A
2N/Astatic void
2N/Amkprstatus(struct ps_prochandle *P, const lwpstatus_t *lsp,
2N/A const lwpsinfo_t *lip, prstatus_t *psp)
2N/A{
2N/A bzero(psp, sizeof (*psp));
2N/A
2N/A if (lsp->pr_flags & PR_STOPPED)
2N/A psp->pr_flags = 0x0001;
2N/A if (lsp->pr_flags & PR_ISTOP)
2N/A psp->pr_flags = 0x0002;
2N/A if (lsp->pr_flags & PR_DSTOP)
2N/A psp->pr_flags = 0x0004;
2N/A if (lsp->pr_flags & PR_ASLEEP)
2N/A psp->pr_flags = 0x0008;
2N/A if (lsp->pr_flags & PR_FORK)
2N/A psp->pr_flags = 0x0010;
2N/A if (lsp->pr_flags & PR_RLC)
2N/A psp->pr_flags = 0x0020;
2N/A /*
2N/A * Note that PR_PTRACE (0x0040) from <sys/old_procfs.h> is never set;
2N/A * PR_PCOMPAT corresponds to PR_PTRACE in the newer <sys/procfs.h>.
2N/A */
2N/A if (lsp->pr_flags & PR_PCINVAL)
2N/A psp->pr_flags = 0x0080;
2N/A if (lsp->pr_flags & PR_ISSYS)
2N/A psp->pr_flags = 0x0100;
2N/A if (lsp->pr_flags & PR_STEP)
2N/A psp->pr_flags = 0x0200;
2N/A if (lsp->pr_flags & PR_KLC)
2N/A psp->pr_flags = 0x0400;
2N/A if (lsp->pr_flags & PR_ASYNC)
2N/A psp->pr_flags = 0x0800;
2N/A if (lsp->pr_flags & PR_PTRACE)
2N/A psp->pr_flags = 0x1000;
2N/A if (lsp->pr_flags & PR_MSACCT)
2N/A psp->pr_flags = 0x2000;
2N/A if (lsp->pr_flags & PR_BPTADJ)
2N/A psp->pr_flags = 0x4000;
2N/A if (lsp->pr_flags & PR_ASLWP)
2N/A psp->pr_flags = 0x8000;
2N/A
2N/A psp->pr_why = lsp->pr_why;
2N/A psp->pr_what = lsp->pr_what;
2N/A psp->pr_info = lsp->pr_info;
2N/A psp->pr_cursig = lsp->pr_cursig;
2N/A psp->pr_nlwp = P->status.pr_nlwp;
2N/A psp->pr_sigpend = P->status.pr_sigpend;
2N/A psp->pr_sighold = lsp->pr_lwphold;
2N/A psp->pr_altstack = lsp->pr_altstack;
2N/A psp->pr_action = lsp->pr_action;
2N/A psp->pr_pid = P->status.pr_pid;
2N/A psp->pr_ppid = P->status.pr_ppid;
2N/A psp->pr_pgrp = P->status.pr_pgid;
2N/A psp->pr_sid = P->status.pr_sid;
2N/A psp->pr_utime = P->status.pr_utime;
2N/A psp->pr_stime = P->status.pr_stime;
2N/A psp->pr_cutime = P->status.pr_cutime;
2N/A psp->pr_cstime = P->status.pr_cstime;
2N/A (void) strncpy(psp->pr_clname, lsp->pr_clname, sizeof (psp->pr_clname));
2N/A psp->pr_syscall = lsp->pr_syscall;
2N/A psp->pr_nsysarg = lsp->pr_nsysarg;
2N/A bcopy(lsp->pr_sysarg, psp->pr_sysarg, sizeof (psp->pr_sysarg));
2N/A psp->pr_who = lsp->pr_lwpid;
2N/A psp->pr_lwppend = lsp->pr_lwppend;
2N/A psp->pr_oldcontext = (ucontext_t *)lsp->pr_oldcontext;
2N/A psp->pr_brkbase = (caddr_t)P->status.pr_brkbase;
2N/A psp->pr_brksize = P->status.pr_brksize;
2N/A psp->pr_stkbase = (caddr_t)P->status.pr_stkbase;
2N/A psp->pr_stksize = P->status.pr_stksize;
2N/A psp->pr_processor = (short)lip->pr_onpro;
2N/A psp->pr_bind = (short)lip->pr_bindpro;
2N/A psp->pr_instr = lsp->pr_instr;
2N/A bcopy(lsp->pr_reg, psp->pr_reg, sizeof (psp->pr_sysarg));
2N/A}
2N/A
2N/Astatic void
2N/Amkprpsinfo(struct ps_prochandle *P, prpsinfo_t *psp)
2N/A{
2N/A bzero(psp, sizeof (*psp));
2N/A psp->pr_state = P->psinfo.pr_lwp.pr_state;
2N/A psp->pr_sname = P->psinfo.pr_lwp.pr_sname;
2N/A psp->pr_zomb = (psp->pr_state == SZOMB);
2N/A psp->pr_nice = P->psinfo.pr_lwp.pr_nice;
2N/A psp->pr_flag = P->psinfo.pr_lwp.pr_flag;
2N/A psp->pr_uid = P->psinfo.pr_uid;
2N/A psp->pr_gid = P->psinfo.pr_gid;
2N/A psp->pr_pid = P->psinfo.pr_pid;
2N/A psp->pr_ppid = P->psinfo.pr_ppid;
2N/A psp->pr_pgrp = P->psinfo.pr_pgid;
2N/A psp->pr_sid = P->psinfo.pr_sid;
2N/A psp->pr_addr = (caddr_t)P->psinfo.pr_addr;
2N/A psp->pr_size = P->psinfo.pr_size;
2N/A psp->pr_rssize = P->psinfo.pr_rssize;
2N/A psp->pr_wchan = (caddr_t)P->psinfo.pr_lwp.pr_wchan;
2N/A psp->pr_start = P->psinfo.pr_start;
2N/A psp->pr_time = P->psinfo.pr_time;
2N/A psp->pr_pri = P->psinfo.pr_lwp.pr_pri;
2N/A psp->pr_oldpri = P->psinfo.pr_lwp.pr_oldpri;
2N/A psp->pr_cpu = P->psinfo.pr_lwp.pr_cpu;
2N/A psp->pr_ottydev = cmpdev(P->psinfo.pr_ttydev);
2N/A psp->pr_lttydev = P->psinfo.pr_ttydev;
2N/A (void) strncpy(psp->pr_clname, P->psinfo.pr_lwp.pr_clname,
2N/A sizeof (psp->pr_clname));
2N/A (void) strncpy(psp->pr_fname, P->psinfo.pr_fname,
2N/A sizeof (psp->pr_fname));
2N/A bcopy(&P->psinfo.pr_psargs, &psp->pr_psargs,
2N/A sizeof (psp->pr_psargs));
2N/A psp->pr_syscall = P->psinfo.pr_lwp.pr_syscall;
2N/A psp->pr_ctime = P->psinfo.pr_ctime;
2N/A psp->pr_bysize = psp->pr_size * PAGESIZE;
2N/A psp->pr_byrssize = psp->pr_rssize * PAGESIZE;
2N/A psp->pr_argc = P->psinfo.pr_argc;
2N/A psp->pr_argv = (char **)P->psinfo.pr_argv;
2N/A psp->pr_envp = (char **)P->psinfo.pr_envp;
2N/A psp->pr_wstat = P->psinfo.pr_wstat;
2N/A psp->pr_pctcpu = P->psinfo.pr_pctcpu;
2N/A psp->pr_pctmem = P->psinfo.pr_pctmem;
2N/A psp->pr_euid = P->psinfo.pr_euid;
2N/A psp->pr_egid = P->psinfo.pr_egid;
2N/A psp->pr_aslwpid = 0;
2N/A psp->pr_dmodel = P->psinfo.pr_dmodel;
2N/A}
2N/A
2N/A#ifdef _LP64
2N/A
2N/Astatic void
2N/Amkprstatus32(struct ps_prochandle *P, const lwpstatus_t *lsp,
2N/A const lwpsinfo_t *lip, prstatus32_t *psp)
2N/A{
2N/A bzero(psp, sizeof (*psp));
2N/A
2N/A if (lsp->pr_flags & PR_STOPPED)
2N/A psp->pr_flags = 0x0001;
2N/A if (lsp->pr_flags & PR_ISTOP)
2N/A psp->pr_flags = 0x0002;
2N/A if (lsp->pr_flags & PR_DSTOP)
2N/A psp->pr_flags = 0x0004;
2N/A if (lsp->pr_flags & PR_ASLEEP)
2N/A psp->pr_flags = 0x0008;
2N/A if (lsp->pr_flags & PR_FORK)
2N/A psp->pr_flags = 0x0010;
2N/A if (lsp->pr_flags & PR_RLC)
2N/A psp->pr_flags = 0x0020;
2N/A /*
2N/A * Note that PR_PTRACE (0x0040) from <sys/old_procfs.h> is never set;
2N/A * PR_PCOMPAT corresponds to PR_PTRACE in the newer <sys/procfs.h>.
2N/A */
2N/A if (lsp->pr_flags & PR_PCINVAL)
2N/A psp->pr_flags = 0x0080;
2N/A if (lsp->pr_flags & PR_ISSYS)
2N/A psp->pr_flags = 0x0100;
2N/A if (lsp->pr_flags & PR_STEP)
2N/A psp->pr_flags = 0x0200;
2N/A if (lsp->pr_flags & PR_KLC)
2N/A psp->pr_flags = 0x0400;
2N/A if (lsp->pr_flags & PR_ASYNC)
2N/A psp->pr_flags = 0x0800;
2N/A if (lsp->pr_flags & PR_PTRACE)
2N/A psp->pr_flags = 0x1000;
2N/A if (lsp->pr_flags & PR_MSACCT)
2N/A psp->pr_flags = 0x2000;
2N/A if (lsp->pr_flags & PR_BPTADJ)
2N/A psp->pr_flags = 0x4000;
2N/A if (lsp->pr_flags & PR_ASLWP)
2N/A psp->pr_flags = 0x8000;
2N/A
2N/A psp->pr_why = lsp->pr_why;
2N/A psp->pr_what = lsp->pr_what;
2N/A siginfo_n_to_32(&lsp->pr_info, &psp->pr_info);
2N/A psp->pr_cursig = lsp->pr_cursig;
2N/A psp->pr_nlwp = P->status.pr_nlwp;
2N/A psp->pr_sigpend = P->status.pr_sigpend;
2N/A psp->pr_sighold = lsp->pr_lwphold;
2N/A stack_n_to_32(&lsp->pr_altstack, &psp->pr_altstack);
2N/A sigaction_n_to_32(&lsp->pr_action, &psp->pr_action);
2N/A psp->pr_pid = P->status.pr_pid;
2N/A psp->pr_ppid = P->status.pr_ppid;
2N/A psp->pr_pgrp = P->status.pr_pgid;
2N/A psp->pr_sid = P->status.pr_sid;
2N/A timestruc_n_to_32(&P->status.pr_utime, &psp->pr_utime);
2N/A timestruc_n_to_32(&P->status.pr_stime, &psp->pr_stime);
2N/A timestruc_n_to_32(&P->status.pr_cutime, &psp->pr_cutime);
2N/A timestruc_n_to_32(&P->status.pr_cstime, &psp->pr_cstime);
2N/A (void) strncpy(psp->pr_clname, lsp->pr_clname, sizeof (psp->pr_clname));
2N/A psp->pr_syscall = lsp->pr_syscall;
2N/A psp->pr_nsysarg = lsp->pr_nsysarg;
2N/A bcopy(lsp->pr_sysarg, psp->pr_sysarg, sizeof (psp->pr_sysarg));
2N/A psp->pr_who = lsp->pr_lwpid;
2N/A psp->pr_lwppend = lsp->pr_lwppend;
2N/A psp->pr_oldcontext = (caddr32_t)lsp->pr_oldcontext;
2N/A psp->pr_brkbase = (caddr32_t)P->status.pr_brkbase;
2N/A psp->pr_brksize = P->status.pr_brksize;
2N/A psp->pr_stkbase = (caddr32_t)P->status.pr_stkbase;
2N/A psp->pr_stksize = P->status.pr_stksize;
2N/A psp->pr_processor = (short)lip->pr_onpro;
2N/A psp->pr_bind = (short)lip->pr_bindpro;
2N/A psp->pr_instr = lsp->pr_instr;
2N/A bcopy(lsp->pr_reg, psp->pr_reg, sizeof (psp->pr_sysarg));
2N/A}
2N/A
2N/Astatic void
2N/Amkprpsinfo32(struct ps_prochandle *P, prpsinfo32_t *psp)
2N/A{
2N/A bzero(psp, sizeof (*psp));
2N/A psp->pr_state = P->psinfo.pr_lwp.pr_state;
2N/A psp->pr_sname = P->psinfo.pr_lwp.pr_sname;
2N/A psp->pr_zomb = (psp->pr_state == SZOMB);
2N/A psp->pr_nice = P->psinfo.pr_lwp.pr_nice;
2N/A psp->pr_flag = P->psinfo.pr_lwp.pr_flag;
2N/A psp->pr_uid = P->psinfo.pr_uid;
2N/A psp->pr_gid = P->psinfo.pr_gid;
2N/A psp->pr_pid = P->psinfo.pr_pid;
2N/A psp->pr_ppid = P->psinfo.pr_ppid;
2N/A psp->pr_pgrp = P->psinfo.pr_pgid;
2N/A psp->pr_sid = P->psinfo.pr_sid;
2N/A psp->pr_addr = (caddr32_t)P->psinfo.pr_addr;
2N/A psp->pr_size = P->psinfo.pr_size;
2N/A psp->pr_rssize = P->psinfo.pr_rssize;
2N/A psp->pr_wchan = (caddr32_t)P->psinfo.pr_lwp.pr_wchan;
2N/A timestruc_n_to_32(&P->psinfo.pr_start, &psp->pr_start);
2N/A timestruc_n_to_32(&P->psinfo.pr_time, &psp->pr_time);
2N/A psp->pr_pri = P->psinfo.pr_lwp.pr_pri;
2N/A psp->pr_oldpri = P->psinfo.pr_lwp.pr_oldpri;
2N/A psp->pr_cpu = P->psinfo.pr_lwp.pr_cpu;
2N/A psp->pr_ottydev = cmpdev(P->psinfo.pr_ttydev);
2N/A psp->pr_lttydev = prcmpldev(P->psinfo.pr_ttydev);
2N/A (void) strncpy(psp->pr_clname, P->psinfo.pr_lwp.pr_clname,
2N/A sizeof (psp->pr_clname));
2N/A (void) strncpy(psp->pr_fname, P->psinfo.pr_fname,
2N/A sizeof (psp->pr_fname));
2N/A bcopy(&P->psinfo.pr_psargs, &psp->pr_psargs,
2N/A sizeof (psp->pr_psargs));
2N/A psp->pr_syscall = P->psinfo.pr_lwp.pr_syscall;
2N/A timestruc_n_to_32(&P->psinfo.pr_ctime, &psp->pr_ctime);
2N/A psp->pr_bysize = psp->pr_size * PAGESIZE;
2N/A psp->pr_byrssize = psp->pr_rssize * PAGESIZE;
2N/A psp->pr_argc = P->psinfo.pr_argc;
2N/A psp->pr_argv = (caddr32_t)P->psinfo.pr_argv;
2N/A psp->pr_envp = (caddr32_t)P->psinfo.pr_envp;
2N/A psp->pr_wstat = P->psinfo.pr_wstat;
2N/A psp->pr_pctcpu = P->psinfo.pr_pctcpu;
2N/A psp->pr_pctmem = P->psinfo.pr_pctmem;
2N/A psp->pr_euid = P->psinfo.pr_euid;
2N/A psp->pr_egid = P->psinfo.pr_egid;
2N/A psp->pr_aslwpid = 0;
2N/A psp->pr_dmodel = P->psinfo.pr_dmodel;
2N/A}
2N/A
2N/A#endif /* _LP64 */
2N/A
2N/Astatic int
2N/Awrite_note(int fd, uint_t type, const void *desc, size_t descsz, off64_t *offp)
2N/A{
2N/A /*
2N/A * Note headers are the same regardless of the data model of the
2N/A * ELF file; we arbitrarily use Elf64_Nhdr here.
2N/A */
2N/A struct {
2N/A Elf64_Nhdr nhdr;
2N/A char name[8];
2N/A } n;
2N/A
2N/A bzero(&n, sizeof (n));
2N/A bcopy("CORE", n.name, 4);
2N/A n.nhdr.n_type = type;
2N/A n.nhdr.n_namesz = 5;
2N/A n.nhdr.n_descsz = roundup(descsz, 4);
2N/A
2N/A if (pwrite64(fd, &n, sizeof (n), *offp) != sizeof (n))
2N/A return (-1);
2N/A
2N/A *offp += sizeof (n);
2N/A
2N/A if (pwrite64(fd, desc, n.nhdr.n_descsz, *offp) != n.nhdr.n_descsz)
2N/A return (-1);
2N/A
2N/A *offp += n.nhdr.n_descsz;
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aold_per_lwp(void *data, const lwpstatus_t *lsp, const lwpsinfo_t *lip)
2N/A{
2N/A pgcore_t *pgc = data;
2N/A struct ps_prochandle *P = pgc->P;
2N/A
2N/A /*
2N/A * Legacy core files don't contain information about zombie LWPs.
2N/A * We use Plwp_iter_all() so that we get the lwpsinfo_t structure
2N/A * more cheaply.
2N/A */
2N/A if (lsp == NULL)
2N/A return (0);
2N/A
2N/A if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
2N/A prstatus_t prstatus;
2N/A mkprstatus(P, lsp, lip, &prstatus);
2N/A if (write_note(pgc->pgc_fd, NT_PRSTATUS, &prstatus,
2N/A sizeof (prstatus_t), pgc->pgc_doff) != 0)
2N/A return (0);
2N/A if (write_note(pgc->pgc_fd, NT_PRFPREG, &lsp->pr_fpreg,
2N/A sizeof (prfpregset_t), pgc->pgc_doff) != 0)
2N/A return (1);
2N/A#ifdef _LP64
2N/A } else {
2N/A prstatus32_t pr32;
2N/A prfpregset32_t pf32;
2N/A mkprstatus32(P, lsp, lip, &pr32);
2N/A if (write_note(pgc->pgc_fd, NT_PRSTATUS, &pr32,
2N/A sizeof (prstatus32_t), pgc->pgc_doff) != 0)
2N/A return (1);
2N/A prfpregset_n_to_32(&lsp->pr_fpreg, &pf32);
2N/A if (write_note(pgc->pgc_fd, NT_PRFPREG, &pf32,
2N/A sizeof (prfpregset32_t), pgc->pgc_doff) != 0)
2N/A return (1);
2N/A#endif /* _LP64 */
2N/A }
2N/A
2N/A {
2N/A prxregset_t xregs;
2N/A if (Plwp_getxregs(P, lsp->pr_lwpid, &xregs) == 0 &&
2N/A write_note(pgc->pgc_fd, NT_PRXREG, &xregs,
2N/A sizeof (prxregset_t), pgc->pgc_doff) != 0)
2N/A return (1);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Anew_per_lwp(void *data, const lwpstatus_t *lsp, const lwpsinfo_t *lip)
2N/A{
2N/A pgcore_t *pgc = data;
2N/A struct ps_prochandle *P = pgc->P;
2N/A
2N/A /*
2N/A * If lsp is NULL this indicates that this is a zombie LWP in
2N/A * which case we dump only the lwpsinfo_t structure and none of
2N/A * the other ancillary LWP state data.
2N/A */
2N/A if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
2N/A if (write_note(pgc->pgc_fd, NT_LWPSINFO, lip,
2N/A sizeof (lwpsinfo_t), pgc->pgc_doff) != 0)
2N/A return (1);
2N/A if (lsp == NULL)
2N/A return (0);
2N/A if (write_note(pgc->pgc_fd, NT_LWPSTATUS, lsp,
2N/A sizeof (lwpstatus_t), pgc->pgc_doff) != 0)
2N/A return (1);
2N/A#ifdef _LP64
2N/A } else {
2N/A lwpsinfo32_t li32;
2N/A lwpstatus32_t ls32;
2N/A lwpsinfo_n_to_32(lip, &li32);
2N/A if (write_note(pgc->pgc_fd, NT_LWPSINFO, &li32,
2N/A sizeof (lwpsinfo32_t), pgc->pgc_doff) != 0)
2N/A return (1);
2N/A if (lsp == NULL)
2N/A return (0);
2N/A lwpstatus_n_to_32(lsp, &ls32);
2N/A if (write_note(pgc->pgc_fd, NT_LWPSTATUS, &ls32,
2N/A sizeof (lwpstatus32_t), pgc->pgc_doff) != 0)
2N/A return (1);
2N/A#endif /* _LP64 */
2N/A }
2N/A
2N/A {
2N/A prxregset_t xregs;
2N/A if (Plwp_getxregs(P, lsp->pr_lwpid, &xregs) == 0) {
2N/A if (write_note(pgc->pgc_fd, NT_PRXREG, &xregs,
2N/A sizeof (prxregset_t), pgc->pgc_doff) != 0)
2N/A return (1);
2N/A }
2N/A }
2N/A
2N/A#ifdef sparc
2N/A {
2N/A gwindows_t gwins;
2N/A size_t size;
2N/A
2N/A if (Plwp_getgwindows(P, lsp->pr_lwpid, &gwins) == 0 &&
2N/A gwins.wbcnt > 0) {
2N/A size = sizeof (gwins) - sizeof (gwins.wbuf) +
2N/A gwins.wbcnt * sizeof (gwins.wbuf[0]);
2N/A
2N/A if (write_note(pgc->pgc_fd, NT_GWINDOWS, &gwins, size,
2N/A pgc->pgc_doff) != 0)
2N/A return (1);
2N/A }
2N/A
2N/A }
2N/A#ifdef __sparcv9
2N/A if (P->status.pr_dmodel == PR_MODEL_LP64) {
2N/A asrset_t asrs;
2N/A if (Plwp_getasrs(P, lsp->pr_lwpid, asrs) == 0) {
2N/A if (write_note(pgc->pgc_fd, NT_ASRS, &asrs,
2N/A sizeof (asrset_t), pgc->pgc_doff) != 0)
2N/A return (1);
2N/A }
2N/A }
2N/A#endif /* __sparcv9 */
2N/A
2N/A {
2N/A prcpuxregset_t *cxregs;
2N/A int cxregsize;
2N/A ps_err_e ret;
2N/A
2N/A ret = ps_lgetcxregsize(P, lsp->pr_lwpid, &cxregsize);
2N/A if (ret == PS_OK && cxregsize > 0) {
2N/A
2N/A if ((cxregs = malloc(cxregsize)) == NULL)
2N/A return (1);
2N/A
2N/A if (Plwp_getcxregs(P, lsp->pr_lwpid, cxregs) == 0) {
2N/A if (write_note(pgc->pgc_fd, NT_PRCPUXREG,
2N/A cxregs, cxregsize, pgc->pgc_doff) != 0) {
2N/A free(cxregs);
2N/A return (1);
2N/A }
2N/A }
2N/A free(cxregs);
2N/A }
2N/A }
2N/A
2N/A#endif /* sparc */
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic uint_t
2N/Acount_sections(pgcore_t *pgc)
2N/A{
2N/A struct ps_prochandle *P = pgc->P;
2N/A file_info_t *fptr;
2N/A uint_t cnt;
2N/A uint_t nshdrs = 0;
2N/A
2N/A if (!(pgc->pgc_content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)))
2N/A return (0);
2N/A
2N/A fptr = list_next(&P->file_head);
2N/A for (cnt = P->num_files; cnt > 0; cnt--, fptr = list_next(fptr)) {
2N/A int hit_symtab = 0;
2N/A
2N/A Pbuild_file_symtab(P, fptr);
2N/A
2N/A if ((pgc->pgc_content & CC_CONTENT_CTF) &&
2N/A Pbuild_file_ctf(P, fptr) != NULL) {
2N/A sym_tbl_t *sym;
2N/A
2N/A nshdrs++;
2N/A
2N/A if (fptr->file_ctf_dyn) {
2N/A sym = &fptr->file_dynsym;
2N/A } else {
2N/A sym = &fptr->file_symtab;
2N/A hit_symtab = 1;
2N/A }
2N/A
2N/A if (sym->sym_data_pri != NULL && sym->sym_symn != 0 &&
2N/A sym->sym_strs != NULL)
2N/A nshdrs += 2;
2N/A }
2N/A
2N/A if ((pgc->pgc_content & CC_CONTENT_SYMTAB) && !hit_symtab &&
2N/A fptr->file_symtab.sym_data_pri != NULL &&
2N/A fptr->file_symtab.sym_symn != 0 &&
2N/A fptr->file_symtab.sym_strs != NULL) {
2N/A nshdrs += 2;
2N/A }
2N/A }
2N/A
2N/A return (nshdrs == 0 ? 0 : nshdrs + 2);
2N/A}
2N/A
2N/Astatic int
2N/Awrite_shdr(pgcore_t *pgc, shstrtype_t name, uint_t type, ulong_t flags,
2N/A uintptr_t addr, ulong_t offset, size_t size, uint_t link, uint_t info,
2N/A uintptr_t addralign, uintptr_t entsize)
2N/A{
2N/A if (pgc->P->status.pr_dmodel == PR_MODEL_ILP32) {
2N/A Elf32_Shdr shdr;
2N/A
2N/A bzero(&shdr, sizeof (shdr));
2N/A shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, name);
2N/A shdr.sh_type = type;
2N/A shdr.sh_flags = flags;
2N/A shdr.sh_addr = (Elf32_Addr)addr;
2N/A shdr.sh_offset = offset;
2N/A shdr.sh_size = size;
2N/A shdr.sh_link = link;
2N/A shdr.sh_info = info;
2N/A shdr.sh_addralign = addralign;
2N/A shdr.sh_entsize = entsize;
2N/A
2N/A if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
2N/A *pgc->pgc_soff) != sizeof (shdr))
2N/A return (-1);
2N/A
2N/A *pgc->pgc_soff += sizeof (shdr);
2N/A#ifdef _LP64
2N/A } else {
2N/A Elf64_Shdr shdr;
2N/A
2N/A bzero(&shdr, sizeof (shdr));
2N/A shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, name);
2N/A shdr.sh_type = type;
2N/A shdr.sh_flags = flags;
2N/A shdr.sh_addr = addr;
2N/A shdr.sh_offset = offset;
2N/A shdr.sh_size = size;
2N/A shdr.sh_link = link;
2N/A shdr.sh_info = info;
2N/A shdr.sh_addralign = addralign;
2N/A shdr.sh_entsize = entsize;
2N/A
2N/A if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
2N/A *pgc->pgc_soff) != sizeof (shdr))
2N/A return (-1);
2N/A
2N/A *pgc->pgc_soff += sizeof (shdr);
2N/A#endif /* _LP64 */
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Adump_symtab(pgcore_t *pgc, file_info_t *fptr, uint_t index, int dynsym)
2N/A{
2N/A sym_tbl_t *sym = dynsym ? &fptr->file_dynsym : &fptr->file_symtab;
2N/A shstrtype_t symname = dynsym ? STR_DYNSYM : STR_SYMTAB;
2N/A shstrtype_t strname = dynsym ? STR_DYNSTR : STR_STRTAB;
2N/A uint_t symtype = dynsym ? SHT_DYNSYM : SHT_SYMTAB;
2N/A size_t size;
2N/A uintptr_t addr = fptr->file_map->map_pmap.pr_vaddr;
2N/A
2N/A if (sym->sym_data_pri == NULL || sym->sym_symn == 0 ||
2N/A sym->sym_strs == NULL)
2N/A return (0);
2N/A
2N/A size = sym->sym_hdr_pri.sh_size;
2N/A if (pwrite64(pgc->pgc_fd, sym->sym_data_pri->d_buf, size,
2N/A *pgc->pgc_doff) != size)
2N/A return (-1);
2N/A
2N/A if (write_shdr(pgc, symname, symtype, 0, addr, *pgc->pgc_doff, size,
2N/A index + 1, sym->sym_hdr_pri.sh_info, sym->sym_hdr_pri.sh_addralign,
2N/A sym->sym_hdr_pri.sh_entsize) != 0)
2N/A return (-1);
2N/A
2N/A *pgc->pgc_doff += roundup(size, 8);
2N/A
2N/A size = sym->sym_strhdr.sh_size;
2N/A if (pwrite64(pgc->pgc_fd, sym->sym_strs, size, *pgc->pgc_doff) != size)
2N/A return (-1);
2N/A
2N/A if (write_shdr(pgc, strname, SHT_STRTAB, SHF_STRINGS, addr,
2N/A *pgc->pgc_doff, size, 0, 0, 1, 0) != 0)
2N/A return (-1);
2N/A
2N/A *pgc->pgc_doff += roundup(size, 8);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Adump_sections(pgcore_t *pgc)
2N/A{
2N/A struct ps_prochandle *P = pgc->P;
2N/A file_info_t *fptr;
2N/A uint_t cnt;
2N/A uint_t index = 1;
2N/A
2N/A if (!(pgc->pgc_content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)))
2N/A return (0);
2N/A
2N/A fptr = list_next(&P->file_head);
2N/A for (cnt = P->num_files; cnt > 0; cnt--, fptr = list_next(fptr)) {
2N/A int hit_symtab = 0;
2N/A
2N/A Pbuild_file_symtab(P, fptr);
2N/A
2N/A if ((pgc->pgc_content & CC_CONTENT_CTF) &&
2N/A Pbuild_file_ctf(P, fptr) != NULL) {
2N/A sym_tbl_t *sym;
2N/A uint_t dynsym;
2N/A uint_t symindex = 0;
2N/A
2N/A /*
2N/A * Write the symtab out first so we can correctly
2N/A * set the sh_link field in the CTF section header.
2N/A * symindex will be 0 if there is no corresponding
2N/A * symbol table section.
2N/A */
2N/A if (fptr->file_ctf_dyn) {
2N/A sym = &fptr->file_dynsym;
2N/A dynsym = 1;
2N/A } else {
2N/A sym = &fptr->file_symtab;
2N/A dynsym = 0;
2N/A hit_symtab = 1;
2N/A }
2N/A
2N/A if (sym->sym_data_pri != NULL && sym->sym_symn != 0 &&
2N/A sym->sym_strs != NULL) {
2N/A symindex = index;
2N/A if (dump_symtab(pgc, fptr, index, dynsym) != 0)
2N/A return (-1);
2N/A index += 2;
2N/A }
2N/A
2N/A /*
2N/A * Write the CTF data that we've read out of the
2N/A * file itself into the core file.
2N/A */
2N/A if (pwrite64(pgc->pgc_fd, fptr->file_ctf_buf,
2N/A fptr->file_ctf_size, *pgc->pgc_doff) !=
2N/A fptr->file_ctf_size)
2N/A return (-1);
2N/A
2N/A if (write_shdr(pgc, STR_CTF, SHT_PROGBITS, 0,
2N/A fptr->file_map->map_pmap.pr_vaddr, *pgc->pgc_doff,
2N/A fptr->file_ctf_size, symindex, 0, 4, 0) != 0)
2N/A return (-1);
2N/A
2N/A index++;
2N/A *pgc->pgc_doff += roundup(fptr->file_ctf_size, 8);
2N/A }
2N/A
2N/A if ((pgc->pgc_content & CC_CONTENT_SYMTAB) && !hit_symtab &&
2N/A fptr->file_symtab.sym_data_pri != NULL &&
2N/A fptr->file_symtab.sym_symn != 0 &&
2N/A fptr->file_symtab.sym_strs != NULL) {
2N/A if (dump_symtab(pgc, fptr, index, 0) != 0)
2N/A return (-1);
2N/A index += 2;
2N/A }
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Adump_map(void *data, const prmap_t *pmp, const char *name)
2N/A{
2N/A pgcore_t *pgc = data;
2N/A struct ps_prochandle *P = pgc->P;
2N/A#ifdef _LP64
2N/A Elf64_Phdr phdr;
2N/A#else
2N/A Elf32_Phdr phdr;
2N/A#endif
2N/A size_t n;
2N/A
2N/A bzero(&phdr, sizeof (phdr));
2N/A phdr.p_type = PT_LOAD;
2N/A phdr.p_vaddr = pmp->pr_vaddr;
2N/A phdr.p_memsz = pmp->pr_size;
2N/A if (pmp->pr_mflags & MA_READ)
2N/A phdr.p_flags |= PF_R;
2N/A if (pmp->pr_mflags & MA_WRITE)
2N/A phdr.p_flags |= PF_W;
2N/A if (pmp->pr_mflags & MA_EXEC)
2N/A phdr.p_flags |= PF_X;
2N/A
2N/A if (pmp->pr_vaddr + pmp->pr_size > P->status.pr_stkbase &&
2N/A pmp->pr_vaddr < P->status.pr_stkbase + P->status.pr_stksize) {
2N/A if (!(pgc->pgc_content & CC_CONTENT_STACK))
2N/A goto exclude;
2N/A
2N/A } else if ((pmp->pr_mflags & MA_ANON) &&
2N/A pmp->pr_vaddr + pmp->pr_size > P->status.pr_brkbase &&
2N/A pmp->pr_vaddr < P->status.pr_brkbase + P->status.pr_brksize) {
2N/A if (!(pgc->pgc_content & CC_CONTENT_HEAP))
2N/A goto exclude;
2N/A
2N/A } else if (pmp->pr_mflags & MA_ISM) {
2N/A if (pmp->pr_mflags & MA_NORESERVE) {
2N/A if (!(pgc->pgc_content & CC_CONTENT_ISM))
2N/A goto exclude;
2N/A } else {
2N/A if (!(pgc->pgc_content & CC_CONTENT_DISM))
2N/A goto exclude;
2N/A }
2N/A
2N/A } else if (pmp->pr_mflags & MA_SHM) {
2N/A if (!(pgc->pgc_content & CC_CONTENT_SHM))
2N/A goto exclude;
2N/A
2N/A } else if (pmp->pr_mflags & MA_SHARED) {
2N/A if (pmp->pr_mflags & MA_ANON) {
2N/A if (!(pgc->pgc_content & CC_CONTENT_SHANON))
2N/A goto exclude;
2N/A } else {
2N/A if (!(pgc->pgc_content & CC_CONTENT_SHFILE))
2N/A goto exclude;
2N/A }
2N/A
2N/A } else if (pmp->pr_mflags & MA_ANON) {
2N/A if (!(pgc->pgc_content & CC_CONTENT_ANON))
2N/A goto exclude;
2N/A
2N/A } else if (phdr.p_flags == (PF_R | PF_X)) {
2N/A if (!(pgc->pgc_content & CC_CONTENT_TEXT))
2N/A goto exclude;
2N/A
2N/A } else if (phdr.p_flags == PF_R) {
2N/A if (!(pgc->pgc_content & CC_CONTENT_RODATA))
2N/A goto exclude;
2N/A
2N/A } else {
2N/A if (!(pgc->pgc_content & CC_CONTENT_DATA))
2N/A goto exclude;
2N/A }
2N/A
2N/A n = 0;
2N/A while (n < pmp->pr_size) {
2N/A size_t csz = MIN(pmp->pr_size - n, pgc->pgc_chunksz);
2N/A
2N/A /*
2N/A * If we can't read out part of the victim's address
2N/A * space for some reason ignore that failure and try to
2N/A * emit a partial core file without that mapping's data.
2N/A * As in the kernel, we mark these failures with the
2N/A * PF_SUNW_FAILURE flag and store the errno where the
2N/A * mapping would have been.
2N/A */
2N/A if (Pread(P, pgc->pgc_chunk, csz, pmp->pr_vaddr + n) != csz ||
2N/A pwrite64(pgc->pgc_fd, pgc->pgc_chunk, csz,
2N/A *pgc->pgc_doff + n) != csz) {
2N/A int err = errno;
2N/A (void) pwrite64(pgc->pgc_fd, &err, sizeof (err),
2N/A *pgc->pgc_doff);
2N/A *pgc->pgc_doff += roundup(sizeof (err), 8);
2N/A
2N/A phdr.p_flags |= PF_SUNW_FAILURE;
2N/A (void) ftruncate64(pgc->pgc_fd, *pgc->pgc_doff);
2N/A goto exclude;
2N/A }
2N/A
2N/A n += csz;
2N/A }
2N/A
2N/A phdr.p_offset = *pgc->pgc_doff;
2N/A phdr.p_filesz = pmp->pr_size;
2N/A *pgc->pgc_doff += roundup(phdr.p_filesz, 8);
2N/A
2N/Aexclude:
2N/A if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
2N/A if (pwrite64(pgc->pgc_fd, &phdr, sizeof (phdr),
2N/A *pgc->pgc_poff) != sizeof (phdr))
2N/A return (1);
2N/A
2N/A *pgc->pgc_poff += sizeof (phdr);
2N/A#ifdef _LP64
2N/A } else {
2N/A Elf32_Phdr phdr32;
2N/A
2N/A bzero(&phdr32, sizeof (phdr32));
2N/A phdr32.p_type = phdr.p_type;
2N/A phdr32.p_vaddr = (Elf32_Addr)phdr.p_vaddr;
2N/A phdr32.p_memsz = (Elf32_Word)phdr.p_memsz;
2N/A phdr32.p_flags = phdr.p_flags;
2N/A phdr32.p_offset = (Elf32_Off)phdr.p_offset;
2N/A phdr32.p_filesz = (Elf32_Word)phdr.p_filesz;
2N/A
2N/A if (pwrite64(pgc->pgc_fd, &phdr32, sizeof (phdr32),
2N/A *pgc->pgc_poff) != sizeof (phdr32))
2N/A return (1);
2N/A
2N/A *pgc->pgc_poff += sizeof (phdr32);
2N/A#endif /* _LP64 */
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Awrite_shstrtab(struct ps_prochandle *P, pgcore_t *pgc)
2N/A{
2N/A off64_t off = *pgc->pgc_doff;
2N/A size_t size = 0;
2N/A shstrtab_t *s = &pgc->pgc_shstrtab;
2N/A int i, ndx;
2N/A
2N/A if (shstrtab_size(s) == 1)
2N/A return (0);
2N/A
2N/A /*
2N/A * Preemptively stick the name of the shstrtab in the string table.
2N/A */
2N/A (void) shstrtab_ndx(&pgc->pgc_shstrtab, STR_SHSTRTAB);
2N/A size = shstrtab_size(s);
2N/A
2N/A /*
2N/A * Dump all the strings that we used being sure we include the
2N/A * terminating null character.
2N/A */
2N/A for (i = 0; i < STR_NUM; i++) {
2N/A if ((ndx = s->sst_ndx[i]) != 0 || i == STR_NONE) {
2N/A const char *str = shstrtab_data[i];
2N/A size_t len = strlen(str) + 1;
2N/A if (pwrite64(pgc->pgc_fd, str, len, off + ndx) != len)
2N/A return (1);
2N/A }
2N/A }
2N/A
2N/A if (P->status.pr_dmodel == PR_MODEL_ILP32) {
2N/A Elf32_Shdr shdr;
2N/A
2N/A bzero(&shdr, sizeof (shdr));
2N/A shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, STR_SHSTRTAB);
2N/A shdr.sh_size = size;
2N/A shdr.sh_offset = *pgc->pgc_doff;
2N/A shdr.sh_addralign = 1;
2N/A shdr.sh_flags = SHF_STRINGS;
2N/A shdr.sh_type = SHT_STRTAB;
2N/A
2N/A if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
2N/A *pgc->pgc_soff) != sizeof (shdr))
2N/A return (1);
2N/A
2N/A *pgc->pgc_soff += sizeof (shdr);
2N/A#ifdef _LP64
2N/A } else {
2N/A Elf64_Shdr shdr;
2N/A
2N/A bzero(&shdr, sizeof (shdr));
2N/A shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, STR_SHSTRTAB);
2N/A shdr.sh_size = size;
2N/A shdr.sh_offset = *pgc->pgc_doff;
2N/A shdr.sh_addralign = 1;
2N/A shdr.sh_flags = SHF_STRINGS;
2N/A shdr.sh_type = SHT_STRTAB;
2N/A
2N/A if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
2N/A *pgc->pgc_soff) != sizeof (shdr))
2N/A return (1);
2N/A
2N/A *pgc->pgc_soff += sizeof (shdr);
2N/A#endif /* _LP64 */
2N/A }
2N/A
2N/A *pgc->pgc_doff += roundup(size, 8);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Don't explicity stop the process; that's up to the consumer.
2N/A */
2N/Aint
2N/APfgcore(struct ps_prochandle *P, int fd, core_content_t content)
2N/A{
2N/A char plat[SYS_NMLN];
2N/A char zonename[ZONENAME_MAX];
2N/A int platlen = -1;
2N/A pgcore_t pgc;
2N/A off64_t poff, soff, doff, boff;
2N/A struct utsname uts;
2N/A uint_t nphdrs, nshdrs;
2N/A
2N/A if (ftruncate64(fd, 0) != 0)
2N/A return (-1);
2N/A
2N/A if (content == CC_CONTENT_INVALID) {
2N/A errno = EINVAL;
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * Cache the mappings and other useful data.
2N/A */
2N/A (void) Prd_agent(P);
2N/A (void) Ppsinfo(P);
2N/A
2N/A pgc.P = P;
2N/A pgc.pgc_fd = fd;
2N/A pgc.pgc_poff = &poff;
2N/A pgc.pgc_soff = &soff;
2N/A pgc.pgc_doff = &doff;
2N/A pgc.pgc_content = content;
2N/A pgc.pgc_chunksz = PAGESIZE;
2N/A if ((pgc.pgc_chunk = malloc(pgc.pgc_chunksz)) == NULL)
2N/A return (-1);
2N/A
2N/A shstrtab_init(&pgc.pgc_shstrtab);
2N/A
2N/A /*
2N/A * There are two PT_NOTE program headers for ancillary data, and
2N/A * one for each mapping.
2N/A */
2N/A nphdrs = 2 + P->map_count;
2N/A nshdrs = count_sections(&pgc);
2N/A
2N/A (void) Pplatform(P, plat, sizeof (plat));
2N/A platlen = strlen(plat) + 1;
2N/A Preadauxvec(P);
2N/A (void) Puname(P, &uts);
2N/A if (Pzonename(P, zonename, sizeof (zonename)) == NULL)
2N/A zonename[0] = '\0';
2N/A
2N/A /*
2N/A * The core file contents may required zero section headers, but if we
2N/A * overflow the 16 bits allotted to the program header count in the ELF
2N/A * header, we'll need that program header at index zero.
2N/A */
2N/A if (nshdrs == 0 && nphdrs >= PN_XNUM)
2N/A nshdrs = 1;
2N/A
2N/A /*
2N/A * Set up the ELF header.
2N/A */
2N/A if (P->status.pr_dmodel == PR_MODEL_ILP32) {
2N/A Elf32_Ehdr ehdr;
2N/A
2N/A bzero(&ehdr, sizeof (ehdr));
2N/A ehdr.e_ident[EI_MAG0] = ELFMAG0;
2N/A ehdr.e_ident[EI_MAG1] = ELFMAG1;
2N/A ehdr.e_ident[EI_MAG2] = ELFMAG2;
2N/A ehdr.e_ident[EI_MAG3] = ELFMAG3;
2N/A ehdr.e_type = ET_CORE;
2N/A
2N/A ehdr.e_ident[EI_CLASS] = ELFCLASS32;
2N/A#if defined(__sparc)
2N/A ehdr.e_machine = EM_SPARC;
2N/A ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
2N/A#elif defined(__i386) || defined(__amd64)
2N/A ehdr.e_machine = EM_386;
2N/A ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
2N/A#else
2N/A#error "unknown machine type"
2N/A#endif
2N/A ehdr.e_ident[EI_VERSION] = EV_CURRENT;
2N/A
2N/A ehdr.e_version = EV_CURRENT;
2N/A ehdr.e_ehsize = sizeof (ehdr);
2N/A
2N/A if (nphdrs >= PN_XNUM)
2N/A ehdr.e_phnum = PN_XNUM;
2N/A else
2N/A ehdr.e_phnum = (unsigned short)nphdrs;
2N/A
2N/A ehdr.e_phentsize = sizeof (Elf32_Phdr);
2N/A ehdr.e_phoff = ehdr.e_ehsize;
2N/A
2N/A if (nshdrs > 0) {
2N/A if (nshdrs >= SHN_LORESERVE)
2N/A ehdr.e_shnum = 0;
2N/A else
2N/A ehdr.e_shnum = (unsigned short)nshdrs;
2N/A
2N/A if (nshdrs - 1 >= SHN_LORESERVE)
2N/A ehdr.e_shstrndx = SHN_XINDEX;
2N/A else
2N/A ehdr.e_shstrndx = (unsigned short)(nshdrs - 1);
2N/A
2N/A ehdr.e_shentsize = sizeof (Elf32_Shdr);
2N/A ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs;
2N/A }
2N/A
2N/A if (pwrite64(fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
2N/A goto err;
2N/A
2N/A poff = ehdr.e_phoff;
2N/A soff = ehdr.e_shoff;
2N/A doff = boff = ehdr.e_ehsize +
2N/A ehdr.e_phentsize * nphdrs +
2N/A ehdr.e_shentsize * nshdrs;
2N/A
2N/A#ifdef _LP64
2N/A } else {
2N/A Elf64_Ehdr ehdr;
2N/A
2N/A bzero(&ehdr, sizeof (ehdr));
2N/A ehdr.e_ident[EI_MAG0] = ELFMAG0;
2N/A ehdr.e_ident[EI_MAG1] = ELFMAG1;
2N/A ehdr.e_ident[EI_MAG2] = ELFMAG2;
2N/A ehdr.e_ident[EI_MAG3] = ELFMAG3;
2N/A ehdr.e_type = ET_CORE;
2N/A
2N/A ehdr.e_ident[EI_CLASS] = ELFCLASS64;
2N/A#if defined(__sparc)
2N/A ehdr.e_machine = EM_SPARCV9;
2N/A ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
2N/A#elif defined(__i386) || defined(__amd64)
2N/A ehdr.e_machine = EM_AMD64;
2N/A ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
2N/A#else
2N/A#error "unknown machine type"
2N/A#endif
2N/A ehdr.e_ident[EI_VERSION] = EV_CURRENT;
2N/A
2N/A ehdr.e_version = EV_CURRENT;
2N/A ehdr.e_ehsize = sizeof (ehdr);
2N/A
2N/A if (nphdrs >= PN_XNUM)
2N/A ehdr.e_phnum = PN_XNUM;
2N/A else
2N/A ehdr.e_phnum = (unsigned short)nphdrs;
2N/A
2N/A ehdr.e_phentsize = sizeof (Elf64_Phdr);
2N/A ehdr.e_phoff = ehdr.e_ehsize;
2N/A
2N/A if (nshdrs > 0) {
2N/A if (nshdrs >= SHN_LORESERVE)
2N/A ehdr.e_shnum = 0;
2N/A else
2N/A ehdr.e_shnum = (unsigned short)nshdrs;
2N/A
2N/A if (nshdrs - 1 >= SHN_LORESERVE)
2N/A ehdr.e_shstrndx = SHN_XINDEX;
2N/A else
2N/A ehdr.e_shstrndx = (unsigned short)(nshdrs - 1);
2N/A
2N/A ehdr.e_shentsize = sizeof (Elf64_Shdr);
2N/A ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs;
2N/A }
2N/A
2N/A if (pwrite64(fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
2N/A goto err;
2N/A
2N/A poff = ehdr.e_phoff;
2N/A soff = ehdr.e_shoff;
2N/A doff = boff = ehdr.e_ehsize +
2N/A ehdr.e_phentsize * nphdrs +
2N/A ehdr.e_shentsize * nshdrs;
2N/A
2N/A#endif /* _LP64 */
2N/A }
2N/A
2N/A /*
2N/A * Write the zero indexed section if it exists.
2N/A */
2N/A if (nshdrs > 0 && write_shdr(&pgc, STR_NONE, 0, 0, 0, 0,
2N/A nshdrs >= SHN_LORESERVE ? nshdrs : 0,
2N/A nshdrs - 1 >= SHN_LORESERVE ? nshdrs - 1 : 0,
2N/A nphdrs >= PN_XNUM ? nphdrs : 0, 0, 0) != 0)
2N/A goto err;
2N/A
2N/A /*
2N/A * Construct the old-style note header and section.
2N/A */
2N/A
2N/A if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
2N/A prpsinfo_t prpsinfo;
2N/A
2N/A mkprpsinfo(P, &prpsinfo);
2N/A if (write_note(fd, NT_PRPSINFO, &prpsinfo, sizeof (prpsinfo_t),
2N/A &doff) != 0) {
2N/A goto err;
2N/A }
2N/A if (write_note(fd, NT_AUXV, P->auxv,
2N/A P->nauxv * sizeof (P->auxv[0]), &doff) != 0) {
2N/A goto err;
2N/A }
2N/A#ifdef _LP64
2N/A } else {
2N/A prpsinfo32_t pi32;
2N/A auxv32_t *av32;
2N/A size_t size = sizeof (auxv32_t) * P->nauxv;
2N/A int i;
2N/A
2N/A mkprpsinfo32(P, &pi32);
2N/A if (write_note(fd, NT_PRPSINFO, &pi32, sizeof (prpsinfo32_t),
2N/A &doff) != 0) {
2N/A goto err;
2N/A }
2N/A
2N/A if ((av32 = malloc(size)) == NULL)
2N/A goto err;
2N/A
2N/A for (i = 0; i < P->nauxv; i++) {
2N/A auxv_n_to_32(&P->auxv[i], &av32[i]);
2N/A }
2N/A
2N/A if (write_note(fd, NT_AUXV, av32, size, &doff) != 0) {
2N/A free(av32);
2N/A goto err;
2N/A }
2N/A
2N/A free(av32);
2N/A#endif /* _LP64 */
2N/A }
2N/A
2N/A if (write_note(fd, NT_PLATFORM, plat, platlen, &doff) != 0)
2N/A goto err;
2N/A
2N/A if (Plwp_iter_all(P, old_per_lwp, &pgc) != 0)
2N/A goto err;
2N/A
2N/A if (P->status.pr_dmodel == PR_MODEL_ILP32) {
2N/A Elf32_Phdr phdr;
2N/A
2N/A bzero(&phdr, sizeof (phdr));
2N/A phdr.p_type = PT_NOTE;
2N/A phdr.p_flags = PF_R;
2N/A phdr.p_offset = (Elf32_Off)boff;
2N/A phdr.p_filesz = doff - boff;
2N/A boff = doff;
2N/A
2N/A if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
2N/A goto err;
2N/A poff += sizeof (phdr);
2N/A#ifdef _LP64
2N/A } else {
2N/A Elf64_Phdr phdr;
2N/A
2N/A bzero(&phdr, sizeof (phdr));
2N/A phdr.p_type = PT_NOTE;
2N/A phdr.p_flags = PF_R;
2N/A phdr.p_offset = boff;
2N/A phdr.p_filesz = doff - boff;
2N/A boff = doff;
2N/A
2N/A if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
2N/A goto err;
2N/A poff += sizeof (phdr);
2N/A#endif /* _LP64 */
2N/A }
2N/A
2N/A /*
2N/A * Construct the new-style note header and section.
2N/A */
2N/A
2N/A if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
2N/A if (write_note(fd, NT_PSINFO, &P->psinfo, sizeof (psinfo_t),
2N/A &doff) != 0) {
2N/A goto err;
2N/A }
2N/A if (write_note(fd, NT_PSTATUS, &P->status, sizeof (pstatus_t),
2N/A &doff) != 0) {
2N/A goto err;
2N/A }
2N/A if (write_note(fd, NT_AUXV, P->auxv,
2N/A P->nauxv * sizeof (P->auxv[0]), &doff) != 0) {
2N/A goto err;
2N/A }
2N/A#ifdef _LP64
2N/A } else {
2N/A psinfo32_t pi32;
2N/A pstatus32_t ps32;
2N/A auxv32_t *av32;
2N/A size_t size = sizeof (auxv32_t) * P->nauxv;
2N/A int i;
2N/A
2N/A psinfo_n_to_32(&P->psinfo, &pi32);
2N/A if (write_note(fd, NT_PSINFO, &pi32, sizeof (psinfo32_t),
2N/A &doff) != 0) {
2N/A goto err;
2N/A }
2N/A pstatus_n_to_32(&P->status, &ps32);
2N/A if (write_note(fd, NT_PSTATUS, &ps32, sizeof (pstatus32_t),
2N/A &doff) != 0) {
2N/A goto err;
2N/A }
2N/A if ((av32 = malloc(size)) == NULL)
2N/A goto err;
2N/A
2N/A for (i = 0; i < P->nauxv; i++) {
2N/A auxv_n_to_32(&P->auxv[i], &av32[i]);
2N/A }
2N/A
2N/A if (write_note(fd, NT_AUXV, av32, size, &doff) != 0) {
2N/A free(av32);
2N/A goto err;
2N/A }
2N/A
2N/A free(av32);
2N/A#endif /* _LP64 */
2N/A }
2N/A
2N/A if (write_note(fd, NT_PLATFORM, plat, platlen, &doff) != 0 ||
2N/A write_note(fd, NT_UTSNAME, &uts, sizeof (uts), &doff) != 0 ||
2N/A write_note(fd, NT_CONTENT, &content, sizeof (content), &doff) != 0)
2N/A goto err;
2N/A
2N/A {
2N/A prcred_t cred, *cp;
2N/A size_t size = sizeof (prcred_t);
2N/A
2N/A if (Pcred(P, &cred, 0) != 0)
2N/A goto err;
2N/A
2N/A if (cred.pr_ngroups > 0)
2N/A size += sizeof (gid_t) * (cred.pr_ngroups - 1);
2N/A if ((cp = malloc(size)) == NULL)
2N/A goto err;
2N/A
2N/A if (Pcred(P, cp, cred.pr_ngroups) != 0 ||
2N/A write_note(fd, NT_PRCRED, cp, size, &doff) != 0) {
2N/A free(cp);
2N/A goto err;
2N/A }
2N/A
2N/A free(cp);
2N/A }
2N/A
2N/A {
2N/A prpriv_t *ppriv;
2N/A const priv_impl_info_t *pinfo;
2N/A size_t pprivsz, pinfosz;
2N/A
2N/A if ((ppriv = proc_get_priv(P->pid)) == NULL)
2N/A goto err;
2N/A pprivsz = PRIV_PRPRIV_SIZE(ppriv);
2N/A
2N/A if (write_note(fd, NT_PRPRIV, ppriv, pprivsz, &doff) != 0) {
2N/A free(ppriv);
2N/A goto err;
2N/A }
2N/A free(ppriv);
2N/A
2N/A if ((pinfo = getprivimplinfo()) == NULL)
2N/A goto err;
2N/A pinfosz = PRIV_IMPL_INFO_SIZE(pinfo);
2N/A
2N/A if (write_note(fd, NT_PRPRIVINFO, pinfo, pinfosz, &doff) != 0)
2N/A goto err;
2N/A }
2N/A
2N/A if (write_note(fd, NT_ZONENAME, zonename, strlen(zonename) + 1,
2N/A &doff) != 0)
2N/A goto err;
2N/A
2N/A#if defined(__i386) || defined(__amd64)
2N/A /* CSTYLED */
2N/A {
2N/A struct ssd *ldtp;
2N/A size_t size;
2N/A int nldt;
2N/A
2N/A /*
2N/A * Only dump out non-zero sized LDT notes.
2N/A */
2N/A if ((nldt = Pldt(P, NULL, 0)) != 0) {
2N/A size = sizeof (struct ssd) * nldt;
2N/A if ((ldtp = malloc(size)) == NULL)
2N/A goto err;
2N/A
2N/A if (Pldt(P, ldtp, nldt) == -1 ||
2N/A write_note(fd, NT_LDT, ldtp, size, &doff) != 0) {
2N/A free(ldtp);
2N/A goto err;
2N/A }
2N/A
2N/A free(ldtp);
2N/A }
2N/A }
2N/A#endif /* __i386 || __amd64 */
2N/A
2N/A if (Plwp_iter_all(P, new_per_lwp, &pgc) != 0)
2N/A goto err;
2N/A
2N/A if (P->status.pr_dmodel == PR_MODEL_ILP32) {
2N/A Elf32_Phdr phdr;
2N/A
2N/A bzero(&phdr, sizeof (phdr));
2N/A phdr.p_type = PT_NOTE;
2N/A phdr.p_flags = PF_R;
2N/A phdr.p_offset = (Elf32_Off)boff;
2N/A phdr.p_filesz = doff - boff;
2N/A boff = doff;
2N/A
2N/A if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
2N/A goto err;
2N/A poff += sizeof (phdr);
2N/A#ifdef _LP64
2N/A } else {
2N/A Elf64_Phdr phdr;
2N/A
2N/A bzero(&phdr, sizeof (phdr));
2N/A phdr.p_type = PT_NOTE;
2N/A phdr.p_flags = PF_R;
2N/A phdr.p_offset = boff;
2N/A phdr.p_filesz = doff - boff;
2N/A boff = doff;
2N/A
2N/A if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
2N/A goto err;
2N/A poff += sizeof (phdr);
2N/A#endif /* _LP64 */
2N/A }
2N/A
2N/A /*
2N/A * Construct the headers for each mapping and write out its data
2N/A * if the content parameter indicates that it should be present
2N/A * in the core file.
2N/A */
2N/A if (Pmapping_iter(P, dump_map, &pgc) != 0)
2N/A goto err;
2N/A
2N/A if (dump_sections(&pgc) != 0)
2N/A goto err;
2N/A
2N/A if (write_shstrtab(P, &pgc) != 0)
2N/A goto err;
2N/A
2N/A free(pgc.pgc_chunk);
2N/A
2N/A return (0);
2N/A
2N/Aerr:
2N/A /*
2N/A * Wipe out anything we may have written if there was an error.
2N/A */
2N/A (void) ftruncate64(fd, 0);
2N/A free(pgc.pgc_chunk);
2N/A return (-1);
2N/A}
2N/A
2N/Astatic const char *content_str[] = {
2N/A "stack", /* CC_CONTENT_STACK */
2N/A "heap", /* CC_CONTENT_HEAP */
2N/A "shfile", /* CC_CONTENT_SHFILE */
2N/A "shanon", /* CC_CONTENT_SHANON */
2N/A "text", /* CC_CONTENT_TEXT */
2N/A "data", /* CC_CONTENT_DATA */
2N/A "rodata", /* CC_CONTENT_RODATA */
2N/A "anon", /* CC_CONTENT_ANON */
2N/A "shm", /* CC_CONTENT_SHM */
2N/A "ism", /* CC_CONTENT_ISM */
2N/A "dism", /* CC_CONTENT_DISM */
2N/A "ctf", /* CC_CONTENT_CTF */
2N/A "symtab", /* CC_CONTENT_SYMTAB */
2N/A};
2N/A
2N/Astatic uint_t ncontent_str = sizeof (content_str) / sizeof (content_str[0]);
2N/A
2N/A#define STREQ(a, b, n) (strlen(b) == (n) && strncmp(a, b, n) == 0)
2N/A
2N/Aint
2N/Aproc_str2content(const char *str, core_content_t *cp)
2N/A{
2N/A const char *cur = str;
2N/A int add = 1;
2N/A core_content_t mask, content = 0;
2N/A
2N/A for (;;) {
2N/A for (cur = str; isalpha(*cur); cur++)
2N/A continue;
2N/A
2N/A if (STREQ(str, "default", cur - str)) {
2N/A mask = CC_CONTENT_DEFAULT;
2N/A } else if (STREQ(str, "all", cur - str)) {
2N/A mask = CC_CONTENT_ALL;
2N/A } else if (STREQ(str, "none", cur - str)) {
2N/A mask = 0;
2N/A } else {
2N/A int i = 0;
2N/A
2N/A while (!STREQ(str, content_str[i], cur - str)) {
2N/A i++;
2N/A
2N/A if (i >= ncontent_str)
2N/A return (-1);
2N/A }
2N/A
2N/A mask = (core_content_t)1 << i;
2N/A }
2N/A
2N/A if (add)
2N/A content |= mask;
2N/A else
2N/A content &= ~mask;
2N/A
2N/A switch (*cur) {
2N/A case '\0':
2N/A *cp = content;
2N/A return (0);
2N/A case '+':
2N/A add = 1;
2N/A break;
2N/A case '-':
2N/A add = 0;
2N/A break;
2N/A default:
2N/A return (-1);
2N/A }
2N/A
2N/A str = cur + 1;
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Apopc(core_content_t x)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; x != 0; i++)
2N/A x &= x - 1;
2N/A
2N/A return (i);
2N/A}
2N/A
2N/Aint
2N/Aproc_content2str(core_content_t content, char *buf, size_t size)
2N/A{
2N/A int nonecnt, defcnt, allcnt;
2N/A core_content_t mask, bit;
2N/A int first;
2N/A uint_t index;
2N/A size_t n, tot = 0;
2N/A
2N/A if (content == 0)
2N/A return ((int)strlcpy(buf, "none", size));
2N/A
2N/A if (content & ~CC_CONTENT_ALL)
2N/A return ((int)strlcpy(buf, "<invalid>", size));
2N/A
2N/A nonecnt = popc(content);
2N/A defcnt = 1 + popc(content ^ CC_CONTENT_DEFAULT);
2N/A allcnt = 1 + popc(content ^ CC_CONTENT_ALL);
2N/A
2N/A if (defcnt <= nonecnt && defcnt <= allcnt) {
2N/A mask = content ^ CC_CONTENT_DEFAULT;
2N/A first = 0;
2N/A tot += (n = strlcpy(buf, "default", size));
2N/A if (n > size)
2N/A n = size;
2N/A buf += n;
2N/A size -= n;
2N/A } else if (allcnt < nonecnt) {
2N/A mask = content ^ CC_CONTENT_ALL;
2N/A first = 0;
2N/A tot += (n = strlcpy(buf, "all", size));
2N/A if (n > size)
2N/A n = size;
2N/A buf += n;
2N/A size -= n;
2N/A } else {
2N/A mask = content;
2N/A first = 1;
2N/A }
2N/A
2N/A while (mask != 0) {
2N/A bit = mask ^ (mask & (mask - 1));
2N/A
2N/A if (!first) {
2N/A if (size > 1) {
2N/A *buf = (bit & content) ? '+' : '-';
2N/A buf++;
2N/A size--;
2N/A }
2N/A
2N/A tot++;
2N/A }
2N/A index = popc(bit - 1);
2N/A tot += (n = strlcpy(buf, content_str[index], size));
2N/A if (n > size)
2N/A n = size;
2N/A buf += n;
2N/A size -= n;
2N/A
2N/A mask ^= bit;
2N/A first = 0;
2N/A }
2N/A
2N/A return ((int)tot);
2N/A}