1
2 /*---------------------------------------------------------------*/
3 /*--- begin main_util.c ---*/
4 /*---------------------------------------------------------------*/
5
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2004-2012 OpenWorks LLP
11 info@open-works.net
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 02110-1301, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29
30 Neither the names of the U.S. Department of Energy nor the
31 University of California nor the names of its contributors may be
32 used to endorse or promote products derived from this software
33 without prior written permission.
34 */
35
36 #include "libvex_basictypes.h"
37 #include "libvex.h"
38
39 #include "main_globals.h"
40 #include "main_util.h"
41
42
43 /*---------------------------------------------------------*/
44 /*--- Storage ---*/
45 /*---------------------------------------------------------*/
46
47 /* Try to keep this as low as possible -- in particular, less than the
48 size of the smallest L2 cache we might encounter. At 50000, my VIA
49 Nehemiah 1 GHz (a weedy machine) can satisfy 27 million calls/
50 second to LibVEX_Alloc(16) -- that is, allocate memory at over 400
51 MByte/sec. Once the size increases enough to fall out of the cache
52 into memory, the rate falls by about a factor of 3.
53 */
54 #define N_TEMPORARY_BYTES 5000000
55
56 static HChar temporary[N_TEMPORARY_BYTES] __attribute__((aligned(8)));
57 static HChar* temporary_first = &temporary[0];
58 static HChar* temporary_curr = &temporary[0];
59 static HChar* temporary_last = &temporary[N_TEMPORARY_BYTES-1];
60
61 static ULong temporary_bytes_allocd_TOT = 0;
62
63 #define N_PERMANENT_BYTES 10000
64
65 static HChar permanent[N_PERMANENT_BYTES] __attribute__((aligned(8)));
66 static HChar* permanent_first = &permanent[0];
67 static HChar* permanent_curr = &permanent[0];
68 static HChar* permanent_last = &permanent[N_PERMANENT_BYTES-1];
69
70 static VexAllocMode mode = VexAllocModeTEMP;
71
vexAllocSanityCheck(void)72 void vexAllocSanityCheck ( void )
73 {
74 vassert(temporary_first == &temporary[0]);
75 vassert(temporary_last == &temporary[N_TEMPORARY_BYTES-1]);
76 vassert(permanent_first == &permanent[0]);
77 vassert(permanent_last == &permanent[N_PERMANENT_BYTES-1]);
78 vassert(temporary_first <= temporary_curr);
79 vassert(temporary_curr <= temporary_last);
80 vassert(permanent_first <= permanent_curr);
81 vassert(permanent_curr <= permanent_last);
82 vassert(private_LibVEX_alloc_first <= private_LibVEX_alloc_curr);
83 vassert(private_LibVEX_alloc_curr <= private_LibVEX_alloc_last);
84 if (mode == VexAllocModeTEMP){
85 vassert(private_LibVEX_alloc_first == temporary_first);
86 vassert(private_LibVEX_alloc_last == temporary_last);
87 }
88 else
89 if (mode == VexAllocModePERM) {
90 vassert(private_LibVEX_alloc_first == permanent_first);
91 vassert(private_LibVEX_alloc_last == permanent_last);
92 }
93 else
94 vassert(0);
95
96 # define IS_WORD_ALIGNED(p) (0 == (((HWord)p) & (sizeof(HWord)-1)))
97 vassert(sizeof(HWord) == 4 || sizeof(HWord) == 8);
98 vassert(IS_WORD_ALIGNED(temporary_first));
99 vassert(IS_WORD_ALIGNED(temporary_curr));
100 vassert(IS_WORD_ALIGNED(temporary_last+1));
101 vassert(IS_WORD_ALIGNED(permanent_first));
102 vassert(IS_WORD_ALIGNED(permanent_curr));
103 vassert(IS_WORD_ALIGNED(permanent_last+1));
104 vassert(IS_WORD_ALIGNED(private_LibVEX_alloc_first));
105 vassert(IS_WORD_ALIGNED(private_LibVEX_alloc_curr));
106 vassert(IS_WORD_ALIGNED(private_LibVEX_alloc_last+1));
107 # undef IS_WORD_ALIGNED
108 }
109
110 /* The current allocation mode. */
111
vexSetAllocMode(VexAllocMode m)112 void vexSetAllocMode ( VexAllocMode m )
113 {
114 vexAllocSanityCheck();
115
116 /* Save away the current allocation point .. */
117 if (mode == VexAllocModeTEMP){
118 temporary_curr = private_LibVEX_alloc_curr;
119 }
120 else
121 if (mode == VexAllocModePERM) {
122 permanent_curr = private_LibVEX_alloc_curr;
123 }
124 else
125 vassert(0);
126
127 /* Did that screw anything up? */
128 vexAllocSanityCheck();
129
130 if (m == VexAllocModeTEMP){
131 private_LibVEX_alloc_first = temporary_first;
132 private_LibVEX_alloc_curr = temporary_curr;
133 private_LibVEX_alloc_last = temporary_last;
134 }
135 else
136 if (m == VexAllocModePERM) {
137 private_LibVEX_alloc_first = permanent_first;
138 private_LibVEX_alloc_curr = permanent_curr;
139 private_LibVEX_alloc_last = permanent_last;
140 }
141 else
142 vassert(0);
143
144 mode = m;
145 }
146
vexGetAllocMode(void)147 VexAllocMode vexGetAllocMode ( void )
148 {
149 return mode;
150 }
151
152 /* Visible to library client, unfortunately. */
153
154 HChar* private_LibVEX_alloc_first = &temporary[0];
155 HChar* private_LibVEX_alloc_curr = &temporary[0];
156 HChar* private_LibVEX_alloc_last = &temporary[N_TEMPORARY_BYTES-1];
157
158 __attribute__((noreturn))
private_LibVEX_alloc_OOM(void)159 void private_LibVEX_alloc_OOM(void)
160 {
161 HChar* pool = "???";
162 if (private_LibVEX_alloc_first == &temporary[0]) pool = "TEMP";
163 if (private_LibVEX_alloc_first == &permanent[0]) pool = "PERM";
164 vex_printf("VEX temporary storage exhausted.\n");
165 vex_printf("Pool = %s, start %p curr %p end %p (size %lld)\n",
166 pool,
167 private_LibVEX_alloc_first,
168 private_LibVEX_alloc_curr,
169 private_LibVEX_alloc_last,
170 (Long)(private_LibVEX_alloc_last + 1 - private_LibVEX_alloc_first));
171 vpanic("VEX temporary storage exhausted.\n"
172 "Increase N_{TEMPORARY,PERMANENT}_BYTES and recompile.");
173 }
174
vexSetAllocModeTEMP_and_clear(void)175 void vexSetAllocModeTEMP_and_clear ( void )
176 {
177 /* vassert(vex_initdone); */ /* causes infinite assert loops */
178 temporary_bytes_allocd_TOT
179 += (ULong)(private_LibVEX_alloc_curr - private_LibVEX_alloc_first);
180
181 mode = VexAllocModeTEMP;
182 temporary_curr = &temporary[0];
183 private_LibVEX_alloc_curr = &temporary[0];
184
185 /* Set to (1) and change the fill byte to 0x00 or 0xFF to test for
186 any potential bugs due to using uninitialised memory in the main
187 VEX storage area. */
188 if (0) {
189 Int i;
190 for (i = 0; i < N_TEMPORARY_BYTES; i++)
191 temporary[i] = 0x00;
192 }
193
194 vexAllocSanityCheck();
195 }
196
197
198 /* Exported to library client. */
199
LibVEX_ShowAllocStats(void)200 void LibVEX_ShowAllocStats ( void )
201 {
202 vex_printf("vex storage: T total %lld bytes allocated\n",
203 (Long)temporary_bytes_allocd_TOT );
204 vex_printf("vex storage: P total %lld bytes allocated\n",
205 (Long)(permanent_curr - permanent_first) );
206 }
207
208
209 /*---------------------------------------------------------*/
210 /*--- Bombing out ---*/
211 /*---------------------------------------------------------*/
212
213 __attribute__ ((noreturn))
vex_assert_fail(const HChar * expr,const HChar * file,Int line,const HChar * fn)214 void vex_assert_fail ( const HChar* expr,
215 const HChar* file, Int line, const HChar* fn )
216 {
217 vex_printf( "\nvex: %s:%d (%s): Assertion `%s' failed.\n",
218 file, line, fn, expr );
219 (*vex_failure_exit)();
220 }
221
222 __attribute__ ((noreturn))
vpanic(HChar * str)223 void vpanic ( HChar* str )
224 {
225 vex_printf("\nvex: the `impossible' happened:\n %s\n", str);
226 (*vex_failure_exit)();
227 }
228
229
230 /*---------------------------------------------------------*/
231 /*--- vex_printf ---*/
232 /*---------------------------------------------------------*/
233
234 /* This should be the only <...> include in the entire VEX library.
235 New code for vex_util.c should go above this point. */
236 #include <stdarg.h>
237
vex_strlen(const HChar * str)238 Int vex_strlen ( const HChar* str )
239 {
240 Int i = 0;
241 while (str[i] != 0) i++;
242 return i;
243 }
244
vex_streq(const HChar * s1,const HChar * s2)245 Bool vex_streq ( const HChar* s1, const HChar* s2 )
246 {
247 while (True) {
248 if (*s1 == 0 && *s2 == 0)
249 return True;
250 if (*s1 != *s2)
251 return False;
252 s1++;
253 s2++;
254 }
255 }
256
vex_bzero(void * sV,UInt n)257 void vex_bzero ( void* sV, UInt n )
258 {
259 UInt i;
260 UChar* s = (UChar*)sV;
261 /* No laughing, please. Just don't call this too often. Thank you
262 for your attention. */
263 for (i = 0; i < n; i++) s[i] = 0;
264 }
265
266
267 /* Convert N0 into ascii in BUF, which is assumed to be big enough (at
268 least 67 bytes long). Observe BASE, SYNED and HEXCAPS. */
269 static
convert_int(HChar * buf,Long n0,Int base,Bool syned,Bool hexcaps)270 void convert_int ( /*OUT*/HChar* buf, Long n0,
271 Int base, Bool syned, Bool hexcaps )
272 {
273 ULong u0;
274 HChar c;
275 Bool minus = False;
276 Int i, j, bufi = 0;
277 buf[bufi] = 0;
278
279 if (syned) {
280 if (n0 < 0) {
281 minus = True;
282 u0 = (ULong)(-n0);
283 } else {
284 u0 = (ULong)(n0);
285 }
286 } else {
287 u0 = (ULong)n0;
288 }
289
290 while (1) {
291 buf[bufi++] = toHChar('0' + toUInt(u0 % base));
292 u0 /= base;
293 if (u0 == 0) break;
294 }
295 if (minus)
296 buf[bufi++] = '-';
297
298 buf[bufi] = 0;
299 for (i = 0; i < bufi; i++)
300 if (buf[i] > '9')
301 buf[i] = toHChar(buf[i] + (hexcaps ? 'A' : 'a') - '9' - 1);
302
303 i = 0;
304 j = bufi-1;
305 while (i <= j) {
306 c = buf[i];
307 buf[i] = buf[j];
308 buf[j] = c;
309 i++;
310 j--;
311 }
312 }
313
314
315 /* A half-arsed and buggy, but good-enough, implementation of
316 printf. */
317 static
vprintf_wrk(void (* sink)(HChar),HChar * format,va_list ap)318 UInt vprintf_wrk ( void(*sink)(HChar),
319 HChar* format,
320 va_list ap )
321 {
322 # define PUT(_ch) \
323 do { sink(_ch); nout++; } \
324 while (0)
325
326 # define PAD(_n) \
327 do { Int _qq = (_n); for (; _qq > 0; _qq--) PUT(padchar); } \
328 while (0)
329
330 # define PUTSTR(_str) \
331 do { HChar* _qq = _str; for (; *_qq; _qq++) PUT(*_qq); } \
332 while (0)
333
334 HChar* saved_format;
335 Bool longlong, ljustify;
336 HChar padchar;
337 Int fwidth, nout, len1, len2, len3;
338 HChar intbuf[100]; /* big enough for a 64-bit # in base 2 */
339
340 nout = 0;
341 while (1) {
342
343 if (!format)
344 break;
345 if (*format == 0)
346 break;
347
348 if (*format != '%') {
349 PUT(*format);
350 format++;
351 continue;
352 }
353
354 saved_format = format;
355 longlong = False;
356 ljustify = False;
357 padchar = ' ';
358 fwidth = 0;
359 format++;
360
361 if (*format == '-') {
362 format++;
363 ljustify = True;
364 }
365 if (*format == '0') {
366 format++;
367 padchar = '0';
368 }
369 while (*format >= '0' && *format <= '9') {
370 fwidth = fwidth * 10 + (*format - '0');
371 format++;
372 }
373 if (*format == 'l') {
374 format++;
375 if (*format == 'l') {
376 format++;
377 longlong = True;
378 }
379 }
380
381 switch (*format) {
382 case 's': {
383 HChar* str = va_arg(ap, HChar*);
384 if (str == NULL)
385 str = "(null)";
386 len1 = len3 = 0;
387 len2 = vex_strlen(str);
388 if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
389 len3 = ljustify ? fwidth-len2 : 0; }
390 PAD(len1); PUTSTR(str); PAD(len3);
391 break;
392 }
393 case 'c': {
394 HChar c = (HChar)va_arg(ap, int);
395 HChar str[2];
396 str[0] = c;
397 str[1] = 0;
398 len1 = len3 = 0;
399 len2 = vex_strlen(str);
400 if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
401 len3 = ljustify ? fwidth-len2 : 0; }
402 PAD(len1); PUTSTR(str); PAD(len3);
403 break;
404 }
405 case 'd': {
406 Long l;
407 if (longlong) {
408 l = va_arg(ap, Long);
409 } else {
410 l = (Long)va_arg(ap, Int);
411 }
412 convert_int(intbuf, l, 10/*base*/, True/*signed*/,
413 False/*irrelevant*/);
414 len1 = len3 = 0;
415 len2 = vex_strlen(intbuf);
416 if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
417 len3 = ljustify ? fwidth-len2 : 0; }
418 PAD(len1); PUTSTR(intbuf); PAD(len3);
419 break;
420 }
421 case 'u':
422 case 'x':
423 case 'X': {
424 Int base = *format == 'u' ? 10 : 16;
425 Bool hexcaps = True; /* *format == 'X'; */
426 ULong l;
427 if (longlong) {
428 l = va_arg(ap, ULong);
429 } else {
430 l = (ULong)va_arg(ap, UInt);
431 }
432 convert_int(intbuf, l, base, False/*unsigned*/, hexcaps);
433 len1 = len3 = 0;
434 len2 = vex_strlen(intbuf);
435 if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
436 len3 = ljustify ? fwidth-len2 : 0; }
437 PAD(len1); PUTSTR(intbuf); PAD(len3);
438 break;
439 }
440 case 'p':
441 case 'P': {
442 Bool hexcaps = toBool(*format == 'P');
443 ULong l = Ptr_to_ULong( va_arg(ap, void*) );
444 convert_int(intbuf, l, 16/*base*/, False/*unsigned*/, hexcaps);
445 len1 = len3 = 0;
446 len2 = vex_strlen(intbuf)+2;
447 if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
448 len3 = ljustify ? fwidth-len2 : 0; }
449 PAD(len1); PUT('0'); PUT('x'); PUTSTR(intbuf); PAD(len3);
450 break;
451 }
452 case '%': {
453 PUT('%');
454 break;
455 }
456 default:
457 /* no idea what it is. Print the format literally and
458 move on. */
459 while (saved_format <= format) {
460 PUT(*saved_format);
461 saved_format++;
462 }
463 break;
464 }
465
466 format++;
467
468 }
469
470 return nout;
471
472 # undef PUT
473 # undef PAD
474 # undef PUTSTR
475 }
476
477
478 /* A general replacement for printf(). Note that only low-level
479 debugging info should be sent via here. The official route is to
480 to use vg_message(). This interface is deprecated.
481 */
482 static HChar myprintf_buf[1000];
483 static Int n_myprintf_buf;
484
add_to_myprintf_buf(HChar c)485 static void add_to_myprintf_buf ( HChar c )
486 {
487 Bool emit = toBool(c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/);
488 myprintf_buf[n_myprintf_buf++] = c;
489 myprintf_buf[n_myprintf_buf] = 0;
490 if (emit) {
491 (*vex_log_bytes)( myprintf_buf, vex_strlen(myprintf_buf) );
492 n_myprintf_buf = 0;
493 myprintf_buf[n_myprintf_buf] = 0;
494 }
495 }
496
vex_printf(HChar * format,...)497 UInt vex_printf ( HChar* format, ... )
498 {
499 UInt ret;
500 va_list vargs;
501 va_start(vargs,format);
502
503 n_myprintf_buf = 0;
504 myprintf_buf[n_myprintf_buf] = 0;
505 ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs );
506
507 if (n_myprintf_buf > 0) {
508 (*vex_log_bytes)( myprintf_buf, n_myprintf_buf );
509 }
510
511 va_end(vargs);
512
513 return ret;
514 }
515
516
517 /* A general replacement for sprintf(). */
518
519 static HChar *vg_sprintf_ptr;
520
add_to_vg_sprintf_buf(HChar c)521 static void add_to_vg_sprintf_buf ( HChar c )
522 {
523 *vg_sprintf_ptr++ = c;
524 }
525
vex_sprintf(HChar * buf,HChar * format,...)526 UInt vex_sprintf ( HChar* buf, HChar *format, ... )
527 {
528 Int ret;
529 va_list vargs;
530
531 vg_sprintf_ptr = buf;
532
533 va_start(vargs,format);
534
535 ret = vprintf_wrk ( add_to_vg_sprintf_buf, format, vargs );
536 add_to_vg_sprintf_buf(0);
537
538 va_end(vargs);
539
540 vassert(vex_strlen(buf) == ret);
541 return ret;
542 }
543
544
545 /*---------------------------------------------------------------*/
546 /*--- end main_util.c ---*/
547 /*---------------------------------------------------------------*/
548