summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-04-22 13:34:17 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-04-22 13:34:17 +0900
commita840cc0a5d08237063cff5d06f927566008f57db (patch)
tree153ea6d300ec21262576f24dcc1beec90fc2ce6a
mtrack! my little evil memory debugger in a can
:)
-rwxr-xr-xbuild.sh20
-rwxr-xr-xmtd8
-rw-r--r--mtdump.c219
-rwxr-xr-xmtf4
-rw-r--r--mtrack.c1361
-rw-r--r--mtshow.c197
-rwxr-xr-xmtt5
7 files changed, 1814 insertions, 0 deletions
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..4424480
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,20 @@
1#!/bin/sh
2gcc -O2 mtrack.c -shared -o mtrack.so -ldl -pthread -fPIC -g
3gcc -O2 mtdump.c -o mtdump -g `pkg-config --cflags --libs eina`
4gcc -O2 mtshow.c -o mtshow -g `pkg-config --cflags --libs eina`
5
6sudo rm -f /usr/local/bin/mtshow
7sudo rm -f /usr/local/bin/mtdump
8sudo rm -f /usr/local/lib/mtrack.so
9sudo rm -f /usr/local/bin/mtf
10sudo rm -f /usr/local/bin/mtt
11sudo cp mtshow /usr/local/bin/mtshow
12sudo cp mtdump /usr/local/bin/mtdump
13sudo cp mtrack.so /usr/local/lib/mtrack.so
14sudo cp mtf /usr/local/bin/mtf
15sudo cp mtt /usr/local/bin/mtt
16sudo cp mtd /usr/local/bin/mtd
17
18#rm -f mtrack.so
19#rm -f mtdump
20rm -f *~
diff --git a/mtd b/mtd
new file mode 100755
index 0000000..8db6769
--- /dev/null
+++ b/mtd
@@ -0,0 +1,8 @@
1#!/bin/sh
2export MTRACK=debug
3export MTRACK_ALLOC_FILL=2
4export MTRACK_FREE_FILL=1
5export MTRACK_CANARY_SIZE=16
6export MTRACK_CANARY=3
7export LD_PRELOAD=/usr/local/lib/mtrack.so
8exec $@
diff --git a/mtdump.c b/mtdump.c
new file mode 100644
index 0000000..6f18d0c
--- /dev/null
+++ b/mtdump.c
@@ -0,0 +1,219 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <string.h>
5#include <time.h>
6#include <Eina.h>
7
8static char *
9pstr(const char *cmd, int lines)
10{
11 FILE *f;
12 char *str = NULL;
13 char buf[4096];
14 int str_len = 0;
15 int n = 0;
16 int count = 0;
17
18 f = popen(cmd, "r");
19 if (!f) return NULL;
20 while (fgets(buf, sizeof(buf) - 1, f))
21 {
22 int len = strlen(buf);
23 if ((len > 1) && (buf[len - 1] == '\n'))
24 {
25 buf[len - 1] = 0;
26 len--;
27 }
28 str_len += len;
29 str = realloc(str, str_len + 1);
30 if (count == 0) str[0] = 0;
31 strcat(str, buf);
32 n++;
33 count++;
34 if (n >= lines) break;
35 }
36 pclose(f);
37 return str;
38}
39
40static char *
41addr2func(const char *file, const char *addr)
42{
43 char *s;
44 char cmd[4096], buf[4096];
45 static Eina_Hash *hash = NULL;
46
47 if (!hash) hash = eina_hash_string_superfast_new(NULL);
48 snprintf(buf, sizeof(buf), "%s %s", file, addr);
49 s = eina_hash_find(hash, buf);
50 if (s) return strdup(s);
51 snprintf(cmd, sizeof(cmd), "addr2line -f -e %s", buf);
52 s = pstr(cmd, 1);
53 eina_hash_add(hash, buf, s);
54 return strdup(s);
55}
56
57static FILE *outf = NULL;
58
59#define OUT(fmt, args...) fprintf(outf, fmt, ##args)
60
61int
62main(int argc, char **argv)
63{
64 FILE *f;
65 char buf[4096];
66 int items = 0;
67 int btnum = 0;
68 int expected = 0;
69 time_t t0;
70
71 if (argc < 3)
72 {
73 printf("usage: mtdump MTLOGFILE OUTFILE\n");
74 exit(1);
75 }
76
77 f = fopen(argv[1], "r");
78 if (!f)
79 {
80 perror("fopen");
81 exit(1);
82 }
83
84 outf = fopen(argv[2], "w");
85 if (!outf)
86 {
87 perror("fopen");
88 exit(1);
89 }
90
91 while (fgets(buf, sizeof(buf) - 1, f))
92 {
93 if (!strncmp(buf, "== ", 3)) expected++;
94 }
95 fseek(f, 0, SEEK_SET);
96 t0 = time(NULL);
97 while (fgets(buf, sizeof(buf) - 1, f))
98 {
99 int len;
100
101 len = strlen(buf);
102 if (len < 2) continue;
103 if ((len > 1) && (buf[len - 1] == '\n'))
104 {
105 buf[len - 1] = 0;
106 len--;
107 }
108 if (!strncmp(buf, "== ", 3))
109 {
110 unsigned long size;
111 char type[4096] = "";
112 unsigned long alloctime;
113
114 if (sscanf(buf, "%*s %s %lu %*s %lu", type, &size, &alloctime)
115 == 3)
116 {
117 time_t t;
118 struct tm *tmp;
119 char out[256] = "??";
120 int eta;
121
122 if (items > 0) OUT("\n");
123 items++;
124 t = time(NULL) - t0;
125 eta = (expected * (int)t) / items;
126 printf("%i/%i -- ETA %i min %i sec \r",
127 items, expected, eta / 60, eta % 60);
128 fflush(stdout);
129 btnum = 0;
130 t = alloctime;
131 tmp = localtime(&t);
132 if (tmp)
133 strftime(out, sizeof(out), "%F/%T", tmp);
134 else
135 strcpy(out, "??");
136 OUT("%lu %s %s |", size, type, out);
137 }
138 }
139 else
140 {
141 if (btnum > 0)
142 {
143 if (strchr(buf, '['))
144 {
145 // 1 of:
146 // /usr/local/lib/libeina.so.1(+0x16ab8)[0x7fdaccc4cab8]
147 // /lib/x86_64-linux-gnu/libc.so.6(__strdup+0x22)[0x7fdace0732f2]
148 // ello[0x402d8c]
149 // /usr/local/bin/ello[0x402d8c]
150 if (strchr(buf, '('))
151 {
152 char file[4096], addr[4096];
153 // 1 of:
154 // /usr/local/lib/libeina.so.1(+0x16ab8)[0x7fdaccc4cab8]
155 // /lib/x86_64-linux-gnu/libc.so.6(__strdup+0x22)[0x7fdace0732f2]
156 if (sscanf(buf, "%[^(](%[^)])%*s", file, addr) == 2)
157 {
158 if (addr[0] == '+')
159 {
160 char *s = addr2func(file, addr + 1);
161 if (s)
162 {
163 OUT(" %s", s);
164 free(s);
165 }
166 else
167 OUT(" ??");
168 }
169 else
170 {
171 char *s;
172
173 s = strchr(addr, '+');
174 if (s) *s = 0;
175 OUT(" %s", addr);
176 }
177 }
178 else
179 OUT(" ??");
180 }
181 else
182 {
183 // 1 of:
184 // ello[0x402d8c]
185 // /usr/local/bin/ello[0x402d8c]
186 if (buf[0] == '/')
187 {
188 char file[4096], addr[4096];
189
190 if (sscanf(buf, "%[^\\[][%[^]]]", file, addr) == 2)
191 {
192 char *s = addr2func(file, addr);
193 if (s)
194 {
195 OUT(" %s", s);
196 free(s);
197 }
198 else
199 OUT(" ??");
200 }
201 else
202 OUT(" ??");
203 }
204 else
205 OUT(" ?main?");
206 }
207 }
208 else
209 OUT(" ??");
210 }
211 btnum++;
212 }
213 }
214 fclose(f);
215 fclose(outf);
216
217 exit(0);
218 return 0;
219}
diff --git a/mtf b/mtf
new file mode 100755
index 0000000..ca228ab
--- /dev/null
+++ b/mtf
@@ -0,0 +1,4 @@
1#!/bin/sh
2export MTRACK=fill
3export LD_PRELOAD=/usr/local/lib/mtrack.so
4exec $@
diff --git a/mtrack.c b/mtrack.c
new file mode 100644
index 0000000..8eb867e
--- /dev/null
+++ b/mtrack.c
@@ -0,0 +1,1361 @@
1/*
2gcc -O2 mtrack.c -shared -o mtrack.so -ldl -pthread
3 */
4#ifndef _GNU_SOURCE
5# define _GNU_SOURCE
6#endif
7#include <signal.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <unistd.h>
11#include <string.h>
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <fcntl.h>
15#include <dlfcn.h>
16#include <execinfo.h>
17#include <pthread.h>
18
19#ifdef __GNUC__
20# if __GNUC__ >= 4
21# define EAPI __attribute__ ((visibility("default")))
22# else
23# define EAPI
24# endif
25#else
26# define EAPI
27#endif
28
29static void _mhook_do_init(void);
30
31/*============================================================================*
32* Local *
33*============================================================================*/
34
35enum {
36 MHOOK_NONE = 0,
37 MHOOK_FILL = 1,
38 MHOOK_TRACE = 2,
39 MHOOK_TRACK = 3,
40 MHOOK_DEBUG = 4
41};
42
43/**
44 * @cond LOCAL
45 */
46
47#define MHOOK_CANARY_MAGIC 0xf0
48
49static int _mhook_mode = MHOOK_NONE;
50
51static unsigned char _mhook_fill_pat_malloc = 0xaa;
52static unsigned char _mhook_fill_pat_free = 0xbb;
53
54static unsigned char _mhook_canary_size = 0x00;
55static unsigned char _mhook_canary = 0xfe;
56
57static int _mhook_trace_fd = -1;
58static int _mhook_track_fd = -1;
59
60static unsigned char _mhook_buf[256];
61static int _mhook_first = 1;
62
63static void *(*_mhook_orig_malloc) (size_t) = NULL;
64static void (*_mhook_orig_free) (void *) = NULL;
65static void *(*_mhook_orig_realloc) (void *, size_t) = NULL;
66static void *(*_mhook_orig_memalign) (size_t, size_t) = NULL;
67static void *(*_mhook_orig_calloc) (size_t, size_t) = NULL;
68
69static pthread_mutex_t lk;
70
71/**
72 * @endcond
73 */
74
75/*============================================================================*
76* Global *
77*============================================================================*/
78
79
80
81
82
83
84
85/*****************************************************************************/
86/* memory null implementation */
87
88static void *
89_mhook_null_malloc(size_t size)
90{
91 void *result = NULL;
92
93 // FIXME: hack around dlsym doing a malloc/calloc
94 if (!_mhook_orig_malloc) return _mhook_buf;
95 result = _mhook_orig_malloc(size);
96 return result;
97}
98
99static void
100_mhook_null_free(void *ptr)
101{
102 // FIXME: hack around dlsym doing a malloc/calloc
103 if (ptr == _mhook_buf) return;
104 _mhook_orig_free(ptr);
105}
106
107static void *
108_mhook_null_realloc(void *ptr, size_t size)
109{
110 void *result = NULL;
111
112 // FIXME: hack around dlsym doing a malloc/calloc
113 if (ptr == _mhook_buf)
114 {
115 fprintf(stderr, "mtrack: realloc()ing initial _mhook_buf\n");
116 abort();
117 }
118 result = _mhook_orig_realloc(ptr, size);
119 return result;
120}
121
122static void *
123_mhook_null_memalign(size_t alignment, size_t size)
124{
125 void *result = NULL;
126
127 // FIXME: hack around dlsym doing a malloc/calloc
128 if (!_mhook_orig_memalign) return _mhook_buf;
129 result = _mhook_orig_memalign(alignment, size);
130 return result;
131}
132
133static void *
134_mhook_null_calloc(size_t nmemb, size_t size)
135{
136 void *result = NULL;
137
138 // FIXME: hack around dlsym doing a malloc/calloc
139 if (!_mhook_orig_malloc)
140 {
141 memset(_mhook_buf, 0, nmemb * size);
142 return _mhook_buf;
143 }
144 result = _mhook_orig_calloc(nmemb, size);
145 return result;
146}
147
148
149
150
151
152
153
154
155
156/*****************************************************************************/
157/* memory filler implementation */
158#define MHOOK_FILL_HEADER_SPACE (sizeof(void *) * 2)
159typedef struct _Mhook_Mem_Fill
160{
161 size_t size;
162 void *magic;
163} Mhook_Mem_Fill;
164
165static void *
166_mhook_fill_malloc(size_t size)
167{
168 Mhook_Mem_Fill *m;
169 size_t ms = size + MHOOK_FILL_HEADER_SPACE;
170 void *result = NULL;
171
172 // FIXME: hack around dlsym doing a malloc/calloc
173 if (!_mhook_orig_malloc) return _mhook_buf;
174 m = _mhook_orig_malloc(ms);
175 if (m)
176 {
177 memset(m, _mhook_fill_pat_malloc, MHOOK_FILL_HEADER_SPACE);
178 result = ((unsigned char *)m) + MHOOK_FILL_HEADER_SPACE;
179 m->size = size;
180 memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
181 memset(result, _mhook_fill_pat_malloc, size);
182 }
183 return result;
184}
185
186static void
187_mhook_fill_free(void *ptr)
188{
189 Mhook_Mem_Fill *m;
190
191 // FIXME: hack around dlsym doing a malloc/calloc
192 if (ptr == _mhook_buf) return;
193 if (ptr)
194 {
195 m = (Mhook_Mem_Fill *)(((unsigned char *)ptr) - MHOOK_FILL_HEADER_SPACE);
196 memset(ptr, _mhook_fill_pat_free, m->size);
197 memset(m, _mhook_fill_pat_free, MHOOK_FILL_HEADER_SPACE);
198 _mhook_orig_free(m);
199 }
200}
201
202static void *
203_mhook_fill_realloc(void *ptr, size_t size)
204{
205 Mhook_Mem_Fill *m, *mold;
206 void *result = NULL;
207 size_t ms = size + MHOOK_FILL_HEADER_SPACE;
208
209 // FIXME: hack around dlsym doing a malloc/calloc
210 if (ptr == _mhook_buf)
211 {
212 fprintf(stderr, "mtrack: realloc()ing initial _mhook_buf\n");
213 abort();
214 }
215 if (size == 0)
216 {
217 if (ptr)
218 {
219 m = (Mhook_Mem_Fill *)(((unsigned char *)ptr) - MHOOK_FILL_HEADER_SPACE);
220 memset(ptr, _mhook_fill_pat_free, m->size);
221 memset(m, _mhook_fill_pat_free, MHOOK_FILL_HEADER_SPACE);
222 _mhook_orig_free(m);
223 }
224 }
225 else if (ptr)
226 {
227 m = _mhook_orig_malloc(ms);
228 if (m)
229 {
230 mold = (Mhook_Mem_Fill *)(((unsigned char *)ptr) - MHOOK_FILL_HEADER_SPACE);
231
232 memset(m, _mhook_fill_pat_malloc, MHOOK_FILL_HEADER_SPACE);
233 result = ((unsigned char *)m) + MHOOK_FILL_HEADER_SPACE;
234 m->size = size;
235 memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
236 if (mold->size < m->size)
237 {
238 memcpy(result, ptr, mold->size);
239 memset(((unsigned char *)result) + mold->size,
240 _mhook_fill_pat_malloc, m->size - mold->size);
241 }
242 else
243 memcpy(result, ptr, m->size);
244
245 memset(ptr, _mhook_fill_pat_free, mold->size);
246 memset(mold, _mhook_fill_pat_free, MHOOK_FILL_HEADER_SPACE);
247 _mhook_orig_free(mold);
248 }
249 }
250 else
251 {
252 m = _mhook_orig_malloc(ms);
253 if (m)
254 {
255 result = ((unsigned char *)m) + MHOOK_FILL_HEADER_SPACE;
256 m->size = size;
257 memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
258 memset(result, _mhook_fill_pat_malloc, size);
259 }
260 }
261 return result;
262}
263
264static void *
265_mhook_fill_memalign(size_t alignment, size_t size)
266{
267 Mhook_Mem_Fill *m;
268 size_t ms = size + MHOOK_FILL_HEADER_SPACE + alignment;
269 void *result = NULL;
270
271 // FIXME: hack around dlsym doing a malloc/calloc
272 if (!_mhook_orig_memalign) return _mhook_buf;
273 m = _mhook_orig_malloc(ms);
274 if (m)
275 {
276 unsigned char *p = ((unsigned char *)m) + MHOOK_FILL_HEADER_SPACE;
277 unsigned char *palign;
278 size_t align, mask = ~(alignment - 1);
279
280 palign = (unsigned char *)((unsigned long)((p + (alignment - 1))) & mask);
281 align = palign - p;
282 memset(m, _mhook_fill_pat_malloc, align);
283 result = ((unsigned char *)m) + align;
284 m->size = size;
285 memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
286 memset(result, _mhook_fill_pat_malloc, size);
287 }
288 return result;
289}
290
291static void *
292_mhook_fill_calloc(size_t nmemb, size_t size)
293{
294 Mhook_Mem_Fill *m;
295 size_t ms = (size * nmemb) + MHOOK_FILL_HEADER_SPACE;
296 void *result = NULL;
297
298 // FIXME: hack around dlsym doing a malloc/calloc
299 if (!_mhook_orig_malloc)
300 {
301 memset(_mhook_buf, 0, nmemb * size);
302 return _mhook_buf;
303 }
304 m = _mhook_orig_malloc(ms);
305 if (m)
306 {
307 memset(m, _mhook_fill_pat_malloc, MHOOK_FILL_HEADER_SPACE);
308 result = ((unsigned char *)m) + MHOOK_FILL_HEADER_SPACE;
309 m->size = nmemb * size;
310 memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
311 memset(result, 0, nmemb * size);
312 }
313 return result;
314}
315
316
317
318
319
320
321/*****************************************************************************/
322/* memory trace implementation */
323
324static void
325_mhook_trace_log(const char *str)
326{
327 void *bt[256];
328 char buf[16384], *p;
329 int n, skip, i, tot;
330 static int inside = 0;
331
332 if (inside)
333 {
334 if (write(_mhook_trace_fd, str, strlen(str)) < 0) perror("write");
335 if (write(_mhook_trace_fd, " XX\n", 4) < 0) perror("write");
336 return;
337 }
338 inside = 1;
339 tot = sizeof(buf);
340 n = backtrace(bt, 256);
341 strcpy(buf, str);
342 p = buf + strlen(str); tot -= p - buf;
343 strcpy(p, " =="); p += 3; tot -= 3;
344 if (n > 0)
345 {
346 skip = 3;
347
348 for (i = skip; i < n; i++)
349 {
350 int len = 0;
351 Dl_info info;
352
353 if (dladdr(bt[i], &info))
354 {
355 len = snprintf(p, tot, " %s", info.dli_sname);
356 }
357 else
358 len = snprintf(p, tot, " ?");
359 p += len; tot -= len;
360 }
361 }
362 p[0] = '\n'; p += 1; tot -= 1;
363 if (write(_mhook_trace_fd, buf, p - buf) < 0) perror("write");
364 inside = 0;
365}
366
367static void
368intstr(unsigned long value, char *str, int radix)
369{
370 static char dig[] = "0123456789abcdefghijklmnopqrstuvwxyz";
371 int n = 0, neg = 0;
372 unsigned long v;
373 char *p, *q;
374 char c;
375
376 if ((radix == 10) && (value < 0))
377 {
378 value = -value;
379 neg = 1;
380 }
381 v = value;
382 do
383 {
384 str[n++] = dig[v % radix];
385 v /= radix;
386 }
387 while (v);
388 if (neg) str[n++] = '-';
389 str[n] = 0;
390 for (p = str, q = p + (n - 1); p < q; p++, q--)
391 {
392 c = *p; *p = *q; *q = c;
393 }
394}
395static void *
396_mhook_trace_malloc(size_t size)
397{
398 char buf[256], b[64];
399 void *result = NULL;
400
401 // FIXME: hack around dlsym doing a malloc/calloc
402 if (!_mhook_orig_malloc) return _mhook_buf;
403 result = _mhook_orig_malloc(size);
404 strcpy(buf, "M ");
405 intstr((unsigned long)size, b, 16);
406 strcat(buf, b);
407 strcat(buf, " > ");
408 intstr((unsigned long)result, b, 16);
409 strcat(buf, b);
410 _mhook_trace_log(buf);
411 return result;
412}
413
414static void
415_mhook_trace_free(void *ptr)
416{
417 char buf[256], b[64];
418 // FIXME: hack around dlsym doing a malloc/calloc
419 if (ptr == _mhook_buf) return;
420 _mhook_orig_free(ptr);
421 strcpy(buf, "F ");
422 intstr((unsigned long)ptr, b, 16);
423 strcat(buf, b);
424 _mhook_trace_log(buf);
425}
426
427static void *
428_mhook_trace_realloc(void *ptr, size_t size)
429{
430 char buf[256], b[64];
431 void *result = NULL;
432
433 // FIXME: hack around dlsym doing a malloc/calloc
434 if (ptr == _mhook_buf)
435 {
436 fprintf(stderr, "mtrack: realloc()ing initial _mhook_buf\n");
437 abort();
438 }
439 result = _mhook_orig_realloc(ptr, size);
440 strcpy(buf, "R ");
441 intstr((unsigned long)ptr, b, 16);
442 strcat(buf, b);
443 strcat(buf, " ");
444 intstr((unsigned long)size, b, 16);
445 strcat(buf, b);
446 strcat(buf, " > ");
447 intstr((unsigned long)result, b, 16);
448 strcat(buf, b);
449 _mhook_trace_log(buf);
450 return result;
451}
452
453static void *
454_mhook_trace_memalign(size_t alignment, size_t size)
455{
456 char buf[256], b[64];
457 void *result = NULL;
458
459 // FIXME: hack around dlsym doing a malloc/calloc
460 if (!_mhook_orig_memalign) return _mhook_buf;
461 result = _mhook_orig_memalign(alignment, size);
462 strcpy(buf, "A ");
463 intstr((unsigned long)alignment, b, 16);
464 strcat(buf, b);
465 strcat(buf, " ");
466 intstr((unsigned long)size, b, 16);
467 strcat(buf, b);
468 strcat(buf, " > ");
469 intstr((unsigned long)result, b, 16);
470 strcat(buf, b);
471 _mhook_trace_log(buf);
472 return result;
473}
474
475static void *
476_mhook_trace_calloc(size_t nmemb, size_t size)
477{
478 char buf[256], b[64];
479 void *result = NULL;
480
481 // FIXME: hack around dlsym doing a malloc/calloc
482 if (!_mhook_orig_malloc)
483 {
484 memset(_mhook_buf, 0, nmemb * size);
485 return _mhook_buf;
486 }
487 result = _mhook_orig_calloc(nmemb, size);
488 strcpy(buf, "C ");
489 intstr((unsigned long)(nmemb * size), b, 16);
490 strcat(buf, b);
491 strcat(buf, " > ");
492 intstr((unsigned long)result, b, 16);
493 strcat(buf, b);
494 _mhook_trace_log(buf);
495 return result;
496}
497
498
499
500
501
502
503/*****************************************************************************/
504/* memory tracker implementation */
505#define MALLOC (void *)0
506#define REALLOC (void *)1
507#define CALLOC (void *)2
508#define MEMALIGN (void *)3
509
510#define MHOOK_TRACK_HEADER_SPACE (sizeof(void *) * 80)
511typedef struct _Mhook_Mem_Track Mhook_Mem_Track;
512
513struct _Mhook_Mem_Track
514{
515 size_t size;
516 void *type;
517 void *magic;
518 void *bt[64];
519 int btnum;
520 time_t alloctime;
521 Mhook_Mem_Track *prev, *next;
522};
523
524static Mhook_Mem_Track *mems = NULL;
525static int allocs = 0;
526static int frees = 0;
527static int recurse = 0;
528
529#define BAD_CANARY \
530 fprintf(stderr, "BAD CANARY for %p\n", ptr); \
531 if (getenv("MTRACK_CANARY_ABORT")) abort(); \
532 return
533
534static void
535_mhook_track_dump(void)
536{
537 Mhook_Mem_Track *m;
538
539 if (ftruncate(_mhook_track_fd, 0) < 0) perror("truncate");
540 for (m = mems; m; m = m->next)
541 {
542 char buf[512];
543 int i;
544
545 char *type[] = { "MALLOC", "REALLOC", "CALLOC", "MEMALIGN" };
546 snprintf(buf, sizeof(buf), "== %s %lu @ %lu\n",
547 type[(unsigned long)m->type],
548 (unsigned long)m->size,
549 (unsigned long)m->alloctime);
550 if (write(_mhook_track_fd, buf, strlen(buf)) < 0)
551 perror("write");
552 if (m->btnum > 0)
553 backtrace_symbols_fd(m->bt, m->btnum, _mhook_track_fd);
554 }
555}
556
557static void *
558_mhook_track_malloc(size_t size)
559{
560 Mhook_Mem_Track *m;
561 size_t ms = size + MHOOK_TRACK_HEADER_SPACE;
562 void *result = NULL;
563
564 // FIXME: hack around dlsym doing a malloc/calloc
565 if (!_mhook_orig_malloc) return _mhook_buf;
566 recurse++;
567 m = _mhook_orig_malloc(ms);
568 if (m)
569 {
570 memset(m, _mhook_fill_pat_malloc, MHOOK_TRACK_HEADER_SPACE);
571 result = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
572 m->size = size;
573 memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
574 memset(result, _mhook_fill_pat_malloc, size);
575 memset(m->bt, 0, sizeof(m->bt));
576 if (recurse < 2)
577 {
578 m->btnum = backtrace
579 (m->bt, sizeof(m->bt) / sizeof(void *));
580 m->alloctime = time(NULL);
581 }
582 m->next = m->prev = NULL;
583 m->type = MALLOC;
584 m->next = mems;
585 if (mems) mems->prev = m;
586 mems = m;
587 allocs++;
588 }
589 recurse--;
590// printf("MALLOC %p\n", result);fflush(stdout);
591 return result;
592}
593
594static void
595_mhook_track_free(void *ptr)
596{
597 Mhook_Mem_Track *m;
598
599 if (ptr == _mhook_buf) return;
600 recurse++;
601 if (ptr)
602 {
603 void *magic;
604 memset(&(magic), MHOOK_CANARY_MAGIC, sizeof(void *));
605 m = (Mhook_Mem_Track *)(((unsigned char *)ptr) - MHOOK_TRACK_HEADER_SPACE);
606 if (memcmp(&magic, &m->magic, sizeof(void *)))
607 {
608 BAD_CANARY;
609 }
610 if (m->prev) m->prev->next = m->next;
611 else mems = m->next;
612 if (m->next) m->next->prev = m->prev;
613 memset(ptr, _mhook_fill_pat_free, m->size);
614 memset(m, _mhook_fill_pat_free, MHOOK_TRACK_HEADER_SPACE);
615 _mhook_orig_free(m);
616 frees++;
617 }
618// printf("FREE %p\n", ptr);fflush(stdout);
619 recurse--;
620}
621
622static void *
623_mhook_track_realloc(void *ptr, size_t size)
624{
625 Mhook_Mem_Track *m, *mold;
626 void *result = NULL;
627 size_t ms = size + MHOOK_TRACK_HEADER_SPACE;
628
629 if (ptr == _mhook_buf)
630 {
631 fprintf(stderr, "mtrack: realloc()ing initial _mhook_buf\n");
632 abort();
633 }
634 recurse++;
635 if (size == 0)
636 {
637 if (ptr)
638 {
639 void *magic;
640 memset(&(magic), MHOOK_CANARY_MAGIC, sizeof(void *));
641 m = (Mhook_Mem_Track *)(((unsigned char *)ptr) - MHOOK_TRACK_HEADER_SPACE);
642 if (memcmp(&magic, &m->magic, sizeof(void *)))
643 {
644 BAD_CANARY NULL;
645 }
646 if (m->prev) m->prev->next = m->next;
647 else mems = m->next;
648 if (m->next) m->next->prev = m->prev;
649 memset(ptr, _mhook_fill_pat_free, m->size);
650 memset(m, _mhook_fill_pat_free, MHOOK_TRACK_HEADER_SPACE);
651 _mhook_orig_free(m);
652 frees++;
653// printf("R1:FREE %p\n", ptr);fflush(stdout);
654 }
655 }
656 else if (ptr)
657 {
658 m = _mhook_orig_malloc(ms);
659 if (m)
660 {
661 void *magic;
662 mold = (Mhook_Mem_Track *)(((unsigned char *)ptr) - MHOOK_TRACK_HEADER_SPACE);
663 memset(&(magic), MHOOK_CANARY_MAGIC, sizeof(void *));
664 if (memcmp(&magic, &mold->magic, sizeof(void *)))
665 {
666 BAD_CANARY NULL;
667 }
668
669 memset(m, _mhook_fill_pat_malloc, MHOOK_TRACK_HEADER_SPACE);
670 result = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
671 m->size = size;
672 memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
673 if (mold->size < m->size)
674 {
675 memcpy(result, ptr, mold->size);
676 memset(((unsigned char *)result) + mold->size, _mhook_fill_pat_malloc, m->size - mold->size);
677 }
678 else
679 memcpy(result, ptr, m->size);
680
681 memset(m->bt, 0, sizeof(m->bt));
682 if (recurse < 2)
683 {
684 m->btnum = backtrace
685 (m->bt, sizeof(m->bt) / sizeof(void *));
686 m->alloctime = time(NULL);
687 }
688 m->type = REALLOC;
689
690 m->next = m->prev = NULL;
691 m->next = mems;
692 if (mems) mems->prev = m;
693 mems = m;
694
695 if (mold->prev) mold->prev->next = mold->next;
696 else mems = mold->next;
697 if (mold->next) mold->next->prev = mold->prev;
698 memset(ptr, _mhook_fill_pat_free, mold->size);
699 memset(mold, _mhook_fill_pat_free, MHOOK_TRACK_HEADER_SPACE);
700 _mhook_orig_free(mold);
701 allocs++;
702 frees++;
703// printf("R2:FREE %p\n", ptr);fflush(stdout);
704// printf("R2:MALLOC %p\n", result);fflush(stdout);
705 }
706 }
707 else
708 {
709 m = _mhook_orig_malloc(ms);
710 if (m)
711 {
712 result = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
713 m->size = size;
714 memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
715 memset(result, _mhook_fill_pat_malloc, size);
716 memset(m->bt, 0, sizeof(m->bt));
717 if (recurse < 2)
718 {
719 m->btnum = backtrace
720 (m->bt, sizeof(m->bt) / sizeof(void *));
721 m->alloctime = time(NULL);
722 }
723 m->type = REALLOC;
724 m->next = m->prev = NULL;
725 m->next = mems;
726 if (mems) mems->prev = m;
727 mems = m;
728 allocs++;
729// printf("R3:MALLOC %p\n", result);fflush(stdout);
730 }
731 }
732 recurse--;
733 return result;
734}
735
736static void *
737_mhook_track_memalign(size_t alignment, size_t size)
738{
739 Mhook_Mem_Track *m;
740 size_t ms;
741 void *result = NULL;
742
743 if (alignment < 1) alignment = 1;
744 ms = size + MHOOK_TRACK_HEADER_SPACE + alignment;
745 if (!_mhook_orig_memalign) return _mhook_buf;
746 recurse++;
747 m = _mhook_orig_malloc(ms);
748 if (m)
749 {
750// unsigned char *p = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
751// unsigned char *palign;
752// size_t align, mask = ~(alignment - 1);
753
754// align = MHOOK_TRACK_HEADER_SPACE;
755// for now lets never align as asked
756// palign = (unsigned char *)((unsigned long)((p + (alignment - 1))) & mask);
757// align = palign - p;
758// memset(m, _mhook_fill_pat_malloc, align);
759// result = ((unsigned char *)m) + align;
760 memset(m, _mhook_fill_pat_malloc, MHOOK_TRACK_HEADER_SPACE);
761 result = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
762 m->size = size;
763 memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
764 memset(result, _mhook_fill_pat_malloc, size);
765 memset(m->bt, 0, sizeof(m->bt));
766 if (recurse < 2)
767 {
768 m->btnum = backtrace
769 (m->bt, sizeof(m->bt) / sizeof(void *));
770 m->alloctime = time(NULL);
771 }
772 m->type = MEMALIGN;
773 m->next = m->prev = NULL;
774 m->next = mems;
775 if (mems) mems->prev = m;
776 mems = m;
777 allocs++;
778 }
779 recurse--;
780// printf("MEMALIGN %p\n", result);fflush(stdout);
781 return result;
782}
783
784static void *
785_mhook_track_calloc(size_t nmemb, size_t size)
786{
787 Mhook_Mem_Track *m;
788 size_t ms = (size * nmemb) + MHOOK_TRACK_HEADER_SPACE;
789 void *result = NULL;
790
791 // FIXME: hack around dlsym doing a malloc/calloc
792 if (!_mhook_orig_malloc)
793 {
794 memset(_mhook_buf, 0, nmemb * size);
795 return _mhook_buf;
796 }
797 recurse++;
798 m = _mhook_orig_malloc(ms);
799 if (m)
800 {
801 memset(m, _mhook_fill_pat_malloc, MHOOK_TRACK_HEADER_SPACE);
802 result = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
803 m->size = nmemb * size;
804 memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
805 memset(result, 0, nmemb * size);
806 memset(m->bt, 0, sizeof(m->bt));
807 if (recurse < 2)
808 {
809 m->btnum = backtrace
810 (m->bt, sizeof(m->bt) / sizeof(void *));
811 m->alloctime = time(NULL);
812 }
813 m->type = CALLOC;
814 m->next = m->prev = NULL;
815 m->next = mems;
816 if (mems) mems->prev = m;
817 mems = m;
818 allocs++;
819 }
820 recurse--;
821// printf("CALLOC %p\n", result);fflush(stdout);
822 return result;
823}
824
825
826
827
828
829
830/*****************************************************************************/
831/* memory debug implementation */
832#define MHOOK_DEBUG_CANARY_SPACE (_mhook_canary_size * 8)
833#define MHOOK_DEBUG_HEADER_SPACE ((sizeof(void *) * 4) + MHOOK_DEBUG_CANARY_SPACE)
834typedef struct _Mhook_Mem_Debug
835{
836 size_t size;
837 unsigned char *realptr;
838 void *magic;
839 void *blah;
840} Mhook_Mem_Debug;
841
842#define MHOOK_DEBUG_FREEBUF_SIZE (1024 * 256)
843//#define MHOOK_DEBUG_FREEBUF_SIZE (1)
844
845static unsigned int _mhook_debug_freebuf_slot = 0;
846static void *_mhook_debug_freebuf[MHOOK_DEBUG_FREEBUF_SIZE] = { NULL };
847
848static void
849_mhook_debug_canary_check(Mhook_Mem_Debug *m)
850{
851 unsigned char *head = ((unsigned char *)m) + (sizeof(void *) * 4);
852 unsigned char *tail = head + MHOOK_DEBUG_CANARY_SPACE + m->size;
853 int i;
854
855 for (i = 0; i < (_mhook_canary_size * 8); i++)
856 {
857 if (head[i] != _mhook_canary)
858 {
859 fprintf(stderr, "CANARY ERROR HEAD @ %p = %x\n",
860 head + MHOOK_DEBUG_CANARY_SPACE, head[i]);
861 abort();
862 }
863 }
864 for (i = 0; i < (_mhook_canary_size * 8); i++)
865 {
866 if (tail[i] != _mhook_canary)
867 {
868 fprintf(stderr, "CANARY ERROR TAIL @ %p = %x\n",
869 head + MHOOK_DEBUG_CANARY_SPACE, tail[i]);
870 abort();
871 }
872 }
873}
874
875static void
876_mhook_debug_canary_fill(void *ptr, size_t size)
877{
878 unsigned char *head = ptr;
879 unsigned char *tail = ptr;
880 head -= MHOOK_DEBUG_CANARY_SPACE;
881 tail += size;
882
883 memset(head, _mhook_canary, MHOOK_DEBUG_CANARY_SPACE);
884 memset(tail, _mhook_canary, MHOOK_DEBUG_CANARY_SPACE);
885}
886
887static void
888_mhook_debug_free_check(void *ptr, size_t size)
889{
890 size_t i;
891 unsigned char *p = ptr;
892
893 for (i = 0; i < size; i++)
894 {
895 if (p[i] != _mhook_fill_pat_free)
896 {
897 fprintf(stderr, "CANARY ERROR BODY @ %p = %x\n",
898 ptr, p[i]);
899 abort();
900 }
901 }
902}
903
904static void
905_mhook_debug_magic_fill(Mhook_Mem_Debug *m)
906{
907 m->blah = (void *)0xf0f0f0f0;
908 memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
909}
910
911static void
912_mhook_debug_real_free(void *ptr)
913{
914 Mhook_Mem_Debug *m;
915 unsigned char *realptr;
916 size_t psize;
917
918 m = (Mhook_Mem_Debug *)(((unsigned char *)ptr) - MHOOK_DEBUG_HEADER_SPACE);
919 realptr = m->realptr;
920 psize = m->size;
921// fprintf(stderr, "real free %p size %lu @ slot %i\n", ptr, psize, _mhook_debug_freebuf_slot);
922 _mhook_debug_canary_check(m);
923 _mhook_debug_free_check(ptr, psize);
924 memset(m, _mhook_fill_pat_free, MHOOK_DEBUG_HEADER_SPACE);
925 memset(((unsigned char *)ptr) + psize, _mhook_fill_pat_free, MHOOK_DEBUG_CANARY_SPACE);
926 _mhook_orig_free(realptr);
927}
928
929static void
930_mhook_debug_free2(void *ptr)
931{
932// _mhook_debug_real_free(ptr);
933// return;
934
935 _mhook_debug_freebuf[_mhook_debug_freebuf_slot] = ptr;
936 _mhook_debug_freebuf_slot++;
937 if (_mhook_debug_freebuf_slot >= MHOOK_DEBUG_FREEBUF_SIZE)
938 {
939 _mhook_debug_freebuf_slot = 0;
940 }
941 if (_mhook_debug_freebuf[_mhook_debug_freebuf_slot])
942 {
943 _mhook_debug_real_free(_mhook_debug_freebuf[_mhook_debug_freebuf_slot]);
944 _mhook_debug_freebuf[_mhook_debug_freebuf_slot] = NULL;
945 }
946}
947
948static void *
949_mhook_debug_malloc(size_t size)
950{
951 Mhook_Mem_Debug *m;
952 size_t ms = size + MHOOK_DEBUG_HEADER_SPACE + MHOOK_DEBUG_CANARY_SPACE;
953 void *result = NULL;
954
955 // FIXME: hack around dlsym doing a malloc/calloc
956 if (!_mhook_orig_malloc) return _mhook_buf;
957 m = _mhook_orig_malloc(ms);
958 if (m)
959 {
960 result = ((unsigned char *)m) + MHOOK_DEBUG_HEADER_SPACE;
961 m->realptr = (unsigned char *)m;
962 m->size = size;
963 _mhook_debug_magic_fill(m);
964 memset(result, _mhook_fill_pat_malloc, size);
965 _mhook_debug_canary_fill(result, size);
966 }
967 return result;
968}
969
970static void
971_mhook_debug_free(void *ptr)
972{
973 Mhook_Mem_Debug *m;
974 size_t psize;
975
976 // FIXME: hack around dlsym doing a malloc/calloc
977 if (ptr == _mhook_buf) return;
978 if (ptr)
979 {
980 m = (Mhook_Mem_Debug *)(((unsigned char *)ptr) - MHOOK_DEBUG_HEADER_SPACE);
981 psize = m->size;
982
983 _mhook_debug_canary_check(m);
984 memset(ptr, _mhook_fill_pat_free, psize);
985 _mhook_debug_free2(ptr);
986 }
987}
988
989static void *
990_mhook_debug_realloc(void *ptr, size_t size)
991{
992 Mhook_Mem_Debug *m, *mold;
993 void *result = NULL;
994 size_t ms = size + MHOOK_DEBUG_HEADER_SPACE + MHOOK_DEBUG_CANARY_SPACE;
995 size_t psize;
996
997 // FIXME: hack around dlsym doing a malloc/calloc
998 if (ptr == _mhook_buf)
999 {
1000 fprintf(stderr, "mtrack: realloc()ing initial _mhook_buf\n");
1001 abort();
1002 }
1003 if (size == 0)
1004 {
1005 if (ptr)
1006 {
1007 m = (Mhook_Mem_Debug *)(((unsigned char *)ptr) - MHOOK_DEBUG_HEADER_SPACE);
1008 psize = m->size;
1009
1010 _mhook_debug_canary_check(m);
1011 memset(ptr, _mhook_fill_pat_free, psize);
1012 _mhook_debug_free2(ptr);
1013 }
1014 }
1015 else if (ptr)
1016 {
1017 m = _mhook_orig_malloc(ms);
1018 if (m)
1019 {
1020 mold = (Mhook_Mem_Debug *)(((unsigned char *)ptr) - MHOOK_DEBUG_HEADER_SPACE);
1021 psize = mold->size;
1022
1023 _mhook_debug_canary_check(mold);
1024 result = ((unsigned char *)m) + MHOOK_DEBUG_HEADER_SPACE;
1025 m->realptr = (unsigned char *)m;
1026 m->size = size;
1027 _mhook_debug_magic_fill(m);
1028 _mhook_debug_canary_fill(result, size);
1029
1030 if (psize < size)
1031 {
1032 memcpy(result, ptr, psize);
1033 memset(((unsigned char *)result) + psize,
1034 _mhook_fill_pat_malloc, size - psize);
1035 }
1036 else memcpy(result, ptr, size);
1037
1038 _mhook_debug_canary_check(mold);
1039 memset(ptr, _mhook_fill_pat_free, psize);
1040 _mhook_debug_free2(ptr);
1041 }
1042 }
1043 else
1044 {
1045 m = _mhook_orig_malloc(ms);
1046 if (m)
1047 {
1048 result = ((unsigned char *)m) + MHOOK_DEBUG_HEADER_SPACE;
1049 m->realptr = (unsigned char *)m;
1050 m->size = size;
1051 _mhook_debug_magic_fill(m);
1052 memset(result, _mhook_fill_pat_malloc, size);
1053 _mhook_debug_canary_fill(result, size);
1054 }
1055 }
1056 return result;
1057}
1058
1059static void *
1060_mhook_debug_memalign(size_t alignment, size_t size)
1061{
1062 Mhook_Mem_Debug *m;
1063 size_t ms = size + MHOOK_DEBUG_HEADER_SPACE + MHOOK_DEBUG_CANARY_SPACE + alignment;
1064 unsigned char *mem;
1065 void *result = NULL;
1066
1067 // FIXME: hack around dlsym doing a malloc/calloc
1068 if (!_mhook_orig_memalign) return _mhook_buf;
1069 mem = _mhook_orig_malloc(ms);
1070 if (mem)
1071 {
1072 unsigned char *palign = mem + MHOOK_DEBUG_HEADER_SPACE;
1073 size_t valign = ((size_t)palign) % alignment;
1074
1075 if (valign > 0) valign = alignment - valign;
1076 palign += valign;
1077 m = (Mhook_Mem_Debug *)palign - (MHOOK_DEBUG_HEADER_SPACE);
1078 result = palign;
1079 m->realptr = (unsigned char *)mem;
1080 m->size = size;
1081 _mhook_debug_magic_fill(m);
1082 memset(result, _mhook_fill_pat_malloc, size);
1083 _mhook_debug_canary_fill(result, size);
1084 }
1085 return result;
1086}
1087
1088static void *
1089_mhook_debug_calloc(size_t nmemb, size_t size)
1090{
1091 Mhook_Mem_Debug *m;
1092 size_t ms = (size * nmemb) + MHOOK_DEBUG_HEADER_SPACE + MHOOK_DEBUG_CANARY_SPACE;
1093 void *result = NULL;
1094
1095 // FIXME: hack around dlsym doing a malloc/calloc
1096 if (!_mhook_orig_malloc)
1097 {
1098 memset(_mhook_buf, 0, nmemb * size);
1099 return _mhook_buf;
1100 }
1101 m = _mhook_orig_malloc(ms);
1102 if (m)
1103 {
1104 result = ((unsigned char *)m) + MHOOK_DEBUG_HEADER_SPACE;
1105 m->realptr = (unsigned char *)m;
1106 m->size = nmemb * size;
1107 _mhook_debug_magic_fill(m);
1108 memset(result, 0, nmemb * size);
1109 _mhook_debug_canary_fill(result, nmemb * size);
1110 }
1111 return result;
1112}
1113
1114
1115
1116
1117
1118
1119/*****************************************************************************/
1120static void *
1121_mhook_malloc(size_t size)
1122{
1123 void *result = NULL;
1124
1125 if (!_mhook_first) pthread_mutex_lock(&lk);
1126 _mhook_do_init();
1127 switch (_mhook_mode)
1128 {
1129 case MHOOK_NONE: result = _mhook_null_malloc(size); break;
1130 case MHOOK_FILL: result = _mhook_fill_malloc(size); break;
1131 case MHOOK_TRACE: result = _mhook_trace_malloc(size); break;
1132 case MHOOK_TRACK: result = _mhook_track_malloc(size); break;
1133 case MHOOK_DEBUG: result = _mhook_debug_malloc(size); break;
1134 }
1135 if (!_mhook_first) pthread_mutex_unlock(&lk);
1136 _mhook_first = 0;
1137 return result;
1138}
1139
1140static void
1141_mhook_free(void *ptr)
1142{
1143 if (!ptr) return;
1144 if (!_mhook_first) pthread_mutex_lock(&lk);
1145 _mhook_do_init();
1146 switch (_mhook_mode)
1147 {
1148 case MHOOK_NONE: _mhook_null_free(ptr); break;
1149 case MHOOK_FILL: _mhook_fill_free(ptr); break;
1150 case MHOOK_TRACE: _mhook_trace_free(ptr); break;
1151 case MHOOK_TRACK: _mhook_track_free(ptr); break;
1152 case MHOOK_DEBUG: _mhook_debug_free(ptr); break;
1153 }
1154 if (!_mhook_first) pthread_mutex_unlock(&lk);
1155 _mhook_first = 0;
1156}
1157
1158static void *
1159_mhook_realloc(void *ptr, size_t size)
1160{
1161 void *result = NULL;
1162
1163 if ((!ptr) && (size == 0)) return NULL;
1164 if (!_mhook_first) pthread_mutex_lock(&lk);
1165 _mhook_do_init();
1166 switch (_mhook_mode)
1167 {
1168 case MHOOK_NONE: result = _mhook_null_realloc(ptr, size); break;
1169 case MHOOK_FILL: result = _mhook_fill_realloc(ptr, size); break;
1170 case MHOOK_TRACE: result = _mhook_trace_realloc(ptr, size); break;
1171 case MHOOK_TRACK: result = _mhook_track_realloc(ptr, size); break;
1172 case MHOOK_DEBUG: result = _mhook_debug_realloc(ptr, size); break;
1173 }
1174 if (!_mhook_first) pthread_mutex_unlock(&lk);
1175 _mhook_first = 0;
1176 return result;
1177}
1178
1179static void *
1180_mhook_memalign(size_t alignment, size_t size)
1181{
1182 void *result = NULL;
1183
1184 if (!_mhook_first) pthread_mutex_lock(&lk);
1185 _mhook_do_init();
1186 switch (_mhook_mode)
1187 {
1188 case MHOOK_NONE: result = _mhook_null_memalign(alignment, size); break;
1189 case MHOOK_FILL: result = _mhook_fill_memalign(alignment, size); break;
1190 case MHOOK_TRACE: result = _mhook_trace_memalign(alignment, size); break;
1191 case MHOOK_TRACK: result = _mhook_track_memalign(alignment, size); break;
1192 case MHOOK_DEBUG: result = _mhook_debug_memalign(alignment, size); break;
1193 }
1194 if (!_mhook_first) pthread_mutex_unlock(&lk);
1195 _mhook_first = 0;
1196 return result;
1197}
1198
1199static void *
1200_mhook_calloc(size_t nmemb, size_t size)
1201{
1202 void *result = NULL;
1203
1204 if (!_mhook_first) pthread_mutex_lock(&lk);
1205 _mhook_do_init();
1206 switch (_mhook_mode)
1207 {
1208 case MHOOK_NONE: result = _mhook_null_calloc(nmemb, size); break;
1209 case MHOOK_FILL: result = _mhook_fill_calloc(nmemb, size); break;
1210 case MHOOK_TRACE: result = _mhook_trace_calloc(nmemb, size); break;
1211 case MHOOK_TRACK: result = _mhook_track_calloc(nmemb, size); break;
1212 case MHOOK_DEBUG: result = _mhook_debug_calloc(nmemb, size); break;
1213 }
1214 if (!_mhook_first) pthread_mutex_unlock(&lk);
1215 _mhook_first = 0;
1216 return result;
1217}
1218
1219
1220/*****************************************************************************/
1221static void
1222_mhook_signal(int sig, siginfo_t *si, void *foo)
1223{
1224 switch (_mhook_mode)
1225 {
1226 case MHOOK_NONE: break;
1227 case MHOOK_FILL: break;
1228 case MHOOK_TRACE: break;
1229 case MHOOK_TRACK: _mhook_track_dump(); break;
1230 case MHOOK_DEBUG: break;
1231 }
1232 return;
1233 sig = 0; si = NULL; foo = NULL;
1234}
1235
1236/*============================================================================*
1237* API *
1238*============================================================================*/
1239
1240static void
1241_mhook_init(void)
1242{
1243 const char *s = getenv("MTRACK");
1244 pthread_mutexattr_t attr;
1245 pthread_mutexattr_init(&attr);
1246 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1247 pthread_mutex_init(&lk, &attr);
1248 if (s)
1249 {
1250 if (!strcmp(s, "fill"))
1251 {
1252 _mhook_mode = MHOOK_FILL;
1253 s = getenv("MTRACK_ALLOC_FILL");
1254 if (s) _mhook_fill_pat_malloc = atoi(s);
1255 s = getenv("MTRACK_FREE_FILL");
1256 if (s) _mhook_fill_pat_free = atoi(s);
1257 }
1258 else if (!strcmp(s, "debug"))
1259 {
1260 _mhook_mode = MHOOK_DEBUG;
1261 s = getenv("MTRACK_ALLOC_FILL");
1262 if (s) _mhook_fill_pat_malloc = atoi(s);
1263 s = getenv("MTRACK_FREE_FILL");
1264 if (s) _mhook_fill_pat_free = atoi(s);
1265 s = getenv("MTRACK_CANARY_SIZE");
1266 if (s) _mhook_canary_size = atoi(s);
1267 s = getenv("MTRACK_CANARY");
1268 if (s) _mhook_canary = atoi(s);
1269 }
1270 else if (!strcmp(s, "trace"))
1271 {
1272 _mhook_mode = MHOOK_TRACE;
1273 s = getenv("MTRACK_TRACE_FILE");
1274 if (s)
1275 {
1276 _mhook_trace_fd = open(s,
1277 O_CREAT | O_WRONLY | O_TRUNC,
1278 S_IRUSR | S_IWUSR);
1279 if (_mhook_trace_fd < 0)
1280 _mhook_mode = MHOOK_NONE;
1281 else
1282 {
1283 if (fcntl(_mhook_trace_fd, F_SETFD, FD_CLOEXEC) < 0)
1284 {
1285 close(_mhook_trace_fd);
1286 _mhook_trace_fd = -1;
1287 _mhook_mode = MHOOK_NONE;
1288 }
1289 }
1290 }
1291 }
1292 else if (!strcmp(s, "track"))
1293 {
1294 _mhook_mode = MHOOK_TRACK;
1295 s = getenv("MTRACK_TRACE_FILE");
1296 if (s)
1297 {
1298 _mhook_track_fd = open(s,
1299 O_CREAT | O_WRONLY | O_TRUNC,
1300 S_IRUSR | S_IWUSR);
1301 if (_mhook_track_fd < 0)
1302 _mhook_mode = MHOOK_NONE;
1303 else
1304 {
1305 if (fcntl(_mhook_track_fd, F_SETFD, FD_CLOEXEC) < 0)
1306 {
1307 close(_mhook_track_fd);
1308 _mhook_track_fd = -1;
1309 _mhook_mode = MHOOK_NONE;
1310 }
1311 else
1312 {
1313 struct sigaction sa;
1314
1315 sa.sa_sigaction = _mhook_signal;
1316 sa.sa_flags = SA_RESTART | SA_SIGINFO;
1317 sigemptyset(&sa.sa_mask);
1318 sigaction(SIGURG, &sa, NULL);
1319 }
1320 }
1321 }
1322 }
1323 else _mhook_mode = MHOOK_NONE;
1324 }
1325}
1326
1327EAPI void *__libc_malloc (size_t size) { return _mhook_malloc(size); }
1328EAPI void *malloc (size_t size) { return _mhook_malloc(size); }
1329EAPI void __libc_free (void *ptr) { _mhook_free(ptr); }
1330EAPI void free (void *ptr) { _mhook_free(ptr); }
1331EAPI void *__libc_realloc (void *ptr, size_t size) { return _mhook_realloc(ptr, size); }
1332EAPI void *realloc (void *ptr, size_t size) { return _mhook_realloc(ptr, size); }
1333EAPI void *__libc_memalign(size_t algn, size_t size) { return _mhook_memalign(algn, size); }
1334EAPI void *memalign (size_t algn, size_t size) { return _mhook_memalign(algn, size); }
1335EAPI void *__libc_calloc (size_t num, size_t size) { return _mhook_calloc(num, size); }
1336EAPI void *calloc (size_t num, size_t size) { return _mhook_calloc(num, size); }
1337
1338static void
1339_mhook_do_init(void)
1340{
1341 static int initted = 0;
1342
1343 if (initted) return;
1344 unsetenv("LD_PRELOAD");
1345 initted = 1;
1346 _mhook_init();
1347 _mhook_orig_malloc = dlsym(RTLD_NEXT, "__libc_malloc");
1348 _mhook_orig_free = dlsym(RTLD_NEXT, "__libc_free");
1349 _mhook_orig_realloc = dlsym(RTLD_NEXT, "__libc_realloc");
1350 _mhook_orig_memalign = dlsym(RTLD_NEXT, "__libc_memalign");
1351 _mhook_orig_calloc = dlsym(RTLD_NEXT, "__libc_calloc");
1352 if (!_mhook_orig_malloc) _mhook_orig_malloc = dlsym(RTLD_NEXT, "malloc");
1353 if (!_mhook_orig_free) _mhook_orig_free = dlsym(RTLD_NEXT, "free");
1354 if (!_mhook_orig_realloc) _mhook_orig_realloc = dlsym(RTLD_NEXT, "realloc");
1355 if (!_mhook_orig_memalign) _mhook_orig_memalign = dlsym(RTLD_NEXT, "memalign");
1356 if (!_mhook_orig_calloc) _mhook_orig_calloc = dlsym(RTLD_NEXT, "calloc");
1357 _mhook_first = 0;
1358}
1359/**
1360 * @}
1361 */
diff --git a/mtshow.c b/mtshow.c
new file mode 100644
index 0000000..a39602b
--- /dev/null
+++ b/mtshow.c
@@ -0,0 +1,197 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <string.h>
5#include <time.h>
6#include <ctype.h>
7#include <Eina.h>
8
9enum {
10 BYTES, KB, MB, SIZE, COUNT
11};
12
13typedef struct _Group Group;
14
15struct _Group
16{
17 char *trace;
18 unsigned long total;
19 unsigned long count;
20};
21
22static Eina_Hash *groups = NULL;
23static Eina_List *sorted = NULL;
24static int size = BYTES;
25static int sort = SIZE;
26
27static int
28listsort(const void *data1, const void *data2)
29{
30 Group *g = (Group *)data1;
31 Group *gg = (Group *)data2;
32 if (sort == SIZE) return (int)(g->total - gg->total);
33 else if (sort == COUNT) return (int)(g->count - gg->count);
34 return (int)(g->total - gg->total);
35}
36
37static Eina_Bool
38hashwalk(const Eina_Hash *hash, const void *key, void *data, void *fdata)
39{
40 Group *g = data;
41 sorted = eina_list_append(sorted, g);
42 return EINA_TRUE;
43}
44
45int
46main(int argc, char **argv)
47{
48 FILE *f;
49 char *file;
50 char buf[4096];
51 int i;
52 int group = 0;
53 Group *g;
54 Eina_List *l;
55 unsigned long total_count = 0, total_size = 0;
56
57 eina_init();
58 if (argc < 1)
59 {
60 printf("usage: mtdump MTOUTFILE [OPT]\n"
61 "OPT can be 0 or more of:\n"
62 " -f N - group by trace of up to N functions in backtrace (0 == unlimited)\n"
63 " -m - show size in Mb\n"
64 " -k - show size in Kb\n"
65 " -b - show size in bytes\n"
66 " -s - sout by size\n"
67 " -c - sout by count\n"
68 );
69 exit(1);
70 }
71 for (i = 0; i < argc; i++)
72 {
73 if (!strcmp(argv[i], "-f"))
74 {
75 i++;
76 group = atoi(argv[i]);
77 }
78 else if (!strcmp(argv[i], "-m"))
79 {
80 size = MB;
81 }
82 else if (!strcmp(argv[i], "-k"))
83 {
84 size = KB;
85 }
86 else if (!strcmp(argv[i], "-b"))
87 {
88 size = BYTES;
89 }
90 else if (!strcmp(argv[i], "-s"))
91 {
92 sort = SIZE;
93 }
94 else if (!strcmp(argv[i], "-c"))
95 {
96 sort = COUNT;
97 }
98 else
99 file = argv[i];
100 }
101 f = fopen(file, "r");
102 if (!f)
103 {
104 perror("fopen");
105 exit(1);
106 }
107
108 groups = eina_hash_string_superfast_new(NULL);
109 while (fgets(buf, sizeof(buf) - 1, f))
110 {
111 int len;
112 unsigned long bytes = 0;
113 char *p;
114
115 len = strlen(buf);
116 if (len < 2) continue;
117 if ((len > 1) && (buf[len - 1] == '\n'))
118 {
119 buf[len - 1] = 0;
120 len--;
121 }
122 sscanf(buf, "%lu", &bytes);
123 p = strchr(buf, '|');
124 if (p)
125 {
126 char trace[4096] = "", *t;
127
128 p += 2;
129 if (group == 0)
130 {
131 strcpy(trace, p);
132 }
133 else
134 {
135 i = group;
136 t = trace;
137 while (*p)
138 {
139 if (isspace(*p))
140 {
141 i--;
142 if (i == 0) break;
143 }
144 *t = *p;
145 t++; p++;
146 }
147 *t = 0;
148 }
149 g = eina_hash_find(groups, trace);
150 if (!g)
151 {
152 g = calloc(1, sizeof(Group));
153 g->trace = strdup(trace);
154 eina_hash_add(groups, trace, g);
155 }
156 g->total += bytes;
157 g->count++;
158 }
159 }
160 fclose(f);
161 eina_hash_foreach(groups, hashwalk, NULL);
162 printf("|-- MEM --|- COUNT --|----------------------------------------------\n");
163 sorted = eina_list_sort(sorted, eina_list_count(sorted), listsort);
164 EINA_LIST_FOREACH(sorted, l, g)
165 {
166 switch (size)
167 {
168 case MB:
169 printf("%10lu [%8lu] %s\n", g->total / (1024 * 1024), g->count, g->trace);
170 break;
171 case KB:
172 printf("%10lu [%8lu] %s\n", g->total / 1024, g->count, g->trace);
173 break;
174 default:
175 printf("%10lu [%8lu] %s\n", g->total, g->count, g->trace);
176 break;
177 }
178 total_count += g->count;
179 total_size += g->total;
180 }
181 printf("|-- MEM --|- COUNT --|----------------------------------------------\n");
182 printf("Total allocs: %lu\n", total_count);
183 switch (size)
184 {
185 case MB:
186 printf("Total memory: %lu Mb\n", total_size / (1024 * 1024));
187 break;
188 case KB:
189 printf("Total memory: %lu Kb\n", total_size / 1024);
190 break;
191 default:
192 printf("Total memory: %lu bytes\n", total_size);
193 break;
194 }
195 exit(0);
196 return 0;
197}
diff --git a/mtt b/mtt
new file mode 100755
index 0000000..363d7cf
--- /dev/null
+++ b/mtt
@@ -0,0 +1,5 @@
1#!/bin/sh
2export MTRACK=trace
3export MTRACK_TRACE_FILE=./mtrack.log
4export LD_PRELOAD=/usr/local/lib/mtrack.so
5exec $@