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