xref: /plan9/sys/src/cmd/snap/read.c (revision 353937820181d9ceece9f7e799bfae37fdcac66e)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "snap.h"
5 
6 void
panic(char * s)7 panic(char *s)
8 {
9 	fprint(2, "%s\n", s);
10 	abort();
11 	exits(s);
12 }
13 
14 static Proc*
findpid(Proc * plist,long pid)15 findpid(Proc *plist, long pid)
16 {
17 	while(plist) {
18 		if(plist->pid == pid)
19 			break;
20 		plist = plist->link;
21 	}
22 	return plist;
23 }
24 
25 Page*
findpage(Proc * plist,long pid,int type,uvlong off)26 findpage(Proc *plist, long pid, int type, uvlong off)
27 {
28 	Seg *s;
29 	int i;
30 
31 	plist = findpid(plist, pid);
32 	if(plist == nil)
33 		panic("can't find referenced pid");
34 
35 	if(type == 't') {
36 		if(off%Pagesize)
37 			panic("bad text offset alignment");
38 		s = plist->text;
39 		if(off >= s->len)
40 			return nil;
41 		return s->pg[off/Pagesize];
42 	}
43 
44 	s = nil;
45 	for(i=0; i<plist->nseg; i++) {
46 		s = plist->seg[i];
47 		if(s && s->offset <= off && off < s->offset+s->len)
48 			break;
49 		s = nil;
50 	}
51 	if(s == nil)
52 		return nil;
53 
54 	off -= s->offset;
55 	if(off%Pagesize)
56 		panic("bad mem offset alignment");
57 
58 	return s->pg[off/Pagesize];
59 }
60 
61 static int
Breadnumber(Biobuf * b,char * buf)62 Breadnumber(Biobuf *b, char *buf)
63 {
64 	int i;
65 	int c;
66 	int havedigits;
67 
68 	havedigits = 0;
69 	for(i=0; i<22; i++){
70 		if((c = Bgetc(b)) == Beof)
71 			return -1;
72 		if('0' <= c && c <= '9'){
73 			*buf++ = c;
74 			havedigits = 1;
75 		}else if(c == ' '){
76 			if(havedigits){
77 				while((c = Bgetc(b)) == ' ')
78 					;
79 				if(c != Beof)
80 					Bungetc(b);
81 				break;
82 			}
83 		}else{
84 			werrstr("bad character %.2ux", c);
85 			return -1;
86 		}
87 	}
88 	*buf = 0;
89 	return 0;
90 }
91 
92 static int
Breadulong(Biobuf * b,ulong * x)93 Breadulong(Biobuf *b, ulong *x)
94 {
95 	char buf[32];
96 
97 	if(Breadnumber(b, buf) < 0)
98 		return -1;
99 	*x = strtoul(buf, 0, 0);
100 	return 0;
101 }
102 
103 static int
Breaduvlong(Biobuf * b,uvlong * x)104 Breaduvlong(Biobuf *b, uvlong *x)
105 {
106 	char buf[32];
107 
108 	if(Breadnumber(b, buf) < 0)
109 		return -1;
110 	*x = strtoull(buf, 0, 0);
111 	return 0;
112 }
113 
114 static Data*
readdata(Biobuf * b)115 readdata(Biobuf *b)
116 {
117 	Data *d;
118 	char str[32];
119 	long len;
120 
121 	if(Bread(b, str, 12) != 12)
122 		panic("can't read data hdr\n");
123 
124 	len = atoi(str);
125 	d = emalloc(sizeof(*d) + len);
126 	if(Bread(b, d->data, len) != len)
127 		panic("can't read data body\n");
128 	d->len = len;
129 	return d;
130 }
131 
132 static Seg*
readseg(Seg ** ps,Biobuf * b,Proc * plist)133 readseg(Seg **ps, Biobuf *b, Proc *plist)
134 {
135 	Seg *s;
136 	Page **pp;
137 	int i, npg;
138 	int t;
139 	int n, len;
140 	ulong pid;
141 	uvlong off;
142 	char buf[Pagesize];
143 	static char zero[Pagesize];
144 
145 	s = emalloc(sizeof *s);
146 	if(Breaduvlong(b, &s->offset) < 0
147 	|| Breaduvlong(b, &s->len) < 0)
148 		panic("error reading segment");
149 
150 	npg = (s->len + Pagesize-1)/Pagesize;
151 	s->npg = npg;
152 
153 	if(s->npg == 0)
154 		return s;
155 
156 	pp = emalloc(sizeof(*pp)*npg);
157 	s->pg = pp;
158 	*ps = s;
159 
160 	len = Pagesize;
161 	for(i=0; i<npg; i++) {
162 		if(i == npg-1)
163 			len = s->len - i*Pagesize;
164 
165 		switch(t = Bgetc(b)) {
166 		case 'z':
167 			pp[i] = datapage(zero, len);
168 			if(debug)
169 				fprint(2, "0x%.8llux all zeros\n", s->offset+i*Pagesize);
170 			break;
171 		case 'm':
172 		case 't':
173 			if(Breadulong(b, &pid) < 0
174 			|| Breaduvlong(b, &off) < 0)
175 				panic("error reading segment x");
176 			pp[i] = findpage(plist, pid, t, off);
177 			if(pp[i] == nil)
178 				panic("bad page reference in snapshot");
179 			if(debug)
180 				fprint(2, "0x%.8llux same as %s pid %lud 0x%.8llux\n", s->offset+i*Pagesize, t=='m'?"mem":"text", pid, off);
181 			break;
182 		case 'r':
183 			if((n=Bread(b, buf, len)) != len)
184 				sysfatal("short read of segment %d/%d at %llx: %r", n, len, Boffset(b));
185 			pp[i] = datapage(buf, len);
186 			if(debug)
187 				fprint(2, "0x%.8llux is raw data\n", s->offset+i*Pagesize);
188 			break;
189 		default:
190 			fprint(2, "bad type char %#.2ux\n", t);
191 			panic("error reading segment");
192 		}
193 	}
194 	return s;
195 }
196 
197 Proc*
readsnap(Biobuf * b)198 readsnap(Biobuf *b)
199 {
200 	char *q;
201 	char buf[12];
202 	long pid;
203 	Proc *p, *plist;
204 	int i, n;
205 
206 	if((q = Brdline(b, '\n')) == nil)
207 		panic("error reading snapshot file");
208 	if(strncmp(q, "process snapshot", strlen("process snapshot")) != 0)
209 		panic("bad snapshot file format");
210 
211 	plist = nil;
212 	while(q = Brdline(b, '\n')) {
213 		q[Blinelen(b)-1] = 0;
214 		pid = atol(q);
215 		q += 12;
216 		p = findpid(plist, pid);
217 		if(p == nil) {
218 			p = emalloc(sizeof(*p));
219 			p->link = plist;
220 			p->pid = pid;
221 			plist = p;
222 		}
223 
224 		for(i=0; i<Npfile; i++) {
225 			if(strcmp(pfile[i], q) == 0) {
226 				p->d[i] = readdata(b);
227 				break;
228 			}
229 		}
230 		if(i != Npfile)
231 			continue;
232 		if(strcmp(q, "mem") == 0) {
233 			if(Bread(b, buf, 12) != 12)
234 				panic("can't read memory section");
235 			n = atoi(buf);
236 			p->nseg = n;
237 			p->seg = emalloc(n*sizeof(*p->seg));
238 			for(i=0; i<n; i++)
239 				readseg(&p->seg[i], b, plist);
240 		} else if(strcmp(q, "text") == 0)
241 			readseg(&p->text, b, plist);
242 		else
243 			panic("unknown section");
244 	}
245 	return plist;
246 }
247