diff options
Diffstat (limited to 'usr/src/lib/libproc')
-rw-r--r-- | usr/src/lib/libproc/Makefile.com | 21 | ||||
-rw-r--r-- | usr/src/lib/libproc/amd64/Pisadep.c | 130 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pcontrol.c | 8 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pcontrol.h | 12 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pcore.c | 24 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pfdinfo.c | 168 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pgcore.c | 28 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/libproc.h | 7 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/mapfile-vers | 2 |
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; |