195af4ce809c85e3659843aa4156089c80b2b4353florian/* -*- mode: C; c-basic-offset: 3; -*- */
2de4a1d01951937632098a6cda45859afa587a06fsewardj
3de4a1d01951937632098a6cda45859afa587a06fsewardj/*--------------------------------------------------------------------*/
455f9d1a56f3542c68f5b24006c14b1f9aaefff6fsewardj/*--- The address space manager: segment initialisation and        ---*/
555f9d1a56f3542c68f5b24006c14b1f9aaefff6fsewardj/*--- tracking, stack operations                                   ---*/
6297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj/*---                                                              ---*/
7da9420ce499f657b2cb66bf1b5e2a6c5461bb9d8florian/*--- Implementation for Linux (and Darwin!)     aspacemgr-linux.c ---*/
8de4a1d01951937632098a6cda45859afa587a06fsewardj/*--------------------------------------------------------------------*/
9de4a1d01951937632098a6cda45859afa587a06fsewardj
10de4a1d01951937632098a6cda45859afa587a06fsewardj/*
11b9c427c63a278cc612ae0ec573be7bb1abaa447fnjn   This file is part of Valgrind, a dynamic binary instrumentation
12b9c427c63a278cc612ae0ec573be7bb1abaa447fnjn   framework.
13de4a1d01951937632098a6cda45859afa587a06fsewardj
14b3a1e4bffbdbbf38304f216af405009868f43628sewardj   Copyright (C) 2000-2015 Julian Seward
15de4a1d01951937632098a6cda45859afa587a06fsewardj      jseward@acm.org
16de4a1d01951937632098a6cda45859afa587a06fsewardj
17de4a1d01951937632098a6cda45859afa587a06fsewardj   This program is free software; you can redistribute it and/or
18de4a1d01951937632098a6cda45859afa587a06fsewardj   modify it under the terms of the GNU General Public License as
19de4a1d01951937632098a6cda45859afa587a06fsewardj   published by the Free Software Foundation; either version 2 of the
20de4a1d01951937632098a6cda45859afa587a06fsewardj   License, or (at your option) any later version.
21de4a1d01951937632098a6cda45859afa587a06fsewardj
22de4a1d01951937632098a6cda45859afa587a06fsewardj   This program is distributed in the hope that it will be useful, but
23de4a1d01951937632098a6cda45859afa587a06fsewardj   WITHOUT ANY WARRANTY; without even the implied warranty of
24de4a1d01951937632098a6cda45859afa587a06fsewardj   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25de4a1d01951937632098a6cda45859afa587a06fsewardj   General Public License for more details.
26de4a1d01951937632098a6cda45859afa587a06fsewardj
27de4a1d01951937632098a6cda45859afa587a06fsewardj   You should have received a copy of the GNU General Public License
28de4a1d01951937632098a6cda45859afa587a06fsewardj   along with this program; if not, write to the Free Software
29de4a1d01951937632098a6cda45859afa587a06fsewardj   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
30de4a1d01951937632098a6cda45859afa587a06fsewardj   02111-1307, USA.
31de4a1d01951937632098a6cda45859afa587a06fsewardj
32e49d8e7dfd3a9c96feb9935b5920973dfc0b170anjn   The GNU General Public License is contained in the file COPYING.
33de4a1d01951937632098a6cda45859afa587a06fsewardj*/
34de4a1d01951937632098a6cda45859afa587a06fsewardj
358eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
368b68b64759254d514d98328c496cbd88cde4c9a5njn
37297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj/* *************************************************************
38297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj   DO NOT INCLUDE ANY OTHER FILES HERE.
39297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj   ADD NEW INCLUDES ONLY TO priv_aspacemgr.h
40297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj   AND THEN ONLY AFTER READING DIRE WARNINGS THERE TOO.
41297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj   ************************************************************* */
4255f9d1a56f3542c68f5b24006c14b1f9aaefff6fsewardj
43297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj#include "priv_aspacemgr.h"
44870f7451dcc5ff1ec6c84e8bb2832bd5834459c2bart#include "config.h"
4504e1698d9f92df36742be7c1e0fefb9af1c5b1bdnjn
4604e1698d9f92df36742be7c1e0fefb9af1c5b1bdnjn
47aa34929c0d86ce6577bc43da5f3d922bc8d595a2sewardj/* Note: many of the exported functions implemented below are
48aa34929c0d86ce6577bc43da5f3d922bc8d595a2sewardj   described more fully in comments in pub_core_aspacemgr.h.
49aa34929c0d86ce6577bc43da5f3d922bc8d595a2sewardj*/
50aa34929c0d86ce6577bc43da5f3d922bc8d595a2sewardj
51aa34929c0d86ce6577bc43da5f3d922bc8d595a2sewardj
5245f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
5345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
54a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj/*--- Overview.                                                 ---*/
55a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj/*---                                                           ---*/
56a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj/*-----------------------------------------------------------------*/
57a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
58a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj/* Purpose
59a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   ~~~~~~~
60a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   The purpose of the address space manager (aspacem) is:
61a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
62a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   (1) to record the disposition of all parts of the process' address
63a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj       space at all times.
64a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
65a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   (2) to the extent that it can, influence layout in ways favourable
66a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj       to our purposes.
67a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
68a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   It is important to appreciate that whilst it can and does attempt
69a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   to influence layout, and usually succeeds, it isn't possible to
70a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   impose absolute control: in the end, the kernel is the final
71a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   arbiter, and can always bounce our requests.
72a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
73a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   Strategy
74a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   ~~~~~~~~
75a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   The strategy is therefore as follows:
76a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
77a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   * Track ownership of mappings.  Each one can belong either to
78a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     Valgrind or to the client.
79a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
80a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   * Try to place the client's fixed and hinted mappings at the
81a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     requested addresses.  Fixed mappings are allowed anywhere except
82a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     in areas reserved by Valgrind; the client can trash its own
83a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     mappings if it wants.  Hinted mappings are allowed providing they
84a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     fall entirely in free areas; if not, they will be placed by
85a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     aspacem in a free area.
86a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
87a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   * Anonymous mappings are allocated so as to keep Valgrind and
88a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     client areas widely separated when possible.  If address space
89a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     runs low, then they may become intermingled: aspacem will attempt
90a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     to use all possible space.  But under most circumstances lack of
91a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     address space is not a problem and so the areas will remain far
92a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     apart.
93a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
94a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     Searches for client space start at aspacem_cStart and will wrap
95a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     around the end of the available space if needed.  Searches for
96a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     Valgrind space start at aspacem_vStart and will also wrap around.
97a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     Because aspacem_cStart is approximately at the start of the
98a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     available space and aspacem_vStart is approximately in the
99a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     middle, for the most part the client anonymous mappings will be
100a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     clustered towards the start of available space, and Valgrind ones
101a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     in the middle.
102a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
1038eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     On Solaris, searches for client space start at (aspacem_vStart - 1)
1048eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     and for Valgrind space start at (aspacem_maxAddr - 1) and go backwards.
1058eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     This simulates what kernel does - brk limit grows from bottom and mmap'ed
1068eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     objects from top. It is in contrary with Linux where data segment
1078eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     and mmap'ed objects grow from bottom (leading to early data segment
1088eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     exhaustion for tools which do not use m_replacemalloc). While Linux glibc
1098eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     can cope with this problem by employing mmap, Solaris libc treats inability
1108eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     to grow brk limit as a hard failure.
1118eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
112a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     The available space is delimited by aspacem_minAddr and
113a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     aspacem_maxAddr.  aspacem is flexible and can operate with these
114a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     at any (sane) setting.  For 32-bit Linux, aspacem_minAddr is set
115a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     to some low-ish value at startup (64M) and aspacem_maxAddr is
116a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     derived from the stack pointer at system startup.  This seems a
117a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     reliable way to establish the initial boundaries.
118e4d78123089e55bec64a4f848bdc09556192e259philippe     A command line option allows to change the value of aspacem_minAddr,
119e4d78123089e55bec64a4f848bdc09556192e259philippe     so as to allow memory hungry applications to use the lowest
120e4d78123089e55bec64a4f848bdc09556192e259philippe     part of the memory.
121a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
122a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     64-bit Linux is similar except for the important detail that the
123e06727f0a4f01862c908ce95eb3af4e401d9fa9dsewardj     upper boundary is set to 64G.  The reason is so that all
124a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     anonymous mappings (basically all client data areas) are kept
125e06727f0a4f01862c908ce95eb3af4e401d9fa9dsewardj     below 64G, since that is the maximum range that memcheck can
126a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     track shadow memory using a fast 2-level sparse array.  It can go
127e06727f0a4f01862c908ce95eb3af4e401d9fa9dsewardj     beyond that but runs much more slowly.  The 64G limit is
128a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     arbitrary and is trivially changed.  So, with the current
129a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     settings, programs on 64-bit Linux will appear to run out of
130e06727f0a4f01862c908ce95eb3af4e401d9fa9dsewardj     address space and presumably fail at the 64G limit.  Given the
131e06727f0a4f01862c908ce95eb3af4e401d9fa9dsewardj     considerable space overhead of Memcheck, that means you should be
132e06727f0a4f01862c908ce95eb3af4e401d9fa9dsewardj     able to memcheckify programs that use up to about 32G natively.
133a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
134a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   Note that the aspacem_minAddr/aspacem_maxAddr limits apply only to
135a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   anonymous mappings.  The client can still do fixed and hinted maps
136a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   at any addresses provided they do not overlap Valgrind's segments.
137a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   This makes Valgrind able to load prelinked .so's at their requested
138a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   addresses on 64-bit platforms, even if they are very high (eg,
139a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   112TB).
140a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
141a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   At startup, aspacem establishes the usable limits, and advises
142a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   m_main to place the client stack at the top of the range, which on
143a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   a 32-bit machine will be just below the real initial stack.  One
144a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   effect of this is that self-hosting sort-of works, because an inner
145a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   valgrind will then place its client's stack just below its own
146a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   initial stack.
147a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
148a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   The segment array and segment kinds
149a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
150a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   The central data structure is the segment array (segments[0
151a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   .. nsegments_used-1]).  This covers the entire address space in
152a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   order, giving account of every byte of it.  Free spaces are
153a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   represented explicitly as this makes many operations simpler.
154a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   Mergeable adjacent segments are aggressively merged so as to create
155a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   a "normalised" representation (preen_nsegments).
156a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
157a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   There are 7 (mutually-exclusive) segment kinds, the meaning of
158a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   which is important:
159a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
160a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   SkFree: a free space, which may be allocated either to Valgrind (V)
161a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj      or the client (C).
162a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
163a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   SkAnonC: an anonymous mapping belonging to C.  For these, aspacem
164a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj      tracks a boolean indicating whether or not is is part of the
165a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj      client's heap area (can't remember why).
166a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
167a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   SkFileC: a file mapping belonging to C.
168a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
169a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   SkShmC: a shared memory segment belonging to C.
170a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
171a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   SkAnonV: an anonymous mapping belonging to V.  These cover all V's
172a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj      dynamic memory needs, including non-client malloc/free areas,
173a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj      shadow memory, and the translation cache.
174a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
175a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   SkFileV: a file mapping belonging to V.  As far as I know these are
176a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj      only created transiently for the purposes of reading debug info.
177a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
178a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   SkResvn: a reservation segment.
179a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
180a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   These are mostly straightforward.  Reservation segments have some
181a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   subtlety, however.
182a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
183a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   A reservation segment is unmapped from the kernel's point of view,
184a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   but is an area in which aspacem will not create anonymous maps
185a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   (either Vs or Cs).  The idea is that we will try to keep it clear
186a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   when the choice to do so is ours.  Reservation segments are
187a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   'invisible' from the client's point of view: it may choose to park
188a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   a fixed mapping in the middle of one, and that's just tough -- we
189a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   can't do anything about that.  From the client's perspective
190a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   reservations are semantically equivalent to (although
191a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   distinguishable from, if it makes enquiries) free areas.
192a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
193a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   Reservations are a primitive mechanism provided for whatever
194a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   purposes the rest of the system wants.  Currently they are used to
195a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   reserve the expansion space into which a growdown stack is
196a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   expanded, and into which the data segment is extended.  Note,
197a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   though, those uses are entirely external to this module, which only
198a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   supplies the primitives.
199a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
200a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   Reservations may be shrunk in order that an adjoining anonymous
201a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   mapping may be extended.  This makes dataseg/stack expansion work.
202a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   A reservation may not be shrunk below one page.
203a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
204a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   The advise/notify concept
205a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   ~~~~~~~~~~~~~~~~~~~~~~~~~
206a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   All mmap-related calls must be routed via aspacem.  Calling
207a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   sys_mmap directly from the rest of the system is very dangerous
208a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   because aspacem's data structures will become out of date.
209a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
210a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   The fundamental mode of operation of aspacem is to support client
211a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   mmaps.  Here's what happens (in ML_(generic_PRE_sys_mmap)):
212a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
213a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   * m_syswrap intercepts the mmap call.  It examines the parameters
214a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     and identifies the requested placement constraints.  There are
215a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     three possibilities: no constraint (MAny), hinted (MHint, "I
216a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     prefer X but will accept anything"), and fixed (MFixed, "X or
217a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     nothing").
218a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
219a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   * This request is passed to VG_(am_get_advisory).  This decides on
220a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     a placement as described in detail in Strategy above.  It may
221a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     also indicate that the map should fail, because it would trash
222a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     one of Valgrind's areas, which would probably kill the system.
223a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
224a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   * Control returns to the wrapper.  If VG_(am_get_advisory) has
225a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     declared that the map should fail, then it must be made to do so.
226a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     Usually, though, the request is considered acceptable, in which
227a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     case an "advised" address is supplied.  The advised address
228a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     replaces the original address supplied by the client, and
229a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     MAP_FIXED is set.
230a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
231a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     Note at this point that although aspacem has been asked for
232a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     advice on where to place the mapping, no commitment has yet been
233a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     made by either it or the kernel.
234a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
235a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   * The adjusted request is handed off to the kernel.
236a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
237a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj   * The kernel's result is examined.  If the map succeeded, aspacem
238a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     is told of the outcome (VG_(am_notify_client_mmap)), so it can
239a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj     update its records accordingly.
240a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
241a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  This then is the central advise-notify idiom for handling client
242a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  mmap/munmap/mprotect/shmat:
243a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
244a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  * ask aspacem for an advised placement (or a veto)
245a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
246a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  * if not vetoed, hand request to kernel, using the advised placement
247a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
248a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  * examine result, and if successful, notify aspacem of the result.
249a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
250a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  There are also many convenience functions, eg
251a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  VG_(am_mmap_anon_fixed_client), which do both phases entirely within
252a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  aspacem.
253a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
254a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  To debug all this, a sync-checker is provided.  It reads
255a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  /proc/self/maps, compares what it sees with aspacem's records, and
256a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  complains if there is a difference.  --sanity-level=3 runs it before
257a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  and after each syscall, which is a powerful, if slow way of finding
258a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj  buggy syscall wrappers.
2594f3ef1ff3af3c637f38d4352f38581effba95c4esewardj
2604f3ef1ff3af3c637f38d4352f38581effba95c4esewardj  Loss of pointercheck
2614f3ef1ff3af3c637f38d4352f38581effba95c4esewardj  ~~~~~~~~~~~~~~~~~~~~
2624f3ef1ff3af3c637f38d4352f38581effba95c4esewardj  Up to and including Valgrind 2.4.1, x86 segmentation was used to
2634f3ef1ff3af3c637f38d4352f38581effba95c4esewardj  enforce seperation of V and C, so that wild writes by C could not
2644f3ef1ff3af3c637f38d4352f38581effba95c4esewardj  trash V.  This got called "pointercheck".  Unfortunately, the new
2654f3ef1ff3af3c637f38d4352f38581effba95c4esewardj  more flexible memory layout, plus the need to be portable across
2664f3ef1ff3af3c637f38d4352f38581effba95c4esewardj  different architectures, means doing this in hardware is no longer
2674f3ef1ff3af3c637f38d4352f38581effba95c4esewardj  viable, and doing it in software is expensive.  So at the moment we
2684f3ef1ff3af3c637f38d4352f38581effba95c4esewardj  don't do it at all.
269a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj*/
270a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
271a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj
272a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj/*-----------------------------------------------------------------*/
273a07dce4dd13dcdc96ad5dc1c7d7b0f8a1bbac2e6sewardj/*---                                                           ---*/
27445f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--- The Address Space Manager's state.                        ---*/
27545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
27645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
27704e1698d9f92df36742be7c1e0fefb9af1c5b1bdnjn
27845f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* ------ start of STATE for the address-space manager ------ */
279b69f7c12ae343c3435b4b3bd0aa372144bdf5977njn
280f049d1dc2a4df13444555135a59a78c56fc76b2fsewardj/* Max number of segments we can track.  On Android, virtual address
281f049d1dc2a4df13444555135a59a78c56fc76b2fsewardj   space is limited, so keep a low limit -- 5000 x sizef(NSegment) is
282f049d1dc2a4df13444555135a59a78c56fc76b2fsewardj   360KB. */
28326ed419d60369d0545510eba0832566e24452e1esewardj#if defined(VGPV_arm_linux_android) \
28426ed419d60369d0545510eba0832566e24452e1esewardj    || defined(VGPV_x86_linux_android) \
28526ed419d60369d0545510eba0832566e24452e1esewardj    || defined(VGPV_mips32_linux_android) \
28626ed419d60369d0545510eba0832566e24452e1esewardj    || defined(VGPV_arm64_linux_android)
287f049d1dc2a4df13444555135a59a78c56fc76b2fsewardj# define VG_N_SEGMENTS 5000
288f049d1dc2a4df13444555135a59a78c56fc76b2fsewardj#else
289f049d1dc2a4df13444555135a59a78c56fc76b2fsewardj# define VG_N_SEGMENTS 30000
290f049d1dc2a4df13444555135a59a78c56fc76b2fsewardj#endif
291f049d1dc2a4df13444555135a59a78c56fc76b2fsewardj
29245f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Array [0 .. nsegments_used-1] of all mappings. */
29345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Sorted by .addr field. */
29445f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* I: len may not be zero. */
29545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* I: overlapping segments are not allowed. */
29645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* I: the segments cover the entire address space precisely. */
29745f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Each segment can optionally hold an index into the filename table. */
29845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
29945f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic NSegment nsegments[VG_N_SEGMENTS];
30045f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic Int      nsegments_used = 0;
30145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
30245f4e7c91119c7d01a59f5e827c67841632c9314sewardj#define Addr_MIN ((Addr)0)
30345f4e7c91119c7d01a59f5e827c67841632c9314sewardj#define Addr_MAX ((Addr)(-1ULL))
30445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
30545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Limits etc */
30645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
307e4d78123089e55bec64a4f848bdc09556192e259philippe
308e4d78123089e55bec64a4f848bdc09556192e259philippeAddr VG_(clo_aspacem_minAddr)
3098eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#if defined(VGO_linux)
3108eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   = (Addr) 0x04000000; // 64M
3118eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#elif defined(VGO_darwin)
312e4d78123089e55bec64a4f848bdc09556192e259philippe# if VG_WORDSIZE == 4
313e4d78123089e55bec64a4f848bdc09556192e259philippe   = (Addr) 0x00001000;
314e4d78123089e55bec64a4f848bdc09556192e259philippe# else
315e4d78123089e55bec64a4f848bdc09556192e259philippe   = (Addr) 0x100000000;  // 4GB page zero
316e4d78123089e55bec64a4f848bdc09556192e259philippe# endif
3178eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#elif defined(VGO_solaris)
3188eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   = (Addr) 0x00100000; // 1MB
319e4d78123089e55bec64a4f848bdc09556192e259philippe#else
320e4d78123089e55bec64a4f848bdc09556192e259philippe#endif
321e4d78123089e55bec64a4f848bdc09556192e259philippe
322e4d78123089e55bec64a4f848bdc09556192e259philippe
32345f4e7c91119c7d01a59f5e827c67841632c9314sewardj// The smallest address that aspacem will try to allocate
32445f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic Addr aspacem_minAddr = 0;
32545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
32645f4e7c91119c7d01a59f5e827c67841632c9314sewardj// The largest address that aspacem will try to allocate
32745f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic Addr aspacem_maxAddr = 0;
32845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
32945f4e7c91119c7d01a59f5e827c67841632c9314sewardj// Where aspacem will start looking for client space
33045f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic Addr aspacem_cStart = 0;
33145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
33245f4e7c91119c7d01a59f5e827c67841632c9314sewardj// Where aspacem will start looking for Valgrind space
33345f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic Addr aspacem_vStart = 0;
33445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
33545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
33645f4e7c91119c7d01a59f5e827c67841632c9314sewardj#define AM_SANITY_CHECK                                      \
33745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   do {                                                      \
33845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (VG_(clo_sanity_level >= 3))                        \
33945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         aspacem_assert(VG_(am_do_sync_check)                \
34045f4e7c91119c7d01a59f5e827c67841632c9314sewardj            (__PRETTY_FUNCTION__,__FILE__,__LINE__));        \
34145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   } while (0)
34245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
34345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* ------ end of STATE for the address-space manager ------ */
34445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
345cb249ab3febb3757a0b0582be21952efacf415e5sewardj/* ------ Forwards decls ------ */
346a364d119b3847143d804e388d7a37c2c82be93bfsewardjinline
34745f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic Int  find_nsegment_idx ( Addr a );
34845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
349cb249ab3febb3757a0b0582be21952efacf415e5sewardjstatic void parse_procselfmaps (
350cb249ab3febb3757a0b0582be21952efacf415e5sewardj      void (*record_mapping)( Addr addr, SizeT len, UInt prot,
351c4431bfe04c7490ea2d74939d222d87f13f30960njn                              ULong dev, ULong ino, Off64T offset,
352dbb3584f591710a15a437918c0fc27e300993566florian                              const HChar* filename ),
353cb249ab3febb3757a0b0582be21952efacf415e5sewardj      void (*record_gap)( Addr addr, SizeT len )
354cb249ab3febb3757a0b0582be21952efacf415e5sewardj   );
355cb249ab3febb3757a0b0582be21952efacf415e5sewardj
35638a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj/* ----- Hacks to do with the "commpage" on arm-linux ----- */
35738a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj/* Not that I have anything against the commpage per se.  It's just
35838a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj   that it's not listed in /proc/self/maps, which is a royal PITA --
359f90dcbc6bfab3c26fa1802c1e307d4673a1412e5sewardj   we have to fake it up, in parse_procselfmaps.
360f90dcbc6bfab3c26fa1802c1e307d4673a1412e5sewardj
361f90dcbc6bfab3c26fa1802c1e307d4673a1412e5sewardj   But note also bug 254556 comment #2: this is now fixed in newer
362f90dcbc6bfab3c26fa1802c1e307d4673a1412e5sewardj   kernels -- it is listed as a "[vectors]" entry.  Presumably the
363f90dcbc6bfab3c26fa1802c1e307d4673a1412e5sewardj   fake entry made here duplicates the [vectors] entry, and so, if at
364f90dcbc6bfab3c26fa1802c1e307d4673a1412e5sewardj   some point in the future, we can stop supporting buggy kernels,
365f90dcbc6bfab3c26fa1802c1e307d4673a1412e5sewardj   then this kludge can be removed entirely, since the procmap parser
366f90dcbc6bfab3c26fa1802c1e307d4673a1412e5sewardj   below will read that entry in the normal way. */
36738a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj#if defined(VGP_arm_linux)
36838a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj#  define ARM_LINUX_FAKE_COMMPAGE_START 0xFFFF0000
369f90dcbc6bfab3c26fa1802c1e307d4673a1412e5sewardj#  define ARM_LINUX_FAKE_COMMPAGE_END1  0xFFFF1000
37038a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj#endif
37138a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj
37245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
373548be6d64c58729588a559b1512ad7625bc1b86esewardj
37445f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
37545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
37645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--- Displaying the segment array.                             ---*/
37745f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
37845f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
37945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
380dbb3584f591710a15a437918c0fc27e300993566florianstatic const HChar* show_SegKind ( SegKind sk )
38145f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
38245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   switch (sk) {
38345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkFree:  return "    ";
38445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkAnonC: return "anon";
38545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkAnonV: return "ANON";
38645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkFileC: return "file";
38745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkFileV: return "FILE";
3881340c35bebb175c6d158361596ee6171b4cfc2a2tom      case SkShmC:  return "shm ";
38945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkResvn: return "RSVN";
39045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      default:      return "????";
39145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
39245f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
39345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
394dbb3584f591710a15a437918c0fc27e300993566florianstatic const HChar* show_ShrinkMode ( ShrinkMode sm )
39545f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
39645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   switch (sm) {
39745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SmLower: return "SmLower";
39845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SmUpper: return "SmUpper";
39945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SmFixed: return "SmFixed";
40045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      default: return "Sm?????";
40145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
40245f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
40345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
404ddaef35bf689bb5192881aa6d455050e1423df7cnjnstatic void show_len_concisely ( /*OUT*/HChar* buf, Addr start, Addr end )
40545f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
406dbb3584f591710a15a437918c0fc27e300993566florian   const HChar* fmt;
407ddaef35bf689bb5192881aa6d455050e1423df7cnjn   ULong len = ((ULong)end) - ((ULong)start) + 1;
40845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
409ddaef35bf689bb5192881aa6d455050e1423df7cnjn   if (len < 10*1000*1000ULL) {
41045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      fmt = "%7llu";
41145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
412ddaef35bf689bb5192881aa6d455050e1423df7cnjn   else if (len < 999999ULL * (1ULL<<20)) {
41345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      fmt = "%6llum";
414ddaef35bf689bb5192881aa6d455050e1423df7cnjn      len >>= 20;
41545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
416ddaef35bf689bb5192881aa6d455050e1423df7cnjn   else if (len < 999999ULL * (1ULL<<30)) {
41745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      fmt = "%6llug";
418ddaef35bf689bb5192881aa6d455050e1423df7cnjn      len >>= 30;
41945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
420ddaef35bf689bb5192881aa6d455050e1423df7cnjn   else if (len < 999999ULL * (1ULL<<40)) {
42145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      fmt = "%6llut";
422ddaef35bf689bb5192881aa6d455050e1423df7cnjn      len >>= 40;
42345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
42445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   else {
42545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      fmt = "%6llue";
426ddaef35bf689bb5192881aa6d455050e1423df7cnjn      len >>= 50;
42745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
428ddaef35bf689bb5192881aa6d455050e1423df7cnjn   ML_(am_sprintf)(buf, fmt, len);
42945f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
43045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
43145f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Show full details of an NSegment */
43245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
433a0d557c70142e7c518b4f3757f580645b57405bcflorianstatic void show_nsegment_full ( Int logLevel, Int segNo, const NSegment* seg )
43445f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
435ddaef35bf689bb5192881aa6d455050e1423df7cnjn   HChar len_buf[20];
4364ecd48360351f666f008148c12a24cbda455c6b1florian   const HChar* name = ML_(am_get_segname)( seg->fnIdx );
437ddaef35bf689bb5192881aa6d455050e1423df7cnjn
438346ee2f7978bf2ab1ead4982e56870da276fc44bflorian   if (name == NULL)
439346ee2f7978bf2ab1ead4982e56870da276fc44bflorian      name = "(none)";
440616cf594d1c06d74632ef291c51c0545e3906f92sewardj
441ddaef35bf689bb5192881aa6d455050e1423df7cnjn   show_len_concisely(len_buf, seg->start, seg->end);
442ddaef35bf689bb5192881aa6d455050e1423df7cnjn
443ddaef35bf689bb5192881aa6d455050e1423df7cnjn   VG_(debugLog)(
444ddaef35bf689bb5192881aa6d455050e1423df7cnjn      logLevel, "aspacem",
445a5e06c36bf9d93461bc8c4351e960888020ea1c4florian      "%3d: %s %010lx-%010lx %s %c%c%c%c%c %s "
446a5e06c36bf9d93461bc8c4351e960888020ea1c4florian      "d=0x%03llx i=%-7llu o=%-7lld (%d,%d) %s\n",
447ddaef35bf689bb5192881aa6d455050e1423df7cnjn      segNo, show_SegKind(seg->kind),
448a5e06c36bf9d93461bc8c4351e960888020ea1c4florian      seg->start, seg->end, len_buf,
449ddaef35bf689bb5192881aa6d455050e1423df7cnjn      seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
450ddaef35bf689bb5192881aa6d455050e1423df7cnjn      seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
451ddaef35bf689bb5192881aa6d455050e1423df7cnjn      seg->isCH ? 'H' : '-',
45245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      show_ShrinkMode(seg->smode),
453e6c3b4348515ac6ea803b8c1908c476a05261f71philippe      seg->dev, seg->ino, seg->offset,
4544ecd48360351f666f008148c12a24cbda455c6b1florian      ML_(am_segname_get_seqnr)(seg->fnIdx), seg->fnIdx,
455bcf1d7f5230fae63eee2fad64258f3cc1dbd72fdflorian      name
45645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   );
45745f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
45845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
45945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
46045f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Show an NSegment in a user-friendly-ish way. */
46145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
4623297124fa2116737066ac3cd709f18fdd5405163florianstatic void show_nsegment ( Int logLevel, Int segNo, const NSegment* seg )
46345f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
46445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   HChar len_buf[20];
465ddaef35bf689bb5192881aa6d455050e1423df7cnjn   show_len_concisely(len_buf, seg->start, seg->end);
46645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
46745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   switch (seg->kind) {
46845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
46945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkFree:
47045f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(debugLog)(
47145f4e7c91119c7d01a59f5e827c67841632c9314sewardj            logLevel, "aspacem",
472a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            "%3d: %s %010lx-%010lx %s\n",
47345f4e7c91119c7d01a59f5e827c67841632c9314sewardj            segNo, show_SegKind(seg->kind),
474a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            seg->start, seg->end, len_buf
47545f4e7c91119c7d01a59f5e827c67841632c9314sewardj         );
47645f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
47745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
4781340c35bebb175c6d158361596ee6171b4cfc2a2tom      case SkAnonC: case SkAnonV: case SkShmC:
47945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(debugLog)(
48045f4e7c91119c7d01a59f5e827c67841632c9314sewardj            logLevel, "aspacem",
481a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            "%3d: %s %010lx-%010lx %s %c%c%c%c%c\n",
48245f4e7c91119c7d01a59f5e827c67841632c9314sewardj            segNo, show_SegKind(seg->kind),
483a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            seg->start, seg->end, len_buf,
48445f4e7c91119c7d01a59f5e827c67841632c9314sewardj            seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
48545f4e7c91119c7d01a59f5e827c67841632c9314sewardj            seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
48645f4e7c91119c7d01a59f5e827c67841632c9314sewardj            seg->isCH ? 'H' : '-'
48745f4e7c91119c7d01a59f5e827c67841632c9314sewardj         );
48845f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
48945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
49045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkFileC: case SkFileV:
49145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(debugLog)(
49245f4e7c91119c7d01a59f5e827c67841632c9314sewardj            logLevel, "aspacem",
493a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            "%3d: %s %010lx-%010lx %s %c%c%c%c%c d=0x%03llx "
494a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            "i=%-7llu o=%-7lld (%d,%d)\n",
49545f4e7c91119c7d01a59f5e827c67841632c9314sewardj            segNo, show_SegKind(seg->kind),
496a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            seg->start, seg->end, len_buf,
49745f4e7c91119c7d01a59f5e827c67841632c9314sewardj            seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
49845f4e7c91119c7d01a59f5e827c67841632c9314sewardj            seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
49945f4e7c91119c7d01a59f5e827c67841632c9314sewardj            seg->isCH ? 'H' : '-',
500e6c3b4348515ac6ea803b8c1908c476a05261f71philippe            seg->dev, seg->ino, seg->offset,
5014ecd48360351f666f008148c12a24cbda455c6b1florian            ML_(am_segname_get_seqnr)(seg->fnIdx), seg->fnIdx
50245f4e7c91119c7d01a59f5e827c67841632c9314sewardj         );
50345f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
50445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
50545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkResvn:
50645f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(debugLog)(
50745f4e7c91119c7d01a59f5e827c67841632c9314sewardj            logLevel, "aspacem",
508a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            "%3d: %s %010lx-%010lx %s %c%c%c%c%c %s\n",
50945f4e7c91119c7d01a59f5e827c67841632c9314sewardj            segNo, show_SegKind(seg->kind),
510a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            seg->start, seg->end, len_buf,
51145f4e7c91119c7d01a59f5e827c67841632c9314sewardj            seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
51245f4e7c91119c7d01a59f5e827c67841632c9314sewardj            seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
51345f4e7c91119c7d01a59f5e827c67841632c9314sewardj            seg->isCH ? 'H' : '-',
51445f4e7c91119c7d01a59f5e827c67841632c9314sewardj            show_ShrinkMode(seg->smode)
51545f4e7c91119c7d01a59f5e827c67841632c9314sewardj         );
51645f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
51745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
51845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      default:
51945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(debugLog)(
52045f4e7c91119c7d01a59f5e827c67841632c9314sewardj            logLevel, "aspacem",
52145f4e7c91119c7d01a59f5e827c67841632c9314sewardj            "%3d: ???? UNKNOWN SEGMENT KIND\n",
52245f4e7c91119c7d01a59f5e827c67841632c9314sewardj            segNo
52345f4e7c91119c7d01a59f5e827c67841632c9314sewardj         );
52445f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
52545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
52645f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
52745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
52845f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Print out the segment array (debugging only!). */
529dbb3584f591710a15a437918c0fc27e300993566florianvoid VG_(am_show_nsegments) ( Int logLevel, const HChar* who )
53045f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
53145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int i;
53245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(logLevel, "aspacem",
533346ee2f7978bf2ab1ead4982e56870da276fc44bflorian                 "<<< SHOW_SEGMENTS: %s (%d segments)\n",
534346ee2f7978bf2ab1ead4982e56870da276fc44bflorian                 who, nsegments_used);
5354ecd48360351f666f008148c12a24cbda455c6b1florian   ML_(am_show_segnames)( logLevel, who);
53645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (i = 0; i < nsegments_used; i++)
53745f4e7c91119c7d01a59f5e827c67841632c9314sewardj     show_nsegment( logLevel, i, &nsegments[i] );
53845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(logLevel, "aspacem",
53945f4e7c91119c7d01a59f5e827c67841632c9314sewardj                 ">>>\n");
54045f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
54145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
54245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
54345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Get the filename corresponding to this segment, if known and if it
54495af4ce809c85e3659843aa4156089c80b2b4353florian   has one. */
545d3166c4cf9d2545242da71d8baeaaf203b02a09dflorianconst HChar* VG_(am_get_filename)( NSegment const * seg )
54645f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
54745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(seg);
5484ecd48360351f666f008148c12a24cbda455c6b1florian   return ML_(am_get_segname)( seg->fnIdx );
54945f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
55045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
551ea8a88c21eecdd9e91c75ccbd3c864e708e2f41bflorian/* Collect up the start addresses of segments whose kind matches one of
552ea8a88c21eecdd9e91c75ccbd3c864e708e2f41bflorian   the kinds specified in kind_mask.
55345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   The interface is a bit strange in order to avoid potential
55445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   segment-creation races caused by dynamic allocation of the result
55545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   buffer *starts.
55645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
55745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   The function first computes how many entries in the result
55845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   buffer *starts will be needed.  If this number <= nStarts,
55945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   they are placed in starts[0..], and the number is returned.
56045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   If nStarts is not large enough, nothing is written to
56145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   starts[0..], and the negation of the size is returned.
56245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
56345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Correct use of this function may mean calling it multiple times in
56445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   order to establish a suitably-sized buffer. */
56545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
566ea8a88c21eecdd9e91c75ccbd3c864e708e2f41bflorianInt VG_(am_get_segment_starts)( UInt kind_mask, Addr* starts, Int nStarts )
56745f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
56845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int i, j, nSegs;
56945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
57045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* don't pass dumbass arguments */
5717af930d9cbf43d775f205d61a5429658dd57266fflorian   aspacem_assert(nStarts > 0);
57245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
57345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   nSegs = 0;
57445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (i = 0; i < nsegments_used; i++) {
575ea8a88c21eecdd9e91c75ccbd3c864e708e2f41bflorian      if ((nsegments[i].kind & kind_mask) != 0)
576ea8a88c21eecdd9e91c75ccbd3c864e708e2f41bflorian         nSegs++;
57745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
57845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
57945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (nSegs > nStarts) {
58045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* The buffer isn't big enough.  Tell the caller how big it needs
58145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         to be. */
58245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return -nSegs;
58345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
58445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
58545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* There's enough space.  So write into the result buffer. */
58645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nSegs <= nStarts);
58745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
58845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   j = 0;
58945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (i = 0; i < nsegments_used; i++) {
590ea8a88c21eecdd9e91c75ccbd3c864e708e2f41bflorian      if ((nsegments[i].kind & kind_mask) != 0)
591ea8a88c21eecdd9e91c75ccbd3c864e708e2f41bflorian         starts[j++] = nsegments[i].start;
59245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
59345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
59445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(j == nSegs); /* this should not fail */
59545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return nSegs;
59645f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
59745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
59845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
59945f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
60045f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
60145f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--- Sanity checking and preening of the segment array.        ---*/
60245f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
60345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
60445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
60545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Check representational invariants for NSegments. */
60645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
6073297124fa2116737066ac3cd709f18fdd5405163florianstatic Bool sane_NSegment ( const NSegment* s )
60845f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
60945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (s == NULL) return False;
61045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
61145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* No zero sized segments and no wraparounds. */
612fb823ae9d34cd7dfe189990a9ccfb933762319a1florian   if (s->start > s->end) return False;
61345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
61445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* require page alignment */
61545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!VG_IS_PAGE_ALIGNED(s->start)) return False;
61645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!VG_IS_PAGE_ALIGNED(s->end+1)) return False;
61745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
61845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   switch (s->kind) {
61945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
62045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkFree:
62145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return
62245f4e7c91119c7d01a59f5e827c67841632c9314sewardj            s->smode == SmFixed
62345f4e7c91119c7d01a59f5e827c67841632c9314sewardj            && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
62445f4e7c91119c7d01a59f5e827c67841632c9314sewardj            && !s->hasR && !s->hasW && !s->hasX && !s->hasT
62545f4e7c91119c7d01a59f5e827c67841632c9314sewardj            && !s->isCH;
62645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
6271340c35bebb175c6d158361596ee6171b4cfc2a2tom      case SkAnonC: case SkAnonV: case SkShmC:
62845f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return
62945f4e7c91119c7d01a59f5e827c67841632c9314sewardj            s->smode == SmFixed
63045f4e7c91119c7d01a59f5e827c67841632c9314sewardj            && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
63145f4e7c91119c7d01a59f5e827c67841632c9314sewardj            && (s->kind==SkAnonC ? True : !s->isCH);
63245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
63345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkFileC: case SkFileV:
63445f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return
63545f4e7c91119c7d01a59f5e827c67841632c9314sewardj            s->smode == SmFixed
6364ecd48360351f666f008148c12a24cbda455c6b1florian            && ML_(am_sane_segname)(s->fnIdx)
63745f4e7c91119c7d01a59f5e827c67841632c9314sewardj            && !s->isCH;
63845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
63945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkResvn:
64045f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return
64145f4e7c91119c7d01a59f5e827c67841632c9314sewardj            s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
64245f4e7c91119c7d01a59f5e827c67841632c9314sewardj            && !s->hasR && !s->hasW && !s->hasX && !s->hasT
64345f4e7c91119c7d01a59f5e827c67841632c9314sewardj            && !s->isCH;
64445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
64545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      default:
64645f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return False;
64745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
64845f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
64945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
65045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
65145f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Try merging s2 into s1, if possible.  If successful, s1 is
65245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   modified, and True is returned.  Otherwise s1 is unchanged and
65345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   False is returned. */
65445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
6553297124fa2116737066ac3cd709f18fdd5405163florianstatic Bool maybe_merge_nsegments ( NSegment* s1, const NSegment* s2 )
65645f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
65745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (s1->kind != s2->kind)
65845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
65945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
66045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (s1->end+1 != s2->start)
66145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
66245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
66345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* reject cases which would cause wraparound */
66445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (s1->start > s2->end)
66545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
66645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
66745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   switch (s1->kind) {
66845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
66945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkFree:
67045f4e7c91119c7d01a59f5e827c67841632c9314sewardj         s1->end = s2->end;
67145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return True;
67245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
67345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkAnonC: case SkAnonV:
67445f4e7c91119c7d01a59f5e827c67841632c9314sewardj         if (s1->hasR == s2->hasR && s1->hasW == s2->hasW
67545f4e7c91119c7d01a59f5e827c67841632c9314sewardj             && s1->hasX == s2->hasX && s1->isCH == s2->isCH) {
67645f4e7c91119c7d01a59f5e827c67841632c9314sewardj            s1->end = s2->end;
67745f4e7c91119c7d01a59f5e827c67841632c9314sewardj            s1->hasT |= s2->hasT;
67845f4e7c91119c7d01a59f5e827c67841632c9314sewardj            return True;
67945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         }
68045f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
68145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
68245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkFileC: case SkFileV:
68345f4e7c91119c7d01a59f5e827c67841632c9314sewardj         if (s1->hasR == s2->hasR
68445f4e7c91119c7d01a59f5e827c67841632c9314sewardj             && s1->hasW == s2->hasW && s1->hasX == s2->hasX
68545f4e7c91119c7d01a59f5e827c67841632c9314sewardj             && s1->dev == s2->dev && s1->ino == s2->ino
68645f4e7c91119c7d01a59f5e827c67841632c9314sewardj             && s2->offset == s1->offset
68745f4e7c91119c7d01a59f5e827c67841632c9314sewardj                              + ((ULong)s2->start) - ((ULong)s1->start) ) {
68845f4e7c91119c7d01a59f5e827c67841632c9314sewardj            s1->end = s2->end;
68945f4e7c91119c7d01a59f5e827c67841632c9314sewardj            s1->hasT |= s2->hasT;
6904ecd48360351f666f008148c12a24cbda455c6b1florian            ML_(am_dec_refcount)(s1->fnIdx);
69145f4e7c91119c7d01a59f5e827c67841632c9314sewardj            return True;
69245f4e7c91119c7d01a59f5e827c67841632c9314sewardj         }
69345f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
69445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
6951340c35bebb175c6d158361596ee6171b4cfc2a2tom      case SkShmC:
6961340c35bebb175c6d158361596ee6171b4cfc2a2tom         return False;
6971340c35bebb175c6d158361596ee6171b4cfc2a2tom
698613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj      case SkResvn:
699613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj         if (s1->smode == SmFixed && s2->smode == SmFixed) {
700613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj            s1->end = s2->end;
701613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj            return True;
702613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj         }
703613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj
70445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      default:
70545f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
70645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
70745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
70845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
70945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return False;
71045f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
71145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
71245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
71345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Sanity-check and canonicalise the segment array (merge mergable
71445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   segments).  Returns True if any segments were merged. */
71545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
71645f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic Bool preen_nsegments ( void )
71745f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
71895af4ce809c85e3659843aa4156089c80b2b4353florian   Int i, r, w, nsegments_used_old = nsegments_used;
71945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
72045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Pass 1: check the segment array covers the entire address space
72145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      exactly once, and also that each segment is sane. */
72245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments_used > 0);
72345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments[0].start == Addr_MIN);
72445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments[nsegments_used-1].end == Addr_MAX);
72545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
72645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(sane_NSegment(&nsegments[0]));
72745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (i = 1; i < nsegments_used; i++) {
72845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      aspacem_assert(sane_NSegment(&nsegments[i]));
72945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      aspacem_assert(nsegments[i-1].end+1 == nsegments[i].start);
73045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
73145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
73245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Pass 2: merge as much as possible, using
73345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      maybe_merge_segments. */
73445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   w = 0;
73545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (r = 1; r < nsegments_used; r++) {
73645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (maybe_merge_nsegments(&nsegments[w], &nsegments[r])) {
73745f4e7c91119c7d01a59f5e827c67841632c9314sewardj         /* nothing */
73845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      } else {
73945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         w++;
74045f4e7c91119c7d01a59f5e827c67841632c9314sewardj         if (w != r)
74145f4e7c91119c7d01a59f5e827c67841632c9314sewardj            nsegments[w] = nsegments[r];
74245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
74345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
74445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   w++;
74545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(w > 0 && w <= nsegments_used);
74645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   nsegments_used = w;
74745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
74845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return nsegments_used != nsegments_used_old;
74945f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
75045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
75145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
75245f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Check the segment array corresponds with the kernel's view of
75345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   memory layout.  sync_check_ok returns True if no anomalies were
75445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   found, else False.  In the latter case the mismatching segments are
75545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   displayed.
75645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
75745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   The general idea is: we get the kernel to show us all its segments
75845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   and also the gaps in between.  For each such interval, try and find
75945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   a sequence of appropriate intervals in our segment array which
76045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   cover or more than cover the kernel's interval, and which all have
76145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   suitable kinds/permissions etc.
76245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
76345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Although any specific kernel interval is not matched exactly to a
76445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   valgrind interval or sequence thereof, eventually any disagreement
76545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   on mapping boundaries will be detected.  This is because, if for
76645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   example valgrind's intervals cover a greater range than the current
76745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   kernel interval, it must be the case that a neighbouring free-space
76845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   interval belonging to valgrind cannot cover the neighbouring
76945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   free-space interval belonging to the kernel.  So the disagreement
77045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   is detected.
77145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
77245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   In other words, we examine each kernel interval in turn, and check
77345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   we do not disagree over the range of that interval.  Because all of
77445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   the address space is examined, any disagreements must eventually be
77545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   detected.
77679048ce723a3463c70257ce647f04b111de71863sewardj*/
77745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
77845f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic Bool sync_check_ok = False;
77945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
78045f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic void sync_check_mapping_callback ( Addr addr, SizeT len, UInt prot,
781c4431bfe04c7490ea2d74939d222d87f13f30960njn                                          ULong dev, ULong ino, Off64T offset,
782dbb3584f591710a15a437918c0fc27e300993566florian                                          const HChar* filename )
78345f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
784aa34929c0d86ce6577bc43da5f3d922bc8d595a2sewardj   Int  iLo, iHi, i;
785954d6bb39f9109ee58b69d346894c50b78605c50florian   Bool sloppyXcheck, sloppyRcheck;
78645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
78745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* If a problem has already been detected, don't continue comparing
78845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      segments, so as to avoid flooding the output with error
78945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      messages. */
790f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#if !defined(VGO_darwin)
791f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* GrP fixme not */
79245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!sync_check_ok)
79345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return;
794f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#endif
79545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (len == 0)
79645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return;
79745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
79845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* The kernel should not give us wraparounds. */
79945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(addr <= addr + len - 1);
80045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
80145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   iLo = find_nsegment_idx( addr );
80245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   iHi = find_nsegment_idx( addr + len - 1 );
80345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
80445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* These 5 should be guaranteed by find_nsegment_idx. */
80545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(0 <= iLo && iLo < nsegments_used);
80645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(0 <= iHi && iHi < nsegments_used);
80745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(iLo <= iHi);
80845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments[iLo].start <= addr );
80945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments[iHi].end   >= addr + len - 1 );
81045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
811aa34929c0d86ce6577bc43da5f3d922bc8d595a2sewardj   /* x86 doesn't differentiate 'x' and 'r' (at least, all except the
812c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom      most recent NX-bit enabled CPUs) and so recent kernels attempt
813c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom      to provide execute protection by placing all executable mappings
814c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom      low down in the address space and then reducing the size of the
815c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom      code segment to prevent code at higher addresses being executed.
816c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom
817c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom      These kernels report which mappings are really executable in
818c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom      the /proc/self/maps output rather than mirroring what was asked
819c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom      for when each mapping was created. In order to cope with this we
820b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj      have a sloppyXcheck mode which we enable on x86 and s390 - in this
821b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj      mode we allow the kernel to report execute permission when we weren't
822c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom      expecting it but not vice versa. */
823b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj#  if defined(VGA_x86) || defined (VGA_s390x)
824c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom   sloppyXcheck = True;
8254c245e595b9f6300d3120408ca873f7115d9cc7dnjn#  else
8264c245e595b9f6300d3120408ca873f7115d9cc7dnjn   sloppyXcheck = False;
827aa34929c0d86ce6577bc43da5f3d922bc8d595a2sewardj#  endif
828aa34929c0d86ce6577bc43da5f3d922bc8d595a2sewardj
829954d6bb39f9109ee58b69d346894c50b78605c50florian   /* Some kernels on s390 provide 'r' permission even when it was not
830a6cece92d30ee2213e6fd1960488e6f19022855brhyskidd      explicitly requested. It seems that 'x' permission implies 'r'.
831a6cece92d30ee2213e6fd1960488e6f19022855brhyskidd      This behaviour also occurs on OS X. */
832a6cece92d30ee2213e6fd1960488e6f19022855brhyskidd#  if defined(VGA_s390x) || defined(VGO_darwin)
833954d6bb39f9109ee58b69d346894c50b78605c50florian   sloppyRcheck = True;
834954d6bb39f9109ee58b69d346894c50b78605c50florian#  else
835954d6bb39f9109ee58b69d346894c50b78605c50florian   sloppyRcheck = False;
836954d6bb39f9109ee58b69d346894c50b78605c50florian#  endif
837954d6bb39f9109ee58b69d346894c50b78605c50florian
83845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* NSegments iLo .. iHi inclusive should agree with the presented
83945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      data. */
84045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (i = iLo; i <= iHi; i++) {
84145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
84245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      Bool same, cmp_offsets, cmp_devino;
843aa55dcae7b925e113f6fe3eda73cd940f0e4f209tom      UInt seg_prot;
84445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
84545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* compare the kernel's offering against ours. */
84645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      same = nsegments[i].kind == SkAnonC
84745f4e7c91119c7d01a59f5e827c67841632c9314sewardj             || nsegments[i].kind == SkAnonV
84845f4e7c91119c7d01a59f5e827c67841632c9314sewardj             || nsegments[i].kind == SkFileC
8491340c35bebb175c6d158361596ee6171b4cfc2a2tom             || nsegments[i].kind == SkFileV
8501340c35bebb175c6d158361596ee6171b4cfc2a2tom             || nsegments[i].kind == SkShmC;
85145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
852aa55dcae7b925e113f6fe3eda73cd940f0e4f209tom      seg_prot = 0;
853aa55dcae7b925e113f6fe3eda73cd940f0e4f209tom      if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
854aa55dcae7b925e113f6fe3eda73cd940f0e4f209tom      if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
855aa55dcae7b925e113f6fe3eda73cd940f0e4f209tom      if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
856aa55dcae7b925e113f6fe3eda73cd940f0e4f209tom
85745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      cmp_offsets
85845f4e7c91119c7d01a59f5e827c67841632c9314sewardj         = nsegments[i].kind == SkFileC || nsegments[i].kind == SkFileV;
859616cf594d1c06d74632ef291c51c0545e3906f92sewardj
86045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      cmp_devino
86145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         = nsegments[i].dev != 0 || nsegments[i].ino != 0;
86245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
863616cf594d1c06d74632ef291c51c0545e3906f92sewardj      /* Consider other reasons to not compare dev/inode */
864f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#if defined(VGO_linux)
865616cf594d1c06d74632ef291c51c0545e3906f92sewardj      /* bproc does some godawful hack on /dev/zero at process
866616cf594d1c06d74632ef291c51c0545e3906f92sewardj         migration, which changes the name of it, and its dev & ino */
867616cf594d1c06d74632ef291c51c0545e3906f92sewardj      if (filename && 0==VG_(strcmp)(filename, "/dev/zero (deleted)"))
868616cf594d1c06d74632ef291c51c0545e3906f92sewardj         cmp_devino = False;
869616cf594d1c06d74632ef291c51c0545e3906f92sewardj
870f36e99ae1e4abc42b1b35bbdafc19a19e149b490sewardj      /* hack apparently needed on MontaVista Linux */
871f36e99ae1e4abc42b1b35bbdafc19a19e149b490sewardj      if (filename && VG_(strstr)(filename, "/.lib-ro/"))
872f36e99ae1e4abc42b1b35bbdafc19a19e149b490sewardj         cmp_devino = False;
873f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#endif
874f36e99ae1e4abc42b1b35bbdafc19a19e149b490sewardj
875f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#if defined(VGO_darwin)
876f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      // GrP fixme kernel info doesn't have dev/inode
877f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      cmp_devino = False;
878f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
879f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      // GrP fixme V and kernel don't agree on offsets
880f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      cmp_offsets = False;
881f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#endif
882f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
883c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom      /* If we are doing sloppy execute permission checks then we
884c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom         allow segment to have X permission when we weren't expecting
885c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom         it (but not vice versa) so if the kernel reported execute
886c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom         permission then pretend that this segment has it regardless
887c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom         of what we were expecting. */
888c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom      if (sloppyXcheck && (prot & VKI_PROT_EXEC) != 0) {
889c28e3ddb9aaf5b6cc093c91eabb42e1e884444edtom         seg_prot |= VKI_PROT_EXEC;
890aa34929c0d86ce6577bc43da5f3d922bc8d595a2sewardj      }
891aa34929c0d86ce6577bc43da5f3d922bc8d595a2sewardj
892954d6bb39f9109ee58b69d346894c50b78605c50florian      if (sloppyRcheck && (prot & (VKI_PROT_EXEC | VKI_PROT_READ)) ==
893954d6bb39f9109ee58b69d346894c50b78605c50florian          (VKI_PROT_EXEC | VKI_PROT_READ)) {
894954d6bb39f9109ee58b69d346894c50b78605c50florian         seg_prot |= VKI_PROT_READ;
895954d6bb39f9109ee58b69d346894c50b78605c50florian      }
896954d6bb39f9109ee58b69d346894c50b78605c50florian
89745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      same = same
898aa55dcae7b925e113f6fe3eda73cd940f0e4f209tom             && seg_prot == prot
89945f4e7c91119c7d01a59f5e827c67841632c9314sewardj             && (cmp_devino
90045f4e7c91119c7d01a59f5e827c67841632c9314sewardj                   ? (nsegments[i].dev == dev && nsegments[i].ino == ino)
90145f4e7c91119c7d01a59f5e827c67841632c9314sewardj                   : True)
90245f4e7c91119c7d01a59f5e827c67841632c9314sewardj             && (cmp_offsets
90345f4e7c91119c7d01a59f5e827c67841632c9314sewardj                   ? nsegments[i].start-nsegments[i].offset == addr-offset
90445f4e7c91119c7d01a59f5e827c67841632c9314sewardj                   : True);
90545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (!same) {
906ddaef35bf689bb5192881aa6d455050e1423df7cnjn         Addr start = addr;
907ddaef35bf689bb5192881aa6d455050e1423df7cnjn         Addr end = start + len - 1;
908ddaef35bf689bb5192881aa6d455050e1423df7cnjn         HChar len_buf[20];
909ddaef35bf689bb5192881aa6d455050e1423df7cnjn         show_len_concisely(len_buf, start, end);
910ddaef35bf689bb5192881aa6d455050e1423df7cnjn
91145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         sync_check_ok = False;
912ddaef35bf689bb5192881aa6d455050e1423df7cnjn
91345f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(debugLog)(
91445f4e7c91119c7d01a59f5e827c67841632c9314sewardj            0,"aspacem",
915ddaef35bf689bb5192881aa6d455050e1423df7cnjn              "segment mismatch: V's seg 1st, kernel's 2nd:\n");
916ddaef35bf689bb5192881aa6d455050e1423df7cnjn         show_nsegment_full( 0, i, &nsegments[i] );
917ddaef35bf689bb5192881aa6d455050e1423df7cnjn         VG_(debugLog)(0,"aspacem",
918a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            "...: .... %010lx-%010lx %s %c%c%c.. ....... "
919a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            "d=0x%03llx i=%-7llu o=%-7lld (.) m=. %s\n",
920a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            start, end, len_buf,
921ddaef35bf689bb5192881aa6d455050e1423df7cnjn            prot & VKI_PROT_READ  ? 'r' : '-',
922ddaef35bf689bb5192881aa6d455050e1423df7cnjn            prot & VKI_PROT_WRITE ? 'w' : '-',
923ddaef35bf689bb5192881aa6d455050e1423df7cnjn            prot & VKI_PROT_EXEC  ? 'x' : '-',
924dbb3584f591710a15a437918c0fc27e300993566florian            dev, ino, offset, filename ? filename : "(none)" );
925ddaef35bf689bb5192881aa6d455050e1423df7cnjn
926ddaef35bf689bb5192881aa6d455050e1423df7cnjn         return;
92745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
92845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
92945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
93045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Looks harmless.  Keep going. */
93145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return;
93245f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
93345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
93445f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic void sync_check_gap_callback ( Addr addr, SizeT len )
93545f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
93645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int iLo, iHi, i;
93745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
93845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* If a problem has already been detected, don't continue comparing
93945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      segments, so as to avoid flooding the output with error
94045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      messages. */
941f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#if !defined(VGO_darwin)
942f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* GrP fixme not */
94345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!sync_check_ok)
94445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return;
945f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#endif
94645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (len == 0)
94745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return;
94845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
94945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* The kernel should not give us wraparounds. */
95045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(addr <= addr + len - 1);
95145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
95245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   iLo = find_nsegment_idx( addr );
95345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   iHi = find_nsegment_idx( addr + len - 1 );
95445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
95545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* These 5 should be guaranteed by find_nsegment_idx. */
95645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(0 <= iLo && iLo < nsegments_used);
95745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(0 <= iHi && iHi < nsegments_used);
95845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(iLo <= iHi);
95945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments[iLo].start <= addr );
96045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments[iHi].end   >= addr + len - 1 );
96145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
96245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* NSegments iLo .. iHi inclusive should agree with the presented
96345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      data. */
96445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (i = iLo; i <= iHi; i++) {
96545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
96645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      Bool same;
96745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
96845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* compare the kernel's offering against ours. */
96945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      same = nsegments[i].kind == SkFree
97045f4e7c91119c7d01a59f5e827c67841632c9314sewardj             || nsegments[i].kind == SkResvn;
97145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
97245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (!same) {
973ddaef35bf689bb5192881aa6d455050e1423df7cnjn         Addr start = addr;
974ddaef35bf689bb5192881aa6d455050e1423df7cnjn         Addr end = start + len - 1;
975ddaef35bf689bb5192881aa6d455050e1423df7cnjn         HChar len_buf[20];
976ddaef35bf689bb5192881aa6d455050e1423df7cnjn         show_len_concisely(len_buf, start, end);
977ddaef35bf689bb5192881aa6d455050e1423df7cnjn
97845f4e7c91119c7d01a59f5e827c67841632c9314sewardj         sync_check_ok = False;
979ddaef35bf689bb5192881aa6d455050e1423df7cnjn
98045f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(debugLog)(
98145f4e7c91119c7d01a59f5e827c67841632c9314sewardj            0,"aspacem",
982ddaef35bf689bb5192881aa6d455050e1423df7cnjn              "segment mismatch: V's gap 1st, kernel's 2nd:\n");
983ddaef35bf689bb5192881aa6d455050e1423df7cnjn         show_nsegment_full( 0, i, &nsegments[i] );
984ddaef35bf689bb5192881aa6d455050e1423df7cnjn         VG_(debugLog)(0,"aspacem",
985a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            "   : .... %010lx-%010lx %s\n",
986a5e06c36bf9d93461bc8c4351e960888020ea1c4florian            start, end, len_buf);
987ddaef35bf689bb5192881aa6d455050e1423df7cnjn         return;
98845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
98945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
99045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
99145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Looks harmless.  Keep going. */
99245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return;
99345f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
99445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
99545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
99645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Sanity check: check that Valgrind and the kernel agree on the
99745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   address space layout.  Prints offending segments and call point if
99845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   a discrepancy is detected, but does not abort the system.  Returned
99945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool is False if a discrepancy was found. */
100045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
100145f4e7c91119c7d01a59f5e827c67841632c9314sewardjBool VG_(am_do_sync_check) ( const HChar* fn,
100245f4e7c91119c7d01a59f5e827c67841632c9314sewardj                             const HChar* file, Int line )
100345f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
100445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   sync_check_ok = True;
100545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (0)
100645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      VG_(debugLog)(0,"aspacem", "do_sync_check %s:%d\n", file,line);
1007cb249ab3febb3757a0b0582be21952efacf415e5sewardj   parse_procselfmaps( sync_check_mapping_callback,
1008cb249ab3febb3757a0b0582be21952efacf415e5sewardj                       sync_check_gap_callback );
100945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!sync_check_ok) {
101045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      VG_(debugLog)(0,"aspacem",
101145f4e7c91119c7d01a59f5e827c67841632c9314sewardj                      "sync check at %s:%d (%s): FAILED\n",
101245f4e7c91119c7d01a59f5e827c67841632c9314sewardj                      file, line, fn);
101345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      VG_(debugLog)(0,"aspacem", "\n");
101445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
101545f4e7c91119c7d01a59f5e827c67841632c9314sewardj#     if 0
101645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      {
10177b7d59405204f88cb944155d6bc5114025ebda98florian         HChar buf[100];   // large enough
101845f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(am_show_nsegments)(0,"post syncheck failure");
101945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(sprintf)(buf, "/bin/cat /proc/%d/maps", VG_(getpid)());
102045f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(system)(buf);
102145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
102245f4e7c91119c7d01a59f5e827c67841632c9314sewardj#     endif
102345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
102445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
102545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return sync_check_ok;
102645f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
102745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1028297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj/* Hook to allow sanity checks to be done from aspacemgr-common.c. */
1029297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardjvoid ML_(am_do_sanity_check)( void )
1030297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj{
1031297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj   AM_SANITY_CHECK;
1032297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj}
1033297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj
103445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
103545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
103645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
103745f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--- Low level access / modification of the segment array.     ---*/
103845f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
103945f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
104045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
104145f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Binary search the interval array for a given address.  Since the
1042a364d119b3847143d804e388d7a37c2c82be93bfsewardj   array covers the entire address space the search cannot fail.  The
1043a364d119b3847143d804e388d7a37c2c82be93bfsewardj   _WRK function does the real work.  Its caller (just below) caches
1044a364d119b3847143d804e388d7a37c2c82be93bfsewardj   the results thereof, to save time.  With N_CACHE of 63 we get a hit
1045a364d119b3847143d804e388d7a37c2c82be93bfsewardj   rate exceeding 90% when running OpenOffice.
1046a364d119b3847143d804e388d7a37c2c82be93bfsewardj
1047a364d119b3847143d804e388d7a37c2c82be93bfsewardj   Re ">> 12", it doesn't matter that the page size of some targets
1048a364d119b3847143d804e388d7a37c2c82be93bfsewardj   might be different from 12.  Really "(a >> 12) % N_CACHE" is merely
1049a364d119b3847143d804e388d7a37c2c82be93bfsewardj   a hash function, and the actual cache entry is always validated
1050a364d119b3847143d804e388d7a37c2c82be93bfsewardj   correctly against the selected cache entry before use.
1051a364d119b3847143d804e388d7a37c2c82be93bfsewardj*/
1052a364d119b3847143d804e388d7a37c2c82be93bfsewardj/* Don't call find_nsegment_idx_WRK; use find_nsegment_idx instead. */
1053a364d119b3847143d804e388d7a37c2c82be93bfsewardj__attribute__((noinline))
1054a364d119b3847143d804e388d7a37c2c82be93bfsewardjstatic Int find_nsegment_idx_WRK ( Addr a )
1055548be6d64c58729588a559b1512ad7625bc1b86esewardj{
105645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr a_mid_lo, a_mid_hi;
105745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int  mid,
105845f4e7c91119c7d01a59f5e827c67841632c9314sewardj        lo = 0,
105945f4e7c91119c7d01a59f5e827c67841632c9314sewardj        hi = nsegments_used-1;
106045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   while (True) {
106145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* current unsearched space is from lo to hi, inclusive. */
106245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (lo > hi) {
106345f4e7c91119c7d01a59f5e827c67841632c9314sewardj         /* Not found.  This can't happen. */
1064297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj         ML_(am_barf)("find_nsegment_idx: not found");
106545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
106645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      mid      = (lo + hi) / 2;
106745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      a_mid_lo = nsegments[mid].start;
106845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      a_mid_hi = nsegments[mid].end;
106945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
107045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (a < a_mid_lo) { hi = mid-1; continue; }
107145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (a > a_mid_hi) { lo = mid+1; continue; }
107245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      aspacem_assert(a >= a_mid_lo && a <= a_mid_hi);
107345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      aspacem_assert(0 <= mid && mid < nsegments_used);
107445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return mid;
107545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
107645f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
107745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1078a364d119b3847143d804e388d7a37c2c82be93bfsewardjinline static Int find_nsegment_idx ( Addr a )
1079a364d119b3847143d804e388d7a37c2c82be93bfsewardj{
1080bbfcb260e026d9da39f5528677f23f619ed686cdsewardj#  define N_CACHE 131 /*prime*/
1081a364d119b3847143d804e388d7a37c2c82be93bfsewardj   static Addr cache_pageno[N_CACHE];
1082a364d119b3847143d804e388d7a37c2c82be93bfsewardj   static Int  cache_segidx[N_CACHE];
1083a364d119b3847143d804e388d7a37c2c82be93bfsewardj   static Bool cache_inited = False;
1084a364d119b3847143d804e388d7a37c2c82be93bfsewardj
1085a364d119b3847143d804e388d7a37c2c82be93bfsewardj   static UWord n_q = 0;
1086a364d119b3847143d804e388d7a37c2c82be93bfsewardj   static UWord n_m = 0;
1087a364d119b3847143d804e388d7a37c2c82be93bfsewardj
1088a364d119b3847143d804e388d7a37c2c82be93bfsewardj   UWord ix;
1089a364d119b3847143d804e388d7a37c2c82be93bfsewardj
1090a364d119b3847143d804e388d7a37c2c82be93bfsewardj   if (LIKELY(cache_inited)) {
1091a364d119b3847143d804e388d7a37c2c82be93bfsewardj      /* do nothing */
1092a364d119b3847143d804e388d7a37c2c82be93bfsewardj   } else {
1093a364d119b3847143d804e388d7a37c2c82be93bfsewardj      for (ix = 0; ix < N_CACHE; ix++) {
1094a364d119b3847143d804e388d7a37c2c82be93bfsewardj         cache_pageno[ix] = 0;
1095a364d119b3847143d804e388d7a37c2c82be93bfsewardj         cache_segidx[ix] = -1;
1096a364d119b3847143d804e388d7a37c2c82be93bfsewardj      }
1097a364d119b3847143d804e388d7a37c2c82be93bfsewardj      cache_inited = True;
1098a364d119b3847143d804e388d7a37c2c82be93bfsewardj   }
1099a364d119b3847143d804e388d7a37c2c82be93bfsewardj
1100a364d119b3847143d804e388d7a37c2c82be93bfsewardj   ix = (a >> 12) % N_CACHE;
1101a364d119b3847143d804e388d7a37c2c82be93bfsewardj
1102a364d119b3847143d804e388d7a37c2c82be93bfsewardj   n_q++;
1103a364d119b3847143d804e388d7a37c2c82be93bfsewardj   if (0 && 0 == (n_q & 0xFFFF))
1104a364d119b3847143d804e388d7a37c2c82be93bfsewardj      VG_(debugLog)(0,"xxx","find_nsegment_idx: %lu %lu\n", n_q, n_m);
1105a364d119b3847143d804e388d7a37c2c82be93bfsewardj
1106a364d119b3847143d804e388d7a37c2c82be93bfsewardj   if ((a >> 12) == cache_pageno[ix]
1107a364d119b3847143d804e388d7a37c2c82be93bfsewardj       && cache_segidx[ix] >= 0
1108a364d119b3847143d804e388d7a37c2c82be93bfsewardj       && cache_segidx[ix] < nsegments_used
1109a364d119b3847143d804e388d7a37c2c82be93bfsewardj       && nsegments[cache_segidx[ix]].start <= a
1110a364d119b3847143d804e388d7a37c2c82be93bfsewardj       && a <= nsegments[cache_segidx[ix]].end) {
1111a364d119b3847143d804e388d7a37c2c82be93bfsewardj      /* hit */
1112a364d119b3847143d804e388d7a37c2c82be93bfsewardj      /* aspacem_assert( cache_segidx[ix] == find_nsegment_idx_WRK(a) ); */
1113a364d119b3847143d804e388d7a37c2c82be93bfsewardj      return cache_segidx[ix];
1114a364d119b3847143d804e388d7a37c2c82be93bfsewardj   }
1115a364d119b3847143d804e388d7a37c2c82be93bfsewardj   /* miss */
1116a364d119b3847143d804e388d7a37c2c82be93bfsewardj   n_m++;
1117a364d119b3847143d804e388d7a37c2c82be93bfsewardj   cache_segidx[ix] = find_nsegment_idx_WRK(a);
1118a364d119b3847143d804e388d7a37c2c82be93bfsewardj   cache_pageno[ix] = a >> 12;
1119a364d119b3847143d804e388d7a37c2c82be93bfsewardj   return cache_segidx[ix];
1120a364d119b3847143d804e388d7a37c2c82be93bfsewardj#  undef N_CACHE
1121a364d119b3847143d804e388d7a37c2c82be93bfsewardj}
1122a364d119b3847143d804e388d7a37c2c82be93bfsewardj
1123a364d119b3847143d804e388d7a37c2c82be93bfsewardj
11247cb1293f977ba78a06a63053e404493d545394edflorian/* Finds the segment containing 'a'.  Only returns non-SkFree segments. */
1125716f31ac50be6070a96b490d0b0bbd39b8e77342sewardjNSegment const * VG_(am_find_nsegment) ( Addr a )
112645f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
112745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int i = find_nsegment_idx(a);
112845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(i >= 0 && i < nsegments_used);
112945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments[i].start <= a);
113045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(a <= nsegments[i].end);
113145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (nsegments[i].kind == SkFree)
113245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return NULL;
113345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   else
113445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return &nsegments[i];
113545f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
113645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
11378eb8bab992e3998c33770b0cdb16059a8b918a06sewardj/* Finds an anonymous segment containing 'a'. Returned pointer is read only. */
11388eb8bab992e3998c33770b0cdb16059a8b918a06sewardjNSegment const *VG_(am_find_anon_segment) ( Addr a )
11398eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
11408eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Int i = find_nsegment_idx(a);
11418eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   aspacem_assert(i >= 0 && i < nsegments_used);
11428eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   aspacem_assert(nsegments[i].start <= a);
11438eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   aspacem_assert(a <= nsegments[i].end);
11448eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV)
11458eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      return &nsegments[i];
11468eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   else
11478eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      return NULL;
11488eb8bab992e3998c33770b0cdb16059a8b918a06sewardj}
114945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1150686b8cad58180b009f8df91509d0a5da2191167aflorian/* Map segment pointer to segment index. */
11513e7986312a0ffc7646b0552d4c4ea3744a870e73florianstatic Int segAddr_to_index ( const NSegment* seg )
115245f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
1153686b8cad58180b009f8df91509d0a5da2191167aflorian   aspacem_assert(seg >= &nsegments[0] && seg < &nsegments[nsegments_used]);
1154686b8cad58180b009f8df91509d0a5da2191167aflorian
1155686b8cad58180b009f8df91509d0a5da2191167aflorian   return seg - &nsegments[0];
115645f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
115745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
115845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
11597cb1293f977ba78a06a63053e404493d545394edflorian/* Find the next segment along from 'here', if it is a non-SkFree segment. */
11603e7986312a0ffc7646b0552d4c4ea3744a870e73florianNSegment const * VG_(am_next_nsegment) ( const NSegment* here, Bool fwds )
116145f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
116245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int i = segAddr_to_index(here);
1163686b8cad58180b009f8df91509d0a5da2191167aflorian
116445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (fwds) {
116545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      i++;
116645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (i >= nsegments_used)
116745f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return NULL;
116845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   } else {
116945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      i--;
117045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (i < 0)
117145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return NULL;
117245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
11737cb1293f977ba78a06a63053e404493d545394edflorian   if (nsegments[i].kind == SkFree)
11747cb1293f977ba78a06a63053e404493d545394edflorian      return NULL;
11757cb1293f977ba78a06a63053e404493d545394edflorian   else
11767cb1293f977ba78a06a63053e404493d545394edflorian      return &nsegments[i];
117745f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
117845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
117945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
118045f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Trivial fn: return the total amount of space in anonymous mappings,
118145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   both for V and the client.  Is used for printing stats in
118245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   out-of-memory messages. */
118345f4e7c91119c7d01a59f5e827c67841632c9314sewardjULong VG_(am_get_anonsize_total)( void )
118445f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
118545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int   i;
118645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   ULong total = 0;
118745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (i = 0; i < nsegments_used; i++) {
118845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV) {
118945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         total += (ULong)nsegments[i].end
119045f4e7c91119c7d01a59f5e827c67841632c9314sewardj                  - (ULong)nsegments[i].start + 1ULL;
119145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
119245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
119345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return total;
119445f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
119545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
119645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1197adfff76735ea5bca870dec8f382b225728e1b32dphilippe/* Test if a piece of memory is addressable by client or by valgrind with at
119845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   least the "prot" protection permissions by examining the underlying
1199a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian   segments. The KINDS argument specifies the allowed segments ADDR may
1200a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian   belong to in order to be considered "valid".
120145f4e7c91119c7d01a59f5e827c67841632c9314sewardj*/
120245f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic
1203a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorianBool is_valid_for( UInt kinds, Addr start, SizeT len, UInt prot )
120445f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
120545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int  i, iLo, iHi;
120645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool needR, needW, needX;
120745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
120845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (len == 0)
120945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return True; /* somewhat dubious case */
121045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (start + len < start)
121145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False; /* reject wraparounds */
121245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
121345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   needR = toBool(prot & VKI_PROT_READ);
121445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   needW = toBool(prot & VKI_PROT_WRITE);
121545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   needX = toBool(prot & VKI_PROT_EXEC);
121645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
121745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   iLo = find_nsegment_idx(start);
121845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(start >= nsegments[iLo].start);
121945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
122045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (start+len-1 <= nsegments[iLo].end) {
122145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* This is a speedup hack which avoids calling find_nsegment_idx
122245f4e7c91119c7d01a59f5e827c67841632c9314sewardj         a second time when possible.  It is always correct to just
122345f4e7c91119c7d01a59f5e827c67841632c9314sewardj         use the "else" clause below, but is_valid_for_client is
122445f4e7c91119c7d01a59f5e827c67841632c9314sewardj         called a lot by the leak checker, so avoiding pointless calls
122545f4e7c91119c7d01a59f5e827c67841632c9314sewardj         to find_nsegment_idx, which can be expensive, is helpful. */
122645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      iHi = iLo;
122745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   } else {
122845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      iHi = find_nsegment_idx(start + len - 1);
122945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
123045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1231a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian   for (i = iLo; i <= iHi; i++) {
1232a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian      if ( (nsegments[i].kind & kinds) != 0
1233a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian           && (needR ? nsegments[i].hasR : True)
1234a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian           && (needW ? nsegments[i].hasW : True)
1235a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian           && (needX ? nsegments[i].hasX : True) ) {
1236a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian         /* ok */
1237a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian      } else {
1238a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian         return False;
123945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
124045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
1241a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian
124245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return True;
124345f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
124445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
124545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Test if a piece of memory is addressable by the client with at
124645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   least the "prot" protection permissions by examining the underlying
124745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   segments. */
124845f4e7c91119c7d01a59f5e827c67841632c9314sewardjBool VG_(am_is_valid_for_client)( Addr start, SizeT len,
124945f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                  UInt prot )
125045f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
1251a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian   const UInt kinds = SkFileC | SkAnonC | SkShmC;
1252a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian
1253a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian   return is_valid_for(kinds, start, len, prot);
125445f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
125545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
125645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Variant of VG_(am_is_valid_for_client) which allows free areas to
125745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   be consider part of the client's addressable space.  It also
125845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   considers reservations to be allowable, since from the client's
125945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   point of view they don't exist. */
126045f4e7c91119c7d01a59f5e827c67841632c9314sewardjBool VG_(am_is_valid_for_client_or_free_or_resvn)
126145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   ( Addr start, SizeT len, UInt prot )
126245f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
1263a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian   const UInt kinds = SkFileC | SkAnonC | SkShmC | SkFree | SkResvn;
1264a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian
1265a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian   return is_valid_for(kinds, start, len, prot);
126645f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
126745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1268e8b9ee37f8a49881dffd1900b5c397768f54a53biraisr/* Checks if a piece of memory consists of either free or reservation
1269e8b9ee37f8a49881dffd1900b5c397768f54a53biraisr   segments. */
1270e8b9ee37f8a49881dffd1900b5c397768f54a53biraisrBool VG_(am_is_free_or_resvn)( Addr start, SizeT len )
1271e8b9ee37f8a49881dffd1900b5c397768f54a53biraisr{
1272e8b9ee37f8a49881dffd1900b5c397768f54a53biraisr   const UInt kinds = SkFree | SkResvn;
1273e8b9ee37f8a49881dffd1900b5c397768f54a53biraisr
1274e8b9ee37f8a49881dffd1900b5c397768f54a53biraisr   return is_valid_for(kinds, start, len, 0);
1275e8b9ee37f8a49881dffd1900b5c397768f54a53biraisr}
1276e8b9ee37f8a49881dffd1900b5c397768f54a53biraisr
127745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1278adfff76735ea5bca870dec8f382b225728e1b32dphilippeBool VG_(am_is_valid_for_valgrind) ( Addr start, SizeT len, UInt prot )
127945f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
1280a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian   const UInt kinds = SkFileV | SkAnonV;
1281a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian
1282a623345e71045f9b4f130d2a9a22c1ad0c101b6fflorian   return is_valid_for(kinds, start, len, prot);
128345f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
128445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
128545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
128645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Returns True if any part of the address range is marked as having
128745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   translations made from it.  This is used to determine when to
128845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   discard code, so if in doubt return True. */
128945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
129045f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic Bool any_Ts_in_range ( Addr start, SizeT len )
129145f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
129245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int iLo, iHi, i;
129345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(len > 0);
129445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(start + len > start);
129545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   iLo = find_nsegment_idx(start);
129645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   iHi = find_nsegment_idx(start + len - 1);
129745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (i = iLo; i <= iHi; i++) {
129845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (nsegments[i].hasT)
129945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return True;
130045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
130145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return False;
130245f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
130345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
130445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
13058f3cd17f6de44d563b7a3b2fdc5be9f0571bcdd8florian/* Check whether ADDR looks like an address or address-to-be located in an
13068f3cd17f6de44d563b7a3b2fdc5be9f0571bcdd8florian   extensible client stack segment. Return true if
13078f3cd17f6de44d563b7a3b2fdc5be9f0571bcdd8florian   (1) ADDR is located in an already mapped stack segment, OR
13088f3cd17f6de44d563b7a3b2fdc5be9f0571bcdd8florian   (2) ADDR is located in a reservation segment into which an abutting SkAnonC
1309017d8f5410cff379575eee4f5056fb1a82a6526bflorian       segment can be extended. */
13108f3cd17f6de44d563b7a3b2fdc5be9f0571bcdd8florianBool VG_(am_addr_is_in_extensible_client_stack)( Addr addr )
1311017d8f5410cff379575eee4f5056fb1a82a6526bflorian{
1312017d8f5410cff379575eee4f5056fb1a82a6526bflorian   const NSegment *seg = nsegments + find_nsegment_idx(addr);
1313017d8f5410cff379575eee4f5056fb1a82a6526bflorian
1314017d8f5410cff379575eee4f5056fb1a82a6526bflorian   switch (seg->kind) {
1315017d8f5410cff379575eee4f5056fb1a82a6526bflorian   case SkFree:
1316017d8f5410cff379575eee4f5056fb1a82a6526bflorian   case SkAnonV:
1317017d8f5410cff379575eee4f5056fb1a82a6526bflorian   case SkFileV:
1318017d8f5410cff379575eee4f5056fb1a82a6526bflorian   case SkFileC:
1319017d8f5410cff379575eee4f5056fb1a82a6526bflorian   case SkShmC:
13208f3cd17f6de44d563b7a3b2fdc5be9f0571bcdd8florian      return False;
1321017d8f5410cff379575eee4f5056fb1a82a6526bflorian
1322017d8f5410cff379575eee4f5056fb1a82a6526bflorian   case SkResvn: {
13238f3cd17f6de44d563b7a3b2fdc5be9f0571bcdd8florian      if (seg->smode != SmUpper) return False;
1324ad4e979f408239dabbaae955d8ffcb84a51a5c85florian      /* If the abutting segment towards higher addresses is an SkAnonC
1325017d8f5410cff379575eee4f5056fb1a82a6526bflorian         segment, then ADDR is a future stack pointer. */
1326017d8f5410cff379575eee4f5056fb1a82a6526bflorian      const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ True);
13278f3cd17f6de44d563b7a3b2fdc5be9f0571bcdd8florian      if (next == NULL || next->kind != SkAnonC) return False;
1328017d8f5410cff379575eee4f5056fb1a82a6526bflorian
1329017d8f5410cff379575eee4f5056fb1a82a6526bflorian      /* OK; looks like a stack segment */
13308f3cd17f6de44d563b7a3b2fdc5be9f0571bcdd8florian      return True;
1331017d8f5410cff379575eee4f5056fb1a82a6526bflorian   }
1332017d8f5410cff379575eee4f5056fb1a82a6526bflorian
1333017d8f5410cff379575eee4f5056fb1a82a6526bflorian   case SkAnonC: {
1334017d8f5410cff379575eee4f5056fb1a82a6526bflorian      /* If the abutting segment towards lower addresses is an SkResvn
1335017d8f5410cff379575eee4f5056fb1a82a6526bflorian         segment, then ADDR is a stack pointer into mapped memory. */
1336017d8f5410cff379575eee4f5056fb1a82a6526bflorian      const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ False);
1337d57686f198efb6fea6b0f5dd932bdf4f2299a96aflorian      if (next == NULL || next->kind != SkResvn || next->smode != SmUpper)
13388f3cd17f6de44d563b7a3b2fdc5be9f0571bcdd8florian         return False;
1339017d8f5410cff379575eee4f5056fb1a82a6526bflorian
1340017d8f5410cff379575eee4f5056fb1a82a6526bflorian      /* OK; looks like a stack segment */
13418f3cd17f6de44d563b7a3b2fdc5be9f0571bcdd8florian      return True;
1342017d8f5410cff379575eee4f5056fb1a82a6526bflorian   }
1343017d8f5410cff379575eee4f5056fb1a82a6526bflorian
1344017d8f5410cff379575eee4f5056fb1a82a6526bflorian   default:
1345017d8f5410cff379575eee4f5056fb1a82a6526bflorian      aspacem_assert(0);   // should never happen
1346017d8f5410cff379575eee4f5056fb1a82a6526bflorian   }
1347017d8f5410cff379575eee4f5056fb1a82a6526bflorian}
1348017d8f5410cff379575eee4f5056fb1a82a6526bflorian
134945f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
135045f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
135145f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--- Modifying the segment array, and constructing segments.   ---*/
135245f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
135345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
135445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
135545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Split the segment containing 'a' into two, so that 'a' is
135645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   guaranteed to be the start of a new segment.  If 'a' is already the
135745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   start of a segment, do nothing. */
135845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
135945f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic void split_nsegment_at ( Addr a )
136045f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
136145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int i, j;
136245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
136345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(a > 0);
136445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(a));
136545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
136645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   i = find_nsegment_idx(a);
136745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(i >= 0 && i < nsegments_used);
136845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
136945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (nsegments[i].start == a)
137045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* 'a' is already the start point of a segment, so nothing to be
137145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         done. */
137245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return;
137345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
137445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* else we have to slide the segments upwards to make a hole */
137545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (nsegments_used >= VG_N_SEGMENTS)
1376297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj      ML_(am_barf_toolow)("VG_N_SEGMENTS");
137745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (j = nsegments_used-1; j > i; j--)
137845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      nsegments[j+1] = nsegments[j];
137945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   nsegments_used++;
138045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
138145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   nsegments[i+1]       = nsegments[i];
138245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   nsegments[i+1].start = a;
138345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   nsegments[i].end     = a-1;
138445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
138545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (nsegments[i].kind == SkFileV || nsegments[i].kind == SkFileC)
138645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      nsegments[i+1].offset
138745f4e7c91119c7d01a59f5e827c67841632c9314sewardj         += ((ULong)nsegments[i+1].start) - ((ULong)nsegments[i].start);
138845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
13894ecd48360351f666f008148c12a24cbda455c6b1florian   ML_(am_inc_refcount)(nsegments[i].fnIdx);
1390346ee2f7978bf2ab1ead4982e56870da276fc44bflorian
139145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(sane_NSegment(&nsegments[i]));
139245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(sane_NSegment(&nsegments[i+1]));
139345f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
139445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
139545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
139645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Do the minimum amount of segment splitting necessary to ensure that
139745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   sLo is the first address denoted by some segment and sHi is the
139845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   highest address denoted by some other segment.  Returns the indices
139945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   of the lowest and highest segments in the range. */
140045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
140145f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic
140245f4e7c91119c7d01a59f5e827c67841632c9314sewardjvoid split_nsegments_lo_and_hi ( Addr sLo, Addr sHi,
140345f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                 /*OUT*/Int* iLo,
140445f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                 /*OUT*/Int* iHi )
140545f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
140645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(sLo < sHi);
140745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(sLo));
140845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(sHi+1));
140945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
141045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (sLo > 0)
141145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      split_nsegment_at(sLo);
141245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (sHi < sHi+1)
141345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      split_nsegment_at(sHi+1);
141445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
141545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   *iLo = find_nsegment_idx(sLo);
141645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   *iHi = find_nsegment_idx(sHi);
141745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(0 <= *iLo && *iLo < nsegments_used);
141845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(0 <= *iHi && *iHi < nsegments_used);
141945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(*iLo <= *iHi);
142045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments[*iLo].start == sLo);
142145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments[*iHi].end == sHi);
142245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Not that I'm overly paranoid or anything, definitely not :-) */
142345f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
142445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
142545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
142645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Add SEG to the collection, deleting/truncating any it overlaps.
142745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   This deals with all the tricky cases of splitting up segments as
142845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   needed. */
142945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
14303297124fa2116737066ac3cd709f18fdd5405163florianstatic void add_segment ( const NSegment* seg )
143145f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
143245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int  i, iLo, iHi, delta;
143345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool segment_is_sane;
143445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
143545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr sStart = seg->start;
143645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr sEnd   = seg->end;
143745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
143845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(sStart <= sEnd);
143945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(sStart));
144045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(sEnd+1));
144145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
144245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   segment_is_sane = sane_NSegment(seg);
1443ddaef35bf689bb5192881aa6d455050e1423df7cnjn   if (!segment_is_sane) show_nsegment_full(0,-1,seg);
144445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(segment_is_sane);
144545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
144645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   split_nsegments_lo_and_hi( sStart, sEnd, &iLo, &iHi );
144745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
144845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Now iLo .. iHi inclusive is the range of segment indices which
144945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      seg will replace.  If we're replacing more than one segment,
1450346ee2f7978bf2ab1ead4982e56870da276fc44bflorian      slide those above the range down to fill the hole. Before doing
1451346ee2f7978bf2ab1ead4982e56870da276fc44bflorian      that decrement the reference counters for the segments names of
1452346ee2f7978bf2ab1ead4982e56870da276fc44bflorian      the replaced segments. */
1453346ee2f7978bf2ab1ead4982e56870da276fc44bflorian   for (i = iLo; i <= iHi; ++i)
14544ecd48360351f666f008148c12a24cbda455c6b1florian      ML_(am_dec_refcount)(nsegments[i].fnIdx);
145545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   delta = iHi - iLo;
145645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(delta >= 0);
145745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (delta > 0) {
145845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      for (i = iLo; i < nsegments_used-delta; i++)
145945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         nsegments[i] = nsegments[i+delta];
146045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      nsegments_used -= delta;
146145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
146245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
146345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   nsegments[iLo] = *seg;
146445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
146545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   (void)preen_nsegments();
146645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (0) VG_(am_show_nsegments)(0,"AFTER preen (add_segment)");
146745f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
146845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
146945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
147045f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Clear out an NSegment record. */
147145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
147245f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic void init_nsegment ( /*OUT*/NSegment* seg )
147345f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
147445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->kind     = SkFree;
147545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->start    = 0;
147645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->end      = 0;
147745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->smode    = SmFixed;
147845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->dev      = 0;
147945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->ino      = 0;
1480f4c231081a5c8ff6f24b3fa1980349199f1d9ea3tom   seg->mode     = 0;
148145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->offset   = 0;
148245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->fnIdx    = -1;
148345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->hasR = seg->hasW = seg->hasX = seg->hasT = seg->isCH = False;
148445f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
148545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
148645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Make an NSegment which holds a reservation. */
148745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
148845f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic void init_resvn ( /*OUT*/NSegment* seg, Addr start, Addr end )
148945f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
149045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(start < end);
149145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
149245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(end+1));
149345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment(seg);
149445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->kind  = SkResvn;
149545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->start = start;
149645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg->end   = end;
149745f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
149845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
149945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
150045f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
150145f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
150245f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--- Startup, including reading /proc/self/maps.               ---*/
150345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
150445f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
150545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
150645f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic void read_maps_callback ( Addr addr, SizeT len, UInt prot,
1507c4431bfe04c7490ea2d74939d222d87f13f30960njn                                 ULong dev, ULong ino, Off64T offset,
1508dbb3584f591710a15a437918c0fc27e300993566florian                                 const HChar* filename )
150945f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
151045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   NSegment seg;
151145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment( &seg );
151245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.start  = addr;
151345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.end    = addr+len-1;
151445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.dev    = dev;
151545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.ino    = ino;
151645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.offset = offset;
151745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasR   = toBool(prot & VKI_PROT_READ);
151845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasW   = toBool(prot & VKI_PROT_WRITE);
151945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasX   = toBool(prot & VKI_PROT_EXEC);
152045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasT   = False;
152145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1522981ffbd4d8f303856a0183e801b934ed7e3cd957florian   /* A segment in the initial /proc/self/maps is considered a FileV
1523981ffbd4d8f303856a0183e801b934ed7e3cd957florian      segment if either it has a file name associated with it or both its
1524981ffbd4d8f303856a0183e801b934ed7e3cd957florian      device and inode numbers are != 0. See bug #124528. */
152545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.kind = SkAnonV;
1526981ffbd4d8f303856a0183e801b934ed7e3cd957florian   if (filename || (dev != 0 && ino != 0))
1527c2fe246d0d85a81c1f63ad3e6f7496667e2f6711sewardj      seg.kind = SkFileV;
152838a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj
152938a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj#  if defined(VGO_darwin)
1530f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // GrP fixme no dev/ino on darwin
1531f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (offset != 0)
153238a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      seg.kind = SkFileV;
153338a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj#  endif // defined(VGO_darwin)
153438a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj
153538a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj#  if defined(VGP_arm_linux)
153638a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj   /* The standard handling of entries read from /proc/self/maps will
153738a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      cause the faked up commpage segment to have type SkAnonV, which
153838a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      is a problem because it contains code we want the client to
153938a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      execute, and so later m_translate will segfault the client when
154038a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      it tries to go in there.  Hence change the ownership of it here
154138a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      to the client (SkAnonC).  The least-worst kludge I could think
154238a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      of. */
154338a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj   if (addr == ARM_LINUX_FAKE_COMMPAGE_START
154438a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj       && addr + len == ARM_LINUX_FAKE_COMMPAGE_END1
154538a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj       && seg.kind == SkAnonV)
154638a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      seg.kind = SkAnonC;
154738a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj#  endif // defined(VGP_arm_linux)
154838a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj
1549c2fe246d0d85a81c1f63ad3e6f7496667e2f6711sewardj   if (filename)
15504ecd48360351f666f008148c12a24cbda455c6b1florian      seg.fnIdx = ML_(am_allocate_segname)( filename );
155145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
155245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (0) show_nsegment( 2,0, &seg );
155345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment( &seg );
1554548be6d64c58729588a559b1512ad7625bc1b86esewardj}
1555548be6d64c58729588a559b1512ad7625bc1b86esewardj
155682e7a5439ce882f99cdb49bc064616d95124738dflorianBool
155782e7a5439ce882f99cdb49bc064616d95124738dflorianVG_(am_is_valid_for_aspacem_minAddr)( Addr addr, const HChar **errmsg )
155882e7a5439ce882f99cdb49bc064616d95124738dflorian{
1559d738b46bd7dd65fe55736744fb3be1f0159d3a58florian   const Addr min = VKI_PAGE_SIZE;
156082e7a5439ce882f99cdb49bc064616d95124738dflorian#if VG_WORDSIZE == 4
156182e7a5439ce882f99cdb49bc064616d95124738dflorian   const Addr max = 0x40000000;  // 1Gb
156282e7a5439ce882f99cdb49bc064616d95124738dflorian#else
156382e7a5439ce882f99cdb49bc064616d95124738dflorian   const Addr max = 0x200000000; // 8Gb
156482e7a5439ce882f99cdb49bc064616d95124738dflorian#endif
156582e7a5439ce882f99cdb49bc064616d95124738dflorian   Bool ok = VG_IS_PAGE_ALIGNED(addr) && addr >= min && addr <= max;
156682e7a5439ce882f99cdb49bc064616d95124738dflorian
156782e7a5439ce882f99cdb49bc064616d95124738dflorian   if (errmsg) {
156882e7a5439ce882f99cdb49bc064616d95124738dflorian      *errmsg = "";
156982e7a5439ce882f99cdb49bc064616d95124738dflorian      if (! ok) {
157082e7a5439ce882f99cdb49bc064616d95124738dflorian         const HChar fmt[] = "Must be a page aligned address between "
157182e7a5439ce882f99cdb49bc064616d95124738dflorian                             "0x%lx and 0x%lx";
157282e7a5439ce882f99cdb49bc064616d95124738dflorian         static HChar buf[sizeof fmt + 2 * 16];   // large enough
157382e7a5439ce882f99cdb49bc064616d95124738dflorian         ML_(am_sprintf)(buf, fmt, min, max);
157482e7a5439ce882f99cdb49bc064616d95124738dflorian         *errmsg = buf;
157582e7a5439ce882f99cdb49bc064616d95124738dflorian      }
157682e7a5439ce882f99cdb49bc064616d95124738dflorian   }
157782e7a5439ce882f99cdb49bc064616d95124738dflorian   return ok;
157882e7a5439ce882f99cdb49bc064616d95124738dflorian}
157982e7a5439ce882f99cdb49bc064616d95124738dflorian
158038a74d2cc4670e3eb559adff51a376cd6ec98005philippe/* See description in pub_core_aspacemgr.h */
158145f4e7c91119c7d01a59f5e827c67841632c9314sewardjAddr VG_(am_startup) ( Addr sp_at_startup )
158245f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
158345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   NSegment seg;
158438a74d2cc4670e3eb559adff51a376cd6ec98005philippe   Addr     suggested_clstack_end;
158545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
158645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(sizeof(Word)   == sizeof(void*));
158745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(sizeof(Addr)   == sizeof(void*));
158845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(sizeof(SizeT)  == sizeof(void*));
158945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(sizeof(SSizeT) == sizeof(void*));
159045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1591346ee2f7978bf2ab1ead4982e56870da276fc44bflorian   /* Initialise the string table for segment names. */
15924ecd48360351f666f008148c12a24cbda455c6b1florian   ML_(am_segnames_init)();
1593346ee2f7978bf2ab1ead4982e56870da276fc44bflorian
1594419060073e7943846cc9e0bcdcb25258d90da2dcsewardj   /* Check that we can store the largest imaginable dev, ino and
1595419060073e7943846cc9e0bcdcb25258d90da2dcsewardj      offset numbers in an NSegment. */
1596419060073e7943846cc9e0bcdcb25258d90da2dcsewardj   aspacem_assert(sizeof(seg.dev)    == 8);
1597419060073e7943846cc9e0bcdcb25258d90da2dcsewardj   aspacem_assert(sizeof(seg.ino)    == 8);
1598419060073e7943846cc9e0bcdcb25258d90da2dcsewardj   aspacem_assert(sizeof(seg.offset) == 8);
1599419060073e7943846cc9e0bcdcb25258d90da2dcsewardj   aspacem_assert(sizeof(seg.mode)   == 4);
160045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
160145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Add a single interval covering the entire address space. */
160245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment(&seg);
160345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.kind        = SkFree;
160445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.start       = Addr_MIN;
160545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.end         = Addr_MAX;
160645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   nsegments[0]    = seg;
160745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   nsegments_used  = 1;
160845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1609e4d78123089e55bec64a4f848bdc09556192e259philippe   aspacem_minAddr = VG_(clo_aspacem_minAddr);
1610e4d78123089e55bec64a4f848bdc09556192e259philippe
1611f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#if defined(VGO_darwin)
1612f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
1613f76d27a697a7b0bf3b84490baf60623fc96a23afnjn# if VG_WORDSIZE == 4
1614f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   aspacem_maxAddr = (Addr) 0xffffffff;
1615f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
1616f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   aspacem_cStart = aspacem_minAddr;
1617f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   aspacem_vStart = 0xf0000000;  // 0xc0000000..0xf0000000 available
1618f76d27a697a7b0bf3b84490baf60623fc96a23afnjn# else
1619f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   aspacem_maxAddr = (Addr) 0x7fffffffffff;
1620f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
1621f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   aspacem_cStart = aspacem_minAddr;
1622f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   aspacem_vStart = 0x700000000000; // 0x7000:00000000..0x7fff:5c000000 avail
1623f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // 0x7fff:5c000000..0x7fff:ffe00000? is stack, dyld, shared cache
1624f76d27a697a7b0bf3b84490baf60623fc96a23afnjn# endif
1625f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
162638a74d2cc4670e3eb559adff51a376cd6ec98005philippe   suggested_clstack_end = -1; // ignored; Mach-O specifies its stack
1627f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
16288eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#elif defined(VGO_solaris)
16298eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  if VG_WORDSIZE == 4
16308eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /*
16318eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      Intended address space partitioning:
16328eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
16338eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      ,--------------------------------, 0x00000000
16348eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |                                |
16358eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------|
16368eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      | initial stack given to V by OS |
16378eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------| 0x08000000
16388eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |          client text           |
16398eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------|
16408eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |                                |
16418eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |                                |
16428eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------|
16438eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |          client stack          |
16448eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------| 0x38000000
16458eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |            V's text            |
16468eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------|
16478eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |                                |
16488eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |                                |
16498eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------|
16508eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |     dynamic shared objects     |
16518eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      '--------------------------------' 0xffffffff
16528eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
16538eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      */
16548eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
16558eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Anonymous pages need to fit under user limit (USERLIMIT32)
16568eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      which is 4KB + 16MB below the top of the 32-bit range. */
16578eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#    ifdef ENABLE_INNER
16588eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     aspacem_maxAddr = (Addr)0x4fffffff; // 1.25GB
16598eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     aspacem_vStart  = (Addr)0x40000000; // 1GB
16608eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#    else
16618eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     aspacem_maxAddr = (Addr)0xfefff000 - 1; // 4GB - 16MB - 4KB
16628eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     aspacem_vStart  = (Addr)0x50000000; // 1.25GB
16638eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#    endif
16648eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  elif VG_WORDSIZE == 8
16658eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /*
16668eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      Intended address space partitioning:
16678eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
16688eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      ,--------------------------------, 0x00000000_00000000
16698eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |                                |
16708eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------| 0x00000000_00400000
16718eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |          client text           |
16728eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------|
16738eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |                                |
16748eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |                                |
16758eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------|
16768eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |          client stack          |
16778eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------| 0x00000000_38000000
16788eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |            V's text            |
16798eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------|
16808eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |                                |
16818eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------|
16828eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |     dynamic shared objects     |
16838eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------| 0x0000000f_ffffffff
16848eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |                                |
16858eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |                                |
16868eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      |--------------------------------|
16878eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      | initial stack given to V by OS |
16888eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      '--------------------------------' 0xffffffff_ffffffff
16898eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
16908eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      */
16918eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
16928eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Kernel likes to place objects at the end of the address space.
16938eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      However accessing memory beyond 64GB makes memcheck slow
16948eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      (see memcheck/mc_main.c, internal representation). Therefore:
16958eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      - mmapobj() syscall is emulated so that libraries are subject to
16968eb8bab992e3998c33770b0cdb16059a8b918a06sewardj        Valgrind's aspacemgr control
16978eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      - Kernel shared pages (such as schedctl and hrt) are left as they are
16988eb8bab992e3998c33770b0cdb16059a8b918a06sewardj        because kernel cannot be told where they should be put */
16998eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#    ifdef ENABLE_INNER
17008eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     aspacem_maxAddr = (Addr) 0x00000007ffffffff; // 32GB
17018eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     aspacem_vStart  = (Addr) 0x0000000400000000; // 16GB
17028eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#    else
17038eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     aspacem_maxAddr = (Addr) 0x0000000fffffffff; // 64GB
17048eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     aspacem_vStart  = (Addr) 0x0000000800000000; // 32GB
17058eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#    endif
17068eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  else
17078eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#    error "Unknown word size"
17088eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  endif
17098eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
17108eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   aspacem_cStart = aspacem_minAddr;
17118eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  ifdef ENABLE_INNER
17128eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   suggested_clstack_end = (Addr) 0x27ff0000 - 1; // 64kB below V's text
17138eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  else
17148eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   suggested_clstack_end = (Addr) 0x37ff0000 - 1; // 64kB below V's text
17158eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  endif
17168eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
17178eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#else
1718f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
171945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Establish address limits and block out unusable parts
172045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      accordingly. */
172145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
172245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(2, "aspacem",
1723a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    "        sp_at_startup = 0x%010lx (supplied)\n",
1724a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    sp_at_startup );
172545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
172645f4e7c91119c7d01a59f5e827c67841632c9314sewardj#  if VG_WORDSIZE == 8
17276805a4a08d862003b6039493eec1b2e6b7829e78sewardj     aspacem_maxAddr = (Addr)0x1000000000ULL - 1; // 64G
172870c91dd9e5768adb7195fe7280aac359c7848984sewardj#    ifdef ENABLE_INNER
1729420c6555d36e7ad19cf3b9e068397435d4acca51sewardj     { Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1;
1730420c6555d36e7ad19cf3b9e068397435d4acca51sewardj       if (aspacem_maxAddr > cse)
1731420c6555d36e7ad19cf3b9e068397435d4acca51sewardj          aspacem_maxAddr = cse;
1732420c6555d36e7ad19cf3b9e068397435d4acca51sewardj     }
173370c91dd9e5768adb7195fe7280aac359c7848984sewardj#    endif
173445f4e7c91119c7d01a59f5e827c67841632c9314sewardj#  else
173570c91dd9e5768adb7195fe7280aac359c7848984sewardj     aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1;
173645f4e7c91119c7d01a59f5e827c67841632c9314sewardj#  endif
173745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1738e4d78123089e55bec64a4f848bdc09556192e259philippe   aspacem_cStart = aspacem_minAddr;
1739d4f5aac98c40fb66d193587d72d024e86cdf3075philippe   aspacem_vStart = VG_PGROUNDUP(aspacem_minAddr
1740d4f5aac98c40fb66d193587d72d024e86cdf3075philippe                                 + (aspacem_maxAddr - aspacem_minAddr + 1) / 2);
174145f4e7c91119c7d01a59f5e827c67841632c9314sewardj#  ifdef ENABLE_INNER
174245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_vStart -= 0x10000000; // 256M
174345f4e7c91119c7d01a59f5e827c67841632c9314sewardj#  endif
174445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
174538a74d2cc4670e3eb559adff51a376cd6ec98005philippe   suggested_clstack_end = aspacem_maxAddr - 16*1024*1024ULL
174645f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                           + VKI_PAGE_SIZE;
174745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
17488eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#endif
1749f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
175045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr));
175145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_maxAddr + 1));
175245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_cStart));
175345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_vStart));
175438a74d2cc4670e3eb559adff51a376cd6ec98005philippe   aspacem_assert(VG_IS_PAGE_ALIGNED(suggested_clstack_end + 1));
175545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
175645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(2, "aspacem",
1757a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    "              minAddr = 0x%010lx (computed)\n",
1758a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    aspacem_minAddr);
175945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(2, "aspacem",
1760a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    "              maxAddr = 0x%010lx (computed)\n",
1761a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    aspacem_maxAddr);
176245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(2, "aspacem",
1763a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    "               cStart = 0x%010lx (computed)\n",
1764a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    aspacem_cStart);
176545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(2, "aspacem",
1766a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    "               vStart = 0x%010lx (computed)\n",
1767a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    aspacem_vStart);
176845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(2, "aspacem",
1769a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    "suggested_clstack_end = 0x%010lx (computed)\n",
1770a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    suggested_clstack_end);
177145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
177245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (aspacem_cStart > Addr_MIN) {
177345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      init_resvn(&seg, Addr_MIN, aspacem_cStart-1);
177445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      add_segment(&seg);
177545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
177645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (aspacem_maxAddr < Addr_MAX) {
177745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      init_resvn(&seg, aspacem_maxAddr+1, Addr_MAX);
177845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      add_segment(&seg);
177945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
178045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
178145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Create a 1-page reservation at the notional initial
178245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      client/valgrind boundary.  This isn't strictly necessary, but
178345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      because the advisor does first-fit and starts searches for
178445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      valgrind allocations at the boundary, this is kind of necessary
178545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      in order to get it to start allocating in the right place. */
178645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_resvn(&seg, aspacem_vStart,  aspacem_vStart + VKI_PAGE_SIZE - 1);
178745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment(&seg);
178845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
178945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(am_show_nsegments)(2, "Initial layout");
179045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
179145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(2, "aspacem", "Reading /proc/self/maps\n");
1792cb249ab3febb3757a0b0582be21952efacf415e5sewardj   parse_procselfmaps( read_maps_callback, NULL );
179338a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj   /* NB: on arm-linux, parse_procselfmaps automagically kludges up
179438a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      (iow, hands to its callbacks) a description of the ARM Commpage,
179538a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      since that's not listed in /proc/self/maps (kernel bug IMO).  We
179638a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      have to fake up its existence in parse_procselfmaps and not
179738a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      merely add it here as an extra segment, because doing the latter
179838a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      causes sync checking to fail: we see we have an extra segment in
179938a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      the segments array, which isn't listed in /proc/self/maps.
180038a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      Hence we must make it appear that /proc/self/maps contained this
180138a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      segment all along.  Sigh. */
180245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
180345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(am_show_nsegments)(2, "With contents of /proc/self/maps");
180445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
180545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
180638a74d2cc4670e3eb559adff51a376cd6ec98005philippe   return suggested_clstack_end;
180745f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
180845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
180945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
181045f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
181145f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
181245f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--- The core query-notify mechanism.                          ---*/
181345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
181445f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
181545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
181645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Query aspacem to ask where a mapping should go. */
181745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
18183297124fa2116737066ac3cd709f18fdd5405163florianAddr VG_(am_get_advisory) ( const MapRequest*  req,
18193297124fa2116737066ac3cd709f18fdd5405163florian                            Bool  forClient,
182045f4e7c91119c7d01a59f5e827c67841632c9314sewardj                            /*OUT*/Bool* ok )
182145f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
182245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* This function implements allocation policy.
182345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
182445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      The nature of the allocation request is determined by req, which
182545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      specifies the start and length of the request and indicates
182645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      whether the start address is mandatory, a hint, or irrelevant,
182745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      and by forClient, which says whether this is for the client or
182845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      for V.
182945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
183045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      Return values: the request can be vetoed (*ok is set to False),
183145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      in which case the caller should not attempt to proceed with
183245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      making the mapping.  Otherwise, *ok is set to True, the caller
183345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      may proceed, and the preferred address at which the mapping
183445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      should happen is returned.
183545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
183645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      Note that this is an advisory system only: the kernel can in
183745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      fact do whatever it likes as far as placement goes, and we have
183845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      no absolute control over it.
183945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
184045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      Allocations will never be granted in a reserved area.
184145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
184245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      The Default Policy is:
184345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
184445f4e7c91119c7d01a59f5e827c67841632c9314sewardj        Search the address space for two free intervals: one of them
184545f4e7c91119c7d01a59f5e827c67841632c9314sewardj        big enough to contain the request without regard to the
184645f4e7c91119c7d01a59f5e827c67841632c9314sewardj        specified address (viz, as if it was a floating request) and
184745f4e7c91119c7d01a59f5e827c67841632c9314sewardj        the other being able to contain the request at the specified
184845f4e7c91119c7d01a59f5e827c67841632c9314sewardj        address (viz, as if were a fixed request).  Then, depending on
184945f4e7c91119c7d01a59f5e827c67841632c9314sewardj        the outcome of the search and the kind of request made, decide
185045f4e7c91119c7d01a59f5e827c67841632c9314sewardj        whether the request is allowable and what address to advise.
185145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
185245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      The Default Policy is overriden by Policy Exception #1:
185345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
185445f4e7c91119c7d01a59f5e827c67841632c9314sewardj        If the request is for a fixed client map, we are prepared to
185545f4e7c91119c7d01a59f5e827c67841632c9314sewardj        grant it providing all areas inside the request are either
185645f4e7c91119c7d01a59f5e827c67841632c9314sewardj        free, reservations, or mappings belonging to the client.  In
185745f4e7c91119c7d01a59f5e827c67841632c9314sewardj        other words we are prepared to let the client trash its own
185845f4e7c91119c7d01a59f5e827c67841632c9314sewardj        mappings if it wants to.
185945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1860caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj      The Default Policy is overriden by Policy Exception #2:
186145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1862caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj        If the request is for a hinted client map, we are prepared to
1863caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj        grant it providing all areas inside the request are either
1864caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj        free or reservations.  In other words we are prepared to let
1865caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj        the client have a hinted mapping anywhere it likes provided
1866caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj        it does not trash either any of its own mappings or any of
1867caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj        valgrind's mappings.
186845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   */
186945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int  i, j;
187045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr holeStart, holeEnd, holeLen;
187145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool fixed_not_required;
187245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
18738eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#if defined(VGO_solaris)
18748eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Addr startPoint = forClient ? aspacem_vStart - 1 : aspacem_maxAddr - 1;
18758eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#else
187645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr startPoint = forClient ? aspacem_cStart : aspacem_vStart;
18778eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#endif /* VGO_solaris */
187845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
18798eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Addr reqStart = req->rkind==MFixed || req->rkind==MHint ? req->start : 0;
188045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr reqEnd   = reqStart + req->len - 1;
188145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr reqLen   = req->len;
188245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
188345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* These hold indices for segments found during search, or -1 if not
188445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      found. */
188545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int floatIdx = -1;
188645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int fixedIdx = -1;
188745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
188845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments_used > 0);
188945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
189045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (0) {
189145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      VG_(am_show_nsegments)(0,"getAdvisory");
1892a5e06c36bf9d93461bc8c4351e960888020ea1c4florian      VG_(debugLog)(0,"aspacem", "getAdvisory 0x%lx %lu\n",
1893a5e06c36bf9d93461bc8c4351e960888020ea1c4florian                    req->start, req->len);
189445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
189545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
189645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Reject zero-length requests */
189745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (req->len == 0) {
189845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      *ok = False;
189945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return 0;
190045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
190145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
190245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Reject wraparounds */
1903e354a1fd9e4a4ca836d3c6bbf159b5811fa25124florian   if (req->start + req->len < req->start) {
190445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      *ok = False;
190545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return 0;
190645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
190779048ce723a3463c70257ce647f04b111de71863sewardj
190845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* ------ Implement Policy Exception #1 ------ */
190945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1910caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj   if (forClient && req->rkind == MFixed) {
191145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      Int  iLo   = find_nsegment_idx(reqStart);
191245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      Int  iHi   = find_nsegment_idx(reqEnd);
191345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      Bool allow = True;
191445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      for (i = iLo; i <= iHi; i++) {
191545f4e7c91119c7d01a59f5e827c67841632c9314sewardj         if (nsegments[i].kind == SkFree
191645f4e7c91119c7d01a59f5e827c67841632c9314sewardj             || nsegments[i].kind == SkFileC
191745f4e7c91119c7d01a59f5e827c67841632c9314sewardj             || nsegments[i].kind == SkAnonC
19181340c35bebb175c6d158361596ee6171b4cfc2a2tom             || nsegments[i].kind == SkShmC
191945f4e7c91119c7d01a59f5e827c67841632c9314sewardj             || nsegments[i].kind == SkResvn) {
192045f4e7c91119c7d01a59f5e827c67841632c9314sewardj            /* ok */
192145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         } else {
192245f4e7c91119c7d01a59f5e827c67841632c9314sewardj            allow = False;
192345f4e7c91119c7d01a59f5e827c67841632c9314sewardj            break;
192445f4e7c91119c7d01a59f5e827c67841632c9314sewardj         }
192545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
192645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (allow) {
192745f4e7c91119c7d01a59f5e827c67841632c9314sewardj         /* Acceptable.  Granted. */
192845f4e7c91119c7d01a59f5e827c67841632c9314sewardj         *ok = True;
192945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return reqStart;
193045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
1931caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj      /* Not acceptable.  Fail. */
1932caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj      *ok = False;
1933caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj      return 0;
1934caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj   }
1935caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj
1936caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj   /* ------ Implement Policy Exception #2 ------ */
1937caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj
1938caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj   if (forClient && req->rkind == MHint) {
1939caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj      Int  iLo   = find_nsegment_idx(reqStart);
1940caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj      Int  iHi   = find_nsegment_idx(reqEnd);
1941caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj      Bool allow = True;
1942caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj      for (i = iLo; i <= iHi; i++) {
1943caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj         if (nsegments[i].kind == SkFree
1944caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj             || nsegments[i].kind == SkResvn) {
1945caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj            /* ok */
1946caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj         } else {
1947caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj            allow = False;
1948caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj            break;
1949caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj         }
1950caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj      }
1951caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj      if (allow) {
1952caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj         /* Acceptable.  Granted. */
1953caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj         *ok = True;
1954caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj         return reqStart;
195545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
1956caf971dea8c108cbd200dce1c6a94e96bf2e91b1sewardj      /* Not acceptable.  Fall through to the default policy. */
1957548be6d64c58729588a559b1512ad7625bc1b86esewardj   }
1958548be6d64c58729588a559b1512ad7625bc1b86esewardj
195945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* ------ Implement the Default Policy ------ */
1960548be6d64c58729588a559b1512ad7625bc1b86esewardj
196145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Don't waste time looking for a fixed match if not requested to. */
19628eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   fixed_not_required = req->rkind == MAny || req->rkind == MAlign;
196345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
196445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   i = find_nsegment_idx(startPoint);
196545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
19668eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#if defined(VGO_solaris)
19678eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  define UPDATE_INDEX(index)                               \
19688eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      (index)--;                                            \
19698eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      if ((index) <= 0)                                     \
19708eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         (index) = nsegments_used - 1;
19718eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  define ADVISE_ADDRESS(segment)                           \
19728eb8bab992e3998c33770b0cdb16059a8b918a06sewardj       VG_PGROUNDDN((segment)->end + 1 - reqLen)
19738eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  define ADVISE_ADDRESS_ALIGNED(segment)                   \
19748eb8bab992e3998c33770b0cdb16059a8b918a06sewardj        VG_ROUNDDN((segment)->end + 1 - reqLen, req->start)
19758eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
19768eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#else
19778eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
19788eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  define UPDATE_INDEX(index)                               \
19798eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      (index)++;                                            \
19808eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      if ((index) >= nsegments_used)                        \
19818eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         (index) = 0;
19828eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  define ADVISE_ADDRESS(segment)                           \
19838eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      (segment)->start
19848eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  define ADVISE_ADDRESS_ALIGNED(segment)                   \
19858eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      VG_ROUNDUP((segment)->start, req->start)
19868eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#endif /* VGO_solaris */
19878eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
198845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Examine holes from index i back round to i-1.  Record the
198945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      index first fixed hole and the first floating hole which would
199045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      satisfy the request. */
199145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (j = 0; j < nsegments_used; j++) {
199245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
199345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (nsegments[i].kind != SkFree) {
19948eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         UPDATE_INDEX(i);
199579048ce723a3463c70257ce647f04b111de71863sewardj         continue;
199645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
1997548be6d64c58729588a559b1512ad7625bc1b86esewardj
199845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      holeStart = nsegments[i].start;
199945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      holeEnd   = nsegments[i].end;
2000548be6d64c58729588a559b1512ad7625bc1b86esewardj
200145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* Stay sane .. */
200245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      aspacem_assert(holeStart <= holeEnd);
200345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      aspacem_assert(aspacem_minAddr <= holeStart);
200445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      aspacem_assert(holeEnd <= aspacem_maxAddr);
2005548be6d64c58729588a559b1512ad7625bc1b86esewardj
20068eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      if (req->rkind == MAlign) {
20078eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         holeStart = VG_ROUNDUP(holeStart, req->start);
20088eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         if (holeStart >= holeEnd) {
20098eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            /* This hole can't be used. */
20108eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            UPDATE_INDEX(i);
20118eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            continue;
20128eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         }
20138eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      }
20148eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
201545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* See if it's any use to us. */
201645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      holeLen = holeEnd - holeStart + 1;
2017548be6d64c58729588a559b1512ad7625bc1b86esewardj
201845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (fixedIdx == -1 && holeStart <= reqStart && reqEnd <= holeEnd)
201945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         fixedIdx = i;
202045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
202145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (floatIdx == -1 && holeLen >= reqLen)
202245f4e7c91119c7d01a59f5e827c67841632c9314sewardj         floatIdx = i;
202345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
202445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* Don't waste time searching once we've found what we wanted. */
202545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if ((fixed_not_required || fixedIdx >= 0) && floatIdx >= 0)
202645f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
202745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
20288eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      UPDATE_INDEX(i);
202979048ce723a3463c70257ce647f04b111de71863sewardj   }
2030548be6d64c58729588a559b1512ad7625bc1b86esewardj
203145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(fixedIdx >= -1 && fixedIdx < nsegments_used);
203245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (fixedIdx >= 0)
203345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      aspacem_assert(nsegments[fixedIdx].kind == SkFree);
203479048ce723a3463c70257ce647f04b111de71863sewardj
203545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(floatIdx >= -1 && floatIdx < nsegments_used);
203645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (floatIdx >= 0)
203745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      aspacem_assert(nsegments[floatIdx].kind == SkFree);
203845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
203945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
204045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
204145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Now see if we found anything which can satisfy the request. */
204245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   switch (req->rkind) {
204345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case MFixed:
204445f4e7c91119c7d01a59f5e827c67841632c9314sewardj         if (fixedIdx >= 0) {
204545f4e7c91119c7d01a59f5e827c67841632c9314sewardj            *ok = True;
204645f4e7c91119c7d01a59f5e827c67841632c9314sewardj            return req->start;
204745f4e7c91119c7d01a59f5e827c67841632c9314sewardj         } else {
204845f4e7c91119c7d01a59f5e827c67841632c9314sewardj            *ok = False;
204945f4e7c91119c7d01a59f5e827c67841632c9314sewardj            return 0;
205045f4e7c91119c7d01a59f5e827c67841632c9314sewardj         }
205145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
205245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case MHint:
205345f4e7c91119c7d01a59f5e827c67841632c9314sewardj         if (fixedIdx >= 0) {
205445f4e7c91119c7d01a59f5e827c67841632c9314sewardj            *ok = True;
205545f4e7c91119c7d01a59f5e827c67841632c9314sewardj            return req->start;
205645f4e7c91119c7d01a59f5e827c67841632c9314sewardj         }
205745f4e7c91119c7d01a59f5e827c67841632c9314sewardj         if (floatIdx >= 0) {
205845f4e7c91119c7d01a59f5e827c67841632c9314sewardj            *ok = True;
20598eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            return ADVISE_ADDRESS(&nsegments[floatIdx]);
206045f4e7c91119c7d01a59f5e827c67841632c9314sewardj         }
206145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         *ok = False;
206245f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return 0;
206345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case MAny:
206445f4e7c91119c7d01a59f5e827c67841632c9314sewardj         if (floatIdx >= 0) {
206545f4e7c91119c7d01a59f5e827c67841632c9314sewardj            *ok = True;
20668eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            return ADVISE_ADDRESS(&nsegments[floatIdx]);
20678eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         }
20688eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         *ok = False;
20698eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         return 0;
20708eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      case MAlign:
20718eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         if (floatIdx >= 0) {
20728eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            *ok = True;
20738eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            return ADVISE_ADDRESS_ALIGNED(&nsegments[floatIdx]);
207445f4e7c91119c7d01a59f5e827c67841632c9314sewardj         }
207545f4e7c91119c7d01a59f5e827c67841632c9314sewardj         *ok = False;
207645f4e7c91119c7d01a59f5e827c67841632c9314sewardj         return 0;
207745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      default:
207845f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
2079f6ec8ec39b3977f5a8ce446353ea990ae2c6e4b2njn   }
208045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
208145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /*NOTREACHED*/
2082297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj   ML_(am_barf)("getAdvisory: unknown request kind");
208345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   *ok = False;
208445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return 0;
20858eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
20868eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#undef UPDATE_INDEX
20878eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#undef ADVISE_ADDRESS
20888eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#undef ADVISE_ADDRESS_ALIGNED
2089548be6d64c58729588a559b1512ad7625bc1b86esewardj}
2090548be6d64c58729588a559b1512ad7625bc1b86esewardj
209145f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Convenience wrapper for VG_(am_get_advisory) for client floating or
209245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   fixed requests.  If start is zero, a floating request is issued; if
209345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   nonzero, a fixed request at that address is issued.  Same comments
209445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   about return values apply. */
2095548be6d64c58729588a559b1512ad7625bc1b86esewardj
209645f4e7c91119c7d01a59f5e827c67841632c9314sewardjAddr VG_(am_get_advisory_client_simple) ( Addr start, SizeT len,
209745f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                          /*OUT*/Bool* ok )
2098548be6d64c58729588a559b1512ad7625bc1b86esewardj{
209945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   MapRequest mreq;
210045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   mreq.rkind = start==0 ? MAny : MFixed;
210145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   mreq.start = start;
210245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   mreq.len   = len;
2103515e26933c61eed21ba8d74ecdfc89c217832fedphilippe   return VG_(am_get_advisory)( &mreq, True/*forClient*/, ok );
2104548be6d64c58729588a559b1512ad7625bc1b86esewardj}
2105548be6d64c58729588a559b1512ad7625bc1b86esewardj
210615e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe/* Similar to VG_(am_find_nsegment) but only returns free segments. */
210715e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippestatic NSegment const * VG_(am_find_free_nsegment) ( Addr a )
210815e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe{
210915e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe   Int i = find_nsegment_idx(a);
211015e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe   aspacem_assert(i >= 0 && i < nsegments_used);
211115e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe   aspacem_assert(nsegments[i].start <= a);
211215e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe   aspacem_assert(a <= nsegments[i].end);
211315e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe   if (nsegments[i].kind == SkFree)
211415e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe      return &nsegments[i];
211515e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe   else
211615e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe      return NULL;
211715e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe}
211815e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe
211915e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippeBool VG_(am_covered_by_single_free_segment)
212015e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe   ( Addr start, SizeT len)
212115e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe{
212215e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe   NSegment const* segLo = VG_(am_find_free_nsegment)( start );
212315e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe   NSegment const* segHi = VG_(am_find_free_nsegment)( start + len - 1 );
212415e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe
212515e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe   return segLo != NULL && segHi != NULL && segLo == segHi;
212615e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe}
212715e301e2b0540fea8dd8b5410bf75d2fa0e8eac1philippe
212879048ce723a3463c70257ce647f04b111de71863sewardj
212945f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Notifies aspacem that the client completed an mmap successfully.
213045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   The segment array is updated accordingly.  If the returned Bool is
213145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   True, the caller should immediately discard translations from the
213245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   specified address range. */
213379048ce723a3463c70257ce647f04b111de71863sewardj
213445f4e7c91119c7d01a59f5e827c67841632c9314sewardjBool
213545f4e7c91119c7d01a59f5e827c67841632c9314sewardjVG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags,
2136274461dcb67f680196c97e8afb7028a79b97dcb7sewardj                            Int fd, Off64T offset )
2137548be6d64c58729588a559b1512ad7625bc1b86esewardj{
213845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   HChar    buf[VKI_PATH_MAX];
2139419060073e7943846cc9e0bcdcb25258d90da2dcsewardj   ULong    dev, ino;
2140f4c231081a5c8ff6f24b3fa1980349199f1d9ea3tom   UInt     mode;
214145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   NSegment seg;
214245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool     needDiscard;
214345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
214445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(len > 0);
214545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(a));
214645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2147274461dcb67f680196c97e8afb7028a79b97dcb7sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(offset));
214845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
214945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Discard is needed if any of the just-trashed range had T. */
215045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   needDiscard = any_Ts_in_range( a, len );
215145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
215245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment( &seg );
215345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.kind   = (flags & VKI_MAP_ANONYMOUS) ? SkAnonC : SkFileC;
215445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.start  = a;
215545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.end    = a + len - 1;
215645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasR   = toBool(prot & VKI_PROT_READ);
215745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasW   = toBool(prot & VKI_PROT_WRITE);
215845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasX   = toBool(prot & VKI_PROT_EXEC);
215945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!(flags & VKI_MAP_ANONYMOUS)) {
21604395ad459576d155df4270a96bc46279c43d498anjn      // Nb: We ignore offset requests in anonymous mmaps (see bug #126722)
2161dadff0a77b92b9c81648850d628ab781b44965f9tom      seg.offset = offset;
2162dad944add53e6361751c6832066c00c456854622njn      if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
216345f4e7c91119c7d01a59f5e827c67841632c9314sewardj         seg.dev = dev;
216445f4e7c91119c7d01a59f5e827c67841632c9314sewardj         seg.ino = ino;
2165f4c231081a5c8ff6f24b3fa1980349199f1d9ea3tom         seg.mode = mode;
216645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
2167dad944add53e6361751c6832066c00c456854622njn      if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
21684ecd48360351f666f008148c12a24cbda455c6b1florian         seg.fnIdx = ML_(am_allocate_segname)( buf );
216945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
217079048ce723a3463c70257ce647f04b111de71863sewardj   }
217145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment( &seg );
217245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
217345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return needDiscard;
2174548be6d64c58729588a559b1512ad7625bc1b86esewardj}
2175548be6d64c58729588a559b1512ad7625bc1b86esewardj
21761340c35bebb175c6d158361596ee6171b4cfc2a2tom/* Notifies aspacem that the client completed a shmat successfully.
21771340c35bebb175c6d158361596ee6171b4cfc2a2tom   The segment array is updated accordingly.  If the returned Bool is
21781340c35bebb175c6d158361596ee6171b4cfc2a2tom   True, the caller should immediately discard translations from the
21791340c35bebb175c6d158361596ee6171b4cfc2a2tom   specified address range. */
21801340c35bebb175c6d158361596ee6171b4cfc2a2tom
21811340c35bebb175c6d158361596ee6171b4cfc2a2tomBool
21821340c35bebb175c6d158361596ee6171b4cfc2a2tomVG_(am_notify_client_shmat)( Addr a, SizeT len, UInt prot )
21831340c35bebb175c6d158361596ee6171b4cfc2a2tom{
21841340c35bebb175c6d158361596ee6171b4cfc2a2tom   NSegment seg;
21851340c35bebb175c6d158361596ee6171b4cfc2a2tom   Bool     needDiscard;
21861340c35bebb175c6d158361596ee6171b4cfc2a2tom
21871340c35bebb175c6d158361596ee6171b4cfc2a2tom   aspacem_assert(len > 0);
21881340c35bebb175c6d158361596ee6171b4cfc2a2tom   aspacem_assert(VG_IS_PAGE_ALIGNED(a));
21891340c35bebb175c6d158361596ee6171b4cfc2a2tom   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
21901340c35bebb175c6d158361596ee6171b4cfc2a2tom
21911340c35bebb175c6d158361596ee6171b4cfc2a2tom   /* Discard is needed if any of the just-trashed range had T. */
21921340c35bebb175c6d158361596ee6171b4cfc2a2tom   needDiscard = any_Ts_in_range( a, len );
21931340c35bebb175c6d158361596ee6171b4cfc2a2tom
21941340c35bebb175c6d158361596ee6171b4cfc2a2tom   init_nsegment( &seg );
21951340c35bebb175c6d158361596ee6171b4cfc2a2tom   seg.kind   = SkShmC;
21961340c35bebb175c6d158361596ee6171b4cfc2a2tom   seg.start  = a;
21971340c35bebb175c6d158361596ee6171b4cfc2a2tom   seg.end    = a + len - 1;
21981340c35bebb175c6d158361596ee6171b4cfc2a2tom   seg.offset = 0;
21991340c35bebb175c6d158361596ee6171b4cfc2a2tom   seg.hasR   = toBool(prot & VKI_PROT_READ);
22001340c35bebb175c6d158361596ee6171b4cfc2a2tom   seg.hasW   = toBool(prot & VKI_PROT_WRITE);
22011340c35bebb175c6d158361596ee6171b4cfc2a2tom   seg.hasX   = toBool(prot & VKI_PROT_EXEC);
22021340c35bebb175c6d158361596ee6171b4cfc2a2tom   add_segment( &seg );
22031340c35bebb175c6d158361596ee6171b4cfc2a2tom   AM_SANITY_CHECK;
22041340c35bebb175c6d158361596ee6171b4cfc2a2tom   return needDiscard;
22051340c35bebb175c6d158361596ee6171b4cfc2a2tom}
22061340c35bebb175c6d158361596ee6171b4cfc2a2tom
220745f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Notifies aspacem that an mprotect was completed successfully.  The
220845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   segment array is updated accordingly.  Note, as with
220945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(am_notify_munmap), it is not the job of this function to reject
221045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   stupid mprotects, for example the client doing mprotect of
221145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   non-client areas.  Such requests should be intercepted earlier, by
221245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   the syscall wrapper for mprotect.  This function merely records
221345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   whatever it is told.  If the returned Bool is True, the caller
221445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   should immediately discard translations from the specified address
221545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   range. */
221645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
221745f4e7c91119c7d01a59f5e827c67841632c9314sewardjBool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot )
221845f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
221945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int  i, iLo, iHi;
222045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool newR, newW, newX, needDiscard;
222179048ce723a3463c70257ce647f04b111de71863sewardj
222245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
222345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2224548be6d64c58729588a559b1512ad7625bc1b86esewardj
222545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (len == 0)
222645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
2227548be6d64c58729588a559b1512ad7625bc1b86esewardj
222845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   newR = toBool(prot & VKI_PROT_READ);
222945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   newW = toBool(prot & VKI_PROT_WRITE);
223045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   newX = toBool(prot & VKI_PROT_EXEC);
223145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
223245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Discard is needed if we're dumping X permission */
223345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   needDiscard = any_Ts_in_range( start, len ) && !newX;
223445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
223545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
223645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
223745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   iLo = find_nsegment_idx(start);
223845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   iHi = find_nsegment_idx(start + len - 1);
223945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
224045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (i = iLo; i <= iHi; i++) {
224145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* Apply the permissions to all relevant segments. */
224245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      switch (nsegments[i].kind) {
22431340c35bebb175c6d158361596ee6171b4cfc2a2tom         case SkAnonC: case SkAnonV: case SkFileC: case SkFileV: case SkShmC:
224445f4e7c91119c7d01a59f5e827c67841632c9314sewardj            nsegments[i].hasR = newR;
224545f4e7c91119c7d01a59f5e827c67841632c9314sewardj            nsegments[i].hasW = newW;
224645f4e7c91119c7d01a59f5e827c67841632c9314sewardj            nsegments[i].hasX = newX;
224745f4e7c91119c7d01a59f5e827c67841632c9314sewardj            aspacem_assert(sane_NSegment(&nsegments[i]));
224845f4e7c91119c7d01a59f5e827c67841632c9314sewardj            break;
224945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         default:
225045f4e7c91119c7d01a59f5e827c67841632c9314sewardj            break;
225145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
225245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
2253548be6d64c58729588a559b1512ad7625bc1b86esewardj
225445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Changing permissions could have made previously un-mergable
225545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      segments mergeable.  Therefore have to re-preen them. */
225645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   (void)preen_nsegments();
225745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
225845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return needDiscard;
2259548be6d64c58729588a559b1512ad7625bc1b86esewardj}
2260548be6d64c58729588a559b1512ad7625bc1b86esewardj
226179048ce723a3463c70257ce647f04b111de71863sewardj
226245f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Notifies aspacem that an munmap completed successfully.  The
226345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   segment array is updated accordingly.  As with
2264135c9f1d417cb4b1f453b8e6786ad55b89c9143eflorian   VG_(am_notify_mprotect), we merely record the given info, and don't
226545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   check it for sensibleness.  If the returned Bool is True, the
226645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   caller should immediately discard translations from the specified
226745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   address range. */
226845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
226945f4e7c91119c7d01a59f5e827c67841632c9314sewardjBool VG_(am_notify_munmap)( Addr start, SizeT len )
227079048ce723a3463c70257ce647f04b111de71863sewardj{
227145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   NSegment seg;
227245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool     needDiscard;
227345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
227445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
227579048ce723a3463c70257ce647f04b111de71863sewardj
227645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (len == 0)
227779048ce723a3463c70257ce647f04b111de71863sewardj      return False;
227879048ce723a3463c70257ce647f04b111de71863sewardj
227945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   needDiscard = any_Ts_in_range( start, len );
228079048ce723a3463c70257ce647f04b111de71863sewardj
228145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment( &seg );
228245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.start = start;
228345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.end   = start + len - 1;
2284613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj
2285613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj   /* The segment becomes unused (free).  Segments from above
2286613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj      aspacem_maxAddr were originally SkResvn and so we make them so
2287613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj      again.  Note, this isn't really right when the segment straddles
2288613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj      the aspacem_maxAddr boundary - then really it should be split in
2289613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj      two, the lower part marked as SkFree and the upper part as
2290613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj      SkResvn.  Ah well. */
2291613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj   if (start > aspacem_maxAddr
2292613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj       && /* check previous comparison is meaningful */
2293613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj          aspacem_maxAddr < Addr_MAX)
2294613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj      seg.kind = SkResvn;
22957cc2040098cb14f021e04ac44f127195b98a1c30sewardj   else
22967cc2040098cb14f021e04ac44f127195b98a1c30sewardj   /* Ditto for segments from below aspacem_minAddr. */
22977cc2040098cb14f021e04ac44f127195b98a1c30sewardj   if (seg.end < aspacem_minAddr && aspacem_minAddr > 0)
22987cc2040098cb14f021e04ac44f127195b98a1c30sewardj      seg.kind = SkResvn;
2299613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj   else
2300613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj      seg.kind = SkFree;
2301613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj
230245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment( &seg );
230379048ce723a3463c70257ce647f04b111de71863sewardj
230445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Unmapping could create two adjacent free segments, so a preen is
230545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      needed.  add_segment() will do that, so no need to here. */
230645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
230745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return needDiscard;
230879048ce723a3463c70257ce647f04b111de71863sewardj}
230979048ce723a3463c70257ce647f04b111de71863sewardj
231079048ce723a3463c70257ce647f04b111de71863sewardj
231145f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
231245f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
231345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--- Handling mappings which do not arise directly from the    ---*/
231445f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--- simulation of the client.                                 ---*/
231545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
231645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
231779048ce723a3463c70257ce647f04b111de71863sewardj
231845f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* --- --- --- map, unmap, protect  --- --- --- */
231979048ce723a3463c70257ce647f04b111de71863sewardj
232045f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Map a file at a fixed address for the client, and update the
232145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   segment array accordingly. */
232279048ce723a3463c70257ce647f04b111de71863sewardj
232345f4e7c91119c7d01a59f5e827c67841632c9314sewardjSysRes VG_(am_mmap_file_fixed_client)
2324274461dcb67f680196c97e8afb7028a79b97dcb7sewardj     ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset )
232545f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
23268eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
23278eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
23288eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                                                     fd, offset, NULL);
23298eb8bab992e3998c33770b0cdb16059a8b918a06sewardj}
23308eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
23318eb8bab992e3998c33770b0cdb16059a8b918a06sewardjSysRes VG_(am_mmap_file_fixed_client_flags)
23328eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     ( Addr start, SizeT length, UInt prot, UInt flags, Int fd, Off64T offset )
23338eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
23348eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
23358eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                                                     fd, offset, NULL);
2336f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
2337f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
2338f76d27a697a7b0bf3b84490baf60623fc96a23afnjnSysRes VG_(am_mmap_named_file_fixed_client)
2339f76d27a697a7b0bf3b84490baf60623fc96a23afnjn     ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name )
2340f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
23418eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
23428eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
23438eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                                                     fd, offset, name);
23448eb8bab992e3998c33770b0cdb16059a8b918a06sewardj}
23458eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
23468eb8bab992e3998c33770b0cdb16059a8b918a06sewardjSysRes VG_(am_mmap_named_file_fixed_client_flags)
23478eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     ( Addr start, SizeT length, UInt prot, UInt flags,
23488eb8bab992e3998c33770b0cdb16059a8b918a06sewardj       Int fd, Off64T offset, const HChar *name )
23498eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
235045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes     sres;
235145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   NSegment   seg;
235245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr       advised;
235345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool       ok;
235445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   MapRequest req;
2355419060073e7943846cc9e0bcdcb25258d90da2dcsewardj   ULong      dev, ino;
2356f4c231081a5c8ff6f24b3fa1980349199f1d9ea3tom   UInt       mode;
235745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   HChar      buf[VKI_PATH_MAX];
235845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
235945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Not allowable. */
2360274461dcb67f680196c97e8afb7028a79b97dcb7sewardj   if (length == 0
2361274461dcb67f680196c97e8afb7028a79b97dcb7sewardj       || !VG_IS_PAGE_ALIGNED(start)
2362274461dcb67f680196c97e8afb7028a79b97dcb7sewardj       || !VG_IS_PAGE_ALIGNED(offset))
236345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
236445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
236545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Ask for an advisory.  If it's negative, fail immediately. */
236645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.rkind = MFixed;
236745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.start = start;
236845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.len   = length;
2369515e26933c61eed21ba8d74ecdfc89c217832fedphilippe   advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
237045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!ok || advised != start)
237145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
237245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
237345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* We have been advised that the mapping is allowable at the
237445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      specified address.  So hand it off to the kernel, and propagate
237545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      any resulting failure immediately. */
2376f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
237745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   sres = VG_(am_do_mmap_NO_NOTIFY)(
23788eb8bab992e3998c33770b0cdb16059a8b918a06sewardj             start, length, prot, flags,
237945f4e7c91119c7d01a59f5e827c67841632c9314sewardj             fd, offset
238045f4e7c91119c7d01a59f5e827c67841632c9314sewardj          );
2381cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_isError(sres))
238245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return sres;
238345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
2384cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_Res(sres) != start) {
238545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* I don't think this can happen.  It means the kernel made a
238645f4e7c91119c7d01a59f5e827c67841632c9314sewardj         fixed map succeed but not at the requested location.  Try to
238745f4e7c91119c7d01a59f5e827c67841632c9314sewardj         repair the damage, then return saying the mapping failed. */
2388cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
238945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
239079048ce723a3463c70257ce647f04b111de71863sewardj   }
239179048ce723a3463c70257ce647f04b111de71863sewardj
239245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Ok, the mapping succeeded.  Now notify the interval map. */
239345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment( &seg );
239445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.kind   = SkFileC;
239545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.start  = start;
239645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.end    = seg.start + VG_PGROUNDUP(length) - 1;
239745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.offset = offset;
239845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasR   = toBool(prot & VKI_PROT_READ);
239945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasW   = toBool(prot & VKI_PROT_WRITE);
240045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasX   = toBool(prot & VKI_PROT_EXEC);
2401dad944add53e6361751c6832066c00c456854622njn   if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
240245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      seg.dev = dev;
240345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      seg.ino = ino;
2404f4c231081a5c8ff6f24b3fa1980349199f1d9ea3tom      seg.mode = mode;
240579048ce723a3463c70257ce647f04b111de71863sewardj   }
2406f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (name) {
24074ecd48360351f666f008148c12a24cbda455c6b1florian      seg.fnIdx = ML_(am_allocate_segname)( name );
2408f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   } else if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
24094ecd48360351f666f008148c12a24cbda455c6b1florian      seg.fnIdx = ML_(am_allocate_segname)( buf );
241079048ce723a3463c70257ce647f04b111de71863sewardj   }
241145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment( &seg );
241279048ce723a3463c70257ce647f04b111de71863sewardj
241345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
241445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return sres;
241579048ce723a3463c70257ce647f04b111de71863sewardj}
241679048ce723a3463c70257ce647f04b111de71863sewardj
241779048ce723a3463c70257ce647f04b111de71863sewardj
241845f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Map anonymously at a fixed address for the client, and update
241945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   the segment array accordingly. */
2420de4a1d01951937632098a6cda45859afa587a06fsewardj
242145f4e7c91119c7d01a59f5e827c67841632c9314sewardjSysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot )
242298abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge{
242345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes     sres;
242445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   NSegment   seg;
242545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr       advised;
242645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool       ok;
242745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   MapRequest req;
242845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
242945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Not allowable. */
243045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (length == 0 || !VG_IS_PAGE_ALIGNED(start))
243145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
243245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
243345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Ask for an advisory.  If it's negative, fail immediately. */
243445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.rkind = MFixed;
243545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.start = start;
243645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.len   = length;
2437515e26933c61eed21ba8d74ecdfc89c217832fedphilippe   advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
243845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!ok || advised != start)
243945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
244045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
244145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* We have been advised that the mapping is allowable at the
244245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      specified address.  So hand it off to the kernel, and propagate
244345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      any resulting failure immediately. */
2444f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
244545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   sres = VG_(am_do_mmap_NO_NOTIFY)(
244645f4e7c91119c7d01a59f5e827c67841632c9314sewardj             start, length, prot,
244745f4e7c91119c7d01a59f5e827c67841632c9314sewardj             VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
244845f4e7c91119c7d01a59f5e827c67841632c9314sewardj             0, 0
244945f4e7c91119c7d01a59f5e827c67841632c9314sewardj          );
2450cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_isError(sres))
245145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return sres;
245245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
2453cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_Res(sres) != start) {
245445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* I don't think this can happen.  It means the kernel made a
245545f4e7c91119c7d01a59f5e827c67841632c9314sewardj         fixed map succeed but not at the requested location.  Try to
245645f4e7c91119c7d01a59f5e827c67841632c9314sewardj         repair the damage, then return saying the mapping failed. */
2457cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
245845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
245945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
246098abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
246145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Ok, the mapping succeeded.  Now notify the interval map. */
246245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment( &seg );
246345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.kind  = SkAnonC;
246445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.start = start;
246545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
246645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasR  = toBool(prot & VKI_PROT_READ);
246745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasW  = toBool(prot & VKI_PROT_WRITE);
246845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasX  = toBool(prot & VKI_PROT_EXEC);
246945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment( &seg );
247045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
247145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
247245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return sres;
247398abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge}
247498abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
247598abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
247645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Map anonymously at an unconstrained address for the client, and
247745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   update the segment array accordingly.  */
247898abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
247945f4e7c91119c7d01a59f5e827c67841632c9314sewardjSysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot )
248098abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge{
248145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes     sres;
248245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   NSegment   seg;
248345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr       advised;
248445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool       ok;
248545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   MapRequest req;
248645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
248745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Not allowable. */
248845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (length == 0)
248945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
249045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
249145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Ask for an advisory.  If it's negative, fail immediately. */
249245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.rkind = MAny;
249345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.start = 0;
249445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.len   = length;
2495515e26933c61eed21ba8d74ecdfc89c217832fedphilippe   advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
249645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!ok)
249745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
249845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
249945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* We have been advised that the mapping is allowable at the
250045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      advised address.  So hand it off to the kernel, and propagate
250145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      any resulting failure immediately. */
2502f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
250345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   sres = VG_(am_do_mmap_NO_NOTIFY)(
250445f4e7c91119c7d01a59f5e827c67841632c9314sewardj             advised, length, prot,
250545f4e7c91119c7d01a59f5e827c67841632c9314sewardj             VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
250645f4e7c91119c7d01a59f5e827c67841632c9314sewardj             0, 0
250745f4e7c91119c7d01a59f5e827c67841632c9314sewardj          );
2508cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_isError(sres))
250945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return sres;
251045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
2511cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_Res(sres) != advised) {
251245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* I don't think this can happen.  It means the kernel made a
251345f4e7c91119c7d01a59f5e827c67841632c9314sewardj         fixed map succeed but not at the requested location.  Try to
251445f4e7c91119c7d01a59f5e827c67841632c9314sewardj         repair the damage, then return saying the mapping failed. */
2515cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
251645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
2517e49d8e7dfd3a9c96feb9935b5920973dfc0b170anjn   }
251845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
251945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Ok, the mapping succeeded.  Now notify the interval map. */
252045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment( &seg );
252145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.kind  = SkAnonC;
252245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.start = advised;
252345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
252445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasR  = toBool(prot & VKI_PROT_READ);
252545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasW  = toBool(prot & VKI_PROT_WRITE);
252645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasX  = toBool(prot & VKI_PROT_EXEC);
252745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment( &seg );
252845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
252945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
253045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return sres;
253198abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge}
253298abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
253345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
253445f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Map anonymously at an unconstrained address for V, and update the
253545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   segment array accordingly.  This is fundamentally how V allocates
253645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   itself more address space when needed. */
253745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
253845f4e7c91119c7d01a59f5e827c67841632c9314sewardjSysRes VG_(am_mmap_anon_float_valgrind)( SizeT length )
25391024cf78e01e14eaa19ed6a8cd11beb50e6bc687sewardj{
254045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes     sres;
254145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   NSegment   seg;
254245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr       advised;
254345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool       ok;
254445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   MapRequest req;
254545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
254645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Not allowable. */
254745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (length == 0)
254845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
254945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
255045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Ask for an advisory.  If it's negative, fail immediately. */
255145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.rkind = MAny;
255245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.start = 0;
255345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.len   = length;
2554515e26933c61eed21ba8d74ecdfc89c217832fedphilippe   advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
255545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!ok)
255645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
255745f4e7c91119c7d01a59f5e827c67841632c9314sewardj
2558f76d27a697a7b0bf3b84490baf60623fc96a23afnjn// On Darwin, for anonymous maps you can pass in a tag which is used by
2559f76d27a697a7b0bf3b84490baf60623fc96a23afnjn// programs like vmmap for statistical purposes.
2560f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#ifndef VM_TAG_VALGRIND
2561f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#  define VM_TAG_VALGRIND 0
2562f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#endif
2563f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
256445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* We have been advised that the mapping is allowable at the
256545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      specified address.  So hand it off to the kernel, and propagate
256645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      any resulting failure immediately. */
2567f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* GrP fixme darwin: use advisory as a hint only, otherwise syscall in
2568f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      another thread can pre-empt our spot.  [At one point on the DARWIN
2569f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      branch the VKI_MAP_FIXED was commented out;  unclear if this is
2570f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      necessary or not given the second Darwin-only call that immediately
25713bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      follows if this one fails.  --njn]
25723bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      Also, an inner valgrind cannot observe the mmap syscalls done by
25733bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      the outer valgrind. The outer Valgrind might make the mmap
25743bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      fail here, as the inner valgrind believes that a segment is free,
25753bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      while it is in fact used by the outer valgrind.
25763bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      So, for an inner valgrind, similarly to DARWIN, if the fixed mmap
25773bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      fails, retry the mmap without map fixed.
25783bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      This is a kludge which on linux is only activated for the inner.
25793bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      The state of the inner aspacemgr is not made correct by this kludge
25803bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      and so a.o. VG_(am_do_sync_check) could fail.
25813bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      A proper solution implies a better collaboration between the
25823bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      inner and the outer (e.g. inner VG_(am_get_advisory) should do
25833bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      a client request to call the outer VG_(am_get_advisory). */
258445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   sres = VG_(am_do_mmap_NO_NOTIFY)(
258545f4e7c91119c7d01a59f5e827c67841632c9314sewardj             advised, length,
258645f4e7c91119c7d01a59f5e827c67841632c9314sewardj             VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
258745f4e7c91119c7d01a59f5e827c67841632c9314sewardj             VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2588f76d27a697a7b0bf3b84490baf60623fc96a23afnjn             VM_TAG_VALGRIND, 0
258945f4e7c91119c7d01a59f5e827c67841632c9314sewardj          );
25903bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe#if defined(VGO_darwin) || defined(ENABLE_INNER)
25913bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe   /* Kludge on Darwin and inner linux if the fixed mmap failed. */
2592f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (sr_isError(sres)) {
2593f76d27a697a7b0bf3b84490baf60623fc96a23afnjn       /* try again, ignoring the advisory */
2594f76d27a697a7b0bf3b84490baf60623fc96a23afnjn       sres = VG_(am_do_mmap_NO_NOTIFY)(
2595f76d27a697a7b0bf3b84490baf60623fc96a23afnjn             0, length,
2596f76d27a697a7b0bf3b84490baf60623fc96a23afnjn             VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
2597f76d27a697a7b0bf3b84490baf60623fc96a23afnjn             /*VKI_MAP_FIXED|*/VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2598f76d27a697a7b0bf3b84490baf60623fc96a23afnjn             VM_TAG_VALGRIND, 0
2599f76d27a697a7b0bf3b84490baf60623fc96a23afnjn          );
2600f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
2601f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#endif
2602cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_isError(sres))
260345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return sres;
260445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
26053bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe#if defined(VGO_linux) && !defined(ENABLE_INNER)
26063bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe   /* Doing the check only in linux not inner, as the below
26073bf117dd6e0ab3bec8eedd36da9d9602bb82c542philippe      check can fail when the kludge above has been used. */
2608cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_Res(sres) != advised) {
260945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* I don't think this can happen.  It means the kernel made a
261045f4e7c91119c7d01a59f5e827c67841632c9314sewardj         fixed map succeed but not at the requested location.  Try to
261145f4e7c91119c7d01a59f5e827c67841632c9314sewardj         repair the damage, then return saying the mapping failed. */
2612cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
261345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
26141024cf78e01e14eaa19ed6a8cd11beb50e6bc687sewardj   }
2615f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#endif
261645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
261745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Ok, the mapping succeeded.  Now notify the interval map. */
261845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment( &seg );
261945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.kind  = SkAnonV;
2620cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   seg.start = sr_Res(sres);
262145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
262245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasR  = True;
262345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasW  = True;
262445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasX  = True;
262545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment( &seg );
262645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
262745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
262845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return sres;
262998abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge}
263098abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
263145f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */
26321024cf78e01e14eaa19ed6a8cd11beb50e6bc687sewardj
263345f4e7c91119c7d01a59f5e827c67841632c9314sewardjvoid* VG_(am_shadow_alloc)(SizeT size)
263498abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge{
263545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes sres = VG_(am_mmap_anon_float_valgrind)( size );
2636cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   return sr_isError(sres) ? NULL : (void*)sr_Res(sres);
263745f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
263898abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
263945f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Map a file at an unconstrained address for V, and update the
26403b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   segment array accordingly. Use the provided flags */
264198abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
26423b290486cd4cd601b20e04340e593c9ed9717e5fsewardjstatic SysRes VG_(am_mmap_file_float_valgrind_flags) ( SizeT length, UInt prot,
26433b290486cd4cd601b20e04340e593c9ed9717e5fsewardj                                                       UInt flags,
26443b290486cd4cd601b20e04340e593c9ed9717e5fsewardj                                                       Int fd, Off64T offset )
264545f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
264645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes     sres;
264745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   NSegment   seg;
264845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr       advised;
264945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool       ok;
265045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   MapRequest req;
2651419060073e7943846cc9e0bcdcb25258d90da2dcsewardj   ULong      dev, ino;
2652f4c231081a5c8ff6f24b3fa1980349199f1d9ea3tom   UInt       mode;
265345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   HChar      buf[VKI_PATH_MAX];
265445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
265545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Not allowable. */
2656274461dcb67f680196c97e8afb7028a79b97dcb7sewardj   if (length == 0 || !VG_IS_PAGE_ALIGNED(offset))
265745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
265845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
265945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Ask for an advisory.  If it's negative, fail immediately. */
266045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.rkind = MAny;
266145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   req.start = 0;
26620eb0d5a73655b8ed1b6c93d7032311a5d102a8f0philippe   #if defined(VGA_arm) || defined(VGA_arm64) \
26630eb0d5a73655b8ed1b6c93d7032311a5d102a8f0philippe      || defined(VGA_mips32) || defined(VGA_mips64)
266453b0d9a5e90ecd4e4b50489915c221c86734908fphilippe   aspacem_assert(VKI_SHMLBA >= VKI_PAGE_SIZE);
266553b0d9a5e90ecd4e4b50489915c221c86734908fphilippe   #else
266653b0d9a5e90ecd4e4b50489915c221c86734908fphilippe   aspacem_assert(VKI_SHMLBA == VKI_PAGE_SIZE);
266753b0d9a5e90ecd4e4b50489915c221c86734908fphilippe   #endif
266853b0d9a5e90ecd4e4b50489915c221c86734908fphilippe   if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags)) {
266953b0d9a5e90ecd4e4b50489915c221c86734908fphilippe      /* arm-linux only. See ML_(generic_PRE_sys_shmat) and bug 290974 */
267053b0d9a5e90ecd4e4b50489915c221c86734908fphilippe      req.len = length + VKI_SHMLBA - VKI_PAGE_SIZE;
267153b0d9a5e90ecd4e4b50489915c221c86734908fphilippe   } else {
267253b0d9a5e90ecd4e4b50489915c221c86734908fphilippe      req.len = length;
267353b0d9a5e90ecd4e4b50489915c221c86734908fphilippe   }
2674515e26933c61eed21ba8d74ecdfc89c217832fedphilippe   advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
267545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!ok)
267645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
267753b0d9a5e90ecd4e4b50489915c221c86734908fphilippe   if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags))
267853b0d9a5e90ecd4e4b50489915c221c86734908fphilippe      advised = VG_ROUNDUP(advised, VKI_SHMLBA);
267945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
268045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* We have been advised that the mapping is allowable at the
268145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      specified address.  So hand it off to the kernel, and propagate
268245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      any resulting failure immediately. */
268345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   sres = VG_(am_do_mmap_NO_NOTIFY)(
268445f4e7c91119c7d01a59f5e827c67841632c9314sewardj             advised, length, prot,
26853b290486cd4cd601b20e04340e593c9ed9717e5fsewardj             flags,
268645f4e7c91119c7d01a59f5e827c67841632c9314sewardj             fd, offset
268745f4e7c91119c7d01a59f5e827c67841632c9314sewardj          );
2688cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_isError(sres))
268945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return sres;
269045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
2691cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_Res(sres) != advised) {
269245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* I don't think this can happen.  It means the kernel made a
269345f4e7c91119c7d01a59f5e827c67841632c9314sewardj         fixed map succeed but not at the requested location.  Try to
269445f4e7c91119c7d01a59f5e827c67841632c9314sewardj         repair the damage, then return saying the mapping failed. */
2695cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
269645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Error)( VKI_EINVAL );
269745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
269898abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
269945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Ok, the mapping succeeded.  Now notify the interval map. */
270045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment( &seg );
270145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.kind   = SkFileV;
2702cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   seg.start  = sr_Res(sres);
270345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.end    = seg.start + VG_PGROUNDUP(length) - 1;
270445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.offset = offset;
270545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasR   = toBool(prot & VKI_PROT_READ);
270645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasW   = toBool(prot & VKI_PROT_WRITE);
270745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.hasX   = toBool(prot & VKI_PROT_EXEC);
2708dad944add53e6361751c6832066c00c456854622njn   if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
2709cf4ac71eeefa63bb2edc6b9ed09584612a3a7db0sewardj      seg.dev  = dev;
2710cf4ac71eeefa63bb2edc6b9ed09584612a3a7db0sewardj      seg.ino  = ino;
2711cf4ac71eeefa63bb2edc6b9ed09584612a3a7db0sewardj      seg.mode = mode;
271245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
2713dad944add53e6361751c6832066c00c456854622njn   if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
27144ecd48360351f666f008148c12a24cbda455c6b1florian      seg.fnIdx = ML_(am_allocate_segname)( buf );
271545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
271645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment( &seg );
271747c98a767e79e36511bf7b177a5b5d24930efd7csewardj
271845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
271945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return sres;
272045f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
27213b290486cd4cd601b20e04340e593c9ed9717e5fsewardj/* Map privately a file at an unconstrained address for V, and update the
27223b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   segment array accordingly.  This is used by V for transiently
27233b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   mapping in object files to read their debug info.  */
27243b290486cd4cd601b20e04340e593c9ed9717e5fsewardj
27253b290486cd4cd601b20e04340e593c9ed9717e5fsewardjSysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot,
27263b290486cd4cd601b20e04340e593c9ed9717e5fsewardj                                          Int fd, Off64T offset )
27273b290486cd4cd601b20e04340e593c9ed9717e5fsewardj{
27283b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
27293b290486cd4cd601b20e04340e593c9ed9717e5fsewardj                                                  VKI_MAP_FIXED|VKI_MAP_PRIVATE,
27303b290486cd4cd601b20e04340e593c9ed9717e5fsewardj                                                  fd, offset );
27313b290486cd4cd601b20e04340e593c9ed9717e5fsewardj}
273247c98a767e79e36511bf7b177a5b5d24930efd7csewardj
2733d6633333a292fc9b64f04200d836b08f55889321sewardjSysRes VG_(am_shared_mmap_file_float_valgrind)
27343b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   ( SizeT length, UInt prot, Int fd, Off64T offset )
27353b290486cd4cd601b20e04340e593c9ed9717e5fsewardj{
27363b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
27373b290486cd4cd601b20e04340e593c9ed9717e5fsewardj                                                  VKI_MAP_FIXED|VKI_MAP_SHARED,
27383b290486cd4cd601b20e04340e593c9ed9717e5fsewardj                                                  fd, offset );
27393b290486cd4cd601b20e04340e593c9ed9717e5fsewardj}
274098abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
27412fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian/* Convenience wrapper around VG_(am_mmap_anon_float_client) which also
27422fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   marks the segment as containing the client heap. This is for the benefit
27432fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   of the leak checker which needs to be able to identify such segments
27442fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   so as not to use them as sources of roots during leak checks. */
27452fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorianSysRes VG_(am_mmap_client_heap) ( SizeT length, Int prot )
27462fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian{
27472fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   SysRes res = VG_(am_mmap_anon_float_client)(length, prot);
27482fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian
27492fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   if (! sr_isError(res)) {
27502fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian      Addr addr = sr_Res(res);
27512fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian      Int ix = find_nsegment_idx(addr);
27522fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian
27532fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian      nsegments[ix].isCH = True;
27542fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   }
27552fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   return res;
27562fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian}
27572fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian
275845f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* --- --- munmap helper --- --- */
275998abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
276045f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic
276145f4e7c91119c7d01a59f5e827c67841632c9314sewardjSysRes am_munmap_both_wrk ( /*OUT*/Bool* need_discard,
276245f4e7c91119c7d01a59f5e827c67841632c9314sewardj                            Addr start, SizeT len, Bool forClient )
276345f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
276445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool   d;
276545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes sres;
276698abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
276745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!VG_IS_PAGE_ALIGNED(start))
276845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      goto eINVAL;
276947c98a767e79e36511bf7b177a5b5d24930efd7csewardj
277045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (len == 0) {
277145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      *need_discard = False;
277245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return VG_(mk_SysRes_Success)( 0 );
2773e49d8e7dfd3a9c96feb9935b5920973dfc0b170anjn   }
277498abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
277545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (start + len < len)
277645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      goto eINVAL;
2777a8d8e239876796bc194636b8bb4b3b3c86db8528sewardj
277813bfd85dfab2cd301c92e308b274ebd17de830d2njn   len = VG_PGROUNDUP(len);
277945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
278045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
278198abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
278245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (forClient) {
278345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (!VG_(am_is_valid_for_client_or_free_or_resvn)
278445f4e7c91119c7d01a59f5e827c67841632c9314sewardj            ( start, len, VKI_PROT_NONE ))
278545f4e7c91119c7d01a59f5e827c67841632c9314sewardj         goto eINVAL;
278645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   } else {
2787adfff76735ea5bca870dec8f382b225728e1b32dphilippe      if (!VG_(am_is_valid_for_valgrind)
2788adfff76735ea5bca870dec8f382b225728e1b32dphilippe            ( start, len, VKI_PROT_NONE ))
278945f4e7c91119c7d01a59f5e827c67841632c9314sewardj         goto eINVAL;
279098abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge   }
279198abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
279245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   d = any_Ts_in_range( start, len );
279398abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
2794297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj   sres = ML_(am_do_munmap_NO_NOTIFY)( start, len );
2795cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_isError(sres))
279645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return sres;
279798abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
279845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(am_notify_munmap)( start, len );
279945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
280045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   *need_discard = d;
280145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return sres;
280298abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
280345f4e7c91119c7d01a59f5e827c67841632c9314sewardj  eINVAL:
280445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return VG_(mk_SysRes_Error)( VKI_EINVAL );
280545f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
280698abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
280745f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Unmap the given address range and update the segment array
280845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   accordingly.  This fails if the range isn't valid for the client.
280945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   If *need_discard is True after a successful return, the caller
281045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   should immediately discard translations from the specified address
281145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   range. */
281298abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
281345f4e7c91119c7d01a59f5e827c67841632c9314sewardjSysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard,
281445f4e7c91119c7d01a59f5e827c67841632c9314sewardj                              Addr start, SizeT len )
281545f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
281645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return am_munmap_both_wrk( need_discard, start, len, True/*client*/ );
2817de4a1d01951937632098a6cda45859afa587a06fsewardj}
2818de4a1d01951937632098a6cda45859afa587a06fsewardj
281945f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Unmap the given address range and update the segment array
282045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   accordingly.  This fails if the range isn't valid for valgrind. */
2821de4a1d01951937632098a6cda45859afa587a06fsewardj
282245f4e7c91119c7d01a59f5e827c67841632c9314sewardjSysRes VG_(am_munmap_valgrind)( Addr start, SizeT len )
282345f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
282445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Bool need_discard;
282545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes r = am_munmap_both_wrk( &need_discard,
282645f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                  start, len, False/*valgrind*/ );
282745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* If this assertion fails, it means we allowed translations to be
282845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      made from a V-owned section.  Which shouldn't happen. */
2829cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (!sr_isError(r))
283045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      aspacem_assert(!need_discard);
283145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return r;
283298abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge}
283398abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
283445f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Let (start,len) denote an area within a single Valgrind-owned
283545f4e7c91119c7d01a59f5e827c67841632c9314sewardj  segment (anon or file).  Change the ownership of [start, start+len)
283645f4e7c91119c7d01a59f5e827c67841632c9314sewardj  to the client instead.  Fails if (start,len) does not denote a
283745f4e7c91119c7d01a59f5e827c67841632c9314sewardj  suitable segment. */
283845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
283945f4e7c91119c7d01a59f5e827c67841632c9314sewardjBool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len )
2840de4a1d01951937632098a6cda45859afa587a06fsewardj{
284145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int i, iLo, iHi;
2842de4a1d01951937632098a6cda45859afa587a06fsewardj
284345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (len == 0)
284445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return True;
284545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (start + len < start)
284645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
284745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!VG_IS_PAGE_ALIGNED(start) || !VG_IS_PAGE_ALIGNED(len))
284845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
2849e517b80ab9ac4da3544fdb905ce76fcabf92da97sewardj
285045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   i = find_nsegment_idx(start);
285145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (nsegments[i].kind != SkFileV && nsegments[i].kind != SkAnonV)
285245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
285345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (start+len-1 > nsegments[i].end)
285445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
285598abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
285645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(start >= nsegments[i].start);
285745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(start+len-1 <= nsegments[i].end);
285845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
285945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* This scheme is like how mprotect works: split the to-be-changed
286045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      range into its own segment(s), then mess with them (it).  There
286145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      should be only one. */
286245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
286345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(iLo == iHi);
286445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   switch (nsegments[iLo].kind) {
286545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkFileV: nsegments[iLo].kind = SkFileC; break;
286645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      case SkAnonV: nsegments[iLo].kind = SkAnonC; break;
286745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      default: aspacem_assert(0); /* can't happen - guarded above */
286845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
286998abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
287045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   preen_nsegments();
287145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return True;
287245f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
2873548be6d64c58729588a559b1512ad7625bc1b86esewardj
28742fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian/* Set the 'hasT' bit on the segment containing ADDR indicating that
28752fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   translations have or may have been taken from this segment. ADDR is
28762fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   expected to belong to a client segment. */
28772fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorianvoid VG_(am_set_segment_hasT)( Addr addr )
2878716f31ac50be6070a96b490d0b0bbd39b8e77342sewardj{
28792fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   Int i = find_nsegment_idx(addr);
28802fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   SegKind kind = nsegments[i].kind;
28812fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   aspacem_assert(kind == SkAnonC || kind == SkFileC || kind == SkShmC);
28822fa66ce8abeb95c722dcbd5bd233a26288f2cd7dflorian   nsegments[i].hasT = True;
2883716f31ac50be6070a96b490d0b0bbd39b8e77342sewardj}
2884716f31ac50be6070a96b490d0b0bbd39b8e77342sewardj
288598abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
288645f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* --- --- --- reservations --- --- --- */
2887de4a1d01951937632098a6cda45859afa587a06fsewardj
288845f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Create a reservation from START .. START+LENGTH-1, with the given
288945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   ShrinkMode.  When checking whether the reservation can be created,
289045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   also ensure that at least abs(EXTRA) extra free bytes will remain
289145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   above (> 0) or below (< 0) the reservation.
289298abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
289345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   The reservation will only be created if it, plus the extra-zone,
289445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   falls entirely within a single free segment.  The returned Bool
289545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   indicates whether the creation succeeded. */
289679048ce723a3463c70257ce647f04b111de71863sewardj
289745f4e7c91119c7d01a59f5e827c67841632c9314sewardjBool VG_(am_create_reservation) ( Addr start, SizeT length,
289845f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                  ShrinkMode smode, SSizeT extra )
289945f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
290045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int      startI, endI;
290145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   NSegment seg;
2902e517b80ab9ac4da3544fdb905ce76fcabf92da97sewardj
290345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* start and end, not taking into account the extra space. */
290445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr start1 = start;
290545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr end1   = start + length - 1;
2906e517b80ab9ac4da3544fdb905ce76fcabf92da97sewardj
290745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* start and end, taking into account the extra space. */
290845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr start2 = start1;
290945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr end2   = end1;
291098abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
291145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (extra < 0) start2 += extra; // this moves it down :-)
291245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (extra > 0) end2 += extra;
291398abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
291445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
291545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(start+length));
291645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(start2));
291745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(end2+1));
291898abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
291945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   startI = find_nsegment_idx( start2 );
292045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   endI = find_nsegment_idx( end2 );
2921548be6d64c58729588a559b1512ad7625bc1b86esewardj
292245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* If the start and end points don't fall within the same (free)
292345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      segment, we're hosed.  This does rely on the assumption that all
292445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      mergeable adjacent segments can be merged, but add_segment()
292545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      should ensure that. */
292645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (startI != endI)
292745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
2928548be6d64c58729588a559b1512ad7625bc1b86esewardj
292945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (nsegments[startI].kind != SkFree)
293045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
2931548be6d64c58729588a559b1512ad7625bc1b86esewardj
293245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Looks good - make the reservation. */
293345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(nsegments[startI].start <= start2);
293445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(end2 <= nsegments[startI].end);
2935548be6d64c58729588a559b1512ad7625bc1b86esewardj
293645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment( &seg );
293745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.kind  = SkResvn;
293845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.start = start1;  /* NB: extra space is not included in the
293945f4e7c91119c7d01a59f5e827c67841632c9314sewardj                           reservation. */
294045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.end   = end1;
294145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.smode = smode;
294245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment( &seg );
2943548be6d64c58729588a559b1512ad7625bc1b86esewardj
294445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
294545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return True;
294645f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
2947548be6d64c58729588a559b1512ad7625bc1b86esewardj
2948548be6d64c58729588a559b1512ad7625bc1b86esewardj
2949888b8159535580b30550f99cb7361f62edd83100florian/* ADDR is the start address of an anonymous client mapping.  This fn extends
2950888b8159535580b30550f99cb7361f62edd83100florian   the mapping by DELTA bytes, taking the space from a reservation section
295145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   which must be adjacent.  If DELTA is positive, the segment is
295245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   extended forwards in the address space, and the reservation must be
295345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   the next one along.  If DELTA is negative, the segment is extended
295445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   backwards in the address space and the reservation must be the
29556684d2afc25363b29a9ce4281050161d91baeebfsewardj   previous one.  DELTA must be page aligned.  abs(DELTA) must not
29566684d2afc25363b29a9ce4281050161d91baeebfsewardj   exceed the size of the reservation segment minus one page, that is,
29576684d2afc25363b29a9ce4281050161d91baeebfsewardj   the reservation segment after the operation must be at least one
2958888b8159535580b30550f99cb7361f62edd83100florian   page long. The function returns a pointer to the resized segment. */
2959548be6d64c58729588a559b1512ad7625bc1b86esewardj
2960888b8159535580b30550f99cb7361f62edd83100florianconst NSegment *VG_(am_extend_into_adjacent_reservation_client)( Addr addr,
296115fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian                                                                 SSizeT delta,
296215fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian                                                                 Bool *overflow)
296345f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
296445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int    segA, segR;
296545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   UInt   prot;
296645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes sres;
2967548be6d64c58729588a559b1512ad7625bc1b86esewardj
296815fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian   *overflow = False;
296915fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian
2970888b8159535580b30550f99cb7361f62edd83100florian   segA = find_nsegment_idx(addr);
2971888b8159535580b30550f99cb7361f62edd83100florian   aspacem_assert(nsegments[segA].kind == SkAnonC);
297245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
297345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (delta == 0)
2974888b8159535580b30550f99cb7361f62edd83100florian      return nsegments + segA;
297545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
297645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   prot =   (nsegments[segA].hasR ? VKI_PROT_READ : 0)
297745f4e7c91119c7d01a59f5e827c67841632c9314sewardj          | (nsegments[segA].hasW ? VKI_PROT_WRITE : 0)
297845f4e7c91119c7d01a59f5e827c67841632c9314sewardj          | (nsegments[segA].hasX ? VKI_PROT_EXEC : 0);
297945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
298045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   aspacem_assert(VG_IS_PAGE_ALIGNED(delta<0 ? -delta : delta));
298145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
298245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (delta > 0) {
298345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
298445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* Extending the segment forwards. */
298545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      segR = segA+1;
298645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (segR >= nsegments_used
298745f4e7c91119c7d01a59f5e827c67841632c9314sewardj          || nsegments[segR].kind != SkResvn
298815fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian          || nsegments[segR].smode != SmLower)
298915fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian         return NULL;
299015fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian
299115fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian      if (delta + VKI_PAGE_SIZE
299215fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian                > (nsegments[segR].end - nsegments[segR].start + 1)) {
299315fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian         *overflow = True;
299415fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian         return NULL;
299515fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian      }
299645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
299745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* Extend the kernel's mapping. */
2998f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
299945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      sres = VG_(am_do_mmap_NO_NOTIFY)(
300045f4e7c91119c7d01a59f5e827c67841632c9314sewardj                nsegments[segR].start, delta,
300145f4e7c91119c7d01a59f5e827c67841632c9314sewardj                prot,
300245f4e7c91119c7d01a59f5e827c67841632c9314sewardj                VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
300345f4e7c91119c7d01a59f5e827c67841632c9314sewardj                0, 0
300445f4e7c91119c7d01a59f5e827c67841632c9314sewardj             );
3005cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      if (sr_isError(sres))
3006888b8159535580b30550f99cb7361f62edd83100florian         return NULL; /* kernel bug if this happens? */
3007cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      if (sr_Res(sres) != nsegments[segR].start) {
300845f4e7c91119c7d01a59f5e827c67841632c9314sewardj         /* kernel bug if this happens? */
3009cda2f0fbda4c4b2644babc830244be8aed95de1dnjn        (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
3010888b8159535580b30550f99cb7361f62edd83100florian        return NULL;
3011548be6d64c58729588a559b1512ad7625bc1b86esewardj      }
3012548be6d64c58729588a559b1512ad7625bc1b86esewardj
301345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* Ok, success with the kernel.  Update our structures. */
30143bfb914e76943b35e96bbaead678c2c96f3380edflorian      nsegments[segR].start += delta;
30153bfb914e76943b35e96bbaead678c2c96f3380edflorian      nsegments[segA].end += delta;
30163bfb914e76943b35e96bbaead678c2c96f3380edflorian      aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
3017548be6d64c58729588a559b1512ad7625bc1b86esewardj
3018548be6d64c58729588a559b1512ad7625bc1b86esewardj   } else {
3019548be6d64c58729588a559b1512ad7625bc1b86esewardj
302045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* Extending the segment backwards. */
302145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      delta = -delta;
302245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      aspacem_assert(delta > 0);
302345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
302445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      segR = segA-1;
302545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (segR < 0
302645f4e7c91119c7d01a59f5e827c67841632c9314sewardj          || nsegments[segR].kind != SkResvn
302715fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian          || nsegments[segR].smode != SmUpper)
302815fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian         return NULL;
302915fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian
303015fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian      if (delta + VKI_PAGE_SIZE
303115fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian                > (nsegments[segR].end - nsegments[segR].start + 1)) {
303215fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian         *overflow = True;
303315fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian         return NULL;
303415fa8a2f9b64e24c76ef88d8bf660ea2296f0c36florian      }
303545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
303645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* Extend the kernel's mapping. */
3037f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
303845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      sres = VG_(am_do_mmap_NO_NOTIFY)(
303945f4e7c91119c7d01a59f5e827c67841632c9314sewardj                nsegments[segA].start-delta, delta,
304045f4e7c91119c7d01a59f5e827c67841632c9314sewardj                prot,
304145f4e7c91119c7d01a59f5e827c67841632c9314sewardj                VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
304245f4e7c91119c7d01a59f5e827c67841632c9314sewardj                0, 0
304345f4e7c91119c7d01a59f5e827c67841632c9314sewardj             );
3044cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      if (sr_isError(sres))
3045888b8159535580b30550f99cb7361f62edd83100florian         return NULL; /* kernel bug if this happens? */
3046cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      if (sr_Res(sres) != nsegments[segA].start-delta) {
304745f4e7c91119c7d01a59f5e827c67841632c9314sewardj         /* kernel bug if this happens? */
3048cda2f0fbda4c4b2644babc830244be8aed95de1dnjn        (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
3049888b8159535580b30550f99cb7361f62edd83100florian        return NULL;
305045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
3051548be6d64c58729588a559b1512ad7625bc1b86esewardj
305245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* Ok, success with the kernel.  Update our structures. */
30533bfb914e76943b35e96bbaead678c2c96f3380edflorian      nsegments[segR].end -= delta;
30543bfb914e76943b35e96bbaead678c2c96f3380edflorian      nsegments[segA].start -= delta;
30553bfb914e76943b35e96bbaead678c2c96f3380edflorian      aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
3056b5f6f51ebcac183818061bf53427a3e7808ef10dsewardj   }
3057b5f6f51ebcac183818061bf53427a3e7808ef10dsewardj
305845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
3059888b8159535580b30550f99cb7361f62edd83100florian   return nsegments + segA;
306098abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge}
306198abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
306279048ce723a3463c70257ce647f04b111de71863sewardj
306345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* --- --- --- resizing/move a mapping --- --- --- */
3064646c6aa268d4f1e524f2a9b721eef7a62d87046dthughes
3065f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#if HAVE_MREMAP
3066f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3067dd7318bea2a008f15085e12e026a78a6802e2e9cflorian/* This function grows a client mapping in place into an adjacent free segment.
3068dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   ADDR is the client mapping's start address and DELTA, which must be page
3069dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   aligned, is the growth amount. The function returns a pointer to the
3070dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   resized segment. The function is used in support of mremap. */
3071dd7318bea2a008f15085e12e026a78a6802e2e9cflorianconst NSegment *VG_(am_extend_map_client)( Addr addr, SizeT delta )
307245f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
307345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Addr     xStart;
307445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes   sres;
30759aaebc3476170f0776fe2e246bbc8baea6cc64fbthughes
307663a622f4da0254c435348f2c78b31aa66f4549c8sewardj   if (0)
307763a622f4da0254c435348f2c78b31aa66f4549c8sewardj      VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) BEFORE");
307863a622f4da0254c435348f2c78b31aa66f4549c8sewardj
3079dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   /* Get the client segment */
3080dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   Int ix = find_nsegment_idx(addr);
3081dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   aspacem_assert(ix >= 0 && ix < nsegments_used);
30829aaebc3476170f0776fe2e246bbc8baea6cc64fbthughes
3083dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   NSegment *seg = nsegments + ix;
3084dd7318bea2a008f15085e12e026a78a6802e2e9cflorian
30857a5681fd96d9ccf3527daf6a32a0378fe2ca7faeflorian   aspacem_assert(seg->kind == SkFileC || seg->kind == SkAnonC ||
30867a5681fd96d9ccf3527daf6a32a0378fe2ca7faeflorian                  seg->kind == SkShmC);
3087dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   aspacem_assert(delta > 0 && VG_IS_PAGE_ALIGNED(delta)) ;
3088394790db0f8e9ce913e12df8555af7155b9aa0bdsewardj
308945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   xStart = seg->end+1;
3090dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   aspacem_assert(xStart + delta >= delta);   // no wrap-around
30919aaebc3476170f0776fe2e246bbc8baea6cc64fbthughes
3092dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   /* The segment following the client segment must be a free segment and
3093dd7318bea2a008f15085e12e026a78a6802e2e9cflorian      it must be large enough to cover the additional memory. */
3094dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   NSegment *segf = seg + 1;
3095dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   aspacem_assert(segf->kind == SkFree);
3096dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   aspacem_assert(segf->start == xStart);
3097dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   aspacem_assert(xStart + delta - 1 <= segf->end);
3098dd7318bea2a008f15085e12e026a78a6802e2e9cflorian
3099dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   SizeT seg_old_len = seg->end + 1 - seg->start;
31009aaebc3476170f0776fe2e246bbc8baea6cc64fbthughes
310145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
3102297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj   sres = ML_(am_do_extend_mapping_NO_NOTIFY)( seg->start,
3103297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj                                               seg_old_len,
3104297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj                                               seg_old_len + delta );
3105cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_isError(sres)) {
310645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      AM_SANITY_CHECK;
3107dd7318bea2a008f15085e12e026a78a6802e2e9cflorian      return NULL;
310863a622f4da0254c435348f2c78b31aa66f4549c8sewardj   } else {
310963a622f4da0254c435348f2c78b31aa66f4549c8sewardj      /* the area must not have moved */
3110cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      aspacem_assert(sr_Res(sres) == seg->start);
31119aaebc3476170f0776fe2e246bbc8baea6cc64fbthughes   }
31129aaebc3476170f0776fe2e246bbc8baea6cc64fbthughes
3113dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   NSegment seg_copy = *seg;
311445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg_copy.end += delta;
311545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment( &seg_copy );
3116548be6d64c58729588a559b1512ad7625bc1b86esewardj
311763a622f4da0254c435348f2c78b31aa66f4549c8sewardj   if (0)
311863a622f4da0254c435348f2c78b31aa66f4549c8sewardj      VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) AFTER");
311963a622f4da0254c435348f2c78b31aa66f4549c8sewardj
312045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
3121dd7318bea2a008f15085e12e026a78a6802e2e9cflorian   return nsegments + find_nsegment_idx(addr);
3122548be6d64c58729588a559b1512ad7625bc1b86esewardj}
3123548be6d64c58729588a559b1512ad7625bc1b86esewardj
3124548be6d64c58729588a559b1512ad7625bc1b86esewardj
312545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Remap the old address range to the new address range.  Fails if any
312645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   parameter is not page aligned, if the either size is zero, if any
312745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   wraparound is implied, if the old address range does not fall
312845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   entirely within a single segment, if the new address range overlaps
312945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   with the old one, or if the old address range is not a valid client
313045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   mapping.  If *need_discard is True after a successful return, the
313145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   caller should immediately discard translations from both specified
313245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   address ranges.  */
3133b5f6f51ebcac183818061bf53427a3e7808ef10dsewardj
313445f4e7c91119c7d01a59f5e827c67841632c9314sewardjBool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
313545f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                        Addr old_addr, SizeT old_len,
313645f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                        Addr new_addr, SizeT new_len )
3137855d93d2e9940890b28874520fa4c1677bf825e2jsgf{
313845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int      iLo, iHi;
313945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes   sres;
3140fcb3bc99945217eb66980488b933a6b65dc2f091tom   NSegment seg;
3141855d93d2e9940890b28874520fa4c1677bf825e2jsgf
314245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (old_len == 0 || new_len == 0)
314345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
3144b5f6f51ebcac183818061bf53427a3e7808ef10dsewardj
314545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (!VG_IS_PAGE_ALIGNED(old_addr) || !VG_IS_PAGE_ALIGNED(old_len)
314645f4e7c91119c7d01a59f5e827c67841632c9314sewardj       || !VG_IS_PAGE_ALIGNED(new_addr) || !VG_IS_PAGE_ALIGNED(new_len))
314745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
3148b5f6f51ebcac183818061bf53427a3e7808ef10dsewardj
314945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (old_addr + old_len < old_addr
315045f4e7c91119c7d01a59f5e827c67841632c9314sewardj       || new_addr + new_len < new_addr)
315145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
3152b5f6f51ebcac183818061bf53427a3e7808ef10dsewardj
315345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (old_addr + old_len - 1 < new_addr
315445f4e7c91119c7d01a59f5e827c67841632c9314sewardj       || new_addr + new_len - 1 < old_addr) {
315545f4e7c91119c7d01a59f5e827c67841632c9314sewardj      /* no overlap */
315645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   } else
315745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
3158855d93d2e9940890b28874520fa4c1677bf825e2jsgf
315945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   iLo = find_nsegment_idx( old_addr );
316045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   iHi = find_nsegment_idx( old_addr + old_len - 1 );
316145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (iLo != iHi)
316245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
3163b5f6f51ebcac183818061bf53427a3e7808ef10dsewardj
31647a5681fd96d9ccf3527daf6a32a0378fe2ca7faeflorian   if (nsegments[iLo].kind != SkFileC && nsegments[iLo].kind != SkAnonC &&
31657a5681fd96d9ccf3527daf6a32a0378fe2ca7faeflorian       nsegments[iLo].kind != SkShmC)
316645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
316798abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
3168297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj   sres = ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)
3169297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj             ( old_addr, old_len, new_addr, new_len );
3170cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_isError(sres)) {
317145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      AM_SANITY_CHECK;
317245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      return False;
3173ee2de2c04815768bd994d3c341e736eca1e72175sewardj   } else {
3174cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      aspacem_assert(sr_Res(sres) == new_addr);
317545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
317686f12dca3206f958abe000ff8c7de58098e0897cnjn
317745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   *need_discard = any_Ts_in_range( old_addr, old_len )
317845f4e7c91119c7d01a59f5e827c67841632c9314sewardj                   || any_Ts_in_range( new_addr, new_len );
317986f12dca3206f958abe000ff8c7de58098e0897cnjn
3180fcb3bc99945217eb66980488b933a6b65dc2f091tom   seg = nsegments[iLo];
3181fcb3bc99945217eb66980488b933a6b65dc2f091tom
3182fcb3bc99945217eb66980488b933a6b65dc2f091tom   /* Mark the new area based on the old seg. */
3183fcb3bc99945217eb66980488b933a6b65dc2f091tom   if (seg.kind == SkFileC) {
3184fcb3bc99945217eb66980488b933a6b65dc2f091tom      seg.offset += ((ULong)old_addr) - ((ULong)seg.start);
3185fcb3bc99945217eb66980488b933a6b65dc2f091tom   }
3186fcb3bc99945217eb66980488b933a6b65dc2f091tom   seg.start = new_addr;
3187fcb3bc99945217eb66980488b933a6b65dc2f091tom   seg.end   = new_addr + new_len - 1;
3188fcb3bc99945217eb66980488b933a6b65dc2f091tom   add_segment( &seg );
318986f12dca3206f958abe000ff8c7de58098e0897cnjn
319045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Create a free hole in the old location. */
319145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   init_nsegment( &seg );
319245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.start = old_addr;
319345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   seg.end   = old_addr + old_len - 1;
3194613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj   /* See comments in VG_(am_notify_munmap) about this SkResvn vs
3195613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj      SkFree thing. */
3196613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj   if (old_addr > aspacem_maxAddr
3197613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj       && /* check previous comparison is meaningful */
3198613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj          aspacem_maxAddr < Addr_MAX)
3199613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj      seg.kind = SkResvn;
3200613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj   else
3201613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj      seg.kind = SkFree;
3202613a9f26e5b66b34c4031bdb9452c11c0a006d57sewardj
320345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   add_segment( &seg );
320486f12dca3206f958abe000ff8c7de58098e0897cnjn
320545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   AM_SANITY_CHECK;
320645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   return True;
320798abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge}
320898abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge
3209f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#endif // HAVE_MREMAP
3210f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3211f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3212c401ae7ea8e709040d70a2ea6e2e44979aa90ac0bart#if defined(VGO_linux)
3213c401ae7ea8e709040d70a2ea6e2e44979aa90ac0bart
321445f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*-----------------------------------------------------------------*/
321545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*---                                                           ---*/
3216cb249ab3febb3757a0b0582be21952efacf415e5sewardj/*--- A simple parser for /proc/self/maps on Linux 2.4.X/2.6.X. ---*/
3217cb249ab3febb3757a0b0582be21952efacf415e5sewardj/*--- Almost completely independent of the stuff above.  The    ---*/
3218cb249ab3febb3757a0b0582be21952efacf415e5sewardj/*--- only function it 'exports' to the code above this comment ---*/
3219cb249ab3febb3757a0b0582be21952efacf415e5sewardj/*--- is parse_procselfmaps.                                    ---*/
3220cb249ab3febb3757a0b0582be21952efacf415e5sewardj/*---                                                           ---*/
3221cb249ab3febb3757a0b0582be21952efacf415e5sewardj/*-----------------------------------------------------------------*/
3222cb249ab3febb3757a0b0582be21952efacf415e5sewardj
322338a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj/*------BEGIN-procmaps-parser-for-Linux--------------------------*/
322438a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj
3225cb249ab3febb3757a0b0582be21952efacf415e5sewardj/* Size of a smallish table used to read /proc/self/map entries. */
3226cb249ab3febb3757a0b0582be21952efacf415e5sewardj#define M_PROCMAP_BUF 100000
3227cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3228cb249ab3febb3757a0b0582be21952efacf415e5sewardj/* static ... to keep it out of the stack frame. */
3229dbb3584f591710a15a437918c0fc27e300993566florianstatic HChar procmap_buf[M_PROCMAP_BUF];
3230cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3231cb249ab3febb3757a0b0582be21952efacf415e5sewardj/* Records length of /proc/self/maps read into procmap_buf. */
3232cb249ab3febb3757a0b0582be21952efacf415e5sewardjstatic Int  buf_n_tot;
3233cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3234cb249ab3febb3757a0b0582be21952efacf415e5sewardj/* Helper fns. */
3235cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3236dbb3584f591710a15a437918c0fc27e300993566florianstatic Int hexdigit ( HChar c )
3237cb249ab3febb3757a0b0582be21952efacf415e5sewardj{
3238cb249ab3febb3757a0b0582be21952efacf415e5sewardj   if (c >= '0' && c <= '9') return (Int)(c - '0');
3239cb249ab3febb3757a0b0582be21952efacf415e5sewardj   if (c >= 'a' && c <= 'f') return 10 + (Int)(c - 'a');
3240cb249ab3febb3757a0b0582be21952efacf415e5sewardj   if (c >= 'A' && c <= 'F') return 10 + (Int)(c - 'A');
3241cb249ab3febb3757a0b0582be21952efacf415e5sewardj   return -1;
3242cb249ab3febb3757a0b0582be21952efacf415e5sewardj}
3243cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3244dbb3584f591710a15a437918c0fc27e300993566florianstatic Int decdigit ( HChar c )
3245cb249ab3febb3757a0b0582be21952efacf415e5sewardj{
3246cb249ab3febb3757a0b0582be21952efacf415e5sewardj   if (c >= '0' && c <= '9') return (Int)(c - '0');
3247cb249ab3febb3757a0b0582be21952efacf415e5sewardj   return -1;
3248cb249ab3febb3757a0b0582be21952efacf415e5sewardj}
3249cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3250dbb3584f591710a15a437918c0fc27e300993566florianstatic Int readchar ( const HChar* buf, HChar* ch )
3251cb249ab3febb3757a0b0582be21952efacf415e5sewardj{
3252cb249ab3febb3757a0b0582be21952efacf415e5sewardj   if (*buf == 0) return 0;
3253cb249ab3febb3757a0b0582be21952efacf415e5sewardj   *ch = *buf;
3254cb249ab3febb3757a0b0582be21952efacf415e5sewardj   return 1;
3255cb249ab3febb3757a0b0582be21952efacf415e5sewardj}
3256cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3257dbb3584f591710a15a437918c0fc27e300993566florianstatic Int readhex ( const HChar* buf, UWord* val )
3258cb249ab3febb3757a0b0582be21952efacf415e5sewardj{
3259274461dcb67f680196c97e8afb7028a79b97dcb7sewardj   /* Read a word-sized hex number. */
3260274461dcb67f680196c97e8afb7028a79b97dcb7sewardj   Int n = 0;
3261274461dcb67f680196c97e8afb7028a79b97dcb7sewardj   *val = 0;
3262274461dcb67f680196c97e8afb7028a79b97dcb7sewardj   while (hexdigit(*buf) >= 0) {
3263274461dcb67f680196c97e8afb7028a79b97dcb7sewardj      *val = (*val << 4) + hexdigit(*buf);
3264274461dcb67f680196c97e8afb7028a79b97dcb7sewardj      n++; buf++;
3265274461dcb67f680196c97e8afb7028a79b97dcb7sewardj   }
3266274461dcb67f680196c97e8afb7028a79b97dcb7sewardj   return n;
3267274461dcb67f680196c97e8afb7028a79b97dcb7sewardj}
3268274461dcb67f680196c97e8afb7028a79b97dcb7sewardj
3269dbb3584f591710a15a437918c0fc27e300993566florianstatic Int readhex64 ( const HChar* buf, ULong* val )
3270274461dcb67f680196c97e8afb7028a79b97dcb7sewardj{
3271274461dcb67f680196c97e8afb7028a79b97dcb7sewardj   /* Read a potentially 64-bit hex number. */
3272cb249ab3febb3757a0b0582be21952efacf415e5sewardj   Int n = 0;
3273cb249ab3febb3757a0b0582be21952efacf415e5sewardj   *val = 0;
3274cb249ab3febb3757a0b0582be21952efacf415e5sewardj   while (hexdigit(*buf) >= 0) {
3275cb249ab3febb3757a0b0582be21952efacf415e5sewardj      *val = (*val << 4) + hexdigit(*buf);
3276cb249ab3febb3757a0b0582be21952efacf415e5sewardj      n++; buf++;
3277cb249ab3febb3757a0b0582be21952efacf415e5sewardj   }
3278cb249ab3febb3757a0b0582be21952efacf415e5sewardj   return n;
3279cb249ab3febb3757a0b0582be21952efacf415e5sewardj}
3280cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3281dbb3584f591710a15a437918c0fc27e300993566florianstatic Int readdec64 ( const HChar* buf, ULong* val )
3282cb249ab3febb3757a0b0582be21952efacf415e5sewardj{
3283cb249ab3febb3757a0b0582be21952efacf415e5sewardj   Int n = 0;
3284cb249ab3febb3757a0b0582be21952efacf415e5sewardj   *val = 0;
328554212b6475e26755d9ecf452b9cc44fbc5772b7eflorian   while (decdigit(*buf) >= 0) {
3286cb249ab3febb3757a0b0582be21952efacf415e5sewardj      *val = (*val * 10) + decdigit(*buf);
3287cb249ab3febb3757a0b0582be21952efacf415e5sewardj      n++; buf++;
3288cb249ab3febb3757a0b0582be21952efacf415e5sewardj   }
3289cb249ab3febb3757a0b0582be21952efacf415e5sewardj   return n;
3290cb249ab3febb3757a0b0582be21952efacf415e5sewardj}
3291cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3292cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3293cb249ab3febb3757a0b0582be21952efacf415e5sewardj/* Get the contents of /proc/self/maps into a static buffer.  If
3294cb249ab3febb3757a0b0582be21952efacf415e5sewardj   there's a syntax error, it won't fit, or other failure, just
3295cb249ab3febb3757a0b0582be21952efacf415e5sewardj   abort. */
3296cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3297cb249ab3febb3757a0b0582be21952efacf415e5sewardjstatic void read_procselfmaps_into_buf ( void )
3298cb249ab3febb3757a0b0582be21952efacf415e5sewardj{
3299cb249ab3febb3757a0b0582be21952efacf415e5sewardj   Int    n_chunk;
3300cb249ab3febb3757a0b0582be21952efacf415e5sewardj   SysRes fd;
3301cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3302cb249ab3febb3757a0b0582be21952efacf415e5sewardj   /* Read the initial memory mapping from the /proc filesystem. */
3303297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj   fd = ML_(am_open)( "/proc/self/maps", VKI_O_RDONLY, 0 );
3304cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   if (sr_isError(fd))
3305297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj      ML_(am_barf)("can't open /proc/self/maps");
3306cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3307cb249ab3febb3757a0b0582be21952efacf415e5sewardj   buf_n_tot = 0;
3308cb249ab3febb3757a0b0582be21952efacf415e5sewardj   do {
3309cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      n_chunk = ML_(am_read)( sr_Res(fd), &procmap_buf[buf_n_tot],
3310cb249ab3febb3757a0b0582be21952efacf415e5sewardj                              M_PROCMAP_BUF - buf_n_tot );
3311297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj      if (n_chunk >= 0)
3312297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj         buf_n_tot += n_chunk;
3313cb249ab3febb3757a0b0582be21952efacf415e5sewardj   } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
3314cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3315cda2f0fbda4c4b2644babc830244be8aed95de1dnjn   ML_(am_close)(sr_Res(fd));
3316cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3317cb249ab3febb3757a0b0582be21952efacf415e5sewardj   if (buf_n_tot >= M_PROCMAP_BUF-5)
3318297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj      ML_(am_barf_toolow)("M_PROCMAP_BUF");
3319cb249ab3febb3757a0b0582be21952efacf415e5sewardj   if (buf_n_tot == 0)
3320297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj      ML_(am_barf)("I/O error on /proc/self/maps");
3321cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3322cb249ab3febb3757a0b0582be21952efacf415e5sewardj   procmap_buf[buf_n_tot] = 0;
3323cb249ab3febb3757a0b0582be21952efacf415e5sewardj}
3324cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3325cb249ab3febb3757a0b0582be21952efacf415e5sewardj/* Parse /proc/self/maps.  For each map entry, call
3326cb249ab3febb3757a0b0582be21952efacf415e5sewardj   record_mapping, passing it, in this order:
3327cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3328cb249ab3febb3757a0b0582be21952efacf415e5sewardj      start address in memory
3329cb249ab3febb3757a0b0582be21952efacf415e5sewardj      length
3330cb249ab3febb3757a0b0582be21952efacf415e5sewardj      page protections (using the VKI_PROT_* flags)
3331cb249ab3febb3757a0b0582be21952efacf415e5sewardj      mapped file device and inode
3332cb249ab3febb3757a0b0582be21952efacf415e5sewardj      offset in file, or zero if no file
3333cb249ab3febb3757a0b0582be21952efacf415e5sewardj      filename, zero terminated, or NULL if no file
3334cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3335cb249ab3febb3757a0b0582be21952efacf415e5sewardj   So the sig of the called fn might be
3336cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3337cb249ab3febb3757a0b0582be21952efacf415e5sewardj      void (*record_mapping)( Addr start, SizeT size, UInt prot,
3338cb249ab3febb3757a0b0582be21952efacf415e5sewardj			      UInt dev, UInt info,
3339cb249ab3febb3757a0b0582be21952efacf415e5sewardj                              ULong foffset, UChar* filename )
3340cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3341cb249ab3febb3757a0b0582be21952efacf415e5sewardj   Note that the supplied filename is transiently stored; record_mapping
3342cb249ab3febb3757a0b0582be21952efacf415e5sewardj   should make a copy if it wants to keep it.
3343cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3344cb249ab3febb3757a0b0582be21952efacf415e5sewardj   Nb: it is important that this function does not alter the contents of
3345cb249ab3febb3757a0b0582be21952efacf415e5sewardj       procmap_buf!
3346cb249ab3febb3757a0b0582be21952efacf415e5sewardj*/
3347cb249ab3febb3757a0b0582be21952efacf415e5sewardjstatic void parse_procselfmaps (
3348cb249ab3febb3757a0b0582be21952efacf415e5sewardj      void (*record_mapping)( Addr addr, SizeT len, UInt prot,
3349c4431bfe04c7490ea2d74939d222d87f13f30960njn                              ULong dev, ULong ino, Off64T offset,
3350dbb3584f591710a15a437918c0fc27e300993566florian                              const HChar* filename ),
3351cb249ab3febb3757a0b0582be21952efacf415e5sewardj      void (*record_gap)( Addr addr, SizeT len )
3352cb249ab3febb3757a0b0582be21952efacf415e5sewardj   )
3353cb249ab3febb3757a0b0582be21952efacf415e5sewardj{
3354cb249ab3febb3757a0b0582be21952efacf415e5sewardj   Int    i, j, i_eol;
3355cb249ab3febb3757a0b0582be21952efacf415e5sewardj   Addr   start, endPlusOne, gapStart;
3356dbb3584f591710a15a437918c0fc27e300993566florian   HChar* filename;
3357dbb3584f591710a15a437918c0fc27e300993566florian   HChar  rr, ww, xx, pp, ch, tmp;
3358419060073e7943846cc9e0bcdcb25258d90da2dcsewardj   UInt	  prot;
3359419060073e7943846cc9e0bcdcb25258d90da2dcsewardj   UWord  maj, min;
3360419060073e7943846cc9e0bcdcb25258d90da2dcsewardj   ULong  foffset, dev, ino;
3361cb249ab3febb3757a0b0582be21952efacf415e5sewardj
33624c3faae4aa73a0693c66a24daccf8bc0a0e421f7sewardj   foffset = ino = 0; /* keep gcc-4.1.0 happy */
33634c3faae4aa73a0693c66a24daccf8bc0a0e421f7sewardj
3364cb249ab3febb3757a0b0582be21952efacf415e5sewardj   read_procselfmaps_into_buf();
3365cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3366cb249ab3febb3757a0b0582be21952efacf415e5sewardj   aspacem_assert('\0' != procmap_buf[0] && 0 != buf_n_tot);
3367cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3368cb249ab3febb3757a0b0582be21952efacf415e5sewardj   if (0)
3369cb249ab3febb3757a0b0582be21952efacf415e5sewardj      VG_(debugLog)(0, "procselfmaps", "raw:\n%s\n", procmap_buf);
3370cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3371cb249ab3febb3757a0b0582be21952efacf415e5sewardj   /* Ok, it's safely aboard.  Parse the entries. */
3372cb249ab3febb3757a0b0582be21952efacf415e5sewardj   i = 0;
3373cb249ab3febb3757a0b0582be21952efacf415e5sewardj   gapStart = Addr_MIN;
3374cb249ab3febb3757a0b0582be21952efacf415e5sewardj   while (True) {
3375cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (i >= buf_n_tot) break;
3376cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3377cb249ab3febb3757a0b0582be21952efacf415e5sewardj      /* Read (without fscanf :) the pattern %16x-%16x %c%c%c%c %16x %2x:%2x %d */
3378cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readhex(&procmap_buf[i], &start);
3379cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j > 0) i += j; else goto syntaxerror;
3380cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readchar(&procmap_buf[i], &ch);
3381cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j == 1 && ch == '-') i += j; else goto syntaxerror;
3382cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readhex(&procmap_buf[i], &endPlusOne);
3383cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j > 0) i += j; else goto syntaxerror;
3384cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3385cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readchar(&procmap_buf[i], &ch);
3386cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3387cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3388cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readchar(&procmap_buf[i], &rr);
3389cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j == 1 && (rr == 'r' || rr == '-')) i += j; else goto syntaxerror;
3390cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readchar(&procmap_buf[i], &ww);
3391cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j == 1 && (ww == 'w' || ww == '-')) i += j; else goto syntaxerror;
3392cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readchar(&procmap_buf[i], &xx);
3393cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j == 1 && (xx == 'x' || xx == '-')) i += j; else goto syntaxerror;
3394cb249ab3febb3757a0b0582be21952efacf415e5sewardj      /* This field is the shared/private flag */
3395cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readchar(&procmap_buf[i], &pp);
3396cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j == 1 && (pp == 'p' || pp == '-' || pp == 's'))
3397cb249ab3febb3757a0b0582be21952efacf415e5sewardj                                              i += j; else goto syntaxerror;
3398cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3399cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readchar(&procmap_buf[i], &ch);
3400cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3401cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3402274461dcb67f680196c97e8afb7028a79b97dcb7sewardj      j = readhex64(&procmap_buf[i], &foffset);
3403cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j > 0) i += j; else goto syntaxerror;
3404cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3405cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readchar(&procmap_buf[i], &ch);
3406cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3407cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3408cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readhex(&procmap_buf[i], &maj);
3409cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j > 0) i += j; else goto syntaxerror;
3410cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readchar(&procmap_buf[i], &ch);
3411cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j == 1 && ch == ':') i += j; else goto syntaxerror;
3412cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readhex(&procmap_buf[i], &min);
3413cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j > 0) i += j; else goto syntaxerror;
3414cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3415cb249ab3febb3757a0b0582be21952efacf415e5sewardj      j = readchar(&procmap_buf[i], &ch);
3416cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3417cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3418419060073e7943846cc9e0bcdcb25258d90da2dcsewardj      j = readdec64(&procmap_buf[i], &ino);
3419cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (j > 0) i += j; else goto syntaxerror;
3420cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3421cb249ab3febb3757a0b0582be21952efacf415e5sewardj      goto read_line_ok;
3422cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3423cb249ab3febb3757a0b0582be21952efacf415e5sewardj    syntaxerror:
3424cb249ab3febb3757a0b0582be21952efacf415e5sewardj      VG_(debugLog)(0, "Valgrind:",
3425cb249ab3febb3757a0b0582be21952efacf415e5sewardj                       "FATAL: syntax error reading /proc/self/maps\n");
3426cb249ab3febb3757a0b0582be21952efacf415e5sewardj      { Int k, m;
3427cb249ab3febb3757a0b0582be21952efacf415e5sewardj        HChar buf50[51];
3428cb249ab3febb3757a0b0582be21952efacf415e5sewardj        m = 0;
3429cb249ab3febb3757a0b0582be21952efacf415e5sewardj        buf50[m] = 0;
3430cb249ab3febb3757a0b0582be21952efacf415e5sewardj        k = i - 50;
3431cb249ab3febb3757a0b0582be21952efacf415e5sewardj        if (k < 0) k = 0;
3432cb249ab3febb3757a0b0582be21952efacf415e5sewardj        for (; k <= i; k++) {
3433cb249ab3febb3757a0b0582be21952efacf415e5sewardj           buf50[m] = procmap_buf[k];
3434cb249ab3febb3757a0b0582be21952efacf415e5sewardj           buf50[m+1] = 0;
3435cb249ab3febb3757a0b0582be21952efacf415e5sewardj           if (m < 50-1) m++;
3436cb249ab3febb3757a0b0582be21952efacf415e5sewardj        }
3437cb249ab3febb3757a0b0582be21952efacf415e5sewardj        VG_(debugLog)(0, "procselfmaps", "Last 50 chars: '%s'\n", buf50);
3438cb249ab3febb3757a0b0582be21952efacf415e5sewardj      }
3439297f6b0565fd0bb08fd3ddc1f2377ee6b3306b82sewardj      ML_(am_exit)(1);
3440cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3441cb249ab3febb3757a0b0582be21952efacf415e5sewardj    read_line_ok:
3442cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3443bd28c5e5dbdf69de901c025f67d4c1af24175492florian      aspacem_assert(i < buf_n_tot);
3444bd28c5e5dbdf69de901c025f67d4c1af24175492florian
3445cb249ab3febb3757a0b0582be21952efacf415e5sewardj      /* Try and find the name of the file mapped to this segment, if
3446bd28c5e5dbdf69de901c025f67d4c1af24175492florian         it exists.  Note that file names can contain spaces. */
3447cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3448bd28c5e5dbdf69de901c025f67d4c1af24175492florian      // Move i to the next non-space char, which should be either a '/',
3449bd28c5e5dbdf69de901c025f67d4c1af24175492florian      // a '[', or a newline.
3450bd28c5e5dbdf69de901c025f67d4c1af24175492florian      while (procmap_buf[i] == ' ') i++;
3451cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3452cb249ab3febb3757a0b0582be21952efacf415e5sewardj      // Move i_eol to the end of the line.
3453cb249ab3febb3757a0b0582be21952efacf415e5sewardj      i_eol = i;
3454bd28c5e5dbdf69de901c025f67d4c1af24175492florian      while (procmap_buf[i_eol] != '\n') i_eol++;
3455cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3456cb249ab3febb3757a0b0582be21952efacf415e5sewardj      // If there's a filename...
3457bd28c5e5dbdf69de901c025f67d4c1af24175492florian      if (procmap_buf[i] == '/') {
3458cb249ab3febb3757a0b0582be21952efacf415e5sewardj         /* Minor hack: put a '\0' at the filename end for the call to
3459cb249ab3febb3757a0b0582be21952efacf415e5sewardj            'record_mapping', then restore the old char with 'tmp'. */
3460cb249ab3febb3757a0b0582be21952efacf415e5sewardj         filename = &procmap_buf[i];
3461cb249ab3febb3757a0b0582be21952efacf415e5sewardj         tmp = filename[i_eol - i];
3462cb249ab3febb3757a0b0582be21952efacf415e5sewardj         filename[i_eol - i] = '\0';
3463cb249ab3febb3757a0b0582be21952efacf415e5sewardj      } else {
3464cb249ab3febb3757a0b0582be21952efacf415e5sewardj	 tmp = 0;
3465cb249ab3febb3757a0b0582be21952efacf415e5sewardj         filename = NULL;
3466cb249ab3febb3757a0b0582be21952efacf415e5sewardj         foffset = 0;
3467cb249ab3febb3757a0b0582be21952efacf415e5sewardj      }
3468cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3469cb249ab3febb3757a0b0582be21952efacf415e5sewardj      prot = 0;
3470cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (rr == 'r') prot |= VKI_PROT_READ;
3471cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (ww == 'w') prot |= VKI_PROT_WRITE;
3472cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (xx == 'x') prot |= VKI_PROT_EXEC;
3473cb249ab3febb3757a0b0582be21952efacf415e5sewardj
347499ffec4b2a139513c77a420a459d5ea9beaadb98tom      /* Linux has two ways to encode a device number when it
347599ffec4b2a139513c77a420a459d5ea9beaadb98tom         is exposed to user space (via fstat etc). The old way
347699ffec4b2a139513c77a420a459d5ea9beaadb98tom         is the traditional unix scheme that produces a 16 bit
347799ffec4b2a139513c77a420a459d5ea9beaadb98tom         device number with the top 8 being the major number and
347899ffec4b2a139513c77a420a459d5ea9beaadb98tom         the bottom 8 the minor number.
347999ffec4b2a139513c77a420a459d5ea9beaadb98tom
348099ffec4b2a139513c77a420a459d5ea9beaadb98tom         The new scheme allows for a 12 bit major number and
348199ffec4b2a139513c77a420a459d5ea9beaadb98tom         a 20 bit minor number by using a 32 bit device number
348299ffec4b2a139513c77a420a459d5ea9beaadb98tom         and putting the top 12 bits of the minor number into
348399ffec4b2a139513c77a420a459d5ea9beaadb98tom         the top 12 bits of the device number thus leaving an
348499ffec4b2a139513c77a420a459d5ea9beaadb98tom         extra 4 bits for the major number.
348599ffec4b2a139513c77a420a459d5ea9beaadb98tom
348699ffec4b2a139513c77a420a459d5ea9beaadb98tom         If the minor and major number are both single byte
348799ffec4b2a139513c77a420a459d5ea9beaadb98tom         values then both schemes give the same result so we
348899ffec4b2a139513c77a420a459d5ea9beaadb98tom         use the new scheme here in case either number is
348999ffec4b2a139513c77a420a459d5ea9beaadb98tom         outside the 0-255 range and then use fstat64 when
349099ffec4b2a139513c77a420a459d5ea9beaadb98tom         available (or fstat on 64 bit systems) so that we
349199ffec4b2a139513c77a420a459d5ea9beaadb98tom         should always have a new style device number and
349299ffec4b2a139513c77a420a459d5ea9beaadb98tom         everything should match. */
349399ffec4b2a139513c77a420a459d5ea9beaadb98tom      dev = (min & 0xff) | (maj << 8) | ((min & ~0xff) << 12);
349499ffec4b2a139513c77a420a459d5ea9beaadb98tom
3495cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if (record_gap && gapStart < start)
3496cb249ab3febb3757a0b0582be21952efacf415e5sewardj         (*record_gap) ( gapStart, start-gapStart );
3497cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3498e6bbc36e0095970ded2564c1763026c79ccadbdesewardj      if (record_mapping && start < endPlusOne)
3499e6bbc36e0095970ded2564c1763026c79ccadbdesewardj         (*record_mapping) ( start, endPlusOne-start,
3500e6bbc36e0095970ded2564c1763026c79ccadbdesewardj                             prot, dev, ino,
3501e6bbc36e0095970ded2564c1763026c79ccadbdesewardj                             foffset, filename );
3502cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3503cb249ab3febb3757a0b0582be21952efacf415e5sewardj      if ('\0' != tmp) {
3504cb249ab3febb3757a0b0582be21952efacf415e5sewardj         filename[i_eol - i] = tmp;
3505cb249ab3febb3757a0b0582be21952efacf415e5sewardj      }
3506cb249ab3febb3757a0b0582be21952efacf415e5sewardj
3507cb249ab3febb3757a0b0582be21952efacf415e5sewardj      i = i_eol + 1;
3508cb249ab3febb3757a0b0582be21952efacf415e5sewardj      gapStart = endPlusOne;
3509cb249ab3febb3757a0b0582be21952efacf415e5sewardj   }
3510cb249ab3febb3757a0b0582be21952efacf415e5sewardj
351138a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj#  if defined(VGP_arm_linux)
351238a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj   /* ARM puts code at the end of memory that contains processor
351338a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      specific stuff (cmpxchg, getting the thread local storage, etc.)
351438a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      This isn't specified in /proc/self/maps, so do it here.  This
351538a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      kludgery causes the view of memory, as presented to
351638a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      record_gap/record_mapping, to actually reflect reality.  IMO
351738a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      (JRS, 2010-Jan-03) the fact that /proc/.../maps does not list
351838a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj      the commpage should be regarded as a bug in the kernel. */
351938a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj   { const Addr commpage_start = ARM_LINUX_FAKE_COMMPAGE_START;
352038a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj     const Addr commpage_end1  = ARM_LINUX_FAKE_COMMPAGE_END1;
352138a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj     if (gapStart < commpage_start) {
352238a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj        if (record_gap)
352338a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj           (*record_gap)( gapStart, commpage_start - gapStart );
352438a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj        if (record_mapping)
352538a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj           (*record_mapping)( commpage_start, commpage_end1 - commpage_start,
352638a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj                              VKI_PROT_READ|VKI_PROT_EXEC,
352738a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj                              0/*dev*/, 0/*ino*/, 0/*foffset*/,
352838a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj                              NULL);
352938a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj        gapStart = commpage_end1;
353038a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj     }
353138a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj   }
353238a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj#  endif
353338a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj
3534cb249ab3febb3757a0b0582be21952efacf415e5sewardj   if (record_gap && gapStart < Addr_MAX)
3535cb249ab3febb3757a0b0582be21952efacf415e5sewardj      (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
3536cb249ab3febb3757a0b0582be21952efacf415e5sewardj}
3537cb249ab3febb3757a0b0582be21952efacf415e5sewardj
353838a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj/*------END-procmaps-parser-for-Linux----------------------------*/
353938a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj
354038a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj/*------BEGIN-procmaps-parser-for-Darwin-------------------------*/
354138a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj
3542f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#elif defined(VGO_darwin)
3543f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <mach/mach.h>
3544f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <mach/mach_vm.h>
3545f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3546f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic unsigned int mach2vki(unsigned int vm_prot)
3547f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
3548f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   return
3549f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      ((vm_prot & VM_PROT_READ)    ? VKI_PROT_READ    : 0) |
3550f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      ((vm_prot & VM_PROT_WRITE)   ? VKI_PROT_WRITE   : 0) |
3551f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      ((vm_prot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC    : 0) ;
3552f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
3553f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3554f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic UInt stats_machcalls = 0;
3555f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3556f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic void parse_procselfmaps (
3557f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      void (*record_mapping)( Addr addr, SizeT len, UInt prot,
3558f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                              ULong dev, ULong ino, Off64T offset,
3559dbb3584f591710a15a437918c0fc27e300993566florian                              const HChar* filename ),
3560f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      void (*record_gap)( Addr addr, SizeT len )
3561f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   )
3562f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
3563f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   vm_address_t iter;
3564f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   unsigned int depth;
3565f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   vm_address_t last;
3566f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3567f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   iter = 0;
3568f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   depth = 0;
3569f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   last = 0;
3570f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   while (1) {
3571f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      mach_vm_address_t addr = iter;
3572f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      mach_vm_size_t size;
3573f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      vm_region_submap_short_info_data_64_t info;
3574f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      kern_return_t kr;
3575f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3576f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      while (1) {
3577f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         mach_msg_type_number_t info_count
3578f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
3579f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         stats_machcalls++;
3580f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth,
3581f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                                     (vm_region_info_t)&info, &info_count);
3582f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         if (kr)
3583f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            return;
3584f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         if (info.is_submap) {
3585f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            depth++;
3586f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            continue;
3587f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         }
3588f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         break;
3589f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
3590f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      iter = addr + size;
3591f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3592f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (addr > last  &&  record_gap) {
3593f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         (*record_gap)(last, addr - last);
3594f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
3595f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (record_mapping) {
3596f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         (*record_mapping)(addr, size, mach2vki(info.protection),
3597f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                           0, 0, info.offset, NULL);
3598f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
3599f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      last = addr + size;
3600f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
3601f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3602f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if ((Addr)-1 > last  &&  record_gap)
3603f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      (*record_gap)(last, (Addr)-1 - last);
3604f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
3605f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
36069edd09f2aa4555db69fde8c78dedc8f8fb30e46bsewardj// Urr.  So much for thread safety.
36079edd09f2aa4555db69fde8c78dedc8f8fb30e46bsewardjstatic Bool        css_overflowed;
36089edd09f2aa4555db69fde8c78dedc8f8fb30e46bsewardjstatic ChangedSeg* css_local;
36099edd09f2aa4555db69fde8c78dedc8f8fb30e46bsewardjstatic Int         css_size_local;
36109edd09f2aa4555db69fde8c78dedc8f8fb30e46bsewardjstatic Int         css_used_local;
3611f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3612e139a46c2961c48392005fb367ef6380ea57df4bsewardjstatic Addr Addr__max ( Addr a, Addr b ) { return a > b ? a : b; }
3613e139a46c2961c48392005fb367ef6380ea57df4bsewardjstatic Addr Addr__min ( Addr a, Addr b ) { return a < b ? a : b; }
3614e139a46c2961c48392005fb367ef6380ea57df4bsewardj
3615f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic void add_mapping_callback(Addr addr, SizeT len, UInt prot,
3616f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                                 ULong dev, ULong ino, Off64T offset,
3617dbb3584f591710a15a437918c0fc27e300993566florian                                 const HChar *filename)
3618f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
3619f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // derived from sync_check_mapping_callback()
3620f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3621e139a46c2961c48392005fb367ef6380ea57df4bsewardj   /* JRS 2012-Mar-07: this all seems very dubious to me.  It would be
3622e139a46c2961c48392005fb367ef6380ea57df4bsewardj      safer to see if we can find, in V's segment collection, one
3623e139a46c2961c48392005fb367ef6380ea57df4bsewardj      single segment that completely covers the range [addr, +len)
3624e139a46c2961c48392005fb367ef6380ea57df4bsewardj      (and possibly more), and that has the exact same other
3625e139a46c2961c48392005fb367ef6380ea57df4bsewardj      properties (prot, dev, ino, offset, etc) as the data presented
3626e139a46c2961c48392005fb367ef6380ea57df4bsewardj      here.  If found, we just skip.  Otherwise add the data presented
3627e139a46c2961c48392005fb367ef6380ea57df4bsewardj      here into css_local[]. */
3628e139a46c2961c48392005fb367ef6380ea57df4bsewardj
3629f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   Int iLo, iHi, i;
3630f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3631f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (len == 0) return;
3632f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3633f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* The kernel should not give us wraparounds. */
3634f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   aspacem_assert(addr <= addr + len - 1);
3635f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3636f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   iLo = find_nsegment_idx( addr );
3637f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   iHi = find_nsegment_idx( addr + len - 1 );
3638f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3639f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* NSegments iLo .. iHi inclusive should agree with the presented
3640f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      data. */
3641f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (i = iLo; i <= iHi; i++) {
3642f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3643f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      UInt seg_prot;
3644f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3645f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (nsegments[i].kind == SkAnonV  ||  nsegments[i].kind == SkFileV) {
3646f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         /* Ignore V regions */
3647f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         continue;
3648f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
3649f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      else if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn) {
3650e139a46c2961c48392005fb367ef6380ea57df4bsewardj         /* Add mapping for SkResvn regions */
3651f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         ChangedSeg* cs = &css_local[css_used_local];
3652fd1b461d19d0fd0484682a51138308413a3eab0cnjn         if (css_used_local < css_size_local) {
3653fd1b461d19d0fd0484682a51138308413a3eab0cnjn            cs->is_added = True;
3654fd1b461d19d0fd0484682a51138308413a3eab0cnjn            cs->start    = addr;
3655fd1b461d19d0fd0484682a51138308413a3eab0cnjn            cs->end      = addr + len - 1;
3656fd1b461d19d0fd0484682a51138308413a3eab0cnjn            cs->prot     = prot;
3657fd1b461d19d0fd0484682a51138308413a3eab0cnjn            cs->offset   = offset;
3658fd1b461d19d0fd0484682a51138308413a3eab0cnjn            css_used_local++;
3659fd1b461d19d0fd0484682a51138308413a3eab0cnjn         } else {
3660fd1b461d19d0fd0484682a51138308413a3eab0cnjn            css_overflowed = True;
3661fd1b461d19d0fd0484682a51138308413a3eab0cnjn         }
3662f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         return;
3663f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3664f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj      }
3665f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj      else if (nsegments[i].kind == SkAnonC ||
3666f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj               nsegments[i].kind == SkFileC ||
3667f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj               nsegments[i].kind == SkShmC)
3668f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      {
3669f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         /* Check permissions on client regions */
3670f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         // GrP fixme
3671f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         seg_prot = 0;
3672f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
3673f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
3674f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#        if defined(VGA_x86)
3675f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         // GrP fixme sloppyXcheck
3676f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         // darwin: kernel X ignored and spuriously changes? (vm_copy)
3677f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         seg_prot |= (prot & VKI_PROT_EXEC);
3678f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#        else
3679f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
3680f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#        endif
3681f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         if (seg_prot != prot) {
3682f76d27a697a7b0bf3b84490baf60623fc96a23afnjn             if (VG_(clo_trace_syscalls))
368308a631925b44574c66af84dc7ffd9f50976a5fdfsewardj                 VG_(debugLog)(0,"aspacem","region %p..%p permission "
368408a631925b44574c66af84dc7ffd9f50976a5fdfsewardj                                 "mismatch (kernel %x, V %x)\n",
3685f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                                 (void*)nsegments[i].start,
3686f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                                 (void*)(nsegments[i].end+1), prot, seg_prot);
3687f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj            /* Add mapping for regions with protection changes */
3688f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj            ChangedSeg* cs = &css_local[css_used_local];
3689f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj            if (css_used_local < css_size_local) {
3690f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj               cs->is_added = True;
3691f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj               cs->start    = addr;
3692f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj               cs->end      = addr + len - 1;
3693f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj               cs->prot     = prot;
3694f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj               cs->offset   = offset;
3695f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj               css_used_local++;
3696f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj            } else {
3697f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj               css_overflowed = True;
3698f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj            }
3699f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj	    return;
3700f1a9bd244c900db7478b68f6fc0ca7aebd4fead7sewardj
3701f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         }
3702f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3703f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      } else {
3704f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         aspacem_assert(0);
3705f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
3706f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
3707f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
3708f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3709f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic void remove_mapping_callback(Addr addr, SizeT len)
3710f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
3711f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // derived from sync_check_gap_callback()
3712f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3713f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   Int iLo, iHi, i;
3714f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3715f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (len == 0)
3716f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      return;
3717f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3718f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* The kernel should not give us wraparounds. */
3719f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   aspacem_assert(addr <= addr + len - 1);
3720f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3721f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   iLo = find_nsegment_idx( addr );
3722f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   iHi = find_nsegment_idx( addr + len - 1 );
3723f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3724f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* NSegments iLo .. iHi inclusive should agree with the presented data. */
3725f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (i = iLo; i <= iHi; i++) {
3726e139a46c2961c48392005fb367ef6380ea57df4bsewardj      if (nsegments[i].kind != SkFree && nsegments[i].kind != SkResvn) {
3727e139a46c2961c48392005fb367ef6380ea57df4bsewardj         /* V has a mapping, kernel doesn't.  Add to css_local[],
3728e139a46c2961c48392005fb367ef6380ea57df4bsewardj            directives to chop off the part of the V mapping that
3729e139a46c2961c48392005fb367ef6380ea57df4bsewardj            falls within the gap that the kernel tells us is
3730e139a46c2961c48392005fb367ef6380ea57df4bsewardj            present. */
3731f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         ChangedSeg* cs = &css_local[css_used_local];
3732fd1b461d19d0fd0484682a51138308413a3eab0cnjn         if (css_used_local < css_size_local) {
3733fd1b461d19d0fd0484682a51138308413a3eab0cnjn            cs->is_added = False;
3734e139a46c2961c48392005fb367ef6380ea57df4bsewardj            cs->start    = Addr__max(nsegments[i].start, addr);
3735e139a46c2961c48392005fb367ef6380ea57df4bsewardj            cs->end      = Addr__min(nsegments[i].end,   addr + len - 1);
3736e139a46c2961c48392005fb367ef6380ea57df4bsewardj            aspacem_assert(VG_IS_PAGE_ALIGNED(cs->start));
3737e139a46c2961c48392005fb367ef6380ea57df4bsewardj            aspacem_assert(VG_IS_PAGE_ALIGNED(cs->end+1));
3738e139a46c2961c48392005fb367ef6380ea57df4bsewardj            /* I don't think the following should fail.  But if it
3739e139a46c2961c48392005fb367ef6380ea57df4bsewardj               does, just omit the css_used_local++ in the cases where
3740e139a46c2961c48392005fb367ef6380ea57df4bsewardj               it doesn't hold. */
3741e139a46c2961c48392005fb367ef6380ea57df4bsewardj            aspacem_assert(cs->start < cs->end);
3742fd1b461d19d0fd0484682a51138308413a3eab0cnjn            cs->prot     = 0;
3743fd1b461d19d0fd0484682a51138308413a3eab0cnjn            cs->offset   = 0;
3744fd1b461d19d0fd0484682a51138308413a3eab0cnjn            css_used_local++;
3745fd1b461d19d0fd0484682a51138308413a3eab0cnjn         } else {
3746fd1b461d19d0fd0484682a51138308413a3eab0cnjn            css_overflowed = True;
3747fd1b461d19d0fd0484682a51138308413a3eab0cnjn         }
3748f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
3749f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
3750f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
3751f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3752f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3753fd1b461d19d0fd0484682a51138308413a3eab0cnjn// Returns False if 'css' wasn't big enough.
3754fd1b461d19d0fd0484682a51138308413a3eab0cnjnBool VG_(get_changed_segments)(
3755f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      const HChar* when, const HChar* where, /*OUT*/ChangedSeg* css,
3756f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      Int css_size, /*OUT*/Int* css_used)
3757f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
3758f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   static UInt stats_synccalls = 1;
3759f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   aspacem_assert(when && where);
3760f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3761f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (0)
3762f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      VG_(debugLog)(0,"aspacem",
3763f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         "[%u,%u] VG_(get_changed_segments)(%s, %s)\n",
3764f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         stats_synccalls++, stats_machcalls, when, where
3765f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      );
3766f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3767fd1b461d19d0fd0484682a51138308413a3eab0cnjn   css_overflowed = False;
3768f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   css_local = css;
3769f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   css_size_local = css_size;
3770f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   css_used_local = 0;
3771f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3772f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // Get the list of segs that need to be added/removed.
3773f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   parse_procselfmaps(&add_mapping_callback, &remove_mapping_callback);
3774f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
3775f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   *css_used = css_used_local;
3776fd1b461d19d0fd0484682a51138308413a3eab0cnjn
3777fd1b461d19d0fd0484682a51138308413a3eab0cnjn   if (css_overflowed) {
3778fd1b461d19d0fd0484682a51138308413a3eab0cnjn      aspacem_assert(css_used_local == css_size_local);
3779fd1b461d19d0fd0484682a51138308413a3eab0cnjn   }
3780fd1b461d19d0fd0484682a51138308413a3eab0cnjn
3781fd1b461d19d0fd0484682a51138308413a3eab0cnjn   return !css_overflowed;
3782f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
3783f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
378438a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj#endif // defined(VGO_darwin)
3785c401ae7ea8e709040d70a2ea6e2e44979aa90ac0bart
378638a21ac27cec0d1631ad91f8aa3eecd95fa5663bsewardj/*------END-procmaps-parser-for-Darwin---------------------------*/
37878b68b64759254d514d98328c496cbd88cde4c9a5njn
37888eb8bab992e3998c33770b0cdb16059a8b918a06sewardj/*------BEGIN-procmaps-parser-for-Solaris------------------------*/
37898eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
37908eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#if defined(VGO_solaris)
37918eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
37928eb8bab992e3998c33770b0cdb16059a8b918a06sewardj/* Note: /proc/self/xmap contains extended information about already
37938eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   materialized mappings whereas /proc/self/rmap contains information about
37948eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   all mappings including reserved but yet-to-materialize mappings (mmap'ed
37958eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   with MAP_NORESERVE flag, such as thread stacks). But /proc/self/rmap does
37968eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   not contain extended information found in /proc/self/xmap. Therefore
37978eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   information from both sources need to be combined.
37988eb8bab992e3998c33770b0cdb16059a8b918a06sewardj */
37998eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38008eb8bab992e3998c33770b0cdb16059a8b918a06sewardjtypedef struct
38018eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
38028eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Addr   addr;
38038eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   SizeT  size;
38048eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   UInt   prot;
38058eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   ULong  dev;
38068eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   ULong  ino;
38078eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Off64T foffset;
38088eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   HChar  filename[VKI_PATH_MAX];
38098eb8bab992e3998c33770b0cdb16059a8b918a06sewardj} Mapping;
38108eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38118eb8bab992e3998c33770b0cdb16059a8b918a06sewardjstatic SizeT read_proc_file(const HChar *filename, HChar *buf,
38128eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                            SizeT buf_size, const HChar *buf_size_name,
38138eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                            SizeT entry_size)
38148eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
38158eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   SysRes res = ML_(am_open)(filename, VKI_O_RDONLY, 0);
38168eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (sr_isError(res)) {
38178eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      HChar message[100];
38188eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      ML_(am_sprintf)(message, "Cannot open %s.", filename);
38198eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      ML_(am_barf)(message);
38208eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
38218eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Int fd = sr_Res(res);
38228eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38238eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Int r = ML_(am_read)(fd, buf, buf_size);
38248eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   ML_(am_close)(fd);
38258eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (r < 0) {
38268eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      HChar message[100];
38278eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      ML_(am_sprintf)(message, "I/O error on %s.", filename);
38288eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      ML_(am_barf)(message);
38298eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
38308eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38318eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (r >= buf_size)
38328eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      ML_(am_barf_toolow)(buf_size_name);
38338eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38348eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (r % entry_size != 0) {
38358eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      HChar message[100];
38368eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      ML_(am_sprintf)(message, "Bogus values read from %s.", filename);
38378eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      ML_(am_barf)(message);
38388eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
38398eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38408eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   return r / entry_size;
38418eb8bab992e3998c33770b0cdb16059a8b918a06sewardj}
38428eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38438eb8bab992e3998c33770b0cdb16059a8b918a06sewardjstatic Mapping *next_xmap(const HChar *buffer, SizeT entries, SizeT *idx,
38448eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                          Mapping *mapping)
38458eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
38468eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   aspacem_assert(idx);
38478eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   aspacem_assert(mapping);
38488eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38498eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (*idx >= entries)
38508eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      return NULL; /* No more entries */
38518eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38528eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   const vki_prxmap_t *map = (const vki_prxmap_t *)buffer + *idx;
38538eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38548eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   mapping->addr = map->pr_vaddr;
38558eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   mapping->size = map->pr_size;
38568eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38578eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   mapping->prot = 0;
38588eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (map->pr_mflags & VKI_MA_READ)
38598eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->prot |= VKI_PROT_READ;
38608eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (map->pr_mflags & VKI_MA_WRITE)
38618eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->prot |= VKI_PROT_WRITE;
38628eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (map->pr_mflags & VKI_MA_EXEC)
38638eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->prot |= VKI_PROT_EXEC;
38648eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38658eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (map->pr_dev != VKI_PRNODEV) {
38668eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->dev = map->pr_dev;
38678eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->ino = map->pr_ino;
38688eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->foffset = map->pr_offset;
38698eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
38708eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   else {
38718eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->dev = 0;
38728eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->ino = 0;
38738eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->foffset = 0;
38748eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
38758eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38768eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Try to get the filename. */
38778eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   mapping->filename[0] = '\0';
38788eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (map->pr_mapname[0] != '\0') {
38798eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      ML_(am_sprintf)(mapping->filename, "/proc/self/path/%s",
38808eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                      map->pr_mapname);
38818eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      Int r = ML_(am_readlink)(mapping->filename, mapping->filename,
38828eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                               sizeof(mapping->filename) - 1);
38838eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      if (r == -1) {
38848eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         /* If Valgrind is executed in a non-global zone and the link in
38858eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            /proc/self/path/ represents a file that is available through lofs
38868eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            from a global zone then the kernel may not be able to resolve the
38878eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            link.
38888eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38898eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            In such a case, return a corresponding /proc/self/object/ file to
38908eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            allow Valgrind to read the file if it is necessary.
38918eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38928eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            This can create some discrepancy for the sanity check. For
38938eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            instance, if a client program mmaps some file then the address
38948eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            space manager will have a correct zone-local name of that file,
38958eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            but the sanity check will receive a different file name from this
38968eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            code. This currently does not represent a problem because the
38978eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            sanity check ignores the file names (it uses device and inode
38988eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            numbers for the comparison).
38998eb8bab992e3998c33770b0cdb16059a8b918a06sewardj          */
39008eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         ML_(am_sprintf)(mapping->filename, "/proc/self/object/%s",
39018eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                         map->pr_mapname);
39028eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      }
39038eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      else {
39048eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         aspacem_assert(r >= 0);
39058eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         mapping->filename[r] = '\0';
39068eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      }
39078eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
39088eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39098eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   *idx += 1;
39108eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   return mapping;
39118eb8bab992e3998c33770b0cdb16059a8b918a06sewardj}
39128eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39138eb8bab992e3998c33770b0cdb16059a8b918a06sewardjstatic Mapping *next_rmap(const HChar *buffer, SizeT entries, SizeT *idx,
39148eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                          Mapping *mapping)
39158eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
39168eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   aspacem_assert(idx);
39178eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   aspacem_assert(mapping);
39188eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39198eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (*idx >= entries)
39208eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      return NULL; /* No more entries */
39218eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39228eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   const vki_prmap_t *map = (const vki_prmap_t *)buffer + *idx;
39238eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39248eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   mapping->addr = map->pr_vaddr;
39258eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   mapping->size = map->pr_size;
39268eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39278eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   mapping->prot = 0;
39288eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (map->pr_mflags & VKI_MA_READ)
39298eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->prot |= VKI_PROT_READ;
39308eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (map->pr_mflags & VKI_MA_WRITE)
39318eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->prot |= VKI_PROT_WRITE;
39328eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (map->pr_mflags & VKI_MA_EXEC)
39338eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      mapping->prot |= VKI_PROT_EXEC;
39348eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39358eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   mapping->dev = 0;
39368eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   mapping->ino = 0;
39378eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   mapping->foffset = 0;
39388eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   mapping->filename[0] = '\0';
39398eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39408eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   *idx += 1;
39418eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   return mapping;
39428eb8bab992e3998c33770b0cdb16059a8b918a06sewardj}
39438eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39448eb8bab992e3998c33770b0cdb16059a8b918a06sewardj/* Used for two purposes:
39458eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   1. Establish initial mappings upon the process startup
39468eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   2. Check mappings during aspacemgr sanity check
39478eb8bab992e3998c33770b0cdb16059a8b918a06sewardj */
39488eb8bab992e3998c33770b0cdb16059a8b918a06sewardjstatic void parse_procselfmaps (
39498eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      void (*record_mapping)( Addr addr, SizeT len, UInt prot,
39508eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                              ULong dev, ULong ino, Off64T offset,
39518eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                              const HChar *filename ),
39528eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      void (*record_gap)( Addr addr, SizeT len )
39538eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   )
39548eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
39558eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Addr start = Addr_MIN;
39568eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Addr gap_start = Addr_MIN;
39578eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39588eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#define M_XMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prxmap_t))
39598eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Static to keep it out of stack frame... */
39608eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   static HChar xmap_buf[M_XMAP_BUF];
39618eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   const Mapping *xmap = NULL;
39628eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   SizeT xmap_index = 0; /* Current entry */
39638eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   SizeT xmap_entries;
39648eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Mapping xmap_mapping;
39658eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Bool advance_xmap;
39668eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39678eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#define M_RMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prmap_t))
39688eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   static HChar rmap_buf[M_RMAP_BUF];
39698eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   const Mapping *rmap = NULL;
39708eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   SizeT rmap_index = 0; /* Current entry */
39718eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   SizeT rmap_entries;
39728eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Mapping rmap_mapping;
39738eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   Bool advance_rmap;
39748eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39758eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Read fully /proc/self/xmap and /proc/self/rmap. */
39768eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   xmap_entries = read_proc_file("/proc/self/xmap", xmap_buf, M_XMAP_BUF,
39778eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                                 "M_XMAP_BUF", sizeof(vki_prxmap_t));
39788eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39798eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   rmap_entries = read_proc_file("/proc/self/rmap", rmap_buf, M_RMAP_BUF,
39808eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                                 "M_RMAP_BUF", sizeof(vki_prmap_t));
39818eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39828eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Get the first xmap and rmap. */
39838eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   advance_xmap = True;
39848eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   advance_rmap = True;
39858eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39868eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   while (1) {
39878eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      /* Get next xmap or rmap if necessary. */
39888eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      if (advance_xmap) {
39898eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         xmap = next_xmap(xmap_buf, xmap_entries, &xmap_index, &xmap_mapping);
39908eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         advance_xmap = False;
39918eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      }
39928eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      if (advance_rmap) {
39938eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         rmap = next_rmap(rmap_buf, rmap_entries, &rmap_index, &rmap_mapping);
39948eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         advance_rmap = False;
39958eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      }
39968eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
39978eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      /* Check if the end has been reached. */
39988eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      if (rmap == NULL)
39998eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         break;
40008eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
40018eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      /* Invariants */
40028eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      if (xmap != NULL) {
40038eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         aspacem_assert(start <= xmap->addr);
40048eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         aspacem_assert(rmap->addr <= xmap->addr);
40058eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      }
40068eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
40078eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      if (xmap != NULL && start == xmap->addr) {
40088eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         /* xmap mapping reached. */
40098eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         aspacem_assert(xmap->addr >= rmap->addr &&
40108eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                        xmap->addr + xmap->size <= rmap->addr + rmap->size);
40118eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         aspacem_assert(xmap->prot == rmap->prot);
40128eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
40138eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         if (record_mapping != NULL)
40148eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            (*record_mapping)(xmap->addr, xmap->size, xmap->prot, xmap->dev,
40158eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                              xmap->ino, xmap->foffset,
40168eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                              (xmap->filename[0] != '\0') ?
40178eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                               xmap->filename : NULL);
40188eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
40198eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         start = xmap->addr + xmap->size;
40208eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         advance_xmap = True;
40218eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      }
40228eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      else if (start >= rmap->addr) {
40238eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         /* Reserved-only part. */
40248eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         /* First calculate size until the end of this reserved mapping... */
40258eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         SizeT size = rmap->addr + rmap->size - start;
40268eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         /* ... but shrink it if some xmap is in a way. */
40278eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         if (xmap != NULL && size > xmap->addr - start)
40288eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            size = xmap->addr - start;
40298eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
40308eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         if (record_mapping != NULL)
40318eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            (*record_mapping)(start, size, rmap->prot, 0, 0, 0, NULL);
40328eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         start += size;
40338eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      }
40348eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      else {
40358eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         /* Gap. */
40368eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         if (record_gap != NULL && gap_start < start)
40378eb8bab992e3998c33770b0cdb16059a8b918a06sewardj            (*record_gap)(gap_start, start - gap_start);
40388eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         start = rmap->addr;
40398eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      }
40408eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
40418eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      if (rmap->addr + rmap->size <= start)
40428eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         advance_rmap = True;
40438eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
40448eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      gap_start = start;
40458eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
40468eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
40478eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (record_gap != NULL && gap_start < Addr_MAX)
40488eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      (*record_gap)(gap_start, Addr_MAX - gap_start + 1);
40498eb8bab992e3998c33770b0cdb16059a8b918a06sewardj}
40508eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
40518eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#endif // defined(VGO_solaris)
40528eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
40538eb8bab992e3998c33770b0cdb16059a8b918a06sewardj/*------END-procmaps-parser-for-Solaris--------------------------*/
40548eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
40558eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
4056f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
405798abfc7bb7798c4ac4580f7e0bc7171de94a0255fitzhardinge/*--------------------------------------------------------------------*/
4058945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/*--- end                                                          ---*/
4059de4a1d01951937632098a6cda45859afa587a06fsewardj/*--------------------------------------------------------------------*/
4060