/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #include <fcntl.h> #include <libproc.h> #include <limits.h> #include <stdio.h> #include <strings.h> #include <sys/mkdev.h> #include <sys/stat.h> #include <sys/types.h> #include "pmap_common.h" /* * We compare the high memory addresses since stacks are faulted in from * high memory addresses to low memory addresses, and our prmap_t * structures identify only the range of addresses that have been faulted * in so far. */ int cmpstacks(const void *ap, const void *bp) { const lwpstack_t *as = ap; const lwpstack_t *bs = bp; uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size; uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size; if (a < b) return (1); if (a > b) return (-1); return (0); } /* * Create labels for non-anon, non-heap mappings */ char * make_name(struct ps_prochandle *Pr, int lflag, uintptr_t addr, const char *mapname, char *buf, size_t bufsz) { const pstatus_t *Psp = Pstatus(Pr); struct stat statb; char path[PATH_MAX]; int len; if (lflag || Pstate(Pr) == PS_DEAD) { if (Pobjname(Pr, addr, buf, bufsz) != NULL) return (buf); } else { if (Pobjname_resolved(Pr, addr, buf, bufsz) != NULL) { /* Verify that the path exists */ if ((len = resolvepath(buf, buf, bufsz)) > 0) { buf[len] = '\0'; return (buf); } } } if (Pstate(Pr) == PS_DEAD || *mapname == '\0') return (NULL); /* first see if we can find a path via /proc */ (void) snprintf(path, sizeof (path), "/proc/%d/path/%s", (int)Psp->pr_pid, mapname); len = readlink(path, buf, bufsz - 1); if (len >= 0) { buf[len] = '\0'; return (buf); } /* fall back to object information reported by /proc */ (void) snprintf(path, sizeof (path), "/proc/%d/object/%s", (int)Psp->pr_pid, mapname); if (stat(path, &statb) == 0) { dev_t dev = statb.st_dev; ino_t ino = statb.st_ino; (void) snprintf(buf, bufsz, "dev:%lu,%lu ino:%lu", (ulong_t)major(dev), (ulong_t)minor(dev), ino); return (buf); } return (NULL); } /* * Create label for anon mappings */ char * anon_name(char *name, const pstatus_t *Psp, lwpstack_t *stacks, uint_t nstacks, uintptr_t vaddr, size_t size, int mflags, int shmid, int *mtypesp) { int mtypes = 0; if (mflags & MA_ISM) { if (shmid == -1) (void) snprintf(name, PATH_MAX, " [ %s shmid=null ]", (mflags & MA_NORESERVE) ? "ism" : "dism"); else (void) snprintf(name, PATH_MAX, " [ %s shmid=0x%x ]", (mflags & MA_NORESERVE) ? "ism" : "dism", shmid); mtypes |= (1 << AT_SHARED); } else if (mflags & MA_SHM) { if (shmid == -1) (void) sprintf(name, " [ shmid=null ]"); else (void) sprintf(name, " [ shmid=0x%x ]", shmid); mtypes |= (1 << AT_SHARED); } else if (vaddr + size > Psp->pr_stkbase && vaddr < Psp->pr_stkbase + Psp->pr_stksize) { (void) strcpy(name, " [ stack ]"); mtypes |= (1 << AT_STACK); } else if ((mflags & MA_ANON) && vaddr + size > Psp->pr_brkbase && vaddr < Psp->pr_brkbase + Psp->pr_brksize) { (void) strcpy(name, " [ heap ]"); mtypes |= (1 << AT_HEAP); } else { lwpstack_t key, *stk; key.lwps_stack.ss_sp = (void *)vaddr; key.lwps_stack.ss_size = size; if (nstacks > 0 && (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]), cmpstacks)) != NULL) { (void) snprintf(name, PATH_MAX, " [ %s tid=%d ]", (stk->lwps_stack.ss_flags & SS_ONSTACK) ? "altstack" : "stack", stk->lwps_lwpid); mtypes |= (1 << AT_STACK); } else { (void) strcpy(name, " [ anon ]"); mtypes |= (1 << AT_PRIVM); } } if (mtypesp) *mtypesp = mtypes; return (name); }