summaryrefslogtreecommitdiff
path: root/usr/src/lib/libproc
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libproc')
-rw-r--r--usr/src/lib/libproc/Makefile.com21
-rw-r--r--usr/src/lib/libproc/amd64/Pisadep.c130
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.c8
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.h12
-rw-r--r--usr/src/lib/libproc/common/Pcore.c24
-rw-r--r--usr/src/lib/libproc/common/Pfdinfo.c168
-rw-r--r--usr/src/lib/libproc/common/Pgcore.c28
-rw-r--r--usr/src/lib/libproc/common/libproc.h7
-rw-r--r--usr/src/lib/libproc/common/mapfile-vers2
9 files changed, 390 insertions, 10 deletions
diff --git a/usr/src/lib/libproc/Makefile.com b/usr/src/lib/libproc/Makefile.com
index 042b42fd53..794c54f3eb 100644
--- a/usr/src/lib/libproc/Makefile.com
+++ b/usr/src/lib/libproc/Makefile.com
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
#
LIBRARY = libproc.a
@@ -30,6 +31,7 @@ CMNOBJS = \
Pcontrol.o \
Pcore.o \
Pexecname.o \
+ Pfdinfo.o \
Pgcore.o \
Pidle.o \
Pisprocdir.o \
@@ -72,7 +74,14 @@ CMNOBJS = \
ISAOBJS = \
Pisadep.o
-OBJECTS = $(CMNOBJS) $(ISAOBJS)
+amd64_SAVEOBJS = \
+ saveargs.o
+
+amd64_CPPFLAGS = -I$(SRC)/common/saveargs
+
+SAVEOBJS = $($(MACH64)_SAVEOBJS)
+
+OBJECTS = $(CMNOBJS) $(ISAOBJS) $(SAVEOBJS)
# include library definitions
include ../../Makefile.lib
@@ -82,6 +91,7 @@ SRCS = $(CMNOBJS:%.o=../common/%.c) $(ISAOBJS:%.o=%.c)
LIBS = $(DYNLIB) $(LINTLIB)
LDLIBS += -lrtld_db -lelf -lctf -lc
+CPPFLAGS += $($(MACH64)_CPPFLAGS)
SRCDIR = ../common
$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
@@ -89,6 +99,11 @@ $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
CFLAGS += $(CCVERBOSE)
CPPFLAGS += -I$(SRCDIR)
+CERRWARN += -_gcc=-Wno-uninitialized
+CERRWARN += -_gcc=-Wno-parentheses
+CERRWARN += -_gcc=-Wno-type-limits
+CERRWARN += -_gcc=-Wno-unused-label
+
# All interfaces are interposable, therefore don't allow direct binding to
# libproc. Disable libproc from directly binding to itself, but allow libperl
# to directly bind to its dependencies (ie. map -Bdirect -> -zdirect). Ensure
@@ -108,3 +123,7 @@ include ../../Makefile.targ
objs/%.o pics/%.o: %.c
$(COMPILE.c) -o $@ $<
$(POST_PROCESS_O)
+
+objs/%.o pics/%.o: $(SRC)/common/saveargs/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
diff --git a/usr/src/lib/libproc/amd64/Pisadep.c b/usr/src/lib/libproc/amd64/Pisadep.c
index a78e304d4c..8ef8340b02 100644
--- a/usr/src/lib/libproc/amd64/Pisadep.c
+++ b/usr/src/lib/libproc/amd64/Pisadep.c
@@ -36,6 +36,7 @@
#include <errno.h>
#include <string.h>
+#include <saveargs.h>
#include "Pcontrol.h"
#include "Pstack.h"
@@ -346,6 +347,121 @@ ucontext_n_to_prgregs(const ucontext_t *src, prgregset_t dst)
(void) memcpy(dst, src->uc_mcontext.gregs, sizeof (gregset_t));
}
+/*
+ * Read arguments from the frame indicated by regs into args, return the
+ * number of arguments successfully read
+ */
+static int
+read_args(struct ps_prochandle *P, uintptr_t fp, uintptr_t pc, prgreg_t *args,
+ size_t argsize)
+{
+ GElf_Sym sym;
+ ctf_file_t *ctfp = NULL;
+ ctf_funcinfo_t finfo;
+ prsyminfo_t si = {0};
+ uint8_t ins[SAVEARGS_INSN_SEQ_LEN];
+ size_t insnsize;
+ int argc = 0;
+ int rettype = 0;
+ int start_index = 0;
+ int args_style = 0;
+ int i;
+ ctf_id_t args_types[5];
+
+ if (Pxlookup_by_addr(P, pc, NULL, 0, &sym, &si) != 0)
+ return (0);
+
+ if ((ctfp = Paddr_to_ctf(P, pc)) == NULL)
+ return (0);
+
+ if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR)
+ return (0);
+
+ argc = finfo.ctc_argc;
+
+ if (argc == 0)
+ return (0);
+
+ rettype = ctf_type_kind(ctfp, finfo.ctc_return);
+
+ /*
+ * If the function returns a structure or union greater than 16 bytes
+ * in size %rdi contains the address in which to store the return
+ * value rather than for an argument.
+ */
+ if (((rettype == CTF_K_STRUCT) || (rettype == CTF_K_UNION)) &&
+ ctf_type_size(ctfp, finfo.ctc_return) > 16)
+ start_index = 1;
+ else
+ start_index = 0;
+
+ /*
+ * If any of the first 5 arguments are a structure less than 16 bytes
+ * in size, it will be passed spread across two argument registers,
+ * and we will not cope.
+ */
+ if (ctf_func_args(ctfp, si.prs_id, 5, args_types) == CTF_ERR)
+ return (0);
+
+ for (i = 0; i < MIN(5, finfo.ctc_argc); i++) {
+ int t = ctf_type_kind(ctfp, args_types[i]);
+
+ if (((t == CTF_K_STRUCT) || (t == CTF_K_UNION)) &&
+ ctf_type_size(ctfp, args_types[i]) <= 16)
+ return (0);
+ }
+
+ /*
+ * The number of instructions to search for argument saving is limited
+ * such that only instructions prior to %pc are considered and we
+ * never read arguments from a function where the saving code has not
+ * in fact yet executed.
+ */
+ insnsize = MIN(MIN(sym.st_size, SAVEARGS_INSN_SEQ_LEN),
+ pc - sym.st_value);
+
+ if (Pread(P, ins, insnsize, sym.st_value) != insnsize)
+ return (0);
+
+ if ((argc != 0) &&
+ ((args_style = saveargs_has_args(ins, insnsize, argc,
+ start_index)) != SAVEARGS_NO_ARGS)) {
+ int regargs = MIN((6 - start_index), argc);
+ size_t size = regargs * sizeof (long);
+ int i;
+
+ /*
+ * If Studio pushed a structure return address as an argument,
+ * we need to read one more argument than actually exists (the
+ * addr) to make everything line up.
+ */
+ if (args_style == SAVEARGS_STRUCT_ARGS)
+ size += sizeof (long);
+
+ if (Pread(P, args, size, (fp - size)) != size)
+ return (0);
+
+ for (i = 0; i < (regargs / 2); i++) {
+ prgreg_t t = args[i];
+
+ args[i] = args[regargs - i - 1];
+ args[regargs - i - 1] = t;
+ }
+
+ if (argc > regargs) {
+ size = MIN((argc - regargs) * sizeof (long),
+ argsize - (regargs * sizeof (long)));
+
+ if (Pread(P, &args[regargs], size, fp +
+ (sizeof (uintptr_t) * 2)) != size)
+ return (6);
+ }
+
+ return (argc);
+ } else {
+ return (0);
+ }
+}
int
Pstack_iter(struct ps_prochandle *P, const prgregset_t regs,
@@ -381,7 +497,7 @@ Pstack_iter(struct ps_prochandle *P, const prgregset_t regs,
prgreg_t signo;
siginfo_t *sip;
} sigframe_t;
- prgreg_t args[32];
+ prgreg_t args[32] = {0};
if (P->status.pr_dmodel != PR_MODEL_LP64)
return (Pstack_iter32(P, regs, func, arg));
@@ -400,20 +516,16 @@ Pstack_iter(struct ps_prochandle *P, const prgregset_t regs,
if (fp != 0 &&
Pread(P, &frame, sizeof (frame), (uintptr_t)fp) ==
sizeof (frame)) {
-
- if (frame.pc != -1) {
- /*
- * Function arguments are not available on
- * amd64 without extensive DWARF processing.
- */
- argc = 0;
- } else {
+ if (frame.pc == -1) {
argc = 3;
args[2] = fp + sizeof (sigframe_t);
if (Pread(P, &args, 2 * sizeof (prgreg_t),
fp + 2 * sizeof (prgreg_t)) !=
2 * sizeof (prgreg_t))
argc = 0;
+ } else {
+ argc = read_args(P, fp, pc, args,
+ sizeof (args));
}
} else {
(void) memset(&frame, 0, sizeof (frame));
diff --git a/usr/src/lib/libproc/common/Pcontrol.c b/usr/src/lib/libproc/common/Pcontrol.c
index 2a32522e0c..1e7ce1556e 100644
--- a/usr/src/lib/libproc/common/Pcontrol.c
+++ b/usr/src/lib/libproc/common/Pcontrol.c
@@ -24,6 +24,7 @@
* Use is subject to license terms.
*
* Portions Copyright 2007 Chad Mynhier
+ * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
*/
#include <assert.h>
@@ -986,6 +987,13 @@ Pfree(struct ps_prochandle *P)
}
free(P->hashtab);
}
+
+ while (P->num_fd > 0) {
+ fd_info_t *fip = list_next(&P->fd_head);
+ list_unlink(fip);
+ free(fip);
+ P->num_fd--;
+ }
(void) mutex_unlock(&P->proc_lock);
(void) mutex_destroy(&P->proc_lock);
diff --git a/usr/src/lib/libproc/common/Pcontrol.h b/usr/src/lib/libproc/common/Pcontrol.h
index 192038b9b6..4774093b6d 100644
--- a/usr/src/lib/libproc/common/Pcontrol.h
+++ b/usr/src/lib/libproc/common/Pcontrol.h
@@ -22,6 +22,9 @@
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
+ */
#ifndef _PCONTROL_H
#define _PCONTROL_H
@@ -136,6 +139,11 @@ typedef struct lwp_info { /* per-lwp information from core file */
#endif
} lwp_info_t;
+typedef struct fd_info {
+ plist_t fd_list; /* linked list */
+ prfdinfo_t fd_info; /* fd info */
+} fd_info_t;
+
typedef struct core_info { /* information specific to core files */
char core_dmodel; /* data model for core file */
int core_errno; /* error during initialization if != 0 */
@@ -223,6 +231,8 @@ struct ps_prochandle {
uintptr_t *ucaddrs; /* ucontext-list addresses */
uint_t ucnelems; /* number of elements in the ucaddrs list */
char *zoneroot; /* cached path to zone root */
+ plist_t fd_head; /* head of file desc info list */
+ int num_fd; /* number of file descs in list */
};
/* flags */
@@ -269,6 +279,8 @@ 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 fd_info_t *Pfd2info(struct ps_prochandle *, int);
+
extern char *Pfindmap(struct ps_prochandle *, map_info_t *, char *,
size_t);
diff --git a/usr/src/lib/libproc/common/Pcore.c b/usr/src/lib/libproc/common/Pcore.c
index de868725db..3e0350eb04 100644
--- a/usr/src/lib/libproc/common/Pcore.c
+++ b/usr/src/lib/libproc/common/Pcore.c
@@ -22,6 +22,9 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
+ */
#include <sys/types.h>
#include <sys/utsname.h>
@@ -300,6 +303,26 @@ err:
}
static int
+note_fdinfo(struct ps_prochandle *P, size_t nbytes)
+{
+ prfdinfo_t prfd;
+ fd_info_t *fip;
+
+ if ((nbytes < sizeof (prfd)) ||
+ (read(P->asfd, &prfd, sizeof (prfd)) != sizeof (prfd))) {
+ dprintf("Pgrab_core: failed to read NT_FDINFO\n");
+ return (-1);
+ }
+
+ if ((fip = Pfd2info(P, prfd.pr_fd)) == NULL) {
+ dprintf("Pgrab_core: failed to add NT_FDINFO\n");
+ return (-1);
+ }
+ (void) memcpy(&fip->fd_info, &prfd, sizeof (prfd));
+ return (0);
+}
+
+static int
note_platform(struct ps_prochandle *P, size_t nbytes)
{
char *plat;
@@ -701,6 +724,7 @@ static int (*nhdlrs[])(struct ps_prochandle *, size_t) = {
note_priv_info, /* 19 NT_PRPRIVINFO */
note_content, /* 20 NT_CONTENT */
note_zonename, /* 21 NT_ZONENAME */
+ note_fdinfo, /* 22 NT_FDINFO */
};
/*
diff --git a/usr/src/lib/libproc/common/Pfdinfo.c b/usr/src/lib/libproc/common/Pfdinfo.c
new file mode 100644
index 0000000000..0d41b5606d
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pfdinfo.c
@@ -0,0 +1,168 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/mkdev.h>
+
+#include "libproc.h"
+#include "Pcontrol.h"
+
+/*
+ * Pfdinfo.c - obtain open file information.
+ */
+
+/*
+ * Allocate an fd_info structure and stick it on the list.
+ * (Unless one already exists.) The list is sorted in
+ * reverse order. We will traverse it in that order later.
+ * This makes the usual ordered insert *fast*.
+ */
+fd_info_t *
+Pfd2info(struct ps_prochandle *P, int fd)
+{
+ fd_info_t *fip = list_next(&P->fd_head);
+ fd_info_t *next;
+ int i;
+
+ if (fip == NULL) {
+ list_link(&P->fd_head, NULL);
+ fip = list_next(&P->fd_head);
+ }
+
+ for (i = 0; i < P->num_fd; i++, fip = list_next(fip)) {
+ if (fip->fd_info.pr_fd == fd) {
+ return (fip);
+ }
+ if (fip->fd_info.pr_fd < fd) {
+ break;
+ }
+ }
+
+ next = fip;
+ if ((fip = calloc(1, sizeof (*fip))) == NULL)
+ return (NULL);
+
+ fip->fd_info.pr_fd = fd;
+ list_link(fip, next ? next : (void *)&(P->fd_head));
+ P->num_fd++;
+ return (fip);
+}
+
+/*
+ * Attempt to load the open file information from a live process.
+ */
+static void
+load_fdinfo(struct ps_prochandle *P)
+{
+ /*
+ * In the unlikely case there are *no* file descriptors open,
+ * we will keep rescanning the proc directory, which will be empty.
+ * This is an edge case it isn't worth adding additional state to
+ * to eliminate.
+ */
+ if (P->num_fd > 0) {
+ return;
+ }
+
+ if (P->state != PS_DEAD && P->state != PS_IDLE) {
+ char dir_name[PATH_MAX];
+ char path[PATH_MAX];
+ struct dirent *ent;
+ DIR *dirp;
+ int fd;
+
+ /*
+ * Try to get the path information first.
+ */
+ (void) snprintf(dir_name, sizeof (dir_name),
+ "%s/%d/path", procfs_path, (int)P->pid);
+ dirp = opendir(dir_name);
+ if (dirp == NULL) {
+ return;
+ }
+ ent = NULL;
+ while ((ent = readdir(dirp)) != NULL) {
+ fd_info_t *fip;
+ prfdinfo_t *info;
+ int len;
+ struct stat64 stat;
+
+ if (!isdigit(ent->d_name[0]))
+ continue;
+
+ fd = atoi(ent->d_name);
+
+ fip = Pfd2info(P, fd);
+ info = &fip->fd_info;
+ info->pr_fd = fd;
+
+ if (pr_fstat64(P, fd, &stat) == 0) {
+ info->pr_mode = stat.st_mode;
+ info->pr_uid = stat.st_uid;
+ info->pr_gid = stat.st_gid;
+ info->pr_major = major(stat.st_dev);
+ info->pr_minor = minor(stat.st_dev);
+ info->pr_rmajor = major(stat.st_rdev);
+ info->pr_rminor = minor(stat.st_rdev);
+ info->pr_size = stat.st_size;
+ info->pr_ino = stat.st_ino;
+ }
+
+ info->pr_fileflags = pr_fcntl(P, fd, F_GETXFL, 0);
+ info->pr_fdflags = pr_fcntl(P, fd, F_GETFD, 0);
+ info->pr_offset = pr_llseek(P, fd, 0, SEEK_CUR);
+
+ /* attempt to determine the path to it */
+ (void) snprintf(path, sizeof (path),
+ "%s/%d/path/%d", procfs_path, (int)P->pid, fd);
+ len = readlink(path, info->pr_path,
+ sizeof (info->pr_path) - 1);
+
+ if (len < 0) {
+ info->pr_path[0] = 0;
+ } else {
+ info->pr_path[len] = 0;
+ }
+ }
+ (void) closedir(dirp);
+
+ }
+}
+
+int
+Pfdinfo_iter(struct ps_prochandle *P, proc_fdinfo_f *func, void *cd)
+{
+ fd_info_t *fip;
+ int rv;
+
+ /* Make sure we have live data, if appropriate */
+ load_fdinfo(P);
+
+ /* NB: We walk the list backwards. */
+
+ for (fip = list_prev(&P->fd_head);
+ fip != (void *)&P->fd_head;
+ fip = list_prev(fip)) {
+ if ((rv = func(cd, &fip->fd_info)) != 0)
+ return (rv);
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libproc/common/Pgcore.c b/usr/src/lib/libproc/common/Pgcore.c
index 590c55142a..f409e96259 100644
--- a/usr/src/lib/libproc/common/Pgcore.c
+++ b/usr/src/lib/libproc/common/Pgcore.c
@@ -23,6 +23,9 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
+ */
#define _STRUCTURED_PROC 1
@@ -84,6 +87,11 @@ typedef struct {
shstrtab_t pgc_shstrtab;
} pgcore_t;
+typedef struct {
+ int fd_fd;
+ off64_t *fd_doff;
+} fditer_t;
+
static void
shstrtab_init(shstrtab_t *s)
{
@@ -543,6 +551,17 @@ new_per_lwp(void *data, const lwpstatus_t *lsp, const lwpsinfo_t *lip)
return (0);
}
+static int
+iter_fd(void *data, prfdinfo_t *fdinfo)
+{
+ fditer_t *iter = data;
+
+ if (write_note(iter->fd_fd, NT_FDINFO, fdinfo,
+ sizeof (*fdinfo), iter->fd_doff) != 0)
+ return (1);
+ return (0);
+}
+
static uint_t
count_sections(pgcore_t *pgc)
{
@@ -1341,6 +1360,15 @@ Pfgcore(struct ps_prochandle *P, int fd, core_content_t content)
&doff) != 0)
goto err;
+ {
+ fditer_t iter;
+ iter.fd_fd = fd;
+ iter.fd_doff = &doff;
+
+ if (Pfdinfo_iter(P, iter_fd, &iter) != 0)
+ goto err;
+ }
+
#if defined(__i386) || defined(__amd64)
/* CSTYLED */
{
diff --git a/usr/src/lib/libproc/common/libproc.h b/usr/src/lib/libproc/common/libproc.h
index b4374324a1..1e59b5089f 100644
--- a/usr/src/lib/libproc/common/libproc.h
+++ b/usr/src/lib/libproc/common/libproc.h
@@ -24,6 +24,7 @@
* Use is subject to license terms.
*
* Portions Copyright 2007 Chad Mynhier
+ * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
*/
/*
@@ -713,6 +714,12 @@ extern int proc_initstdio(void);
extern int proc_flushstdio(void);
extern int proc_finistdio(void);
+/*
+ * Iterate over all open files.
+ */
+typedef int proc_fdinfo_f(void *, prfdinfo_t *);
+extern int Pfdinfo_iter(struct ps_prochandle *, proc_fdinfo_f *, void *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libproc/common/mapfile-vers b/usr/src/lib/libproc/common/mapfile-vers
index c3e2eb2e8a..9482a53145 100644
--- a/usr/src/lib/libproc/common/mapfile-vers
+++ b/usr/src/lib/libproc/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
#
#
@@ -298,6 +299,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
Pzonename;
Pzonepath;
Pzoneroot;
+ Pfdinfo_iter;
$if _x86 && _ELF32
Pldt;