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