| #include <u.h> |
| #include <thread_db.h> |
| #include <sys/ptrace.h> |
| #include <errno.h> |
| #include <sys/procfs.h> /* psaddr_t */ |
| #include <libc.h> |
| #include <mach.h> |
| |
| 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; i<corhdr->nthread; 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; |
| } |
| |