summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb.h10
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_proc.c114
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_set.c12
-rw-r--r--usr/src/cmd/ptools/Makefile9
-rw-r--r--usr/src/cmd/ptools/Makefile.bld29
-rw-r--r--usr/src/cmd/ptools/pldd/pldd.c22
-rw-r--r--usr/src/cmd/ptools/pmadvise/pmadvise.c195
-rw-r--r--usr/src/cmd/ptools/pmap/pmap.c201
-rw-r--r--usr/src/cmd/ptools/pmap/pmap_common.c164
-rw-r--r--usr/src/cmd/ptools/pmap/pmap_common.h (renamed from usr/src/lib/libproc/common/Pbrand.c)46
-rw-r--r--usr/src/cmd/ptools/pstack/pstack.c41
-rw-r--r--usr/src/cmd/truss/fcall.c16
-rw-r--r--usr/src/cmd/truss/ramdata.c6
-rw-r--r--usr/src/cmd/truss/ramdata.h6
-rw-r--r--usr/src/lib/libproc/Makefile.com4
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.h13
-rw-r--r--usr/src/lib/libproc/common/Pcore.c59
-rw-r--r--usr/src/lib/libproc/common/Pexecname.c43
-rw-r--r--usr/src/lib/libproc/common/Pidle.c34
-rw-r--r--usr/src/lib/libproc/common/Psymtab.c215
-rw-r--r--usr/src/lib/libproc/common/Pzone.c748
-rw-r--r--usr/src/lib/libproc/common/libproc.h11
-rw-r--r--usr/src/lib/libproc/common/llib-lproc12
-rw-r--r--usr/src/lib/libproc/common/mapfile-vers10
24 files changed, 1437 insertions, 583 deletions
diff --git a/usr/src/cmd/mdb/common/mdb/mdb.h b/usr/src/cmd/mdb/common/mdb/mdb.h
index 9af83546db..61f299db1f 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb.h
+++ b/usr/src/cmd/mdb/common/mdb/mdb.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _MDB_H
#define _MDB_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <mdb/mdb_nv.h>
#include <mdb/mdb_io.h>
#include <mdb/mdb_gelf.h>
@@ -93,6 +90,7 @@ extern "C" {
#ifdef _KMDB
#define MDB_FL_NOUNLOAD 0x40000 /* Don't allow debugger unload */
#endif
+#define MDB_FL_LMRAW 0x80000 /* Show unresolved link map object names */
#define MDB_FL_VOLATILE 0x0001 /* Mask of all volatile flags to save/restore */
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_proc.c b/usr/src/cmd/mdb/common/mdb/mdb_proc.c
index dfa7c470e5..421edf0678 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_proc.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_proc.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* User Process Target
*
@@ -311,7 +309,7 @@ pt_rtld_event(mdb_tgt_t *t, int vid, void *private)
struct ps_prochandle *P = t->t_pshandle;
pt_data_t *pt = t->t_data;
rd_event_msg_t rdm;
- int docontinue = 1;
+ int rv, docontinue = 1;
if (rd_event_getmsg(pt->p_rtld, &rdm) == RD_OK) {
@@ -324,8 +322,15 @@ pt_rtld_event(mdb_tgt_t *t, int vid, void *private)
Pupdate_maps(P);
- if (Pobject_iter(P, (proc_map_f *)thr_check, t) == 0 &&
- pt->p_ptl_ops != &proc_lwp_ops) {
+ if ((mdb.m_flags & MDB_FL_LMRAW) == 0) {
+ rv = Pobject_iter_resolved(P,
+ (proc_map_f *)thr_check, t);
+ } else {
+ rv = Pobject_iter(P,
+ (proc_map_f *)thr_check, t);
+ }
+
+ if ((rv == 0) && (pt->p_ptl_ops != &proc_lwp_ops)) {
mdb_dprintf(MDB_DBG_TGT, "unloading thread_db "
"support after dlclose\n");
PTL_DTOR(t);
@@ -780,7 +785,14 @@ pt_fork(mdb_tgt_t *t, int vid, void *private)
else {
t->t_pshandle = C;
pt->p_rtld = Prd_agent(C);
- (void) Pobject_iter(t->t_pshandle, (proc_map_f *)thr_check, t);
+
+ if ((mdb.m_flags & MDB_FL_LMRAW) == 0) {
+ (void) Pobject_iter_resolved(t->t_pshandle,
+ (proc_map_f *)thr_check, t);
+ } else {
+ (void) Pobject_iter(t->t_pshandle,
+ (proc_map_f *)thr_check, t);
+ }
}
(void) mdb_tgt_sespec_activate_all(t);
@@ -1783,8 +1795,13 @@ pt_tmodel(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
pt->p_ptl_hdl = NULL;
if (ptl_ops == &proc_tdb_ops) {
- (void) Pobject_iter(t->t_pshandle, (proc_map_f *)
- thr_check, t);
+ if ((mdb.m_flags & MDB_FL_LMRAW) == 0) {
+ (void) Pobject_iter(t->t_pshandle,
+ (proc_map_f *)thr_check, t);
+ } else {
+ (void) Pobject_iter_resolved(t->t_pshandle,
+ (proc_map_f *)thr_check, t);
+ }
}
}
@@ -2166,8 +2183,15 @@ pt_activate_common(mdb_tgt_t *t)
* and initialize the corresponding libthread_db. If this fails, fall
* back to our native LWP implementation and issue a warning.
*/
- if (t->t_pshandle != NULL && Pstate(t->t_pshandle) != PS_IDLE)
- (void) Pobject_iter(t->t_pshandle, (proc_map_f *)thr_check, t);
+ if (t->t_pshandle != NULL && Pstate(t->t_pshandle) != PS_IDLE) {
+ if ((mdb.m_flags & MDB_FL_LMRAW) == 0) {
+ (void) Pobject_iter_resolved(t->t_pshandle,
+ (proc_map_f *)thr_check, t);
+ } else {
+ (void) Pobject_iter(t->t_pshandle,
+ (proc_map_f *)thr_check, t);
+ }
+ }
/*
* If there's a global object named '_mdb_abort_info', assuming we're
@@ -2579,8 +2603,14 @@ pt_lookup_by_name_thr(mdb_tgt_t *t, const char *object,
pl.pl_found = FALSE;
if (object == MDB_TGT_OBJ_EVERY) {
- if (Pobject_iter(P, pt_lookup_cb, &pl) == -1)
- return (-1); /* errno is set for us */
+ if ((mdb.m_flags & MDB_FL_LMRAW) == 0) {
+ if (Pobject_iter_resolved(P, pt_lookup_cb,
+ &pl) == -1)
+ return (-1); /* errno is set for us */
+ } else {
+ if (Pobject_iter(P, pt_lookup_cb, &pl) == -1)
+ return (-1); /* errno is set for us */
+ }
} else {
const prmap_t *pmp;
@@ -2677,10 +2707,10 @@ pt_lookup_by_addr(mdb_tgt_t *t, uintptr_t addr, uint_t flags,
{
struct ps_prochandle *P = t->t_pshandle;
pt_data_t *pt = t->t_data;
-
rd_plt_info_t rpi = { 0 };
+
const char *pltsym;
- int match, i;
+ int rv, match, i;
mdb_gelf_symtab_t *gsts[3]; /* mdb.m_prsym, .symtab, .dynsym */
int gstc = 0; /* number of valid gsts[] entries */
@@ -2782,9 +2812,15 @@ pt_lookup_by_addr(mdb_tgt_t *t, uintptr_t addr, uint_t flags,
* Once we get the closest symbol, we perform the EXACT match or
* smart-mode or absolute distance check ourself:
*/
- if (Pxlookup_by_addr(P, addr, buf, nbytes, symp, &si) == 0 &&
- symp->st_value != 0 && (gst == NULL ||
- mdb_gelf_sym_closer(symp, &sym, addr))) {
+ if ((mdb.m_flags & MDB_FL_LMRAW) == 0) {
+ rv = Pxlookup_by_addr_resolved(P, addr, buf, nbytes,
+ symp, &si);
+ } else {
+ rv = Pxlookup_by_addr(P, addr, buf, nbytes,
+ symp, &si);
+ }
+ if ((rv == 0) && (symp->st_value != 0) &&
+ (gst == NULL || mdb_gelf_sym_closer(symp, &sym, addr))) {
if (flags & MDB_TGT_SYM_EXACT)
match = (addr == symp->st_value);
@@ -2821,8 +2857,14 @@ found:
const char *prefix = pmp->pr_mapname;
Lmid_t lmid;
- if (Pobjname(P, addr, pt->p_objname, MDB_TGT_MAPSZ))
- prefix = pt->p_objname;
+ if ((mdb.m_flags & MDB_FL_LMRAW) == 0) {
+ if (Pobjname_resolved(P, addr, pt->p_objname,
+ MDB_TGT_MAPSZ))
+ prefix = pt->p_objname;
+ } else {
+ if (Pobjname(P, addr, pt->p_objname, MDB_TGT_MAPSZ))
+ prefix = pt->p_objname;
+ }
if (buf != NULL && nbytes > 1) {
(void) strncpy(pt->p_symname, buf, MDB_TGT_SYM_NAMLEN);
@@ -2917,7 +2959,13 @@ pt_symbol_iter(mdb_tgt_t *t, const char *object, uint_t which,
which, type, pt_symbol_iter_cb, &ps);
return (0);
} else if (Prd_agent(t->t_pshandle) != NULL) {
- (void) Pobject_iter(t->t_pshandle, pt_objsym_iter, &ps);
+ if ((mdb.m_flags & MDB_FL_LMRAW) == 0) {
+ (void) Pobject_iter_resolved(t->t_pshandle,
+ pt_objsym_iter, &ps);
+ } else {
+ (void) Pobject_iter(t->t_pshandle,
+ pt_objsym_iter, &ps);
+ }
return (0);
}
}
@@ -2947,10 +2995,16 @@ static const mdb_map_t *
pt_prmap_to_mdbmap(mdb_tgt_t *t, const prmap_t *prp, mdb_map_t *mp)
{
struct ps_prochandle *P = t->t_pshandle;
- char name[MAXPATHLEN];
+ char *rv, name[MAXPATHLEN];
Lmid_t lmid;
- if (Pobjname(P, prp->pr_vaddr, name, sizeof (name)) != NULL) {
+ if ((mdb.m_flags & MDB_FL_LMRAW) == 0) {
+ rv = Pobjname_resolved(P, prp->pr_vaddr, name, sizeof (name));
+ } else {
+ rv = Pobjname(P, prp->pr_vaddr, name, sizeof (name));
+ }
+
+ if (rv != NULL) {
if (Plmid(P, prp->pr_vaddr, &lmid) == 0 && (
(lmid != LM_ID_BASE && lmid != LM_ID_LDSO) ||
(mdb.m_flags & MDB_FL_SHOWLMID))) {
@@ -3010,7 +3064,13 @@ pt_mapping_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private)
pm.pmap_func = func;
pm.pmap_private = private;
- (void) Pmapping_iter(t->t_pshandle, pt_map_apply, &pm);
+ if ((mdb.m_flags & MDB_FL_LMRAW) == 0) {
+ (void) Pmapping_iter_resolved(t->t_pshandle,
+ pt_map_apply, &pm);
+ } else {
+ (void) Pmapping_iter(t->t_pshandle,
+ pt_map_apply, &pm);
+ }
return (0);
}
@@ -3033,7 +3093,13 @@ pt_object_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private)
pm.pmap_func = func;
pm.pmap_private = private;
- (void) Pobject_iter(t->t_pshandle, pt_map_apply, &pm);
+ if ((mdb.m_flags & MDB_FL_LMRAW) == 0) {
+ (void) Pobject_iter_resolved(t->t_pshandle,
+ pt_map_apply, &pm);
+ } else {
+ (void) Pobject_iter(t->t_pshandle,
+ pt_map_apply, &pm);
+ }
return (0);
}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_set.c b/usr/src/cmd/mdb/common/mdb/mdb_set.c
index 55992c1657..c1c8538219 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_set.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_set.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Support for ::set dcmd. The +/-o option processing code is provided in a
* stand-alone function so it can be used by the command-line option processing
@@ -174,6 +171,7 @@ mdb_set_options(const char *s, int enable)
{ "noctf", opt_set_mflags, MDB_FL_NOCTF },
{ "nomods", opt_set_mflags, MDB_FL_NOMODS },
{ "showlmid", opt_set_mflags, MDB_FL_SHOWLMID },
+ { "lmraw", opt_set_mflags, MDB_FL_LMRAW },
{ "stop_on_bpt_nosym", opt_set_mflags, MDB_FL_BPTNOSYMSTOP },
{ "write_readback", opt_set_mflags, MDB_FL_READBACK },
@@ -299,6 +297,8 @@ print_properties(void)
COMMAFLAG("adb");
if (mdb.m_flags & MDB_FL_IGNEOF)
COMMAFLAG("ignoreeof");
+ if (mdb.m_flags & MDB_FL_LMRAW)
+ COMMAFLAG("lmraw");
if (mdb.m_flags & MDB_FL_PAGER)
COMMAFLAG("pager");
if (mdb.m_flags & MDB_FL_REPLAST)
diff --git a/usr/src/cmd/ptools/Makefile b/usr/src/cmd/ptools/Makefile
index 081145ded2..230f5aa7d4 100644
--- a/usr/src/cmd/ptools/Makefile
+++ b/usr/src/cmd/ptools/Makefile
@@ -20,11 +20,9 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
include ../Makefile.cmd
@@ -67,6 +65,11 @@ clobber := TARGET = clobber
lint := TARGET = lint
_msg := TARGET = _msg
+
+# pmadvise depends on pmap components
+PMAP = $(SRC)/cmd/ptools/pmap
+pmadvise/pmadvise.po := CPPFLAGS += -I$(PMAP)
+
#
# Commands with messages support
#
diff --git a/usr/src/cmd/ptools/Makefile.bld b/usr/src/cmd/ptools/Makefile.bld
index 40101123d1..ac0854383d 100644
--- a/usr/src/cmd/ptools/Makefile.bld
+++ b/usr/src/cmd/ptools/Makefile.bld
@@ -23,7 +23,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
PROG:sh = basename `cd ..; pwd`
@@ -56,28 +55,40 @@ LDLIBS_pwdx = -lproc
LDLIBS += $(LDLIBS_$(PROG))
-# pargs requires to link with ../../common/elfcap components
+# pargs depends on ../../common/elfcap components
+# pmadvise depends on pmap components
ELFCAP = $(SRC)/common/elfcap
+PMAP = $(SRC)/cmd/ptools/pmap
-CPPFLAGS_pargs =-I$(ELFCAP)
-OBJS_pargs = elfcap.o
-SRCS_pargs = $(ELFCAP)/elfcap.c
+CPPFLAGS_pargs = -I$(ELFCAP)
+OBJS_pargs = elfcap.o
+SRCS_pargs = $(ELFCAP)/elfcap.c
+
+CPPFLAGS_pmap = -I$(PMAP)
+OBJS_pmap = pmap_common.o
+SRCS_pmap = $(PMAP)/pmap_common.c
+
+CPPFLAGS_pmadvise = -I$(PMAP)
+OBJS_pmadvise = pmap_common.o
+SRCS_pmadvise = $(PMAP)/pmap_common.c
CPPFLAGS += $(CPPFLAGS_$(PROG))
OBJS += $(OBJS_$(PROG))
SRCS += $(SRCS_$(PROG))
-elfcap.o: $(ELFCAP)/elfcap.c
- $(COMPILE.c) -o $@ $(ELFCAP)/elfcap.c
-
-
INSTALL_NEW=
INSTALL_LEGACY=$(RM) $(ROOTPROCBINSYMLINK) ; \
$(LN) -s ../../bin/$(PROG) $(ROOTPROCBINSYMLINK)
.KEEP_STATE:
+elfcap.o: $(ELFCAP)/elfcap.c
+ $(COMPILE.c) -o $@ $(ELFCAP)/elfcap.c
+
+pmap_common.o: $(PMAP)/pmap_common.c
+ $(COMPILE.c) -o $@ $(PMAP)/pmap_common.c
+
%.o: ../%.c
$(COMPILE.c) $<
diff --git a/usr/src/cmd/ptools/pldd/pldd.c b/usr/src/cmd/ptools/pldd/pldd.c
index 72f3c9bf8d..c9158ef34c 100644
--- a/usr/src/cmd/ptools/pldd/pldd.c
+++ b/usr/src/cmd/ptools/pldd/pldd.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
@@ -46,6 +44,7 @@ main(int argc, char **argv)
int opt;
int errflg = 0;
int Fflag = 0;
+ int lflag = 0;
core_content_t content = CC_CONTENT_DATA | CC_CONTENT_ANON;
struct rlimit rlim;
@@ -55,11 +54,14 @@ main(int argc, char **argv)
command = argv[0];
/* options */
- while ((opt = getopt(argc, argv, "F")) != EOF) {
+ while ((opt = getopt(argc, argv, "Fl")) != EOF) {
switch (opt) {
case 'F': /* force grabbing (no O_EXCL) */
Fflag = PGRAB_FORCE;
break;
+ case 'l': /* show unresolved link map names */
+ lflag = 1;
+ break;
default:
errflg = 1;
break;
@@ -71,11 +73,12 @@ main(int argc, char **argv)
if (errflg || argc <= 0) {
(void) fprintf(stderr,
- "usage:\t%s [-F] { pid | core } ...\n", command);
+ "usage:\t%s [-Fl] { pid | core } ...\n", command);
(void) fprintf(stderr,
- " (report process dynamic libraries)\n");
+ " (report process dynamic libraries)\n");
(void) fprintf(stderr,
- " -F: force grabbing of the target process\n");
+ " -F: force grabbing of the target process\n"
+ " -l: show unresolved dynamic linker map names\n");
return (2);
}
@@ -131,7 +134,10 @@ main(int argc, char **argv)
"not be available\n", command);
}
- rc += Pobject_iter(Pr, show_map, Pr);
+ if (lflag)
+ rc += Pobject_iter(Pr, show_map, Pr);
+ else
+ rc += Pobject_iter_resolved(Pr, show_map, Pr);
Prelease(Pr, 0);
}
(void) proc_finistdio();
diff --git a/usr/src/cmd/ptools/pmadvise/pmadvise.c b/usr/src/cmd/ptools/pmadvise/pmadvise.c
index 9cc3e2e1f1..8500a00dc6 100644
--- a/usr/src/cmd/ptools/pmadvise/pmadvise.c
+++ b/usr/src/cmd/ptools/pmadvise/pmadvise.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* pmadvise
*
@@ -44,6 +42,7 @@
* free, access_lwp, access_many, access_default
* -v: verbose output
* -F: force grabbing of the target process(es)
+ * -l: show unresolved dynamic linker map names
* pid: process id list
*
*
@@ -124,6 +123,8 @@
#include <libgen.h>
#include <signal.h>
+#include "pmap_common.h"
+
#ifndef TEXT_DOMAIN /* should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */
#endif
@@ -173,32 +174,15 @@ static int pr_madvise(struct ps_prochandle *, caddr_t, size_t, int);
static char *mflags(uint_t);
static char *advtostr(int);
+static int lflag = 0;
+
static int addr_width, size_width;
static char *progname;
static struct ps_prochandle *Pr;
-typedef struct lwpstack {
- lwpid_t lwps_lwpid;
- stack_t lwps_stack;
-} lwpstack_t;
-
static lwpstack_t *stacks;
static uint_t nstacks;
-/*
- * Used to set the advice type var (at_map) when parsing the arguments to
- * pmadvise. Later, when creating the map list, at_map is used as a mask
- * to determine if any generic advice applies to each memory mapping.
- */
-enum atype_enum {
- AT_PRIVM,
- AT_SHARED,
- AT_HEAP,
- AT_STACK,
- AT_SEG,
- AT_NTYPES
-};
-
static char *suboptstr[] = {
"private",
"shared",
@@ -306,49 +290,29 @@ getstack(void *data, const lwpstatus_t *lsp)
}
/*
- * 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.
- */
-static 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);
-}
-
-/*
* Prints usage and exits
*/
static void
usage()
{
(void) fprintf(stderr,
- gettext("usage:\t%s -o option[,option] [-v] [-F] pid ...\n"),
+ gettext("usage:\t%s [-o option[,option]] [-Flv] pid ...\n"),
progname);
(void) fprintf(stderr,
gettext(" (Give \"advice\" about a process's memory)\n"
- " -o option[,option]: options are\n"
- " private=<advice>\n"
- " shared=<advice>\n"
- " heap=<advice>\n"
- " stack=<advice>\n"
- " <segaddr>[:<length>]=<advice>\n"
- " valid <advice> is one of:\n"
- " normal, random, sequential, willneed, dontneed,\n"
- " free, access_lwp, access_many, access_default\n"
- " -v: verbose output\n"
- " -F: force grabbing of the target process(es)\n"
- " pid: process id list\n"));
+ " -o option[,option]: options are\n"
+ " private=<advice>\n"
+ " shared=<advice>\n"
+ " heap=<advice>\n"
+ " stack=<advice>\n"
+ " <segaddr>[:<length>]=<advice>\n"
+ " valid <advice> is one of:\n"
+ " normal, random, sequential, willneed, dontneed,\n"
+ " free, access_lwp, access_many, access_default\n"
+ " -v: verbose output\n"
+ " -F: force grabbing of the target process(es)\n"
+ " -l: show unresolved dynamic linker map names\n"
+ " pid: process id list\n"));
exit(2);
}
@@ -580,99 +544,6 @@ parse_suboptions(char *value)
}
/*
- * Create labels for non-anon, non-heap mappings
- */
-static char *
-make_name(struct ps_prochandle *Pr, uintptr_t addr, const char *mapname,
- char *buf, size_t bufsz)
-{
- const pstatus_t *Psp = Pstatus(Pr);
- char fname[100];
- struct stat statb;
- int len;
-
- if (strcmp(mapname, "a.out") == 0 &&
- Pexecname(Pr, buf, bufsz) != NULL)
- return (buf);
-
- if (Pobjname(Pr, addr, buf, bufsz) != NULL) {
- if ((len = resolvepath(buf, buf, bufsz)) > 0) {
- buf[len] = '\0';
- return (buf);
- }
- }
-
- if (*mapname != '\0') {
- (void) snprintf(fname, sizeof (fname), "/proc/%d/object/%s",
- (int)Psp->pr_pid, mapname);
- if (stat(fname, &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
- */
-static char *
-anon_name(char *name, const pstatus_t *Psp,
- uintptr_t vaddr, size_t size, int mflags, int shmid, int *mtypes)
-{
- 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);
- }
- }
-
- return (name);
-}
-
-/*
* Create linked list of mappings for current process
* In addition, add generic advice and raw advice
* entries to merged_list.
@@ -704,7 +575,7 @@ create_maplist(void *arg, const prmap_t *pmp, const char *object_name)
if (!(pmp->pr_mflags & MA_ANON) ||
(pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase ||
pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize)) {
- lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname,
+ lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname,
newmap->label, sizeof (newmap->label));
if (pmp->pr_mflags & MA_SHARED)
newmap->mtypes |= 1 << AT_SHARED;
@@ -713,8 +584,8 @@ create_maplist(void *arg, const prmap_t *pmp, const char *object_name)
}
if (lname == NULL && (pmp->pr_mflags & MA_ANON)) {
- lname = anon_name(newmap->label, Psp, pmp->pr_vaddr,
- pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid,
+ lname = anon_name(newmap->label, Psp, stacks, nstacks,
+ pmp->pr_vaddr, pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid,
&newmap->mtypes);
}
@@ -816,8 +687,8 @@ apply_advice(saddr_t **advicelist)
*/
(void) fprintf(stderr,
gettext("Error applying "
- "advice (%s) to memory range "
- "[%lx, %lx):\n"),
+ "advice (%s) to memory range "
+ "[%lx, %lx):\n"),
advicestr[i], (ulong_t)psaddr->addr,
(ulong_t)psaddr->addr +
psaddr->length);
@@ -900,14 +771,15 @@ create_choplist(saddr_t **choppedlist, saddr_t *mergedlist)
}
for (clptr = *choppedlist; clptr != NULL; clptr = clptr->next) {
- if (clptr->next)
+ if (clptr->next) {
clptr->length = clptr->next->addr - clptr->addr;
- else {
+ } else {
/*
* must be last element, now that we've calculated
* all segment lengths, we can remove this node
*/
delete_addr(choppedlist, clptr);
+ break;
}
}
@@ -986,7 +858,7 @@ static int
pr_madvise(struct ps_prochandle *Pr, caddr_t addr, size_t len, int advice)
{
return (pr_memcntl(Pr, addr, len, MC_ADVISE,
- (caddr_t)(uintptr_t)advice, 0, 0));
+ (caddr_t)(uintptr_t)advice, 0, 0));
}
static char *
@@ -1097,7 +969,7 @@ main(int argc, char **argv)
* rawadv_list from specific address advice.
*/
- while ((opt = getopt(argc, argv, "Fo:v")) != EOF) {
+ while ((opt = getopt(argc, argv, "Flo:v")) != EOF) {
switch (opt) {
case 'o':
options = optarg;
@@ -1133,6 +1005,9 @@ main(int argc, char **argv)
case 'F': /* force grabbing (no O_EXCL) */
Fflag = PGRAB_FORCE;
break;
+ case 'l': /* show unresolved link map names */
+ lflag = 1;
+ break;
default:
usage();
break;
@@ -1200,9 +1075,9 @@ main(int argc, char **argv)
Prd_agent(Pr) == NULL) {
(void) fprintf(stderr,
gettext("%s: warning: "
- "librtld_db failed to initialize; "
- "shared library information will not "
- "be available\n"),
+ "librtld_db failed to initialize; "
+ "shared library information will not "
+ "be available\n"),
progname);
}
diff --git a/usr/src/cmd/ptools/pmap/pmap.c b/usr/src/cmd/ptools/pmap/pmap.c
index 2a95598381..78bfa6b596 100644
--- a/usr/src/cmd/ptools/pmap/pmap.c
+++ b/usr/src/cmd/ptools/pmap/pmap.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
@@ -44,7 +42,8 @@
#include <sys/mman.h>
#include <sys/lgrp_user.h>
#include <libproc.h>
-#include <libzonecfg.h>
+
+#include "pmap_common.h"
#define KILOBYTE 1024
#define MEGABYTE (KILOBYTE * KILOBYTE)
@@ -152,11 +151,6 @@ static struct ps_prochandle *Pr;
static void intr(int);
-typedef struct lwpstack {
- lwpid_t lwps_lwpid;
- stack_t lwps_stack;
-} lwpstack_t;
-
typedef struct {
prxmap_t md_xmap;
prmap_t md_map;
@@ -193,28 +187,6 @@ getstack(void *data, const lwpstatus_t *lsp)
return (0);
}
-/*
- * 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.
- */
-static 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);
-}
-
-
int
main(int argc, char **argv)
{
@@ -483,9 +455,12 @@ again:
else if (sflag)
rc += xmapping_iter(Pr, gather_xmap,
NULL, 0);
+ else if (lflag)
+ rc += Pmapping_iter(Pr,
+ gather_map, NULL);
else
- rc += Pmapping_iter(Pr, gather_map,
- NULL);
+ rc += Pmapping_iter_resolved(Pr,
+ gather_map, NULL);
}
/*
@@ -606,144 +581,6 @@ again:
return (rc);
}
-static char *
-make_name(struct ps_prochandle *Pr, uintptr_t addr, const char *mapname,
- char *buf, size_t bufsz)
-{
- const pstatus_t *Psp = Pstatus(Pr);
- const psinfo_t *pi = Ppsinfo(Pr);
- char fname[100];
- struct stat statb;
- int len;
- char zname[ZONENAME_MAX];
- char zpath[PATH_MAX];
- char objname[PATH_MAX];
-
- if (!lflag && strcmp(mapname, "a.out") == 0 &&
- Pexecname(Pr, buf, bufsz) != NULL)
- return (buf);
-
- if (Pobjname(Pr, addr, objname, sizeof (objname)) != NULL) {
- (void) strncpy(buf, objname, bufsz);
-
- if (lflag)
- return (buf);
-
- if ((len = resolvepath(buf, buf, bufsz)) > 0) {
- buf[len] = '\0';
- return (buf);
- }
-
- /*
- * If the target is in a non-global zone, attempt to prepend
- * the zone path in order to give the global-zone caller the
- * real path to the file.
- */
- if (getzonenamebyid(pi->pr_zoneid, zname,
- sizeof (zname)) != -1 && strcmp(zname, "global") != 0) {
- typedef int (*fptr)(char *, char *, size_t);
- fptr zone_get_zonepath;
- void *dlhdl;
-
- if (((dlhdl =
- dlopen(LIBZONECFG_PATH, RTLD_LAZY)) == NULL) ||
- ((zone_get_zonepath =
- (fptr) dlsym(dlhdl, "zone_get_zonepath")) == NULL))
- return (NULL);
-
- if ((*zone_get_zonepath)(zname, zpath, sizeof (zpath))
- == Z_OK) {
- (void) strncat(zpath, "/root",
- MAXPATHLEN - strlen(zpath));
-
- if (bufsz <= strlen(zpath)) {
- (void) dlclose(dlhdl);
- return (NULL);
- }
-
- (void) strncpy(buf, zpath, bufsz);
- (void) strncat(buf, objname,
- bufsz - strlen(zpath));
- }
- (void) dlclose(dlhdl);
- }
-
- if ((len = resolvepath(buf, buf, bufsz)) > 0) {
- buf[len] = '\0';
- return (buf);
- }
- }
-
- if (Pstate(Pr) != PS_DEAD && *mapname != '\0') {
- (void) snprintf(fname, sizeof (fname), "/proc/%d/path/%s",
- (int)Psp->pr_pid, mapname);
- len = readlink(fname, buf, bufsz - 1);
- if (len >= 0) {
- buf[len] = '\0';
- return (buf);
- } else { /* there is no path and readlink() error */
- (void) snprintf(fname, sizeof (fname),
- "/proc/%d/object/%s", (int)Psp->pr_pid, mapname);
- if (stat(fname, &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);
-}
-
-static char *
-anon_name(char *name, const pstatus_t *Psp,
- uintptr_t vaddr, size_t size, int mflags, int shmid)
-{
- 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);
- } else if (mflags & MA_SHM) {
- if (shmid == -1)
- (void) sprintf(name, " [ shmid=null ]");
- else
- (void) sprintf(name, " [ shmid=0x%x ]", shmid);
- } else if (vaddr + size > Psp->pr_stkbase &&
- vaddr < Psp->pr_stkbase + Psp->pr_stksize) {
- (void) strcpy(name, " [ stack ]");
- } else if ((mflags & MA_ANON) &&
- vaddr + size > Psp->pr_brkbase &&
- vaddr < Psp->pr_brkbase + Psp->pr_brksize) {
- (void) strcpy(name, " [ 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);
- } else if (Pstate(Pr) != PS_DEAD) {
- (void) strcpy(name, " [ anon ]");
- } else {
- return (NULL);
- }
- }
-
- return (name);
-}
-
static int
rmapping_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd)
{
@@ -862,14 +699,14 @@ look_map(void *data, const prmap_t *pmp, const char *object_name)
if (!(pmp->pr_mflags & MA_ANON) ||
segment_end <= Psp->pr_brkbase ||
pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) {
- lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname,
+ lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname,
mname, sizeof (mname));
}
if (lname == NULL &&
((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) {
- lname = anon_name(mname, Psp, pmp->pr_vaddr,
- pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid);
+ lname = anon_name(mname, Psp, stacks, nstacks, pmp->pr_vaddr,
+ pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, NULL);
}
/*
@@ -1000,14 +837,14 @@ look_smap(void *data,
if (!(pmp->pr_mflags & MA_ANON) ||
pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase ||
pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) {
- lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname,
+ lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname,
mname, sizeof (mname));
}
if (lname == NULL &&
((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) {
- lname = anon_name(mname, Psp, pmp->pr_vaddr,
- pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid);
+ lname = anon_name(mname, Psp, stacks, nstacks, pmp->pr_vaddr,
+ pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, NULL);
}
/*
@@ -1104,7 +941,7 @@ look_xmap(void *data,
if (!(pmp->pr_mflags & MA_ANON) ||
pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase ||
pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) {
- lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname,
+ lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname,
mname, sizeof (mname));
}
@@ -1112,8 +949,8 @@ look_xmap(void *data,
if ((ln = strrchr(lname, '/')) != NULL)
lname = ln + 1;
} else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) {
- lname = anon_name(mname, Psp, pmp->pr_vaddr,
- pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid);
+ lname = anon_name(mname, Psp, stacks, nstacks, pmp->pr_vaddr,
+ pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, NULL);
}
(void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr);
@@ -1183,7 +1020,7 @@ look_xmap_nopgsz(void *data,
if (!(pmp->pr_mflags & MA_ANON) ||
pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase ||
pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) {
- lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname,
+ lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname,
mname, sizeof (mname));
}
@@ -1191,8 +1028,8 @@ look_xmap_nopgsz(void *data,
if ((ln = strrchr(lname, '/')) != NULL)
lname = ln + 1;
} else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) {
- lname = anon_name(mname, Psp, pmp->pr_vaddr,
- pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid);
+ lname = anon_name(mname, Psp, stacks, nstacks, pmp->pr_vaddr,
+ pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, NULL);
}
kperpage = pmp->pr_pagesize / KILOBYTE;
diff --git a/usr/src/cmd/ptools/pmap/pmap_common.c b/usr/src/cmd/ptools/pmap/pmap_common.c
new file mode 100644
index 0000000000..7594fd30e3
--- /dev/null
+++ b/usr/src/cmd/ptools/pmap/pmap_common.c
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+#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) {
+ 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);
+}
diff --git a/usr/src/lib/libproc/common/Pbrand.c b/usr/src/cmd/ptools/pmap/pmap_common.h
index 605a3afa20..5edc536ad4 100644
--- a/usr/src/lib/libproc/common/Pbrand.c
+++ b/usr/src/cmd/ptools/pmap/pmap_common.h
@@ -18,25 +18,47 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+#ifndef _PMAP_COMMON_H
+#define _PMAP_COMMON_H
-#include "libproc.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
-char *
-Pbrandname(struct ps_prochandle *P, char *buf, size_t buflen)
-{
- long addr;
+typedef struct lwpstack {
+ lwpid_t lwps_lwpid;
+ stack_t lwps_stack;
+} lwpstack_t;
- if ((addr = Pgetauxval(P, AT_SUN_BRANDNAME)) == -1)
- return (NULL);
+/*
+ * Used to set the advice type var (at_map) when parsing the arguments to
+ * pmadvise. Later, when creating the map list, at_map is used as a mask
+ * to determine if any generic advice applies to each memory mapping.
+ */
+enum atype_enum {
+ AT_PRIVM,
+ AT_SHARED,
+ AT_HEAP,
+ AT_STACK,
+ AT_SEG,
+ AT_NTYPES
+};
- if (Pread_string(P, buf, buflen, addr) == -1)
- return (NULL);
+extern int cmpstacks(const void *, const void *);
+extern char *make_name(struct ps_prochandle *, int, uintptr_t,
+ const char *, char *, size_t);
+extern char *anon_name(char *, const pstatus_t *, lwpstack_t *, uint_t,
+ uintptr_t, size_t, int, int, int *);
- return (buf);
+
+#ifdef __cplusplus
}
+#endif
+
+#endif /* _PMAP_COMMON_H */
diff --git a/usr/src/cmd/ptools/pstack/pstack.c b/usr/src/cmd/ptools/pstack/pstack.c
index 53f07e433c..6d9ad10fa7 100644
--- a/usr/src/cmd/ptools/pstack/pstack.c
+++ b/usr/src/cmd/ptools/pstack/pstack.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/isa_defs.h>
#include <stdio.h>
@@ -170,7 +168,7 @@ main(int argc, char **argv)
"usage:\t%s [-F] { pid | core }[/lwps] ...\n", command);
(void) fprintf(stderr, " (show process call stack)\n");
(void) fprintf(stderr,
- " -F: force grabbing of the target process\n");
+ " -F: force grabbing of the target process\n");
exit(2);
}
@@ -380,7 +378,7 @@ thread_call_stack(void *data, const lwpstatus_t *psp,
else {
(void) memset(&lwpstatus, 0, sizeof (lwpstatus));
(void) memcpy(lwpstatus.pr_reg, tip->regs,
- sizeof (prgregset_t));
+ sizeof (prgregset_t));
call_stack(h, &lwpstatus);
}
}
@@ -402,7 +400,7 @@ lwp_call_stack(void *data,
call_stack(h, psp);
else
(void) printf("\t** zombie "
- "(exited, not detached, not yet joined) **\n");
+ "(exited, not detached, not yet joined) **\n");
return (0);
}
@@ -440,7 +438,7 @@ all_call_stacks(pstack_handle_t *h, int dothreads)
if ((tid = tip->threadid) != 0) {
(void) memcpy(lwpstatus.pr_reg, tip->regs,
- sizeof (prgregset_t));
+ sizeof (prgregset_t));
tlhead(tid, tip->lwpid);
if (tip->state == TD_THR_ZOMBIE)
print_zombie(Pr, tip);
@@ -464,7 +462,7 @@ tlhead(id_t threadid, id_t lwpid)
if (threadid && lwpid)
(void) printf(" lwp# %d / thread# %d ",
- (int)lwpid, (int)threadid);
+ (int)lwpid, (int)threadid);
else if (threadid)
(void) printf("--------- thread# %d ", (int)threadid);
else if (lwpid)
@@ -556,12 +554,10 @@ print_frame(void *cd, prgregset_t gregs, uint_t argc, const long *argv)
(void) printf(" %-17s (", buff);
for (i = 0; i < argc && i < MAX_ARGS; i++)
- (void) printf((i+1 == argc)? "%lx" : "%lx, ",
- argv[i]);
+ (void) printf((i+1 == argc) ? "%lx" : "%lx, ", argv[i]);
if (i != argc)
(void) printf("...");
- (void) printf((start != pc)?
- ") + %lx\n" : ")\n", (long)(pc - start));
+ (void) printf((start != pc) ? ") + %lx\n" : ")\n", (long)(pc - start));
/*
* If the frame's pc is in the "sigh" (a.k.a. signal handler, signal
@@ -598,7 +594,7 @@ print_zombie(struct ps_prochandle *Pr, struct threadinfo *tip)
(void) printf("+%lx", (long)(tip->startfunc - start));
(void) printf(", exit value = 0x%.*lx\n", length, (long)tip->exitval);
(void) printf("\t** zombie "
- "(exited, not detached, not yet joined) **\n");
+ "(exited, not detached, not yet joined) **\n");
}
static void
@@ -612,7 +608,7 @@ print_syscall(const lwpstatus_t *psp, prgregset_t reg)
(void) printf(" %.*lx %-8s (", length, (long)reg[R_PC], sname);
for (i = 0; i < psp->pr_nsysarg; i++)
(void) printf((i+1 == psp->pr_nsysarg)? "%lx" : "%lx, ",
- (long)psp->pr_sysarg[i]);
+ (long)psp->pr_sysarg[i]);
(void) printf(")\n");
}
@@ -676,6 +672,23 @@ load_libjvm(struct ps_prochandle *Pr)
{
jvm_agent_t *ret;
+ /*
+ * Iterate through all the loaded objects in the target, looking
+ * for libjvm.so. If we find libjvm.so we'll try to load the
+ * corresponding libjvm_db.so that lives in the same directory.
+ *
+ * At first glance it seems like we'd want to use
+ * Pobject_iter_resolved() here since we'd want to make sure that
+ * we have the full path to the libjvm.so. But really, we don't
+ * want that since we're going to be dlopen()ing a library and
+ * executing code from that path, and therefore we don't want to
+ * load any library code that could be from a zone since it could
+ * have been replaced with a trojan. Hence, we use Pobject_iter().
+ * So if we're debugging java processes in a zone from the global
+ * zone, and we want to get proper java stack stack frames, then
+ * the same jvm that is running within the zone needs to be
+ * installed in the global zone.
+ */
(void) Pobject_iter(Pr, jvm_object_iter, Pr);
if (libjvm) {
diff --git a/usr/src/cmd/truss/fcall.c b/usr/src/cmd/truss/fcall.c
index b64a807686..e1fe503409 100644
--- a/usr/src/cmd/truss/fcall.c
+++ b/usr/src/cmd/truss/fcall.c
@@ -189,10 +189,10 @@ establish_breakpoints(void)
struct dynlib **Dpp;
struct dynlib *Dp;
- for (Dp = Dyn; Dp != NULL; Dp = Dp->next)
+ for (Dp = Dynlib; Dp != NULL; Dp = Dp->next)
Dp->present = FALSE;
(void) Pobject_iter(Proc, object_present, NULL);
- Dpp = &Dyn;
+ Dpp = &Dynlib;
while ((Dp = *Dpp) != NULL) {
if (Dp->present) {
Dpp = &Dp->next;
@@ -313,7 +313,7 @@ object_iter(void *cd, const prmap_t *pmp, const char *object_name)
if (Thr_agent == NULL && strstr(object_name, "/libc.so.") != NULL)
setup_thread_agent();
- for (Dp = Dyn; Dp != NULL; Dp = Dp->next)
+ for (Dp = Dynlib; Dp != NULL; Dp = Dp->next)
if (strcmp(object_name, Dp->lib_name) == 0 ||
(strcmp(Dp->lib_name, "a.out") == 0 &&
strcmp(pmp->pr_mapname, "a.out") == 0))
@@ -340,8 +340,8 @@ object_iter(void *cd, const prmap_t *pmp, const char *object_name)
(void) strcat(name, ":");
Dp->prt_name = strdup(name);
}
- Dp->next = Dyn;
- Dyn = Dp;
+ Dp->next = Dynlib;
+ Dynlib = Dp;
}
if (Dp->built ||
@@ -397,7 +397,7 @@ object_present(void *cd, const prmap_t *pmp, const char *object_name)
{
struct dynlib *Dp;
- for (Dp = Dyn; Dp != NULL; Dp = Dp->next) {
+ for (Dp = Dynlib; Dp != NULL; Dp = Dp->next) {
if (Dp->base == pmp->pr_vaddr)
Dp->present = TRUE;
}
@@ -1072,8 +1072,8 @@ reset_breakpoints(void)
return;
/* destroy all previous dynamic library information */
- while ((Dp = Dyn) != NULL) {
- Dyn = Dp->next;
+ while ((Dp = Dynlib) != NULL) {
+ Dynlib = Dp->next;
free(Dp->lib_name);
free(Dp->match_name);
free(Dp->prt_name);
diff --git a/usr/src/cmd/truss/ramdata.c b/usr/src/cmd/truss/ramdata.c
index 6e115cb37e..bd02ab6e2a 100644
--- a/usr/src/cmd/truss/ramdata.c
+++ b/usr/src/cmd/truss/ramdata.c
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
-
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -102,7 +100,7 @@ lwpid_t *truss_lwpid; /* array of truss lwpid's */
struct counts *Cp; /* for counting: malloc() or shared memory */
struct global_psinfo *gps; /* contains global process information */
-struct dynlib *Dyn; /* for tracing functions in shared libraries */
+struct dynlib *Dynlib; /* for tracing functions in shared libraries */
struct dynpat *Dynpat;
struct dynpat *Lastpat;
struct bkpt **bpt_hashtable; /* breakpoint hash table */
diff --git a/usr/src/cmd/truss/ramdata.h b/usr/src/cmd/truss/ramdata.h
index b0408a053a..24cea0dbd8 100644
--- a/usr/src/cmd/truss/ramdata.h
+++ b/usr/src/cmd/truss/ramdata.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,8 +30,6 @@
#ifndef _RAMDATA_H
#define _RAMDATA_H
-#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -258,7 +256,7 @@ struct dynpat { /* structure specifying patterns for dynlib's */
struct dynlib *Dp; /* set to the dynlib instance when searching */
};
-extern struct dynlib *Dyn; /* for tracing functions in shared libraries */
+extern struct dynlib *Dynlib; /* for tracing functions in shared libraries */
extern struct dynpat *Dynpat;
extern struct dynpat *Lastpat;
extern struct bkpt **bpt_hashtable; /* breakpoint hash table */
diff --git a/usr/src/lib/libproc/Makefile.com b/usr/src/lib/libproc/Makefile.com
index 74ccc23c36..577aea87ec 100644
--- a/usr/src/lib/libproc/Makefile.com
+++ b/usr/src/lib/libproc/Makefile.com
@@ -22,15 +22,12 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
LIBRARY = libproc.a
VERS = .1
CMNOBJS = \
P32ton.o \
- Pbrand.o \
Pcontrol.o \
Pcore.o \
Pexecname.o \
@@ -46,6 +43,7 @@ CMNOBJS = \
Pstack.o \
Psyscall.o \
Putil.o \
+ Pzone.o \
pr_door.o \
pr_exit.o \
pr_fcntl.o \
diff --git a/usr/src/lib/libproc/common/Pcontrol.h b/usr/src/lib/libproc/common/Pcontrol.h
index b195db3b63..192038b9b6 100644
--- a/usr/src/lib/libproc/common/Pcontrol.h
+++ b/usr/src/lib/libproc/common/Pcontrol.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _PCONTROL_H
#define _PCONTROL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Implemention-specific include file for libproc process management.
* This is not to be seen by the clients of libproc.
@@ -98,6 +96,8 @@ typedef struct file_info { /* symbol information for a mapped file */
rd_loadobj_t *file_lo; /* load object structure from rtld_db */
char *file_lname; /* load object name from rtld_db */
char *file_lbase; /* pointer to basename of file_lname */
+ char *file_rname; /* resolved on-disk object pathname */
+ char *file_rbase; /* pointer to basename of file_rname */
Elf *file_elf; /* ELF handle so we can close */
void *file_elfmem; /* data for faked-up ELF handle */
sym_tbl_t file_symtab; /* symbol table */
@@ -222,6 +222,7 @@ struct ps_prochandle {
core_info_t *core; /* information specific to core (if PS_DEAD) */
uintptr_t *ucaddrs; /* ucontext-list addresses */
uint_t ucnelems; /* number of elements in the ucaddrs list */
+ char *zoneroot; /* cached path to zone root */
};
/* flags */
@@ -264,6 +265,12 @@ extern char *Pfindexec(struct ps_prochandle *, const char *,
extern int getlwpstatus(struct ps_prochandle *, lwpid_t, lwpstatus_t *);
int Pstopstatus(struct ps_prochandle *, long, uint32_t);
extern file_info_t *file_info_new(struct ps_prochandle *, map_info_t *);
+extern char *Plofspath(const char *, char *, size_t);
+extern char *Pzoneroot(struct ps_prochandle *, char *, size_t);
+extern char *Pzonepath(struct ps_prochandle *, const char *, char *,
+ size_t);
+extern char *Pfindmap(struct ps_prochandle *, map_info_t *, char *,
+ size_t);
extern int Padd_mapping(struct ps_prochandle *, off64_t, file_info_t *,
prmap_t *);
diff --git a/usr/src/lib/libproc/common/Pcore.c b/usr/src/lib/libproc/common/Pcore.c
index ca109c8158..203408c5b9 100644
--- a/usr/src/lib/libproc/common/Pcore.c
+++ b/usr/src/lib/libproc/common/Pcore.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/sysmacros.h>
@@ -40,6 +38,7 @@
#include <gelf.h>
#include <stddef.h>
+#include "libproc.h"
#include "Pcontrol.h"
#include "P32ton.h"
#include "Putil.h"
@@ -1365,7 +1364,7 @@ core_find_data(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp)
static int
core_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P)
{
- char lname[PATH_MAX];
+ char lname[PATH_MAX], buf[PATH_MAX];
file_info_t *fp;
map_info_t *mp;
@@ -1399,27 +1398,16 @@ core_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P)
fp->file_map = mp;
/* Create a local copy of the load object representation */
- if ((fp->file_lo = malloc(sizeof (rd_loadobj_t))) == NULL) {
+ if ((fp->file_lo = calloc(1, sizeof (rd_loadobj_t))) == NULL) {
P->core->core_errno = errno;
dprintf("failed to malloc mapping data\n");
return (0); /* Abort */
}
*fp->file_lo = *rlp;
- if (fp->file_lname == NULL &&
- strcmp(mp->map_pmap.pr_mapname, "a.out") == 0) {
- /*
- * Naming dance part 1: if the file_info_t is unnamed and
- * it represents the main executable, name it after the
- * execname.
- */
- fp->file_lname = P->execname ?
- strdup(P->execname) : strdup("a.out");
- }
-
if (lname[0] != '\0') {
/*
- * Naming dance part 2: if we got a name from librtld_db, then
+ * Naming dance part 1: if we got a name from librtld_db, then
* copy this name to the prmap_t if it is unnamed. If the
* file_info_t is unnamed, name it after the lname.
*/
@@ -1434,14 +1422,20 @@ core_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P)
} else if (fp->file_lname == NULL &&
mp->map_pmap.pr_mapname[0] != '\0') {
/*
- * Naming dance part 3: if the mapping is named and the
+ * Naming dance part 2: if the mapping is named and the
* file_info_t is not, name the file after the mapping.
*/
fp->file_lname = strdup(mp->map_pmap.pr_mapname);
}
+ if ((fp->file_rname == NULL) &&
+ (Pfindmap(P, mp, buf, sizeof (buf)) != NULL))
+ fp->file_rname = strdup(buf);
+
if (fp->file_lname != NULL)
fp->file_lbase = basename(fp->file_lname);
+ if (fp->file_rname != NULL)
+ fp->file_rbase = basename(fp->file_rname);
/* Associate the file and the mapping. */
(void) strncpy(fp->file_pname, mp->map_pmap.pr_mapname, PRMAPSZ);
@@ -1507,12 +1501,16 @@ core_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P)
/*
* Callback function for Pfindexec(). In order to confirm a given pathname,
- * we verify that we can open it as an ELF file of type ET_EXEC.
+ * we verify that we can open it as an ELF file of type ET_EXEC or ET_DYN.
*/
static int
core_exec_open(const char *path, void *efp)
{
- return (core_elf_open(efp, path, ET_EXEC, NULL) == 0);
+ if (core_elf_open(efp, path, ET_EXEC, NULL) == 0)
+ return (1);
+ if (core_elf_open(efp, path, ET_DYN, NULL) == 0)
+ return (1);
+ return (0);
}
/*
@@ -1731,6 +1729,7 @@ Pfgrab_core(int core_fd, const char *aout_path, int *perr)
P->statfd = -1;
P->agentctlfd = -1;
P->agentstatfd = -1;
+ P->zoneroot = NULL;
P->info_valid = 1;
P->ops = &P_core_ops;
@@ -1751,19 +1750,13 @@ Pfgrab_core(int core_fd, const char *aout_path, int *perr)
* Allocate and initialize a core_info_t to hang off the ps_prochandle
* structure. We keep all core-specific information in this structure.
*/
- if ((P->core = malloc(sizeof (core_info_t))) == NULL) {
+ if ((P->core = calloc(1, sizeof (core_info_t))) == NULL) {
*perr = G_STRANGE;
goto err;
}
list_link(&P->core->core_lwp_head, NULL);
- P->core->core_errno = 0;
- P->core->core_lwp = NULL;
- P->core->core_nlwp = 0;
P->core->core_size = stbuf.st_size;
- P->core->core_platform = NULL;
- P->core->core_uts = NULL;
- P->core->core_cred = NULL;
/*
* In the days before adjustable core file content, this was the
* default core file content. For new core files, this value will
@@ -1772,16 +1765,6 @@ Pfgrab_core(int core_fd, const char *aout_path, int *perr)
P->core->core_content = CC_CONTENT_STACK | CC_CONTENT_HEAP |
CC_CONTENT_DATA | CC_CONTENT_RODATA | CC_CONTENT_ANON |
CC_CONTENT_SHANON;
- P->core->core_priv = NULL;
- P->core->core_priv_size = 0;
- P->core->core_privinfo = NULL;
- P->core->core_zonename = NULL;
- P->core->core_ppii = NULL;
-
-#if defined(__i386) || defined(__amd64)
- P->core->core_ldt = NULL;
- P->core->core_nldt = 0;
-#endif
switch (core.e_hdr.e_ident[EI_CLASS]) {
case ELFCLASS32:
@@ -2098,6 +2081,8 @@ Pfgrab_core(int core_fd, const char *aout_path, int *perr)
*fp->file_lo = rl;
if (fp->file_lname)
fp->file_lbase = basename(fp->file_lname);
+ if (fp->file_rname)
+ fp->file_rbase = basename(fp->file_rname);
(void) strcpy(fp->file_pname,
P->mappings[0].map_pmap.pr_mapname);
diff --git a/usr/src/lib/libproc/common/Pexecname.c b/usr/src/lib/libproc/common/Pexecname.c
index d240c9b427..82b4219560 100644
--- a/usr/src/lib/libproc/common/Pexecname.c
+++ b/usr/src/lib/libproc/common/Pexecname.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#define __EXTENSIONS__
#include <string.h>
#undef __EXTENSIONS__
@@ -36,6 +34,7 @@
#include <unistd.h>
#include <zone.h>
+#include "libproc.h"
#include "Pcontrol.h"
/*
@@ -49,7 +48,7 @@
* caller's function do the final confirmation.
*/
static int
-try_exec(const char *cwd, const char *path, char *buf,
+try_exec(struct ps_prochandle *P, const char *cwd, const char *path, char *buf,
int (*isexec)(const char *, void *), void *isdata)
{
int i;
@@ -61,6 +60,7 @@ try_exec(const char *cwd, const char *path, char *buf,
dprintf("try_exec \"%s\"\n", buf);
+ (void) Pfindobj(P, buf, buf, PATH_MAX);
if ((i = resolvepath(buf, buf, PATH_MAX)) > 0) {
buf[i] = '\0';
return (isexec(buf, isdata));
@@ -87,6 +87,8 @@ Pfindexec(struct ps_prochandle *P, const char *aout,
uintptr_t addr;
char *p = path, *q;
+ dprintf("Pfindexec '%s'\n", aout);
+
if (P->execname)
return (P->execname); /* Already found */
@@ -99,7 +101,7 @@ Pfindexec(struct ps_prochandle *P, const char *aout,
* our subsequent attempts to locate the executable.
*/
if (aout != NULL && stat(aout, &st) == 0 && !S_ISDIR(st.st_mode)) {
- if (try_exec(".", aout, buf, isexec, isdata))
+ if (try_exec(P, ".", aout, buf, isexec, isdata))
goto found;
else
aout = ".";
@@ -127,17 +129,17 @@ Pfindexec(struct ps_prochandle *P, const char *aout,
char zpath[PATH_MAX];
const psinfo_t *pi = Ppsinfo(P);
- if (try_exec(cwd, path, buf, isexec, isdata))
+ if (try_exec(P, cwd, path, buf, isexec, isdata))
goto found;
if (strchr(path, '/') != NULL && (p = basename(path)) != NULL &&
- try_exec(cwd, p, buf, isexec, isdata))
+ try_exec(P, cwd, p, buf, isexec, isdata))
goto found;
if (getzoneid() == GLOBAL_ZONEID &&
pi->pr_zoneid != GLOBAL_ZONEID &&
zone_getattr(pi->pr_zoneid, ZONE_ATTR_ROOT, zpath,
- sizeof (zpath)) != -1) {
+ sizeof (zpath)) != -1) {
/*
* try_exec() only combines its cwd and path arguments
* if path is relative; but in our case even an absolute
@@ -147,7 +149,7 @@ Pfindexec(struct ps_prochandle *P, const char *aout,
* calling try_exec().
*/
p = (path[0] == '/') ? path + 1 : path;
- if (try_exec(zpath, p, buf, isexec, isdata))
+ if (try_exec(P, zpath, p, buf, isexec, isdata))
goto found;
}
}
@@ -163,11 +165,11 @@ Pfindexec(struct ps_prochandle *P, const char *aout,
if ((p = strchr(path, ' ')) != NULL)
*p = '\0';
- if (try_exec(cwd, path, buf, isexec, isdata))
+ if (try_exec(P, cwd, path, buf, isexec, isdata))
goto found;
if (strchr(path, '/') != NULL && (p = basename(path)) != NULL &&
- try_exec(cwd, p, buf, isexec, isdata))
+ try_exec(P, cwd, p, buf, isexec, isdata))
goto found;
}
@@ -179,11 +181,11 @@ Pfindexec(struct ps_prochandle *P, const char *aout,
Pread(P, &addr, sizeof (addr), P->psinfo.pr_argv) != -1 &&
Pread_string(P, path, sizeof (path), (off_t)addr) > 0) {
- if (try_exec(cwd, path, buf, isexec, isdata))
+ if (try_exec(P, cwd, path, buf, isexec, isdata))
goto found;
if (strchr(path, '/') != NULL && (p = basename(path)) != NULL &&
- try_exec(cwd, p, buf, isexec, isdata))
+ try_exec(P, cwd, p, buf, isexec, isdata))
goto found;
}
@@ -218,7 +220,7 @@ Pfindexec(struct ps_prochandle *P, const char *aout,
if (*p != '/')
continue; /* Ignore anything relative */
- if (try_exec(p, path, buf, isexec, isdata))
+ if (try_exec(P, p, path, buf, isexec, isdata))
goto found;
}
}
@@ -255,7 +257,12 @@ stat_exec(const char *path, struct stat64 *stp)
char *
Pexecname(struct ps_prochandle *P, char *buf, size_t buflen)
{
- if (P->execname == NULL && P->state != PS_DEAD && P->state != PS_IDLE) {
+ if (P->execname != NULL) {
+ (void) strncpy(buf, P->execname, buflen);
+ return (buf);
+ }
+
+ if (P->state != PS_DEAD && P->state != PS_IDLE) {
char exec_name[PATH_MAX];
char cwd[PATH_MAX];
char proc_cwd[64];
@@ -269,6 +276,7 @@ Pexecname(struct ps_prochandle *P, char *buf, size_t buflen)
"%s/%d/path/a.out", procfs_path, (int)P->pid);
if ((ret = readlink(exec_name, buf, buflen - 1)) > 0) {
buf[ret] = '\0';
+ (void) Pfindobj(P, buf, buf, buflen);
return (buf);
}
@@ -297,10 +305,5 @@ Pexecname(struct ps_prochandle *P, char *buf, size_t buflen)
(int (*)(const char *, void *))stat_exec, &st);
}
- if (P->execname != NULL) {
- (void) strncpy(buf, P->execname, buflen);
- return (buf);
- }
-
return (NULL);
}
diff --git a/usr/src/lib/libproc/common/Pidle.c b/usr/src/lib/libproc/common/Pidle.c
index 4e23112152..5562385ef5 100644
--- a/usr/src/lib/libproc/common/Pidle.c
+++ b/usr/src/lib/libproc/common/Pidle.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <libelf.h>
#include <libgen.h>
@@ -34,6 +31,7 @@
#include <errno.h>
#include <sys/sysmacros.h>
+#include "libproc.h"
#include "Pcontrol.h"
static ssize_t
@@ -111,6 +109,7 @@ struct ps_prochandle *
Pgrab_file(const char *fname, int *perr)
{
struct ps_prochandle *P = NULL;
+ char buf[PATH_MAX];
GElf_Ehdr ehdr;
Elf *elf = NULL;
size_t phnum;
@@ -183,10 +182,16 @@ Pgrab_file(const char *fname, int *perr)
fp->file_fd = fd;
fp->file_lo->rl_lmident = LM_ID_BASE;
- fp->file_lname = strdup(fp->file_pname);
+ if ((fp->file_lname = strdup(fp->file_pname)) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
fp->file_lbase = basename(fp->file_lname);
- P->execname = strdup(fp->file_pname);
+ if ((P->execname = strdup(fp->file_pname)) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
P->num_files++;
list_link(fp, &P->file_head);
@@ -236,6 +241,7 @@ Pgrab_file(const char *fname, int *perr)
P->status.pr_sid = (pid_t)-1;
P->status.pr_taskid = (taskid_t)-1;
P->status.pr_projid = (projid_t)-1;
+ P->status.pr_zoneid = (zoneid_t)-1;
switch (ehdr.e_ident[EI_CLASS]) {
case ELFCLASS32:
P->status.pr_dmodel = PR_MODEL_ILP32;
@@ -249,6 +255,18 @@ Pgrab_file(const char *fname, int *perr)
}
/*
+ * Pfindobj() checks what zone a process is associated with, so
+ * we call it after initializing pr_zoneid to -1. This ensures
+ * we don't get associated with any zone on the system.
+ */
+ if (Pfindobj(P, fp->file_lname, buf, sizeof (buf)) != NULL) {
+ free(P->execname);
+ P->execname = strdup(buf);
+ if ((fp->file_rname = strdup(buf)) != NULL)
+ fp->file_rbase = basename(fp->file_rname);
+ }
+
+ /*
* The file and map lists are complete, and will never need to be
* adjusted.
*/
diff --git a/usr/src/lib/libproc/common/Psymtab.c b/usr/src/lib/libproc/common/Psymtab.c
index 9b14931a18..ad14ec1a0e 100644
--- a/usr/src/lib/libproc/common/Psymtab.c
+++ b/usr/src/lib/libproc/common/Psymtab.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
@@ -41,7 +39,6 @@
#include <signal.h>
#include <limits.h>
#include <libgen.h>
-#include <zone.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/systeminfo.h>
@@ -269,6 +266,8 @@ file_info_free(struct ps_prochandle *P, file_info_t *fptr)
free(fptr->file_lo);
if (fptr->file_lname)
free(fptr->file_lname);
+ if (fptr->file_rname)
+ free(fptr->file_rname);
if (fptr->file_elf)
(void) elf_end(fptr->file_elf);
if (fptr->file_elfmem != NULL)
@@ -355,6 +354,12 @@ map_iter(const rd_loadobj_t *lop, void *cd)
if (fptr->file_lname) {
free(fptr->file_lname);
fptr->file_lname = NULL;
+ fptr->file_lbase = NULL;
+ }
+ if (fptr->file_rname) {
+ free(fptr->file_rname);
+ fptr->file_rname = NULL;
+ fptr->file_rbase = NULL;
}
if (Pread_string(P, buf, sizeof (buf), lop->rl_nameaddr) > 0) {
@@ -365,8 +370,12 @@ map_iter(const rd_loadobj_t *lop, void *cd)
(void *)lop->rl_nameaddr);
}
+ if ((Pfindmap(P, mptr, buf, sizeof (buf)) != NULL) &&
+ ((fptr->file_rname = strdup(buf)) != NULL))
+ fptr->file_rbase = basename(fptr->file_rname);
+
dprintf("loaded rd object %s lmid %lx\n",
- fptr->file_lname ? fptr->file_lname : "<NULL>", lop->rl_lmident);
+ fptr->file_lname ? buf : "<NULL>", lop->rl_lmident);
return (1);
}
@@ -395,9 +404,15 @@ map_set(struct ps_prochandle *P, map_info_t *mptr, const char *lname)
fptr->file_lo->rl_plt_base = fptr->file_plt_base;
fptr->file_lo->rl_plt_size = fptr->file_plt_size;
- if (fptr->file_lname == NULL &&
+ if ((fptr->file_lname == NULL) &&
(fptr->file_lname = strdup(lname)) != NULL)
fptr->file_lbase = basename(fptr->file_lname);
+
+ /*
+ * Don't bother to set file_rname/file_rbase since lname is really
+ * just a token name (either "a.out" or "ld.so.1") and not a real
+ * filesystem object path.
+ */
}
static void
@@ -1610,6 +1625,7 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
}
if (P->state == PS_DEAD || P->state == PS_IDLE) {
+ char *name;
/*
* If we're a not live, we can't open files from the /proc
* object directory; we have only the mapping and file names
@@ -1617,9 +1633,18 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
* the case of it being NULL in order to bootstrap: we first
* come here during rd_new() when the only information we have
* is interpreter name associated with the AT_BASE mapping.
+ *
+ * Also, if the zone associated with the core file seems
+ * to exists on this machine we'll try to open the object
+ * file within the zone.
*/
- (void) snprintf(objectfile, sizeof (objectfile), "%s",
- fptr->file_lname ? fptr->file_lname : fptr->file_pname);
+ if (fptr->file_rname != NULL)
+ name = fptr->file_rname;
+ else if (fptr->file_lname != NULL)
+ name = fptr->file_lname;
+ else
+ name = fptr->file_pname;
+ (void) strlcpy(objectfile, name, sizeof (objectfile));
} else {
(void) snprintf(objectfile, sizeof (objectfile),
"%s/%d/object/%s",
@@ -2027,7 +2052,8 @@ object_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *objname)
for (i = 0, mp = P->mappings; i < P->map_count; i++, mp++) {
if (mp->map_pmap.pr_mapname[0] == '\0' ||
- (fp = mp->map_file) == NULL || fp->file_lname == NULL)
+ (fp = mp->map_file) == NULL ||
+ ((fp->file_lname == NULL) && (fp->file_rname == NULL)))
continue;
if (lmid != PR_LMID_EVERY &&
@@ -2038,8 +2064,10 @@ object_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *objname)
* If we match, return the primary text mapping; otherwise
* just return the mapping we matched.
*/
- if (strcmp(fp->file_lname, objname) == 0 ||
- strcmp(fp->file_lbase, objname) == 0)
+ if ((fp->file_lbase && strcmp(fp->file_lbase, objname) == 0) ||
+ (fp->file_rbase && strcmp(fp->file_rbase, objname) == 0) ||
+ (fp->file_lname && strcmp(fp->file_lname, objname) == 0) ||
+ (fp->file_rname && strcmp(fp->file_rname, objname) == 0))
return (fp->file_map ? fp->file_map : mp);
}
@@ -2051,7 +2079,8 @@ object_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *objname)
for (i = 0, mp = P->mappings; i < P->map_count; i++, mp++) {
if (mp->map_pmap.pr_mapname[0] == '\0' ||
- (fp = mp->map_file) == NULL || fp->file_lname == NULL)
+ (fp = mp->map_file) == NULL ||
+ ((fp->file_lname == NULL) && (fp->file_rname == NULL)))
continue;
if (lmid != PR_LMID_EVERY &&
@@ -2062,8 +2091,13 @@ object_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *objname)
* If we match, return the primary text mapping; otherwise
* just return the mapping we matched.
*/
- if (strncmp(fp->file_lbase, objname, objlen) == 0 &&
- fp->file_lbase[objlen] == '.')
+ if ((fp->file_lbase != NULL) &&
+ (strncmp(fp->file_lbase, objname, objlen) == 0) &&
+ (fp->file_lbase[objlen] == '.'))
+ return (fp->file_map ? fp->file_map : mp);
+ if ((fp->file_rbase != NULL) &&
+ (strncmp(fp->file_rbase, objname, objlen) == 0) &&
+ (fp->file_rbase[objlen] == '.'))
return (fp->file_map ? fp->file_map : mp);
}
@@ -2344,9 +2378,10 @@ sym_by_name(sym_tbl_t *symtab, const char *name, GElf_Sym *symp, uint_t *idp)
* prsyminfo_t ancillary symbol information
* Returns 0 on success, -1 on failure.
*/
-int
-Pxlookup_by_addr(
+static int
+i_Pxlookup_by_addr(
struct ps_prochandle *P,
+ int lmresolve, /* use resolve linker object names */
uintptr_t addr, /* process address being sought */
char *sym_name_buffer, /* buffer for the symbol name */
size_t bufsize, /* size of sym_name_buffer */
@@ -2397,7 +2432,10 @@ Pxlookup_by_addr(
*symbolp = *symp;
if (sip != NULL) {
sip->prs_name = bufsize == 0 ? NULL : sym_name_buffer;
- sip->prs_object = fptr->file_lbase;
+ if (lmresolve && (fptr->file_rname != NULL))
+ sip->prs_object = fptr->file_rbase;
+ else
+ sip->prs_object = fptr->file_lbase;
sip->prs_id = (symp == sym1p) ? i1 : i2;
sip->prs_table = (symp == sym1p) ? PR_SYMTAB : PR_DYNSYM;
sip->prs_lmid = (fptr->file_lo == NULL) ? LM_ID_BASE :
@@ -2411,10 +2449,24 @@ Pxlookup_by_addr(
}
int
-Plookup_by_addr(struct ps_prochandle *P, uintptr_t addr, char *buf, size_t size,
- GElf_Sym *symp)
+Pxlookup_by_addr(struct ps_prochandle *P, uintptr_t addr, char *buf,
+ size_t bufsize, GElf_Sym *symp, prsyminfo_t *sip)
+{
+ return (i_Pxlookup_by_addr(P, B_FALSE, addr, buf, bufsize, symp, sip));
+}
+
+int
+Pxlookup_by_addr_resolved(struct ps_prochandle *P, uintptr_t addr, char *buf,
+ size_t bufsize, GElf_Sym *symp, prsyminfo_t *sip)
+{
+ return (i_Pxlookup_by_addr(P, B_TRUE, addr, buf, bufsize, symp, sip));
+}
+
+int
+Plookup_by_addr(struct ps_prochandle *P, uintptr_t addr, char *buf,
+ size_t size, GElf_Sym *symp)
{
- return (Pxlookup_by_addr(P, addr, buf, size, symp, NULL));
+ return (i_Pxlookup_by_addr(P, B_FALSE, addr, buf, size, symp, NULL));
}
/*
@@ -2531,8 +2583,9 @@ Plookup_by_name(struct ps_prochandle *P, const char *object,
/*
* Iterate over the process's address space mappings.
*/
-int
-Pmapping_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
+static int
+i_Pmapping_iter(struct ps_prochandle *P, boolean_t lmresolve,
+ proc_map_f *func, void *cd)
{
map_info_t *mptr;
file_info_t *fptr;
@@ -2546,6 +2599,8 @@ Pmapping_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
for (i = 0, mptr = P->mappings; i < P->map_count; i++, mptr++) {
if ((fptr = mptr->map_file) == NULL)
object_name = NULL;
+ else if (lmresolve && (fptr->file_rname != NULL))
+ object_name = fptr->file_rname;
else
object_name = fptr->file_lname;
if ((rc = func(cd, &mptr->map_pmap, object_name)) != 0)
@@ -2554,11 +2609,24 @@ Pmapping_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
return (0);
}
+int
+Pmapping_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
+{
+ return (i_Pmapping_iter(P, B_FALSE, func, cd));
+}
+
+int
+Pmapping_iter_resolved(struct ps_prochandle *P, proc_map_f *func, void *cd)
+{
+ return (i_Pmapping_iter(P, B_TRUE, func, cd));
+}
+
/*
* Iterate over the process's mapped objects.
*/
-int
-Pobject_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
+static int
+i_Pobject_iter(struct ps_prochandle *P, boolean_t lmresolve,
+ proc_map_f *func, void *cd)
{
map_info_t *mptr;
file_info_t *fptr;
@@ -2570,8 +2638,14 @@ Pobject_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
for (cnt = P->num_files, fptr = list_next(&P->file_head);
cnt; cnt--, fptr = list_next(fptr)) {
+ const char *lname;
- const char *lname = fptr->file_lname ? fptr->file_lname : "";
+ if (lmresolve && (fptr->file_rname != NULL))
+ lname = fptr->file_rname;
+ else if (fptr->file_lname != NULL)
+ lname = fptr->file_lname;
+ else
+ lname = "";
if ((mptr = fptr->file_map) == NULL)
continue;
@@ -2582,13 +2656,20 @@ Pobject_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
return (0);
}
-/*
- * Given a virtual address, return the name of the underlying
- * mapped object (file), as provided by the dynamic linker.
- * Return NULL on failure (no underlying shared library).
- */
-char *
-Pobjname(struct ps_prochandle *P, uintptr_t addr,
+int
+Pobject_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
+{
+ return (i_Pobject_iter(P, B_FALSE, func, cd));
+}
+
+int
+Pobject_iter_resolved(struct ps_prochandle *P, proc_map_f *func, void *cd)
+{
+ return (i_Pobject_iter(P, B_TRUE, func, cd));
+}
+
+static char *
+i_Pobjname(struct ps_prochandle *P, boolean_t lmresolve, uintptr_t addr,
char *buffer, size_t bufsize)
{
map_info_t *mptr;
@@ -2597,18 +2678,52 @@ Pobjname(struct ps_prochandle *P, uintptr_t addr,
/* create all the file_info_t's for all the mappings */
(void) Prd_agent(P);
- if ((mptr = Paddr2mptr(P, addr)) != NULL &&
- (fptr = mptr->map_file) != NULL &&
- fptr->file_lname != NULL) {
- (void) strncpy(buffer, fptr->file_lname, bufsize);
- if (strlen(fptr->file_lname) >= bufsize)
- buffer[bufsize-1] = '\0';
+ if ((mptr = Paddr2mptr(P, addr)) == NULL)
+ return (NULL);
+
+ if (!lmresolve) {
+ if (((fptr = mptr->map_file) == NULL) ||
+ (fptr->file_lname == NULL))
+ return (NULL);
+ (void) strlcpy(buffer, fptr->file_lname, bufsize);
return (buffer);
}
+
+ /* Check for a cached copy of the resolved path */
+ if (Pfindmap(P, mptr, buffer, bufsize) != NULL)
+ return (buffer);
+
return (NULL);
}
/*
+ * Given a virtual address, return the name of the underlying
+ * mapped object (file) as provided by the dynamic linker.
+ * Return NULL if we can't find any name information for the object.
+ */
+char *
+Pobjname(struct ps_prochandle *P, uintptr_t addr,
+ char *buffer, size_t bufsize)
+{
+ return (i_Pobjname(P, B_FALSE, addr, buffer, bufsize));
+}
+
+/*
+ * Given a virtual address, try to return a filesystem path to the
+ * underlying mapped object (file). If we're in the global zone,
+ * this path could resolve to an object in another zone. If we're
+ * unable return a valid filesystem path, we'll fall back to providing
+ * the mapped object (file) name provided by the dynamic linker in
+ * the target process (ie, the object reported by Pobjname()).
+ */
+char *
+Pobjname_resolved(struct ps_prochandle *P, uintptr_t addr,
+ char *buffer, size_t bufsize)
+{
+ return (i_Pobjname(P, B_TRUE, addr, buffer, bufsize));
+}
+
+/*
* Given a virtual address, return the link map id of the underlying mapped
* object (file), as provided by the dynamic linker. Return -1 on failure.
*/
@@ -2846,32 +2961,6 @@ Puname(struct ps_prochandle *P, struct utsname *u)
}
/*
- * Get the zone name from the core file if we have it; look up the
- * name based on the zone id if this is a live process.
- */
-char *
-Pzonename(struct ps_prochandle *P, char *s, size_t n)
-{
- if (P->state == PS_IDLE) {
- errno = ENODATA;
- return (NULL);
- }
-
- if (P->state == PS_DEAD) {
- if (P->core->core_zonename == NULL) {
- errno = ENODATA;
- return (NULL);
- }
- (void) strlcpy(s, P->core->core_zonename, n);
- } else {
- if (getzonenamebyid(P->status.pr_zoneid, s, n) < 0)
- return (NULL);
- s[n - 1] = '\0';
- }
- return (s);
-}
-
-/*
* Called from Pcreate(), Pgrab(), and Pfgrab_core() to initialize
* the symbol table heads in the new ps_prochandle.
*/
diff --git a/usr/src/lib/libproc/common/Pzone.c b/usr/src/lib/libproc/common/Pzone.c
new file mode 100644
index 0000000000..c4023c2301
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pzone.c
@@ -0,0 +1,748 @@
+/*
+ * 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.
+ */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <libzonecfg.h>
+#include <link.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/list.h>
+#include <sys/types.h>
+#include <sys/mkdev.h>
+#include <sys/mman.h>
+#include <sys/mnttab.h>
+
+#include "Pcontrol.h"
+
+struct path_node {
+ struct path_node *pn_next;
+ char *pn_path;
+};
+typedef struct path_node path_node_t;
+
+static path_node_t *
+pn_push(path_node_t **pnp, char *path)
+{
+ path_node_t *pn;
+
+ if ((pn = calloc(sizeof (path_node_t), 1)) == NULL)
+ return (NULL);
+
+ if ((pn->pn_path = strdup(path)) == NULL) {
+ free(pn);
+ return (NULL);
+ }
+ pn->pn_next = *pnp;
+ return (*pnp = pn);
+}
+
+static void
+pn_free(path_node_t **pnp)
+{
+ path_node_t *pn;
+
+ while (*pnp != NULL) {
+ pn = *pnp;
+ *pnp = pn->pn_next;
+ free(pn->pn_path);
+ free(pn);
+ }
+}
+
+static void
+pn_free2(path_node_t **pn1, path_node_t **pn2)
+{
+ pn_free(pn1);
+ pn_free(pn2);
+}
+
+static char *
+pn_pop(path_node_t **pnp, char *path)
+{
+ path_node_t *pn;
+
+ if (*pnp == NULL)
+ return (NULL);
+
+ pn = *pnp;
+ *pnp = pn->pn_next;
+ pn->pn_next = NULL;
+
+ if (path == NULL) {
+ pn_free(&pn);
+ return (NULL);
+ }
+ (void) strlcpy(path, pn->pn_path, PATH_MAX);
+ pn_free(&pn);
+ return (path);
+}
+
+
+/*
+ * Libzonecfg.so links against libproc, so libproc can't link against
+ * libzonecfg.so. Also, libzonecfg.so is optional and might not be
+ * installed. Hence instead of relying on linking to access libzonecfg.so,
+ * we'll try dlopening it here. This trick is borrowed from
+ * libc`zone_get_id(), see that function for more detailed comments.
+ */
+static int
+i_zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
+{
+ typedef int (*zone_get_zonepath_t)(char *, char *, size_t);
+ static zone_get_zonepath_t zone_get_zonepath_fp = NULL;
+
+ if (zone_get_zonepath_fp == NULL) {
+ /* There's no harm in doing this multiple times. */
+ void *dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY);
+ void *sym = (void *)(-1);
+ if (dlhandle != NULL &&
+ (sym = dlsym(dlhandle, "zone_get_zonepath")) == NULL) {
+ sym = (void *)(-1);
+ (void) dlclose(dlhandle);
+ }
+ zone_get_zonepath_fp = (zone_get_zonepath_t)sym;
+ }
+
+ /* If we've successfully loaded it, call the real function */
+ if (zone_get_zonepath_fp != (zone_get_zonepath_t)(-1))
+ return (zone_get_zonepath_fp(zone_name, zonepath, rp_sz));
+ return (Z_NO_ZONE);
+}
+
+char *
+Pbrandname(struct ps_prochandle *P, char *buf, size_t buflen)
+{
+ long addr;
+
+ if ((addr = Pgetauxval(P, AT_SUN_BRANDNAME)) == -1)
+ return (NULL);
+
+ if (Pread_string(P, buf, buflen, addr) == -1)
+ return (NULL);
+
+ return (buf);
+}
+
+/*
+ * Get the zone name from the core file if we have it; look up the
+ * name based on the zone id if this is a live process.
+ */
+char *
+Pzonename(struct ps_prochandle *P, char *s, size_t n)
+{
+ if (P->state == PS_IDLE) {
+ errno = ENODATA;
+ return (NULL);
+ }
+
+ if (P->state == PS_DEAD) {
+ if (P->core->core_zonename == NULL) {
+ errno = ENODATA;
+ return (NULL);
+ }
+ (void) strlcpy(s, P->core->core_zonename, n);
+ } else {
+ if (getzonenamebyid(P->status.pr_zoneid, s, n) < 0)
+ return (NULL);
+ s[n - 1] = '\0';
+ }
+ return (s);
+}
+
+char *
+Pzoneroot(struct ps_prochandle *P, char *s, size_t n)
+{
+ char zname[ZONENAME_MAX], zpath[PATH_MAX], tmp[PATH_MAX];
+ int rv;
+
+ if (P->zoneroot != NULL) {
+ (void) strlcpy(s, P->zoneroot, n);
+ return (s);
+ }
+
+ if ((Pzonename(P, zname, sizeof (zname)) == NULL) ||
+ (strcmp(zname, GLOBAL_ZONENAME) == 0)) {
+ if ((P->zoneroot = strdup("")) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ dprintf("Pzoneroot defaulting to '%s'\n", GLOBAL_ZONENAME);
+ (void) strlcpy(s, P->zoneroot, n);
+ return (s);
+ }
+
+ if (i_zone_get_zonepath(zname, zpath, sizeof (zpath)) != Z_OK) {
+ if ((P->zoneroot = strdup("")) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ dprintf(
+ "Pzoneroot zone not found '%s', defaulting to '%s'\n",
+ zname, GLOBAL_ZONENAME);
+ (void) strlcpy(s, P->zoneroot, n);
+ return (s);
+ }
+ (void) strlcat(zpath, "/root", sizeof (zpath));
+
+ if ((rv = resolvepath(zpath, tmp, sizeof (tmp) - 1)) < 0) {
+ if ((P->zoneroot = strdup("")) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ dprintf(
+ "Pzoneroot can't access '%s:%s', defaulting to '%s'\n",
+ zname, zpath, GLOBAL_ZONENAME);
+ (void) strlcpy(s, P->zoneroot, n);
+ return (s);
+ }
+ tmp[rv] = '\0';
+ (void) strlcpy(zpath, tmp, sizeof (zpath));
+
+ if ((P->zoneroot = strdup(zpath)) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ dprintf("Pzoneroot found zone root '%s:%s'\n", zname, zpath);
+ (void) strlcpy(s, P->zoneroot, n);
+ return (s);
+}
+
+/*
+ * Plofspath() takes a path, "path", and removes any lofs components from
+ * that path. The resultant path (if different from the starting path)
+ * is placed in "s", which is limited to "n" characters, and the return
+ * value is the pointer s. If there are no lofs components in the path
+ * the NULL is returned and s is not modified. It's ok for "path" and
+ * "s" to be the same pointer. (ie, the results can be stored directly
+ * in the input buffer.) The path that is passed in must be an absolute
+ * path.
+ *
+ * Example:
+ * if "path" == "/foo/bar", and "/candy/" is lofs mounted on "/foo/"
+ * then "/candy/bar/" will be written into "s" and "s" will be returned.
+ */
+char *
+Plofspath(const char *path, char *s, size_t n)
+{
+ char tmp[PATH_MAX + 1];
+ struct mnttab mt, mt_find;
+ FILE *fp;
+ char *p, *p2;
+ int rv;
+
+ dprintf("Plofspath path '%s'\n", path);
+
+ /* We only deal with absolute paths */
+ if (path[0] != '/')
+ return (NULL);
+
+ /* Open /etc/mnttab */
+ if ((fp = fopen(MNTTAB, "r")) == NULL)
+ return (NULL);
+
+ /* Make a copy of the path so that we can muck with it */
+ (void) strlcpy(tmp, path, sizeof (tmp) - 1);
+
+ /*
+ * Use resolvepath() to make sure there are no consecutive or
+ * trailing '/'s in the path.
+ */
+ if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
+ tmp[rv] = '\0';
+
+ /*
+ * So now we're going to search the path for any components that
+ * might be lofs mounts. We'll start out search from the full
+ * path and then step back through each parent directly till
+ * we reach the root. If we find a lofs mount point in the path
+ * then we'll replace the initial portion of the path (up
+ * to that mount point) with the source of that mount point
+ * and then start our search over again.
+ *
+ * Here's some of the variables we're going to use:
+ *
+ * tmp - A pointer to our working copy of the path. Sometimes
+ * this path will be divided into two strings by a
+ * '\0' (NUL) character. The first string is the
+ * component we're currently checking and the second
+ * string is the path components we've already checked.
+ *
+ * p - A pointer to the last '/' seen in the string.
+ *
+ * p[1] - A pointer to the component of the string we've already
+ * checked.
+ *
+ * Initially, p will point to the end of our path and p[1] will point
+ * to an extra '\0' (NUL) that we'll append to the end of the string.
+ * (This is why we declared tmp with a size of PATH_MAX + 1).
+ */
+ p = &tmp[strlen(tmp)];
+ p[1] = '\0';
+ for (;;) {
+ /* Check if tmp is a mount point */
+ rewind(fp);
+ bzero(&mt_find, sizeof (mt_find));
+ mt_find.mnt_mountp = tmp;
+ rv = getmntany(fp, &mt, &mt_find);
+
+ /* We only care about lofs mount points */
+ if ((rv == 0) && (strcmp(mt.mnt_fstype, "lofs") == 0)) {
+ char tmp2[PATH_MAX + 1];
+
+ /*
+ * We found a lofs mount. Update the path that we're
+ * checking and start over. This means append the
+ * portion of the path we've already checked to the
+ * source of the lofs mount and re-start this entire
+ * lofs resolution loop. Use resolvepath() to make
+ * sure there are no consecutive or trailing '/'s
+ * in the path.
+ */
+ (void) strlcpy(tmp2, mt.mnt_special, sizeof (tmp2) - 1);
+ (void) strlcat(tmp2, "/", sizeof (tmp2) - 1);
+ (void) strlcat(tmp2, &p[1], sizeof (tmp2) - 1);
+ (void) strlcpy(tmp, tmp2, sizeof (tmp) - 1);
+ if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
+ tmp[rv] = '\0';
+ p = &tmp[strlen(tmp)];
+ p[1] = '\0';
+ continue;
+ }
+
+ /* No lofs mount found */
+ if ((p2 = strrchr(tmp, '/')) == NULL) {
+ char tmp2[PATH_MAX];
+
+ /*
+ * We know that tmp was an absolute path, so if we
+ * made it here we know that (p == tmp) and that
+ * (*p == '\0'). This means that we've managed
+ * to check the whole path and so we're done.
+ */
+ assert(p == tmp);
+ assert(p[0] == '\0');
+ (void) fclose(fp);
+
+ /* Restore the leading '/' in the path */
+ p[0] = '/';
+
+ if (strcmp(tmp, path) == 0) {
+ /* The path didn't change */
+ return (NULL);
+ }
+
+ /*
+ * It's possible that lofs source path we just
+ * obtained contains a symbolic link. Use
+ * resolvepath() to clean it up.
+ */
+ (void) strlcpy(tmp2, tmp, sizeof (tmp2));
+ if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
+ tmp[rv] = '\0';
+
+ /*
+ * It's always possible that our lofs source path is
+ * actually another lofs mount. So call ourselves
+ * recursively to resolve that path.
+ */
+ (void) Plofspath(tmp, tmp, PATH_MAX);
+
+ /* Copy out our final resolved lofs source path */
+ (void) strlcpy(s, tmp, n);
+ dprintf("Plofspath path result '%s'\n", s);
+ return (s);
+ }
+
+ /*
+ * So the path we just checked is not a lofs mount. Next we
+ * want to check the parent path component for a lofs mount.
+ *
+ * First, restore any '/' that we replaced with a '\0' (NUL).
+ * We can determine if we should do this by looking at p[1].
+ * If p[1] points to a '\0' (NUL) then we know that p points
+ * to the end of the string and there is no '/' to restore.
+ * if p[1] doesn't point to a '\0' (NUL) then it points to
+ * the part of the path that we've already verified so there
+ * is a '/' to restore.
+ */
+ if (p[1] != '\0')
+ p[0] = '/';
+
+ /*
+ * Second, replace the last '/' in the part of the path
+ * that we've already checked with a '\0' (NUL) so that
+ * when we loop around we check the parent component of the
+ * path.
+ */
+ p2[0] = '\0';
+ p = p2;
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * Pzonepath() - Way too much code to attempt to derive the full path of
+ * an object within a zone.
+ *
+ * Pzonepath() takes a path and attempts to resolve it relative to the
+ * root associated with the current process handle. If it fails it will
+ * not update the results string. It is safe to specify the same pointer
+ * for the file string and the results string.
+ *
+ * Doing this resolution is more difficult than it initially sounds.
+ * We can't simply append the file path to the zone root, because in
+ * a root directory, '..' is treated the same as '.'. Also, symbolic
+ * links that specify an absolute path need to be interpreted relative
+ * to the zone root.
+ *
+ * It seems like perhaps we could do a chroot(<zone root>) followed by a
+ * resolvepath(). But we can't do this because chroot requires special
+ * privileges and affects the entire process. Perhaps if there was a
+ * special version of resolvepath() which took an addition root path
+ * we could use that, but this isn't ideal either. The reason is
+ * that we want to have special handling for native paths. (A native path
+ * is a path that begins with "/native/" or "/.SUNWnative/".) Native
+ * paths could be passed explicity to this function or could be embedded
+ * in a symlink that is part of the path passed into this function.
+ * These paths are always lofs mounts of global zone paths, but lofs
+ * mounts only exist when a zone is booted. So if we were to try to do
+ * a resolvepath() on a native path when the zone wasn't booted the
+ * resolvepath() would fail even though we know that the components
+ * exists in the global zone.
+ *
+ * Given all these constraints, we just implement a path walking function
+ * that resolves a file path relative to a zone root by manually inspecting
+ * each of the path components and verifying its existence. This means that
+ * we must have access to the zone and that all the components of the
+ * path must exist for this operation to succeed.
+ */
+char *
+Pzonepath(struct ps_prochandle *P, const char *path, char *s, size_t n)
+{
+ char zroot[PATH_MAX], zpath[PATH_MAX], tmp[PATH_MAX], link[PATH_MAX];
+ path_node_t *pn_stack = NULL, *pn_links = NULL, *pn;
+ struct stat64 sb;
+ char *p;
+ int i, rv;
+
+ dprintf("Pzonepath lookup '%s'\n", path);
+
+ /* First lookup the zone root */
+ if (Pzoneroot(P, zroot, sizeof (zroot)) == NULL)
+ return (NULL);
+
+ /*
+ * Make a temporary copy of the path specified.
+ * If it's a relative path then make it into an absolute path.
+ */
+ tmp[0] = '\0';
+ if (path[0] != '/')
+ (void) strlcat(tmp, "/", sizeof (tmp));
+ (void) strlcat(tmp, path, sizeof (tmp));
+
+ /*
+ * If the path that was passed in is the zone root, we're done.
+ * If the path that was passed in already contains the zone root
+ * then strip the zone root out and verify the rest of the path.
+ */
+ if (strcmp(tmp, zroot) == 0) {
+ (void) Plofspath(zroot, zroot, sizeof (zroot));
+ dprintf("Pzonepath found zone path (1) '%s'\n", zroot);
+ (void) strlcpy(s, zroot, n);
+ return (s);
+ }
+ i = strlen(zroot);
+ if ((strncmp(tmp, zroot, i) == 0) && (tmp[i] == '/'))
+ (void) memmove(tmp, tmp + i, strlen(tmp + i) + 1);
+
+ /* If no path is passed in, then it maps to the zone root */
+ if (strlen(tmp) == 0) {
+ (void) Plofspath(zroot, zroot, sizeof (zroot));
+ dprintf("Pzonepath found zone path (2) '%s'\n", zroot);
+ (void) strlcpy(s, zroot, n);
+ return (s);
+ }
+
+ /*
+ * Push each path component that we plan to verify onto a stack of
+ * path components, with parent components at the top of the stack.
+ * So for example, if we're going to verify the path /foo/bar/bang
+ * then our stack will look like:
+ * foo (top)
+ * bar
+ * bang (bottom)
+ */
+ while ((p = strrchr(tmp, '/')) != NULL) {
+ *p = '\0';
+ if (pn_push(&pn_stack, &p[1]) != NULL)
+ continue;
+ pn_free(&pn_stack);
+ return (NULL);
+ }
+
+ /* We're going to store the final zone relative path in zpath */
+ *zpath = '\0';
+
+ while (pn_pop(&pn_stack, tmp) != NULL) {
+ /*
+ * Drop zero length path components (which come from
+ * consecutive '/'s) and '.' path components.
+ */
+ if ((strlen(tmp) == 0) || (strcmp(tmp, ".") == 0))
+ continue;
+
+ /*
+ * Check the current path component for '..', if found
+ * drop any previous path component.
+ */
+ if (strcmp(tmp, "..") == 0) {
+ if ((p = strrchr(zpath, '/')) != NULL)
+ *p = '\0';
+ continue;
+ }
+
+ /* The path we want to verify now is zpath + / + tmp. */
+ (void) strlcat(zpath, "/", sizeof (zpath));
+ (void) strlcat(zpath, tmp, sizeof (zpath));
+
+ /*
+ * Check if this is a native object. A native object is an
+ * object from the global zone that is running in a branded
+ * zone. These objects are lofs mounted into a zone. So if a
+ * branded zone is not booted then lofs mounts won't be setup
+ * so we won't be able to find these objects. Luckily, we know
+ * that they exist in the global zone with the same path sans
+ * the initial native component, so we'll just strip out the
+ * native component here.
+ */
+ if ((strncmp(zpath, "/native", sizeof ("/native")) == 0) ||
+ (strncmp(zpath, "/.SUNWnative",
+ sizeof ("/.SUNWnative")) == 0)) {
+
+ /* Free any cached symlink paths */
+ pn_free(&pn_links);
+
+ /* Reconstruct the path from our path component stack */
+ *zpath = '\0';
+ while (pn_pop(&pn_stack, tmp) != NULL) {
+ (void) strlcat(zpath, "/", sizeof (zpath));
+ (void) strlcat(zpath, tmp, sizeof (zpath));
+ }
+
+ /* Verify that the path actually exists */
+ rv = resolvepath(zpath, tmp, sizeof (tmp) - 1);
+ if (rv < 0) {
+ dprintf("Pzonepath invalid native path '%s'\n",
+ zpath);
+ return (NULL);
+ }
+ tmp[rv] = '\0';
+
+ /* Return the path */
+ dprintf("Pzonepath found native path '%s'\n", tmp);
+ (void) Plofspath(tmp, tmp, sizeof (tmp));
+ (void) strlcpy(s, tmp, n);
+ return (s);
+ }
+
+ /*
+ * Check if the path points to a symlink. We do this
+ * explicitly since any absolute symlink needs to be
+ * interpreted relativly to the zone root and not "/".
+ */
+ (void) strlcpy(tmp, zroot, sizeof (tmp));
+ (void) strlcat(tmp, zpath, sizeof (tmp));
+ if (lstat64(tmp, &sb) != 0) {
+ pn_free2(&pn_stack, &pn_links);
+ return (NULL);
+ }
+ if (!S_ISLNK(sb.st_mode)) {
+ /*
+ * Since the lstat64() above succeeded we know that
+ * zpath exists, since this is not a symlink loop
+ * around and check the next path component.
+ */
+ continue;
+ }
+
+ /*
+ * Symlink allow for paths with loops. Make sure
+ * we're not stuck in a loop.
+ */
+ for (pn = pn_links; pn != NULL; pn = pn->pn_next) {
+ if (strcmp(zpath, pn->pn_path) != 0)
+ continue;
+
+ /* We have a loop. Fail. */
+ dprintf("Pzonepath symlink loop '%s'\n", zpath);
+ pn_free2(&pn_stack, &pn_links);
+ return (NULL);
+ }
+
+ /* Save this symlink path for future loop checks */
+ if (pn_push(&pn_links, zpath) == NULL) {
+ /* Out of memory */
+ pn_free2(&pn_stack, &pn_links);
+ return (NULL);
+ }
+
+ /* Now follow the contents of the symlink */
+ bzero(link, sizeof (link));
+ if (readlink(tmp, link, sizeof (link)) == -1) {
+ pn_free2(&pn_stack, &pn_links);
+ return (NULL);
+ }
+
+ dprintf("Pzonepath following symlink '%s' -> '%s'\n",
+ zpath, link);
+
+ /*
+ * Push each path component of the symlink target onto our
+ * path components stack since we need to verify each one.
+ */
+ while ((p = strrchr(link, '/')) != NULL) {
+ *p = '\0';
+ if (pn_push(&pn_stack, &p[1]) != NULL)
+ continue;
+ pn_free2(&pn_stack, &pn_links);
+ return (NULL);
+ }
+
+ /* absolute or relative symlink? */
+ if (*link == '\0') {
+ /* Absolute symlink, nuke existing zpath. */
+ *zpath = '\0';
+ continue;
+ }
+
+ /*
+ * Relative symlink. Push the first path component of the
+ * symlink target onto our stack for verification and then
+ * remove the current path component from zpath.
+ */
+ if (pn_push(&pn_stack, link) == NULL) {
+ pn_free2(&pn_stack, &pn_links);
+ return (NULL);
+ }
+ p = strrchr(zpath, '/');
+ assert(p != NULL);
+ *p = '\0';
+ continue;
+ }
+ pn_free(&pn_links);
+
+ /* Place the final result in zpath */
+ (void) strlcpy(tmp, zroot, sizeof (tmp));
+ (void) strlcat(tmp, zpath, sizeof (tmp));
+ (void) strlcpy(zpath, tmp, sizeof (zpath));
+
+ (void) Plofspath(zpath, zpath, sizeof (zpath));
+ dprintf("Pzonepath found zone path (3) '%s'\n", zpath);
+
+ (void) strlcpy(s, zpath, n);
+ return (s);
+}
+
+char *
+Pfindobj(struct ps_prochandle *P, const char *path, char *s, size_t n)
+{
+ int len;
+
+ dprintf("Pfindobj '%s'\n", path);
+
+ /* We only deal with absolute paths */
+ if (path[0] != '/')
+ return (NULL);
+
+ /* First try to resolve the path to some zone */
+ if (Pzonepath(P, path, s, n) != NULL)
+ return (s);
+
+ /* If that fails resolve any lofs links in the path */
+ if (Plofspath(path, s, n) != NULL)
+ return (s);
+
+ /* If that fails then just see if the path exists */
+ if ((len = resolvepath(path, s, n)) > 0) {
+ s[len] = '\0';
+ return (s);
+ }
+
+ return (NULL);
+}
+
+char *
+Pfindmap(struct ps_prochandle *P, map_info_t *mptr, char *s, size_t n)
+{
+ file_info_t *fptr = mptr->map_file;
+ char buf[PATH_MAX];
+ int len;
+
+ /* If it's already been explicity set return that */
+ if ((fptr != NULL) && (fptr->file_rname != NULL)) {
+ (void) strlcpy(s, fptr->file_rname, n);
+ return (s);
+ }
+
+ /* If it's the a.out segment, defer to the magical Pexecname() */
+ if ((P->map_exec == mptr) ||
+ (strcmp(mptr->map_pmap.pr_mapname, "a.out") == 0) ||
+ ((fptr != NULL) && (fptr->file_lname != NULL) &&
+ (strcmp(fptr->file_lname, "a.out") == 0))) {
+ (void) Pexecname(P, buf, sizeof (buf));
+ (void) strlcpy(s, buf, n);
+ return (s);
+ }
+
+ /* Try /proc first to get the real object name */
+ if ((Pstate(P) != PS_DEAD) && (mptr->map_pmap.pr_mapname[0] != '\0')) {
+ (void) snprintf(buf, sizeof (buf), "%s/%d/path/%s",
+ procfs_path, (int)P->pid, mptr->map_pmap.pr_mapname);
+ if ((len = readlink(buf, buf, sizeof (buf))) > 0) {
+ buf[len] = '\0';
+ (void) Plofspath(buf, buf, sizeof (buf));
+ (void) strlcpy(s, buf, n);
+ return (s);
+ }
+ }
+
+ /*
+ * If we couldn't get the name from /proc, take the lname and
+ * try to expand it on the current system to a real object path.
+ */
+ fptr = mptr->map_file;
+ if ((fptr != NULL) && (fptr->file_lname != NULL)) {
+ (void) strlcpy(buf, fptr->file_lname, sizeof (buf));
+ if (Pfindobj(P, buf, buf, sizeof (buf)) == NULL)
+ return (NULL);
+ (void) strlcpy(s, buf, n);
+ return (s);
+ }
+
+ return (NULL);
+}
diff --git a/usr/src/lib/libproc/common/libproc.h b/usr/src/lib/libproc/common/libproc.h
index e12d41f3ae..3d2c2978d4 100644
--- a/usr/src/lib/libproc/common/libproc.h
+++ b/usr/src/lib/libproc/common/libproc.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Portions Copyright 2007 Chad Mynhier
@@ -43,8 +43,6 @@
#ifndef _LIBPROC_H
#define _LIBPROC_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
@@ -467,11 +465,15 @@ extern int Pxlookup_by_name(struct ps_prochandle *,
extern int Pxlookup_by_addr(struct ps_prochandle *,
uintptr_t, char *, size_t, GElf_Sym *, prsyminfo_t *);
+extern int Pxlookup_by_addr_resolved(struct ps_prochandle *,
+ uintptr_t, char *, size_t, GElf_Sym *, prsyminfo_t *);
typedef int proc_map_f(void *, const prmap_t *, const char *);
extern int Pmapping_iter(struct ps_prochandle *, proc_map_f *, void *);
+extern int Pmapping_iter_resolved(struct ps_prochandle *, proc_map_f *, void *);
extern int Pobject_iter(struct ps_prochandle *, proc_map_f *, void *);
+extern int Pobject_iter_resolved(struct ps_prochandle *, proc_map_f *, void *);
extern const prmap_t *Paddr_to_map(struct ps_prochandle *, uintptr_t);
extern const prmap_t *Paddr_to_text_map(struct ps_prochandle *, uintptr_t);
@@ -491,9 +493,12 @@ extern ctf_file_t *Pname_to_ctf(struct ps_prochandle *, const char *);
extern char *Pplatform(struct ps_prochandle *, char *, size_t);
extern int Puname(struct ps_prochandle *, struct utsname *);
extern char *Pzonename(struct ps_prochandle *, char *, size_t);
+extern char *Pfindobj(struct ps_prochandle *, const char *, char *, size_t);
extern char *Pexecname(struct ps_prochandle *, char *, size_t);
extern char *Pobjname(struct ps_prochandle *, uintptr_t, char *, size_t);
+extern char *Pobjname_resolved(struct ps_prochandle *, uintptr_t, char *,
+ size_t);
extern int Plmid(struct ps_prochandle *, uintptr_t, Lmid_t *);
typedef int proc_env_f(void *, struct ps_prochandle *, uintptr_t, const char *);
diff --git a/usr/src/lib/libproc/common/llib-lproc b/usr/src/lib/libproc/common/llib-lproc
index b9eff09617..2faf27865d 100644
--- a/usr/src/lib/libproc/common/llib-lproc
+++ b/usr/src/lib/libproc/common/llib-lproc
@@ -22,11 +22,9 @@
/* PROTOLIB1 */
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "libproc.h"
/*
@@ -194,9 +192,15 @@ const rd_loadobj_t *Pname_to_loadobj(struct ps_prochandle *, const char *);
const rd_loadobj_t *Plmid_to_loadobj(struct ps_prochandle *, Lmid_t,
const char *);
int Pmapping_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd);
+int Pmapping_iter_resolved(struct ps_prochandle *Pr, proc_map_f *func,
+ void *cd);
int Pobject_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd);
+int Pobject_iter_resolved(struct ps_prochandle *Pr, proc_map_f *func,
+ void *cd);
char *Pobjname(struct ps_prochandle *Pr, uintptr_t addr,
char *buffer, size_t bufsize);
+char *Pobjname_resolved(struct ps_prochandle *Pr, uintptr_t addr,
+ char *buffer, size_t bufsize);
int Plmid(struct ps_prochandle *Pr, uintptr_t addr, Lmid_t *lmidp);
int Psymbol_iter(struct ps_prochandle *Pr, const char *object_name,
int which, int type, proc_sym_f *func, void *cd);
@@ -208,6 +212,8 @@ char *Pgetenv(struct ps_prochandle *Pr, const char *name,
char *Pplatform(struct ps_prochandle *Pr, char *s, size_t n);
int Puname(struct ps_prochandle *Pr, struct utsname *u);
char *Pzonename(struct ps_prochandle *Pr, char *s, size_t n);
+char *Pfindobj(struct ps_prochandle *Pr, const char *path,
+ char *s, size_t n);
char *Pexecname(struct ps_prochandle *Pr, char *buffer, size_t bufsize);
void Preset_maps(struct ps_prochandle *Pr);
diff --git a/usr/src/lib/libproc/common/mapfile-vers b/usr/src/lib/libproc/common/mapfile-vers
index a2fc5c9be6..bf7b3b9426 100644
--- a/usr/src/lib/libproc/common/mapfile-vers
+++ b/usr/src/lib/libproc/common/mapfile-vers
@@ -19,11 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# Due to mistakes made early in the history of this library, there are no
# SUNW_1.1 through SUNW_1.4 symbols, but they are now kept as placeholders.
@@ -126,11 +124,14 @@ SUNWprivate_1.1 {
Plwp_setregs;
Plwp_stack;
Pmapping_iter;
+ Pmapping_iter_resolved;
Pname_to_ctf;
Pname_to_loadobj;
Pname_to_map;
Pobject_iter;
+ Pobject_iter_resolved;
Pobjname;
+ Pobjname_resolved;
Pplatform;
Ppltdest;
Ppriv;
@@ -276,9 +277,12 @@ SUNWprivate_1.1 {
Pxecbkpt;
Pxecwapt;
Pxlookup_by_addr;
+ Pxlookup_by_addr_resolved;
Pxlookup_by_name;
Pxsymbol_iter;
Pzonename;
+ Pzonepath;
+ Pzoneroot;
local:
*;
};