1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 #include	"vmhdr.h"
15 
16 #if _BLD_INSTRUMENT_ || cray
17 int _STUB_malloc;
18 #else
19 
20 /*	malloc compatibility functions.
21 **	These are aware of debugging/profiling and driven by the environment variables:
22 **	VMETHOD: select an allocation method by name.
23 **
24 **	VMPROFILE: if is a file name, write profile data to it.
25 **	VMTRACE: if is a file name, write trace data to it.
26 **	The pattern %p in a file name will be replaced by the process ID.
27 **
28 **	VMDEBUG:
29 **		a:			abort on any warning
30 **		[decimal]:		period to check arena.
31 **		0x[hexadecimal]:	address to watch.
32 **
33 **	Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
34 */
35 
36 #ifdef HAVE_STAT_H
37 #include	<stat.h>
38 #else
39 #ifdef HAVE_SYS_STAT_H
40 #include	<sys/stat.h>
41 #endif
42 #endif
43 
44 #if defined(S_IRUSR)&&defined(S_IWUSR)&&defined(S_IRGRP)&&defined(S_IROTH)
45 #define CREAT_MODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
46 #else
47 #define CREAT_MODE	0644
48 #endif
49 
50 #undef malloc
51 #undef free
52 #undef realloc
53 #undef calloc
54 #undef cfree
55 #undef memalign
56 #undef valloc
57 
atou(char ** sp)58 static Vmulong_t atou(char **sp)
59 {
60     char *s = *sp;
61     Vmulong_t v = 0;
62 
63     if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
64 	for (s += 2; *s; ++s) {
65 	    if (*s >= '0' && *s <= '9')
66 		v = (v << 4) + (*s - '0');
67 	    else if (*s >= 'a' && *s <= 'f')
68 		v = (v << 4) + (*s - 'a') + 10;
69 	    else if (*s >= 'A' && *s <= 'F')
70 		v = (v << 4) + (*s - 'A') + 10;
71 	    else
72 		break;
73 	}
74     } else {
75 	for (; *s; ++s) {
76 	    if (*s >= '0' && *s <= '9')
77 		v = v * 10 + (*s - '0');
78 	    else
79 		break;
80 	}
81     }
82 
83     *sp = s;
84     return v;
85 }
86 
87 static int _Vmflinit = 0;
88 static Vmulong_t _Vmdbcheck = 0;
89 static Vmulong_t _Vmdbtime = 0;
90 static int _Vmpffd = -1;
91 #define VMFLINIT() \
92 	{ if(!_Vmflinit)	vmflinit(); \
93 	  if(_Vmdbcheck && (++_Vmdbtime % _Vmdbcheck) == 0 && \
94 	     Vmregion->meth.meth == VM_MTDEBUG) \
95 		vmdbcheck(Vmregion); \
96 	}
97 
insertpid(char * begs,char * ends)98 static char *insertpid(char *begs, char *ends)
99 {
100     int pid;
101     char *s;
102 
103     if ((pid = getpid()) < 0)
104 	return NIL(char *);
105 
106     s = ends;
107     do {
108 	if (s == begs)
109 	    return NIL(char *);
110 	*--s = '0' + pid % 10;
111     } while ((pid /= 10) > 0);
112     while (s < ends)
113 	*begs++ = *s++;
114 
115     return begs;
116 }
117 
createfile(char * file)118 static int createfile(char *file)
119 {
120     char buf[1024];
121     char *next, *endb;
122 
123     next = buf;
124     endb = buf + sizeof(buf);
125     while (*file) {
126 	if (*file == '%') {
127 	    switch (file[1]) {
128 	    case 'p':
129 		if (!(next = insertpid(next, endb)))
130 		    return -1;
131 		file += 2;
132 		break;
133 	    default:
134 		goto copy;
135 	    }
136 	} else {
137 	  copy:
138 	    *next++ = *file++;
139 	}
140 
141 	if (next >= endb)
142 	    return -1;
143     }
144 
145     *next = '\0';
146     return creat(buf, CREAT_MODE);
147 }
148 
pfprint(void)149 static void pfprint(void)
150 {
151     if (Vmregion->meth.meth == VM_MTPROFILE)
152 	vmprofile(Vmregion, _Vmpffd);
153 }
154 
vmflinit(void)155 static int vmflinit(void)
156 {
157     char *env;
158     Vmalloc_t *vm;
159     int fd;
160     Vmulong_t addr;
161     char *file;
162     int line;
163 
164     /* this must be done now to avoid any inadvertent recursion (more below) */
165     _Vmflinit = 1;
166     VMFILELINE(Vmregion, file, line);
167 
168     /* if getenv() calls malloc(), this may not be caught by the eventual region */
169     vm = NIL(Vmalloc_t *);
170     if ((env = getenv("VMETHOD"))) {
171 	if (strcmp(env, "Vmdebug") == 0 || strcmp(env, "vmdebug") == 0)
172 	    vm = vmopen(Vmdcsbrk, Vmdebug, 0);
173 	else if (strcmp(env, "Vmprofile") == 0
174 		 || strcmp(env, "vmprofile") == 0)
175 	    vm = vmopen(Vmdcsbrk, Vmprofile, 0);
176 	else if (strcmp(env, "Vmlast") == 0 || strcmp(env, "vmlast") == 0)
177 	    vm = vmopen(Vmdcsbrk, Vmlast, 0);
178 	else if (strcmp(env, "Vmpool") == 0 || strcmp(env, "vmpool") == 0)
179 	    vm = vmopen(Vmdcsbrk, Vmpool, 0);
180 	else if (strcmp(env, "Vmbest") == 0 || strcmp(env, "vmbest") == 0)
181 	    vm = Vmheap;
182     }
183 
184     if ((!vm || vm->meth.meth == VM_MTDEBUG) &&
185 	(env = getenv("VMDEBUG")) && env[0]) {
186 	if (vm || (vm = vmopen(Vmdcsbrk, Vmdebug, 0))) {
187 	    reg int setcheck = 0;
188 
189 	    while (*env) {
190 		if (*env == 'a')
191 		    vmset(vm, VM_DBABORT, 1);
192 
193 		if (*env < '0' || *env > '9')
194 		    env += 1;
195 		else if (env[0] == '0' && (env[1] == 'x' || env[1] == 'X')) {
196 		    if ((addr = atou(&env)) != 0)
197 			vmdbwatch((void *) addr);
198 		} else {
199 		    _Vmdbcheck = atou(&env);
200 		    setcheck = 1;
201 		}
202 	    }
203 	    if (!setcheck)
204 		_Vmdbcheck = 1;
205 	}
206     }
207 
208     if ((!vm || vm->meth.meth == VM_MTPROFILE) &&
209 	(env = getenv("VMPROFILE")) && env[0]) {
210 	_Vmpffd = createfile(env);
211 	if (!vm)
212 	    vm = vmopen(Vmdcsbrk, Vmprofile, 0);
213     }
214 
215     /* slip in the new region now so that malloc() will work fine */
216     if (vm)
217 	Vmregion = vm;
218 
219     /* turn on tracing if requested */
220     if ((env = getenv("VMTRACE")) && env[0] && (fd = createfile(env)) >= 0) {
221 	vmset(Vmregion, VM_TRACE, 1);
222 	vmtrace(fd);
223     }
224 
225     /* make sure that profile data is output upon exiting */
226     if (vm && vm->meth.meth == VM_MTPROFILE) {
227 	if (_Vmpffd < 0)
228 	    _Vmpffd = 2;
229 	/* this may wind up calling malloc(), but region is ok now */
230 	atexit(pfprint);
231     } else if (_Vmpffd >= 0) {
232 	close(_Vmpffd);
233 	_Vmpffd = -1;
234     }
235 
236     /* reset file and line number to correct values for the call */
237     Vmregion->file = file;
238     Vmregion->line = line;
239 
240     return 0;
241 }
242 
malloc(reg size_t size)243 void *malloc(reg size_t size)
244 {
245     VMFLINIT();
246     return (*Vmregion->meth.allocf) (Vmregion, size);
247 }
248 
249 /**
250  * @param data block to be reallocated
251  * @param size new size
252  */
realloc(reg void * data,reg size_t size)253 void *realloc(reg void * data, reg size_t size)
254 {
255     VMFLINIT();
256     return (*Vmregion->meth.resizef) (Vmregion, data, size,
257 				      VM_RSCOPY | VM_RSMOVE);
258 }
259 
free(reg void * data)260 void free(reg void * data)
261 {
262     VMFLINIT();
263     (void) (*Vmregion->meth.freef) (Vmregion, data);
264 }
265 
calloc(reg size_t n_obj,reg size_t s_obj)266 void *calloc(reg size_t n_obj, reg size_t s_obj)
267 {
268     VMFLINIT();
269     return (*Vmregion->meth.resizef) (Vmregion, NIL(void *),
270 				      n_obj * s_obj, VM_RSZERO);
271 }
272 
cfree(reg void * data)273 void cfree(reg void * data)
274 {
275     VMFLINIT();
276     (void) (*Vmregion->meth.freef) (Vmregion, data);
277 }
278 
memalign(reg size_t align,reg size_t size)279 void *memalign(reg size_t align, reg size_t size)
280 {
281     VMFLINIT();
282     return (*Vmregion->meth.alignf) (Vmregion, size, align);
283 }
284 
valloc(reg size_t size)285 void *valloc(reg size_t size)
286 {
287     VMFLINIT();
288     GETPAGESIZE(_Vmpagesize);
289     return (*Vmregion->meth.alignf) (Vmregion, size, _Vmpagesize);
290 }
291 
292 #ifdef HAVE_MALLOC_H
293 
294 #define calloc	______calloc
295 #define free	______free
296 #define malloc	______malloc
297 #define realloc	______realloc
298 
299 #include	<malloc.h>
300 
301 /* in Windows, this is a macro defined in malloc.h and not a function */
302 #undef alloca
303 
304 #ifdef HAVE_MALLOPT
mallopt(int cmd,int value)305 int mallopt(int cmd, int value)
306 {
307     VMFLINIT();
308     return 0;
309 }
310 #endif
311 
312 #ifdef HAVE_MALLINFO
mallinfo(void)313 struct mallinfo mallinfo(void)
314 {
315     Vmstat_t sb;
316     struct mallinfo mi;
317 
318     VMFLINIT();
319     memset(&mi, 0, sizeof(mi));
320     if (vmstat(Vmregion, &sb) >= 0) {
321 	mi.arena = sb.extent;
322 	mi.ordblks = sb.n_busy + sb.n_free;
323 	mi.uordblks = sb.s_busy;
324 	mi.fordblks = sb.s_free;
325     }
326     return mi;
327 }
328 #endif
329 
330 #ifdef HAVE_MSTATS
mstats(void)331 struct mstats mstats(void)
332 {
333     Vmstat_t sb;
334     struct mstats ms;
335 
336     VMFLINIT();
337     memset(&ms, 0, sizeof(ms));
338     if (vmstat(Vmregion, &sb) >= 0) {
339 	ms.bytes_total = sb.extent;
340 	ms.chunks_used = sb.n_busy;
341 	ms.bytes_used = sb.s_busy;
342 	ms.chunks_free = sb.n_free;
343 	ms.bytes_free = sb.s_free;
344     }
345     return ms;
346 }
347 #endif
348 
349 #endif/* HAVE_MALLOC_H */
350 
351 #endif /*_BLD_INSTRUMENT_ || cray*/
352