main_util.c revision 9bea4c13fca0e3bb4b719dcb3ed63d47d479294e
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@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
238static Int 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
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. */
260static
261void 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. */
308static
309UInt 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*/
473static HChar myprintf_buf[1000];
474static Int   n_myprintf_buf;
475
476static 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
488UInt 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
510static HChar *vg_sprintf_ptr;
511
512static void add_to_vg_sprintf_buf ( HChar c )
513{
514   *vg_sprintf_ptr++ = c;
515}
516
517UInt 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