]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/snap/take.c
stats: show amount of reclaimable pages (add -r flag)
[plan9front.git] / sys / src / cmd / snap / take.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 #include "snap.h"
6
7 /* research 16-bit crc.  good enough. */
8 static ulong
9 sumr(ulong sum, void *buf, int n)
10 {
11         uchar *s, *send;
12
13         if(buf == 0)
14                 return sum;
15         for(s=buf, send=s+n; s<send; s++)
16                 if(sum & 1)
17                         sum = 0xffff & ((sum>>1)+*s+0x8000);
18                 else
19                         sum = 0xffff & ((sum>>1)+*s);
20         return sum;
21 }
22
23 static int npage;
24 static Page *pgtab[1<<10];
25
26 Page*
27 datapage(char *p, long len)
28 {
29         Page *pg;
30         char *q, *ep;
31         long    sum;
32         int iszero;
33
34         if(len > Pagesize) {
35                 fprint(2, "datapage cannot handle pages > 1024\n");
36                 exits("datapage");
37         }
38
39         sum = sumr(0, p, len) & (nelem(pgtab)-1);
40         if(sum == 0) {
41                 iszero = 1;
42                 for(q=p, ep=p+len; q<ep; q++)
43                         if(*q != 0) {
44                                 iszero = 0;
45                                 break;
46                         }
47         } else
48                 iszero = 0;
49
50         for(pg = pgtab[sum]; pg; pg=pg->link)
51                 if(pg->len == len && memcmp(pg->data, p, len) == 0)
52                         break;
53         if(pg)
54                 return pg;
55
56         pg = emalloc(sizeof(*pg)+len);
57         pg->data = (char*)&pg[1];
58         pg->type = 0;
59         pg->len = len;
60         memmove(pg->data, p, len);
61         pg->link = pgtab[sum];
62         pgtab[sum] = pg;
63         if(iszero) {
64                 pg->type = 'z';
65                 pg->written = 1;
66         }
67
68         ++npage;
69         return pg;
70 }
71
72 static Data*
73 readsection(long pid, char *sec)
74 {
75         char buf[8192];
76         int n, fd;
77         int hdr, tot;
78         Data *d = nil;
79
80         snprint(buf, sizeof buf, "/proc/%ld/%s", pid, sec);
81         if((fd = open(buf, OREAD)) < 0)
82                 return nil;
83
84         tot = 0;
85         hdr = (int)((Data*)0)->data;
86         while((n = read(fd, buf, sizeof buf)) > 0) {
87                 d = erealloc(d, tot+n+hdr);
88                 memmove(d->data+tot, buf, n);
89                 tot += n;
90         }
91         close(fd);
92         if(d == nil)
93                 return nil;
94         d->len = tot;
95         return d;
96 }
97
98 static Seg*
99 readseg(int fd, uvlong off, uvlong len, char *name)
100 {
101         char buf[Pagesize];
102         ulong npg;
103         Page **pg;
104         Seg *s;
105         int n;
106
107         s = emalloc(sizeof(*s));
108         s->name = estrdup(name);
109         if(seek(fd, off, 0) < 0) {
110                 fprint(2, "seek fails\n");
111                 goto Die;
112         }
113         s->offset = off;
114         s->len = 0;
115         pg = nil;
116         npg = 0;
117         while(s->len < len){
118                 n = Pagesize;
119                 if(n > len - s->len)
120                         n = len - s->len;
121                 if((n = readn(fd, buf, n)) <= 0)
122                         break;
123                 s->len += n;
124                 if((npg & (npg-1)) == 0)
125                         pg = erealloc(pg, sizeof(*pg) * (npg==0 | npg*2));
126                 pg[npg++] = datapage(buf, n);
127                 if(n != Pagesize)       /* any short read, planned or otherwise */
128                         break;
129         }
130         if(s->len==0 && len!=0){
131                 free(pg);
132                 goto Die;
133         }
134         pg = erealloc(pg, sizeof(*pg) * npg);
135         s->pg = pg;
136         s->npg = npg;
137         return s;
138 Die:
139         free(s->name);
140         free(s);
141         return nil;
142 }
143
144 /* discover the stack pointer of the given process */
145 uvlong
146 stackptr(Proc *proc, int fd)
147 {
148         char *q;
149         Fhdr f;
150         Reglist *r;
151         long textoff;
152         int i;
153         Data *dreg;
154
155         textoff = -1;
156         for(i=0; i<proc->nseg; i++)
157                 if(proc->seg[i] && strcmp(proc->seg[i]->name, "Text") == 0)
158                         textoff = proc->seg[i]->offset;
159
160         if(textoff == -1)
161                 return 0;
162
163         seek(fd, textoff, 0);
164         if(crackhdr(fd, &f) == 0)
165                 return 0;
166
167         machbytype(f.type);
168         for(r=mach->reglist; r->rname; r++)
169                 if(strcmp(r->rname, mach->sp) == 0)
170                         break;
171         if(r == nil) {
172                 fprint(2, "couldn't find stack pointer register?\n");
173                 return 0;
174         }
175         
176         if((dreg = proc->d[Pregs]) == nil)
177                 return 0;
178
179         if(r->roffs+mach->szreg > dreg->len) {
180                 fprint(2, "SP register too far into registers?\n");
181                 return 0;
182         }
183
184         q = dreg->data+r->roffs;
185         switch(mach->szreg) {
186         case 2: return machdata->swab(*(ushort*)q);
187         case 4: return machdata->swal(*(ulong*)q);
188         case 8: return machdata->swav(*(uvlong*)q);
189         default:
190                 fprint(2, "register size is %d bytes?\n", mach->szreg);
191                 return 0;
192         }
193 }
194
195 Proc*
196 snap(long pid, int usetext)
197 {
198         Data *d;
199         Proc *proc;
200         Seg **s;
201         char *name, *segdat, *q, *f[128+1], buf[128];
202         int fd, i, stacki, nf, np;
203         uvlong off, len, stackoff, stacklen, sp;
204
205         proc = emalloc(sizeof(*proc));
206         proc->pid = pid;
207
208         np = 0;
209         for(i=0; i<Npfile; i++) {
210                 if(proc->d[i] = readsection(pid, pfile[i]))
211                         np++;
212                 else
213                         fprint(2, "warning: can't include /proc/%ld/%s\n", pid, pfile[i]);
214         }
215         if(np == 0)
216                 return nil;
217
218         if(usetext) {
219                 snprint(buf, sizeof buf, "/proc/%ld/text", pid);
220                 if((fd = open(buf, OREAD)) >= 0) {
221                         werrstr("");
222                         if((proc->text = readseg(fd, 0, 1<<31, "textfile")) == nil)
223                                 fprint(2, "warning: can't include %s: %r\n", buf);
224                         close(fd);
225                 } else
226                         fprint(2, "warning: can't include /proc/%ld/text\n", pid);
227         }
228
229         if((d=proc->d[Psegment]) == nil) {
230                 fprint(2, "warning: no segment table, no memory image\n");
231                 return proc;
232         }
233
234         segdat = emalloc(d->len+1);
235         memmove(segdat, d->data, d->len);
236         segdat[d->len] = 0;
237
238         nf = getfields(segdat, f, nelem(f), 1, "\n");
239         if(nf == nelem(f)) {
240                 nf--;
241                 fprint(2, "process %ld has >%d segments; only using first %d\n",
242                         pid, nf, nf);
243         }
244         if(nf <= 0) {
245                 fprint(2, "warning: couldn't understand segment table, no memory image\n");
246                 free(segdat);
247                 return proc;
248         }
249
250         snprint(buf, sizeof buf, "/proc/%ld/mem", pid);
251         if((fd = open(buf, OREAD)) < 0) {
252                 fprint(2, "warning: can't include /proc/%ld/mem\n", pid);
253                 return proc;
254         }
255
256         s = emalloc(nf*sizeof(*s));
257         stacklen = 0;
258         stackoff = 0;
259         stacki = 0;
260         for(i=0; i<nf; i++) {
261                 if(q = strchr(f[i], ' ')) 
262                         *q = 0;
263                 name = f[i];
264                 off = strtoull(name+10, &q, 16);
265                 len = strtoull(q, &q, 16) - off;
266                 if(strcmp(name, "Stack") == 0) {
267                         stackoff = off;
268                         stacklen = len;
269                         stacki = i;
270                 } else
271                         s[i] = readseg(fd, off, len, name);
272         }
273         proc->nseg = nf;
274         proc->seg = s;
275
276         /* stack hack: figure sp so don't need to page in the whole segment */
277         if(stacklen) {
278                 sp = stackptr(proc, fd);
279                 if(stackoff <= sp && sp < stackoff+stacklen) {
280                         off = (sp - Pagesize) & ~(Pagesize - 1);
281                         if(off < stackoff)
282                                 off = stackoff;
283                         len = stacklen - (off - stackoff);
284                 } else {        /* stack pointer not in segment.  thread library? */
285                         off = stackoff + stacklen - 16*1024;
286                         len = 16*1024;
287                 }
288                 s[stacki] = readseg(fd, off, len, "Stack");
289         }
290
291         return proc;
292 }