123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <mach.h>
- #include "snap.h"
- /* research 16-bit crc. good enough. */
- static uint32_t
- sumr(uint32_t sum, void *buf, int n)
- {
- uint8_t *s, *send;
- if(buf == 0)
- return sum;
- for(s=buf, send=s+n; s<send; s++)
- if(sum & 1)
- sum = 0xffff & ((sum>>1)+*s+0x8000);
- else
- sum = 0xffff & ((sum>>1)+*s);
- return sum;
- }
- static int npage;
- static Page *pgtab[1<<10];
- Page*
- datapage(char *p, int32_t len)
- {
- Page *pg;
- char *q, *ep;
- int32_t sum;
- int iszero;
- if(len > Pagesize) {
- fprint(2, "datapage cannot handle pages > 1024\n");
- exits("datapage");
- }
- sum = sumr(0, p, len) & (nelem(pgtab)-1);
- if(sum == 0) {
- iszero = 1;
- for(q=p, ep=p+len; q<ep; q++)
- if(*q != 0) {
- iszero = 0;
- break;
- }
- } else
- iszero = 0;
- for(pg = pgtab[sum]; pg; pg=pg->link)
- if(pg->len == len && memcmp(pg->data, p, len) == 0)
- break;
- if(pg)
- return pg;
- pg = emalloc(sizeof(*pg)+len);
- pg->data = (char*)&pg[1];
- pg->type = 0;
- pg->len = len;
- memmove(pg->data, p, len);
- pg->link = pgtab[sum];
- pgtab[sum] = pg;
- if(iszero) {
- pg->type = 'z';
- pg->written = 1;
- }
- ++npage;
- return pg;
- }
- static Data*
- readsection(int32_t pid, char *sec)
- {
- char buf[8192];
- int n, fd;
- int hdr, tot;
- Data *d = nil;
- snprint(buf, sizeof buf, "/proc/%ld/%s", pid, sec);
- if((fd = open(buf, OREAD)) < 0)
- return nil;
- tot = 0;
- hdr = (int)((Data*)0)->data;
- while((n = read(fd, buf, sizeof buf)) > 0) {
- d = erealloc(d, tot+n+hdr);
- memmove(d->data+tot, buf, n);
- tot += n;
- }
- close(fd);
- if(d == nil)
- return nil;
- d->len = tot;
- return d;
- }
- static Seg*
- readseg(int fd, int64_t off, uint32_t len, char *name)
- {
- char buf[Pagesize];
- Page **pg;
- int npg;
- Seg *s;
- uint32_t i;
- int n;
- s = emalloc(sizeof(*s));
- s->name = estrdup(name);
- if(seek(fd, off, 0) < 0) {
- fprint(2, "seek fails\n");
- goto Die;
- }
- pg = nil;
- npg = 0;
- for(i=0; i<len; ) {
- n = Pagesize;
- if(n > len-i)
- n = len-i;
- if((n = readn(fd, buf, n)) <= 0)
- break;
- pg = erealloc(pg, sizeof(*pg)*(npg+1));
- pg[npg++] = datapage(buf, n);
- i += n;
- if(n != Pagesize) /* any short read, planned or otherwise */
- break;
- }
- if(i==0 && len!=0)
- goto Die;
- s->offset = off;
- s->len = i;
- s->pg = pg;
- s->npg = npg;
- return s;
- Die:
- free(s->name);
- free(s);
- return nil;
- }
- /* discover the stack pointer of the given process */
- uint32_t
- stackptr(Proc *proc, int fd)
- {
- char *q;
- Fhdr f;
- Reglist *r;
- int32_t textoff;
- int i;
- Data *dreg;
- textoff = -1;
- for(i=0; i<proc->nseg; i++)
- if(proc->seg[i] && strcmp(proc->seg[i]->name, "Text") == 0)
- textoff = proc->seg[i]->offset;
- if(textoff == -1)
- return 0;
- seek(fd, textoff, 0);
- if(crackhdr(fd, &f) == 0)
- return 0;
- machbytype(f.type);
- for(r=mach->reglist; r->rname; r++)
- if(strcmp(r->rname, mach->sp) == 0)
- break;
- if(r == nil) {
- fprint(2, "couldn't find stack pointer register?\n");
- return 0;
- }
-
- if((dreg = proc->d[Pregs]) == nil)
- return 0;
- if(r->roffs+mach->szreg > dreg->len) {
- fprint(2, "SP register too far into registers?\n");
- return 0;
- }
- q = dreg->data+r->roffs;
- switch(mach->szreg) {
- case 2: return machdata->swab(*(uint16_t*)q);
- case 4: return machdata->swal(*(uint32_t*)q);
- case 8: return machdata->swav(*(uint64_t*)q);
- default:
- fprint(2, "register size is %d bytes?\n", mach->szreg);
- return 0;
- }
- }
- Proc*
- snap(int32_t pid, int usetext)
- {
- Data *d;
- Proc *proc;
- Seg **s;
- char *name, *segdat, *q, *f[128+1], buf[128];
- int fd, i, stacki, nf, np;
- uint64_t off, len, stackoff, stacklen;
- uint64_t sp;
- proc = emalloc(sizeof(*proc));
- proc->pid = pid;
- np = 0;
- for(i=0; i<Npfile; i++) {
- if(proc->d[i] = readsection(pid, pfile[i]))
- np++;
- else
- fprint(2, "warning: can't include /proc/%ld/%s\n", pid, pfile[i]);
- }
- if(np == 0)
- return nil;
- if(usetext) {
- snprint(buf, sizeof buf, "/proc/%ld/text", pid);
- if((fd = open(buf, OREAD)) >= 0) {
- werrstr("");
- if((proc->text = readseg(fd, 0, 1<<31, "textfile")) == nil)
- fprint(2, "warning: can't include %s: %r\n", buf);
- close(fd);
- } else
- fprint(2, "warning: can't include /proc/%ld/text\n", pid);
- }
- if((d=proc->d[Psegment]) == nil) {
- fprint(2, "warning: no segment table, no memory image\n");
- return proc;
- }
- segdat = emalloc(d->len+1);
- memmove(segdat, d->data, d->len);
- segdat[d->len] = 0;
- nf = getfields(segdat, f, nelem(f), 1, "\n");
- if(nf == nelem(f)) {
- nf--;
- fprint(2, "process %ld has >%d segments; only using first %d\n",
- pid, nf, nf);
- }
- if(nf <= 0) {
- fprint(2, "warning: couldn't understand segment table, no memory image\n");
- free(segdat);
- return proc;
- }
- snprint(buf, sizeof buf, "/proc/%ld/mem", pid);
- if((fd = open(buf, OREAD)) < 0) {
- fprint(2, "warning: can't include /proc/%ld/mem\n", pid);
- return proc;
- }
- s = emalloc(nf*sizeof(*s));
- stacklen = 0;
- stackoff = 0;
- stacki = 0;
- for(i=0; i<nf; i++) {
- if(q = strchr(f[i], ' '))
- *q = 0;
- name = f[i];
- off = strtoull(name+10, &q, 16);
- len = strtoull(q, &q, 16) - off;
- if(strcmp(name, "Stack") == 0) {
- stackoff = off;
- stacklen = len;
- stacki = i;
- } else
- s[i] = readseg(fd, off, len, name);
- }
- proc->nseg = nf;
- proc->seg = s;
- /* stack hack: figure sp so don't need to page in the whole segment */
- if(stacklen) {
- sp = stackptr(proc, fd);
- if(stackoff <= sp && sp < stackoff+stacklen) {
- off = (sp - Pagesize) & ~(Pagesize - 1);
- if(off < stackoff)
- off = stackoff;
- len = stacklen - (off - stackoff);
- } else { /* stack pointer not in segment. thread library? */
- off = stackoff + stacklen - 16*1024;
- len = 16*1024;
- }
- s[stacki] = readseg(fd, off, len, "Stack");
- }
- return proc;
- }
|