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