take.c 5.5 KB

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