summaryrefslogtreecommitdiff
path: root/usr/src/lib/libproc/common/Pidle.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libproc/common/Pidle.c
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libproc/common/Pidle.c')
-rw-r--r--usr/src/lib/libproc/common/Pidle.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/usr/src/lib/libproc/common/Pidle.c b/usr/src/lib/libproc/common/Pidle.c
new file mode 100644
index 0000000000..bf05e6a2e9
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pidle.c
@@ -0,0 +1,259 @@
+/*
+ * 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.
+ *
+ * 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 2005 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>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/sysmacros.h>
+
+#include "Pcontrol.h"
+
+static ssize_t
+Pread_idle(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr)
+{
+ size_t resid = n;
+
+ while (resid > 0) {
+ map_info_t *mp;
+ uintptr_t mapoff;
+ ssize_t len;
+ off64_t off;
+
+ if ((mp = Paddr2mptr(P, addr)) == NULL)
+ break;
+
+ mapoff = addr - mp->map_pmap.pr_vaddr;
+ len = MIN(resid, mp->map_pmap.pr_size - mapoff);
+ off = mp->map_offset + mapoff;
+
+ if ((len = pread64(P->asfd, buf, len, off)) <= 0)
+ break;
+
+ resid -= len;
+ addr += len;
+ buf = (char *)buf + len;
+ }
+
+ return (n - resid);
+}
+
+/*ARGSUSED*/
+static ssize_t
+Pwrite_idle(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr)
+{
+ errno = EIO;
+ return (-1);
+}
+
+static const ps_rwops_t P_idle_ops = {
+ Pread_idle,
+ Pwrite_idle
+};
+
+static int
+idle_add_mapping(struct ps_prochandle *P, GElf_Phdr *php, file_info_t *fp)
+{
+ prmap_t pmap;
+
+ dprintf("mapping base %llx filesz %llu memsz %llu offset %llu\n",
+ (u_longlong_t)php->p_vaddr, (u_longlong_t)php->p_filesz,
+ (u_longlong_t)php->p_memsz, (u_longlong_t)php->p_offset);
+
+ pmap.pr_vaddr = (uintptr_t)php->p_vaddr;
+ pmap.pr_size = php->p_filesz;
+ (void) strncpy(pmap.pr_mapname, fp->file_pname,
+ sizeof (pmap.pr_mapname));
+ pmap.pr_offset = php->p_offset;
+
+ pmap.pr_mflags = 0;
+ if (php->p_flags & PF_R)
+ pmap.pr_mflags |= MA_READ;
+ if (php->p_flags & PF_W)
+ pmap.pr_mflags |= MA_WRITE;
+ if (php->p_flags & PF_X)
+ pmap.pr_mflags |= MA_EXEC;
+
+ pmap.pr_pagesize = 0;
+ pmap.pr_shmid = -1;
+
+ return (Padd_mapping(P, php->p_offset, fp, &pmap));
+}
+
+struct ps_prochandle *
+Pgrab_file(const char *fname, int *perr)
+{
+ struct ps_prochandle *P = NULL;
+ GElf_Ehdr ehdr;
+ Elf *elf = NULL;
+ file_info_t *fp = NULL;
+ int fd;
+ int i;
+
+ if ((fd = open64(fname, O_RDONLY)) < 0) {
+ dprintf("couldn't open file");
+ *perr = (errno == ENOENT) ? G_NOEXEC : G_STRANGE;
+ return (NULL);
+ }
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ dprintf("libproc ELF version is more recent than libelf");
+ *perr = G_ELF;
+ goto err;
+ }
+
+ if ((P = calloc(1, sizeof (struct ps_prochandle))) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ (void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
+ P->state = PS_IDLE;
+ P->pid = (pid_t)-1;
+ P->asfd = fd;
+ P->ctlfd = -1;
+ P->statfd = -1;
+ P->agentctlfd = -1;
+ P->agentstatfd = -1;
+ P->info_valid = -1;
+ P->ops = &P_idle_ops;
+ Pinitsym(P);
+
+ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
+ *perr = G_ELF;
+ return (NULL);
+ }
+
+ /*
+ * Construct a file_info_t that corresponds to this file.
+ */
+ if ((fp = calloc(1, sizeof (file_info_t))) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ if ((fp->file_lo = calloc(1, sizeof (rd_loadobj_t))) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ if (*fname == '/') {
+ (void) strncpy(fp->file_pname, fname, sizeof (fp->file_pname));
+ } else {
+ size_t sz;
+
+ if (getcwd(fp->file_pname, sizeof (fp->file_pname) - 1) ==
+ NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ sz = strlen(fp->file_pname);
+ (void) snprintf(&fp->file_pname[sz],
+ sizeof (fp->file_pname) - sz, "/%s", fname);
+ }
+
+ fp->file_fd = fd;
+ fp->file_lo->rl_lmident = LM_ID_BASE;
+ fp->file_lname = strdup(fp->file_pname);
+ fp->file_lbase = basename(fp->file_lname);
+
+ P->execname = strdup(fp->file_pname);
+
+ P->num_files++;
+ list_link(fp, &P->file_head);
+
+ if (gelf_getehdr(elf, &ehdr) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ dprintf("Pgrab_file: ehdr.e_phnum = %d\n", ehdr.e_phnum);
+
+ /*
+ * Sift through the program headers making the relevant maps.
+ */
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ GElf_Phdr phdr, *php;
+
+ if ((php = gelf_getphdr(elf, i, &phdr)) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ if (php->p_type != PT_LOAD)
+ continue;
+
+ if (idle_add_mapping(P, php, fp) != 0) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+ }
+ Psort_mappings(P);
+
+ (void) elf_end(elf);
+
+ P->map_exec = fp->file_map;
+
+ P->status.pr_flags = PR_STOPPED;
+ P->status.pr_nlwp = 0;
+ P->status.pr_pid = (pid_t)-1;
+ P->status.pr_ppid = (pid_t)-1;
+ P->status.pr_pgid = (pid_t)-1;
+ P->status.pr_sid = (pid_t)-1;
+ P->status.pr_taskid = (taskid_t)-1;
+ P->status.pr_projid = (projid_t)-1;
+ switch (ehdr.e_ident[EI_CLASS]) {
+ case ELFCLASS32:
+ P->status.pr_dmodel = PR_MODEL_ILP32;
+ break;
+ case ELFCLASS64:
+ P->status.pr_dmodel = PR_MODEL_LP64;
+ break;
+ default:
+ *perr = G_FORMAT;
+ goto err;
+ }
+
+ /*
+ * The file and map lists are complete, and will never need to be
+ * adjusted.
+ */
+ P->info_valid = 1;
+
+ return (P);
+err:
+ (void) close(fd);
+ if (P != NULL)
+ Pfree(P);
+ if (elf != NULL)
+ (void) elf_end(elf);
+ return (NULL);
+}