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-2013 OpenWorks Ltd
13 info@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
is_sane_TId(ThreadId tid)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
sg_malloc(const HChar * cc,SizeT n)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
sg_free(void * p)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
cmp_nonempty_intervals(Addr a1,SizeT n1,Addr a2,SizeT n2)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
is_subinterval_of(Addr aBig,SizeT nBig,Addr aSmall,SizeT nSmall)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
Addr__min(Addr a1,Addr a2)114 static Addr Addr__min ( Addr a1, Addr a2 ) {
115 return a1 < a2 ? a1 : a2;
116 }
117
118 inline
Addr__max(Addr a1,Addr a2)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
StackBlock__sane(const StackBlock * fb)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. */
StackBlock__cmp(const StackBlock * fb1,const StackBlock * fb2)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. */
StackBlock__all_fields_except_szB_are_equal(StackBlock * fb1,StackBlock * fb2)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. */
StackBlocks__cmp(XArray * fb1s,XArray * fb2s)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
pp_StackBlocks(XArray * sbs)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
init_StackBlocks_set(void)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 */
StackBlocks__find_and_dealloc__or_add(XArray * orig)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
get_StackBlocks_for_IP(Addr ip)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. */
GlobalBlock__cmp(GlobalBlock * gb1,GlobalBlock * gb2)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
init_GlobalBlock_set(void)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
get_persistent_GlobalBlock(GlobalBlock * orig)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
pp_StackTree(WordFM * sitree,const HChar * who)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 */
cmp_intervals_StackTreeNode(StackTreeNode * sn1,StackTreeNode * sn2)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. */
find_StackTreeNode(WordFM * sitree,Addr a)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))
add_blocks_to_StackTree(WordFM * sitree,XArray * descrs,XArray * bases,UWord depth)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
del_blocks_from_StackTree(WordFM * sitree,XArray * bases)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
delete_StackTree__kFin(UWord keyW)592 static void delete_StackTree__kFin ( UWord keyW ) {
593 StackTreeNode* nd = (StackTreeNode*)keyW;
594 tl_assert(nd);
595 sg_free(nd);
596 }
delete_StackTree__vFin(UWord valW)597 static void delete_StackTree__vFin ( UWord valW ) {
598 tl_assert(valW == 0);
599 }
delete_StackTree(WordFM * sitree)600 static void delete_StackTree ( WordFM* sitree )
601 {
602 VG_(deleteFM)( sitree,
603 delete_StackTree__kFin, delete_StackTree__vFin );
604 }
605
new_StackTree(void)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
GlobalTreeNode__pp(GlobalTreeNode * nd)632 static void GlobalTreeNode__pp ( GlobalTreeNode* nd ) {
633 tl_assert(nd->descr);
634 VG_(printf)("GTNode [%#lx,+%ld) %s",
635 nd->addr, nd->szB, nd->descr->name);
636 }
637
GlobalTree__pp(WordFM * gitree,const HChar * who)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 */
cmp_intervals_GlobalTreeNode(GlobalTreeNode * gn1,GlobalTreeNode * gn2)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. */
find_GlobalTreeNode(WordFM * gitree,Addr a)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. */
add_block_to_GlobalTree(WordFM * gitree,GlobalBlock * descr)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
del_GlobalTree_range(WordFM * gitree,Addr a,SizeT szB)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. */
pp_Invar(Invar * i)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. */
eq_Invar(Invar * i1,Invar * i2)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 */
gen_delta_str(HChar * buf,UWord * absDelta,Invar * inv,Addr ea)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. */
show_Invar(HChar * buf,Word nBuf,Invar * inv,Word depth)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
QCache__invalidate(QCache * qc)1013 static void QCache__invalidate ( QCache* qc ) {
1014 tl_assert(qc->nInUse >= 0);
1015 qc->nInUse = 0;
1016 }
1017
QCache__pp(QCache * qc,const HChar * who)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
invalidate_all_QCaches(void)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
ourGlobals_init(void)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
acquire_globals(ULong di_handle)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. */
sg_new_mem_mmap(Addr a,SizeT len,Bool rr,Bool ww,Bool xx,ULong di_handle)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 }
sg_new_mem_startup(Addr a,SizeT len,Bool rr,Bool ww,Bool xx,ULong di_handle)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 }
sg_die_mem_munmap(Addr a,SizeT len)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))
preen_global_Invar(Invar * inv,Addr a,SizeT len)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))
preen_global_Invars(Addr a,SizeT len)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 */
compute_II_hash(Addr ip,UWord htab_size)1323 inline static UWord compute_II_hash ( Addr ip, UWord htab_size ) {
1324 return (ip >> 0) & (htab_size - 1);
1325 }
1326
1327 __attribute__((noinline))
initialise_II_hash_table(StackFrame * sf)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))
resize_II_hash_table(StackFrame * sf)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))
find_or_create_IInstance_SLOW(StackFrame * sf,Addr ip,XArray * ip_frameblocks)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
find_or_create_IInstance(StackFrame * sf,Addr ip,XArray * ip_frameblocks)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))
calculate_StackBlock_EA(StackBlock * descr,Addr sp,Addr fp)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))
calculate_StackBlock_EAs(XArray * blocks,Addr sp,Addr fp)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))
classify_address(Invar * inv,ThreadId tid,Addr ea,Addr sp,Addr fp,UWord szB,XArray * thisInstrBlocks)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 %ld %ld\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)
helperc__mem_access(Addr ea,Addr sp,Addr fp,Word sszB,Addr ip,XArray * ip_frameBlocks)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
shadowStack_new_frame(ThreadId tid,Addr sp_at_call_insn,Addr sp_post_call_insn,Addr fp_at_call_insn,Addr ip_post_call_insn,XArray * descrs_at_call_insn)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 %ld, GlobalTree %ld\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)
helperc__new_frame(Addr sp_post_call_insn,Addr fp_at_call_insn,Addr ip_post_call_insn,XArray * blocks_at_call_insn,Word sp_adjust)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))
shadowStack_unwind(ThreadId tid,Addr sp_now)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
gen_Get_SP(struct _SGEnv * sge,IRSB * bbOut,const VexGuestLayout * layout,Int hWordTy_szB)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
gen_Get_FP(struct _SGEnv * sge,IRSB * bbOut,const VexGuestLayout * layout,Int hWordTy_szB)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
instrument_mem_access(struct _SGEnv * sge,IRSB * bbOut,IRExpr * addr,Int szB,Bool isStore,Int hWordTy_szB,Addr curr_IP,const VexGuestLayout * layout)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
sg_instrument_init(IRTemp (* newIRTemp_cb)(IRType,void *),void * newIRTemp_opaque)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
sg_instrument_fini(struct _SGEnv * env)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'. */
sg_instrument_IRStmt(struct _SGEnv * env,IRSB * sbOut,IRStmt * st,const VexGuestLayout * layout,IRType gWordTy,IRType hWordTy)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. */
sg_instrument_final_jump(struct _SGEnv * env,IRSB * sbOut,IRExpr * next,IRJumpKind jumpkind,const VexGuestLayout * layout,IRType gWordTy,IRType hWordTy)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. */
new_root_StackFrame(void)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. */
shadowStack_thread_create(ThreadId parent,ThreadId child)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. */
shadowStack_set_initial_SP(ThreadId tid)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(). */
sg_die_mem_stack(Addr old_SP,SizeT len)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
sg_pre_clo_init(void)2502 void sg_pre_clo_init ( void ) {
2503 ourGlobals_init();
2504 init_StackBlocks_set();
2505 init_GlobalBlock_set();
2506 }
2507
sg_post_clo_init(void)2508 void sg_post_clo_init ( void ) {
2509 }
2510
sg_pre_thread_ll_create(ThreadId parent,ThreadId child)2511 void sg_pre_thread_ll_create ( ThreadId parent, ThreadId child ) {
2512 shadowStack_thread_create(parent, child);
2513 }
2514
sg_pre_thread_first_insn(ThreadId tid)2515 void sg_pre_thread_first_insn ( ThreadId tid ) {
2516 shadowStack_set_initial_SP(tid);
2517 }
2518
sg_fini(Int exitcode)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