/* * plants a breakpoint at the specified location in * the target process, and saves the existing instruction. */ static prb_status_t bpt(prb_proc_ctl_t *proc_p, uintptr_t addr) { prb_status_t prbstat; bptsave_t instr; if (!proc_p->bpt_inserted) { DBG_TNF_PROBE_1(bpt_1, "libtnfctl", "sunw%verbosity 2", tnf_opaque, bpt_planted_at, addr); prbstat = prb_proc_read(proc_p, addr, &(proc_p->saveinstr), sizeof (proc_p->saveinstr)); if (prbstat) return (prbstat); DBG_TNF_PROBE_1(bpt_2, "libtnfctl", "sunw%verbosity 2", tnf_opaque, saved_instr, (unsigned)proc_p->saveinstr); instr = INS_BPT; prbstat = prb_proc_write(proc_p, addr, &instr, sizeof (instr)); if (prbstat) return (prbstat); proc_p->bpt_inserted = B_TRUE; } return (PRB_STATUS_OK); }
/* * dyn_findtag() - searches tags in _DYNAMIC table */ static tnfctl_errcode_t dyn_findtag(Elf3264_Dyn * start, /* start of dynam table read in */ Elf3264_Sword tag, /* tag to search for */ uintptr_t dynam_addr, /* base address of _DYNAMIC in target */ int limit, /* number of entries in table */ uintptr_t * dentry_address) { /* return value */ Elf3264_Dyn *dp; for (dp = start; dp->d_tag != DT_NULL; dp++) { DBG_TNF_PROBE_1(dyn_findtag_1, "libtnfctl", "sunw%verbosity 3; sunw%debug 'in loop'", tnf_long, tag, dp->d_tag); if (dp->d_tag == tag) { *dentry_address = dynam_addr + (dp - start) * sizeof (Elf3264_Dyn); return (TNFCTL_ERR_NONE); } if (--limit <= 0) { DBG((void) fprintf(stderr, "dyn_findtag: exceeded limit of table\n")); return (TNFCTL_ERR_INTERNAL); } } DBG((void) fprintf(stderr, "dyn_findtag: couldn't find tag, last tag=%d\n", (int) dp->d_tag)); return (TNFCTL_ERR_INTERNAL); }
/* * prb_child_create() - this routine instantiates and rendevous with the * target child process. This routine returns an opaque handle for the * childs /proc entry. */ prb_status_t prb_child_create(const char *cmdname, char * const *cmdargs, const char *loption, const char *libtnfprobe_path, char * const *envp, prb_proc_ctl_t **ret_val) { prb_status_t prbstat; pid_t childpid; char executable_name[PATH_MAX + 2]; extern char **environ; char * const * env_to_use; size_t loptlen, probepathlen; volatile shmem_msg_t *smp; /* initialize shmem communication buffer to cause child to wait */ prbstat = prb_shmem_init(&smp); if (prbstat) return (prbstat); /* fork to create the child process */ childpid = fork(); if (childpid == (pid_t) - 1) { DBG(perror("prb_child_create: fork failed")); return (prb_status_map(errno)); } if (childpid == 0) { char *oldenv; char *newenv; /* ---- CHILD PROCESS ---- */ DBG_TNF_PROBE_1(prb_child_create_1, "libtnfctl", "sunw%verbosity 1; sunw%debug 'child process created'", tnf_long, pid, getpid()); if (envp) { env_to_use = envp; goto ContChild; } /* append libtnfprobe.so to the LD_PRELOAD environment */ loptlen = (loption) ? strlen(loption) : 0; /* probepathlen has a "/" added in ("+ 1") */ probepathlen = (libtnfprobe_path) ? (strlen(libtnfprobe_path) + 1) : 0; oldenv = getenv(PRELOAD); if (oldenv) { newenv = (char *) malloc(strlen(PRELOAD) + 1 + /* "=" */ strlen(oldenv) + 1 + /* " " */ probepathlen + strlen(LIBPROBE) + 1 + /* " " */ loptlen + 1); /* NULL */ if (!newenv) goto ContChild; (void) strcpy(newenv, PRELOAD); (void) strcat(newenv, "="); (void) strcat(newenv, oldenv); (void) strcat(newenv, " "); if (probepathlen) { (void) strcat(newenv, libtnfprobe_path); (void) strcat(newenv, "/"); } (void) strcat(newenv, LIBPROBE); if (loptlen) { (void) strcat(newenv, " "); (void) strcat(newenv, loption); } } else { newenv = (char *) malloc(strlen(PRELOAD) + 1 + /* "=" */ probepathlen + strlen(LIBPROBE) + 1 + /* " " */ loptlen + 1); /* NULL */ if (!newenv) goto ContChild; (void) strcpy(newenv, PRELOAD); (void) strcat(newenv, "="); if (probepathlen) { (void) strcat(newenv, libtnfprobe_path); (void) strcat(newenv, "/"); } (void) strcat(newenv, LIBPROBE); if (loptlen) { (void) strcat(newenv, " "); (void) strcat(newenv, loption); } } (void) putenv((char *) newenv); env_to_use = environ; /* * We don't check the return value of putenv because the * desired libraries might already be in the target, even * if our effort to change the environment fails. We * should continue either way ... */ ContChild: /* wait until the parent releases us */ (void) prb_shmem_wait(smp); DBG_TNF_PROBE_1(prb_child_create_2, "libtnfctl", "sunw%verbosity 2; " "sunw%debug 'child process about to exec'", tnf_string, cmdname, cmdname); /* * make the child it's own process group. * This is so that signals delivered to parent are not * also delivered to child. */ (void) setpgrp(); prbstat = find_executable(cmdname, executable_name); if (prbstat) { DBG((void) fprintf(stderr, "prb_child_create: %s\n", prb_status_str(prbstat))); /* parent waits for exit */ _exit(1); } if (execve(executable_name, cmdargs, env_to_use) == -1) { DBG(perror("prb_child_create: exec failed")); _exit(1); } /* Never reached */ _exit(1); } /* ---- PARENT PROCESS ---- */ /* child is waiting for us */ prbstat = sync_child(childpid, smp, ret_val); if (prbstat) { return (prbstat); } return (PRB_STATUS_OK); }
/* * iterate over all loadobjects in the same address space calling the * callback function "obj_func". */ static int inprocess_loadobj_iter(void *opq, tnfctl_ind_obj_f *obj_func, void *cd) { Elf3264_Dyn *dtdebug = opq; struct r_debug *r_dbg; struct link_map *lmap; char path[MAXPATHLEN]; int procfd; tnfctl_ind_obj_info_t loadobj; int retval = 0; /* sucessful return */ DBG_TNF_PROBE_0(inprocess_loadobj_iter_start, "libtnfctl", "start inprocess_loadobj_iter; sunw%verbosity 1"); r_dbg = (struct r_debug *)dtdebug->d_un.d_ptr; DBG_TNF_PROBE_1(inprocess_loadobj_iter_1, "libtnfctl", "sunw%verbosity 1", tnf_string, link_map_state, (r_dbg->r_state == RT_CONSISTENT) ? "RT_CONSISTENT" : (r_dbg->r_state == RT_ADD) ? "RT_ADD" : "RT_DELETE"); /* bail if link map is not consistent */ if (r_dbg->r_state != RT_CONSISTENT) return (1); (void) sprintf(path, PROCFORMAT, (int) getpid()); /* * opening /proc readonly, so debuggers can still run * We use /proc in order to get fd on the object. */ procfd = open(path, O_RDONLY); if (procfd == -1) return (1); for (lmap = r_dbg->r_map; lmap; lmap = lmap->l_next) { loadobj.text_base = lmap->l_addr; loadobj.data_base = lmap->l_addr; loadobj.objname = lmap->l_name; /* * client of this interface should deal with -1 for objfd, * so no error checking is needed on this ioctl */ loadobj.objfd = ioctl(procfd, PIOCOPENM, &(lmap->l_addr)); retval = obj_func(opq, &loadobj, cd); /* close the fd */ if (loadobj.objfd != -1) close(loadobj.objfd); /* check for error */ if (retval == 1) goto end_of_func; } end_of_func: close(procfd); DBG_TNF_PROBE_0(inprocess_loadobj_iter_end, "libtnfctl", "end inprocess_loadobj_iter; sunw%verbosity 1"); return (retval); }