• 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-2010 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 static 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 
257 
258 /* Convert N0 into ascii in BUF, which is assumed to be big enough (at
259    least 67 bytes long).  Observe BASE, SYNED and HEXCAPS. */
260 static
convert_int(HChar * buf,Long n0,Int base,Bool syned,Bool hexcaps)261 void convert_int ( /*OUT*/HChar* buf, Long n0,
262                    Int base, Bool syned, Bool hexcaps )
263 {
264    ULong u0;
265    HChar c;
266    Bool minus = False;
267    Int i, j, bufi = 0;
268    buf[bufi] = 0;
269 
270    if (syned) {
271       if (n0 < 0) {
272          minus = True;
273          u0 = (ULong)(-n0);
274       } else {
275          u0 = (ULong)(n0);
276       }
277    } else {
278       u0 = (ULong)n0;
279    }
280 
281    while (1) {
282      buf[bufi++] = toHChar('0' + toUInt(u0 % base));
283      u0 /= base;
284      if (u0 == 0) break;
285    }
286    if (minus)
287       buf[bufi++] = '-';
288 
289    buf[bufi] = 0;
290    for (i = 0; i < bufi; i++)
291       if (buf[i] > '9')
292          buf[i] = toHChar(buf[i] + (hexcaps ? 'A' : 'a') - '9' - 1);
293 
294    i = 0;
295    j = bufi-1;
296    while (i <= j) {
297       c = buf[i];
298       buf[i] = buf[j];
299       buf[j] = c;
300       i++;
301       j--;
302    }
303 }
304 
305 
306 /* A half-arsed and buggy, but good-enough, implementation of
307    printf. */
308 static
vprintf_wrk(void (* sink)(HChar),HChar * format,va_list ap)309 UInt vprintf_wrk ( void(*sink)(HChar),
310                    HChar* format,
311                    va_list ap )
312 {
313 #  define PUT(_ch)  \
314       do { sink(_ch); nout++; } \
315       while (0)
316 
317 #  define PAD(_n) \
318       do { Int _qq = (_n); for (; _qq > 0; _qq--) PUT(padchar); } \
319       while (0)
320 
321 #  define PUTSTR(_str) \
322       do { HChar* _qq = _str; for (; *_qq; _qq++) PUT(*_qq); } \
323       while (0)
324 
325    HChar* saved_format;
326    Bool   longlong, ljustify;
327    HChar  padchar;
328    Int    fwidth, nout, len1, len2, len3;
329    HChar  intbuf[100];  /* big enough for a 64-bit # in base 2 */
330 
331    nout = 0;
332    while (1) {
333 
334       if (!format)
335          break;
336       if (*format == 0)
337          break;
338 
339       if (*format != '%') {
340          PUT(*format);
341          format++;
342          continue;
343       }
344 
345       saved_format = format;
346       longlong = False;
347       ljustify = False;
348       padchar = ' ';
349       fwidth = 0;
350       format++;
351 
352       if (*format == '-') {
353          format++;
354          ljustify = True;
355       }
356       if (*format == '0') {
357          format++;
358          padchar = '0';
359       }
360       while (*format >= '0' && *format <= '9') {
361          fwidth = fwidth * 10 + (*format - '0');
362          format++;
363       }
364       if (*format == 'l') {
365          format++;
366          if (*format == 'l') {
367             format++;
368            longlong = True;
369          }
370       }
371 
372       switch (*format) {
373          case 's': {
374             HChar* str = va_arg(ap, HChar*);
375             if (str == NULL)
376                str = "(null)";
377             len1 = len3 = 0;
378             len2 = vex_strlen(str);
379             if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
380                                  len3 = ljustify ? fwidth-len2 : 0; }
381             PAD(len1); PUTSTR(str); PAD(len3);
382             break;
383          }
384          case 'c': {
385             HChar c = (HChar)va_arg(ap, int);
386             HChar str[2];
387             str[0] = c;
388             str[1] = 0;
389             len1 = len3 = 0;
390             len2 = vex_strlen(str);
391             if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
392                                  len3 = ljustify ? fwidth-len2 : 0; }
393             PAD(len1); PUTSTR(str); PAD(len3);
394             break;
395          }
396          case 'd': {
397             Long l;
398             if (longlong) {
399                l = va_arg(ap, Long);
400             } else {
401                l = (Long)va_arg(ap, Int);
402             }
403             convert_int(intbuf, l, 10/*base*/, True/*signed*/,
404                                 False/*irrelevant*/);
405             len1 = len3 = 0;
406             len2 = vex_strlen(intbuf);
407             if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
408                                  len3 = ljustify ? fwidth-len2 : 0; }
409             PAD(len1); PUTSTR(intbuf); PAD(len3);
410             break;
411          }
412          case 'u':
413          case 'x':
414          case 'X': {
415             Int   base = *format == 'u' ? 10 : 16;
416             Bool  hexcaps = True; /* *format == 'X'; */
417             ULong l;
418             if (longlong) {
419                l = va_arg(ap, ULong);
420             } else {
421                l = (ULong)va_arg(ap, UInt);
422             }
423             convert_int(intbuf, l, base, False/*unsigned*/, hexcaps);
424             len1 = len3 = 0;
425             len2 = vex_strlen(intbuf);
426             if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
427                                  len3 = ljustify ? fwidth-len2 : 0; }
428             PAD(len1); PUTSTR(intbuf); PAD(len3);
429             break;
430          }
431          case 'p':
432          case 'P': {
433             Bool hexcaps = toBool(*format == 'P');
434             ULong l = Ptr_to_ULong( va_arg(ap, void*) );
435             convert_int(intbuf, l, 16/*base*/, False/*unsigned*/, hexcaps);
436             len1 = len3 = 0;
437             len2 = vex_strlen(intbuf)+2;
438             if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
439                                  len3 = ljustify ? fwidth-len2 : 0; }
440             PAD(len1); PUT('0'); PUT('x'); PUTSTR(intbuf); PAD(len3);
441             break;
442          }
443          case '%': {
444             PUT('%');
445             break;
446          }
447          default:
448             /* no idea what it is.  Print the format literally and
449                move on. */
450             while (saved_format <= format) {
451                PUT(*saved_format);
452                saved_format++;
453             }
454             break;
455       }
456 
457       format++;
458 
459    }
460 
461    return nout;
462 
463 #  undef PUT
464 #  undef PAD
465 #  undef PUTSTR
466 }
467 
468 
469 /* A general replacement for printf().  Note that only low-level
470    debugging info should be sent via here.  The official route is to
471    to use vg_message().  This interface is deprecated.
472 */
473 static HChar myprintf_buf[1000];
474 static Int   n_myprintf_buf;
475 
add_to_myprintf_buf(HChar c)476 static void add_to_myprintf_buf ( HChar c )
477 {
478    Bool emit = toBool(c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/);
479    myprintf_buf[n_myprintf_buf++] = c;
480    myprintf_buf[n_myprintf_buf] = 0;
481    if (emit) {
482       (*vex_log_bytes)( myprintf_buf, vex_strlen(myprintf_buf) );
483       n_myprintf_buf = 0;
484       myprintf_buf[n_myprintf_buf] = 0;
485    }
486 }
487 
vex_printf(HChar * format,...)488 UInt vex_printf ( HChar* format, ... )
489 {
490    UInt ret;
491    va_list vargs;
492    va_start(vargs,format);
493 
494    n_myprintf_buf = 0;
495    myprintf_buf[n_myprintf_buf] = 0;
496    ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs );
497 
498    if (n_myprintf_buf > 0) {
499       (*vex_log_bytes)( myprintf_buf, n_myprintf_buf );
500    }
501 
502    va_end(vargs);
503 
504    return ret;
505 }
506 
507 
508 /* A general replacement for sprintf(). */
509 
510 static HChar *vg_sprintf_ptr;
511 
add_to_vg_sprintf_buf(HChar c)512 static void add_to_vg_sprintf_buf ( HChar c )
513 {
514    *vg_sprintf_ptr++ = c;
515 }
516 
vex_sprintf(HChar * buf,HChar * format,...)517 UInt vex_sprintf ( HChar* buf, HChar *format, ... )
518 {
519    Int ret;
520    va_list vargs;
521 
522    vg_sprintf_ptr = buf;
523 
524    va_start(vargs,format);
525 
526    ret = vprintf_wrk ( add_to_vg_sprintf_buf, format, vargs );
527    add_to_vg_sprintf_buf(0);
528 
529    va_end(vargs);
530 
531    vassert(vex_strlen(buf) == ret);
532    return ret;
533 }
534 
535 
536 /*---------------------------------------------------------------*/
537 /*--- end                                         main_util.c ---*/
538 /*---------------------------------------------------------------*/
539