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-2013 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
55 #define N_TEMPORARY_BYTES 5000000
56
57 static HChar temporary[N_TEMPORARY_BYTES] __attribute__((aligned(REQ_ALIGN)));
58 static HChar* temporary_first = &temporary[0];
59 static HChar* temporary_curr = &temporary[0];
60 static HChar* temporary_last = &temporary[N_TEMPORARY_BYTES-1];
61
62 static ULong temporary_bytes_allocd_TOT = 0;
63
64 #define N_PERMANENT_BYTES 10000
65
66 static HChar permanent[N_PERMANENT_BYTES] __attribute__((aligned(REQ_ALIGN)));
67 static HChar* permanent_first = &permanent[0];
68 static HChar* permanent_curr = &permanent[0];
69 static HChar* permanent_last = &permanent[N_PERMANENT_BYTES-1];
70
71 HChar* private_LibVEX_alloc_first = &temporary[0];
72 HChar* private_LibVEX_alloc_curr = &temporary[0];
73 HChar* private_LibVEX_alloc_last = &temporary[N_TEMPORARY_BYTES-1];
74
75
76 static VexAllocMode mode = VexAllocModeTEMP;
77
vexAllocSanityCheck(void)78 void vexAllocSanityCheck ( void )
79 {
80 vassert(temporary_first == &temporary[0]);
81 vassert(temporary_last == &temporary[N_TEMPORARY_BYTES-1]);
82 vassert(permanent_first == &permanent[0]);
83 vassert(permanent_last == &permanent[N_PERMANENT_BYTES-1]);
84 vassert(temporary_first <= temporary_curr);
85 vassert(temporary_curr <= temporary_last);
86 vassert(permanent_first <= permanent_curr);
87 vassert(permanent_curr <= permanent_last);
88 vassert(private_LibVEX_alloc_first <= private_LibVEX_alloc_curr);
89 vassert(private_LibVEX_alloc_curr <= private_LibVEX_alloc_last);
90 if (mode == VexAllocModeTEMP){
91 vassert(private_LibVEX_alloc_first == temporary_first);
92 vassert(private_LibVEX_alloc_last == temporary_last);
93 }
94 else
95 if (mode == VexAllocModePERM) {
96 vassert(private_LibVEX_alloc_first == permanent_first);
97 vassert(private_LibVEX_alloc_last == permanent_last);
98 }
99 else
100 vassert(0);
101
102 # define IS_WORD_ALIGNED(p) (0 == (((HWord)p) & (sizeof(HWord)-1)))
103 vassert(sizeof(HWord) == 4 || sizeof(HWord) == 8);
104 vassert(IS_WORD_ALIGNED(temporary_first));
105 vassert(IS_WORD_ALIGNED(temporary_curr));
106 vassert(IS_WORD_ALIGNED(temporary_last+1));
107 vassert(IS_WORD_ALIGNED(permanent_first));
108 vassert(IS_WORD_ALIGNED(permanent_curr));
109 vassert(IS_WORD_ALIGNED(permanent_last+1));
110 vassert(IS_WORD_ALIGNED(private_LibVEX_alloc_first));
111 vassert(IS_WORD_ALIGNED(private_LibVEX_alloc_curr));
112 vassert(IS_WORD_ALIGNED(private_LibVEX_alloc_last+1));
113 # undef IS_WORD_ALIGNED
114 }
115
116 /* The current allocation mode. */
117
vexSetAllocMode(VexAllocMode m)118 void vexSetAllocMode ( VexAllocMode m )
119 {
120 vexAllocSanityCheck();
121
122 /* Save away the current allocation point .. */
123 if (mode == VexAllocModeTEMP){
124 temporary_curr = private_LibVEX_alloc_curr;
125 }
126 else
127 if (mode == VexAllocModePERM) {
128 permanent_curr = private_LibVEX_alloc_curr;
129 }
130 else
131 vassert(0);
132
133 /* Did that screw anything up? */
134 vexAllocSanityCheck();
135
136 if (m == VexAllocModeTEMP){
137 private_LibVEX_alloc_first = temporary_first;
138 private_LibVEX_alloc_curr = temporary_curr;
139 private_LibVEX_alloc_last = temporary_last;
140 }
141 else
142 if (m == VexAllocModePERM) {
143 private_LibVEX_alloc_first = permanent_first;
144 private_LibVEX_alloc_curr = permanent_curr;
145 private_LibVEX_alloc_last = permanent_last;
146 }
147 else
148 vassert(0);
149
150 mode = m;
151 }
152
vexGetAllocMode(void)153 VexAllocMode vexGetAllocMode ( void )
154 {
155 return mode;
156 }
157
158 __attribute__((noreturn))
private_LibVEX_alloc_OOM(void)159 void private_LibVEX_alloc_OOM(void)
160 {
161 const 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
LibVEX_Alloc(SizeT nbytes)208 void *LibVEX_Alloc ( SizeT nbytes )
209 {
210 return LibVEX_Alloc_inline(nbytes);
211 }
212
213 /*---------------------------------------------------------*/
214 /*--- Bombing out ---*/
215 /*---------------------------------------------------------*/
216
217 __attribute__ ((noreturn))
vex_assert_fail(const HChar * expr,const HChar * file,Int line,const HChar * fn)218 void vex_assert_fail ( const HChar* expr,
219 const HChar* file, Int line, const HChar* fn )
220 {
221 vex_printf( "\nvex: %s:%d (%s): Assertion `%s' failed.\n",
222 file, line, fn, expr );
223 (*vex_failure_exit)();
224 }
225
226 /* To be used in assert-like (i.e. should never ever happen) situations */
227 __attribute__ ((noreturn))
vpanic(const HChar * str)228 void vpanic ( const HChar* str )
229 {
230 vex_printf("\nvex: the `impossible' happened:\n %s\n", str);
231 (*vex_failure_exit)();
232 }
233
234
235 /*---------------------------------------------------------*/
236 /*--- vex_printf ---*/
237 /*---------------------------------------------------------*/
238
239 /* This should be the only <...> include in the entire VEX library.
240 New code for vex_util.c should go above this point. */
241 #include <stdarg.h>
242
vex_strlen(const HChar * str)243 SizeT vex_strlen ( const HChar* str )
244 {
245 SizeT i = 0;
246 while (str[i] != 0) i++;
247 return i;
248 }
249
vex_streq(const HChar * s1,const HChar * s2)250 Bool vex_streq ( const HChar* s1, const HChar* s2 )
251 {
252 while (True) {
253 if (*s1 == 0 && *s2 == 0)
254 return True;
255 if (*s1 != *s2)
256 return False;
257 s1++;
258 s2++;
259 }
260 }
261
vex_bzero(void * sV,SizeT n)262 void vex_bzero ( void* sV, SizeT n )
263 {
264 SizeT i;
265 UChar* s = (UChar*)sV;
266 /* No laughing, please. Just don't call this too often. Thank you
267 for your attention. */
268 for (i = 0; i < n; i++) s[i] = 0;
269 }
270
271
272 /* Convert N0 into ascii in BUF, which is assumed to be big enough (at
273 least 67 bytes long). Observe BASE, SYNED and HEXCAPS. */
274 static
convert_int(HChar * buf,Long n0,Int base,Bool syned,Bool hexcaps)275 void convert_int ( /*OUT*/HChar* buf, Long n0,
276 Int base, Bool syned, Bool hexcaps )
277 {
278 ULong u0;
279 HChar c;
280 Bool minus = False;
281 Int i, j, bufi = 0;
282 buf[bufi] = 0;
283
284 if (syned) {
285 if (n0 < 0) {
286 minus = True;
287 u0 = (ULong)(-n0);
288 } else {
289 u0 = (ULong)(n0);
290 }
291 } else {
292 u0 = (ULong)n0;
293 }
294
295 while (1) {
296 buf[bufi++] = toHChar('0' + toUInt(u0 % base));
297 u0 /= base;
298 if (u0 == 0) break;
299 }
300 if (minus)
301 buf[bufi++] = '-';
302
303 buf[bufi] = 0;
304 for (i = 0; i < bufi; i++)
305 if (buf[i] > '9')
306 buf[i] = toHChar(buf[i] + (hexcaps ? 'A' : 'a') - '9' - 1);
307
308 i = 0;
309 j = bufi-1;
310 while (i <= j) {
311 c = buf[i];
312 buf[i] = buf[j];
313 buf[j] = c;
314 i++;
315 j--;
316 }
317 }
318
319
320 /* A half-arsed and buggy, but good-enough, implementation of
321 printf. */
322 static
vprintf_wrk(void (* sink)(HChar),const HChar * format,va_list ap)323 UInt vprintf_wrk ( void(*sink)(HChar),
324 const HChar* format,
325 va_list ap )
326 {
327 # define PUT(_ch) \
328 do { sink(_ch); nout++; } \
329 while (0)
330
331 # define PAD(_n) \
332 do { Int _qq = (_n); for (; _qq > 0; _qq--) PUT(padchar); } \
333 while (0)
334
335 # define PUTSTR(_str) \
336 do { const HChar* _qq = _str; for (; *_qq; _qq++) PUT(*_qq); } \
337 while (0)
338
339 const HChar* saved_format;
340 Bool longlong, ljustify, is_sizet;
341 HChar padchar;
342 Int fwidth, nout, len1, len3;
343 SizeT len2;
344 HChar intbuf[100]; /* big enough for a 64-bit # in base 2 */
345
346 nout = 0;
347 while (1) {
348
349 if (!format)
350 break;
351 if (*format == 0)
352 break;
353
354 if (*format != '%') {
355 PUT(*format);
356 format++;
357 continue;
358 }
359
360 saved_format = format;
361 longlong = is_sizet = False;
362 ljustify = False;
363 padchar = ' ';
364 fwidth = 0;
365 format++;
366
367 if (*format == '-') {
368 format++;
369 ljustify = True;
370 }
371 if (*format == '0') {
372 format++;
373 padchar = '0';
374 }
375 if (*format == '*') {
376 fwidth = va_arg(ap, Int);
377 vassert(fwidth >= 0);
378 format++;
379 } else {
380 while (*format >= '0' && *format <= '9') {
381 fwidth = fwidth * 10 + (*format - '0');
382 format++;
383 }
384 }
385 if (*format == 'l') {
386 format++;
387 if (*format == 'l') {
388 format++;
389 longlong = True;
390 }
391 } else if (*format == 'z') {
392 format++;
393 is_sizet = True;
394 }
395
396 switch (*format) {
397 case 's': {
398 const HChar* str = va_arg(ap, HChar*);
399 if (str == NULL)
400 str = "(null)";
401 len1 = len3 = 0;
402 len2 = vex_strlen(str);
403 if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
404 len3 = ljustify ? fwidth-len2 : 0; }
405 PAD(len1); PUTSTR(str); PAD(len3);
406 break;
407 }
408 case 'c': {
409 HChar c = (HChar)va_arg(ap, int);
410 HChar str[2];
411 str[0] = c;
412 str[1] = 0;
413 len1 = len3 = 0;
414 len2 = vex_strlen(str);
415 if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
416 len3 = ljustify ? fwidth-len2 : 0; }
417 PAD(len1); PUTSTR(str); PAD(len3);
418 break;
419 }
420 case 'd': {
421 Long l;
422 vassert(is_sizet == False); // %zd is obscure; we don't allow it
423 if (longlong) {
424 l = va_arg(ap, Long);
425 } else {
426 l = (Long)va_arg(ap, Int);
427 }
428 convert_int(intbuf, l, 10/*base*/, True/*signed*/,
429 False/*irrelevant*/);
430 len1 = len3 = 0;
431 len2 = vex_strlen(intbuf);
432 if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
433 len3 = ljustify ? fwidth-len2 : 0; }
434 PAD(len1); PUTSTR(intbuf); PAD(len3);
435 break;
436 }
437 case 'u':
438 case 'x':
439 case 'X': {
440 Int base = *format == 'u' ? 10 : 16;
441 Bool hexcaps = True; /* *format == 'X'; */
442 ULong l;
443 if (is_sizet) {
444 l = (ULong)va_arg(ap, SizeT);
445 } else if (longlong) {
446 l = va_arg(ap, ULong);
447 } else {
448 l = (ULong)va_arg(ap, UInt);
449 }
450 convert_int(intbuf, l, base, False/*unsigned*/, hexcaps);
451 len1 = len3 = 0;
452 len2 = vex_strlen(intbuf);
453 if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
454 len3 = ljustify ? fwidth-len2 : 0; }
455 PAD(len1); PUTSTR(intbuf); PAD(len3);
456 break;
457 }
458 case 'p':
459 case 'P': {
460 Bool hexcaps = toBool(*format == 'P');
461 ULong l = (Addr)va_arg(ap, void*);
462 convert_int(intbuf, l, 16/*base*/, False/*unsigned*/, hexcaps);
463 len1 = len3 = 0;
464 len2 = vex_strlen(intbuf)+2;
465 if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
466 len3 = ljustify ? fwidth-len2 : 0; }
467 PAD(len1); PUT('0'); PUT('x'); PUTSTR(intbuf); PAD(len3);
468 break;
469 }
470 case '%': {
471 PUT('%');
472 break;
473 }
474 default:
475 /* no idea what it is. Print the format literally and
476 move on. */
477 while (saved_format <= format) {
478 PUT(*saved_format);
479 saved_format++;
480 }
481 break;
482 }
483
484 format++;
485
486 }
487
488 return nout;
489
490 # undef PUT
491 # undef PAD
492 # undef PUTSTR
493 }
494
495
496 /* A general replacement for printf(). Note that only low-level
497 debugging info should be sent via here. The official route is to
498 to use vg_message(). This interface is deprecated.
499 */
500 static HChar myprintf_buf[1000];
501 static Int n_myprintf_buf;
502
add_to_myprintf_buf(HChar c)503 static void add_to_myprintf_buf ( HChar c )
504 {
505 Bool emit = toBool(c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/);
506 myprintf_buf[n_myprintf_buf++] = c;
507 myprintf_buf[n_myprintf_buf] = 0;
508 if (emit) {
509 (*vex_log_bytes)( myprintf_buf, vex_strlen(myprintf_buf) );
510 n_myprintf_buf = 0;
511 myprintf_buf[n_myprintf_buf] = 0;
512 }
513 }
514
vex_vprintf(const HChar * format,va_list vargs)515 static UInt vex_vprintf ( const HChar* format, va_list vargs )
516 {
517 UInt ret;
518
519 n_myprintf_buf = 0;
520 myprintf_buf[n_myprintf_buf] = 0;
521 ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs );
522
523 if (n_myprintf_buf > 0) {
524 (*vex_log_bytes)( myprintf_buf, n_myprintf_buf );
525 }
526
527 return ret;
528 }
529
vex_printf(const HChar * format,...)530 UInt vex_printf ( const HChar* format, ... )
531 {
532 UInt ret;
533 va_list vargs;
534 va_start(vargs, format);
535 ret = vex_vprintf(format, vargs);
536 va_end(vargs);
537
538 return ret;
539 }
540
541 /* Use this function to communicate to users that a (legitimate) situation
542 occured that we cannot handle (yet). */
543 __attribute__ ((noreturn))
vfatal(const HChar * format,...)544 void vfatal ( const HChar* format, ... )
545 {
546 va_list vargs;
547 va_start(vargs, format);
548 vex_vprintf( format, vargs );
549 va_end(vargs);
550 vex_printf("Cannot continue. Good-bye\n\n");
551
552 (*vex_failure_exit)();
553 }
554
555 /* A general replacement for sprintf(). */
556
557 static HChar *vg_sprintf_ptr;
558
add_to_vg_sprintf_buf(HChar c)559 static void add_to_vg_sprintf_buf ( HChar c )
560 {
561 *vg_sprintf_ptr++ = c;
562 }
563
vex_sprintf(HChar * buf,const HChar * format,...)564 UInt vex_sprintf ( HChar* buf, const HChar *format, ... )
565 {
566 Int ret;
567 va_list vargs;
568
569 vg_sprintf_ptr = buf;
570
571 va_start(vargs,format);
572
573 ret = vprintf_wrk ( add_to_vg_sprintf_buf, format, vargs );
574 add_to_vg_sprintf_buf(0);
575
576 va_end(vargs);
577
578 vassert(vex_strlen(buf) == ret);
579 return ret;
580 }
581
582
583 /*---------------------------------------------------------------*/
584 /*--- end main_util.c ---*/
585 /*---------------------------------------------------------------*/
586