10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52712Snn35248 * Common Development and Distribution License (the "License").
62712Snn35248 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
229900SAli.Bahrami@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/utsname.h>
280Sstevel@tonic-gate #include <sys/sysmacros.h>
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <alloca.h>
310Sstevel@tonic-gate #include <rtld_db.h>
320Sstevel@tonic-gate #include <libgen.h>
330Sstevel@tonic-gate #include <limits.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <unistd.h>
370Sstevel@tonic-gate #include <errno.h>
380Sstevel@tonic-gate #include <gelf.h>
390Sstevel@tonic-gate #include <stddef.h>
400Sstevel@tonic-gate
417675SEdward.Pilatowicz@Sun.COM #include "libproc.h"
420Sstevel@tonic-gate #include "Pcontrol.h"
430Sstevel@tonic-gate #include "P32ton.h"
440Sstevel@tonic-gate #include "Putil.h"
450Sstevel@tonic-gate
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate * Pcore.c - Code to initialize a ps_prochandle from a core dump. We
480Sstevel@tonic-gate * allocate an additional structure to hold information from the core
490Sstevel@tonic-gate * file, and attach this to the standard ps_prochandle in place of the
500Sstevel@tonic-gate * ability to examine /proc/<pid>/ files.
510Sstevel@tonic-gate */
520Sstevel@tonic-gate
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate * Basic i/o function for reading and writing from the process address space
550Sstevel@tonic-gate * stored in the core file and associated shared libraries. We compute the
560Sstevel@tonic-gate * appropriate fd and offsets, and let the provided prw function do the rest.
570Sstevel@tonic-gate */
580Sstevel@tonic-gate static ssize_t
core_rw(struct ps_prochandle * P,void * buf,size_t n,uintptr_t addr,ssize_t (* prw)(int,void *,size_t,off64_t))590Sstevel@tonic-gate core_rw(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr,
600Sstevel@tonic-gate ssize_t (*prw)(int, void *, size_t, off64_t))
610Sstevel@tonic-gate {
620Sstevel@tonic-gate ssize_t resid = n;
630Sstevel@tonic-gate
640Sstevel@tonic-gate while (resid != 0) {
650Sstevel@tonic-gate map_info_t *mp = Paddr2mptr(P, addr);
660Sstevel@tonic-gate
670Sstevel@tonic-gate uintptr_t mapoff;
680Sstevel@tonic-gate ssize_t len;
690Sstevel@tonic-gate off64_t off;
700Sstevel@tonic-gate int fd;
710Sstevel@tonic-gate
720Sstevel@tonic-gate if (mp == NULL)
730Sstevel@tonic-gate break; /* No mapping for this address */
740Sstevel@tonic-gate
750Sstevel@tonic-gate if (mp->map_pmap.pr_mflags & MA_RESERVED1) {
760Sstevel@tonic-gate if (mp->map_file == NULL || mp->map_file->file_fd < 0)
770Sstevel@tonic-gate break; /* No file or file not open */
780Sstevel@tonic-gate
790Sstevel@tonic-gate fd = mp->map_file->file_fd;
800Sstevel@tonic-gate } else
810Sstevel@tonic-gate fd = P->asfd;
820Sstevel@tonic-gate
830Sstevel@tonic-gate mapoff = addr - mp->map_pmap.pr_vaddr;
840Sstevel@tonic-gate len = MIN(resid, mp->map_pmap.pr_size - mapoff);
850Sstevel@tonic-gate off = mp->map_offset + mapoff;
860Sstevel@tonic-gate
870Sstevel@tonic-gate if ((len = prw(fd, buf, len, off)) <= 0)
880Sstevel@tonic-gate break;
890Sstevel@tonic-gate
900Sstevel@tonic-gate resid -= len;
910Sstevel@tonic-gate addr += len;
920Sstevel@tonic-gate buf = (char *)buf + len;
930Sstevel@tonic-gate }
940Sstevel@tonic-gate
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate * Important: Be consistent with the behavior of i/o on the as file:
970Sstevel@tonic-gate * writing to an invalid address yields EIO; reading from an invalid
980Sstevel@tonic-gate * address falls through to returning success and zero bytes.
990Sstevel@tonic-gate */
1000Sstevel@tonic-gate if (resid == n && n != 0 && prw != pread64) {
1010Sstevel@tonic-gate errno = EIO;
1020Sstevel@tonic-gate return (-1);
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate return (n - resid);
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate static ssize_t
Pread_core(struct ps_prochandle * P,void * buf,size_t n,uintptr_t addr)1090Sstevel@tonic-gate Pread_core(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr)
1100Sstevel@tonic-gate {
1110Sstevel@tonic-gate return (core_rw(P, buf, n, addr, pread64));
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate static ssize_t
Pwrite_core(struct ps_prochandle * P,const void * buf,size_t n,uintptr_t addr)1150Sstevel@tonic-gate Pwrite_core(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr)
1160Sstevel@tonic-gate {
1170Sstevel@tonic-gate return (core_rw(P, (void *)buf, n, addr,
1180Sstevel@tonic-gate (ssize_t (*)(int, void *, size_t, off64_t)) pwrite64));
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate static const ps_rwops_t P_core_ops = { Pread_core, Pwrite_core };
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate /*
1240Sstevel@tonic-gate * Return the lwp_info_t for the given lwpid. If no such lwpid has been
1250Sstevel@tonic-gate * encountered yet, allocate a new structure and return a pointer to it.
1260Sstevel@tonic-gate * Create a list of lwp_info_t structures sorted in decreasing lwp_id order.
1270Sstevel@tonic-gate */
1280Sstevel@tonic-gate static lwp_info_t *
lwpid2info(struct ps_prochandle * P,lwpid_t id)1290Sstevel@tonic-gate lwpid2info(struct ps_prochandle *P, lwpid_t id)
1300Sstevel@tonic-gate {
1310Sstevel@tonic-gate lwp_info_t *lwp = list_next(&P->core->core_lwp_head);
1320Sstevel@tonic-gate lwp_info_t *next;
1330Sstevel@tonic-gate uint_t i;
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate for (i = 0; i < P->core->core_nlwp; i++, lwp = list_next(lwp)) {
1360Sstevel@tonic-gate if (lwp->lwp_id == id) {
1370Sstevel@tonic-gate P->core->core_lwp = lwp;
1380Sstevel@tonic-gate return (lwp);
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate if (lwp->lwp_id < id) {
1410Sstevel@tonic-gate break;
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate next = lwp;
1460Sstevel@tonic-gate if ((lwp = calloc(1, sizeof (lwp_info_t))) == NULL)
1470Sstevel@tonic-gate return (NULL);
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate list_link(lwp, next);
1500Sstevel@tonic-gate lwp->lwp_id = id;
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate P->core->core_lwp = lwp;
1530Sstevel@tonic-gate P->core->core_nlwp++;
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate return (lwp);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate /*
1590Sstevel@tonic-gate * The core file itself contains a series of NOTE segments containing saved
1600Sstevel@tonic-gate * structures from /proc at the time the process died. For each note we
1610Sstevel@tonic-gate * comprehend, we define a function to read it in from the core file,
1620Sstevel@tonic-gate * convert it to our native data model if necessary, and store it inside
1630Sstevel@tonic-gate * the ps_prochandle. Each function is invoked by Pfgrab_core() with the
1640Sstevel@tonic-gate * seek pointer on P->asfd positioned appropriately. We populate a table
1650Sstevel@tonic-gate * of pointers to these note functions below.
1660Sstevel@tonic-gate */
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate static int
note_pstatus(struct ps_prochandle * P,size_t nbytes)1690Sstevel@tonic-gate note_pstatus(struct ps_prochandle *P, size_t nbytes)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate #ifdef _LP64
1720Sstevel@tonic-gate if (P->core->core_dmodel == PR_MODEL_ILP32) {
1730Sstevel@tonic-gate pstatus32_t ps32;
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate if (nbytes < sizeof (pstatus32_t) ||
1760Sstevel@tonic-gate read(P->asfd, &ps32, sizeof (ps32)) != sizeof (ps32))
1770Sstevel@tonic-gate goto err;
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate pstatus_32_to_n(&ps32, &P->status);
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate } else
1820Sstevel@tonic-gate #endif
1830Sstevel@tonic-gate if (nbytes < sizeof (pstatus_t) ||
1840Sstevel@tonic-gate read(P->asfd, &P->status, sizeof (pstatus_t)) != sizeof (pstatus_t))
1850Sstevel@tonic-gate goto err;
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate P->orig_status = P->status;
1880Sstevel@tonic-gate P->pid = P->status.pr_pid;
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate return (0);
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate err:
1930Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_PSTATUS\n");
1940Sstevel@tonic-gate return (-1);
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate static int
note_lwpstatus(struct ps_prochandle * P,size_t nbytes)1980Sstevel@tonic-gate note_lwpstatus(struct ps_prochandle *P, size_t nbytes)
1990Sstevel@tonic-gate {
2000Sstevel@tonic-gate lwp_info_t *lwp;
2010Sstevel@tonic-gate lwpstatus_t lps;
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate #ifdef _LP64
2040Sstevel@tonic-gate if (P->core->core_dmodel == PR_MODEL_ILP32) {
2050Sstevel@tonic-gate lwpstatus32_t l32;
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate if (nbytes < sizeof (lwpstatus32_t) ||
2080Sstevel@tonic-gate read(P->asfd, &l32, sizeof (l32)) != sizeof (l32))
2090Sstevel@tonic-gate goto err;
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate lwpstatus_32_to_n(&l32, &lps);
2120Sstevel@tonic-gate } else
2130Sstevel@tonic-gate #endif
2140Sstevel@tonic-gate if (nbytes < sizeof (lwpstatus_t) ||
2150Sstevel@tonic-gate read(P->asfd, &lps, sizeof (lps)) != sizeof (lps))
2160Sstevel@tonic-gate goto err;
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate if ((lwp = lwpid2info(P, lps.pr_lwpid)) == NULL) {
2190Sstevel@tonic-gate dprintf("Pgrab_core: failed to add NT_LWPSTATUS\n");
2200Sstevel@tonic-gate return (-1);
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate /*
2240Sstevel@tonic-gate * Erase a useless and confusing artifact of the kernel implementation:
2250Sstevel@tonic-gate * the lwps which did *not* create the core will show SIGKILL. We can
2260Sstevel@tonic-gate * be assured this is bogus because SIGKILL can't produce core files.
2270Sstevel@tonic-gate */
2280Sstevel@tonic-gate if (lps.pr_cursig == SIGKILL)
2290Sstevel@tonic-gate lps.pr_cursig = 0;
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate (void) memcpy(&lwp->lwp_status, &lps, sizeof (lps));
2320Sstevel@tonic-gate return (0);
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate err:
2350Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_LWPSTATUS\n");
2360Sstevel@tonic-gate return (-1);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate static int
note_psinfo(struct ps_prochandle * P,size_t nbytes)2400Sstevel@tonic-gate note_psinfo(struct ps_prochandle *P, size_t nbytes)
2410Sstevel@tonic-gate {
2420Sstevel@tonic-gate #ifdef _LP64
2430Sstevel@tonic-gate if (P->core->core_dmodel == PR_MODEL_ILP32) {
2440Sstevel@tonic-gate psinfo32_t ps32;
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate if (nbytes < sizeof (psinfo32_t) ||
2470Sstevel@tonic-gate read(P->asfd, &ps32, sizeof (ps32)) != sizeof (ps32))
2480Sstevel@tonic-gate goto err;
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate psinfo_32_to_n(&ps32, &P->psinfo);
2510Sstevel@tonic-gate } else
2520Sstevel@tonic-gate #endif
2530Sstevel@tonic-gate if (nbytes < sizeof (psinfo_t) ||
2540Sstevel@tonic-gate read(P->asfd, &P->psinfo, sizeof (psinfo_t)) != sizeof (psinfo_t))
2550Sstevel@tonic-gate goto err;
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate dprintf("pr_fname = <%s>\n", P->psinfo.pr_fname);
2580Sstevel@tonic-gate dprintf("pr_psargs = <%s>\n", P->psinfo.pr_psargs);
2590Sstevel@tonic-gate dprintf("pr_wstat = 0x%x\n", P->psinfo.pr_wstat);
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate return (0);
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate err:
2640Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_PSINFO\n");
2650Sstevel@tonic-gate return (-1);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate static int
note_lwpsinfo(struct ps_prochandle * P,size_t nbytes)2690Sstevel@tonic-gate note_lwpsinfo(struct ps_prochandle *P, size_t nbytes)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate lwp_info_t *lwp;
2720Sstevel@tonic-gate lwpsinfo_t lps;
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate #ifdef _LP64
2750Sstevel@tonic-gate if (P->core->core_dmodel == PR_MODEL_ILP32) {
2760Sstevel@tonic-gate lwpsinfo32_t l32;
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate if (nbytes < sizeof (lwpsinfo32_t) ||
2790Sstevel@tonic-gate read(P->asfd, &l32, sizeof (l32)) != sizeof (l32))
2800Sstevel@tonic-gate goto err;
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate lwpsinfo_32_to_n(&l32, &lps);
2830Sstevel@tonic-gate } else
2840Sstevel@tonic-gate #endif
2850Sstevel@tonic-gate if (nbytes < sizeof (lwpsinfo_t) ||
2860Sstevel@tonic-gate read(P->asfd, &lps, sizeof (lps)) != sizeof (lps))
2870Sstevel@tonic-gate goto err;
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate if ((lwp = lwpid2info(P, lps.pr_lwpid)) == NULL) {
2900Sstevel@tonic-gate dprintf("Pgrab_core: failed to add NT_LWPSINFO\n");
2910Sstevel@tonic-gate return (-1);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate (void) memcpy(&lwp->lwp_psinfo, &lps, sizeof (lps));
2950Sstevel@tonic-gate return (0);
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate err:
2980Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_LWPSINFO\n");
2990Sstevel@tonic-gate return (-1);
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate static int
note_platform(struct ps_prochandle * P,size_t nbytes)3030Sstevel@tonic-gate note_platform(struct ps_prochandle *P, size_t nbytes)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate char *plat;
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate if (P->core->core_platform != NULL)
3080Sstevel@tonic-gate return (0); /* Already seen */
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate if (nbytes != 0 && ((plat = malloc(nbytes + 1)) != NULL)) {
3110Sstevel@tonic-gate if (read(P->asfd, plat, nbytes) != nbytes) {
3120Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_PLATFORM\n");
3130Sstevel@tonic-gate free(plat);
3140Sstevel@tonic-gate return (-1);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate plat[nbytes - 1] = '\0';
3170Sstevel@tonic-gate P->core->core_platform = plat;
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate return (0);
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate static int
note_utsname(struct ps_prochandle * P,size_t nbytes)3240Sstevel@tonic-gate note_utsname(struct ps_prochandle *P, size_t nbytes)
3250Sstevel@tonic-gate {
3260Sstevel@tonic-gate size_t ubytes = sizeof (struct utsname);
3270Sstevel@tonic-gate struct utsname *utsp;
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate if (P->core->core_uts != NULL || nbytes < ubytes)
3300Sstevel@tonic-gate return (0); /* Already seen or bad size */
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate if ((utsp = malloc(ubytes)) == NULL)
3330Sstevel@tonic-gate return (-1);
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate if (read(P->asfd, utsp, ubytes) != ubytes) {
3360Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_UTSNAME\n");
3370Sstevel@tonic-gate free(utsp);
3380Sstevel@tonic-gate return (-1);
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate if (_libproc_debug) {
3420Sstevel@tonic-gate dprintf("uts.sysname = \"%s\"\n", utsp->sysname);
3430Sstevel@tonic-gate dprintf("uts.nodename = \"%s\"\n", utsp->nodename);
3440Sstevel@tonic-gate dprintf("uts.release = \"%s\"\n", utsp->release);
3450Sstevel@tonic-gate dprintf("uts.version = \"%s\"\n", utsp->version);
3460Sstevel@tonic-gate dprintf("uts.machine = \"%s\"\n", utsp->machine);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate P->core->core_uts = utsp;
3500Sstevel@tonic-gate return (0);
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate static int
note_content(struct ps_prochandle * P,size_t nbytes)3540Sstevel@tonic-gate note_content(struct ps_prochandle *P, size_t nbytes)
3550Sstevel@tonic-gate {
3560Sstevel@tonic-gate core_content_t content;
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate if (sizeof (P->core->core_content) != nbytes)
3590Sstevel@tonic-gate return (-1);
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate if (read(P->asfd, &content, sizeof (content)) != sizeof (content))
3620Sstevel@tonic-gate return (-1);
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate P->core->core_content = content;
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate dprintf("core content = %llx\n", content);
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate return (0);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate static int
note_cred(struct ps_prochandle * P,size_t nbytes)3720Sstevel@tonic-gate note_cred(struct ps_prochandle *P, size_t nbytes)
3730Sstevel@tonic-gate {
3740Sstevel@tonic-gate prcred_t *pcrp;
3750Sstevel@tonic-gate int ngroups;
3760Sstevel@tonic-gate const size_t min_size = sizeof (prcred_t) - sizeof (gid_t);
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate /*
3790Sstevel@tonic-gate * We allow for prcred_t notes that are actually smaller than a
3800Sstevel@tonic-gate * prcred_t since the last member isn't essential if there are
3810Sstevel@tonic-gate * no group memberships. This allows for more flexibility when it
3820Sstevel@tonic-gate * comes to slightly malformed -- but still valid -- notes.
3830Sstevel@tonic-gate */
3840Sstevel@tonic-gate if (P->core->core_cred != NULL || nbytes < min_size)
3850Sstevel@tonic-gate return (0); /* Already seen or bad size */
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate ngroups = (nbytes - min_size) / sizeof (gid_t);
3880Sstevel@tonic-gate nbytes = sizeof (prcred_t) + (ngroups - 1) * sizeof (gid_t);
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate if ((pcrp = malloc(nbytes)) == NULL)
3910Sstevel@tonic-gate return (-1);
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate if (read(P->asfd, pcrp, nbytes) != nbytes) {
3940Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_PRCRED\n");
3950Sstevel@tonic-gate free(pcrp);
3960Sstevel@tonic-gate return (-1);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate if (pcrp->pr_ngroups > ngroups) {
4000Sstevel@tonic-gate dprintf("pr_ngroups = %d; resetting to %d based on note size\n",
4010Sstevel@tonic-gate pcrp->pr_ngroups, ngroups);
4020Sstevel@tonic-gate pcrp->pr_ngroups = ngroups;
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate
4050Sstevel@tonic-gate P->core->core_cred = pcrp;
4060Sstevel@tonic-gate return (0);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
4100Sstevel@tonic-gate static int
note_ldt(struct ps_prochandle * P,size_t nbytes)4110Sstevel@tonic-gate note_ldt(struct ps_prochandle *P, size_t nbytes)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate struct ssd *pldt;
4140Sstevel@tonic-gate uint_t nldt;
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate if (P->core->core_ldt != NULL || nbytes < sizeof (struct ssd))
4170Sstevel@tonic-gate return (0); /* Already seen or bad size */
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate nldt = nbytes / sizeof (struct ssd);
4200Sstevel@tonic-gate nbytes = nldt * sizeof (struct ssd);
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate if ((pldt = malloc(nbytes)) == NULL)
4230Sstevel@tonic-gate return (-1);
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate if (read(P->asfd, pldt, nbytes) != nbytes) {
4260Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_LDT\n");
4270Sstevel@tonic-gate free(pldt);
4280Sstevel@tonic-gate return (-1);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate P->core->core_ldt = pldt;
4320Sstevel@tonic-gate P->core->core_nldt = nldt;
4330Sstevel@tonic-gate return (0);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate #endif /* __i386 */
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate static int
note_priv(struct ps_prochandle * P,size_t nbytes)4380Sstevel@tonic-gate note_priv(struct ps_prochandle *P, size_t nbytes)
4390Sstevel@tonic-gate {
4400Sstevel@tonic-gate prpriv_t *pprvp;
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate if (P->core->core_priv != NULL || nbytes < sizeof (prpriv_t))
4430Sstevel@tonic-gate return (0); /* Already seen or bad size */
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate if ((pprvp = malloc(nbytes)) == NULL)
4460Sstevel@tonic-gate return (-1);
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate if (read(P->asfd, pprvp, nbytes) != nbytes) {
4490Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_PRPRIV\n");
4500Sstevel@tonic-gate free(pprvp);
4510Sstevel@tonic-gate return (-1);
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate P->core->core_priv = pprvp;
4550Sstevel@tonic-gate P->core->core_priv_size = nbytes;
4560Sstevel@tonic-gate return (0);
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate static int
note_priv_info(struct ps_prochandle * P,size_t nbytes)4600Sstevel@tonic-gate note_priv_info(struct ps_prochandle *P, size_t nbytes)
4610Sstevel@tonic-gate {
4620Sstevel@tonic-gate extern void *__priv_parse_info();
4630Sstevel@tonic-gate priv_impl_info_t *ppii;
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate if (P->core->core_privinfo != NULL ||
4660Sstevel@tonic-gate nbytes < sizeof (priv_impl_info_t))
4670Sstevel@tonic-gate return (0); /* Already seen or bad size */
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate if ((ppii = malloc(nbytes)) == NULL)
4700Sstevel@tonic-gate return (-1);
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate if (read(P->asfd, ppii, nbytes) != nbytes ||
4730Sstevel@tonic-gate PRIV_IMPL_INFO_SIZE(ppii) != nbytes) {
4740Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_PRPRIVINFO\n");
4750Sstevel@tonic-gate free(ppii);
4760Sstevel@tonic-gate return (-1);
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate
4790Sstevel@tonic-gate P->core->core_privinfo = __priv_parse_info(ppii);
4800Sstevel@tonic-gate P->core->core_ppii = ppii;
4810Sstevel@tonic-gate return (0);
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate static int
note_zonename(struct ps_prochandle * P,size_t nbytes)4850Sstevel@tonic-gate note_zonename(struct ps_prochandle *P, size_t nbytes)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate char *zonename;
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate if (P->core->core_zonename != NULL)
4900Sstevel@tonic-gate return (0); /* Already seen */
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate if (nbytes != 0) {
4930Sstevel@tonic-gate if ((zonename = malloc(nbytes)) == NULL)
4940Sstevel@tonic-gate return (-1);
4950Sstevel@tonic-gate if (read(P->asfd, zonename, nbytes) != nbytes) {
4960Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_ZONENAME\n");
4970Sstevel@tonic-gate free(zonename);
4980Sstevel@tonic-gate return (-1);
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate zonename[nbytes - 1] = '\0';
5010Sstevel@tonic-gate P->core->core_zonename = zonename;
5020Sstevel@tonic-gate }
5030Sstevel@tonic-gate
5040Sstevel@tonic-gate return (0);
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate static int
note_auxv(struct ps_prochandle * P,size_t nbytes)5080Sstevel@tonic-gate note_auxv(struct ps_prochandle *P, size_t nbytes)
5090Sstevel@tonic-gate {
5100Sstevel@tonic-gate size_t n, i;
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate #ifdef _LP64
5130Sstevel@tonic-gate if (P->core->core_dmodel == PR_MODEL_ILP32) {
5140Sstevel@tonic-gate auxv32_t *a32;
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate n = nbytes / sizeof (auxv32_t);
5170Sstevel@tonic-gate nbytes = n * sizeof (auxv32_t);
5180Sstevel@tonic-gate a32 = alloca(nbytes);
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate if (read(P->asfd, a32, nbytes) != nbytes) {
5210Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_AUXV\n");
5220Sstevel@tonic-gate return (-1);
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate if ((P->auxv = malloc(sizeof (auxv_t) * (n + 1))) == NULL)
5260Sstevel@tonic-gate return (-1);
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate for (i = 0; i < n; i++)
5290Sstevel@tonic-gate auxv_32_to_n(&a32[i], &P->auxv[i]);
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate } else {
5320Sstevel@tonic-gate #endif
5330Sstevel@tonic-gate n = nbytes / sizeof (auxv_t);
5340Sstevel@tonic-gate nbytes = n * sizeof (auxv_t);
5350Sstevel@tonic-gate
5360Sstevel@tonic-gate if ((P->auxv = malloc(nbytes + sizeof (auxv_t))) == NULL)
5370Sstevel@tonic-gate return (-1);
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate if (read(P->asfd, P->auxv, nbytes) != nbytes) {
5400Sstevel@tonic-gate free(P->auxv);
5410Sstevel@tonic-gate P->auxv = NULL;
5420Sstevel@tonic-gate return (-1);
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate #ifdef _LP64
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate #endif
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate if (_libproc_debug) {
5490Sstevel@tonic-gate for (i = 0; i < n; i++) {
5500Sstevel@tonic-gate dprintf("P->auxv[%lu] = ( %d, 0x%lx )\n", (ulong_t)i,
5510Sstevel@tonic-gate P->auxv[i].a_type, P->auxv[i].a_un.a_val);
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate /*
5560Sstevel@tonic-gate * Defensive coding for loops which depend upon the auxv array being
5570Sstevel@tonic-gate * terminated by an AT_NULL element; in each case, we've allocated
5580Sstevel@tonic-gate * P->auxv to have an additional element which we force to be AT_NULL.
5590Sstevel@tonic-gate */
5600Sstevel@tonic-gate P->auxv[n].a_type = AT_NULL;
5610Sstevel@tonic-gate P->auxv[n].a_un.a_val = 0L;
5620Sstevel@tonic-gate P->nauxv = (int)n;
5630Sstevel@tonic-gate
5640Sstevel@tonic-gate return (0);
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate #ifdef __sparc
5680Sstevel@tonic-gate static int
note_xreg(struct ps_prochandle * P,size_t nbytes)5690Sstevel@tonic-gate note_xreg(struct ps_prochandle *P, size_t nbytes)
5700Sstevel@tonic-gate {
5710Sstevel@tonic-gate lwp_info_t *lwp = P->core->core_lwp;
5720Sstevel@tonic-gate size_t xbytes = sizeof (prxregset_t);
5730Sstevel@tonic-gate prxregset_t *xregs;
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate if (lwp == NULL || lwp->lwp_xregs != NULL || nbytes < xbytes)
5760Sstevel@tonic-gate return (0); /* No lwp yet, already seen, or bad size */
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate if ((xregs = malloc(xbytes)) == NULL)
5790Sstevel@tonic-gate return (-1);
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate if (read(P->asfd, xregs, xbytes) != xbytes) {
5820Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_PRXREG\n");
5830Sstevel@tonic-gate free(xregs);
5840Sstevel@tonic-gate return (-1);
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate lwp->lwp_xregs = xregs;
5880Sstevel@tonic-gate return (0);
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate
5910Sstevel@tonic-gate static int
note_gwindows(struct ps_prochandle * P,size_t nbytes)5920Sstevel@tonic-gate note_gwindows(struct ps_prochandle *P, size_t nbytes)
5930Sstevel@tonic-gate {
5940Sstevel@tonic-gate lwp_info_t *lwp = P->core->core_lwp;
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate if (lwp == NULL || lwp->lwp_gwins != NULL || nbytes == 0)
5970Sstevel@tonic-gate return (0); /* No lwp yet or already seen or no data */
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate if ((lwp->lwp_gwins = malloc(sizeof (gwindows_t))) == NULL)
6000Sstevel@tonic-gate return (-1);
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate /*
6030Sstevel@tonic-gate * Since the amount of gwindows data varies with how many windows were
6040Sstevel@tonic-gate * actually saved, we just read up to the minimum of the note size
6050Sstevel@tonic-gate * and the size of the gwindows_t type. It doesn't matter if the read
6060Sstevel@tonic-gate * fails since we have to zero out gwindows first anyway.
6070Sstevel@tonic-gate */
6080Sstevel@tonic-gate #ifdef _LP64
6090Sstevel@tonic-gate if (P->core->core_dmodel == PR_MODEL_ILP32) {
6100Sstevel@tonic-gate gwindows32_t g32;
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate (void) memset(&g32, 0, sizeof (g32));
6130Sstevel@tonic-gate (void) read(P->asfd, &g32, MIN(nbytes, sizeof (g32)));
6140Sstevel@tonic-gate gwindows_32_to_n(&g32, lwp->lwp_gwins);
6150Sstevel@tonic-gate
6160Sstevel@tonic-gate } else {
6170Sstevel@tonic-gate #endif
6180Sstevel@tonic-gate (void) memset(lwp->lwp_gwins, 0, sizeof (gwindows_t));
6190Sstevel@tonic-gate (void) read(P->asfd, lwp->lwp_gwins,
6200Sstevel@tonic-gate MIN(nbytes, sizeof (gwindows_t)));
6210Sstevel@tonic-gate #ifdef _LP64
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate #endif
6240Sstevel@tonic-gate return (0);
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate
6270Sstevel@tonic-gate #ifdef __sparcv9
6280Sstevel@tonic-gate static int
note_asrs(struct ps_prochandle * P,size_t nbytes)6290Sstevel@tonic-gate note_asrs(struct ps_prochandle *P, size_t nbytes)
6300Sstevel@tonic-gate {
6310Sstevel@tonic-gate lwp_info_t *lwp = P->core->core_lwp;
6320Sstevel@tonic-gate int64_t *asrs;
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate if (lwp == NULL || lwp->lwp_asrs != NULL || nbytes < sizeof (asrset_t))
6350Sstevel@tonic-gate return (0); /* No lwp yet, already seen, or bad size */
6360Sstevel@tonic-gate
6370Sstevel@tonic-gate if ((asrs = malloc(sizeof (asrset_t))) == NULL)
6380Sstevel@tonic-gate return (-1);
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate if (read(P->asfd, asrs, sizeof (asrset_t)) != sizeof (asrset_t)) {
6410Sstevel@tonic-gate dprintf("Pgrab_core: failed to read NT_ASRS\n");
6420Sstevel@tonic-gate free(asrs);
6430Sstevel@tonic-gate return (-1);
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate
6460Sstevel@tonic-gate lwp->lwp_asrs = asrs;
6470Sstevel@tonic-gate return (0);
6480Sstevel@tonic-gate }
6490Sstevel@tonic-gate #endif /* __sparcv9 */
6500Sstevel@tonic-gate #endif /* __sparc */
6510Sstevel@tonic-gate
6520Sstevel@tonic-gate /*ARGSUSED*/
6530Sstevel@tonic-gate static int
note_notsup(struct ps_prochandle * P,size_t nbytes)6540Sstevel@tonic-gate note_notsup(struct ps_prochandle *P, size_t nbytes)
6550Sstevel@tonic-gate {
6560Sstevel@tonic-gate dprintf("skipping unsupported note type\n");
6570Sstevel@tonic-gate return (0);
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate /*
6610Sstevel@tonic-gate * Populate a table of function pointers indexed by Note type with our
6620Sstevel@tonic-gate * functions to process each type of core file note:
6630Sstevel@tonic-gate */
6640Sstevel@tonic-gate static int (*nhdlrs[])(struct ps_prochandle *, size_t) = {
6650Sstevel@tonic-gate note_notsup, /* 0 unassigned */
6660Sstevel@tonic-gate note_notsup, /* 1 NT_PRSTATUS (old) */
6670Sstevel@tonic-gate note_notsup, /* 2 NT_PRFPREG (old) */
6680Sstevel@tonic-gate note_notsup, /* 3 NT_PRPSINFO (old) */
6690Sstevel@tonic-gate #ifdef __sparc
6700Sstevel@tonic-gate note_xreg, /* 4 NT_PRXREG */
6710Sstevel@tonic-gate #else
6720Sstevel@tonic-gate note_notsup, /* 4 NT_PRXREG */
6730Sstevel@tonic-gate #endif
6740Sstevel@tonic-gate note_platform, /* 5 NT_PLATFORM */
6750Sstevel@tonic-gate note_auxv, /* 6 NT_AUXV */
6760Sstevel@tonic-gate #ifdef __sparc
6770Sstevel@tonic-gate note_gwindows, /* 7 NT_GWINDOWS */
6780Sstevel@tonic-gate #ifdef __sparcv9
6790Sstevel@tonic-gate note_asrs, /* 8 NT_ASRS */
6800Sstevel@tonic-gate #else
6810Sstevel@tonic-gate note_notsup, /* 8 NT_ASRS */
6820Sstevel@tonic-gate #endif
6830Sstevel@tonic-gate #else
6840Sstevel@tonic-gate note_notsup, /* 7 NT_GWINDOWS */
6850Sstevel@tonic-gate note_notsup, /* 8 NT_ASRS */
6860Sstevel@tonic-gate #endif
6870Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
6880Sstevel@tonic-gate note_ldt, /* 9 NT_LDT */
6890Sstevel@tonic-gate #else
6900Sstevel@tonic-gate note_notsup, /* 9 NT_LDT */
6910Sstevel@tonic-gate #endif
6920Sstevel@tonic-gate note_pstatus, /* 10 NT_PSTATUS */
6930Sstevel@tonic-gate note_notsup, /* 11 unassigned */
6940Sstevel@tonic-gate note_notsup, /* 12 unassigned */
6950Sstevel@tonic-gate note_psinfo, /* 13 NT_PSINFO */
6960Sstevel@tonic-gate note_cred, /* 14 NT_PRCRED */
6970Sstevel@tonic-gate note_utsname, /* 15 NT_UTSNAME */
6980Sstevel@tonic-gate note_lwpstatus, /* 16 NT_LWPSTATUS */
6990Sstevel@tonic-gate note_lwpsinfo, /* 17 NT_LWPSINFO */
7000Sstevel@tonic-gate note_priv, /* 18 NT_PRPRIV */
7010Sstevel@tonic-gate note_priv_info, /* 19 NT_PRPRIVINFO */
7020Sstevel@tonic-gate note_content, /* 20 NT_CONTENT */
7030Sstevel@tonic-gate note_zonename, /* 21 NT_ZONENAME */
7040Sstevel@tonic-gate };
7050Sstevel@tonic-gate
7060Sstevel@tonic-gate /*
7070Sstevel@tonic-gate * Add information on the address space mapping described by the given
7080Sstevel@tonic-gate * PT_LOAD program header. We fill in more information on the mapping later.
7090Sstevel@tonic-gate */
7100Sstevel@tonic-gate static int
core_add_mapping(struct ps_prochandle * P,GElf_Phdr * php)7110Sstevel@tonic-gate core_add_mapping(struct ps_prochandle *P, GElf_Phdr *php)
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate int err = 0;
7140Sstevel@tonic-gate prmap_t pmap;
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate dprintf("mapping base %llx filesz %llu memsz %llu offset %llu\n",
7170Sstevel@tonic-gate (u_longlong_t)php->p_vaddr, (u_longlong_t)php->p_filesz,
7180Sstevel@tonic-gate (u_longlong_t)php->p_memsz, (u_longlong_t)php->p_offset);
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate pmap.pr_vaddr = (uintptr_t)php->p_vaddr;
7210Sstevel@tonic-gate pmap.pr_size = php->p_memsz;
7220Sstevel@tonic-gate
7230Sstevel@tonic-gate /*
7240Sstevel@tonic-gate * If Pgcore() or elfcore() fail to write a mapping, they will set
7250Sstevel@tonic-gate * PF_SUNW_FAILURE in the Phdr and try to stash away the errno for us.
7260Sstevel@tonic-gate */
7270Sstevel@tonic-gate if (php->p_flags & PF_SUNW_FAILURE) {
7280Sstevel@tonic-gate (void) pread64(P->asfd, &err,
7290Sstevel@tonic-gate sizeof (err), (off64_t)php->p_offset);
7300Sstevel@tonic-gate
7310Sstevel@tonic-gate Perror_printf(P, "core file data for mapping at %p not saved: "
7320Sstevel@tonic-gate "%s\n", (void *)(uintptr_t)php->p_vaddr, strerror(err));
7330Sstevel@tonic-gate dprintf("core file data for mapping at %p not saved: %s\n",
7340Sstevel@tonic-gate (void *)(uintptr_t)php->p_vaddr, strerror(err));
7350Sstevel@tonic-gate
7360Sstevel@tonic-gate } else if (php->p_filesz != 0 && php->p_offset >= P->core->core_size) {
7370Sstevel@tonic-gate Perror_printf(P, "core file may be corrupt -- data for mapping "
7380Sstevel@tonic-gate "at %p is missing\n", (void *)(uintptr_t)php->p_vaddr);
7390Sstevel@tonic-gate dprintf("core file may be corrupt -- data for mapping "
7400Sstevel@tonic-gate "at %p is missing\n", (void *)(uintptr_t)php->p_vaddr);
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate /*
7440Sstevel@tonic-gate * The mapping name and offset will hopefully be filled in
7450Sstevel@tonic-gate * by the librtld_db agent. Unfortunately, if it isn't a
7460Sstevel@tonic-gate * shared library mapping, this information is gone forever.
7470Sstevel@tonic-gate */
7480Sstevel@tonic-gate pmap.pr_mapname[0] = '\0';
7490Sstevel@tonic-gate pmap.pr_offset = 0;
7500Sstevel@tonic-gate
7510Sstevel@tonic-gate pmap.pr_mflags = 0;
7520Sstevel@tonic-gate if (php->p_flags & PF_R)
7530Sstevel@tonic-gate pmap.pr_mflags |= MA_READ;
7540Sstevel@tonic-gate if (php->p_flags & PF_W)
7550Sstevel@tonic-gate pmap.pr_mflags |= MA_WRITE;
7560Sstevel@tonic-gate if (php->p_flags & PF_X)
7570Sstevel@tonic-gate pmap.pr_mflags |= MA_EXEC;
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate if (php->p_filesz == 0)
7600Sstevel@tonic-gate pmap.pr_mflags |= MA_RESERVED1;
7610Sstevel@tonic-gate
7620Sstevel@tonic-gate /*
7630Sstevel@tonic-gate * At the time of adding this mapping, we just zero the pagesize.
7640Sstevel@tonic-gate * Once we've processed more of the core file, we'll have the
7650Sstevel@tonic-gate * pagesize from the auxv's AT_PAGESZ element and we can fill this in.
7660Sstevel@tonic-gate */
7670Sstevel@tonic-gate pmap.pr_pagesize = 0;
7680Sstevel@tonic-gate
7690Sstevel@tonic-gate /*
7700Sstevel@tonic-gate * Unfortunately whether or not the mapping was a System V
7710Sstevel@tonic-gate * shared memory segment is lost. We use -1 to mark it as not shm.
7720Sstevel@tonic-gate */
7730Sstevel@tonic-gate pmap.pr_shmid = -1;
7740Sstevel@tonic-gate
7750Sstevel@tonic-gate return (Padd_mapping(P, php->p_offset, NULL, &pmap));
7760Sstevel@tonic-gate }
7770Sstevel@tonic-gate
7780Sstevel@tonic-gate /*
7790Sstevel@tonic-gate * Given a virtual address, name the mapping at that address using the
7800Sstevel@tonic-gate * specified name, and return the map_info_t pointer.
7810Sstevel@tonic-gate */
7820Sstevel@tonic-gate static map_info_t *
core_name_mapping(struct ps_prochandle * P,uintptr_t addr,const char * name)7830Sstevel@tonic-gate core_name_mapping(struct ps_prochandle *P, uintptr_t addr, const char *name)
7840Sstevel@tonic-gate {
7850Sstevel@tonic-gate map_info_t *mp = Paddr2mptr(P, addr);
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate if (mp != NULL) {
7880Sstevel@tonic-gate (void) strncpy(mp->map_pmap.pr_mapname, name, PRMAPSZ);
7890Sstevel@tonic-gate mp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
7900Sstevel@tonic-gate }
7910Sstevel@tonic-gate
7920Sstevel@tonic-gate return (mp);
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate
7950Sstevel@tonic-gate /*
7960Sstevel@tonic-gate * libproc uses libelf for all of its symbol table manipulation. This function
7970Sstevel@tonic-gate * takes a symbol table and string table from a core file and places them
7980Sstevel@tonic-gate * in a memory backed elf file.
7990Sstevel@tonic-gate */
8000Sstevel@tonic-gate static void
fake_up_symtab(struct ps_prochandle * P,const elf_file_header_t * ehdr,GElf_Shdr * symtab,GElf_Shdr * strtab)801942Sahl fake_up_symtab(struct ps_prochandle *P, const elf_file_header_t *ehdr,
8020Sstevel@tonic-gate GElf_Shdr *symtab, GElf_Shdr *strtab)
8030Sstevel@tonic-gate {
8040Sstevel@tonic-gate size_t size;
8050Sstevel@tonic-gate off64_t off, base;
8060Sstevel@tonic-gate map_info_t *mp;
8070Sstevel@tonic-gate file_info_t *fp;
8080Sstevel@tonic-gate Elf_Scn *scn;
8090Sstevel@tonic-gate Elf_Data *data;
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate if (symtab->sh_addr == 0 ||
8120Sstevel@tonic-gate (mp = Paddr2mptr(P, symtab->sh_addr)) == NULL ||
813*10201SEdward.Pilatowicz@Sun.COM (fp = mp->map_file) == NULL) {
8142712Snn35248 dprintf("fake_up_symtab: invalid section\n");
815*10201SEdward.Pilatowicz@Sun.COM return;
816*10201SEdward.Pilatowicz@Sun.COM }
817*10201SEdward.Pilatowicz@Sun.COM
818*10201SEdward.Pilatowicz@Sun.COM if (fp->file_symtab.sym_data_pri != NULL) {
819*10201SEdward.Pilatowicz@Sun.COM dprintf("Symbol table already loaded (sh_addr 0x%lx)\n",
820*10201SEdward.Pilatowicz@Sun.COM (long)symtab->sh_addr);
8210Sstevel@tonic-gate return;
8222712Snn35248 }
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate if (P->status.pr_dmodel == PR_MODEL_ILP32) {
8250Sstevel@tonic-gate struct {
8260Sstevel@tonic-gate Elf32_Ehdr ehdr;
8270Sstevel@tonic-gate Elf32_Shdr shdr[3];
8280Sstevel@tonic-gate char data[1];
8290Sstevel@tonic-gate } *b;
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate base = sizeof (b->ehdr) + sizeof (b->shdr);
8320Sstevel@tonic-gate size = base + symtab->sh_size + strtab->sh_size;
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate if ((b = calloc(1, size)) == NULL)
8350Sstevel@tonic-gate return;
8360Sstevel@tonic-gate
837942Sahl (void) memcpy(b->ehdr.e_ident, ehdr->e_ident,
838942Sahl sizeof (ehdr->e_ident));
839942Sahl b->ehdr.e_type = ehdr->e_type;
840942Sahl b->ehdr.e_machine = ehdr->e_machine;
841942Sahl b->ehdr.e_version = ehdr->e_version;
842942Sahl b->ehdr.e_flags = ehdr->e_flags;
8430Sstevel@tonic-gate b->ehdr.e_ehsize = sizeof (b->ehdr);
8440Sstevel@tonic-gate b->ehdr.e_shoff = sizeof (b->ehdr);
8450Sstevel@tonic-gate b->ehdr.e_shentsize = sizeof (b->shdr[0]);
8460Sstevel@tonic-gate b->ehdr.e_shnum = 3;
8470Sstevel@tonic-gate off = 0;
8480Sstevel@tonic-gate
8490Sstevel@tonic-gate b->shdr[1].sh_size = symtab->sh_size;
8500Sstevel@tonic-gate b->shdr[1].sh_type = SHT_SYMTAB;
8510Sstevel@tonic-gate b->shdr[1].sh_offset = off + base;
8520Sstevel@tonic-gate b->shdr[1].sh_entsize = sizeof (Elf32_Sym);
8530Sstevel@tonic-gate b->shdr[1].sh_link = 2;
8540Sstevel@tonic-gate b->shdr[1].sh_info = symtab->sh_info;
8550Sstevel@tonic-gate b->shdr[1].sh_addralign = symtab->sh_addralign;
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate if (pread64(P->asfd, &b->data[off], b->shdr[1].sh_size,
8580Sstevel@tonic-gate symtab->sh_offset) != b->shdr[1].sh_size) {
8592712Snn35248 dprintf("fake_up_symtab: pread of symtab[1] failed\n");
8600Sstevel@tonic-gate free(b);
8610Sstevel@tonic-gate return;
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate
8640Sstevel@tonic-gate off += b->shdr[1].sh_size;
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate b->shdr[2].sh_flags = SHF_STRINGS;
8670Sstevel@tonic-gate b->shdr[2].sh_size = strtab->sh_size;
8680Sstevel@tonic-gate b->shdr[2].sh_type = SHT_STRTAB;
8690Sstevel@tonic-gate b->shdr[2].sh_offset = off + base;
8700Sstevel@tonic-gate b->shdr[2].sh_info = strtab->sh_info;
8710Sstevel@tonic-gate b->shdr[2].sh_addralign = 1;
8720Sstevel@tonic-gate
8730Sstevel@tonic-gate if (pread64(P->asfd, &b->data[off], b->shdr[2].sh_size,
8740Sstevel@tonic-gate strtab->sh_offset) != b->shdr[2].sh_size) {
8752712Snn35248 dprintf("fake_up_symtab: pread of symtab[2] failed\n");
8760Sstevel@tonic-gate free(b);
8770Sstevel@tonic-gate return;
8780Sstevel@tonic-gate }
8790Sstevel@tonic-gate
8800Sstevel@tonic-gate off += b->shdr[2].sh_size;
8810Sstevel@tonic-gate
8820Sstevel@tonic-gate fp->file_symtab.sym_elf = elf_memory((char *)b, size);
8830Sstevel@tonic-gate if (fp->file_symtab.sym_elf == NULL) {
8840Sstevel@tonic-gate free(b);
8850Sstevel@tonic-gate return;
8860Sstevel@tonic-gate }
8870Sstevel@tonic-gate
8880Sstevel@tonic-gate fp->file_symtab.sym_elfmem = b;
8890Sstevel@tonic-gate #ifdef _LP64
8900Sstevel@tonic-gate } else {
8910Sstevel@tonic-gate struct {
8920Sstevel@tonic-gate Elf64_Ehdr ehdr;
8930Sstevel@tonic-gate Elf64_Shdr shdr[3];
8940Sstevel@tonic-gate char data[1];
8950Sstevel@tonic-gate } *b;
8960Sstevel@tonic-gate
8970Sstevel@tonic-gate base = sizeof (b->ehdr) + sizeof (b->shdr);
8980Sstevel@tonic-gate size = base + symtab->sh_size + strtab->sh_size;
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate if ((b = calloc(1, size)) == NULL)
9010Sstevel@tonic-gate return;
9020Sstevel@tonic-gate
903942Sahl (void) memcpy(b->ehdr.e_ident, ehdr->e_ident,
904942Sahl sizeof (ehdr->e_ident));
905942Sahl b->ehdr.e_type = ehdr->e_type;
906942Sahl b->ehdr.e_machine = ehdr->e_machine;
907942Sahl b->ehdr.e_version = ehdr->e_version;
908942Sahl b->ehdr.e_flags = ehdr->e_flags;
9090Sstevel@tonic-gate b->ehdr.e_ehsize = sizeof (b->ehdr);
9100Sstevel@tonic-gate b->ehdr.e_shoff = sizeof (b->ehdr);
9110Sstevel@tonic-gate b->ehdr.e_shentsize = sizeof (b->shdr[0]);
9120Sstevel@tonic-gate b->ehdr.e_shnum = 3;
9130Sstevel@tonic-gate off = 0;
9140Sstevel@tonic-gate
9150Sstevel@tonic-gate b->shdr[1].sh_size = symtab->sh_size;
9160Sstevel@tonic-gate b->shdr[1].sh_type = SHT_SYMTAB;
9170Sstevel@tonic-gate b->shdr[1].sh_offset = off + base;
9180Sstevel@tonic-gate b->shdr[1].sh_entsize = sizeof (Elf64_Sym);
9190Sstevel@tonic-gate b->shdr[1].sh_link = 2;
9200Sstevel@tonic-gate b->shdr[1].sh_info = symtab->sh_info;
9210Sstevel@tonic-gate b->shdr[1].sh_addralign = symtab->sh_addralign;
9220Sstevel@tonic-gate
9230Sstevel@tonic-gate if (pread64(P->asfd, &b->data[off], b->shdr[1].sh_size,
9240Sstevel@tonic-gate symtab->sh_offset) != b->shdr[1].sh_size) {
9250Sstevel@tonic-gate free(b);
9260Sstevel@tonic-gate return;
9270Sstevel@tonic-gate }
9280Sstevel@tonic-gate
9290Sstevel@tonic-gate off += b->shdr[1].sh_size;
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate b->shdr[2].sh_flags = SHF_STRINGS;
9320Sstevel@tonic-gate b->shdr[2].sh_size = strtab->sh_size;
9330Sstevel@tonic-gate b->shdr[2].sh_type = SHT_STRTAB;
9340Sstevel@tonic-gate b->shdr[2].sh_offset = off + base;
9350Sstevel@tonic-gate b->shdr[2].sh_info = strtab->sh_info;
9360Sstevel@tonic-gate b->shdr[2].sh_addralign = 1;
9370Sstevel@tonic-gate
9380Sstevel@tonic-gate if (pread64(P->asfd, &b->data[off], b->shdr[2].sh_size,
9390Sstevel@tonic-gate strtab->sh_offset) != b->shdr[2].sh_size) {
9400Sstevel@tonic-gate free(b);
9410Sstevel@tonic-gate return;
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate off += b->shdr[2].sh_size;
9450Sstevel@tonic-gate
9460Sstevel@tonic-gate fp->file_symtab.sym_elf = elf_memory((char *)b, size);
9470Sstevel@tonic-gate if (fp->file_symtab.sym_elf == NULL) {
9480Sstevel@tonic-gate free(b);
9490Sstevel@tonic-gate return;
9500Sstevel@tonic-gate }
9510Sstevel@tonic-gate
9520Sstevel@tonic-gate fp->file_symtab.sym_elfmem = b;
9530Sstevel@tonic-gate #endif
9540Sstevel@tonic-gate }
9550Sstevel@tonic-gate
9560Sstevel@tonic-gate if ((scn = elf_getscn(fp->file_symtab.sym_elf, 1)) == NULL ||
9573347Sab196087 (fp->file_symtab.sym_data_pri = elf_getdata(scn, NULL)) == NULL ||
9580Sstevel@tonic-gate (scn = elf_getscn(fp->file_symtab.sym_elf, 2)) == NULL ||
9592712Snn35248 (data = elf_getdata(scn, NULL)) == NULL) {
9602712Snn35248 dprintf("fake_up_symtab: failed to get section data at %p\n",
9612712Snn35248 (void *)scn);
9620Sstevel@tonic-gate goto err;
9632712Snn35248 }
9640Sstevel@tonic-gate
9650Sstevel@tonic-gate fp->file_symtab.sym_strs = data->d_buf;
9660Sstevel@tonic-gate fp->file_symtab.sym_strsz = data->d_size;
9670Sstevel@tonic-gate fp->file_symtab.sym_symn = symtab->sh_size / symtab->sh_entsize;
9683347Sab196087 fp->file_symtab.sym_hdr_pri = *symtab;
9690Sstevel@tonic-gate fp->file_symtab.sym_strhdr = *strtab;
9700Sstevel@tonic-gate
9710Sstevel@tonic-gate optimize_symtab(&fp->file_symtab);
9720Sstevel@tonic-gate
9730Sstevel@tonic-gate return;
9740Sstevel@tonic-gate err:
9750Sstevel@tonic-gate (void) elf_end(fp->file_symtab.sym_elf);
9760Sstevel@tonic-gate free(fp->file_symtab.sym_elfmem);
9770Sstevel@tonic-gate fp->file_symtab.sym_elf = NULL;
9780Sstevel@tonic-gate fp->file_symtab.sym_elfmem = NULL;
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate
9810Sstevel@tonic-gate static void
core_phdr_to_gelf(const Elf32_Phdr * src,GElf_Phdr * dst)9820Sstevel@tonic-gate core_phdr_to_gelf(const Elf32_Phdr *src, GElf_Phdr *dst)
9830Sstevel@tonic-gate {
9840Sstevel@tonic-gate dst->p_type = src->p_type;
9850Sstevel@tonic-gate dst->p_flags = src->p_flags;
9860Sstevel@tonic-gate dst->p_offset = (Elf64_Off)src->p_offset;
9870Sstevel@tonic-gate dst->p_vaddr = (Elf64_Addr)src->p_vaddr;
9880Sstevel@tonic-gate dst->p_paddr = (Elf64_Addr)src->p_paddr;
9890Sstevel@tonic-gate dst->p_filesz = (Elf64_Xword)src->p_filesz;
9900Sstevel@tonic-gate dst->p_memsz = (Elf64_Xword)src->p_memsz;
9910Sstevel@tonic-gate dst->p_align = (Elf64_Xword)src->p_align;
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate
9940Sstevel@tonic-gate static void
core_shdr_to_gelf(const Elf32_Shdr * src,GElf_Shdr * dst)9950Sstevel@tonic-gate core_shdr_to_gelf(const Elf32_Shdr *src, GElf_Shdr *dst)
9960Sstevel@tonic-gate {
9970Sstevel@tonic-gate dst->sh_name = src->sh_name;
9980Sstevel@tonic-gate dst->sh_type = src->sh_type;
9990Sstevel@tonic-gate dst->sh_flags = (Elf64_Xword)src->sh_flags;
10000Sstevel@tonic-gate dst->sh_addr = (Elf64_Addr)src->sh_addr;
10010Sstevel@tonic-gate dst->sh_offset = (Elf64_Off)src->sh_offset;
10020Sstevel@tonic-gate dst->sh_size = (Elf64_Xword)src->sh_size;
10030Sstevel@tonic-gate dst->sh_link = src->sh_link;
10040Sstevel@tonic-gate dst->sh_info = src->sh_info;
10050Sstevel@tonic-gate dst->sh_addralign = (Elf64_Xword)src->sh_addralign;
10060Sstevel@tonic-gate dst->sh_entsize = (Elf64_Xword)src->sh_entsize;
10070Sstevel@tonic-gate }
10080Sstevel@tonic-gate
10090Sstevel@tonic-gate /*
10100Sstevel@tonic-gate * Perform elf_begin on efp->e_fd and verify the ELF file's type and class.
10110Sstevel@tonic-gate */
10120Sstevel@tonic-gate static int
core_elf_fdopen(elf_file_t * efp,GElf_Half type,int * perr)10130Sstevel@tonic-gate core_elf_fdopen(elf_file_t *efp, GElf_Half type, int *perr)
10140Sstevel@tonic-gate {
10150Sstevel@tonic-gate #ifdef _BIG_ENDIAN
10160Sstevel@tonic-gate uchar_t order = ELFDATA2MSB;
10170Sstevel@tonic-gate #else
10180Sstevel@tonic-gate uchar_t order = ELFDATA2LSB;
10190Sstevel@tonic-gate #endif
10200Sstevel@tonic-gate Elf32_Ehdr e32;
10210Sstevel@tonic-gate int is_noelf = -1;
10220Sstevel@tonic-gate int isa_err = 0;
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate /*
10250Sstevel@tonic-gate * Because 32-bit libelf cannot deal with large files, we need to read,
10260Sstevel@tonic-gate * check, and convert the file header manually in case type == ET_CORE.
10270Sstevel@tonic-gate */
10280Sstevel@tonic-gate if (pread64(efp->e_fd, &e32, sizeof (e32), 0) != sizeof (e32)) {
10290Sstevel@tonic-gate if (perr != NULL)
10300Sstevel@tonic-gate *perr = G_FORMAT;
10310Sstevel@tonic-gate goto err;
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate if ((is_noelf = memcmp(&e32.e_ident[EI_MAG0], ELFMAG, SELFMAG)) != 0 ||
10340Sstevel@tonic-gate e32.e_type != type || (isa_err = (e32.e_ident[EI_DATA] != order)) ||
10350Sstevel@tonic-gate e32.e_version != EV_CURRENT) {
10360Sstevel@tonic-gate if (perr != NULL) {
10370Sstevel@tonic-gate if (is_noelf == 0 && isa_err) {
10380Sstevel@tonic-gate *perr = G_ISAINVAL;
10390Sstevel@tonic-gate } else {
10400Sstevel@tonic-gate *perr = G_FORMAT;
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate goto err;
10440Sstevel@tonic-gate }
10450Sstevel@tonic-gate
10460Sstevel@tonic-gate /*
10470Sstevel@tonic-gate * If the file is 64-bit and we are 32-bit, fail with G_LP64. If the
1048942Sahl * file is 64-bit and we are 64-bit, re-read the header as a Elf64_Ehdr,
1049942Sahl * and convert it to a elf_file_header_t. Otherwise, the file is
1050942Sahl * 32-bit, so convert e32 to a elf_file_header_t.
10510Sstevel@tonic-gate */
10520Sstevel@tonic-gate if (e32.e_ident[EI_CLASS] == ELFCLASS64) {
10530Sstevel@tonic-gate #ifdef _LP64
1054942Sahl Elf64_Ehdr e64;
1055942Sahl
1056942Sahl if (pread64(efp->e_fd, &e64, sizeof (e64), 0) != sizeof (e64)) {
10570Sstevel@tonic-gate if (perr != NULL)
10580Sstevel@tonic-gate *perr = G_FORMAT;
10590Sstevel@tonic-gate goto err;
10600Sstevel@tonic-gate }
1061942Sahl
1062942Sahl (void) memcpy(efp->e_hdr.e_ident, e64.e_ident, EI_NIDENT);
1063942Sahl efp->e_hdr.e_type = e64.e_type;
1064942Sahl efp->e_hdr.e_machine = e64.e_machine;
1065942Sahl efp->e_hdr.e_version = e64.e_version;
1066942Sahl efp->e_hdr.e_entry = e64.e_entry;
1067942Sahl efp->e_hdr.e_phoff = e64.e_phoff;
1068942Sahl efp->e_hdr.e_shoff = e64.e_shoff;
1069942Sahl efp->e_hdr.e_flags = e64.e_flags;
1070942Sahl efp->e_hdr.e_ehsize = e64.e_ehsize;
1071942Sahl efp->e_hdr.e_phentsize = e64.e_phentsize;
1072942Sahl efp->e_hdr.e_phnum = (Elf64_Word)e64.e_phnum;
1073942Sahl efp->e_hdr.e_shentsize = e64.e_shentsize;
1074942Sahl efp->e_hdr.e_shnum = (Elf64_Word)e64.e_shnum;
1075942Sahl efp->e_hdr.e_shstrndx = (Elf64_Word)e64.e_shstrndx;
10760Sstevel@tonic-gate #else /* _LP64 */
10770Sstevel@tonic-gate if (perr != NULL)
10780Sstevel@tonic-gate *perr = G_LP64;
10790Sstevel@tonic-gate goto err;
10800Sstevel@tonic-gate #endif /* _LP64 */
1081942Sahl } else {
1082942Sahl (void) memcpy(efp->e_hdr.e_ident, e32.e_ident, EI_NIDENT);
1083942Sahl efp->e_hdr.e_type = e32.e_type;
1084942Sahl efp->e_hdr.e_machine = e32.e_machine;
1085942Sahl efp->e_hdr.e_version = e32.e_version;
1086942Sahl efp->e_hdr.e_entry = (Elf64_Addr)e32.e_entry;
1087942Sahl efp->e_hdr.e_phoff = (Elf64_Off)e32.e_phoff;
1088942Sahl efp->e_hdr.e_shoff = (Elf64_Off)e32.e_shoff;
1089942Sahl efp->e_hdr.e_flags = e32.e_flags;
1090942Sahl efp->e_hdr.e_ehsize = e32.e_ehsize;
1091942Sahl efp->e_hdr.e_phentsize = e32.e_phentsize;
1092942Sahl efp->e_hdr.e_phnum = (Elf64_Word)e32.e_phnum;
1093942Sahl efp->e_hdr.e_shentsize = e32.e_shentsize;
1094942Sahl efp->e_hdr.e_shnum = (Elf64_Word)e32.e_shnum;
1095942Sahl efp->e_hdr.e_shstrndx = (Elf64_Word)e32.e_shstrndx;
1096942Sahl }
1097942Sahl
1098942Sahl /*
1099942Sahl * If the number of section headers or program headers or the section
1100942Sahl * header string table index would overflow their respective fields
1101942Sahl * in the ELF header, they're stored in the section header at index
1102942Sahl * zero. To simplify use elsewhere, we look for those sentinel values
1103942Sahl * here.
1104942Sahl */
1105942Sahl if ((efp->e_hdr.e_shnum == 0 && efp->e_hdr.e_shoff != 0) ||
1106942Sahl efp->e_hdr.e_shstrndx == SHN_XINDEX ||
1107942Sahl efp->e_hdr.e_phnum == PN_XNUM) {
1108942Sahl GElf_Shdr shdr;
1109942Sahl
1110942Sahl dprintf("extended ELF header\n");
1111942Sahl
1112942Sahl if (efp->e_hdr.e_shoff == 0) {
1113942Sahl if (perr != NULL)
1114942Sahl *perr = G_FORMAT;
1115942Sahl goto err;
1116942Sahl }
1117942Sahl
1118942Sahl if (efp->e_hdr.e_ident[EI_CLASS] == ELFCLASS32) {
1119942Sahl Elf32_Shdr shdr32;
1120942Sahl
1121942Sahl if (pread64(efp->e_fd, &shdr32, sizeof (shdr32),
1122942Sahl efp->e_hdr.e_shoff) != sizeof (shdr32)) {
1123942Sahl if (perr != NULL)
1124942Sahl *perr = G_FORMAT;
1125942Sahl goto err;
1126942Sahl }
1127942Sahl
1128942Sahl core_shdr_to_gelf(&shdr32, &shdr);
1129942Sahl } else {
1130942Sahl if (pread64(efp->e_fd, &shdr, sizeof (shdr),
1131942Sahl efp->e_hdr.e_shoff) != sizeof (shdr)) {
1132942Sahl if (perr != NULL)
1133942Sahl *perr = G_FORMAT;
1134942Sahl goto err;
1135942Sahl }
1136942Sahl }
1137942Sahl
1138942Sahl if (efp->e_hdr.e_shnum == 0) {
1139942Sahl efp->e_hdr.e_shnum = shdr.sh_size;
1140942Sahl dprintf("section header count %lu\n",
1141942Sahl (ulong_t)shdr.sh_size);
1142942Sahl }
1143942Sahl
1144942Sahl if (efp->e_hdr.e_shstrndx == SHN_XINDEX) {
1145942Sahl efp->e_hdr.e_shstrndx = shdr.sh_link;
1146942Sahl dprintf("section string index %u\n", shdr.sh_link);
1147942Sahl }
1148942Sahl
1149942Sahl if (efp->e_hdr.e_phnum == PN_XNUM && shdr.sh_info != 0) {
1150942Sahl efp->e_hdr.e_phnum = shdr.sh_info;
1151942Sahl dprintf("program header count %u\n", shdr.sh_info);
1152942Sahl }
1153942Sahl
1154942Sahl } else if (efp->e_hdr.e_phoff != 0) {
1155942Sahl GElf_Phdr phdr;
1156942Sahl uint64_t phnum;
1157942Sahl
1158942Sahl /*
1159942Sahl * It's possible this core file came from a system that
1160942Sahl * accidentally truncated the e_phnum field without correctly
1161942Sahl * using the extended format in the section header at index
1162942Sahl * zero. We try to detect and correct that specific type of
1163942Sahl * corruption by using the knowledge that the core dump
1164942Sahl * routines usually place the data referenced by the first
1165942Sahl * program header immediately after the last header element.
1166942Sahl */
1167942Sahl if (efp->e_hdr.e_ident[EI_CLASS] == ELFCLASS32) {
1168942Sahl Elf32_Phdr phdr32;
1169942Sahl
1170942Sahl if (pread64(efp->e_fd, &phdr32, sizeof (phdr32),
1171942Sahl efp->e_hdr.e_phoff) != sizeof (phdr32)) {
1172942Sahl if (perr != NULL)
1173942Sahl *perr = G_FORMAT;
1174942Sahl goto err;
1175942Sahl }
1176942Sahl
1177942Sahl core_phdr_to_gelf(&phdr32, &phdr);
1178942Sahl } else {
1179942Sahl if (pread64(efp->e_fd, &phdr, sizeof (phdr),
1180942Sahl efp->e_hdr.e_phoff) != sizeof (phdr)) {
1181942Sahl if (perr != NULL)
1182942Sahl *perr = G_FORMAT;
1183942Sahl goto err;
1184942Sahl }
1185942Sahl }
1186942Sahl
1187942Sahl phnum = phdr.p_offset - efp->e_hdr.e_ehsize -
1188942Sahl (uint64_t)efp->e_hdr.e_shnum * efp->e_hdr.e_shentsize;
1189942Sahl phnum /= efp->e_hdr.e_phentsize;
1190942Sahl
1191942Sahl if (phdr.p_offset != 0 && phnum != efp->e_hdr.e_phnum) {
1192942Sahl dprintf("suspicious program header count %u %u\n",
1193942Sahl (uint_t)phnum, efp->e_hdr.e_phnum);
1194942Sahl
1195942Sahl /*
1196942Sahl * If the new program header count we computed doesn't
1197942Sahl * jive with count in the ELF header, we'll use the
1198942Sahl * data that's there and hope for the best.
1199942Sahl *
1200942Sahl * If it does, it's also possible that the section
1201942Sahl * header offset is incorrect; we'll check that and
1202942Sahl * possibly try to fix it.
1203942Sahl */
1204942Sahl if (phnum <= INT_MAX &&
1205942Sahl (uint16_t)phnum == efp->e_hdr.e_phnum) {
1206942Sahl
1207942Sahl if (efp->e_hdr.e_shoff == efp->e_hdr.e_phoff +
1208942Sahl efp->e_hdr.e_phentsize *
1209942Sahl (uint_t)efp->e_hdr.e_phnum) {
1210942Sahl efp->e_hdr.e_shoff =
1211942Sahl efp->e_hdr.e_phoff +
1212942Sahl efp->e_hdr.e_phentsize * phnum;
1213942Sahl }
1214942Sahl
1215942Sahl efp->e_hdr.e_phnum = (Elf64_Word)phnum;
1216942Sahl dprintf("using new program header count\n");
1217942Sahl } else {
1218942Sahl dprintf("inconsistent program header count\n");
1219942Sahl }
1220942Sahl }
1221942Sahl }
12220Sstevel@tonic-gate
12230Sstevel@tonic-gate /*
12240Sstevel@tonic-gate * The libelf implementation was never ported to be large-file aware.
12250Sstevel@tonic-gate * This is typically not a problem for your average executable or
12260Sstevel@tonic-gate * shared library, but a large 32-bit core file can exceed 2GB in size.
12270Sstevel@tonic-gate * So if type is ET_CORE, we don't bother doing elf_begin; the code
12280Sstevel@tonic-gate * in Pfgrab_core() below will do its own i/o and struct conversion.
12290Sstevel@tonic-gate */
12300Sstevel@tonic-gate
12310Sstevel@tonic-gate if (type == ET_CORE) {
12320Sstevel@tonic-gate efp->e_elf = NULL;
12330Sstevel@tonic-gate return (0);
12340Sstevel@tonic-gate }
12350Sstevel@tonic-gate
12360Sstevel@tonic-gate if ((efp->e_elf = elf_begin(efp->e_fd, ELF_C_READ, NULL)) == NULL) {
12370Sstevel@tonic-gate if (perr != NULL)
12380Sstevel@tonic-gate *perr = G_ELF;
12390Sstevel@tonic-gate goto err;
12400Sstevel@tonic-gate }
12410Sstevel@tonic-gate
12420Sstevel@tonic-gate return (0);
12430Sstevel@tonic-gate
12440Sstevel@tonic-gate err:
12450Sstevel@tonic-gate efp->e_elf = NULL;
12460Sstevel@tonic-gate return (-1);
12470Sstevel@tonic-gate }
12480Sstevel@tonic-gate
12490Sstevel@tonic-gate /*
12500Sstevel@tonic-gate * Open the specified file and then do a core_elf_fdopen on it.
12510Sstevel@tonic-gate */
12520Sstevel@tonic-gate static int
core_elf_open(elf_file_t * efp,const char * path,GElf_Half type,int * perr)12530Sstevel@tonic-gate core_elf_open(elf_file_t *efp, const char *path, GElf_Half type, int *perr)
12540Sstevel@tonic-gate {
12550Sstevel@tonic-gate (void) memset(efp, 0, sizeof (elf_file_t));
12560Sstevel@tonic-gate
12570Sstevel@tonic-gate if ((efp->e_fd = open64(path, O_RDONLY)) >= 0) {
12580Sstevel@tonic-gate if (core_elf_fdopen(efp, type, perr) == 0)
12590Sstevel@tonic-gate return (0);
12600Sstevel@tonic-gate
12610Sstevel@tonic-gate (void) close(efp->e_fd);
12620Sstevel@tonic-gate efp->e_fd = -1;
12630Sstevel@tonic-gate }
12640Sstevel@tonic-gate
12650Sstevel@tonic-gate return (-1);
12660Sstevel@tonic-gate }
12670Sstevel@tonic-gate
12680Sstevel@tonic-gate /*
12690Sstevel@tonic-gate * Close the ELF handle and file descriptor.
12700Sstevel@tonic-gate */
12710Sstevel@tonic-gate static void
core_elf_close(elf_file_t * efp)12720Sstevel@tonic-gate core_elf_close(elf_file_t *efp)
12730Sstevel@tonic-gate {
12740Sstevel@tonic-gate if (efp->e_elf != NULL) {
12750Sstevel@tonic-gate (void) elf_end(efp->e_elf);
12760Sstevel@tonic-gate efp->e_elf = NULL;
12770Sstevel@tonic-gate }
12780Sstevel@tonic-gate
12790Sstevel@tonic-gate if (efp->e_fd != -1) {
12800Sstevel@tonic-gate (void) close(efp->e_fd);
12810Sstevel@tonic-gate efp->e_fd = -1;
12820Sstevel@tonic-gate }
12830Sstevel@tonic-gate }
12840Sstevel@tonic-gate
12850Sstevel@tonic-gate /*
12860Sstevel@tonic-gate * Given an ELF file for a statically linked executable, locate the likely
12870Sstevel@tonic-gate * primary text section and fill in rl_base with its virtual address.
12880Sstevel@tonic-gate */
12890Sstevel@tonic-gate static map_info_t *
core_find_text(struct ps_prochandle * P,Elf * elf,rd_loadobj_t * rlp)12900Sstevel@tonic-gate core_find_text(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp)
12910Sstevel@tonic-gate {
12920Sstevel@tonic-gate GElf_Phdr phdr;
12930Sstevel@tonic-gate uint_t i;
1294942Sahl size_t nphdrs;
12950Sstevel@tonic-gate
12969900SAli.Bahrami@Sun.COM if (elf_getphdrnum(elf, &nphdrs) == -1)
1297942Sahl return (NULL);
1298942Sahl
1299942Sahl for (i = 0; i < nphdrs; i++) {
1300942Sahl if (gelf_getphdr(elf, i, &phdr) != NULL &&
1301942Sahl phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) {
1302942Sahl rlp->rl_base = phdr.p_vaddr;
1303942Sahl return (Paddr2mptr(P, rlp->rl_base));
13040Sstevel@tonic-gate }
13050Sstevel@tonic-gate }
13060Sstevel@tonic-gate
13070Sstevel@tonic-gate return (NULL);
13080Sstevel@tonic-gate }
13090Sstevel@tonic-gate
13100Sstevel@tonic-gate /*
13110Sstevel@tonic-gate * Given an ELF file and the librtld_db structure corresponding to its primary
13120Sstevel@tonic-gate * text mapping, deduce where its data segment was loaded and fill in
13130Sstevel@tonic-gate * rl_data_base and prmap_t.pr_offset accordingly.
13140Sstevel@tonic-gate */
13150Sstevel@tonic-gate static map_info_t *
core_find_data(struct ps_prochandle * P,Elf * elf,rd_loadobj_t * rlp)13160Sstevel@tonic-gate core_find_data(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp)
13170Sstevel@tonic-gate {
13180Sstevel@tonic-gate GElf_Ehdr ehdr;
13190Sstevel@tonic-gate GElf_Phdr phdr;
13200Sstevel@tonic-gate map_info_t *mp;
13210Sstevel@tonic-gate uint_t i, pagemask;
1322942Sahl size_t nphdrs;
13230Sstevel@tonic-gate
13240Sstevel@tonic-gate rlp->rl_data_base = NULL;
13250Sstevel@tonic-gate
13260Sstevel@tonic-gate /*
13270Sstevel@tonic-gate * Find the first loadable, writeable Phdr and compute rl_data_base
13280Sstevel@tonic-gate * as the virtual address at which is was loaded.
13290Sstevel@tonic-gate */
1330942Sahl if (gelf_getehdr(elf, &ehdr) == NULL ||
13319900SAli.Bahrami@Sun.COM elf_getphdrnum(elf, &nphdrs) == -1)
1332942Sahl return (NULL);
13330Sstevel@tonic-gate
1334942Sahl for (i = 0; i < nphdrs; i++) {
1335942Sahl if (gelf_getphdr(elf, i, &phdr) != NULL &&
1336942Sahl phdr.p_type == PT_LOAD && (phdr.p_flags & PF_W)) {
1337942Sahl rlp->rl_data_base = phdr.p_vaddr;
1338942Sahl if (ehdr.e_type == ET_DYN)
1339942Sahl rlp->rl_data_base += rlp->rl_base;
1340942Sahl break;
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate }
13430Sstevel@tonic-gate
13440Sstevel@tonic-gate /*
13450Sstevel@tonic-gate * If we didn't find an appropriate phdr or if the address we
13460Sstevel@tonic-gate * computed has no mapping, return NULL.
13470Sstevel@tonic-gate */
13480Sstevel@tonic-gate if (rlp->rl_data_base == NULL ||
13490Sstevel@tonic-gate (mp = Paddr2mptr(P, rlp->rl_data_base)) == NULL)
13500Sstevel@tonic-gate return (NULL);
13510Sstevel@tonic-gate
13520Sstevel@tonic-gate /*
13530Sstevel@tonic-gate * It wouldn't be procfs-related code if we didn't make use of
13540Sstevel@tonic-gate * unclean knowledge of segvn, even in userland ... the prmap_t's
13550Sstevel@tonic-gate * pr_offset field will be the segvn offset from mmap(2)ing the
13560Sstevel@tonic-gate * data section, which will be the file offset & PAGEMASK.
13570Sstevel@tonic-gate */
13580Sstevel@tonic-gate pagemask = ~(mp->map_pmap.pr_pagesize - 1);
13590Sstevel@tonic-gate mp->map_pmap.pr_offset = phdr.p_offset & pagemask;
13600Sstevel@tonic-gate
13610Sstevel@tonic-gate return (mp);
13620Sstevel@tonic-gate }
13630Sstevel@tonic-gate
13640Sstevel@tonic-gate /*
13650Sstevel@tonic-gate * Librtld_db agent callback for iterating over load object mappings.
13660Sstevel@tonic-gate * For each load object, we allocate a new file_info_t, perform naming,
13670Sstevel@tonic-gate * and attempt to construct a symbol table for the load object.
13680Sstevel@tonic-gate */
13690Sstevel@tonic-gate static int
core_iter_mapping(const rd_loadobj_t * rlp,struct ps_prochandle * P)13700Sstevel@tonic-gate core_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P)
13710Sstevel@tonic-gate {
13727675SEdward.Pilatowicz@Sun.COM char lname[PATH_MAX], buf[PATH_MAX];
13730Sstevel@tonic-gate file_info_t *fp;
13740Sstevel@tonic-gate map_info_t *mp;
13750Sstevel@tonic-gate
13760Sstevel@tonic-gate if (Pread_string(P, lname, PATH_MAX, (off_t)rlp->rl_nameaddr) <= 0) {
13770Sstevel@tonic-gate dprintf("failed to read name %p\n", (void *)rlp->rl_nameaddr);
13780Sstevel@tonic-gate return (1); /* Keep going; forget this if we can't get a name */
13790Sstevel@tonic-gate }
13800Sstevel@tonic-gate
13810Sstevel@tonic-gate dprintf("rd_loadobj name = \"%s\" rl_base = %p\n",
13820Sstevel@tonic-gate lname, (void *)rlp->rl_base);
13830Sstevel@tonic-gate
13840Sstevel@tonic-gate if ((mp = Paddr2mptr(P, rlp->rl_base)) == NULL) {
13850Sstevel@tonic-gate dprintf("no mapping for %p\n", (void *)rlp->rl_base);
13860Sstevel@tonic-gate return (1); /* No mapping; advance to next mapping */
13870Sstevel@tonic-gate }
13880Sstevel@tonic-gate
13894753Srh87107 /*
13904753Srh87107 * Create a new file_info_t for this mapping, and therefore for
13914753Srh87107 * this load object.
13924753Srh87107 *
13934753Srh87107 * If there's an ELF header at the beginning of this mapping,
13944753Srh87107 * file_info_new() will try to use its section headers to
13954753Srh87107 * identify any other mappings that belong to this load object.
13964753Srh87107 */
13974753Srh87107 if ((fp = mp->map_file) == NULL &&
13984753Srh87107 (fp = file_info_new(P, mp)) == NULL) {
13994753Srh87107 P->core->core_errno = errno;
14004753Srh87107 dprintf("failed to malloc mapping data\n");
14014753Srh87107 return (0); /* Abort */
14024753Srh87107 }
14034753Srh87107 fp->file_map = mp;
14040Sstevel@tonic-gate
14054753Srh87107 /* Create a local copy of the load object representation */
14067675SEdward.Pilatowicz@Sun.COM if ((fp->file_lo = calloc(1, sizeof (rd_loadobj_t))) == NULL) {
14070Sstevel@tonic-gate P->core->core_errno = errno;
14080Sstevel@tonic-gate dprintf("failed to malloc mapping data\n");
14090Sstevel@tonic-gate return (0); /* Abort */
14100Sstevel@tonic-gate }
14110Sstevel@tonic-gate *fp->file_lo = *rlp;
14120Sstevel@tonic-gate
14130Sstevel@tonic-gate if (lname[0] != '\0') {
14140Sstevel@tonic-gate /*
14157675SEdward.Pilatowicz@Sun.COM * Naming dance part 1: if we got a name from librtld_db, then
14160Sstevel@tonic-gate * copy this name to the prmap_t if it is unnamed. If the
14170Sstevel@tonic-gate * file_info_t is unnamed, name it after the lname.
14180Sstevel@tonic-gate */
14190Sstevel@tonic-gate if (mp->map_pmap.pr_mapname[0] == '\0') {
14200Sstevel@tonic-gate (void) strncpy(mp->map_pmap.pr_mapname, lname, PRMAPSZ);
14210Sstevel@tonic-gate mp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
14220Sstevel@tonic-gate }
14230Sstevel@tonic-gate
14240Sstevel@tonic-gate if (fp->file_lname == NULL)
14250Sstevel@tonic-gate fp->file_lname = strdup(lname);
14260Sstevel@tonic-gate
14270Sstevel@tonic-gate } else if (fp->file_lname == NULL &&
14280Sstevel@tonic-gate mp->map_pmap.pr_mapname[0] != '\0') {
14290Sstevel@tonic-gate /*
14307675SEdward.Pilatowicz@Sun.COM * Naming dance part 2: if the mapping is named and the
14310Sstevel@tonic-gate * file_info_t is not, name the file after the mapping.
14320Sstevel@tonic-gate */
14330Sstevel@tonic-gate fp->file_lname = strdup(mp->map_pmap.pr_mapname);
14340Sstevel@tonic-gate }
14350Sstevel@tonic-gate
14367675SEdward.Pilatowicz@Sun.COM if ((fp->file_rname == NULL) &&
14377675SEdward.Pilatowicz@Sun.COM (Pfindmap(P, mp, buf, sizeof (buf)) != NULL))
14387675SEdward.Pilatowicz@Sun.COM fp->file_rname = strdup(buf);
14397675SEdward.Pilatowicz@Sun.COM
14400Sstevel@tonic-gate if (fp->file_lname != NULL)
14410Sstevel@tonic-gate fp->file_lbase = basename(fp->file_lname);
14427675SEdward.Pilatowicz@Sun.COM if (fp->file_rname != NULL)
14437675SEdward.Pilatowicz@Sun.COM fp->file_rbase = basename(fp->file_rname);
14440Sstevel@tonic-gate
14454753Srh87107 /* Associate the file and the mapping. */
14464753Srh87107 (void) strncpy(fp->file_pname, mp->map_pmap.pr_mapname, PRMAPSZ);
14474753Srh87107 fp->file_pname[PRMAPSZ - 1] = '\0';
14480Sstevel@tonic-gate
14490Sstevel@tonic-gate /*
14504753Srh87107 * If no section headers were available then we'll have to
14514753Srh87107 * identify this load object's other mappings with what we've
14524753Srh87107 * got: the start and end of the object's corresponding
14534753Srh87107 * address space.
14540Sstevel@tonic-gate */
14554753Srh87107 if (fp->file_saddrs == NULL) {
14564753Srh87107 for (mp = fp->file_map + 1; mp < P->mappings + P->map_count &&
14574753Srh87107 mp->map_pmap.pr_vaddr < rlp->rl_bend; mp++) {
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate if (mp->map_file == NULL) {
14604753Srh87107 dprintf("core_iter_mapping %s: associating "
14614753Srh87107 "segment at %p\n",
14622712Snn35248 fp->file_pname,
14632712Snn35248 (void *)mp->map_pmap.pr_vaddr);
14640Sstevel@tonic-gate mp->map_file = fp;
14650Sstevel@tonic-gate fp->file_ref++;
14662712Snn35248 } else {
14674753Srh87107 dprintf("core_iter_mapping %s: segment at "
14684753Srh87107 "%p already associated with %s\n",
14694753Srh87107 fp->file_pname,
14702712Snn35248 (void *)mp->map_pmap.pr_vaddr,
14714753Srh87107 (mp == fp->file_map ? "this file" :
14724753Srh87107 mp->map_file->file_pname));
14730Sstevel@tonic-gate }
14744753Srh87107 }
14754753Srh87107 }
14760Sstevel@tonic-gate
14774753Srh87107 /* Ensure that all this file's mappings are named. */
14784753Srh87107 for (mp = fp->file_map; mp < P->mappings + P->map_count &&
14794753Srh87107 mp->map_file == fp; mp++) {
14804753Srh87107 if (mp->map_pmap.pr_mapname[0] == '\0' &&
14814753Srh87107 !(mp->map_pmap.pr_mflags & MA_BREAK)) {
14824753Srh87107 (void) strncpy(mp->map_pmap.pr_mapname, fp->file_pname,
14834753Srh87107 PRMAPSZ);
14844753Srh87107 mp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
14850Sstevel@tonic-gate }
14864753Srh87107 }
14874753Srh87107
14884753Srh87107 /* Attempt to build a symbol table for this file. */
14894753Srh87107 Pbuild_file_symtab(P, fp);
14904753Srh87107 if (fp->file_elf == NULL)
14914753Srh87107 dprintf("core_iter_mapping: no symtab for %s\n",
14924753Srh87107 fp->file_pname);
14934753Srh87107
14944753Srh87107 /* Locate the start of a data segment associated with this file. */
14954753Srh87107 if ((mp = core_find_data(P, fp->file_elf, fp->file_lo)) != NULL) {
14964753Srh87107 dprintf("found data for %s at %p (pr_offset 0x%llx)\n",
14974753Srh87107 fp->file_pname, (void *)fp->file_lo->rl_data_base,
14984753Srh87107 mp->map_pmap.pr_offset);
14992712Snn35248 } else {
15002712Snn35248 dprintf("core_iter_mapping: no data found for %s\n",
15012712Snn35248 fp->file_pname);
15020Sstevel@tonic-gate }
15030Sstevel@tonic-gate
15040Sstevel@tonic-gate return (1); /* Advance to next mapping */
15050Sstevel@tonic-gate }
15060Sstevel@tonic-gate
15070Sstevel@tonic-gate /*
15080Sstevel@tonic-gate * Callback function for Pfindexec(). In order to confirm a given pathname,
15097675SEdward.Pilatowicz@Sun.COM * we verify that we can open it as an ELF file of type ET_EXEC or ET_DYN.
15100Sstevel@tonic-gate */
15110Sstevel@tonic-gate static int
core_exec_open(const char * path,void * efp)15120Sstevel@tonic-gate core_exec_open(const char *path, void *efp)
15130Sstevel@tonic-gate {
15147675SEdward.Pilatowicz@Sun.COM if (core_elf_open(efp, path, ET_EXEC, NULL) == 0)
15157675SEdward.Pilatowicz@Sun.COM return (1);
15167675SEdward.Pilatowicz@Sun.COM if (core_elf_open(efp, path, ET_DYN, NULL) == 0)
15177675SEdward.Pilatowicz@Sun.COM return (1);
15187675SEdward.Pilatowicz@Sun.COM return (0);
15190Sstevel@tonic-gate }
15200Sstevel@tonic-gate
15210Sstevel@tonic-gate /*
15220Sstevel@tonic-gate * Attempt to load any section headers found in the core file. If present,
15230Sstevel@tonic-gate * this will refer to non-loadable data added to the core file by the kernel
15240Sstevel@tonic-gate * based on coreadm(1M) settings, including CTF data and the symbol table.
15250Sstevel@tonic-gate */
15260Sstevel@tonic-gate static void
core_load_shdrs(struct ps_prochandle * P,elf_file_t * efp)15270Sstevel@tonic-gate core_load_shdrs(struct ps_prochandle *P, elf_file_t *efp)
15280Sstevel@tonic-gate {
15290Sstevel@tonic-gate GElf_Shdr *shp, *shdrs = NULL;
15300Sstevel@tonic-gate char *shstrtab = NULL;
15310Sstevel@tonic-gate ulong_t shstrtabsz;
15320Sstevel@tonic-gate const char *name;
15330Sstevel@tonic-gate map_info_t *mp;
15340Sstevel@tonic-gate
15350Sstevel@tonic-gate size_t nbytes;
15360Sstevel@tonic-gate void *buf;
15370Sstevel@tonic-gate int i;
15380Sstevel@tonic-gate
15390Sstevel@tonic-gate if (efp->e_hdr.e_shstrndx >= efp->e_hdr.e_shnum) {
15400Sstevel@tonic-gate dprintf("corrupt shstrndx (%u) exceeds shnum (%u)\n",
1541942Sahl efp->e_hdr.e_shstrndx, efp->e_hdr.e_shnum);
15420Sstevel@tonic-gate return;
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate
15450Sstevel@tonic-gate /*
15460Sstevel@tonic-gate * Read the section header table from the core file and then iterate
15470Sstevel@tonic-gate * over the section headers, converting each to a GElf_Shdr.
15480Sstevel@tonic-gate */
15492712Snn35248 if ((shdrs = malloc(efp->e_hdr.e_shnum * sizeof (GElf_Shdr))) == NULL) {
15500Sstevel@tonic-gate dprintf("failed to malloc %u section headers: %s\n",
15510Sstevel@tonic-gate (uint_t)efp->e_hdr.e_shnum, strerror(errno));
15522712Snn35248 return;
15532712Snn35248 }
15542712Snn35248
15552712Snn35248 nbytes = efp->e_hdr.e_shnum * efp->e_hdr.e_shentsize;
15562712Snn35248 if ((buf = malloc(nbytes)) == NULL) {
15572712Snn35248 dprintf("failed to malloc %d bytes: %s\n", (int)nbytes,
15582712Snn35248 strerror(errno));
15592712Snn35248 free(shdrs);
15600Sstevel@tonic-gate goto out;
15610Sstevel@tonic-gate }
15620Sstevel@tonic-gate
15630Sstevel@tonic-gate if (pread64(efp->e_fd, buf, nbytes, efp->e_hdr.e_shoff) != nbytes) {
15640Sstevel@tonic-gate dprintf("failed to read section headers at off %lld: %s\n",
15650Sstevel@tonic-gate (longlong_t)efp->e_hdr.e_shoff, strerror(errno));
15660Sstevel@tonic-gate free(buf);
15670Sstevel@tonic-gate goto out;
15680Sstevel@tonic-gate }
15690Sstevel@tonic-gate
15700Sstevel@tonic-gate for (i = 0; i < efp->e_hdr.e_shnum; i++) {
15710Sstevel@tonic-gate void *p = (uchar_t *)buf + efp->e_hdr.e_shentsize * i;
15720Sstevel@tonic-gate
15730Sstevel@tonic-gate if (efp->e_hdr.e_ident[EI_CLASS] == ELFCLASS32)
15740Sstevel@tonic-gate core_shdr_to_gelf(p, &shdrs[i]);
15750Sstevel@tonic-gate else
15760Sstevel@tonic-gate (void) memcpy(&shdrs[i], p, sizeof (GElf_Shdr));
15770Sstevel@tonic-gate }
15780Sstevel@tonic-gate
15790Sstevel@tonic-gate free(buf);
15800Sstevel@tonic-gate buf = NULL;
15810Sstevel@tonic-gate
15820Sstevel@tonic-gate /*
15830Sstevel@tonic-gate * Read the .shstrtab section from the core file, terminating it with
15840Sstevel@tonic-gate * an extra \0 so that a corrupt section will not cause us to die.
15850Sstevel@tonic-gate */
15860Sstevel@tonic-gate shp = &shdrs[efp->e_hdr.e_shstrndx];
15870Sstevel@tonic-gate shstrtabsz = shp->sh_size;
15880Sstevel@tonic-gate
15890Sstevel@tonic-gate if ((shstrtab = malloc(shstrtabsz + 1)) == NULL) {
15900Sstevel@tonic-gate dprintf("failed to allocate %lu bytes for shstrtab\n",
15910Sstevel@tonic-gate (ulong_t)shstrtabsz);
15920Sstevel@tonic-gate goto out;
15930Sstevel@tonic-gate }
15940Sstevel@tonic-gate
15950Sstevel@tonic-gate if (pread64(efp->e_fd, shstrtab, shstrtabsz,
15960Sstevel@tonic-gate shp->sh_offset) != shstrtabsz) {
15970Sstevel@tonic-gate dprintf("failed to read %lu bytes of shstrs at off %lld: %s\n",
15980Sstevel@tonic-gate shstrtabsz, (longlong_t)shp->sh_offset, strerror(errno));
15990Sstevel@tonic-gate goto out;
16000Sstevel@tonic-gate }
16010Sstevel@tonic-gate
16020Sstevel@tonic-gate shstrtab[shstrtabsz] = '\0';
16030Sstevel@tonic-gate
16040Sstevel@tonic-gate /*
16050Sstevel@tonic-gate * Now iterate over each section in the section header table, locating
16060Sstevel@tonic-gate * sections of interest and initializing more of the ps_prochandle.
16070Sstevel@tonic-gate */
16080Sstevel@tonic-gate for (i = 0; i < efp->e_hdr.e_shnum; i++) {
16090Sstevel@tonic-gate shp = &shdrs[i];
16100Sstevel@tonic-gate name = shstrtab + shp->sh_name;
16110Sstevel@tonic-gate
16120Sstevel@tonic-gate if (shp->sh_name >= shstrtabsz) {
16130Sstevel@tonic-gate dprintf("skipping section [%d]: corrupt sh_name\n", i);
16140Sstevel@tonic-gate continue;
16150Sstevel@tonic-gate }
16160Sstevel@tonic-gate
16170Sstevel@tonic-gate if (shp->sh_link >= efp->e_hdr.e_shnum) {
16180Sstevel@tonic-gate dprintf("skipping section [%d]: corrupt sh_link\n", i);
16190Sstevel@tonic-gate continue;
16200Sstevel@tonic-gate }
16210Sstevel@tonic-gate
16220Sstevel@tonic-gate dprintf("found section header %s (sh_addr 0x%llx)\n",
16230Sstevel@tonic-gate name, (u_longlong_t)shp->sh_addr);
16240Sstevel@tonic-gate
16250Sstevel@tonic-gate if (strcmp(name, ".SUNW_ctf") == 0) {
16260Sstevel@tonic-gate if ((mp = Paddr2mptr(P, shp->sh_addr)) == NULL) {
16270Sstevel@tonic-gate dprintf("no map at addr 0x%llx for %s [%d]\n",
16280Sstevel@tonic-gate (u_longlong_t)shp->sh_addr, name, i);
16290Sstevel@tonic-gate continue;
16300Sstevel@tonic-gate }
16310Sstevel@tonic-gate
16320Sstevel@tonic-gate if (mp->map_file == NULL ||
16330Sstevel@tonic-gate mp->map_file->file_ctf_buf != NULL) {
16340Sstevel@tonic-gate dprintf("no mapping file or duplicate buffer "
16350Sstevel@tonic-gate "for %s [%d]\n", name, i);
16360Sstevel@tonic-gate continue;
16370Sstevel@tonic-gate }
16380Sstevel@tonic-gate
16390Sstevel@tonic-gate if ((buf = malloc(shp->sh_size)) == NULL ||
16400Sstevel@tonic-gate pread64(efp->e_fd, buf, shp->sh_size,
16410Sstevel@tonic-gate shp->sh_offset) != shp->sh_size) {
16420Sstevel@tonic-gate dprintf("skipping section %s [%d]: %s\n",
16430Sstevel@tonic-gate name, i, strerror(errno));
16440Sstevel@tonic-gate free(buf);
16450Sstevel@tonic-gate continue;
16460Sstevel@tonic-gate }
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate mp->map_file->file_ctf_size = shp->sh_size;
16490Sstevel@tonic-gate mp->map_file->file_ctf_buf = buf;
16500Sstevel@tonic-gate
16510Sstevel@tonic-gate if (shdrs[shp->sh_link].sh_type == SHT_DYNSYM)
16520Sstevel@tonic-gate mp->map_file->file_ctf_dyn = 1;
16530Sstevel@tonic-gate
16540Sstevel@tonic-gate } else if (strcmp(name, ".symtab") == 0) {
16550Sstevel@tonic-gate fake_up_symtab(P, &efp->e_hdr,
16560Sstevel@tonic-gate shp, &shdrs[shp->sh_link]);
16570Sstevel@tonic-gate }
16580Sstevel@tonic-gate }
16590Sstevel@tonic-gate out:
16600Sstevel@tonic-gate free(shstrtab);
16610Sstevel@tonic-gate free(shdrs);
16620Sstevel@tonic-gate }
16630Sstevel@tonic-gate
16640Sstevel@tonic-gate /*
16650Sstevel@tonic-gate * Main engine for core file initialization: given an fd for the core file
16660Sstevel@tonic-gate * and an optional pathname, construct the ps_prochandle. The aout_path can
16670Sstevel@tonic-gate * either be a suggested executable pathname, or a suggested directory to
16680Sstevel@tonic-gate * use as a possible current working directory.
16690Sstevel@tonic-gate */
16700Sstevel@tonic-gate struct ps_prochandle *
Pfgrab_core(int core_fd,const char * aout_path,int * perr)16710Sstevel@tonic-gate Pfgrab_core(int core_fd, const char *aout_path, int *perr)
16720Sstevel@tonic-gate {
16730Sstevel@tonic-gate struct ps_prochandle *P;
16740Sstevel@tonic-gate map_info_t *stk_mp, *brk_mp;
16750Sstevel@tonic-gate const char *execname;
16760Sstevel@tonic-gate char *interp;
16770Sstevel@tonic-gate int i, notes, pagesize;
16780Sstevel@tonic-gate uintptr_t addr, base_addr;
16790Sstevel@tonic-gate struct stat64 stbuf;
16800Sstevel@tonic-gate void *phbuf, *php;
16810Sstevel@tonic-gate size_t nbytes;
16820Sstevel@tonic-gate
16830Sstevel@tonic-gate elf_file_t aout;
16840Sstevel@tonic-gate elf_file_t core;
16850Sstevel@tonic-gate
16860Sstevel@tonic-gate Elf_Scn *scn, *intp_scn = NULL;
16870Sstevel@tonic-gate Elf_Data *dp;
16880Sstevel@tonic-gate
16890Sstevel@tonic-gate GElf_Phdr phdr, note_phdr;
16900Sstevel@tonic-gate GElf_Shdr shdr;
16910Sstevel@tonic-gate GElf_Xword nleft;
16920Sstevel@tonic-gate
16930Sstevel@tonic-gate if (elf_version(EV_CURRENT) == EV_NONE) {
16940Sstevel@tonic-gate dprintf("libproc ELF version is more recent than libelf\n");
16950Sstevel@tonic-gate *perr = G_ELF;
16960Sstevel@tonic-gate return (NULL);
16970Sstevel@tonic-gate }
16980Sstevel@tonic-gate
16990Sstevel@tonic-gate aout.e_elf = NULL;
17000Sstevel@tonic-gate aout.e_fd = -1;
17010Sstevel@tonic-gate
17020Sstevel@tonic-gate core.e_elf = NULL;
17030Sstevel@tonic-gate core.e_fd = core_fd;
17040Sstevel@tonic-gate
17050Sstevel@tonic-gate /*
17060Sstevel@tonic-gate * Allocate and initialize a ps_prochandle structure for the core.
17070Sstevel@tonic-gate * There are several key pieces of initialization here:
17080Sstevel@tonic-gate *
17090Sstevel@tonic-gate * 1. The PS_DEAD state flag marks this prochandle as a core file.
17100Sstevel@tonic-gate * PS_DEAD also thus prevents all operations which require state
17110Sstevel@tonic-gate * to be PS_STOP from operating on this handle.
17120Sstevel@tonic-gate *
17130Sstevel@tonic-gate * 2. We keep the core file fd in P->asfd since the core file contains
17140Sstevel@tonic-gate * the remnants of the process address space.
17150Sstevel@tonic-gate *
17160Sstevel@tonic-gate * 3. We set the P->info_valid bit because all information about the
17170Sstevel@tonic-gate * core is determined by the end of this function; there is no need
17180Sstevel@tonic-gate * for proc_update_maps() to reload mappings at any later point.
17190Sstevel@tonic-gate *
17200Sstevel@tonic-gate * 4. The read/write ops vector uses our core_rw() function defined
17210Sstevel@tonic-gate * above to handle i/o requests.
17220Sstevel@tonic-gate */
17230Sstevel@tonic-gate if ((P = malloc(sizeof (struct ps_prochandle))) == NULL) {
17240Sstevel@tonic-gate *perr = G_STRANGE;
17250Sstevel@tonic-gate return (NULL);
17260Sstevel@tonic-gate }
17270Sstevel@tonic-gate
17280Sstevel@tonic-gate (void) memset(P, 0, sizeof (struct ps_prochandle));
17290Sstevel@tonic-gate (void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
17300Sstevel@tonic-gate P->state = PS_DEAD;
17310Sstevel@tonic-gate P->pid = (pid_t)-1;
17320Sstevel@tonic-gate P->asfd = core.e_fd;
17330Sstevel@tonic-gate P->ctlfd = -1;
17340Sstevel@tonic-gate P->statfd = -1;
17350Sstevel@tonic-gate P->agentctlfd = -1;
17360Sstevel@tonic-gate P->agentstatfd = -1;
17377675SEdward.Pilatowicz@Sun.COM P->zoneroot = NULL;
17380Sstevel@tonic-gate P->info_valid = 1;
17390Sstevel@tonic-gate P->ops = &P_core_ops;
17400Sstevel@tonic-gate
17410Sstevel@tonic-gate Pinitsym(P);
17420Sstevel@tonic-gate
17430Sstevel@tonic-gate /*
17440Sstevel@tonic-gate * Fstat and open the core file and make sure it is a valid ELF core.
17450Sstevel@tonic-gate */
17460Sstevel@tonic-gate if (fstat64(P->asfd, &stbuf) == -1) {
17470Sstevel@tonic-gate *perr = G_STRANGE;
17480Sstevel@tonic-gate goto err;
17490Sstevel@tonic-gate }
17500Sstevel@tonic-gate
17510Sstevel@tonic-gate if (core_elf_fdopen(&core, ET_CORE, perr) == -1)
17520Sstevel@tonic-gate goto err;
17530Sstevel@tonic-gate
17540Sstevel@tonic-gate /*
17550Sstevel@tonic-gate * Allocate and initialize a core_info_t to hang off the ps_prochandle
17560Sstevel@tonic-gate * structure. We keep all core-specific information in this structure.
17570Sstevel@tonic-gate */
17587675SEdward.Pilatowicz@Sun.COM if ((P->core = calloc(1, sizeof (core_info_t))) == NULL) {
17590Sstevel@tonic-gate *perr = G_STRANGE;
17600Sstevel@tonic-gate goto err;
17610Sstevel@tonic-gate }
17620Sstevel@tonic-gate
17630Sstevel@tonic-gate list_link(&P->core->core_lwp_head, NULL);
17640Sstevel@tonic-gate P->core->core_size = stbuf.st_size;
17650Sstevel@tonic-gate /*
17660Sstevel@tonic-gate * In the days before adjustable core file content, this was the
17670Sstevel@tonic-gate * default core file content. For new core files, this value will
17680Sstevel@tonic-gate * be overwritten by the NT_CONTENT note section.
17690Sstevel@tonic-gate */
17700Sstevel@tonic-gate P->core->core_content = CC_CONTENT_STACK | CC_CONTENT_HEAP |
17710Sstevel@tonic-gate CC_CONTENT_DATA | CC_CONTENT_RODATA | CC_CONTENT_ANON |
17720Sstevel@tonic-gate CC_CONTENT_SHANON;
17730Sstevel@tonic-gate
17740Sstevel@tonic-gate switch (core.e_hdr.e_ident[EI_CLASS]) {
17750Sstevel@tonic-gate case ELFCLASS32:
17760Sstevel@tonic-gate P->core->core_dmodel = PR_MODEL_ILP32;
17770Sstevel@tonic-gate break;
17780Sstevel@tonic-gate case ELFCLASS64:
17790Sstevel@tonic-gate P->core->core_dmodel = PR_MODEL_LP64;
17800Sstevel@tonic-gate break;
17810Sstevel@tonic-gate default:
17820Sstevel@tonic-gate *perr = G_FORMAT;
17830Sstevel@tonic-gate goto err;
17840Sstevel@tonic-gate }
17850Sstevel@tonic-gate
17860Sstevel@tonic-gate /*
17870Sstevel@tonic-gate * Because the core file may be a large file, we can't use libelf to
17880Sstevel@tonic-gate * read the Phdrs. We use e_phnum and e_phentsize to simplify things.
17890Sstevel@tonic-gate */
17900Sstevel@tonic-gate nbytes = core.e_hdr.e_phnum * core.e_hdr.e_phentsize;
17910Sstevel@tonic-gate
17920Sstevel@tonic-gate if ((phbuf = malloc(nbytes)) == NULL) {
17930Sstevel@tonic-gate *perr = G_STRANGE;
17940Sstevel@tonic-gate goto err;
17950Sstevel@tonic-gate }
17960Sstevel@tonic-gate
17970Sstevel@tonic-gate if (pread64(core_fd, phbuf, nbytes, core.e_hdr.e_phoff) != nbytes) {
17980Sstevel@tonic-gate *perr = G_STRANGE;
17990Sstevel@tonic-gate free(phbuf);
18000Sstevel@tonic-gate goto err;
18010Sstevel@tonic-gate }
18020Sstevel@tonic-gate
18030Sstevel@tonic-gate /*
18040Sstevel@tonic-gate * Iterate through the program headers in the core file.
18050Sstevel@tonic-gate * We're interested in two types of Phdrs: PT_NOTE (which
18060Sstevel@tonic-gate * contains a set of saved /proc structures), and PT_LOAD (which
18070Sstevel@tonic-gate * represents a memory mapping from the process's address space).
18080Sstevel@tonic-gate * In the case of PT_NOTE, we're interested in the last PT_NOTE
18090Sstevel@tonic-gate * in the core file; currently the first PT_NOTE (if present)
18100Sstevel@tonic-gate * contains /proc structs in the pre-2.6 unstructured /proc format.
18110Sstevel@tonic-gate */
18120Sstevel@tonic-gate for (php = phbuf, notes = 0, i = 0; i < core.e_hdr.e_phnum; i++) {
18130Sstevel@tonic-gate if (core.e_hdr.e_ident[EI_CLASS] == ELFCLASS64)
18140Sstevel@tonic-gate (void) memcpy(&phdr, php, sizeof (GElf_Phdr));
18150Sstevel@tonic-gate else
18160Sstevel@tonic-gate core_phdr_to_gelf(php, &phdr);
18170Sstevel@tonic-gate
18180Sstevel@tonic-gate switch (phdr.p_type) {
18190Sstevel@tonic-gate case PT_NOTE:
18200Sstevel@tonic-gate note_phdr = phdr;
18210Sstevel@tonic-gate notes++;
18220Sstevel@tonic-gate break;
18230Sstevel@tonic-gate
18240Sstevel@tonic-gate case PT_LOAD:
18250Sstevel@tonic-gate if (core_add_mapping(P, &phdr) == -1) {
18260Sstevel@tonic-gate *perr = G_STRANGE;
18270Sstevel@tonic-gate free(phbuf);
18280Sstevel@tonic-gate goto err;
18290Sstevel@tonic-gate }
18300Sstevel@tonic-gate break;
18310Sstevel@tonic-gate }
18320Sstevel@tonic-gate
18330Sstevel@tonic-gate php = (char *)php + core.e_hdr.e_phentsize;
18340Sstevel@tonic-gate }
18350Sstevel@tonic-gate
18360Sstevel@tonic-gate free(phbuf);
18370Sstevel@tonic-gate
18380Sstevel@tonic-gate Psort_mappings(P);
18390Sstevel@tonic-gate
18400Sstevel@tonic-gate /*
18410Sstevel@tonic-gate * If we couldn't find anything of type PT_NOTE, or only one PT_NOTE
18420Sstevel@tonic-gate * was present, abort. The core file is either corrupt or too old.
18430Sstevel@tonic-gate */
18440Sstevel@tonic-gate if (notes == 0 || notes == 1) {
18450Sstevel@tonic-gate *perr = G_NOTE;
18460Sstevel@tonic-gate goto err;
18470Sstevel@tonic-gate }
18480Sstevel@tonic-gate
18490Sstevel@tonic-gate /*
18500Sstevel@tonic-gate * Advance the seek pointer to the start of the PT_NOTE data
18510Sstevel@tonic-gate */
18520Sstevel@tonic-gate if (lseek64(P->asfd, note_phdr.p_offset, SEEK_SET) == (off64_t)-1) {
18530Sstevel@tonic-gate dprintf("Pgrab_core: failed to lseek to PT_NOTE data\n");
18540Sstevel@tonic-gate *perr = G_STRANGE;
18550Sstevel@tonic-gate goto err;
18560Sstevel@tonic-gate }
18570Sstevel@tonic-gate
18580Sstevel@tonic-gate /*
18590Sstevel@tonic-gate * Now process the PT_NOTE structures. Each one is preceded by
18600Sstevel@tonic-gate * an Elf{32/64}_Nhdr structure describing its type and size.
18610Sstevel@tonic-gate *
18620Sstevel@tonic-gate * +--------+
18630Sstevel@tonic-gate * | header |
18640Sstevel@tonic-gate * +--------+
18650Sstevel@tonic-gate * | name |
18660Sstevel@tonic-gate * | ... |
18670Sstevel@tonic-gate * +--------+
18680Sstevel@tonic-gate * | desc |
18690Sstevel@tonic-gate * | ... |
18700Sstevel@tonic-gate * +--------+
18710Sstevel@tonic-gate */
18720Sstevel@tonic-gate for (nleft = note_phdr.p_filesz; nleft > 0; ) {
18730Sstevel@tonic-gate Elf64_Nhdr nhdr;
18740Sstevel@tonic-gate off64_t off, namesz;
18750Sstevel@tonic-gate
18760Sstevel@tonic-gate /*
18770Sstevel@tonic-gate * Although <sys/elf.h> defines both Elf32_Nhdr and Elf64_Nhdr
18780Sstevel@tonic-gate * as different types, they are both of the same content and
18790Sstevel@tonic-gate * size, so we don't need to worry about 32/64 conversion here.
18800Sstevel@tonic-gate */
18810Sstevel@tonic-gate if (read(P->asfd, &nhdr, sizeof (nhdr)) != sizeof (nhdr)) {
18820Sstevel@tonic-gate dprintf("Pgrab_core: failed to read ELF note header\n");
18830Sstevel@tonic-gate *perr = G_NOTE;
18840Sstevel@tonic-gate goto err;
18850Sstevel@tonic-gate }
18860Sstevel@tonic-gate
18870Sstevel@tonic-gate /*
18880Sstevel@tonic-gate * According to the System V ABI, the amount of padding
18890Sstevel@tonic-gate * following the name field should align the description
18900Sstevel@tonic-gate * field on a 4 byte boundary for 32-bit binaries or on an 8
18910Sstevel@tonic-gate * byte boundary for 64-bit binaries. However, this change
18920Sstevel@tonic-gate * was not made correctly during the 64-bit port so all
18930Sstevel@tonic-gate * descriptions can assume only 4-byte alignment. We ignore
18940Sstevel@tonic-gate * the name field and the padding to 4-byte alignment.
18950Sstevel@tonic-gate */
18960Sstevel@tonic-gate namesz = P2ROUNDUP((off64_t)nhdr.n_namesz, (off64_t)4);
18970Sstevel@tonic-gate if (lseek64(P->asfd, namesz, SEEK_CUR) == (off64_t)-1) {
18980Sstevel@tonic-gate dprintf("failed to seek past name and padding\n");
18990Sstevel@tonic-gate *perr = G_STRANGE;
19000Sstevel@tonic-gate goto err;
19010Sstevel@tonic-gate }
19020Sstevel@tonic-gate
19030Sstevel@tonic-gate dprintf("Note hdr n_type=%u n_namesz=%u n_descsz=%u\n",
19040Sstevel@tonic-gate nhdr.n_type, nhdr.n_namesz, nhdr.n_descsz);
19050Sstevel@tonic-gate
19060Sstevel@tonic-gate off = lseek64(P->asfd, (off64_t)0L, SEEK_CUR);
19070Sstevel@tonic-gate
19080Sstevel@tonic-gate /*
19090Sstevel@tonic-gate * Invoke the note handler function from our table
19100Sstevel@tonic-gate */
19110Sstevel@tonic-gate if (nhdr.n_type < sizeof (nhdlrs) / sizeof (nhdlrs[0])) {
19120Sstevel@tonic-gate if (nhdlrs[nhdr.n_type](P, nhdr.n_descsz) < 0) {
19130Sstevel@tonic-gate *perr = G_NOTE;
19140Sstevel@tonic-gate goto err;
19150Sstevel@tonic-gate }
19160Sstevel@tonic-gate } else
19170Sstevel@tonic-gate (void) note_notsup(P, nhdr.n_descsz);
19180Sstevel@tonic-gate
19190Sstevel@tonic-gate /*
19200Sstevel@tonic-gate * Seek past the current note data to the next Elf_Nhdr
19210Sstevel@tonic-gate */
19220Sstevel@tonic-gate if (lseek64(P->asfd, off + nhdr.n_descsz,
19230Sstevel@tonic-gate SEEK_SET) == (off64_t)-1) {
19240Sstevel@tonic-gate dprintf("Pgrab_core: failed to seek to next nhdr\n");
19250Sstevel@tonic-gate *perr = G_STRANGE;
19260Sstevel@tonic-gate goto err;
19270Sstevel@tonic-gate }
19280Sstevel@tonic-gate
19290Sstevel@tonic-gate /*
19300Sstevel@tonic-gate * Subtract the size of the header and its data from what
19310Sstevel@tonic-gate * we have left to process.
19320Sstevel@tonic-gate */
19330Sstevel@tonic-gate nleft -= sizeof (nhdr) + namesz + nhdr.n_descsz;
19340Sstevel@tonic-gate }
19350Sstevel@tonic-gate
19360Sstevel@tonic-gate if (nleft != 0) {
19370Sstevel@tonic-gate dprintf("Pgrab_core: note section malformed\n");
19380Sstevel@tonic-gate *perr = G_STRANGE;
19390Sstevel@tonic-gate goto err;
19400Sstevel@tonic-gate }
19410Sstevel@tonic-gate
19420Sstevel@tonic-gate if ((pagesize = Pgetauxval(P, AT_PAGESZ)) == -1) {
19430Sstevel@tonic-gate pagesize = getpagesize();
19440Sstevel@tonic-gate dprintf("AT_PAGESZ missing; defaulting to %d\n", pagesize);
19450Sstevel@tonic-gate }
19460Sstevel@tonic-gate
19470Sstevel@tonic-gate /*
19480Sstevel@tonic-gate * Locate and label the mappings corresponding to the end of the
19490Sstevel@tonic-gate * heap (MA_BREAK) and the base of the stack (MA_STACK).
19500Sstevel@tonic-gate */
19510Sstevel@tonic-gate if ((P->status.pr_brkbase != 0 || P->status.pr_brksize != 0) &&
19520Sstevel@tonic-gate (brk_mp = Paddr2mptr(P, P->status.pr_brkbase +
19530Sstevel@tonic-gate P->status.pr_brksize - 1)) != NULL)
19540Sstevel@tonic-gate brk_mp->map_pmap.pr_mflags |= MA_BREAK;
19550Sstevel@tonic-gate else
19560Sstevel@tonic-gate brk_mp = NULL;
19570Sstevel@tonic-gate
19580Sstevel@tonic-gate if ((stk_mp = Paddr2mptr(P, P->status.pr_stkbase)) != NULL)
19590Sstevel@tonic-gate stk_mp->map_pmap.pr_mflags |= MA_STACK;
19600Sstevel@tonic-gate
19610Sstevel@tonic-gate /*
19620Sstevel@tonic-gate * At this point, we have enough information to look for the
19630Sstevel@tonic-gate * executable and open it: we have access to the auxv, a psinfo_t,
19640Sstevel@tonic-gate * and the ability to read from mappings provided by the core file.
19650Sstevel@tonic-gate */
19660Sstevel@tonic-gate (void) Pfindexec(P, aout_path, core_exec_open, &aout);
19670Sstevel@tonic-gate dprintf("P->execname = \"%s\"\n", P->execname ? P->execname : "NULL");
19680Sstevel@tonic-gate execname = P->execname ? P->execname : "a.out";
19690Sstevel@tonic-gate
19700Sstevel@tonic-gate /*
19710Sstevel@tonic-gate * Iterate through the sections, looking for the .dynamic and .interp
19720Sstevel@tonic-gate * sections. If we encounter them, remember their section pointers.
19730Sstevel@tonic-gate */
19740Sstevel@tonic-gate for (scn = NULL; (scn = elf_nextscn(aout.e_elf, scn)) != NULL; ) {
19750Sstevel@tonic-gate char *sname;
19760Sstevel@tonic-gate
19770Sstevel@tonic-gate if ((gelf_getshdr(scn, &shdr) == NULL) ||
19780Sstevel@tonic-gate (sname = elf_strptr(aout.e_elf, aout.e_hdr.e_shstrndx,
19790Sstevel@tonic-gate (size_t)shdr.sh_name)) == NULL)
19800Sstevel@tonic-gate continue;
19810Sstevel@tonic-gate
19820Sstevel@tonic-gate if (strcmp(sname, ".interp") == 0)
19830Sstevel@tonic-gate intp_scn = scn;
19840Sstevel@tonic-gate }
19850Sstevel@tonic-gate
19860Sstevel@tonic-gate /*
19870Sstevel@tonic-gate * Get the AT_BASE auxv element. If this is missing (-1), then
19880Sstevel@tonic-gate * we assume this is a statically-linked executable.
19890Sstevel@tonic-gate */
19900Sstevel@tonic-gate base_addr = Pgetauxval(P, AT_BASE);
19910Sstevel@tonic-gate
19920Sstevel@tonic-gate /*
19930Sstevel@tonic-gate * In order to get librtld_db initialized, we'll need to identify
19940Sstevel@tonic-gate * and name the mapping corresponding to the run-time linker. The
19950Sstevel@tonic-gate * AT_BASE auxv element tells us the address where it was mapped,
19960Sstevel@tonic-gate * and the .interp section of the executable tells us its path.
19970Sstevel@tonic-gate * If for some reason that doesn't pan out, just use ld.so.1.
19980Sstevel@tonic-gate */
19990Sstevel@tonic-gate if (intp_scn != NULL && (dp = elf_getdata(intp_scn, NULL)) != NULL &&
20000Sstevel@tonic-gate dp->d_size != 0) {
20010Sstevel@tonic-gate dprintf(".interp = <%s>\n", (char *)dp->d_buf);
20020Sstevel@tonic-gate interp = dp->d_buf;
20030Sstevel@tonic-gate
20040Sstevel@tonic-gate } else if (base_addr != (uintptr_t)-1L) {
20050Sstevel@tonic-gate if (P->core->core_dmodel == PR_MODEL_LP64)
20060Sstevel@tonic-gate interp = "/usr/lib/64/ld.so.1";
20070Sstevel@tonic-gate else
20080Sstevel@tonic-gate interp = "/usr/lib/ld.so.1";
20090Sstevel@tonic-gate
20100Sstevel@tonic-gate dprintf(".interp section is missing or could not be read; "
20110Sstevel@tonic-gate "defaulting to %s\n", interp);
20120Sstevel@tonic-gate } else
20130Sstevel@tonic-gate dprintf("detected statically linked executable\n");
20140Sstevel@tonic-gate
20150Sstevel@tonic-gate /*
20160Sstevel@tonic-gate * If we have an AT_BASE element, name the mapping at that address
20170Sstevel@tonic-gate * using the interpreter pathname. Name the corresponding data
20180Sstevel@tonic-gate * mapping after the interpreter as well.
20190Sstevel@tonic-gate */
20200Sstevel@tonic-gate if (base_addr != (uintptr_t)-1L) {
20210Sstevel@tonic-gate elf_file_t intf;
20220Sstevel@tonic-gate
20230Sstevel@tonic-gate P->map_ldso = core_name_mapping(P, base_addr, interp);
20240Sstevel@tonic-gate
20250Sstevel@tonic-gate if (core_elf_open(&intf, interp, ET_DYN, NULL) == 0) {
20260Sstevel@tonic-gate rd_loadobj_t rl;
20270Sstevel@tonic-gate map_info_t *dmp;
20280Sstevel@tonic-gate
20290Sstevel@tonic-gate rl.rl_base = base_addr;
20300Sstevel@tonic-gate dmp = core_find_data(P, intf.e_elf, &rl);
20310Sstevel@tonic-gate
20320Sstevel@tonic-gate if (dmp != NULL) {
20330Sstevel@tonic-gate dprintf("renamed data at %p to %s\n",
20340Sstevel@tonic-gate (void *)rl.rl_data_base, interp);
20350Sstevel@tonic-gate (void) strncpy(dmp->map_pmap.pr_mapname,
20360Sstevel@tonic-gate interp, PRMAPSZ);
20370Sstevel@tonic-gate dmp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
20380Sstevel@tonic-gate }
20390Sstevel@tonic-gate }
20400Sstevel@tonic-gate
20410Sstevel@tonic-gate core_elf_close(&intf);
20420Sstevel@tonic-gate }
20430Sstevel@tonic-gate
20440Sstevel@tonic-gate /*
20450Sstevel@tonic-gate * If we have an AT_ENTRY element, name the mapping at that address
20460Sstevel@tonic-gate * using the special name "a.out" just like /proc does.
20470Sstevel@tonic-gate */
20480Sstevel@tonic-gate if ((addr = Pgetauxval(P, AT_ENTRY)) != (uintptr_t)-1L)
20490Sstevel@tonic-gate P->map_exec = core_name_mapping(P, addr, "a.out");
20500Sstevel@tonic-gate
20510Sstevel@tonic-gate /*
20520Sstevel@tonic-gate * If we're a statically linked executable, then just locate the
20530Sstevel@tonic-gate * executable's text and data and name them after the executable.
20540Sstevel@tonic-gate */
20550Sstevel@tonic-gate if (base_addr == (uintptr_t)-1L) {
20560Sstevel@tonic-gate map_info_t *tmp, *dmp;
20570Sstevel@tonic-gate file_info_t *fp;
20580Sstevel@tonic-gate rd_loadobj_t rl;
20590Sstevel@tonic-gate
20600Sstevel@tonic-gate if ((tmp = core_find_text(P, aout.e_elf, &rl)) != NULL &&
20610Sstevel@tonic-gate (dmp = core_find_data(P, aout.e_elf, &rl)) != NULL) {
20620Sstevel@tonic-gate (void) strncpy(tmp->map_pmap.pr_mapname,
20630Sstevel@tonic-gate execname, PRMAPSZ);
20640Sstevel@tonic-gate tmp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
20650Sstevel@tonic-gate (void) strncpy(dmp->map_pmap.pr_mapname,
20660Sstevel@tonic-gate execname, PRMAPSZ);
20670Sstevel@tonic-gate dmp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
20680Sstevel@tonic-gate }
20690Sstevel@tonic-gate
20700Sstevel@tonic-gate if ((P->map_exec = tmp) != NULL &&
20710Sstevel@tonic-gate (fp = malloc(sizeof (file_info_t))) != NULL) {
20720Sstevel@tonic-gate
20730Sstevel@tonic-gate (void) memset(fp, 0, sizeof (file_info_t));
20740Sstevel@tonic-gate
20750Sstevel@tonic-gate list_link(fp, &P->file_head);
20760Sstevel@tonic-gate tmp->map_file = fp;
20770Sstevel@tonic-gate P->num_files++;
20780Sstevel@tonic-gate
20790Sstevel@tonic-gate fp->file_ref = 1;
20800Sstevel@tonic-gate fp->file_fd = -1;
20810Sstevel@tonic-gate
20820Sstevel@tonic-gate fp->file_lo = malloc(sizeof (rd_loadobj_t));
20830Sstevel@tonic-gate fp->file_lname = strdup(execname);
20840Sstevel@tonic-gate
20850Sstevel@tonic-gate if (fp->file_lo)
20860Sstevel@tonic-gate *fp->file_lo = rl;
20870Sstevel@tonic-gate if (fp->file_lname)
20880Sstevel@tonic-gate fp->file_lbase = basename(fp->file_lname);
20897675SEdward.Pilatowicz@Sun.COM if (fp->file_rname)
20907675SEdward.Pilatowicz@Sun.COM fp->file_rbase = basename(fp->file_rname);
20910Sstevel@tonic-gate
20920Sstevel@tonic-gate (void) strcpy(fp->file_pname,
20930Sstevel@tonic-gate P->mappings[0].map_pmap.pr_mapname);
20940Sstevel@tonic-gate fp->file_map = tmp;
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate Pbuild_file_symtab(P, fp);
20970Sstevel@tonic-gate
20980Sstevel@tonic-gate if (dmp != NULL) {
20990Sstevel@tonic-gate dmp->map_file = fp;
21000Sstevel@tonic-gate fp->file_ref++;
21010Sstevel@tonic-gate }
21020Sstevel@tonic-gate }
21030Sstevel@tonic-gate }
21040Sstevel@tonic-gate
21050Sstevel@tonic-gate core_elf_close(&aout);
21060Sstevel@tonic-gate
21070Sstevel@tonic-gate /*
21080Sstevel@tonic-gate * We now have enough information to initialize librtld_db.
21090Sstevel@tonic-gate * After it warms up, we can iterate through the load object chain
21100Sstevel@tonic-gate * in the core, which will allow us to construct the file info
21110Sstevel@tonic-gate * we need to provide symbol information for the other shared
21120Sstevel@tonic-gate * libraries, and also to fill in the missing mapping names.
21130Sstevel@tonic-gate */
21140Sstevel@tonic-gate rd_log(_libproc_debug);
21150Sstevel@tonic-gate
21160Sstevel@tonic-gate if ((P->rap = rd_new(P)) != NULL) {
21170Sstevel@tonic-gate (void) rd_loadobj_iter(P->rap, (rl_iter_f *)
21180Sstevel@tonic-gate core_iter_mapping, P);
21190Sstevel@tonic-gate
21200Sstevel@tonic-gate if (P->core->core_errno != 0) {
21210Sstevel@tonic-gate errno = P->core->core_errno;
21220Sstevel@tonic-gate *perr = G_STRANGE;
21230Sstevel@tonic-gate goto err;
21240Sstevel@tonic-gate }
21250Sstevel@tonic-gate } else
21260Sstevel@tonic-gate dprintf("failed to initialize rtld_db agent\n");
21270Sstevel@tonic-gate
21280Sstevel@tonic-gate /*
21290Sstevel@tonic-gate * If there are sections, load them and process the data from any
21300Sstevel@tonic-gate * sections that we can use to annotate the file_info_t's.
21310Sstevel@tonic-gate */
21320Sstevel@tonic-gate core_load_shdrs(P, &core);
21330Sstevel@tonic-gate
21340Sstevel@tonic-gate /*
21350Sstevel@tonic-gate * If we previously located a stack or break mapping, and they are
21360Sstevel@tonic-gate * still anonymous, we now assume that they were MAP_ANON mappings.
21370Sstevel@tonic-gate * If brk_mp turns out to now have a name, then the heap is still
21380Sstevel@tonic-gate * sitting at the end of the executable's data+bss mapping: remove
21390Sstevel@tonic-gate * the previous MA_BREAK setting to be consistent with /proc.
21400Sstevel@tonic-gate */
21410Sstevel@tonic-gate if (stk_mp != NULL && stk_mp->map_pmap.pr_mapname[0] == '\0')
21420Sstevel@tonic-gate stk_mp->map_pmap.pr_mflags |= MA_ANON;
21430Sstevel@tonic-gate if (brk_mp != NULL && brk_mp->map_pmap.pr_mapname[0] == '\0')
21440Sstevel@tonic-gate brk_mp->map_pmap.pr_mflags |= MA_ANON;
21450Sstevel@tonic-gate else if (brk_mp != NULL)
21460Sstevel@tonic-gate brk_mp->map_pmap.pr_mflags &= ~MA_BREAK;
21470Sstevel@tonic-gate
21480Sstevel@tonic-gate *perr = 0;
21490Sstevel@tonic-gate return (P);
21500Sstevel@tonic-gate
21510Sstevel@tonic-gate err:
21520Sstevel@tonic-gate Pfree(P);
21530Sstevel@tonic-gate core_elf_close(&aout);
21540Sstevel@tonic-gate return (NULL);
21550Sstevel@tonic-gate }
21560Sstevel@tonic-gate
21570Sstevel@tonic-gate /*
21580Sstevel@tonic-gate * Grab a core file using a pathname. We just open it and call Pfgrab_core().
21590Sstevel@tonic-gate */
21600Sstevel@tonic-gate struct ps_prochandle *
Pgrab_core(const char * core,const char * aout,int gflag,int * perr)21610Sstevel@tonic-gate Pgrab_core(const char *core, const char *aout, int gflag, int *perr)
21620Sstevel@tonic-gate {
21630Sstevel@tonic-gate int fd, oflag = (gflag & PGRAB_RDONLY) ? O_RDONLY : O_RDWR;
21640Sstevel@tonic-gate
21650Sstevel@tonic-gate if ((fd = open64(core, oflag)) >= 0)
21660Sstevel@tonic-gate return (Pfgrab_core(fd, aout, perr));
21670Sstevel@tonic-gate
21680Sstevel@tonic-gate if (errno != ENOENT)
21690Sstevel@tonic-gate *perr = G_STRANGE;
21700Sstevel@tonic-gate else
21710Sstevel@tonic-gate *perr = G_NOCORE;
21720Sstevel@tonic-gate
21730Sstevel@tonic-gate return (NULL);
21740Sstevel@tonic-gate }
2175