blob: 343581baeac6229a893ab8c23637ca4ff6074828 [file] [log] [blame]
njn3e884182003-04-15 13:03:23 +00001
2/*--------------------------------------------------------------------*/
3/*--- Replacements for strcpy(), memcpy() et al, which run on the ---*/
4/*--- simulated CPU. ---*/
njn1d0825f2006-03-27 11:37:07 +00005/*--- mc_replace_strmem.c ---*/
njn3e884182003-04-15 13:03:23 +00006/*--------------------------------------------------------------------*/
7
8/*
nethercote137bc552003-11-14 17:47:54 +00009 This file is part of MemCheck, a heavyweight Valgrind tool for
njn0e1b5142003-04-15 14:58:06 +000010 detecting memory errors.
njn3e884182003-04-15 13:03:23 +000011
sewardjec062e82011-10-23 07:32:08 +000012 Copyright (C) 2000-2011 Julian Seward
njn3e884182003-04-15 13:03:23 +000013 jseward@acm.org
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 COPYING.
31*/
32
njnc7561b92005-06-19 01:24:32 +000033#include "pub_tool_basics.h"
philippe6643e962012-01-17 21:16:30 +000034#include "pub_tool_poolalloc.h"
njnc7561b92005-06-19 01:24:32 +000035#include "pub_tool_hashtable.h"
njnc7561b92005-06-19 01:24:32 +000036#include "pub_tool_redir.h"
37#include "pub_tool_tooliface.h"
38#include "valgrind.h"
39
njn34419c12003-05-02 17:24:29 +000040#include "mc_include.h"
fitzhardinge98abfc72003-12-16 02:05:15 +000041#include "memcheck.h"
njn3e884182003-04-15 13:03:23 +000042
njn3e884182003-04-15 13:03:23 +000043/* ---------------------------------------------------------------------
njn1f8b3e72005-03-22 04:27:14 +000044 We have our own versions of these functions for two reasons:
45 (a) it allows us to do overlap checking
46 (b) some of the normal versions are hyper-optimised, which fools
47 Memcheck and cause spurious value warnings. Our versions are
48 simpler.
49
njn16eeb4e2005-06-16 03:56:58 +000050 Note that overenthusiastic use of PLT bypassing by the glibc people also
51 means that we need to patch multiple versions of some of the functions to
52 our own implementations.
53
njn1f8b3e72005-03-22 04:27:14 +000054 THEY RUN ON THE SIMD CPU!
njn3e884182003-04-15 13:03:23 +000055 ------------------------------------------------------------------ */
56
sewardj96044842011-08-18 13:09:55 +000057/* Assignment of behavioural equivalence class tags: 2NNNP is intended
sewardjbd2cff22011-08-16 21:45:28 +000058 to be reserved for Memcheck. Current usage:
59
sewardj96044842011-08-18 13:09:55 +000060 20010 STRRCHR
61 20020 STRCHR
62 20030 STRCAT
63 20040 STRNCAT
64 20050 STRLCAT
65 20060 STRNLEN
66 20070 STRLEN
67 20080 STRCPY
68 20090 STRNCPY
69 20100 STRLCPY
70 20110 STRNCMP
71 20120 STRCASECMP
72 20130 STRNCASECMP
73 20140 STRCASECMP_L
74 20150 STRNCASECMP_L
75 20160 STRCMP
76 20170 MEMCHR
77
78 20180 MEMCPY if there's a conflict between memcpy and
79 20181 MEMMOVE memmove, prefer memmove
80
81 20190 MEMCMP
82 20200 STPCPY
83 20210 MEMSET
84 2022P unused (was previously MEMMOVE)
85 20230 BCOPY
86 20240 GLIBC25___MEMMOVE_CHK
87 20250 GLIBC232_STRCHRNUL
88 20260 GLIBC232_RAWMEMCHR
89 20270 GLIBC25___STRCPY_CHK
90 20280 GLIBC25___STPCPY_CHK
91 20290 GLIBC25_MEMPCPY
92 20300 GLIBC26___MEMCPY_CHK
93 20310 STRSTR
94 20320 STRPBRK
95 20330 STRCSPN
96 20340 STRSPN
sewardj284f2a32011-10-21 08:07:13 +000097 20350 STRCASESTR
sewardjbd2cff22011-08-16 21:45:28 +000098*/
99
sewardj126e82d2011-07-12 13:33:00 +0000100
sewardjdda830a2003-07-20 22:28:42 +0000101/* Figure out if [dst .. dst+dstlen-1] overlaps with
102 [src .. src+srclen-1].
103 We assume that the address ranges do not wrap around
104 (which is safe since on Linux addresses >= 0xC0000000
105 are not accessible and the program will segfault in this
106 circumstance, presumably).
107*/
sewardj126e82d2011-07-12 13:33:00 +0000108static inline
njnc6168192004-11-29 13:54:10 +0000109Bool is_overlap ( void* dst, const void* src, SizeT dstlen, SizeT srclen )
njn3e884182003-04-15 13:03:23 +0000110{
sewardjdda830a2003-07-20 22:28:42 +0000111 Addr loS, hiS, loD, hiD;
112
113 if (dstlen == 0 || srclen == 0)
114 return False;
115
116 loS = (Addr)src;
117 loD = (Addr)dst;
118 hiS = loS + srclen - 1;
119 hiD = loD + dstlen - 1;
120
121 /* So figure out if [loS .. hiS] overlaps with [loD .. hiD]. */
122 if (loS < loD) {
123 return !(hiS < loD);
124 }
125 else if (loD < loS) {
126 return !(hiD < loS);
127 }
128 else {
129 /* They start at same place. Since we know neither of them has
130 zero length, they must overlap. */
131 return True;
132 }
njn3e884182003-04-15 13:03:23 +0000133}
134
sewardj126e82d2011-07-12 13:33:00 +0000135
136/* Call here to exit if we can't continue. On Android we can't call
137 _exit for some reason, so we have to blunt-instrument it. */
138__attribute__ ((__noreturn__))
139static inline void my_exit ( int x )
140{
141# if defined(VGPV_arm_linux_android)
142 __asm__ __volatile__(".word 0xFFFFFFFF");
143 while (1) {}
144# else
florian28936a82011-10-05 14:36:00 +0000145 extern __attribute__ ((__noreturn__)) void _exit(int status);
sewardj49665422011-07-12 13:50:59 +0000146 _exit(x);
sewardj126e82d2011-07-12 13:33:00 +0000147# endif
148}
149
150
njn1f8b3e72005-03-22 04:27:14 +0000151// This is a macro rather than a function because we don't want to have an
152// extra function in the stack trace.
bart575ce8e2011-05-15 07:04:03 +0000153#define RECORD_OVERLAP_ERROR(s, src, dst, len) \
sewardj4b3a7422011-10-24 13:21:57 +0000154 VALGRIND_DO_CLIENT_REQUEST_STMT( \
bart575ce8e2011-05-15 07:04:03 +0000155 _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR, \
156 s, src, dst, len, 0)
njn3e884182003-04-15 13:03:23 +0000157
njn16eeb4e2005-06-16 03:56:58 +0000158
sewardj3c944452011-09-05 20:39:57 +0000159/*---------------------- strrchr ----------------------*/
160
njn16eeb4e2005-06-16 03:56:58 +0000161#define STRRCHR(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000162 char* VG_REPLACE_FUNCTION_EZU(20010,soname,fnname)( const char* s, int c ); \
163 char* VG_REPLACE_FUNCTION_EZU(20010,soname,fnname)( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000164 { \
165 UChar ch = (UChar)((UInt)c); \
166 UChar* p = (UChar*)s; \
167 UChar* last = NULL; \
168 while (True) { \
169 if (*p == ch) last = p; \
170 if (*p == 0) return last; \
171 p++; \
172 } \
njn3e884182003-04-15 13:03:23 +0000173 }
njn3e884182003-04-15 13:03:23 +0000174
njn16eeb4e2005-06-16 03:56:58 +0000175// Apparently rindex() is the same thing as strrchr()
njnb4cfbc42009-05-04 04:20:02 +0000176#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000177 STRRCHR(VG_Z_LIBC_SONAME, strrchr)
178 STRRCHR(VG_Z_LIBC_SONAME, rindex)
179 STRRCHR(VG_Z_LIBC_SONAME, __GI_strrchr)
180 STRRCHR(VG_Z_LD_LINUX_SO_2, rindex)
sewardj4157d4f2011-09-05 22:18:13 +0000181
njnf76d27a2009-05-28 01:53:07 +0000182#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000183 //STRRCHR(VG_Z_LIBC_SONAME, strrchr)
184 //STRRCHR(VG_Z_LIBC_SONAME, rindex)
185 //STRRCHR(VG_Z_DYLD, strrchr)
186 //STRRCHR(VG_Z_DYLD, rindex)
187 STRRCHR(VG_Z_LIBC_SONAME, strrchr)
sewardj4157d4f2011-09-05 22:18:13 +0000188
njnb4cfbc42009-05-04 04:20:02 +0000189#endif
njn16eeb4e2005-06-16 03:56:58 +0000190
191
sewardj3c944452011-09-05 20:39:57 +0000192/*---------------------- strchr ----------------------*/
193
njn16eeb4e2005-06-16 03:56:58 +0000194#define STRCHR(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000195 char* VG_REPLACE_FUNCTION_EZU(20020,soname,fnname) ( const char* s, int c ); \
196 char* VG_REPLACE_FUNCTION_EZU(20020,soname,fnname) ( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000197 { \
198 UChar ch = (UChar)((UInt)c); \
199 UChar* p = (UChar*)s; \
200 while (True) { \
201 if (*p == ch) return p; \
202 if (*p == 0) return NULL; \
203 p++; \
204 } \
njn3e884182003-04-15 13:03:23 +0000205 }
njn3e884182003-04-15 13:03:23 +0000206
njn16eeb4e2005-06-16 03:56:58 +0000207// Apparently index() is the same thing as strchr()
njnb4cfbc42009-05-04 04:20:02 +0000208#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000209 STRCHR(VG_Z_LIBC_SONAME, strchr)
210 STRCHR(VG_Z_LIBC_SONAME, index)
211 STRCHR(VG_Z_LIBC_SONAME, __GI_strchr)
212# if !defined(VGP_x86_linux)
213 STRCHR(VG_Z_LD_LINUX_SO_2, strchr)
214 STRCHR(VG_Z_LD_LINUX_SO_2, index)
215 STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr)
216 STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index)
217# endif
sewardj4157d4f2011-09-05 22:18:13 +0000218
njnf76d27a2009-05-28 01:53:07 +0000219#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000220 //STRCHR(VG_Z_LIBC_SONAME, strchr)
221 //STRCHR(VG_Z_LIBC_SONAME, index)
222 //STRCHR(VG_Z_DYLD, strchr)
223 //STRCHR(VG_Z_DYLD, index)
224 STRCHR(VG_Z_LIBC_SONAME, strchr)
sewardj4157d4f2011-09-05 22:18:13 +0000225
njnb4cfbc42009-05-04 04:20:02 +0000226#endif
njn3e884182003-04-15 13:03:23 +0000227
njn3e884182003-04-15 13:03:23 +0000228
sewardj3c944452011-09-05 20:39:57 +0000229/*---------------------- strcat ----------------------*/
230
njn16eeb4e2005-06-16 03:56:58 +0000231#define STRCAT(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000232 char* VG_REPLACE_FUNCTION_EZU(20030,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000233 ( char* dst, const char* src ); \
sewardj96044842011-08-18 13:09:55 +0000234 char* VG_REPLACE_FUNCTION_EZU(20030,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000235 ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000236 { \
237 const Char* src_orig = src; \
238 Char* dst_orig = dst; \
239 while (*dst) dst++; \
240 while (*src) *dst++ = *src++; \
241 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000242 \
njn16eeb4e2005-06-16 03:56:58 +0000243 /* This is a bit redundant, I think; any overlap and the strcat will */ \
244 /* go forever... or until a seg fault occurs. */ \
245 if (is_overlap(dst_orig, \
246 src_orig, \
247 (Addr)dst-(Addr)dst_orig+1, \
248 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000249 RECORD_OVERLAP_ERROR("strcat", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000250 \
njn16eeb4e2005-06-16 03:56:58 +0000251 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000252 }
njn3e884182003-04-15 13:03:23 +0000253
tomd2645142009-10-29 09:27:11 +0000254#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000255 STRCAT(VG_Z_LIBC_SONAME, strcat)
256 STRCAT(VG_Z_LIBC_SONAME, __GI_strcat)
sewardj4157d4f2011-09-05 22:18:13 +0000257
sewardj3c944452011-09-05 20:39:57 +0000258#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000259 //STRCAT(VG_Z_LIBC_SONAME, strcat)
sewardj4157d4f2011-09-05 22:18:13 +0000260
tomd2645142009-10-29 09:27:11 +0000261#endif
njn16eeb4e2005-06-16 03:56:58 +0000262
sewardj3c944452011-09-05 20:39:57 +0000263
264/*---------------------- strncat ----------------------*/
265
njn16eeb4e2005-06-16 03:56:58 +0000266#define STRNCAT(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000267 char* VG_REPLACE_FUNCTION_EZU(20040,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000268 ( char* dst, const char* src, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000269 char* VG_REPLACE_FUNCTION_EZU(20040,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000270 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000271 { \
272 const Char* src_orig = src; \
273 Char* dst_orig = dst; \
274 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000275 \
njn16eeb4e2005-06-16 03:56:58 +0000276 while (*dst) dst++; \
277 while (m < n && *src) { m++; *dst++ = *src++; } /* concat <= n chars */ \
278 *dst = 0; /* always add null */ \
sewardjb6c04032007-11-13 20:52:29 +0000279 \
njn16eeb4e2005-06-16 03:56:58 +0000280 /* This checks for overlap after copying, unavoidable without */ \
281 /* pre-counting lengths... should be ok */ \
282 if (is_overlap(dst_orig, \
283 src_orig, \
sewardjbd2cff22011-08-16 21:45:28 +0000284 (Addr)dst-(Addr)dst_orig+1, \
njn16eeb4e2005-06-16 03:56:58 +0000285 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000286 RECORD_OVERLAP_ERROR("strncat", dst_orig, src_orig, n); \
sewardjb6c04032007-11-13 20:52:29 +0000287 \
njn16eeb4e2005-06-16 03:56:58 +0000288 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000289 }
njn3e884182003-04-15 13:03:23 +0000290
sewardj3c944452011-09-05 20:39:57 +0000291#if defined(VGO_linux)
292 STRNCAT(VG_Z_LIBC_SONAME, strncat)
sewardj4157d4f2011-09-05 22:18:13 +0000293
sewardj3c944452011-09-05 20:39:57 +0000294#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000295 //STRNCAT(VG_Z_LIBC_SONAME, strncat)
296 //STRNCAT(VG_Z_DYLD, strncat)
sewardj4157d4f2011-09-05 22:18:13 +0000297
njnf76d27a2009-05-28 01:53:07 +0000298#endif
299
300
sewardj3c944452011-09-05 20:39:57 +0000301/*---------------------- strlcat ----------------------*/
302
njnf76d27a2009-05-28 01:53:07 +0000303/* Append src to dst. n is the size of dst's buffer. dst is guaranteed
304 to be nul-terminated after the copy, unless n <= strlen(dst_orig).
305 Returns min(n, strlen(dst_orig)) + strlen(src_orig).
306 Truncation occurred if retval >= n.
307*/
308#define STRLCAT(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000309 SizeT VG_REPLACE_FUNCTION_EZU(20050,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000310 ( char* dst, const char* src, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000311 SizeT VG_REPLACE_FUNCTION_EZU(20050,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000312 ( char* dst, const char* src, SizeT n ) \
313 { \
314 const Char* src_orig = src; \
315 Char* dst_orig = dst; \
316 SizeT m = 0; \
sewardjbd2cff22011-08-16 21:45:28 +0000317 \
njnf76d27a2009-05-28 01:53:07 +0000318 while (m < n && *dst) { m++; dst++; } \
319 if (m < n) { \
320 /* Fill as far as dst_orig[n-2], then nul-terminate. */ \
321 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
322 *dst = 0; \
323 } else { \
324 /* No space to copy anything to dst. m == n */ \
325 } \
326 /* Finish counting min(n, strlen(dst_orig)) + strlen(src_orig) */ \
327 while (*src) { m++; src++; } \
328 /* This checks for overlap after copying, unavoidable without */ \
329 /* pre-counting lengths... should be ok */ \
330 if (is_overlap(dst_orig, \
331 src_orig, \
332 (Addr)dst-(Addr)dst_orig+1, \
333 (Addr)src-(Addr)src_orig+1)) \
334 RECORD_OVERLAP_ERROR("strlcat", dst_orig, src_orig, n); \
sewardjbd2cff22011-08-16 21:45:28 +0000335 \
njnf76d27a2009-05-28 01:53:07 +0000336 return m; \
337 }
338
sewardj3c944452011-09-05 20:39:57 +0000339#if defined(VGO_linux)
sewardj4157d4f2011-09-05 22:18:13 +0000340
sewardj3c944452011-09-05 20:39:57 +0000341#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000342 //STRLCAT(VG_Z_LIBC_SONAME, strlcat)
343 //STRLCAT(VG_Z_DYLD, strlcat)
sewardj3c944452011-09-05 20:39:57 +0000344 STRLCAT(VG_Z_LIBC_SONAME, strlcat)
sewardj4157d4f2011-09-05 22:18:13 +0000345
njnf76d27a2009-05-28 01:53:07 +0000346#endif
sewardj31b9ce12006-10-17 01:27:13 +0000347
njn3e884182003-04-15 13:03:23 +0000348
sewardj3c944452011-09-05 20:39:57 +0000349/*---------------------- strnlen ----------------------*/
350
njn16eeb4e2005-06-16 03:56:58 +0000351#define STRNLEN(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000352 SizeT VG_REPLACE_FUNCTION_EZU(20060,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000353 ( const char* str, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000354 SizeT VG_REPLACE_FUNCTION_EZU(20060,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000355 ( const char* str, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000356 { \
357 SizeT i = 0; \
358 while (i < n && str[i] != 0) i++; \
359 return i; \
njn3e884182003-04-15 13:03:23 +0000360 }
njn3e884182003-04-15 13:03:23 +0000361
tomd2645142009-10-29 09:27:11 +0000362#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000363 STRNLEN(VG_Z_LIBC_SONAME, strnlen)
364 STRNLEN(VG_Z_LIBC_SONAME, __GI_strnlen)
sewardj4157d4f2011-09-05 22:18:13 +0000365
sewardj3c944452011-09-05 20:39:57 +0000366#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000367 //STRNLEN(VG_Z_LIBC_SONAME, strnlen)
sewardj4157d4f2011-09-05 22:18:13 +0000368
tomd2645142009-10-29 09:27:11 +0000369#endif
njn16eeb4e2005-06-16 03:56:58 +0000370
sewardj3ceec242003-07-30 21:24:25 +0000371
sewardj3c944452011-09-05 20:39:57 +0000372/*---------------------- strlen ----------------------*/
373
njn5ec15ed2005-08-24 19:55:51 +0000374// Note that this replacement often doesn't get used because gcc inlines
375// calls to strlen() with its own built-in version. This can be very
sewardj3c944452011-09-05 20:39:57 +0000376// confusing if you aren't expecting it. Other small functions in
377// this file may also be inline by gcc.
378
njn16eeb4e2005-06-16 03:56:58 +0000379#define STRLEN(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000380 SizeT VG_REPLACE_FUNCTION_EZU(20070,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000381 ( const char* str ); \
sewardj96044842011-08-18 13:09:55 +0000382 SizeT VG_REPLACE_FUNCTION_EZU(20070,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000383 ( const char* str ) \
njn16eeb4e2005-06-16 03:56:58 +0000384 { \
385 SizeT i = 0; \
386 while (str[i] != 0) i++; \
387 return i; \
sewardj3ceec242003-07-30 21:24:25 +0000388 }
njn16eeb4e2005-06-16 03:56:58 +0000389
njnb4cfbc42009-05-04 04:20:02 +0000390#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000391 STRLEN(VG_Z_LIBC_SONAME, strlen)
392 STRLEN(VG_Z_LIBC_SONAME, __GI_strlen)
sewardj70f291d2011-09-26 20:20:19 +0000393# if defined(VGPV_arm_linux_android)
394 STRLEN(NONE, __dl_strlen); /* in /system/bin/linker */
395# endif
sewardj4157d4f2011-09-05 22:18:13 +0000396
sewardj3c944452011-09-05 20:39:57 +0000397#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000398 //STRLEN(VG_Z_LIBC_SONAME, strlen)
399 STRLEN(VG_Z_LIBC_SONAME, strlen)
sewardj4157d4f2011-09-05 22:18:13 +0000400
njnb4cfbc42009-05-04 04:20:02 +0000401#endif
sewardj31b9ce12006-10-17 01:27:13 +0000402
njn16eeb4e2005-06-16 03:56:58 +0000403
sewardj3c944452011-09-05 20:39:57 +0000404/*---------------------- strcpy ----------------------*/
405
njn16eeb4e2005-06-16 03:56:58 +0000406#define STRCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000407 char* VG_REPLACE_FUNCTION_EZU(20080,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000408 ( char* dst, const char* src ); \
sewardj96044842011-08-18 13:09:55 +0000409 char* VG_REPLACE_FUNCTION_EZU(20080,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000410 ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000411 { \
412 const Char* src_orig = src; \
413 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000414 \
njn16eeb4e2005-06-16 03:56:58 +0000415 while (*src) *dst++ = *src++; \
416 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000417 \
njn16eeb4e2005-06-16 03:56:58 +0000418 /* This checks for overlap after copying, unavoidable without */ \
419 /* pre-counting length... should be ok */ \
420 if (is_overlap(dst_orig, \
421 src_orig, \
sewardjbd2cff22011-08-16 21:45:28 +0000422 (Addr)dst-(Addr)dst_orig+1, \
njn16eeb4e2005-06-16 03:56:58 +0000423 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000424 RECORD_OVERLAP_ERROR("strcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000425 \
njn16eeb4e2005-06-16 03:56:58 +0000426 return dst_orig; \
427 }
428
tomd2645142009-10-29 09:27:11 +0000429#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000430 STRCPY(VG_Z_LIBC_SONAME, strcpy)
431 STRCPY(VG_Z_LIBC_SONAME, __GI_strcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000432
tomd2645142009-10-29 09:27:11 +0000433#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000434 //STRCPY(VG_Z_LIBC_SONAME, strcpy)
435 //STRCPY(VG_Z_DYLD, strcpy)
sewardj3c944452011-09-05 20:39:57 +0000436 STRCPY(VG_Z_LIBC_SONAME, strcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000437
njnf76d27a2009-05-28 01:53:07 +0000438#endif
njn16eeb4e2005-06-16 03:56:58 +0000439
440
sewardj3c944452011-09-05 20:39:57 +0000441/*---------------------- strncpy ----------------------*/
442
njn16eeb4e2005-06-16 03:56:58 +0000443#define STRNCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000444 char* VG_REPLACE_FUNCTION_EZU(20090,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000445 ( char* dst, const char* src, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000446 char* VG_REPLACE_FUNCTION_EZU(20090,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000447 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000448 { \
449 const Char* src_orig = src; \
450 Char* dst_orig = dst; \
451 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000452 \
njn16eeb4e2005-06-16 03:56:58 +0000453 while (m < n && *src) { m++; *dst++ = *src++; } \
454 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
455 /* but only m+1 bytes of src if terminator was found */ \
456 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
njn718d3b12006-12-16 00:54:12 +0000457 RECORD_OVERLAP_ERROR("strncpy", dst, src, n); \
njn16eeb4e2005-06-16 03:56:58 +0000458 while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */ \
sewardj3c944452011-09-05 20:39:57 +0000459 \
njn16eeb4e2005-06-16 03:56:58 +0000460 return dst_orig; \
461 }
462
tomd2645142009-10-29 09:27:11 +0000463#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000464 STRNCPY(VG_Z_LIBC_SONAME, strncpy)
465 STRNCPY(VG_Z_LIBC_SONAME, __GI_strncpy)
sewardj4157d4f2011-09-05 22:18:13 +0000466
tomd2645142009-10-29 09:27:11 +0000467#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000468 //STRNCPY(VG_Z_LIBC_SONAME, strncpy)
469 //STRNCPY(VG_Z_DYLD, strncpy)
sewardj3c944452011-09-05 20:39:57 +0000470 STRNCPY(VG_Z_LIBC_SONAME, strncpy)
sewardj4157d4f2011-09-05 22:18:13 +0000471
njnf76d27a2009-05-28 01:53:07 +0000472#endif
473
474
sewardj3c944452011-09-05 20:39:57 +0000475/*---------------------- strlcpy ----------------------*/
476
njnf76d27a2009-05-28 01:53:07 +0000477/* Copy up to n-1 bytes from src to dst. Then nul-terminate dst if n > 0.
478 Returns strlen(src). Does not zero-fill the remainder of dst. */
479#define STRLCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000480 SizeT VG_REPLACE_FUNCTION_EZU(20100,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000481 ( char* dst, const char* src, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000482 SizeT VG_REPLACE_FUNCTION_EZU(20100,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000483 ( char* dst, const char* src, SizeT n ) \
484 { \
485 const char* src_orig = src; \
486 char* dst_orig = dst; \
487 SizeT m = 0; \
sewardjbd2cff22011-08-16 21:45:28 +0000488 \
njnf76d27a2009-05-28 01:53:07 +0000489 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
490 /* m non-nul bytes have now been copied, and m <= n-1. */ \
491 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
492 /* but only m+1 bytes of src if terminator was found */ \
493 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
494 RECORD_OVERLAP_ERROR("strlcpy", dst, src, n); \
495 /* Nul-terminate dst. */ \
496 if (n > 0) *dst = 0; \
497 /* Finish counting strlen(src). */ \
498 while (*src) src++; \
499 return src - src_orig; \
500 }
501
sewardj3c944452011-09-05 20:39:57 +0000502#if defined(VGO_linux)
sewardj4157d4f2011-09-05 22:18:13 +0000503
sewardj3c944452011-09-05 20:39:57 +0000504#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000505 //STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
506 //STRLCPY(VG_Z_DYLD, strlcpy)
sewardj3c944452011-09-05 20:39:57 +0000507 STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000508
njnf76d27a2009-05-28 01:53:07 +0000509#endif
njn16eeb4e2005-06-16 03:56:58 +0000510
511
sewardj3c944452011-09-05 20:39:57 +0000512/*---------------------- strncmp ----------------------*/
513
njn16eeb4e2005-06-16 03:56:58 +0000514#define STRNCMP(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000515 int VG_REPLACE_FUNCTION_EZU(20110,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000516 ( const char* s1, const char* s2, SizeT nmax ); \
sewardj96044842011-08-18 13:09:55 +0000517 int VG_REPLACE_FUNCTION_EZU(20110,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000518 ( const char* s1, const char* s2, SizeT nmax ) \
njn16eeb4e2005-06-16 03:56:58 +0000519 { \
520 SizeT n = 0; \
521 while (True) { \
522 if (n >= nmax) return 0; \
523 if (*s1 == 0 && *s2 == 0) return 0; \
524 if (*s1 == 0) return -1; \
525 if (*s2 == 0) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000526 \
njn16eeb4e2005-06-16 03:56:58 +0000527 if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1; \
528 if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000529 \
njn16eeb4e2005-06-16 03:56:58 +0000530 s1++; s2++; n++; \
531 } \
532 }
533
tomd2645142009-10-29 09:27:11 +0000534#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000535 STRNCMP(VG_Z_LIBC_SONAME, strncmp)
536 STRNCMP(VG_Z_LIBC_SONAME, __GI_strncmp)
sewardj4157d4f2011-09-05 22:18:13 +0000537
tomd2645142009-10-29 09:27:11 +0000538#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000539 //STRNCMP(VG_Z_LIBC_SONAME, strncmp)
540 //STRNCMP(VG_Z_DYLD, strncmp)
541 STRNCMP(VG_Z_LIBC_SONAME, strncmp)
sewardj4157d4f2011-09-05 22:18:13 +0000542
njnf76d27a2009-05-28 01:53:07 +0000543#endif
njn16eeb4e2005-06-16 03:56:58 +0000544
545
sewardj3c944452011-09-05 20:39:57 +0000546/*---------------------- strcasecmp ----------------------*/
547
tomce6d0ac2010-11-12 10:03:13 +0000548#define STRCASECMP(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000549 int VG_REPLACE_FUNCTION_EZU(20120,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000550 ( const char* s1, const char* s2 ); \
sewardj96044842011-08-18 13:09:55 +0000551 int VG_REPLACE_FUNCTION_EZU(20120,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000552 ( const char* s1, const char* s2 ) \
553 { \
tome03c8c42010-11-12 10:40:20 +0000554 extern int tolower(int); \
tomce6d0ac2010-11-12 10:03:13 +0000555 register unsigned char c1; \
556 register unsigned char c2; \
557 while (True) { \
558 c1 = tolower(*(unsigned char *)s1); \
559 c2 = tolower(*(unsigned char *)s2); \
560 if (c1 != c2) break; \
561 if (c1 == 0) break; \
562 s1++; s2++; \
563 } \
564 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
565 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
566 return 0; \
567 }
568
sewardj3c944452011-09-05 20:39:57 +0000569#if defined(VGO_linux)
570# if !defined(VGPV_arm_linux_android)
571 STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp)
572 STRCASECMP(VG_Z_LIBC_SONAME, __GI_strcasecmp)
573# endif
sewardj4157d4f2011-09-05 22:18:13 +0000574
sewardj3c944452011-09-05 20:39:57 +0000575#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000576 //STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp)
sewardj4157d4f2011-09-05 22:18:13 +0000577
tomce6d0ac2010-11-12 10:03:13 +0000578#endif
579
580
sewardj3c944452011-09-05 20:39:57 +0000581/*---------------------- strncasecmp ----------------------*/
582
tomce6d0ac2010-11-12 10:03:13 +0000583#define STRNCASECMP(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000584 int VG_REPLACE_FUNCTION_EZU(20130,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000585 ( const char* s1, const char* s2, SizeT nmax ); \
sewardj96044842011-08-18 13:09:55 +0000586 int VG_REPLACE_FUNCTION_EZU(20130,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000587 ( const char* s1, const char* s2, SizeT nmax ) \
588 { \
tome03c8c42010-11-12 10:40:20 +0000589 extern int tolower(int); \
tomce6d0ac2010-11-12 10:03:13 +0000590 SizeT n = 0; \
591 while (True) { \
592 if (n >= nmax) return 0; \
593 if (*s1 == 0 && *s2 == 0) return 0; \
594 if (*s1 == 0) return -1; \
595 if (*s2 == 0) return 1; \
596 \
sewardjbd2cff22011-08-16 21:45:28 +0000597 if (tolower(*(unsigned char*)s1) \
598 < tolower(*(unsigned char*)s2)) return -1; \
599 if (tolower(*(unsigned char*)s1) \
600 > tolower(*(unsigned char*)s2)) return 1; \
tomce6d0ac2010-11-12 10:03:13 +0000601 \
602 s1++; s2++; n++; \
603 } \
604 }
605
sewardj3c944452011-09-05 20:39:57 +0000606#if defined(VGO_linux)
607# if !defined(VGPV_arm_linux_android)
608 STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp)
609 STRNCASECMP(VG_Z_LIBC_SONAME, __GI_strncasecmp)
610# endif
sewardj4157d4f2011-09-05 22:18:13 +0000611
tomce6d0ac2010-11-12 10:03:13 +0000612#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000613 //STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp)
614 //STRNCASECMP(VG_Z_DYLD, strncasecmp)
sewardj4157d4f2011-09-05 22:18:13 +0000615
tomce6d0ac2010-11-12 10:03:13 +0000616#endif
617
618
sewardj3c944452011-09-05 20:39:57 +0000619/*---------------------- strcasecmp_l ----------------------*/
620
tomce6d0ac2010-11-12 10:03:13 +0000621#define STRCASECMP_L(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000622 int VG_REPLACE_FUNCTION_EZU(20140,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000623 ( const char* s1, const char* s2, void* locale ); \
sewardj96044842011-08-18 13:09:55 +0000624 int VG_REPLACE_FUNCTION_EZU(20140,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000625 ( const char* s1, const char* s2, void* locale ) \
tomce6d0ac2010-11-12 10:03:13 +0000626 { \
sewardj3c944452011-09-05 20:39:57 +0000627 extern int tolower_l(int, void*) __attribute__((weak)); \
tomce6d0ac2010-11-12 10:03:13 +0000628 register unsigned char c1; \
629 register unsigned char c2; \
630 while (True) { \
631 c1 = tolower_l(*(unsigned char *)s1, locale); \
632 c2 = tolower_l(*(unsigned char *)s2, locale); \
633 if (c1 != c2) break; \
634 if (c1 == 0) break; \
635 s1++; s2++; \
636 } \
637 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
638 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
639 return 0; \
640 }
641
tomce6d0ac2010-11-12 10:03:13 +0000642#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000643 STRCASECMP_L(VG_Z_LIBC_SONAME, strcasecmp_l)
644 STRCASECMP_L(VG_Z_LIBC_SONAME, __GI_strcasecmp_l)
645 STRCASECMP_L(VG_Z_LIBC_SONAME, __GI___strcasecmp_l)
sewardj4157d4f2011-09-05 22:18:13 +0000646
sewardj3c944452011-09-05 20:39:57 +0000647#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000648 //STRCASECMP_L(VG_Z_LIBC_SONAME, strcasecmp_l)
sewardj4157d4f2011-09-05 22:18:13 +0000649
tomce6d0ac2010-11-12 10:03:13 +0000650#endif
651
652
sewardj3c944452011-09-05 20:39:57 +0000653/*---------------------- strncasecmp_l ----------------------*/
654
tomce6d0ac2010-11-12 10:03:13 +0000655#define STRNCASECMP_L(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000656 int VG_REPLACE_FUNCTION_EZU(20150,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000657 ( const char* s1, const char* s2, SizeT nmax, void* locale ); \
sewardj96044842011-08-18 13:09:55 +0000658 int VG_REPLACE_FUNCTION_EZU(20150,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000659 ( const char* s1, const char* s2, SizeT nmax, void* locale ) \
tomce6d0ac2010-11-12 10:03:13 +0000660 { \
tome03c8c42010-11-12 10:40:20 +0000661 extern int tolower_l(int, void*) __attribute__((weak)); \
tomce6d0ac2010-11-12 10:03:13 +0000662 SizeT n = 0; \
663 while (True) { \
664 if (n >= nmax) return 0; \
665 if (*s1 == 0 && *s2 == 0) return 0; \
666 if (*s1 == 0) return -1; \
667 if (*s2 == 0) return 1; \
668 \
sewardjbd2cff22011-08-16 21:45:28 +0000669 if (tolower_l(*(unsigned char*)s1, locale) \
670 < tolower_l(*(unsigned char*)s2, locale)) return -1; \
671 if (tolower_l(*(unsigned char*)s1, locale) \
672 > tolower_l(*(unsigned char*)s2, locale)) return 1; \
tomce6d0ac2010-11-12 10:03:13 +0000673 \
674 s1++; s2++; n++; \
675 } \
676 }
677
tomce6d0ac2010-11-12 10:03:13 +0000678#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000679 STRNCASECMP_L(VG_Z_LIBC_SONAME, strncasecmp_l)
680 STRNCASECMP_L(VG_Z_LIBC_SONAME, __GI_strncasecmp_l)
sewardj4157d4f2011-09-05 22:18:13 +0000681
tomce6d0ac2010-11-12 10:03:13 +0000682#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000683 //STRNCASECMP_L(VG_Z_LIBC_SONAME, strncasecmp_l)
684 //STRNCASECMP_L(VG_Z_DYLD, strncasecmp_l)
sewardj4157d4f2011-09-05 22:18:13 +0000685
tomce6d0ac2010-11-12 10:03:13 +0000686#endif
687
688
sewardj3c944452011-09-05 20:39:57 +0000689/*---------------------- strcmp ----------------------*/
690
njn16eeb4e2005-06-16 03:56:58 +0000691#define STRCMP(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000692 int VG_REPLACE_FUNCTION_EZU(20160,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000693 ( const char* s1, const char* s2 ); \
sewardj96044842011-08-18 13:09:55 +0000694 int VG_REPLACE_FUNCTION_EZU(20160,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000695 ( const char* s1, const char* s2 ) \
njn16eeb4e2005-06-16 03:56:58 +0000696 { \
697 register unsigned char c1; \
698 register unsigned char c2; \
699 while (True) { \
700 c1 = *(unsigned char *)s1; \
701 c2 = *(unsigned char *)s2; \
702 if (c1 != c2) break; \
703 if (c1 == 0) break; \
704 s1++; s2++; \
705 } \
706 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
707 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
708 return 0; \
709 }
710
njnb4cfbc42009-05-04 04:20:02 +0000711#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000712 STRCMP(VG_Z_LIBC_SONAME, strcmp)
713 STRCMP(VG_Z_LIBC_SONAME, __GI_strcmp)
714 STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp)
715 STRCMP(VG_Z_LD64_SO_1, strcmp)
sewardj70f291d2011-09-26 20:20:19 +0000716# if defined(VGPV_arm_linux_android)
717 STRCMP(NONE, __dl_strcmp); /* in /system/bin/linker */
718# endif
sewardj4157d4f2011-09-05 22:18:13 +0000719
sewardj3c944452011-09-05 20:39:57 +0000720#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000721 //STRCMP(VG_Z_LIBC_SONAME, strcmp)
722 STRCMP(VG_Z_LIBC_SONAME, strcmp)
sewardj4157d4f2011-09-05 22:18:13 +0000723
njnb4cfbc42009-05-04 04:20:02 +0000724#endif
njn16eeb4e2005-06-16 03:56:58 +0000725
726
sewardj3c944452011-09-05 20:39:57 +0000727/*---------------------- memchr ----------------------*/
728
njn16eeb4e2005-06-16 03:56:58 +0000729#define MEMCHR(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000730 void* VG_REPLACE_FUNCTION_EZU(20170,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000731 (const void *s, int c, SizeT n); \
sewardj96044842011-08-18 13:09:55 +0000732 void* VG_REPLACE_FUNCTION_EZU(20170,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000733 (const void *s, int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000734 { \
735 SizeT i; \
736 UChar c0 = (UChar)c; \
737 UChar* p = (UChar*)s; \
738 for (i = 0; i < n; i++) \
739 if (p[i] == c0) return (void*)(&p[i]); \
740 return NULL; \
741 }
742
sewardj3c944452011-09-05 20:39:57 +0000743#if defined(VGO_linux)
744 MEMCHR(VG_Z_LIBC_SONAME, memchr)
sewardj4157d4f2011-09-05 22:18:13 +0000745
sewardj3c944452011-09-05 20:39:57 +0000746#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000747 //MEMCHR(VG_Z_LIBC_SONAME, memchr)
748 //MEMCHR(VG_Z_DYLD, memchr)
sewardj4157d4f2011-09-05 22:18:13 +0000749
njnf76d27a2009-05-28 01:53:07 +0000750#endif
njn16eeb4e2005-06-16 03:56:58 +0000751
752
sewardj3c944452011-09-05 20:39:57 +0000753/*---------------------- memcpy ----------------------*/
754
sewardjbd2cff22011-08-16 21:45:28 +0000755#define MEMMOVE_OR_MEMCPY(becTag, soname, fnname, do_ol_check) \
sewardjd88797f2011-08-17 21:25:50 +0000756 void* VG_REPLACE_FUNCTION_EZZ(becTag,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000757 ( void *dst, const void *src, SizeT len ); \
sewardjd88797f2011-08-17 21:25:50 +0000758 void* VG_REPLACE_FUNCTION_EZZ(becTag,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000759 ( void *dst, const void *src, SizeT len ) \
njn16eeb4e2005-06-16 03:56:58 +0000760 { \
sewardjbd2cff22011-08-16 21:45:28 +0000761 if (do_ol_check && is_overlap(dst, src, len, len)) \
njn718d3b12006-12-16 00:54:12 +0000762 RECORD_OVERLAP_ERROR("memcpy", dst, src, len); \
sewardjb6c04032007-11-13 20:52:29 +0000763 \
sewardj7b4e00b2010-08-24 09:05:52 +0000764 const Addr WS = sizeof(UWord); /* 8 or 4 */ \
765 const Addr WM = WS - 1; /* 7 or 3 */ \
766 \
tom863ab7c2011-08-18 08:10:20 +0000767 if (len > 0) { \
768 if (dst < src) { \
sewardj7b4e00b2010-08-24 09:05:52 +0000769 \
tom863ab7c2011-08-18 08:10:20 +0000770 /* Copying backwards. */ \
771 SizeT n = len; \
772 Addr d = (Addr)dst; \
773 Addr s = (Addr)src; \
774 \
775 if (((s^d) & WM) == 0) { \
776 /* s and d have same UWord alignment. */ \
777 /* Pull up to a UWord boundary. */ \
778 while ((s & WM) != 0 && n >= 1) \
779 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
780 /* Copy UWords. */ \
781 while (n >= WS) \
782 { *(UWord*)d = *(UWord*)s; s += WS; d += WS; n -= WS; } \
783 if (n == 0) \
784 return dst; \
785 } \
786 if (((s|d) & 1) == 0) { \
787 /* Both are 16-aligned; copy what we can thusly. */ \
788 while (n >= 2) \
789 { *(UShort*)d = *(UShort*)s; s += 2; d += 2; n -= 2; } \
790 } \
791 /* Copy leftovers, or everything if misaligned. */ \
792 while (n >= 1) \
sewardj7b4e00b2010-08-24 09:05:52 +0000793 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
sewardj7b4e00b2010-08-24 09:05:52 +0000794 \
tom863ab7c2011-08-18 08:10:20 +0000795 } else if (dst > src) { \
796 \
797 SizeT n = len; \
798 Addr d = ((Addr)dst) + n; \
799 Addr s = ((Addr)src) + n; \
800 \
801 /* Copying forwards. */ \
802 if (((s^d) & WM) == 0) { \
803 /* s and d have same UWord alignment. */ \
804 /* Back down to a UWord boundary. */ \
805 while ((s & WM) != 0 && n >= 1) \
806 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
807 /* Copy UWords. */ \
808 while (n >= WS) \
809 { s -= WS; d -= WS; *(UWord*)d = *(UWord*)s; n -= WS; } \
810 if (n == 0) \
811 return dst; \
812 } \
813 if (((s|d) & 1) == 0) { \
814 /* Both are 16-aligned; copy what we can thusly. */ \
815 while (n >= 2) \
816 { s -= 2; d -= 2; *(UShort*)d = *(UShort*)s; n -= 2; } \
817 } \
818 /* Copy leftovers, or everything if misaligned. */ \
819 while (n >= 1) \
sewardj7b4e00b2010-08-24 09:05:52 +0000820 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
tom863ab7c2011-08-18 08:10:20 +0000821 \
njn16eeb4e2005-06-16 03:56:58 +0000822 } \
njn16eeb4e2005-06-16 03:56:58 +0000823 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000824 \
njn16eeb4e2005-06-16 03:56:58 +0000825 return dst; \
826 }
827
sewardjbd2cff22011-08-16 21:45:28 +0000828#define MEMMOVE(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000829 MEMMOVE_OR_MEMCPY(20181, soname, fnname, 0)
sewardjbd2cff22011-08-16 21:45:28 +0000830
831#define MEMCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000832 MEMMOVE_OR_MEMCPY(20180, soname, fnname, 1)
sewardjbd2cff22011-08-16 21:45:28 +0000833
njnb4cfbc42009-05-04 04:20:02 +0000834#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000835 /* For older memcpy we have to use memmove-like semantics and skip
836 the overlap check; sigh; see #275284. */
837 MEMMOVE(VG_Z_LIBC_SONAME, memcpyZAGLIBCZu2Zd2Zd5) /* memcpy@GLIBC_2.2.5 */
838 MEMCPY(VG_Z_LIBC_SONAME, memcpyZAZAGLIBCZu2Zd14) /* memcpy@@GLIBC_2.14 */
839 MEMCPY(VG_Z_LIBC_SONAME, memcpy) /* fallback case */
840 MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */
841 MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */
sewardj3c944452011-09-05 20:39:57 +0000842 /* icc9 blats these around all over the place. Not only in the main
843 executable but various .so's. They are highly tuned and read
844 memory beyond the source boundary (although work correctly and
845 never go across page boundaries), so give errors when run
846 natively, at least for misaligned source arg. Just intercepting
847 in the exe only until we understand more about the problem. See
848 http://bugs.kde.org/show_bug.cgi?id=139776
sewardjf0b34322007-01-16 21:42:28 +0000849 */
sewardj3c944452011-09-05 20:39:57 +0000850 MEMCPY(NONE, ZuintelZufastZumemcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000851
852#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000853 //MEMCPY(VG_Z_LIBC_SONAME, memcpy)
854 //MEMCPY(VG_Z_DYLD, memcpy)
855 MEMCPY(VG_Z_LIBC_SONAME, memcpyZDVARIANTZDsse3x) /* memcpy$VARIANT$sse3x */
856 MEMCPY(VG_Z_LIBC_SONAME, memcpyZDVARIANTZDsse42) /* memcpy$VARIANT$sse42 */
sewardj4157d4f2011-09-05 22:18:13 +0000857
sewardj3c944452011-09-05 20:39:57 +0000858#endif
sewardj31b9ce12006-10-17 01:27:13 +0000859
njn16eeb4e2005-06-16 03:56:58 +0000860
sewardj3c944452011-09-05 20:39:57 +0000861/*---------------------- memcmp ----------------------*/
862
njn16eeb4e2005-06-16 03:56:58 +0000863#define MEMCMP(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000864 int VG_REPLACE_FUNCTION_EZU(20190,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000865 ( const void *s1V, const void *s2V, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000866 int VG_REPLACE_FUNCTION_EZU(20190,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000867 ( const void *s1V, const void *s2V, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000868 { \
869 int res; \
870 unsigned char a0; \
871 unsigned char b0; \
872 unsigned char* s1 = (unsigned char*)s1V; \
873 unsigned char* s2 = (unsigned char*)s2V; \
sewardjb6c04032007-11-13 20:52:29 +0000874 \
njn16eeb4e2005-06-16 03:56:58 +0000875 while (n != 0) { \
876 a0 = s1[0]; \
877 b0 = s2[0]; \
878 s1 += 1; \
879 s2 += 1; \
880 res = ((int)a0) - ((int)b0); \
881 if (res != 0) \
882 return res; \
883 n -= 1; \
884 } \
885 return 0; \
886 }
887
njnb4cfbc42009-05-04 04:20:02 +0000888#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000889 MEMCMP(VG_Z_LIBC_SONAME, memcmp)
890 MEMCMP(VG_Z_LIBC_SONAME, bcmp)
891 MEMCMP(VG_Z_LD_SO_1, bcmp)
sewardj4157d4f2011-09-05 22:18:13 +0000892
njnf76d27a2009-05-28 01:53:07 +0000893#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000894 //MEMCMP(VG_Z_LIBC_SONAME, memcmp)
895 //MEMCMP(VG_Z_LIBC_SONAME, bcmp)
896 //MEMCMP(VG_Z_DYLD, memcmp)
897 //MEMCMP(VG_Z_DYLD, bcmp)
sewardj4157d4f2011-09-05 22:18:13 +0000898
njnb4cfbc42009-05-04 04:20:02 +0000899#endif
njn3e884182003-04-15 13:03:23 +0000900
jseward0845ef82003-12-22 22:31:27 +0000901
sewardj3c944452011-09-05 20:39:57 +0000902/*---------------------- stpcpy ----------------------*/
903
jseward0845ef82003-12-22 22:31:27 +0000904/* Copy SRC to DEST, returning the address of the terminating '\0' in
905 DEST. (minor variant of strcpy) */
njn16eeb4e2005-06-16 03:56:58 +0000906#define STPCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000907 char* VG_REPLACE_FUNCTION_EZU(20200,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000908 ( char* dst, const char* src ); \
sewardj96044842011-08-18 13:09:55 +0000909 char* VG_REPLACE_FUNCTION_EZU(20200,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000910 ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000911 { \
912 const Char* src_orig = src; \
913 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000914 \
njn16eeb4e2005-06-16 03:56:58 +0000915 while (*src) *dst++ = *src++; \
916 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000917 \
njn16eeb4e2005-06-16 03:56:58 +0000918 /* This checks for overlap after copying, unavoidable without */ \
919 /* pre-counting length... should be ok */ \
920 if (is_overlap(dst_orig, \
921 src_orig, \
922 (Addr)dst-(Addr)dst_orig+1, \
923 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000924 RECORD_OVERLAP_ERROR("stpcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000925 \
njn16eeb4e2005-06-16 03:56:58 +0000926 return dst; \
sewardj44e495f2005-05-12 17:58:28 +0000927 }
njn16eeb4e2005-06-16 03:56:58 +0000928
njnb4cfbc42009-05-04 04:20:02 +0000929#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000930 STPCPY(VG_Z_LIBC_SONAME, stpcpy)
931 STPCPY(VG_Z_LIBC_SONAME, __GI_stpcpy)
932 STPCPY(VG_Z_LD_LINUX_SO_2, stpcpy)
933 STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000934
njnf76d27a2009-05-28 01:53:07 +0000935#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000936 //STPCPY(VG_Z_LIBC_SONAME, stpcpy)
937 //STPCPY(VG_Z_DYLD, stpcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000938
njnb4cfbc42009-05-04 04:20:02 +0000939#endif
940
njn16eeb4e2005-06-16 03:56:58 +0000941
sewardj3c944452011-09-05 20:39:57 +0000942/*---------------------- memset ----------------------*/
943
944/* Why are we bothering to intercept this? It seems entirely
945 pointless. */
sewardj731f9cf2011-09-21 08:43:08 +0000946
njn16eeb4e2005-06-16 03:56:58 +0000947#define MEMSET(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000948 void* VG_REPLACE_FUNCTION_EZU(20210,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000949 (void *s, Int c, SizeT n); \
sewardj96044842011-08-18 13:09:55 +0000950 void* VG_REPLACE_FUNCTION_EZU(20210,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000951 (void *s, Int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000952 { \
sewardj7b4e00b2010-08-24 09:05:52 +0000953 Addr a = (Addr)s; \
954 UInt c4 = (c & 0xFF); \
955 c4 = (c4 << 8) | c4; \
956 c4 = (c4 << 16) | c4; \
957 while ((a & 3) != 0 && n >= 1) \
958 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
959 while (n >= 4) \
960 { *(UInt*)a = c4; a += 4; n -= 4; } \
961 while (n >= 1) \
962 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
njn16eeb4e2005-06-16 03:56:58 +0000963 return s; \
sewardj44e495f2005-05-12 17:58:28 +0000964 }
njn16eeb4e2005-06-16 03:56:58 +0000965
sewardj3c944452011-09-05 20:39:57 +0000966#if defined(VGO_linux)
967 MEMSET(VG_Z_LIBC_SONAME, memset)
sewardj4157d4f2011-09-05 22:18:13 +0000968
sewardj3c944452011-09-05 20:39:57 +0000969#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000970 //MEMSET(VG_Z_LIBC_SONAME, memset)
971 //MEMSET(VG_Z_DYLD, memset)
sewardj3c944452011-09-05 20:39:57 +0000972 MEMSET(VG_Z_LIBC_SONAME, memset)
sewardj4157d4f2011-09-05 22:18:13 +0000973
njnf76d27a2009-05-28 01:53:07 +0000974#endif
njn16eeb4e2005-06-16 03:56:58 +0000975
976
sewardj3c944452011-09-05 20:39:57 +0000977/*---------------------- memmove ----------------------*/
978
sewardj96044842011-08-18 13:09:55 +0000979/* memmove -- use the MEMMOVE defn above. */
sewardj731f9cf2011-09-21 08:43:08 +0000980
sewardj3c944452011-09-05 20:39:57 +0000981#if defined(VGO_linux)
982 MEMMOVE(VG_Z_LIBC_SONAME, memmove)
sewardj4157d4f2011-09-05 22:18:13 +0000983
sewardj3c944452011-09-05 20:39:57 +0000984#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000985 //MEMMOVE(VG_Z_LIBC_SONAME, memmove)
986 //MEMMOVE(VG_Z_DYLD, memmove)#
987 MEMMOVE(VG_Z_LIBC_SONAME, memmoveZDVARIANTZDsse3x) /* memmove$VARIANT$sse3x */
988 MEMMOVE(VG_Z_LIBC_SONAME, memmoveZDVARIANTZDsse42) /* memmove$VARIANT$sse42 */
sewardj4157d4f2011-09-05 22:18:13 +0000989
njnf76d27a2009-05-28 01:53:07 +0000990#endif
991
992
sewardj3c944452011-09-05 20:39:57 +0000993/*---------------------- bcopy ----------------------*/
994
njnf76d27a2009-05-28 01:53:07 +0000995#define BCOPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000996 void VG_REPLACE_FUNCTION_EZU(20230,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000997 (const void *srcV, void *dstV, SizeT n); \
sewardj96044842011-08-18 13:09:55 +0000998 void VG_REPLACE_FUNCTION_EZU(20230,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000999 (const void *srcV, void *dstV, SizeT n) \
1000 { \
1001 SizeT i; \
1002 Char* dst = (Char*)dstV; \
1003 Char* src = (Char*)srcV; \
1004 if (dst < src) { \
1005 for (i = 0; i < n; i++) \
1006 dst[i] = src[i]; \
1007 } \
1008 else \
1009 if (dst > src) { \
1010 for (i = 0; i < n; i++) \
1011 dst[n-i-1] = src[n-i-1]; \
1012 } \
1013 }
1014
sewardj3c944452011-09-05 20:39:57 +00001015#if defined(VGO_linux)
sewardj4157d4f2011-09-05 22:18:13 +00001016
sewardj3c944452011-09-05 20:39:57 +00001017#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +00001018 //BCOPY(VG_Z_LIBC_SONAME, bcopy)
1019 //BCOPY(VG_Z_DYLD, bcopy)
sewardj4157d4f2011-09-05 22:18:13 +00001020
njnf76d27a2009-05-28 01:53:07 +00001021#endif
sewardj44e495f2005-05-12 17:58:28 +00001022
jseward0845ef82003-12-22 22:31:27 +00001023
sewardj3c944452011-09-05 20:39:57 +00001024/*-------------------- memmove_chk --------------------*/
1025
sewardj24cb2172007-02-23 09:03:26 +00001026/* glibc 2.5 variant of memmove which checks the dest is big enough.
1027 There is no specific part of glibc that this is copied from. */
1028#define GLIBC25___MEMMOVE_CHK(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001029 void* VG_REPLACE_FUNCTION_EZU(20240,soname,fnname) \
sewardj24cb2172007-02-23 09:03:26 +00001030 (void *dstV, const void *srcV, SizeT n, SizeT destlen); \
sewardj96044842011-08-18 13:09:55 +00001031 void* VG_REPLACE_FUNCTION_EZU(20240,soname,fnname) \
sewardj24cb2172007-02-23 09:03:26 +00001032 (void *dstV, const void *srcV, SizeT n, SizeT destlen) \
1033 { \
sewardj24cb2172007-02-23 09:03:26 +00001034 SizeT i; \
1035 Char* dst = (Char*)dstV; \
1036 Char* src = (Char*)srcV; \
1037 if (destlen < n) \
1038 goto badness; \
1039 if (dst < src) { \
1040 for (i = 0; i < n; i++) \
1041 dst[i] = src[i]; \
1042 } \
1043 else \
1044 if (dst > src) { \
1045 for (i = 0; i < n; i++) \
1046 dst[n-i-1] = src[n-i-1]; \
1047 } \
1048 return dst; \
1049 badness: \
1050 VALGRIND_PRINTF_BACKTRACE( \
1051 "*** memmove_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +00001052 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +00001053 my_exit(127); \
sewardjc271ec82007-02-27 22:36:14 +00001054 /*NOTREACHED*/ \
1055 return NULL; \
sewardj24cb2172007-02-23 09:03:26 +00001056 }
1057
sewardj3c944452011-09-05 20:39:57 +00001058#if defined(VGO_linux)
1059 GLIBC25___MEMMOVE_CHK(VG_Z_LIBC_SONAME, __memmove_chk)
sewardj4157d4f2011-09-05 22:18:13 +00001060
sewardj3c944452011-09-05 20:39:57 +00001061#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001062
sewardj3c944452011-09-05 20:39:57 +00001063#endif
sewardj24cb2172007-02-23 09:03:26 +00001064
1065
sewardj3c944452011-09-05 20:39:57 +00001066/*-------------------- strchrnul --------------------*/
1067
sewardj4e9a4b62004-11-23 00:20:17 +00001068/* Find the first occurrence of C in S or the final NUL byte. */
njn16eeb4e2005-06-16 03:56:58 +00001069#define GLIBC232_STRCHRNUL(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001070 char* VG_REPLACE_FUNCTION_EZU(20250,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001071 (const char* s, int c_in); \
sewardj96044842011-08-18 13:09:55 +00001072 char* VG_REPLACE_FUNCTION_EZU(20250,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001073 (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +00001074 { \
1075 unsigned char c = (unsigned char) c_in; \
1076 unsigned char* char_ptr = (unsigned char *)s; \
1077 while (1) { \
1078 if (*char_ptr == 0) return char_ptr; \
1079 if (*char_ptr == c) return char_ptr; \
1080 char_ptr++; \
1081 } \
sewardj4e9a4b62004-11-23 00:20:17 +00001082 }
njn16eeb4e2005-06-16 03:56:58 +00001083
sewardj3c944452011-09-05 20:39:57 +00001084#if defined(VGO_linux)
1085 GLIBC232_STRCHRNUL(VG_Z_LIBC_SONAME, strchrnul)
sewardj4157d4f2011-09-05 22:18:13 +00001086
sewardj3c944452011-09-05 20:39:57 +00001087#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001088
sewardj3c944452011-09-05 20:39:57 +00001089#endif
sewardj4e9a4b62004-11-23 00:20:17 +00001090
1091
sewardj3c944452011-09-05 20:39:57 +00001092/*---------------------- rawmemchr ----------------------*/
1093
sewardj4e9a4b62004-11-23 00:20:17 +00001094/* Find the first occurrence of C in S. */
njn16eeb4e2005-06-16 03:56:58 +00001095#define GLIBC232_RAWMEMCHR(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001096 char* VG_REPLACE_FUNCTION_EZU(20260,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001097 (const char* s, int c_in); \
sewardj96044842011-08-18 13:09:55 +00001098 char* VG_REPLACE_FUNCTION_EZU(20260,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001099 (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +00001100 { \
1101 unsigned char c = (unsigned char) c_in; \
1102 unsigned char* char_ptr = (unsigned char *)s; \
1103 while (1) { \
1104 if (*char_ptr == c) return char_ptr; \
1105 char_ptr++; \
1106 } \
sewardj4e9a4b62004-11-23 00:20:17 +00001107 }
njn16eeb4e2005-06-16 03:56:58 +00001108
tomd2645142009-10-29 09:27:11 +00001109#if defined (VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001110 GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, rawmemchr)
1111 GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, __GI___rawmemchr)
sewardj4157d4f2011-09-05 22:18:13 +00001112
sewardj3c944452011-09-05 20:39:57 +00001113#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001114
tomd2645142009-10-29 09:27:11 +00001115#endif
sewardj4e9a4b62004-11-23 00:20:17 +00001116
sewardj3c944452011-09-05 20:39:57 +00001117
1118/*---------------------- strcpy_chk ----------------------*/
1119
sewardjdc5d8322007-01-28 06:32:01 +00001120/* glibc variant of strcpy that checks the dest is big enough.
1121 Copied from glibc-2.5/debug/test-strcpy_chk.c. */
sewardj620e5262006-12-31 00:22:30 +00001122#define GLIBC25___STRCPY_CHK(soname,fnname) \
sewardj96044842011-08-18 13:09:55 +00001123 char* VG_REPLACE_FUNCTION_EZU(20270,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001124 (char* dst, const char* src, SizeT len); \
sewardj96044842011-08-18 13:09:55 +00001125 char* VG_REPLACE_FUNCTION_EZU(20270,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001126 (char* dst, const char* src, SizeT len) \
sewardj620e5262006-12-31 00:22:30 +00001127 { \
sewardj620e5262006-12-31 00:22:30 +00001128 char* ret = dst; \
1129 if (! len) \
1130 goto badness; \
1131 while ((*dst++ = *src++) != '\0') \
1132 if (--len == 0) \
1133 goto badness; \
1134 return ret; \
1135 badness: \
1136 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +00001137 "*** strcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +00001138 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +00001139 my_exit(127); \
sewardj620e5262006-12-31 00:22:30 +00001140 /*NOTREACHED*/ \
1141 return NULL; \
1142 }
1143
sewardj3c944452011-09-05 20:39:57 +00001144#if defined(VGO_linux)
1145 GLIBC25___STRCPY_CHK(VG_Z_LIBC_SONAME, __strcpy_chk)
sewardj4157d4f2011-09-05 22:18:13 +00001146
sewardj3c944452011-09-05 20:39:57 +00001147#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001148
sewardj3c944452011-09-05 20:39:57 +00001149#endif
sewardj620e5262006-12-31 00:22:30 +00001150
1151
sewardj3c944452011-09-05 20:39:57 +00001152/*---------------------- stpcpy_chk ----------------------*/
1153
sewardjdc5d8322007-01-28 06:32:01 +00001154/* glibc variant of stpcpy that checks the dest is big enough.
1155 Copied from glibc-2.5/debug/test-stpcpy_chk.c. */
sewardjb8d03852007-01-27 00:49:44 +00001156#define GLIBC25___STPCPY_CHK(soname,fnname) \
sewardj96044842011-08-18 13:09:55 +00001157 char* VG_REPLACE_FUNCTION_EZU(20280,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001158 (char* dst, const char* src, SizeT len); \
sewardj96044842011-08-18 13:09:55 +00001159 char* VG_REPLACE_FUNCTION_EZU(20280,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001160 (char* dst, const char* src, SizeT len) \
sewardjb8d03852007-01-27 00:49:44 +00001161 { \
sewardjdc5d8322007-01-28 06:32:01 +00001162 if (! len) \
1163 goto badness; \
1164 while ((*dst++ = *src++) != '\0') \
1165 if (--len == 0) \
sewardjb8d03852007-01-27 00:49:44 +00001166 goto badness; \
sewardjb8d03852007-01-27 00:49:44 +00001167 return dst - 1; \
1168 badness: \
1169 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +00001170 "*** stpcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +00001171 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +00001172 my_exit(127); \
sewardjb8d03852007-01-27 00:49:44 +00001173 /*NOTREACHED*/ \
1174 return NULL; \
1175 }
1176
sewardj3c944452011-09-05 20:39:57 +00001177#if defined(VGO_linux)
1178 GLIBC25___STPCPY_CHK(VG_Z_LIBC_SONAME, __stpcpy_chk)
sewardj4157d4f2011-09-05 22:18:13 +00001179
sewardj3c944452011-09-05 20:39:57 +00001180#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001181
sewardj3c944452011-09-05 20:39:57 +00001182#endif
sewardjb8d03852007-01-27 00:49:44 +00001183
1184
sewardj3c944452011-09-05 20:39:57 +00001185/*---------------------- mempcpy ----------------------*/
1186
sewardj841b72d2006-12-31 18:55:56 +00001187/* mempcpy */
1188#define GLIBC25_MEMPCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001189 void* VG_REPLACE_FUNCTION_EZU(20290,soname,fnname) \
sewardj841b72d2006-12-31 18:55:56 +00001190 ( void *dst, const void *src, SizeT len ); \
sewardj96044842011-08-18 13:09:55 +00001191 void* VG_REPLACE_FUNCTION_EZU(20290,soname,fnname) \
sewardj841b72d2006-12-31 18:55:56 +00001192 ( void *dst, const void *src, SizeT len ) \
1193 { \
1194 register char *d; \
1195 register char *s; \
1196 SizeT len_saved = len; \
1197 \
1198 if (len == 0) \
1199 return dst; \
1200 \
1201 if (is_overlap(dst, src, len, len)) \
1202 RECORD_OVERLAP_ERROR("mempcpy", dst, src, len); \
1203 \
1204 if ( dst > src ) { \
1205 d = (char *)dst + len - 1; \
1206 s = (char *)src + len - 1; \
1207 while ( len-- ) { \
1208 *d-- = *s--; \
1209 } \
1210 } else if ( dst < src ) { \
1211 d = (char *)dst; \
1212 s = (char *)src; \
1213 while ( len-- ) { \
1214 *d++ = *s++; \
1215 } \
1216 } \
1217 return (void*)( ((char*)dst) + len_saved ); \
1218 }
1219
njnb4cfbc42009-05-04 04:20:02 +00001220#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001221 GLIBC25_MEMPCPY(VG_Z_LIBC_SONAME, mempcpy)
1222 GLIBC25_MEMPCPY(VG_Z_LD_SO_1, mempcpy) /* ld.so.1 */
sewardj4157d4f2011-09-05 22:18:13 +00001223
sewardj3c944452011-09-05 20:39:57 +00001224#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +00001225 //GLIBC25_MEMPCPY(VG_Z_LIBC_SONAME, mempcpy)
sewardj4157d4f2011-09-05 22:18:13 +00001226
njnb4cfbc42009-05-04 04:20:02 +00001227#endif
sewardj841b72d2006-12-31 18:55:56 +00001228
1229
sewardj3c944452011-09-05 20:39:57 +00001230/*-------------------- memcpy_chk --------------------*/
1231
sewardjb6c04032007-11-13 20:52:29 +00001232#define GLIBC26___MEMCPY_CHK(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001233 void* VG_REPLACE_FUNCTION_EZU(20300,soname,fnname) \
sewardjb6c04032007-11-13 20:52:29 +00001234 (void* dst, const void* src, SizeT len, SizeT dstlen ); \
sewardj96044842011-08-18 13:09:55 +00001235 void* VG_REPLACE_FUNCTION_EZU(20300,soname,fnname) \
sewardjb6c04032007-11-13 20:52:29 +00001236 (void* dst, const void* src, SizeT len, SizeT dstlen ) \
1237 { \
sewardjb6c04032007-11-13 20:52:29 +00001238 register char *d; \
1239 register char *s; \
1240 \
1241 if (dstlen < len) goto badness; \
1242 \
1243 if (len == 0) \
1244 return dst; \
1245 \
1246 if (is_overlap(dst, src, len, len)) \
1247 RECORD_OVERLAP_ERROR("memcpy_chk", dst, src, len); \
1248 \
1249 if ( dst > src ) { \
1250 d = (char *)dst + len - 1; \
1251 s = (char *)src + len - 1; \
1252 while ( len-- ) { \
1253 *d-- = *s--; \
1254 } \
1255 } else if ( dst < src ) { \
1256 d = (char *)dst; \
1257 s = (char *)src; \
1258 while ( len-- ) { \
1259 *d++ = *s++; \
1260 } \
1261 } \
1262 return dst; \
1263 badness: \
1264 VALGRIND_PRINTF_BACKTRACE( \
1265 "*** memcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +00001266 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +00001267 my_exit(127); \
sewardjb6c04032007-11-13 20:52:29 +00001268 /*NOTREACHED*/ \
1269 return NULL; \
1270 }
1271
sewardj3c944452011-09-05 20:39:57 +00001272#if defined(VGO_linux)
1273 GLIBC26___MEMCPY_CHK(VG_Z_LIBC_SONAME, __memcpy_chk)
sewardj4157d4f2011-09-05 22:18:13 +00001274
sewardj3c944452011-09-05 20:39:57 +00001275#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001276
sewardj3c944452011-09-05 20:39:57 +00001277#endif
sewardjb6c04032007-11-13 20:52:29 +00001278
1279
sewardj3c944452011-09-05 20:39:57 +00001280/*---------------------- strstr ----------------------*/
1281
sewardja77687c2010-08-19 13:22:34 +00001282#define STRSTR(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001283 void* VG_REPLACE_FUNCTION_EZU(20310,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001284 (void* haystack, void* needle); \
sewardj96044842011-08-18 13:09:55 +00001285 void* VG_REPLACE_FUNCTION_EZU(20310,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001286 (void* haystack, void* needle) \
1287 { \
1288 UChar* h = (UChar*)haystack; \
1289 UChar* n = (UChar*)needle; \
1290 \
1291 /* find the length of n, not including terminating zero */ \
1292 UWord nlen = 0; \
1293 while (n[nlen]) nlen++; \
1294 \
1295 /* if n is the empty string, match immediately. */ \
1296 if (nlen == 0) return h; \
1297 \
1298 /* assert(nlen >= 1); */ \
1299 UChar n0 = n[0]; \
1300 \
1301 while (1) { \
1302 UChar hh = *h; \
1303 if (hh == 0) return NULL; \
1304 if (hh != n0) { h++; continue; } \
1305 \
1306 UWord i; \
1307 for (i = 0; i < nlen; i++) { \
1308 if (n[i] != h[i]) \
1309 break; \
1310 } \
1311 /* assert(i >= 0 && i <= nlen); */ \
1312 if (i == nlen) \
1313 return h; \
1314 \
1315 h++; \
1316 } \
1317 }
1318
1319#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001320 STRSTR(VG_Z_LIBC_SONAME, strstr)
sewardj4157d4f2011-09-05 22:18:13 +00001321
sewardj3c944452011-09-05 20:39:57 +00001322#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001323
sewardja77687c2010-08-19 13:22:34 +00001324#endif
1325
1326
sewardj3c944452011-09-05 20:39:57 +00001327/*---------------------- strpbrk ----------------------*/
1328
sewardja77687c2010-08-19 13:22:34 +00001329#define STRPBRK(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001330 void* VG_REPLACE_FUNCTION_EZU(20320,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001331 (void* sV, void* acceptV); \
sewardj96044842011-08-18 13:09:55 +00001332 void* VG_REPLACE_FUNCTION_EZU(20320,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001333 (void* sV, void* acceptV) \
1334 { \
1335 UChar* s = (UChar*)sV; \
1336 UChar* accept = (UChar*)acceptV; \
1337 \
1338 /* find the length of 'accept', not including terminating zero */ \
1339 UWord nacc = 0; \
1340 while (accept[nacc]) nacc++; \
1341 \
1342 /* if n is the empty string, fail immediately. */ \
1343 if (nacc == 0) return NULL; \
1344 \
1345 /* assert(nacc >= 1); */ \
1346 while (1) { \
1347 UWord i; \
1348 UChar sc = *s; \
1349 if (sc == 0) \
1350 break; \
1351 for (i = 0; i < nacc; i++) { \
1352 if (sc == accept[i]) \
1353 return s; \
1354 } \
1355 s++; \
1356 } \
1357 \
1358 return NULL; \
1359 }
1360
1361#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001362 STRPBRK(VG_Z_LIBC_SONAME, strpbrk)
sewardj4157d4f2011-09-05 22:18:13 +00001363
sewardj3c944452011-09-05 20:39:57 +00001364#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001365
sewardja77687c2010-08-19 13:22:34 +00001366#endif
1367
1368
sewardj3c944452011-09-05 20:39:57 +00001369/*---------------------- strcspn ----------------------*/
1370
sewardja77687c2010-08-19 13:22:34 +00001371#define STRCSPN(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001372 SizeT VG_REPLACE_FUNCTION_EZU(20330,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001373 (void* sV, void* rejectV); \
sewardj96044842011-08-18 13:09:55 +00001374 SizeT VG_REPLACE_FUNCTION_EZU(20330,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001375 (void* sV, void* rejectV) \
1376 { \
1377 UChar* s = (UChar*)sV; \
1378 UChar* reject = (UChar*)rejectV; \
1379 \
1380 /* find the length of 'reject', not including terminating zero */ \
1381 UWord nrej = 0; \
1382 while (reject[nrej]) nrej++; \
1383 \
1384 UWord len = 0; \
1385 while (1) { \
1386 UWord i; \
1387 UChar sc = *s; \
1388 if (sc == 0) \
1389 break; \
1390 for (i = 0; i < nrej; i++) { \
1391 if (sc == reject[i]) \
1392 break; \
1393 } \
1394 /* assert(i >= 0 && i <= nrej); */ \
1395 if (i < nrej) \
1396 break; \
1397 s++; \
1398 len++; \
1399 } \
1400 \
1401 return len; \
1402 }
1403
1404#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001405 STRCSPN(VG_Z_LIBC_SONAME, strcspn)
sewardj4157d4f2011-09-05 22:18:13 +00001406
sewardj3c944452011-09-05 20:39:57 +00001407#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001408
sewardja77687c2010-08-19 13:22:34 +00001409#endif
1410
1411
sewardj3c944452011-09-05 20:39:57 +00001412/*---------------------- strspn ----------------------*/
1413
sewardjbd2cff22011-08-16 21:45:28 +00001414#define STRSPN(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001415 SizeT VG_REPLACE_FUNCTION_EZU(20340,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001416 (void* sV, void* acceptV); \
sewardj96044842011-08-18 13:09:55 +00001417 SizeT VG_REPLACE_FUNCTION_EZU(20340,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001418 (void* sV, void* acceptV) \
1419 { \
1420 UChar* s = (UChar*)sV; \
1421 UChar* accept = (UChar*)acceptV; \
1422 \
1423 /* find the length of 'accept', not including terminating zero */ \
1424 UWord nacc = 0; \
1425 while (accept[nacc]) nacc++; \
1426 if (nacc == 0) return 0; \
1427 \
1428 UWord len = 0; \
1429 while (1) { \
1430 UWord i; \
1431 UChar sc = *s; \
1432 if (sc == 0) \
1433 break; \
1434 for (i = 0; i < nacc; i++) { \
1435 if (sc == accept[i]) \
1436 break; \
1437 } \
1438 /* assert(i >= 0 && i <= nacc); */ \
1439 if (i == nacc) \
1440 break; \
1441 s++; \
1442 len++; \
1443 } \
1444 \
1445 return len; \
1446 }
1447
1448#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001449 STRSPN(VG_Z_LIBC_SONAME, strspn)
sewardj4157d4f2011-09-05 22:18:13 +00001450
sewardj3c944452011-09-05 20:39:57 +00001451#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001452
sewardjbd2cff22011-08-16 21:45:28 +00001453#endif
sewardjba189352010-08-20 18:24:16 +00001454
1455
sewardj284f2a32011-10-21 08:07:13 +00001456/*---------------------- strcasestr ----------------------*/
1457
1458#define STRCASESTR(soname, fnname) \
1459 void* VG_REPLACE_FUNCTION_EZU(20350,soname,fnname) \
1460 (void* haystack, void* needle); \
1461 void* VG_REPLACE_FUNCTION_EZU(20350,soname,fnname) \
1462 (void* haystack, void* needle) \
1463 { \
1464 extern int tolower(int); \
1465 UChar* h = (UChar*)haystack; \
1466 UChar* n = (UChar*)needle; \
1467 \
1468 /* find the length of n, not including terminating zero */ \
1469 UWord nlen = 0; \
1470 while (n[nlen]) nlen++; \
1471 \
1472 /* if n is the empty string, match immediately. */ \
1473 if (nlen == 0) return h; \
1474 \
1475 /* assert(nlen >= 1); */ \
1476 UChar n0 = tolower(n[0]); \
1477 \
1478 while (1) { \
1479 UChar hh = tolower(*h); \
1480 if (hh == 0) return NULL; \
1481 if (hh != n0) { h++; continue; } \
1482 \
1483 UWord i; \
1484 for (i = 0; i < nlen; i++) { \
1485 if (tolower(n[i]) != tolower(h[i])) \
1486 break; \
1487 } \
1488 /* assert(i >= 0 && i <= nlen); */ \
1489 if (i == nlen) \
1490 return h; \
1491 \
1492 h++; \
1493 } \
1494 }
1495
1496#if defined(VGO_linux)
sewardj1b3a7a42011-10-26 15:10:49 +00001497# if !defined(VGPV_arm_linux_android)
1498 STRCASESTR(VG_Z_LIBC_SONAME, strcasestr)
1499# endif
sewardj284f2a32011-10-21 08:07:13 +00001500
1501#elif defined(VGO_darwin)
1502
1503#endif
1504
1505
sewardj31b9ce12006-10-17 01:27:13 +00001506/*------------------------------------------------------------*/
dirk09beb9e2007-04-19 09:47:32 +00001507/*--- Improve definedness checking of process environment ---*/
1508/*------------------------------------------------------------*/
1509
sewardjddc00dd2007-11-27 11:42:47 +00001510#if defined(VGO_linux)
1511
sewardjbd2cff22011-08-16 21:45:28 +00001512/* If these wind up getting generated via a macro, so that multiple
1513 versions of each function exist (as above), use the _EZU variants
1514 to assign equivalance class tags. */
1515
sewardj3c944452011-09-05 20:39:57 +00001516/*---------------------- putenv ----------------------*/
1517
njne6154662009-02-10 04:23:41 +00001518int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string);
1519int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string)
dirk09beb9e2007-04-19 09:47:32 +00001520{
1521 OrigFn fn;
1522 Word result;
1523 const char* p = string;
1524 VALGRIND_GET_ORIG_FN(fn);
1525 /* Now by walking over the string we magically produce
1526 traces when hitting undefined memory. */
1527 if (p)
1528 while (*p++)
sewardj3c944452011-09-05 20:39:57 +00001529 __asm__ __volatile__("" ::: "memory");
dirk09beb9e2007-04-19 09:47:32 +00001530 CALL_FN_W_W(result, fn, string);
1531 return result;
1532}
1533
sewardj3c944452011-09-05 20:39:57 +00001534
1535/*---------------------- unsetenv ----------------------*/
1536
njne6154662009-02-10 04:23:41 +00001537int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name);
1538int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name)
dirk09beb9e2007-04-19 09:47:32 +00001539{
1540 OrigFn fn;
1541 Word result;
1542 const char* p = name;
1543 VALGRIND_GET_ORIG_FN(fn);
1544 /* Now by walking over the string we magically produce
1545 traces when hitting undefined memory. */
1546 if (p)
1547 while (*p++)
sewardj3c944452011-09-05 20:39:57 +00001548 __asm__ __volatile__("" ::: "memory");
dirk09beb9e2007-04-19 09:47:32 +00001549 CALL_FN_W_W(result, fn, name);
1550 return result;
1551}
1552
sewardj3c944452011-09-05 20:39:57 +00001553
1554/*---------------------- setenv ----------------------*/
1555
dirk09beb9e2007-04-19 09:47:32 +00001556/* setenv */
njne6154662009-02-10 04:23:41 +00001557int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001558 (const char* name, const char* value, int overwrite);
njne6154662009-02-10 04:23:41 +00001559int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001560 (const char* name, const char* value, int overwrite)
1561{
1562 OrigFn fn;
1563 Word result;
1564 const char* p;
1565 VALGRIND_GET_ORIG_FN(fn);
1566 /* Now by walking over the string we magically produce
1567 traces when hitting undefined memory. */
1568 if (name)
1569 for (p = name; *p; p++)
sewardj3c944452011-09-05 20:39:57 +00001570 __asm__ __volatile__("" ::: "memory");
dirk09beb9e2007-04-19 09:47:32 +00001571 if (value)
1572 for (p = value; *p; p++)
sewardj3c944452011-09-05 20:39:57 +00001573 __asm__ __volatile__("" ::: "memory");
dirk09beb9e2007-04-19 09:47:32 +00001574 VALGRIND_CHECK_VALUE_IS_DEFINED (overwrite);
1575 CALL_FN_W_WWW(result, fn, name, value, overwrite);
1576 return result;
1577}
1578
sewardjddc00dd2007-11-27 11:42:47 +00001579#endif /* defined(VGO_linux) */
1580
njn3e884182003-04-15 13:03:23 +00001581/*--------------------------------------------------------------------*/
njn46275862005-03-24 04:00:03 +00001582/*--- end ---*/
njn3e884182003-04-15 13:03:23 +00001583/*--------------------------------------------------------------------*/