• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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