blob: 45f4b7317ab06bfbfd50f2acae5b4fb2c54e667f [file] [log] [blame]
sewardjcf2b14a2002-04-12 11:49:29 +00001
2/*--------------------------------------------------------------------*/
3/*--- Code which runs on the simulated CPU. ---*/
4/*--- vg_clientfuncs.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, an x86 protected-mode emulator
9 designed for debugging and profiling binaries on x86-Unixes.
10
11 Copyright (C) 2000-2002 Julian Seward
12 jseward@acm.org
sewardjcf2b14a2002-04-12 11:49:29 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file LICENSE.
30*/
31
32#include "vg_include.h"
33#include "vg_constants.h"
34
35#include "valgrind.h" /* for VALGRIND_MAGIC_SEQUENCE */
36
37
38/* ---------------------------------------------------------------------
39 All the code in this file runs on the SIMULATED CPU. It is
40 intended for various reasons as drop-in replacements for libc
41 functions. These functions have global visibility (obviously) and
42 have no prototypes in vg_include.h, since they are not intended to
43 be called from within Valgrind.
44 ------------------------------------------------------------------ */
45
46/* ---------------------------------------------------------------------
47 Intercepts for the GNU malloc interface.
48 ------------------------------------------------------------------ */
49
50#define SIMPLE_REQUEST1(_qyy_request, _qyy_arg1) \
51 ({unsigned int _qyy_res; \
52 VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, \
53 _qyy_request, \
54 _qyy_arg1, 0, 0, 0); \
55 _qyy_res; \
56 })
57
58#define SIMPLE_REQUEST2(_qyy_request, _qyy_arg1, _qyy_arg2) \
59 ({unsigned int _qyy_res; \
60 VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, \
61 _qyy_request, \
62 _qyy_arg1, _qyy_arg2, 0, 0); \
63 _qyy_res; \
64 })
65
66
67/* Below are new versions of malloc, __builtin_new, free,
68 __builtin_delete, calloc and realloc.
69
70 malloc, __builtin_new, free, __builtin_delete, calloc and realloc
71 can be entered either on the real CPU or the simulated one. If on
72 the real one, this is because the dynamic linker is running the
73 static initialisers for C++, before starting up Valgrind itself.
74 In this case it is safe to route calls through to
75 VG_(malloc)/vg_free, since that is self-initialising.
76
77 Once Valgrind is initialised, vg_running_on_simd_CPU becomes True.
78 The call needs to be transferred from the simulated CPU back to the
79 real one and routed to the vg_client_* functions. To do that, the
80 client-request mechanism (in valgrind.h) is used to convey requests
81 to the scheduler.
82*/
83
84/* ALL calls to malloc wind up here. */
85void* malloc ( UInt n )
86{
87 void* v;
88
89 if (VG_(clo_trace_malloc))
90 VG_(printf)("malloc[simd=%d](%d)",
91 (UInt)VG_(running_on_simd_CPU), n );
92
93 if (VG_(clo_sloppy_malloc)) { while ((n % 4) > 0) n++; }
94
95 if (VG_(running_on_simd_CPU)) {
96 v = (void*)SIMPLE_REQUEST1(VG_USERREQ__MALLOC, n);
97 } else {
98 v = VG_(malloc)(VG_AR_CLIENT, n);
99 }
100 if (VG_(clo_trace_malloc))
101 VG_(printf)(" = %p\n", v );
102 return (void*)v;
103}
104
105
106void* __builtin_new ( UInt n )
107{
108 void* v;
109
110 if (VG_(clo_trace_malloc))
111 VG_(printf)("__builtin_new[simd=%d](%d)",
112 (UInt)VG_(running_on_simd_CPU), n );
113
114 if (VG_(clo_sloppy_malloc)) { while ((n % 4) > 0) n++; }
115
116 if (VG_(running_on_simd_CPU)) {
117 v = (void*)SIMPLE_REQUEST1(VG_USERREQ__BUILTIN_NEW, n);
118 } else {
119 v = VG_(malloc)(VG_AR_CLIENT, n);
120 }
121 if (VG_(clo_trace_malloc))
122 VG_(printf)(" = %p\n", v );
123 return v;
124}
125
126
127void* __builtin_vec_new ( Int n )
128{
129 void* v;
130
131 if (VG_(clo_trace_malloc))
132 VG_(printf)("__builtin_vec_new[simd=%d](%d)",
133 (UInt)VG_(running_on_simd_CPU), n );
134
135 if (VG_(clo_sloppy_malloc)) { while ((n % 4) > 0) n++; }
136
137 if (VG_(running_on_simd_CPU)) {
138 v = (void*)SIMPLE_REQUEST1(VG_USERREQ__BUILTIN_VEC_NEW, n);
139 } else {
140 v = VG_(malloc)(VG_AR_CLIENT, n);
141 }
142 if (VG_(clo_trace_malloc))
143 VG_(printf)(" = %p\n", v );
144 return v;
145}
146
147
148void free ( void* p )
149{
150 if (VG_(clo_trace_malloc))
151 VG_(printf)("free[simd=%d](%p)\n",
152 (UInt)VG_(running_on_simd_CPU), p );
153 if (p == NULL)
154 return;
155 if (VG_(running_on_simd_CPU)) {
156 (void)SIMPLE_REQUEST1(VG_USERREQ__FREE, p);
157 } else {
158 VG_(free)(VG_AR_CLIENT, p);
159 }
160}
161
162
163void __builtin_delete ( void* p )
164{
165 if (VG_(clo_trace_malloc))
166 VG_(printf)("__builtin_delete[simd=%d](%p)\n",
167 (UInt)VG_(running_on_simd_CPU), p );
168 if (p == NULL)
169 return;
170 if (VG_(running_on_simd_CPU)) {
171 (void)SIMPLE_REQUEST1(VG_USERREQ__BUILTIN_DELETE, p);
172 } else {
173 VG_(free)(VG_AR_CLIENT, p);
174 }
175}
176
177
178void __builtin_vec_delete ( void* p )
179{
180 if (VG_(clo_trace_malloc))
181 VG_(printf)("__builtin_vec_delete[simd=%d](%p)\n",
182 (UInt)VG_(running_on_simd_CPU), p );
183 if (p == NULL)
184 return;
185 if (VG_(running_on_simd_CPU)) {
186 (void)SIMPLE_REQUEST1(VG_USERREQ__BUILTIN_VEC_DELETE, p);
187 } else {
188 VG_(free)(VG_AR_CLIENT, p);
189 }
190}
191
192
193void* calloc ( UInt nmemb, UInt size )
194{
195 void* v;
196
197 if (VG_(clo_trace_malloc))
198 VG_(printf)("calloc[simd=%d](%d,%d)",
199 (UInt)VG_(running_on_simd_CPU), nmemb, size );
200
201 if (VG_(running_on_simd_CPU)) {
202 v = (void*)SIMPLE_REQUEST2(VG_USERREQ__CALLOC, nmemb, size);
203 } else {
204 v = VG_(calloc)(VG_AR_CLIENT, nmemb, size);
205 }
206 if (VG_(clo_trace_malloc))
207 VG_(printf)(" = %p\n", v );
208 return v;
209}
210
211
212void* realloc ( void* ptrV, UInt new_size )
213{
214 void* v;
215
216 if (VG_(clo_trace_malloc))
217 VG_(printf)("realloc[simd=%d](%p,%d)",
218 (UInt)VG_(running_on_simd_CPU), ptrV, new_size );
219
220 if (VG_(clo_sloppy_malloc))
221 { while ((new_size % 4) > 0) new_size++; }
222
223 if (ptrV == NULL)
224 return malloc(new_size);
225 if (new_size == 0) {
226 free(ptrV);
227 if (VG_(clo_trace_malloc))
228 VG_(printf)(" = 0\n" );
229 return NULL;
230 }
231 if (VG_(running_on_simd_CPU)) {
232 v = (void*)SIMPLE_REQUEST2(VG_USERREQ__REALLOC, ptrV, new_size);
233 } else {
234 v = VG_(realloc)(VG_AR_CLIENT, ptrV, new_size);
235 }
236 if (VG_(clo_trace_malloc))
237 VG_(printf)(" = %p\n", v );
238 return v;
239}
240
241
242void* memalign ( Int alignment, Int n )
243{
244 void* v;
245
246 if (VG_(clo_trace_malloc))
247 VG_(printf)("memalign[simd=%d](al %d, size %d)",
248 (UInt)VG_(running_on_simd_CPU), alignment, n );
249
250 if (VG_(clo_sloppy_malloc)) { while ((n % 4) > 0) n++; }
251
252 if (VG_(running_on_simd_CPU)) {
253 v = (void*)SIMPLE_REQUEST2(VG_USERREQ__MEMALIGN, alignment, n);
254 } else {
255 v = VG_(malloc_aligned)(VG_AR_CLIENT, alignment, n);
256 }
257 if (VG_(clo_trace_malloc))
258 VG_(printf)(" = %p\n", v );
259 return (void*)v;
260}
261
262
263void* valloc ( Int size )
264{
265 return memalign(VKI_BYTES_PER_PAGE, size);
266}
267
268
269/* Various compatibility wrapper functions, for glibc and libstdc++. */
270void cfree ( void* p )
271{
272 free ( p );
273}
274
275
276int mallopt ( int cmd, int value )
277{
278 /* In glibc-2.2.4, 1 denotes a successful return value for mallopt */
279 return 1;
280}
281
282
283int __posix_memalign ( void **memptr, UInt alignment, UInt size )
284{
285 void *mem;
286
287 /* Test whether the SIZE argument is valid. It must be a power of
288 two multiple of sizeof (void *). */
289 if (size % sizeof (void *) != 0 || (size & (size - 1)) != 0)
290 return VKI_EINVAL /*22*/ /*EINVAL*/;
291
292 mem = memalign (alignment, size);
293
294 if (mem != NULL) {
295 *memptr = mem;
296 return 0;
297 }
298
299 return VKI_ENOMEM /*12*/ /*ENOMEM*/;
300}
301
302
303/* Bomb out if we get any of these. */
304/* HACK: We shouldn't call VG_(panic) or VG_(message) on the simulated
305 CPU. Really we should pass the request in the usual way, and
306 Valgrind itself can do the panic. Too tedious, however.
307*/
308void pvalloc ( void )
309{ VG_(panic)("call to pvalloc\n"); }
310void malloc_stats ( void )
311{ VG_(panic)("call to malloc_stats\n"); }
312void malloc_usable_size ( void )
313{ VG_(panic)("call to malloc_usable_size\n"); }
314void malloc_trim ( void )
315{ VG_(panic)("call to malloc_trim\n"); }
316void malloc_get_state ( void )
317{ VG_(panic)("call to malloc_get_state\n"); }
318void malloc_set_state ( void )
319{ VG_(panic)("call to malloc_set_state\n"); }
320
321void* mallinfo ( void )
322{
323 VG_(message)(Vg_UserMsg,
324 "Warning: incorrectly-handled call to mallinfo()");
325 return NULL;
326}
327
328
329/* ---------------------------------------------------------------------
330 Replace some C lib things with equivs which don't get
331 spurious value warnings. THEY RUN ON SIMD CPU!
332 ------------------------------------------------------------------ */
333
334char* strrchr ( const char* s, int c )
335{
336 UChar ch = (UChar)((UInt)c);
337 UChar* p = (UChar*)s;
338 UChar* last = NULL;
339 while (True) {
340 if (*p == ch) last = p;
341 if (*p == 0) return last;
342 p++;
343 }
344}
345
346char* strchr ( const char* s, int c )
347{
348 UChar ch = (UChar)((UInt)c);
349 UChar* p = (UChar*)s;
350 while (True) {
351 if (*p == ch) return p;
352 if (*p == 0) return NULL;
353 p++;
354 }
355}
356
357char* strcat ( char* dest, const char* src )
358{
359 Char* dest_orig = dest;
360 while (*dest) dest++;
361 while (*src) *dest++ = *src++;
362 *dest = 0;
363 return dest_orig;
364}
365
366unsigned int strlen ( const char* str )
367{
368 UInt i = 0;
369 while (str[i] != 0) i++;
370 return i;
371}
372
373char* strcpy ( char* dest, const char* src )
374{
375 Char* dest_orig = dest;
376 while (*src) *dest++ = *src++;
377 *dest = 0;
378 return dest_orig;
379}
380
381int strncmp ( const char* s1, const char* s2, unsigned int nmax )
382{
383 unsigned int n = 0;
384 while (True) {
385 if (n >= nmax) return 0;
386 if (*s1 == 0 && *s2 == 0) return 0;
387 if (*s1 == 0) return -1;
388 if (*s2 == 0) return 1;
389
390 if (*(UChar*)s1 < *(UChar*)s2) return -1;
391 if (*(UChar*)s1 > *(UChar*)s2) return 1;
392
393 s1++; s2++; n++;
394 }
395}
396
397int strcmp ( const char* s1, const char* s2 )
398{
399 while (True) {
400 if (*s1 == 0 && *s2 == 0) return 0;
401 if (*s1 == 0) return -1;
402 if (*s2 == 0) return 1;
403
404 if (*(char*)s1 < *(char*)s2) return -1;
405 if (*(char*)s1 > *(char*)s2) return 1;
406
407 s1++; s2++;
408 }
409}
410
411void* memchr(const void *s, int c, unsigned int n)
412{
413 unsigned int i;
414 UChar c0 = (UChar)c;
415 UChar* p = (UChar*)s;
416 for (i = 0; i < n; i++)
417 if (p[i] == c0) return (void*)(&p[i]);
418 return NULL;
419}
420
421void* memcpy( void *dst, const void *src, unsigned int len )
422{
423 register char *d;
424 register char *s;
425 if ( dst > src ) {
426 d = (char *)dst + len - 1;
427 s = (char *)src + len - 1;
428 while ( len-- )
429 *d-- = *s--;
430 } else if ( dst < src ) {
431 d = (char *)dst;
432 s = (char *)src;
433 while ( len-- )
434 *d++ = *s++;
435 }
436 return dst;
437}
438
439/*--------------------------------------------------------------------*/
440/*--- end vg_clientfuncs.c ---*/
441/*--------------------------------------------------------------------*/