| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 1 |  | 
 | 2 | /*--------------------------------------------------------------------*/ | 
 | 3 | /*--- Ptrcheck: a pointer-use checker.                             ---*/ | 
 | 4 | /*--- This file checks heap accesses.                              ---*/ | 
 | 5 | /*---                                                     h_main.c ---*/ | 
 | 6 | /*--------------------------------------------------------------------*/ | 
 | 7 |  | 
 | 8 | /* | 
 | 9 |    This file is part of Ptrcheck, a Valgrind tool for checking pointer | 
 | 10 |    use in programs. | 
 | 11 |  | 
 | 12 |    Initial version (Annelid): | 
 | 13 |  | 
 | 14 |    Copyright (C) 2003-2008 Nicholas Nethercote | 
 | 15 |       njn@valgrind.org | 
 | 16 |  | 
 | 17 |    Valgrind-3.X port: | 
 | 18 |  | 
 | 19 |    Copyright (C) 2008-2008 OpenWorks Ltd | 
 | 20 |       info@open-works.co.uk | 
 | 21 |  | 
 | 22 |    This program is free software; you can redistribute it and/or | 
 | 23 |    modify it under the terms of the GNU General Public License as | 
 | 24 |    published by the Free Software Foundation; either version 2 of the | 
 | 25 |    License, or (at your option) any later version. | 
 | 26 |  | 
 | 27 |    This program is distributed in the hope that it will be useful, but | 
 | 28 |    WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 29 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 30 |    General Public License for more details. | 
 | 31 |  | 
 | 32 |    You should have received a copy of the GNU General Public License | 
 | 33 |    along with this program; if not, write to the Free Software | 
 | 34 |    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | 
 | 35 |    02111-1307, USA. | 
 | 36 |  | 
 | 37 |    The GNU General Public License is contained in the file COPYING. | 
 | 38 | */ | 
 | 39 |  | 
 | 40 | // FIXME: 64-bit cleanness, check the following | 
 | 41 | // struct _ISNode.ownerCount is 32-bit | 
 | 42 | // struct _ISNode.topLevel is 32-bit | 
 | 43 | // or is that not really right now?  add assertion checks about | 
 | 44 | // the max size of a node | 
 | 45 |  | 
 | 46 | // FIXME: should we shadow %RIP?  Maybe not. | 
 | 47 |  | 
 | 48 | // FIXME: shadows of temporaries created in preamble, a la memcheck? | 
 | 49 |  | 
 | 50 | // FIXME: result of add_new_segment is always ignored | 
 | 51 |  | 
 | 52 | // FIXME: the mechanism involving last_seg_added is really ugly. | 
 | 53 | // Do something cleaner. | 
 | 54 |  | 
 | 55 | // FIXME: post_reg_write_clientcall: check function pointer comparisons | 
 | 56 | // are safe on toc-afflicted platforms | 
 | 57 |  | 
 | 58 | // FIXME: tidy up findShadowTmp | 
 | 59 |  | 
 | 60 | // FIXME: post_reg_write_demux(Vg_CoreSysCall) is redundant w.r.t. | 
 | 61 | // the default 'NONPTR' behaviour of post_syscall.  post_reg_write_demux | 
 | 62 | // is called first, then post_syscall. | 
 | 63 |  | 
 | 64 | // FIXME: check nothing is mapped in the lowest 1M of memory at | 
 | 65 | // startup, or quit (to do with nonptr_or_unknown, also sync 1M | 
 | 66 | // magic value with PIE default load address in m_ume.c. | 
 | 67 |  | 
 | 68 | // FIXME: consider whether we could paint memory acquired from | 
 | 69 | // sys_read etc as NONPTR rather than UNKNOWN. | 
 | 70 |  | 
 | 71 | // XXX: recycle freed segments | 
 | 72 |  | 
 | 73 | //-------------------------------------------------------------- | 
 | 74 | // Metadata: | 
 | 75 | //   HeapBlock.id :: Seg (stored as heap shadowchunk; always non-zero) | 
 | 76 | //   MemLoc.aseg  :: Seg (implicitly stored) | 
 | 77 | //   MemLoc.vseg  :: Seg (explicitly stored as the shadow memory) | 
 | 78 | //   RegLoc.vseg  :: Seg (explicitly stored as shadow registers) | 
 | 79 | // | 
 | 80 | // A Seg is made when new memory is created, eg. with malloc() or mmap(). | 
 | 81 | // There are two other Segs: | 
 | 82 | //  - NONPTR:  for something that's definitely not a pointer | 
 | 83 | //  - UNKNOWN: for something that could be a pointer | 
 | 84 | //  - BOTTOM:  used with pointer differences (see below) | 
 | 85 | // | 
 | 86 | // MemLoc.vseg is done at word granularity.  If a pointer is written | 
 | 87 | // to memory misaligned, the information about it will be lost -- it's | 
 | 88 | // treated as two sub-word writes to two adjacent words.  This avoids | 
 | 89 | // certain nasty cases that could arise if we tried to track unaligned | 
 | 90 | // pointers.  Fortunately, misalignment is rare so we don't lose much | 
 | 91 | // information this way. | 
 | 92 | // | 
 | 93 | // MemLoc.aseg is done at byte granularity, and *implicitly* -- ie. not | 
 | 94 | // directly accessible like MemLoc.vseg, but only by searching through all | 
 | 95 | // the segments.  Fortunately, it's mostly checked at LOADs/STOREs;  at that | 
 | 96 | // point we have a pointer p to the MemLoc m as the other arg of the | 
 | 97 | // LOAD/STORE, so we can check to see if the p.vseg's range includes m.  If | 
 | 98 | // not, it's an error and we have to search through all segments to find out | 
 | 99 | // what m.aseg really is.  That's still pretty fast though, thanks to the | 
 | 100 | // interval skip-list used.  With syscalls we must also do the skip-list | 
 | 101 | // search, but only on the first and last bytes touched. | 
 | 102 | //-------------------------------------------------------------- | 
 | 103 |  | 
 | 104 | //-------------------------------------------------------------- | 
 | 105 | // Assumptions, etc: | 
 | 106 | // - see comment at top of SK_(instrument)() for how sub-word ops are | 
 | 107 | //   handled. | 
 | 108 | // | 
 | 109 | // - ioctl(), socketcall() (and ipc() will be) assumed to return non-pointers | 
 | 110 | // | 
 | 111 | // - FPU_W is assumed to never write pointers. | 
 | 112 | // | 
 | 113 | // - Assuming none of the post_mem_writes create segments worth tracking. | 
 | 114 | // | 
 | 115 | // - Treating mmap'd segments (all! including code) like heap segments.  But | 
 | 116 | //   their ranges can change, new ones can be created by unmapping parts of | 
 | 117 | //   old segments, etc.  But this nasty behaviour seems to never happen --  | 
 | 118 | //   there are assertions checking it. | 
 | 119 | //-------------------------------------------------------------- | 
 | 120 |  | 
 | 121 | //-------------------------------------------------------------- | 
 | 122 | // What I am checking: | 
 | 123 | // - Type errors: | 
 | 124 | //    * ADD, OR, LEA2: error if two pointer inputs. | 
 | 125 | //    * ADC, SBB: error if one or two pointer inputs. | 
 | 126 | //    * AND, OR: error if two unequal pointer inputs. | 
 | 127 | //    * NEG: error if pointer input. | 
 | 128 | //    * {,i}mul_32_64 if either input is a pointer. | 
 | 129 | //    * shldl/shrdl, bsf/bsr if any inputs are pointers. | 
 | 130 | // | 
 | 131 | // - LOAD, STORE: | 
 | 132 | //    * ptr.vseg must match ptee.aseg. | 
 | 133 | //    * ptee.aseg must not be a freed segment. | 
 | 134 | // | 
 | 135 | // - syscalls: for those accessing memory, look at first and last bytes: | 
 | 136 | //    * check first.aseg == last.aseg | 
 | 137 | //    * check first.aseg and last.aseg are not freed segments. | 
 | 138 | // | 
 | 139 | // What I am not checking, that I expected to when I started: | 
 | 140 | // - AND, XOR: allowing two pointers to be used if both from the same segment, | 
 | 141 | //   because "xor %r,%r" is commonly used to zero %r, and "test %r,%r" | 
 | 142 | //   (which is translated with an AND) is common too. | 
 | 143 | // | 
 | 144 | // - div_64_32/idiv_64_32 can take pointer inputs for the dividend; | 
 | 145 | //   division doesn't make sense, but modulo does, and they're done with the | 
 | 146 | //   same instruction.  (Could try to be super-clever and watch the outputs | 
 | 147 | //   to see if the quotient is used, but not worth it.) | 
 | 148 | // | 
 | 149 | // - mul_64_32/imul_64_32 can take pointers inputs for one arg or the | 
 | 150 | //   other, but not both.  This is because some programs (eg. Mozilla | 
 | 151 | //   Firebird) multiply pointers in hash routines. | 
 | 152 | // | 
 | 153 | // - NEG: can take a pointer.  It happens in glibc in a few places.  I've | 
 | 154 | //   seen the code, didn't understand it, but it's done deliberately. | 
 | 155 | // | 
 | 156 | // What I am not checking/doing, but could, but it would require more | 
 | 157 | // instrumentation and/or slow things down a bit: | 
 | 158 | // - SUB: when differencing two pointers, result is BOTTOM, ie. "don't | 
 | 159 | //   check".  Could link segments instead, slower but a bit more accurate. | 
 | 160 | //   Also use BOTTOM when doing (ptr - unknown), which could be a pointer | 
 | 161 | //   difference with a stack/static pointer. | 
 | 162 | // | 
 | 163 | // - PUTF: input should be non-pointer | 
 | 164 | // | 
 | 165 | // - arithmetic error messages: eg. for adding two pointers, just giving the | 
 | 166 | //   segments, not the actual pointers. | 
 | 167 | // | 
 | 168 | // What I am not checking, and would be difficult: | 
 | 169 | // - mmap(...MAP_FIXED...) is not handled specially.  It might be used in | 
 | 170 | //   ways that fool Ptrcheck into giving false positives. | 
 | 171 | // | 
 | 172 | // - syscalls: for those accessing memory, not checking that the asegs of the | 
 | 173 | //   accessed words match the vseg of the accessing pointer, because the | 
 | 174 | //   vseg is not easily accessible at the required time (would required | 
 | 175 | //   knowing for every syscall which register each arg came in, and looking | 
 | 176 | //   there). | 
 | 177 | // | 
 | 178 | // What I am not checking, and would be difficult, but doesn't matter: | 
 | 179 | // - free(p): similar to syscalls, not checking that the p.vseg matches the | 
 | 180 | //   aseg of the first byte in the block.  However, Memcheck does an | 
 | 181 | //   equivalent "bad free" check using shadow_chunks;  indeed, Ptrcheck could | 
 | 182 | //   do the same check, but there's no point duplicating functionality.  So | 
 | 183 | //   no loss, really. | 
 | 184 | // | 
 | 185 | // Other: | 
 | 186 | // - not doing anything with mprotect();  probably not worth the effort. | 
 | 187 | //-------------------------------------------------------------- | 
 | 188 |  | 
 | 189 | //-------------------------------------------------------------- | 
 | 190 | // Todo: | 
 | 191 | // - Segments for stack frames.  Would detect (some, large) stack | 
 | 192 | //   over/under-runs, dangling pointers. | 
 | 193 | // | 
 | 194 | // - Segments for static data.  Would detect over/under-runs.  Requires | 
 | 195 | //   reading debug info. | 
 | 196 | //-------------------------------------------------------------- | 
 | 197 |  | 
 | 198 | //-------------------------------------------------------------- | 
 | 199 | // Some profiling results: | 
 | 200 | //                                                 twolf   konq    date sz | 
 | 201 | // 1. started                                              35.0s   14.7 | 
 | 202 | // 2. introduced GETV/PUTV                                 30.2s   10.1 | 
 | 203 | // 3. inlined check_load_or_store                  5.6s    27.5s   10.1 | 
 | 204 | // 4. (made check_load, check_store4 regparm(0))          (27.9s) (11.0) | 
 | 205 | // 5. um, not sure                                 5.3s    27.3s   10.6 | 
 | 206 | //    ... | 
 | 207 | // 6. after big changes, corrections              11.2s    32.8s   14.0 | 
 | 208 | // 7. removed link-segment chasing in check/L/S    8.9s    30.8s   14.0 | 
 | 209 | // 8. avoiding do_lea1 if k is a nonptr            8.0s    28.0s   12.9 | 
 | 210 | //-------------------------------------------------------------- | 
 | 211 |  | 
 | 212 | //#include "vg_skin.h" | 
 | 213 |  | 
 | 214 | #include "pub_tool_basics.h" | 
 | 215 | #include "pub_tool_libcbase.h" | 
 | 216 | #include "pub_tool_libcprint.h" | 
 | 217 | #include "pub_tool_libcassert.h" | 
 | 218 | #include "pub_tool_mallocfree.h" | 
 | 219 | #include "pub_tool_execontext.h" | 
 | 220 | #include "pub_tool_hashtable.h" | 
 | 221 | #include "pub_tool_tooliface.h" | 
 | 222 | #include "pub_tool_replacemalloc.h" | 
 | 223 | #include "pub_tool_options.h" | 
 | 224 | #include "pub_tool_execontext.h" | 
 | 225 | #include "pub_tool_aspacemgr.h"    // VG_(am_shadow_malloc) | 
 | 226 | #include "pub_tool_vki.h"          // VKI_MAX_PAGE_SIZE | 
 | 227 | #include "pub_tool_machine.h"      // VG_({get,set}_shadow_regs_area) et al | 
 | 228 | #include "pub_tool_debuginfo.h"    // VG_(get_fnname) | 
 | 229 | #include "pub_tool_threadstate.h"  // VG_(get_running_tid) | 
 | 230 | #include "pub_tool_oset.h" | 
 | 231 | #include "pub_tool_vkiscnums.h" | 
 | 232 | #include "pub_tool_machine.h" | 
 | 233 | #include "pub_tool_wordfm.h" | 
 | 234 | #include "pub_tool_xarray.h" | 
 | 235 |  | 
 | 236 | #include "pc_common.h" | 
 | 237 |  | 
 | 238 | //#include "h_list.h" | 
 | 239 | #include "h_main.h" | 
 | 240 |  | 
 | 241 | #include "sg_main.h"   // sg_instrument_*, and struct _SGEnv | 
 | 242 |  | 
 | 243 |  | 
 | 244 |  | 
 | 245 | /*------------------------------------------------------------*/ | 
 | 246 | /*--- Debug/trace options                                  ---*/ | 
 | 247 | /*------------------------------------------------------------*/ | 
 | 248 |  | 
 | 249 | /* Set to 1 to do sanity checks on Seg values in many places, which | 
 | 250 |    checks if bogus Segs are in circulation.  Quite expensive from a | 
 | 251 |    performance point of view. */ | 
 | 252 | #define SC_SEGS 0 | 
 | 253 |  | 
 | 254 | static ULong stats__client_mallocs = 0; | 
 | 255 | static ULong stats__client_frees   = 0; | 
 | 256 | static ULong stats__segs_allocd    = 0; | 
 | 257 | static ULong stats__segs_recycled  = 0; | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 258 |  | 
 | 259 |  | 
 | 260 | ////////////////////////////////////////////////////////////// | 
 | 261 | //                                                          // | 
 | 262 | // Segments low level storage                               // | 
 | 263 | //                                                          // | 
 | 264 | ////////////////////////////////////////////////////////////// | 
 | 265 |  | 
 | 266 | // NONPTR, UNKNOWN, BOTTOM defined in h_main.h since  | 
 | 267 | // pc_common.c needs to see them, for error processing | 
 | 268 |  | 
 | 269 | // we only start recycling segs when this many exist | 
 | 270 | #define N_FREED_SEGS (1 * 1000 * 1000) | 
 | 271 |  | 
 | 272 | struct _Seg { | 
 | 273 |    Addr  addr; | 
 | 274 |    SizeT szB; /* may be zero */ | 
 | 275 |    ExeContext* ec;  /* where malloc'd or freed */ | 
 | 276 |    /* When 1, indicates block is in use.  Otherwise, used to form a | 
 | 277 |       linked list of freed blocks, running from oldest freed block to | 
 | 278 |       the most recently freed block. */ | 
 | 279 |    struct _Seg* nextfree; | 
 | 280 | }; | 
 | 281 |  | 
 | 282 | // Determines if 'a' is before, within, or after seg's range.  Sets 'cmp' to | 
 | 283 | // -1/0/1 accordingly.  Sets 'n' to the number of bytes before/within/after. | 
 | 284 | void Seg__cmp(Seg* seg, Addr a, Int* cmp, UWord* n) | 
 | 285 | { | 
 | 286 |    if (a < seg->addr) { | 
 | 287 |       *cmp = -1; | 
 | 288 |       *n   = seg->addr - a; | 
 | 289 |    } else if (a < seg->addr + seg->szB && seg->szB > 0) { | 
 | 290 |       *cmp = 0; | 
 | 291 |       *n = a - seg->addr; | 
 | 292 |    } else { | 
 | 293 |       *cmp = 1; | 
 | 294 |       *n = a - (seg->addr + seg->szB); | 
 | 295 |    } | 
 | 296 | } | 
 | 297 |  | 
 | 298 | inline Bool Seg__is_freed(Seg* seg) | 
 | 299 | { | 
 | 300 |    if (!is_known_segment(seg)) | 
 | 301 |       return False; | 
 | 302 |    else | 
 | 303 |       return seg->nextfree != (Seg*)1; | 
 | 304 | } | 
 | 305 |  | 
 | 306 | ExeContext* Seg__where(Seg* seg) | 
 | 307 | { | 
 | 308 |    tl_assert(is_known_segment(seg)); | 
 | 309 |    return seg->ec; | 
 | 310 | } | 
 | 311 |  | 
 | 312 | SizeT Seg__size(Seg* seg) | 
 | 313 | { | 
 | 314 |    tl_assert(is_known_segment(seg)); | 
 | 315 |    return seg->szB; | 
 | 316 | } | 
 | 317 |  | 
 | 318 | Addr Seg__addr(Seg* seg) | 
 | 319 | { | 
 | 320 |    tl_assert(is_known_segment(seg)); | 
 | 321 |    return seg->addr; | 
 | 322 | } | 
 | 323 |  | 
 | 324 |  | 
 | 325 | #define N_SEGS_PER_GROUP 10000 | 
 | 326 |  | 
 | 327 | typedef | 
 | 328 |    struct _SegGroup { | 
 | 329 |       struct _SegGroup* admin; | 
 | 330 |       UWord nextfree; /* 0 .. N_SEGS_PER_GROUP */ | 
 | 331 |       Seg segs[N_SEGS_PER_GROUP]; | 
 | 332 |    } | 
 | 333 |    SegGroup; | 
 | 334 |  | 
 | 335 | static SegGroup* group_list = NULL; | 
 | 336 | static UWord     nFreeSegs = 0; | 
 | 337 | static Seg*      freesegs_youngest = NULL; | 
 | 338 | static Seg*      freesegs_oldest = NULL; | 
 | 339 |  | 
 | 340 |  | 
 | 341 | static SegGroup* new_SegGroup ( void ) { | 
 | 342 |    SegGroup* g = VG_(malloc)("pc.h_main.nTG.1", sizeof(SegGroup)); | 
 | 343 |    VG_(memset)(g, 0, sizeof(*g)); | 
 | 344 |    return g; | 
 | 345 | } | 
 | 346 |  | 
 | 347 | /* Get a completely new Seg */ | 
 | 348 | static Seg* new_Seg ( void ) | 
 | 349 | { | 
 | 350 |    Seg*      teg; | 
 | 351 |    SegGroup* g; | 
 | 352 |    if (group_list == NULL) { | 
 | 353 |       g = new_SegGroup(); | 
 | 354 |       g->admin = NULL; | 
 | 355 |       group_list = g; | 
 | 356 |    } | 
 | 357 |    tl_assert(group_list->nextfree <= N_SEGS_PER_GROUP); | 
 | 358 |    if (group_list->nextfree == N_SEGS_PER_GROUP) { | 
 | 359 |       g = new_SegGroup(); | 
 | 360 |       g->admin = group_list; | 
 | 361 |       group_list = g; | 
 | 362 |    } | 
 | 363 |    tl_assert(group_list->nextfree < N_SEGS_PER_GROUP); | 
 | 364 |    teg = &group_list->segs[ group_list->nextfree ]; | 
 | 365 |    group_list->nextfree++; | 
 | 366 |    stats__segs_allocd++; | 
 | 367 |    return teg; | 
 | 368 | } | 
 | 369 |  | 
 | 370 | static Seg* get_Seg_for_malloc ( void ) | 
 | 371 | { | 
 | 372 |    Seg* seg; | 
 | 373 |    if (nFreeSegs < N_FREED_SEGS) { | 
 | 374 |       seg = new_Seg(); | 
 | 375 |       seg->nextfree = (Seg*)1; | 
 | 376 |       return seg; | 
 | 377 |    } | 
 | 378 |    /* else recycle the oldest Seg in the free list */ | 
 | 379 |    tl_assert(freesegs_youngest); | 
 | 380 |    tl_assert(freesegs_oldest); | 
 | 381 |    tl_assert(freesegs_youngest != freesegs_oldest); | 
 | 382 |    seg = freesegs_oldest; | 
 | 383 |    freesegs_oldest = seg->nextfree; | 
 | 384 |    nFreeSegs--; | 
 | 385 |    seg->nextfree = (Seg*)1; | 
 | 386 |    stats__segs_recycled++; | 
 | 387 |    return seg; | 
 | 388 | } | 
 | 389 |  | 
 | 390 | static void set_Seg_freed ( Seg* seg ) | 
 | 391 | { | 
 | 392 |    tl_assert(seg); | 
 | 393 |    tl_assert(!Seg__is_freed(seg)); | 
 | 394 |    if (nFreeSegs == 0) { | 
 | 395 |       tl_assert(freesegs_oldest == NULL); | 
 | 396 |       tl_assert(freesegs_youngest == NULL); | 
 | 397 |       seg->nextfree = NULL; | 
 | 398 |       freesegs_youngest = seg; | 
 | 399 |       freesegs_oldest = seg; | 
 | 400 |       nFreeSegs++; | 
 | 401 |    } else { | 
 | 402 |       tl_assert(freesegs_youngest); | 
 | 403 |       tl_assert(freesegs_oldest); | 
 | 404 |       if (nFreeSegs == 1) { | 
 | 405 |          tl_assert(freesegs_youngest == freesegs_oldest); | 
 | 406 |       } else { | 
 | 407 |          tl_assert(freesegs_youngest != freesegs_oldest); | 
 | 408 |       } | 
 | 409 |       tl_assert(freesegs_youngest->nextfree == NULL); | 
 | 410 |       tl_assert(seg != freesegs_youngest && seg != freesegs_oldest); | 
 | 411 |       seg->nextfree = NULL; | 
 | 412 |       freesegs_youngest->nextfree = seg; | 
 | 413 |       freesegs_youngest = seg; | 
 | 414 |       nFreeSegs++; | 
 | 415 |    } | 
 | 416 | } | 
 | 417 |  | 
| sewardj | 9520845 | 2008-10-18 19:55:31 +0000 | [diff] [blame] | 418 | static WordFM* addr_to_seg_map = NULL; /* GuestAddr -> Seg* */ | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 419 |  | 
 | 420 | static void addr_to_seg_map_ENSURE_INIT ( void ) | 
 | 421 | { | 
 | 422 |    if (UNLIKELY(addr_to_seg_map == NULL)) { | 
 | 423 |       addr_to_seg_map = VG_(newFM)( VG_(malloc), "pc.h_main.attmEI.1", | 
| sewardj | 9520845 | 2008-10-18 19:55:31 +0000 | [diff] [blame] | 424 |                                     VG_(free), NULL/*unboxedcmp*/ ); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 425 |    } | 
 | 426 | } | 
 | 427 |  | 
 | 428 | static Seg* find_Seg_by_addr ( Addr ga ) | 
 | 429 | { | 
 | 430 |    UWord keyW, valW; | 
 | 431 |    addr_to_seg_map_ENSURE_INIT(); | 
 | 432 |    if (VG_(lookupFM)( addr_to_seg_map, &keyW, &valW, (UWord)ga )) { | 
 | 433 |       tl_assert(keyW == ga); | 
 | 434 |       return (Seg*)valW; | 
 | 435 |    } else { | 
 | 436 |       return NULL; | 
 | 437 |    } | 
 | 438 | } | 
 | 439 |  | 
 | 440 | static void bind_addr_to_Seg ( Addr ga, Seg* seg ) | 
 | 441 | { | 
 | 442 |    Bool b; | 
 | 443 |    addr_to_seg_map_ENSURE_INIT(); | 
 | 444 |    b = VG_(addToFM)( addr_to_seg_map, (UWord)ga, (UWord)seg ); | 
 | 445 |    tl_assert(!b); /* else ga is already bound */ | 
 | 446 | } | 
 | 447 |  | 
 | 448 | static void unbind_addr_from_Seg ( Addr ga ) | 
 | 449 | { | 
 | 450 |    Bool b; | 
 | 451 |    UWord keyW, valW; | 
 | 452 |    addr_to_seg_map_ENSURE_INIT(); | 
 | 453 |    b = VG_(delFromFM)( addr_to_seg_map, &keyW, &valW, (UWord)ga ); | 
 | 454 |    tl_assert(b); /* else ga was not already bound */ | 
 | 455 |    tl_assert(keyW == ga); | 
 | 456 |    tl_assert(valW != 0); | 
 | 457 | } | 
 | 458 |  | 
 | 459 |  | 
 | 460 | ////////////////////////////////////////////////////////////// | 
 | 461 | ////////////////////////////////////////////////////////////// | 
 | 462 | ////////////////////////////////////////////////////////////// | 
 | 463 |  | 
 | 464 | // So that post_reg_write_clientcall knows the segment just allocated. | 
 | 465 | static Seg* last_seg_added = NULL; | 
 | 466 |  | 
 | 467 | // Returns the added heap segment | 
 | 468 | static Seg* add_new_segment ( ThreadId tid, Addr p, SizeT size ) | 
 | 469 | { | 
 | 470 |    Seg* seg = get_Seg_for_malloc(); | 
 | 471 |    tl_assert(seg != (Seg*)1); /* since we're using 1 as a special value */ | 
 | 472 |    seg->addr = p; | 
 | 473 |    seg->szB  = size; | 
 | 474 |    seg->ec   = VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ ); | 
 | 475 |    tl_assert(!Seg__is_freed(seg)); | 
 | 476 |  | 
 | 477 |    bind_addr_to_Seg(p, seg); | 
 | 478 |  | 
 | 479 |    last_seg_added = seg; | 
 | 480 |  | 
 | 481 |    return seg; | 
 | 482 | } | 
 | 483 |  | 
 | 484 | // Forward declarations | 
 | 485 | static void copy_mem( Addr from, Addr to, SizeT len ); | 
 | 486 | static void set_mem_unknown ( Addr a, SizeT len ); | 
 | 487 |  | 
 | 488 | static inline VG_REGPARM(1) Seg* nonptr_or_unknown(UWord x); /*fwds*/ | 
 | 489 |  | 
 | 490 | static | 
 | 491 | void* alloc_and_new_mem_heap ( ThreadId tid, | 
 | 492 |                                SizeT size, SizeT alignment, Bool is_zeroed ) | 
 | 493 | { | 
 | 494 |    Addr p; | 
 | 495 |  | 
 | 496 |    if ( ((SSizeT)size) < 0) return NULL; | 
 | 497 |  | 
 | 498 |    p = (Addr)VG_(cli_malloc)(alignment, size); | 
 | 499 |    if (is_zeroed) VG_(memset)((void*)p, 0, size); | 
 | 500 |  | 
 | 501 |    set_mem_unknown( p, size ); | 
 | 502 |    add_new_segment( tid, p, size ); | 
 | 503 |  | 
 | 504 |    stats__client_mallocs++; | 
 | 505 |    return (void*)p; | 
 | 506 | } | 
 | 507 |  | 
 | 508 | static void die_and_free_mem_heap ( ThreadId tid, Seg* seg ) | 
 | 509 | { | 
 | 510 |    // Empty and free the actual block | 
 | 511 |    tl_assert(!Seg__is_freed(seg)); | 
 | 512 |    set_mem_unknown( seg->addr, seg->szB ); | 
 | 513 |  | 
 | 514 |    VG_(cli_free)( (void*)seg->addr ); | 
 | 515 |  | 
 | 516 |    // Remember where freed | 
 | 517 |    seg->ec = VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ ); | 
 | 518 |  | 
 | 519 |    set_Seg_freed(seg); | 
 | 520 |    unbind_addr_from_Seg( seg->addr ); | 
 | 521 |  | 
 | 522 |    stats__client_frees++; | 
 | 523 | } | 
 | 524 |  | 
 | 525 | static void handle_free_heap( ThreadId tid, void* p ) | 
 | 526 | { | 
 | 527 |    Seg* seg = find_Seg_by_addr( (Addr)p ); | 
 | 528 |    if (!seg) { | 
 | 529 |       /* freeing a block that wasn't malloc'd.  Ignore. */ | 
 | 530 |       return; | 
 | 531 |    } | 
 | 532 |    die_and_free_mem_heap( tid, seg ); | 
 | 533 | } | 
 | 534 |  | 
 | 535 |  | 
 | 536 | /*------------------------------------------------------------*/ | 
 | 537 | /*--- Shadow memory                                        ---*/ | 
 | 538 | /*------------------------------------------------------------*/ | 
 | 539 |  | 
 | 540 | /* Shadow memory holds one Seg for each naturally aligned (guest) | 
 | 541 |    word.  For a 32 bit target (assuming host word size == guest word | 
 | 542 |    size) that means one Seg per 4 bytes, and each Seg occupies 4 | 
 | 543 |    bytes.  For a 64 bit target that means one Seg per 8 bytes, and | 
 | 544 |    each Seg occupies 8 bytes.  Hence in each case the overall space | 
 | 545 |    overhead for shadow memory is 1:1. | 
 | 546 |  | 
 | 547 |    This does however make it a bit tricky to size SecMap.vseg[], simce | 
 | 548 |    it needs to hold 16384 entries for 32 bit targets but only 8192 | 
 | 549 |    entries for 64 bit targets. */ | 
 | 550 |  | 
 | 551 | #if 0 | 
 | 552 | __attribute__((unused)) | 
 | 553 | static void pp_curr_ExeContext(void) | 
 | 554 | { | 
 | 555 |    VG_(pp_ExeContext)( | 
 | 556 |       VG_(get_ExeContext)( | 
 | 557 |          VG_(get_current_or_recent_tid)() ) ); | 
 | 558 |    VG_(message)(Vg_UserMsg, ""); | 
 | 559 | } | 
 | 560 | #endif | 
 | 561 |  | 
 | 562 | #if defined(VGA_x86) || defined(VGA_ppc32) | 
 | 563 | #  define SHMEM_SECMAP_MASK         0xFFFC | 
 | 564 | #  define SHMEM_SECMAP_SHIFT        2 | 
 | 565 | #  define SHMEM_IS_WORD_ALIGNED(_a) VG_IS_4_ALIGNED(_a) | 
 | 566 | #  define SEC_MAP_WORDS             (0x10000UL / 4UL) /* 16k */ | 
 | 567 | #elif defined(VGA_amd64) || defined(VGA_ppc64) | 
 | 568 | #  define SHMEM_SECMAP_MASK         0xFFF8 | 
 | 569 | #  define SHMEM_SECMAP_SHIFT        3 | 
 | 570 | #  define SHMEM_IS_WORD_ALIGNED(_a) VG_IS_8_ALIGNED(_a) | 
 | 571 | #  define SEC_MAP_WORDS             (0x10000UL / 8UL) /* 8k */ | 
 | 572 | #else | 
 | 573 | #  error "Unknown arch" | 
 | 574 | #endif | 
 | 575 |  | 
 | 576 | typedef | 
 | 577 |    struct { | 
 | 578 |       Seg* vseg[SEC_MAP_WORDS]; | 
 | 579 |    } | 
 | 580 |    SecMap; | 
 | 581 |  | 
 | 582 | static SecMap  distinguished_secondary_map; | 
 | 583 |  | 
 | 584 | /* An entry in the primary map.  base must be a 64k-aligned value, and | 
 | 585 |    sm points at the relevant secondary map.  The secondary may be | 
 | 586 |    either a real secondary, or the distinguished secondary.  DO NOT | 
 | 587 |    CHANGE THIS LAYOUT: the first word has to be the key for OSet fast | 
 | 588 |    lookups. | 
 | 589 | */ | 
 | 590 | typedef | 
 | 591 |    struct { | 
 | 592 |       Addr    base; | 
 | 593 |       SecMap* sm; | 
 | 594 |    } | 
 | 595 |    PriMapEnt; | 
 | 596 |  | 
 | 597 | /* Primary map is an OSet of PriMapEnt (primap_L2), "fronted" by a | 
 | 598 |    cache (primap_L1). */ | 
 | 599 |  | 
 | 600 | /* Tunable parameter: How big is the L1 queue? */ | 
 | 601 | #define N_PRIMAP_L1 24 | 
 | 602 |  | 
 | 603 | /* Tunable parameter: How far along the L1 queue to insert | 
 | 604 |    entries resulting from L2 lookups? */ | 
 | 605 | #define PRIMAP_L1_INSERT_IX 12 | 
 | 606 |  | 
 | 607 | static struct { | 
 | 608 |           Addr       base; // must be 64k aligned | 
 | 609 |           PriMapEnt* ent; // pointer to the matching primap_L2 node | 
 | 610 |        } | 
 | 611 |        primap_L1[N_PRIMAP_L1]; | 
 | 612 |  | 
 | 613 | static OSet* primap_L2 = NULL; | 
 | 614 |  | 
 | 615 |  | 
 | 616 | /* # searches initiated in auxmap_L1, and # base cmps required */ | 
 | 617 | static ULong n_primap_L1_searches  = 0; | 
 | 618 | static ULong n_primap_L1_cmps      = 0; | 
 | 619 | /* # of searches that missed in auxmap_L1 and therefore had to | 
 | 620 |    be handed to auxmap_L2. And the number of nodes inserted. */ | 
 | 621 | static ULong n_primap_L2_searches  = 0; | 
 | 622 | static ULong n_primap_L2_nodes     = 0; | 
 | 623 |  | 
 | 624 |  | 
 | 625 | static void init_shadow_memory ( void ) | 
 | 626 | { | 
 | 627 |    Int i; | 
 | 628 |  | 
 | 629 |    for (i = 0; i < SEC_MAP_WORDS; i++) | 
 | 630 |       distinguished_secondary_map.vseg[i] = NONPTR; | 
 | 631 |  | 
 | 632 |    for (i = 0; i < N_PRIMAP_L1; i++) { | 
 | 633 |       primap_L1[i].base = 1; /* not 64k aligned, so doesn't match any | 
 | 634 |                                 request ==> slot is empty */ | 
 | 635 |       primap_L1[i].ent  = NULL; | 
 | 636 |    } | 
 | 637 |  | 
 | 638 |    tl_assert(0 == offsetof(PriMapEnt,base)); | 
 | 639 |    tl_assert(sizeof(Addr) == sizeof(void*)); | 
 | 640 |    primap_L2 = VG_(OSetGen_Create)( /*keyOff*/  offsetof(PriMapEnt,base), | 
 | 641 |                                     /*fastCmp*/ NULL, | 
 | 642 |                                     VG_(malloc), "pc.h_main.ism.1", | 
 | 643 |                                     VG_(free) ); | 
 | 644 |    tl_assert(primap_L2); | 
 | 645 | } | 
 | 646 |  | 
 | 647 | static void insert_into_primap_L1_at ( Word rank, PriMapEnt* ent ) | 
 | 648 | { | 
 | 649 |    Word i; | 
 | 650 |    tl_assert(ent); | 
 | 651 |    tl_assert(rank >= 0 && rank < N_PRIMAP_L1); | 
 | 652 |    for (i = N_PRIMAP_L1-1; i > rank; i--) | 
 | 653 |       primap_L1[i] = primap_L1[i-1]; | 
 | 654 |    primap_L1[rank].base = ent->base; | 
 | 655 |    primap_L1[rank].ent  = ent; | 
 | 656 | } | 
 | 657 |  | 
 | 658 | static inline PriMapEnt* maybe_find_in_primap ( Addr a ) | 
 | 659 | { | 
 | 660 |    PriMapEnt  key; | 
 | 661 |    PriMapEnt* res; | 
 | 662 |    Word       i; | 
 | 663 |  | 
 | 664 |    a &= ~(Addr)0xFFFF; | 
 | 665 |  | 
 | 666 |    /* First search the front-cache, which is a self-organising | 
 | 667 |       list containing the most popular entries. */ | 
 | 668 |  | 
 | 669 |    if (LIKELY(primap_L1[0].base == a)) | 
 | 670 |       return primap_L1[0].ent; | 
 | 671 |    if (LIKELY(primap_L1[1].base == a)) { | 
 | 672 |       Addr       t_base = primap_L1[0].base; | 
 | 673 |       PriMapEnt* t_ent  = primap_L1[0].ent; | 
 | 674 |       primap_L1[0].base = primap_L1[1].base; | 
 | 675 |       primap_L1[0].ent  = primap_L1[1].ent; | 
 | 676 |       primap_L1[1].base = t_base; | 
 | 677 |       primap_L1[1].ent  = t_ent; | 
 | 678 |       return primap_L1[0].ent; | 
 | 679 |    } | 
 | 680 |  | 
 | 681 |    n_primap_L1_searches++; | 
 | 682 |  | 
 | 683 |    for (i = 0; i < N_PRIMAP_L1; i++) { | 
 | 684 |       if (primap_L1[i].base == a) { | 
 | 685 |          break; | 
 | 686 |       } | 
 | 687 |    } | 
 | 688 |    tl_assert(i >= 0 && i <= N_PRIMAP_L1); | 
 | 689 |  | 
 | 690 |    n_primap_L1_cmps += (ULong)(i+1); | 
 | 691 |  | 
 | 692 |    if (i < N_PRIMAP_L1) { | 
 | 693 |       if (i > 0) { | 
 | 694 |          Addr       t_base = primap_L1[i-1].base; | 
 | 695 |          PriMapEnt* t_ent  = primap_L1[i-1].ent; | 
 | 696 |          primap_L1[i-1].base = primap_L1[i-0].base; | 
 | 697 |          primap_L1[i-1].ent  = primap_L1[i-0].ent; | 
 | 698 |          primap_L1[i-0].base = t_base; | 
 | 699 |          primap_L1[i-0].ent  = t_ent; | 
 | 700 |          i--; | 
 | 701 |       } | 
 | 702 |       return primap_L1[i].ent; | 
 | 703 |    } | 
 | 704 |  | 
 | 705 |    n_primap_L2_searches++; | 
 | 706 |  | 
 | 707 |    /* First see if we already have it. */ | 
 | 708 |    key.base = a; | 
 | 709 |    key.sm   = 0; | 
 | 710 |  | 
 | 711 |    res = VG_(OSetGen_Lookup)(primap_L2, &key); | 
 | 712 |    if (res) | 
 | 713 |       insert_into_primap_L1_at( PRIMAP_L1_INSERT_IX, res ); | 
 | 714 |    return res; | 
 | 715 | } | 
 | 716 |  | 
 | 717 | static SecMap* alloc_secondary_map ( void ) | 
 | 718 | { | 
 | 719 |    SecMap* map; | 
 | 720 |    UInt  i; | 
 | 721 |  | 
 | 722 |    // JRS 2008-June-25: what's the following assertion for? | 
 | 723 |    tl_assert(0 == (sizeof(SecMap) % VKI_MAX_PAGE_SIZE)); | 
 | 724 |  | 
 | 725 |    map = VG_(am_shadow_alloc)( sizeof(SecMap) ); | 
 | 726 |    if (map == NULL) | 
 | 727 |       VG_(out_of_memory_NORETURN)( "annelid:allocate new SecMap", | 
 | 728 |                                    sizeof(SecMap) ); | 
 | 729 |  | 
 | 730 |    for (i = 0; i < SEC_MAP_WORDS; i++) | 
 | 731 |       map->vseg[i] = NONPTR; | 
 | 732 |    if (0) VG_(printf)("XXX new secmap %p\n", map); | 
 | 733 |    return map; | 
 | 734 | } | 
 | 735 |  | 
 | 736 | static PriMapEnt* find_or_alloc_in_primap ( Addr a ) | 
 | 737 | { | 
 | 738 |    PriMapEnt *nyu, *res; | 
 | 739 |  | 
 | 740 |    /* First see if we already have it. */ | 
 | 741 |    res = maybe_find_in_primap( a ); | 
 | 742 |    if (LIKELY(res)) | 
 | 743 |       return res; | 
 | 744 |  | 
 | 745 |    /* Ok, there's no entry in the secondary map, so we'll have | 
 | 746 |       to allocate one. */ | 
 | 747 |    a &= ~(Addr)0xFFFF; | 
 | 748 |  | 
 | 749 |    nyu = (PriMapEnt*) VG_(OSetGen_AllocNode)(  | 
 | 750 |                          primap_L2, sizeof(PriMapEnt) ); | 
 | 751 |    tl_assert(nyu); | 
 | 752 |    nyu->base = a; | 
 | 753 |    nyu->sm   = alloc_secondary_map(); | 
 | 754 |    tl_assert(nyu->sm); | 
 | 755 |    VG_(OSetGen_Insert)( primap_L2, nyu ); | 
 | 756 |    insert_into_primap_L1_at( PRIMAP_L1_INSERT_IX, nyu ); | 
 | 757 |    n_primap_L2_nodes++; | 
 | 758 |    return nyu; | 
 | 759 | } | 
 | 760 |  | 
 | 761 | ///////////////////////////////////////////////// | 
 | 762 |  | 
 | 763 | // Nb: 'a' must be naturally word aligned for the host. | 
 | 764 | static inline Seg* get_mem_vseg ( Addr a ) | 
 | 765 | { | 
 | 766 |    SecMap* sm     = find_or_alloc_in_primap(a)->sm; | 
 | 767 |    UWord   sm_off = (a & SHMEM_SECMAP_MASK) >> SHMEM_SECMAP_SHIFT; | 
 | 768 |    tl_assert(SHMEM_IS_WORD_ALIGNED(a)); | 
 | 769 |    return sm->vseg[sm_off]; | 
 | 770 | } | 
 | 771 |  | 
 | 772 | // Nb: 'a' must be naturally word aligned for the host. | 
 | 773 | static inline void set_mem_vseg ( Addr a, Seg* vseg ) | 
 | 774 | { | 
 | 775 |    SecMap* sm     = find_or_alloc_in_primap(a)->sm; | 
 | 776 |    UWord   sm_off = (a & SHMEM_SECMAP_MASK) >> SHMEM_SECMAP_SHIFT; | 
 | 777 |    tl_assert(SHMEM_IS_WORD_ALIGNED(a)); | 
 | 778 |    sm->vseg[sm_off] = vseg; | 
 | 779 | } | 
 | 780 |  | 
