diff options
| author | DJ Delorie <dj@delorie.com> | 2016-02-11 01:49:48 -0500 |
|---|---|---|
| committer | DJ Delorie <dj@delorie.com> | 2016-02-11 01:49:48 -0500 |
| commit | 1322011d96a58f2d7cf9658eaa91f6645ff31b1a (patch) | |
| tree | abe8a109898a46103ecccd2b9e27d517e36de06c /malloc | |
| parent | 649255b5d3d24089ecc0024972a875ee83a2be0a (diff) | |
| download | glibc-1322011d96a58f2d7cf9658eaa91f6645ff31b1a.tar.xz glibc-1322011d96a58f2d7cf9658eaa91f6645ff31b1a.zip | |
Update malloc tracing utility.
Change head pointer to be total calls; adjust users to modulo after
incrementing.
Use mmap() instead of sbrk().
Split environment variables so count and file can be specified.
Export trace hooks so mtrace-ctl can be built against libc.so.
Allow NULL to be passed to __mtrace_get_trace_buffer.
Add some error handling to mtrace-ctl.
Diffstat (limited to 'malloc')
| -rw-r--r-- | malloc/Versions | 4 | ||||
| -rw-r--r-- | malloc/malloc.c | 17 | ||||
| -rw-r--r-- | malloc/mtrace-ctl.c | 62 | ||||
| -rw-r--r-- | malloc/mtrace.h | 10 |
4 files changed, 73 insertions, 20 deletions
diff --git a/malloc/Versions b/malloc/Versions index f3c3d8a093..43cb90938a 100644 --- a/malloc/Versions +++ b/malloc/Versions @@ -72,5 +72,9 @@ libc { __libc_scratch_buffer_grow; __libc_scratch_buffer_grow_preserve; __libc_scratch_buffer_set_array_size; + + # malloc trace hooks for mtrace-ctl + __malloc_set_trace_buffer; + __malloc_get_trace_buffer; } } diff --git a/malloc/malloc.c b/malloc/malloc.c index 6765aba6eb..2fe4adaaf0 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -1093,12 +1093,11 @@ static __thread __malloc_trace_buffer_ptr trace_ptr; static inline void __attribute__((always_inline)) __mtb_trace_entry (uint32_t type, int64_t size, void *ptr1) { - int head1, head2; - do { - head1 = head2 = __malloc_trace_buffer_head; - head2 = (head2 + 1) % __malloc_trace_buffer_size; - } while (catomic_compare_and_exchange_bool_acq (&__malloc_trace_buffer_head, head2, head1)); - trace_ptr = __malloc_trace_buffer + head1; + int head1; + + head1 = catomic_exchange_and_add (&__malloc_trace_buffer_head, 1); + + trace_ptr = __malloc_trace_buffer + (head1 % __malloc_trace_buffer_size); trace_ptr->thread = syscall(__NR_gettid); trace_ptr->type = type; @@ -1128,8 +1127,10 @@ __malloc_set_trace_buffer (void *bufptr, int bufsize) void * __malloc_get_trace_buffer (int *bufcount, int *bufhead) { - *bufcount = __malloc_trace_buffer_size; - *bufhead = __malloc_trace_buffer_head; + if (bufcount) + *bufcount = __malloc_trace_buffer_size; + if (bufhead) + *bufhead = __malloc_trace_buffer_head; return __malloc_trace_buffer; } diff --git a/malloc/mtrace-ctl.c b/malloc/mtrace-ctl.c index 2acc8976ce..641a6a2aff 100644 --- a/malloc/mtrace-ctl.c +++ b/malloc/mtrace-ctl.c @@ -1,19 +1,49 @@ #include <stdio.h> #include <stdlib.h> #include <stdint.h> +#include <string.h> #include <unistd.h> +#include <sys/mman.h> + +/* Build like this: + + gcc -shared -fpic mtrace-ctl.c -o /tmp/mtrace-ctl.so ../../glibc.build/libc.so + + Invoke like this: + + LD_PRELOAD=/tmp/mtrace-ctl.so ./myprog + +*/ #include "mtrace.h" +static void +err(const char *str) +{ + write (2, str, strlen(str)); + write (2, "\n", 1); + exit(1); +} + void __attribute__((constructor)) djmain() { - char *e = getenv("MTRACE_CTL"); - if (!e) e = "1000"; - int sz = atoi(e) * sizeof(struct __malloc_trace_buffer_s); - char *buf = sbrk (sz+15); - while ((intptr_t)buf & 15) - buf ++; + char *e; + int sz; + + e = getenv("MTRACE_CTL_COUNT"); + if (!e) + e = "1000"; + sz = atoi(e) * sizeof(struct __malloc_trace_buffer_s); + + char *buf = mmap (NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (!buf) + err("Cannot mmap"); + + buf[0] = 1; + buf[sz-1] = 1; + + /* This must be the last thing we do. */ __malloc_set_trace_buffer ((void *)buf, sz); return; } @@ -31,17 +61,29 @@ const char * const typenames[] = { void __attribute__((destructor)) djend() { + char *e; FILE *outf; int head, size, i; + + /* Prevent problems with recursion etc by shutting off trace right away. */ __malloc_trace_buffer_ptr buf = __malloc_get_trace_buffer (&size, &head); - outf = fopen("/tmp/mtrace.out", "w"); + __malloc_set_trace_buffer (NULL, 0); + + e = getenv("MTRACE_CTL_FILE"); + if (!e) + e = "/tmp/mtrace.out"; + + outf = fopen(e, "w"); if (!outf) - return; + err("cannot open output file"); + setbuf (outf, NULL); + + fprintf (outf, "%d out of %d events captured\n", head, size); fprintf (outf, "threadid type path ptr1 size ptr2\n"); for (i=0; i<size; i++) { - __malloc_trace_buffer_ptr t = buf + i % size; + __malloc_trace_buffer_ptr t = buf + (i+head) % size; switch (t->type) { @@ -65,5 +107,7 @@ djend() } } fclose (outf); + + munmap (buf, size * sizeof(struct __malloc_trace_buffer_s)); return; } diff --git a/malloc/mtrace.h b/malloc/mtrace.h index bcb5b63a59..e0fdd7bd48 100644 --- a/malloc/mtrace.h +++ b/malloc/mtrace.h @@ -51,14 +51,18 @@ extern volatile int __malloc_trace_buffer_head; chunk in BYTES. Returns the size of __malloc_trace_buffer_s. The buffer should be filled with NUL bytes before passing, such that each record's type is UNUSED (below). The trace buffer may be - disabled by passing NULL,0 although it's up to the caller to free - the previous buffer first. */ + disabled by passing NULL,0 although it's up to the caller to obtain + and free/unmap the previous buffer first. */ int __malloc_set_trace_buffer (void *bufptr, int bufsize); /* Returns the location of the buffer (same as passed above, or NULL). Also fills in BUFCOUNT which is the number of records (not bytes) in the buffer, and BUFHEAD which is the index of the most recently - filled entry. */ + filled entry. NOTE that BUFHEAD might be greater than bufcount; if + so it reflects the number of records that would have been stored + had there been size, and the caller must modulo that by BUFCOUNT to + get the ending index. The last BUFCOUNT records are stored; + earlier records are overwritten. */ void * __malloc_get_trace_buffer (int *bufcount, int *bufhead); |
