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-2013 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    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 
    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 ( const 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                    const 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 { const HChar* _qq = _str; for (; *_qq; _qq++) PUT(*_qq); } \
    332       while (0)
    333 
    334    const 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       if (*format == '*') {
    370          fwidth = va_arg(ap, Int);
    371          format++;
    372       } else {
    373          while (*format >= '0' && *format <= '9') {
    374             fwidth = fwidth * 10 + (*format - '0');
    375             format++;
    376          }
    377       }
    378       if (*format == 'l') {
    379          format++;
    380          if (*format == 'l') {
    381             format++;
    382            longlong = True;
    383          }
    384       }
    385 
    386       switch (*format) {
    387          case 's': {
    388             const HChar* str = va_arg(ap, HChar*);
    389             if (str == NULL)
    390                str = "(null)";
    391             len1 = len3 = 0;
    392             len2 = vex_strlen(str);
    393             if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
    394                                  len3 = ljustify ? fwidth-len2 : 0; }
    395             PAD(len1); PUTSTR(str); PAD(len3);
    396             break;
    397          }
    398          case 'c': {
    399             HChar c = (HChar)va_arg(ap, int);
    400             HChar str[2];
    401             str[0] = c;
    402             str[1] = 0;
    403             len1 = len3 = 0;
    404             len2 = vex_strlen(str);
    405             if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
    406                                  len3 = ljustify ? fwidth-len2 : 0; }
    407             PAD(len1); PUTSTR(str); PAD(len3);
    408             break;
    409          }
    410          case 'd': {
    411             Long l;
    412             if (longlong) {
    413                l = va_arg(ap, Long);
    414             } else {
    415                l = (Long)va_arg(ap, Int);
    416             }
    417             convert_int(intbuf, l, 10/*base*/, True/*signed*/,
    418                                 False/*irrelevant*/);
    419             len1 = len3 = 0;
    420             len2 = vex_strlen(intbuf);
    421             if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
    422                                  len3 = ljustify ? fwidth-len2 : 0; }
    423             PAD(len1); PUTSTR(intbuf); PAD(len3);
    424             break;
    425          }
    426          case 'u':
    427          case 'x':
    428          case 'X': {
    429             Int   base = *format == 'u' ? 10 : 16;
    430             Bool  hexcaps = True; /* *format == 'X'; */
    431             ULong l;
    432             if (longlong) {
    433                l = va_arg(ap, ULong);
    434             } else {
    435                l = (ULong)va_arg(ap, UInt);
    436             }
    437             convert_int(intbuf, l, base, False/*unsigned*/, hexcaps);
    438             len1 = len3 = 0;
    439             len2 = vex_strlen(intbuf);
    440             if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
    441                                  len3 = ljustify ? fwidth-len2 : 0; }
    442             PAD(len1); PUTSTR(intbuf); PAD(len3);
    443             break;
    444          }
    445          case 'p':
    446          case 'P': {
    447             Bool hexcaps = toBool(*format == 'P');
    448             ULong l = Ptr_to_ULong( va_arg(ap, void*) );
    449             convert_int(intbuf, l, 16/*base*/, False/*unsigned*/, hexcaps);
    450             len1 = len3 = 0;
    451             len2 = vex_strlen(intbuf)+2;
    452             if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2;
    453                                  len3 = ljustify ? fwidth-len2 : 0; }
    454             PAD(len1); PUT('0'); PUT('x'); PUTSTR(intbuf); PAD(len3);
    455             break;
    456          }
    457          case '%': {
    458             PUT('%');
    459             break;
    460          }
    461          default:
    462             /* no idea what it is.  Print the format literally and
    463                move on. */
    464             while (saved_format <= format) {
    465                PUT(*saved_format);
    466                saved_format++;
    467             }
    468             break;
    469       }
    470 
    471       format++;
    472 
    473    }
    474 
    475    return nout;
    476 
    477 #  undef PUT
    478 #  undef PAD
    479 #  undef PUTSTR
    480 }
    481 
    482 
    483 /* A general replacement for printf().  Note that only low-level
    484    debugging info should be sent via here.  The official route is to
    485    to use vg_message().  This interface is deprecated.
    486 */
    487 static HChar myprintf_buf[1000];
    488 static Int   n_myprintf_buf;
    489 
    490 static void add_to_myprintf_buf ( HChar c )
    491 {
    492    Bool emit = toBool(c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/);
    493    myprintf_buf[n_myprintf_buf++] = c;
    494    myprintf_buf[n_myprintf_buf] = 0;
    495    if (emit) {
    496       (*vex_log_bytes)( myprintf_buf, vex_strlen(myprintf_buf) );
    497       n_myprintf_buf = 0;
    498       myprintf_buf[n_myprintf_buf] = 0;
    499    }
    500 }
    501 
    502 UInt vex_printf ( const HChar* format, ... )
    503 {
    504    UInt ret;
    505    va_list vargs;
    506    va_start(vargs,format);
    507 
    508    n_myprintf_buf = 0;
    509    myprintf_buf[n_myprintf_buf] = 0;
    510    ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs );
    511 
    512    if (n_myprintf_buf > 0) {
    513       (*vex_log_bytes)( myprintf_buf, n_myprintf_buf );
    514    }
    515 
    516    va_end(vargs);
    517 
    518    return ret;
    519 }
    520 
    521 
    522 /* A general replacement for sprintf(). */
    523 
    524 static HChar *vg_sprintf_ptr;
    525 
    526 static void add_to_vg_sprintf_buf ( HChar c )
    527 {
    528    *vg_sprintf_ptr++ = c;
    529 }
    530 
    531 UInt vex_sprintf ( HChar* buf, const HChar *format, ... )
    532 {
    533    Int ret;
    534    va_list vargs;
    535 
    536    vg_sprintf_ptr = buf;
    537 
    538    va_start(vargs,format);
    539 
    540    ret = vprintf_wrk ( add_to_vg_sprintf_buf, format, vargs );
    541    add_to_vg_sprintf_buf(0);
    542 
    543    va_end(vargs);
    544 
    545    vassert(vex_strlen(buf) == ret);
    546    return ret;
    547 }
    548 
    549 
    550 /*---------------------------------------------------------------*/
    551 /*--- end                                         main_util.c ---*/
    552 /*---------------------------------------------------------------*/
    553