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
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   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
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 ( 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
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                   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*/
487static HChar myprintf_buf[1000];
488static Int   n_myprintf_buf;
489
490static 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
502UInt 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
524static HChar *vg_sprintf_ptr;
525
526static void add_to_vg_sprintf_buf ( HChar c )
527{
528   *vg_sprintf_ptr++ = c;
529}
530
531UInt 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