1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2004-2016. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24 #include "sys.h"
25 #include "erl_mtrace.h"
26
27 #ifdef ERTS_CAN_TRACK_MALLOC
28 #if defined(HAVE_END_SYMBOL)
29 extern char end;
30 #elif defined(HAVE__END_SYMBOL)
31 extern char _end;
32 #endif
33
34 static int inited = 0;
35 static int init(void);
36
37 static volatile char *heap_start = NULL;
38 static volatile char *heap_end = NULL;
39
40 #if defined(ERTS___AFTER_MORECORE_HOOK_CAN_TRACK_MALLOC) /* ----------------- */
41
42 #ifdef HAVE_MALLOC_H
43 # include <malloc.h>
44 #endif
45
46 #undef SBRK_0
47 #define SBRK_0 sbrk(0)
48
49 static void
init_hook(void)50 init_hook(void)
51 {
52 __after_morecore_hook = erts_mtrace_update_heap_size;
53 if (inited)
54 return;
55 heap_end = NULL;
56 #if defined(HAVE_END_SYMBOL)
57 heap_start = &end;
58 #elif defined(HAVE__END_SYMBOL)
59 heap_start = &_end;
60 #else
61 heap_start = SBRK_0;
62 if (heap_start == (SBRK_RET_TYPE) -1) {
63 heap_start = NULL;
64 return;
65 }
66 #endif
67 inited = 1;
68 }
69
70 static int
init(void)71 init(void)
72 {
73 init_hook();
74 return inited;
75 }
76
77 void (*__malloc_initialize_hook)(void) = init_hook;
78
79 #elif defined(ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC) /* ------------------------ */
80 #ifdef HAVE_DLFCN_H
81 # include <dlfcn.h>
82 #endif
83
84 #undef SBRK_0
85 #define SBRK_0 (*real_sbrk)(0)
86
87 #ifndef HAVE_SBRK
88 # error no sbrk()
89 #endif
90 #if !defined(HAVE_END_SYMBOL) && !defined(HAVE__END_SYMBOL)
91 # error no 'end' nor '_end'
92 #endif
93
94 static void update_heap_size(char *new_end);
95
96 #define SBRK_IMPL(RET_TYPE, FUNC, ARG_TYPE) \
97 RET_TYPE FUNC (ARG_TYPE); \
98 static RET_TYPE (*real_ ## FUNC)(ARG_TYPE) = NULL; \
99 RET_TYPE FUNC (ARG_TYPE arg) \
100 { \
101 RET_TYPE res; \
102 if (!inited && !init()) \
103 return (RET_TYPE) -1; \
104 res = (*real_ ## FUNC)(arg); \
105 if (erts_mtrace_enabled && res != ((RET_TYPE) -1)) \
106 update_heap_size((char *) (*real_ ## FUNC)(0)); \
107 return res; \
108 }
109
110 #define BRK_IMPL(RET_TYPE, FUNC, ARG_TYPE) \
111 RET_TYPE FUNC (ARG_TYPE); \
112 static RET_TYPE (*real_ ## FUNC)(ARG_TYPE) = NULL; \
113 RET_TYPE FUNC (ARG_TYPE arg) \
114 { \
115 RET_TYPE res; \
116 if (!inited && !init()) \
117 return (RET_TYPE) -1; \
118 res = (*real_ ## FUNC)(arg); \
119 if (erts_mtrace_enabled && res != ((RET_TYPE) -1)) \
120 update_heap_size((char *) arg); \
121 return res; \
122 }
123
SBRK_IMPL(SBRK_RET_TYPE,sbrk,SBRK_ARG_TYPE)124 SBRK_IMPL(SBRK_RET_TYPE, sbrk, SBRK_ARG_TYPE)
125 #ifdef HAVE_BRK
126 BRK_IMPL(BRK_RET_TYPE, brk, BRK_ARG_TYPE)
127 #endif
128
129 #ifdef HAVE__SBRK
130 SBRK_IMPL(SBRK_RET_TYPE, _sbrk, SBRK_ARG_TYPE)
131 #endif
132 #ifdef HAVE__BRK
133 BRK_IMPL(BRK_RET_TYPE, _brk, BRK_ARG_TYPE)
134 #endif
135
136 #ifdef HAVE___SBRK
137 SBRK_IMPL(SBRK_RET_TYPE, __sbrk, SBRK_ARG_TYPE)
138 #endif
139 #ifdef HAVE___BRK
140 BRK_IMPL(BRK_RET_TYPE, __brk, BRK_ARG_TYPE)
141 #endif
142
143 static int
144 init(void)
145 {
146 if (inited)
147 return 1;
148
149 #define INIT_XBRK_SYM(SYM) \
150 do { \
151 if (!real_ ## SYM) { \
152 real_ ## SYM = dlsym(RTLD_NEXT, #SYM); \
153 if (!real_ ## SYM) { \
154 errno = ENOMEM; \
155 return 0; \
156 } \
157 } \
158 } while (0)
159
160 heap_end = NULL;
161 #if defined(HAVE_END_SYMBOL)
162 heap_start = &end;
163 #elif defined(HAVE__END_SYMBOL)
164 heap_start = &_end;
165 #endif
166
167 INIT_XBRK_SYM(sbrk);
168 #ifdef HAVE_BRK
169 INIT_XBRK_SYM(brk);
170 #endif
171 #ifdef HAVE__SBRK
172 INIT_XBRK_SYM(_sbrk);
173 #endif
174 #ifdef HAVE__BRK
175 INIT_XBRK_SYM(_brk);
176 #endif
177 #ifdef HAVE___SBRK
178 INIT_XBRK_SYM(__sbrk);
179 #endif
180 #ifdef HAVE___BRK
181 INIT_XBRK_SYM(__brk);
182 #endif
183
184 return inited = 1;
185 #undef INIT_XBRK_SYM
186 }
187
188 #endif /* #elif defined(ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC) */ /* ----------- */
189
190 static void
update_heap_size(char * new_end)191 update_heap_size(char *new_end)
192 {
193 volatile char *new_start, *old_start, *old_end;
194 Uint size;
195
196 if (new_end == ((char *) -1))
197 return;
198
199 new_start = (old_start = heap_start);
200 old_end = heap_end;
201 heap_end = new_end;
202 if (new_end < old_start || !old_start)
203 heap_start = (new_start = new_end);
204
205 size = (Uint) (new_end - new_start);
206
207 if (!old_end) {
208 if (size)
209 erts_mtrace_crr_alloc((void *) new_start,
210 ERTS_ALC_A_SYSTEM,
211 ERTS_MTRACE_SEGMENT_ID,
212 size);
213 else
214 heap_end = NULL;
215 }
216 else {
217 if (old_end != new_end || old_start != new_start) {
218
219 if (size)
220 erts_mtrace_crr_realloc((void *) new_start,
221 ERTS_ALC_A_SYSTEM,
222 ERTS_MTRACE_SEGMENT_ID,
223 (void *) old_start,
224 size);
225 else {
226 if (old_start)
227 erts_mtrace_crr_free(ERTS_ALC_A_SYSTEM,
228 ERTS_MTRACE_SEGMENT_ID,
229 (void *) old_start);
230 heap_end = NULL;
231 }
232 }
233 }
234 }
235
236 #endif /* #ifdef ERTS_CAN_TRACK_MALLOC */
237
238 void
erts_mtrace_update_heap_size(void)239 erts_mtrace_update_heap_size(void)
240 {
241 #ifdef ERTS_CAN_TRACK_MALLOC
242 if (erts_mtrace_enabled && (inited || init()))
243 update_heap_size((char *) SBRK_0);
244 #endif
245 }
246
247