#include #include #include #include #include /* psaddr_t */ #include #include typedef struct Ptprog Ptprog; struct Pprog { Pthread *t; uint nt; }; typedef struct Pthread Pthread; struct Pthread { td_thrhandle_t handle; }; void pthreadattach(int pid) { } void pthreadattach() set up mapping Regs *pthreadregs() int npthread(); static int td_get_allthreads(td_thragent_t*, td_thrhandle_t**); static int terr(int); Regs* threadregs() { } typedef struct AllThread AllThread; struct AllThread { td_thrhandle_t *a; int n; int err; }; static int thritercb(const td_thrhandle_t *th, void *cb) { td_thrhandle_t **p; AllThread *a; int n; a = cb; if((a->n&(a->n-1)) == 0){ if(a->n == 0) n = 1; else n = a->n<<1; if((p = realloc(a->a, n*sizeof a->a[0])) == 0){ a->err = -1; return -1; /* stop iteration */ } a->a = p; } a->a[a->n++] = *th; return 0; } int td_get_allthreads(td_thragent_t *ta, td_thrhandle_t **pall) { int e; AllThread a; a.a = nil; a.n = 0; a.err = 0; if((e = td_ta_thr_iter(ta, thritercb, &a, TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS)) != TD_OK){ werrstr("%s", terr(e)); return -1; } if(a.err){ free(a.a); return -1; } *pall = a.a; return a.n; } static char *tderrstr[] = { [TD_OK] "no error", [TD_ERR] "some error", [TD_NOTHR] "no matching thread found", [TD_NOSV] "no matching synchronization handle found", [TD_NOLWP] "no matching light-weight process found", [TD_BADPH] "invalid process handle", [TD_BADTH] "invalid thread handle", [TD_BADSH] "invalid synchronization handle", [TD_BADTA] "invalid thread agent", [TD_BADKEY] "invalid key", [TD_NOMSG] "no event available", [TD_NOFPREGS] "no floating-point register content available", [TD_NOLIBTHREAD] "application not linked with thread library", [TD_NOEVENT] "requested event is not supported", [TD_NOEVENT] "requested event is not supported", [TD_NOCAPAB] "capability not available", [TD_DBERR] "internal debug library error", [TD_NOAPLIC] "operation is not applicable", [TD_NOTSD] "no thread-specific data available", [TD_MALLOC] "out of memory", [TD_PARTIALREG] "not entire register set was read or written", [TD_NOXREGS] "X register set not available for given threads", [TD_TLSDEFER] "thread has not yet allocated TLS for given module", [TD_VERSION] "version mismatch twixt libpthread and libthread_db", [TD_NOTLS] "there is no TLS segment in the given module", }; static char* terr(int e) { static char buf[50]; if(e < 0 || e >= nelem(tderrstr) || tderrstr[e] == nil){ snprint(buf, sizeof buf, "thread err %d", e); return buf; } return tderrstr[e]; } /* * bottom-end functions for libthread_db to call */ enum { PS_OK, PS_ERR, PS_BADPID, PS_BADLWPID, PS_BADADDR, PS_NOSYM, PS_NOFPREGS, }; pid_t ps_getpid(struct ps_prochandle *ph) { return ph->pid; } int ps_pstop(const struct ps_prochandle *ph) { return PS_ERR; } int ps_pcontinue(const struct ps_prochandle *ph) { return PS_ERR; } int ps_lstop(const struct ps_prochandle *ph) { return PS_ERR; } int ps_lcontinue(const struct ps_prochandle *ph) { return PS_ERR; } /* read/write data or text memory */ int ps_pdread(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz) { if(get1(ph->map, addr, v, sz) < 0) return PS_ERR; return PS_OK; } int ps_pdwrite(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz) { if(put1(ph->map, addr, v, sz) < 0) return PS_ERR; return PS_OK; } int ps_ptread(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz) { return ps_pdread(ph, addr, v, sz); } int ps_ptwrite(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz) { return ps_pdwrite(ph, addr, v, sz); } int ps_lgetregs(struct ps_prochandle *ph, lwpid_t lwp, prgregset_t regs) { int i; USED(ph); if(corhdr == nil) return sys_ps_lgetregs(ph, lwp, regs); for(i=0; inthread; i++){ if(corhdr->thread[i].id == lwp){ ureg2prgregset(corhdr->thread[i].ureg, regs); return PS_OK; } } return PS_ERR; } int ps_lsetregs(struct ps_prochandle *ph, lwpid_t lwp, prgregset_t regs) { if(corhdr == nil) return sys_ps_lsetregs(ph, lwp, regs); return PS_ERR; } int ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lwp, prfpregset_t *fpregs) { if(corhdr == nil) return sys_ps_lgetfpregs(ph, lwp, fpregs); /* BUG - Look in core dump. */ return PS_ERR: } int ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lwp, prfpregset_t *fpregs) { if(corhdr == nil) return sys_ps_lsetfpregs(ph, lwp, fpregs); return PS_ERR; } /* Fetch the special per-thread address associated with the given LWP. This call is only used on a few platforms (most use a normal register). The meaning of the `int' parameter is machine-dependent. */ int ps_get_thread_area(struct ps_prochandle *ph, lwpid_t lwp, int xxx, psaddr_t *addr) { return sys_ps_get_thread_area(ph, lwp, xxx, addr); } int ps_pglobal_lookup(struct ps_prochandle *ph, char *object_name, char *sym_name, psaddr_t *sym_addr) { Fhdr *fp; ulong addr; if((fp = findhdr(object_name)) == nil){ print("libmach pthread: lookup %d %s %s => no such hdr\n", ph->pid, object_name, sym_name); return PS_NOSYM; } if(elfsymlookup(fp->elf, sym_name, &addr) < 0){ print("libmach pthread: lookup %d %s %s => name not found\n", ph->pid, object_name, sym_name); return PS_NOSYM; } /* print("libmach pthread: lookup %d %s %s => 0x%lux\n", ph->pid, object_name, sym_name, addr); */ *sym_addr = (void*)(addr+fp->base); return PS_OK; }