xref: /plan9/sys/src/cmd/snap/take.c (revision 50e5f38d649a06ef8aef42696e09b6c4c5964957)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <mach.h>
57dd7cddfSDavid du Colombier #include "snap.h"
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier /* research 16-bit crc.  good enough. */
87dd7cddfSDavid du Colombier static ulong
sumr(ulong sum,void * buf,int n)97dd7cddfSDavid du Colombier sumr(ulong sum, void *buf, int n)
107dd7cddfSDavid du Colombier {
117dd7cddfSDavid du Colombier 	uchar *s, *send;
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier 	if(buf == 0)
147dd7cddfSDavid du Colombier 		return sum;
157dd7cddfSDavid du Colombier 	for(s=buf, send=s+n; s<send; s++)
167dd7cddfSDavid du Colombier 		if(sum & 1)
177dd7cddfSDavid du Colombier 			sum = 0xffff & ((sum>>1)+*s+0x8000);
187dd7cddfSDavid du Colombier 		else
197dd7cddfSDavid du Colombier 			sum = 0xffff & ((sum>>1)+*s);
207dd7cddfSDavid du Colombier 	return sum;
217dd7cddfSDavid du Colombier }
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier static int npage;
247dd7cddfSDavid du Colombier static Page *pgtab[1<<10];
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier Page*
datapage(char * p,long len)277dd7cddfSDavid du Colombier datapage(char *p, long len)
287dd7cddfSDavid du Colombier {
297dd7cddfSDavid du Colombier 	Page *pg;
307dd7cddfSDavid du Colombier 	char *q, *ep;
317dd7cddfSDavid du Colombier 	long	sum;
327dd7cddfSDavid du Colombier 	int iszero;
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier 	if(len > Pagesize) {
357dd7cddfSDavid du Colombier 		fprint(2, "datapage cannot handle pages > 1024\n");
367dd7cddfSDavid du Colombier 		exits("datapage");
377dd7cddfSDavid du Colombier 	}
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier 	sum = sumr(0, p, len) & (nelem(pgtab)-1);
407dd7cddfSDavid du Colombier 	if(sum == 0) {
417dd7cddfSDavid du Colombier 		iszero = 1;
427dd7cddfSDavid du Colombier 		for(q=p, ep=p+len; q<ep; q++)
437dd7cddfSDavid du Colombier 			if(*q != 0) {
447dd7cddfSDavid du Colombier 				iszero = 0;
457dd7cddfSDavid du Colombier 				break;
467dd7cddfSDavid du Colombier 			}
477dd7cddfSDavid du Colombier 	} else
487dd7cddfSDavid du Colombier 		iszero = 0;
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier 	for(pg = pgtab[sum]; pg; pg=pg->link)
517dd7cddfSDavid du Colombier 		if(pg->len == len && memcmp(pg->data, p, len) == 0)
527dd7cddfSDavid du Colombier 			break;
537dd7cddfSDavid du Colombier 	if(pg)
547dd7cddfSDavid du Colombier 		return pg;
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier 	pg = emalloc(sizeof(*pg)+len);
577dd7cddfSDavid du Colombier 	pg->data = (char*)&pg[1];
587dd7cddfSDavid du Colombier 	pg->type = 0;
597dd7cddfSDavid du Colombier 	pg->len = len;
607dd7cddfSDavid du Colombier 	memmove(pg->data, p, len);
617dd7cddfSDavid du Colombier 	pg->link = pgtab[sum];
627dd7cddfSDavid du Colombier 	pgtab[sum] = pg;
637dd7cddfSDavid du Colombier 	if(iszero) {
647dd7cddfSDavid du Colombier 		pg->type = 'z';
657dd7cddfSDavid du Colombier 		pg->written = 1;
667dd7cddfSDavid du Colombier 	}
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier 	++npage;
697dd7cddfSDavid du Colombier 	return pg;
707dd7cddfSDavid du Colombier }
717dd7cddfSDavid du Colombier 
727dd7cddfSDavid du Colombier static Data*
readsection(long pid,char * sec)737dd7cddfSDavid du Colombier readsection(long pid, char *sec)
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier 	char buf[8192];
767dd7cddfSDavid du Colombier 	int n, fd;
777dd7cddfSDavid du Colombier 	int hdr, tot;
787dd7cddfSDavid du Colombier 	Data *d = nil;
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "/proc/%ld/%s", pid, sec);
817dd7cddfSDavid du Colombier 	if((fd = open(buf, OREAD)) < 0)
827dd7cddfSDavid du Colombier 		return nil;
837dd7cddfSDavid du Colombier 
847dd7cddfSDavid du Colombier 	tot = 0;
857dd7cddfSDavid du Colombier 	hdr = (int)((Data*)0)->data;
867dd7cddfSDavid du Colombier 	while((n = read(fd, buf, sizeof buf)) > 0) {
877dd7cddfSDavid du Colombier 		d = erealloc(d, tot+n+hdr);
887dd7cddfSDavid du Colombier 		memmove(d->data+tot, buf, n);
897dd7cddfSDavid du Colombier 		tot += n;
907dd7cddfSDavid du Colombier 	}
917dd7cddfSDavid du Colombier 	close(fd);
927dd7cddfSDavid du Colombier 	if(d == nil)
937dd7cddfSDavid du Colombier 		return nil;
947dd7cddfSDavid du Colombier 	d->len = tot;
957dd7cddfSDavid du Colombier 	return d;
967dd7cddfSDavid du Colombier }
977dd7cddfSDavid du Colombier 
987dd7cddfSDavid du Colombier static Seg*
readseg(int fd,vlong off,ulong len,char * name)99*50e5f38dSDavid du Colombier readseg(int fd, vlong off, ulong len, char *name)
1007dd7cddfSDavid du Colombier {
1017dd7cddfSDavid du Colombier 	char buf[Pagesize];
1027dd7cddfSDavid du Colombier 	Page **pg;
1037dd7cddfSDavid du Colombier 	int npg;
1047dd7cddfSDavid du Colombier 	Seg *s;
1057dd7cddfSDavid du Colombier 	ulong i;
1067dd7cddfSDavid du Colombier 	int n;
1077dd7cddfSDavid du Colombier 
1087dd7cddfSDavid du Colombier 	s = emalloc(sizeof(*s));
1097dd7cddfSDavid du Colombier 	s->name = estrdup(name);
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier 	if(seek(fd, off, 0) < 0) {
1127dd7cddfSDavid du Colombier 		fprint(2, "seek fails\n");
1137dd7cddfSDavid du Colombier 		goto Die;
1147dd7cddfSDavid du Colombier 	}
1157dd7cddfSDavid du Colombier 
1167dd7cddfSDavid du Colombier 	pg = nil;
1177dd7cddfSDavid du Colombier 	npg = 0;
1187dd7cddfSDavid du Colombier 	for(i=0; i<len; ) {
1197dd7cddfSDavid du Colombier 		n = Pagesize;
1207dd7cddfSDavid du Colombier 		if(n > len-i)
1217dd7cddfSDavid du Colombier 			n = len-i;
1227dd7cddfSDavid du Colombier 		if((n = readn(fd, buf, n)) <= 0)
1237dd7cddfSDavid du Colombier 			break;
1247dd7cddfSDavid du Colombier 		pg = erealloc(pg, sizeof(*pg)*(npg+1));
1257dd7cddfSDavid du Colombier 		pg[npg++] = datapage(buf, n);
1267dd7cddfSDavid du Colombier 		i += n;
1277dd7cddfSDavid du Colombier 		if(n != Pagesize)	/* any short read, planned or otherwise */
1287dd7cddfSDavid du Colombier 			break;
1297dd7cddfSDavid du Colombier 	}
1307dd7cddfSDavid du Colombier 
1313ff48bf5SDavid du Colombier 	if(i==0 && len!=0)
1327dd7cddfSDavid du Colombier 		goto Die;
1337dd7cddfSDavid du Colombier 
1347dd7cddfSDavid du Colombier 	s->offset = off;
1357dd7cddfSDavid du Colombier 	s->len = i;
1367dd7cddfSDavid du Colombier 	s->pg = pg;
1377dd7cddfSDavid du Colombier 	s->npg = npg;
1387dd7cddfSDavid du Colombier 	return s;
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier Die:
1417dd7cddfSDavid du Colombier 	free(s->name);
1427dd7cddfSDavid du Colombier 	free(s);
1437dd7cddfSDavid du Colombier 	return nil;
1447dd7cddfSDavid du Colombier }
1457dd7cddfSDavid du Colombier 
1467dd7cddfSDavid du Colombier /* discover the stack pointer of the given process */
1477dd7cddfSDavid du Colombier ulong
stackptr(Proc * proc,int fd)1487dd7cddfSDavid du Colombier stackptr(Proc *proc, int fd)
1497dd7cddfSDavid du Colombier {
1507dd7cddfSDavid du Colombier 	char *q;
1517dd7cddfSDavid du Colombier 	Fhdr f;
1527dd7cddfSDavid du Colombier 	Reglist *r;
1537dd7cddfSDavid du Colombier 	long textoff;
1547dd7cddfSDavid du Colombier 	int i;
1557dd7cddfSDavid du Colombier 	Data *dreg;
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier 	textoff = -1;
1587dd7cddfSDavid du Colombier 	for(i=0; i<proc->nseg; i++)
1597dd7cddfSDavid du Colombier 		if(proc->seg[i] && strcmp(proc->seg[i]->name, "Text") == 0)
1607dd7cddfSDavid du Colombier 			textoff = proc->seg[i]->offset;
1617dd7cddfSDavid du Colombier 
1627dd7cddfSDavid du Colombier 	if(textoff == -1)
1637dd7cddfSDavid du Colombier 		return 0;
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier 	seek(fd, textoff, 0);
1667dd7cddfSDavid du Colombier 	if(crackhdr(fd, &f) == 0)
1677dd7cddfSDavid du Colombier 		return 0;
1687dd7cddfSDavid du Colombier 
1697dd7cddfSDavid du Colombier 	machbytype(f.type);
1707dd7cddfSDavid du Colombier 	for(r=mach->reglist; r->rname; r++)
1717dd7cddfSDavid du Colombier 		if(strcmp(r->rname, mach->sp) == 0)
1727dd7cddfSDavid du Colombier 			break;
1737dd7cddfSDavid du Colombier 	if(r == nil) {
1747dd7cddfSDavid du Colombier 		fprint(2, "couldn't find stack pointer register?\n");
1757dd7cddfSDavid du Colombier 		return 0;
1767dd7cddfSDavid du Colombier 	}
1777dd7cddfSDavid du Colombier 
1787dd7cddfSDavid du Colombier 	if((dreg = proc->d[Pregs]) == nil)
1797dd7cddfSDavid du Colombier 		return 0;
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier 	if(r->roffs+mach->szreg > dreg->len) {
1827dd7cddfSDavid du Colombier 		fprint(2, "SP register too far into registers?\n");
1837dd7cddfSDavid du Colombier 		return 0;
1847dd7cddfSDavid du Colombier 	}
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier 	q = dreg->data+r->roffs;
1877dd7cddfSDavid du Colombier 	switch(mach->szreg) {
1887dd7cddfSDavid du Colombier 	case 2:	return machdata->swab(*(ushort*)q);
1897dd7cddfSDavid du Colombier 	case 4:	return machdata->swal(*(ulong*)q);
190*50e5f38dSDavid du Colombier 	case 8:	return machdata->swav(*(uvlong*)q);
1917dd7cddfSDavid du Colombier 	default:
1927dd7cddfSDavid du Colombier 		fprint(2, "register size is %d bytes?\n", mach->szreg);
1937dd7cddfSDavid du Colombier 		return 0;
1947dd7cddfSDavid du Colombier 	}
1957dd7cddfSDavid du Colombier }
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier Proc*
snap(long pid,int usetext)1987dd7cddfSDavid du Colombier snap(long pid, int usetext)
1997dd7cddfSDavid du Colombier {
2007dd7cddfSDavid du Colombier 	Data *d;
2017dd7cddfSDavid du Colombier 	Proc *proc;
2027dd7cddfSDavid du Colombier 	Seg **s;
203*50e5f38dSDavid du Colombier 	char *name, *segdat, *q, *f[128+1], buf[128];
2047dd7cddfSDavid du Colombier 	int fd, i, stacki, nf, np;
205*50e5f38dSDavid du Colombier 	uvlong off, len, stackoff, stacklen;
206*50e5f38dSDavid du Colombier 	uvlong sp;
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 	proc = emalloc(sizeof(*proc));
2097dd7cddfSDavid du Colombier 	proc->pid = pid;
2107dd7cddfSDavid du Colombier 
2117dd7cddfSDavid du Colombier 	np = 0;
2127dd7cddfSDavid du Colombier 	for(i=0; i<Npfile; i++) {
2137dd7cddfSDavid du Colombier 		if(proc->d[i] = readsection(pid, pfile[i]))
2147dd7cddfSDavid du Colombier 			np++;
2157dd7cddfSDavid du Colombier 		else
2167dd7cddfSDavid du Colombier 			fprint(2, "warning: can't include /proc/%ld/%s\n", pid, pfile[i]);
2177dd7cddfSDavid du Colombier 	}
2187dd7cddfSDavid du Colombier 	if(np == 0)
2197dd7cddfSDavid du Colombier 		return nil;
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier 	if(usetext) {
2227dd7cddfSDavid du Colombier 		snprint(buf, sizeof buf, "/proc/%ld/text", pid);
2237dd7cddfSDavid du Colombier 		if((fd = open(buf, OREAD)) >= 0) {
2247dd7cddfSDavid du Colombier 			werrstr("");
2257dd7cddfSDavid du Colombier 			if((proc->text = readseg(fd, 0, 1<<31, "textfile")) == nil)
2267dd7cddfSDavid du Colombier 				fprint(2, "warning: can't include %s: %r\n", buf);
2277dd7cddfSDavid du Colombier 			close(fd);
2287dd7cddfSDavid du Colombier 		} else
2297dd7cddfSDavid du Colombier 			fprint(2, "warning: can't include /proc/%ld/text\n", pid);
2307dd7cddfSDavid du Colombier 	}
2317dd7cddfSDavid du Colombier 
2327dd7cddfSDavid du Colombier 	if((d=proc->d[Psegment]) == nil) {
2337dd7cddfSDavid du Colombier 		fprint(2, "warning: no segment table, no memory image\n");
2347dd7cddfSDavid du Colombier 		return proc;
2357dd7cddfSDavid du Colombier 	}
2367dd7cddfSDavid du Colombier 
2377dd7cddfSDavid du Colombier 	segdat = emalloc(d->len+1);
2387dd7cddfSDavid du Colombier 	memmove(segdat, d->data, d->len);
2397dd7cddfSDavid du Colombier 	segdat[d->len] = 0;
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier 	nf = getfields(segdat, f, nelem(f), 1, "\n");
2427dd7cddfSDavid du Colombier 	if(nf == nelem(f)) {
2437dd7cddfSDavid du Colombier 		nf--;
2447dd7cddfSDavid du Colombier 		fprint(2, "process %ld has >%d segments; only using first %d\n",
2457dd7cddfSDavid du Colombier 			pid, nf, nf);
2467dd7cddfSDavid du Colombier 	}
2477dd7cddfSDavid du Colombier 	if(nf <= 0) {
2487dd7cddfSDavid du Colombier 		fprint(2, "warning: couldn't understand segment table, no memory image\n");
2497dd7cddfSDavid du Colombier 		free(segdat);
2507dd7cddfSDavid du Colombier 		return proc;
2517dd7cddfSDavid du Colombier 	}
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "/proc/%ld/mem", pid);
2547dd7cddfSDavid du Colombier 	if((fd = open(buf, OREAD)) < 0) {
2557dd7cddfSDavid du Colombier 		fprint(2, "warning: can't include /proc/%ld/mem\n", pid);
2567dd7cddfSDavid du Colombier 		return proc;
2577dd7cddfSDavid du Colombier 	}
2587dd7cddfSDavid du Colombier 
2597dd7cddfSDavid du Colombier 	s = emalloc(nf*sizeof(*s));
2607dd7cddfSDavid du Colombier 	stacklen = 0;
2617dd7cddfSDavid du Colombier 	stackoff = 0;
2627dd7cddfSDavid du Colombier 	stacki = 0;
2637dd7cddfSDavid du Colombier 	for(i=0; i<nf; i++) {
2647dd7cddfSDavid du Colombier 		if(q = strchr(f[i], ' '))
2657dd7cddfSDavid du Colombier 			*q = 0;
266*50e5f38dSDavid du Colombier 		name = f[i];
267*50e5f38dSDavid du Colombier 		off = strtoull(name+10, &q, 16);
268*50e5f38dSDavid du Colombier 		len = strtoull(q, &q, 16) - off;
269*50e5f38dSDavid du Colombier 		if(strcmp(name, "Stack") == 0) {
2707dd7cddfSDavid du Colombier 			stackoff = off;
2717dd7cddfSDavid du Colombier 			stacklen = len;
2727dd7cddfSDavid du Colombier 			stacki = i;
2737dd7cddfSDavid du Colombier 		} else
274*50e5f38dSDavid du Colombier 			s[i] = readseg(fd, off, len, name);
2757dd7cddfSDavid du Colombier 	}
2767dd7cddfSDavid du Colombier 	proc->nseg = nf;
2777dd7cddfSDavid du Colombier 	proc->seg = s;
2787dd7cddfSDavid du Colombier 
2797dd7cddfSDavid du Colombier 	/* stack hack: figure sp so don't need to page in the whole segment */
2807dd7cddfSDavid du Colombier 	if(stacklen) {
2817dd7cddfSDavid du Colombier 		sp = stackptr(proc, fd);
2827dd7cddfSDavid du Colombier 		if(stackoff <= sp && sp < stackoff+stacklen) {
2837dd7cddfSDavid du Colombier 			off = (sp - Pagesize) & ~(Pagesize - 1);
2847dd7cddfSDavid du Colombier 			if(off < stackoff)
2857dd7cddfSDavid du Colombier 				off = stackoff;
2867dd7cddfSDavid du Colombier 			len = stacklen - (off - stackoff);
2877dd7cddfSDavid du Colombier 		} else {	/* stack pointer not in segment.  thread library? */
2887dd7cddfSDavid du Colombier 			off = stackoff + stacklen - 16*1024;
2897dd7cddfSDavid du Colombier 			len = 16*1024;
2907dd7cddfSDavid du Colombier 		}
2917dd7cddfSDavid du Colombier 		s[stacki] = readseg(fd, off, len, "Stack");
2927dd7cddfSDavid du Colombier 	}
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier 	return proc;
2957dd7cddfSDavid du Colombier }
296