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