Home | History | Annotate | Download | only in priv
      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 (at) 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 
     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 
    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 
    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))
    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 
    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 
    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))
    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))
    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 
    238 static Int vex_strlen ( const HChar* str )
    239 {
    240    Int i = 0;
    241    while (str[i] != 0) i++;
    242    return i;
    243 }
    244 
    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
    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
    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 
    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 
    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 
    512 static void add_to_vg_sprintf_buf ( HChar c )
    513 {
    514    *vg_sprintf_ptr++ = c;
    515 }
    516 
    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