| sewardj | 9520845 | 2008-10-18 19:55:31 +0000 | [diff] [blame] | 781 | // Find the Seg which contains the given address. | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 782 | // Returns UNKNOWN if no matches.  Never returns BOTTOM or NONPTR. | 
 | 783 | // Also, only returns in-use segments, not freed ones. | 
| sewardj | 9520845 | 2008-10-18 19:55:31 +0000 | [diff] [blame] | 784 | /* Doing this fast is distinctly difficult when there are more than a | 
 | 785 |    few heap allocated blocks live.  Basically it is done by searching | 
 | 786 |    addr_to_seg_map for 'a'. | 
 | 787 |  | 
 | 788 |    First, if 'a' is the start address of a segment, then we can detect | 
 | 789 |    that by simply doing a VG_(lookupFM) of 'a', and we are done (nice | 
 | 790 |    and easy). | 
 | 791 |  | 
 | 792 |    If 'a' is within some segment, but does not point to the start, it | 
 | 793 |    is much more complex.  We use VG_(findBoundsFM) to find the segment | 
 | 794 |    with the largest .addr field which is <= a, and we then inspect the | 
 | 795 |    segment to see if 'a' really falls inside it or not.  This is all a | 
 | 796 |    bit complex and fragile, and so there's a lot of assertery in the | 
 | 797 |    code below.  It has been crosschecked however against the trivial | 
 | 798 |    _SLOW implementation shown after the end of this fn. | 
 | 799 | */ | 
 | 800 | static Seg* get_Seg_containing_addr( Addr a ) | 
 | 801 | { | 
 | 802 |    UWord keyW, valW; | 
 | 803 |    Seg*  s2; | 
 | 804 |  | 
 | 805 |    /* Since we are going to poke around in it */ | 
 | 806 |    addr_to_seg_map_ENSURE_INIT(); | 
 | 807 |  | 
 | 808 |    /* first, see if 'a' is at the start of a block.  We do this both | 
 | 809 |       because it's easy and more imporantly because VG_(findBoundsFM) | 
 | 810 |       will fail in this case, so we need to exclude it first. */ | 
 | 811 |    if (VG_(lookupFM)( addr_to_seg_map, &keyW, &valW, a )) { | 
 | 812 |       tl_assert(keyW == a); | 
 | 813 |       s2 = (Seg*)valW; | 
 | 814 |       tl_assert(s2->addr == a); | 
 | 815 |    } else { | 
 | 816 |       Bool  ok; | 
 | 817 |       UWord kMin, vMin, kMax, vMax; | 
 | 818 |       Seg   minSeg; | 
 | 819 |       Seg   maxSeg; | 
 | 820 |       UWord minAddr = 0; | 
 | 821 |       UWord maxAddr = ~minAddr; | 
 | 822 |       VG_(memset)(&minSeg, 0, sizeof(minSeg)); | 
 | 823 |       VG_(memset)(&maxSeg, 0, sizeof(maxSeg)); | 
 | 824 |       minSeg.addr = minAddr; | 
 | 825 |       maxSeg.addr = maxAddr; | 
 | 826 |       ok = VG_(findBoundsFM)( addr_to_seg_map, | 
 | 827 |                               &kMin, &vMin, &kMax, &vMax, | 
 | 828 |                               minAddr, (UWord)&minSeg, | 
 | 829 |                               maxAddr, (UWord)&maxSeg, a ); | 
 | 830 |       tl_assert(ok); /* must be so, since False is only returned when | 
 | 831 |                         'a' is directly present in the map, and we | 
 | 832 |                         just established that it isn't. */ | 
 | 833 |       /* At this point, either vMin points at minSeg, or it points at a | 
 | 834 |          real Seg.  In the former case, there is no live heap-allocated | 
 | 835 |          Seg which has a start address <= a, so a is not in any block. | 
 | 836 |          In the latter case, the Seg vMin points at may or may not | 
 | 837 |          actually contain 'a'; we can only tell that by inspecting the | 
 | 838 |          Seg itself. */ | 
 | 839 |       s2 = (Seg*)vMin; | 
 | 840 |       tl_assert(kMin == s2->addr); | 
 | 841 |       if (s2 == &minSeg) { | 
 | 842 |          /* the former */ | 
 | 843 |          s2 = UNKNOWN; | 
 | 844 |       } else { | 
 | 845 |          /* the latter */ | 
 | 846 |          tl_assert(s2->addr <= a); | 
 | 847 |          /* if s2 doesn't actually contain 'a', we must forget about it. */ | 
 | 848 |          if (s2->szB == 0 /* a zero sized block can't contain anything */ | 
 | 849 |              || s2->addr + s2->szB < a /* the usual range check */) | 
 | 850 |             s2 = UNKNOWN; | 
 | 851 |       } | 
 | 852 |       /* while we're at it, do as much assertery as we can, since this | 
 | 853 |          is all rather complex.  Either vMax points at maxSeg, or it | 
 | 854 |          points to a real block, which must have a start address | 
 | 855 |          greater than a. */ | 
 | 856 |       tl_assert(kMax == ((Seg*)vMax)->addr); | 
 | 857 |       if (kMax == (UWord)&maxSeg) { | 
 | 858 |          /* nothing we can check */ | 
 | 859 |       } else { | 
 | 860 |          tl_assert(a < kMax); /* hence also a < ((Seg*)vMax)->addr */ | 
 | 861 |       } | 
 | 862 |    } | 
 | 863 |  | 
 | 864 |    return s2; | 
 | 865 | } | 
 | 866 |  | 
 | 867 | /* XXXX very slow reference implementation.  Do not use. | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 868 | static Seg* get_Seg_containing_addr_SLOW( Addr a ) | 
 | 869 | { | 
 | 870 |    SegGroup* group; | 
 | 871 |    UWord i; | 
 | 872 |    stats__slow_searches++; | 
 | 873 |    for (group = group_list; group; group = group->admin) { | 
 | 874 |       for (i = 0; i < group->nextfree; i++) { | 
 | 875 |          stats__slow_totcmps++; | 
 | 876 |          if (Seg__is_freed(&group->segs[i])) | 
 | 877 |             continue; | 
 | 878 |          if (group->segs[i].addr <= a | 
 | 879 |              && a < group->segs[i].addr + group->segs[i].szB) | 
 | 880 |             return &group->segs[i]; | 
 | 881 |       } | 
 | 882 |    } | 
 | 883 |    return UNKNOWN; | 
 | 884 | } | 
| sewardj | 9520845 | 2008-10-18 19:55:31 +0000 | [diff] [blame] | 885 | */ | 
 | 886 |  | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 887 |  | 
 | 888 |  | 
 | 889 | /*------------------------------------------------------------*/ | 
 | 890 | /*--- malloc() et al replacements                          ---*/ | 
 | 891 | /*------------------------------------------------------------*/ | 
 | 892 |  | 
 | 893 | void* h_replace_malloc ( ThreadId tid, SizeT n ) | 
 | 894 | { | 
 | 895 |    return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment), | 
 | 896 |                                         /*is_zeroed*/False ); | 
 | 897 | } | 
 | 898 |  | 
 | 899 | void* h_replace___builtin_new ( ThreadId tid, SizeT n ) | 
 | 900 | { | 
 | 901 |    return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment), | 
 | 902 |                                            /*is_zeroed*/False ); | 
 | 903 | } | 
 | 904 |  | 
 | 905 | void* h_replace___builtin_vec_new ( ThreadId tid, SizeT n ) | 
 | 906 | { | 
 | 907 |    return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment), | 
 | 908 |                                            /*is_zeroed*/False ); | 
 | 909 | } | 
 | 910 |  | 
 | 911 | void* h_replace_memalign ( ThreadId tid, SizeT align, SizeT n ) | 
 | 912 | { | 
 | 913 |    return alloc_and_new_mem_heap ( tid, n, align, | 
 | 914 |                                         /*is_zeroed*/False ); | 
 | 915 | } | 
 | 916 |  | 
 | 917 | void* h_replace_calloc ( ThreadId tid, SizeT nmemb, SizeT size1 ) | 
 | 918 | { | 
 | 919 |    return alloc_and_new_mem_heap ( tid, nmemb*size1, VG_(clo_alignment), | 
 | 920 |                                         /*is_zeroed*/True ); | 
 | 921 | } | 
 | 922 |  | 
 | 923 | void h_replace_free ( ThreadId tid, void* p ) | 
 | 924 | { | 
 | 925 |    // Should arguably check here if p.vseg matches the segID of the | 
 | 926 |    // pointed-to block... unfortunately, by this stage, we don't know what | 
 | 927 |    // p.vseg is, because we don't know the address of p (the p here is a | 
 | 928 |    // copy, and we've lost the address of its source).  To do so would | 
 | 929 |    // require passing &p in, which would require rewriting part of | 
 | 930 |    // vg_replace_malloc.c... argh. | 
 | 931 |    // | 
 | 932 |    // However, Memcheck does free checking, and will catch almost all | 
 | 933 |    // violations this checking would have caught.  (Would only miss if we | 
 | 934 |    // unluckily passed an unrelated pointer to the very start of a heap | 
 | 935 |    // block that was unrelated to that block.  This is very unlikely!)    So | 
 | 936 |    // we haven't lost much. | 
 | 937 |  | 
 | 938 |    handle_free_heap(tid, p); | 
 | 939 | } | 
 | 940 |  | 
 | 941 | void h_replace___builtin_delete ( ThreadId tid, void* p ) | 
 | 942 | { | 
 | 943 |    handle_free_heap(tid, p); | 
 | 944 | } | 
 | 945 |  | 
 | 946 | void h_replace___builtin_vec_delete ( ThreadId tid, void* p ) | 
 | 947 | { | 
 | 948 |    handle_free_heap(tid, p); | 
 | 949 | } | 
 | 950 |  | 
 | 951 | void* h_replace_realloc ( ThreadId tid, void* p_old, SizeT new_size ) | 
 | 952 | { | 
 | 953 |    Seg* seg; | 
 | 954 |  | 
 | 955 |    /* First try and find the block. */ | 
 | 956 |    seg = find_Seg_by_addr( (Addr)p_old ); | 
 | 957 |    if (!seg) | 
 | 958 |       return NULL; | 
 | 959 |  | 
 | 960 |    tl_assert(seg->addr == (Addr)p_old); | 
 | 961 |  | 
 | 962 |    if (new_size <= seg->szB) { | 
 | 963 |       /* new size is smaller: allocate, copy from old to new */ | 
 | 964 |       Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size); | 
 | 965 |       VG_(memcpy)((void*)p_new, p_old, new_size); | 
 | 966 |  | 
 | 967 |       /* Notification: copy retained part */ | 
 | 968 |       copy_mem       ( (Addr)p_old, p_new, new_size ); | 
 | 969 |  | 
 | 970 |       /* Free old memory */ | 
 | 971 |       die_and_free_mem_heap( tid, seg ); | 
 | 972 |  | 
 | 973 |       /* This has to be after die_and_free_mem_heap, otherwise the | 
 | 974 |          former succeeds in shorting out the new block, not the | 
 | 975 |          old, in the case when both are on the same list.  */ | 
 | 976 |       add_new_segment ( tid, p_new, new_size ); | 
 | 977 |  | 
 | 978 |       return (void*)p_new; | 
 | 979 |    } else { | 
 | 980 |       /* new size is bigger: allocate, copy from old to new */ | 
 | 981 |       Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size); | 
 | 982 |       VG_(memcpy)((void*)p_new, p_old, seg->szB); | 
 | 983 |  | 
 | 984 |       /* Notification: first half kept and copied, second half new */ | 
 | 985 |       copy_mem       ( (Addr)p_old, p_new, seg->szB ); | 
 | 986 |       set_mem_unknown( p_new + seg->szB, new_size - seg->szB ); | 
 | 987 |  | 
 | 988 |       /* Free old memory */ | 
 | 989 |       die_and_free_mem_heap( tid, seg ); | 
 | 990 |  | 
 | 991 |       /* This has to be after die_and_free_mem_heap, otherwise the | 
 | 992 |          former succeeds in shorting out the new block, not the old, | 
 | 993 |          in the case when both are on the same list.  NB jrs | 
 | 994 |          2008-Sept-11: not sure if this comment is valid/correct any | 
 | 995 |          more -- I suspect not. */ | 
 | 996 |       add_new_segment ( tid, p_new, new_size ); | 
 | 997 |  | 
 | 998 |       return (void*)p_new; | 
 | 999 |    } | 
 | 1000 | } | 
 | 1001 |  | 
 | 1002 |  | 
 | 1003 | /*------------------------------------------------------------*/ | 
 | 1004 | /*--- Memory events                                        ---*/ | 
 | 1005 | /*------------------------------------------------------------*/ | 
 | 1006 |  | 
 | 1007 | static inline | 
 | 1008 | void set_mem ( Addr a, SizeT len, Seg* seg ) | 
 | 1009 | { | 
 | 1010 |    Addr end; | 
 | 1011 |  | 
 | 1012 |    if (0 == len) | 
 | 1013 |       return; | 
 | 1014 |  | 
 | 1015 |    if (len > 100 * 1000 * 1000) | 
 | 1016 |       VG_(message)(Vg_UserMsg, | 
 | 1017 |                    "Warning: set address range state: large range %lu", len); | 
 | 1018 |  | 
 | 1019 |    a   = VG_ROUNDDN(a,       sizeof(UWord)); | 
 | 1020 |    end = VG_ROUNDUP(a + len, sizeof(UWord)); | 
 | 1021 |    for ( ; a < end; a += sizeof(UWord)) | 
 | 1022 |       set_mem_vseg(a, seg); | 
 | 1023 | } | 
 | 1024 |  | 
 | 1025 | static void set_mem_unknown( Addr a, SizeT len ) | 
 | 1026 | { | 
 | 1027 |    set_mem( a, len, UNKNOWN ); | 
 | 1028 | } | 
 | 1029 |  | 
 | 1030 | //zz static void set_mem_nonptr( Addr a, UInt len ) | 
 | 1031 | //zz { | 
 | 1032 | //zz    set_mem( a, len, NONPTR ); | 
 | 1033 | //zz } | 
 | 1034 |  | 
 | 1035 | void h_new_mem_startup( Addr a, SizeT len, | 
 | 1036 |                         Bool rr, Bool ww, Bool xx, ULong di_handle ) | 
 | 1037 | { | 
 | 1038 |    if (0) VG_(printf)("new_mem_startup(%#lx,%lu)\n", a, len); | 
 | 1039 |    set_mem_unknown( a, len ); | 
 | 1040 |    //add_new_segment( VG_(get_running_tid)(), a, len, SegMmap ); | 
 | 1041 | } | 
 | 1042 |  | 
 | 1043 | //zz // XXX: Currently not doing anything with brk() -- new segments, or not? | 
 | 1044 | //zz // Proper way to do it would be to grow/shrink a single, special brk segment. | 
 | 1045 | //zz // | 
 | 1046 | //zz // brk is difficult: it defines a single segment, of changeable size. | 
 | 1047 | //zz // It starts off with size zero, at the address given by brk(0).  There are | 
 | 1048 | //zz // no pointers within the program to it.  Any subsequent calls by the | 
 | 1049 | //zz // program to brk() (possibly growing or shrinking it) return pointers to | 
 | 1050 | //zz // the *end* of the segment (nb: this is the kernel brk(), which is | 
 | 1051 | //zz // different to the libc brk()). | 
 | 1052 | //zz // | 
 | 1053 | //zz // If fixing this, don't forget to update the brk case in SK_(post_syscall). | 
 | 1054 | //zz // | 
 | 1055 | //zz // Nb: not sure if the return value is the last byte addressible, or one | 
 | 1056 | //zz // past the end of the segment. | 
 | 1057 | //zz // | 
 | 1058 | //zz static void new_mem_brk( Addr a, UInt len ) | 
 | 1059 | //zz { | 
 | 1060 | //zz    set_mem_unknown(a, len); | 
 | 1061 | //zz    //VG_(skin_panic)("can't handle new_mem_brk"); | 
 | 1062 | //zz } | 
 | 1063 |  | 
 | 1064 | // Not quite right:  if you mmap a segment into a specified place, it could | 
 | 1065 | // be legitimate to do certain arithmetic with the pointer that it wouldn't | 
 | 1066 | // otherwise.  Hopefully this is rare, though. | 
 | 1067 | void h_new_mem_mmap( Addr a, SizeT len, | 
 | 1068 |                      Bool rr, Bool ww, Bool xx, ULong di_handle ) | 
 | 1069 | { | 
 | 1070 |    if (0) VG_(printf)("new_mem_mmap(%#lx,%lu)\n", a, len); | 
 | 1071 | //zz #if 0 | 
 | 1072 | //zz    Seg seg = NULL; | 
 | 1073 | //zz  | 
 | 1074 | //zz    // Check for overlapping segments | 
 | 1075 | //zz #if 0 | 
 | 1076 | //zz    is_overlapping_seg___a   = a;    // 'free' variable | 
 | 1077 | //zz    is_overlapping_seg___len = len;  // 'free' variable | 
 | 1078 | //zz    seg = (Seg)VG_(HT_first_match) ( mlist, is_overlapping_seg ); | 
 | 1079 | //zz    is_overlapping_seg___a   = 0;    // paranoia, reset | 
 | 1080 | //zz    is_overlapping_seg___len = 0;    // paranoia, reset | 
 | 1081 | //zz #endif | 
 | 1082 | //zz  | 
 | 1083 | //zz    // XXX: do this check properly with ISLists | 
 | 1084 | //zz  | 
 | 1085 | //zz    if ( ISList__findI( seglist, a, &seg )) { | 
 | 1086 | //zz       sk_assert(SegMmap == seg->status || SegMmapFree == seg->status); | 
 | 1087 | //zz       if (SegMmap == seg->status) | 
 | 1088 | //zz     | 
 | 1089 | //zz    } | 
 | 1090 | //zz  | 
 | 1091 | //zz    if (NULL != seg) { | 
 | 1092 | //zz       // Right, we found an overlap | 
 | 1093 | //zz       if (VG_(clo_verbosity) > 1) | 
 | 1094 | //zz          VG_(message)(Vg_UserMsg, "mmap overlap:  old: %#lx, %d;  new: %#lx, %d", | 
 | 1095 | //zz                                   seg->left, Seg__size(seg), a, len); | 
 | 1096 | //zz       if (seg->left <= a && a <= seg->right) { | 
 | 1097 | //zz          // New one truncates end of the old one.  Nb: we don't adjust its | 
 | 1098 | //zz          // size, because the first segment's pointer can be (and for | 
 | 1099 | //zz          // Konqueror, is) legitimately used to access parts of the second | 
 | 1100 | //zz          // segment.  At least, I assume Konqueror is doing something legal. | 
 | 1101 | //zz          // so that a size mismatch upon munmap isn't a problem. | 
 | 1102 | //zz //         seg->size = a - seg->data; | 
 | 1103 | //zz //         seg->is_truncated_map = True; | 
 | 1104 | //zz //         if (VG_(clo_verbosity) > 1) | 
 | 1105 | //zz //            VG_(message)(Vg_UserMsg, "old seg truncated to length %d", | 
 | 1106 | //zz //                                     seg->size); | 
 | 1107 | //zz       } else { | 
 | 1108 | //zz          VG_(skin_panic)("Can't handle this mmap() overlap case"); | 
 | 1109 | //zz       } | 
 | 1110 | //zz    } | 
 | 1111 |    set_mem_unknown( a, len ); | 
 | 1112 |    //add_new_segment( VG_(get_running_tid)(), a, len, SegMmap ); | 
 | 1113 | //zz #endif | 
 | 1114 | } | 
 | 1115 |  | 
 | 1116 | static void copy_mem( Addr from, Addr to, SizeT len ) | 
 | 1117 | { | 
 | 1118 |    Addr fromend = from + len; | 
 | 1119 |  | 
 | 1120 |    // Must be aligned due to malloc always returning aligned objects. | 
 | 1121 |    tl_assert(VG_IS_8_ALIGNED(from) && VG_IS_8_ALIGNED(to)); | 
 | 1122 |  | 
 | 1123 |    // Must only be called with positive len. | 
 | 1124 |    if (0 == len) | 
 | 1125 |       return; | 
 | 1126 |  | 
 | 1127 |    for ( ; from < fromend; from += sizeof(UWord), to += sizeof(UWord)) | 
 | 1128 |       set_mem_vseg( to, get_mem_vseg(from) ); | 
 | 1129 | } | 
 | 1130 |  | 
 | 1131 | //zz // Similar to SK_(realloc)() | 
 | 1132 | //zz static void copy_mem_remap( Addr from, Addr to, UInt len ) | 
 | 1133 | //zz { | 
 | 1134 | //zz    VG_(skin_panic)("argh: copy_mem_remap"); | 
 | 1135 | //zz } | 
 | 1136 | //zz  | 
 | 1137 | //zz static void die_mem_brk( Addr a, UInt len ) | 
 | 1138 | //zz { | 
 | 1139 | //zz    set_mem_unknown(a, len); | 
 | 1140 | //zz //   VG_(skin_panic)("can't handle die_mem_brk()"); | 
 | 1141 | //zz } | 
 | 1142 |  | 
 | 1143 | void h_die_mem_munmap( Addr a, SizeT len ) | 
 | 1144 | { | 
 | 1145 | //   handle_free_munmap( (void*)a, len ); | 
 | 1146 | } | 
 | 1147 |  | 
 | 1148 | // Don't need to check all addresses within the block; in the absence of | 
 | 1149 | // discontiguous segments, the segments for the first and last bytes should | 
 | 1150 | // be the same.  Can't easily check the pointer segment matches the block | 
 | 1151 | // segment, unfortunately, but the first/last check should catch most | 
 | 1152 | // errors. | 
 | 1153 | static void pre_mem_access2 ( CorePart part, ThreadId tid, Char* str, | 
 | 1154 |                               Addr s/*tart*/, Addr e/*nd*/ ) | 
 | 1155 | { | 
 | 1156 |    Seg  *seglo, *seghi; | 
 | 1157 |    Bool s_in_seglo, s_in_seghi, e_in_seglo, e_in_seghi; | 
 | 1158 |  | 
 | 1159 |    // Don't check code being translated -- very slow, and not much point | 
 | 1160 |    if (Vg_CoreTranslate == part) return; | 
 | 1161 |  | 
 | 1162 |    // Don't check the signal case -- only happens in core, no need to check | 
 | 1163 |    if (Vg_CoreSignal == part) return; | 
 | 1164 |  | 
 | 1165 |    // Only expect syscalls after this point | 
 | 1166 |    if (part != Vg_CoreSysCall) { | 
 | 1167 |       VG_(printf)("part = %d\n", part); | 
 | 1168 |       VG_(tool_panic)("unknown corepart in pre_mem_access2"); | 
 | 1169 |    } | 
 | 1170 |  | 
 | 1171 |    // Check first and last bytes match | 
| sewardj | 9520845 | 2008-10-18 19:55:31 +0000 | [diff] [blame] | 1172 |    seglo = get_Seg_containing_addr( s ); | 
 | 1173 |    seghi = get_Seg_containing_addr( e ); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 1174 |    tl_assert( BOTTOM != seglo && NONPTR != seglo ); | 
 | 1175 |    tl_assert( BOTTOM != seghi && NONPTR != seghi ); | 
 | 1176 |  | 
 | 1177 |    /* so seglo and seghi are either UNKNOWN or P(..) */ | 
 | 1178 |    s_in_seglo | 
 | 1179 |       = is_known_segment(seglo) | 
 | 1180 |         && seglo->addr <= s && s < seglo->addr + seglo->szB; | 
 | 1181 |    s_in_seghi | 
 | 1182 |       = is_known_segment(seghi) | 
 | 1183 |         && seghi->addr <= s && s < seghi->addr + seghi->szB; | 
 | 1184 |    e_in_seglo | 
 | 1185 |       = is_known_segment(seglo) | 
 | 1186 |         && seglo->addr <= e && e < seglo->addr + seglo->szB; | 
 | 1187 |    e_in_seghi | 
 | 1188 |       = is_known_segment(seghi) | 
 | 1189 |         && seghi->addr <= e && e < seghi->addr + seghi->szB; | 
 | 1190 |  | 
 | 1191 |    /* record an error if start and end are in different, but known | 
 | 1192 |       segments */ | 
 | 1193 |    if (is_known_segment(seglo) && is_known_segment(seghi) | 
 | 1194 |        && seglo != seghi) { | 
 | 1195 |       h_record_sysparam_error(tid, part, str, s, e, seglo, seghi); | 
 | 1196 |    } | 
 | 1197 |    else | 
 | 1198 |    /* record an error if start is in a known segment but end isn't */ | 
 | 1199 |    if (is_known_segment(seglo) && !is_known_segment(seghi)) { | 
 | 1200 |       h_record_sysparam_error(tid, part, str, s, e, seglo, UNKNOWN); | 
 | 1201 |    } | 
 | 1202 |    else | 
 | 1203 |    /* record an error if end is in a known segment but start isn't */ | 
 | 1204 |    if (!is_known_segment(seglo) && is_known_segment(seghi)) { | 
 | 1205 |       h_record_sysparam_error(tid, part, str, s, e, UNKNOWN, seghi); | 
 | 1206 |    } | 
 | 1207 | } | 
 | 1208 |  | 
 | 1209 | void h_pre_mem_access ( CorePart part, ThreadId tid, Char* s, | 
 | 1210 |                         Addr base, SizeT size ) | 
 | 1211 | { | 
 | 1212 |    pre_mem_access2( part, tid, s, base, base + size - 1 ); | 
 | 1213 | } | 
 | 1214 |  | 
 | 1215 | void h_pre_mem_read_asciiz ( CorePart part, ThreadId tid,  | 
 | 1216 |                              Char* s, Addr lo ) | 
 | 1217 | { | 
 | 1218 |    Addr hi = lo; | 
 | 1219 |  | 
 | 1220 |    // Nb: the '\0' must be included in the lo...hi range | 
 | 1221 |    while ('\0' != *(Char*)hi) hi++; | 
 | 1222 |    pre_mem_access2( part, tid, s, lo, hi ); | 
 | 1223 | } | 
 | 1224 |  | 
 | 1225 | //zz static void post_mem_write(Addr a, UInt len) | 
 | 1226 | //zz { | 
 | 1227 | //zz    set_mem_unknown(a, len); | 
 | 1228 | //zz } | 
 | 1229 |  | 
 | 1230 |  | 
 | 1231 | /*------------------------------------------------------------*/ | 
 | 1232 | /*--- Register event handlers                              ---*/ | 
 | 1233 | /*------------------------------------------------------------*/ | 
 | 1234 |  | 
 | 1235 | //zz static void post_regs_write_init ( void ) | 
 | 1236 | //zz { | 
 | 1237 | //zz    UInt i; | 
 | 1238 | //zz    for (i = R_EAX; i <= R_EDI; i++) | 
 | 1239 | //zz       VG_(set_shadow_archreg)( i, (UInt)UNKNOWN ); | 
 | 1240 | //zz  | 
 | 1241 | //zz    // Don't bother about eflags | 
 | 1242 | //zz } | 
 | 1243 |  | 
 | 1244 | // BEGIN move this uglyness to pc_machine.c | 
 | 1245 |  | 
 | 1246 | static inline Bool host_is_big_endian ( void ) { | 
 | 1247 |    UInt x = 0x11223344; | 
 | 1248 |    return 0x1122 == *(UShort*)(&x); | 
 | 1249 | } | 
 | 1250 | static inline Bool host_is_little_endian ( void ) { | 
 | 1251 |    UInt x = 0x11223344; | 
 | 1252 |    return 0x3344 == *(UShort*)(&x); | 
 | 1253 | } | 
 | 1254 |  | 
 | 1255 | #define N_INTREGINFO_OFFSETS 4 | 
 | 1256 |  | 
 | 1257 | /* Holds the result of a query to 'get_IntRegInfo'.  Valid values for | 
 | 1258 |    n_offsets are: | 
 | 1259 |  | 
 | 1260 |    -1: means the queried guest state slice exactly matches | 
 | 1261 |        one integer register | 
 | 1262 |  | 
 | 1263 |    0: means the queried guest state slice does not overlap any | 
 | 1264 |       integer registers | 
 | 1265 |  | 
 | 1266 |    1 .. N_INTREGINFO_OFFSETS: means the queried guest state offset | 
 | 1267 |       overlaps n_offsets different integer registers, and their base | 
 | 1268 |       offsets are placed in the offsets array. | 
 | 1269 | */ | 
 | 1270 | typedef | 
 | 1271 |    struct { | 
 | 1272 |       Int offsets[N_INTREGINFO_OFFSETS]; | 
 | 1273 |       Int n_offsets; | 
 | 1274 |    } | 
 | 1275 |    IntRegInfo; | 
 | 1276 |  | 
 | 1277 |  | 
 | 1278 | #if defined(VGA_x86) | 
 | 1279 | # include "libvex_guest_x86.h" | 
 | 1280 | # define MC_SIZEOF_GUEST_STATE sizeof(VexGuestX86State) | 
 | 1281 | #endif | 
 | 1282 |  | 
 | 1283 | #if defined(VGA_amd64) | 
 | 1284 | # include "libvex_guest_amd64.h" | 
 | 1285 | # define MC_SIZEOF_GUEST_STATE sizeof(VexGuestAMD64State) | 
 | 1286 | # define PC_OFF_FS_ZERO offsetof(VexGuestAMD64State,guest_FS_ZERO) | 
 | 1287 | # define PC_SZB_FS_ZERO sizeof( ((VexGuestAMD64State*)0)->guest_FS_ZERO) | 
 | 1288 | #endif | 
 | 1289 |  | 
 | 1290 | #if defined(VGA_ppc32) | 
 | 1291 | # include "libvex_guest_ppc32.h" | 
 | 1292 | # define MC_SIZEOF_GUEST_STATE sizeof(VexGuestPPC32State) | 
 | 1293 | #endif | 
 | 1294 |  | 
 | 1295 | #if defined(VGA_ppc64) | 
 | 1296 | # include "libvex_guest_ppc64.h" | 
 | 1297 | # define MC_SIZEOF_GUEST_STATE sizeof(VexGuestPPC64State) | 
 | 1298 | #endif | 
 | 1299 |  | 
 | 1300 |  | 
 | 1301 | /* See description on definition of type IntRegInfo. */ | 
 | 1302 | static void get_IntRegInfo ( /*OUT*/IntRegInfo* iii, Int offset, Int szB ) | 
 | 1303 | { | 
 | 1304 |    /* --------------------- x86 --------------------- */ | 
 | 1305 |  | 
 | 1306 | #  if defined(VGA_x86) | 
 | 1307 |  | 
 | 1308 | #  define GOF(_fieldname) \ | 
 | 1309 |       (offsetof(VexGuestX86State,guest_##_fieldname)) | 
 | 1310 |  | 
 | 1311 |    Int  o    = offset; | 
 | 1312 |    Int  sz   = szB; | 
 | 1313 |    Bool is4  = sz == 4; | 
 | 1314 |    Bool is21 = sz == 2 || sz == 1; | 
 | 1315 |  | 
 | 1316 |    tl_assert(sz > 0); | 
 | 1317 |    tl_assert(host_is_little_endian()); | 
 | 1318 |  | 
 | 1319 |    /* Set default state to "does not intersect any int register". */ | 
 | 1320 |    VG_(memset)( iii, 0, sizeof(*iii) ); | 
 | 1321 |  | 
 | 1322 |    /* Exact accesses to integer registers */ | 
 | 1323 |    if (o == GOF(EAX)     && is4) goto exactly1; | 
 | 1324 |    if (o == GOF(ECX)     && is4) goto exactly1; | 
 | 1325 |    if (o == GOF(EDX)     && is4) goto exactly1; | 
 | 1326 |    if (o == GOF(EBX)     && is4) goto exactly1; | 
 | 1327 |    if (o == GOF(ESP)     && is4) goto exactly1; | 
 | 1328 |    if (o == GOF(EBP)     && is4) goto exactly1; | 
 | 1329 |    if (o == GOF(ESI)     && is4) goto exactly1; | 
 | 1330 |    if (o == GOF(EDI)     && is4) goto exactly1; | 
 | 1331 |    if (o == GOF(EIP)     && is4) goto none; | 
 | 1332 |    if (o == GOF(CC_OP)   && is4) goto none; | 
 | 1333 |    if (o == GOF(CC_DEP1) && is4) goto none; | 
 | 1334 |    if (o == GOF(CC_DEP2) && is4) goto none; | 
 | 1335 |    if (o == GOF(CC_NDEP) && is4) goto none; | 
 | 1336 |    if (o == GOF(DFLAG)   && is4) goto none; | 
 | 1337 |    if (o == GOF(IDFLAG)  && is4) goto none; | 
 | 1338 |    if (o == GOF(ACFLAG)  && is4) goto none; | 
 | 1339 |  | 
 | 1340 |    /* Partial accesses to integer registers */ | 
 | 1341 |    if (o == GOF(EAX)     && is21) {         o -= 0; goto contains_o; } | 
 | 1342 |    if (o == GOF(EAX)+1   && is21) { o -= 1; o -= 0; goto contains_o; } | 
 | 1343 |    if (o == GOF(ECX)     && is21) {         o -= 0; goto contains_o; } | 
 | 1344 |    if (o == GOF(ECX)+1   && is21) { o -= 1; o -= 0; goto contains_o; } | 
 | 1345 |    if (o == GOF(EBX)     && is21) {         o -= 0; goto contains_o; } | 
| sewardj | db44098 | 2008-10-11 10:18:16 +0000 | [diff] [blame] | 1346 |    if (o == GOF(EBX)+1   && is21) { o -= 1; o -= 0; goto contains_o; } | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 1347 |    if (o == GOF(EDX)     && is21) {         o -= 0; goto contains_o; } | 
 | 1348 |    if (o == GOF(EDX)+1   && is21) { o -= 1; o -= 0; goto contains_o; } | 
 | 1349 |    if (o == GOF(ESI)     && is21) {         o -= 0; goto contains_o; } | 
 | 1350 |    if (o == GOF(EDI)     && is21) {         o -= 0; goto contains_o; } | 
 | 1351 |  | 
 | 1352 |    /* Segment related guff */ | 
 | 1353 |    if (o == GOF(GS)  && sz == 2) goto none; | 
 | 1354 |    if (o == GOF(LDT) && is4) goto none; | 
 | 1355 |    if (o == GOF(GDT) && is4) goto none; | 
 | 1356 |  | 
 | 1357 |    /* FP admin related */ | 
 | 1358 |    if (o == GOF(SSEROUND) && is4) goto none; | 
 | 1359 |    if (o == GOF(FPROUND)  && is4) goto none; | 
 | 1360 |    if (o == GOF(EMWARN)   && is4) goto none; | 
 | 1361 |    if (o == GOF(FTOP)     && is4) goto none; | 
 | 1362 |    if (o == GOF(FPTAG)    && sz == 8) goto none; | 
 | 1363 |    if (o == GOF(FC3210)   && is4) goto none; | 
 | 1364 |  | 
 | 1365 |    /* xmm registers, including arbitrary sub-parts */ | 
 | 1366 |    if (o >= GOF(XMM0) && o+sz <= GOF(XMM0)+16) goto none; | 
 | 1367 |    if (o >= GOF(XMM1) && o+sz <= GOF(XMM1)+16) goto none; | 
 | 1368 |    if (o >= GOF(XMM2) && o+sz <= GOF(XMM2)+16) goto none; | 
 | 1369 |    if (o >= GOF(XMM3) && o+sz <= GOF(XMM3)+16) goto none; | 
 | 1370 |    if (o >= GOF(XMM4) && o+sz <= GOF(XMM4)+16) goto none; | 
 | 1371 |    if (o >= GOF(XMM5) && o+sz <= GOF(XMM5)+16) goto none; | 
 | 1372 |    if (o >= GOF(XMM6) && o+sz <= GOF(XMM6)+16) goto none; | 
 | 1373 |    if (o >= GOF(XMM7) && o+sz <= GOF(XMM7)+16) goto none; | 
 | 1374 |  | 
 | 1375 |    /* mmx/x87 registers (a bit of a kludge, since 'o' is not checked | 
 | 1376 |       to be exactly equal to one of FPREG[0] .. FPREG[7]) */ | 
 | 1377 |    if (o >= GOF(FPREG[0]) && o < GOF(FPREG[7])+8 && sz == 8) goto none; | 
 | 1378 |  | 
 | 1379 |    /* the entire mmx/x87 register bank in one big piece */ | 
 | 1380 |    if (o == GOF(FPREG) && sz == 64) goto none; | 
 | 1381 |  | 
 | 1382 |    VG_(printf)("get_IntRegInfo(x86):failing on (%d,%d)\n", o, sz); | 
 | 1383 |    tl_assert(0); | 
 | 1384 | #  undef GOF | 
 | 1385 |  | 
 | 1386 |    /* -------------------- amd64 -------------------- */ | 
 | 1387 |  | 
 | 1388 | #  elif defined(VGA_amd64) | 
 | 1389 |  | 
 | 1390 | #  define GOF(_fieldname) \ | 
 | 1391 |       (offsetof(VexGuestAMD64State,guest_##_fieldname)) | 
 | 1392 |  | 
 | 1393 |    Int  o     = offset; | 
 | 1394 |    Int  sz    = szB; | 
 | 1395 |    Bool is421 = sz == 4 || sz == 2 || sz == 1; | 
 | 1396 |    Bool is8   = sz == 8; | 
 | 1397 |  | 
 | 1398 |    tl_assert(sz > 0); | 
 | 1399 |    tl_assert(host_is_little_endian()); | 
 | 1400 |  | 
 | 1401 |    /* Set default state to "does not intersect any int register". */ | 
 | 1402 |    VG_(memset)( iii, 0, sizeof(*iii) ); | 
 | 1403 |  | 
 | 1404 |    /* Exact accesses to integer registers */ | 
 | 1405 |    if (o == GOF(RAX)     && is8) goto exactly1; | 
 | 1406 |    if (o == GOF(RCX)     && is8) goto exactly1; | 
 | 1407 |    if (o == GOF(RDX)     && is8) goto exactly1; | 
 | 1408 |    if (o == GOF(RBX)     && is8) goto exactly1; | 
 | 1409 |    if (o == GOF(RSP)     && is8) goto exactly1; | 
 | 1410 |    if (o == GOF(RBP)     && is8) goto exactly1; | 
 | 1411 |    if (o == GOF(RSI)     && is8) goto exactly1; | 
 | 1412 |    if (o == GOF(RDI)     && is8) goto exactly1; | 
 | 1413 |    if (o == GOF(R8)      && is8) goto exactly1; | 
 | 1414 |    if (o == GOF(R9)      && is8) goto exactly1; | 
 | 1415 |    if (o == GOF(R10)     && is8) goto exactly1; | 
 | 1416 |    if (o == GOF(R11)     && is8) goto exactly1; | 
 | 1417 |    if (o == GOF(R12)     && is8) goto exactly1; | 
 | 1418 |    if (o == GOF(R13)     && is8) goto exactly1; | 
 | 1419 |    if (o == GOF(R14)     && is8) goto exactly1; | 
 | 1420 |    if (o == GOF(R15)     && is8) goto exactly1; | 
 | 1421 |    if (o == GOF(RIP)     && is8) goto exactly1; | 
 | 1422 |    if (o == GOF(CC_OP)   && is8) goto none; | 
 | 1423 |    if (o == GOF(CC_DEP1) && is8) goto none; | 
 | 1424 |    if (o == GOF(CC_DEP2) && is8) goto none; | 
 | 1425 |    if (o == GOF(CC_NDEP) && is8) goto none; | 
 | 1426 |    if (o == GOF(DFLAG)   && is8) goto none; | 
 | 1427 |    if (o == GOF(IDFLAG)  && is8) goto none; | 
 | 1428 |  | 
 | 1429 |    /* Partial accesses to integer registers */ | 
 | 1430 |    if (o == GOF(RAX)     && is421) {         o -= 0; goto contains_o; } | 
 | 1431 |    if (o == GOF(RAX)+1   && is421) { o -= 1; o -= 0; goto contains_o; } | 
 | 1432 |    if (o == GOF(RCX)     && is421) {         o -= 0; goto contains_o; } | 
 | 1433 |    if (o == GOF(RCX)+1   && is421) { o -= 1; o -= 0; goto contains_o; } | 
 | 1434 |    if (o == GOF(RDX)     && is421) {         o -= 0; goto contains_o; } | 
 | 1435 |    if (o == GOF(RDX)+1   && is421) { o -= 1; o -= 0; goto contains_o; } | 
 | 1436 |    if (o == GOF(RBX)     && is421) {         o -= 0; goto contains_o; } | 
 | 1437 |    if (o == GOF(RBX)+1   && is421) { o -= 1; o -= 0; goto contains_o; } | 
 | 1438 |    if (o == GOF(RBP)     && is421) {         o -= 0; goto contains_o; } | 
 | 1439 |    if (o == GOF(RSI)     && is421) {         o -= 0; goto contains_o; } | 
 | 1440 |    if (o == GOF(RDI)     && is421) {         o -= 0; goto contains_o; } | 
 | 1441 |    if (o == GOF(R8)      && is421) {         o -= 0; goto contains_o; } | 
 | 1442 |    if (o == GOF(R9)      && is421) {         o -= 0; goto contains_o; } | 
 | 1443 |    if (o == GOF(R10)     && is421) {         o -= 0; goto contains_o; } | 
 | 1444 |    if (o == GOF(R11)     && is421) {         o -= 0; goto contains_o; } | 
 | 1445 |    if (o == GOF(R12)     && is421) {         o -= 0; goto contains_o; } | 
 | 1446 |    if (o == GOF(R13)     && is421) {         o -= 0; goto contains_o; } | 
 | 1447 |    if (o == GOF(R14)     && is421) {         o -= 0; goto contains_o; } | 
 | 1448 |    if (o == GOF(R15)     && is421) {         o -= 0; goto contains_o; } | 
 | 1449 |  | 
 | 1450 |    /* Segment related guff */ | 
 | 1451 |    if (o == GOF(FS_ZERO) && is8) goto exactly1; | 
 | 1452 |  | 
 | 1453 |    /* FP admin related */ | 
 | 1454 |    if (o == GOF(SSEROUND) && is8) goto none; | 
 | 1455 |    if (o == GOF(FPROUND)  && is8) goto none; | 
 | 1456 |    if (o == GOF(EMWARN)   && sz == 4) goto none; | 
 | 1457 |    if (o == GOF(FTOP)     && sz == 4) goto none; | 
 | 1458 |    if (o == GOF(FPTAG)    && is8) goto none; | 
 | 1459 |    if (o == GOF(FC3210)   && is8) goto none; | 
 | 1460 |  | 
 | 1461 |    /* xmm registers, including arbitrary sub-parts */ | 
 | 1462 |    if (o >= GOF(XMM0)  && o+sz <= GOF(XMM0)+16)  goto none; | 
 | 1463 |    if (o >= GOF(XMM1)  && o+sz <= GOF(XMM1)+16)  goto none; | 
 | 1464 |    if (o >= GOF(XMM2)  && o+sz <= GOF(XMM2)+16)  goto none; | 
 | 1465 |    if (o >= GOF(XMM3)  && o+sz <= GOF(XMM3)+16)  goto none; | 
 | 1466 |    if (o >= GOF(XMM4)  && o+sz <= GOF(XMM4)+16)  goto none; | 
 | 1467 |    if (o >= GOF(XMM5)  && o+sz <= GOF(XMM5)+16)  goto none; | 
 | 1468 |    if (o >= GOF(XMM6)  && o+sz <= GOF(XMM6)+16)  goto none; | 
 | 1469 |    if (o >= GOF(XMM7)  && o+sz <= GOF(XMM7)+16)  goto none; | 
 | 1470 |    if (o >= GOF(XMM8)  && o+sz <= GOF(XMM8)+16)  goto none; | 
 | 1471 |    if (o >= GOF(XMM9)  && o+sz <= GOF(XMM9)+16)  goto none; | 
 | 1472 |    if (o >= GOF(XMM10) && o+sz <= GOF(XMM10)+16) goto none; | 
 | 1473 |    if (o >= GOF(XMM11) && o+sz <= GOF(XMM11)+16) goto none; | 
 | 1474 |    if (o >= GOF(XMM12) && o+sz <= GOF(XMM12)+16) goto none; | 
 | 1475 |    if (o >= GOF(XMM13) && o+sz <= GOF(XMM13)+16) goto none; | 
 | 1476 |    if (o >= GOF(XMM14) && o+sz <= GOF(XMM14)+16) goto none; | 
 | 1477 |    if (o >= GOF(XMM15) && o+sz <= GOF(XMM15)+16) goto none; | 
 | 1478 |  | 
 | 1479 |    /* mmx/x87 registers (a bit of a kludge, since 'o' is not checked | 
 | 1480 |       to be exactly equal to one of FPREG[0] .. FPREG[7]) */ | 
 | 1481 |    if (o >= GOF(FPREG[0]) && o < GOF(FPREG[7])+8 && sz == 8) goto none; | 
 | 1482 |  | 
 | 1483 |    VG_(printf)("get_IntRegInfo(amd64):failing on (%d,%d)\n", o, sz); | 
 | 1484 |    tl_assert(0); | 
 | 1485 | #  undef GOF | 
 | 1486 |  | 
 | 1487 |    /* -------------------- ppc32 -------------------- */ | 
 | 1488 |  | 
 | 1489 | #  elif defined(VGA_ppc32) | 
 | 1490 |  | 
 | 1491 | #  define GOF(_fieldname) \ | 
 | 1492 |       (offsetof(VexGuestPPC32State,guest_##_fieldname)) | 
 | 1493 |  | 
 | 1494 |    Int  o    = offset; | 
 | 1495 |    Int  sz   = szB; | 
 | 1496 |    Bool is4  = sz == 4; | 
 | 1497 |    Bool is8  = sz == 8; | 
 | 1498 |  | 
 | 1499 |    tl_assert(sz > 0); | 
 | 1500 |    tl_assert(host_is_big_endian()); | 
 | 1501 |  | 
 | 1502 |    /* Set default state to "does not intersect any int register". */ | 
 | 1503 |    VG_(memset)( iii, 0, sizeof(*iii) ); | 
 | 1504 |  | 
 | 1505 |    /* Exact accesses to integer registers */ | 
 | 1506 |    if (o == GOF(GPR0)  && is4) goto exactly1; | 
 | 1507 |    if (o == GOF(GPR1)  && is4) goto exactly1; | 
 | 1508 |    if (o == GOF(GPR2)  && is4) goto exactly1; | 
 | 1509 |    if (o == GOF(GPR3)  && is4) goto exactly1; | 
 | 1510 |    if (o == GOF(GPR4)  && is4) goto exactly1; | 
 | 1511 |    if (o == GOF(GPR5)  && is4) goto exactly1; | 
 | 1512 |    if (o == GOF(GPR6)  && is4) goto exactly1; | 
 | 1513 |    if (o == GOF(GPR7)  && is4) goto exactly1; | 
 | 1514 |    if (o == GOF(GPR8)  && is4) goto exactly1; | 
 | 1515 |    if (o == GOF(GPR9)  && is4) goto exactly1; | 
 | 1516 |    if (o == GOF(GPR10) && is4) goto exactly1; | 
 | 1517 |    if (o == GOF(GPR11) && is4) goto exactly1; | 
 | 1518 |    if (o == GOF(GPR12) && is4) goto exactly1; | 
 | 1519 |    if (o == GOF(GPR13) && is4) goto exactly1; | 
 | 1520 |    if (o == GOF(GPR14) && is4) goto exactly1; | 
 | 1521 |    if (o == GOF(GPR15) && is4) goto exactly1; | 
 | 1522 |    if (o == GOF(GPR16) && is4) goto exactly1; | 
 | 1523 |    if (o == GOF(GPR17) && is4) goto exactly1; | 
 | 1524 |    if (o == GOF(GPR18) && is4) goto exactly1; | 
 | 1525 |    if (o == GOF(GPR19) && is4) goto exactly1; | 
 | 1526 |    if (o == GOF(GPR20) && is4) goto exactly1; | 
 | 1527 |    if (o == GOF(GPR21) && is4) goto exactly1; | 
 | 1528 |    if (o == GOF(GPR22) && is4) goto exactly1; | 
 | 1529 |    if (o == GOF(GPR23) && is4) goto exactly1; | 
 | 1530 |    if (o == GOF(GPR24) && is4) goto exactly1; | 
 | 1531 |    if (o == GOF(GPR25) && is4) goto exactly1; | 
 | 1532 |    if (o == GOF(GPR26) && is4) goto exactly1; | 
 | 1533 |    if (o == GOF(GPR27) && is4) goto exactly1; | 
 | 1534 |    if (o == GOF(GPR28) && is4) goto exactly1; | 
 | 1535 |    if (o == GOF(GPR29) && is4) goto exactly1; | 
 | 1536 |    if (o == GOF(GPR30) && is4) goto exactly1; | 
 | 1537 |    if (o == GOF(GPR31) && is4) goto exactly1; | 
 | 1538 |  | 
 | 1539 |    /* Misc integer reg and condition code accesses */ | 
 | 1540 |    if (o == GOF(LR)        && is4) goto exactly1; | 
 | 1541 |    if (o == GOF(CTR)       && is4) goto exactly1; | 
 | 1542 |    if (o == GOF(CIA)       && is4) goto none; | 
 | 1543 |    if (o == GOF(CIA_AT_SC) && is4) goto none; | 
 | 1544 |    if (o == GOF(RESVN)     && is4) goto none; | 
 | 1545 |    if (o == GOF(TISTART)   && is4) goto none; | 
 | 1546 |    if (o == GOF(TILEN)     && is4) goto none; | 
 | 1547 |    if (o == GOF(REDIR_SP)  && is4) goto none; | 
 | 1548 |  | 
 | 1549 |    if (sz == 1) { | 
 | 1550 |       if (o == GOF(XER_SO))  goto none; | 
 | 1551 |       if (o == GOF(XER_OV))  goto none; | 
 | 1552 |       if (o == GOF(XER_CA))  goto none; | 
 | 1553 |       if (o == GOF(XER_BC))  goto none; | 
 | 1554 |       if (o == GOF(CR0_321)) goto none; | 
 | 1555 |       if (o == GOF(CR0_0))   goto none; | 
 | 1556 |       if (o == GOF(CR1_321)) goto none; | 
 | 1557 |       if (o == GOF(CR1_0))   goto none; | 
 | 1558 |       if (o == GOF(CR2_321)) goto none; | 
 | 1559 |       if (o == GOF(CR2_0))   goto none; | 
 | 1560 |       if (o == GOF(CR3_321)) goto none; | 
 | 1561 |       if (o == GOF(CR3_0))   goto none; | 
 | 1562 |       if (o == GOF(CR4_321)) goto none; | 
 | 1563 |       if (o == GOF(CR4_0))   goto none; | 
 | 1564 |       if (o == GOF(CR5_321)) goto none; | 
 | 1565 |       if (o == GOF(CR5_0))   goto none; | 
 | 1566 |       if (o == GOF(CR6_321)) goto none; | 
 | 1567 |       if (o == GOF(CR6_0))   goto none; | 
 | 1568 |       if (o == GOF(CR7_321)) goto none; | 
 | 1569 |       if (o == GOF(CR7_0))   goto none; | 
 | 1570 |    } | 
 | 1571 |  | 
 | 1572 |    /* Exact accesses to FP registers */ | 
 | 1573 |    if (o == GOF(FPR0)  && is8) goto none; | 
 | 1574 |    if (o == GOF(FPR1)  && is8) goto none; | 
 | 1575 |    if (o == GOF(FPR2)  && is8) goto none; | 
 | 1576 |    if (o == GOF(FPR3)  && is8) goto none; | 
 | 1577 |    if (o == GOF(FPR4)  && is8) goto none; | 
 | 1578 |    if (o == GOF(FPR5)  && is8) goto none; | 
 | 1579 |    if (o == GOF(FPR6)  && is8) goto none; | 
 | 1580 |    if (o == GOF(FPR7)  && is8) goto none; | 
 | 1581 |    if (o == GOF(FPR8)  && is8) goto none; | 
 | 1582 |    if (o == GOF(FPR9)  && is8) goto none; | 
 | 1583 |    if (o == GOF(FPR10) && is8) goto none; | 
 | 1584 |    if (o == GOF(FPR11) && is8) goto none; | 
 | 1585 |    if (o == GOF(FPR12) && is8) goto none; | 
 | 1586 |    if (o == GOF(FPR13) && is8) goto none; | 
 | 1587 |    if (o == GOF(FPR14) && is8) goto none; | 
 | 1588 |    if (o == GOF(FPR15) && is8) goto none; | 
 | 1589 |    if (o == GOF(FPR16) && is8) goto none; | 
 | 1590 |    if (o == GOF(FPR17) && is8) goto none; | 
 | 1591 |    if (o == GOF(FPR18) && is8) goto none; | 
 | 1592 |    if (o == GOF(FPR19) && is8) goto none; | 
 | 1593 |    if (o == GOF(FPR20) && is8) goto none; | 
 | 1594 |    if (o == GOF(FPR21) && is8) goto none; | 
 | 1595 |    if (o == GOF(FPR22) && is8) goto none; | 
 | 1596 |    if (o == GOF(FPR23) && is8) goto none; | 
 | 1597 |    if (o == GOF(FPR24) && is8) goto none; | 
 | 1598 |    if (o == GOF(FPR25) && is8) goto none; | 
 | 1599 |    if (o == GOF(FPR26) && is8) goto none; | 
 | 1600 |    if (o == GOF(FPR27) && is8) goto none; | 
 | 1601 |    if (o == GOF(FPR28) && is8) goto none; | 
 | 1602 |    if (o == GOF(FPR29) && is8) goto none; | 
 | 1603 |    if (o == GOF(FPR30) && is8) goto none; | 
 | 1604 |    if (o == GOF(FPR31) && is8) goto none; | 
 | 1605 |  | 
 | 1606 |    /* FP admin related */ | 
 | 1607 |    if (o == GOF(FPROUND) && is4) goto none; | 
 | 1608 |    if (o == GOF(EMWARN)  && is4) goto none; | 
 | 1609 |  | 
 | 1610 |    /* Altivec registers */ | 
 | 1611 |    if (o == GOF(VR0)  && sz == 16) goto none; | 
 | 1612 |    if (o == GOF(VR1)  && sz == 16) goto none; | 
 | 1613 |    if (o == GOF(VR2)  && sz == 16) goto none; | 
 | 1614 |    if (o == GOF(VR3)  && sz == 16) goto none; | 
 | 1615 |    if (o == GOF(VR4)  && sz == 16) goto none; | 
 | 1616 |    if (o == GOF(VR5)  && sz == 16) goto none; | 
 | 1617 |    if (o == GOF(VR6)  && sz == 16) goto none; | 
 | 1618 |    if (o == GOF(VR7)  && sz == 16) goto none; | 
 | 1619 |    if (o == GOF(VR8)  && sz == 16) goto none; | 
 | 1620 |    if (o == GOF(VR9)  && sz == 16) goto none; | 
 | 1621 |    if (o == GOF(VR10) && sz == 16) goto none; | 
 | 1622 |    if (o == GOF(VR11) && sz == 16) goto none; | 
 | 1623 |    if (o == GOF(VR12) && sz == 16) goto none; | 
 | 1624 |    if (o == GOF(VR13) && sz == 16) goto none; | 
 | 1625 |    if (o == GOF(VR14) && sz == 16) goto none; | 
 | 1626 |    if (o == GOF(VR15) && sz == 16) goto none; | 
 | 1627 |    if (o == GOF(VR16) && sz == 16) goto none; | 
 | 1628 |    if (o == GOF(VR17) && sz == 16) goto none; | 
 | 1629 |    if (o == GOF(VR18) && sz == 16) goto none; | 
 | 1630 |    if (o == GOF(VR19) && sz == 16) goto none; | 
 | 1631 |    if (o == GOF(VR20) && sz == 16) goto none; | 
 | 1632 |    if (o == GOF(VR21) && sz == 16) goto none; | 
 | 1633 |    if (o == GOF(VR22) && sz == 16) goto none; | 
 | 1634 |    if (o == GOF(VR23) && sz == 16) goto none; | 
 | 1635 |    if (o == GOF(VR24) && sz == 16) goto none; | 
 | 1636 |    if (o == GOF(VR25) && sz == 16) goto none; | 
 | 1637 |    if (o == GOF(VR26) && sz == 16) goto none; | 
 | 1638 |    if (o == GOF(VR27) && sz == 16) goto none; | 
 | 1639 |    if (o == GOF(VR28) && sz == 16) goto none; | 
 | 1640 |    if (o == GOF(VR29) && sz == 16) goto none; | 
 | 1641 |    if (o == GOF(VR30) && sz == 16) goto none; | 
 | 1642 |    if (o == GOF(VR31) && sz == 16) goto none; | 
 | 1643 |  | 
| sewardj | aae8208 | 2008-10-21 23:10:18 +0000 | [diff] [blame] | 1644 |    /* Altivec admin related */ | 
 | 1645 |    if (o == GOF(VRSAVE) && is4) goto none; | 
 | 1646 |  | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 1647 |    VG_(printf)("get_IntRegInfo(ppc32):failing on (%d,%d)\n", o, sz); | 
 | 1648 |    tl_assert(0); | 
 | 1649 | #  undef GOF | 
 | 1650 |  | 
 | 1651 |    /* -------------------- ppc64 -------------------- */ | 
 | 1652 |  | 
 | 1653 | #  elif defined(VGA_ppc64) | 
 | 1654 |  | 
 | 1655 | #  define GOF(_fieldname) \ | 
 | 1656 |       (offsetof(VexGuestPPC64State,guest_##_fieldname)) | 
 | 1657 |  | 
 | 1658 |    Int  o    = offset; | 
 | 1659 |    Int  sz   = szB; | 
 | 1660 |    Bool is4  = sz == 4; | 
 | 1661 |    Bool is8  = sz == 8; | 
 | 1662 |  | 
 | 1663 |    tl_assert(sz > 0); | 
 | 1664 |    tl_assert(host_is_big_endian()); | 
 | 1665 |  | 
 | 1666 |    /* Set default state to "does not intersect any int register". */ | 
 | 1667 |    VG_(memset)( iii, 0, sizeof(*iii) ); | 
 | 1668 |  | 
 | 1669 |    /* Exact accesses to integer registers */ | 
 | 1670 |    if (o == GOF(GPR0)  && is8) goto exactly1; | 
 | 1671 |    if (o == GOF(GPR1)  && is8) goto exactly1; | 
 | 1672 |    if (o == GOF(GPR2)  && is8) goto exactly1; | 
 | 1673 |    if (o == GOF(GPR3)  && is8) goto exactly1; | 
 | 1674 |    if (o == GOF(GPR4)  && is8) goto exactly1; | 
 | 1675 |    if (o == GOF(GPR5)  && is8) goto exactly1; | 
 | 1676 |    if (o == GOF(GPR6)  && is8) goto exactly1; | 
 | 1677 |    if (o == GOF(GPR7)  && is8) goto exactly1; | 
 | 1678 |    if (o == GOF(GPR8)  && is8) goto exactly1; | 
 | 1679 |    if (o == GOF(GPR9)  && is8) goto exactly1; | 
 | 1680 |    if (o == GOF(GPR10) && is8) goto exactly1; | 
 | 1681 |    if (o == GOF(GPR11) && is8) goto exactly1; | 
 | 1682 |    if (o == GOF(GPR12) && is8) goto exactly1; | 
 | 1683 |    if (o == GOF(GPR13) && is8) goto exactly1; | 
 | 1684 |    if (o == GOF(GPR14) && is8) goto exactly1; | 
 | 1685 |    if (o == GOF(GPR15) && is8) goto exactly1; | 
 | 1686 |    if (o == GOF(GPR16) && is8) goto exactly1; | 
 | 1687 |    if (o == GOF(GPR17) && is8) goto exactly1; | 
 | 1688 |    if (o == GOF(GPR18) && is8) goto exactly1; | 
 | 1689 |    if (o == GOF(GPR19) && is8) goto exactly1; | 
 | 1690 |    if (o == GOF(GPR20) && is8) goto exactly1; | 
 | 1691 |    if (o == GOF(GPR21) && is8) goto exactly1; | 
 | 1692 |    if (o == GOF(GPR22) && is8) goto exactly1; | 
 | 1693 |    if (o == GOF(GPR23) && is8) goto exactly1; | 
 | 1694 |    if (o == GOF(GPR24) && is8) goto exactly1; | 
 | 1695 |    if (o == GOF(GPR25) && is8) goto exactly1; | 
 | 1696 |    if (o == GOF(GPR26) && is8) goto exactly1; | 
 | 1697 |    if (o == GOF(GPR27) && is8) goto exactly1; | 
 | 1698 |    if (o == GOF(GPR28) && is8) goto exactly1; | 
 | 1699 |    if (o == GOF(GPR29) && is8) goto exactly1; | 
 | 1700 |    if (o == GOF(GPR30) && is8) goto exactly1; | 
 | 1701 |    if (o == GOF(GPR31) && is8) goto exactly1; | 
 | 1702 |  | 
 | 1703 |    /* Misc integer reg and condition code accesses */ | 
 | 1704 |    if (o == GOF(LR)        && is8) goto exactly1; | 
 | 1705 |    if (o == GOF(CTR)       && is8) goto exactly1; | 
 | 1706 |    if (o == GOF(CIA)       && is8) goto none; | 
 | 1707 |    if (o == GOF(CIA_AT_SC) && is8) goto none; | 
 | 1708 |    if (o == GOF(RESVN)     && is8) goto none; | 
 | 1709 |    if (o == GOF(TISTART)   && is8) goto none; | 
 | 1710 |    if (o == GOF(TILEN)     && is8) goto none; | 
 | 1711 |    if (o == GOF(REDIR_SP)  && is8) goto none; | 
 | 1712 |  | 
 | 1713 |    if (sz == 1) { | 
 | 1714 |       if (o == GOF(XER_SO))  goto none; | 
 | 1715 |       if (o == GOF(XER_OV))  goto none; | 
 | 1716 |       if (o == GOF(XER_CA))  goto none; | 
 | 1717 |       if (o == GOF(XER_BC))  goto none; | 
 | 1718 |       if (o == GOF(CR0_321)) goto none; | 
 | 1719 |       if (o == GOF(CR0_0))   goto none; | 
 | 1720 |       if (o == GOF(CR1_321)) goto none; | 
 | 1721 |       if (o == GOF(CR1_0))   goto none; | 
 | 1722 |       if (o == GOF(CR2_321)) goto none; | 
 | 1723 |       if (o == GOF(CR2_0))   goto none; | 
 | 1724 |       if (o == GOF(CR3_321)) goto none; | 
 | 1725 |       if (o == GOF(CR3_0))   goto none; | 
 | 1726 |       if (o == GOF(CR4_321)) goto none; | 
 | 1727 |       if (o == GOF(CR4_0))   goto none; | 
 | 1728 |       if (o == GOF(CR5_321)) goto none; | 
 | 1729 |       if (o == GOF(CR5_0))   goto none; | 
 | 1730 |       if (o == GOF(CR6_321)) goto none; | 
 | 1731 |       if (o == GOF(CR6_0))   goto none; | 
 | 1732 |       if (o == GOF(CR7_321)) goto none; | 
 | 1733 |       if (o == GOF(CR7_0))   goto none; | 
 | 1734 |    } | 
 | 1735 |  | 
 | 1736 |    /* Exact accesses to FP registers */ | 
 | 1737 |    if (o == GOF(FPR0)  && is8) goto none; | 
 | 1738 |    if (o == GOF(FPR1)  && is8) goto none; | 
 | 1739 |    if (o == GOF(FPR2)  && is8) goto none; | 
 | 1740 |    if (o == GOF(FPR3)  && is8) goto none; | 
 | 1741 |    if (o == GOF(FPR4)  && is8) goto none; | 
 | 1742 |    if (o == GOF(FPR5)  && is8) goto none; | 
 | 1743 |    if (o == GOF(FPR6)  && is8) goto none; | 
 | 1744 |    if (o == GOF(FPR7)  && is8) goto none; | 
 | 1745 |    if (o == GOF(FPR8)  && is8) goto none; | 
 | 1746 |    if (o == GOF(FPR9)  && is8) goto none; | 
 | 1747 |    if (o == GOF(FPR10) && is8) goto none; | 
 | 1748 |    if (o == GOF(FPR11) && is8) goto none; | 
 | 1749 |    if (o == GOF(FPR12) && is8) goto none; | 
 | 1750 |    if (o == GOF(FPR13) && is8) goto none; | 
 | 1751 |    if (o == GOF(FPR14) && is8) goto none; | 
 | 1752 |    if (o == GOF(FPR15) && is8) goto none; | 
 | 1753 |    if (o == GOF(FPR16) && is8) goto none; | 
 | 1754 |    if (o == GOF(FPR17) && is8) goto none; | 
 | 1755 |    if (o == GOF(FPR18) && is8) goto none; | 
 | 1756 |    if (o == GOF(FPR19) && is8) goto none; | 
 | 1757 |    if (o == GOF(FPR20) && is8) goto none; | 
 | 1758 |    if (o == GOF(FPR21) && is8) goto none; | 
 | 1759 |    if (o == GOF(FPR22) && is8) goto none; | 
 | 1760 |    if (o == GOF(FPR23) && is8) goto none; | 
 | 1761 |    if (o == GOF(FPR24) && is8) goto none; | 
 | 1762 |    if (o == GOF(FPR25) && is8) goto none; | 
 | 1763 |    if (o == GOF(FPR26) && is8) goto none; | 
 | 1764 |    if (o == GOF(FPR27) && is8) goto none; | 
 | 1765 |    if (o == GOF(FPR28) && is8) goto none; | 
 | 1766 |    if (o == GOF(FPR29) && is8) goto none; | 
 | 1767 |    if (o == GOF(FPR30) && is8) goto none; | 
 | 1768 |    if (o == GOF(FPR31) && is8) goto none; | 
 | 1769 |  | 
 | 1770 |    /* FP admin related */ | 
 | 1771 |    if (o == GOF(FPROUND) && is4) goto none; | 
 | 1772 |    if (o == GOF(EMWARN)  && is4) goto none; | 
 | 1773 |  | 
 | 1774 |    /* Altivec registers */ | 
 | 1775 |    if (o == GOF(VR0)  && sz == 16) goto none; | 
 | 1776 |    if (o == GOF(VR1)  && sz == 16) goto none; | 
 | 1777 |    if (o == GOF(VR2)  && sz == 16) goto none; | 
 | 1778 |    if (o == GOF(VR3)  && sz == 16) goto none; | 
 | 1779 |    if (o == GOF(VR4)  && sz == 16) goto none; | 
 | 1780 |    if (o == GOF(VR5)  && sz == 16) goto none; | 
 | 1781 |    if (o == GOF(VR6)  && sz == 16) goto none; | 
 | 1782 |    if (o == GOF(VR7)  && sz == 16) goto none; | 
 | 1783 |    if (o == GOF(VR8)  && sz == 16) goto none; | 
 | 1784 |    if (o == GOF(VR9)  && sz == 16) goto none; | 
 | 1785 |    if (o == GOF(VR10) && sz == 16) goto none; | 
 | 1786 |    if (o == GOF(VR11) && sz == 16) goto none; | 
 | 1787 |    if (o == GOF(VR12) && sz == 16) goto none; | 
 | 1788 |    if (o == GOF(VR13) && sz == 16) goto none; | 
 | 1789 |    if (o == GOF(VR14) && sz == 16) goto none; | 
 | 1790 |    if (o == GOF(VR15) && sz == 16) goto none; | 
 | 1791 |    if (o == GOF(VR16) && sz == 16) goto none; | 
 | 1792 |    if (o == GOF(VR17) && sz == 16) goto none; | 
 | 1793 |    if (o == GOF(VR18) && sz == 16) goto none; | 
 | 1794 |    if (o == GOF(VR19) && sz == 16) goto none; | 
 | 1795 |    if (o == GOF(VR20) && sz == 16) goto none; | 
 | 1796 |    if (o == GOF(VR21) && sz == 16) goto none; | 
 | 1797 |    if (o == GOF(VR22) && sz == 16) goto none; | 
 | 1798 |    if (o == GOF(VR23) && sz == 16) goto none; | 
 | 1799 |    if (o == GOF(VR24) && sz == 16) goto none; | 
 | 1800 |    if (o == GOF(VR25) && sz == 16) goto none; | 
 | 1801 |    if (o == GOF(VR26) && sz == 16) goto none; | 
 | 1802 |    if (o == GOF(VR27) && sz == 16) goto none; | 
 | 1803 |    if (o == GOF(VR28) && sz == 16) goto none; | 
 | 1804 |    if (o == GOF(VR29) && sz == 16) goto none; | 
 | 1805 |    if (o == GOF(VR30) && sz == 16) goto none; | 
 | 1806 |    if (o == GOF(VR31) && sz == 16) goto none; | 
 | 1807 |  | 
| sewardj | aae8208 | 2008-10-21 23:10:18 +0000 | [diff] [blame] | 1808 |    /* Altivec admin related */ | 
 | 1809 |    if (o == GOF(VRSAVE) && is4) goto none; | 
 | 1810 |  | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 1811 |    VG_(printf)("get_IntRegInfo(ppc64):failing on (%d,%d)\n", o, sz); | 
 | 1812 |    tl_assert(0); | 
 | 1813 | #  undef GOF | 
 | 1814 |  | 
 | 1815 |  | 
 | 1816 | #  else | 
 | 1817 | #    error "FIXME: not implemented for this architecture" | 
 | 1818 | #  endif | 
 | 1819 |  | 
 | 1820 |   exactly1: | 
 | 1821 |    iii->n_offsets = -1; | 
 | 1822 |    return; | 
 | 1823 |   none: | 
 | 1824 |    iii->n_offsets = 0; | 
 | 1825 |    return; | 
 | 1826 |   contains_o: | 
 | 1827 |    tl_assert(o >= 0 && 0 == (o % sizeof(UWord))); | 
 | 1828 |    iii->n_offsets = 1; | 
 | 1829 |    iii->offsets[0] = o; | 
 | 1830 |    return; | 
 | 1831 | } | 
 | 1832 |  | 
 | 1833 |  | 
 | 1834 | /* Does 'arr' describe an indexed guest state section containing host | 
 | 1835 |    words, that we want to shadow? */ | 
 | 1836 |  | 
 | 1837 | static Bool is_integer_guest_reg_array ( IRRegArray* arr ) | 
 | 1838 | { | 
 | 1839 |    /* --------------------- x86 --------------------- */ | 
 | 1840 | #  if defined(VGA_x86) | 
 | 1841 |    /* The x87 tag array. */ | 
 | 1842 |    if (arr->base == offsetof(VexGuestX86State,guest_FPTAG[0]) | 
 | 1843 |        && arr->elemTy == Ity_I8 && arr->nElems == 8) | 
 | 1844 |       return False; | 
 | 1845 |    /* The x87 register array. */ | 
 | 1846 |    if (arr->base == offsetof(VexGuestX86State,guest_FPREG[0]) | 
 | 1847 |        && arr->elemTy == Ity_F64 && arr->nElems == 8) | 
 | 1848 |       return False; | 
 | 1849 |  | 
 | 1850 |    VG_(printf)("is_integer_guest_reg_array(x86): unhandled: "); | 
 | 1851 |    ppIRRegArray(arr); | 
 | 1852 |    VG_(printf)("\n"); | 
 | 1853 |    tl_assert(0); | 
 | 1854 |  | 
 | 1855 |    /* -------------------- amd64 -------------------- */ | 
 | 1856 | #  elif defined(VGA_amd64) | 
 | 1857 |    /* The x87 tag array. */ | 
 | 1858 |    if (arr->base == offsetof(VexGuestAMD64State,guest_FPTAG[0]) | 
 | 1859 |        && arr->elemTy == Ity_I8 && arr->nElems == 8) | 
 | 1860 |       return False; | 
 | 1861 |    /* The x87 register array. */ | 
 | 1862 |    if (arr->base == offsetof(VexGuestAMD64State,guest_FPREG[0]) | 
 | 1863 |        && arr->elemTy == Ity_F64 && arr->nElems == 8) | 
 | 1864 |       return False; | 
 | 1865 |  | 
 | 1866 |    VG_(printf)("is_integer_guest_reg_array(amd64): unhandled: "); | 
 | 1867 |    ppIRRegArray(arr); | 
 | 1868 |    VG_(printf)("\n"); | 
 | 1869 |    tl_assert(0); | 
 | 1870 |  | 
 | 1871 |    /* -------------------- ppc32 -------------------- */ | 
 | 1872 | #  elif defined(VGA_ppc32) | 
 | 1873 |    /* The redir stack. */ | 
 | 1874 |    if (arr->base == offsetof(VexGuestPPC32State,guest_REDIR_STACK[0]) | 
 | 1875 |        && arr->elemTy == Ity_I32 | 
 | 1876 |        && arr->nElems == VEX_GUEST_PPC32_REDIR_STACK_SIZE) | 
 | 1877 |       return True; | 
 | 1878 |  | 
 | 1879 |    VG_(printf)("is_integer_guest_reg_array(ppc32): unhandled: "); | 
 | 1880 |    ppIRRegArray(arr); | 
 | 1881 |    VG_(printf)("\n"); | 
 | 1882 |    tl_assert(0); | 
 | 1883 |  | 
 | 1884 |    /* -------------------- ppc64 -------------------- */ | 
 | 1885 | #  elif defined(VGA_ppc64) | 
 | 1886 |    /* The redir stack. */ | 
 | 1887 |    if (arr->base == offsetof(VexGuestPPC64State,guest_REDIR_STACK[0]) | 
 | 1888 |        && arr->elemTy == Ity_I64 | 
 | 1889 |        && arr->nElems == VEX_GUEST_PPC64_REDIR_STACK_SIZE) | 
 | 1890 |       return True; | 
 | 1891 |  | 
 | 1892 |    VG_(printf)("is_integer_guest_reg_array(ppc64): unhandled: "); | 
 | 1893 |    ppIRRegArray(arr); | 
 | 1894 |    VG_(printf)("\n"); | 
 | 1895 |    tl_assert(0); | 
 | 1896 |  | 
 | 1897 | #  else | 
 | 1898 | #    error "FIXME: not implemented for this architecture" | 
 | 1899 | #  endif | 
 | 1900 | } | 
 | 1901 |  | 
 | 1902 |  | 
 | 1903 | // END move this uglyness to pc_machine.c | 
 | 1904 |  | 
 | 1905 | /* returns True iff given slice exactly matches an int reg.  Merely | 
 | 1906 |    a convenience wrapper around get_IntRegInfo. */ | 
 | 1907 | static Bool is_integer_guest_reg ( Int offset, Int szB ) | 
 | 1908 | { | 
 | 1909 |    IntRegInfo iii; | 
 | 1910 |    get_IntRegInfo( &iii, offset, szB ); | 
 | 1911 |    tl_assert(iii.n_offsets >= -1 && iii.n_offsets <= N_INTREGINFO_OFFSETS); | 
 | 1912 |    return iii.n_offsets == -1; | 
 | 1913 | } | 
 | 1914 |  | 
 | 1915 | /* these assume guest and host have the same endianness and | 
 | 1916 |    word size (probably). */ | 
 | 1917 | static UWord get_guest_intreg ( ThreadId tid, Int shadowNo, | 
| njn | c4431bf | 2009-01-15 21:29:24 +0000 | [diff] [blame] | 1918 |                                 PtrdiffT offset, SizeT size ) | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 1919 | { | 
 | 1920 |    UChar tmp[ 2 + sizeof(UWord) ]; | 
 | 1921 |    tl_assert(size == sizeof(UWord)); | 
 | 1922 |    tl_assert(0 == (offset % sizeof(UWord))); | 
 | 1923 |    VG_(memset)(tmp, 0, sizeof(tmp)); | 
 | 1924 |    tmp[0] = 0x31; | 
 | 1925 |    tmp[ sizeof(tmp)-1 ] = 0x27; | 
 | 1926 |    VG_(get_shadow_regs_area)(tid, &tmp[1], shadowNo, offset, size); | 
 | 1927 |    tl_assert(tmp[0] == 0x31); | 
 | 1928 |    tl_assert(tmp[ sizeof(tmp)-1 ] == 0x27); | 
 | 1929 |    return * ((UWord*) &tmp[1] ); /* MISALIGNED LOAD */ | 
 | 1930 | } | 
 | 1931 | static void put_guest_intreg ( ThreadId tid, Int shadowNo, | 
| njn | c4431bf | 2009-01-15 21:29:24 +0000 | [diff] [blame] | 1932 |                                PtrdiffT offset, SizeT size, UWord w ) | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 1933 | { | 
 | 1934 |    tl_assert(size == sizeof(UWord)); | 
 | 1935 |    tl_assert(0 == (offset % sizeof(UWord))); | 
 | 1936 |    VG_(set_shadow_regs_area)(tid, shadowNo, offset, size, | 
 | 1937 |                              (const UChar*)&w); | 
 | 1938 | } | 
 | 1939 |  | 
 | 1940 | /* Initialise the integer shadow registers to UNKNOWN.  This is a bit | 
 | 1941 |    of a nasty kludge, but it does mean we don't need to know which | 
 | 1942 |    registers we really need to initialise -- simply assume that all | 
 | 1943 |    integer registers will be naturally aligned w.r.t. the start of the | 
 | 1944 |    guest state, and fill in all possible entries. */ | 
 | 1945 | static void init_shadow_registers ( ThreadId tid ) | 
 | 1946 | { | 
 | 1947 |    Int i, wordSzB = sizeof(UWord); | 
 | 1948 |    for (i = 0; i < MC_SIZEOF_GUEST_STATE-wordSzB; i += wordSzB) { | 
 | 1949 |       put_guest_intreg( tid, 1, i, wordSzB, (UWord)UNKNOWN ); | 
 | 1950 |    } | 
 | 1951 | } | 
 | 1952 |  | 
| njn | c4431bf | 2009-01-15 21:29:24 +0000 | [diff] [blame] | 1953 | static void post_reg_write_nonptr ( ThreadId tid, PtrdiffT offset, SizeT size ) | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 1954 | { | 
 | 1955 |    // syscall_return: Default is non-pointer.  If it really is a pointer | 
 | 1956 |    // (eg. for mmap()), SK_(post_syscall) sets it again afterwards. | 
 | 1957 |    // | 
 | 1958 |    // clientreq_return: All the global client requests return non-pointers | 
 | 1959 |    // (except possibly CLIENT_CALL[0123], but they're handled by | 
 | 1960 |    // post_reg_write_clientcall, not here). | 
 | 1961 |    // | 
 | 1962 |    if (is_integer_guest_reg( (Int)offset, (Int)size )) { | 
 | 1963 |       put_guest_intreg( tid, 1, offset, size, (UWord)NONPTR ); | 
 | 1964 |    } else { | 
 | 1965 |       tl_assert(0); | 
 | 1966 |    } | 
 | 1967 |    //   VG_(set_thread_shadow_archreg)( tid, reg, (UInt)NONPTR ); | 
 | 1968 | } | 
 | 1969 |  | 
 | 1970 | static void post_reg_write_nonptr_or_unknown ( ThreadId tid, | 
| njn | c4431bf | 2009-01-15 21:29:24 +0000 | [diff] [blame] | 1971 |                                                PtrdiffT offset, SizeT size ) | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 1972 | { | 
 | 1973 |    // deliver_signal: called from two places; one sets the reg to zero, the | 
 | 1974 |    // other sets the stack pointer. | 
 | 1975 |    // | 
 | 1976 |    if (is_integer_guest_reg( (Int)offset, (Int)size )) { | 
 | 1977 |       put_guest_intreg( | 
 | 1978 |          tid, 1/*shadowno*/, offset, size, | 
 | 1979 |          (UWord)nonptr_or_unknown(  | 
 | 1980 |                    get_guest_intreg( tid, 0/*shadowno*/, | 
 | 1981 |                                      offset, size ))); | 
 | 1982 |    } else { | 
 | 1983 |       tl_assert(0); | 
 | 1984 |    } | 
 | 1985 | } | 
 | 1986 |  | 
 | 1987 | void h_post_reg_write_demux ( CorePart part, ThreadId tid, | 
| njn | c4431bf | 2009-01-15 21:29:24 +0000 | [diff] [blame] | 1988 |                               PtrdiffT guest_state_offset, SizeT size) | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 1989 | { | 
 | 1990 |    if (0) | 
 | 1991 |    VG_(printf)("post_reg_write_demux: tid %d part %d off %ld size %ld\n", | 
 | 1992 |                (Int)tid, (Int)part, | 
 | 1993 |               guest_state_offset, size); | 
 | 1994 |    switch (part) { | 
 | 1995 |       case Vg_CoreStartup: | 
 | 1996 |          /* This is a bit of a kludge since for any Vg_CoreStartup | 
 | 1997 |             event we overwrite the entire shadow register set.  But | 
 | 1998 |             that's ok - we're only called once with | 
 | 1999 |             part==Vg_CoreStartup event, and in that case the supplied | 
 | 2000 |             offset & size cover the entire guest state anyway. */ | 
 | 2001 |          init_shadow_registers(tid); | 
 | 2002 |          break; | 
 | 2003 |       case Vg_CoreSysCall: | 
 | 2004 |          if (0) VG_(printf)("ZZZZZZZ p_r_w    -> NONPTR\n"); | 
 | 2005 |          post_reg_write_nonptr( tid, guest_state_offset, size ); | 
 | 2006 |          break; | 
 | 2007 |       case Vg_CoreClientReq: | 
 | 2008 |          post_reg_write_nonptr( tid, guest_state_offset, size ); | 
 | 2009 |          break; | 
 | 2010 |       case Vg_CoreSignal: | 
 | 2011 |          post_reg_write_nonptr_or_unknown( tid, guest_state_offset, size ); | 
 | 2012 |          break; | 
 | 2013 |       default: | 
 | 2014 |          tl_assert(0); | 
 | 2015 |    } | 
 | 2016 | } | 
 | 2017 |  | 
| njn | c4431bf | 2009-01-15 21:29:24 +0000 | [diff] [blame] | 2018 | void h_post_reg_write_clientcall(ThreadId tid, PtrdiffT guest_state_offset, | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2019 |                                  SizeT size, Addr f ) | 
 | 2020 | { | 
 | 2021 |    UWord p; | 
 | 2022 |  | 
 | 2023 |    // Having to do this is a bit nasty... | 
 | 2024 |    if (f == (Addr)h_replace_malloc | 
 | 2025 |        || f == (Addr)h_replace___builtin_new | 
 | 2026 |        || f == (Addr)h_replace___builtin_vec_new | 
 | 2027 |        || f == (Addr)h_replace_calloc | 
 | 2028 |        || f == (Addr)h_replace_memalign | 
 | 2029 |        || f == (Addr)h_replace_realloc) | 
 | 2030 |    { | 
 | 2031 |       // We remembered the last added segment;  make sure it's the right one. | 
 | 2032 |       /* What's going on: at this point, the scheduler has just called | 
 | 2033 |          'f' -- one of our malloc replacement functions -- and it has | 
 | 2034 |          returned.  The return value has been written to the guest | 
 | 2035 |          state of thread 'tid', offset 'guest_state_offset' length | 
 | 2036 |          'size'.  We need to look at that return value and set the | 
 | 2037 |          shadow return value accordingly.  The shadow return value | 
 | 2038 |          required is handed to us "under the counter" through the | 
 | 2039 |          global variable 'last_seg_added'.  This is all very ugly, not | 
 | 2040 |          to mention, non-thread-safe should V ever become | 
 | 2041 |          multithreaded. */ | 
 | 2042 |       /* assert the place where the return value is is a legit int reg */ | 
 | 2043 |       tl_assert(is_integer_guest_reg(guest_state_offset, size)); | 
 | 2044 |       /* Now we need to look at the returned value, to see whether the | 
 | 2045 |          malloc succeeded or not. */ | 
 | 2046 |       p = get_guest_intreg(tid, 0/*non-shadow*/, guest_state_offset, size); | 
 | 2047 |       if ((UWord)NULL == p) { | 
 | 2048 |          // if alloc failed, eg. realloc on bogus pointer | 
 | 2049 |          put_guest_intreg(tid, 1/*first-shadow*/, | 
 | 2050 |                           guest_state_offset, size, (UWord)NONPTR ); | 
 | 2051 |       } else { | 
 | 2052 |          // alloc didn't fail.  Check we have the correct segment. | 
 | 2053 |          tl_assert(p == last_seg_added->addr); | 
 | 2054 |          put_guest_intreg(tid, 1/*first-shadow*/, | 
 | 2055 |                           guest_state_offset, size, (UWord)last_seg_added ); | 
 | 2056 |       } | 
 | 2057 |    }  | 
 | 2058 |    else if (f == (Addr)h_replace_free | 
 | 2059 |             || f == (Addr)h_replace___builtin_delete | 
 | 2060 |             || f == (Addr)h_replace___builtin_vec_delete | 
 | 2061 |    //            || f == (Addr)VG_(cli_block_size) | 
 | 2062 |             || f == (Addr)VG_(message)) | 
 | 2063 |    { | 
 | 2064 |       // Probably best to set the (non-existent!) return value to | 
 | 2065 |       // non-pointer. | 
 | 2066 |       tl_assert(is_integer_guest_reg(guest_state_offset, size)); | 
 | 2067 |       put_guest_intreg(tid, 1/*first-shadow*/, | 
 | 2068 |                        guest_state_offset, size, (UWord)NONPTR ); | 
 | 2069 |    } | 
 | 2070 |    else { | 
 | 2071 |       // Anything else, probably best to set return value to non-pointer. | 
 | 2072 |       //VG_(set_thread_shadow_archreg)(tid, reg, (UInt)UNKNOWN); | 
 | 2073 |       Char fbuf[100]; | 
 | 2074 |       VG_(printf)("f = %#lx\n", f); | 
 | 2075 |       VG_(get_fnname)(f, fbuf, 100); | 
 | 2076 |       VG_(printf)("name = %s\n", fbuf); | 
 | 2077 |       VG_(tool_panic)("argh: clientcall"); | 
 | 2078 |    } | 
 | 2079 | } | 
 | 2080 |  | 
 | 2081 |  | 
 | 2082 | //zz /*--------------------------------------------------------------------*/ | 
 | 2083 | //zz /*--- Sanity checking                                              ---*/ | 
 | 2084 | //zz /*--------------------------------------------------------------------*/ | 
 | 2085 | //zz  | 
 | 2086 | //zz /* Check that nobody has spuriously claimed that the first or last 16 | 
 | 2087 | //zz    pages (64 KB) of address space have become accessible.  Failure of | 
 | 2088 | //zz    the following do not per se indicate an internal consistency | 
 | 2089 | //zz    problem, but they are so likely to that we really want to know | 
 | 2090 | //zz    about it if so. */ | 
 | 2091 | //zz Bool pc_replace_cheap_sanity_check) ( void ) | 
 | 2092 | //zz { | 
 | 2093 | //zz    if (IS_DISTINGUISHED_SM(primary_map[0]) | 
 | 2094 | //zz        /* kludge: kernel drops a page up at top of address range for | 
 | 2095 | //zz           magic "optimized syscalls", so we can no longer check the | 
 | 2096 | //zz           highest page */ | 
 | 2097 | //zz        /* && IS_DISTINGUISHED_SM(primary_map[65535]) */ | 
 | 2098 | //zz       ) | 
 | 2099 | //zz       return True; | 
 | 2100 | //zz    else | 
 | 2101 | //zz       return False; | 
 | 2102 | //zz } | 
 | 2103 | //zz  | 
 | 2104 | //zz Bool SK_(expensive_sanity_check) ( void ) | 
 | 2105 | //zz { | 
 | 2106 | //zz    Int i; | 
 | 2107 | //zz  | 
 | 2108 | //zz    /* Make sure nobody changed the distinguished secondary. */ | 
 | 2109 | //zz    for (i = 0; i < SEC_MAP_WORDS; i++) | 
 | 2110 | //zz       if (distinguished_secondary_map.vseg[i] != UNKNOWN) | 
 | 2111 | //zz          return False; | 
 | 2112 | //zz  | 
 | 2113 | //zz    return True; | 
 | 2114 | //zz } | 
 | 2115 |  | 
 | 2116 |  | 
 | 2117 | /*--------------------------------------------------------------------*/ | 
 | 2118 | /*--- System calls                                                 ---*/ | 
 | 2119 | /*--------------------------------------------------------------------*/ | 
 | 2120 |  | 
 | 2121 | void h_pre_syscall ( ThreadId tid, UInt sysno ) | 
 | 2122 | { | 
 | 2123 |    /* we don't do anything at the pre-syscall point */ | 
 | 2124 | } | 
 | 2125 |  | 
 | 2126 | /* The post-syscall table is a table of pairs (number, flag). | 
 | 2127 |  | 
 | 2128 |    'flag' is only ever zero or one.  If it is zero, it indicates that | 
 | 2129 |    default handling for that syscall is required -- namely that the | 
 | 2130 |    syscall is deemed to return NONPTR.  This is the case for the vast | 
 | 2131 |    majority of syscalls.  If it is one then some special | 
 | 2132 |    syscall-specific handling is is required.  No further details of it | 
 | 2133 |    are stored in the table. | 
 | 2134 |  | 
 | 2135 |    On Linux, 'number' is a __NR_xxx constant. | 
 | 2136 |  | 
 | 2137 |    On AIX5, 'number' is an Int*, which points to the Int variable | 
 | 2138 |    holding the currently assigned number for this syscall. | 
 | 2139 |  | 
 | 2140 |    When querying the table, we compare the supplied syscall number | 
 | 2141 |    with the 'number' field (directly on Linux, after dereferencing on | 
 | 2142 |    AIX5), to find the relevant entry.  This requires a linear search | 
 | 2143 |    of the table.  To stop the costs getting too high, the table is | 
 | 2144 |    incrementally rearranged after each search, to move commonly | 
 | 2145 |    requested items a bit closer to the front. | 
 | 2146 |  | 
 | 2147 |    The table is built once, the first time it is used.  After that we | 
 | 2148 |    merely query it (and reorder the entries as a result). */ | 
 | 2149 |  | 
 | 2150 | static XArray* /* of UWordPair */ post_syscall_table = NULL; | 
 | 2151 |  | 
 | 2152 | static void setup_post_syscall_table ( void ) | 
 | 2153 | { | 
 | 2154 |    tl_assert(!post_syscall_table); | 
 | 2155 |    post_syscall_table = VG_(newXA)( VG_(malloc), "pc.h_main.spst.1", | 
 | 2156 |                                     VG_(free), sizeof(UWordPair) ); | 
 | 2157 |    tl_assert(post_syscall_table); | 
 | 2158 |  | 
 | 2159 |    /* --------------- LINUX --------------- */ | 
 | 2160 |  | 
 | 2161 | #  if defined(VGO_linux) | 
 | 2162 |  | 
 | 2163 | #     define ADD(_flag, _syscallname) \ | 
 | 2164 |          do { UWordPair p; p.uw1 = (_syscallname); p.uw2 = (_flag); \ | 
 | 2165 |               VG_(addToXA)( post_syscall_table, &p ); \ | 
 | 2166 |          } while (0) | 
 | 2167 |  | 
 | 2168 |       /* These ones definitely don't return pointers.  They're not | 
 | 2169 |          particularly grammatical, either. */ | 
 | 2170 |  | 
 | 2171 | #     if defined(__NR__llseek) | 
 | 2172 |       ADD(0, __NR__llseek); | 
 | 2173 | #     endif | 
 | 2174 |       ADD(0, __NR__sysctl); | 
 | 2175 | #     if defined(__NR__newselect) | 
 | 2176 |       ADD(0, __NR__newselect); | 
 | 2177 | #     endif | 
 | 2178 | #     if defined(__NR_accept) | 
 | 2179 |       ADD(0, __NR_accept); | 
 | 2180 | #     endif | 
 | 2181 |       ADD(0, __NR_access); | 
| tom | 332ffec | 2009-01-05 12:16:21 +0000 | [diff] [blame] | 2182 |       ADD(0, __NR_alarm); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2183 | #     if defined(__NR_bind) | 
 | 2184 |       ADD(0, __NR_bind); | 
 | 2185 | #     endif | 
 | 2186 | #     if defined(__NR_chdir) | 
 | 2187 |       ADD(0, __NR_chdir); | 
 | 2188 | #     endif | 
 | 2189 |       ADD(0, __NR_chmod); | 
 | 2190 |       ADD(0, __NR_chown); | 
| sewardj | 41d5dea | 2009-01-24 10:52:32 +0000 | [diff] [blame] | 2191 | #     if defined(__NR_chown32) | 
 | 2192 |       ADD(0, __NR_chown32); | 
 | 2193 | #     endif | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2194 |       ADD(0, __NR_clock_getres); | 
 | 2195 |       ADD(0, __NR_clock_gettime); | 
 | 2196 |       ADD(0, __NR_clone); | 
 | 2197 |       ADD(0, __NR_close); | 
 | 2198 | #     if defined(__NR_connect) | 
 | 2199 |       ADD(0, __NR_connect); | 
 | 2200 | #     endif | 
| tom | 332ffec | 2009-01-05 12:16:21 +0000 | [diff] [blame] | 2201 |       ADD(0, __NR_creat); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2202 |       ADD(0, __NR_dup); | 
 | 2203 |       ADD(0, __NR_dup2); | 
 | 2204 |       ADD(0, __NR_execve); /* presumably we see this because the call failed? */ | 
 | 2205 |       ADD(0, __NR_exit); /* hmm, why are we still alive? */ | 
 | 2206 |       ADD(0, __NR_exit_group); | 
 | 2207 |       ADD(0, __NR_fadvise64); | 
 | 2208 |       ADD(0, __NR_fchmod); | 
 | 2209 |       ADD(0, __NR_fchown); | 
 | 2210 | #     if defined(__NR_fchown32) | 
 | 2211 |       ADD(0, __NR_fchown32); | 
 | 2212 | #     endif | 
 | 2213 |       ADD(0, __NR_fcntl); | 
 | 2214 | #     if defined(__NR_fcntl64) | 
 | 2215 |       ADD(0, __NR_fcntl64); | 
 | 2216 | #     endif | 
 | 2217 |       ADD(0, __NR_fdatasync); | 
| sewardj | 33c57f2 | 2009-01-26 00:09:08 +0000 | [diff] [blame^] | 2218 |       ADD(0, __NR_flock); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2219 |       ADD(0, __NR_fstat); | 
 | 2220 | #     if defined(__NR_fstat64) | 
 | 2221 |       ADD(0, __NR_fstat64); | 
 | 2222 | #     endif | 
 | 2223 |       ADD(0, __NR_fstatfs); | 
 | 2224 |       ADD(0, __NR_fsync); | 
 | 2225 |       ADD(0, __NR_ftruncate); | 
 | 2226 | #     if defined(__NR_ftruncate64) | 
 | 2227 |       ADD(0, __NR_ftruncate64); | 
 | 2228 | #     endif | 
 | 2229 |       ADD(0, __NR_futex); | 
 | 2230 |       ADD(0, __NR_getcwd); | 
 | 2231 |       ADD(0, __NR_getdents); // something to do with teeth | 
 | 2232 |       ADD(0, __NR_getdents64); | 
 | 2233 |       ADD(0, __NR_getegid); | 
 | 2234 | #     if defined(__NR_getegid32) | 
 | 2235 |       ADD(0, __NR_getegid32); | 
 | 2236 | #     endif | 
 | 2237 |       ADD(0, __NR_geteuid); | 
 | 2238 | #     if defined(__NR_geteuid32) | 
 | 2239 |       ADD(0, __NR_geteuid32); | 
 | 2240 | #     endif | 
 | 2241 |       ADD(0, __NR_getgid); | 
 | 2242 | #     if defined(__NR_getgid32) | 
 | 2243 |       ADD(0, __NR_getgid32); | 
 | 2244 | #     endif | 
 | 2245 |       ADD(0, __NR_getitimer); | 
 | 2246 | #     if defined(__NR_getpeername) | 
 | 2247 |       ADD(0, __NR_getpeername); | 
 | 2248 | #     endif | 
 | 2249 |       ADD(0, __NR_getpid); | 
| sewardj | 7d76911 | 2008-10-30 01:44:03 +0000 | [diff] [blame] | 2250 |       ADD(0, __NR_getpgrp); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2251 |       ADD(0, __NR_getppid); | 
 | 2252 |       ADD(0, __NR_getresgid); | 
 | 2253 |       ADD(0, __NR_getresuid); | 
 | 2254 |       ADD(0, __NR_getrlimit); | 
| tom | 332ffec | 2009-01-05 12:16:21 +0000 | [diff] [blame] | 2255 |       ADD(0, __NR_getrusage); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2256 | #     if defined(__NR_getsockname) | 
 | 2257 |       ADD(0, __NR_getsockname); | 
 | 2258 | #     endif | 
 | 2259 | #     if defined(__NR_getsockopt) | 
 | 2260 |       ADD(0, __NR_getsockopt); | 
 | 2261 | #     endif | 
| sewardj | 41d5dea | 2009-01-24 10:52:32 +0000 | [diff] [blame] | 2262 |       ADD(0, __NR_gettid); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2263 |       ADD(0, __NR_gettimeofday); | 
 | 2264 |       ADD(0, __NR_getuid); | 
 | 2265 | #     if defined(__NR_getuid32) | 
 | 2266 |       ADD(0, __NR_getuid32); | 
 | 2267 | #     endif | 
 | 2268 |       ADD(0, __NR_getxattr); | 
| sewardj | 738db7b | 2008-10-20 10:30:08 +0000 | [diff] [blame] | 2269 |       ADD(0, __NR_inotify_add_watch); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2270 |       ADD(0, __NR_inotify_init); | 
| sewardj | 738db7b | 2008-10-20 10:30:08 +0000 | [diff] [blame] | 2271 |       ADD(0, __NR_inotify_rm_watch); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2272 |       ADD(0, __NR_ioctl); // ioctl -- assuming no pointers returned | 
| sewardj | 33c57f2 | 2009-01-26 00:09:08 +0000 | [diff] [blame^] | 2273 |       ADD(0, __NR_ioprio_get); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2274 |       ADD(0, __NR_kill); | 
 | 2275 |       ADD(0, __NR_link); | 
 | 2276 | #     if defined(__NR_listen) | 
 | 2277 |       ADD(0, __NR_listen); | 
 | 2278 | #     endif | 
 | 2279 |       ADD(0, __NR_lseek); | 
 | 2280 |       ADD(0, __NR_lstat); | 
 | 2281 | #     if defined(__NR_lstat64) | 
 | 2282 |       ADD(0, __NR_lstat64); | 
 | 2283 | #     endif | 
 | 2284 |       ADD(0, __NR_madvise); | 
 | 2285 |       ADD(0, __NR_mkdir); | 
| sewardj | 33c57f2 | 2009-01-26 00:09:08 +0000 | [diff] [blame^] | 2286 |       ADD(0, __NR_mlock); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2287 |       ADD(0, __NR_mprotect); | 
 | 2288 |       ADD(0, __NR_munmap); // die_mem_munmap already called, segment remove); | 
| sewardj | 738db7b | 2008-10-20 10:30:08 +0000 | [diff] [blame] | 2289 |       ADD(0, __NR_nanosleep); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2290 |       ADD(0, __NR_open); | 
 | 2291 |       ADD(0, __NR_pipe); | 
 | 2292 |       ADD(0, __NR_poll); | 
 | 2293 |       ADD(0, __NR_pread64); | 
 | 2294 |       ADD(0, __NR_pwrite64); | 
 | 2295 |       ADD(0, __NR_read); | 
 | 2296 |       ADD(0, __NR_readlink); | 
 | 2297 |       ADD(0, __NR_readv); | 
 | 2298 | #     if defined(__NR_recvfrom) | 
 | 2299 |       ADD(0, __NR_recvfrom); | 
 | 2300 | #     endif | 
 | 2301 | #     if defined(__NR_recvmsg) | 
 | 2302 |       ADD(0, __NR_recvmsg); | 
 | 2303 | #     endif | 
 | 2304 |       ADD(0, __NR_rename); | 
 | 2305 |       ADD(0, __NR_rmdir); | 
 | 2306 |       ADD(0, __NR_rt_sigaction); | 
 | 2307 |       ADD(0, __NR_rt_sigprocmask); | 
 | 2308 |       ADD(0, __NR_rt_sigreturn); /* not sure if we should see this or not */ | 
 | 2309 |       ADD(0, __NR_sched_get_priority_max); | 
 | 2310 |       ADD(0, __NR_sched_get_priority_min); | 
| sewardj | 738db7b | 2008-10-20 10:30:08 +0000 | [diff] [blame] | 2311 |       ADD(0, __NR_sched_getaffinity); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2312 |       ADD(0, __NR_sched_getparam); | 
 | 2313 |       ADD(0, __NR_sched_getscheduler); | 
| sewardj | 41d5dea | 2009-01-24 10:52:32 +0000 | [diff] [blame] | 2314 |       ADD(0, __NR_sched_setaffinity); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2315 |       ADD(0, __NR_sched_setscheduler); | 
 | 2316 |       ADD(0, __NR_sched_yield); | 
 | 2317 |       ADD(0, __NR_select); | 
| sewardj | 33c57f2 | 2009-01-26 00:09:08 +0000 | [diff] [blame^] | 2318 | #     if defined(__NR_semctl) | 
 | 2319 |       ADD(0, __NR_semctl); | 
 | 2320 | #     endif | 
 | 2321 | #     if defined(__NR_semget) | 
 | 2322 |       ADD(0, __NR_semget); | 
 | 2323 | #     endif | 
 | 2324 | #     if defined(__NR_semop) | 
 | 2325 |       ADD(0, __NR_semop); | 
 | 2326 | #     endif | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2327 | #     if defined(__NR_sendto) | 
 | 2328 |       ADD(0, __NR_sendto); | 
 | 2329 | #     endif | 
| tom | 332ffec | 2009-01-05 12:16:21 +0000 | [diff] [blame] | 2330 | #     if defined(__NR_sendmsg) | 
 | 2331 |       ADD(0, __NR_sendmsg); | 
 | 2332 | #     endif | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2333 |       ADD(0, __NR_set_robust_list); | 
 | 2334 | #     if defined(__NR_set_thread_area) | 
 | 2335 |       ADD(0, __NR_set_thread_area); | 
 | 2336 | #     endif | 
 | 2337 |       ADD(0, __NR_set_tid_address); | 
 | 2338 |       ADD(0, __NR_setitimer); | 
| sewardj | 7d76911 | 2008-10-30 01:44:03 +0000 | [diff] [blame] | 2339 |       ADD(0, __NR_setpgid); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2340 |       ADD(0, __NR_setrlimit); | 
 | 2341 |       ADD(0, __NR_setsid); | 
 | 2342 | #     if defined(__NR_setsockopt) | 
 | 2343 |       ADD(0, __NR_setsockopt); | 
 | 2344 | #     endif | 
 | 2345 | #     if defined(__NR_shmctl) | 
 | 2346 |       ADD(0, __NR_shmctl); | 
 | 2347 |       ADD(0, __NR_shmdt); | 
 | 2348 | #     endif | 
 | 2349 | #     if defined(__NR_shutdown) | 
 | 2350 |       ADD(0, __NR_shutdown); | 
 | 2351 | #     endif | 
| sewardj | 41d5dea | 2009-01-24 10:52:32 +0000 | [diff] [blame] | 2352 |       ADD(0, __NR_sigaltstack); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2353 | #     if defined(__NR_socket) | 
 | 2354 |       ADD(0, __NR_socket); | 
 | 2355 | #     endif | 
 | 2356 | #     if defined(__NR_socketcall) | 
 | 2357 |       ADD(0, __NR_socketcall); /* the nasty x86-linux socket multiplexor */ | 
 | 2358 | #     endif | 
| sewardj | 23e8a29 | 2009-01-07 09:35:10 +0000 | [diff] [blame] | 2359 | #     if defined(__NR_socketpair) | 
 | 2360 |       ADD(0, __NR_socketpair); | 
 | 2361 | #     endif | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2362 | #     if defined(__NR_statfs64) | 
 | 2363 |       ADD(0, __NR_statfs64); | 
 | 2364 | #     endif | 
 | 2365 | #     if defined(__NR_sigreturn) | 
 | 2366 |       ADD(0, __NR_sigreturn); /* not sure if we should see this or not */ | 
 | 2367 | #     endif | 
 | 2368 | #     if defined(__NR_stat64) | 
 | 2369 |       ADD(0, __NR_stat64); | 
 | 2370 | #     endif | 
 | 2371 |       ADD(0, __NR_stat); | 
 | 2372 |       ADD(0, __NR_statfs); | 
 | 2373 |       ADD(0, __NR_symlink); | 
 | 2374 |       ADD(0, __NR_sysinfo); | 
 | 2375 |       ADD(0, __NR_tgkill); | 
 | 2376 |       ADD(0, __NR_time); | 
 | 2377 |       ADD(0, __NR_times); | 
 | 2378 |       ADD(0, __NR_truncate); | 
 | 2379 | #     if defined(__NR_truncate64) | 
 | 2380 |       ADD(0, __NR_truncate64); | 
 | 2381 | #     endif | 
 | 2382 | #     if defined(__NR_ugetrlimit) | 
 | 2383 |       ADD(0, __NR_ugetrlimit); | 
 | 2384 | #     endif | 
 | 2385 |       ADD(0, __NR_umask); | 
 | 2386 |       ADD(0, __NR_uname); | 
 | 2387 |       ADD(0, __NR_unlink); | 
 | 2388 |       ADD(0, __NR_utime); | 
 | 2389 | #     if defined(__NR_waitpid) | 
 | 2390 |       ADD(0, __NR_waitpid); | 
 | 2391 | #     endif | 
 | 2392 |       ADD(0, __NR_wait4); | 
 | 2393 |       ADD(0, __NR_write); | 
 | 2394 |       ADD(0, __NR_writev); | 
 | 2395 |  | 
 | 2396 |       /* Whereas the following need special treatment */ | 
 | 2397 | #     if defined(__NR_arch_prctl) | 
 | 2398 |       ADD(1, __NR_arch_prctl); | 
 | 2399 | #     endif | 
 | 2400 |       ADD(1, __NR_brk); | 
 | 2401 |       ADD(1, __NR_mmap); | 
 | 2402 | #     if defined(__NR_mmap2) | 
 | 2403 |       ADD(1, __NR_mmap2); | 
 | 2404 | #     endif | 
 | 2405 | #     if defined(__NR_shmat) | 
 | 2406 |       ADD(1, __NR_shmat); | 
 | 2407 | #     endif | 
 | 2408 | #     if defined(__NR_shmget) | 
 | 2409 |       ADD(1, __NR_shmget); | 
 | 2410 | #     endif | 
 | 2411 |  | 
 | 2412 |    /* --------------- AIX5 --------------- */ | 
 | 2413 |  | 
 | 2414 | #  elif defined(VGO_aix5) | 
 | 2415 |  | 
 | 2416 | #     define ADD(_flag, _syscallname) \ | 
 | 2417 |          do { \ | 
 | 2418 |             UWordPair p; \ | 
 | 2419 |             if ((_syscallname) != __NR_AIX5_UNKNOWN) { \ | 
 | 2420 |                p.uw1 = (UWord)&(_syscallname); p.uw2 = (_flag); \ | 
 | 2421 |                VG_(addToXA)( post_syscall_table, &p ); \ | 
 | 2422 |             } \ | 
 | 2423 |          } while (0) | 
 | 2424 |  | 
 | 2425 |       /* Just a minimal set of handlers, enough to make | 
 | 2426 |          a 32- and 64-bit hello-world program run. */ | 
 | 2427 |       ADD(1, __NR_AIX5___loadx); /* not sure what to do here */ | 
 | 2428 |       ADD(0, __NR_AIX5__exit); | 
 | 2429 |       ADD(0, __NR_AIX5_access); | 
 | 2430 |       ADD(0, __NR_AIX5_getgidx); | 
 | 2431 |       ADD(0, __NR_AIX5_getuidx); | 
 | 2432 |       ADD(0, __NR_AIX5_kfcntl); | 
 | 2433 |       ADD(0, __NR_AIX5_kioctl); | 
 | 2434 |       ADD(1, __NR_AIX5_kload); /* not sure what to do here */ | 
 | 2435 |       ADD(0, __NR_AIX5_kwrite); | 
 | 2436 |  | 
 | 2437 | #  else | 
 | 2438 | #     error "Unsupported OS" | 
 | 2439 | #  endif | 
 | 2440 |  | 
 | 2441 | #  undef ADD | 
 | 2442 | } | 
 | 2443 |  | 
 | 2444 |  | 
 | 2445 | void h_post_syscall ( ThreadId tid, UInt sysno, SysRes res ) | 
 | 2446 | { | 
 | 2447 |    Word i, n; | 
 | 2448 |    UWordPair* pair; | 
 | 2449 |  | 
 | 2450 |    if (!post_syscall_table) | 
 | 2451 |       setup_post_syscall_table(); | 
 | 2452 |  | 
 | 2453 |    /* search for 'sysno' in the post_syscall_table */ | 
 | 2454 |    n = VG_(sizeXA)( post_syscall_table ); | 
 | 2455 |    for (i = 0; i < n; i++) { | 
 | 2456 |       pair = VG_(indexXA)( post_syscall_table, i ); | 
 | 2457 | #     if defined(VGO_linux) | 
 | 2458 |       if (pair->uw1 == (UWord)sysno) | 
 | 2459 |          break; | 
 | 2460 | #     elif defined(VGO_aix5) | 
 | 2461 |       if (*(Int*)(pair->uw1) == (Int)sysno) | 
 | 2462 |          break; | 
 | 2463 | #     else | 
 | 2464 | #        error "Unsupported OS" | 
 | 2465 | #     endif | 
 | 2466 |    } | 
 | 2467 |  | 
 | 2468 |    tl_assert(i >= 0 && i <= n); | 
 | 2469 |  | 
 | 2470 |    if (i == n) { | 
 | 2471 |       VG_(printf)("sysno == %u\n", sysno); | 
 | 2472 | #     if defined(VGO_aix5) | 
 | 2473 |       VG_(printf)("syscallnm == %s\n", | 
 | 2474 |                   VG_(aix5_sysno_to_sysname)(sysno)); | 
 | 2475 | #     endif | 
 | 2476 |       VG_(tool_panic)("unhandled syscall"); | 
 | 2477 |    } | 
 | 2478 |  | 
 | 2479 |    /* So we found the relevant entry.  Move it one step | 
 | 2480 |       forward so as to speed future accesses to it. */ | 
 | 2481 |    if (i > 0) { | 
 | 2482 |       UWordPair tmp, *p, *q; | 
 | 2483 |       p = VG_(indexXA)( post_syscall_table, i-1 ); | 
 | 2484 |       q = VG_(indexXA)( post_syscall_table, i-0 ); | 
 | 2485 |       tmp = *p; | 
 | 2486 |       *p = *q; | 
 | 2487 |       *q = tmp; | 
 | 2488 |       i--; | 
 | 2489 |    } | 
 | 2490 |  | 
 | 2491 |    /* Deal with the common case */ | 
 | 2492 |    pair = VG_(indexXA)( post_syscall_table, i ); | 
 | 2493 |    if (pair->uw2 == 0) { | 
 | 2494 |      /* the common case */ | 
 | 2495 |       VG_(set_syscall_return_shadows)(  | 
 | 2496 |          tid, /* retval */ (UWord)NONPTR, 0, | 
 | 2497 |               /* error */  (UWord)NONPTR, 0 | 
 | 2498 |       ); | 
 | 2499 |       return; | 
 | 2500 |    } | 
 | 2501 |  | 
 | 2502 |    /* Special handling for all remaining cases */ | 
 | 2503 |    tl_assert(pair->uw2 == 1); | 
 | 2504 |  | 
 | 2505 | #  if defined(__NR_arch_prctl) | 
 | 2506 |    if (sysno == __NR_arch_prctl) { | 
 | 2507 |       /* This is nasty.  On amd64-linux, arch_prctl may write a | 
 | 2508 |          value to guest_FS_ZERO, and we need to shadow that value. | 
 | 2509 |          Hence apply nonptr_or_unknown to it here, after the | 
 | 2510 |          syscall completes. */ | 
 | 2511 |       post_reg_write_nonptr_or_unknown( tid, PC_OFF_FS_ZERO,  | 
 | 2512 |                                              PC_SZB_FS_ZERO ); | 
 | 2513 |       VG_(set_syscall_return_shadows)(  | 
 | 2514 |          tid, /* retval */ (UWord)NONPTR, 0, | 
 | 2515 |               /* error */  (UWord)NONPTR, 0 | 
 | 2516 |       ); | 
 | 2517 |       return; | 
 | 2518 |    } | 
 | 2519 | #  endif | 
 | 2520 |  | 
 | 2521 | #  if defined(__NR_brk) | 
 | 2522 |    // With brk(), result (of kernel syscall, not glibc wrapper) is a heap | 
 | 2523 |    // pointer.  Make the shadow UNKNOWN. | 
 | 2524 |    if (sysno ==  __NR_brk) { | 
 | 2525 |       VG_(set_syscall_return_shadows)(  | 
 | 2526 |          tid, /* retval */ (UWord)UNKNOWN, 0, | 
 | 2527 |               /* error */  (UWord)NONPTR,  0 | 
 | 2528 |       ); | 
 | 2529 |       return; | 
 | 2530 |    } | 
 | 2531 | #  endif | 
 | 2532 |  | 
 | 2533 |    // With mmap, new_mem_mmap() has already been called and added the | 
 | 2534 |    // segment (we did it there because we had the result address and size | 
 | 2535 |    // handy).  So just set the return value shadow. | 
 | 2536 |    if (sysno == __NR_mmap | 
 | 2537 | #      if defined(__NR_mmap2) | 
 | 2538 |        || sysno == __NR_mmap2 | 
 | 2539 | #      endif | 
 | 2540 | #      if defined(__NR_AIX5___loadx) | 
 | 2541 |        || (sysno == __NR_AIX5___loadx && __NR_AIX5___loadx != __NR_AIX5_UNKNOWN) | 
 | 2542 | #      endif | 
 | 2543 | #      if defined(__NR_AIX5_kload) | 
 | 2544 |        || (sysno == __NR_AIX5_kload && __NR_AIX5_kload != __NR_AIX5_UNKNOWN) | 
 | 2545 | #      endif | 
 | 2546 |       ) { | 
 | 2547 |       if (res.isError) { | 
 | 2548 |          // mmap() had an error, return value is a small negative integer | 
 | 2549 |          VG_(set_syscall_return_shadows)( tid, /*val*/ (UWord)NONPTR, 0, | 
 | 2550 |                                                /*err*/ (UWord)NONPTR, 0 ); | 
 | 2551 |          if (0) VG_(printf)("ZZZZZZZ mmap res -> NONPTR\n"); | 
 | 2552 |       } else { | 
 | 2553 |          VG_(set_syscall_return_shadows)( tid, /*val*/ (UWord)UNKNOWN, 0, | 
 | 2554 |                                                /*err*/ (UWord)NONPTR, 0 ); | 
 | 2555 |          if (0) VG_(printf)("ZZZZZZZ mmap res -> UNKNOWN\n"); | 
 | 2556 |       } | 
 | 2557 |       return; | 
 | 2558 |    } | 
 | 2559 |  | 
 | 2560 |    // shmat uses the same scheme.  We will just have had a | 
 | 2561 |    // notification via new_mem_mmap.  Just set the return value shadow. | 
 | 2562 | #  if defined(__NR_shmat) | 
 | 2563 |    if (sysno == __NR_shmat) { | 
 | 2564 |       if (res.isError) { | 
 | 2565 |          VG_(set_syscall_return_shadows)( tid, /*val*/ (UWord)NONPTR, 0, | 
 | 2566 |                                                /*err*/ (UWord)NONPTR, 0 ); | 
 | 2567 |          if (0) VG_(printf)("ZZZZZZZ shmat res -> NONPTR\n"); | 
 | 2568 |       } else { | 
 | 2569 |          VG_(set_syscall_return_shadows)( tid, /*val*/ (UWord)UNKNOWN, 0, | 
 | 2570 |                                                /*err*/ (UWord)NONPTR, 0 ); | 
 | 2571 |          if (0) VG_(printf)("ZZZZZZZ shmat res -> UNKNOWN\n"); | 
 | 2572 |       } | 
 | 2573 |       return; | 
 | 2574 |    } | 
 | 2575 | #  endif | 
 | 2576 |  | 
 | 2577 | #  if defined(__NR_shmget) | 
 | 2578 |    if (sysno == __NR_shmget) { | 
 | 2579 |       // FIXME: is this correct? | 
 | 2580 |       VG_(set_syscall_return_shadows)( tid, /*val*/ (UWord)UNKNOWN, 0, | 
 | 2581 |                                             /*err*/ (UWord)NONPTR, 0 ); | 
 | 2582 |       return; | 
 | 2583 |    } | 
 | 2584 | #  endif | 
 | 2585 |  | 
 | 2586 |    /* If we get here, it implies the corresponding entry in | 
 | 2587 |       post_syscall_table has .w2 == 1, which in turn implies there | 
 | 2588 |       should be special-case code for it above. */ | 
 | 2589 |    tl_assert(0); | 
 | 2590 | } | 
 | 2591 |  | 
 | 2592 |  | 
 | 2593 | /*--------------------------------------------------------------------*/ | 
 | 2594 | /*--- Functions called from generated code                         ---*/ | 
 | 2595 | /*--------------------------------------------------------------------*/ | 
 | 2596 |  | 
 | 2597 | #if SC_SEGS | 
 | 2598 | static void checkSeg ( Seg vseg ) { | 
 | 2599 |    tl_assert(vseg == UNKNOWN || vseg == NONPTR || vseg == BOTTOM | 
 | 2600 |              || Seg__plausible(vseg) ); | 
 | 2601 | } | 
 | 2602 | #endif | 
 | 2603 |  | 
 | 2604 | // XXX: could be more sophisticated -- actually track the lowest/highest | 
 | 2605 | // valid address used by the program, and then return False for anything | 
 | 2606 | // below that (using a suitable safety margin).  Also, nothing above | 
 | 2607 | // 0xc0000000 is valid [unless you've changed that in your kernel] | 
 | 2608 | static inline Bool looks_like_a_pointer(Addr a) | 
 | 2609 | { | 
 | 2610 | #  if defined(VGA_x86) || defined(VGA_ppc32) | 
 | 2611 |    tl_assert(sizeof(UWord) == 4); | 
 | 2612 |    return (a > 0x01000000UL && a < 0xFF000000UL); | 
 | 2613 | #  elif defined(VGA_amd64) || defined(VGA_ppc64) | 
 | 2614 |    tl_assert(sizeof(UWord) == 8); | 
 | 2615 |    return (a >= 16 * 0x10000UL && a < 0xFF00000000000000UL); | 
 | 2616 | #  else | 
 | 2617 | #    error "Unsupported architecture" | 
 | 2618 | #  endif | 
 | 2619 | } | 
 | 2620 |  | 
 | 2621 | static inline VG_REGPARM(1) | 
 | 2622 | Seg* nonptr_or_unknown(UWord x) | 
 | 2623 | { | 
 | 2624 |    Seg* res = looks_like_a_pointer(x) ? UNKNOWN : NONPTR; | 
 | 2625 |    if (0) VG_(printf)("nonptr_or_unknown %s %#lx\n",  | 
 | 2626 |                       res==UNKNOWN ? "UUU" : "nnn", x); | 
 | 2627 |    return res; | 
 | 2628 | } | 
 | 2629 |  | 
 | 2630 | //zz static __attribute__((regparm(1))) | 
 | 2631 | //zz void print_BB_entry(UInt bb) | 
 | 2632 | //zz { | 
 | 2633 | //zz    VG_(printf)("%u =\n", bb); | 
 | 2634 | //zz } | 
 | 2635 |  | 
| sewardj | 59347ff | 2008-12-23 02:31:22 +0000 | [diff] [blame] | 2636 | //static ULong stats__tot_mem_refs  = 0; | 
 | 2637 | //static ULong stats__refs_in_a_seg = 0; | 
 | 2638 | //static ULong stats__refs_lost_seg = 0; | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2639 |  | 
 | 2640 | typedef | 
 | 2641 |    struct { ExeContext* ec; UWord count; } | 
 | 2642 |    Lossage; | 
 | 2643 |  | 
 | 2644 | static OSet* lossage = NULL; | 
 | 2645 |  | 
| sewardj | 59347ff | 2008-12-23 02:31:22 +0000 | [diff] [blame] | 2646 | //static void inc_lossage ( ExeContext* ec )  | 
 | 2647 | //{ | 
 | 2648 | //   Lossage key, *res, *nyu; | 
 | 2649 | //   key.ec = ec; | 
 | 2650 | //   key.count = 0; /* frivolous */ | 
 | 2651 | //   res = VG_(OSetGen_Lookup)(lossage, &key); | 
 | 2652 | //   if (res) { | 
 | 2653 | //      tl_assert(res->ec == ec); | 
 | 2654 | //      res->count++; | 
 | 2655 | //   } else { | 
 | 2656 | //      nyu = (Lossage*)VG_(OSetGen_AllocNode)(lossage, sizeof(Lossage)); | 
 | 2657 | //      tl_assert(nyu); | 
 | 2658 | //      nyu->ec = ec; | 
 | 2659 | //      nyu->count = 1; | 
 | 2660 | //      VG_(OSetGen_Insert)( lossage, nyu ); | 
 | 2661 | //   } | 
 | 2662 | //} | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2663 |  | 
 | 2664 | static void init_lossage ( void ) | 
 | 2665 | { | 
 | 2666 |    lossage = VG_(OSetGen_Create)( /*keyOff*/ offsetof(Lossage,ec), | 
 | 2667 |                                   /*fastCmp*/NULL, | 
 | 2668 |                                   VG_(malloc), "pc.h_main.il.1", | 
 | 2669 |                                   VG_(free) ); | 
 | 2670 |    tl_assert(lossage); | 
 | 2671 | } | 
 | 2672 |  | 
| sewardj | 59347ff | 2008-12-23 02:31:22 +0000 | [diff] [blame] | 2673 | //static void show_lossage ( void ) | 
 | 2674 | //{ | 
 | 2675 | //   Lossage* elem; | 
 | 2676 | //   VG_(OSetGen_ResetIter)( lossage ); | 
 | 2677 | //   while ( (elem = VG_(OSetGen_Next)(lossage)) ) { | 
 | 2678 | //      if (elem->count < 10) continue; | 
 | 2679 | //      //Char buf[100]; | 
 | 2680 | //      //(void)VG_(describe_IP)(elem->ec, buf, sizeof(buf)-1); | 
 | 2681 | //      //buf[sizeof(buf)-1] = 0; | 
 | 2682 | //      //VG_(printf)("  %,8lu  %s\n", elem->count, buf); | 
 | 2683 | //      VG_(message)(Vg_UserMsg, "Lossage count %'lu at", elem->count); | 
 | 2684 | //      VG_(pp_ExeContext)(elem->ec); | 
 | 2685 | //   } | 
 | 2686 | //} | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2687 |  | 
 | 2688 | // This function is called *a lot*; inlining it sped up Konqueror by 20%. | 
 | 2689 | static inline | 
 | 2690 | void check_load_or_store(Bool is_write, Addr m, UWord sz, Seg* mptr_vseg) | 
 | 2691 | { | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2692 | #if 0 | 
| sewardj | 4815eb5 | 2008-10-20 23:33:49 +0000 | [diff] [blame] | 2693 |    tl_assert(0); | 
 | 2694 |    if (h_clo_lossage_check) { | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2695 |       Seg* seg; | 
 | 2696 |       stats__tot_mem_refs++; | 
 | 2697 |       if (ISList__findI0( seglist, (Addr)m, &seg )) { | 
 | 2698 |          /* m falls inside 'seg' (that is, we are making a memory | 
 | 2699 |             reference inside 'seg').  Now, really mptr_vseg should be | 
 | 2700 |             a tracked segment of some description.  Badness is when | 
 | 2701 |             mptr_vseg is UNKNOWN, BOTTOM or NONPTR at this point, | 
 | 2702 |             since that means we've lost the type of it somehow: it | 
 | 2703 |             shoud say that m points into a real segment (preferable | 
 | 2704 |             'seg'), but it doesn't. */ | 
 | 2705 |          if (Seg__status_is_SegHeap(seg)) { | 
 | 2706 |             stats__refs_in_a_seg++; | 
 | 2707 |             if (UNKNOWN == mptr_vseg | 
 | 2708 |                 || BOTTOM == mptr_vseg || NONPTR == mptr_vseg) { | 
 | 2709 |                ExeContext* ec; | 
 | 2710 |                Char buf[100]; | 
 | 2711 |                static UWord xx = 0; | 
 | 2712 |                stats__refs_lost_seg++; | 
 | 2713 |                ec = VG_(record_ExeContext)( VG_(get_running_tid)(), 0 ); | 
 | 2714 |                inc_lossage(ec); | 
 | 2715 |                if (0) { | 
 | 2716 |                   VG_(message)(Vg_DebugMsg, ""); | 
 | 2717 |                   VG_(message)(Vg_DebugMsg, | 
 | 2718 |                                "Lossage %s %#lx sz %lu inside block alloc'd", | 
 | 2719 |                                is_write ? "wr" : "rd", m, (UWord)sz); | 
 | 2720 |                   VG_(pp_ExeContext)(Seg__where(seg)); | 
 | 2721 |                } | 
 | 2722 |                if (xx++ < 0) { | 
 | 2723 |                   Addr ip = VG_(get_IP)( VG_(get_running_tid)() ); | 
 | 2724 |                   (void)VG_(describe_IP)( ip, buf, sizeof(buf)-1); | 
 | 2725 |                   buf[sizeof(buf)-1] = 0; | 
 | 2726 |                   VG_(printf)("lossage at %p %s\n", ec, buf ); | 
 | 2727 |                } | 
 | 2728 |             } | 
 | 2729 |          } | 
 | 2730 |       } | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2731 |    } /* clo_lossage_check */ | 
| sewardj | 4815eb5 | 2008-10-20 23:33:49 +0000 | [diff] [blame] | 2732 | #endif | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 2733 |  | 
 | 2734 | #  if SC_SEGS | 
 | 2735 |    checkSeg(mptr_vseg); | 
 | 2736 | #  endif | 
 | 2737 |  | 
 | 2738 |    if (UNKNOWN == mptr_vseg) { | 
 | 2739 |       // do nothing | 
 | 2740 |  | 
 | 2741 |    } else if (BOTTOM == mptr_vseg) { | 
 | 2742 |       // do nothing | 
 | 2743 |  | 
 | 2744 |    } else if (NONPTR == mptr_vseg) { | 
 | 2745 |       h_record_heap_error( m, sz, mptr_vseg, is_write ); | 
 | 2746 |  | 
 | 2747 |    } else { | 
 | 2748 |       // check all segment ranges in the circle | 
 | 2749 |       // if none match, warn about 1st seg | 
 | 2750 |       // else,          check matching one isn't freed | 
 | 2751 |       Bool is_ok = False; | 
 | 2752 |       Seg* curr  = mptr_vseg; | 
 | 2753 |       Addr mhi; | 
 | 2754 |  | 
 | 2755 |       // Accesses partly outside range are an error, unless it's an aligned | 
 | 2756 |       // word-sized read, and --partial-loads-ok=yes.  This is to cope with | 
 | 2757 |       // gcc's/glibc's habits of doing word-sized accesses that read past | 
 | 2758 |       // the ends of arrays/strings. | 
 | 2759 |       // JRS 2008-sept-11: couldn't this be moved off the critical path? | 
 | 2760 |       if (!is_write && sz == sizeof(UWord) | 
 | 2761 |           && h_clo_partial_loads_ok && SHMEM_IS_WORD_ALIGNED(m)) { | 
 | 2762 |          mhi = m; | 
 | 2763 |       } else { | 
 | 2764 |          mhi = m+sz-1; | 
 | 2765 |       } | 
 | 2766 |  | 
 | 2767 |       if (0) VG_(printf)("calling seg_ci %p %#lx %#lx\n", curr,m,mhi); | 
 | 2768 |       is_ok = curr->addr <= m && mhi < curr->addr + curr->szB; | 
 | 2769 |  | 
 | 2770 |       // If it's an overrun/underrun of a freed block, don't give both | 
 | 2771 |       // warnings, since the first one mentions that the block has been | 
 | 2772 |       // freed. | 
 | 2773 |       if ( ! is_ok || Seg__is_freed(curr) ) | 
 | 2774 |          h_record_heap_error( m, sz, mptr_vseg, is_write ); | 
 | 2775 |    } | 
 | 2776 | } | 
 | 2777 |  | 
 | 2778 | // ------------------ Load handlers ------------------ // | 
 | 2779 |  | 
 | 2780 | /* On 32 bit targets, we will use: | 
 | 2781 |       check_load1 check_load2 check_load4_P | 
 | 2782 |       check_load4  (for 32-bit FP reads) | 
 | 2783 |       check_load8  (for 64-bit FP reads) | 
 | 2784 |       check_load16 (for xmm/altivec reads) | 
 | 2785 |    On 64 bit targets, we will use: | 
 | 2786 |       check_load1 check_load2 check_load4 check_load8_P | 
 | 2787 |       check_load8  (for 64-bit FP reads) | 
 | 2788 |       check_load16 (for xmm/altivec reads) | 
 | 2789 |  | 
 | 2790 |    A "_P" handler reads a pointer from memory, and so returns a value | 
 | 2791 |    to the generated code -- the pointer's shadow value.  That implies | 
 | 2792 |    that check_load4_P is only to be called on a 32 bit host and | 
 | 2793 |    check_load8_P is only to be called on a 64 bit host.  For all other | 
 | 2794 |    cases no shadow value is returned; we merely check that the pointer | 
 | 2795 |    (m) matches the block described by its shadow value (mptr_vseg). | 
 | 2796 | */ | 
 | 2797 |  | 
 | 2798 | // This handles 128 bit loads on both 32 bit and 64 bit targets. | 
 | 2799 | static VG_REGPARM(2) | 
 | 2800 | void check_load16(Addr m, Seg* mptr_vseg) | 
 | 2801 | { | 
 | 2802 | #  if SC_SEGS | 
 | 2803 |    checkSeg(mptr_vseg); | 
 | 2804 | #  endif | 
 | 2805 |    check_load_or_store(/*is_write*/False, m, 16, mptr_vseg); | 
 | 2806 | } | 
 | 2807 |  | 
 | 2808 | // This handles 64 bit FP-or-otherwise-nonpointer loads on both | 
 | 2809 | // 32 bit and 64 bit targets. | 
 | 2810 | static VG_REGPARM(2) | 
 | 2811 | void check_load8(Addr m, Seg* mptr_vseg) | 
 | 2812 | { | 
 | 2813 | #  if SC_SEGS | 
 | 2814 |    checkSeg(mptr_vseg); | 
 | 2815 | #  endif | 
 | 2816 |    check_load_or_store(/*is_write*/False, m, 8, mptr_vseg); | 
 | 2817 | } | 
 | 2818 |  | 
 | 2819 | // This handles 64 bit loads on 64 bit targets.  It must | 
 | 2820 | // not be called on 32 bit targets. | 
 | 2821 | // return m.vseg | 
 | 2822 | static VG_REGPARM(2) | 
 | 2823 | Seg* check_load8_P(Addr m, Seg* mptr_vseg) | 
 | 2824 | { | 
 | 2825 |    Seg* vseg; | 
 | 2826 |    tl_assert(sizeof(UWord) == 8); /* DO NOT REMOVE */ | 
 | 2827 | #  if SC_SEGS | 
 | 2828 |    checkSeg(mptr_vseg); | 
 | 2829 | #  endif | 
 | 2830 |    check_load_or_store(/*is_write*/False, m, 8, mptr_vseg); | 
 | 2831 |    if (VG_IS_8_ALIGNED(m)) { | 
 | 2832 |       vseg = get_mem_vseg(m); | 
 | 2833 |    } else { | 
 | 2834 |       vseg = nonptr_or_unknown( *(ULong*)m ); | 
 | 2835 |    } | 
 | 2836 |    return vseg; | 
 | 2837 | } | 
 | 2838 |  | 
 | 2839 | // This handles 32 bit loads on 32 bit targets.  It must | 
 | 2840 | // not be called on 64 bit targets. | 
 | 2841 | // return m.vseg | 
 | 2842 | static VG_REGPARM(2) | 
 | 2843 | Seg* check_load4_P(Addr m, Seg* mptr_vseg) | 
 | 2844 | { | 
 | 2845 |    Seg* vseg; | 
 | 2846 |    tl_assert(sizeof(UWord) == 4); /* DO NOT REMOVE */ | 
 | 2847 | #  if SC_SEGS | 
 | 2848 |    checkSeg(mptr_vseg); | 
 | 2849 | #  endif | 
 | 2850 |    check_load_or_store(/*is_write*/False, m, 4, mptr_vseg); | 
 | 2851 |    if (VG_IS_4_ALIGNED(m)) { | 
 | 2852 |       vseg = get_mem_vseg(m); | 
 | 2853 |    } else { | 
 | 2854 |       vseg = nonptr_or_unknown( *(UInt*)m ); | 
 | 2855 |    } | 
 | 2856 |    return vseg; | 
 | 2857 | } | 
 | 2858 |  | 
 | 2859 | // Used for both 32 bit and 64 bit targets. | 
 | 2860 | static VG_REGPARM(2) | 
 | 2861 | void check_load4(Addr m, Seg* mptr_vseg) | 
 | 2862 | { | 
 | 2863 | #  if SC_SEGS | 
 | 2864 |    checkSeg(mptr_vseg); | 
 | 2865 | #  endif | 
 | 2866 |    check_load_or_store(/*is_write*/False, m, 4, mptr_vseg); | 
 | 2867 | } | 
 | 2868 |  | 
 | 2869 | // Used for both 32 bit and 64 bit targets. | 
 | 2870 | static VG_REGPARM(2) | 
 | 2871 | void check_load2(Addr m, Seg* mptr_vseg) | 
 | 2872 | { | 
 | 2873 | #  if SC_SEGS | 
 | 2874 |    checkSeg(mptr_vseg); | 
 | 2875 | #  endif | 
 | 2876 |    check_load_or_store(/*is_write*/False, m, 2, mptr_vseg); | 
 | 2877 | } | 
 | 2878 |  | 
 | 2879 | // Used for both 32 bit and 64 bit targets. | 
 | 2880 | static VG_REGPARM(2) | 
 | 2881 | void check_load1(Addr m, Seg* mptr_vseg) | 
 | 2882 | { | 
 | 2883 | #  if SC_SEGS | 
 | 2884 |    checkSeg(mptr_vseg); | 
 | 2885 | #  endif | 
 | 2886 |    check_load_or_store(/*is_write*/False, m, 1, mptr_vseg); | 
 | 2887 | } | 
 | 2888 |  | 
 | 2889 | // ------------------ Store handlers ------------------ // | 
 | 2890 |  | 
 | 2891 | /* On 32 bit targets, we will use: | 
 | 2892 |       check_store1 check_store2 check_store4_P | 
 | 2893 |       check_store4 (for 32-bit nonpointer stores) | 
 | 2894 |       check_store8_ms4B_ls4B (for 64-bit stores) | 
 | 2895 |       check_store16_ms4B_4B_4B_ls4B (for xmm/altivec stores) | 
 | 2896 |  | 
 | 2897 |    On 64 bit targets, we will use: | 
 | 2898 |       check_store1 check_store2 check_store4 check_store8_P | 
 | 2899 |       check_store8_all8B (for 64-bit nonpointer stores) | 
 | 2900 |       check_store16_ms8B_ls8B (for xmm/altivec stores) | 
 | 2901 |  | 
 | 2902 |    A "_P" handler writes a pointer to memory, and so has an extra | 
 | 2903 |    argument -- the pointer's shadow value.  That implies that | 
 | 2904 |    check_store4_P is only to be called on a 32 bit host and | 
 | 2905 |    check_store8_P is only to be called on a 64 bit host.  For all | 
 | 2906 |    other cases, and for the misaligned _P cases, the strategy is to | 
 | 2907 |    let the store go through, and then snoop around with | 
 | 2908 |    nonptr_or_unknown to fix up the shadow values of any affected | 
 | 2909 |    words. */ | 
 | 2910 |  | 
 | 2911 | /* Apply nonptr_or_unknown to all the words intersecting | 
 | 2912 |    [a, a+len). */ | 
 | 2913 | static VG_REGPARM(2) | 
 | 2914 | void nonptr_or_unknown_range ( Addr a, SizeT len ) | 
 | 2915 | { | 
 | 2916 |    const SizeT wszB = sizeof(UWord); | 
 | 2917 |    Addr wfirst = VG_ROUNDDN(a,       wszB); | 
 | 2918 |    Addr wlast  = VG_ROUNDDN(a+len-1, wszB); | 
 | 2919 |    Addr a2; | 
 | 2920 |    tl_assert(wfirst <= wlast); | 
 | 2921 |    for (a2 = wfirst ; a2 <= wlast; a2 += wszB) { | 
 | 2922 |       set_mem_vseg( a2, nonptr_or_unknown( *(UWord*)a2 )); | 
 | 2923 |    } | 
 | 2924 | } | 
 | 2925 |  | 
 | 2926 | // This handles 128 bit stores on 64 bit targets.  The | 
 | 2927 | // store data is passed in 2 pieces, the most significant | 
 | 2928 | // bits first. | 
 | 2929 | static VG_REGPARM(3) | 
 | 2930 | void check_store16_ms8B_ls8B(Addr m, Seg* mptr_vseg, | 
 | 2931 |                              UWord ms8B, UWord ls8B) | 
 | 2932 | { | 
 | 2933 |    tl_assert(sizeof(UWord) == 8); /* DO NOT REMOVE */ | 
 | 2934 | #  if SC_SEGS | 
 | 2935 |    checkSeg(mptr_vseg); | 
 | 2936 | #  endif | 
 | 2937 |    check_load_or_store(/*is_write*/True, m, 16, mptr_vseg); | 
 | 2938 |    // Actually *do* the STORE here | 
 | 2939 |    if (host_is_little_endian()) { | 
 | 2940 |       // FIXME: aren't we really concerned whether the guest | 
 | 2941 |       // is little endian, not whether the host is? | 
 | 2942 |       *(ULong*)(m + 0) = ls8B; | 
 | 2943 |       *(ULong*)(m + 8) = ms8B; | 
 | 2944 |    } else { | 
 | 2945 |       *(ULong*)(m + 0) = ms8B; | 
 | 2946 |       *(ULong*)(m + 8) = ls8B; | 
 | 2947 |    } | 
 | 2948 |    nonptr_or_unknown_range(m, 16); | 
 | 2949 | } | 
 | 2950 |  | 
 | 2951 | // This handles 128 bit stores on 64 bit targets.  The | 
 | 2952 | // store data is passed in 2 pieces, the most significant | 
 | 2953 | // bits first. | 
 | 2954 | static VG_REGPARM(3) | 
 | 2955 | void check_store16_ms4B_4B_4B_ls4B(Addr m, Seg* mptr_vseg, | 
 | 2956 |                                    UWord ms4B, UWord w2, | 
 | 2957 |                                    UWord w1,   UWord ls4B) | 
 | 2958 | { | 
 | 2959 |    tl_assert(sizeof(UWord) == 4); /* DO NOT REMOVE */ | 
 | 2960 | #  if SC_SEGS | 
 | 2961 |    checkSeg(mptr_vseg); | 
 | 2962 | #  endif | 
 | 2963 |    check_load_or_store(/*is_write*/True, m, 16, mptr_vseg); | 
 | 2964 |    // Actually *do* the STORE here | 
 | 2965 |    if (host_is_little_endian()) { | 
 | 2966 |       // FIXME: aren't we really concerned whether the guest | 
 | 2967 |       // is little endian, not whether the host is? | 
 | 2968 |       *(UInt*)(m +  0) = ls4B; | 
 | 2969 |       *(UInt*)(m +  4) = w1; | 
 | 2970 |       *(UInt*)(m +  8) = w2; | 
 | 2971 |       *(UInt*)(m + 12) = ms4B; | 
 | 2972 |    } else { | 
 | 2973 |       *(UInt*)(m +  0) = ms4B; | 
 | 2974 |       *(UInt*)(m +  4) = w2; | 
 | 2975 |       *(UInt*)(m +  8) = w1; | 
 | 2976 |       *(UInt*)(m + 12) = ls4B; | 
 | 2977 |    } | 
 | 2978 |    nonptr_or_unknown_range(m, 16); | 
 | 2979 | } | 
 | 2980 |  | 
 | 2981 | // This handles 64 bit stores on 32 bit targets.  The | 
 | 2982 | // store data is passed in 2 pieces, the most significant | 
 | 2983 | // bits first. | 
 | 2984 | static VG_REGPARM(3) | 
 | 2985 | void check_store8_ms4B_ls4B(Addr m, Seg* mptr_vseg, | 
 | 2986 |                             UWord ms4B, UWord ls4B) | 
 | 2987 | { | 
 | 2988 |    tl_assert(sizeof(UWord) == 4); /* DO NOT REMOVE */ | 
 | 2989 | #  if SC_SEGS | 
 | 2990 |    checkSeg(mptr_vseg); | 
 | 2991 | #  endif | 
 | 2992 |    check_load_or_store(/*is_write*/True, m, 8, mptr_vseg); | 
 | 2993 |    // Actually *do* the STORE here | 
 | 2994 |    if (host_is_little_endian()) { | 
 | 2995 |       // FIXME: aren't we really concerned whether the guest | 
 | 2996 |       // is little endian, not whether the host is? | 
 | 2997 |       *(UInt*)(m + 0) = ls4B; | 
 | 2998 |       *(UInt*)(m + 4) = ms4B; | 
 | 2999 |    } else { | 
 | 3000 |       *(UInt*)(m + 0) = ms4B; | 
 | 3001 |       *(UInt*)(m + 4) = ls4B; | 
 | 3002 |    } | 
 | 3003 |    nonptr_or_unknown_range(m, 8); | 
 | 3004 | } | 
 | 3005 |  | 
 | 3006 | // This handles 64 bit non pointer stores on 64 bit targets. | 
 | 3007 | // It must not be called on 32 bit targets. | 
 | 3008 | static VG_REGPARM(3) | 
 | 3009 | void check_store8_all8B(Addr m, Seg* mptr_vseg, UWord all8B) | 
 | 3010 | { | 
 | 3011 |    tl_assert(sizeof(UWord) == 8); /* DO NOT REMOVE */ | 
 | 3012 | #  if SC_SEGS | 
 | 3013 |    checkSeg(mptr_vseg); | 
 | 3014 | #  endif | 
 | 3015 |    check_load_or_store(/*is_write*/True, m, 8, mptr_vseg); | 
 | 3016 |    // Actually *do* the STORE here | 
 | 3017 |    *(ULong*)m = all8B; | 
 | 3018 |    nonptr_or_unknown_range(m, 8); | 
 | 3019 | } | 
 | 3020 |  | 
 | 3021 | // This handles 64 bit stores on 64 bit targets.  It must | 
 | 3022 | // not be called on 32 bit targets. | 
 | 3023 | static VG_REGPARM(3) | 
 | 3024 | void check_store8_P(Addr m, Seg* mptr_vseg, UWord t, Seg* t_vseg) | 
 | 3025 | { | 
 | 3026 |    tl_assert(sizeof(UWord) == 8); /* DO NOT REMOVE */ | 
 | 3027 | #  if SC_SEGS | 
 | 3028 |    checkSeg(t_vseg); | 
 | 3029 |    checkSeg(mptr_vseg); | 
 | 3030 | #  endif | 
 | 3031 |    check_load_or_store(/*is_write*/True, m, 8, mptr_vseg); | 
 | 3032 |    // Actually *do* the STORE here | 
 | 3033 |    *(ULong*)m = t; | 
 | 3034 |    if (VG_IS_8_ALIGNED(m)) { | 
 | 3035 |       set_mem_vseg( m, t_vseg ); | 
 | 3036 |    } else { | 
 | 3037 |       // straddling two words | 
 | 3038 |       nonptr_or_unknown_range(m, 8); | 
 | 3039 |    } | 
 | 3040 | } | 
 | 3041 |  | 
 | 3042 | // This handles 32 bit stores on 32 bit targets.  It must | 
 | 3043 | // not be called on 64 bit targets. | 
 | 3044 | static VG_REGPARM(3) | 
 | 3045 | void check_store4_P(Addr m, Seg* mptr_vseg, UWord t, Seg* t_vseg) | 
 | 3046 | { | 
 | 3047 |    tl_assert(sizeof(UWord) == 4); /* DO NOT REMOVE */ | 
 | 3048 | #  if SC_SEGS | 
 | 3049 |    checkSeg(t_vseg); | 
 | 3050 |    checkSeg(mptr_vseg); | 
 | 3051 | #  endif | 
 | 3052 |    check_load_or_store(/*is_write*/True, m, 4, mptr_vseg); | 
 | 3053 |    // Actually *do* the STORE here | 
 | 3054 |    *(UInt*)m = t; | 
 | 3055 |    if (VG_IS_4_ALIGNED(m)) { | 
 | 3056 |       set_mem_vseg( m, t_vseg ); | 
 | 3057 |    } else { | 
 | 3058 |       // straddling two words | 
 | 3059 |       nonptr_or_unknown_range(m, 4); | 
 | 3060 |    } | 
 | 3061 | } | 
 | 3062 |  | 
 | 3063 | // Used for both 32 bit and 64 bit targets. | 
 | 3064 | static VG_REGPARM(3) | 
 | 3065 | void check_store4(Addr m, Seg* mptr_vseg, UWord t) | 
 | 3066 | { | 
 | 3067 | #  if SC_SEGS | 
 | 3068 |    checkSeg(mptr_vseg); | 
 | 3069 | #  endif | 
 | 3070 |    check_load_or_store(/*is_write*/True, m, 4, mptr_vseg); | 
 | 3071 |    // Actually *do* the STORE here  (Nb: cast must be to 4-byte type!) | 
 | 3072 |    *(UInt*)m = t; | 
 | 3073 |    nonptr_or_unknown_range(m, 4); | 
 | 3074 | } | 
 | 3075 |  | 
 | 3076 | // Used for both 32 bit and 64 bit targets. | 
 | 3077 | static VG_REGPARM(3) | 
 | 3078 | void check_store2(Addr m, Seg* mptr_vseg, UWord t) | 
 | 3079 | { | 
 | 3080 | #  if SC_SEGS | 
 | 3081 |    checkSeg(mptr_vseg); | 
 | 3082 | #  endif | 
 | 3083 |    check_load_or_store(/*is_write*/True, m, 2, mptr_vseg); | 
 | 3084 |    // Actually *do* the STORE here  (Nb: cast must be to 2-byte type!) | 
 | 3085 |    *(UShort*)m = t; | 
 | 3086 |    nonptr_or_unknown_range(m, 2); | 
 | 3087 | } | 
 | 3088 |  | 
 | 3089 | // Used for both 32 bit and 64 bit targets. | 
 | 3090 | static VG_REGPARM(3) | 
 | 3091 | void check_store1(Addr m, Seg* mptr_vseg, UWord t) | 
 | 3092 | { | 
 | 3093 | #  if SC_SEGS | 
 | 3094 |    checkSeg(mptr_vseg); | 
 | 3095 | #  endif | 
 | 3096 |    check_load_or_store(/*is_write*/True, m, 1, mptr_vseg); | 
 | 3097 |    // Actually *do* the STORE here  (Nb: cast must be to 1-byte type!) | 
 | 3098 |    *(UChar*)m = t; | 
 | 3099 |    nonptr_or_unknown_range(m, 1); | 
 | 3100 | } | 
 | 3101 |  | 
 | 3102 |  | 
 | 3103 | // Nb: if the result is BOTTOM, return immedately -- don't let BOTTOM | 
 | 3104 | //     be changed to NONPTR by a range check on the result. | 
 | 3105 | #define BINOP(bt, nn, nu, np, un, uu, up, pn, pu, pp) \ | 
 | 3106 |    if (BOTTOM == seg1 || BOTTOM == seg2) { bt;                   \ | 
 | 3107 |    } else if (NONPTR == seg1)  { if      (NONPTR == seg2)  { nn; }  \ | 
 | 3108 |                                  else if (UNKNOWN == seg2) { nu; }    \ | 
 | 3109 |                                  else                      { np; }    \ | 
 | 3110 |    } else if (UNKNOWN == seg1) { if      (NONPTR == seg2)  { un; }    \ | 
 | 3111 |                                  else if (UNKNOWN == seg2) { uu; }    \ | 
 | 3112 |                                  else                      { up; }    \ | 
 | 3113 |    } else                      { if      (NONPTR == seg2)  { pn; }    \ | 
 | 3114 |                                  else if (UNKNOWN == seg2) { pu; }    \ | 
 | 3115 |                                  else                      { pp; }    \ | 
 | 3116 |    } | 
 | 3117 |  | 
 | 3118 | #define BINERROR(opname)                    \ | 
 | 3119 |    h_record_arith_error(seg1, seg2, opname);  \ | 
 | 3120 |    out = NONPTR | 
 | 3121 |  | 
 | 3122 |  | 
 | 3123 | // ------------- | 
 | 3124 | //  + | n  ?  p | 
 | 3125 | // ------------- | 
 | 3126 | //  n | n  ?  p | 
 | 3127 | //  ? | ?  ?  ? | 
 | 3128 | //  p | p  ?  e   (all results become n if they look like a non-pointer) | 
 | 3129 | // ------------- | 
 | 3130 | static Seg* do_addW_result(Seg* seg1, Seg* seg2, UWord result, HChar* opname) | 
 | 3131 | { | 
 | 3132 |    Seg* out; | 
 | 3133 | #  if SC_SEGS | 
 | 3134 |    checkSeg(seg1); | 
 | 3135 |    checkSeg(seg2); | 
 | 3136 | #  endif | 
 | 3137 |    BINOP( | 
 | 3138 |       return BOTTOM, | 
 | 3139 |       out = NONPTR,  out = UNKNOWN, out = seg2, | 
 | 3140 |       out = UNKNOWN, out = UNKNOWN, out = UNKNOWN, | 
 | 3141 |       out = seg1,    out = UNKNOWN,       BINERROR(opname) | 
 | 3142 |    ); | 
 | 3143 |    return ( looks_like_a_pointer(result) ? out : NONPTR ); | 
 | 3144 | } | 
 | 3145 |  | 
 | 3146 | static VG_REGPARM(3) Seg* do_addW(Seg* seg1, Seg* seg2, UWord result) | 
 | 3147 | { | 
 | 3148 |    Seg* out; | 
 | 3149 | #  if SC_SEGS | 
 | 3150 |    checkSeg(seg1); | 
 | 3151 |    checkSeg(seg2); | 
 | 3152 | #  endif | 
 | 3153 |    out = do_addW_result(seg1, seg2, result, "Add32/Add64"); | 
 | 3154 | #  if SC_SEGS | 
 | 3155 |    checkSeg(out); | 
 | 3156 | #  endif | 
 | 3157 |    return out; | 
 | 3158 | } | 
 | 3159 |  | 
 | 3160 | // ------------- | 
 | 3161 | //  - | n  ?  p      (Nb: operation is seg1 - seg2) | 
 | 3162 | // ------------- | 
 | 3163 | //  n | n  ?  n+     (+) happens a lot due to "cmp", but result should never | 
 | 3164 | //  ? | ?  ?  n/B        be used, so give 'n' | 
 | 3165 | //  p | p  p? n*/B   (*) and possibly link the segments | 
 | 3166 | // ------------- | 
 | 3167 | static VG_REGPARM(3) Seg* do_subW(Seg* seg1, Seg* seg2, UWord result) | 
 | 3168 | { | 
 | 3169 |    Seg* out; | 
 | 3170 | #  if SC_SEGS | 
 | 3171 |    checkSeg(seg1); | 
 | 3172 |    checkSeg(seg2); | 
 | 3173 | #  endif | 
 | 3174 |    // Nb: when returning BOTTOM, don't let it go through the range-check; | 
 | 3175 |    //     a segment linking offset can easily look like a nonptr. | 
 | 3176 |    BINOP( | 
 | 3177 |       return BOTTOM, | 
 | 3178 |       out = NONPTR,  out = UNKNOWN,    out = NONPTR, | 
 | 3179 |       out = UNKNOWN, out = UNKNOWN,    return BOTTOM, | 
 | 3180 |       out = seg1,    out = seg1/*??*/, return BOTTOM | 
 | 3181 |    ); | 
 | 3182 |    #if 0 | 
 | 3183 |          // This is for the p-p segment-linking case | 
 | 3184 |          Seg end2 = seg2; | 
 | 3185 |          while (end2->links != seg2) end2 = end2->links; | 
 | 3186 |          end2->links = seg1->links; | 
 | 3187 |          seg1->links = seg2; | 
 | 3188 |          return NONPTR; | 
 | 3189 |    #endif | 
 | 3190 |    return ( looks_like_a_pointer(result) ? out : NONPTR ); | 
 | 3191 | } | 
 | 3192 |  | 
 | 3193 | // ------------- | 
 | 3194 | //  & | n  ?  p | 
 | 3195 | // ------------- | 
 | 3196 | //  n | n  ?  p | 
 | 3197 | //  ? | ?  ?  ? | 
 | 3198 | //  p | p  ?  *  (*) if p1==p2 then p else e (see comment) | 
 | 3199 | // ------------- | 
 | 3200 | /* Seems to be OK to And two pointers: | 
 | 3201 |      testq %ptr1,%ptr2 | 
 | 3202 |      jnz .. | 
 | 3203 |    which possibly derives from | 
 | 3204 |      if (ptr1 & ptr2) { A } else { B } | 
 | 3205 |    not sure what that means | 
 | 3206 | */ | 
 | 3207 | static VG_REGPARM(3) Seg* do_andW(Seg* seg1, Seg* seg2,  | 
 | 3208 |                                   UWord result, UWord args_diff) | 
 | 3209 | { | 
 | 3210 |    Seg* out; | 
 | 3211 |    if (0 == args_diff) { | 
 | 3212 |       // p1==p2 | 
 | 3213 |       out = seg1; | 
 | 3214 |    } else { | 
 | 3215 |       BINOP( | 
 | 3216 |          return BOTTOM, | 
 | 3217 |          out = NONPTR,  out = UNKNOWN, out = seg2, | 
 | 3218 |          out = UNKNOWN, out = UNKNOWN, out = UNKNOWN, | 
 | 3219 |          out = seg1,    out = UNKNOWN, out = NONPTR | 
 | 3220 |                                        /*BINERROR("And32/And64")*/ | 
 | 3221 |       ); | 
 | 3222 |    } | 
 | 3223 |    out = ( looks_like_a_pointer(result) ? out : NONPTR ); | 
 | 3224 |    return out; | 
 | 3225 | } | 
 | 3226 |  | 
 | 3227 | // ------------- | 
 | 3228 | // `|`| n  ?  p | 
 | 3229 | // ------------- | 
 | 3230 | //  n | n  ?  p | 
 | 3231 | //  ? | ?  ?  ? | 
 | 3232 | //  p | p  ?  n | 
 | 3233 | // ------------- | 
 | 3234 | /* It's OK to Or two pointers together, but the result definitely | 
 | 3235 |    isn't a pointer.  Why would you want to do that?  Because of this: | 
 | 3236 |      char* p1 = malloc(..); | 
 | 3237 |      char* p2 = malloc(..); | 
 | 3238 |      ... | 
 | 3239 |      if (p1 || p2) { .. } | 
 | 3240 |    In this case gcc on x86/amd64 quite literally or-s the two pointers | 
 | 3241 |    together and throws away the result, the purpose of which is merely | 
 | 3242 |    to sets %eflags.Z/%rflags.Z.  So we have to allow it. | 
 | 3243 | */ | 
 | 3244 | static VG_REGPARM(3) Seg* do_orW(Seg* seg1, Seg* seg2, UWord result) | 
 | 3245 | { | 
 | 3246 |    Seg* out; | 
 | 3247 |    BINOP( | 
 | 3248 |       return BOTTOM, | 
 | 3249 |       out = NONPTR,  out = UNKNOWN, out = seg2, | 
 | 3250 |       out = UNKNOWN, out = UNKNOWN, out = UNKNOWN, | 
 | 3251 |       out = seg1,    out = UNKNOWN, out = NONPTR | 
 | 3252 |    ); | 
 | 3253 |    out = ( looks_like_a_pointer(result) ? out : NONPTR ); | 
 | 3254 |    return out; | 
 | 3255 | } | 
 | 3256 |  | 
 | 3257 | // ------------- | 
 | 3258 | //  ~ | n  ?  p | 
 | 3259 | // ------------- | 
 | 3260 | //    | n  n  n | 
 | 3261 | // ------------- | 
 | 3262 | static VG_REGPARM(2) Seg* do_notW(Seg* seg1, UWord result) | 
 | 3263 | { | 
 | 3264 | #  if SC_SEGS | 
 | 3265 |    checkSeg(seg1); | 
 | 3266 | #  endif | 
 | 3267 |    if (BOTTOM == seg1) return BOTTOM; | 
 | 3268 |    return NONPTR; | 
 | 3269 | } | 
 | 3270 |  | 
 | 3271 | // Pointers are rarely multiplied, but sometimes legitimately, eg. as hash | 
 | 3272 | // function inputs.  But two pointers args --> error. | 
 | 3273 | // Pretend it always returns a nonptr.  Maybe improve later. | 
 | 3274 | static VG_REGPARM(2) Seg* do_mulW(Seg* seg1, Seg* seg2) | 
 | 3275 | { | 
 | 3276 | #  if SC_SEGS | 
 | 3277 |    checkSeg(seg1); | 
 | 3278 |    checkSeg(seg2); | 
 | 3279 | #  endif | 
 | 3280 |    if (is_known_segment(seg1) && is_known_segment(seg2)) | 
 | 3281 |       h_record_arith_error(seg1, seg2, "Mul32/Mul64"); | 
 | 3282 |    return NONPTR; | 
 | 3283 | } | 
 | 3284 |  | 
 | 3285 |   | 
 | 3286 | /*--------------------------------------------------------------------*/ | 
 | 3287 | /*--- Instrumentation                                              ---*/ | 
 | 3288 | /*--------------------------------------------------------------------*/ | 
 | 3289 |  | 
 | 3290 | /* The h_ instrumenter that follows is complex, since it deals with | 
 | 3291 |    shadow value computation. | 
 | 3292 |  | 
 | 3293 |    It also needs to generate instrumentation for the sg_ side of | 
 | 3294 |    things.  That's relatively straightforward.  However, rather than | 
 | 3295 |    confuse the code herein any further, we simply delegate the problem | 
 | 3296 |    to sg_main.c, by using the four functions | 
 | 3297 |    sg_instrument_{init,fini,IRStmt,final_jump}.  These four completely | 
 | 3298 |    abstractify the sg_ instrumentation.  See comments in sg_main.c's | 
 | 3299 |    instrumentation section for further details. */ | 
 | 3300 |  | 
 | 3301 | /* Carries around state during Ptrcheck instrumentation. */ | 
 | 3302 | typedef | 
 | 3303 |    struct { | 
 | 3304 |       /* MODIFIED: the superblock being constructed.  IRStmts are | 
 | 3305 |          added. */ | 
 | 3306 |       IRSB* bb; | 
 | 3307 |       Bool  trace; | 
 | 3308 |  | 
 | 3309 |       /* MODIFIED: a table [0 .. #temps_in_original_bb-1] which maps | 
 | 3310 |          original temps to their current their current shadow temp. | 
 | 3311 |          Initially all entries are IRTemp_INVALID.  Entries are added | 
 | 3312 |          lazily since many original temps are not used due to | 
 | 3313 |          optimisation prior to instrumentation.  Note that only | 
 | 3314 |          integer temps of the guest word size are shadowed, since it | 
 | 3315 |          is impossible (or meaningless) to hold a pointer in any other | 
 | 3316 |          type of temp. */ | 
 | 3317 |       IRTemp* tmpMap; | 
 | 3318 |       Int     n_originalTmps; /* for range checking */ | 
 | 3319 |  | 
 | 3320 |       /* READONLY: the host word type.  Needed for constructing | 
 | 3321 |          arguments of type 'HWord' to be passed to helper functions. | 
 | 3322 |          Ity_I32 or Ity_I64 only. */ | 
 | 3323 |       IRType hWordTy; | 
 | 3324 |  | 
 | 3325 |       /* READONLY: the guest word type, Ity_I32 or Ity_I64 only. */ | 
 | 3326 |       IRType gWordTy; | 
 | 3327 |  | 
 | 3328 |       /* READONLY: the guest state size, so we can generate shadow | 
 | 3329 |          offsets correctly. */ | 
 | 3330 |       Int guest_state_sizeB; | 
 | 3331 |    } | 
 | 3332 |    PCEnv; | 
 | 3333 |  | 
 | 3334 | /* SHADOW TMP MANAGEMENT.  Shadow tmps are allocated lazily (on | 
 | 3335 |    demand), as they are encountered.  This is for two reasons. | 
 | 3336 |  | 
 | 3337 |    (1) (less important reason): Many original tmps are unused due to | 
 | 3338 |    initial IR optimisation, and we do not want to spaces in tables | 
 | 3339 |    tracking them. | 
 | 3340 |  | 
 | 3341 |    Shadow IRTemps are therefore allocated on demand.  pce.tmpMap is a | 
 | 3342 |    table indexed [0 .. n_types-1], which gives the current shadow for | 
 | 3343 |    each original tmp, or INVALID_IRTEMP if none is so far assigned. | 
 | 3344 |    It is necessary to support making multiple assignments to a shadow | 
 | 3345 |    -- specifically, after testing a shadow for definedness, it needs | 
 | 3346 |    to be made defined.  But IR's SSA property disallows this. | 
 | 3347 |  | 
 | 3348 |    (2) (more important reason): Therefore, when a shadow needs to get | 
 | 3349 |    a new value, a new temporary is created, the value is assigned to | 
 | 3350 |    that, and the tmpMap is updated to reflect the new binding. | 
 | 3351 |  | 
 | 3352 |    A corollary is that if the tmpMap maps a given tmp to | 
 | 3353 |    IRTemp_INVALID and we are hoping to read that shadow tmp, it means | 
 | 3354 |    there's a read-before-write error in the original tmps.  The IR | 
 | 3355 |    sanity checker should catch all such anomalies, however. | 
 | 3356 | */ | 
 | 3357 |  | 
 | 3358 | /* Find the tmp currently shadowing the given original tmp.  If none | 
 | 3359 |    so far exists, allocate one.  */ | 
 | 3360 | static IRTemp findShadowTmp ( PCEnv* pce, IRTemp orig ) | 
 | 3361 | { | 
 | 3362 |    tl_assert(orig < pce->n_originalTmps); | 
 | 3363 |    tl_assert(pce->bb->tyenv->types[orig] == pce->gWordTy); | 
 | 3364 |    if (pce->tmpMap[orig] == IRTemp_INVALID) { | 
 | 3365 |       tl_assert(0); | 
 | 3366 |       pce->tmpMap[orig] | 
 | 3367 |          = newIRTemp(pce->bb->tyenv, pce->gWordTy); | 
 | 3368 |    } | 
 | 3369 |    return pce->tmpMap[orig]; | 
 | 3370 | } | 
 | 3371 |  | 
 | 3372 | /* Allocate a new shadow for the given original tmp.  This means any | 
 | 3373 |    previous shadow is abandoned.  This is needed because it is | 
 | 3374 |    necessary to give a new value to a shadow once it has been tested | 
 | 3375 |    for undefinedness, but unfortunately IR's SSA property disallows | 
 | 3376 |    this.  Instead we must abandon the old shadow, allocate a new one | 
 | 3377 |    and use that instead. */ | 
 | 3378 | __attribute__((noinline)) | 
 | 3379 | static IRTemp newShadowTmp ( PCEnv* pce, IRTemp orig ) | 
 | 3380 | { | 
 | 3381 |    tl_assert(orig < pce->n_originalTmps); | 
 | 3382 |    tl_assert(pce->bb->tyenv->types[orig] == pce->gWordTy); | 
 | 3383 |    pce->tmpMap[orig] | 
 | 3384 |       = newIRTemp(pce->bb->tyenv, pce->gWordTy); | 
 | 3385 |    return pce->tmpMap[orig]; | 
 | 3386 | } | 
 | 3387 |  | 
 | 3388 |  | 
 | 3389 | /*------------------------------------------------------------*/ | 
 | 3390 | /*--- IRAtoms -- a subset of IRExprs                       ---*/ | 
 | 3391 | /*------------------------------------------------------------*/ | 
 | 3392 |  | 
 | 3393 | /* An atom is either an IRExpr_Const or an IRExpr_Tmp, as defined by | 
 | 3394 |    isIRAtom() in libvex_ir.h.  Because this instrumenter expects flat | 
 | 3395 |    input, most of this code deals in atoms.  Usefully, a value atom | 
 | 3396 |    always has a V-value which is also an atom: constants are shadowed | 
 | 3397 |    by constants, and temps are shadowed by the corresponding shadow | 
 | 3398 |    temporary. */ | 
 | 3399 |  | 
 | 3400 | typedef  IRExpr  IRAtom; | 
 | 3401 |  | 
 | 3402 | //zz /* (used for sanity checks only): is this an atom which looks | 
 | 3403 | //zz    like it's from original code? */ | 
 | 3404 | //zz static Bool isOriginalAtom ( PCEnv* pce, IRAtom* a1 ) | 
 | 3405 | //zz { | 
 | 3406 | //zz    if (a1->tag == Iex_Const) | 
 | 3407 | //zz       return True; | 
 | 3408 | //zz    if (a1->tag == Iex_RdTmp && a1->Iex.RdTmp.tmp < pce->n_originalTmps) | 
 | 3409 | //zz       return True; | 
 | 3410 | //zz    return False; | 
 | 3411 | //zz } | 
 | 3412 | //zz  | 
 | 3413 | //zz /* (used for sanity checks only): is this an atom which looks | 
 | 3414 | //zz    like it's from shadow code? */ | 
 | 3415 | //zz static Bool isShadowAtom ( PCEnv* pce, IRAtom* a1 ) | 
 | 3416 | //zz { | 
 | 3417 | //zz    if (a1->tag == Iex_Const) | 
 | 3418 | //zz       return True; | 
 | 3419 | //zz    if (a1->tag == Iex_RdTmp && a1->Iex.RdTmp.tmp >= pce->n_originalTmps) | 
 | 3420 | //zz       return True; | 
 | 3421 | //zz    return False; | 
 | 3422 | //zz } | 
 | 3423 | //zz  | 
 | 3424 | //zz /* (used for sanity checks only): check that both args are atoms and | 
 | 3425 | //zz    are identically-kinded. */ | 
 | 3426 | //zz static Bool sameKindedAtoms ( IRAtom* a1, IRAtom* a2 ) | 
 | 3427 | //zz { | 
 | 3428 | //zz    if (a1->tag == Iex_RdTmp && a2->tag == Iex_RdTmp) | 
 | 3429 | //zz       return True; | 
 | 3430 | //zz    if (a1->tag == Iex_Const && a2->tag == Iex_Const) | 
 | 3431 | //zz       return True; | 
 | 3432 | //zz    return False; | 
 | 3433 | //zz } | 
 | 3434 |  | 
 | 3435 |  | 
 | 3436 | /*------------------------------------------------------------*/ | 
 | 3437 | /*--- Constructing IR fragments                            ---*/ | 
 | 3438 | /*------------------------------------------------------------*/ | 
 | 3439 |  | 
 | 3440 | /* add stmt to a bb */ | 
 | 3441 | static inline void stmt ( HChar cat, PCEnv* pce, IRStmt* st ) { | 
 | 3442 |    if (pce->trace) { | 
 | 3443 |       VG_(printf)("  %c: ", cat); | 
 | 3444 |       ppIRStmt(st); | 
 | 3445 |       VG_(printf)("\n"); | 
 | 3446 |    } | 
 | 3447 |    addStmtToIRSB(pce->bb, st); | 
 | 3448 | } | 
 | 3449 |  | 
 | 3450 | /* assign value to tmp */ | 
 | 3451 | static inline | 
 | 3452 | void assign ( HChar cat, PCEnv* pce, IRTemp tmp, IRExpr* expr ) { | 
 | 3453 |    stmt(cat, pce, IRStmt_WrTmp(tmp,expr)); | 
 | 3454 | } | 
 | 3455 |  | 
 | 3456 | /* build various kinds of expressions */ | 
 | 3457 | #define binop(_op, _arg1, _arg2) IRExpr_Binop((_op),(_arg1),(_arg2)) | 
 | 3458 | #define unop(_op, _arg)          IRExpr_Unop((_op),(_arg)) | 
 | 3459 | #define mkU8(_n)                 IRExpr_Const(IRConst_U8(_n)) | 
 | 3460 | #define mkU16(_n)                IRExpr_Const(IRConst_U16(_n)) | 
 | 3461 | #define mkU32(_n)                IRExpr_Const(IRConst_U32(_n)) | 
 | 3462 | #define mkU64(_n)                IRExpr_Const(IRConst_U64(_n)) | 
 | 3463 | #define mkV128(_n)               IRExpr_Const(IRConst_V128(_n)) | 
 | 3464 | #define mkexpr(_tmp)             IRExpr_RdTmp((_tmp)) | 
 | 3465 |  | 
 | 3466 | /* Bind the given expression to a new temporary, and return the | 
 | 3467 |    temporary.  This effectively converts an arbitrary expression into | 
 | 3468 |    an atom. | 
 | 3469 |  | 
 | 3470 |    'ty' is the type of 'e' and hence the type that the new temporary | 
 | 3471 |    needs to be.  But passing it is redundant, since we can deduce the | 
 | 3472 |    type merely by inspecting 'e'.  So at least that fact to assert | 
 | 3473 |    that the two types agree. */ | 
 | 3474 | static IRAtom* assignNew ( HChar cat, PCEnv* pce, IRType ty, IRExpr* e ) { | 
 | 3475 |    IRTemp t; | 
 | 3476 |    IRType tyE = typeOfIRExpr(pce->bb->tyenv, e); | 
 | 3477 |    tl_assert(tyE == ty); /* so 'ty' is redundant (!) */ | 
 | 3478 |    t = newIRTemp(pce->bb->tyenv, ty); | 
 | 3479 |    assign(cat, pce, t, e); | 
 | 3480 |    return mkexpr(t); | 
 | 3481 | } | 
 | 3482 |  | 
 | 3483 |  | 
 | 3484 |  | 
 | 3485 | //----------------------------------------------------------------------- | 
 | 3486 | // Approach taken for range-checking for NONPTR/UNKNOWN-ness as follows. | 
 | 3487 | // | 
 | 3488 | // Range check (NONPTR/seg):  | 
 | 3489 | // - after modifying a word-sized value in/into a TempReg: | 
 | 3490 | //    - {ADD, SUB, ADC, SBB, AND, OR, XOR, LEA, LEA2, NEG, NOT}L | 
 | 3491 | //    - BSWAP | 
 | 3492 | //  | 
 | 3493 | // Range check (NONPTR/UNKNOWN): | 
 | 3494 | // - when introducing a new word-sized value into a TempReg: | 
 | 3495 | //    - MOVL l, t2 | 
 | 3496 | // | 
 | 3497 | // - when copying a word-sized value which lacks a corresponding segment | 
 | 3498 | //   into a TempReg: | 
 | 3499 | //    - straddled LDL | 
 | 3500 | // | 
 | 3501 | // - when a sub-word of a word (or two) is updated: | 
 | 3502 | //    - SHROTL | 
 | 3503 | //    - {ADD, SUB, ADC, SBB, AND, OR, XOR, SHROT, NEG, NOT}[WB] | 
 | 3504 | //    - PUT[WB] | 
 | 3505 | //    - straddled   STL (2 range checks) | 
 | 3506 | //    - straddled   STW (2 range checks) | 
 | 3507 | //    - unstraddled STW | 
 | 3508 | //    - STB | 
 | 3509 | //     | 
 | 3510 | // Just copy: | 
 | 3511 | // - when copying word-sized values: | 
 | 3512 | //    - MOVL t1, t2 (--optimise=no only) | 
 | 3513 | //    - CMOV | 
 | 3514 | //    - GETL, PUTL | 
 | 3515 | //    - unstraddled LDL, unstraddled STL | 
 | 3516 | // | 
 | 3517 | // - when barely changing | 
 | 3518 | //    - INC[LWB]/DEC[LWB] | 
 | 3519 | //  | 
 | 3520 | // Set to NONPTR: | 
 | 3521 | // - after copying a sub-word value into a TempReg: | 
 | 3522 | //    - MOV[WB] l, t2 | 
 | 3523 | //    - GET[WB] | 
 | 3524 | //    - unstraddled LDW | 
 | 3525 | //    - straddled   LDW | 
 | 3526 | //    - LDB | 
 | 3527 | //    - POP[WB] | 
 | 3528 | // | 
 | 3529 | // - after copying an obvious non-ptr into a TempReg: | 
 | 3530 | //    - GETF | 
 | 3531 | //    - CC2VAL | 
 | 3532 | //    - POPL | 
 | 3533 | // | 
 | 3534 | // - after copying an obvious non-ptr into a memory word: | 
 | 3535 | //    - FPU_W | 
 | 3536 | //  | 
 | 3537 | // Do nothing: | 
 | 3538 | // - LOCK, INCEIP | 
 | 3539 | // - WIDEN[WB] | 
 | 3540 | // - JMP, JIFZ | 
 | 3541 | // - CALLM_[SE], PUSHL, CALLM, CLEAR | 
 | 3542 | // - FPU, FPU_R (and similar MMX/SSE ones) | 
 | 3543 | // | 
 | 3544 |  | 
 | 3545 |  | 
 | 3546 |  | 
 | 3547 |  | 
 | 3548 | /* Call h_fn (name h_nm) with the given arg, and return a new IRTemp | 
 | 3549 |    holding the result.  The arg must be a word-typed atom.  Callee | 
 | 3550 |    must be a VG_REGPARM(1) function. */ | 
 | 3551 | __attribute__((noinline)) | 
 | 3552 | static IRTemp gen_dirty_W_W ( PCEnv* pce, void* h_fn, HChar* h_nm,  | 
 | 3553 |                               IRExpr* a1 ) | 
 | 3554 | { | 
 | 3555 |    IRTemp   res; | 
 | 3556 |    IRDirty* di; | 
 | 3557 |    tl_assert(isIRAtom(a1)); | 
 | 3558 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a1) == pce->gWordTy); | 
 | 3559 |    res = newIRTemp(pce->bb->tyenv, pce->gWordTy); | 
 | 3560 |    di = unsafeIRDirty_1_N( res, 1/*regparms*/, | 
 | 3561 |                            h_nm, VG_(fnptr_to_fnentry)( h_fn ), | 
 | 3562 |                            mkIRExprVec_1( a1 ) ); | 
 | 3563 |    stmt( 'I', pce, IRStmt_Dirty(di) ); | 
 | 3564 |    return res; | 
 | 3565 | } | 
 | 3566 |  | 
 | 3567 | /* Two-arg version of gen_dirty_W_W.  Callee must be a VG_REGPARM(2) | 
 | 3568 |    function.*/ | 
 | 3569 | static IRTemp gen_dirty_W_WW ( PCEnv* pce, void* h_fn, HChar* h_nm,  | 
 | 3570 |                                IRExpr* a1, IRExpr* a2 ) | 
 | 3571 | { | 
 | 3572 |    IRTemp   res; | 
 | 3573 |    IRDirty* di; | 
 | 3574 |    tl_assert(isIRAtom(a1)); | 
 | 3575 |    tl_assert(isIRAtom(a2)); | 
 | 3576 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a1) == pce->gWordTy); | 
 | 3577 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a2) == pce->gWordTy); | 
 | 3578 |    res = newIRTemp(pce->bb->tyenv, pce->gWordTy); | 
 | 3579 |    di = unsafeIRDirty_1_N( res, 2/*regparms*/, | 
 | 3580 |                            h_nm, VG_(fnptr_to_fnentry)( h_fn ), | 
 | 3581 |                            mkIRExprVec_2( a1, a2 ) ); | 
 | 3582 |    stmt( 'I', pce, IRStmt_Dirty(di) ); | 
 | 3583 |    return res; | 
 | 3584 | } | 
 | 3585 |  | 
 | 3586 | /* Three-arg version of gen_dirty_W_W.  Callee must be a VG_REGPARM(3) | 
 | 3587 |    function.*/ | 
 | 3588 | static IRTemp gen_dirty_W_WWW ( PCEnv* pce, void* h_fn, HChar* h_nm,  | 
 | 3589 |                                 IRExpr* a1, IRExpr* a2, IRExpr* a3 ) | 
 | 3590 | { | 
 | 3591 |    IRTemp   res; | 
 | 3592 |    IRDirty* di; | 
 | 3593 |    tl_assert(isIRAtom(a1)); | 
 | 3594 |    tl_assert(isIRAtom(a2)); | 
 | 3595 |    tl_assert(isIRAtom(a3)); | 
 | 3596 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a1) == pce->gWordTy); | 
 | 3597 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a2) == pce->gWordTy); | 
 | 3598 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a3) == pce->gWordTy); | 
 | 3599 |    res = newIRTemp(pce->bb->tyenv, pce->gWordTy); | 
 | 3600 |    di = unsafeIRDirty_1_N( res, 3/*regparms*/, | 
 | 3601 |                            h_nm, VG_(fnptr_to_fnentry)( h_fn ), | 
 | 3602 |                            mkIRExprVec_3( a1, a2, a3 ) ); | 
 | 3603 |    stmt( 'I', pce, IRStmt_Dirty(di) ); | 
 | 3604 |    return res; | 
 | 3605 | } | 
 | 3606 |  | 
 | 3607 | /* Four-arg version of gen_dirty_W_W.  Callee must be a VG_REGPARM(3) | 
 | 3608 |    function.*/ | 
 | 3609 | static IRTemp gen_dirty_W_WWWW ( PCEnv* pce, void* h_fn, HChar* h_nm,  | 
 | 3610 |                                  IRExpr* a1, IRExpr* a2, | 
 | 3611 |                                  IRExpr* a3, IRExpr* a4 ) | 
 | 3612 | { | 
 | 3613 |    IRTemp   res; | 
 | 3614 |    IRDirty* di; | 
 | 3615 |    tl_assert(isIRAtom(a1)); | 
 | 3616 |    tl_assert(isIRAtom(a2)); | 
 | 3617 |    tl_assert(isIRAtom(a3)); | 
 | 3618 |    tl_assert(isIRAtom(a4)); | 
 | 3619 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a1) == pce->gWordTy); | 
 | 3620 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a2) == pce->gWordTy); | 
 | 3621 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a3) == pce->gWordTy); | 
 | 3622 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a4) == pce->gWordTy); | 
 | 3623 |    res = newIRTemp(pce->bb->tyenv, pce->gWordTy); | 
 | 3624 |    di = unsafeIRDirty_1_N( res, 3/*regparms*/, | 
 | 3625 |                            h_nm, VG_(fnptr_to_fnentry)( h_fn ), | 
 | 3626 |                            mkIRExprVec_4( a1, a2, a3, a4 ) ); | 
 | 3627 |    stmt( 'I', pce, IRStmt_Dirty(di) ); | 
 | 3628 |    return res; | 
 | 3629 | } | 
 | 3630 |  | 
 | 3631 | /* Version of gen_dirty_W_WW with no return value.  Callee must be a | 
 | 3632 |    VG_REGPARM(2) function.*/ | 
 | 3633 | static void gen_dirty_v_WW ( PCEnv* pce, void* h_fn, HChar* h_nm,  | 
 | 3634 |                              IRExpr* a1, IRExpr* a2 ) | 
 | 3635 | { | 
 | 3636 |    IRDirty* di; | 
 | 3637 |    tl_assert(isIRAtom(a1)); | 
 | 3638 |    tl_assert(isIRAtom(a2)); | 
 | 3639 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a1) == pce->gWordTy); | 
 | 3640 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a2) == pce->gWordTy); | 
 | 3641 |    di = unsafeIRDirty_0_N( 2/*regparms*/, | 
 | 3642 |                            h_nm, VG_(fnptr_to_fnentry)( h_fn ), | 
 | 3643 |                            mkIRExprVec_2( a1, a2 ) ); | 
 | 3644 |    stmt( 'I', pce, IRStmt_Dirty(di) ); | 
 | 3645 | } | 
 | 3646 |  | 
 | 3647 | /* Version of gen_dirty_W_WWW with no return value.  Callee must be a | 
 | 3648 |    VG_REGPARM(3) function.*/ | 
 | 3649 | static void gen_dirty_v_WWW ( PCEnv* pce, void* h_fn, HChar* h_nm,  | 
 | 3650 |                               IRExpr* a1, IRExpr* a2, IRExpr* a3 ) | 
 | 3651 | { | 
 | 3652 |    IRDirty* di; | 
 | 3653 |    tl_assert(isIRAtom(a1)); | 
 | 3654 |    tl_assert(isIRAtom(a2)); | 
 | 3655 |    tl_assert(isIRAtom(a3)); | 
 | 3656 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a1) == pce->gWordTy); | 
 | 3657 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a2) == pce->gWordTy); | 
 | 3658 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a3) == pce->gWordTy); | 
 | 3659 |    di = unsafeIRDirty_0_N( 3/*regparms*/, | 
 | 3660 |                            h_nm, VG_(fnptr_to_fnentry)( h_fn ), | 
 | 3661 |                            mkIRExprVec_3( a1, a2, a3 ) ); | 
 | 3662 |    stmt( 'I', pce, IRStmt_Dirty(di) ); | 
 | 3663 | } | 
 | 3664 |  | 
 | 3665 | /* Version of gen_dirty_v_WWW for 4 arguments.  Callee must be a | 
 | 3666 |    VG_REGPARM(3) function.*/ | 
 | 3667 | static void gen_dirty_v_WWWW ( PCEnv* pce, void* h_fn, HChar* h_nm,  | 
 | 3668 |                                IRExpr* a1, IRExpr* a2, | 
 | 3669 |                                IRExpr* a3, IRExpr* a4 ) | 
 | 3670 | { | 
 | 3671 |    IRDirty* di; | 
 | 3672 |    tl_assert(isIRAtom(a1)); | 
 | 3673 |    tl_assert(isIRAtom(a2)); | 
 | 3674 |    tl_assert(isIRAtom(a3)); | 
 | 3675 |    tl_assert(isIRAtom(a4)); | 
 | 3676 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a1) == pce->gWordTy); | 
 | 3677 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a2) == pce->gWordTy); | 
 | 3678 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a3) == pce->gWordTy); | 
 | 3679 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a4) == pce->gWordTy); | 
 | 3680 |    di = unsafeIRDirty_0_N( 3/*regparms*/, | 
 | 3681 |                            h_nm, VG_(fnptr_to_fnentry)( h_fn ), | 
 | 3682 |                            mkIRExprVec_4( a1, a2, a3, a4 ) ); | 
 | 3683 |    stmt( 'I', pce, IRStmt_Dirty(di) ); | 
 | 3684 | } | 
 | 3685 |  | 
 | 3686 | /* Version of gen_dirty_v_WWW for 6 arguments.  Callee must be a | 
 | 3687 |    VG_REGPARM(3) function.*/ | 
 | 3688 | static void gen_dirty_v_6W ( PCEnv* pce, void* h_fn, HChar* h_nm,  | 
 | 3689 |                              IRExpr* a1, IRExpr* a2, IRExpr* a3, | 
 | 3690 |                              IRExpr* a4, IRExpr* a5, IRExpr* a6 ) | 
 | 3691 | { | 
 | 3692 |    IRDirty* di; | 
 | 3693 |    tl_assert(isIRAtom(a1)); | 
 | 3694 |    tl_assert(isIRAtom(a2)); | 
 | 3695 |    tl_assert(isIRAtom(a3)); | 
 | 3696 |    tl_assert(isIRAtom(a4)); | 
 | 3697 |    tl_assert(isIRAtom(a5)); | 
 | 3698 |    tl_assert(isIRAtom(a6)); | 
 | 3699 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a1) == pce->gWordTy); | 
 | 3700 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a2) == pce->gWordTy); | 
 | 3701 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a3) == pce->gWordTy); | 
 | 3702 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a4) == pce->gWordTy); | 
 | 3703 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a5) == pce->gWordTy); | 
 | 3704 |    tl_assert(typeOfIRExpr(pce->bb->tyenv, a6) == pce->gWordTy); | 
 | 3705 |    di = unsafeIRDirty_0_N( 3/*regparms*/, | 
 | 3706 |                            h_nm, VG_(fnptr_to_fnentry)( h_fn ), | 
 | 3707 |                            mkIRExprVec_6( a1, a2, a3, a4, a5, a6 ) ); | 
 | 3708 |    stmt( 'I', pce, IRStmt_Dirty(di) ); | 
 | 3709 | } | 
 | 3710 |  | 
 | 3711 | static IRAtom* uwiden_to_host_word ( PCEnv* pce, IRAtom* a ) | 
 | 3712 | { | 
 | 3713 |    IRType a_ty = typeOfIRExpr(pce->bb->tyenv, a); | 
 | 3714 |    tl_assert(isIRAtom(a)); | 
 | 3715 |    if (pce->hWordTy == Ity_I32) { | 
 | 3716 |       switch (a_ty) { | 
 | 3717 |          case Ity_I8: | 
 | 3718 |             return assignNew( 'I', pce, Ity_I32, unop(Iop_8Uto32, a) ); | 
 | 3719 |          case Ity_I16: | 
 | 3720 |             return assignNew( 'I', pce, Ity_I32, unop(Iop_16Uto32, a) ); | 
 | 3721 |          default: | 
 | 3722 |             ppIRType(a_ty); | 
 | 3723 |             tl_assert(0); | 
 | 3724 |       } | 
 | 3725 |    } else { | 
 | 3726 |       tl_assert(pce->hWordTy == Ity_I64); | 
 | 3727 |       switch (a_ty) { | 
 | 3728 |          case Ity_I8: | 
 | 3729 |             return assignNew( 'I', pce, Ity_I64, unop(Iop_8Uto64, a) ); | 
 | 3730 |          case Ity_I16: | 
 | 3731 |             return assignNew( 'I', pce, Ity_I64, unop(Iop_16Uto64, a) ); | 
 | 3732 |          case Ity_I32: | 
 | 3733 |             return assignNew( 'I', pce, Ity_I64, unop(Iop_32Uto64, a) ); | 
 | 3734 |          default: | 
 | 3735 |             ppIRType(a_ty); | 
 | 3736 |             tl_assert(0); | 
 | 3737 |       } | 
 | 3738 |    } | 
 | 3739 | } | 
 | 3740 |  | 
 | 3741 | /* 'e' is a word-sized atom.  Call nonptr_or_unknown with it, bind the | 
 | 3742 |    results to a new temporary, and return the temporary.  Note this | 
 | 3743 |    takes an original expression but returns a shadow value. */ | 
 | 3744 | static IRTemp gen_call_nonptr_or_unknown_w ( PCEnv* pce, IRExpr* e ) | 
 | 3745 | { | 
 | 3746 |    return gen_dirty_W_W( pce, &nonptr_or_unknown,  | 
 | 3747 |                               "nonptr_or_unknown", e ); | 
 | 3748 | } | 
 | 3749 |  | 
 | 3750 |  | 
 | 3751 | /* Generate the shadow value for an IRExpr which is an atom and | 
 | 3752 |    guaranteed to be word-sized. */ | 
 | 3753 | static IRAtom* schemeEw_Atom ( PCEnv* pce, IRExpr* e ) | 
 | 3754 | { | 
 | 3755 |    if (pce->gWordTy == Ity_I32) { | 
 | 3756 |       if (e->tag == Iex_Const && e->Iex.Const.con->tag == Ico_U32) { | 
 | 3757 |          IRTemp t; | 
 | 3758 |          tl_assert(sizeof(UWord) == 4); | 
 | 3759 |          t = gen_call_nonptr_or_unknown_w(pce, e); | 
 | 3760 |          return mkexpr(t); | 
 | 3761 |       } | 
 | 3762 |       if (e->tag == Iex_RdTmp | 
 | 3763 |           && typeOfIRExpr(pce->bb->tyenv, e) == Ity_I32) { | 
 | 3764 |          return mkexpr( findShadowTmp(pce, e->Iex.RdTmp.tmp) ); | 
 | 3765 |       } | 
 | 3766 |       /* there are no other word-sized atom cases */ | 
 | 3767 |    } else { | 
 | 3768 |       if (e->tag == Iex_Const && e->Iex.Const.con->tag == Ico_U64) { | 
 | 3769 |          IRTemp t; | 
 | 3770 |          tl_assert(sizeof(UWord) == 8); | 
 | 3771 |          //return mkU64( (ULong)(UWord)NONPTR ); | 
 | 3772 |          t = gen_call_nonptr_or_unknown_w(pce, e); | 
 | 3773 |          return mkexpr(t); | 
 | 3774 |       } | 
 | 3775 |       if (e->tag == Iex_RdTmp | 
 | 3776 |           && typeOfIRExpr(pce->bb->tyenv, e) == Ity_I64) { | 
 | 3777 |          return mkexpr( findShadowTmp(pce, e->Iex.RdTmp.tmp) ); | 
 | 3778 |       } | 
 | 3779 |       /* there are no other word-sized atom cases */ | 
 | 3780 |    } | 
 | 3781 |    ppIRExpr(e); | 
 | 3782 |    tl_assert(0); | 
 | 3783 | } | 
 | 3784 |  | 
 | 3785 |  | 
 | 3786 | static | 
 | 3787 | void instrument_arithop ( PCEnv* pce, | 
 | 3788 |                           IRTemp dst, /* already holds result */ | 
 | 3789 |                           IRTemp dstv, /* generate an assignment to this */ | 
 | 3790 |                           IROp op, | 
 | 3791 |                           /* original args, guaranteed to be atoms */ | 
 | 3792 |                           IRExpr* a1, IRExpr* a2, IRExpr* a3, IRExpr* a4 ) | 
 | 3793 | { | 
 | 3794 |    HChar*  nm  = NULL; | 
 | 3795 |    void*   fn  = NULL; | 
 | 3796 |    IRExpr* a1v = NULL; | 
 | 3797 |    IRExpr* a2v = NULL; | 
 | 3798 |    //IRExpr* a3v = NULL; | 
 | 3799 |    //IRExpr* a4v = NULL; | 
 | 3800 |    IRTemp  res = IRTemp_INVALID; | 
 | 3801 |  | 
 | 3802 |    if (pce->gWordTy == Ity_I32) { | 
 | 3803 |  | 
 | 3804 |       tl_assert(pce->hWordTy == Ity_I32); | 
 | 3805 |       switch (op) { | 
 | 3806 |  | 
 | 3807 |          /* For these cases, pass Segs for both arguments, and the | 
 | 3808 |             result value. */ | 
 | 3809 |          case Iop_Add32: nm = "do_addW"; fn = &do_addW; goto ssr32; | 
 | 3810 |          case Iop_Sub32: nm = "do_subW"; fn = &do_subW; goto ssr32; | 
 | 3811 |          case Iop_Or32:  nm = "do_orW";  fn = &do_orW;  goto ssr32; | 
 | 3812 |          ssr32: | 
 | 3813 |             a1v = schemeEw_Atom( pce, a1 ); | 
 | 3814 |             a2v = schemeEw_Atom( pce, a2 ); | 
 | 3815 |             res = gen_dirty_W_WWW( pce, fn, nm, a1v, a2v, mkexpr(dst) ); | 
 | 3816 |             assign( 'I', pce, dstv, mkexpr(res) ); | 
 | 3817 |             break; | 
 | 3818 |  | 
 | 3819 |          /* In this case, pass Segs for both arguments, the result | 
 | 3820 |             value, and the difference between the (original) values of | 
 | 3821 |             the arguments. */ | 
 | 3822 |          case Iop_And32: | 
 | 3823 |             nm = "do_andW"; fn = &do_andW; | 
 | 3824 |             a1v = schemeEw_Atom( pce, a1 ); | 
 | 3825 |             a2v = schemeEw_Atom( pce, a2 ); | 
 | 3826 |             res = gen_dirty_W_WWWW(  | 
 | 3827 |                      pce, fn, nm, a1v, a2v, mkexpr(dst), | 
 | 3828 |                      assignNew( 'I', pce, Ity_I32, | 
 | 3829 |                                 binop(Iop_Sub32,a1,a2) ) ); | 
 | 3830 |             assign( 'I', pce, dstv, mkexpr(res) ); | 
 | 3831 |             break; | 
 | 3832 |  | 
 | 3833 |          /* Pass one shadow arg and the result to the helper. */ | 
 | 3834 |          case Iop_Not32: nm = "do_notW"; fn = &do_notW; goto vr32; | 
 | 3835 |          vr32: | 
 | 3836 |             a1v = schemeEw_Atom( pce, a1 ); | 
 | 3837 |             res = gen_dirty_W_WW( pce, fn, nm, a1v, mkexpr(dst) ); | 
 | 3838 |             assign( 'I', pce, dstv, mkexpr(res) ); | 
 | 3839 |             break; | 
 | 3840 |  | 
 | 3841 |          /* Pass two shadow args only to the helper. */ | 
 | 3842 |          case Iop_Mul32: nm = "do_mulW"; fn = &do_mulW; goto vv32; | 
 | 3843 |          vv32: | 
 | 3844 |             a1v = schemeEw_Atom( pce, a1 ); | 
 | 3845 |             a2v = schemeEw_Atom( pce, a2 ); | 
 | 3846 |             res = gen_dirty_W_WW( pce, fn, nm, a1v, a2v ); | 
 | 3847 |             assign( 'I', pce, dstv, mkexpr(res) ); | 
 | 3848 |             break; | 
 | 3849 |  | 
 | 3850 |          /* We don't really know what the result could be; test at run | 
 | 3851 |             time. */ | 
 | 3852 |          case Iop_64HIto32: goto n_or_u_32; | 
 | 3853 |          case Iop_64to32:   goto n_or_u_32; | 
 | 3854 |          case Iop_Xor32:    goto n_or_u_32; | 
 | 3855 |          n_or_u_32: | 
 | 3856 |             assign( 'I', pce, dstv, | 
 | 3857 |                     mkexpr( | 
 | 3858 |                        gen_call_nonptr_or_unknown_w( pce,  | 
 | 3859 |                                                      mkexpr(dst) ) ) ); | 
 | 3860 |             break; | 
 | 3861 |  | 
 | 3862 |          /* Cases where it's very obvious that the result cannot be a | 
 | 3863 |             pointer.  Hence declare directly that it's NONPTR; don't | 
 | 3864 |             bother with the overhead of calling nonptr_or_unknown. */ | 
 | 3865 |  | 
 | 3866 |          /* cases where it makes no sense for the result to be a ptr */ | 
 | 3867 |          /* FIXME: for Shl/Shr/Sar, really should do a test on the 2nd | 
 | 3868 |             arg, so that shift by zero preserves the original | 
 | 3869 |             value. */ | 
 | 3870 |          case Iop_Shl32:    goto n32; | 
 | 3871 |          case Iop_Sar32:    goto n32; | 
 | 3872 |          case Iop_Shr32:    goto n32; | 
 | 3873 |          case Iop_16Uto32:  goto n32; | 
 | 3874 |          case Iop_16Sto32:  goto n32; | 
 | 3875 |          case Iop_F64toI32: goto n32; | 
 | 3876 |          case Iop_16HLto32: goto n32; | 
 | 3877 |          case Iop_MullS16:  goto n32; | 
 | 3878 |          case Iop_MullU16:  goto n32; | 
 | 3879 |          case Iop_PRemC3210F64: goto n32; | 
 | 3880 |          case Iop_DivU32:   goto n32; | 
 | 3881 |          case Iop_DivS32:   goto n32; | 
 | 3882 |          case Iop_V128to32: goto n32; | 
 | 3883 |  | 
 | 3884 |          /* cases where result range is very limited and clearly cannot | 
 | 3885 |             be a pointer */ | 
 | 3886 |          case Iop_1Uto32: goto n32; | 
 | 3887 |          case Iop_1Sto32: goto n32; | 
 | 3888 |          case Iop_8Uto32: goto n32; | 
 | 3889 |          case Iop_8Sto32: goto n32; | 
 | 3890 |          case Iop_Clz32:  goto n32; | 
 | 3891 |          case Iop_Ctz32:  goto n32; | 
 | 3892 |          case Iop_CmpF64: goto n32; | 
 | 3893 |          case Iop_CmpORD32S: goto n32; | 
 | 3894 |          case Iop_CmpORD32U: goto n32; | 
 | 3895 |          n32: | 
 | 3896 |             assign( 'I', pce, dstv, mkU32( (UWord)NONPTR )); | 
 | 3897 |             break; | 
 | 3898 |  | 
 | 3899 |          default: | 
 | 3900 |             VG_(printf)("instrument_arithop(32-bit): unhandled: "); | 
 | 3901 |             ppIROp(op); | 
 | 3902 |             tl_assert(0); | 
 | 3903 |       } | 
 | 3904 |  | 
 | 3905 |    } else { | 
 | 3906 |  | 
 | 3907 |       tl_assert(pce->gWordTy == Ity_I64); | 
 | 3908 |       switch (op) { | 
 | 3909 |  | 
 | 3910 |          /* For these cases, pass Segs for both arguments, and the | 
 | 3911 |             result value. */ | 
 | 3912 |          case Iop_Add64: nm = "do_addW"; fn = &do_addW; goto ssr64; | 
 | 3913 |          case Iop_Sub64: nm = "do_subW"; fn = &do_subW; goto ssr64; | 
 | 3914 |          case Iop_Or64:  nm = "do_orW";  fn = &do_orW;  goto ssr64; | 
 | 3915 |          ssr64: | 
 | 3916 |             a1v = schemeEw_Atom( pce, a1 ); | 
 | 3917 |             a2v = schemeEw_Atom( pce, a2 ); | 
 | 3918 |             res = gen_dirty_W_WWW( pce, fn, nm, a1v, a2v, mkexpr(dst) ); | 
 | 3919 |             assign( 'I', pce, dstv, mkexpr(res) ); | 
 | 3920 |             break; | 
 | 3921 |  | 
 | 3922 |          /* In this case, pass Segs for both arguments, the result | 
 | 3923 |             value, and the difference between the (original) values of | 
 | 3924 |             the arguments. */ | 
 | 3925 |          case Iop_And64: | 
 | 3926 |             nm = "do_andW"; fn = &do_andW; | 
 | 3927 |             a1v = schemeEw_Atom( pce, a1 ); | 
 | 3928 |             a2v = schemeEw_Atom( pce, a2 ); | 
 | 3929 |             res = gen_dirty_W_WWWW(  | 
 | 3930 |                      pce, fn, nm, a1v, a2v, mkexpr(dst), | 
 | 3931 |                      assignNew( 'I', pce, Ity_I64, | 
 | 3932 |                                 binop(Iop_Sub64,a1,a2) ) ); | 
 | 3933 |             assign( 'I', pce, dstv, mkexpr(res) ); | 
 | 3934 |             break; | 
 | 3935 |  | 
 | 3936 |          /* Pass one shadow arg and the result to the helper. */ | 
 | 3937 |          case Iop_Not64: nm = "do_notW"; fn = &do_notW; goto vr64; | 
 | 3938 |          vr64: | 
 | 3939 |             a1v = schemeEw_Atom( pce, a1 ); | 
 | 3940 |             res = gen_dirty_W_WW( pce, fn, nm, a1v, mkexpr(dst) ); | 
 | 3941 |             assign( 'I', pce, dstv, mkexpr(res) ); | 
 | 3942 |             break; | 
 | 3943 |  | 
 | 3944 |          /* Pass two shadow args only to the helper. */ | 
 | 3945 |          case Iop_Mul64: nm = "do_mulW"; fn = &do_mulW; goto vv64; | 
 | 3946 |          vv64: | 
 | 3947 |             a1v = schemeEw_Atom( pce, a1 ); | 
 | 3948 |             a2v = schemeEw_Atom( pce, a2 ); | 
 | 3949 |             res = gen_dirty_W_WW( pce, fn, nm, a1v, a2v ); | 
 | 3950 |             assign( 'I', pce, dstv, mkexpr(res) ); | 
 | 3951 |             break; | 
 | 3952 |  | 
 | 3953 |          /* We don't really know what the result could be; test at run | 
 | 3954 |             time. */ | 
 | 3955 |          case Iop_Xor64:      goto n_or_u_64; | 
 | 3956 |          case Iop_128HIto64:  goto n_or_u_64; | 
 | 3957 |          case Iop_128to64:    goto n_or_u_64; | 
 | 3958 |          case Iop_V128HIto64: goto n_or_u_64; | 
 | 3959 |          case Iop_V128to64:   goto n_or_u_64; | 
 | 3960 |          n_or_u_64: | 
 | 3961 |             assign( 'I', pce, dstv, | 
 | 3962 |                     mkexpr( | 
 | 3963 |                        gen_call_nonptr_or_unknown_w( pce,  | 
 | 3964 |                                                      mkexpr(dst) ) ) ); | 
 | 3965 |             break; | 
 | 3966 |  | 
 | 3967 |          /* Cases where it's very obvious that the result cannot be a | 
 | 3968 |             pointer.  Hence declare directly that it's NONPTR; don't | 
 | 3969 |             bother with the overhead of calling nonptr_or_unknown. */ | 
 | 3970 |  | 
 | 3971 |          /* cases where it makes no sense for the result to be a ptr */ | 
 | 3972 |          /* FIXME: for Shl/Shr/Sar, really should do a test on the 2nd | 
 | 3973 |             arg, so that shift by zero preserves the original | 
 | 3974 |             value. */ | 
 | 3975 |          case Iop_Shl64:      goto n64; | 
 | 3976 |          case Iop_Sar64:      goto n64; | 
 | 3977 |          case Iop_Shr64:      goto n64; | 
 | 3978 |          case Iop_32Uto64:    goto n64; | 
 | 3979 |          case Iop_32Sto64:    goto n64; | 
 | 3980 |          case Iop_16Uto64:    goto n64; | 
 | 3981 |          case Iop_16Sto64:    goto n64; | 
 | 3982 |          case Iop_32HLto64:   goto n64; | 
 | 3983 |          case Iop_DivModU64to32: goto n64; | 
 | 3984 |          case Iop_DivModS64to32: goto n64; | 
 | 3985 |          case Iop_F64toI64:      goto n64; | 
 | 3986 |          case Iop_MullS32:    goto n64; | 
 | 3987 |          case Iop_MullU32:    goto n64; | 
 | 3988 |          case Iop_DivU64:     goto n64; | 
 | 3989 |          case Iop_DivS64:     goto n64; | 
 | 3990 |          case Iop_ReinterpF64asI64: goto n64; | 
 | 3991 |  | 
 | 3992 |          /* cases where result range is very limited and clearly cannot | 
 | 3993 |             be a pointer */ | 
 | 3994 |          case Iop_1Uto64:        goto n64; | 
 | 3995 |          case Iop_8Uto64:        goto n64; | 
 | 3996 |          case Iop_8Sto64:        goto n64; | 
 | 3997 |          case Iop_Ctz64:         goto n64; | 
 | 3998 |          case Iop_Clz64:         goto n64; | 
 | 3999 |          case Iop_CmpORD64S:     goto n64; | 
 | 4000 |          case Iop_CmpORD64U:     goto n64; | 
 | 4001 |          /* 64-bit simd */ | 
 | 4002 |          case Iop_Avg8Ux8: case Iop_Avg16Ux4: | 
 | 4003 |          case Iop_Max16Sx4: case Iop_Max8Ux8: case Iop_Min16Sx4: | 
 | 4004 |          case Iop_Min8Ux8: case Iop_MulHi16Ux4: | 
 | 4005 |          case Iop_QNarrow32Sx2: case Iop_QNarrow16Sx4: | 
 | 4006 |          case Iop_QNarrow16Ux4: case Iop_Add8x8: case Iop_Add32x2: | 
 | 4007 |          case Iop_QAdd8Sx8: case Iop_QAdd16Sx4: case Iop_QAdd8Ux8: | 
 | 4008 |          case Iop_QAdd16Ux4: case Iop_Add16x4: case Iop_CmpEQ8x8: | 
 | 4009 |          case Iop_CmpEQ32x2: case Iop_CmpEQ16x4: case Iop_CmpGT8Sx8: | 
 | 4010 |          case Iop_CmpGT32Sx2: case Iop_CmpGT16Sx4: case Iop_MulHi16Sx4: | 
 | 4011 |          case Iop_Mul16x4: case Iop_ShlN32x2: case Iop_ShlN16x4: | 
 | 4012 |          case Iop_SarN32x2: case Iop_SarN16x4: case Iop_ShrN32x2: | 
 | 4013 |          case Iop_ShrN16x4: case Iop_Sub8x8: case Iop_Sub32x2: | 
 | 4014 |          case Iop_QSub8Sx8: case Iop_QSub16Sx4: case Iop_QSub8Ux8: | 
 | 4015 |          case Iop_QSub16Ux4: case Iop_Sub16x4: case Iop_InterleaveHI8x8: | 
 | 4016 |          case Iop_InterleaveHI32x2: case Iop_InterleaveHI16x4: | 
 | 4017 |          case Iop_InterleaveLO8x8: case Iop_InterleaveLO32x2: | 
 | 4018 |          case Iop_InterleaveLO16x4: case Iop_SarN8x8: | 
 | 4019 |          case Iop_Perm8x8: case Iop_ShlN8x8: case Iop_Mul32x2: | 
 | 4020 |          case Iop_CatEvenLanes16x4: case Iop_CatOddLanes16x4: | 
 | 4021 |          n64: | 
 | 4022 |             assign( 'I', pce, dstv, mkU64( (UWord)NONPTR )); | 
 | 4023 |             break; | 
 | 4024 |  | 
 | 4025 |          default: | 
 | 4026 |             VG_(printf)("instrument_arithop(64-bit): unhandled: "); | 
 | 4027 |             ppIROp(op); | 
 | 4028 |             tl_assert(0); | 
 | 4029 |       } | 
 | 4030 |    } | 
 | 4031 | } | 
 | 4032 |  | 
 | 4033 | static  | 
 | 4034 | void gen_call_nonptr_or_unknown_range ( PCEnv* pce, | 
 | 4035 |                                         IRAtom* addr, IRAtom* len ) | 
 | 4036 | { | 
 | 4037 |    gen_dirty_v_WW( pce,  | 
 | 4038 |                    &nonptr_or_unknown_range, | 
 | 4039 |                    "nonptr_or_unknown_range", | 
 | 4040 |                    addr, len ); | 
 | 4041 | } | 
 | 4042 |  | 
 | 4043 | /* iii describes zero or more non-exact integer register updates.  For | 
 | 4044 |    each one, generate IR to get the containing register, apply | 
 | 4045 |    nonptr_or_unknown to it, and write it back again. */ | 
 | 4046 | static void gen_nonptr_or_unknown_for_III( PCEnv* pce, IntRegInfo* iii ) | 
 | 4047 | { | 
 | 4048 |    Int i; | 
 | 4049 |    tl_assert(iii && iii->n_offsets >= 0); | 
 | 4050 |    for (i = 0; i < iii->n_offsets; i++) { | 
 | 4051 |       IRAtom* a1 = assignNew( 'I', pce, pce->gWordTy,  | 
 | 4052 |                               IRExpr_Get( iii->offsets[i], pce->gWordTy )); | 
 | 4053 |       IRTemp a2 = gen_call_nonptr_or_unknown_w( pce, a1 ); | 
 | 4054 |       stmt( 'I', pce, IRStmt_Put( iii->offsets[i]  | 
 | 4055 |                                      + pce->guest_state_sizeB, | 
 | 4056 |                                   mkexpr(a2) )); | 
 | 4057 |    } | 
 | 4058 | } | 
 | 4059 |  | 
 | 4060 | /* Generate into 'ane', instrumentation for 'st'.  Also copy 'st' | 
 | 4061 |    itself into 'ane' (the caller does not do so).  This is somewhat | 
 | 4062 |    complex and relies heavily on the assumption that the incoming IR | 
 | 4063 |    is in flat form. | 
 | 4064 |  | 
 | 4065 |    Generally speaking, the instrumentation is placed after the | 
 | 4066 |    original statement, so that results computed by the original can be | 
 | 4067 |    used in the instrumentation.  However, that isn't safe for memory | 
 | 4068 |    references, since we need the instrumentation (hence bounds check | 
 | 4069 |    and potential error message) to happen before the reference itself, | 
 | 4070 |    as the latter could cause a fault. */ | 
 | 4071 | static void schemeS ( PCEnv* pce, IRStmt* st ) | 
 | 4072 | { | 
 | 4073 |    tl_assert(st); | 
 | 4074 |    tl_assert(isFlatIRStmt(st)); | 
 | 4075 |  | 
 | 4076 |    switch (st->tag) { | 
 | 4077 |  | 
 | 4078 |       case Ist_Dirty: { | 
 | 4079 |          Int i; | 
 | 4080 |          IRDirty* di; | 
 | 4081 |          stmt( 'C', pce, st ); | 
 | 4082 |          /* nasty.  assumes that (1) all helpers are unconditional, | 
 | 4083 |             and (2) all outputs are non-ptr */ | 
 | 4084 |          di = st->Ist.Dirty.details; | 
 | 4085 |          /* deal with the return tmp, if any */ | 
 | 4086 |          if (di->tmp != IRTemp_INVALID | 
 | 4087 |              && typeOfIRTemp(pce->bb->tyenv, di->tmp) == pce->gWordTy) { | 
 | 4088 |             /* di->tmp is shadowed.  Set it to NONPTR. */ | 
 | 4089 |             IRTemp dstv = newShadowTmp( pce, di->tmp ); | 
 | 4090 |             if (pce->gWordTy == Ity_I32) { | 
 | 4091 |               assign( 'I', pce, dstv, mkU32( (UWord)NONPTR )); | 
 | 4092 |             } else { | 
 | 4093 |               assign( 'I', pce, dstv, mkU64( (UWord)NONPTR )); | 
 | 4094 |             } | 
 | 4095 |          } | 
 | 4096 |          /* apply the nonptr_or_unknown technique to any parts of | 
 | 4097 |             the guest state that happen to get written */ | 
 | 4098 |          for (i = 0; i < di->nFxState; i++) { | 
 | 4099 |             IntRegInfo iii; | 
 | 4100 |             tl_assert(di->fxState[i].fx != Ifx_None); | 
 | 4101 |             if (di->fxState[i].fx == Ifx_Read) | 
 | 4102 |                continue; /* this bit is only read -- not interesting */ | 
 | 4103 |             get_IntRegInfo( &iii, di->fxState[i].offset, | 
 | 4104 |                                   di->fxState[i].size ); | 
 | 4105 |             tl_assert(iii.n_offsets >= -1  | 
 | 4106 |                       && iii.n_offsets <= N_INTREGINFO_OFFSETS); | 
 | 4107 |             /* Deal with 3 possible cases, same as with Ist_Put | 
 | 4108 |                elsewhere in this function. */ | 
 | 4109 |             if (iii.n_offsets == -1) { | 
 | 4110 |                /* case (1): exact write of an integer register. */ | 
 | 4111 |                IRAtom* a1 | 
 | 4112 |                   = assignNew( 'I', pce, pce->gWordTy,  | 
 | 4113 |                                IRExpr_Get( iii.offsets[i], pce->gWordTy )); | 
 | 4114 |                IRTemp a2 = gen_call_nonptr_or_unknown_w( pce, a1 ); | 
 | 4115 |                stmt( 'I', pce, IRStmt_Put( iii.offsets[i]  | 
 | 4116 |                                               + pce->guest_state_sizeB, | 
 | 4117 |                                            mkexpr(a2) )); | 
 | 4118 |             } else { | 
 | 4119 |                /* when == 0: case (3): no instrumentation needed */ | 
 | 4120 |                /* when > 0: case (2) .. complex case.  Fish out the | 
 | 4121 |                   stored value for the whole register, heave it | 
 | 4122 |                   through nonptr_or_unknown, and use that as the new | 
 | 4123 |                   shadow value. */ | 
 | 4124 |                tl_assert(iii.n_offsets >= 0  | 
 | 4125 |                          && iii.n_offsets <= N_INTREGINFO_OFFSETS); | 
 | 4126 |                gen_nonptr_or_unknown_for_III( pce, &iii ); | 
 | 4127 |             } | 
 | 4128 |          } /* for (i = 0; i < di->nFxState; i++) */ | 
 | 4129 |          /* finally, deal with memory outputs */ | 
 | 4130 |          if (di->mFx != Ifx_None) { | 
 | 4131 |             tl_assert(di->mAddr && isIRAtom(di->mAddr)); | 
 | 4132 |             tl_assert(di->mSize > 0); | 
 | 4133 |             gen_call_nonptr_or_unknown_range( pce, di->mAddr, | 
 | 4134 |                                               mkIRExpr_HWord(di->mSize)); | 
 | 4135 |          } | 
 | 4136 |          break; | 
 | 4137 |       } | 
 | 4138 |  | 
 | 4139 |       case Ist_NoOp: | 
 | 4140 |          break; | 
 | 4141 |  | 
 | 4142 |       /* nothing interesting in these; just copy them through */ | 
 | 4143 |       case Ist_AbiHint: | 
 | 4144 |       case Ist_MBE: | 
 | 4145 |       case Ist_Exit: | 
 | 4146 |       case Ist_IMark: | 
 | 4147 |          stmt( 'C', pce, st ); | 
 | 4148 |          break; | 
 | 4149 |  | 
 | 4150 |       case Ist_PutI: { | 
 | 4151 |          IRRegArray* descr = st->Ist.PutI.descr; | 
 | 4152 |          stmt( 'C', pce, st ); | 
 | 4153 |          tl_assert(descr && descr->elemTy); | 
 | 4154 |          if (is_integer_guest_reg_array(descr)) { | 
 | 4155 |             /* if this fails, is_integer_guest_reg_array is returning | 
 | 4156 |                bogus results */ | 
 | 4157 |             tl_assert(descr->elemTy == pce->gWordTy); | 
 | 4158 |             stmt( | 
 | 4159 |                'I', pce, | 
 | 4160 |                IRStmt_PutI( | 
 | 4161 |                   mkIRRegArray(descr->base + pce->guest_state_sizeB, | 
 | 4162 |                                descr->elemTy, descr->nElems), | 
 | 4163 |                   st->Ist.PutI.ix, | 
 | 4164 |                   st->Ist.PutI.bias, | 
 | 4165 |                   schemeEw_Atom( pce, st->Ist.PutI.data) | 
 | 4166 |                ) | 
 | 4167 |             ); | 
 | 4168 |          } | 
 | 4169 |          break; | 
 | 4170 |       } | 
 | 4171 |  | 
 | 4172 |       case Ist_Put: { | 
 | 4173 |          /* PUT(offset) = atom */ | 
 | 4174 |          /* 3 cases: | 
 | 4175 |             1. It's a complete write of an integer register.  Get hold of | 
 | 4176 |                'atom's shadow value and write it in the shadow state. | 
 | 4177 |             2. It's a partial write of an integer register.  Let the write | 
 | 4178 |                happen, then fish out the complete register value and see if, | 
 | 4179 |                via range checking, consultation of tea leaves, etc, its | 
 | 4180 |                shadow value can be upgraded to anything useful. | 
 | 4181 |             3. It is none of the above.  Generate no instrumentation. */ | 
 | 4182 |          IntRegInfo iii; | 
 | 4183 |          IRType     ty; | 
 | 4184 |          stmt( 'C', pce, st ); | 
 | 4185 |          ty = typeOfIRExpr(pce->bb->tyenv, st->Ist.Put.data); | 
 | 4186 |          get_IntRegInfo( &iii, st->Ist.Put.offset, | 
 | 4187 |                          sizeofIRType(ty) ); | 
 | 4188 |          if (iii.n_offsets == -1) { | 
 | 4189 |             /* case (1): exact write of an integer register. */ | 
 | 4190 |             tl_assert(ty == pce->gWordTy); | 
 | 4191 |             stmt( 'I', pce, | 
 | 4192 |                        IRStmt_Put( st->Ist.Put.offset | 
 | 4193 |                                       + pce->guest_state_sizeB, | 
 | 4194 |                                    schemeEw_Atom( pce, st->Ist.Put.data)) ); | 
 | 4195 |          } else { | 
 | 4196 |             /* when == 0: case (3): no instrumentation needed */ | 
 | 4197 |             /* when > 0: case (2) .. complex case.  Fish out the | 
 | 4198 |                stored value for the whole register, heave it through | 
 | 4199 |                nonptr_or_unknown, and use that as the new shadow | 
 | 4200 |                value. */ | 
 | 4201 |             tl_assert(iii.n_offsets >= 0  | 
 | 4202 |                       && iii.n_offsets <= N_INTREGINFO_OFFSETS); | 
 | 4203 |             gen_nonptr_or_unknown_for_III( pce, &iii ); | 
 | 4204 |          } | 
 | 4205 |          break; | 
 | 4206 |       } /* case Ist_Put */ | 
 | 4207 |  | 
 | 4208 |       case Ist_Store: { | 
 | 4209 |          /* We have: STle(addr) = data | 
 | 4210 |             if data is int-word sized, do | 
 | 4211 |             check_store4(addr, addr#, data, data#) | 
 | 4212 |             for all other stores | 
 | 4213 |             check_store{1,2}(addr, addr#, data) | 
 | 4214 |  | 
 | 4215 |             The helper actually *does* the store, so that it can do | 
 | 4216 |             the post-hoc ugly hack of inspecting and "improving" the | 
 | 4217 |             shadow data after the store, in the case where it isn't an | 
 | 4218 |             aligned word store. | 
 | 4219 |          */ | 
 | 4220 |          IRExpr* data  = st->Ist.Store.data; | 
 | 4221 |          IRExpr* addr  = st->Ist.Store.addr; | 
 | 4222 |          IRType  d_ty  = typeOfIRExpr(pce->bb->tyenv, data); | 
 | 4223 |          IRExpr* addrv = schemeEw_Atom( pce, addr ); | 
 | 4224 |          if (pce->gWordTy == Ity_I32) { | 
 | 4225 |             /* ------ 32 bit host/guest (cough, cough) ------ */ | 
 | 4226 |             switch (d_ty) { | 
 | 4227 |                /* Integer word case */ | 
 | 4228 |                case Ity_I32: { | 
 | 4229 |                   IRExpr* datav = schemeEw_Atom( pce, data ); | 
 | 4230 |                   gen_dirty_v_WWWW( pce, | 
 | 4231 |                                     &check_store4_P, "check_store4_P", | 
 | 4232 |                                     addr, addrv, data, datav ); | 
 | 4233 |                   break; | 
 | 4234 |                } | 
 | 4235 |                /* Integer subword cases */ | 
 | 4236 |                case Ity_I16: | 
 | 4237 |                   gen_dirty_v_WWW( pce, | 
 | 4238 |                                    &check_store2, "check_store2", | 
 | 4239 |                                    addr, addrv, | 
 | 4240 |                                    uwiden_to_host_word( pce, data )); | 
 | 4241 |                   break; | 
 | 4242 |                case Ity_I8: | 
 | 4243 |                   gen_dirty_v_WWW( pce, | 
 | 4244 |                                    &check_store1, "check_store1", | 
 | 4245 |                                    addr, addrv, | 
 | 4246 |                                    uwiden_to_host_word( pce, data )); | 
 | 4247 |                   break; | 
 | 4248 |                /* 64-bit float.  Pass store data in 2 32-bit pieces. */ | 
 | 4249 |                case Ity_F64: { | 
 | 4250 |                   IRAtom* d64 = assignNew( 'I', pce, Ity_I64, | 
 | 4251 |                                            unop(Iop_ReinterpF64asI64, data) ); | 
 | 4252 |                   IRAtom* dLo32 = assignNew( 'I', pce, Ity_I32, | 
 | 4253 |                                              unop(Iop_64to32, d64) ); | 
 | 4254 |                   IRAtom* dHi32 = assignNew( 'I', pce, Ity_I32, | 
 | 4255 |                                              unop(Iop_64HIto32, d64) ); | 
 | 4256 |                   gen_dirty_v_WWWW( pce, | 
 | 4257 |                                     &check_store8_ms4B_ls4B,  | 
 | 4258 |                                     "check_store8_ms4B_ls4B", | 
 | 4259 |                                     addr, addrv, dHi32, dLo32 ); | 
 | 4260 |                   break; | 
 | 4261 |                } | 
 | 4262 |                /* 32-bit float.  We can just use _store4, but need | 
 | 4263 |                   to futz with the argument type. */ | 
 | 4264 |                case Ity_F32: { | 
 | 4265 |                   IRAtom* i32 = assignNew( 'I', pce, Ity_I32,  | 
 | 4266 |                                            unop(Iop_ReinterpF32asI32, | 
 | 4267 |                                                 data ) ); | 
 | 4268 |                   gen_dirty_v_WWW( pce, | 
 | 4269 |                                    &check_store4, | 
 | 4270 |                                    "check_store4", | 
 | 4271 |                                    addr, addrv, i32 ); | 
 | 4272 |                   break; | 
 | 4273 |                } | 
 | 4274 |                /* 64-bit int.  Pass store data in 2 32-bit pieces. */ | 
 | 4275 |                case Ity_I64: { | 
 | 4276 |                   IRAtom* dLo32 = assignNew( 'I', pce, Ity_I32, | 
 | 4277 |                                              unop(Iop_64to32, data) ); | 
 | 4278 |                   IRAtom* dHi32 = assignNew( 'I', pce, Ity_I32, | 
 | 4279 |                                              unop(Iop_64HIto32, data) ); | 
 | 4280 |                   gen_dirty_v_WWWW( pce, | 
 | 4281 |                                     &check_store8_ms4B_ls4B,  | 
 | 4282 |                                     "check_store8_ms4B_ls4B", | 
 | 4283 |                                     addr, addrv, dHi32, dLo32 ); | 
 | 4284 |                   break; | 
 | 4285 |                } | 
 | 4286 |  | 
 | 4287 |                /* 128-bit vector.  Pass store data in 4 32-bit pieces. | 
 | 4288 |                   This is all very ugly and inefficient, but it is | 
 | 4289 |                   hard to better without considerably complicating the | 
 | 4290 |                   store-handling schemes. */ | 
 | 4291 |                case Ity_V128: { | 
 | 4292 |                   IRAtom* dHi64 = assignNew( 'I', pce, Ity_I64, | 
 | 4293 |                                              unop(Iop_V128HIto64, data) ); | 
 | 4294 |                   IRAtom* dLo64 = assignNew( 'I', pce, Ity_I64, | 
 | 4295 |                                              unop(Iop_V128to64, data) ); | 
 | 4296 |                   IRAtom* w3    = assignNew( 'I', pce, Ity_I32, | 
 | 4297 |                                              unop(Iop_64HIto32, dHi64) ); | 
 | 4298 |                   IRAtom* w2    = assignNew( 'I', pce, Ity_I32, | 
 | 4299 |                                              unop(Iop_64to32, dHi64) ); | 
 | 4300 |                   IRAtom* w1    = assignNew( 'I', pce, Ity_I32, | 
 | 4301 |                                              unop(Iop_64HIto32, dLo64) ); | 
 | 4302 |                   IRAtom* w0    = assignNew( 'I', pce, Ity_I32, | 
 | 4303 |                                              unop(Iop_64to32, dLo64) ); | 
 | 4304 |                   gen_dirty_v_6W( pce, | 
 | 4305 |                                   &check_store16_ms4B_4B_4B_ls4B,  | 
 | 4306 |                                   "check_store16_ms4B_4B_4B_ls4B", | 
 | 4307 |                                   addr, addrv, w3, w2, w1, w0 ); | 
 | 4308 |                   break; | 
 | 4309 |                } | 
 | 4310 |  | 
 | 4311 |  | 
 | 4312 |                default: | 
 | 4313 |                   ppIRType(d_ty); tl_assert(0); | 
 | 4314 |             } | 
 | 4315 |          } else { | 
 | 4316 |             /* ------ 64 bit host/guest (cough, cough) ------ */ | 
 | 4317 |             switch (d_ty) { | 
 | 4318 |                /* Integer word case */ | 
 | 4319 |                case Ity_I64: { | 
 | 4320 |                   IRExpr* datav = schemeEw_Atom( pce, data ); | 
 | 4321 |                   gen_dirty_v_WWWW( pce, | 
 | 4322 |                                     &check_store8_P, "check_store8_P", | 
 | 4323 |                                     addr, addrv, data, datav ); | 
 | 4324 |                   break; | 
 | 4325 |                } | 
 | 4326 |                /* Integer subword cases */ | 
 | 4327 |                case Ity_I32: | 
 | 4328 |                   gen_dirty_v_WWW( pce, | 
 | 4329 |                                    &check_store4, "check_store4", | 
 | 4330 |                                    addr, addrv, | 
 | 4331 |                                    uwiden_to_host_word( pce, data )); | 
 | 4332 |                   break; | 
 | 4333 |                case Ity_I16: | 
 | 4334 |                   gen_dirty_v_WWW( pce, | 
 | 4335 |                                    &check_store2, "check_store2", | 
 | 4336 |                                    addr, addrv, | 
 | 4337 |                                    uwiden_to_host_word( pce, data )); | 
 | 4338 |                   break; | 
 | 4339 |                case Ity_I8: | 
 | 4340 |                   gen_dirty_v_WWW( pce, | 
 | 4341 |                                    &check_store1, "check_store1", | 
 | 4342 |                                    addr, addrv, | 
 | 4343 |                                    uwiden_to_host_word( pce, data )); | 
 | 4344 |                   break; | 
 | 4345 |                /* 128-bit vector.  Pass store data in 2 64-bit pieces. */ | 
 | 4346 |                case Ity_V128: { | 
 | 4347 |                   IRAtom* dHi64 = assignNew( 'I', pce, Ity_I64, | 
 | 4348 |                                              unop(Iop_V128HIto64, data) ); | 
 | 4349 |                   IRAtom* dLo64 = assignNew( 'I', pce, Ity_I64, | 
 | 4350 |                                              unop(Iop_V128to64, data) ); | 
 | 4351 |                   gen_dirty_v_WWWW( pce, | 
 | 4352 |                                     &check_store16_ms8B_ls8B,  | 
 | 4353 |                                     "check_store16_ms8B_ls8B", | 
 | 4354 |                                     addr, addrv, dHi64, dLo64 ); | 
 | 4355 |                   break; | 
 | 4356 |                } | 
 | 4357 |                /* 64-bit float. */ | 
 | 4358 |                case Ity_F64: { | 
 | 4359 |                   IRAtom* dI = assignNew( 'I', pce, Ity_I64,  | 
 | 4360 |                                            unop(Iop_ReinterpF64asI64, | 
 | 4361 |                                                 data ) ); | 
 | 4362 |                   gen_dirty_v_WWW( pce, | 
 | 4363 |                                    &check_store8_all8B, | 
 | 4364 |                                    "check_store8_all8B", | 
 | 4365 |                                    addr, addrv, dI ); | 
 | 4366 |                   break; | 
 | 4367 |                } | 
 | 4368 |                /* 32-bit float.  We can just use _store4, but need | 
 | 4369 |                   to futz with the argument type. */ | 
 | 4370 |                case Ity_F32: { | 
 | 4371 |                   IRAtom* i32 = assignNew( 'I', pce, Ity_I32,  | 
 | 4372 |                                            unop(Iop_ReinterpF32asI32, | 
 | 4373 |                                                 data ) ); | 
 | 4374 |                   IRAtom* i64 = assignNew( 'I', pce, Ity_I64,  | 
 | 4375 |                                            unop(Iop_32Uto64, | 
 | 4376 |                                                 i32 ) ); | 
 | 4377 |                   gen_dirty_v_WWW( pce, | 
 | 4378 |                                    &check_store4, | 
 | 4379 |                                    "check_store4", | 
 | 4380 |                                    addr, addrv, i64 ); | 
 | 4381 |                   break; | 
 | 4382 |                } | 
 | 4383 |                default: | 
 | 4384 |                   ppIRType(d_ty); tl_assert(0); | 
 | 4385 |             } | 
 | 4386 |          } | 
 | 4387 |          /* And don't copy the original, since the helper does the | 
 | 4388 |             store.  Ick. */ | 
 | 4389 |          break; | 
 | 4390 |       } /* case Ist_Store */ | 
 | 4391 |  | 
 | 4392 |       case Ist_WrTmp: { | 
 | 4393 |          /* This is the only place we have to deal with the full | 
 | 4394 |             IRExpr range.  In all other places where an IRExpr could | 
 | 4395 |             appear, we in fact only get an atom (Iex_RdTmp or | 
 | 4396 |             Iex_Const). */ | 
 | 4397 |          IRExpr* e      = st->Ist.WrTmp.data; | 
 | 4398 |          IRType  e_ty   = typeOfIRExpr( pce->bb->tyenv, e ); | 
 | 4399 |          Bool    isWord = e_ty == pce->gWordTy; | 
 | 4400 |          IRTemp  dst    = st->Ist.WrTmp.tmp; | 
 | 4401 |          IRTemp  dstv   = isWord ? newShadowTmp( pce, dst ) | 
 | 4402 |                                  : IRTemp_INVALID; | 
 | 4403 |  | 
 | 4404 |          switch (e->tag) { | 
 | 4405 |  | 
 | 4406 |             case Iex_Const: { | 
 | 4407 |                stmt( 'C', pce, st ); | 
 | 4408 |                if (isWord) | 
 | 4409 |                   assign( 'I', pce, dstv, schemeEw_Atom( pce, e ) ); | 
 | 4410 |                break; | 
 | 4411 |             } | 
 | 4412 |  | 
 | 4413 |             case Iex_CCall: { | 
 | 4414 |                stmt( 'C', pce, st ); | 
 | 4415 |                if (isWord) | 
 | 4416 |                   assign( 'I', pce, dstv, | 
 | 4417 |                           mkexpr( gen_call_nonptr_or_unknown_w(  | 
 | 4418 |                                      pce, mkexpr(dst))));  | 
 | 4419 |                break; | 
 | 4420 |             } | 
 | 4421 |  | 
 | 4422 |             case Iex_Mux0X: { | 
 | 4423 |                /* Just steer the shadow values in the same way as the | 
 | 4424 |                   originals. */ | 
 | 4425 |                stmt( 'C', pce, st ); | 
 | 4426 |                if (isWord) | 
 | 4427 |                   assign( 'I', pce, dstv,  | 
 | 4428 |                           IRExpr_Mux0X( | 
 | 4429 |                              e->Iex.Mux0X.cond, | 
 | 4430 |                              schemeEw_Atom( pce, e->Iex.Mux0X.expr0 ), | 
 | 4431 |                              schemeEw_Atom( pce, e->Iex.Mux0X.exprX ) )); | 
 | 4432 |                break; | 
 | 4433 |             } | 
 | 4434 |  | 
 | 4435 |             case Iex_RdTmp: { | 
 | 4436 |                stmt( 'C', pce, st ); | 
 | 4437 |                if (isWord) | 
 | 4438 |                   assign( 'I', pce, dstv, schemeEw_Atom( pce, e )); | 
 | 4439 |                break; | 
 | 4440 |             } | 
 | 4441 |  | 
 | 4442 |             case Iex_Load: { | 
 | 4443 |                IRExpr* addr  = e->Iex.Load.addr; | 
 | 4444 |                HChar*  h_nm  = NULL; | 
 | 4445 |                void*   h_fn  = NULL; | 
 | 4446 |                IRExpr* addrv = NULL; | 
 | 4447 |                if (pce->gWordTy == Ity_I32) { | 
 | 4448 |                   /* 32 bit host/guest (cough, cough) */ | 
 | 4449 |                   switch (e_ty) { | 
 | 4450 |                      /* Ity_I32: helper returns shadow value. */ | 
 | 4451 |                      case Ity_I32:  h_fn = &check_load4_P; | 
 | 4452 |                                     h_nm = "check_load4_P"; break; | 
 | 4453 |                      /* all others: helper does not return a shadow | 
 | 4454 |                         value. */ | 
 | 4455 |                      case Ity_V128: h_fn = &check_load16; | 
 | 4456 |                                     h_nm = "check_load16"; break; | 
 | 4457 |                      case Ity_I64: | 
 | 4458 |                      case Ity_F64:  h_fn = &check_load8; | 
 | 4459 |                                     h_nm = "check_load8"; break; | 
 | 4460 |                      case Ity_F32:  h_fn = &check_load4; | 
 | 4461 |                                     h_nm = "check_load4"; break; | 
 | 4462 |                      case Ity_I16:  h_fn = &check_load2; | 
 | 4463 |                                     h_nm = "check_load2"; break; | 
 | 4464 |                      case Ity_I8:   h_fn = &check_load1; | 
 | 4465 |                                     h_nm = "check_load1"; break; | 
 | 4466 |                      default: ppIRType(e_ty); tl_assert(0); | 
 | 4467 |                   } | 
 | 4468 |                   addrv = schemeEw_Atom( pce, addr ); | 
 | 4469 |                   if (e_ty == Ity_I32) { | 
 | 4470 |                      assign( 'I', pce, dstv,  | 
 | 4471 |                               mkexpr( gen_dirty_W_WW( pce, h_fn, h_nm, | 
 | 4472 |                                                            addr, addrv )) ); | 
 | 4473 |                   } else { | 
 | 4474 |                      gen_dirty_v_WW( pce, h_fn, h_nm, addr, addrv ); | 
 | 4475 |                   } | 
 | 4476 |                } else { | 
 | 4477 |                   /* 64 bit host/guest (cough, cough) */ | 
 | 4478 |                   switch (e_ty) { | 
 | 4479 |                      /* Ity_I64: helper returns shadow value. */ | 
 | 4480 |                      case Ity_I64:  h_fn = &check_load8_P; | 
 | 4481 |                                     h_nm = "check_load8_P"; break; | 
 | 4482 |                      /* all others: helper does not return a shadow | 
 | 4483 |                         value. */ | 
 | 4484 |                      case Ity_V128: h_fn = &check_load16; | 
 | 4485 |                                     h_nm = "check_load16"; break; | 
 | 4486 |                      case Ity_F64:  h_fn = &check_load8; | 
 | 4487 |                                     h_nm = "check_load8"; break; | 
 | 4488 |                      case Ity_F32: | 
 | 4489 |                      case Ity_I32:  h_fn = &check_load4; | 
 | 4490 |                                     h_nm = "check_load4"; break; | 
 | 4491 |                      case Ity_I16:  h_fn = &check_load2; | 
 | 4492 |                                     h_nm = "check_load2"; break; | 
 | 4493 |                      case Ity_I8:   h_fn = &check_load1; | 
 | 4494 |                                     h_nm = "check_load1"; break; | 
 | 4495 |                      default: ppIRType(e_ty); tl_assert(0); | 
 | 4496 |                   } | 
 | 4497 |                   addrv = schemeEw_Atom( pce, addr ); | 
 | 4498 |                   if (e_ty == Ity_I64) { | 
 | 4499 |                      assign( 'I', pce, dstv,  | 
 | 4500 |                               mkexpr( gen_dirty_W_WW( pce, h_fn, h_nm, | 
 | 4501 |                                                            addr, addrv )) ); | 
 | 4502 |                   } else { | 
 | 4503 |                      gen_dirty_v_WW( pce, h_fn, h_nm, addr, addrv ); | 
 | 4504 |                   } | 
 | 4505 |                } | 
 | 4506 |                /* copy the original -- must happen after the helper call */ | 
 | 4507 |                stmt( 'C', pce, st ); | 
 | 4508 |                break; | 
 | 4509 |             } | 
 | 4510 |  | 
 | 4511 |             case Iex_GetI: { | 
 | 4512 |                IRRegArray* descr = e->Iex.GetI.descr; | 
 | 4513 |                stmt( 'C', pce, st ); | 
 | 4514 |                tl_assert(descr && descr->elemTy); | 
 | 4515 |                if (is_integer_guest_reg_array(descr)) { | 
 | 4516 |                   /* if this fails, is_integer_guest_reg_array is | 
 | 4517 |                      returning bogus results */ | 
 | 4518 |                   tl_assert(isWord); | 
 | 4519 |                   assign( | 
 | 4520 |                      'I', pce, dstv, | 
 | 4521 |                      IRExpr_GetI( | 
 | 4522 |                         mkIRRegArray(descr->base + pce->guest_state_sizeB, | 
 | 4523 |                                      descr->elemTy, descr->nElems), | 
 | 4524 |                         e->Iex.GetI.ix, | 
 | 4525 |                         e->Iex.GetI.bias | 
 | 4526 |                      ) | 
 | 4527 |                   ); | 
 | 4528 |                } | 
 | 4529 |                break; | 
 | 4530 |             } | 
 | 4531 |  | 
 | 4532 |             case Iex_Get: { | 
 | 4533 |                stmt( 'C', pce, st ); | 
 | 4534 |                if (isWord) { | 
 | 4535 |                   /* guest-word-typed tmp assignment, so it will have a | 
 | 4536 |                      shadow tmp, and we must make an assignment to | 
 | 4537 |                      that */ | 
 | 4538 |                   if (is_integer_guest_reg(e->Iex.Get.offset, | 
 | 4539 |                                            sizeofIRType(e->Iex.Get.ty))) { | 
 | 4540 |                      assign( 'I', pce, dstv, | 
 | 4541 |                              IRExpr_Get( e->Iex.Get.offset  | 
 | 4542 |                                             + pce->guest_state_sizeB, | 
 | 4543 |                                          e->Iex.Get.ty) ); | 
 | 4544 |                   } else { | 
 | 4545 |                      if (pce->hWordTy == Ity_I32) { | 
 | 4546 |                         assign( 'I', pce, dstv, mkU32( (UWord)NONPTR )); | 
 | 4547 |                      } else { | 
 | 4548 |                        assign( 'I', pce, dstv, mkU64( (UWord)NONPTR )); | 
 | 4549 |                      } | 
 | 4550 |                   } | 
 | 4551 |                } else { | 
 | 4552 |                   /* tmp isn't guest-word-typed, so isn't shadowed, so | 
 | 4553 |                      generate no instrumentation */ | 
 | 4554 |                } | 
 | 4555 |                break; | 
 | 4556 |             } | 
 | 4557 |  | 
 | 4558 |             case Iex_Unop: { | 
 | 4559 |                stmt( 'C', pce, st ); | 
 | 4560 |                tl_assert(isIRAtom(e->Iex.Unop.arg)); | 
 | 4561 |                if (isWord) | 
 | 4562 |                   instrument_arithop( pce, dst, dstv, e->Iex.Unop.op, | 
 | 4563 |                                       e->Iex.Unop.arg, | 
 | 4564 |                                       NULL, NULL, NULL ); | 
 | 4565 |                break; | 
 | 4566 |             } | 
 | 4567 |  | 
 | 4568 |             case Iex_Binop: { | 
 | 4569 |                stmt( 'C', pce, st ); | 
 | 4570 |                tl_assert(isIRAtom(e->Iex.Binop.arg1)); | 
 | 4571 |                tl_assert(isIRAtom(e->Iex.Binop.arg2)); | 
 | 4572 |                if (isWord) | 
 | 4573 |                   instrument_arithop( pce, dst, dstv, e->Iex.Binop.op, | 
 | 4574 |                                       e->Iex.Binop.arg1, e->Iex.Binop.arg2, | 
 | 4575 |                                       NULL, NULL ); | 
 | 4576 |                break; | 
 | 4577 |             } | 
 | 4578 |  | 
 | 4579 |             case Iex_Triop: { | 
 | 4580 |                stmt( 'C', pce, st ); | 
 | 4581 |                tl_assert(isIRAtom(e->Iex.Triop.arg1)); | 
 | 4582 |                tl_assert(isIRAtom(e->Iex.Triop.arg2)); | 
 | 4583 |                tl_assert(isIRAtom(e->Iex.Triop.arg3)); | 
 | 4584 |                if (isWord) | 
 | 4585 |                   instrument_arithop( pce, dst, dstv, e->Iex.Triop.op, | 
 | 4586 |                                       e->Iex.Triop.arg1, e->Iex.Triop.arg2, | 
 | 4587 |                                       e->Iex.Triop.arg3, NULL ); | 
 | 4588 |                break; | 
 | 4589 |             } | 
 | 4590 |  | 
 | 4591 |             case Iex_Qop: { | 
 | 4592 |                stmt( 'C', pce, st ); | 
 | 4593 |                tl_assert(isIRAtom(e->Iex.Qop.arg1)); | 
 | 4594 |                tl_assert(isIRAtom(e->Iex.Qop.arg2)); | 
 | 4595 |                tl_assert(isIRAtom(e->Iex.Qop.arg3)); | 
 | 4596 |                tl_assert(isIRAtom(e->Iex.Qop.arg4)); | 
 | 4597 |                if (isWord) | 
 | 4598 |                   instrument_arithop( pce, dst, dstv, e->Iex.Qop.op, | 
 | 4599 |                                       e->Iex.Qop.arg1, e->Iex.Qop.arg2, | 
 | 4600 |                                       e->Iex.Qop.arg3, e->Iex.Qop.arg4 ); | 
 | 4601 |                break; | 
 | 4602 |             } | 
 | 4603 |  | 
 | 4604 |             default: | 
 | 4605 |                goto unhandled; | 
 | 4606 |          } /* switch (e->tag) */ | 
 | 4607 |  | 
 | 4608 |          break; | 
 | 4609 |  | 
 | 4610 |       } /* case Ist_WrTmp */ | 
 | 4611 |  | 
 | 4612 |       default: | 
 | 4613 |       unhandled: | 
 | 4614 |          ppIRStmt(st); | 
 | 4615 |          tl_assert(0); | 
 | 4616 |    } | 
 | 4617 | } | 
 | 4618 |  | 
 | 4619 |  | 
 | 4620 | IRSB* h_instrument ( VgCallbackClosure* closure, | 
 | 4621 |                      IRSB* sbIn, | 
 | 4622 |                      VexGuestLayout* layout, | 
 | 4623 |                      VexGuestExtents* vge, | 
 | 4624 |                      IRType gWordTy, IRType hWordTy ) | 
 | 4625 | { | 
 | 4626 |    Bool  verboze = 0||False; | 
 | 4627 |    Int   i /*, j*/; | 
 | 4628 |    PCEnv pce; | 
 | 4629 |    struct _SGEnv* sgenv; | 
 | 4630 |  | 
 | 4631 |    if (gWordTy != hWordTy) { | 
 | 4632 |       /* We don't currently support this case. */ | 
 | 4633 |       VG_(tool_panic)("host/guest word size mismatch"); | 
 | 4634 |    } | 
 | 4635 |  | 
 | 4636 |    /* Check we're not completely nuts */ | 
 | 4637 |    tl_assert(sizeof(UWord)  == sizeof(void*)); | 
 | 4638 |    tl_assert(sizeof(Word)   == sizeof(void*)); | 
 | 4639 |    tl_assert(sizeof(Addr)   == sizeof(void*)); | 
 | 4640 |    tl_assert(sizeof(ULong)  == 8); | 
 | 4641 |    tl_assert(sizeof(Long)   == 8); | 
 | 4642 |    tl_assert(sizeof(Addr64) == 8); | 
 | 4643 |    tl_assert(sizeof(UInt)   == 4); | 
 | 4644 |    tl_assert(sizeof(Int)    == 4); | 
 | 4645 |  | 
 | 4646 |    /* Set up the running environment.  Only .bb is modified as we go | 
 | 4647 |       along. */ | 
 | 4648 |    pce.bb                = deepCopyIRSBExceptStmts(sbIn); | 
 | 4649 |    pce.trace             = verboze; | 
 | 4650 |    pce.n_originalTmps    = sbIn->tyenv->types_used; | 
 | 4651 |    pce.hWordTy           = hWordTy; | 
 | 4652 |    pce.gWordTy           = gWordTy; | 
 | 4653 |    pce.guest_state_sizeB = layout->total_sizeB; | 
 | 4654 |    pce.tmpMap            = LibVEX_Alloc(pce.n_originalTmps * sizeof(IRTemp)); | 
 | 4655 |    for (i = 0; i < pce.n_originalTmps; i++) | 
 | 4656 |       pce.tmpMap[i] = IRTemp_INVALID; | 
 | 4657 |  | 
 | 4658 |    /* Also set up for the sg_ instrumenter.  See comments | 
 | 4659 |       at the top of this instrumentation section for details. */ | 
 | 4660 |    sgenv = sg_instrument_init(); | 
 | 4661 |  | 
 | 4662 |    /* Stay sane.  These two should agree! */ | 
 | 4663 |    tl_assert(layout->total_sizeB == MC_SIZEOF_GUEST_STATE); | 
 | 4664 |  | 
 | 4665 |    /* Copy verbatim any IR preamble preceding the first IMark */ | 
 | 4666 |  | 
 | 4667 |    i = 0; | 
 | 4668 |    while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) { | 
 | 4669 |       IRStmt* st = sbIn->stmts[i]; | 
 | 4670 |       tl_assert(st); | 
 | 4671 |       tl_assert(isFlatIRStmt(st)); | 
 | 4672 |       stmt( 'C', &pce, sbIn->stmts[i] ); | 
 | 4673 |       i++; | 
 | 4674 |    } | 
 | 4675 |  | 
 | 4676 |    /* Nasty problem.  IR optimisation of the pre-instrumented IR may | 
 | 4677 |       cause the IR following the preamble to contain references to IR | 
 | 4678 |       temporaries defined in the preamble.  Because the preamble isn't | 
 | 4679 |       instrumented, these temporaries don't have any shadows. | 
 | 4680 |       Nevertheless uses of them following the preamble will cause | 
 | 4681 |       memcheck to generate references to their shadows.  End effect is | 
 | 4682 |       to cause IR sanity check failures, due to references to | 
 | 4683 |       non-existent shadows.  This is only evident for the complex | 
 | 4684 |       preambles used for function wrapping on TOC-afflicted platforms | 
 | 4685 |       (ppc64-linux, ppc32-aix5, ppc64-aix5). | 
 | 4686 |  | 
 | 4687 |       The following loop therefore scans the preamble looking for | 
 | 4688 |       assignments to temporaries.  For each one found it creates an | 
 | 4689 |       assignment to the corresponding shadow temp, marking it as | 
 | 4690 |       'defined'.  This is the same resulting IR as if the main | 
 | 4691 |       instrumentation loop before had been applied to the statement | 
 | 4692 |       'tmp = CONSTANT'. | 
 | 4693 |    */ | 
 | 4694 | #if 0 | 
 | 4695 |    // FIXME: this isn't exactly right; only needs to generate shadows | 
 | 4696 |    // for guest-word-typed temps | 
 | 4697 |    for (j = 0; j < i; j++) { | 
 | 4698 |       if (sbIn->stmts[j]->tag == Ist_WrTmp) { | 
 | 4699 |          /* findShadowTmpV checks its arg is an original tmp; | 
 | 4700 |             no need to assert that here. */ | 
 | 4701 |          IRTemp tmp_o = sbIn->stmts[j]->Ist.WrTmp.tmp; | 
 | 4702 |          IRTemp tmp_s = findShadowTmp(&pce, tmp_o); | 
 | 4703 |          IRType ty_s  = typeOfIRTemp(sbIn->tyenv, tmp_s); | 
 | 4704 |          assign( 'V', &pce, tmp_s, definedOfType( ty_s ) ); | 
 | 4705 |          if (0) { | 
 | 4706 |             VG_(printf)("create shadow tmp for preamble tmp [%d] ty ", j); | 
 | 4707 |             ppIRType( ty_s ); | 
 | 4708 |             VG_(printf)("\n"); | 
 | 4709 |          } | 
 | 4710 |       } | 
 | 4711 |    } | 
 | 4712 | #endif | 
 | 4713 |  | 
 | 4714 |    /* Iterate over the remaining stmts to generate instrumentation. */ | 
 | 4715 |  | 
 | 4716 |    tl_assert(sbIn->stmts_used > 0); | 
 | 4717 |    tl_assert(i >= 0); | 
 | 4718 |    tl_assert(i < sbIn->stmts_used); | 
 | 4719 |    tl_assert(sbIn->stmts[i]->tag == Ist_IMark); | 
 | 4720 |  | 
 | 4721 |    for (/*use current i*/; i < sbIn->stmts_used; i++) { | 
 | 4722 |       /* generate sg_ instrumentation for this stmt */ | 
 | 4723 |       sg_instrument_IRStmt( sgenv, pce.bb, sbIn->stmts[i], | 
 | 4724 |                             layout, gWordTy, hWordTy ); | 
 | 4725 |       /* generate h_ instrumentation for this stmt */ | 
 | 4726 |       schemeS( &pce, sbIn->stmts[i] ); | 
 | 4727 |    } | 
 | 4728 |  | 
 | 4729 |    /* generate sg_ instrumentation for the final jump */ | 
 | 4730 |    sg_instrument_final_jump( sgenv, pce.bb, sbIn->next, sbIn->jumpkind, | 
 | 4731 |                              layout, gWordTy, hWordTy ); | 
 | 4732 |  | 
 | 4733 |    /* and finalise .. */ | 
 | 4734 |    sg_instrument_fini( sgenv ); | 
 | 4735 |  | 
 | 4736 |    return pce.bb; | 
 | 4737 | } | 
 | 4738 |  | 
 | 4739 |  | 
 | 4740 | /*--------------------------------------------------------------------*/ | 
 | 4741 | /*--- Initialisation                                               ---*/ | 
 | 4742 | /*--------------------------------------------------------------------*/ | 
 | 4743 |  | 
 | 4744 | void h_pre_clo_init ( void ) | 
 | 4745 | { | 
 | 4746 |    // Other initialisation | 
 | 4747 |    init_shadow_memory(); | 
 | 4748 |    init_lossage(); | 
 | 4749 | } | 
 | 4750 |  | 
 | 4751 | void h_post_clo_init ( void ) | 
 | 4752 | { | 
 | 4753 | } | 
 | 4754 |  | 
 | 4755 | /*--------------------------------------------------------------------*/ | 
 | 4756 | /*--- Finalisation                                                 ---*/ | 
 | 4757 | /*--------------------------------------------------------------------*/ | 
 | 4758 |  | 
 | 4759 | void h_fini ( Int exitcode ) | 
 | 4760 | { | 
 | 4761 |    if (VG_(clo_verbosity) >= 2) { | 
 | 4762 |       VG_(message)(Vg_DebugMsg, | 
 | 4763 |                    "  h_:  %'10llu client allocs, %'10llu client frees",  | 
 | 4764 |                    stats__client_mallocs, stats__client_frees); | 
 | 4765 |       VG_(message)(Vg_DebugMsg, | 
 | 4766 |                    "  h_:  %'10llu Segs allocd,   %'10llu Segs recycled",  | 
 | 4767 |                    stats__segs_allocd, stats__segs_recycled); | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 4768 |    } | 
 | 4769 |  | 
| sewardj | 4815eb5 | 2008-10-20 23:33:49 +0000 | [diff] [blame] | 4770 | #if 0 | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 4771 |    if (h_clo_lossage_check) { | 
 | 4772 |       VG_(message)(Vg_UserMsg, ""); | 
 | 4773 |       VG_(message)(Vg_UserMsg, "%12lld total memory references", | 
 | 4774 |                                stats__tot_mem_refs); | 
 | 4775 |       VG_(message)(Vg_UserMsg, "%12lld   of which are in a known segment", | 
 | 4776 |                                stats__refs_in_a_seg); | 
 | 4777 |       VG_(message)(Vg_UserMsg, "%12lld   of which are 'lost' w.r.t the seg", | 
 | 4778 |                                stats__refs_lost_seg); | 
 | 4779 |       VG_(message)(Vg_UserMsg, ""); | 
 | 4780 |       show_lossage(); | 
 | 4781 |       VG_(message)(Vg_UserMsg, ""); | 
 | 4782 |    } else { | 
 | 4783 |       tl_assert( 0 == VG_(OSetGen_Size)(lossage) ); | 
 | 4784 |    } | 
| sewardj | 4815eb5 | 2008-10-20 23:33:49 +0000 | [diff] [blame] | 4785 | #endif | 
| sewardj | 024598e | 2008-09-18 14:43:05 +0000 | [diff] [blame] | 4786 | } | 
 | 4787 |  | 
 | 4788 |  | 
 | 4789 | /*--------------------------------------------------------------------*/ | 
 | 4790 | /*--- end                                                 h_main.c ---*/ | 
 | 4791 | /*--------------------------------------------------------------------*/ |