1 2 /*--------------------------------------------------------------------*/ 3 /*--- Ptrcheck: a pointer-use checker. ---*/ 4 /*--- This file checks stack and global array accesses. ---*/ 5 /*--- sg_main.c ---*/ 6 /*--------------------------------------------------------------------*/ 7 8 /* 9 This file is part of Ptrcheck, a Valgrind tool for checking pointer 10 use in programs. 11 12 Copyright (C) 2008-2017 OpenWorks Ltd 13 info (at) open-works.co.uk 14 15 This program is free software; you can redistribute it and/or 16 modify it under the terms of the GNU General Public License as 17 published by the Free Software Foundation; either version 2 of the 18 License, or (at your option) any later version. 19 20 This program is distributed in the hope that it will be useful, but 21 WITHOUT ANY WARRANTY; without even the implied warranty of 22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 General Public License for more details. 24 25 You should have received a copy of the GNU General Public License 26 along with this program; if not, write to the Free Software 27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 28 02111-1307, USA. 29 30 The GNU General Public License is contained in the file COPYING. 31 32 Neither the names of the U.S. Department of Energy nor the 33 University of California nor the names of its contributors may be 34 used to endorse or promote products derived from this software 35 without prior written permission. 36 */ 37 38 #include "pub_tool_basics.h" 39 #include "pub_tool_libcbase.h" 40 #include "pub_tool_libcassert.h" 41 #include "pub_tool_libcprint.h" 42 #include "pub_tool_tooliface.h" 43 #include "pub_tool_wordfm.h" 44 #include "pub_tool_xarray.h" 45 #include "pub_tool_threadstate.h" 46 #include "pub_tool_mallocfree.h" 47 #include "pub_tool_machine.h" 48 #include "pub_tool_debuginfo.h" 49 #include "pub_tool_options.h" 50 51 #include "pc_common.h" 52 53 #include "sg_main.h" // self 54 55 56 static 57 void preen_global_Invars ( Addr a, SizeT len ); /*fwds*/ 58 59 60 ////////////////////////////////////////////////////////////// 61 // // 62 // Basic Stuff // 63 // // 64 ////////////////////////////////////////////////////////////// 65 66 static inline Bool is_sane_TId ( ThreadId tid ) 67 { 68 return tid >= 0 && tid < VG_N_THREADS 69 && tid != VG_INVALID_THREADID; 70 } 71 72 static void* sg_malloc ( const HChar* cc, SizeT n ) { 73 void* p; 74 tl_assert(n > 0); 75 p = VG_(malloc)( cc, n ); 76 return p; 77 } 78 79 static void sg_free ( void* p ) { 80 tl_assert(p); 81 VG_(free)(p); 82 } 83 84 85 /* Compare the intervals [a1,a1+n1) and [a2,a2+n2). Return -1 if the 86 first interval is lower, 1 if the first interval is higher, and 0 87 if there is any overlap. Redundant paranoia with casting is there 88 following what looked distinctly like a bug in gcc-4.1.2, in which 89 some of the comparisons were done signedly instead of 90 unsignedly. */ 91 inline 92 static Word cmp_nonempty_intervals ( Addr a1, SizeT n1, 93 Addr a2, SizeT n2 ) { 94 UWord a1w = (UWord)a1; 95 UWord n1w = (UWord)n1; 96 UWord a2w = (UWord)a2; 97 UWord n2w = (UWord)n2; 98 tl_assert(n1w > 0 && n2w > 0); 99 if (a1w + n1w <= a2w) return -1L; 100 if (a2w + n2w <= a1w) return 1L; 101 return 0; 102 } 103 104 /* Return true iff [aSmall,aSmall+nSmall) is entirely contained 105 within [aBig,aBig+nBig). */ 106 inline 107 static Bool is_subinterval_of ( Addr aBig, SizeT nBig, 108 Addr aSmall, SizeT nSmall ) { 109 tl_assert(nBig > 0 && nSmall > 0); 110 return aBig <= aSmall && aSmall + nSmall <= aBig + nBig; 111 } 112 113 inline 114 static Addr Addr__min ( Addr a1, Addr a2 ) { 115 return a1 < a2 ? a1 : a2; 116 } 117 118 inline 119 static Addr Addr__max ( Addr a1, Addr a2 ) { 120 return a1 < a2 ? a2 : a1; 121 } 122 123 124 ////////////////////////////////////////////////////////////// 125 // // 126 // StackBlocks Persistent Cache // 127 // // 128 ////////////////////////////////////////////////////////////// 129 130 /* We maintain a set of XArray* of StackBlocks. These are never 131 freed. When a new StackBlock vector is acquired from 132 VG_(di_get_local_blocks_at_ip), we compare it to the existing set. 133 If not present, it is added. If present, the just-acquired one is 134 freed and the copy used. 135 136 This simplifies storage management elsewhere. It allows us to 137 assume that a pointer to an XArray* of StackBlock is valid forever. 138 It also means there are no duplicates anywhere, which could be 139 important from a space point of view for programs that generate a 140 lot of translations, or where translations are frequently discarded 141 and re-made. 142 143 Note that we normalise the arrays by sorting the elements according 144 to an arbitrary total order, so as to avoid the situation that two 145 vectors describe the same set of variables but are not structurally 146 identical. */ 147 148 static inline Bool StackBlock__sane ( const StackBlock* fb ) 149 { 150 if (fb->name[ sizeof(fb->name)-1 ] != 0) 151 return False; 152 if (fb->spRel != False && fb->spRel != True) 153 return False; 154 if (fb->isVec != False && fb->isVec != True) 155 return False; 156 return True; 157 } 158 159 /* Generate an arbitrary total ordering on StackBlocks. */ 160 static Word StackBlock__cmp ( const StackBlock* fb1, const StackBlock* fb2 ) 161 { 162 Word r; 163 tl_assert(StackBlock__sane(fb1)); 164 tl_assert(StackBlock__sane(fb2)); 165 /* Hopefully the .base test hits most of the time. For the blocks 166 associated with any particular instruction, if the .base values 167 are the same then probably it doesn't make sense for the other 168 fields to be different. But this is supposed to be a completely 169 general structural total order, so we have to compare everything 170 anyway. */ 171 if (fb1->base < fb2->base) return -1; 172 if (fb1->base > fb2->base) return 1; 173 /* compare sizes */ 174 if (fb1->szB < fb2->szB) return -1; 175 if (fb1->szB > fb2->szB) return 1; 176 /* compare sp/fp flag */ 177 if (fb1->spRel < fb2->spRel) return -1; 178 if (fb1->spRel > fb2->spRel) return 1; 179 /* compare is/is-not array-typed flag */ 180 if (fb1->isVec < fb2->isVec) return -1; 181 if (fb1->isVec > fb2->isVec) return 1; 182 /* compare the name */ 183 r = (Word)VG_(strcmp)(fb1->name, fb2->name); 184 return r; 185 } 186 187 /* Returns True if all fields except .szB are the same. szBs may or 188 may not be the same; they are simply not consulted. */ 189 static Bool StackBlock__all_fields_except_szB_are_equal ( 190 StackBlock* fb1, 191 StackBlock* fb2 192 ) 193 { 194 tl_assert(StackBlock__sane(fb1)); 195 tl_assert(StackBlock__sane(fb2)); 196 return fb1->base == fb2->base 197 && fb1->spRel == fb2->spRel 198 && fb1->isVec == fb2->isVec 199 && 0 == VG_(strcmp)(fb1->name, fb2->name); 200 } 201 202 203 /* Generate an arbitrary total ordering on vectors of StackBlocks. */ 204 static Word StackBlocks__cmp ( XArray* fb1s, XArray* fb2s ) 205 { 206 Word i, r, n1, n2; 207 n1 = VG_(sizeXA)( fb1s ); 208 n2 = VG_(sizeXA)( fb2s ); 209 if (n1 < n2) return -1; 210 if (n1 > n2) return 1; 211 for (i = 0; i < n1; i++) { 212 StackBlock *fb1, *fb2; 213 fb1 = VG_(indexXA)( fb1s, i ); 214 fb2 = VG_(indexXA)( fb2s, i ); 215 r = StackBlock__cmp( fb1, fb2 ); 216 if (r != 0) return r; 217 } 218 tl_assert(i == n1 && i == n2); 219 return 0; 220 } 221 222 static void pp_StackBlocks ( XArray* sbs ) 223 { 224 Word i, n = VG_(sizeXA)( sbs ); 225 VG_(message)(Vg_DebugMsg, "<<< STACKBLOCKS\n" ); 226 for (i = 0; i < n; i++) { 227 StackBlock* sb = (StackBlock*)VG_(indexXA)( sbs, i ); 228 VG_(message)(Vg_DebugMsg, 229 " StackBlock{ off %ld szB %lu spRel:%c isVec:%c \"%s\" }\n", 230 sb->base, sb->szB, sb->spRel ? 'Y' : 'N', 231 sb->isVec ? 'Y' : 'N', &sb->name[0] 232 ); 233 } 234 VG_(message)(Vg_DebugMsg, ">>> STACKBLOCKS\n" ); 235 } 236 237 238 /* ---------- The StackBlock vector cache ---------- */ 239 240 static WordFM* /* XArray* of StackBlock -> nothing */ 241 frameBlocks_set = NULL; 242 243 static void init_StackBlocks_set ( void ) 244 { 245 tl_assert(!frameBlocks_set); 246 frameBlocks_set 247 = VG_(newFM)( sg_malloc, "di.sg_main.iSBs.1", sg_free, 248 (Word(*)(UWord,UWord))StackBlocks__cmp ); 249 tl_assert(frameBlocks_set); 250 } 251 252 /* Find the given StackBlock-vector in our collection thereof. If 253 found, deallocate the supplied one, and return the address of the 254 copy. If not found, add the supplied one to our collection and 255 return its address. */ 256 static XArray* /* of StackBlock */ 257 StackBlocks__find_and_dealloc__or_add 258 ( XArray* /* of StackBlock */ orig ) 259 { 260 UWord key, val; 261 262 /* First, normalise, as per comments above. */ 263 VG_(setCmpFnXA)( orig, (XACmpFn_t)StackBlock__cmp ); 264 VG_(sortXA)( orig ); 265 266 /* Now get rid of any exact duplicates. */ 267 nuke_dups: 268 { Word r, w, nEQ, n = VG_(sizeXA)( orig ); 269 if (n >= 2) { 270 w = 0; 271 nEQ = 0; 272 for (r = 0; r < n; r++) { 273 if (r+1 < n) { 274 StackBlock* pR0 = VG_(indexXA)( orig, r+0 ); 275 StackBlock* pR1 = VG_(indexXA)( orig, r+1 ); 276 Word c = StackBlock__cmp(pR0,pR1); 277 tl_assert(c == -1 || c == 0); 278 if (c == 0) { nEQ++; continue; } 279 } 280 if (w != r) { 281 StackBlock* pW = VG_(indexXA)( orig, w ); 282 StackBlock* pR = VG_(indexXA)( orig, r ); 283 *pW = *pR; 284 } 285 w++; 286 } 287 tl_assert(r == n); 288 tl_assert(w + nEQ == n); 289 if (w < n) { 290 VG_(dropTailXA)( orig, n-w ); 291 } 292 if (0) VG_(printf)("delta %ld\n", n-w); 293 } 294 } 295 296 /* Deal with the following strangeness, where two otherwise 297 identical blocks are claimed to have different sizes. In which 298 case we use the larger size. */ 299 /* StackBlock{ off 16 szB 66 spRel:Y isVec:Y "sz" } 300 StackBlock{ off 16 szB 130 spRel:Y isVec:Y "sz" } 301 StackBlock{ off 208 szB 16 spRel:Y isVec:Y "ar" } 302 */ 303 { Word i, n = VG_(sizeXA)( orig ); 304 if (n >= 2) { 305 for (i = 0; i < n-1; i++) { 306 StackBlock* sb0 = VG_(indexXA)( orig, i+0 ); 307 StackBlock* sb1 = VG_(indexXA)( orig, i+1 ); 308 if (StackBlock__all_fields_except_szB_are_equal(sb0, sb1)) { 309 /* They can't be identical because the previous tidying 310 pass would have removed the duplicates. And they 311 can't be > because the earlier sorting pass would 312 have ordered otherwise-identical descriptors 313 according to < on .szB fields. Hence: */ 314 tl_assert(sb0->szB < sb1->szB); 315 sb0->szB = sb1->szB; 316 /* This makes the blocks identical, at the size of the 317 larger one. Rather than go to all the hassle of 318 sliding the rest down, simply go back to the 319 remove-duplicates stage. The assertion guarantees 320 that we eventually make progress, since the rm-dups 321 stage will get rid of one of the blocks. This is 322 expected to happen only exceedingly rarely. */ 323 tl_assert(StackBlock__cmp(sb0,sb1) == 0); 324 goto nuke_dups; 325 } 326 } 327 } 328 } 329 330 /* If there are any blocks which overlap and have the same 331 fpRel-ness, junk the whole descriptor; it's obviously bogus. 332 Icc11 certainly generates bogus info from time to time. 333 334 This check is pretty weak; really we ought to have a stronger 335 sanity check. */ 336 { Word i, n = VG_(sizeXA)( orig ); 337 static Int moans = 3; 338 for (i = 0; i < n-1; i++) { 339 StackBlock* sb1 = (StackBlock*)VG_(indexXA)( orig, i ); 340 StackBlock* sb2 = (StackBlock*)VG_(indexXA)( orig, i+1 ); 341 if (sb1->spRel == sb2->spRel 342 && (sb1->base >= sb2->base 343 || sb1->base + sb1->szB > sb2->base)) { 344 if (moans > 0 && !VG_(clo_xml)) { 345 moans--; 346 VG_(message)(Vg_UserMsg, "Warning: bogus DWARF3 info: " 347 "overlapping stack blocks\n"); 348 if (VG_(clo_verbosity) >= 2) 349 pp_StackBlocks(orig); 350 if (moans == 0) 351 VG_(message)(Vg_UserMsg, "Further instances of this " 352 "message will not be shown\n" ); 353 } 354 VG_(dropTailXA)( orig, VG_(sizeXA)( orig )); 355 break; 356 } 357 } 358 } 359 360 /* Now, do we have it already? */ 361 if (VG_(lookupFM)( frameBlocks_set, &key, &val, (UWord)orig )) { 362 /* yes */ 363 XArray* res; 364 tl_assert(val == 0); 365 tl_assert(key != (UWord)orig); 366 VG_(deleteXA)(orig); 367 res = (XArray*)key; 368 return res; 369 } else { 370 /* no */ 371 VG_(addToFM)( frameBlocks_set, (UWord)orig, 0 ); 372 return orig; 373 } 374 } 375 376 /* Top level function for getting the StackBlock vector for a given 377 instruction. It is guaranteed that the returned pointer will be 378 valid for the entire rest of the run, and also that the addresses 379 of the individual elements of the array will not change. */ 380 381 static XArray* /* of StackBlock */ get_StackBlocks_for_IP ( Addr ip ) 382 { 383 XArray* blocks = VG_(di_get_stack_blocks_at_ip)( ip, True/*arrays only*/ ); 384 tl_assert(blocks); 385 return StackBlocks__find_and_dealloc__or_add( blocks ); 386 } 387 388 389 ////////////////////////////////////////////////////////////// 390 // // 391 // GlobalBlocks Persistent Cache // 392 // // 393 ////////////////////////////////////////////////////////////// 394 395 /* Generate an arbitrary total ordering on GlobalBlocks. */ 396 static Word GlobalBlock__cmp ( GlobalBlock* gb1, GlobalBlock* gb2 ) 397 { 398 Word r; 399 /* compare addrs */ 400 if (gb1->addr < gb2->addr) return -1; 401 if (gb1->addr > gb2->addr) return 1; 402 /* compare sizes */ 403 if (gb1->szB < gb2->szB) return -1; 404 if (gb1->szB > gb2->szB) return 1; 405 /* compare is/is-not array-typed flag */ 406 if (gb1->isVec < gb2->isVec) return -1; 407 if (gb1->isVec > gb2->isVec) return 1; 408 /* compare the name */ 409 r = (Word)VG_(strcmp)(gb1->name, gb2->name); 410 if (r != 0) return r; 411 /* compare the soname */ 412 r = (Word)VG_(strcmp)(gb1->soname, gb2->soname); 413 return r; 414 } 415 416 static WordFM* /* GlobalBlock* -> nothing */ 417 globalBlock_set = NULL; 418 419 static void init_GlobalBlock_set ( void ) 420 { 421 tl_assert(!globalBlock_set); 422 globalBlock_set 423 = VG_(newFM)( sg_malloc, "di.sg_main.iGBs.1", sg_free, 424 (Word(*)(UWord,UWord))GlobalBlock__cmp ); 425 tl_assert(globalBlock_set); 426 } 427 428 429 /* Top level function for making GlobalBlocks persistent. Call here 430 with a non-persistent version, and the returned one is guaranteed 431 to be valid for the entire rest of the run. The supplied one is 432 copied, not stored, so can be freed after the call. */ 433 434 static GlobalBlock* get_persistent_GlobalBlock ( GlobalBlock* orig ) 435 { 436 UWord key, val; 437 /* Now, do we have it already? */ 438 if (VG_(lookupFM)( globalBlock_set, &key, &val, (UWord)orig )) { 439 /* yes, return the copy */ 440 GlobalBlock* res; 441 tl_assert(val == 0); 442 res = (GlobalBlock*)key; 443 tl_assert(res != orig); 444 return res; 445 } else { 446 /* no. clone it, store the clone and return the clone's 447 address. */ 448 GlobalBlock* clone = sg_malloc( "di.sg_main.gpGB.1", 449 sizeof(GlobalBlock) ); 450 tl_assert(clone); 451 *clone = *orig; 452 VG_(addToFM)( globalBlock_set, (UWord)clone, 0 ); 453 return clone; 454 } 455 } 456 457 458 ////////////////////////////////////////////////////////////// 459 // // 460 // Interval tree of StackTreeBlock // 461 // // 462 ////////////////////////////////////////////////////////////// 463 464 /* A node in a stack interval tree. Zero length intervals (.szB == 0) 465 are not allowed. 466 467 A stack interval tree is a (WordFM StackTreeNode* void). There is 468 one stack interval tree for each thread. 469 */ 470 typedef 471 struct { 472 Addr addr; 473 SizeT szB; /* copied from .descr->szB */ 474 StackBlock* descr; /* it's an instance of this block */ 475 UWord depth; /* depth of stack at time block was pushed */ 476 } 477 StackTreeNode; 478 479 static void pp_StackTree ( WordFM* sitree, const HChar* who ) 480 { 481 UWord keyW, valW; 482 VG_(printf)("<<< BEGIN pp_StackTree %s\n", who ); 483 VG_(initIterFM)( sitree ); 484 while (VG_(nextIterFM)( sitree, &keyW, &valW )) { 485 StackTreeNode* nd = (StackTreeNode*)keyW; 486 VG_(printf)(" [%#lx,+%lu) descr=%p %s %lu\n", nd->addr, nd->szB, 487 nd->descr, nd->descr->name, nd->descr->szB); 488 } 489 VG_(printf)(">>> END pp_StackTree %s\n", who ); 490 } 491 492 /* Interval comparison function for StackTreeNode */ 493 static Word cmp_intervals_StackTreeNode ( StackTreeNode* sn1, 494 StackTreeNode* sn2 ) 495 { 496 return cmp_nonempty_intervals(sn1->addr, sn1->szB, 497 sn2->addr, sn2->szB); 498 } 499 500 /* Find the node holding 'a', if any. */ 501 static StackTreeNode* find_StackTreeNode ( WordFM* sitree, Addr a ) 502 { 503 UWord keyW, valW; 504 StackTreeNode key; 505 tl_assert(sitree); 506 key.addr = a; 507 key.szB = 1; 508 if (VG_(lookupFM)( sitree, &keyW, &valW, (UWord)&key )) { 509 StackTreeNode* res = (StackTreeNode*)keyW; 510 tl_assert(valW == 0); 511 tl_assert(res != &key); 512 return res; 513 } else { 514 return NULL; 515 } 516 } 517 518 /* Note that the supplied XArray of FrameBlock must have been 519 made persistent already. */ 520 __attribute__((noinline)) 521 static void add_blocks_to_StackTree ( 522 /*MOD*/WordFM* sitree, 523 XArray* /* FrameBlock */ descrs, 524 XArray* /* Addr */ bases, 525 UWord depth 526 ) 527 { 528 Bool debug = (Bool)0; 529 Word i, nDescrs, nBases; 530 531 nDescrs = VG_(sizeXA)( descrs ), 532 nBases = VG_(sizeXA)( bases ); 533 tl_assert(nDescrs == nBases); 534 535 if (nDescrs == 0) return; 536 537 tl_assert(sitree); 538 if (debug) { 539 VG_(printf)("\ndepth = %lu\n", depth); 540 pp_StackTree( sitree, "add_blocks_to_StackTree-pre" ); 541 pp_StackBlocks(descrs); 542 } 543 544 for (i = 0; i < nDescrs; i++) { 545 Bool already_present; 546 StackTreeNode* nyu; 547 Addr addr = *(Addr*)VG_(indexXA)( bases, i ); 548 StackBlock* descr = (StackBlock*)VG_(indexXA)( descrs, i ); 549 tl_assert(descr->szB > 0); 550 nyu = sg_malloc( "di.sg_main.abtST.1", sizeof(StackTreeNode) ); 551 nyu->addr = addr; 552 nyu->szB = descr->szB; 553 nyu->descr = descr; 554 nyu->depth = depth; 555 if (debug) VG_(printf)("ADD %#lx %lu\n", addr, descr->szB); 556 already_present = VG_(addToFM)( sitree, (UWord)nyu, 0 ); 557 /* The interval can't already be there; else we have 558 overlapping stack blocks. */ 559 tl_assert(!already_present); 560 if (debug) { 561 pp_StackTree( sitree, "add_blocks_to_StackTree-step" ); 562 } 563 } 564 if (debug) { 565 pp_StackTree( sitree, "add_blocks_to_StackTree-post" ); 566 VG_(printf)("\n"); 567 } 568 } 569 570 static void del_blocks_from_StackTree ( /*MOD*/WordFM* sitree, 571 XArray* /* Addr */ bases ) 572 { 573 UWord oldK, oldV; 574 Word i, nBases = VG_(sizeXA)( bases ); 575 for (i = 0; i < nBases; i++) { 576 Bool b; 577 Addr addr = *(Addr*)VG_(indexXA)( bases, i ); 578 StackTreeNode* nd = find_StackTreeNode(sitree, addr); 579 /* The interval must be there; we added it earlier when 580 the associated frame was created. */ 581 tl_assert(nd); 582 b = VG_(delFromFM)( sitree, &oldK, &oldV, (UWord)nd ); 583 /* we just found the block! */ 584 tl_assert(b); 585 tl_assert(oldV == 0); 586 tl_assert(nd == (StackTreeNode*)oldK); 587 sg_free(nd); 588 } 589 } 590 591 592 static void delete_StackTree__kFin ( UWord keyW ) { 593 StackTreeNode* nd = (StackTreeNode*)keyW; 594 tl_assert(nd); 595 sg_free(nd); 596 } 597 static void delete_StackTree__vFin ( UWord valW ) { 598 tl_assert(valW == 0); 599 } 600 static void delete_StackTree ( WordFM* sitree ) 601 { 602 VG_(deleteFM)( sitree, 603 delete_StackTree__kFin, delete_StackTree__vFin ); 604 } 605 606 static WordFM* new_StackTree ( void ) { 607 return VG_(newFM)( sg_malloc, "di.sg_main.nST.1", sg_free, 608 (Word(*)(UWord,UWord))cmp_intervals_StackTreeNode ); 609 } 610 611 612 ////////////////////////////////////////////////////////////// 613 // // 614 // Interval tree of GlobalTreeBlock // 615 // // 616 ////////////////////////////////////////////////////////////// 617 618 /* A node in a global interval tree. Zero length intervals 619 (.szB == 0) are not allowed. 620 621 A global interval tree is a (WordFM GlobalTreeNode* void). There 622 is one global interval tree for the entire process. 623 */ 624 typedef 625 struct { 626 Addr addr; /* copied from .descr->addr */ 627 SizeT szB; /* copied from .descr->szB */ 628 GlobalBlock* descr; /* it's this block */ 629 } 630 GlobalTreeNode; 631 632 static void GlobalTreeNode__pp ( GlobalTreeNode* nd ) { 633 tl_assert(nd->descr); 634 VG_(printf)("GTNode [%#lx,+%lu) %s", 635 nd->addr, nd->szB, nd->descr->name); 636 } 637 638 static void GlobalTree__pp ( WordFM* /* of (GlobalTreeNode,void) */ gitree, 639 const HChar* who ) 640 { 641 UWord keyW, valW; 642 GlobalTreeNode* nd; 643 VG_(printf)("<<< GlobalBlockTree (%s)\n", who); 644 VG_(initIterFM)( gitree ); 645 while (VG_(nextIterFM)( gitree, &keyW, &valW )) { 646 tl_assert(valW == 0); 647 nd = (GlobalTreeNode*)keyW; 648 VG_(printf)(" "); 649 GlobalTreeNode__pp(nd); 650 VG_(printf)("\n"); 651 } 652 VG_(doneIterFM)( gitree ); 653 VG_(printf)(">>>\n"); 654 } 655 656 /* Interval comparison function for GlobalTreeNode */ 657 static Word cmp_intervals_GlobalTreeNode ( GlobalTreeNode* gn1, 658 GlobalTreeNode* gn2 ) 659 { 660 return cmp_nonempty_intervals( gn1->addr, gn1->szB, 661 gn2->addr, gn2->szB ); 662 } 663 664 /* Find the node holding 'a', if any. */ 665 static GlobalTreeNode* find_GlobalTreeNode ( WordFM* gitree, Addr a ) 666 { 667 UWord keyW, valW; 668 GlobalTreeNode key; 669 key.addr = a; 670 key.szB = 1; 671 if (VG_(lookupFM)( gitree, &keyW, &valW, (UWord)&key )) { 672 GlobalTreeNode* res = (GlobalTreeNode*)keyW; 673 tl_assert(valW == 0); 674 tl_assert(res != &key); 675 return res; 676 } else { 677 return NULL; 678 } 679 } 680 681 /* Note that the supplied GlobalBlock must have been made persistent 682 already. */ 683 static void add_block_to_GlobalTree ( 684 /*MOD*/WordFM* gitree, 685 GlobalBlock* descr 686 ) 687 { 688 Bool already_present; 689 GlobalTreeNode *nyu, *nd; 690 UWord keyW, valW; 691 static Int moans = 3; 692 693 tl_assert(descr->szB > 0); 694 nyu = sg_malloc( "di.sg_main.abtG.1", sizeof(GlobalTreeNode) ); 695 nyu->addr = descr->addr; 696 nyu->szB = descr->szB; 697 nyu->descr = descr; 698 699 /* Basically it's an error to add a global block to the tree that 700 is already in the tree. However, detect and ignore attempts to 701 insert exact duplicates; they do appear for some reason 702 (possible a bug in m_debuginfo?) */ 703 already_present = VG_(lookupFM)( gitree, &keyW, &valW, (UWord)nyu ); 704 if (already_present) { 705 tl_assert(valW == 0); 706 nd = (GlobalTreeNode*)keyW; 707 tl_assert(nd); 708 tl_assert(nd != nyu); 709 tl_assert(nd->descr); 710 tl_assert(nyu->descr); 711 if (nd->addr == nyu->addr && nd->szB == nyu->szB 712 /* && 0 == VG_(strcmp)(nd->descr->name, nyu->descr->name) */ 713 /* Although it seems reasonable to demand that duplicate 714 blocks have identical names, that is too strict. For 715 example, reading debuginfo from glibc produces two 716 otherwise identical blocks with names "tzname" and 717 "__tzname". A constraint of the form "must be identical, 718 or one must be a substring of the other" would fix that. 719 However, such trickery is scuppered by the fact that we 720 truncate all variable names to 15 characters to make 721 storage management simpler, hence giving pairs like 722 "__EI___pthread_" (truncated) vs "__pthread_keys". So 723 it's simplest just to skip the name comparison 724 completely. */ 725 && 0 == VG_(strcmp)(nd->descr->soname, nyu->descr->soname)) { 726 /* exact duplicate; ignore it */ 727 sg_free(nyu); 728 return; 729 } 730 /* else fall through; the assertion below will catch it */ 731 } 732 733 already_present = VG_(addToFM)( gitree, (UWord)nyu, 0 ); 734 /* The interval can't already be there; else we have 735 overlapping global blocks. */ 736 /* Unfortunately (25 Jan 09) at least icc11 has been seen to 737 generate overlapping block descriptions in the Dwarf3; clearly 738 bogus. */ 739 if (already_present && moans > 0 && !VG_(clo_xml)) { 740 moans--; 741 VG_(message)(Vg_UserMsg, "Warning: bogus DWARF3 info: " 742 "overlapping global blocks\n"); 743 if (VG_(clo_verbosity) >= 2) { 744 GlobalTree__pp( gitree, 745 "add_block_to_GlobalTree: non-exact duplicate" ); 746 VG_(printf)("Overlapping block: "); 747 GlobalTreeNode__pp(nyu); 748 VG_(printf)("\n"); 749 } 750 if (moans == 0) 751 VG_(message)(Vg_UserMsg, "Further instances of this " 752 "message will not be shown\n" ); 753 } 754 /* tl_assert(!already_present); */ 755 } 756 757 static Bool del_GlobalTree_range ( /*MOD*/WordFM* gitree, 758 Addr a, SizeT szB ) 759 { 760 /* One easy way to do this: look up [a,a+szB) in the tree. That 761 will either succeed, producing a block which intersects that 762 range, in which case we delete it and repeat; or it will fail, 763 in which case there are no blocks intersecting the range, and we 764 can bring the process to a halt. */ 765 UWord keyW, valW, oldK, oldV; 766 GlobalTreeNode key, *nd; 767 Bool b, anyFound; 768 769 tl_assert(szB > 0); 770 771 anyFound = False; 772 773 key.addr = a; 774 key.szB = szB; 775 776 while (VG_(lookupFM)( gitree, &keyW, &valW, (UWord)&key )) { 777 anyFound = True; 778 nd = (GlobalTreeNode*)keyW; 779 tl_assert(valW == 0); 780 tl_assert(nd != &key); 781 tl_assert(cmp_nonempty_intervals(a, szB, nd->addr, nd->szB) == 0); 782 783 b = VG_(delFromFM)( gitree, &oldK, &oldV, (UWord)&key ); 784 tl_assert(b); 785 tl_assert(oldV == 0); 786 tl_assert(oldK == keyW); /* check we deleted the node we just found */ 787 } 788 789 return anyFound; 790 } 791 792 793 ////////////////////////////////////////////////////////////// 794 // // 795 // Invar // 796 // // 797 ////////////////////////////////////////////////////////////// 798 799 /* An invariant, as resulting from watching the destination of a 800 memory referencing instruction. Initially is Inv_Unset until the 801 instruction makes a first access. */ 802 803 typedef 804 enum { 805 Inv_Unset=1, /* not established yet */ 806 Inv_Unknown, /* unknown location */ 807 Inv_Stack0, /* array-typed stack block in innermost frame */ 808 Inv_StackN, /* array-typed stack block in non-innermost frame */ 809 Inv_Global, /* array-typed global block */ 810 } 811 InvarTag; 812 813 typedef 814 struct { 815 InvarTag tag; 816 union { 817 struct { 818 } Unset; 819 struct { 820 } Unknown; 821 struct { 822 Addr addr; 823 SizeT szB; 824 StackBlock* descr; 825 } Stack0; /* innermost stack frame */ 826 struct { 827 /* Pointer to a node in the interval tree for 828 this thread. */ 829 StackTreeNode* nd; 830 } StackN; /* non-innermost stack frame */ 831 struct { 832 /* Pointer to a GlobalBlock in the interval tree of 833 global blocks. */ 834 GlobalTreeNode* nd; 835 } Global; 836 } 837 Inv; 838 } 839 Invar; 840 841 /* Partial debugging printing for an Invar. */ 842 static void pp_Invar ( Invar* i ) 843 { 844 switch (i->tag) { 845 case Inv_Unset: 846 VG_(printf)("Unset"); 847 break; 848 case Inv_Unknown: 849 VG_(printf)("Unknown"); 850 break; 851 case Inv_Stack0: 852 VG_(printf)("Stack0 [%#lx,+%lu)", 853 i->Inv.Stack0.addr, i->Inv.Stack0.szB); 854 break; 855 case Inv_StackN: 856 VG_(printf)("StackN [%#lx,+%lu)", 857 i->Inv.StackN.nd->addr, i->Inv.StackN.nd->szB); 858 break; 859 case Inv_Global: 860 VG_(printf)("Global [%#lx,+%lu)", 861 i->Inv.Global.nd->addr, i->Inv.Global.nd->szB); 862 break; 863 default: 864 tl_assert(0); 865 } 866 } 867 868 /* Compare two Invars for equality. */ 869 static Bool eq_Invar ( Invar* i1, Invar* i2 ) 870 { 871 if (i1->tag != i2->tag) 872 return False; 873 switch (i1->tag) { 874 case Inv_Unset: 875 return True; 876 case Inv_Unknown: 877 return True; 878 case Inv_Stack0: 879 return i1->Inv.Stack0.addr == i2->Inv.Stack0.addr 880 && i1->Inv.Stack0.szB == i2->Inv.Stack0.szB; 881 case Inv_StackN: 882 return i1->Inv.StackN.nd == i2->Inv.StackN.nd; 883 case Inv_Global: 884 return i1->Inv.Global.nd == i2->Inv.Global.nd; 885 default: 886 tl_assert(0); 887 } 888 /*NOTREACHED*/ 889 tl_assert(0); 890 } 891 892 /* Generate a piece of text showing 'ea' is relative to 'invar', if 893 known. If unknown, generate an empty string. 'buf' must be at 894 least 32 bytes in size. Also return the absolute value of the 895 delta, if known, or zero if not known. 896 */ 897 static void gen_delta_str ( /*OUT*/HChar* buf, 898 /*OUT*/UWord* absDelta, 899 Invar* inv, Addr ea ) 900 { 901 Addr block = 0; 902 SizeT szB = 0; 903 904 buf[0] = 0; 905 *absDelta = 0; 906 907 switch (inv->tag) { 908 case Inv_Unknown: 909 case Inv_Unset: 910 return; /* unknown */ 911 case Inv_Stack0: 912 block = inv->Inv.Stack0.addr; 913 szB = inv->Inv.Stack0.szB; 914 break; 915 case Inv_StackN: 916 block = inv->Inv.StackN.nd->addr; 917 szB = inv->Inv.StackN.nd->szB; 918 break; 919 case Inv_Global: 920 block = inv->Inv.Global.nd->addr; 921 szB = inv->Inv.Global.nd->szB; 922 break; 923 default: 924 tl_assert(0); 925 } 926 tl_assert(szB > 0); 927 if (ea < block) { 928 *absDelta = block - ea; 929 VG_(sprintf)(buf, "%'lu before", *absDelta); 930 } 931 else if (ea >= block + szB) { 932 *absDelta = ea - (block + szB); 933 VG_(sprintf)(buf, "%'lu after", *absDelta); 934 } 935 else { 936 // Leave *absDelta at zero. 937 VG_(sprintf)(buf, "%'lu inside", ea - block); 938 } 939 } 940 941 942 /* Print selected parts of an Invar, suitable for use in error 943 messages. */ 944 static void show_Invar( HChar* buf, Word nBuf, Invar* inv, Word depth ) 945 { 946 const HChar* str; 947 tl_assert(nBuf >= 128); 948 buf[0] = 0; 949 switch (inv->tag) { 950 case Inv_Unknown: 951 VG_(sprintf)(buf, "%s", "unknown"); 952 break; 953 case Inv_Stack0: 954 str = "array"; 955 VG_(sprintf)(buf, "stack %s \"%s\" of size %'lu in this frame", 956 str, inv->Inv.Stack0.descr->name, 957 inv->Inv.Stack0.szB ); 958 break; 959 case Inv_StackN: 960 str = "array"; 961 VG_(sprintf)(buf, "stack %s \"%s\" of size %'lu in frame %lu back from here", 962 str, inv->Inv.StackN.nd->descr->name, 963 inv->Inv.StackN.nd->descr->szB, 964 depth - inv->Inv.StackN.nd->depth ); 965 break; 966 case Inv_Global: 967 str = "array"; 968 VG_(sprintf)(buf, "global %s \"%s\" of size %'lu in object with soname \"%s\"", 969 str, inv->Inv.Global.nd->descr->name, 970 inv->Inv.Global.nd->descr->szB, 971 inv->Inv.Global.nd->descr->soname ); 972 break; 973 case Inv_Unset: 974 VG_(sprintf)(buf, "%s", "Unset!"); 975 break; 976 default: 977 tl_assert(0); 978 } 979 } 980 981 982 ////////////////////////////////////////////////////////////// 983 // // 984 // our globals // 985 // // 986 ////////////////////////////////////////////////////////////// 987 988 ////////////////////////////////////////////////////////////// 989 /// 990 991 #define N_QCACHE 16 992 993 /* Powers of two only, else the result will be chaos */ 994 #define QCACHE_ADVANCE_EVERY 16 995 996 /* Per-thread query cache. Note that the invar can only be Inv_StackN 997 (but not Inv_Stack0), Inv_Global or Inv_Unknown. */ 998 typedef 999 struct { 1000 Addr addr; 1001 SizeT szB; 1002 Invar inv; 1003 } 1004 QCElem; 1005 1006 typedef 1007 struct { 1008 Word nInUse; 1009 QCElem elems[N_QCACHE]; 1010 } 1011 QCache; 1012 1013 static void QCache__invalidate ( QCache* qc ) { 1014 tl_assert(qc->nInUse >= 0); 1015 qc->nInUse = 0; 1016 } 1017 1018 static void QCache__pp ( QCache* qc, const HChar* who ) 1019 { 1020 Word i; 1021 VG_(printf)("<<< QCache with %ld elements (%s)\n", qc->nInUse, who); 1022 for (i = 0; i < qc->nInUse; i++) { 1023 VG_(printf)(" [%#lx,+%#lx) ", qc->elems[i].addr, qc->elems[i].szB); 1024 pp_Invar(&qc->elems[i].inv); 1025 VG_(printf)("\n"); 1026 } 1027 VG_(printf)(">>>\n"); 1028 } 1029 1030 static ULong stats__qcache_queries = 0; 1031 static ULong stats__qcache_misses = 0; 1032 static ULong stats__qcache_probes = 0; 1033 1034 /// 1035 ////////////////////////////////////////////////////////////// 1036 1037 /* Each thread has: 1038 * a shadow stack of StackFrames, which is a double-linked list 1039 * an stack block interval tree 1040 */ 1041 static struct _StackFrame** shadowStacks; 1042 1043 static WordFM** /* StackTreeNode */ siTrees; 1044 1045 static QCache* qcaches; 1046 1047 1048 /* Additionally, there is one global variable interval tree 1049 for the entire process. 1050 */ 1051 static WordFM* /* GlobalTreeNode */ giTree; 1052 1053 1054 static void invalidate_all_QCaches ( void ) 1055 { 1056 Word i; 1057 for (i = 0; i < VG_N_THREADS; i++) { 1058 QCache__invalidate( &qcaches[i] ); 1059 } 1060 } 1061 1062 static void ourGlobals_init ( void ) 1063 { 1064 Word i; 1065 1066 shadowStacks = sg_malloc( "di.sg_main.oGi.2", 1067 VG_N_THREADS * sizeof shadowStacks[0] ); 1068 siTrees = sg_malloc( "di.sg_main.oGi.3", VG_N_THREADS * sizeof siTrees[0] ); 1069 qcaches = sg_malloc( "di.sg_main.oGi.4", VG_N_THREADS * sizeof qcaches[0] ); 1070 1071 for (i = 0; i < VG_N_THREADS; i++) { 1072 shadowStacks[i] = NULL; 1073 siTrees[i] = NULL; 1074 qcaches[i] = (QCache){}; 1075 } 1076 invalidate_all_QCaches(); 1077 giTree = VG_(newFM)( sg_malloc, "di.sg_main.oGi.1", sg_free, 1078 (Word(*)(UWord,UWord))cmp_intervals_GlobalTreeNode ); 1079 } 1080 1081 1082 ////////////////////////////////////////////////////////////// 1083 // // 1084 // Handle global variable load/unload events // 1085 // // 1086 ////////////////////////////////////////////////////////////// 1087 1088 static void acquire_globals ( ULong di_handle ) 1089 { 1090 Word n, i; 1091 XArray* /* of GlobalBlock */ gbs; 1092 if (0) VG_(printf)("ACQUIRE GLOBALS %llu\n", di_handle ); 1093 gbs = VG_(di_get_global_blocks_from_dihandle) 1094 (di_handle, True/*arrays only*/); 1095 if (0) VG_(printf)(" GOT %ld globals\n", VG_(sizeXA)( gbs )); 1096 1097 n = VG_(sizeXA)( gbs ); 1098 for (i = 0; i < n; i++) { 1099 GlobalBlock* gbp; 1100 GlobalBlock* gb = VG_(indexXA)( gbs, i ); 1101 if (0) VG_(printf)(" new Global size %2lu at %#lx: %s %s\n", 1102 gb->szB, gb->addr, gb->soname, gb->name ); 1103 tl_assert(gb->szB > 0); 1104 /* Make a persistent copy of each GlobalBlock, and add it 1105 to the tree. */ 1106 gbp = get_persistent_GlobalBlock( gb ); 1107 add_block_to_GlobalTree( giTree, gbp ); 1108 } 1109 1110 VG_(deleteXA)( gbs ); 1111 } 1112 1113 1114 /* We only intercept these two because we need to see any di_handles 1115 that might arise from the mappings/allocations. */ 1116 void sg_new_mem_mmap( Addr a, SizeT len, 1117 Bool rr, Bool ww, Bool xx, ULong di_handle ) 1118 { 1119 if (di_handle > 0) 1120 acquire_globals(di_handle); 1121 } 1122 void sg_new_mem_startup( Addr a, SizeT len, 1123 Bool rr, Bool ww, Bool xx, ULong di_handle ) 1124 { 1125 if (di_handle > 0) 1126 acquire_globals(di_handle); 1127 } 1128 void sg_die_mem_munmap ( Addr a, SizeT len ) 1129 { 1130 Bool debug = (Bool)0; 1131 Bool overlap = False; 1132 1133 if (debug) VG_(printf)("MUNMAP %#lx %lu\n", a, len ); 1134 1135 if (len == 0) 1136 return; 1137 1138 overlap = del_GlobalTree_range(giTree, a, len); 1139 1140 { /* redundant sanity check */ 1141 UWord keyW, valW; 1142 VG_(initIterFM)( giTree ); 1143 while (VG_(nextIterFM)( giTree, &keyW, &valW )) { 1144 GlobalTreeNode* nd = (GlobalTreeNode*)keyW; 1145 tl_assert(valW == 0); 1146 tl_assert(nd->szB > 0); 1147 tl_assert(nd->addr + nd->szB <= a 1148 || a + len <= nd->addr); 1149 } 1150 VG_(doneIterFM)( giTree ); 1151 } 1152 1153 if (!overlap) 1154 return; 1155 1156 /* Ok, the range contained some blocks. Therefore we'll need to 1157 visit all the Invars in all the thread shadow stacks, and 1158 convert all Inv_Global entries that intersect [a,a+len) to 1159 Inv_Unknown. */ 1160 tl_assert(len > 0); 1161 preen_global_Invars( a, len ); 1162 invalidate_all_QCaches(); 1163 } 1164 1165 1166 ////////////////////////////////////////////////////////////// 1167 // // 1168 // StackFrame // 1169 // // 1170 ////////////////////////////////////////////////////////////// 1171 1172 static ULong stats__total_accesses = 0; 1173 static ULong stats__classify_Stack0 = 0; 1174 static ULong stats__classify_StackN = 0; 1175 static ULong stats__classify_Global = 0; 1176 static ULong stats__classify_Unknown = 0; 1177 static ULong stats__Invars_preened = 0; 1178 static ULong stats__Invars_changed = 0; 1179 static ULong stats__t_i_b_empty = 0; 1180 static ULong stats__htab_fast = 0; 1181 static ULong stats__htab_searches = 0; 1182 static ULong stats__htab_probes = 0; 1183 static ULong stats__htab_resizes = 0; 1184 1185 1186 /* A dynamic instance of an instruction */ 1187 typedef 1188 struct { 1189 /* IMMUTABLE */ 1190 Addr insn_addr; /* NB! zero means 'not in use' */ 1191 XArray* blocks; /* XArray* of StackBlock, or NULL if none */ 1192 /* MUTABLE */ 1193 Invar invar; 1194 } 1195 IInstance; 1196 1197 1198 #define N_HTAB_FIXED 64 1199 1200 typedef 1201 struct _StackFrame { 1202 /* The sp when the frame was created, so we know when to get rid 1203 of it. */ 1204 Addr creation_sp; 1205 /* The stack frames for a thread are arranged as a doubly linked 1206 list. Obviously the outermost frame in the stack has .outer 1207 as NULL and the innermost in theory has .inner as NULL. 1208 However, when a function returns, we don't delete the 1209 just-vacated StackFrame. Instead, it is retained in the list 1210 and will be re-used when the next call happens. This is so 1211 as to avoid constantly having to dynamically allocate and 1212 deallocate frames. */ 1213 struct _StackFrame* inner; 1214 struct _StackFrame* outer; 1215 Word depth; /* 0 for outermost; increases inwards */ 1216 /* Information for each memory referencing instruction, for this 1217 instantiation of the function. The iinstances array is 1218 operated as a simple linear-probe hash table, which is 1219 dynamically expanded as necessary. Once critical thing is 1220 that an IInstance with a .insn_addr of zero is interpreted to 1221 mean that hash table slot is unused. This means we can't 1222 store an IInstance for address zero. */ 1223 /* Note that htab initially points to htab_fixed. If htab_fixed 1224 turns out not to be big enough then htab is made to point to 1225 dynamically allocated memory. But it's often the case that 1226 htab_fixed is big enough, so this optimisation saves a huge 1227 number of sg_malloc/sg_free call pairs. */ 1228 IInstance* htab; 1229 UWord htab_size; /* size of hash table, MAY ONLY BE A POWER OF 2 */ 1230 UWord htab_used; /* number of hash table slots currently in use */ 1231 /* If this frame is currently making a call, then the following 1232 are relevant. */ 1233 Addr sp_at_call; 1234 Addr fp_at_call; 1235 XArray* /* of Addr */ blocks_added_by_call; 1236 /* See comment just above */ 1237 IInstance htab_fixed[N_HTAB_FIXED]; 1238 } 1239 StackFrame; 1240 1241 1242 1243 1244 1245 /* Move this somewhere else? */ 1246 /* Visit all Invars in the entire system. If 'isHeap' is True, change 1247 all Inv_Heap Invars that intersect [a,a+len) to Inv_Unknown. If 1248 'isHeap' is False, do the same but to the Inv_Global{S,V} Invars 1249 instead. */ 1250 1251 __attribute__((noinline)) 1252 static void preen_global_Invar ( Invar* inv, Addr a, SizeT len ) 1253 { 1254 stats__Invars_preened++; 1255 tl_assert(len > 0); 1256 tl_assert(inv); 1257 switch (inv->tag) { 1258 case Inv_Global: 1259 tl_assert(inv->Inv.Global.nd); 1260 tl_assert(inv->Inv.Global.nd->szB > 0); 1261 if (0) VG_(printf)("preen_Invar Global %#lx %lu\n", 1262 inv->Inv.Global.nd->addr, 1263 inv->Inv.Global.nd->szB); 1264 if (0 == cmp_nonempty_intervals(a, len, inv->Inv.Global.nd->addr, 1265 inv->Inv.Global.nd->szB)) { 1266 inv->tag = Inv_Unknown; 1267 stats__Invars_changed++; 1268 } 1269 break; 1270 case Inv_Stack0: 1271 case Inv_StackN: 1272 case Inv_Unknown: 1273 break; 1274 case Inv_Unset: /* this should never happen */ 1275 /* fallthrough */ 1276 default: 1277 tl_assert(0); 1278 } 1279 } 1280 1281 __attribute__((noinline)) 1282 static void preen_global_Invars ( Addr a, SizeT len ) 1283 { 1284 Int i; 1285 UWord u; 1286 StackFrame* frame; 1287 tl_assert(len > 0); 1288 for (i = 0; i < VG_N_THREADS; i++) { 1289 frame = shadowStacks[i]; 1290 if (!frame) 1291 continue; /* no frames for this thread */ 1292 /* start from the innermost frame */ 1293 while (frame->inner) 1294 frame = frame->inner; 1295 tl_assert(frame->outer); 1296 /* work through the frames from innermost to outermost. The 1297 order isn't important; we just need to ensure we visit each 1298 frame once (including those which are not actually active, 1299 more 'inner' than the 'innermost active frame', viz, just 1300 hanging around waiting to be used, when the current innermost 1301 active frame makes more calls. See comments on definition of 1302 struct _StackFrame. */ 1303 for (; frame; frame = frame->outer) { 1304 UWord xx = 0; /* sanity check only; count of used htab entries */ 1305 if (!frame->htab) 1306 continue; /* frame not in use. See shadowStack_unwind(). */ 1307 for (u = 0; u < frame->htab_size; u++) { 1308 IInstance* ii = &frame->htab[u]; 1309 if (ii->insn_addr == 0) 1310 continue; /* not in use */ 1311 if (0) { pp_Invar(&ii->invar); VG_(printf)(" x\n"); } 1312 preen_global_Invar( &ii->invar, a, len ); 1313 xx++; 1314 } 1315 tl_assert(xx == frame->htab_used); 1316 } 1317 } 1318 } 1319 1320 1321 /* XXX this should be >> 2 on ppc32/64 since the bottom two bits 1322 of the ip are guaranteed to be zero */ 1323 inline static UWord compute_II_hash ( Addr ip, UWord htab_size ) { 1324 return (ip >> 0) & (htab_size - 1); 1325 } 1326 1327 __attribute__((noinline)) 1328 static void initialise_II_hash_table ( StackFrame* sf ) 1329 { 1330 UWord i; 1331 sf->htab_size = N_HTAB_FIXED; /* initial hash table size */ 1332 sf->htab = &sf->htab_fixed[0]; 1333 tl_assert(sf->htab); 1334 sf->htab_used = 0; 1335 for (i = 0; i < sf->htab_size; i++) 1336 sf->htab[i].insn_addr = 0; /* NOT IN USE */ 1337 } 1338 1339 1340 __attribute__((noinline)) 1341 static void resize_II_hash_table ( StackFrame* sf ) 1342 { 1343 UWord i, j, ix, old_size, new_size; 1344 IInstance *old_htab, *new_htab, *old; 1345 1346 tl_assert(sf && sf->htab); 1347 old_size = sf->htab_size; 1348 new_size = 2 * old_size; 1349 old_htab = sf->htab; 1350 new_htab = sg_malloc( "di.sg_main.rIht.1", 1351 new_size * sizeof(IInstance) ); 1352 for (i = 0; i < new_size; i++) { 1353 new_htab[i].insn_addr = 0; /* NOT IN USE */ 1354 } 1355 for (i = 0; i < old_size; i++) { 1356 old = &old_htab[i]; 1357 if (old->insn_addr == 0 /* NOT IN USE */) 1358 continue; 1359 ix = compute_II_hash(old->insn_addr, new_size); 1360 /* find out where to put this, in the new table */ 1361 j = new_size; 1362 while (1) { 1363 if (new_htab[ix].insn_addr == 0) 1364 break; 1365 /* This can't ever happen, because it would mean the new 1366 table is full; that isn't allowed -- even the old table is 1367 only allowed to become half full. */ 1368 tl_assert(j > 0); 1369 j--; 1370 ix++; if (ix == new_size) ix = 0; 1371 } 1372 /* copy the old entry to this location */ 1373 tl_assert(ix < new_size); 1374 tl_assert(new_htab[ix].insn_addr == 0); 1375 new_htab[ix] = *old; 1376 tl_assert(new_htab[ix].insn_addr != 0); 1377 } 1378 /* all entries copied; free old table. */ 1379 if (old_htab != &sf->htab_fixed[0]) 1380 sg_free(old_htab); 1381 sf->htab = new_htab; 1382 sf->htab_size = new_size; 1383 /* check sf->htab_used is correct. Optional and a bit expensive 1384 but anyway: */ 1385 j = 0; 1386 for (i = 0; i < new_size; i++) { 1387 if (new_htab[i].insn_addr != 0) { 1388 j++; 1389 } 1390 } 1391 tl_assert(j == sf->htab_used); 1392 if (0) VG_(printf)("resized tab for SF %p to %lu\n", sf, new_size); 1393 } 1394 1395 1396 __attribute__((noinline)) 1397 static IInstance* find_or_create_IInstance_SLOW ( 1398 StackFrame* sf, 1399 Addr ip, 1400 XArray* /* StackBlock */ ip_frameblocks 1401 ) 1402 { 1403 UWord i, ix; 1404 1405 stats__htab_searches++; 1406 1407 tl_assert(sf); 1408 tl_assert(sf->htab); 1409 1410 /* Make sure the table loading doesn't get too high. */ 1411 if (UNLIKELY(2 * sf->htab_used >= 1 * sf->htab_size)) { 1412 stats__htab_resizes++; 1413 resize_II_hash_table(sf); 1414 } 1415 tl_assert(2 * sf->htab_used <= sf->htab_size); 1416 1417 ix = compute_II_hash(ip, sf->htab_size); 1418 i = sf->htab_size; 1419 while (1) { 1420 stats__htab_probes++; 1421 /* Note that because of the way the fast-case handler works, 1422 these two tests are actually redundant in the first iteration 1423 of this loop. (Except they aren't redundant if the code just 1424 above resized the table first. :-) */ 1425 if (sf->htab[ix].insn_addr == ip) 1426 return &sf->htab[ix]; 1427 if (sf->htab[ix].insn_addr == 0) 1428 break; 1429 /* If i ever gets to zero and we have found neither what we're 1430 looking for nor an empty slot, the table must be full. Which 1431 isn't possible -- we monitor the load factor to ensure it 1432 doesn't get above say 50%; if that ever does happen the table 1433 is resized. */ 1434 tl_assert(i > 0); 1435 i--; 1436 ix++; 1437 if (ix == sf->htab_size) ix = 0; 1438 } 1439 1440 /* So now we've found a free slot at ix, and we can use that. */ 1441 tl_assert(sf->htab[ix].insn_addr == 0); 1442 1443 /* Add a new record in this slot. */ 1444 tl_assert(ip != 0); /* CAN'T REPRESENT THIS */ 1445 sf->htab[ix].insn_addr = ip; 1446 sf->htab[ix].blocks = ip_frameblocks; 1447 sf->htab[ix].invar.tag = Inv_Unset; 1448 sf->htab_used++; 1449 return &sf->htab[ix]; 1450 } 1451 1452 1453 inline 1454 static IInstance* find_or_create_IInstance ( 1455 StackFrame* sf, 1456 Addr ip, 1457 XArray* /* StackBlock */ ip_frameblocks 1458 ) 1459 { 1460 UWord ix = compute_II_hash(ip, sf->htab_size); 1461 /* Is it in the first slot we come to? */ 1462 if (LIKELY(sf->htab[ix].insn_addr == ip)) { 1463 stats__htab_fast++; 1464 return &sf->htab[ix]; 1465 } 1466 /* If the first slot we come to is empty, bag it. */ 1467 if (LIKELY(sf->htab[ix].insn_addr == 0)) { 1468 stats__htab_fast++; 1469 tl_assert(ip != 0); 1470 sf->htab[ix].insn_addr = ip; 1471 sf->htab[ix].blocks = ip_frameblocks; 1472 sf->htab[ix].invar.tag = Inv_Unset; 1473 sf->htab_used++; 1474 return &sf->htab[ix]; 1475 } 1476 /* Otherwise we hand off to the slow case, which searches other 1477 slots, and optionally resizes the table if necessary. */ 1478 return find_or_create_IInstance_SLOW( sf, ip, ip_frameblocks ); 1479 } 1480 1481 1482 __attribute__((noinline)) 1483 static Addr calculate_StackBlock_EA ( StackBlock* descr, 1484 Addr sp, Addr fp ) { 1485 UWord w1 = (UWord)descr->base; 1486 UWord w2 = (UWord)(descr->spRel ? sp : fp); 1487 UWord ea = w1 + w2; 1488 return ea; 1489 } 1490 1491 /* Given an array of StackBlocks, return an array of Addrs, holding 1492 their effective addresses. Caller deallocates result array. */ 1493 __attribute__((noinline)) 1494 static XArray* /* Addr */ calculate_StackBlock_EAs ( 1495 XArray* /* StackBlock */ blocks, 1496 Addr sp, Addr fp 1497 ) 1498 { 1499 XArray* res; 1500 Word i, n = VG_(sizeXA)( blocks ); 1501 tl_assert(n > 0); 1502 res = VG_(newXA)( sg_malloc, "di.sg_main.cSBE.1", sg_free, sizeof(Addr) ); 1503 for (i = 0; i < n; i++) { 1504 StackBlock* blk = VG_(indexXA)( blocks, i ); 1505 Addr ea = calculate_StackBlock_EA( blk, sp, fp ); 1506 VG_(addToXA)( res, &ea ); 1507 } 1508 return res; 1509 } 1510 1511 1512 /* Try to classify the block into which a memory access falls, and 1513 write the result in 'inv'. This writes all relevant fields of 1514 'inv'. */ 1515 __attribute__((noinline)) 1516 static void classify_address ( /*OUT*/Invar* inv, 1517 ThreadId tid, 1518 Addr ea, Addr sp, Addr fp, 1519 UWord szB, 1520 XArray* /* of StackBlock */ thisInstrBlocks ) 1521 { 1522 tl_assert(szB > 0); 1523 /* First, look in the stack blocks accessible in this instruction's 1524 frame. */ 1525 { 1526 Word i, nBlocks = VG_(sizeXA)( thisInstrBlocks ); 1527 if (nBlocks == 0) stats__t_i_b_empty++; 1528 for (i = 0; i < nBlocks; i++) { 1529 StackBlock* descr = VG_(indexXA)( thisInstrBlocks, i ); 1530 Addr bea = calculate_StackBlock_EA( descr, sp, fp ); 1531 if (bea <= ea && ea + szB <= bea + descr->szB) { 1532 /* found it */ 1533 inv->tag = Inv_Stack0; 1534 inv->Inv.Stack0.addr = bea; 1535 inv->Inv.Stack0.szB = descr->szB; 1536 inv->Inv.Stack0.descr = descr; 1537 stats__classify_Stack0++; 1538 return; 1539 } 1540 } 1541 } 1542 /* Look in this thread's query cache */ 1543 { Word i; 1544 QCache* cache = &qcaches[tid]; 1545 static UWord ctr = 0; 1546 stats__qcache_queries++; 1547 for (i = 0; i < cache->nInUse; i++) { 1548 if (0) /* expensive in a loop like this */ 1549 tl_assert(cache->elems[i].addr + cache->elems[i].szB != 0); 1550 stats__qcache_probes++; 1551 if (is_subinterval_of(cache->elems[i].addr, 1552 cache->elems[i].szB, ea, szB)) { 1553 if (i > 0 1554 && (ctr++ & (QCACHE_ADVANCE_EVERY-1)) == 0) { 1555 QCElem tmp; 1556 tmp = cache->elems[i-1]; 1557 cache->elems[i-1] = cache->elems[i]; 1558 cache->elems[i] = tmp; 1559 i--; 1560 } 1561 *inv = cache->elems[i].inv; 1562 return; 1563 } 1564 } 1565 stats__qcache_misses++; 1566 } 1567 /* Ok, so it's not a block in the top frame. Perhaps it's a block 1568 in some calling frame? Consult this thread's stack-block 1569 interval tree to find out. */ 1570 { StackTreeNode* nd = find_StackTreeNode( siTrees[tid], ea ); 1571 /* We know that [ea,ea+1) is in the block, but we need to 1572 restrict to the case where the whole access falls within 1573 it. */ 1574 if (nd && !is_subinterval_of(nd->addr, nd->szB, ea, szB)) { 1575 nd = NULL; 1576 } 1577 if (nd) { 1578 /* found it */ 1579 inv->tag = Inv_StackN; 1580 inv->Inv.StackN.nd = nd; 1581 stats__classify_StackN++; 1582 goto out; 1583 } 1584 } 1585 /* Not in a stack block. Try the global pool. */ 1586 { GlobalTreeNode* nd = find_GlobalTreeNode(giTree, ea); 1587 /* We know that [ea,ea+1) is in the block, but we need to 1588 restrict to the case where the whole access falls within 1589 it. */ 1590 if (nd && !is_subinterval_of(nd->addr, nd->szB, ea, szB)) { 1591 nd = NULL; 1592 } 1593 if (nd) { 1594 /* found it */ 1595 inv->tag = Inv_Global; 1596 inv->Inv.Global.nd = nd; 1597 stats__classify_Global++; 1598 goto out; 1599 } 1600 } 1601 /* No idea - give up. */ 1602 inv->tag = Inv_Unknown; 1603 stats__classify_Unknown++; 1604 1605 /* Update the cache */ 1606 out: 1607 { Addr toadd_addr = 0; 1608 SizeT toadd_szB = 0; 1609 QCache* cache = &qcaches[tid]; 1610 1611 static UWord ctr = 0; 1612 Bool show = False; 1613 if (0 && 0 == (ctr++ & 0x1FFFFF)) show = True; 1614 1615 if (show) QCache__pp(cache, "before upd"); 1616 1617 switch (inv->tag) { 1618 case Inv_Global: 1619 toadd_addr = inv->Inv.Global.nd->addr; 1620 toadd_szB = inv->Inv.Global.nd->szB; 1621 break; 1622 case Inv_StackN: 1623 toadd_addr = inv->Inv.StackN.nd->addr; 1624 toadd_szB = inv->Inv.StackN.nd->szB; 1625 break; 1626 case Inv_Unknown: { 1627 /* This is more complex. We need to figure out the 1628 intersection of the "holes" in the global and stack 1629 interval trees into which [ea,ea+szB) falls. This is 1630 further complicated by the fact that [ea,ea+szB) might 1631 not fall cleanly into a hole; it may instead fall across 1632 the boundary of a stack or global block. In that case 1633 we just ignore it and don't update the cache, since we 1634 have no way to represent this situation precisely. */ 1635 StackTreeNode sNegInf, sPosInf, sKey, *sLB, *sUB; 1636 GlobalTreeNode gNegInf, gPosInf, gKey, *gLB, *gUB; 1637 Addr gMin, gMax, sMin, sMax, uMin, uMax; 1638 Bool sOK, gOK; 1639 sNegInf.addr = 0; 1640 sNegInf.szB = 1; 1641 sPosInf.addr = ~(UWord)0; 1642 sPosInf.szB = 1; 1643 gNegInf.addr = 0; 1644 gNegInf.szB = 1; 1645 gPosInf.addr = ~(UWord)0; 1646 gPosInf.szB = 1; 1647 sKey.addr = ea; 1648 sKey.szB = szB; 1649 gKey.addr = ea; 1650 gKey.szB = szB; 1651 if (0) VG_(printf)("Tree sizes %lu %lu\n", 1652 VG_(sizeFM)(siTrees[tid]), VG_(sizeFM)(giTree)); 1653 sOK = VG_(findBoundsFM)( siTrees[tid], 1654 (UWord*)&sLB, NULL/*unused*/, 1655 (UWord*)&sUB, NULL/*unused*/, 1656 (UWord)&sNegInf, 0/*unused*/, 1657 (UWord)&sPosInf, 0/*unused*/, 1658 (UWord)&sKey ); 1659 gOK = VG_(findBoundsFM)( giTree, 1660 (UWord*)&gLB, NULL/*unused*/, 1661 (UWord*)&gUB, NULL/*unused*/, 1662 (UWord)&gNegInf, 0/*unused*/, 1663 (UWord)&gPosInf, 0/*unused*/, 1664 (UWord)&gKey ); 1665 if (!(sOK && gOK)) { 1666 /* If this happens, then [ea,ea+szB) partially overlaps 1667 a heap or stack block. We can't represent that, so 1668 just forget it (should be very rare). However, do 1669 maximum sanity checks first. In such a 1670 partial overlap case, it can't be the case that both 1671 [ea] and [ea+szB-1] overlap the same block, since if 1672 that were indeed the case then it wouldn't be a 1673 partial overlap; rather it would simply fall inside 1674 that block entirely and we shouldn't be inside this 1675 conditional at all. */ 1676 if (!sOK) { 1677 StackTreeNode *ndFirst, *ndLast; 1678 ndFirst = find_StackTreeNode( siTrees[tid], ea ); 1679 ndLast = find_StackTreeNode( siTrees[tid], ea+szB-1 ); 1680 /* if both ends of the range fall inside a block, 1681 they can't be in the same block. */ 1682 if (ndFirst && ndLast) 1683 tl_assert(ndFirst != ndLast); 1684 /* for each end of the range, if it is in a block, 1685 the range as a whole can't be entirely within the 1686 block. */ 1687 if (ndFirst) 1688 tl_assert(!is_subinterval_of(ndFirst->addr, 1689 ndFirst->szB, ea, szB)); 1690 if (ndLast) 1691 tl_assert(!is_subinterval_of(ndLast->addr, 1692 ndLast->szB, ea, szB)); 1693 } 1694 if (!gOK) { 1695 GlobalTreeNode *ndFirst, *ndLast; 1696 ndFirst = find_GlobalTreeNode( giTree, ea ); 1697 ndLast = find_GlobalTreeNode( giTree, ea+szB-1 ); 1698 /* if both ends of the range fall inside a block, 1699 they can't be in the same block. */ 1700 if (ndFirst && ndLast) 1701 tl_assert(ndFirst != ndLast); 1702 /* for each end of the range, if it is in a block, 1703 the range as a whole can't be entirely within the 1704 block. */ 1705 if (ndFirst) 1706 tl_assert(!is_subinterval_of(ndFirst->addr, 1707 ndFirst->szB, ea, szB)); 1708 if (ndLast) 1709 tl_assert(!is_subinterval_of(ndLast->addr, 1710 ndLast->szB, ea, szB)); 1711 } 1712 if (0) VG_(printf)("overlapping blocks in cache\n"); 1713 return; 1714 } 1715 sMin = sLB == &sNegInf ? 0 : (sLB->addr + sLB->szB); 1716 sMax = sUB == &sPosInf ? ~(UWord)0 : (sUB->addr - 1); 1717 gMin = gLB == &gNegInf ? 0 : (gLB->addr + gLB->szB); 1718 gMax = gUB == &gPosInf ? ~(UWord)0 : (gUB->addr - 1); 1719 if (0) VG_(printf)("sMin %lx sMax %lx gMin %lx gMax %lx\n", 1720 sMin, sMax, gMin, gMax); 1721 /* [sMin,sMax] and [gMin,gMax] must both contain 1722 [ea,ea+szB) (right?) That implies they must overlap at 1723 at least over [ea,ea+szB). */ 1724 tl_assert(sMin <= ea && ea+szB-1 <= sMax); 1725 tl_assert(gMin <= ea && ea+szB-1 <= gMax); 1726 /* So now compute their intersection. */ 1727 uMin = Addr__max( sMin, gMin ); 1728 uMax = Addr__min( sMax, gMax ); 1729 if (0) VG_(printf)("uMin %lx uMax %lx\n", uMin, uMax); 1730 tl_assert(uMin <= uMax); 1731 tl_assert(uMin <= ea && ea+szB-1 <= uMax); 1732 /* Finally, we can park [uMin,uMax] in the cache. However, 1733 if uMax is ~0, we can't represent the difference; hence 1734 fudge uMax. */ 1735 if (uMin < uMax && uMax == ~(UWord)0) 1736 uMax--; 1737 toadd_addr = uMin; 1738 toadd_szB = uMax - uMin + 1; 1739 break; 1740 } 1741 default: 1742 /* We should only be caching info for the above 3 cases */ 1743 tl_assert(0); 1744 } /* switch (inv->tag) */ 1745 1746 { /* and actually add this to the cache, finally */ 1747 Word i; 1748 Word ip = cache->nInUse / 2; /* doesn't seem critical */ 1749 1750 if (cache->nInUse < N_QCACHE) 1751 cache->nInUse++; 1752 for (i = cache->nInUse-1; i > ip; i--) { 1753 cache->elems[i] = cache->elems[i-1]; 1754 } 1755 1756 tl_assert(toadd_szB > 0); 1757 cache->elems[ip].addr = toadd_addr; 1758 cache->elems[ip].szB = toadd_szB; 1759 cache->elems[ip].inv = *inv; 1760 } 1761 1762 if (show) QCache__pp(cache, "after upd"); 1763 1764 } 1765 } 1766 1767 1768 /* CALLED FROM GENERATED CODE */ 1769 static 1770 VG_REGPARM(3) 1771 void helperc__mem_access ( /* Known only at run time: */ 1772 Addr ea, Addr sp, Addr fp, 1773 /* Known at translation time: */ 1774 Word sszB, Addr ip, XArray* ip_frameBlocks ) 1775 { 1776 UWord szB; 1777 IInstance* iinstance; 1778 Invar* inv; 1779 Invar new_inv; 1780 ThreadId tid = VG_(get_running_tid)(); 1781 StackFrame* frame; 1782 HChar bufE[160], bufA[160], bufD[32]; 1783 1784 stats__total_accesses++; 1785 1786 tl_assert(is_sane_TId(tid)); 1787 frame = shadowStacks[tid]; 1788 tl_assert(frame); 1789 1790 /* Find the instance info for this instruction. */ 1791 tl_assert(ip_frameBlocks); 1792 iinstance = find_or_create_IInstance( frame, ip, ip_frameBlocks ); 1793 tl_assert(iinstance); 1794 tl_assert(iinstance->blocks == ip_frameBlocks); 1795 1796 szB = (sszB < 0) ? (-sszB) : sszB; 1797 tl_assert(szB > 0); 1798 1799 inv = &iinstance->invar; 1800 1801 /* Deal with first uses of instruction instances. */ 1802 if (inv->tag == Inv_Unset) { 1803 /* This is the first use of this instance of the instruction, so 1804 we can't make any check; we merely record what we saw, so we 1805 can compare it against what happens for 2nd and subsequent 1806 accesses. */ 1807 classify_address( inv, 1808 tid, ea, sp, fp, szB, iinstance->blocks ); 1809 tl_assert(inv->tag != Inv_Unset); 1810 return; 1811 } 1812 1813 /* So generate an Invar and see if it's different from what 1814 we had before. */ 1815 classify_address( &new_inv, 1816 tid, ea, sp, fp, szB, iinstance->blocks ); 1817 tl_assert(new_inv.tag != Inv_Unset); 1818 1819 /* Did we see something different from before? If no, then there's 1820 no error. */ 1821 tl_assert(inv->tag != Inv_Unset); 1822 1823 if (LIKELY(eq_Invar(&new_inv, inv))) 1824 return; 1825 1826 VG_(memset)(bufE, 0, sizeof(bufE)); 1827 show_Invar( bufE, sizeof(bufE)-1, inv, frame->depth ); 1828 1829 VG_(memset)(bufA, 0, sizeof(bufA)); 1830 show_Invar( bufA, sizeof(bufA)-1, &new_inv, frame->depth ); 1831 1832 VG_(memset)(bufD, 0, sizeof(bufD)); 1833 UWord absDelta; 1834 gen_delta_str( bufD, &absDelta, inv, ea ); 1835 1836 if (absDelta < 1024) 1837 sg_record_error_SorG( tid, ea, sszB, bufE, bufA, bufD ); 1838 1839 /* And now install the new observation as "standard", so as to 1840 make future error messages make more sense. */ 1841 *inv = new_inv; 1842 } 1843 1844 1845 //////////////////////////////////////// 1846 /* Primary push-a-new-frame routine. Called indirectly from 1847 generated code. */ 1848 1849 static UWord stats__max_sitree_size = 0; 1850 static UWord stats__max_gitree_size = 0; 1851 1852 static 1853 void shadowStack_new_frame ( ThreadId tid, 1854 Addr sp_at_call_insn, 1855 Addr sp_post_call_insn, 1856 Addr fp_at_call_insn, 1857 Addr ip_post_call_insn, 1858 XArray* descrs_at_call_insn ) 1859 { 1860 StackFrame *callee, *caller; 1861 tl_assert(is_sane_TId(tid)); 1862 1863 caller = shadowStacks[tid]; 1864 tl_assert(caller); 1865 1866 if (caller->outer) { /* "this is not the outermost frame" */ 1867 tl_assert(caller->outer->inner == caller); 1868 tl_assert(caller->outer->depth >= 0); 1869 tl_assert(1 + caller->outer->depth == caller->depth); 1870 } else { 1871 tl_assert(caller->depth == 0); 1872 } 1873 1874 caller->sp_at_call = sp_at_call_insn; 1875 caller->fp_at_call = fp_at_call_insn; 1876 1877 if (descrs_at_call_insn) { 1878 tl_assert( VG_(sizeXA)(descrs_at_call_insn) > 0 ); 1879 caller->blocks_added_by_call 1880 = calculate_StackBlock_EAs( descrs_at_call_insn, 1881 sp_at_call_insn, fp_at_call_insn ); 1882 if (caller->blocks_added_by_call) 1883 add_blocks_to_StackTree( siTrees[tid], 1884 descrs_at_call_insn, 1885 caller->blocks_added_by_call, 1886 caller->depth /* stack depth at which 1887 these blocks are 1888 considered to exist*/ ); 1889 if (1) { 1890 UWord s = VG_(sizeFM)( siTrees[tid] ); 1891 UWord g = VG_(sizeFM)( giTree ); 1892 Bool sb = s > stats__max_sitree_size; 1893 Bool gb = g > stats__max_gitree_size; 1894 if (sb) stats__max_sitree_size = s; 1895 if (gb) stats__max_gitree_size = g; 1896 if (0 && (sb || gb)) 1897 VG_(message)(Vg_DebugMsg, 1898 "exp-sgcheck: new max tree sizes: " 1899 "StackTree %lu, GlobalTree %lu\n", 1900 stats__max_sitree_size, stats__max_gitree_size ); 1901 } 1902 } else { 1903 caller->blocks_added_by_call = NULL; 1904 } 1905 1906 /* caller->blocks_added_by_call is used again (and then freed) when 1907 this frame is removed from the stack. */ 1908 1909 if (caller->inner) { 1910 callee = caller->inner; 1911 } else { 1912 callee = sg_malloc("di.sg_main.sSnf.1", sizeof(StackFrame)); 1913 VG_(memset)(callee, 0, sizeof(StackFrame)); 1914 callee->outer = caller; 1915 caller->inner = callee; 1916 callee->depth = 1 + caller->depth; 1917 tl_assert(callee->inner == NULL); 1918 } 1919 1920 /* This sets up .htab, .htab_size and .htab_used */ 1921 initialise_II_hash_table( callee ); 1922 1923 callee->creation_sp = sp_post_call_insn; 1924 callee->sp_at_call = 0; // not actually required .. 1925 callee->fp_at_call = 0; // .. these 3 initialisations are .. 1926 callee->blocks_added_by_call = NULL; // .. just for cleanness 1927 1928 /* record the new running stack frame */ 1929 shadowStacks[tid] = callee; 1930 1931 /* and this thread's query cache is now invalid */ 1932 QCache__invalidate( &qcaches[tid] ); 1933 1934 if (0) 1935 { Word d = callee->depth; 1936 const HChar *fnname; 1937 Bool ok; 1938 Addr ip = ip_post_call_insn; 1939 ok = VG_(get_fnname_w_offset)( ip, &fnname ); 1940 while (d > 0) { 1941 VG_(printf)(" "); 1942 d--; 1943 } 1944 VG_(printf)("> %s %#lx\n", ok ? fnname : "???", ip); 1945 } 1946 } 1947 1948 /* CALLED FROM GENERATED CODE */ 1949 static 1950 VG_REGPARM(3) 1951 void helperc__new_frame ( Addr sp_post_call_insn, 1952 Addr fp_at_call_insn, 1953 Addr ip_post_call_insn, 1954 XArray* blocks_at_call_insn, 1955 Word sp_adjust ) 1956 { 1957 ThreadId tid = VG_(get_running_tid)(); 1958 Addr sp_at_call_insn = sp_post_call_insn + sp_adjust; 1959 shadowStack_new_frame( tid, 1960 sp_at_call_insn, 1961 sp_post_call_insn, 1962 fp_at_call_insn, 1963 ip_post_call_insn, 1964 blocks_at_call_insn ); 1965 } 1966 1967 1968 //////////////////////////////////////// 1969 /* Primary remove-frame(s) routine. Called indirectly from 1970 generated code. */ 1971 1972 __attribute__((noinline)) 1973 static void shadowStack_unwind ( ThreadId tid, Addr sp_now ) 1974 { 1975 StackFrame *innermost, *innermostOrig; 1976 tl_assert(is_sane_TId(tid)); 1977 innermost = shadowStacks[tid]; 1978 tl_assert(innermost); 1979 innermostOrig = innermost; 1980 //VG_(printf)("UNWIND sp_new = %p\n", sp_now); 1981 while (1) { 1982 if (!innermost->outer) 1983 break; 1984 if (innermost->inner) 1985 tl_assert(innermost->inner->outer == innermost); 1986 tl_assert(innermost->outer->inner == innermost); 1987 tl_assert(innermost->blocks_added_by_call == NULL); 1988 if (sp_now <= innermost->creation_sp) break; 1989 //VG_(printf)("UNWIND dump %p\n", innermost->creation_sp); 1990 tl_assert(innermost->htab); 1991 if (innermost->htab != &innermost->htab_fixed[0]) 1992 sg_free(innermost->htab); 1993 /* be on the safe side */ 1994 innermost->creation_sp = 0; 1995 innermost->htab = NULL; 1996 innermost->htab_size = 0; 1997 innermost->htab_used = 0; 1998 innermost->sp_at_call = 0; 1999 innermost->fp_at_call = 0; 2000 innermost->blocks_added_by_call = NULL; 2001 innermost = innermost->outer; 2002 2003 /* So now we're "back" in the calling frame. Remove from this 2004 thread's stack-interval-tree, the blocks added at the time of 2005 the call. */ 2006 2007 if (innermost->outer) { /* not at the outermost frame */ 2008 if (innermost->blocks_added_by_call == NULL) { 2009 } else { 2010 del_blocks_from_StackTree( siTrees[tid], 2011 innermost->blocks_added_by_call ); 2012 VG_(deleteXA)( innermost->blocks_added_by_call ); 2013 innermost->blocks_added_by_call = NULL; 2014 } 2015 } 2016 /* That completes the required tidying of the interval tree 2017 associated with the frame we just removed. */ 2018 2019 if (0) { 2020 Word d = innermost->depth; 2021 while (d > 0) { 2022 VG_(printf)(" "); 2023 d--; 2024 } 2025 VG_(printf)("X\n"); 2026 } 2027 2028 } 2029 2030 tl_assert(innermost); 2031 2032 if (innermost != innermostOrig) { 2033 shadowStacks[tid] = innermost; 2034 /* this thread's query cache is now invalid */ 2035 QCache__invalidate( &qcaches[tid] ); 2036 } 2037 } 2038 2039 2040 2041 ////////////////////////////////////////////////////////////// 2042 // // 2043 // Instrumentation // 2044 // // 2045 ////////////////////////////////////////////////////////////// 2046 2047 /* What does instrumentation need to do? 2048 2049 - at each Call transfer, generate a call to shadowStack_new_frame 2050 do this by manually inspecting the IR 2051 2052 - at each sp change, if the sp change is negative, 2053 call shadowStack_unwind 2054 do this by asking for SP-change analysis 2055 2056 - for each memory referencing instruction, 2057 call helperc__mem_access 2058 */ 2059 2060 /* A complication: sg_ instrumentation and h_ instrumentation need to 2061 be interleaved. Since the latter is a lot more complex than the 2062 former, we split the sg_ instrumentation here into four functions 2063 and let the h_ instrumenter call the four functions as it goes. 2064 Hence the h_ instrumenter drives the sg_ instrumenter. 2065 2066 To make this viable, the sg_ instrumenter carries what running 2067 state it needs in 'struct _SGEnv'. This is exported only 2068 abstractly from this file. 2069 */ 2070 2071 struct _SGEnv { 2072 /* the current insn's IP */ 2073 Addr curr_IP; 2074 /* whether the above is actually known */ 2075 Bool curr_IP_known; 2076 /* if we find a mem ref, is it the first for this insn? Used for 2077 detecting insns which make more than one memory ref, a situation 2078 we basically can't really handle properly; and so we ignore all 2079 but the first ref. */ 2080 Bool firstRef; 2081 /* READONLY */ 2082 IRTemp (*newIRTemp_cb)(IRType,void*); 2083 void* newIRTemp_opaque; 2084 }; 2085 2086 2087 /* --- Helper fns for instrumentation --- */ 2088 2089 static IRTemp gen_Get_SP ( struct _SGEnv* sge, 2090 IRSB* bbOut, 2091 const VexGuestLayout* layout, 2092 Int hWordTy_szB ) 2093 { 2094 IRExpr* sp_expr; 2095 IRTemp sp_temp; 2096 IRType sp_type; 2097 /* This in effect forces the host and guest word sizes to be the 2098 same. */ 2099 tl_assert(hWordTy_szB == layout->sizeof_SP); 2100 sp_type = layout->sizeof_SP == 8 ? Ity_I64 : Ity_I32; 2101 sp_expr = IRExpr_Get( layout->offset_SP, sp_type ); 2102 sp_temp = sge->newIRTemp_cb( sp_type, sge->newIRTemp_opaque ); 2103 addStmtToIRSB( bbOut, IRStmt_WrTmp( sp_temp, sp_expr ) ); 2104 return sp_temp; 2105 } 2106 2107 static IRTemp gen_Get_FP ( struct _SGEnv* sge, 2108 IRSB* bbOut, 2109 const VexGuestLayout* layout, 2110 Int hWordTy_szB ) 2111 { 2112 IRExpr* fp_expr; 2113 IRTemp fp_temp; 2114 IRType fp_type; 2115 /* This in effect forces the host and guest word sizes to be the 2116 same. */ 2117 tl_assert(hWordTy_szB == layout->sizeof_SP); 2118 fp_type = layout->sizeof_FP == 8 ? Ity_I64 : Ity_I32; 2119 fp_expr = IRExpr_Get( layout->offset_FP, fp_type ); 2120 fp_temp = sge->newIRTemp_cb( fp_type, sge->newIRTemp_opaque ); 2121 addStmtToIRSB( bbOut, IRStmt_WrTmp( fp_temp, fp_expr ) ); 2122 return fp_temp; 2123 } 2124 2125 static void instrument_mem_access ( struct _SGEnv* sge, 2126 IRSB* bbOut, 2127 IRExpr* addr, 2128 Int szB, 2129 Bool isStore, 2130 Int hWordTy_szB, 2131 Addr curr_IP, 2132 const VexGuestLayout* layout ) 2133 { 2134 IRType tyAddr = Ity_INVALID; 2135 XArray* frameBlocks = NULL; 2136 2137 tl_assert(isIRAtom(addr)); 2138 tl_assert(hWordTy_szB == 4 || hWordTy_szB == 8); 2139 2140 tyAddr = typeOfIRExpr( bbOut->tyenv, addr ); 2141 tl_assert(tyAddr == Ity_I32 || tyAddr == Ity_I64); 2142 2143 #if defined(VGA_x86) 2144 { UChar* p = (UChar*)curr_IP; 2145 // pop %ebp; RET 2146 if (p[0] == 0xc3 && p[-1] == 0x5d) return; 2147 // pop %ebp; RET $imm16 2148 if (p[0] == 0xc2 && p[-1] == 0x5d) return; 2149 // PUSH %EBP; mov %esp,%ebp 2150 if (p[0] == 0x55 && p[1] == 0x89 && p[2] == 0xe5) return; 2151 } 2152 #endif 2153 2154 /* First off, find or create the StackBlocks for this instruction. */ 2155 frameBlocks = get_StackBlocks_for_IP( curr_IP ); 2156 tl_assert(frameBlocks); 2157 //if (VG_(sizeXA)( frameBlocks ) == 0) 2158 // frameBlocks = NULL; 2159 2160 /* Generate a call to "helperc__mem_access", passing: 2161 addr current_SP current_FP szB curr_IP frameBlocks 2162 */ 2163 { IRTemp t_SP = gen_Get_SP( sge, bbOut, layout, hWordTy_szB ); 2164 IRTemp t_FP = gen_Get_FP( sge, bbOut, layout, hWordTy_szB ); 2165 IRExpr** args 2166 = mkIRExprVec_6( addr, 2167 IRExpr_RdTmp(t_SP), 2168 IRExpr_RdTmp(t_FP), 2169 mkIRExpr_HWord( isStore ? (-szB) : szB ), 2170 mkIRExpr_HWord( curr_IP ), 2171 mkIRExpr_HWord( (HWord)frameBlocks ) ); 2172 IRDirty* di 2173 = unsafeIRDirty_0_N( 3/*regparms*/, 2174 "helperc__mem_access", 2175 VG_(fnptr_to_fnentry)( &helperc__mem_access ), 2176 args ); 2177 2178 addStmtToIRSB( bbOut, IRStmt_Dirty(di) ); 2179 } 2180 } 2181 2182 2183 /* --- Instrumentation main (4 fns) --- */ 2184 2185 struct _SGEnv * sg_instrument_init ( IRTemp (*newIRTemp_cb)(IRType,void*), 2186 void* newIRTemp_opaque ) 2187 { 2188 struct _SGEnv * env = sg_malloc("di.sg_main.sii.1", 2189 sizeof(struct _SGEnv)); 2190 tl_assert(env); 2191 env->curr_IP = 0; 2192 env->curr_IP_known = False; 2193 env->firstRef = True; 2194 env->newIRTemp_cb = newIRTemp_cb; 2195 env->newIRTemp_opaque = newIRTemp_opaque; 2196 return env; 2197 } 2198 2199 void sg_instrument_fini ( struct _SGEnv * env ) 2200 { 2201 sg_free(env); 2202 } 2203 2204 /* Add instrumentation for 'st' to 'sbOut', and possibly modify 'env' 2205 as required. This must be called before 'st' itself is added to 2206 'sbOut'. */ 2207 void sg_instrument_IRStmt ( /*MOD*/struct _SGEnv * env, 2208 /*MOD*/IRSB* sbOut, 2209 IRStmt* st, 2210 const VexGuestLayout* layout, 2211 IRType gWordTy, IRType hWordTy ) 2212 { 2213 if (!sg_clo_enable_sg_checks) 2214 return; 2215 2216 tl_assert(st); 2217 tl_assert(isFlatIRStmt(st)); 2218 switch (st->tag) { 2219 case Ist_NoOp: 2220 case Ist_AbiHint: 2221 case Ist_Put: 2222 case Ist_PutI: 2223 case Ist_MBE: 2224 /* None of these can contain any memory references. */ 2225 break; 2226 2227 case Ist_Exit: 2228 tl_assert(st->Ist.Exit.jk != Ijk_Call); 2229 /* else we must deal with a conditional call */ 2230 break; 2231 2232 case Ist_IMark: 2233 env->curr_IP_known = True; 2234 env->curr_IP = st->Ist.IMark.addr; 2235 env->firstRef = True; 2236 break; 2237 2238 case Ist_Store: 2239 tl_assert(env->curr_IP_known); 2240 if (env->firstRef) { 2241 instrument_mem_access( 2242 env, sbOut, 2243 st->Ist.Store.addr, 2244 sizeofIRType(typeOfIRExpr(sbOut->tyenv, st->Ist.Store.data)), 2245 True/*isStore*/, 2246 sizeofIRType(hWordTy), 2247 env->curr_IP, layout 2248 ); 2249 env->firstRef = False; 2250 } 2251 break; 2252 2253 case Ist_WrTmp: { 2254 IRExpr* data = st->Ist.WrTmp.data; 2255 if (data->tag == Iex_Load) { 2256 tl_assert(env->curr_IP_known); 2257 if (env->firstRef) { 2258 instrument_mem_access( 2259 env, sbOut, 2260 data->Iex.Load.addr, 2261 sizeofIRType(data->Iex.Load.ty), 2262 False/*!isStore*/, 2263 sizeofIRType(hWordTy), 2264 env->curr_IP, layout 2265 ); 2266 env->firstRef = False; 2267 } 2268 } 2269 break; 2270 } 2271 2272 case Ist_Dirty: { 2273 Int dataSize; 2274 IRDirty* d = st->Ist.Dirty.details; 2275 if (d->mFx != Ifx_None) { 2276 /* This dirty helper accesses memory. Collect the 2277 details. */ 2278 tl_assert(env->curr_IP_known); 2279 if (env->firstRef) { 2280 tl_assert(d->mAddr != NULL); 2281 tl_assert(d->mSize != 0); 2282 dataSize = d->mSize; 2283 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify) { 2284 instrument_mem_access( 2285 env, sbOut, d->mAddr, dataSize, False/*!isStore*/, 2286 sizeofIRType(hWordTy), env->curr_IP, layout 2287 ); 2288 } 2289 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify) { 2290 instrument_mem_access( 2291 env, sbOut, d->mAddr, dataSize, True/*isStore*/, 2292 sizeofIRType(hWordTy), env->curr_IP, layout 2293 ); 2294 } 2295 env->firstRef = False; 2296 } 2297 } else { 2298 tl_assert(d->mAddr == NULL); 2299 tl_assert(d->mSize == 0); 2300 } 2301 break; 2302 } 2303 2304 case Ist_CAS: { 2305 /* We treat it as a read and a write of the location. I 2306 think that is the same behaviour as it was before IRCAS 2307 was introduced, since prior to that point, the Vex front 2308 ends would translate a lock-prefixed instruction into a 2309 (normal) read followed by a (normal) write. */ 2310 if (env->firstRef) { 2311 Int dataSize; 2312 IRCAS* cas = st->Ist.CAS.details; 2313 tl_assert(cas->addr != NULL); 2314 tl_assert(cas->dataLo != NULL); 2315 dataSize = sizeofIRType(typeOfIRExpr(sbOut->tyenv, cas->dataLo)); 2316 if (cas->dataHi != NULL) 2317 dataSize *= 2; /* since it's a doubleword-CAS */ 2318 instrument_mem_access( 2319 env, sbOut, cas->addr, dataSize, False/*!isStore*/, 2320 sizeofIRType(hWordTy), env->curr_IP, layout 2321 ); 2322 instrument_mem_access( 2323 env, sbOut, cas->addr, dataSize, True/*isStore*/, 2324 sizeofIRType(hWordTy), env->curr_IP, layout 2325 ); 2326 env->firstRef = False; 2327 } 2328 break; 2329 } 2330 2331 default: 2332 tl_assert(0); 2333 2334 } /* switch (st->tag) */ 2335 } 2336 2337 2338 /* Add instrumentation for the final jump of an IRSB 'sbOut', and 2339 possibly modify 'env' as required. This must be the last 2340 instrumentation statement in the block. */ 2341 void sg_instrument_final_jump ( /*MOD*/struct _SGEnv * env, 2342 /*MOD*/IRSB* sbOut, 2343 IRExpr* next, 2344 IRJumpKind jumpkind, 2345 const VexGuestLayout* layout, 2346 IRType gWordTy, IRType hWordTy ) 2347 { 2348 if (!sg_clo_enable_sg_checks) 2349 return; 2350 2351 if (jumpkind == Ijk_Call) { 2352 // Assumes x86 or amd64 2353 IRTemp sp_post_call_insn, fp_post_call_insn; 2354 XArray* frameBlocks; 2355 IRExpr** args; 2356 IRDirty* di; 2357 sp_post_call_insn 2358 = gen_Get_SP( env, sbOut, layout, sizeofIRType(hWordTy) ); 2359 fp_post_call_insn 2360 = gen_Get_FP( env, sbOut, layout, sizeofIRType(hWordTy) ); 2361 tl_assert(env->curr_IP_known); 2362 frameBlocks = get_StackBlocks_for_IP( env->curr_IP ); 2363 tl_assert(frameBlocks); 2364 if (VG_(sizeXA)(frameBlocks) == 0) 2365 frameBlocks = NULL; 2366 args 2367 = mkIRExprVec_5( 2368 IRExpr_RdTmp(sp_post_call_insn), 2369 IRExpr_RdTmp(fp_post_call_insn), 2370 /* assume the call doesn't change FP */ 2371 next, 2372 mkIRExpr_HWord( (HWord)frameBlocks ), 2373 mkIRExpr_HWord( sizeofIRType(gWordTy) ) 2374 ); 2375 di = unsafeIRDirty_0_N( 2376 3/*regparms*/, 2377 "helperc__new_frame", 2378 VG_(fnptr_to_fnentry)( &helperc__new_frame ), 2379 args ); 2380 addStmtToIRSB( sbOut, IRStmt_Dirty(di) ); 2381 } 2382 } 2383 2384 2385 ////////////////////////////////////////////////////////////// 2386 // // 2387 // end Instrumentation // 2388 // // 2389 ////////////////////////////////////////////////////////////// 2390 2391 2392 ////////////////////////////////////////////////////////////// 2393 // // 2394 // misc // 2395 // // 2396 ////////////////////////////////////////////////////////////// 2397 2398 /* Make a new empty stack frame that is suitable for being the 2399 outermost frame in a stack. It has a creation_sp of effectively 2400 infinity, so it can never be removed. */ 2401 static StackFrame* new_root_StackFrame ( void ) 2402 { 2403 StackFrame* sframe = sg_malloc("di.sg_main.nrS.1", sizeof(StackFrame)); 2404 VG_(memset)( sframe, 0, sizeof(*sframe) ); 2405 sframe->creation_sp = ~0UL; 2406 2407 /* This sets up .htab, .htab_size and .htab_used */ 2408 initialise_II_hash_table( sframe ); 2409 2410 /* ->depth, ->outer, ->inner are 0, NULL, NULL */ 2411 2412 return sframe; 2413 } 2414 2415 /* Primary routine for setting up the shadow stack for a new thread. 2416 Note that this is used to create not only child thread stacks, but 2417 the root thread's stack too. We create a new stack with 2418 .creation_sp set to infinity, so that the outermost frame can never 2419 be removed (by shadowStack_unwind). The core calls this function 2420 as soon as a thread is created. We cannot yet get its SP value, 2421 since that may not yet be set. */ 2422 static void shadowStack_thread_create ( ThreadId parent, ThreadId child ) 2423 { 2424 tl_assert(is_sane_TId(child)); 2425 if (parent == VG_INVALID_THREADID) { 2426 /* creating the main thread's stack */ 2427 } else { 2428 tl_assert(is_sane_TId(parent)); 2429 tl_assert(parent != child); 2430 tl_assert(shadowStacks[parent] != NULL); 2431 tl_assert(siTrees[parent] != NULL); 2432 } 2433 2434 /* Create the child's stack. Bear in mind we may be re-using 2435 it. */ 2436 if (shadowStacks[child] == NULL) { 2437 /* First use of this stack. Just allocate an initial frame. */ 2438 tl_assert(siTrees[child] == NULL); 2439 } else { 2440 StackFrame *frame, *frame2; 2441 /* re-using a stack. */ 2442 /* get rid of the interval tree */ 2443 tl_assert(siTrees[child] != NULL); 2444 delete_StackTree( siTrees[child] ); 2445 siTrees[child] = NULL; 2446 /* Throw away all existing frames. */ 2447 frame = shadowStacks[child]; 2448 while (frame->outer) 2449 frame = frame->outer; 2450 tl_assert(frame->depth == 0); 2451 while (frame) { 2452 frame2 = frame->inner; 2453 if (frame2) tl_assert(1 + frame->depth == frame2->depth); 2454 sg_free(frame); 2455 frame = frame2; 2456 } 2457 shadowStacks[child] = NULL; 2458 } 2459 2460 tl_assert(shadowStacks[child] == NULL); 2461 tl_assert(siTrees[child] == NULL); 2462 2463 /* Set up the initial stack frame. */ 2464 shadowStacks[child] = new_root_StackFrame(); 2465 2466 /* and set up the child's stack block interval tree. */ 2467 siTrees[child] = new_StackTree(); 2468 } 2469 2470 /* Once a thread is ready to go, the core calls here. We take the 2471 opportunity to push a second frame on its stack, with the 2472 presumably valid SP value that is going to be used for the thread's 2473 startup. Hence we should always wind up with a valid outermost 2474 frame for the thread. */ 2475 static void shadowStack_set_initial_SP ( ThreadId tid ) 2476 { 2477 StackFrame* sf; 2478 tl_assert(is_sane_TId(tid)); 2479 sf = shadowStacks[tid]; 2480 tl_assert(sf != NULL); 2481 tl_assert(sf->outer == NULL); 2482 tl_assert(sf->inner == NULL); 2483 tl_assert(sf->creation_sp == ~0UL); 2484 shadowStack_new_frame( tid, 0, VG_(get_SP)(tid), 2485 0, VG_(get_IP)(tid), NULL ); 2486 } 2487 2488 2489 ////////////////////////////////////////////////////////////// 2490 // // 2491 // main-ish // 2492 // // 2493 ////////////////////////////////////////////////////////////// 2494 2495 /* CALLED indirectly FROM GENERATED CODE. Calls here are created by 2496 sp-change analysis, as requested in pc_pre_clo_int(). */ 2497 void sg_die_mem_stack ( Addr old_SP, SizeT len ) { 2498 ThreadId tid = VG_(get_running_tid)(); 2499 shadowStack_unwind( tid, old_SP+len ); 2500 } 2501 2502 void sg_pre_clo_init ( void ) { 2503 ourGlobals_init(); 2504 init_StackBlocks_set(); 2505 init_GlobalBlock_set(); 2506 } 2507 2508 void sg_post_clo_init ( void ) { 2509 } 2510 2511 void sg_pre_thread_ll_create ( ThreadId parent, ThreadId child ) { 2512 shadowStack_thread_create(parent, child); 2513 } 2514 2515 void sg_pre_thread_first_insn ( ThreadId tid ) { 2516 shadowStack_set_initial_SP(tid); 2517 } 2518 2519 void sg_fini(Int exitcode) 2520 { 2521 if (VG_(clo_stats)) { 2522 VG_(message)(Vg_DebugMsg, 2523 " sg_: %'llu total accesses, of which:\n", stats__total_accesses); 2524 VG_(message)(Vg_DebugMsg, 2525 " sg_: stack0: %'12llu classify\n", 2526 stats__classify_Stack0); 2527 VG_(message)(Vg_DebugMsg, 2528 " sg_: stackN: %'12llu classify\n", 2529 stats__classify_StackN); 2530 VG_(message)(Vg_DebugMsg, 2531 " sg_: global: %'12llu classify\n", 2532 stats__classify_Global); 2533 VG_(message)(Vg_DebugMsg, 2534 " sg_: unknown: %'12llu classify\n", 2535 stats__classify_Unknown); 2536 VG_(message)(Vg_DebugMsg, 2537 " sg_: %'llu Invars preened, of which %'llu changed\n", 2538 stats__Invars_preened, stats__Invars_changed); 2539 VG_(message)(Vg_DebugMsg, 2540 " sg_: t_i_b_MT: %'12llu\n", stats__t_i_b_empty); 2541 VG_(message)(Vg_DebugMsg, 2542 " sg_: qcache: %'llu searches, %'llu probes, %'llu misses\n", 2543 stats__qcache_queries, stats__qcache_probes, stats__qcache_misses); 2544 VG_(message)(Vg_DebugMsg, 2545 " sg_: htab-fast: %'llu hits\n", 2546 stats__htab_fast); 2547 VG_(message)(Vg_DebugMsg, 2548 " sg_: htab-slow: %'llu searches, %'llu probes, %'llu resizes\n", 2549 stats__htab_searches, stats__htab_probes, stats__htab_resizes); 2550 } 2551 } 2552 2553 2554 /*--------------------------------------------------------------------*/ 2555 /*--- end sg_main.c ---*/ 2556 /*--------------------------------------------------------------------*/ 2557