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