acidleak.c 6.4 KB

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