tmore features - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit e8a7b9699925f3f650593d07eb382155e9374ae6
 (DIR) parent 2189e55cde473b2a81492759526f824b0ecd227e
 (HTM) Author: rsc <devnull@localhost>
       Date:   Mon, 27 Dec 2004 17:01:23 +0000
       
       more features
       
       Diffstat:
         A src/libmach/cmdline.c               |     187 +++++++++++++++++++++++++++++++
         A src/libmach/elfdl386.c              |     133 +++++++++++++++++++++++++++++++
         A src/libmach/elfnm.c                 |      38 +++++++++++++++++++++++++++++++
         A src/libmach/pthread.c               |      49 +++++++++++++++++++++++++++++++
         A src/libmach/t.c                     |     269 +++++++++++++++++++++++++++++++
       
       5 files changed, 676 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/src/libmach/cmdline.c b/src/libmach/cmdline.c
       t@@ -0,0 +1,187 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +
       +Fhdr *symhdr;
       +Fhdr *corhdr;
       +char *symfil;
       +char *corfil;
       +int corpid;
       +Regs *correg;
       +Map *symmap;
       +Map *cormap;
       +
       +int
       +alldigs(char *s)
       +{
       +        while(*s){
       +                if(*s<'0' || '9'<*s)
       +                        return 0;
       +                s++;
       +        }
       +        return 1;
       +}
       +
       +/*
       + * attach to arguments in argc, argv
       + */
       +int
       +attachargs(int argc, char **argv, int omode)
       +{
       +        int i;
       +        Fhdr *hdr;
       +        char *s;
       +
       +        symhdr = nil;
       +        corhdr = nil;
       +        symfil = nil;
       +        corfil = nil;
       +        corpid = 0;
       +        correg = nil;
       +
       +        for(i=0; i<argc; i++){
       +                if(alldigs(argv[i])){
       +                        if(corpid){
       +                                fprint(2, "already have corpid %d; ignoring corpid %d\n", corpid, argv[i]);
       +                                continue;
       +                        }
       +                        if(corhdr){
       +                                fprint(2, "already have core %s; ignoring corpid %d\n", corfil, corpid);
       +                                continue;
       +                        }
       +                        corpid = atoi(argv[i]);
       +                        continue;
       +                }
       +                if((hdr = crackhdr(argv[i], omode)) == nil){
       +                        fprint(2, "crackhdr %s: %r\n", argv[i]);
       +                        continue;
       +                }
       +                fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);
       +                if(hdr->ftype == FCORE){
       +                        if(corpid){
       +                                fprint(2, "already have corpid %d; ignoring core %s\n", corpid, argv[i]);
       +                                uncrackhdr(hdr);
       +                                continue;
       +                        }
       +                        if(corhdr){
       +                                fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]);
       +                                uncrackhdr(hdr);
       +                                continue;
       +                        }
       +                        corhdr = hdr;
       +                        corfil = argv[i];
       +                }else{
       +                        if(symhdr){
       +                                fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]);
       +                                uncrackhdr(hdr);
       +                                continue;
       +                        }
       +                        symhdr = hdr;
       +                        symfil = argv[i];
       +                }
       +        }
       +
       +        if(symhdr == nil){
       +                symfil = "a.out";        /* default */
       +                if(corpid){        /* try from corpid */
       +                        if((s = proctextfile(corpid)) != nil){
       +                                fprint(2, "corpid %d: text %s\n", corpid, s);
       +                                symfil = s;
       +                        }
       +                }
       +                if(corhdr){        /* try from core */
       +                        if(corhdr->txtfil != nil){
       +                                fprint(2, "core %s: text %s\n", corfil, corhdr->txtfil);
       +                                symfil = corhdr->txtfil;
       +                        }
       +                }
       +                if((symhdr = crackhdr(symfil, omode)) == nil){
       +                        fprint(2, "crackhdr %s: %r\n", symfil);
       +                        symfil = nil;
       +                }
       +        }
       +
       +        if(symhdr)
       +                syminit(symhdr);
       +
       +        if(!mach)
       +                mach = machcpu;
       +
       +        /*
       +         * Set up maps
       +         */
       +        symmap = allocmap();
       +        cormap = allocmap();
       +        if(symmap == nil || cormap == nil)
       +                sysfatal("allocating maps: %r");
       +
       +        if(symhdr){
       +                if(mapfile(symhdr, 0, symmap, nil) < 0)
       +                        fprint(2, "mapfile %s: %r\n", symfil);
       +                mapfile(symhdr, 0, cormap, nil);
       +        }
       +
       +        if(corpid)        
       +                attachproc(corpid);
       +
       +        if(corhdr)
       +                attachcore(corhdr);
       +
       +        return 0;
       +}
       +
       +static int thecorpid;
       +static Fhdr *thecorhdr;
       +
       +static void
       +unattach(void)
       +{
       +        unmapproc(cormap);
       +        unmapfile(corhdr, cormap);
       +        free(correg);
       +        correg = nil;
       +        thecorpid = 0;
       +        thecorhdr = nil;
       +        corpid = 0;
       +        corhdr = nil;
       +        corfil = nil;
       +}
       +
       +int
       +attachproc(int pid)
       +{
       +        unattach();
       +        if(pid == 0)
       +                return 0;
       +        if(mapproc(pid, cormap, &correg) < 0){
       +                fprint(2, "attachproc %d: %r\n", pid);
       +                return -1;
       +        }
       +        thecorpid = pid;
       +        corpid = pid;
       +        return 0;
       +}
       +
       +int
       +attachcore(Fhdr *hdr)
       +{
       +        unattach();
       +        if(corhdr == nil)
       +                return 0;
       +        if(mapfile(hdr, 0, cormap, &correg) < 0){
       +                fprint(2, "attachcore %s: %r\n", hdr->filename);
       +                return -1;
       +        }
       +        thecorhdr = hdr;
       +        corhdr = hdr;
       +        corfil = hdr->filename;
       +        return 0;
       +}
       +
       +int
       +attachdynamic(void)
       +{
       +        elfdl386mapdl();
       +        return 0;
       +}
       +
 (DIR) diff --git a/src/libmach/elfdl386.c b/src/libmach/elfdl386.c
       t@@ -0,0 +1,133 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "elf.h"
       +
       +/*
       +aggr Linkdebug
       +{
       +        'X' 0 version;
       +        'X' 4 map;
       +};
       +
       +aggr Linkmap
       +{
       +        'X' 0 addr;
       +        'X' 4 name;
       +        'X' 8 dynsect;
       +        'X' 12 next;
       +        'X' 16 prev;
       +};
       +*/
       +enum
       +{
       +        DT_NULL = 0,
       +        DT_NEEDED,
       +        DT_PLTRRELSZ,
       +        DT_PLTGOT,
       +        DT_HASH,
       +        DT_STRTAB,
       +        DT_SYMTAB,
       +        DT_RELA,
       +        DT_RELASZ = 8,
       +        DT_RELAENT,
       +        DT_STSZ,
       +        DT_SYMENT,
       +        DT_INIT,
       +        DT_FINI,
       +        DT_SONAME,
       +        DT_RPATH,
       +        DT_SYMBOLIC = 16,
       +        DT_REL,
       +        DT_RELSZ,
       +        DT_RELENT,
       +        DT_PLTREL,
       +        DT_DEBUG,
       +        DT_TEXTREL,
       +        DT_JMPREL,
       +};
       +
       +static int
       +getstr(Map *map, ulong addr, char *buf, uint nbuf)
       +{
       +        int i;
       +
       +        for(i=0; i<nbuf; i++){
       +                if(get1(map, addr+i, buf+i, 1) < 0)
       +                        return -1;
       +                if(buf[i] == 0)
       +                        return 0;
       +        }
       +        return -1;        /* no nul */
       +}
       +
       +static ulong
       +dyninfo(Fhdr *hdr, int x)
       +{
       +        u32int addr, u;
       +
       +        if(hdr == nil || (addr = ((Elf*)hdr->elf)->dynamic) == 0){
       +                fprint(2, "no hdr/dynamic %p\n", hdr);
       +                return 0;
       +        }
       +        addr += hdr->base;
       +
       +        while(addr != 0){
       +                if(get4(cormap, addr, &u) < 0)
       +                        return 0;
       +                if(u == x){
       +                        if(get4(cormap, addr+4, &u) < 0)
       +                                return 0;
       +                        return u;
       +                }
       +                addr += 8;
       +        }
       +        return 0;
       +}
       +
       +void
       +elfdl386mapdl(void)
       +{
       +        int i;
       +        Fhdr *hdr;
       +        u32int linkdebug, linkmap, name, addr;
       +        char buf[1024];
       +
       +print("elfdl386mapdl\n");
       +        if((linkdebug = dyninfo(symhdr, DT_DEBUG)) == 0){
       +                fprint(2, "no dt_debug section\n");
       +                return;
       +        }
       +        if(get4(cormap, linkdebug+4, &linkmap) < 0){
       +                fprint(2, "get4 linkdebug+4 (0x%lux) failed\n", linkdebug);
       +                return;
       +        }
       +
       +        for(i=0; i<100 && linkmap != 0; i++){
       +                if(get4(cormap, linkmap, &addr) < 0
       +                || get4(cormap, linkmap+4, &name) < 0
       +                || get4(cormap, linkmap+12, &linkmap) < 0)
       +                        break;
       +
       +                if(name
       +                && getstr(cormap, name, buf, sizeof buf) >= 0
       +                && buf[0]
       +                && access(buf, AEXIST) >= 0){
       +                        if((hdr = crackhdr(buf, OREAD)) == nil)
       +                                fprint(2, "crackhdr %s: %r\n", buf);
       +                        else{
       +                                fprint(2, "%s: %s %s %s\n", buf, hdr->aname, hdr->mname, hdr->fname);
       +                                hdr->base = addr;
       +                                if(mapfile(hdr, addr, symmap, nil) < 0)
       +                                        fprint(2, "mapfile %s: %r\n", buf);
       +                                if(corhdr){
       +                                        unmapfile(corhdr, cormap);
       +                                        mapfile(hdr, addr, cormap, nil);
       +                                }
       +                                if(syminit(hdr) < 0)
       +                                        fprint(2, "syminit %s: %\r", buf);
       +                        }
       +                }        
       +        }
       +}
       +
 (DIR) diff --git a/src/libmach/elfnm.c b/src/libmach/elfnm.c
       t@@ -0,0 +1,38 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include <elf.h>
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: elfnm file...\n");
       +        exits("usage");
       +}
       +
       +void
       +main(int argc, char **argv)
       +{
       +        ElfSym esym;
       +        Fhdr *fp;
       +        int i, j;
       +
       +        ARGBEGIN{
       +        default:
       +                usage();
       +        }ARGEND
       +
       +        if(argc == 0)
       +                usage();
       +
       +        for(i=0; i<argc; i++){
       +                if((fp = crackhdr(argv[i], OREAD)) == nil){
       +                        fprint(2, "%s: %r\n", argv[i]);
       +                        continue;
       +                }
       +                for(j=0; elfsym(fp->elf, j, &esym)>=0; j++)
       +                        print("%s 0x%lux\n", esym.name, esym.value);
       +                uncrackhdr(fp);
       +        }
       +        exits(0);
       +}
 (DIR) diff --git a/src/libmach/pthread.c b/src/libmach/pthread.c
       t@@ -0,0 +1,49 @@
       +#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>
       +
       +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];
       +}
       +
 (DIR) diff --git a/src/libmach/t.c b/src/libmach/t.c
       t@@ -0,0 +1,269 @@
       +#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>
       +#include "ureg386.h"
       +
       +int td_get_allthreads(td_thragent_t *ta, td_thrhandle_t **pall);
       +
       +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];
       +}
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: t pid\n");
       +        exits("usage");
       +}
       +
       +#define        STRINGSZ        128
       +
       +/*
       + *        print the value of dot as file:line
       + */
       +void
       +printsource(long dot)
       +{
       +        char str[STRINGSZ];
       +
       +        if (fileline(dot, str, STRINGSZ) >= 0)
       +                print("%s", str);
       +}
       +
       +void
       +printlocals(Symbol *fn, Regs *regs)
       +{
       +        int i;
       +        u32int v;
       +        Symbol s;
       +
       +        for (i = 0; indexlsym(fn, i, &s)>=0; i++) {
       +                if (s.class != CAUTO)
       +                        continue;
       +                if(lget4(cormap, regs, s.loc, &v) >= 0)
       +                        print("\t%s.%s/\t%#lux\n", fn->name, s.name, v);
       +                else
       +                        print("\t%s.%s/\t?\n", fn->name, s.name);
       +        }
       +}
       +
       +void
       +printparams(Symbol *fn, Regs *regs)
       +{
       +        int i;
       +        Symbol s;
       +        u32int v;
       +        int first = 0;
       +        ulong pc, sp, bp;
       +
       +        if(0) print("pc=%lux sp=%lux bp=%lux ", 
       +                (rget(regs, "PC", &pc), pc),
       +                (rget(regs, "SP", &sp), sp),
       +                (rget(regs, "BP", &bp), bp));
       +        for (i = 0; indexlsym(fn, i, &s)>=0; i++) {
       +                if (s.class != CPARAM)
       +                        continue;
       +                if (first++)
       +                        print(", ");
       +                if(0) print("(%d.%s.%ux.%x)", s.loc.type, s.loc.reg, s.loc.addr, s.loc.offset);
       +                if(lget4(cormap, regs, s.loc, &v) >= 0)
       +                        print("%s=%#lux", s.name, v);
       +                else
       +                        print("%s=?", s.name);
       +        }
       +}
       +
       +/*
       + *        callback on stack trace
       + */
       +static int
       +xtrace(Map *map, Regs *regs, ulong pc, ulong nextpc, Symbol *sym, int depth)
       +{
       +        char buf[512];
       +
       +        USED(map);
       +        print("\t");
       +        if(sym){
       +                print("%s(", sym->name);
       +                printparams(sym, regs);
       +                print(")+0x%ux ", pc-sym->loc.addr);
       +        }else
       +                print("%#lux ", pc);
       +        printsource(pc);
       +
       +        print(" called from ");
       +        symoff(buf, 512, nextpc, CTEXT);
       +        print("%s ", buf);
       +/*        printsource(nextpc); */
       +        print("\n");
       +        if(sym)
       +                printlocals(sym, regs);
       +        return depth<40;
       +}
       +
       +void
       +main(int argc, char **argv)
       +{
       +        struct ps_prochandle p;
       +        prgregset_t regs;
       +        int e;
       +        td_thragent_t *ta;
       +        td_thrhandle_t *ts;
       +        td_thrinfo_t info;
       +        int i, n;
       +        Ureg *u;
       +        UregRegs r;
       +
       +        ARGBEGIN{
       +        default:
       +                usage();
       +        }ARGEND
       +
       +        attachargs(argc, argv, OREAD);
       +        attachdynamic();
       +
       +        if(!corpid && !corhdr)
       +                sysfatal("could not attach to process");
       +
       +        p.pid = corpid;
       +        if((e = td_ta_new(&p, &ta)) != TD_OK)
       +                sysfatal("td_ta_new: %s", terr(e));
       +        if((e = td_ta_get_nthreads(ta, &n)) != TD_OK)
       +                sysfatal("td_ta_get_nthreads: %s", terr(e));
       +        print("%d threads\n", n);
       +
       +        if((n = td_get_allthreads(ta, &ts)) < 0)
       +                sysfatal("td_get_allthreads: %r");
       +        print("%d threads - regs = %p\n", n, regs);
       +        for(i=0; i<n; i++){
       +                if((e = td_thr_get_info(&ts[i], &info)) != TD_OK)
       +                        sysfatal("td_thr_get_info: %s", terr(e));
       +                print("%d: startfunc=%lux stkbase=%lux pc=%lux sp=%lux lid=%d\n",
       +                        i, info.ti_startfunc, info.ti_stkbase, info.ti_pc, info.ti_sp, info.ti_lid);        
       +                if((e = td_thr_getgregs(&ts[i], regs)) != TD_OK)
       +                        sysfatal("td_thr_getregs: %s", terr(e));
       +                print("%d: pc=%lux sp=%lux gs=%lux\n", i, regs[12], regs[15], regs[10]);
       +                if((u = _linux2ureg386((UregLinux386*)regs)) == nil)
       +                        sysfatal("%r");
       +                r.r.rw = _uregrw;
       +                r.ureg = (uchar*)u;
       +                stacktrace(cormap, &r.r, xtrace);
       +        }
       +        exits(0);
       +}
       +
       +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;
       +}
       +
       +/* 
       +td_err_e td_ta_map_id2thr(const td_thragent_t *ta_p, thread_t tid,td_thrhandle_t *th_p);
       +*/
       +
       +/*
       +int
       +threadregs(int tid, Regs **rp)
       +{
       +        check pid
       +        look up tid (td_ta_map_id2thr)
       +        create Regs with thr handle inside
       +        rw function calls thr_getregs and then
       +                pulls out the desired register
       +}
       +
       +*/