source: memlog.c @ 0ec59c5

Revision 0ec59c5, 3.9 KB checked in by Hal Finkel <hfinkel@…>, 9 years ago (diff)

Commit something that compiles

  • 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 <sys/types.h>
11#include <sys/stat.h>
12#include <sys/utsname.h>
13#include <fcntl.h>
14#include <unistd.h>
15
16#include <pthread.h>
17
18#define UNW_LOCAL_ONLY
19#include <libunwind.h>
20
21#include <dlfcn.h>
22
23FILE *log_file = NULL;
24static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
25
26__attribute__((__constructor__))
27static void record_init() {
28  struct utsname u;
29  uname(&u);
30
31  char log_name[PATH_MAX];
32  snprintf(log_name, PATH_MAX, "%s.%d.memory.log_file", u.nodename, getpid());
33  log_file = fopen(log_name, "w");
34}
35
36__attribute__((__destructor__))
37static void record_cleanup() {
38  if (!log_file)
39    return;
40
41  (void) fflush(log_file);
42  (void) fclose(log_file);
43}
44
45static void print_context(unw_context_t *context) {
46  unw_cursor_t cursor;
47  if (unw_init_local(&cursor, context))
48    return;
49
50  while (unw_step(&cursor) > 0) {
51    unw_proc_info_t pip;
52    if (unw_get_proc_info(&cursor, &pip))
53      return;
54
55    unw_word_t off;
56    char proc_name[PATH_MAX];
57    if (unw_get_proc_name(&cursor, proc_name, PATH_MAX, &off)) {
58      off = 0;
59      strcpy(proc_name, "?");
60    }
61
62    const char *file_name;
63    Dl_info dlinfo;
64    if (dladdr((void *)(pip.start_ip + off), &dlinfo) && dlinfo.dli_fname &&
65        *dlinfo.dli_fname)
66      file_name = dlinfo.dli_fname;
67    else
68      file_name = "?";
69
70    fprintf(log_file, "\t%s (%s+0x%x) [%p]", file_name, proc_name, (int) off,
71            (void *) (pip.start_ip + off));
72  }
73}
74
75static void record_malloc(size_t size, void *ptr, unw_context_t *uc) {
76  if (!log_file)
77    return;
78
79  if (pthread_mutex_lock(&log_mutex))
80    return;
81
82  fprintf(log_file, "M: %zd %p", size, ptr);
83  print_context(uc);
84  fprintf(log_file, "\n");
85
86done:
87  pthread_mutex_unlock(&log_mutex);
88}
89
90static void record_free(void *ptr, unw_context_t *uc) {
91  if (!log_file)
92    return;
93
94  if (pthread_mutex_lock(&log_mutex))
95    return;
96
97  fprintf(log_file, "F: %p", ptr);
98  print_context(uc);
99  fprintf(log_file, "\n");
100
101done:
102  pthread_mutex_unlock(&log_mutex);
103}
104
105// glibc exports its underlying malloc implementation under the name
106// __libc_malloc so that hooks like this can use it.
107extern void *__libc_malloc(size_t size);
108extern void *__libc_realloc(void *ptr, size_t size);
109extern void *__libc_calloc(size_t nmemb, size_t size);
110extern void *__libc_memalign(size_t boundary, size_t size);
111extern void __libc_free(void *ptr);
112
113// The malloc hook might use functions that call malloc, and we need to make
114// sure this does not cause an infinite loop.
115static __thread int in_malloc = 0;
116
117void *malloc(size_t size) {
118  if (in_malloc)
119    return __libc_malloc(size);
120
121  in_malloc = 1;
122
123  void *ptr = __libc_malloc(size);
124
125  unw_context_t uc;
126  if (!unw_getcontext(&uc))
127    record_malloc(size, ptr, &uc);
128
129  in_malloc = 0;
130  return ptr;
131}
132
133void *realloc(void *ptr, size_t size) {
134  if (in_malloc)
135    return __libc_realloc(ptr, size);
136
137  in_malloc = 1;
138
139  void *nptr = __libc_realloc(ptr, size);
140
141  unw_context_t uc;
142  if (!unw_getcontext(&uc)) {
143    record_free(ptr, &uc);
144    record_malloc(size, nptr, &uc);
145  }
146
147  in_malloc = 0;
148
149  return nptr;
150}
151
152void *calloc(size_t nmemb, size_t size) {
153  if (in_malloc)
154    return __libc_calloc(nmemb, size);
155
156  in_malloc = 1;
157
158  void *ptr = __libc_calloc(nmemb, size);
159
160  unw_context_t uc;
161  if (!unw_getcontext(&uc))
162    record_malloc(nmemb*size, ptr, &uc);
163
164  in_malloc = 0;
165
166  return ptr;
167}
168
169void *memalign(size_t boundary, size_t size) {
170  if (in_malloc)
171    return __libc_memalign(boundary, size);
172
173  in_malloc = 1;
174
175  void *ptr = __libc_memalign(boundary, size);
176
177  unw_context_t uc;
178  if (!unw_getcontext(&uc))
179    record_malloc(size, ptr, &uc);
180
181  in_malloc = 0;
182
183  return ptr;
184}
185
186void free(void *ptr) {
187  if (in_malloc)
188    return __libc_free(ptr);
189
190  in_malloc = 1;
191
192  unw_context_t uc;
193  if (!unw_getcontext(&uc))
194    record_free(ptr, &uc);
195
196  __libc_free(ptr);
197
198  in_malloc = 0;
199}
200
Note: See TracBrowser for help on using the repository browser.