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@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
56static HChar  temporary[N_TEMPORARY_BYTES] __attribute__((aligned(8)));
57static HChar* temporary_first = &temporary[0];
58static HChar* temporary_curr  = &temporary[0];
59static HChar* temporary_last  = &temporary[N_TEMPORARY_BYTES-1];
60
61static ULong  temporary_bytes_allocd_TOT = 0;
62
63#define N_PERMANENT_BYTES 10000
64
65static HChar  permanent[N_PERMANENT_BYTES] __attribute__((aligned(8)));
66static HChar* permanent_first = &permanent[0];
67static HChar* permanent_curr  = &permanent[0];
68static HChar* permanent_last  = &permanent[N_PERMANENT_BYTES-1];
69
70static VexAllocMode mode = VexAllocModeTEMP;
71
72void 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
112void 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
147VexAllocMode vexGetAllocMode ( void )
148{
149   return mode;
150}
151
152/* Visible to library client, unfortunately. */
153
154HChar* private_LibVEX_alloc_first = &temporary[0];
155HChar* private_LibVEX_alloc_curr  = &temporary[0];
156HChar* private_LibVEX_alloc_last  = &temporary[N_TEMPORARY_BYTES-1];
157
158__attribute__((noreturn))
159void 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
175void 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
200void 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))
214void 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))
223void 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
238Int vex_strlen ( const HChar* str )
239{
240   Int i = 0;
241   while (str[i] != 0) i++;
242   return i;
243}
244
245Bool 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
257void 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. */
269static
270void 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. */
317static
318UInt 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*/
482static HChar myprintf_buf[1000];
483static Int   n_myprintf_buf;
484
485static 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
497UInt 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
519static HChar *vg_sprintf_ptr;
520
521static void add_to_vg_sprintf_buf ( HChar c )
522{
523   *vg_sprintf_ptr++ = c;
524}
525
526UInt 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