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 (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 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 /*---------------------------------------------------------------*/ 553