acidleak.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. void*
  5. emalloc(ulong sz)
  6. {
  7. void *v;
  8. v = malloc(sz);
  9. if(v == nil)
  10. sysfatal("malloc %lud fails\n", sz);
  11. memset(v, 0, sz);
  12. return v;
  13. }
  14. void*
  15. erealloc(void *v, ulong sz)
  16. {
  17. v = realloc(v, sz);
  18. if(v == nil)
  19. sysfatal("realloc %lud fails\n", sz);
  20. return v;
  21. }
  22. char*
  23. estrdup(char* s)
  24. {
  25. char *r;
  26. r = strdup(s);
  27. if(r == nil)
  28. sysfatal("strdup fails\n");
  29. return r;
  30. }
  31. typedef struct Block Block;
  32. typedef struct Data Data;
  33. struct Block {
  34. ulong addr;
  35. ulong size;
  36. ulong w0;
  37. ulong w1;
  38. char *s0;
  39. char *s1;
  40. int mark;
  41. int free;
  42. Data *d;
  43. };
  44. struct Data {
  45. ulong addr;
  46. ulong val;
  47. uchar type;
  48. Block *b;
  49. };
  50. Block *block;
  51. int nblock;
  52. Data *data;
  53. Data *edata;
  54. int ndata;
  55. int
  56. addrcmp(void *va, void *vb)
  57. {
  58. ulong *a, *b;
  59. a = va;
  60. b = vb;
  61. if(*a < *b)
  62. return -1;
  63. if(*a > *b)
  64. return 1;
  65. return 0;
  66. }
  67. Block*
  68. findblock(ulong addr)
  69. {
  70. int lo, hi, m;
  71. lo = 0;
  72. hi = nblock;
  73. while(lo < hi) {
  74. m = (lo+hi)/2;
  75. if(block[m].addr < addr)
  76. lo = m+1;
  77. else if(addr < block[m].addr)
  78. hi = m;
  79. else
  80. return &block[m];
  81. }
  82. return nil;
  83. }
  84. Data*
  85. finddata(ulong addr)
  86. {
  87. int lo, hi, m;
  88. lo = 0;
  89. hi = ndata;
  90. while(lo < hi) {
  91. m = (lo+hi)/2;
  92. if(data[m].addr < addr)
  93. lo = m+1;
  94. else if(addr < data[m].addr)
  95. hi = m;
  96. else
  97. return &data[m];
  98. }
  99. if(0 <= lo && lo < ndata)
  100. return &data[lo];
  101. return nil;
  102. }
  103. int nmark;
  104. int
  105. markblock(ulong from, ulong fromval, Block *b)
  106. {
  107. Data *d;
  108. ulong top;
  109. Block *nb;
  110. USED(from, fromval);
  111. //print("trace 0x%.8lux from 0x%.8lux (%d)\n", b->addr, from, b->mark);
  112. if(b->free){
  113. // fprint(2, "possible dangling pointer *0x%.8lux = 0x%.8lux\n", from, fromval);
  114. return 0;
  115. }
  116. if(b->mark)
  117. return 0;
  118. b->mark = 1;
  119. nmark++;
  120. if(d = finddata(b->addr)) {
  121. assert(d->addr >= b->addr);
  122. b->d = d;
  123. top = b->addr+b->size;
  124. for(; d < edata && d->addr < top; d++) {
  125. assert(d->b == 0);
  126. d->b = b;
  127. if((nb = findblock(d->val-8)) || (nb = findblock(d->val-8-8)))
  128. markblock(d->addr, d->val, nb);
  129. }
  130. return 1;
  131. }
  132. return 0;
  133. }
  134. enum {
  135. AllocColor = 2, // dark blue: completely allocated region
  136. HdrColor = 54, // bright blue: region with header
  137. LeakColor = 205, // dark red: region with leak
  138. LeakHdrColor = 240, // bright red: region with leaked header
  139. FreeColor = 252, // bright yellow: completely free region
  140. NoColor = 255, // padding, white
  141. };
  142. int
  143. rXr(int as, int ae, int bs, int be)
  144. {
  145. return bs < ae && as < be;
  146. }
  147. void
  148. main(int argc, char **argv)
  149. {
  150. Biobuf bio;
  151. char *p, *f[10];
  152. int bitmap, c, nf, resolution, n8, n16, hdr, nhdr, nlhdr, nleak, x, y, nb;
  153. ulong allocstart, allocend, len, u;
  154. Data *d, *ed;
  155. Block *b, *eb;
  156. bitmap = 0;
  157. resolution = 8;
  158. x = 512;
  159. ARGBEGIN{
  160. case 'b':
  161. bitmap=1;
  162. break;
  163. case 'r':
  164. resolution = atoi(EARGF(sysfatal("usage")));
  165. break;
  166. case 'x':
  167. x = atoi(EARGF(sysfatal("usage")));
  168. break;
  169. }ARGEND
  170. n8 = n16 = 0;
  171. allocstart = allocend = 0;
  172. Binit(&bio, 0, OREAD);
  173. while(p=Brdline(&bio, '\n')) {
  174. p[Blinelen(&bio)-1] = '\0';
  175. nf = tokenize(p, f, nelem(f));
  176. if(nf >= 4 && strcmp(f[0], "data") == 0) {
  177. if(ndata%64==0)
  178. data = erealloc(data, (ndata+64)*sizeof(Data));
  179. data[ndata].addr = strtoul(f[1], nil, 0);
  180. data[ndata].val = strtoul(f[2], nil, 0);
  181. data[ndata].type = f[3][0];
  182. data[ndata].b = 0;
  183. ndata++;
  184. }
  185. if(nf >= 5 && (strcmp(f[0], "block") == 0 || strcmp(f[0], "free") == 0)) {
  186. if(nblock%64 == 0)
  187. block = erealloc(block, (nblock+64)*sizeof(Block));
  188. block[nblock].addr = strtoul(f[1], nil, 0);
  189. block[nblock].size = strtoul(f[2], nil, 0);
  190. block[nblock].w0 = strtoul(f[3], nil, 0);
  191. block[nblock].w1 = strtoul(f[4], nil, 0);
  192. if (nf >= 7) {
  193. block[nblock].s0 = estrdup(f[5]);
  194. block[nblock].s1 = estrdup(f[6]);
  195. } else {
  196. block[nblock].s0 = "";
  197. block[nblock].s1 = "";
  198. }
  199. block[nblock].mark = 0;
  200. block[nblock].d = 0;
  201. block[nblock].free = strcmp(f[0], "free") == 0;
  202. nblock++;
  203. }
  204. if(nf >= 4 && strcmp(f[0], "range") == 0 && strcmp(f[1], "alloc") == 0) {
  205. allocstart = strtoul(f[2], 0, 0)&~15;
  206. allocend = strtoul(f[3], 0, 0);
  207. }
  208. }
  209. qsort(block, nblock, sizeof(Block), addrcmp);
  210. qsort(data, ndata, sizeof(Data), addrcmp);
  211. ed = edata = data+ndata;
  212. for(d=data; d<ed; d++) {
  213. if(d->type == 'a')
  214. continue;
  215. if(b = findblock(d->val-8)) // pool header 2 words
  216. n8 += markblock(d->addr, d->val, b);
  217. else if(b = findblock(d->val-8-8)) // sometimes malloc header 2 words
  218. n16 += markblock(d->addr, d->val, b);
  219. else
  220. {}//print("noblock %.8lux\n", d->val);
  221. }
  222. Binit(&bio, 1, OWRITE);
  223. if(bitmap){
  224. if(n8 > n16) // guess size of header
  225. hdr = 8;
  226. else
  227. hdr = 16;
  228. for(d=data; d<ed; d++)
  229. if(d->type=='a')
  230. break;
  231. if(d==ed)
  232. sysfatal("no allocated data region");
  233. len = (allocend-allocstart+resolution-1)/resolution;
  234. y = (len+x-1)/x;
  235. Bprint(&bio, "%11s %11d %11d %11d %11d ", "m8", 0, 0, x, y);
  236. //fprint(2, "alloc %lux %lux x %d y %d res %d\n", allocstart, allocend, x, y, resolution);
  237. b = block;
  238. eb = block+nblock;
  239. for(u = allocstart; u<allocend; u+=resolution){
  240. //fprint(2, "u %lux %lux baddr %lux\n", u, u+resolution, b->addr);
  241. while(b->addr+b->size <= u && b < eb)
  242. //{
  243. //fprint(2, "\tskip %lux %lux\n", b->addr, b->addr+b->size);
  244. b++;
  245. //}
  246. nhdr = 0;
  247. nleak = 0;
  248. nb = 0;
  249. nlhdr = 0;
  250. if(block < b && u < (b-1)->addr+(b-1)->size)
  251. b--;
  252. for(; b->addr < u+resolution && b < eb; b++){
  253. //fprint(2, "\tblock %lux %lux %d\n", b->addr, b->addr+b->size, b->mark);
  254. if(rXr(b->addr, b->addr+hdr, u, u+resolution)
  255. || rXr(b->addr+b->size-8, b->addr+b->size, u, u+resolution)){
  256. if(b->mark == 0 && !b->free)
  257. nlhdr++;
  258. else
  259. nhdr++;
  260. }
  261. if(b->mark == 0 && !b->free)
  262. nleak++;
  263. nb++;
  264. }
  265. if(nhdr)
  266. c = HdrColor;
  267. else if(nlhdr)
  268. c = LeakHdrColor;
  269. else if(nleak)
  270. c = LeakColor;
  271. else if(nb)
  272. c = AllocColor;
  273. else
  274. c = FreeColor;
  275. //fprint(2, "\t%d\n", c);
  276. Bputc(&bio, c);
  277. }
  278. allocend = allocstart+x*y*resolution;
  279. for(; u < allocend; u+=resolution)
  280. Bputc(&bio, NoColor);
  281. }else{
  282. eb = block+nblock;
  283. for(b=block; b<eb; b++)
  284. if(b->mark == 0 && !b->free)
  285. Bprint(&bio, "block 0x%.8lux 0x%.8lux 0x%.8lux 0x%.8lux %s %s\n", b->addr, b->size, b->w0, b->w1, b->s0, b->s1);
  286. }
  287. Bterm(&bio);
  288. }