31652304f19dfb249165dfa1405e6701237b68f0
[sdk/tools/upstream/valgrind.git] / VEX / priv / main_util.c
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@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 /*---------------------------------------------------------------*/