diff options
Diffstat (limited to 'usr/src')
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: *; }; |