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