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, vlong off, ulong len, char *name) 100 { 101 char buf[Pagesize]; 102 Page **pg; 103 int npg; 104 Seg *s; 105 ulong i; 106 int n; 107 108 s = emalloc(sizeof(*s)); 109 s->name = estrdup(name); 110 111 if(seek(fd, off, 0) < 0) { 112 fprint(2, "seek fails\n"); 113 goto Die; 114 } 115 116 pg = nil; 117 npg = 0; 118 for(i=0; i<len; ) { 119 n = Pagesize; 120 if(n > len-i) 121 n = len-i; 122 if((n = readn(fd, buf, n)) <= 0) 123 break; 124 pg = erealloc(pg, sizeof(*pg)*(npg+1)); 125 pg[npg++] = datapage(buf, n); 126 i += n; 127 if(n != Pagesize) /* any short read, planned or otherwise */ 128 break; 129 } 130 131 if(i==0 && len!=0) 132 goto Die; 133 134 s->offset = off; 135 s->len = i; 136 s->pg = pg; 137 s->npg = npg; 138 return s; 139 140 Die: 141 free(s->name); 142 free(s); 143 return nil; 144 } 145 146 /* discover the stack pointer of the given process */ 147 ulong 148 stackptr(Proc *proc, int fd) 149 { 150 char *q; 151 Fhdr f; 152 Reglist *r; 153 long textoff; 154 int i; 155 Data *dreg; 156 157 textoff = -1; 158 for(i=0; i<proc->nseg; i++) 159 if(proc->seg[i] && strcmp(proc->seg[i]->name, "Text") == 0) 160 textoff = proc->seg[i]->offset; 161 162 if(textoff == -1) 163 return 0; 164 165 seek(fd, textoff, 0); 166 if(crackhdr(fd, &f) == 0) 167 return 0; 168 169 machbytype(f.type); 170 for(r=mach->reglist; r->rname; r++) 171 if(strcmp(r->rname, mach->sp) == 0) 172 break; 173 if(r == nil) { 174 fprint(2, "couldn't find stack pointer register?\n"); 175 return 0; 176 } 177 178 if((dreg = proc->d[Pregs]) == nil) 179 return 0; 180 181 if(r->roffs+mach->szreg > dreg->len) { 182 fprint(2, "SP register too far into registers?\n"); 183 return 0; 184 } 185 186 q = dreg->data+r->roffs; 187 switch(mach->szreg) { 188 case 2: return machdata->swab(*(ushort*)q); 189 case 4: return machdata->swal(*(ulong*)q); 190 case 8: return machdata->swav(*(uvlong*)q); 191 default: 192 fprint(2, "register size is %d bytes?\n", mach->szreg); 193 return 0; 194 } 195 } 196 197 Proc* 198 snap(long pid, int usetext) 199 { 200 Data *d; 201 Proc *proc; 202 Seg **s; 203 char *name, *segdat, *q, *f[128+1], buf[128]; 204 int fd, i, stacki, nf, np; 205 uvlong off, len, stackoff, stacklen; 206 uvlong sp; 207 208 proc = emalloc(sizeof(*proc)); 209 proc->pid = pid; 210 211 np = 0; 212 for(i=0; i<Npfile; i++) { 213 if(proc->d[i] = readsection(pid, pfile[i])) 214 np++; 215 else 216 fprint(2, "warning: can't include /proc/%ld/%s\n", pid, pfile[i]); 217 } 218 if(np == 0) 219 return nil; 220 221 if(usetext) { 222 snprint(buf, sizeof buf, "/proc/%ld/text", pid); 223 if((fd = open(buf, OREAD)) >= 0) { 224 werrstr(""); 225 if((proc->text = readseg(fd, 0, 1<<31, "textfile")) == nil) 226 fprint(2, "warning: can't include %s: %r\n", buf); 227 close(fd); 228 } else 229 fprint(2, "warning: can't include /proc/%ld/text\n", pid); 230 } 231 232 if((d=proc->d[Psegment]) == nil) { 233 fprint(2, "warning: no segment table, no memory image\n"); 234 return proc; 235 } 236 237 segdat = emalloc(d->len+1); 238 memmove(segdat, d->data, d->len); 239 segdat[d->len] = 0; 240 241 nf = getfields(segdat, f, nelem(f), 1, "\n"); 242 if(nf == nelem(f)) { 243 nf--; 244 fprint(2, "process %ld has >%d segments; only using first %d\n", 245 pid, nf, nf); 246 } 247 if(nf <= 0) { 248 fprint(2, "warning: couldn't understand segment table, no memory image\n"); 249 free(segdat); 250 return proc; 251 } 252 253 snprint(buf, sizeof buf, "/proc/%ld/mem", pid); 254 if((fd = open(buf, OREAD)) < 0) { 255 fprint(2, "warning: can't include /proc/%ld/mem\n", pid); 256 return proc; 257 } 258 259 s = emalloc(nf*sizeof(*s)); 260 stacklen = 0; 261 stackoff = 0; 262 stacki = 0; 263 for(i=0; i<nf; i++) { 264 if(q = strchr(f[i], ' ')) 265 *q = 0; 266 name = f[i]; 267 off = strtoull(name+10, &q, 16); 268 len = strtoull(q, &q, 16) - off; 269 if(strcmp(name, "Stack") == 0) { 270 stackoff = off; 271 stacklen = len; 272 stacki = i; 273 } else 274 s[i] = readseg(fd, off, len, name); 275 } 276 proc->nseg = nf; 277 proc->seg = s; 278 279 /* stack hack: figure sp so don't need to page in the whole segment */ 280 if(stacklen) { 281 sp = stackptr(proc, fd); 282 if(stackoff <= sp && sp < stackoff+stacklen) { 283 off = (sp - Pagesize) & ~(Pagesize - 1); 284 if(off < stackoff) 285 off = stackoff; 286 len = stacklen - (off - stackoff); 287 } else { /* stack pointer not in segment. thread library? */ 288 off = stackoff + stacklen - 16*1024; 289 len = 16*1024; 290 } 291 s[stacki] = readseg(fd, off, len, "Stack"); 292 } 293 294 return proc; 295 } 296