1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- The address space manager: segment initialisation and ---*/ 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- tracking, stack operations ---*/ 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Implementation for Linux (and Darwin!) m_aspacemgr-linux.c ---*/ 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This file is part of Valgrind, a dynamic binary instrumentation 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown framework. 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Copyright (C) 2000-2010 Julian Seward 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown jseward@acm.org 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is free software; you can redistribute it and/or 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown modify it under the terms of the GNU General Public License as 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown published by the Free Software Foundation; either version 2 of the 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown License, or (at your option) any later version. 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is distributed in the hope that it will be useful, but 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WITHOUT ANY WARRANTY; without even the implied warranty of 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown General Public License for more details. 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown You should have received a copy of the GNU General Public License 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown along with this program; if not, write to the Free Software 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 02111-1307, USA. 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The GNU General Public License is contained in the file COPYING. 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_linux) || defined(VGO_darwin) 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ************************************************************* 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DO NOT INCLUDE ANY OTHER FILES HERE. 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ADD NEW INCLUDES ONLY TO priv_aspacemgr.h 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AND THEN ONLY AFTER READING DIRE WARNINGS THERE TOO. 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ************************************************************* */ 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_aspacemgr.h" 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "config.h" 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Note: many of the exported functions implemented below are 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown described more fully in comments in pub_core_aspacemgr.h. 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Overview. ---*/ 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Purpose 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~~~~~~~ 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The purpose of the address space manager (aspacem) is: 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (1) to record the disposition of all parts of the process' address 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown space at all times. 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (2) to the extent that it can, influence layout in ways favourable 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to our purposes. 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown It is important to appreciate that whilst it can and does attempt 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to influence layout, and usually succeeds, it isn't possible to 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown impose absolute control: in the end, the kernel is the final 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown arbiter, and can always bounce our requests. 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Strategy 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~~~~~~~~ 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The strategy is therefore as follows: 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Track ownership of mappings. Each one can belong either to 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Valgrind or to the client. 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Try to place the client's fixed and hinted mappings at the 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown requested addresses. Fixed mappings are allowed anywhere except 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown in areas reserved by Valgrind; the client can trash its own 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mappings if it wants. Hinted mappings are allowed providing they 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fall entirely in free areas; if not, they will be placed by 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem in a free area. 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Anonymous mappings are allocated so as to keep Valgrind and 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown client areas widely separated when possible. If address space 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown runs low, then they may become intermingled: aspacem will attempt 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to use all possible space. But under most circumstances lack of 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown address space is not a problem and so the areas will remain far 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown apart. 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Searches for client space start at aspacem_cStart and will wrap 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown around the end of the available space if needed. Searches for 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Valgrind space start at aspacem_vStart and will also wrap around. 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Because aspacem_cStart is approximately at the start of the 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown available space and aspacem_vStart is approximately in the 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown middle, for the most part the client anonymous mappings will be 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown clustered towards the start of available space, and Valgrind ones 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown in the middle. 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The available space is delimited by aspacem_minAddr and 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_maxAddr. aspacem is flexible and can operate with these 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown at any (sane) setting. For 32-bit Linux, aspacem_minAddr is set 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to some low-ish value at startup (64M) and aspacem_maxAddr is 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown derived from the stack pointer at system startup. This seems a 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown reliable way to establish the initial boundaries. 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 64-bit Linux is similar except for the important detail that the 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown upper boundary is set to 32G. The reason is so that all 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown anonymous mappings (basically all client data areas) are kept 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown below 32G, since that is the maximum range that memcheck can 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown track shadow memory using a fast 2-level sparse array. It can go 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown beyond that but runs much more slowly. The 32G limit is 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown arbitrary and is trivially changed. So, with the current 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown settings, programs on 64-bit Linux will appear to run out of 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown address space and presumably fail at the 32G limit. Given the 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 9/8 space overhead of Memcheck, that means you should be able to 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown memcheckify programs that use up to about 14G natively. 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Note that the aspacem_minAddr/aspacem_maxAddr limits apply only to 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown anonymous mappings. The client can still do fixed and hinted maps 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown at any addresses provided they do not overlap Valgrind's segments. 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This makes Valgrind able to load prelinked .so's at their requested 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown addresses on 64-bit platforms, even if they are very high (eg, 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 112TB). 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown At startup, aspacem establishes the usable limits, and advises 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_main to place the client stack at the top of the range, which on 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a 32-bit machine will be just below the real initial stack. One 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown effect of this is that self-hosting sort-of works, because an inner 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown valgrind will then place its client's stack just below its own 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown initial stack. 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The segment array and segment kinds 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The central data structure is the segment array (segments[0 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown .. nsegments_used-1]). This covers the entire address space in 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown order, giving account of every byte of it. Free spaces are 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown represented explicitly as this makes many operations simpler. 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Mergeable adjacent segments are aggressively merged so as to create 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a "normalised" representation (preen_nsegments). 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown There are 7 (mutually-exclusive) segment kinds, the meaning of 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown which is important: 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SkFree: a free space, which may be allocated either to Valgrind (V) 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown or the client (C). 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SkAnonC: an anonymous mapping belonging to C. For these, aspacem 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tracks a boolean indicating whether or not is is part of the 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown client's heap area (can't remember why). 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SkFileC: a file mapping belonging to C. 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SkShmC: a shared memory segment belonging to C. 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SkAnonV: an anonymous mapping belonging to V. These cover all V's 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown dynamic memory needs, including non-client malloc/free areas, 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown shadow memory, and the translation cache. 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SkFileV: a file mapping belonging to V. As far as I know these are 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown only created transiently for the purposes of reading debug info. 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SkResvn: a reservation segment. 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown These are mostly straightforward. Reservation segments have some 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown subtlety, however. 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown A reservation segment is unmapped from the kernel's point of view, 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown but is an area in which aspacem will not create anonymous maps 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (either Vs or Cs). The idea is that we will try to keep it clear 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown when the choice to do so is ours. Reservation segments are 174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 'invisible' from the client's point of view: it may choose to park 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a fixed mapping in the middle of one, and that's just tough -- we 176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown can't do anything about that. From the client's perspective 177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown reservations are semantically equivalent to (although 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown distinguishable from, if it makes enquiries) free areas. 179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Reservations are a primitive mechanism provided for whatever 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown purposes the rest of the system wants. Currently they are used to 182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown reserve the expansion space into which a growdown stack is 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown expanded, and into which the data segment is extended. Note, 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown though, those uses are entirely external to this module, which only 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown supplies the primitives. 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Reservations may be shrunk in order that an adjoining anonymous 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mapping may be extended. This makes dataseg/stack expansion work. 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown A reservation may not be shrunk below one page. 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The advise/notify concept 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~~~~~~~~~~~~~~~~~~~~~~~~~ 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown All mmap-related calls must be routed via aspacem. Calling 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sys_mmap directly from the rest of the system is very dangerous 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown because aspacem's data structures will become out of date. 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The fundamental mode of operation of aspacem is to support client 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mmaps. Here's what happens (in ML_(generic_PRE_sys_mmap)): 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * m_syswrap intercepts the mmap call. It examines the parameters 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown and identifies the requested placement constraints. There are 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown three possibilities: no constraint (MAny), hinted (MHint, "I 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown prefer X but will accept anything"), and fixed (MFixed, "X or 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nothing"). 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This request is passed to VG_(am_get_advisory). This decides on 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a placement as described in detail in Strategy above. It may 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown also indicate that the map should fail, because it would trash 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown one of Valgrind's areas, which would probably kill the system. 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Control returns to the wrapper. If VG_(am_get_advisory) has 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown declared that the map should fail, then it must be made to do so. 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Usually, though, the request is considered acceptable, in which 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case an "advised" address is supplied. The advised address 215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown replaces the original address supplied by the client, and 216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MAP_FIXED is set. 217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Note at this point that although aspacem has been asked for 219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown advice on where to place the mapping, no commitment has yet been 220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown made by either it or the kernel. 221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * The adjusted request is handed off to the kernel. 223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * The kernel's result is examined. If the map succeeded, aspacem 225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown is told of the outcome (VG_(am_notify_client_mmap)), so it can 226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown update its records accordingly. 227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This then is the central advise-notify idiom for handling client 229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mmap/munmap/mprotect/shmat: 230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * ask aspacem for an advised placement (or a veto) 232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * if not vetoed, hand request to kernel, using the advised placement 234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * examine result, and if successful, notify aspacem of the result. 236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown There are also many convenience functions, eg 238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_mmap_anon_fixed_client), which do both phases entirely within 239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem. 240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown To debug all this, a sync-checker is provided. It reads 242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /proc/self/maps, compares what it sees with aspacem's records, and 243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown complains if there is a difference. --sanity-level=3 runs it before 244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown and after each syscall, which is a powerful, if slow way of finding 245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buggy syscall wrappers. 246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Loss of pointercheck 248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~~~~~~~~~~~~~~~~~~~~ 249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Up to and including Valgrind 2.4.1, x86 segmentation was used to 250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown enforce seperation of V and C, so that wild writes by C could not 251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown trash V. This got called "pointercheck". Unfortunately, the new 252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown more flexible memory layout, plus the need to be portable across 253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown different architectures, means doing this in hardware is no longer 254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown viable, and doing it in software is expensive. So at the moment we 255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown don't do it at all. 256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- The Address Space Manager's state. ---*/ 262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------ start of STATE for the address-space manager ------ */ 266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Max number of segments we can track. */ 268f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov#if defined(VGO_darwin) || defined(ANDROID) 269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define VG_N_SEGMENTS 5000 270f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov#else 271f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov#define VG_N_SEGMENTS 100000 272f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov#endif 273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Max number of segment file names we can track. */ 275f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov#if defined(VGO_darwin) || defined(ANDROID) 276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define VG_N_SEGNAMES 1000 277f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov#else 278f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov#define VG_N_SEGNAMES 100000 279f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov#endif 280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Max length of a segment file name. */ 282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define VG_MAX_SEGNAMELEN 1000 283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef 286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct { 287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool inUse; 288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool mark; 289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar fname[VG_MAX_SEGNAMELEN]; 290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SegName; 292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Filename table. _used is the high water mark; an entry is only 294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown valid if its index >= 0, < _used, and its .inUse field == True. 295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The .mark field is used to garbage-collect dead entries. 296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SegName segnames[VG_N_SEGNAMES]; 298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int segnames_used = 0; 299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Array [0 .. nsegments_used-1] of all mappings. */ 302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Sorted by .addr field. */ 303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* I: len may not be zero. */ 304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* I: overlapping segments are not allowed. */ 305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* I: the segments cover the entire address space precisely. */ 306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Each segment can optionally hold an index into the filename table. */ 307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic NSegment nsegments[VG_N_SEGMENTS]; 309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int nsegments_used = 0; 310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define Addr_MIN ((Addr)0) 312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define Addr_MAX ((Addr)(-1ULL)) 313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Limits etc */ 315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The smallest address that aspacem will try to allocate 317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr aspacem_minAddr = 0; 318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The largest address that aspacem will try to allocate 320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr aspacem_maxAddr = 0; 321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Where aspacem will start looking for client space 323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr aspacem_cStart = 0; 324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Where aspacem will start looking for Valgrind space 326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr aspacem_vStart = 0; 327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define AM_SANITY_CHECK \ 330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown do { \ 331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(clo_sanity_level >= 3)) \ 332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_(am_do_sync_check) \ 333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (__PRETTY_FUNCTION__,__FILE__,__LINE__)); \ 334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } while (0) 335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------ end of STATE for the address-space manager ------ */ 337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------ Forwards decls ------ */ 339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browninline 340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int find_nsegment_idx ( Addr a ); 341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void parse_procselfmaps ( 343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void (*record_mapping)( Addr addr, SizeT len, UInt prot, 344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong dev, ULong ino, Off64T offset, 345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const UChar* filename ), 346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void (*record_gap)( Addr addr, SizeT len ) 347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ----- Hacks to do with the "commpage" on arm-linux ----- */ 350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Not that I have anything against the commpage per se. It's just 351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown that it's not listed in /proc/self/maps, which is a royal PITA -- 352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown we have to fake it up, in parse_procselfmaps. 353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown But note also bug 254556 comment #2: this is now fixed in newer 355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown kernels -- it is listed as a "[vectors]" entry. Presumably the 356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fake entry made here duplicates the [vectors] entry, and so, if at 357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown some point in the future, we can stop supporting buggy kernels, 358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown then this kludge can be removed entirely, since the procmap parser 359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown below will read that entry in the normal way. */ 360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_arm_linux) 361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# define ARM_LINUX_FAKE_COMMPAGE_START 0xFFFF0000 362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# define ARM_LINUX_FAKE_COMMPAGE_END1 0xFFFF1000 363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- SegName array management. ---*/ 369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Searches the filename table to find an index for the given name. 373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown If none is found, an index is allocated and the name stored. If no 374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown space is available we just give up. If the string is too long to 375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown store, return -1. 376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int allocate_segname ( const HChar* name ) 378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, j, len; 380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(name); 382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) VG_(debugLog)(0,"aspacem","allocate_segname %s\n", name); 384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len = VG_(strlen)(name); 386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len >= VG_MAX_SEGNAMELEN-1) { 387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return -1; 388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* first see if we already have the name. */ 391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < segnames_used; i++) { 392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!segnames[i].inUse) 393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0 == VG_(strcmp)(name, &segnames[i].fname[0])) { 395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return i; 396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* no we don't. So look for a free slot. */ 400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < segnames_used; i++) 401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!segnames[i].inUse) 402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i == segnames_used) { 405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* no free slots .. advance the high-water mark. */ 406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (segnames_used+1 < VG_N_SEGNAMES) { 407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = segnames_used; 408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segnames_used++; 409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(am_barf_toolow)("VG_N_SEGNAMES"); 411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* copy it in */ 415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segnames[i].inUse = True; 416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (j = 0; j < len; j++) 417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segnames[i].fname[j] = name[j]; 418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(len < VG_MAX_SEGNAMELEN); 419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segnames[i].fname[len] = 0; 420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return i; 421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Displaying the segment array. ---*/ 427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* show_SegKind ( SegKind sk ) 431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (sk) { 433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkFree: return " "; 434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkAnonC: return "anon"; 435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkAnonV: return "ANON"; 436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkFileC: return "file"; 437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkFileV: return "FILE"; 438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkShmC: return "shm "; 439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkResvn: return "RSVN"; 440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: return "????"; 441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* show_ShrinkMode ( ShrinkMode sm ) 445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (sm) { 447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SmLower: return "SmLower"; 448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SmUpper: return "SmUpper"; 449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SmFixed: return "SmFixed"; 450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: return "Sm?????"; 451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void show_len_concisely ( /*OUT*/HChar* buf, Addr start, Addr end ) 455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar* fmt; 457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong len = ((ULong)end) - ((ULong)start) + 1; 458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len < 10*1000*1000ULL) { 460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fmt = "%7llu"; 461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else if (len < 999999ULL * (1ULL<<20)) { 463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fmt = "%6llum"; 464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len >>= 20; 465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else if (len < 999999ULL * (1ULL<<30)) { 467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fmt = "%6llug"; 468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len >>= 30; 469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else if (len < 999999ULL * (1ULL<<40)) { 471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fmt = "%6llut"; 472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len >>= 40; 473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else { 475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fmt = "%6llue"; 476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len >>= 50; 477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(am_sprintf)(buf, fmt, len); 479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Show full details of an NSegment */ 483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void __attribute__ ((unused)) 485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown show_nsegment_full ( Int logLevel, Int segNo, NSegment* seg ) 486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar len_buf[20]; 488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar* name = "(none)"; 489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (seg->fnIdx >= 0 && seg->fnIdx < segnames_used 491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && segnames[seg->fnIdx].inUse 492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && segnames[seg->fnIdx].fname[0] != 0) 493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown name = segnames[seg->fnIdx].fname; 494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown show_len_concisely(len_buf, seg->start, seg->end); 496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)( 498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown logLevel, "aspacem", 499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "%3d: %s %010llx-%010llx %s %c%c%c%c%c %s " 500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "d=0x%03llx i=%-7lld o=%-7lld (%d) m=%d %s\n", 501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segNo, show_SegKind(seg->kind), 502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)seg->start, (ULong)seg->end, len_buf, 503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-', 504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-', 505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->isCH ? 'H' : '-', 506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown show_ShrinkMode(seg->smode), 507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->dev, seg->ino, seg->offset, seg->fnIdx, 508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (Int)seg->mark, name 509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Show an NSegment in a user-friendly-ish way. */ 514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void show_nsegment ( Int logLevel, Int segNo, NSegment* seg ) 516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar len_buf[20]; 518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown show_len_concisely(len_buf, seg->start, seg->end); 519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (seg->kind) { 521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkFree: 523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)( 524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown logLevel, "aspacem", 525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "%3d: %s %010llx-%010llx %s\n", 526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segNo, show_SegKind(seg->kind), 527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)seg->start, (ULong)seg->end, len_buf 528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkAnonC: case SkAnonV: case SkShmC: 532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)( 533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown logLevel, "aspacem", 534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "%3d: %s %010llx-%010llx %s %c%c%c%c%c\n", 535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segNo, show_SegKind(seg->kind), 536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)seg->start, (ULong)seg->end, len_buf, 537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-', 538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-', 539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->isCH ? 'H' : '-' 540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkFileC: case SkFileV: 544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)( 545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown logLevel, "aspacem", 546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "%3d: %s %010llx-%010llx %s %c%c%c%c%c d=0x%03llx " 547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "i=%-7lld o=%-7lld (%d)\n", 548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segNo, show_SegKind(seg->kind), 549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)seg->start, (ULong)seg->end, len_buf, 550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-', 551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-', 552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->isCH ? 'H' : '-', 553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->dev, seg->ino, seg->offset, seg->fnIdx 554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkResvn: 558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)( 559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown logLevel, "aspacem", 560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "%3d: %s %010llx-%010llx %s %c%c%c%c%c %s\n", 561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segNo, show_SegKind(seg->kind), 562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)seg->start, (ULong)seg->end, len_buf, 563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-', 564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-', 565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->isCH ? 'H' : '-', 566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown show_ShrinkMode(seg->smode) 567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: 571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)( 572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown logLevel, "aspacem", 573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "%3d: ???? UNKNOWN SEGMENT KIND\n", 574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segNo 575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Print out the segment array (debugging only!). */ 581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(am_show_nsegments) ( Int logLevel, HChar* who ) 582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i; 584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(logLevel, "aspacem", 585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "<<< SHOW_SEGMENTS: %s (%d segments, %d segnames)\n", 586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown who, nsegments_used, segnames_used); 587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < segnames_used; i++) { 588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!segnames[i].inUse) 589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(logLevel, "aspacem", 591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "(%2d) %s\n", i, segnames[i].fname); 592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < nsegments_used; i++) 594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown show_nsegment( logLevel, i, &nsegments[i] ); 595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(logLevel, "aspacem", 596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ">>>\n"); 597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get the filename corresponding to this segment, if known and if it 601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown has one. The returned name's storage cannot be assumed to be 602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown persistent, so the caller should immediately copy the name 603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown elsewhere. */ 604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownHChar* VG_(am_get_filename)( NSegment const * seg ) 605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i; 607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(seg); 608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = seg->fnIdx; 609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i < 0 || i >= segnames_used || !segnames[i].inUse) 610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return NULL; 611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return &segnames[i].fname[0]; 613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Collect up the start addresses of all non-free, non-resvn segments. 616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The interface is a bit strange in order to avoid potential 617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment-creation races caused by dynamic allocation of the result 618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buffer *starts. 619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The function first computes how many entries in the result 621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buffer *starts will be needed. If this number <= nStarts, 622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown they are placed in starts[0..], and the number is returned. 623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown If nStarts is not large enough, nothing is written to 624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown starts[0..], and the negation of the size is returned. 625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Correct use of this function may mean calling it multiple times in 627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown order to establish a suitably-sized buffer. */ 628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(am_get_segment_starts)( Addr* starts, Int nStarts ) 630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, j, nSegs; 632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* don't pass dumbass arguments */ 634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nStarts >= 0); 635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nSegs = 0; 637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < nsegments_used; i++) { 638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn) 639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nSegs++; 641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nSegs > nStarts) { 644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* The buffer isn't big enough. Tell the caller how big it needs 645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to be. */ 646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return -nSegs; 647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* There's enough space. So write into the result buffer. */ 650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nSegs <= nStarts); 651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = 0; 653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < nsegments_used; i++) { 654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn) 655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown starts[j] = nsegments[i].start; 657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j++; 658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(j == nSegs); /* this should not fail */ 661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return nSegs; 662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Sanity checking and preening of the segment array. ---*/ 668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Check representational invariants for NSegments. */ 672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool sane_NSegment ( NSegment* s ) 674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s == NULL) return False; 676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* No zero sized segments and no wraparounds. */ 678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s->start >= s->end) return False; 679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* .mark is used for admin purposes only. */ 681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s->mark) return False; 682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* require page alignment */ 684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!VG_IS_PAGE_ALIGNED(s->start)) return False; 685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!VG_IS_PAGE_ALIGNED(s->end+1)) return False; 686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (s->kind) { 688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkFree: 690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s->smode == SmFixed 692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1 693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && !s->hasR && !s->hasW && !s->hasX && !s->hasT 694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && !s->isCH; 695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkAnonC: case SkAnonV: case SkShmC: 697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s->smode == SmFixed 699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1 700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && (s->kind==SkAnonC ? True : !s->isCH); 701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkFileC: case SkFileV: 703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s->smode == SmFixed 705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && (s->fnIdx == -1 || 706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (s->fnIdx >= 0 && s->fnIdx < segnames_used 707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && segnames[s->fnIdx].inUse)) 708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && !s->isCH; 709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkResvn: 711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1 713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && !s->hasR && !s->hasW && !s->hasX && !s->hasT 714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && !s->isCH; 715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: 717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Try merging s2 into s1, if possible. If successful, s1 is 723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown modified, and True is returned. Otherwise s1 is unchanged and 724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown False is returned. */ 725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool maybe_merge_nsegments ( NSegment* s1, NSegment* s2 ) 727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s1->kind != s2->kind) 729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s1->end+1 != s2->start) 732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* reject cases which would cause wraparound */ 735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s1->start > s2->end) 736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (s1->kind) { 739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkFree: 741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s1->end = s2->end; 742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkAnonC: case SkAnonV: 745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s1->hasR == s2->hasR && s1->hasW == s2->hasW 746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && s1->hasX == s2->hasX && s1->isCH == s2->isCH) { 747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s1->end = s2->end; 748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s1->hasT |= s2->hasT; 749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkFileC: case SkFileV: 754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s1->hasR == s2->hasR 755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && s1->hasW == s2->hasW && s1->hasX == s2->hasX 756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && s1->dev == s2->dev && s1->ino == s2->ino 757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && s2->offset == s1->offset 758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown + ((ULong)s2->start) - ((ULong)s1->start) ) { 759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s1->end = s2->end; 760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s1->hasT |= s2->hasT; 761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkShmC: 766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkResvn: 769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s1->smode == SmFixed && s2->smode == SmFixed) { 770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s1->end = s2->end; 771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: 775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Sanity-check and canonicalise the segment array (merge mergable 784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segments). Returns True if any segments were merged. */ 785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool preen_nsegments ( void ) 787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, j, r, w, nsegments_used_old = nsegments_used; 789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Pass 1: check the segment array covers the entire address space 791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown exactly once, and also that each segment is sane. */ 792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments_used > 0); 793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[0].start == Addr_MIN); 794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[nsegments_used-1].end == Addr_MAX); 795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sane_NSegment(&nsegments[0])); 797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 1; i < nsegments_used; i++) { 798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sane_NSegment(&nsegments[i])); 799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[i-1].end+1 == nsegments[i].start); 800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Pass 2: merge as much as possible, using 803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown maybe_merge_segments. */ 804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown w = 0; 805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (r = 1; r < nsegments_used; r++) { 806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (maybe_merge_nsegments(&nsegments[w], &nsegments[r])) { 807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* nothing */ 808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown w++; 810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (w != r) 811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[w] = nsegments[r]; 812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown w++; 815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(w > 0 && w <= nsegments_used); 816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments_used = w; 817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Pass 3: free up unused string table slots */ 819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* clear mark bits */ 820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < segnames_used; i++) 821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segnames[i].mark = False; 822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* mark */ 823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < nsegments_used; i++) { 824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = nsegments[i].fnIdx; 825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(j >= -1 && j < segnames_used); 826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j >= 0) { 827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(segnames[j].inUse); 828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segnames[j].mark = True; 829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* release */ 832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < segnames_used; i++) { 833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (segnames[i].mark == False) { 834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segnames[i].inUse = False; 835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segnames[i].fname[0] = 0; 836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return nsegments_used != nsegments_used_old; 840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Check the segment array corresponds with the kernel's view of 844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown memory layout. sync_check_ok returns True if no anomalies were 845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown found, else False. In the latter case the mismatching segments are 846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown displayed. 847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The general idea is: we get the kernel to show us all its segments 849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown and also the gaps in between. For each such interval, try and find 850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a sequence of appropriate intervals in our segment array which 851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cover or more than cover the kernel's interval, and which all have 852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown suitable kinds/permissions etc. 853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Although any specific kernel interval is not matched exactly to a 855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown valgrind interval or sequence thereof, eventually any disagreement 856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown on mapping boundaries will be detected. This is because, if for 857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown example valgrind's intervals cover a greater range than the current 858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown kernel interval, it must be the case that a neighbouring free-space 859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown interval belonging to valgrind cannot cover the neighbouring 860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown free-space interval belonging to the kernel. So the disagreement 861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown is detected. 862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown In other words, we examine each kernel interval in turn, and check 864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown we do not disagree over the range of that interval. Because all of 865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the address space is examined, any disagreements must eventually be 866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown detected. 867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool sync_check_ok = False; 870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void sync_check_mapping_callback ( Addr addr, SizeT len, UInt prot, 872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong dev, ULong ino, Off64T offset, 873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const UChar* filename ) 874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int iLo, iHi, i; 876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool sloppyXcheck; 877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* If a problem has already been detected, don't continue comparing 879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segments, so as to avoid flooding the output with error 880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown messages. */ 881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if !defined(VGO_darwin) 882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* GrP fixme not */ 883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!sync_check_ok) 884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len == 0) 887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* The kernel should not give us wraparounds. */ 890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(addr <= addr + len - 1); 891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iLo = find_nsegment_idx( addr ); 893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iHi = find_nsegment_idx( addr + len - 1 ); 894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* These 5 should be guaranteed by find_nsegment_idx. */ 896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(0 <= iLo && iLo < nsegments_used); 897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(0 <= iHi && iHi < nsegments_used); 898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(iLo <= iHi); 899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[iLo].start <= addr ); 900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[iHi].end >= addr + len - 1 ); 901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* x86 doesn't differentiate 'x' and 'r' (at least, all except the 903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown most recent NX-bit enabled CPUs) and so recent kernels attempt 904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to provide execute protection by placing all executable mappings 905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown low down in the address space and then reducing the size of the 906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown code segment to prevent code at higher addresses being executed. 907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown These kernels report which mappings are really executable in 909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the /proc/self/maps output rather than mirroring what was asked 910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for when each mapping was created. In order to cope with this we 911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown have a sloppyXcheck mode which we enable on x86 - in this mode we 912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown allow the kernel to report execute permission when we weren't 913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown expecting it but not vice versa. */ 914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if defined(VGA_x86) 915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sloppyXcheck = True; 916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# else 917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sloppyXcheck = False; 918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* NSegments iLo .. iHi inclusive should agree with the presented 921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown data. */ 922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = iLo; i <= iHi; i++) { 923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool same, cmp_offsets, cmp_devino; 925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt seg_prot; 926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* compare the kernel's offering against ours. */ 928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown same = nsegments[i].kind == SkAnonC 929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkAnonV 930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkFileC 931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkFileV 932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkShmC; 933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg_prot = 0; 935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ; 936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE; 937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC; 938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cmp_offsets 940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown = nsegments[i].kind == SkFileC || nsegments[i].kind == SkFileV; 941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cmp_devino 943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown = nsegments[i].dev != 0 || nsegments[i].ino != 0; 944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Consider other reasons to not compare dev/inode */ 946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_linux) 947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* bproc does some godawful hack on /dev/zero at process 948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown migration, which changes the name of it, and its dev & ino */ 949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (filename && 0==VG_(strcmp)(filename, "/dev/zero (deleted)")) 950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cmp_devino = False; 951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* hack apparently needed on MontaVista Linux */ 953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (filename && VG_(strstr)(filename, "/.lib-ro/")) 954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cmp_devino = False; 955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_darwin) 958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // GrP fixme kernel info doesn't have dev/inode 959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cmp_devino = False; 960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // GrP fixme V and kernel don't agree on offsets 962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cmp_offsets = False; 963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* If we are doing sloppy execute permission checks then we 966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown allow segment to have X permission when we weren't expecting 967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown it (but not vice versa) so if the kernel reported execute 968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown permission then pretend that this segment has it regardless 969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown of what we were expecting. */ 970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sloppyXcheck && (prot & VKI_PROT_EXEC) != 0) { 971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg_prot |= VKI_PROT_EXEC; 972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown same = same 975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && seg_prot == prot 976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && (cmp_devino 977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ? (nsegments[i].dev == dev && nsegments[i].ino == ino) 978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : True) 979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && (cmp_offsets 980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ? nsegments[i].start-nsegments[i].offset == addr-offset 981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : True); 982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!same) { 983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr start = addr; 984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr end = start + len - 1; 985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar len_buf[20]; 986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown show_len_concisely(len_buf, start, end); 987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sync_check_ok = False; 989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)( 991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0,"aspacem", 992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "segment mismatch: V's seg 1st, kernel's 2nd:\n"); 993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown show_nsegment_full( 0, i, &nsegments[i] ); 994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0,"aspacem", 995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "...: .... %010llx-%010llx %s %c%c%c.. ....... " 996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "d=0x%03llx i=%-7lld o=%-7lld (.) m=. %s\n", 997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)start, (ULong)end, len_buf, 998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown prot & VKI_PROT_READ ? 'r' : '-', 999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown prot & VKI_PROT_WRITE ? 'w' : '-', 1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown prot & VKI_PROT_EXEC ? 'x' : '-', 1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown dev, ino, offset, filename ? (HChar*)filename : "(none)" ); 1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Looks harmless. Keep going. */ 1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void sync_check_gap_callback ( Addr addr, SizeT len ) 1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int iLo, iHi, i; 1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* If a problem has already been detected, don't continue comparing 1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segments, so as to avoid flooding the output with error 1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown messages. */ 1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if !defined(VGO_darwin) 1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* GrP fixme not */ 1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!sync_check_ok) 1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len == 0) 1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* The kernel should not give us wraparounds. */ 1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(addr <= addr + len - 1); 1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iLo = find_nsegment_idx( addr ); 1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iHi = find_nsegment_idx( addr + len - 1 ); 1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* These 5 should be guaranteed by find_nsegment_idx. */ 1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(0 <= iLo && iLo < nsegments_used); 1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(0 <= iHi && iHi < nsegments_used); 1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(iLo <= iHi); 1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[iLo].start <= addr ); 1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[iHi].end >= addr + len - 1 ); 1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* NSegments iLo .. iHi inclusive should agree with the presented 1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown data. */ 1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = iLo; i <= iHi; i++) { 1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool same; 1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* compare the kernel's offering against ours. */ 1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown same = nsegments[i].kind == SkFree 1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkResvn; 1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!same) { 1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr start = addr; 1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr end = start + len - 1; 1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar len_buf[20]; 1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown show_len_concisely(len_buf, start, end); 1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sync_check_ok = False; 1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)( 1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0,"aspacem", 1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "segment mismatch: V's gap 1st, kernel's 2nd:\n"); 1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown show_nsegment_full( 0, i, &nsegments[i] ); 1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0,"aspacem", 1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown " : .... %010llx-%010llx %s", 1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)start, (ULong)end, len_buf); 1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Looks harmless. Keep going. */ 1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Sanity check: check that Valgrind and the kernel agree on the 1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown address space layout. Prints offending segments and call point if 1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a discrepancy is detected, but does not abort the system. Returned 1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool is False if a discrepancy was found. */ 1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(am_do_sync_check) ( const HChar* fn, 1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const HChar* file, Int line ) 1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sync_check_ok = True; 1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) 1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0,"aspacem", "do_sync_check %s:%d\n", file,line); 1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown parse_procselfmaps( sync_check_mapping_callback, 1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sync_check_gap_callback ); 1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!sync_check_ok) { 1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0,"aspacem", 1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "sync check at %s:%d (%s): FAILED\n", 1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown file, line, fn); 1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0,"aspacem", "\n"); 1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if 0 1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar buf[100]; 1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_show_nsegments)(0,"post syncheck failure"); 1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(sprintf)(buf, "/bin/cat /proc/%d/maps", VG_(getpid)()); 1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(system)(buf); 1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sync_check_ok; 1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Hook to allow sanity checks to be done from aspacemgr-common.c. */ 1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ML_(am_do_sanity_check)( void ) 1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Low level access / modification of the segment array. ---*/ 1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Binary search the interval array for a given address. Since the 1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown array covers the entire address space the search cannot fail. The 1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown _WRK function does the real work. Its caller (just below) caches 1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the results thereof, to save time. With N_CACHE of 63 we get a hit 1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown rate exceeding 90% when running OpenOffice. 1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Re ">> 12", it doesn't matter that the page size of some targets 1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown might be different from 12. Really "(a >> 12) % N_CACHE" is merely 1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a hash function, and the actual cache entry is always validated 1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown correctly against the selected cache entry before use. 1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Don't call find_nsegment_idx_WRK; use find_nsegment_idx instead. */ 1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline)) 1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int find_nsegment_idx_WRK ( Addr a ) 1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr a_mid_lo, a_mid_hi; 1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int mid, 1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lo = 0, 1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown hi = nsegments_used-1; 1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (True) { 1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* current unsearched space is from lo to hi, inclusive. */ 1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (lo > hi) { 1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Not found. This can't happen. */ 1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(am_barf)("find_nsegment_idx: not found"); 1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mid = (lo + hi) / 2; 1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a_mid_lo = nsegments[mid].start; 1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a_mid_hi = nsegments[mid].end; 1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (a < a_mid_lo) { hi = mid-1; continue; } 1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (a > a_mid_hi) { lo = mid+1; continue; } 1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(a >= a_mid_lo && a <= a_mid_hi); 1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(0 <= mid && mid < nsegments_used); 1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return mid; 1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browninline static Int find_nsegment_idx ( Addr a ) 1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# define N_CACHE 63 1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static Addr cache_pageno[N_CACHE]; 1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static Int cache_segidx[N_CACHE]; 1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static Bool cache_inited = False; 1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static UWord n_q = 0; 1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static UWord n_m = 0; 1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UWord ix; 1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (LIKELY(cache_inited)) { 1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* do nothing */ 1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (ix = 0; ix < N_CACHE; ix++) { 1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cache_pageno[ix] = 0; 1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cache_segidx[ix] = -1; 1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cache_inited = True; 1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ix = (a >> 12) % N_CACHE; 1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_q++; 1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0 && 0 == (n_q & 0xFFFF)) 1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0,"xxx","find_nsegment_idx: %lu %lu\n", n_q, n_m); 1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ((a >> 12) == cache_pageno[ix] 1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && cache_segidx[ix] >= 0 1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && cache_segidx[ix] < nsegments_used 1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && nsegments[cache_segidx[ix]].start <= a 1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && a <= nsegments[cache_segidx[ix]].end) { 1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* hit */ 1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* aspacem_assert( cache_segidx[ix] == find_nsegment_idx_WRK(a) ); */ 1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return cache_segidx[ix]; 1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* miss */ 1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_m++; 1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cache_segidx[ix] = find_nsegment_idx_WRK(a); 1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cache_pageno[ix] = a >> 12; 1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return cache_segidx[ix]; 1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# undef N_CACHE 1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Finds the segment containing 'a'. Only returns file/anon/resvn 1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segments. This returns a 'NSegment const *' - a pointer to 1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown readonly data. */ 1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNSegment const * VG_(am_find_nsegment) ( Addr a ) 1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i = find_nsegment_idx(a); 1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(i >= 0 && i < nsegments_used); 1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[i].start <= a); 1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(a <= nsegments[i].end); 1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind == SkFree) 1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return NULL; 1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return &nsegments[i]; 1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given a pointer to a seg, tries to figure out which one it is in 1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[..]. Very paranoid. */ 1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int segAddr_to_index ( NSegment* seg ) 1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i; 1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (seg < &nsegments[0] || seg >= &nsegments[nsegments_used]) 1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return -1; 1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = ((UChar*)seg - (UChar*)(&nsegments[0])) / sizeof(NSegment); 1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i < 0 || i >= nsegments_used) 1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return -1; 1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (seg == &nsegments[i]) 1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return i; 1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return -1; 1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Find the next segment along from 'here', if it is a file/anon/resvn 1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment. */ 1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNSegment const * VG_(am_next_nsegment) ( NSegment* here, Bool fwds ) 1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i = segAddr_to_index(here); 1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i < 0 || i >= nsegments_used) 1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return NULL; 1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fwds) { 1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i++; 1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i >= nsegments_used) 1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return NULL; 1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i--; 1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i < 0) 1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return NULL; 1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (nsegments[i].kind) { 1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkFileC: case SkFileV: case SkShmC: 1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkAnonC: case SkAnonV: case SkResvn: 1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return &nsegments[i]; 1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: 1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return NULL; 1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Trivial fn: return the total amount of space in anonymous mappings, 1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown both for V and the client. Is used for printing stats in 1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown out-of-memory messages. */ 1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong VG_(am_get_anonsize_total)( void ) 1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i; 1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong total = 0; 1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < nsegments_used; i++) { 1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV) { 1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown total += (ULong)nsegments[i].end 1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown - (ULong)nsegments[i].start + 1ULL; 1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return total; 1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Test if a piece of memory is addressable by the client with at 1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown least the "prot" protection permissions by examining the underlying 1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segments. If freeOk is True then SkFree areas are also allowed. 1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic 1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool is_valid_for_client( Addr start, SizeT len, UInt prot, Bool freeOk ) 1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, iLo, iHi; 1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool needR, needW, needX; 1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len == 0) 1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; /* somewhat dubious case */ 1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (start + len < start) 1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; /* reject wraparounds */ 1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown needR = toBool(prot & VKI_PROT_READ); 1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown needW = toBool(prot & VKI_PROT_WRITE); 1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown needX = toBool(prot & VKI_PROT_EXEC); 1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iLo = find_nsegment_idx(start); 1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(start >= nsegments[iLo].start); 1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (start+len-1 <= nsegments[iLo].end) { 1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* This is a speedup hack which avoids calling find_nsegment_idx 1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a second time when possible. It is always correct to just 1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown use the "else" clause below, but is_valid_for_client is 1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown called a lot by the leak checker, so avoiding pointless calls 1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to find_nsegment_idx, which can be expensive, is helpful. */ 1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iHi = iLo; 1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iHi = find_nsegment_idx(start + len - 1); 1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = iLo; i <= iHi; i++) { 1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ( (nsegments[i].kind == SkFileC 1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkAnonC 1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkShmC 1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || (nsegments[i].kind == SkFree && freeOk) 1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || (nsegments[i].kind == SkResvn && freeOk)) 1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && (needR ? nsegments[i].hasR : True) 1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && (needW ? nsegments[i].hasW : True) 1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && (needX ? nsegments[i].hasX : True) ) { 1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* ok */ 1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Test if a piece of memory is addressable by the client with at 1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown least the "prot" protection permissions by examining the underlying 1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segments. */ 1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(am_is_valid_for_client)( Addr start, SizeT len, 1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt prot ) 1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return is_valid_for_client( start, len, prot, False/*free not OK*/ ); 1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Variant of VG_(am_is_valid_for_client) which allows free areas to 1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown be consider part of the client's addressable space. It also 1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown considers reservations to be allowable, since from the client's 1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown point of view they don't exist. */ 1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(am_is_valid_for_client_or_free_or_resvn) 1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ( Addr start, SizeT len, UInt prot ) 1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return is_valid_for_client( start, len, prot, True/*free is OK*/ ); 1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Test if a piece of memory is addressable by valgrind with at least 1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown PROT_NONE protection permissions by examining the underlying 1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segments. */ 1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool is_valid_for_valgrind( Addr start, SizeT len ) 1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, iLo, iHi; 1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len == 0) 1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; /* somewhat dubious case */ 1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (start + len < start) 1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; /* reject wraparounds */ 1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iLo = find_nsegment_idx(start); 1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iHi = find_nsegment_idx(start + len - 1); 1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = iLo; i <= iHi; i++) { 1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind == SkFileV || nsegments[i].kind == SkAnonV) { 1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* ok */ 1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Returns True if any part of the address range is marked as having 1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown translations made from it. This is used to determine when to 1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown discard code, so if in doubt return True. */ 1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool any_Ts_in_range ( Addr start, SizeT len ) 1378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int iLo, iHi, i; 1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(len > 0); 1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(start + len > start); 1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iLo = find_nsegment_idx(start); 1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iHi = find_nsegment_idx(start + len - 1); 1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = iLo; i <= iHi; i++) { 1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].hasT) 1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 1394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Modifying the segment array, and constructing segments. ---*/ 1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Split the segment containing 'a' into two, so that 'a' is 1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown guaranteed to be the start of a new segment. If 'a' is already the 1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown start of a segment, do nothing. */ 1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void split_nsegment_at ( Addr a ) 1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, j; 1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(a > 0); 1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(a)); 1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = find_nsegment_idx(a); 1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(i >= 0 && i < nsegments_used); 1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].start == a) 1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* 'a' is already the start point of a segment, so nothing to be 1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown done. */ 1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* else we have to slide the segments upwards to make a hole */ 1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments_used >= VG_N_SEGMENTS) 1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(am_barf_toolow)("VG_N_SEGMENTS"); 1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (j = nsegments_used-1; j > i; j--) 1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[j+1] = nsegments[j]; 1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments_used++; 1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i+1] = nsegments[i]; 1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i+1].start = a; 1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i].end = a-1; 1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind == SkFileV || nsegments[i].kind == SkFileC) 1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i+1].offset 1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown += ((ULong)nsegments[i+1].start) - ((ULong)nsegments[i].start); 1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sane_NSegment(&nsegments[i])); 1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sane_NSegment(&nsegments[i+1])); 1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Do the minimum amount of segment splitting necessary to ensure that 1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sLo is the first address denoted by some segment and sHi is the 1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown highest address denoted by some other segment. Returns the indices 1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown of the lowest and highest segments in the range. */ 1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic 1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid split_nsegments_lo_and_hi ( Addr sLo, Addr sHi, 1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Int* iLo, 1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Int* iHi ) 1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sLo < sHi); 1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(sLo)); 1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(sHi+1)); 1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sLo > 0) 1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown split_nsegment_at(sLo); 1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sHi < sHi+1) 1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown split_nsegment_at(sHi+1); 1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *iLo = find_nsegment_idx(sLo); 1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *iHi = find_nsegment_idx(sHi); 1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(0 <= *iLo && *iLo < nsegments_used); 1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(0 <= *iHi && *iHi < nsegments_used); 1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(*iLo <= *iHi); 1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[*iLo].start == sLo); 1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[*iHi].end == sHi); 1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Not that I'm overly paranoid or anything, definitely not :-) */ 1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add SEG to the collection, deleting/truncating any it overlaps. 1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This deals with all the tricky cases of splitting up segments as 1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown needed. */ 1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_segment ( NSegment* seg ) 1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, iLo, iHi, delta; 1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool segment_is_sane; 1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr sStart = seg->start; 1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr sEnd = seg->end; 1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sStart <= sEnd); 1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(sStart)); 1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(sEnd+1)); 1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment_is_sane = sane_NSegment(seg); 1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!segment_is_sane) show_nsegment_full(0,-1,seg); 1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(segment_is_sane); 1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown split_nsegments_lo_and_hi( sStart, sEnd, &iLo, &iHi ); 1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Now iLo .. iHi inclusive is the range of segment indices which 1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg will replace. If we're replacing more than one segment, 1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown slide those above the range down to fill the hole. */ 1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delta = iHi - iLo; 1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(delta >= 0); 1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (delta > 0) { 1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = iLo; i < nsegments_used-delta; i++) 1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i] = nsegments[i+delta]; 1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments_used -= delta; 1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[iLo] = *seg; 1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void)preen_nsegments(); 1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) VG_(am_show_nsegments)(0,"AFTER preen (add_segment)"); 1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Clear out an NSegment record. */ 1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void init_nsegment ( /*OUT*/NSegment* seg ) 1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->kind = SkFree; 1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->start = 0; 1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->end = 0; 1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->smode = SmFixed; 1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->dev = 0; 1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->ino = 0; 1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->mode = 0; 1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->offset = 0; 1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->fnIdx = -1; 1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->hasR = seg->hasW = seg->hasX = seg->hasT = seg->isCH = False; 1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->mark = False; 1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Make an NSegment which holds a reservation. */ 1525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void init_resvn ( /*OUT*/NSegment* seg, Addr start, Addr end ) 1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(start < end); 1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(start)); 1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(end+1)); 1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment(seg); 1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->kind = SkResvn; 1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->start = start; 1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->end = end; 1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Startup, including reading /proc/self/maps. ---*/ 1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void read_maps_callback ( Addr addr, SizeT len, UInt prot, 1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong dev, ULong ino, Off64T offset, 1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const UChar* filename ) 1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment( &seg ); 1550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = addr; 1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = addr+len-1; 1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.dev = dev; 1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.ino = ino; 1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.offset = offset; 1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasR = toBool(prot & VKI_PROT_READ); 1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasW = toBool(prot & VKI_PROT_WRITE); 1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasX = toBool(prot & VKI_PROT_EXEC); 1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasT = False; 1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Don't use the presence of a filename to decide if a segment in 1561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the initial /proc/self/maps to decide if the segment is an AnonV 1562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown or FileV segment as some systems don't report the filename. Use 1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the device and inode numbers instead. Fixes bug #124528. */ 1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkAnonV; 1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (dev != 0 && ino != 0) 1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkFileV; 1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if defined(VGO_darwin) 1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // GrP fixme no dev/ino on darwin 1570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (offset != 0) 1571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkFileV; 1572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif // defined(VGO_darwin) 1573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if defined(VGP_arm_linux) 1575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* The standard handling of entries read from /proc/self/maps will 1576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cause the faked up commpage segment to have type SkAnonV, which 1577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown is a problem because it contains code we want the client to 1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown execute, and so later m_translate will segfault the client when 1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown it tries to go in there. Hence change the ownership of it here 1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to the client (SkAnonC). The least-worst kludge I could think 1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown of. */ 1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (addr == ARM_LINUX_FAKE_COMMPAGE_START 1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && addr + len == ARM_LINUX_FAKE_COMMPAGE_END1 1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && seg.kind == SkAnonV) 1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkAnonC; 1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif // defined(VGP_arm_linux) 1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (filename) 1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.fnIdx = allocate_segname( filename ); 1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) show_nsegment( 2,0, &seg ); 1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Initialise the address space manager, setting up the initial 1596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment list, and reading /proc/self/maps into it. This must 1597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown be called before any other function. 1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Takes a pointer to the SP at the time V gained control. This is 1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown taken to be the highest usable address (more or less). Based on 1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown that (and general consultation of tea leaves, etc) return a 1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown suggested end address for the client's stack. */ 1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAddr VG_(am_startup) ( Addr sp_at_startup ) 1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr suggested_clstack_top; 1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sizeof(Word) == sizeof(void*)); 1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sizeof(Addr) == sizeof(void*)); 1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sizeof(SizeT) == sizeof(void*)); 1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sizeof(SSizeT) == sizeof(void*)); 1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Check that we can store the largest imaginable dev, ino and 1615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown offset numbers in an NSegment. */ 1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sizeof(seg.dev) == 8); 1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sizeof(seg.ino) == 8); 1618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sizeof(seg.offset) == 8); 1619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sizeof(seg.mode) == 4); 1620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Add a single interval covering the entire address space. */ 1622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment(&seg); 1623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkFree; 1624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = Addr_MIN; 1625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = Addr_MAX; 1626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[0] = seg; 1627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments_used = 1; 1628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_darwin) 1630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if VG_WORDSIZE == 4 1632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_minAddr = (Addr) 0x00001000; 1633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_maxAddr = (Addr) 0xffffffff; 1634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_cStart = aspacem_minAddr; 1636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_vStart = 0xf0000000; // 0xc0000000..0xf0000000 available 1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# else 1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_minAddr = (Addr) 0x100000000; // 4GB page zero 1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_maxAddr = (Addr) 0x7fffffffffff; 1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_cStart = aspacem_minAddr; 1642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_vStart = 0x700000000000; // 0x7000:00000000..0x7fff:5c000000 avail 1643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // 0x7fff:5c000000..0x7fff:ffe00000? is stack, dyld, shared cache 1644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 1645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown suggested_clstack_top = -1; // ignored; Mach-O specifies its stack 1647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else 1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Establish address limits and block out unusable parts 1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown accordingly. */ 1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(2, "aspacem", 1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown " sp_at_startup = 0x%010llx (supplied)\n", 1655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)sp_at_startup ); 1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_minAddr = (Addr) 0x04000000; // 64M 1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if VG_WORDSIZE == 8 1660f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov aspacem_maxAddr = (Addr)0x8000000000 - 1; // 512G 1661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# ifdef ENABLE_INNER 1662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1; 1663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (aspacem_maxAddr > cse) 1664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_maxAddr = cse; 1665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 1667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# else 1668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1; 1669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 1670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_cStart = aspacem_minAddr; // 64M 1672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_vStart = VG_PGROUNDUP((aspacem_minAddr + aspacem_maxAddr + 1) / 2); 1673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# ifdef ENABLE_INNER 1674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_vStart -= 0x10000000; // 256M 1675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 1676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown suggested_clstack_top = aspacem_maxAddr - 16*1024*1024ULL 1678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown + VKI_PAGE_SIZE; 1679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 1681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr)); 1683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_maxAddr + 1)); 1684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_cStart)); 1685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_vStart)); 1686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(suggested_clstack_top + 1)); 1687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(2, "aspacem", 1689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown " minAddr = 0x%010llx (computed)\n", 1690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)aspacem_minAddr); 1691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(2, "aspacem", 1692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown " maxAddr = 0x%010llx (computed)\n", 1693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)aspacem_maxAddr); 1694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(2, "aspacem", 1695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown " cStart = 0x%010llx (computed)\n", 1696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)aspacem_cStart); 1697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(2, "aspacem", 1698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown " vStart = 0x%010llx (computed)\n", 1699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)aspacem_vStart); 1700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(2, "aspacem", 1701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "suggested_clstack_top = 0x%010llx (computed)\n", 1702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)suggested_clstack_top); 1703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (aspacem_cStart > Addr_MIN) { 1705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_resvn(&seg, Addr_MIN, aspacem_cStart-1); 1706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment(&seg); 1707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (aspacem_maxAddr < Addr_MAX) { 1709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_resvn(&seg, aspacem_maxAddr+1, Addr_MAX); 1710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment(&seg); 1711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Create a 1-page reservation at the notional initial 1714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown client/valgrind boundary. This isn't strictly necessary, but 1715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown because the advisor does first-fit and starts searches for 1716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown valgrind allocations at the boundary, this is kind of necessary 1717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown in order to get it to start allocating in the right place. */ 1718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_resvn(&seg, aspacem_vStart, aspacem_vStart + VKI_PAGE_SIZE - 1); 1719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment(&seg); 1720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_show_nsegments)(2, "Initial layout"); 1722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(2, "aspacem", "Reading /proc/self/maps\n"); 1724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown parse_procselfmaps( read_maps_callback, NULL ); 1725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* NB: on arm-linux, parse_procselfmaps automagically kludges up 1726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (iow, hands to its callbacks) a description of the ARM Commpage, 1727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown since that's not listed in /proc/self/maps (kernel bug IMO). We 1728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown have to fake up its existence in parse_procselfmaps and not 1729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown merely add it here as an extra segment, because doing the latter 1730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown causes sync checking to fail: we see we have an extra segment in 1731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the segments array, which isn't listed in /proc/self/maps. 1732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Hence we must make it appear that /proc/self/maps contained this 1733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment all along. Sigh. */ 1734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_show_nsegments)(2, "With contents of /proc/self/maps"); 1736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 1738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return suggested_clstack_top; 1739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 1743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 1744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- The core query-notify mechanism. ---*/ 1745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 1746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 1747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Query aspacem to ask where a mapping should go. */ 1749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAddr VG_(am_get_advisory) ( MapRequest* req, 1751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool forClient, 1752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Bool* ok ) 1753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* This function implements allocation policy. 1755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The nature of the allocation request is determined by req, which 1757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown specifies the start and length of the request and indicates 1758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown whether the start address is mandatory, a hint, or irrelevant, 1759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown and by forClient, which says whether this is for the client or 1760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for V. 1761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Return values: the request can be vetoed (*ok is set to False), 1763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown in which case the caller should not attempt to proceed with 1764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown making the mapping. Otherwise, *ok is set to True, the caller 1765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown may proceed, and the preferred address at which the mapping 1766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown should happen is returned. 1767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Note that this is an advisory system only: the kernel can in 1769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fact do whatever it likes as far as placement goes, and we have 1770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown no absolute control over it. 1771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Allocations will never be granted in a reserved area. 1773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The Default Policy is: 1775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Search the address space for two free intervals: one of them 1777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown big enough to contain the request without regard to the 1778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown specified address (viz, as if it was a floating request) and 1779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the other being able to contain the request at the specified 1780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown address (viz, as if were a fixed request). Then, depending on 1781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the outcome of the search and the kind of request made, decide 1782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown whether the request is allowable and what address to advise. 1783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The Default Policy is overriden by Policy Exception #1: 1785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown If the request is for a fixed client map, we are prepared to 1787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown grant it providing all areas inside the request are either 1788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown free, reservations, or mappings belonging to the client. In 1789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown other words we are prepared to let the client trash its own 1790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mappings if it wants to. 1791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The Default Policy is overriden by Policy Exception #2: 1793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown If the request is for a hinted client map, we are prepared to 1795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown grant it providing all areas inside the request are either 1796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown free or reservations. In other words we are prepared to let 1797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the client have a hinted mapping anywhere it likes provided 1798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown it does not trash either any of its own mappings or any of 1799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown valgrind's mappings. 1800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 1801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, j; 1802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr holeStart, holeEnd, holeLen; 1803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool fixed_not_required; 1804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr startPoint = forClient ? aspacem_cStart : aspacem_vStart; 1806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr reqStart = req->rkind==MAny ? 0 : req->start; 1808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr reqEnd = reqStart + req->len - 1; 1809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr reqLen = req->len; 1810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* These hold indices for segments found during search, or -1 if not 1812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown found. */ 1813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int floatIdx = -1; 1814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int fixedIdx = -1; 1815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments_used > 0); 1817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) { 1819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_show_nsegments)(0,"getAdvisory"); 1820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0,"aspacem", "getAdvisory 0x%llx %lld\n", 1821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)req->start, (ULong)req->len); 1822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Reject zero-length requests */ 1825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (req->len == 0) { 1826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = False; 1827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 1828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Reject wraparounds */ 1831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ((req->rkind==MFixed || req->rkind==MHint) 1832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && req->start + req->len < req->start) { 1833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = False; 1834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 1835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* ------ Implement Policy Exception #1 ------ */ 1838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (forClient && req->rkind == MFixed) { 1840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int iLo = find_nsegment_idx(reqStart); 1841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int iHi = find_nsegment_idx(reqEnd); 1842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool allow = True; 1843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = iLo; i <= iHi; i++) { 1844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind == SkFree 1845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkFileC 1846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkAnonC 1847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkShmC 1848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkResvn) { 1849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* ok */ 1850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 1851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown allow = False; 1852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 1853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (allow) { 1856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Acceptable. Granted. */ 1857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = True; 1858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return reqStart; 1859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Not acceptable. Fail. */ 1861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = False; 1862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 1863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* ------ Implement Policy Exception #2 ------ */ 1866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (forClient && req->rkind == MHint) { 1868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int iLo = find_nsegment_idx(reqStart); 1869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int iHi = find_nsegment_idx(reqEnd); 1870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool allow = True; 1871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = iLo; i <= iHi; i++) { 1872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind == SkFree 1873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[i].kind == SkResvn) { 1874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* ok */ 1875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 1876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown allow = False; 1877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 1878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (allow) { 1881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Acceptable. Granted. */ 1882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = True; 1883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return reqStart; 1884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Not acceptable. Fall through to the default policy. */ 1886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* ------ Implement the Default Policy ------ */ 1889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Don't waste time looking for a fixed match if not requested to. */ 1891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fixed_not_required = req->rkind == MAny; 1892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = find_nsegment_idx(startPoint); 1894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Examine holes from index i back round to i-1. Record the 1896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown index first fixed hole and the first floating hole which would 1897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown satisfy the request. */ 1898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (j = 0; j < nsegments_used; j++) { 1899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind != SkFree) { 1901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i++; 1902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i >= nsegments_used) i = 0; 1903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 1904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown holeStart = nsegments[i].start; 1907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown holeEnd = nsegments[i].end; 1908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Stay sane .. */ 1910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(holeStart <= holeEnd); 1911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(aspacem_minAddr <= holeStart); 1912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(holeEnd <= aspacem_maxAddr); 1913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* See if it's any use to us. */ 1915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown holeLen = holeEnd - holeStart + 1; 1916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fixedIdx == -1 && holeStart <= reqStart && reqEnd <= holeEnd) 1918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fixedIdx = i; 1919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (floatIdx == -1 && holeLen >= reqLen) 1921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown floatIdx = i; 1922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Don't waste time searching once we've found what we wanted. */ 1924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ((fixed_not_required || fixedIdx >= 0) && floatIdx >= 0) 1925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 1926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i++; 1928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i >= nsegments_used) i = 0; 1929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(fixedIdx >= -1 && fixedIdx < nsegments_used); 1932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fixedIdx >= 0) 1933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[fixedIdx].kind == SkFree); 1934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(floatIdx >= -1 && floatIdx < nsegments_used); 1936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (floatIdx >= 0) 1937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[floatIdx].kind == SkFree); 1938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 1940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Now see if we found anything which can satisfy the request. */ 1942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (req->rkind) { 1943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case MFixed: 1944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fixedIdx >= 0) { 1945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = True; 1946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return req->start; 1947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 1948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = False; 1949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 1950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 1952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case MHint: 1953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fixedIdx >= 0) { 1954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = True; 1955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return req->start; 1956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (floatIdx >= 0) { 1958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = True; 1959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return nsegments[floatIdx].start; 1960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = False; 1962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 1963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case MAny: 1964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (floatIdx >= 0) { 1965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = True; 1966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return nsegments[floatIdx].start; 1967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = False; 1969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 1970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: 1971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 1972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*NOTREACHED*/ 1975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(am_barf)("getAdvisory: unknown request kind"); 1976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ok = False; 1977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 1978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Convenience wrapper for VG_(am_get_advisory) for client floating or 1981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fixed requests. If start is zero, a floating request is issued; if 1982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nonzero, a fixed request at that address is issued. Same comments 1983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown about return values apply. */ 1984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAddr VG_(am_get_advisory_client_simple) ( Addr start, SizeT len, 1986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Bool* ok ) 1987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MapRequest mreq; 1989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mreq.rkind = start==0 ? MAny : MFixed; 1990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mreq.start = start; 1991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mreq.len = len; 1992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(am_get_advisory)( &mreq, True/*client*/, ok ); 1993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Notifies aspacem that the client completed an mmap successfully. 1997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The segment array is updated accordingly. If the returned Bool is 1998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown True, the caller should immediately discard translations from the 1999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown specified address range. */ 2000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool 2002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags, 2003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int fd, Off64T offset ) 2004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar buf[VKI_PATH_MAX]; 2006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong dev, ino; 2007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt mode; 2008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 2009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool needDiscard; 2010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(len > 0); 2012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(a)); 2013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(len)); 2014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(offset)); 2015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Discard is needed if any of the just-trashed range had T. */ 2017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown needDiscard = any_Ts_in_range( a, len ); 2018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment( &seg ); 2020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = (flags & VKI_MAP_ANONYMOUS) ? SkAnonC : SkFileC; 2021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = a; 2022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = a + len - 1; 2023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasR = toBool(prot & VKI_PROT_READ); 2024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasW = toBool(prot & VKI_PROT_WRITE); 2025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasX = toBool(prot & VKI_PROT_EXEC); 2026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!(flags & VKI_MAP_ANONYMOUS)) { 2027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Nb: We ignore offset requests in anonymous mmaps (see bug #126722) 2028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.offset = offset; 2029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) { 2030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.dev = dev; 2031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.ino = ino; 2032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.mode = mode; 2033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) { 2035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.fnIdx = allocate_segname( buf ); 2036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 2039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return needDiscard; 2041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Notifies aspacem that the client completed a shmat successfully. 2044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The segment array is updated accordingly. If the returned Bool is 2045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown True, the caller should immediately discard translations from the 2046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown specified address range. */ 2047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool 2049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVG_(am_notify_client_shmat)( Addr a, SizeT len, UInt prot ) 2050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 2052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool needDiscard; 2053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(len > 0); 2055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(a)); 2056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(len)); 2057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Discard is needed if any of the just-trashed range had T. */ 2059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown needDiscard = any_Ts_in_range( a, len ); 2060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment( &seg ); 2062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkShmC; 2063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = a; 2064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = a + len - 1; 2065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.offset = 0; 2066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasR = toBool(prot & VKI_PROT_READ); 2067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasW = toBool(prot & VKI_PROT_WRITE); 2068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasX = toBool(prot & VKI_PROT_EXEC); 2069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 2070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return needDiscard; 2072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Notifies aspacem that an mprotect was completed successfully. The 2075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment array is updated accordingly. Note, as with 2076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_notify_munmap), it is not the job of this function to reject 2077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stupid mprotects, for example the client doing mprotect of 2078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown non-client areas. Such requests should be intercepted earlier, by 2079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the syscall wrapper for mprotect. This function merely records 2080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown whatever it is told. If the returned Bool is True, the caller 2081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown should immediately discard translations from the specified address 2082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown range. */ 2083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot ) 2085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, iLo, iHi; 2087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool newR, newW, newX, needDiscard; 2088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(start)); 2090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(len)); 2091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len == 0) 2093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown newR = toBool(prot & VKI_PROT_READ); 2096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown newW = toBool(prot & VKI_PROT_WRITE); 2097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown newX = toBool(prot & VKI_PROT_EXEC); 2098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Discard is needed if we're dumping X permission */ 2100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown needDiscard = any_Ts_in_range( start, len ) && !newX; 2101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi ); 2103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iLo = find_nsegment_idx(start); 2105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iHi = find_nsegment_idx(start + len - 1); 2106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = iLo; i <= iHi; i++) { 2108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Apply the permissions to all relevant segments. */ 2109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (nsegments[i].kind) { 2110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkAnonC: case SkAnonV: case SkFileC: case SkFileV: case SkShmC: 2111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i].hasR = newR; 2112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i].hasW = newW; 2113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i].hasX = newX; 2114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sane_NSegment(&nsegments[i])); 2115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 2116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: 2117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 2118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Changing permissions could have made previously un-mergable 2122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segments mergeable. Therefore have to re-preen them. */ 2123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void)preen_nsegments(); 2124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return needDiscard; 2126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Notifies aspacem that an munmap completed successfully. The 2130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment array is updated accordingly. As with 2131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_notify_munmap), we merely record the given info, and don't 2132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown check it for sensibleness. If the returned Bool is True, the 2133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown caller should immediately discard translations from the specified 2134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown address range. */ 2135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(am_notify_munmap)( Addr start, SizeT len ) 2137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 2139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool needDiscard; 2140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(start)); 2141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(len)); 2142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len == 0) 2144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown needDiscard = any_Ts_in_range( start, len ); 2147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment( &seg ); 2149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = start; 2150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = start + len - 1; 2151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* The segment becomes unused (free). Segments from above 2153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_maxAddr were originally SkResvn and so we make them so 2154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown again. Note, this isn't really right when the segment straddles 2155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the aspacem_maxAddr boundary - then really it should be split in 2156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown two, the lower part marked as SkFree and the upper part as 2157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SkResvn. Ah well. */ 2158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (start > aspacem_maxAddr 2159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && /* check previous comparison is meaningful */ 2160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_maxAddr < Addr_MAX) 2161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkResvn; 2162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 2163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ditto for segments from below aspacem_minAddr. */ 2164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (seg.end < aspacem_minAddr && aspacem_minAddr > 0) 2165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkResvn; 2166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 2167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkFree; 2168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 2170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Unmapping could create two adjacent free segments, so a preen is 2172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown needed. add_segment() will do that, so no need to here. */ 2173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return needDiscard; 2175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 2179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 2180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Handling mappings which do not arise directly from the ---*/ 2181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- simulation of the client. ---*/ 2182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 2183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 2184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- --- --- map, unmap, protect --- --- --- */ 2186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map a file at a fixed address for the client, and update the 2188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment array accordingly. */ 2189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(am_mmap_file_fixed_client) 2191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset ) 2192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(am_mmap_named_file_fixed_client)(start, length, prot, fd, offset, NULL); 2194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(am_mmap_named_file_fixed_client) 2197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name ) 2198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres; 2200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 2201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr advised; 2202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool ok; 2203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MapRequest req; 2204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong dev, ino; 2205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt mode; 2206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar buf[VKI_PATH_MAX]; 2207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Not allowable. */ 2209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (length == 0 2210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || !VG_IS_PAGE_ALIGNED(start) 2211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || !VG_IS_PAGE_ALIGNED(offset)) 2212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ask for an advisory. If it's negative, fail immediately. */ 2215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.rkind = MFixed; 2216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.start = start; 2217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.len = length; 2218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown advised = VG_(am_get_advisory)( &req, True/*client*/, &ok ); 2219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!ok || advised != start) 2220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* We have been advised that the mapping is allowable at the 2223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown specified address. So hand it off to the kernel, and propagate 2224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown any resulting failure immediately. */ 2225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // DDD: #warning GrP fixme MAP_FIXED can clobber memory! 2226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = VG_(am_do_mmap_NO_NOTIFY)( 2227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown start, length, prot, 2228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_MAP_FIXED|VKI_MAP_PRIVATE, 2229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fd, offset 2230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 2231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) 2232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_Res(sres) != start) { 2235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* I don't think this can happen. It means the kernel made a 2236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fixed map succeed but not at the requested location. Try to 2237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown repair the damage, then return saying the mapping failed. */ 2238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length ); 2239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ok, the mapping succeeded. Now notify the interval map. */ 2243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment( &seg ); 2244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkFileC; 2245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = start; 2246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = seg.start + VG_PGROUNDUP(length) - 1; 2247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.offset = offset; 2248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasR = toBool(prot & VKI_PROT_READ); 2249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasW = toBool(prot & VKI_PROT_WRITE); 2250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasX = toBool(prot & VKI_PROT_EXEC); 2251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) { 2252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.dev = dev; 2253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.ino = ino; 2254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.mode = mode; 2255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (name) { 2257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.fnIdx = allocate_segname( name ); 2258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) { 2259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.fnIdx = allocate_segname( buf ); 2260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 2262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map anonymously at a fixed address for the client, and update 2269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the segment array accordingly. */ 2270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot ) 2272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres; 2274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 2275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr advised; 2276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool ok; 2277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MapRequest req; 2278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Not allowable. */ 2280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (length == 0 || !VG_IS_PAGE_ALIGNED(start)) 2281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ask for an advisory. If it's negative, fail immediately. */ 2284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.rkind = MFixed; 2285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.start = start; 2286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.len = length; 2287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown advised = VG_(am_get_advisory)( &req, True/*client*/, &ok ); 2288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!ok || advised != start) 2289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* We have been advised that the mapping is allowable at the 2292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown specified address. So hand it off to the kernel, and propagate 2293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown any resulting failure immediately. */ 2294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // DDD: #warning GrP fixme MAP_FIXED can clobber memory! 2295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = VG_(am_do_mmap_NO_NOTIFY)( 2296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown start, length, prot, 2297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 2298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0, 0 2299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 2300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) 2301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_Res(sres) != start) { 2304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* I don't think this can happen. It means the kernel made a 2305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fixed map succeed but not at the requested location. Try to 2306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown repair the damage, then return saying the mapping failed. */ 2307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length ); 2308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ok, the mapping succeeded. Now notify the interval map. */ 2312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment( &seg ); 2313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkAnonC; 2314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = start; 2315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = seg.start + VG_PGROUNDUP(length) - 1; 2316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasR = toBool(prot & VKI_PROT_READ); 2317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasW = toBool(prot & VKI_PROT_WRITE); 2318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasX = toBool(prot & VKI_PROT_EXEC); 2319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 2320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map anonymously at an unconstrained address for the client, and 2327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown update the segment array accordingly. */ 2328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot ) 2330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres; 2332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 2333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr advised; 2334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool ok; 2335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MapRequest req; 2336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Not allowable. */ 2338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (length == 0) 2339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ask for an advisory. If it's negative, fail immediately. */ 2342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.rkind = MAny; 2343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.start = 0; 2344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.len = length; 2345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown advised = VG_(am_get_advisory)( &req, True/*client*/, &ok ); 2346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!ok) 2347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* We have been advised that the mapping is allowable at the 2350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown advised address. So hand it off to the kernel, and propagate 2351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown any resulting failure immediately. */ 2352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // DDD: #warning GrP fixme MAP_FIXED can clobber memory! 2353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = VG_(am_do_mmap_NO_NOTIFY)( 2354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown advised, length, prot, 2355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 2356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0, 0 2357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 2358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) 2359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_Res(sres) != advised) { 2362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* I don't think this can happen. It means the kernel made a 2363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fixed map succeed but not at the requested location. Try to 2364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown repair the damage, then return saying the mapping failed. */ 2365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length ); 2366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ok, the mapping succeeded. Now notify the interval map. */ 2370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment( &seg ); 2371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkAnonC; 2372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = advised; 2373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = seg.start + VG_PGROUNDUP(length) - 1; 2374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasR = toBool(prot & VKI_PROT_READ); 2375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasW = toBool(prot & VKI_PROT_WRITE); 2376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasX = toBool(prot & VKI_PROT_EXEC); 2377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 2378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Similarly, acquire new address space for the client but with 2385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown considerable restrictions on what can be done with it: (1) the 2386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown actual protections may exceed those stated in 'prot', (2) the 2387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown area's protections cannot be later changed using any form of 2388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mprotect, and (3) the area cannot be freed using any form of 2389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown munmap. On Linux this behaves the same as 2390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_mmap_anon_float_client). On AIX5 this *may* allocate memory 2391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown by using sbrk, so as to make use of large pages on AIX. */ 2392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(am_sbrk_anon_float_client) ( SizeT length, Int prot ) 2394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(am_mmap_anon_float_client) ( length, prot ); 2396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map anonymously at an unconstrained address for V, and update the 2400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment array accordingly. This is fundamentally how V allocates 2401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown itself more address space when needed. */ 2402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(am_mmap_anon_float_valgrind)( SizeT length ) 2404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres; 2406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 2407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr advised; 2408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool ok; 2409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MapRequest req; 2410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Not allowable. */ 2412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (length == 0) 2413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ask for an advisory. If it's negative, fail immediately. */ 2416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.rkind = MAny; 2417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.start = 0; 2418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.len = length; 2419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown advised = VG_(am_get_advisory)( &req, False/*valgrind*/, &ok ); 2420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!ok) 2421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// On Darwin, for anonymous maps you can pass in a tag which is used by 2424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// programs like vmmap for statistical purposes. 2425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef VM_TAG_VALGRIND 2426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# define VM_TAG_VALGRIND 0 2427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 2428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* We have been advised that the mapping is allowable at the 2430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown specified address. So hand it off to the kernel, and propagate 2431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown any resulting failure immediately. */ 2432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* GrP fixme darwin: use advisory as a hint only, otherwise syscall in 2433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown another thread can pre-empt our spot. [At one point on the DARWIN 2434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown branch the VKI_MAP_FIXED was commented out; unclear if this is 2435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown necessary or not given the second Darwin-only call that immediately 2436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown follows if this one fails. --njn] */ 2437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = VG_(am_do_mmap_NO_NOTIFY)( 2438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown advised, length, 2439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC, 2440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 2441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VM_TAG_VALGRIND, 0 2442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 2443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_darwin) 2444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) { 2445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* try again, ignoring the advisory */ 2446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = VG_(am_do_mmap_NO_NOTIFY)( 2447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0, length, 2448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC, 2449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*VKI_MAP_FIXED|*/VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 2450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VM_TAG_VALGRIND, 0 2451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 2452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 2454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) 2455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_linux) 2458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_Res(sres) != advised) { 2459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* I don't think this can happen. It means the kernel made a 2460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fixed map succeed but not at the requested location. Try to 2461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown repair the damage, then return saying the mapping failed. */ 2462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length ); 2463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 2466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ok, the mapping succeeded. Now notify the interval map. */ 2468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment( &seg ); 2469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkAnonV; 2470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = sr_Res(sres); 2471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = seg.start + VG_PGROUNDUP(length) - 1; 2472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasR = True; 2473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasW = True; 2474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasX = True; 2475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 2476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */ 2482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* VG_(am_shadow_alloc)(SizeT size) 2484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres = VG_(am_mmap_anon_float_valgrind)( size ); 2486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sr_isError(sres) ? NULL : (void*)sr_Res(sres); 2487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Same comments apply as per VG_(am_sbrk_anon_float_client). On 2490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Linux this behaves the same as VG_(am_mmap_anon_float_valgrind). */ 2491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(am_sbrk_anon_float_valgrind)( SizeT cszB ) 2493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(am_mmap_anon_float_valgrind)( cszB ); 2495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map a file at an unconstrained address for V, and update the 2499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment array accordingly. This is used by V for transiently 2500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mapping in object files to read their debug info. */ 2501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2502f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy StepanovSysRes VG_(am_mmap_file_float_valgrind_with_flags) ( SizeT length, UInt prot, 2503f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov UInt flags, 2504f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov Int fd, Off64T offset ) 2505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres; 2507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 2508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr advised; 2509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool ok; 2510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MapRequest req; 2511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong dev, ino; 2512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt mode; 2513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar buf[VKI_PATH_MAX]; 2514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Not allowable. */ 2516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (length == 0 || !VG_IS_PAGE_ALIGNED(offset)) 2517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ask for an advisory. If it's negative, fail immediately. */ 2520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.rkind = MAny; 2521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.start = 0; 2522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown req.len = length; 2523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown advised = VG_(am_get_advisory)( &req, True/*client*/, &ok ); 2524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!ok) 2525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* We have been advised that the mapping is allowable at the 2528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown specified address. So hand it off to the kernel, and propagate 2529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown any resulting failure immediately. */ 2530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = VG_(am_do_mmap_NO_NOTIFY)( 2531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown advised, length, prot, 2532f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov flags, 2533f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov fd, offset 2534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 2535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) 2536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_Res(sres) != advised) { 2539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* I don't think this can happen. It means the kernel made a 2540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fixed map succeed but not at the requested location. Try to 2541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown repair the damage, then return saying the mapping failed. */ 2542f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov /*TODO(kcc): it apprers this may actually happen if allocating 2543f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov in hugetlbfs. No idea why. */ 2544f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov// (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length ); 2545f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov// return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ok, the mapping succeeded. Now notify the interval map. */ 2549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment( &seg ); 2550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkFileV; 2551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = sr_Res(sres); 2552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = seg.start + VG_PGROUNDUP(length) - 1; 2553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.offset = offset; 2554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasR = toBool(prot & VKI_PROT_READ); 2555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasW = toBool(prot & VKI_PROT_WRITE); 2556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.hasX = toBool(prot & VKI_PROT_EXEC); 2557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) { 2558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.dev = dev; 2559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.ino = ino; 2560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.mode = mode; 2561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) { 2563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.fnIdx = allocate_segname( buf ); 2564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 2566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2571f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy StepanovSysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot, 2572f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov Int fd, Off64T offset ) { 2573f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov return VG_(am_mmap_file_float_valgrind_with_flags) ( 2574f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov length, prot, VKI_MAP_FIXED|VKI_MAP_PRIVATE, fd, offset); 2575f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov} 2576f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov 2577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- --- munmap helper --- --- */ 2579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic 2581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes am_munmap_both_wrk ( /*OUT*/Bool* need_discard, 2582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr start, SizeT len, Bool forClient ) 2583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool d; 2585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres; 2586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!VG_IS_PAGE_ALIGNED(start)) 2588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto eINVAL; 2589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len == 0) { 2591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *need_discard = False; 2592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Success)( 0 ); 2593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (start + len < len) 2596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto eINVAL; 2597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len = VG_PGROUNDUP(len); 2599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(start)); 2600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(len)); 2601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (forClient) { 2603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!VG_(am_is_valid_for_client_or_free_or_resvn) 2604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ( start, len, VKI_PROT_NONE )) 2605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto eINVAL; 2606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 2607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!is_valid_for_valgrind( start, len )) 2608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto eINVAL; 2609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown d = any_Ts_in_range( start, len ); 2612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = ML_(am_do_munmap_NO_NOTIFY)( start, len ); 2614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) 2615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_notify_munmap)( start, len ); 2618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *need_discard = d; 2620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return sres; 2621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown eINVAL: 2623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(mk_SysRes_Error)( VKI_EINVAL ); 2624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Unmap the given address range and update the segment array 2627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown accordingly. This fails if the range isn't valid for the client. 2628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown If *need_discard is True after a successful return, the caller 2629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown should immediately discard translations from the specified address 2630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown range. */ 2631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard, 2633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr start, SizeT len ) 2634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return am_munmap_both_wrk( need_discard, start, len, True/*client*/ ); 2636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Unmap the given address range and update the segment array 2639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown accordingly. This fails if the range isn't valid for valgrind. */ 2640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(am_munmap_valgrind)( Addr start, SizeT len ) 2642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool need_discard; 2644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes r = am_munmap_both_wrk( &need_discard, 2645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown start, len, False/*valgrind*/ ); 2646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* If this assertion fails, it means we allowed translations to be 2647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown made from a V-owned section. Which shouldn't happen. */ 2648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!sr_isError(r)) 2649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(!need_discard); 2650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return r; 2651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Let (start,len) denote an area within a single Valgrind-owned 2654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment (anon or file). Change the ownership of [start, start+len) 2655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to the client instead. Fails if (start,len) does not denote a 2656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown suitable segment. */ 2657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len ) 2659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, iLo, iHi; 2661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len == 0) 2663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 2664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (start + len < start) 2665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!VG_IS_PAGE_ALIGNED(start) || !VG_IS_PAGE_ALIGNED(len)) 2667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = find_nsegment_idx(start); 2670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind != SkFileV && nsegments[i].kind != SkAnonV) 2671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (start+len-1 > nsegments[i].end) 2673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(start >= nsegments[i].start); 2676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(start+len-1 <= nsegments[i].end); 2677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* This scheme is like how mprotect works: split the to-be-changed 2679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown range into its own segment(s), then mess with them (it). There 2680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown should be only one. */ 2681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi ); 2682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(iLo == iHi); 2683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (nsegments[iLo].kind) { 2684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkFileV: nsegments[iLo].kind = SkFileC; break; 2685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case SkAnonV: nsegments[iLo].kind = SkAnonC; break; 2686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: aspacem_assert(0); /* can't happen - guarded above */ 2687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown preen_nsegments(); 2690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 2691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 'seg' must be NULL or have been obtained from 2694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_find_nsegment), and still valid. If non-NULL, and if it 2695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown denotes a SkAnonC (anonymous client mapping) area, set the .isCH 2696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (is-client-heap) flag for that area. Otherwise do nothing. 2697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (Bizarre interface so that the same code works for both Linux and 2698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AIX and does not impose inefficiencies on the Linux version.) */ 2699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(am_set_segment_isCH_if_SkAnonC)( NSegment* seg ) 2700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i = segAddr_to_index( seg ); 2702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(i >= 0 && i < nsegments_used); 2703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind == SkAnonC) { 2704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i].isCH = True; 2705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 2706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[i].isCH == False); 2707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Same idea as VG_(am_set_segment_isCH_if_SkAnonC), except set the 2711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment's hasT bit (has-cached-code) if this is SkFileC or SkAnonC 2712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment. */ 2713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( NSegment* seg ) 2714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i = segAddr_to_index( seg ); 2716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(i >= 0 && i < nsegments_used); 2717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkFileC) { 2718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i].hasT = True; 2719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- --- --- reservations --- --- --- */ 2724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Create a reservation from START .. START+LENGTH-1, with the given 2726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ShrinkMode. When checking whether the reservation can be created, 2727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown also ensure that at least abs(EXTRA) extra free bytes will remain 2728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown above (> 0) or below (< 0) the reservation. 2729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The reservation will only be created if it, plus the extra-zone, 2731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown falls entirely within a single free segment. The returned Bool 2732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown indicates whether the creation succeeded. */ 2733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(am_create_reservation) ( Addr start, SizeT length, 2735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ShrinkMode smode, SSizeT extra ) 2736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int startI, endI; 2738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 2739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* start and end, not taking into account the extra space. */ 2741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr start1 = start; 2742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr end1 = start + length - 1; 2743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* start and end, taking into account the extra space. */ 2745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr start2 = start1; 2746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr end2 = end1; 2747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (extra < 0) start2 += extra; // this moves it down :-) 2749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (extra > 0) end2 += extra; 2750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(start)); 2752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(start+length)); 2753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(start2)); 2754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(end2+1)); 2755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown startI = find_nsegment_idx( start2 ); 2757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown endI = find_nsegment_idx( end2 ); 2758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* If the start and end points don't fall within the same (free) 2760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segment, we're hosed. This does rely on the assumption that all 2761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mergeable adjacent segments can be merged, but add_segment() 2762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown should ensure that. */ 2763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (startI != endI) 2764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[startI].kind != SkFree) 2767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Looks good - make the reservation. */ 2770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[startI].start <= start2); 2771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(end2 <= nsegments[startI].end); 2772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment( &seg ); 2774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkResvn; 2775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = start1; /* NB: extra space is not included in the 2776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown reservation. */ 2777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = end1; 2778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.smode = smode; 2779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 2780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 2783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Let SEG be an anonymous client mapping. This fn extends the 2787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mapping by DELTA bytes, taking the space from a reservation section 2788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown which must be adjacent. If DELTA is positive, the segment is 2789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown extended forwards in the address space, and the reservation must be 2790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the next one along. If DELTA is negative, the segment is extended 2791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown backwards in the address space and the reservation must be the 2792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown previous one. DELTA must be page aligned. abs(DELTA) must not 2793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown exceed the size of the reservation segment minus one page, that is, 2794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the reservation segment after the operation must be at least one 2795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown page long. */ 2796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(am_extend_into_adjacent_reservation_client) ( NSegment* seg, 2798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SSizeT delta ) 2799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int segA, segR; 2801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt prot; 2802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres; 2803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Find the segment array index for SEG. If the assertion fails it 2805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown probably means you passed in a bogus SEG. */ 2806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segA = segAddr_to_index( seg ); 2807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(segA >= 0 && segA < nsegments_used); 2808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[segA].kind != SkAnonC) 2810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (delta == 0) 2813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 2814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown prot = (nsegments[segA].hasR ? VKI_PROT_READ : 0) 2816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown | (nsegments[segA].hasW ? VKI_PROT_WRITE : 0) 2817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown | (nsegments[segA].hasX ? VKI_PROT_EXEC : 0); 2818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(VG_IS_PAGE_ALIGNED(delta<0 ? -delta : delta)); 2820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (delta > 0) { 2822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Extending the segment forwards. */ 2824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segR = segA+1; 2825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (segR >= nsegments_used 2826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[segR].kind != SkResvn 2827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[segR].smode != SmLower 2828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[segR].start != nsegments[segA].end + 1 2829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || delta + VKI_PAGE_SIZE 2830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown > (nsegments[segR].end - nsegments[segR].start + 1)) 2831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Extend the kernel's mapping. */ 2834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // DDD: #warning GrP fixme MAP_FIXED can clobber memory! 2835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = VG_(am_do_mmap_NO_NOTIFY)( 2836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[segR].start, delta, 2837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown prot, 2838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 2839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0, 0 2840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 2841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) 2842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; /* kernel bug if this happens? */ 2843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_Res(sres) != nsegments[segR].start) { 2844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* kernel bug if this happens? */ 2845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta ); 2846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ok, success with the kernel. Update our structures. */ 2850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[segR].start += delta; 2851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[segA].end += delta; 2852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[segR].start <= nsegments[segR].end); 2853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 2855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Extending the segment backwards. */ 2857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delta = -delta; 2858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(delta > 0); 2859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown segR = segA-1; 2861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (segR < 0 2862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[segR].kind != SkResvn 2863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[segR].smode != SmUpper 2864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || nsegments[segR].end + 1 != nsegments[segA].start 2865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || delta + VKI_PAGE_SIZE 2866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown > (nsegments[segR].end - nsegments[segR].start + 1)) 2867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Extend the kernel's mapping. */ 2870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // DDD: #warning GrP fixme MAP_FIXED can clobber memory! 2871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = VG_(am_do_mmap_NO_NOTIFY)( 2872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[segA].start-delta, delta, 2873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown prot, 2874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 2875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0, 0 2876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 2877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) 2878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; /* kernel bug if this happens? */ 2879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_Res(sres) != nsegments[segA].start-delta) { 2880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* kernel bug if this happens? */ 2881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta ); 2882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ok, success with the kernel. Update our structures. */ 2886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[segR].end -= delta; 2887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[segA].start -= delta; 2888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(nsegments[segR].start <= nsegments[segR].end); 2889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 2894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- --- --- resizing/move a mapping --- --- --- */ 2898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if HAVE_MREMAP 2900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Let SEG be a client mapping (anonymous or file). This fn extends 2902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the mapping forwards only by DELTA bytes, and trashes whatever was 2903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown in the new area. Fails if SEG is not a single client mapping or if 2904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the new area is not accessible to the client. Fails if DELTA is 2905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown not page aligned. *seg is invalid after a successful return. If 2906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *need_discard is True after a successful return, the caller should 2907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown immediately discard translations from the new area. */ 2908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(am_extend_map_client)( /*OUT*/Bool* need_discard, 2910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment* seg, SizeT delta ) 2911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr xStart; 2913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres; 2914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg_copy = *seg; 2915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SizeT seg_old_len = seg->end + 1 - seg->start; 2916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) 2918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) BEFORE"); 2919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (seg->kind != SkFileC && seg->kind != SkAnonC) 2921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (delta == 0 || !VG_IS_PAGE_ALIGNED(delta)) 2924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown xStart = seg->end+1; 2927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (xStart + delta < delta) 2928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!VG_(am_is_valid_for_client_or_free_or_resvn)( xStart, delta, 2931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_PROT_NONE )) 2932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = ML_(am_do_extend_mapping_NO_NOTIFY)( seg->start, 2936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg_old_len, 2937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg_old_len + delta ); 2938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) { 2939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 2942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* the area must not have moved */ 2943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sr_Res(sres) == seg->start); 2944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 2945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *need_discard = any_Ts_in_range( seg_copy.end+1, delta ); 2947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg_copy.end += delta; 2949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg_copy ); 2950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) 2952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) AFTER"); 2953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 2955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 2956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 2957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Remap the old address range to the new address range. Fails if any 2960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown parameter is not page aligned, if the either size is zero, if any 2961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown wraparound is implied, if the old address range does not fall 2962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown entirely within a single segment, if the new address range overlaps 2963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown with the old one, or if the old address range is not a valid client 2964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mapping. If *need_discard is True after a successful return, the 2965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown caller should immediately discard translations from both specified 2966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown address ranges. */ 2967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard, 2969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr old_addr, SizeT old_len, 2970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr new_addr, SizeT new_len ) 2971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 2972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int iLo, iHi; 2973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres; 2974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment seg; 2975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (old_len == 0 || new_len == 0) 2977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!VG_IS_PAGE_ALIGNED(old_addr) || !VG_IS_PAGE_ALIGNED(old_len) 2980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || !VG_IS_PAGE_ALIGNED(new_addr) || !VG_IS_PAGE_ALIGNED(new_len)) 2981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (old_addr + old_len < old_addr 2984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || new_addr + new_len < new_addr) 2985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (old_addr + old_len - 1 < new_addr 2988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || new_addr + new_len - 1 < old_addr) { 2989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* no overlap */ 2990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else 2991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iLo = find_nsegment_idx( old_addr ); 2994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iHi = find_nsegment_idx( old_addr + old_len - 1 ); 2995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (iLo != iHi) 2996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 2997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[iLo].kind != SkFileC && nsegments[iLo].kind != SkAnonC) 2999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 3000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY) 3002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ( old_addr, old_len, new_addr, new_len ); 3003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) { 3004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 3005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 3006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 3007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(sr_Res(sres) == new_addr); 3008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *need_discard = any_Ts_in_range( old_addr, old_len ) 3011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || any_Ts_in_range( new_addr, new_len ); 3012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg = nsegments[iLo]; 3014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Mark the new area based on the old seg. */ 3016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (seg.kind == SkFileC) { 3017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.offset += ((ULong)old_addr) - ((ULong)seg.start); 3018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 3019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(seg.kind == SkAnonC); 3020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(seg.offset == 0); 3021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = new_addr; 3023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = new_addr + new_len - 1; 3024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 3025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Create a free hole in the old location. */ 3027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown init_nsegment( &seg ); 3028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.start = old_addr; 3029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.end = old_addr + old_len - 1; 3030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* See comments in VG_(am_notify_munmap) about this SkResvn vs 3031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SkFree thing. */ 3032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (old_addr > aspacem_maxAddr 3033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && /* check previous comparison is meaningful */ 3034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_maxAddr < Addr_MAX) 3035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkResvn; 3036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 3037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg.kind = SkFree; 3038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown add_segment( &seg ); 3040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AM_SANITY_CHECK; 3042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 3043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // HAVE_MREMAP 3046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_linux) 3049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 3051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 3052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- A simple parser for /proc/self/maps on Linux 2.4.X/2.6.X. ---*/ 3053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Almost completely independent of the stuff above. The ---*/ 3054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- only function it 'exports' to the code above this comment ---*/ 3055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- is parse_procselfmaps. ---*/ 3056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 3057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*-----------------------------------------------------------------*/ 3058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------BEGIN-procmaps-parser-for-Linux--------------------------*/ 3060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Size of a smallish table used to read /proc/self/map entries. */ 3062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define M_PROCMAP_BUF 100000 3063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* static ... to keep it out of the stack frame. */ 3065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Char procmap_buf[M_PROCMAP_BUF]; 3066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Records length of /proc/self/maps read into procmap_buf. */ 3068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int buf_n_tot; 3069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper fns. */ 3071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int hexdigit ( Char c ) 3073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (c >= '0' && c <= '9') return (Int)(c - '0'); 3075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (c >= 'a' && c <= 'f') return 10 + (Int)(c - 'a'); 3076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (c >= 'A' && c <= 'F') return 10 + (Int)(c - 'A'); 3077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return -1; 3078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int decdigit ( Char c ) 3081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (c >= '0' && c <= '9') return (Int)(c - '0'); 3083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return -1; 3084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int readchar ( const Char* buf, Char* ch ) 3087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (*buf == 0) return 0; 3089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ch = *buf; 3090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 1; 3091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int readhex ( const Char* buf, UWord* val ) 3094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Read a word-sized hex number. */ 3096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int n = 0; 3097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *val = 0; 3098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (hexdigit(*buf) >= 0) { 3099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *val = (*val << 4) + hexdigit(*buf); 3100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n++; buf++; 3101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return n; 3103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int readhex64 ( const Char* buf, ULong* val ) 3106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Read a potentially 64-bit hex number. */ 3108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int n = 0; 3109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *val = 0; 3110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (hexdigit(*buf) >= 0) { 3111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *val = (*val << 4) + hexdigit(*buf); 3112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n++; buf++; 3113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return n; 3115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int readdec64 ( const Char* buf, ULong* val ) 3118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int n = 0; 3120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *val = 0; 3121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (hexdigit(*buf) >= 0) { 3122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *val = (*val * 10) + decdigit(*buf); 3123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n++; buf++; 3124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return n; 3126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get the contents of /proc/self/maps into a static buffer. If 3130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown there's a syntax error, it won't fit, or other failure, just 3131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown abort. */ 3132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void read_procselfmaps_into_buf ( void ) 3134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int n_chunk; 3136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes fd; 3137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Read the initial memory mapping from the /proc filesystem. */ 3139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fd = ML_(am_open)( "/proc/self/maps", VKI_O_RDONLY, 0 ); 3140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(fd)) 3141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(am_barf)("can't open /proc/self/maps"); 3142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buf_n_tot = 0; 3144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown do { 3145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_chunk = ML_(am_read)( sr_Res(fd), &procmap_buf[buf_n_tot], 3146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown M_PROCMAP_BUF - buf_n_tot ); 3147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (n_chunk >= 0) 3148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buf_n_tot += n_chunk; 3149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF ); 3150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(am_close)(sr_Res(fd)); 3152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (buf_n_tot >= M_PROCMAP_BUF-5) 3154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(am_barf_toolow)("M_PROCMAP_BUF"); 3155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (buf_n_tot == 0) 3156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(am_barf)("I/O error on /proc/self/maps"); 3157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown procmap_buf[buf_n_tot] = 0; 3159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Parse /proc/self/maps. For each map entry, call 3162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown record_mapping, passing it, in this order: 3163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown start address in memory 3165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown length 3166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown page protections (using the VKI_PROT_* flags) 3167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mapped file device and inode 3168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown offset in file, or zero if no file 3169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown filename, zero terminated, or NULL if no file 3170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown So the sig of the called fn might be 3172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void (*record_mapping)( Addr start, SizeT size, UInt prot, 3174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt dev, UInt info, 3175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong foffset, UChar* filename ) 3176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Note that the supplied filename is transiently stored; record_mapping 3178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown should make a copy if it wants to keep it. 3179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Nb: it is important that this function does not alter the contents of 3181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown procmap_buf! 3182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 3183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void parse_procselfmaps ( 3184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void (*record_mapping)( Addr addr, SizeT len, UInt prot, 3185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong dev, ULong ino, Off64T offset, 3186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const UChar* filename ), 3187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void (*record_gap)( Addr addr, SizeT len ) 3188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ) 3189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, j, i_eol; 3191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr start, endPlusOne, gapStart; 3192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UChar* filename; 3193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UChar rr, ww, xx, pp, ch, tmp; 3194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt prot; 3195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UWord maj, min; 3196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong foffset, dev, ino; 3197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown foffset = ino = 0; /* keep gcc-4.1.0 happy */ 3199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown read_procselfmaps_into_buf(); 3201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert('\0' != procmap_buf[0] && 0 != buf_n_tot); 3203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) 3205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0, "procselfmaps", "raw:\n%s\n", procmap_buf); 3206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ok, it's safely aboard. Parse the entries. */ 3208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = 0; 3209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown gapStart = Addr_MIN; 3210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (True) { 3211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i >= buf_n_tot) break; 3212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Read (without fscanf :) the pattern %16x-%16x %c%c%c%c %16x %2x:%2x %d */ 3214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readhex(&procmap_buf[i], &start); 3215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j > 0) i += j; else goto syntaxerror; 3216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readchar(&procmap_buf[i], &ch); 3217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j == 1 && ch == '-') i += j; else goto syntaxerror; 3218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readhex(&procmap_buf[i], &endPlusOne); 3219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j > 0) i += j; else goto syntaxerror; 3220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readchar(&procmap_buf[i], &ch); 3222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j == 1 && ch == ' ') i += j; else goto syntaxerror; 3223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readchar(&procmap_buf[i], &rr); 3225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j == 1 && (rr == 'r' || rr == '-')) i += j; else goto syntaxerror; 3226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readchar(&procmap_buf[i], &ww); 3227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j == 1 && (ww == 'w' || ww == '-')) i += j; else goto syntaxerror; 3228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readchar(&procmap_buf[i], &xx); 3229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j == 1 && (xx == 'x' || xx == '-')) i += j; else goto syntaxerror; 3230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* This field is the shared/private flag */ 3231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readchar(&procmap_buf[i], &pp); 3232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j == 1 && (pp == 'p' || pp == '-' || pp == 's')) 3233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i += j; else goto syntaxerror; 3234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readchar(&procmap_buf[i], &ch); 3236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j == 1 && ch == ' ') i += j; else goto syntaxerror; 3237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readhex64(&procmap_buf[i], &foffset); 3239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j > 0) i += j; else goto syntaxerror; 3240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readchar(&procmap_buf[i], &ch); 3242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j == 1 && ch == ' ') i += j; else goto syntaxerror; 3243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readhex(&procmap_buf[i], &maj); 3245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j > 0) i += j; else goto syntaxerror; 3246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readchar(&procmap_buf[i], &ch); 3247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j == 1 && ch == ':') i += j; else goto syntaxerror; 3248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readhex(&procmap_buf[i], &min); 3249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j > 0) i += j; else goto syntaxerror; 3250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readchar(&procmap_buf[i], &ch); 3252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j == 1 && ch == ' ') i += j; else goto syntaxerror; 3253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown j = readdec64(&procmap_buf[i], &ino); 3255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (j > 0) i += j; else goto syntaxerror; 3256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto read_line_ok; 3258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown syntaxerror: 3260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0, "Valgrind:", 3261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "FATAL: syntax error reading /proc/self/maps\n"); 3262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { Int k, m; 3263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar buf50[51]; 3264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m = 0; 3265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buf50[m] = 0; 3266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown k = i - 50; 3267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (k < 0) k = 0; 3268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (; k <= i; k++) { 3269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buf50[m] = procmap_buf[k]; 3270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buf50[m+1] = 0; 3271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (m < 50-1) m++; 3272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0, "procselfmaps", "Last 50 chars: '%s'\n", buf50); 3274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(am_exit)(1); 3276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown read_line_ok: 3278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Try and find the name of the file mapped to this segment, if 3280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown it exists. Note that files can contains spaces. */ 3281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Move i to the next non-space char, which should be either a '/' or 3283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // a newline. 3284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (procmap_buf[i] == ' ' && i < buf_n_tot-1) i++; 3285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Move i_eol to the end of the line. 3287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i_eol = i; 3288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (procmap_buf[i_eol] != '\n' && i_eol < buf_n_tot-1) i_eol++; 3289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If there's a filename... 3291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i < i_eol-1 && procmap_buf[i] == '/') { 3292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Minor hack: put a '\0' at the filename end for the call to 3293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 'record_mapping', then restore the old char with 'tmp'. */ 3294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown filename = &procmap_buf[i]; 3295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tmp = filename[i_eol - i]; 3296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown filename[i_eol - i] = '\0'; 3297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 3298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tmp = 0; 3299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown filename = NULL; 3300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown foffset = 0; 3301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown prot = 0; 3304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (rr == 'r') prot |= VKI_PROT_READ; 3305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ww == 'w') prot |= VKI_PROT_WRITE; 3306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (xx == 'x') prot |= VKI_PROT_EXEC; 3307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Linux has two ways to encode a device number when it 3309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown is exposed to user space (via fstat etc). The old way 3310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown is the traditional unix scheme that produces a 16 bit 3311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown device number with the top 8 being the major number and 3312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the bottom 8 the minor number. 3313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The new scheme allows for a 12 bit major number and 3315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a 20 bit minor number by using a 32 bit device number 3316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown and putting the top 12 bits of the minor number into 3317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the top 12 bits of the device number thus leaving an 3318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown extra 4 bits for the major number. 3319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown If the minor and major number are both single byte 3321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown values then both schemes give the same result so we 3322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown use the new scheme here in case either number is 3323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown outside the 0-255 range and then use fstat64 when 3324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown available (or fstat on 64 bit systems) so that we 3325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown should always have a new style device number and 3326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown everything should match. */ 3327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown dev = (min & 0xff) | (maj << 8) | ((min & ~0xff) << 12); 3328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (record_gap && gapStart < start) 3330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (*record_gap) ( gapStart, start-gapStart ); 3331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (record_mapping && start < endPlusOne) 3333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (*record_mapping) ( start, endPlusOne-start, 3334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown prot, dev, ino, 3335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown foffset, filename ); 3336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ('\0' != tmp) { 3338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown filename[i_eol - i] = tmp; 3339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = i_eol + 1; 3342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown gapStart = endPlusOne; 3343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if defined(VGP_arm_linux) 3346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* ARM puts code at the end of memory that contains processor 3347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown specific stuff (cmpxchg, getting the thread local storage, etc.) 3348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This isn't specified in /proc/self/maps, so do it here. This 3349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown kludgery causes the view of memory, as presented to 3350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown record_gap/record_mapping, to actually reflect reality. IMO 3351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (JRS, 2010-Jan-03) the fact that /proc/.../maps does not list 3352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the commpage should be regarded as a bug in the kernel. */ 3353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { const Addr commpage_start = ARM_LINUX_FAKE_COMMPAGE_START; 3354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Addr commpage_end1 = ARM_LINUX_FAKE_COMMPAGE_END1; 3355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (gapStart < commpage_start) { 3356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (record_gap) 3357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (*record_gap)( gapStart, commpage_start - gapStart ); 3358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (record_mapping) 3359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (*record_mapping)( commpage_start, commpage_end1 - commpage_start, 3360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_PROT_READ|VKI_PROT_EXEC, 3361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0/*dev*/, 0/*ino*/, 0/*foffset*/, 3362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NULL); 3363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown gapStart = commpage_end1; 3364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 3367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (record_gap && gapStart < Addr_MAX) 3369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 ); 3370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------END-procmaps-parser-for-Linux----------------------------*/ 3373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------BEGIN-procmaps-parser-for-Darwin-------------------------*/ 3375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGO_darwin) 3377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <mach/mach.h> 3378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <mach/mach_vm.h> 3379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic unsigned int mach2vki(unsigned int vm_prot) 3381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 3383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ((vm_prot & VM_PROT_READ) ? VKI_PROT_READ : 0) | 3384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ((vm_prot & VM_PROT_WRITE) ? VKI_PROT_WRITE : 0) | 3385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ((vm_prot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC : 0) ; 3386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt stats_machcalls = 0; 3389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void parse_procselfmaps ( 3391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void (*record_mapping)( Addr addr, SizeT len, UInt prot, 3392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong dev, ULong ino, Off64T offset, 3393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const UChar* filename ), 3394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void (*record_gap)( Addr addr, SizeT len ) 3395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ) 3396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vm_address_t iter; 3398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int depth; 3399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vm_address_t last; 3400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iter = 0; 3402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown depth = 0; 3403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown last = 0; 3404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (1) { 3405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach_vm_address_t addr = iter; 3406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach_vm_size_t size; 3407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vm_region_submap_short_info_data_64_t info; 3408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown kern_return_t kr; 3409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (1) { 3411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach_msg_type_number_t info_count 3412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; 3413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stats_machcalls++; 3414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth, 3415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (vm_region_info_t)&info, &info_count); 3416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (kr) 3417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 3418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (info.is_submap) { 3419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown depth++; 3420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 3421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 3423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iter = addr + size; 3425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (addr > last && record_gap) { 3427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (*record_gap)(last, addr - last); 3428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (record_mapping) { 3430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (*record_mapping)(addr, size, mach2vki(info.protection), 3431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0, 0, info.offset, NULL); 3432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown last = addr + size; 3434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ((Addr)-1 > last && record_gap) 3437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (*record_gap)(last, (Addr)-1 - last); 3438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Urr. So much for thread safety. 3441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool css_overflowed; 3442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ChangedSeg* css_local; 3443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int css_size_local; 3444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int css_used_local; 3445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_mapping_callback(Addr addr, SizeT len, UInt prot, 3447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ULong dev, ULong ino, Off64T offset, 3448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const UChar *filename) 3449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // derived from sync_check_mapping_callback() 3451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int iLo, iHi, i; 3453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len == 0) return; 3455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* The kernel should not give us wraparounds. */ 3457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(addr <= addr + len - 1); 3458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iLo = find_nsegment_idx( addr ); 3460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iHi = find_nsegment_idx( addr + len - 1 ); 3461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* NSegments iLo .. iHi inclusive should agree with the presented 3464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown data. */ 3465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = iLo; i <= iHi; i++) { 3466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt seg_prot; 3468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind == SkAnonV || nsegments[i].kind == SkFileV) { 3470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Ignore V regions */ 3471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 3472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn) { 3474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Add mapping for SkResvn regions */ 3475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ChangedSeg* cs = &css_local[css_used_local]; 3476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (css_used_local < css_size_local) { 3477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cs->is_added = True; 3478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cs->start = addr; 3479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cs->end = addr + len - 1; 3480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cs->prot = prot; 3481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cs->offset = offset; 3482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown css_used_local++; 3483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 3484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown css_overflowed = True; 3485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 3487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else if (nsegments[i].kind == SkAnonC || 3489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i].kind == SkFileC || 3490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nsegments[i].kind == SkShmC) 3491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 3492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Check permissions on client regions */ 3493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // GrP fixme 3494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg_prot = 0; 3495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ; 3496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE; 3497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if defined(VGA_x86) 3498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // GrP fixme sloppyXcheck 3499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // darwin: kernel X ignored and spuriously changes? (vm_copy) 3500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg_prot |= (prot & VKI_PROT_EXEC); 3501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# else 3502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC; 3503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 3504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (seg_prot != prot) { 3505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(clo_trace_syscalls)) 3506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0,"aspacem","region %p..%p permission " 3507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "mismatch (kernel %x, V %x)\n", 3508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void*)nsegments[i].start, 3509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void*)(nsegments[i].end+1), prot, seg_prot); 3510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 3513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(0); 3514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void remove_mapping_callback(Addr addr, SizeT len) 3519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // derived from sync_check_gap_callback() 3521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int iLo, iHi, i; 3523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (len == 0) 3525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 3526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* The kernel should not give us wraparounds. */ 3528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(addr <= addr + len - 1); 3529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iLo = find_nsegment_idx( addr ); 3531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown iHi = find_nsegment_idx( addr + len - 1 ); 3532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* NSegments iLo .. iHi inclusive should agree with the presented data. */ 3534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = iLo; i <= iHi; i++) { 3535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (nsegments[i].kind != SkFree && nsegments[i].kind != SkResvn) { 3536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // V has a mapping, kernel doesn't 3537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ChangedSeg* cs = &css_local[css_used_local]; 3538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (css_used_local < css_size_local) { 3539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cs->is_added = False; 3540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cs->start = nsegments[i].start; 3541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cs->end = nsegments[i].end; 3542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cs->prot = 0; 3543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cs->offset = 0; 3544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown css_used_local++; 3545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 3546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown css_overflowed = True; 3547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 3549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Returns False if 'css' wasn't big enough. 3555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(get_changed_segments)( 3556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const HChar* when, const HChar* where, /*OUT*/ChangedSeg* css, 3557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int css_size, /*OUT*/Int* css_used) 3558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 3559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static UInt stats_synccalls = 1; 3560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(when && where); 3561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) 3563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(debugLog)(0,"aspacem", 3564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "[%u,%u] VG_(get_changed_segments)(%s, %s)\n", 3565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stats_synccalls++, stats_machcalls, when, where 3566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 3567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown css_overflowed = False; 3569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown css_local = css; 3570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown css_size_local = css_size; 3571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown css_used_local = 0; 3572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Get the list of segs that need to be added/removed. 3574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown parse_procselfmaps(&add_mapping_callback, &remove_mapping_callback); 3575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *css_used = css_used_local; 3577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (css_overflowed) { 3579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem_assert(css_used_local == css_size_local); 3580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 3581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return !css_overflowed; 3583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 3584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // defined(VGO_darwin) 3586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------END-procmaps-parser-for-Darwin---------------------------*/ 3588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // defined(VGO_linux) || defined(VGO_darwin) 3590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 3591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 3592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end ---*/ 3593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 3594