summaryrefslogtreecommitdiff
path: root/usr/src/lib/libproc/common
diff options
context:
space:
mode:
authorEdward Pilatowicz <Edward.Pilatowicz@Sun.COM>2008-09-23 22:32:10 -0700
committerEdward Pilatowicz <Edward.Pilatowicz@Sun.COM>2008-09-23 22:32:10 -0700
commit186f7fbf5e07d046b50e4e15c32b21f109b76c80 (patch)
tree7bb0d0b3f1656c4959df4535c7adc296422b5863 /usr/src/lib/libproc/common
parentfeccaf6df4d61f3e7e0723a768ce407f9eb6a1dd (diff)
downloadillumos-joyent-186f7fbf5e07d046b50e4e15c32b21f109b76c80.tar.gz
PSARC/2008/490 pmadvise/pldd unresolved link map flag
6599704 libproc should look inside zones for objects --HG-- rename : usr/src/lib/libproc/common/Pbrand.c => usr/src/lib/libproc/common/Pzone.c
Diffstat (limited to 'usr/src/lib/libproc/common')
-rw-r--r--usr/src/lib/libproc/common/Pbrand.c42
-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
10 files changed, 1005 insertions, 182 deletions
diff --git a/usr/src/lib/libproc/common/Pbrand.c b/usr/src/lib/libproc/common/Pbrand.c
deleted file mode 100644
index 605a3afa20..0000000000
--- a/usr/src/lib/libproc/common/Pbrand.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "libproc.h"
-
-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);
-}
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:
*;
};