diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libproc/common/Pidle.c | |
download | illumos-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.c | 259 |
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); +} |