/*ARGSUSED*/ static tnfctl_errcode_t dynsec_num(tnfctl_handle_t *hndl, uintptr_t baseaddr, int objfd, int *num_dyn) { int num_ent = 0; tnfctl_errcode_t prexstat; tnfctl_elf_search_t search_info; DBG_TNF_PROBE_0(dynsec_num_1, "libtnfctl", "sunw%verbosity 2;" "sunw%debug 'counting number of entries in .dynamic section'"); search_info.section_func = elf_dynmatch; search_info.section_data = &num_ent; prexstat = _tnfctl_traverse_object(objfd, baseaddr, &search_info); if (prexstat) return (prexstat); if (num_ent == 0) return (TNFCTL_ERR_NOTDYNAMIC); *num_dyn = num_ent; return (TNFCTL_ERR_NONE); }
/* * prb_rtld_unstalk() - remove rtld breakpoint */ prb_status_t prb_rtld_unstalk(prb_proc_ctl_t *proc_p) { prb_status_t prbstat; DBG_TNF_PROBE_0(prb_rtld_unstalk_1, "libtnfctl", "sunw%verbosity 2"); /* turn off BPT tracing while out of the water ... */ prbstat = prb_proc_tracebpt(proc_p, B_FALSE); prbstat = unbpt(proc_p, proc_p->bptaddr); return (prbstat); }
/* * prb_rtld_stalk() - setup for a breakpoint when rtld has opened or closed a * shared object. */ prb_status_t prb_rtld_stalk(prb_proc_ctl_t *proc_p) { prb_status_t prbstat = PRB_STATUS_OK; DBG_TNF_PROBE_0(prb_rtld_stalk_1, "libtnfctl", "sunw%verbosity 2"); if (!proc_p->bptaddr) { Elf3264_Dyn dentry; struct r_debug r_dbg; if (proc_p->dbgaddr == 0) { DBG((void) fprintf(stderr, "prb_rtld_stalk: dbgaddr not set\n")); return (PRB_STATUS_BADARG); } prbstat = prb_proc_read(proc_p, proc_p->dbgaddr, &dentry, sizeof (dentry)); if (prbstat || !dentry.d_un.d_ptr) { DBG((void) fprintf(stderr, "prb_rtld_stalk: error in d_un.d_ptr\n")); return (prbstat); } /* read in the debug struct that it points to */ prbstat = prb_proc_read(proc_p, dentry.d_un.d_ptr, &r_dbg, sizeof (r_dbg)); if (prbstat) return (prbstat); proc_p->bptaddr = r_dbg.r_brk; } /* plant a breakpoint trap in the pointed to function */ prbstat = bpt(proc_p, proc_p->bptaddr); if (prbstat) return (prbstat); /* setup process to stop when breakpoint encountered */ prbstat = prb_proc_tracebpt(proc_p, B_TRUE); return (prbstat); }
/* * prb_rtld_setup() - turns on the flag in the rtld structure so that rtld * executes a getpid() stystem call after it done mapping all shared objects * but before it executes any init code. */ static prb_status_t prb_rtld_setup(prb_proc_ctl_t *proc_p, boolean_t *synced) { prb_status_t prbstat = PRB_STATUS_OK; Elf3264_Dyn dentry; DBG_TNF_PROBE_0(prb_rtld_setup_1, "libtnfctl", "sunw%verbosity 2"); if (proc_p->dbgaddr == 0) { DBG((void) fprintf(stderr, "prb_rtld_setup: dbgaddr not set\n")); return (PRB_STATUS_BADARG); } prbstat = prb_proc_read(proc_p, proc_p->dbgaddr, &dentry, sizeof (dentry)); if (prbstat) { DBG((void) fprintf(stderr, "prb_rtld_setup: error in d_un.d_ptr\n")); return (prbstat); } if ((dentry.d_un.d_ptr == 0) || (dentry.d_un.d_ptr == 1)) { *synced = B_FALSE; } else { *synced = B_TRUE; return (PRB_STATUS_OK); } /* modify it - i.e. request rtld to do getpid() */ dentry.d_un.d_ptr = 1; prbstat = prb_proc_write(proc_p, proc_p->dbgaddr, &dentry, sizeof (dentry)); return (prbstat); }
/* * prb_rtld_advance() - we've hit a breakpoint, replace the original * instruction, istep, put the breakpoint back ... */ prb_status_t prb_rtld_advance(prb_proc_ctl_t *proc_p) { prb_status_t prbstat; DBG_TNF_PROBE_0(prb_rtld_advance_1, "libtnfctl", "sunw%verbosity 2"); prbstat = prb_proc_clrbptflt(proc_p); if (prbstat) return (prbstat); prbstat = unbpt(proc_p, proc_p->bptaddr); if (prbstat) return (prbstat); prbstat = prb_proc_istepbpt(proc_p); if (prbstat) return (prbstat); prbstat = bpt(proc_p, proc_p->bptaddr); 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); }
/* * prb_rtld_wait() - waits on target to execute getpid() */ static prb_status_t prb_rtld_wait(prb_proc_ctl_t *proc_p) { prb_proc_state_t pstate; prb_status_t prbstat; DBG_TNF_PROBE_0(prb_rtld_wait_1, "libtnfctl", "sunw%verbosity 2"); /* stop on exit of getpid() */ prbstat = prb_proc_exit(proc_p, SYS_getpid, PRB_SYS_ADD); if (prbstat) { DBG((void) fprintf(stderr, "prb_rtld_wait: couldn't set up child to stop on " "exit of getpid(): %s\n", prb_status_str(prbstat))); return (prbstat); } /* stop on entry of exit() - i.e. exec failed */ prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_ADD); if (prbstat) { DBG((void) fprintf(stderr, "prb_rtld_wait: couldn't set up child to stop on " "entry of exit(): %s\n", prb_status_str(prbstat))); return (prbstat); } /* continue target and wait for it to stop */ prbstat = prb_proc_cont(proc_p); if (prbstat) { DBG((void) fprintf(stderr, "prb_rtld_wait: couldn't continue target process: %s\n", prb_status_str(prbstat))); return (prbstat); } /* wait for target to stop */ prbstat = prb_proc_wait(proc_p, B_FALSE, NULL); if (prbstat) { DBG((void) fprintf(stderr, "prb_rtld_wait: couldn't wait on target process: %s\n", prb_status_str(prbstat))); return (prbstat); } /* make sure it did stop on getpid() */ prbstat = prb_proc_state(proc_p, &pstate); if (prbstat) { DBG((void) fprintf(stderr, "prb_rtld_wait: couldn't get state of target: %s\n", prb_status_str(prbstat))); return (prbstat); } if (pstate.ps_issysentry && (pstate.ps_syscallnum == SYS_exit)) { DBG((void) fprintf(stderr, "prb_rtld_wait: target exited\n")); return (prb_status_map(EACCES)); } /* catch any other errors */ if (!(pstate.ps_issysexit && (pstate.ps_syscallnum == SYS_getpid))) { DBG((void) fprintf(stderr, "prb_rtld_wait: target didn't stop on getpid\n")); return (PRB_STATUS_BADSYNC); } /* clear wait on getpid */ prbstat = prb_proc_exit(proc_p, SYS_getpid, PRB_SYS_DEL); if (prbstat) { DBG((void) fprintf(stderr, "prb_rtld_wait: couldn't clear child to stop on " "exit of getpid(): %s\n", prb_status_str(prbstat))); return (prbstat); } /* clear wait on exit */ prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_DEL); if (prbstat) { DBG((void) fprintf(stderr, "prb_rtld_wait: couldn't clear child to stop on " "entry of exit(): %s\n", prb_status_str(prbstat))); return (prbstat); } /* start-stop the process to clear it out of the system call */ prbstat = prb_proc_prstop(proc_p); if (prbstat) { DBG((void) fprintf(stderr, "prb_rtld_wait: couldn't prstop child: %s\n", prb_status_str(prbstat))); return (prbstat); } return (PRB_STATUS_OK); }