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