source: memlog.c @ 430548b

Revision 430548b, 5.2 KB checked in by Hal Finkel <hfinkel@…>, 9 years ago (diff)

a working solution for static linking

  • Property mode set to 100644
Line 
1#ifndef _GNU_SOURCE
2#define _GNU_SOURCE
3#endif
4
5#include <stdlib.h>
6#include <stdio.h>
7#include <limits.h>
8#include <string.h>
9
10#include <malloc.h>
11#include <execinfo.h>
12#include <sys/syscall.h>
13#include <sys/time.h>
14#include <sys/resource.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <sys/utsname.h>
18#include <fcntl.h>
19#include <unistd.h>
20
21#include <pthread.h>
22
23#include <dlfcn.h>
24
25FILE *log_file = NULL;
26static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
27
28// The malloc hook might use functions that call malloc, and we need to make
29// sure this does not cause an infinite loop.
30static __thread int in_malloc = 0;
31
32__attribute__((__constructor__))
33static void record_init() {
34  struct utsname u;
35  uname(&u);
36
37  char log_name[PATH_MAX];
38  snprintf(log_name, PATH_MAX, "%s.%d.memlog", u.nodename, getpid());
39  log_file = fopen(log_name, "w");
40  if (!log_file)
41    fprintf(stderr, "fopen failed for '%s': %m\n", log_name);
42}
43
44__attribute__((__destructor__))
45static void record_cleanup() {
46  if (!log_file)
47    return;
48
49  // These functions might call free, but we're shutting down, so don't try to
50  // unwind the stack from here...
51  in_malloc = 1;
52
53  (void) fflush(log_file);
54  (void) fclose(log_file);
55}
56
57static void print_context(const void *caller) {
58  struct rusage usage;
59  if (getrusage(RUSAGE_SELF, &usage)) {
60    fprintf(stderr, "getrusage failed: %m\n");
61    return;
62  }
63
64  fprintf(log_file, "\t%ld.%06ld %ld %ld", usage.ru_utime.tv_sec,
65          usage.ru_utime.tv_usec, usage.ru_maxrss, syscall(SYS_gettid));
66
67  void *pcs[1024];
68  int num_pcs = backtrace(pcs, 1024);
69
70  int found_caller = 0;
71  caller =  __builtin_extract_return_addr((void*) caller);
72  for (int pci = 0; pci < num_pcs; ++pci) {
73    intptr_t pc = (intptr_t) pcs[pci];
74
75    if (!pc)
76      break;
77
78    if (!found_caller) {
79      if (pc != (intptr_t) caller)
80        continue;
81
82      found_caller = 1;
83    }
84
85    intptr_t off, relpc;
86    const char *proc_name;
87    const char *file_name;
88    Dl_info dlinfo;
89    if (dladdr((void *) pc, &dlinfo) && dlinfo.dli_fname &&
90        *dlinfo.dli_fname) {
91      intptr_t saddr = (intptr_t) dlinfo.dli_saddr;
92      if (saddr) {
93#if defined(__powerpc64__) && !defined(__powerpc64le__)
94        // On PPC64 ELFv1, the symbol address points to the function descriptor, not
95        // the actual starting address.
96        saddr = *(intptr_t*) saddr;
97#endif
98
99        off = pc - saddr;
100        relpc = pc - ((intptr_t) dlinfo.dli_fbase);
101      } else {
102        off = 0;
103        relpc = 0;
104      }
105
106      proc_name = dlinfo.dli_sname;
107      if (!proc_name)
108        proc_name = "?";
109
110      file_name = dlinfo.dli_fname;
111    } else {
112      off = pc;
113      relpc = pc;
114      proc_name = "?";
115      file_name = "?";
116    }
117
118    fprintf(log_file, "\t%s (%s+0x%x) [0x%lx (0x%lx)]", file_name, proc_name, (int) off,
119            (long) pc, (long) relpc);
120  }
121}
122
123static void record_malloc(size_t size, void *ptr, const void *caller) {
124  if (!log_file)
125    return;
126
127  if (pthread_mutex_lock(&log_mutex))
128    return;
129
130  fprintf(log_file, "M: %zd %p", size, ptr);
131  print_context(caller);
132  fprintf(log_file, "\n");
133
134done:
135  pthread_mutex_unlock(&log_mutex);
136}
137
138static void record_free(void *ptr, const void *caller) {
139  if (!log_file)
140    return;
141
142  if (pthread_mutex_lock(&log_mutex))
143    return;
144
145  fprintf(log_file, "F: %p", ptr);
146  print_context(caller);
147  fprintf(log_file, "\n");
148
149done:
150  pthread_mutex_unlock(&log_mutex);
151}
152
153// glibc exports its underlying malloc implementation under the name
154// __libc_malloc so that hooks like this can use it.
155extern void *__libc_malloc(size_t size);
156extern void *__libc_realloc(void *ptr, size_t size);
157extern void *__libc_calloc(size_t nmemb, size_t size);
158extern void *__libc_memalign(size_t boundary, size_t size);
159extern void __libc_free(void *ptr);
160
161#ifdef __PIC__
162#define FUNC(x) x
163#else
164#define FUNC(x) __wrap_ ## x
165#endif
166
167void *FUNC(malloc)(size_t size) {
168  const void *caller = __builtin_return_address(0);
169
170  if (in_malloc)
171    return __libc_malloc(size);
172
173  in_malloc = 1;
174
175  void *ptr = __libc_malloc(size);
176
177  record_malloc(size, ptr, caller);
178
179  in_malloc = 0;
180  return ptr;
181}
182
183void *FUNC(realloc)(void *ptr, size_t size) {
184  const void *caller = __builtin_return_address(0);
185
186  if (in_malloc)
187    return __libc_realloc(ptr, size);
188
189  in_malloc = 1;
190
191  void *nptr = __libc_realloc(ptr, size);
192
193  if (ptr)
194    record_free(ptr, caller);
195  record_malloc(size, nptr, caller);
196
197  in_malloc = 0;
198
199  return nptr;
200}
201
202void *FUNC(calloc)(size_t nmemb, size_t size) {
203  const void *caller = __builtin_return_address(0);
204
205  if (in_malloc)
206    return __libc_calloc(nmemb, size);
207
208  in_malloc = 1;
209
210  void *ptr = __libc_calloc(nmemb, size);
211
212  record_malloc(nmemb*size, ptr, caller);
213
214  in_malloc = 0;
215
216  return ptr;
217}
218
219void *FUNC(memalign)(size_t boundary, size_t size) {
220  const void *caller = __builtin_return_address(0);
221
222  if (in_malloc)
223    return __libc_memalign(boundary, size);
224
225  in_malloc = 1;
226
227  void *ptr = __libc_memalign(boundary, size);
228
229  record_malloc(size, ptr, caller);
230
231  in_malloc = 0;
232
233  return ptr;
234}
235
236void FUNC(free)(void *ptr) {
237  const void *caller = __builtin_return_address(0);
238
239  if (in_malloc || !ptr)
240    return __libc_free(ptr);
241
242  in_malloc = 1;
243
244  record_free(ptr, caller);
245
246  __libc_free(ptr);
247
248  in_malloc = 0;
249}
250
Note: See TracBrowser for help on using the repository browser.