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