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-2012 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 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 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
    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
    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 
    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 
    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 
    521 static void add_to_vg_sprintf_buf ( HChar c )
    522 {
    523    *vg_sprintf_ptr++ = c;
    524 }
    525 
    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