blob: 907ceb774c94cc94489a2c568e062e6941195ae2 [file] [log] [blame]
florian95af4ce2015-01-31 00:29:50 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
sewardjde4a1d02002-03-22 01:27:54 +00002
3/*--------------------------------------------------------------------*/
sewardj55f9d1a2005-04-25 11:11:44 +00004/*--- The address space manager: segment initialisation and ---*/
5/*--- tracking, stack operations ---*/
sewardj297f6b02006-10-14 22:25:30 +00006/*--- ---*/
florianda9420c2015-06-25 21:12:44 +00007/*--- Implementation for Linux (and Darwin!) aspacemgr-linux.c ---*/
sewardjde4a1d02002-03-22 01:27:54 +00008/*--------------------------------------------------------------------*/
9
10/*
njnb9c427c2004-12-01 14:14:42 +000011 This file is part of Valgrind, a dynamic binary instrumentation
12 framework.
sewardjde4a1d02002-03-22 01:27:54 +000013
sewardjb3a1e4b2015-08-21 11:32:26 +000014 Copyright (C) 2000-2015 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000015 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000016
17 This program is free software; you can redistribute it and/or
18 modify it under the terms of the GNU General Public License as
19 published by the Free Software Foundation; either version 2 of the
20 License, or (at your option) any later version.
21
22 This program is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
26
27 You should have received a copy of the GNU General Public License
28 along with this program; if not, write to the Free Software
29 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
30 02111-1307, USA.
31
njn25e49d8e72002-09-23 09:36:25 +000032 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000033*/
34
sewardj8eb8bab2015-07-21 14:44:28 +000035#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
njn8b68b642009-06-24 00:37:09 +000036
sewardj297f6b02006-10-14 22:25:30 +000037/* *************************************************************
38 DO NOT INCLUDE ANY OTHER FILES HERE.
39 ADD NEW INCLUDES ONLY TO priv_aspacemgr.h
40 AND THEN ONLY AFTER READING DIRE WARNINGS THERE TOO.
41 ************************************************************* */
sewardj45f4e7c2005-09-27 19:20:21 +000042
sewardj297f6b02006-10-14 22:25:30 +000043#include "priv_aspacemgr.h"
bart870f7452009-12-29 16:56:18 +000044#include "config.h"
sewardj55f9d1a2005-04-25 11:11:44 +000045
sewardjde4a1d02002-03-22 01:27:54 +000046
sewardjaa349292005-10-11 22:06:29 +000047/* Note: many of the exported functions implemented below are
48 described more fully in comments in pub_core_aspacemgr.h.
49*/
50
51
sewardj45f4e7c2005-09-27 19:20:21 +000052/*-----------------------------------------------------------------*/
53/*--- ---*/
sewardja07dce42005-10-14 19:05:45 +000054/*--- Overview. ---*/
55/*--- ---*/
56/*-----------------------------------------------------------------*/
57
58/* Purpose
59 ~~~~~~~
60 The purpose of the address space manager (aspacem) is:
61
62 (1) to record the disposition of all parts of the process' address
63 space at all times.
64
65 (2) to the extent that it can, influence layout in ways favourable
66 to our purposes.
67
68 It is important to appreciate that whilst it can and does attempt
69 to influence layout, and usually succeeds, it isn't possible to
70 impose absolute control: in the end, the kernel is the final
71 arbiter, and can always bounce our requests.
72
73 Strategy
74 ~~~~~~~~
75 The strategy is therefore as follows:
76
77 * Track ownership of mappings. Each one can belong either to
78 Valgrind or to the client.
79
80 * Try to place the client's fixed and hinted mappings at the
81 requested addresses. Fixed mappings are allowed anywhere except
82 in areas reserved by Valgrind; the client can trash its own
83 mappings if it wants. Hinted mappings are allowed providing they
84 fall entirely in free areas; if not, they will be placed by
85 aspacem in a free area.
86
87 * Anonymous mappings are allocated so as to keep Valgrind and
88 client areas widely separated when possible. If address space
89 runs low, then they may become intermingled: aspacem will attempt
90 to use all possible space. But under most circumstances lack of
91 address space is not a problem and so the areas will remain far
92 apart.
93
94 Searches for client space start at aspacem_cStart and will wrap
95 around the end of the available space if needed. Searches for
96 Valgrind space start at aspacem_vStart and will also wrap around.
97 Because aspacem_cStart is approximately at the start of the
98 available space and aspacem_vStart is approximately in the
99 middle, for the most part the client anonymous mappings will be
100 clustered towards the start of available space, and Valgrind ones
101 in the middle.
102
sewardj8eb8bab2015-07-21 14:44:28 +0000103 On Solaris, searches for client space start at (aspacem_vStart - 1)
104 and for Valgrind space start at (aspacem_maxAddr - 1) and go backwards.
105 This simulates what kernel does - brk limit grows from bottom and mmap'ed
106 objects from top. It is in contrary with Linux where data segment
107 and mmap'ed objects grow from bottom (leading to early data segment
108 exhaustion for tools which do not use m_replacemalloc). While Linux glibc
109 can cope with this problem by employing mmap, Solaris libc treats inability
110 to grow brk limit as a hard failure.
111
sewardja07dce42005-10-14 19:05:45 +0000112 The available space is delimited by aspacem_minAddr and
113 aspacem_maxAddr. aspacem is flexible and can operate with these
114 at any (sane) setting. For 32-bit Linux, aspacem_minAddr is set
115 to some low-ish value at startup (64M) and aspacem_maxAddr is
116 derived from the stack pointer at system startup. This seems a
117 reliable way to establish the initial boundaries.
philippee4d78122014-04-20 14:20:37 +0000118 A command line option allows to change the value of aspacem_minAddr,
119 so as to allow memory hungry applications to use the lowest
120 part of the memory.
sewardja07dce42005-10-14 19:05:45 +0000121
122 64-bit Linux is similar except for the important detail that the
sewardje06727f2013-09-19 09:27:05 +0000123 upper boundary is set to 64G. The reason is so that all
sewardja07dce42005-10-14 19:05:45 +0000124 anonymous mappings (basically all client data areas) are kept
sewardje06727f2013-09-19 09:27:05 +0000125 below 64G, since that is the maximum range that memcheck can
sewardja07dce42005-10-14 19:05:45 +0000126 track shadow memory using a fast 2-level sparse array. It can go
sewardje06727f2013-09-19 09:27:05 +0000127 beyond that but runs much more slowly. The 64G limit is
sewardja07dce42005-10-14 19:05:45 +0000128 arbitrary and is trivially changed. So, with the current
129 settings, programs on 64-bit Linux will appear to run out of
sewardje06727f2013-09-19 09:27:05 +0000130 address space and presumably fail at the 64G limit. Given the
131 considerable space overhead of Memcheck, that means you should be
132 able to memcheckify programs that use up to about 32G natively.
sewardja07dce42005-10-14 19:05:45 +0000133
134 Note that the aspacem_minAddr/aspacem_maxAddr limits apply only to
135 anonymous mappings. The client can still do fixed and hinted maps
136 at any addresses provided they do not overlap Valgrind's segments.
137 This makes Valgrind able to load prelinked .so's at their requested
138 addresses on 64-bit platforms, even if they are very high (eg,
139 112TB).
140
141 At startup, aspacem establishes the usable limits, and advises
142 m_main to place the client stack at the top of the range, which on
143 a 32-bit machine will be just below the real initial stack. One
144 effect of this is that self-hosting sort-of works, because an inner
145 valgrind will then place its client's stack just below its own
146 initial stack.
147
148 The segment array and segment kinds
149 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
150 The central data structure is the segment array (segments[0
151 .. nsegments_used-1]). This covers the entire address space in
152 order, giving account of every byte of it. Free spaces are
153 represented explicitly as this makes many operations simpler.
154 Mergeable adjacent segments are aggressively merged so as to create
155 a "normalised" representation (preen_nsegments).
156
157 There are 7 (mutually-exclusive) segment kinds, the meaning of
158 which is important:
159
160 SkFree: a free space, which may be allocated either to Valgrind (V)
161 or the client (C).
162
163 SkAnonC: an anonymous mapping belonging to C. For these, aspacem
164 tracks a boolean indicating whether or not is is part of the
165 client's heap area (can't remember why).
166
167 SkFileC: a file mapping belonging to C.
168
169 SkShmC: a shared memory segment belonging to C.
170
171 SkAnonV: an anonymous mapping belonging to V. These cover all V's
172 dynamic memory needs, including non-client malloc/free areas,
173 shadow memory, and the translation cache.
174
175 SkFileV: a file mapping belonging to V. As far as I know these are
176 only created transiently for the purposes of reading debug info.
177
178 SkResvn: a reservation segment.
179
180 These are mostly straightforward. Reservation segments have some
181 subtlety, however.
182
183 A reservation segment is unmapped from the kernel's point of view,
184 but is an area in which aspacem will not create anonymous maps
185 (either Vs or Cs). The idea is that we will try to keep it clear
186 when the choice to do so is ours. Reservation segments are
187 'invisible' from the client's point of view: it may choose to park
188 a fixed mapping in the middle of one, and that's just tough -- we
189 can't do anything about that. From the client's perspective
190 reservations are semantically equivalent to (although
191 distinguishable from, if it makes enquiries) free areas.
192
193 Reservations are a primitive mechanism provided for whatever
194 purposes the rest of the system wants. Currently they are used to
195 reserve the expansion space into which a growdown stack is
196 expanded, and into which the data segment is extended. Note,
197 though, those uses are entirely external to this module, which only
198 supplies the primitives.
199
200 Reservations may be shrunk in order that an adjoining anonymous
201 mapping may be extended. This makes dataseg/stack expansion work.
202 A reservation may not be shrunk below one page.
203
204 The advise/notify concept
205 ~~~~~~~~~~~~~~~~~~~~~~~~~
206 All mmap-related calls must be routed via aspacem. Calling
207 sys_mmap directly from the rest of the system is very dangerous
208 because aspacem's data structures will become out of date.
209
210 The fundamental mode of operation of aspacem is to support client
211 mmaps. Here's what happens (in ML_(generic_PRE_sys_mmap)):
212
213 * m_syswrap intercepts the mmap call. It examines the parameters
214 and identifies the requested placement constraints. There are
215 three possibilities: no constraint (MAny), hinted (MHint, "I
216 prefer X but will accept anything"), and fixed (MFixed, "X or
217 nothing").
218
219 * This request is passed to VG_(am_get_advisory). This decides on
220 a placement as described in detail in Strategy above. It may
221 also indicate that the map should fail, because it would trash
222 one of Valgrind's areas, which would probably kill the system.
223
224 * Control returns to the wrapper. If VG_(am_get_advisory) has
225 declared that the map should fail, then it must be made to do so.
226 Usually, though, the request is considered acceptable, in which
227 case an "advised" address is supplied. The advised address
228 replaces the original address supplied by the client, and
229 MAP_FIXED is set.
230
231 Note at this point that although aspacem has been asked for
232 advice on where to place the mapping, no commitment has yet been
233 made by either it or the kernel.
234
235 * The adjusted request is handed off to the kernel.
236
237 * The kernel's result is examined. If the map succeeded, aspacem
238 is told of the outcome (VG_(am_notify_client_mmap)), so it can
239 update its records accordingly.
240
241 This then is the central advise-notify idiom for handling client
242 mmap/munmap/mprotect/shmat:
243
244 * ask aspacem for an advised placement (or a veto)
245
246 * if not vetoed, hand request to kernel, using the advised placement
247
248 * examine result, and if successful, notify aspacem of the result.
249
250 There are also many convenience functions, eg
251 VG_(am_mmap_anon_fixed_client), which do both phases entirely within
252 aspacem.
253
254 To debug all this, a sync-checker is provided. It reads
255 /proc/self/maps, compares what it sees with aspacem's records, and
256 complains if there is a difference. --sanity-level=3 runs it before
257 and after each syscall, which is a powerful, if slow way of finding
258 buggy syscall wrappers.
sewardj4f3ef1f2005-10-15 00:41:50 +0000259
260 Loss of pointercheck
261 ~~~~~~~~~~~~~~~~~~~~
262 Up to and including Valgrind 2.4.1, x86 segmentation was used to
263 enforce seperation of V and C, so that wild writes by C could not
264 trash V. This got called "pointercheck". Unfortunately, the new
265 more flexible memory layout, plus the need to be portable across
266 different architectures, means doing this in hardware is no longer
267 viable, and doing it in software is expensive. So at the moment we
268 don't do it at all.
sewardja07dce42005-10-14 19:05:45 +0000269*/
270
271
272/*-----------------------------------------------------------------*/
273/*--- ---*/
sewardj45f4e7c2005-09-27 19:20:21 +0000274/*--- The Address Space Manager's state. ---*/
275/*--- ---*/
276/*-----------------------------------------------------------------*/
sewardja4495682002-10-21 07:29:59 +0000277
sewardj45f4e7c2005-09-27 19:20:21 +0000278/* ------ start of STATE for the address-space manager ------ */
sewardj548be6d2005-02-16 01:31:37 +0000279
sewardjf049d1d2013-09-19 10:04:59 +0000280/* Max number of segments we can track. On Android, virtual address
281 space is limited, so keep a low limit -- 5000 x sizef(NSegment) is
282 360KB. */
sewardj26ed4192014-11-04 17:44:21 +0000283#if defined(VGPV_arm_linux_android) \
284 || defined(VGPV_x86_linux_android) \
285 || defined(VGPV_mips32_linux_android) \
286 || defined(VGPV_arm64_linux_android)
sewardjf049d1d2013-09-19 10:04:59 +0000287# define VG_N_SEGMENTS 5000
288#else
289# define VG_N_SEGMENTS 30000
290#endif
sewardj79048ce2005-02-18 08:28:32 +0000291
sewardj45f4e7c2005-09-27 19:20:21 +0000292/* Array [0 .. nsegments_used-1] of all mappings. */
293/* Sorted by .addr field. */
294/* I: len may not be zero. */
295/* I: overlapping segments are not allowed. */
296/* I: the segments cover the entire address space precisely. */
297/* Each segment can optionally hold an index into the filename table. */
298
299static NSegment nsegments[VG_N_SEGMENTS];
300static Int nsegments_used = 0;
301
302#define Addr_MIN ((Addr)0)
303#define Addr_MAX ((Addr)(-1ULL))
304
305/* Limits etc */
306
philippee4d78122014-04-20 14:20:37 +0000307
308Addr VG_(clo_aspacem_minAddr)
sewardj8eb8bab2015-07-21 14:44:28 +0000309#if defined(VGO_linux)
310 = (Addr) 0x04000000; // 64M
311#elif defined(VGO_darwin)
philippee4d78122014-04-20 14:20:37 +0000312# if VG_WORDSIZE == 4
313 = (Addr) 0x00001000;
314# else
315 = (Addr) 0x100000000; // 4GB page zero
316# endif
sewardj8eb8bab2015-07-21 14:44:28 +0000317#elif defined(VGO_solaris)
318 = (Addr) 0x00100000; // 1MB
philippee4d78122014-04-20 14:20:37 +0000319#else
philippee4d78122014-04-20 14:20:37 +0000320#endif
321
322
sewardj45f4e7c2005-09-27 19:20:21 +0000323// The smallest address that aspacem will try to allocate
324static Addr aspacem_minAddr = 0;
325
326// The largest address that aspacem will try to allocate
327static Addr aspacem_maxAddr = 0;
328
329// Where aspacem will start looking for client space
330static Addr aspacem_cStart = 0;
331
332// Where aspacem will start looking for Valgrind space
333static Addr aspacem_vStart = 0;
334
335
336#define AM_SANITY_CHECK \
337 do { \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700338 if (VG_(clo_sanity_level) >= 3) \
sewardj45f4e7c2005-09-27 19:20:21 +0000339 aspacem_assert(VG_(am_do_sync_check) \
340 (__PRETTY_FUNCTION__,__FILE__,__LINE__)); \
341 } while (0)
342
sewardj79048ce2005-02-18 08:28:32 +0000343/* ------ end of STATE for the address-space manager ------ */
344
sewardjcb249ab2005-09-28 09:37:16 +0000345/* ------ Forwards decls ------ */
sewardja364d112008-10-27 01:25:14 +0000346inline
sewardj45f4e7c2005-09-27 19:20:21 +0000347static Int find_nsegment_idx ( Addr a );
348
sewardjcb249ab2005-09-28 09:37:16 +0000349static void parse_procselfmaps (
350 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
njnc4431bf2009-01-15 21:29:24 +0000351 ULong dev, ULong ino, Off64T offset,
floriandbb35842012-10-27 18:39:11 +0000352 const HChar* filename ),
sewardjcb249ab2005-09-28 09:37:16 +0000353 void (*record_gap)( Addr addr, SizeT len )
354 );
355
sewardj38a21ac2010-01-03 10:14:03 +0000356/* ----- Hacks to do with the "commpage" on arm-linux ----- */
357/* Not that I have anything against the commpage per se. It's just
358 that it's not listed in /proc/self/maps, which is a royal PITA --
sewardjf90dcbc2010-10-20 15:43:09 +0000359 we have to fake it up, in parse_procselfmaps.
360
361 But note also bug 254556 comment #2: this is now fixed in newer
362 kernels -- it is listed as a "[vectors]" entry. Presumably the
363 fake entry made here duplicates the [vectors] entry, and so, if at
364 some point in the future, we can stop supporting buggy kernels,
365 then this kludge can be removed entirely, since the procmap parser
366 below will read that entry in the normal way. */
sewardj38a21ac2010-01-03 10:14:03 +0000367#if defined(VGP_arm_linux)
368# define ARM_LINUX_FAKE_COMMPAGE_START 0xFFFF0000
sewardjf90dcbc2010-10-20 15:43:09 +0000369# define ARM_LINUX_FAKE_COMMPAGE_END1 0xFFFF1000
sewardj38a21ac2010-01-03 10:14:03 +0000370#endif
371
sewardj45f4e7c2005-09-27 19:20:21 +0000372
sewardj548be6d2005-02-16 01:31:37 +0000373
sewardj45f4e7c2005-09-27 19:20:21 +0000374/*-----------------------------------------------------------------*/
375/*--- ---*/
376/*--- Displaying the segment array. ---*/
377/*--- ---*/
378/*-----------------------------------------------------------------*/
379
floriandbb35842012-10-27 18:39:11 +0000380static const HChar* show_SegKind ( SegKind sk )
sewardj548be6d2005-02-16 01:31:37 +0000381{
sewardj45f4e7c2005-09-27 19:20:21 +0000382 switch (sk) {
383 case SkFree: return " ";
384 case SkAnonC: return "anon";
385 case SkAnonV: return "ANON";
386 case SkFileC: return "file";
387 case SkFileV: return "FILE";
tom1340c352005-10-04 15:59:54 +0000388 case SkShmC: return "shm ";
sewardj45f4e7c2005-09-27 19:20:21 +0000389 case SkResvn: return "RSVN";
390 default: return "????";
391 }
392}
393
floriandbb35842012-10-27 18:39:11 +0000394static const HChar* show_ShrinkMode ( ShrinkMode sm )
sewardj45f4e7c2005-09-27 19:20:21 +0000395{
396 switch (sm) {
397 case SmLower: return "SmLower";
398 case SmUpper: return "SmUpper";
399 case SmFixed: return "SmFixed";
400 default: return "Sm?????";
401 }
402}
403
njnddaef352009-07-31 05:06:29 +0000404static void show_len_concisely ( /*OUT*/HChar* buf, Addr start, Addr end )
sewardj45f4e7c2005-09-27 19:20:21 +0000405{
floriandbb35842012-10-27 18:39:11 +0000406 const HChar* fmt;
njnddaef352009-07-31 05:06:29 +0000407 ULong len = ((ULong)end) - ((ULong)start) + 1;
sewardj45f4e7c2005-09-27 19:20:21 +0000408
njnddaef352009-07-31 05:06:29 +0000409 if (len < 10*1000*1000ULL) {
sewardj45f4e7c2005-09-27 19:20:21 +0000410 fmt = "%7llu";
411 }
njnddaef352009-07-31 05:06:29 +0000412 else if (len < 999999ULL * (1ULL<<20)) {
sewardj45f4e7c2005-09-27 19:20:21 +0000413 fmt = "%6llum";
njnddaef352009-07-31 05:06:29 +0000414 len >>= 20;
sewardj45f4e7c2005-09-27 19:20:21 +0000415 }
njnddaef352009-07-31 05:06:29 +0000416 else if (len < 999999ULL * (1ULL<<30)) {
sewardj45f4e7c2005-09-27 19:20:21 +0000417 fmt = "%6llug";
njnddaef352009-07-31 05:06:29 +0000418 len >>= 30;
sewardj45f4e7c2005-09-27 19:20:21 +0000419 }
njnddaef352009-07-31 05:06:29 +0000420 else if (len < 999999ULL * (1ULL<<40)) {
sewardj45f4e7c2005-09-27 19:20:21 +0000421 fmt = "%6llut";
njnddaef352009-07-31 05:06:29 +0000422 len >>= 40;
sewardj45f4e7c2005-09-27 19:20:21 +0000423 }
424 else {
425 fmt = "%6llue";
njnddaef352009-07-31 05:06:29 +0000426 len >>= 50;
sewardj45f4e7c2005-09-27 19:20:21 +0000427 }
njnddaef352009-07-31 05:06:29 +0000428 ML_(am_sprintf)(buf, fmt, len);
sewardj548be6d2005-02-16 01:31:37 +0000429}
430
sewardj45f4e7c2005-09-27 19:20:21 +0000431/* Show full details of an NSegment */
432
floriana0d557c2015-01-30 22:21:16 +0000433static void show_nsegment_full ( Int logLevel, Int segNo, const NSegment* seg )
sewardj45f4e7c2005-09-27 19:20:21 +0000434{
njnddaef352009-07-31 05:06:29 +0000435 HChar len_buf[20];
florian4ecd4832015-04-30 17:34:04 +0000436 const HChar* name = ML_(am_get_segname)( seg->fnIdx );
njnddaef352009-07-31 05:06:29 +0000437
florian346ee2f2015-04-06 21:34:30 +0000438 if (name == NULL)
439 name = "(none)";
sewardj616cf592005-10-06 03:04:22 +0000440
njnddaef352009-07-31 05:06:29 +0000441 show_len_concisely(len_buf, seg->start, seg->end);
442
443 VG_(debugLog)(
444 logLevel, "aspacem",
floriana5e06c32015-08-05 21:16:09 +0000445 "%3d: %s %010lx-%010lx %s %c%c%c%c%c %s "
446 "d=0x%03llx i=%-7llu o=%-7lld (%d,%d) %s\n",
njnddaef352009-07-31 05:06:29 +0000447 segNo, show_SegKind(seg->kind),
floriana5e06c32015-08-05 21:16:09 +0000448 seg->start, seg->end, len_buf,
njnddaef352009-07-31 05:06:29 +0000449 seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
450 seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
451 seg->isCH ? 'H' : '-',
sewardj45f4e7c2005-09-27 19:20:21 +0000452 show_ShrinkMode(seg->smode),
philippee6c3b432015-02-05 22:30:57 +0000453 seg->dev, seg->ino, seg->offset,
florian4ecd4832015-04-30 17:34:04 +0000454 ML_(am_segname_get_seqnr)(seg->fnIdx), seg->fnIdx,
florianbcf1d7f2015-01-27 20:46:19 +0000455 name
sewardj45f4e7c2005-09-27 19:20:21 +0000456 );
457}
458
459
460/* Show an NSegment in a user-friendly-ish way. */
461
florian32971242014-10-23 17:47:15 +0000462static void show_nsegment ( Int logLevel, Int segNo, const NSegment* seg )
sewardj45f4e7c2005-09-27 19:20:21 +0000463{
464 HChar len_buf[20];
njnddaef352009-07-31 05:06:29 +0000465 show_len_concisely(len_buf, seg->start, seg->end);
sewardj45f4e7c2005-09-27 19:20:21 +0000466
467 switch (seg->kind) {
468
469 case SkFree:
470 VG_(debugLog)(
471 logLevel, "aspacem",
floriana5e06c32015-08-05 21:16:09 +0000472 "%3d: %s %010lx-%010lx %s\n",
sewardj45f4e7c2005-09-27 19:20:21 +0000473 segNo, show_SegKind(seg->kind),
floriana5e06c32015-08-05 21:16:09 +0000474 seg->start, seg->end, len_buf
sewardj45f4e7c2005-09-27 19:20:21 +0000475 );
476 break;
477
tom1340c352005-10-04 15:59:54 +0000478 case SkAnonC: case SkAnonV: case SkShmC:
sewardj45f4e7c2005-09-27 19:20:21 +0000479 VG_(debugLog)(
480 logLevel, "aspacem",
floriana5e06c32015-08-05 21:16:09 +0000481 "%3d: %s %010lx-%010lx %s %c%c%c%c%c\n",
sewardj45f4e7c2005-09-27 19:20:21 +0000482 segNo, show_SegKind(seg->kind),
floriana5e06c32015-08-05 21:16:09 +0000483 seg->start, seg->end, len_buf,
sewardj45f4e7c2005-09-27 19:20:21 +0000484 seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
485 seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
486 seg->isCH ? 'H' : '-'
487 );
488 break;
489
490 case SkFileC: case SkFileV:
491 VG_(debugLog)(
492 logLevel, "aspacem",
floriana5e06c32015-08-05 21:16:09 +0000493 "%3d: %s %010lx-%010lx %s %c%c%c%c%c d=0x%03llx "
494 "i=%-7llu o=%-7lld (%d,%d)\n",
sewardj45f4e7c2005-09-27 19:20:21 +0000495 segNo, show_SegKind(seg->kind),
floriana5e06c32015-08-05 21:16:09 +0000496 seg->start, seg->end, len_buf,
sewardj45f4e7c2005-09-27 19:20:21 +0000497 seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
498 seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
499 seg->isCH ? 'H' : '-',
philippee6c3b432015-02-05 22:30:57 +0000500 seg->dev, seg->ino, seg->offset,
florian4ecd4832015-04-30 17:34:04 +0000501 ML_(am_segname_get_seqnr)(seg->fnIdx), seg->fnIdx
sewardj45f4e7c2005-09-27 19:20:21 +0000502 );
503 break;
504
505 case SkResvn:
506 VG_(debugLog)(
507 logLevel, "aspacem",
floriana5e06c32015-08-05 21:16:09 +0000508 "%3d: %s %010lx-%010lx %s %c%c%c%c%c %s\n",
sewardj45f4e7c2005-09-27 19:20:21 +0000509 segNo, show_SegKind(seg->kind),
floriana5e06c32015-08-05 21:16:09 +0000510 seg->start, seg->end, len_buf,
sewardj45f4e7c2005-09-27 19:20:21 +0000511 seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-',
512 seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
513 seg->isCH ? 'H' : '-',
514 show_ShrinkMode(seg->smode)
515 );
516 break;
517
518 default:
519 VG_(debugLog)(
520 logLevel, "aspacem",
521 "%3d: ???? UNKNOWN SEGMENT KIND\n",
522 segNo
523 );
524 break;
525 }
526}
527
528/* Print out the segment array (debugging only!). */
floriandbb35842012-10-27 18:39:11 +0000529void VG_(am_show_nsegments) ( Int logLevel, const HChar* who )
sewardj548be6d2005-02-16 01:31:37 +0000530{
531 Int i;
sewardj45f4e7c2005-09-27 19:20:21 +0000532 VG_(debugLog)(logLevel, "aspacem",
florian346ee2f2015-04-06 21:34:30 +0000533 "<<< SHOW_SEGMENTS: %s (%d segments)\n",
534 who, nsegments_used);
florian4ecd4832015-04-30 17:34:04 +0000535 ML_(am_show_segnames)( logLevel, who);
sewardj45f4e7c2005-09-27 19:20:21 +0000536 for (i = 0; i < nsegments_used; i++)
537 show_nsegment( logLevel, i, &nsegments[i] );
538 VG_(debugLog)(logLevel, "aspacem",
539 ">>>\n");
sewardj548be6d2005-02-16 01:31:37 +0000540}
sewardj79048ce2005-02-18 08:28:32 +0000541
sewardj548be6d2005-02-16 01:31:37 +0000542
sewardj45f4e7c2005-09-27 19:20:21 +0000543/* Get the filename corresponding to this segment, if known and if it
florian95af4ce2015-01-31 00:29:50 +0000544 has one. */
floriand3166c42015-01-24 00:02:19 +0000545const HChar* VG_(am_get_filename)( NSegment const * seg )
sewardj548be6d2005-02-16 01:31:37 +0000546{
sewardj45f4e7c2005-09-27 19:20:21 +0000547 aspacem_assert(seg);
florian4ecd4832015-04-30 17:34:04 +0000548 return ML_(am_get_segname)( seg->fnIdx );
sewardj45f4e7c2005-09-27 19:20:21 +0000549}
sewardj548be6d2005-02-16 01:31:37 +0000550
florianea8a88c2015-02-20 14:00:23 +0000551/* Collect up the start addresses of segments whose kind matches one of
552 the kinds specified in kind_mask.
sewardj45f4e7c2005-09-27 19:20:21 +0000553 The interface is a bit strange in order to avoid potential
554 segment-creation races caused by dynamic allocation of the result
555 buffer *starts.
556
557 The function first computes how many entries in the result
558 buffer *starts will be needed. If this number <= nStarts,
559 they are placed in starts[0..], and the number is returned.
560 If nStarts is not large enough, nothing is written to
561 starts[0..], and the negation of the size is returned.
562
563 Correct use of this function may mean calling it multiple times in
564 order to establish a suitably-sized buffer. */
565
florianea8a88c2015-02-20 14:00:23 +0000566Int VG_(am_get_segment_starts)( UInt kind_mask, Addr* starts, Int nStarts )
sewardj45f4e7c2005-09-27 19:20:21 +0000567{
568 Int i, j, nSegs;
569
570 /* don't pass dumbass arguments */
florian7af930d2015-01-20 19:02:05 +0000571 aspacem_assert(nStarts > 0);
sewardj45f4e7c2005-09-27 19:20:21 +0000572
573 nSegs = 0;
574 for (i = 0; i < nsegments_used; i++) {
florianea8a88c2015-02-20 14:00:23 +0000575 if ((nsegments[i].kind & kind_mask) != 0)
576 nSegs++;
sewardj45f4e7c2005-09-27 19:20:21 +0000577 }
578
579 if (nSegs > nStarts) {
580 /* The buffer isn't big enough. Tell the caller how big it needs
581 to be. */
582 return -nSegs;
583 }
584
585 /* There's enough space. So write into the result buffer. */
586 aspacem_assert(nSegs <= nStarts);
587
588 j = 0;
589 for (i = 0; i < nsegments_used; i++) {
florianea8a88c2015-02-20 14:00:23 +0000590 if ((nsegments[i].kind & kind_mask) != 0)
591 starts[j++] = nsegments[i].start;
sewardj45f4e7c2005-09-27 19:20:21 +0000592 }
593
594 aspacem_assert(j == nSegs); /* this should not fail */
595 return nSegs;
sewardj548be6d2005-02-16 01:31:37 +0000596}
597
sewardj79048ce2005-02-18 08:28:32 +0000598
sewardj45f4e7c2005-09-27 19:20:21 +0000599/*-----------------------------------------------------------------*/
600/*--- ---*/
601/*--- Sanity checking and preening of the segment array. ---*/
602/*--- ---*/
603/*-----------------------------------------------------------------*/
604
605/* Check representational invariants for NSegments. */
606
florian32971242014-10-23 17:47:15 +0000607static Bool sane_NSegment ( const NSegment* s )
sewardj79048ce2005-02-18 08:28:32 +0000608{
sewardj45f4e7c2005-09-27 19:20:21 +0000609 if (s == NULL) return False;
sewardj79048ce2005-02-18 08:28:32 +0000610
sewardj45f4e7c2005-09-27 19:20:21 +0000611 /* No zero sized segments and no wraparounds. */
florianfb823ae2015-02-24 11:23:51 +0000612 if (s->start > s->end) return False;
sewardj79048ce2005-02-18 08:28:32 +0000613
sewardj45f4e7c2005-09-27 19:20:21 +0000614 /* require page alignment */
615 if (!VG_IS_PAGE_ALIGNED(s->start)) return False;
616 if (!VG_IS_PAGE_ALIGNED(s->end+1)) return False;
sewardj79048ce2005-02-18 08:28:32 +0000617
sewardj45f4e7c2005-09-27 19:20:21 +0000618 switch (s->kind) {
619
620 case SkFree:
621 return
622 s->smode == SmFixed
623 && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
624 && !s->hasR && !s->hasW && !s->hasX && !s->hasT
625 && !s->isCH;
626
tom1340c352005-10-04 15:59:54 +0000627 case SkAnonC: case SkAnonV: case SkShmC:
sewardj45f4e7c2005-09-27 19:20:21 +0000628 return
629 s->smode == SmFixed
630 && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
631 && (s->kind==SkAnonC ? True : !s->isCH);
632
633 case SkFileC: case SkFileV:
634 return
635 s->smode == SmFixed
florian4ecd4832015-04-30 17:34:04 +0000636 && ML_(am_sane_segname)(s->fnIdx)
sewardj45f4e7c2005-09-27 19:20:21 +0000637 && !s->isCH;
638
639 case SkResvn:
640 return
641 s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
642 && !s->hasR && !s->hasW && !s->hasX && !s->hasT
643 && !s->isCH;
644
645 default:
sewardj79048ce2005-02-18 08:28:32 +0000646 return False;
647 }
sewardj79048ce2005-02-18 08:28:32 +0000648}
649
650
sewardj45f4e7c2005-09-27 19:20:21 +0000651/* Try merging s2 into s1, if possible. If successful, s1 is
652 modified, and True is returned. Otherwise s1 is unchanged and
653 False is returned. */
654
florian32971242014-10-23 17:47:15 +0000655static Bool maybe_merge_nsegments ( NSegment* s1, const NSegment* s2 )
sewardj79048ce2005-02-18 08:28:32 +0000656{
sewardj45f4e7c2005-09-27 19:20:21 +0000657 if (s1->kind != s2->kind)
658 return False;
sewardj79048ce2005-02-18 08:28:32 +0000659
sewardj45f4e7c2005-09-27 19:20:21 +0000660 if (s1->end+1 != s2->start)
661 return False;
sewardj79048ce2005-02-18 08:28:32 +0000662
sewardj45f4e7c2005-09-27 19:20:21 +0000663 /* reject cases which would cause wraparound */
664 if (s1->start > s2->end)
665 return False;
666
667 switch (s1->kind) {
668
669 case SkFree:
670 s1->end = s2->end;
671 return True;
672
673 case SkAnonC: case SkAnonV:
674 if (s1->hasR == s2->hasR && s1->hasW == s2->hasW
675 && s1->hasX == s2->hasX && s1->isCH == s2->isCH) {
676 s1->end = s2->end;
677 s1->hasT |= s2->hasT;
678 return True;
679 }
680 break;
681
682 case SkFileC: case SkFileV:
683 if (s1->hasR == s2->hasR
684 && s1->hasW == s2->hasW && s1->hasX == s2->hasX
685 && s1->dev == s2->dev && s1->ino == s2->ino
686 && s2->offset == s1->offset
687 + ((ULong)s2->start) - ((ULong)s1->start) ) {
688 s1->end = s2->end;
689 s1->hasT |= s2->hasT;
florian4ecd4832015-04-30 17:34:04 +0000690 ML_(am_dec_refcount)(s1->fnIdx);
sewardj45f4e7c2005-09-27 19:20:21 +0000691 return True;
692 }
693 break;
694
tom1340c352005-10-04 15:59:54 +0000695 case SkShmC:
696 return False;
697
sewardj613a9f22006-08-16 01:48:19 +0000698 case SkResvn:
699 if (s1->smode == SmFixed && s2->smode == SmFixed) {
700 s1->end = s2->end;
701 return True;
702 }
703
sewardj45f4e7c2005-09-27 19:20:21 +0000704 default:
705 break;
706
707 }
708
709 return False;
710}
711
712
713/* Sanity-check and canonicalise the segment array (merge mergable
714 segments). Returns True if any segments were merged. */
715
716static Bool preen_nsegments ( void )
717{
florian95af4ce2015-01-31 00:29:50 +0000718 Int i, r, w, nsegments_used_old = nsegments_used;
sewardj45f4e7c2005-09-27 19:20:21 +0000719
720 /* Pass 1: check the segment array covers the entire address space
721 exactly once, and also that each segment is sane. */
722 aspacem_assert(nsegments_used > 0);
723 aspacem_assert(nsegments[0].start == Addr_MIN);
724 aspacem_assert(nsegments[nsegments_used-1].end == Addr_MAX);
725
726 aspacem_assert(sane_NSegment(&nsegments[0]));
727 for (i = 1; i < nsegments_used; i++) {
728 aspacem_assert(sane_NSegment(&nsegments[i]));
729 aspacem_assert(nsegments[i-1].end+1 == nsegments[i].start);
730 }
731
732 /* Pass 2: merge as much as possible, using
733 maybe_merge_segments. */
734 w = 0;
735 for (r = 1; r < nsegments_used; r++) {
736 if (maybe_merge_nsegments(&nsegments[w], &nsegments[r])) {
737 /* nothing */
738 } else {
739 w++;
740 if (w != r)
741 nsegments[w] = nsegments[r];
742 }
743 }
744 w++;
745 aspacem_assert(w > 0 && w <= nsegments_used);
746 nsegments_used = w;
747
sewardj45f4e7c2005-09-27 19:20:21 +0000748 return nsegments_used != nsegments_used_old;
sewardj79048ce2005-02-18 08:28:32 +0000749}
750
751
sewardj45f4e7c2005-09-27 19:20:21 +0000752/* Check the segment array corresponds with the kernel's view of
753 memory layout. sync_check_ok returns True if no anomalies were
754 found, else False. In the latter case the mismatching segments are
755 displayed.
fitzhardinge98abfc72003-12-16 02:05:15 +0000756
sewardj45f4e7c2005-09-27 19:20:21 +0000757 The general idea is: we get the kernel to show us all its segments
758 and also the gaps in between. For each such interval, try and find
759 a sequence of appropriate intervals in our segment array which
760 cover or more than cover the kernel's interval, and which all have
761 suitable kinds/permissions etc.
762
763 Although any specific kernel interval is not matched exactly to a
764 valgrind interval or sequence thereof, eventually any disagreement
765 on mapping boundaries will be detected. This is because, if for
766 example valgrind's intervals cover a greater range than the current
767 kernel interval, it must be the case that a neighbouring free-space
768 interval belonging to valgrind cannot cover the neighbouring
769 free-space interval belonging to the kernel. So the disagreement
770 is detected.
771
772 In other words, we examine each kernel interval in turn, and check
773 we do not disagree over the range of that interval. Because all of
774 the address space is examined, any disagreements must eventually be
775 detected.
776*/
777
778static Bool sync_check_ok = False;
779
780static void sync_check_mapping_callback ( Addr addr, SizeT len, UInt prot,
njnc4431bf2009-01-15 21:29:24 +0000781 ULong dev, ULong ino, Off64T offset,
floriandbb35842012-10-27 18:39:11 +0000782 const HChar* filename )
fitzhardinge98abfc72003-12-16 02:05:15 +0000783{
sewardjaa349292005-10-11 22:06:29 +0000784 Int iLo, iHi, i;
florian954d6bb2015-04-07 20:43:55 +0000785 Bool sloppyXcheck, sloppyRcheck;
fitzhardinge98abfc72003-12-16 02:05:15 +0000786
sewardj45f4e7c2005-09-27 19:20:21 +0000787 /* If a problem has already been detected, don't continue comparing
788 segments, so as to avoid flooding the output with error
789 messages. */
njnf76d27a2009-05-28 01:53:07 +0000790#if !defined(VGO_darwin)
791 /* GrP fixme not */
sewardj45f4e7c2005-09-27 19:20:21 +0000792 if (!sync_check_ok)
793 return;
njnf76d27a2009-05-28 01:53:07 +0000794#endif
fitzhardinge98abfc72003-12-16 02:05:15 +0000795 if (len == 0)
796 return;
797
sewardj45f4e7c2005-09-27 19:20:21 +0000798 /* The kernel should not give us wraparounds. */
799 aspacem_assert(addr <= addr + len - 1);
fitzhardinge1a4adf02003-12-22 10:42:59 +0000800
sewardj45f4e7c2005-09-27 19:20:21 +0000801 iLo = find_nsegment_idx( addr );
802 iHi = find_nsegment_idx( addr + len - 1 );
fitzhardinge98abfc72003-12-16 02:05:15 +0000803
sewardj45f4e7c2005-09-27 19:20:21 +0000804 /* These 5 should be guaranteed by find_nsegment_idx. */
805 aspacem_assert(0 <= iLo && iLo < nsegments_used);
806 aspacem_assert(0 <= iHi && iHi < nsegments_used);
807 aspacem_assert(iLo <= iHi);
808 aspacem_assert(nsegments[iLo].start <= addr );
809 aspacem_assert(nsegments[iHi].end >= addr + len - 1 );
fitzhardinge98abfc72003-12-16 02:05:15 +0000810
sewardjaa349292005-10-11 22:06:29 +0000811 /* x86 doesn't differentiate 'x' and 'r' (at least, all except the
tomc28e3dd2005-11-02 14:42:39 +0000812 most recent NX-bit enabled CPUs) and so recent kernels attempt
813 to provide execute protection by placing all executable mappings
814 low down in the address space and then reducing the size of the
815 code segment to prevent code at higher addresses being executed.
sewardjaa349292005-10-11 22:06:29 +0000816
tomc28e3dd2005-11-02 14:42:39 +0000817 These kernels report which mappings are really executable in
818 the /proc/self/maps output rather than mirroring what was asked
819 for when each mapping was created. In order to cope with this we
sewardjb5b87402011-03-07 16:05:35 +0000820 have a sloppyXcheck mode which we enable on x86 and s390 - in this
821 mode we allow the kernel to report execute permission when we weren't
tomc28e3dd2005-11-02 14:42:39 +0000822 expecting it but not vice versa. */
sewardjb5b87402011-03-07 16:05:35 +0000823# if defined(VGA_x86) || defined (VGA_s390x)
tomc28e3dd2005-11-02 14:42:39 +0000824 sloppyXcheck = True;
njn4c245e52009-03-15 23:25:38 +0000825# else
826 sloppyXcheck = False;
tomc28e3dd2005-11-02 14:42:39 +0000827# endif
sewardjaa349292005-10-11 22:06:29 +0000828
florian954d6bb2015-04-07 20:43:55 +0000829 /* Some kernels on s390 provide 'r' permission even when it was not
rhyskidda6cece92015-05-01 06:29:51 +0000830 explicitly requested. It seems that 'x' permission implies 'r'.
831 This behaviour also occurs on OS X. */
832# if defined(VGA_s390x) || defined(VGO_darwin)
florian954d6bb2015-04-07 20:43:55 +0000833 sloppyRcheck = True;
834# else
835 sloppyRcheck = False;
836# endif
837
sewardj45f4e7c2005-09-27 19:20:21 +0000838 /* NSegments iLo .. iHi inclusive should agree with the presented
839 data. */
840 for (i = iLo; i <= iHi; i++) {
sewardj47c98a72005-03-12 20:36:15 +0000841
sewardj45f4e7c2005-09-27 19:20:21 +0000842 Bool same, cmp_offsets, cmp_devino;
tomaa55dca2005-10-04 13:02:31 +0000843 UInt seg_prot;
njn6081fce2005-06-25 19:45:34 +0000844
sewardj45f4e7c2005-09-27 19:20:21 +0000845 /* compare the kernel's offering against ours. */
846 same = nsegments[i].kind == SkAnonC
847 || nsegments[i].kind == SkAnonV
848 || nsegments[i].kind == SkFileC
tom1340c352005-10-04 15:59:54 +0000849 || nsegments[i].kind == SkFileV
850 || nsegments[i].kind == SkShmC;
fitzhardinge98abfc72003-12-16 02:05:15 +0000851
tomaa55dca2005-10-04 13:02:31 +0000852 seg_prot = 0;
853 if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
854 if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
855 if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
856
sewardj45f4e7c2005-09-27 19:20:21 +0000857 cmp_offsets
858 = nsegments[i].kind == SkFileC || nsegments[i].kind == SkFileV;
sewardj616cf592005-10-06 03:04:22 +0000859
sewardj45f4e7c2005-09-27 19:20:21 +0000860 cmp_devino
861 = nsegments[i].dev != 0 || nsegments[i].ino != 0;
fitzhardinge98abfc72003-12-16 02:05:15 +0000862
sewardj616cf592005-10-06 03:04:22 +0000863 /* Consider other reasons to not compare dev/inode */
njnf76d27a2009-05-28 01:53:07 +0000864#if defined(VGO_linux)
sewardj616cf592005-10-06 03:04:22 +0000865 /* bproc does some godawful hack on /dev/zero at process
866 migration, which changes the name of it, and its dev & ino */
867 if (filename && 0==VG_(strcmp)(filename, "/dev/zero (deleted)"))
868 cmp_devino = False;
869
sewardjf36e99a2005-11-13 02:42:23 +0000870 /* hack apparently needed on MontaVista Linux */
871 if (filename && VG_(strstr)(filename, "/.lib-ro/"))
872 cmp_devino = False;
njnf76d27a2009-05-28 01:53:07 +0000873#endif
sewardjf36e99a2005-11-13 02:42:23 +0000874
njnf76d27a2009-05-28 01:53:07 +0000875#if defined(VGO_darwin)
876 // GrP fixme kernel info doesn't have dev/inode
877 cmp_devino = False;
878
879 // GrP fixme V and kernel don't agree on offsets
880 cmp_offsets = False;
881#endif
882
tomc28e3dd2005-11-02 14:42:39 +0000883 /* If we are doing sloppy execute permission checks then we
884 allow segment to have X permission when we weren't expecting
885 it (but not vice versa) so if the kernel reported execute
886 permission then pretend that this segment has it regardless
887 of what we were expecting. */
888 if (sloppyXcheck && (prot & VKI_PROT_EXEC) != 0) {
889 seg_prot |= VKI_PROT_EXEC;
sewardjaa349292005-10-11 22:06:29 +0000890 }
891
florian954d6bb2015-04-07 20:43:55 +0000892 if (sloppyRcheck && (prot & (VKI_PROT_EXEC | VKI_PROT_READ)) ==
893 (VKI_PROT_EXEC | VKI_PROT_READ)) {
894 seg_prot |= VKI_PROT_READ;
895 }
896
sewardj45f4e7c2005-09-27 19:20:21 +0000897 same = same
tomaa55dca2005-10-04 13:02:31 +0000898 && seg_prot == prot
sewardj45f4e7c2005-09-27 19:20:21 +0000899 && (cmp_devino
900 ? (nsegments[i].dev == dev && nsegments[i].ino == ino)
901 : True)
902 && (cmp_offsets
903 ? nsegments[i].start-nsegments[i].offset == addr-offset
904 : True);
905 if (!same) {
njnddaef352009-07-31 05:06:29 +0000906 Addr start = addr;
907 Addr end = start + len - 1;
908 HChar len_buf[20];
909 show_len_concisely(len_buf, start, end);
910
sewardj45f4e7c2005-09-27 19:20:21 +0000911 sync_check_ok = False;
njnddaef352009-07-31 05:06:29 +0000912
sewardj45f4e7c2005-09-27 19:20:21 +0000913 VG_(debugLog)(
914 0,"aspacem",
njnddaef352009-07-31 05:06:29 +0000915 "segment mismatch: V's seg 1st, kernel's 2nd:\n");
916 show_nsegment_full( 0, i, &nsegments[i] );
917 VG_(debugLog)(0,"aspacem",
floriana5e06c32015-08-05 21:16:09 +0000918 "...: .... %010lx-%010lx %s %c%c%c.. ....... "
919 "d=0x%03llx i=%-7llu o=%-7lld (.) m=. %s\n",
920 start, end, len_buf,
njnddaef352009-07-31 05:06:29 +0000921 prot & VKI_PROT_READ ? 'r' : '-',
922 prot & VKI_PROT_WRITE ? 'w' : '-',
923 prot & VKI_PROT_EXEC ? 'x' : '-',
floriandbb35842012-10-27 18:39:11 +0000924 dev, ino, offset, filename ? filename : "(none)" );
njnddaef352009-07-31 05:06:29 +0000925
926 return;
njnf6ec8ec2005-07-21 23:26:25 +0000927 }
fitzhardinge98abfc72003-12-16 02:05:15 +0000928 }
929
sewardj45f4e7c2005-09-27 19:20:21 +0000930 /* Looks harmless. Keep going. */
931 return;
fitzhardinge98abfc72003-12-16 02:05:15 +0000932}
933
sewardj45f4e7c2005-09-27 19:20:21 +0000934static void sync_check_gap_callback ( Addr addr, SizeT len )
fitzhardinge98abfc72003-12-16 02:05:15 +0000935{
sewardj45f4e7c2005-09-27 19:20:21 +0000936 Int iLo, iHi, i;
fitzhardinge98abfc72003-12-16 02:05:15 +0000937
sewardj45f4e7c2005-09-27 19:20:21 +0000938 /* If a problem has already been detected, don't continue comparing
939 segments, so as to avoid flooding the output with error
940 messages. */
njnf76d27a2009-05-28 01:53:07 +0000941#if !defined(VGO_darwin)
942 /* GrP fixme not */
sewardj45f4e7c2005-09-27 19:20:21 +0000943 if (!sync_check_ok)
944 return;
njnf76d27a2009-05-28 01:53:07 +0000945#endif
sewardj45f4e7c2005-09-27 19:20:21 +0000946 if (len == 0)
947 return;
fitzhardinge98abfc72003-12-16 02:05:15 +0000948
sewardj45f4e7c2005-09-27 19:20:21 +0000949 /* The kernel should not give us wraparounds. */
950 aspacem_assert(addr <= addr + len - 1);
fitzhardinge98abfc72003-12-16 02:05:15 +0000951
sewardj45f4e7c2005-09-27 19:20:21 +0000952 iLo = find_nsegment_idx( addr );
953 iHi = find_nsegment_idx( addr + len - 1 );
fitzhardinge98abfc72003-12-16 02:05:15 +0000954
sewardj45f4e7c2005-09-27 19:20:21 +0000955 /* These 5 should be guaranteed by find_nsegment_idx. */
956 aspacem_assert(0 <= iLo && iLo < nsegments_used);
957 aspacem_assert(0 <= iHi && iHi < nsegments_used);
958 aspacem_assert(iLo <= iHi);
959 aspacem_assert(nsegments[iLo].start <= addr );
960 aspacem_assert(nsegments[iHi].end >= addr + len - 1 );
fitzhardinge98abfc72003-12-16 02:05:15 +0000961
sewardj45f4e7c2005-09-27 19:20:21 +0000962 /* NSegments iLo .. iHi inclusive should agree with the presented
963 data. */
964 for (i = iLo; i <= iHi; i++) {
fitzhardinge98abfc72003-12-16 02:05:15 +0000965
sewardj45f4e7c2005-09-27 19:20:21 +0000966 Bool same;
thughes9aaebc32004-07-15 23:13:37 +0000967
sewardj45f4e7c2005-09-27 19:20:21 +0000968 /* compare the kernel's offering against ours. */
969 same = nsegments[i].kind == SkFree
970 || nsegments[i].kind == SkResvn;
971
972 if (!same) {
njnddaef352009-07-31 05:06:29 +0000973 Addr start = addr;
974 Addr end = start + len - 1;
975 HChar len_buf[20];
976 show_len_concisely(len_buf, start, end);
977
sewardj45f4e7c2005-09-27 19:20:21 +0000978 sync_check_ok = False;
njnddaef352009-07-31 05:06:29 +0000979
sewardj45f4e7c2005-09-27 19:20:21 +0000980 VG_(debugLog)(
981 0,"aspacem",
njnddaef352009-07-31 05:06:29 +0000982 "segment mismatch: V's gap 1st, kernel's 2nd:\n");
983 show_nsegment_full( 0, i, &nsegments[i] );
984 VG_(debugLog)(0,"aspacem",
floriana5e06c32015-08-05 21:16:09 +0000985 " : .... %010lx-%010lx %s\n",
986 start, end, len_buf);
njnddaef352009-07-31 05:06:29 +0000987 return;
thughes9aaebc32004-07-15 23:13:37 +0000988 }
thughes9aaebc32004-07-15 23:13:37 +0000989 }
990
sewardj45f4e7c2005-09-27 19:20:21 +0000991 /* Looks harmless. Keep going. */
992 return;
sewardj548be6d2005-02-16 01:31:37 +0000993}
994
995
sewardj45f4e7c2005-09-27 19:20:21 +0000996/* Sanity check: check that Valgrind and the kernel agree on the
997 address space layout. Prints offending segments and call point if
998 a discrepancy is detected, but does not abort the system. Returned
999 Bool is False if a discrepancy was found. */
sewardjb5f6f512005-03-10 23:59:00 +00001000
sewardj45f4e7c2005-09-27 19:20:21 +00001001Bool VG_(am_do_sync_check) ( const HChar* fn,
1002 const HChar* file, Int line )
jsgf855d93d2003-10-13 22:26:55 +00001003{
sewardj45f4e7c2005-09-27 19:20:21 +00001004 sync_check_ok = True;
sewardj79048ce2005-02-18 08:28:32 +00001005 if (0)
sewardj45f4e7c2005-09-27 19:20:21 +00001006 VG_(debugLog)(0,"aspacem", "do_sync_check %s:%d\n", file,line);
sewardjcb249ab2005-09-28 09:37:16 +00001007 parse_procselfmaps( sync_check_mapping_callback,
1008 sync_check_gap_callback );
sewardj45f4e7c2005-09-27 19:20:21 +00001009 if (!sync_check_ok) {
1010 VG_(debugLog)(0,"aspacem",
1011 "sync check at %s:%d (%s): FAILED\n",
1012 file, line, fn);
1013 VG_(debugLog)(0,"aspacem", "\n");
sewardj79048ce2005-02-18 08:28:32 +00001014
sewardj45f4e7c2005-09-27 19:20:21 +00001015# if 0
1016 {
florian7b7d5942014-12-19 20:29:22 +00001017 HChar buf[100]; // large enough
sewardj45f4e7c2005-09-27 19:20:21 +00001018 VG_(am_show_nsegments)(0,"post syncheck failure");
1019 VG_(sprintf)(buf, "/bin/cat /proc/%d/maps", VG_(getpid)());
1020 VG_(system)(buf);
1021 }
1022# endif
sewardj79048ce2005-02-18 08:28:32 +00001023
njne3f06352005-06-01 03:48:33 +00001024 }
sewardj45f4e7c2005-09-27 19:20:21 +00001025 return sync_check_ok;
njne3f06352005-06-01 03:48:33 +00001026}
1027
sewardj297f6b02006-10-14 22:25:30 +00001028/* Hook to allow sanity checks to be done from aspacemgr-common.c. */
1029void ML_(am_do_sanity_check)( void )
1030{
1031 AM_SANITY_CHECK;
1032}
1033
sewardj45f4e7c2005-09-27 19:20:21 +00001034
1035/*-----------------------------------------------------------------*/
1036/*--- ---*/
1037/*--- Low level access / modification of the segment array. ---*/
1038/*--- ---*/
1039/*-----------------------------------------------------------------*/
1040
1041/* Binary search the interval array for a given address. Since the
sewardja364d112008-10-27 01:25:14 +00001042 array covers the entire address space the search cannot fail. The
1043 _WRK function does the real work. Its caller (just below) caches
1044 the results thereof, to save time. With N_CACHE of 63 we get a hit
1045 rate exceeding 90% when running OpenOffice.
1046
1047 Re ">> 12", it doesn't matter that the page size of some targets
1048 might be different from 12. Really "(a >> 12) % N_CACHE" is merely
1049 a hash function, and the actual cache entry is always validated
1050 correctly against the selected cache entry before use.
1051*/
1052/* Don't call find_nsegment_idx_WRK; use find_nsegment_idx instead. */
1053__attribute__((noinline))
1054static Int find_nsegment_idx_WRK ( Addr a )
sewardj45f4e7c2005-09-27 19:20:21 +00001055{
1056 Addr a_mid_lo, a_mid_hi;
1057 Int mid,
1058 lo = 0,
1059 hi = nsegments_used-1;
1060 while (True) {
1061 /* current unsearched space is from lo to hi, inclusive. */
1062 if (lo > hi) {
1063 /* Not found. This can't happen. */
sewardj297f6b02006-10-14 22:25:30 +00001064 ML_(am_barf)("find_nsegment_idx: not found");
sewardj45f4e7c2005-09-27 19:20:21 +00001065 }
1066 mid = (lo + hi) / 2;
1067 a_mid_lo = nsegments[mid].start;
1068 a_mid_hi = nsegments[mid].end;
1069
1070 if (a < a_mid_lo) { hi = mid-1; continue; }
1071 if (a > a_mid_hi) { lo = mid+1; continue; }
1072 aspacem_assert(a >= a_mid_lo && a <= a_mid_hi);
1073 aspacem_assert(0 <= mid && mid < nsegments_used);
1074 return mid;
1075 }
1076}
1077
sewardja364d112008-10-27 01:25:14 +00001078inline static Int find_nsegment_idx ( Addr a )
1079{
sewardjbbfcb262011-06-07 21:42:07 +00001080# define N_CACHE 131 /*prime*/
sewardja364d112008-10-27 01:25:14 +00001081 static Addr cache_pageno[N_CACHE];
1082 static Int cache_segidx[N_CACHE];
1083 static Bool cache_inited = False;
1084
Elliott Hughesa0664b92017-04-18 17:46:52 -07001085# ifdef N_Q_M_STATS
sewardja364d112008-10-27 01:25:14 +00001086 static UWord n_q = 0;
1087 static UWord n_m = 0;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001088 n_q++;
1089 if (0 == (n_q & 0xFFFF))
1090 VG_(debugLog)(0,"xxx","find_nsegment_idx: %lu %lu\n", n_q, n_m);
1091# endif
sewardja364d112008-10-27 01:25:14 +00001092
1093 UWord ix;
1094
1095 if (LIKELY(cache_inited)) {
1096 /* do nothing */
1097 } else {
1098 for (ix = 0; ix < N_CACHE; ix++) {
1099 cache_pageno[ix] = 0;
1100 cache_segidx[ix] = -1;
1101 }
1102 cache_inited = True;
1103 }
1104
1105 ix = (a >> 12) % N_CACHE;
1106
sewardja364d112008-10-27 01:25:14 +00001107 if ((a >> 12) == cache_pageno[ix]
1108 && cache_segidx[ix] >= 0
1109 && cache_segidx[ix] < nsegments_used
1110 && nsegments[cache_segidx[ix]].start <= a
1111 && a <= nsegments[cache_segidx[ix]].end) {
1112 /* hit */
1113 /* aspacem_assert( cache_segidx[ix] == find_nsegment_idx_WRK(a) ); */
1114 return cache_segidx[ix];
1115 }
1116 /* miss */
Elliott Hughesa0664b92017-04-18 17:46:52 -07001117# ifdef N_Q_M_STATS
sewardja364d112008-10-27 01:25:14 +00001118 n_m++;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001119# endif
sewardja364d112008-10-27 01:25:14 +00001120 cache_segidx[ix] = find_nsegment_idx_WRK(a);
1121 cache_pageno[ix] = a >> 12;
1122 return cache_segidx[ix];
1123# undef N_CACHE
1124}
1125
1126
florian7cb12932015-02-16 23:04:53 +00001127/* Finds the segment containing 'a'. Only returns non-SkFree segments. */
sewardj716f31a2006-10-17 01:23:57 +00001128NSegment const * VG_(am_find_nsegment) ( Addr a )
sewardj45f4e7c2005-09-27 19:20:21 +00001129{
1130 Int i = find_nsegment_idx(a);
1131 aspacem_assert(i >= 0 && i < nsegments_used);
1132 aspacem_assert(nsegments[i].start <= a);
1133 aspacem_assert(a <= nsegments[i].end);
1134 if (nsegments[i].kind == SkFree)
1135 return NULL;
1136 else
1137 return &nsegments[i];
1138}
1139
sewardj8eb8bab2015-07-21 14:44:28 +00001140/* Finds an anonymous segment containing 'a'. Returned pointer is read only. */
1141NSegment const *VG_(am_find_anon_segment) ( Addr a )
1142{
1143 Int i = find_nsegment_idx(a);
1144 aspacem_assert(i >= 0 && i < nsegments_used);
1145 aspacem_assert(nsegments[i].start <= a);
1146 aspacem_assert(a <= nsegments[i].end);
1147 if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV)
1148 return &nsegments[i];
1149 else
1150 return NULL;
1151}
sewardj45f4e7c2005-09-27 19:20:21 +00001152
florian686b8ca2015-02-14 21:17:46 +00001153/* Map segment pointer to segment index. */
florian3e798632012-11-24 19:41:54 +00001154static Int segAddr_to_index ( const NSegment* seg )
sewardj45f4e7c2005-09-27 19:20:21 +00001155{
florian686b8ca2015-02-14 21:17:46 +00001156 aspacem_assert(seg >= &nsegments[0] && seg < &nsegments[nsegments_used]);
1157
1158 return seg - &nsegments[0];
sewardj45f4e7c2005-09-27 19:20:21 +00001159}
1160
1161
florian7cb12932015-02-16 23:04:53 +00001162/* Find the next segment along from 'here', if it is a non-SkFree segment. */
florian3e798632012-11-24 19:41:54 +00001163NSegment const * VG_(am_next_nsegment) ( const NSegment* here, Bool fwds )
sewardj45f4e7c2005-09-27 19:20:21 +00001164{
1165 Int i = segAddr_to_index(here);
florian686b8ca2015-02-14 21:17:46 +00001166
sewardj45f4e7c2005-09-27 19:20:21 +00001167 if (fwds) {
1168 i++;
1169 if (i >= nsegments_used)
1170 return NULL;
1171 } else {
1172 i--;
1173 if (i < 0)
1174 return NULL;
1175 }
florian7cb12932015-02-16 23:04:53 +00001176 if (nsegments[i].kind == SkFree)
1177 return NULL;
1178 else
1179 return &nsegments[i];
sewardj45f4e7c2005-09-27 19:20:21 +00001180}
1181
1182
1183/* Trivial fn: return the total amount of space in anonymous mappings,
1184 both for V and the client. Is used for printing stats in
1185 out-of-memory messages. */
1186ULong VG_(am_get_anonsize_total)( void )
1187{
1188 Int i;
1189 ULong total = 0;
1190 for (i = 0; i < nsegments_used; i++) {
1191 if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV) {
1192 total += (ULong)nsegments[i].end
1193 - (ULong)nsegments[i].start + 1ULL;
1194 }
1195 }
1196 return total;
1197}
1198
1199
philippeadfff762014-04-20 22:10:24 +00001200/* Test if a piece of memory is addressable by client or by valgrind with at
sewardj45f4e7c2005-09-27 19:20:21 +00001201 least the "prot" protection permissions by examining the underlying
floriana6233452015-05-10 11:07:06 +00001202 segments. The KINDS argument specifies the allowed segments ADDR may
1203 belong to in order to be considered "valid".
sewardj45f4e7c2005-09-27 19:20:21 +00001204*/
1205static
floriana6233452015-05-10 11:07:06 +00001206Bool is_valid_for( UInt kinds, Addr start, SizeT len, UInt prot )
sewardj45f4e7c2005-09-27 19:20:21 +00001207{
1208 Int i, iLo, iHi;
1209 Bool needR, needW, needX;
1210
1211 if (len == 0)
1212 return True; /* somewhat dubious case */
1213 if (start + len < start)
1214 return False; /* reject wraparounds */
1215
1216 needR = toBool(prot & VKI_PROT_READ);
1217 needW = toBool(prot & VKI_PROT_WRITE);
1218 needX = toBool(prot & VKI_PROT_EXEC);
1219
1220 iLo = find_nsegment_idx(start);
1221 aspacem_assert(start >= nsegments[iLo].start);
1222
1223 if (start+len-1 <= nsegments[iLo].end) {
1224 /* This is a speedup hack which avoids calling find_nsegment_idx
1225 a second time when possible. It is always correct to just
1226 use the "else" clause below, but is_valid_for_client is
1227 called a lot by the leak checker, so avoiding pointless calls
1228 to find_nsegment_idx, which can be expensive, is helpful. */
1229 iHi = iLo;
1230 } else {
1231 iHi = find_nsegment_idx(start + len - 1);
1232 }
1233
floriana6233452015-05-10 11:07:06 +00001234 for (i = iLo; i <= iHi; i++) {
1235 if ( (nsegments[i].kind & kinds) != 0
1236 && (needR ? nsegments[i].hasR : True)
1237 && (needW ? nsegments[i].hasW : True)
1238 && (needX ? nsegments[i].hasX : True) ) {
1239 /* ok */
1240 } else {
1241 return False;
sewardj45f4e7c2005-09-27 19:20:21 +00001242 }
1243 }
floriana6233452015-05-10 11:07:06 +00001244
sewardj45f4e7c2005-09-27 19:20:21 +00001245 return True;
1246}
1247
1248/* Test if a piece of memory is addressable by the client with at
1249 least the "prot" protection permissions by examining the underlying
1250 segments. */
1251Bool VG_(am_is_valid_for_client)( Addr start, SizeT len,
1252 UInt prot )
1253{
floriana6233452015-05-10 11:07:06 +00001254 const UInt kinds = SkFileC | SkAnonC | SkShmC;
1255
1256 return is_valid_for(kinds, start, len, prot);
sewardj45f4e7c2005-09-27 19:20:21 +00001257}
1258
1259/* Variant of VG_(am_is_valid_for_client) which allows free areas to
1260 be consider part of the client's addressable space. It also
1261 considers reservations to be allowable, since from the client's
1262 point of view they don't exist. */
1263Bool VG_(am_is_valid_for_client_or_free_or_resvn)
1264 ( Addr start, SizeT len, UInt prot )
1265{
floriana6233452015-05-10 11:07:06 +00001266 const UInt kinds = SkFileC | SkAnonC | SkShmC | SkFree | SkResvn;
1267
1268 return is_valid_for(kinds, start, len, prot);
sewardj45f4e7c2005-09-27 19:20:21 +00001269}
1270
iraisre8b9ee32015-08-31 21:31:09 +00001271/* Checks if a piece of memory consists of either free or reservation
1272 segments. */
1273Bool VG_(am_is_free_or_resvn)( Addr start, SizeT len )
1274{
1275 const UInt kinds = SkFree | SkResvn;
1276
1277 return is_valid_for(kinds, start, len, 0);
1278}
1279
sewardj45f4e7c2005-09-27 19:20:21 +00001280
philippeadfff762014-04-20 22:10:24 +00001281Bool VG_(am_is_valid_for_valgrind) ( Addr start, SizeT len, UInt prot )
sewardj45f4e7c2005-09-27 19:20:21 +00001282{
floriana6233452015-05-10 11:07:06 +00001283 const UInt kinds = SkFileV | SkAnonV;
1284
1285 return is_valid_for(kinds, start, len, prot);
sewardj45f4e7c2005-09-27 19:20:21 +00001286}
1287
1288
1289/* Returns True if any part of the address range is marked as having
1290 translations made from it. This is used to determine when to
1291 discard code, so if in doubt return True. */
1292
1293static Bool any_Ts_in_range ( Addr start, SizeT len )
1294{
1295 Int iLo, iHi, i;
1296 aspacem_assert(len > 0);
1297 aspacem_assert(start + len > start);
1298 iLo = find_nsegment_idx(start);
1299 iHi = find_nsegment_idx(start + len - 1);
1300 for (i = iLo; i <= iHi; i++) {
1301 if (nsegments[i].hasT)
1302 return True;
1303 }
1304 return False;
1305}
1306
1307
florian8f3cd172015-04-22 14:16:11 +00001308/* Check whether ADDR looks like an address or address-to-be located in an
1309 extensible client stack segment. Return true if
1310 (1) ADDR is located in an already mapped stack segment, OR
1311 (2) ADDR is located in a reservation segment into which an abutting SkAnonC
florian017d8f52015-03-23 17:13:04 +00001312 segment can be extended. */
florian8f3cd172015-04-22 14:16:11 +00001313Bool VG_(am_addr_is_in_extensible_client_stack)( Addr addr )
florian017d8f52015-03-23 17:13:04 +00001314{
1315 const NSegment *seg = nsegments + find_nsegment_idx(addr);
1316
1317 switch (seg->kind) {
1318 case SkFree:
1319 case SkAnonV:
1320 case SkFileV:
1321 case SkFileC:
1322 case SkShmC:
florian8f3cd172015-04-22 14:16:11 +00001323 return False;
florian017d8f52015-03-23 17:13:04 +00001324
1325 case SkResvn: {
florian8f3cd172015-04-22 14:16:11 +00001326 if (seg->smode != SmUpper) return False;
florianad4e9792015-07-05 21:53:33 +00001327 /* If the abutting segment towards higher addresses is an SkAnonC
florian017d8f52015-03-23 17:13:04 +00001328 segment, then ADDR is a future stack pointer. */
1329 const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ True);
florian8f3cd172015-04-22 14:16:11 +00001330 if (next == NULL || next->kind != SkAnonC) return False;
florian017d8f52015-03-23 17:13:04 +00001331
1332 /* OK; looks like a stack segment */
florian8f3cd172015-04-22 14:16:11 +00001333 return True;
florian017d8f52015-03-23 17:13:04 +00001334 }
1335
1336 case SkAnonC: {
1337 /* If the abutting segment towards lower addresses is an SkResvn
1338 segment, then ADDR is a stack pointer into mapped memory. */
1339 const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ False);
floriand57686f2015-04-22 13:50:13 +00001340 if (next == NULL || next->kind != SkResvn || next->smode != SmUpper)
florian8f3cd172015-04-22 14:16:11 +00001341 return False;
florian017d8f52015-03-23 17:13:04 +00001342
1343 /* OK; looks like a stack segment */
florian8f3cd172015-04-22 14:16:11 +00001344 return True;
florian017d8f52015-03-23 17:13:04 +00001345 }
1346
1347 default:
1348 aspacem_assert(0); // should never happen
1349 }
1350}
1351
sewardj45f4e7c2005-09-27 19:20:21 +00001352/*-----------------------------------------------------------------*/
1353/*--- ---*/
1354/*--- Modifying the segment array, and constructing segments. ---*/
1355/*--- ---*/
1356/*-----------------------------------------------------------------*/
1357
1358/* Split the segment containing 'a' into two, so that 'a' is
1359 guaranteed to be the start of a new segment. If 'a' is already the
1360 start of a segment, do nothing. */
1361
1362static void split_nsegment_at ( Addr a )
1363{
1364 Int i, j;
1365
1366 aspacem_assert(a > 0);
1367 aspacem_assert(VG_IS_PAGE_ALIGNED(a));
1368
1369 i = find_nsegment_idx(a);
1370 aspacem_assert(i >= 0 && i < nsegments_used);
1371
1372 if (nsegments[i].start == a)
1373 /* 'a' is already the start point of a segment, so nothing to be
1374 done. */
1375 return;
1376
1377 /* else we have to slide the segments upwards to make a hole */
1378 if (nsegments_used >= VG_N_SEGMENTS)
sewardj297f6b02006-10-14 22:25:30 +00001379 ML_(am_barf_toolow)("VG_N_SEGMENTS");
sewardj45f4e7c2005-09-27 19:20:21 +00001380 for (j = nsegments_used-1; j > i; j--)
1381 nsegments[j+1] = nsegments[j];
1382 nsegments_used++;
1383
1384 nsegments[i+1] = nsegments[i];
1385 nsegments[i+1].start = a;
1386 nsegments[i].end = a-1;
1387
1388 if (nsegments[i].kind == SkFileV || nsegments[i].kind == SkFileC)
1389 nsegments[i+1].offset
1390 += ((ULong)nsegments[i+1].start) - ((ULong)nsegments[i].start);
1391
florian4ecd4832015-04-30 17:34:04 +00001392 ML_(am_inc_refcount)(nsegments[i].fnIdx);
florian346ee2f2015-04-06 21:34:30 +00001393
sewardj45f4e7c2005-09-27 19:20:21 +00001394 aspacem_assert(sane_NSegment(&nsegments[i]));
1395 aspacem_assert(sane_NSegment(&nsegments[i+1]));
1396}
1397
1398
1399/* Do the minimum amount of segment splitting necessary to ensure that
1400 sLo is the first address denoted by some segment and sHi is the
1401 highest address denoted by some other segment. Returns the indices
1402 of the lowest and highest segments in the range. */
1403
1404static
1405void split_nsegments_lo_and_hi ( Addr sLo, Addr sHi,
1406 /*OUT*/Int* iLo,
1407 /*OUT*/Int* iHi )
1408{
1409 aspacem_assert(sLo < sHi);
1410 aspacem_assert(VG_IS_PAGE_ALIGNED(sLo));
1411 aspacem_assert(VG_IS_PAGE_ALIGNED(sHi+1));
1412
1413 if (sLo > 0)
1414 split_nsegment_at(sLo);
1415 if (sHi < sHi+1)
1416 split_nsegment_at(sHi+1);
1417
1418 *iLo = find_nsegment_idx(sLo);
1419 *iHi = find_nsegment_idx(sHi);
1420 aspacem_assert(0 <= *iLo && *iLo < nsegments_used);
1421 aspacem_assert(0 <= *iHi && *iHi < nsegments_used);
1422 aspacem_assert(*iLo <= *iHi);
1423 aspacem_assert(nsegments[*iLo].start == sLo);
1424 aspacem_assert(nsegments[*iHi].end == sHi);
1425 /* Not that I'm overly paranoid or anything, definitely not :-) */
1426}
1427
1428
1429/* Add SEG to the collection, deleting/truncating any it overlaps.
1430 This deals with all the tricky cases of splitting up segments as
1431 needed. */
1432
florian32971242014-10-23 17:47:15 +00001433static void add_segment ( const NSegment* seg )
sewardj45f4e7c2005-09-27 19:20:21 +00001434{
1435 Int i, iLo, iHi, delta;
1436 Bool segment_is_sane;
1437
1438 Addr sStart = seg->start;
1439 Addr sEnd = seg->end;
1440
1441 aspacem_assert(sStart <= sEnd);
1442 aspacem_assert(VG_IS_PAGE_ALIGNED(sStart));
1443 aspacem_assert(VG_IS_PAGE_ALIGNED(sEnd+1));
1444
1445 segment_is_sane = sane_NSegment(seg);
njnddaef352009-07-31 05:06:29 +00001446 if (!segment_is_sane) show_nsegment_full(0,-1,seg);
sewardj45f4e7c2005-09-27 19:20:21 +00001447 aspacem_assert(segment_is_sane);
1448
1449 split_nsegments_lo_and_hi( sStart, sEnd, &iLo, &iHi );
1450
Elliott Hughesa0664b92017-04-18 17:46:52 -07001451 /* Increase the reference count of SEG's name. We need to do this
1452 *before* decreasing the reference count of the names of the replaced
1453 segments. Consider the case where the segment name of SEG and one of
1454 the replaced segments are the same. If the refcount of that name is 1,
1455 then decrementing first would put the slot for that name on the free
1456 list. Attempting to increment the refcount later would then fail
1457 because the slot is no longer allocated. */
1458 ML_(am_inc_refcount)(seg->fnIdx);
1459
sewardj45f4e7c2005-09-27 19:20:21 +00001460 /* Now iLo .. iHi inclusive is the range of segment indices which
1461 seg will replace. If we're replacing more than one segment,
florian346ee2f2015-04-06 21:34:30 +00001462 slide those above the range down to fill the hole. Before doing
1463 that decrement the reference counters for the segments names of
1464 the replaced segments. */
1465 for (i = iLo; i <= iHi; ++i)
florian4ecd4832015-04-30 17:34:04 +00001466 ML_(am_dec_refcount)(nsegments[i].fnIdx);
sewardj45f4e7c2005-09-27 19:20:21 +00001467 delta = iHi - iLo;
1468 aspacem_assert(delta >= 0);
1469 if (delta > 0) {
1470 for (i = iLo; i < nsegments_used-delta; i++)
1471 nsegments[i] = nsegments[i+delta];
1472 nsegments_used -= delta;
1473 }
1474
1475 nsegments[iLo] = *seg;
1476
1477 (void)preen_nsegments();
1478 if (0) VG_(am_show_nsegments)(0,"AFTER preen (add_segment)");
1479}
1480
1481
1482/* Clear out an NSegment record. */
1483
1484static void init_nsegment ( /*OUT*/NSegment* seg )
1485{
1486 seg->kind = SkFree;
1487 seg->start = 0;
1488 seg->end = 0;
1489 seg->smode = SmFixed;
1490 seg->dev = 0;
1491 seg->ino = 0;
tomf4c23102005-10-31 17:05:21 +00001492 seg->mode = 0;
sewardj45f4e7c2005-09-27 19:20:21 +00001493 seg->offset = 0;
1494 seg->fnIdx = -1;
1495 seg->hasR = seg->hasW = seg->hasX = seg->hasT = seg->isCH = False;
sewardj45f4e7c2005-09-27 19:20:21 +00001496}
1497
1498/* Make an NSegment which holds a reservation. */
1499
1500static void init_resvn ( /*OUT*/NSegment* seg, Addr start, Addr end )
1501{
1502 aspacem_assert(start < end);
1503 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
1504 aspacem_assert(VG_IS_PAGE_ALIGNED(end+1));
1505 init_nsegment(seg);
1506 seg->kind = SkResvn;
1507 seg->start = start;
1508 seg->end = end;
1509}
1510
1511
1512/*-----------------------------------------------------------------*/
1513/*--- ---*/
1514/*--- Startup, including reading /proc/self/maps. ---*/
1515/*--- ---*/
1516/*-----------------------------------------------------------------*/
1517
1518static void read_maps_callback ( Addr addr, SizeT len, UInt prot,
njnc4431bf2009-01-15 21:29:24 +00001519 ULong dev, ULong ino, Off64T offset,
floriandbb35842012-10-27 18:39:11 +00001520 const HChar* filename )
sewardj45f4e7c2005-09-27 19:20:21 +00001521{
1522 NSegment seg;
1523 init_nsegment( &seg );
1524 seg.start = addr;
1525 seg.end = addr+len-1;
1526 seg.dev = dev;
1527 seg.ino = ino;
1528 seg.offset = offset;
1529 seg.hasR = toBool(prot & VKI_PROT_READ);
1530 seg.hasW = toBool(prot & VKI_PROT_WRITE);
1531 seg.hasX = toBool(prot & VKI_PROT_EXEC);
1532 seg.hasT = False;
1533
florian981ffbd2015-09-05 21:27:58 +00001534 /* A segment in the initial /proc/self/maps is considered a FileV
1535 segment if either it has a file name associated with it or both its
1536 device and inode numbers are != 0. See bug #124528. */
sewardj45f4e7c2005-09-27 19:20:21 +00001537 seg.kind = SkAnonV;
florian981ffbd2015-09-05 21:27:58 +00001538 if (filename || (dev != 0 && ino != 0))
sewardjc2fe2462006-04-04 16:57:15 +00001539 seg.kind = SkFileV;
sewardj38a21ac2010-01-03 10:14:03 +00001540
1541# if defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +00001542 // GrP fixme no dev/ino on darwin
1543 if (offset != 0)
sewardj38a21ac2010-01-03 10:14:03 +00001544 seg.kind = SkFileV;
1545# endif // defined(VGO_darwin)
1546
1547# if defined(VGP_arm_linux)
1548 /* The standard handling of entries read from /proc/self/maps will
1549 cause the faked up commpage segment to have type SkAnonV, which
1550 is a problem because it contains code we want the client to
1551 execute, and so later m_translate will segfault the client when
1552 it tries to go in there. Hence change the ownership of it here
1553 to the client (SkAnonC). The least-worst kludge I could think
1554 of. */
1555 if (addr == ARM_LINUX_FAKE_COMMPAGE_START
1556 && addr + len == ARM_LINUX_FAKE_COMMPAGE_END1
1557 && seg.kind == SkAnonV)
1558 seg.kind = SkAnonC;
1559# endif // defined(VGP_arm_linux)
1560
sewardjc2fe2462006-04-04 16:57:15 +00001561 if (filename)
florian4ecd4832015-04-30 17:34:04 +00001562 seg.fnIdx = ML_(am_allocate_segname)( filename );
sewardj45f4e7c2005-09-27 19:20:21 +00001563
1564 if (0) show_nsegment( 2,0, &seg );
1565 add_segment( &seg );
1566}
1567
florian82e7a542015-03-26 21:55:00 +00001568Bool
1569VG_(am_is_valid_for_aspacem_minAddr)( Addr addr, const HChar **errmsg )
1570{
floriand738b462015-03-27 08:47:22 +00001571 const Addr min = VKI_PAGE_SIZE;
florian82e7a542015-03-26 21:55:00 +00001572#if VG_WORDSIZE == 4
1573 const Addr max = 0x40000000; // 1Gb
1574#else
1575 const Addr max = 0x200000000; // 8Gb
1576#endif
1577 Bool ok = VG_IS_PAGE_ALIGNED(addr) && addr >= min && addr <= max;
1578
1579 if (errmsg) {
1580 *errmsg = "";
1581 if (! ok) {
1582 const HChar fmt[] = "Must be a page aligned address between "
1583 "0x%lx and 0x%lx";
1584 static HChar buf[sizeof fmt + 2 * 16]; // large enough
1585 ML_(am_sprintf)(buf, fmt, min, max);
1586 *errmsg = buf;
1587 }
1588 }
1589 return ok;
1590}
1591
philippe38a74d22014-08-29 22:53:19 +00001592/* See description in pub_core_aspacemgr.h */
sewardj45f4e7c2005-09-27 19:20:21 +00001593Addr VG_(am_startup) ( Addr sp_at_startup )
1594{
1595 NSegment seg;
philippe38a74d22014-08-29 22:53:19 +00001596 Addr suggested_clstack_end;
sewardj45f4e7c2005-09-27 19:20:21 +00001597
1598 aspacem_assert(sizeof(Word) == sizeof(void*));
1599 aspacem_assert(sizeof(Addr) == sizeof(void*));
1600 aspacem_assert(sizeof(SizeT) == sizeof(void*));
1601 aspacem_assert(sizeof(SSizeT) == sizeof(void*));
1602
florian346ee2f2015-04-06 21:34:30 +00001603 /* Initialise the string table for segment names. */
florian4ecd4832015-04-30 17:34:04 +00001604 ML_(am_segnames_init)();
florian346ee2f2015-04-06 21:34:30 +00001605
sewardj41906002008-08-18 21:47:11 +00001606 /* Check that we can store the largest imaginable dev, ino and
1607 offset numbers in an NSegment. */
1608 aspacem_assert(sizeof(seg.dev) == 8);
1609 aspacem_assert(sizeof(seg.ino) == 8);
1610 aspacem_assert(sizeof(seg.offset) == 8);
1611 aspacem_assert(sizeof(seg.mode) == 4);
sewardj45f4e7c2005-09-27 19:20:21 +00001612
1613 /* Add a single interval covering the entire address space. */
1614 init_nsegment(&seg);
1615 seg.kind = SkFree;
1616 seg.start = Addr_MIN;
1617 seg.end = Addr_MAX;
1618 nsegments[0] = seg;
1619 nsegments_used = 1;
1620
philippee4d78122014-04-20 14:20:37 +00001621 aspacem_minAddr = VG_(clo_aspacem_minAddr);
1622
njnf76d27a2009-05-28 01:53:07 +00001623#if defined(VGO_darwin)
1624
1625# if VG_WORDSIZE == 4
njnf76d27a2009-05-28 01:53:07 +00001626 aspacem_maxAddr = (Addr) 0xffffffff;
1627
1628 aspacem_cStart = aspacem_minAddr;
1629 aspacem_vStart = 0xf0000000; // 0xc0000000..0xf0000000 available
1630# else
njnf76d27a2009-05-28 01:53:07 +00001631 aspacem_maxAddr = (Addr) 0x7fffffffffff;
1632
1633 aspacem_cStart = aspacem_minAddr;
1634 aspacem_vStart = 0x700000000000; // 0x7000:00000000..0x7fff:5c000000 avail
1635 // 0x7fff:5c000000..0x7fff:ffe00000? is stack, dyld, shared cache
1636# endif
1637
philippe38a74d22014-08-29 22:53:19 +00001638 suggested_clstack_end = -1; // ignored; Mach-O specifies its stack
njnf76d27a2009-05-28 01:53:07 +00001639
sewardj8eb8bab2015-07-21 14:44:28 +00001640#elif defined(VGO_solaris)
1641# if VG_WORDSIZE == 4
1642 /*
1643 Intended address space partitioning:
1644
1645 ,--------------------------------, 0x00000000
1646 | |
1647 |--------------------------------|
1648 | initial stack given to V by OS |
1649 |--------------------------------| 0x08000000
1650 | client text |
1651 |--------------------------------|
1652 | |
1653 | |
1654 |--------------------------------|
1655 | client stack |
1656 |--------------------------------| 0x38000000
1657 | V's text |
1658 |--------------------------------|
1659 | |
1660 | |
1661 |--------------------------------|
1662 | dynamic shared objects |
1663 '--------------------------------' 0xffffffff
1664
1665 */
1666
1667 /* Anonymous pages need to fit under user limit (USERLIMIT32)
1668 which is 4KB + 16MB below the top of the 32-bit range. */
1669# ifdef ENABLE_INNER
1670 aspacem_maxAddr = (Addr)0x4fffffff; // 1.25GB
1671 aspacem_vStart = (Addr)0x40000000; // 1GB
1672# else
1673 aspacem_maxAddr = (Addr)0xfefff000 - 1; // 4GB - 16MB - 4KB
1674 aspacem_vStart = (Addr)0x50000000; // 1.25GB
1675# endif
1676# elif VG_WORDSIZE == 8
1677 /*
1678 Intended address space partitioning:
1679
1680 ,--------------------------------, 0x00000000_00000000
1681 | |
1682 |--------------------------------| 0x00000000_00400000
1683 | client text |
1684 |--------------------------------|
1685 | |
1686 | |
1687 |--------------------------------|
1688 | client stack |
1689 |--------------------------------| 0x00000000_38000000
1690 | V's text |
1691 |--------------------------------|
1692 | |
1693 |--------------------------------|
1694 | dynamic shared objects |
1695 |--------------------------------| 0x0000000f_ffffffff
1696 | |
1697 | |
1698 |--------------------------------|
1699 | initial stack given to V by OS |
1700 '--------------------------------' 0xffffffff_ffffffff
1701
1702 */
1703
1704 /* Kernel likes to place objects at the end of the address space.
1705 However accessing memory beyond 64GB makes memcheck slow
1706 (see memcheck/mc_main.c, internal representation). Therefore:
1707 - mmapobj() syscall is emulated so that libraries are subject to
1708 Valgrind's aspacemgr control
1709 - Kernel shared pages (such as schedctl and hrt) are left as they are
1710 because kernel cannot be told where they should be put */
1711# ifdef ENABLE_INNER
1712 aspacem_maxAddr = (Addr) 0x00000007ffffffff; // 32GB
1713 aspacem_vStart = (Addr) 0x0000000400000000; // 16GB
1714# else
1715 aspacem_maxAddr = (Addr) 0x0000000fffffffff; // 64GB
1716 aspacem_vStart = (Addr) 0x0000000800000000; // 32GB
1717# endif
1718# else
1719# error "Unknown word size"
1720# endif
1721
1722 aspacem_cStart = aspacem_minAddr;
1723# ifdef ENABLE_INNER
1724 suggested_clstack_end = (Addr) 0x27ff0000 - 1; // 64kB below V's text
1725# else
1726 suggested_clstack_end = (Addr) 0x37ff0000 - 1; // 64kB below V's text
1727# endif
1728
1729#else
njnf76d27a2009-05-28 01:53:07 +00001730
sewardj45f4e7c2005-09-27 19:20:21 +00001731 /* Establish address limits and block out unusable parts
1732 accordingly. */
1733
1734 VG_(debugLog)(2, "aspacem",
floriana5e06c32015-08-05 21:16:09 +00001735 " sp_at_startup = 0x%010lx (supplied)\n",
1736 sp_at_startup );
sewardj45f4e7c2005-09-27 19:20:21 +00001737
sewardj45f4e7c2005-09-27 19:20:21 +00001738# if VG_WORDSIZE == 8
sewardj6805a4a2013-01-29 21:14:46 +00001739 aspacem_maxAddr = (Addr)0x1000000000ULL - 1; // 64G
sewardj70c91dd2005-11-13 18:51:31 +00001740# ifdef ENABLE_INNER
sewardj420c6552006-12-01 02:35:02 +00001741 { Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1;
1742 if (aspacem_maxAddr > cse)
1743 aspacem_maxAddr = cse;
1744 }
sewardj70c91dd2005-11-13 18:51:31 +00001745# endif
sewardj45f4e7c2005-09-27 19:20:21 +00001746# else
sewardj70c91dd2005-11-13 18:51:31 +00001747 aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1;
sewardj45f4e7c2005-09-27 19:20:21 +00001748# endif
1749
philippee4d78122014-04-20 14:20:37 +00001750 aspacem_cStart = aspacem_minAddr;
philipped4f5aac2012-03-08 23:42:05 +00001751 aspacem_vStart = VG_PGROUNDUP(aspacem_minAddr
1752 + (aspacem_maxAddr - aspacem_minAddr + 1) / 2);
sewardj45f4e7c2005-09-27 19:20:21 +00001753# ifdef ENABLE_INNER
1754 aspacem_vStart -= 0x10000000; // 256M
1755# endif
1756
philippe38a74d22014-08-29 22:53:19 +00001757 suggested_clstack_end = aspacem_maxAddr - 16*1024*1024ULL
sewardj45f4e7c2005-09-27 19:20:21 +00001758 + VKI_PAGE_SIZE;
1759
sewardj8eb8bab2015-07-21 14:44:28 +00001760#endif
njnf76d27a2009-05-28 01:53:07 +00001761
sewardj45f4e7c2005-09-27 19:20:21 +00001762 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr));
1763 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_maxAddr + 1));
1764 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_cStart));
1765 aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_vStart));
philippe38a74d22014-08-29 22:53:19 +00001766 aspacem_assert(VG_IS_PAGE_ALIGNED(suggested_clstack_end + 1));
sewardj45f4e7c2005-09-27 19:20:21 +00001767
1768 VG_(debugLog)(2, "aspacem",
floriana5e06c32015-08-05 21:16:09 +00001769 " minAddr = 0x%010lx (computed)\n",
1770 aspacem_minAddr);
sewardj45f4e7c2005-09-27 19:20:21 +00001771 VG_(debugLog)(2, "aspacem",
floriana5e06c32015-08-05 21:16:09 +00001772 " maxAddr = 0x%010lx (computed)\n",
1773 aspacem_maxAddr);
sewardj45f4e7c2005-09-27 19:20:21 +00001774 VG_(debugLog)(2, "aspacem",
floriana5e06c32015-08-05 21:16:09 +00001775 " cStart = 0x%010lx (computed)\n",
1776 aspacem_cStart);
sewardj45f4e7c2005-09-27 19:20:21 +00001777 VG_(debugLog)(2, "aspacem",
floriana5e06c32015-08-05 21:16:09 +00001778 " vStart = 0x%010lx (computed)\n",
1779 aspacem_vStart);
sewardj45f4e7c2005-09-27 19:20:21 +00001780 VG_(debugLog)(2, "aspacem",
floriana5e06c32015-08-05 21:16:09 +00001781 "suggested_clstack_end = 0x%010lx (computed)\n",
1782 suggested_clstack_end);
sewardj45f4e7c2005-09-27 19:20:21 +00001783
1784 if (aspacem_cStart > Addr_MIN) {
1785 init_resvn(&seg, Addr_MIN, aspacem_cStart-1);
1786 add_segment(&seg);
1787 }
1788 if (aspacem_maxAddr < Addr_MAX) {
1789 init_resvn(&seg, aspacem_maxAddr+1, Addr_MAX);
1790 add_segment(&seg);
1791 }
1792
1793 /* Create a 1-page reservation at the notional initial
1794 client/valgrind boundary. This isn't strictly necessary, but
1795 because the advisor does first-fit and starts searches for
1796 valgrind allocations at the boundary, this is kind of necessary
1797 in order to get it to start allocating in the right place. */
1798 init_resvn(&seg, aspacem_vStart, aspacem_vStart + VKI_PAGE_SIZE - 1);
1799 add_segment(&seg);
1800
1801 VG_(am_show_nsegments)(2, "Initial layout");
1802
1803 VG_(debugLog)(2, "aspacem", "Reading /proc/self/maps\n");
sewardjcb249ab2005-09-28 09:37:16 +00001804 parse_procselfmaps( read_maps_callback, NULL );
sewardj38a21ac2010-01-03 10:14:03 +00001805 /* NB: on arm-linux, parse_procselfmaps automagically kludges up
1806 (iow, hands to its callbacks) a description of the ARM Commpage,
1807 since that's not listed in /proc/self/maps (kernel bug IMO). We
1808 have to fake up its existence in parse_procselfmaps and not
1809 merely add it here as an extra segment, because doing the latter
1810 causes sync checking to fail: we see we have an extra segment in
1811 the segments array, which isn't listed in /proc/self/maps.
1812 Hence we must make it appear that /proc/self/maps contained this
1813 segment all along. Sigh. */
sewardj45f4e7c2005-09-27 19:20:21 +00001814
1815 VG_(am_show_nsegments)(2, "With contents of /proc/self/maps");
1816
1817 AM_SANITY_CHECK;
philippe38a74d22014-08-29 22:53:19 +00001818 return suggested_clstack_end;
sewardj45f4e7c2005-09-27 19:20:21 +00001819}
1820
1821
1822/*-----------------------------------------------------------------*/
1823/*--- ---*/
1824/*--- The core query-notify mechanism. ---*/
1825/*--- ---*/
1826/*-----------------------------------------------------------------*/
1827
1828/* Query aspacem to ask where a mapping should go. */
1829
florian32971242014-10-23 17:47:15 +00001830Addr VG_(am_get_advisory) ( const MapRequest* req,
1831 Bool forClient,
sewardj45f4e7c2005-09-27 19:20:21 +00001832 /*OUT*/Bool* ok )
1833{
1834 /* This function implements allocation policy.
1835
1836 The nature of the allocation request is determined by req, which
1837 specifies the start and length of the request and indicates
1838 whether the start address is mandatory, a hint, or irrelevant,
1839 and by forClient, which says whether this is for the client or
1840 for V.
1841
1842 Return values: the request can be vetoed (*ok is set to False),
1843 in which case the caller should not attempt to proceed with
1844 making the mapping. Otherwise, *ok is set to True, the caller
1845 may proceed, and the preferred address at which the mapping
1846 should happen is returned.
1847
1848 Note that this is an advisory system only: the kernel can in
1849 fact do whatever it likes as far as placement goes, and we have
1850 no absolute control over it.
1851
1852 Allocations will never be granted in a reserved area.
1853
1854 The Default Policy is:
1855
1856 Search the address space for two free intervals: one of them
1857 big enough to contain the request without regard to the
1858 specified address (viz, as if it was a floating request) and
1859 the other being able to contain the request at the specified
1860 address (viz, as if were a fixed request). Then, depending on
1861 the outcome of the search and the kind of request made, decide
1862 whether the request is allowable and what address to advise.
1863
1864 The Default Policy is overriden by Policy Exception #1:
1865
1866 If the request is for a fixed client map, we are prepared to
1867 grant it providing all areas inside the request are either
1868 free, reservations, or mappings belonging to the client. In
1869 other words we are prepared to let the client trash its own
1870 mappings if it wants to.
1871
sewardjcaf971d2005-09-29 21:20:41 +00001872 The Default Policy is overriden by Policy Exception #2:
sewardj45f4e7c2005-09-27 19:20:21 +00001873
sewardjcaf971d2005-09-29 21:20:41 +00001874 If the request is for a hinted client map, we are prepared to
1875 grant it providing all areas inside the request are either
1876 free or reservations. In other words we are prepared to let
1877 the client have a hinted mapping anywhere it likes provided
1878 it does not trash either any of its own mappings or any of
1879 valgrind's mappings.
sewardj45f4e7c2005-09-27 19:20:21 +00001880 */
1881 Int i, j;
1882 Addr holeStart, holeEnd, holeLen;
1883 Bool fixed_not_required;
1884
sewardj8eb8bab2015-07-21 14:44:28 +00001885#if defined(VGO_solaris)
1886 Addr startPoint = forClient ? aspacem_vStart - 1 : aspacem_maxAddr - 1;
1887#else
sewardj45f4e7c2005-09-27 19:20:21 +00001888 Addr startPoint = forClient ? aspacem_cStart : aspacem_vStart;
sewardj8eb8bab2015-07-21 14:44:28 +00001889#endif /* VGO_solaris */
sewardj45f4e7c2005-09-27 19:20:21 +00001890
sewardj8eb8bab2015-07-21 14:44:28 +00001891 Addr reqStart = req->rkind==MFixed || req->rkind==MHint ? req->start : 0;
sewardj45f4e7c2005-09-27 19:20:21 +00001892 Addr reqEnd = reqStart + req->len - 1;
1893 Addr reqLen = req->len;
1894
1895 /* These hold indices for segments found during search, or -1 if not
1896 found. */
1897 Int floatIdx = -1;
1898 Int fixedIdx = -1;
1899
1900 aspacem_assert(nsegments_used > 0);
1901
1902 if (0) {
1903 VG_(am_show_nsegments)(0,"getAdvisory");
floriana5e06c32015-08-05 21:16:09 +00001904 VG_(debugLog)(0,"aspacem", "getAdvisory 0x%lx %lu\n",
1905 req->start, req->len);
sewardj45f4e7c2005-09-27 19:20:21 +00001906 }
1907
1908 /* Reject zero-length requests */
1909 if (req->len == 0) {
1910 *ok = False;
1911 return 0;
1912 }
1913
1914 /* Reject wraparounds */
floriane354a1f2015-05-26 17:59:50 +00001915 if (req->start + req->len < req->start) {
sewardj45f4e7c2005-09-27 19:20:21 +00001916 *ok = False;
1917 return 0;
1918 }
1919
1920 /* ------ Implement Policy Exception #1 ------ */
1921
sewardjcaf971d2005-09-29 21:20:41 +00001922 if (forClient && req->rkind == MFixed) {
sewardj45f4e7c2005-09-27 19:20:21 +00001923 Int iLo = find_nsegment_idx(reqStart);
1924 Int iHi = find_nsegment_idx(reqEnd);
1925 Bool allow = True;
1926 for (i = iLo; i <= iHi; i++) {
1927 if (nsegments[i].kind == SkFree
1928 || nsegments[i].kind == SkFileC
1929 || nsegments[i].kind == SkAnonC
tom1340c352005-10-04 15:59:54 +00001930 || nsegments[i].kind == SkShmC
sewardj45f4e7c2005-09-27 19:20:21 +00001931 || nsegments[i].kind == SkResvn) {
1932 /* ok */
1933 } else {
1934 allow = False;
1935 break;
1936 }
1937 }
1938 if (allow) {
1939 /* Acceptable. Granted. */
1940 *ok = True;
1941 return reqStart;
1942 }
sewardjcaf971d2005-09-29 21:20:41 +00001943 /* Not acceptable. Fail. */
1944 *ok = False;
1945 return 0;
1946 }
1947
1948 /* ------ Implement Policy Exception #2 ------ */
1949
1950 if (forClient && req->rkind == MHint) {
1951 Int iLo = find_nsegment_idx(reqStart);
1952 Int iHi = find_nsegment_idx(reqEnd);
1953 Bool allow = True;
1954 for (i = iLo; i <= iHi; i++) {
1955 if (nsegments[i].kind == SkFree
1956 || nsegments[i].kind == SkResvn) {
1957 /* ok */
1958 } else {
1959 allow = False;
1960 break;
1961 }
sewardj45f4e7c2005-09-27 19:20:21 +00001962 }
sewardjcaf971d2005-09-29 21:20:41 +00001963 if (allow) {
1964 /* Acceptable. Granted. */
1965 *ok = True;
1966 return reqStart;
1967 }
1968 /* Not acceptable. Fall through to the default policy. */
sewardj45f4e7c2005-09-27 19:20:21 +00001969 }
1970
1971 /* ------ Implement the Default Policy ------ */
1972
1973 /* Don't waste time looking for a fixed match if not requested to. */
sewardj8eb8bab2015-07-21 14:44:28 +00001974 fixed_not_required = req->rkind == MAny || req->rkind == MAlign;
sewardj45f4e7c2005-09-27 19:20:21 +00001975
1976 i = find_nsegment_idx(startPoint);
1977
sewardj8eb8bab2015-07-21 14:44:28 +00001978#if defined(VGO_solaris)
1979# define UPDATE_INDEX(index) \
1980 (index)--; \
1981 if ((index) <= 0) \
1982 (index) = nsegments_used - 1;
1983# define ADVISE_ADDRESS(segment) \
1984 VG_PGROUNDDN((segment)->end + 1 - reqLen)
1985# define ADVISE_ADDRESS_ALIGNED(segment) \
1986 VG_ROUNDDN((segment)->end + 1 - reqLen, req->start)
1987
1988#else
1989
1990# define UPDATE_INDEX(index) \
1991 (index)++; \
1992 if ((index) >= nsegments_used) \
1993 (index) = 0;
1994# define ADVISE_ADDRESS(segment) \
1995 (segment)->start
1996# define ADVISE_ADDRESS_ALIGNED(segment) \
1997 VG_ROUNDUP((segment)->start, req->start)
1998#endif /* VGO_solaris */
1999
sewardj45f4e7c2005-09-27 19:20:21 +00002000 /* Examine holes from index i back round to i-1. Record the
2001 index first fixed hole and the first floating hole which would
2002 satisfy the request. */
2003 for (j = 0; j < nsegments_used; j++) {
2004
2005 if (nsegments[i].kind != SkFree) {
sewardj8eb8bab2015-07-21 14:44:28 +00002006 UPDATE_INDEX(i);
sewardj45f4e7c2005-09-27 19:20:21 +00002007 continue;
2008 }
2009
2010 holeStart = nsegments[i].start;
2011 holeEnd = nsegments[i].end;
2012
2013 /* Stay sane .. */
2014 aspacem_assert(holeStart <= holeEnd);
2015 aspacem_assert(aspacem_minAddr <= holeStart);
2016 aspacem_assert(holeEnd <= aspacem_maxAddr);
2017
sewardj8eb8bab2015-07-21 14:44:28 +00002018 if (req->rkind == MAlign) {
2019 holeStart = VG_ROUNDUP(holeStart, req->start);
2020 if (holeStart >= holeEnd) {
2021 /* This hole can't be used. */
2022 UPDATE_INDEX(i);
2023 continue;
2024 }
2025 }
2026
sewardj45f4e7c2005-09-27 19:20:21 +00002027 /* See if it's any use to us. */
2028 holeLen = holeEnd - holeStart + 1;
2029
2030 if (fixedIdx == -1 && holeStart <= reqStart && reqEnd <= holeEnd)
2031 fixedIdx = i;
2032
2033 if (floatIdx == -1 && holeLen >= reqLen)
2034 floatIdx = i;
2035
2036 /* Don't waste time searching once we've found what we wanted. */
2037 if ((fixed_not_required || fixedIdx >= 0) && floatIdx >= 0)
2038 break;
2039
sewardj8eb8bab2015-07-21 14:44:28 +00002040 UPDATE_INDEX(i);
sewardj45f4e7c2005-09-27 19:20:21 +00002041 }
2042
2043 aspacem_assert(fixedIdx >= -1 && fixedIdx < nsegments_used);
2044 if (fixedIdx >= 0)
2045 aspacem_assert(nsegments[fixedIdx].kind == SkFree);
2046
2047 aspacem_assert(floatIdx >= -1 && floatIdx < nsegments_used);
2048 if (floatIdx >= 0)
2049 aspacem_assert(nsegments[floatIdx].kind == SkFree);
2050
2051 AM_SANITY_CHECK;
2052
2053 /* Now see if we found anything which can satisfy the request. */
2054 switch (req->rkind) {
2055 case MFixed:
2056 if (fixedIdx >= 0) {
2057 *ok = True;
2058 return req->start;
2059 } else {
2060 *ok = False;
2061 return 0;
2062 }
2063 break;
2064 case MHint:
2065 if (fixedIdx >= 0) {
2066 *ok = True;
2067 return req->start;
2068 }
2069 if (floatIdx >= 0) {
2070 *ok = True;
sewardj8eb8bab2015-07-21 14:44:28 +00002071 return ADVISE_ADDRESS(&nsegments[floatIdx]);
sewardj45f4e7c2005-09-27 19:20:21 +00002072 }
2073 *ok = False;
2074 return 0;
2075 case MAny:
2076 if (floatIdx >= 0) {
2077 *ok = True;
sewardj8eb8bab2015-07-21 14:44:28 +00002078 return ADVISE_ADDRESS(&nsegments[floatIdx]);
2079 }
2080 *ok = False;
2081 return 0;
2082 case MAlign:
2083 if (floatIdx >= 0) {
2084 *ok = True;
2085 return ADVISE_ADDRESS_ALIGNED(&nsegments[floatIdx]);
sewardj45f4e7c2005-09-27 19:20:21 +00002086 }
2087 *ok = False;
2088 return 0;
2089 default:
2090 break;
2091 }
2092
2093 /*NOTREACHED*/
sewardj297f6b02006-10-14 22:25:30 +00002094 ML_(am_barf)("getAdvisory: unknown request kind");
sewardj45f4e7c2005-09-27 19:20:21 +00002095 *ok = False;
2096 return 0;
sewardj8eb8bab2015-07-21 14:44:28 +00002097
2098#undef UPDATE_INDEX
2099#undef ADVISE_ADDRESS
2100#undef ADVISE_ADDRESS_ALIGNED
sewardj45f4e7c2005-09-27 19:20:21 +00002101}
2102
2103/* Convenience wrapper for VG_(am_get_advisory) for client floating or
2104 fixed requests. If start is zero, a floating request is issued; if
2105 nonzero, a fixed request at that address is issued. Same comments
2106 about return values apply. */
2107
2108Addr VG_(am_get_advisory_client_simple) ( Addr start, SizeT len,
2109 /*OUT*/Bool* ok )
2110{
2111 MapRequest mreq;
2112 mreq.rkind = start==0 ? MAny : MFixed;
2113 mreq.start = start;
2114 mreq.len = len;
philippe515e2692012-01-08 21:01:02 +00002115 return VG_(am_get_advisory)( &mreq, True/*forClient*/, ok );
sewardj45f4e7c2005-09-27 19:20:21 +00002116}
2117
philippe15e301e2011-12-22 13:25:58 +00002118/* Similar to VG_(am_find_nsegment) but only returns free segments. */
2119static NSegment const * VG_(am_find_free_nsegment) ( Addr a )
2120{
2121 Int i = find_nsegment_idx(a);
2122 aspacem_assert(i >= 0 && i < nsegments_used);
2123 aspacem_assert(nsegments[i].start <= a);
2124 aspacem_assert(a <= nsegments[i].end);
2125 if (nsegments[i].kind == SkFree)
2126 return &nsegments[i];
2127 else
2128 return NULL;
2129}
2130
2131Bool VG_(am_covered_by_single_free_segment)
2132 ( Addr start, SizeT len)
2133{
2134 NSegment const* segLo = VG_(am_find_free_nsegment)( start );
2135 NSegment const* segHi = VG_(am_find_free_nsegment)( start + len - 1 );
2136
2137 return segLo != NULL && segHi != NULL && segLo == segHi;
2138}
2139
sewardj45f4e7c2005-09-27 19:20:21 +00002140
2141/* Notifies aspacem that the client completed an mmap successfully.
2142 The segment array is updated accordingly. If the returned Bool is
2143 True, the caller should immediately discard translations from the
2144 specified address range. */
2145
2146Bool
2147VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags,
sewardj274461d2005-10-02 17:01:41 +00002148 Int fd, Off64T offset )
sewardj45f4e7c2005-09-27 19:20:21 +00002149{
2150 HChar buf[VKI_PATH_MAX];
sewardj41906002008-08-18 21:47:11 +00002151 ULong dev, ino;
tomf4c23102005-10-31 17:05:21 +00002152 UInt mode;
sewardj45f4e7c2005-09-27 19:20:21 +00002153 NSegment seg;
2154 Bool needDiscard;
2155
2156 aspacem_assert(len > 0);
2157 aspacem_assert(VG_IS_PAGE_ALIGNED(a));
2158 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
sewardj274461d2005-10-02 17:01:41 +00002159 aspacem_assert(VG_IS_PAGE_ALIGNED(offset));
sewardj45f4e7c2005-09-27 19:20:21 +00002160
2161 /* Discard is needed if any of the just-trashed range had T. */
2162 needDiscard = any_Ts_in_range( a, len );
2163
2164 init_nsegment( &seg );
2165 seg.kind = (flags & VKI_MAP_ANONYMOUS) ? SkAnonC : SkFileC;
2166 seg.start = a;
2167 seg.end = a + len - 1;
sewardj45f4e7c2005-09-27 19:20:21 +00002168 seg.hasR = toBool(prot & VKI_PROT_READ);
2169 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2170 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2171 if (!(flags & VKI_MAP_ANONYMOUS)) {
njn4395ad42006-05-09 18:46:01 +00002172 // Nb: We ignore offset requests in anonymous mmaps (see bug #126722)
tomdadff0a2006-05-09 09:06:56 +00002173 seg.offset = offset;
njndad944a2009-05-04 05:55:46 +00002174 if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
sewardj45f4e7c2005-09-27 19:20:21 +00002175 seg.dev = dev;
2176 seg.ino = ino;
tomf4c23102005-10-31 17:05:21 +00002177 seg.mode = mode;
sewardj45f4e7c2005-09-27 19:20:21 +00002178 }
njndad944a2009-05-04 05:55:46 +00002179 if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
florian4ecd4832015-04-30 17:34:04 +00002180 seg.fnIdx = ML_(am_allocate_segname)( buf );
sewardj45f4e7c2005-09-27 19:20:21 +00002181 }
2182 }
2183 add_segment( &seg );
2184 AM_SANITY_CHECK;
2185 return needDiscard;
2186}
2187
tom1340c352005-10-04 15:59:54 +00002188/* Notifies aspacem that the client completed a shmat successfully.
2189 The segment array is updated accordingly. If the returned Bool is
2190 True, the caller should immediately discard translations from the
2191 specified address range. */
2192
2193Bool
2194VG_(am_notify_client_shmat)( Addr a, SizeT len, UInt prot )
2195{
2196 NSegment seg;
2197 Bool needDiscard;
2198
2199 aspacem_assert(len > 0);
2200 aspacem_assert(VG_IS_PAGE_ALIGNED(a));
2201 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2202
2203 /* Discard is needed if any of the just-trashed range had T. */
2204 needDiscard = any_Ts_in_range( a, len );
2205
2206 init_nsegment( &seg );
2207 seg.kind = SkShmC;
2208 seg.start = a;
2209 seg.end = a + len - 1;
2210 seg.offset = 0;
2211 seg.hasR = toBool(prot & VKI_PROT_READ);
2212 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2213 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2214 add_segment( &seg );
2215 AM_SANITY_CHECK;
2216 return needDiscard;
2217}
2218
sewardj45f4e7c2005-09-27 19:20:21 +00002219/* Notifies aspacem that an mprotect was completed successfully. The
2220 segment array is updated accordingly. Note, as with
2221 VG_(am_notify_munmap), it is not the job of this function to reject
2222 stupid mprotects, for example the client doing mprotect of
2223 non-client areas. Such requests should be intercepted earlier, by
2224 the syscall wrapper for mprotect. This function merely records
2225 whatever it is told. If the returned Bool is True, the caller
2226 should immediately discard translations from the specified address
2227 range. */
2228
2229Bool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot )
2230{
2231 Int i, iLo, iHi;
2232 Bool newR, newW, newX, needDiscard;
2233
2234 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2235 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2236
2237 if (len == 0)
2238 return False;
2239
2240 newR = toBool(prot & VKI_PROT_READ);
2241 newW = toBool(prot & VKI_PROT_WRITE);
2242 newX = toBool(prot & VKI_PROT_EXEC);
2243
2244 /* Discard is needed if we're dumping X permission */
2245 needDiscard = any_Ts_in_range( start, len ) && !newX;
2246
2247 split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
2248
2249 iLo = find_nsegment_idx(start);
2250 iHi = find_nsegment_idx(start + len - 1);
2251
2252 for (i = iLo; i <= iHi; i++) {
2253 /* Apply the permissions to all relevant segments. */
2254 switch (nsegments[i].kind) {
tom1340c352005-10-04 15:59:54 +00002255 case SkAnonC: case SkAnonV: case SkFileC: case SkFileV: case SkShmC:
sewardj45f4e7c2005-09-27 19:20:21 +00002256 nsegments[i].hasR = newR;
2257 nsegments[i].hasW = newW;
2258 nsegments[i].hasX = newX;
2259 aspacem_assert(sane_NSegment(&nsegments[i]));
2260 break;
2261 default:
2262 break;
2263 }
2264 }
2265
2266 /* Changing permissions could have made previously un-mergable
2267 segments mergeable. Therefore have to re-preen them. */
2268 (void)preen_nsegments();
2269 AM_SANITY_CHECK;
2270 return needDiscard;
2271}
2272
2273
2274/* Notifies aspacem that an munmap completed successfully. The
2275 segment array is updated accordingly. As with
florian135c9f12015-05-22 09:17:28 +00002276 VG_(am_notify_mprotect), we merely record the given info, and don't
sewardj45f4e7c2005-09-27 19:20:21 +00002277 check it for sensibleness. If the returned Bool is True, the
2278 caller should immediately discard translations from the specified
2279 address range. */
2280
2281Bool VG_(am_notify_munmap)( Addr start, SizeT len )
2282{
2283 NSegment seg;
2284 Bool needDiscard;
2285 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2286 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2287
2288 if (len == 0)
2289 return False;
2290
2291 needDiscard = any_Ts_in_range( start, len );
2292
2293 init_nsegment( &seg );
sewardj45f4e7c2005-09-27 19:20:21 +00002294 seg.start = start;
2295 seg.end = start + len - 1;
sewardj613a9f22006-08-16 01:48:19 +00002296
2297 /* The segment becomes unused (free). Segments from above
2298 aspacem_maxAddr were originally SkResvn and so we make them so
2299 again. Note, this isn't really right when the segment straddles
2300 the aspacem_maxAddr boundary - then really it should be split in
2301 two, the lower part marked as SkFree and the upper part as
2302 SkResvn. Ah well. */
2303 if (start > aspacem_maxAddr
2304 && /* check previous comparison is meaningful */
2305 aspacem_maxAddr < Addr_MAX)
2306 seg.kind = SkResvn;
sewardj7cc20402006-09-11 19:49:35 +00002307 else
2308 /* Ditto for segments from below aspacem_minAddr. */
2309 if (seg.end < aspacem_minAddr && aspacem_minAddr > 0)
2310 seg.kind = SkResvn;
sewardj613a9f22006-08-16 01:48:19 +00002311 else
2312 seg.kind = SkFree;
2313
sewardj45f4e7c2005-09-27 19:20:21 +00002314 add_segment( &seg );
2315
2316 /* Unmapping could create two adjacent free segments, so a preen is
2317 needed. add_segment() will do that, so no need to here. */
2318 AM_SANITY_CHECK;
2319 return needDiscard;
2320}
2321
2322
2323/*-----------------------------------------------------------------*/
2324/*--- ---*/
2325/*--- Handling mappings which do not arise directly from the ---*/
2326/*--- simulation of the client. ---*/
2327/*--- ---*/
2328/*-----------------------------------------------------------------*/
2329
2330/* --- --- --- map, unmap, protect --- --- --- */
2331
2332/* Map a file at a fixed address for the client, and update the
2333 segment array accordingly. */
2334
2335SysRes VG_(am_mmap_file_fixed_client)
sewardj274461d2005-10-02 17:01:41 +00002336 ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset )
sewardj45f4e7c2005-09-27 19:20:21 +00002337{
sewardj8eb8bab2015-07-21 14:44:28 +00002338 UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
2339 return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
2340 fd, offset, NULL);
2341}
2342
2343SysRes VG_(am_mmap_file_fixed_client_flags)
2344 ( Addr start, SizeT length, UInt prot, UInt flags, Int fd, Off64T offset )
2345{
2346 return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
2347 fd, offset, NULL);
njnf76d27a2009-05-28 01:53:07 +00002348}
2349
2350SysRes VG_(am_mmap_named_file_fixed_client)
2351 ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name )
2352{
sewardj8eb8bab2015-07-21 14:44:28 +00002353 UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
2354 return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
2355 fd, offset, name);
2356}
2357
2358SysRes VG_(am_mmap_named_file_fixed_client_flags)
2359 ( Addr start, SizeT length, UInt prot, UInt flags,
2360 Int fd, Off64T offset, const HChar *name )
2361{
sewardj45f4e7c2005-09-27 19:20:21 +00002362 SysRes sres;
2363 NSegment seg;
2364 Addr advised;
2365 Bool ok;
2366 MapRequest req;
sewardj41906002008-08-18 21:47:11 +00002367 ULong dev, ino;
tomf4c23102005-10-31 17:05:21 +00002368 UInt mode;
sewardj45f4e7c2005-09-27 19:20:21 +00002369 HChar buf[VKI_PATH_MAX];
2370
2371 /* Not allowable. */
sewardj274461d2005-10-02 17:01:41 +00002372 if (length == 0
2373 || !VG_IS_PAGE_ALIGNED(start)
2374 || !VG_IS_PAGE_ALIGNED(offset))
sewardj45f4e7c2005-09-27 19:20:21 +00002375 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2376
2377 /* Ask for an advisory. If it's negative, fail immediately. */
2378 req.rkind = MFixed;
2379 req.start = start;
2380 req.len = length;
philippe515e2692012-01-08 21:01:02 +00002381 advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
sewardj45f4e7c2005-09-27 19:20:21 +00002382 if (!ok || advised != start)
2383 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2384
2385 /* We have been advised that the mapping is allowable at the
2386 specified address. So hand it off to the kernel, and propagate
2387 any resulting failure immediately. */
njnf76d27a2009-05-28 01:53:07 +00002388 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
sewardj45f4e7c2005-09-27 19:20:21 +00002389 sres = VG_(am_do_mmap_NO_NOTIFY)(
sewardj8eb8bab2015-07-21 14:44:28 +00002390 start, length, prot, flags,
sewardj45f4e7c2005-09-27 19:20:21 +00002391 fd, offset
2392 );
njncda2f0f2009-05-18 02:12:08 +00002393 if (sr_isError(sres))
sewardj45f4e7c2005-09-27 19:20:21 +00002394 return sres;
2395
njncda2f0f2009-05-18 02:12:08 +00002396 if (sr_Res(sres) != start) {
sewardj45f4e7c2005-09-27 19:20:21 +00002397 /* I don't think this can happen. It means the kernel made a
2398 fixed map succeed but not at the requested location. Try to
2399 repair the damage, then return saying the mapping failed. */
njncda2f0f2009-05-18 02:12:08 +00002400 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
sewardj45f4e7c2005-09-27 19:20:21 +00002401 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2402 }
2403
2404 /* Ok, the mapping succeeded. Now notify the interval map. */
2405 init_nsegment( &seg );
2406 seg.kind = SkFileC;
2407 seg.start = start;
2408 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2409 seg.offset = offset;
2410 seg.hasR = toBool(prot & VKI_PROT_READ);
2411 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2412 seg.hasX = toBool(prot & VKI_PROT_EXEC);
njndad944a2009-05-04 05:55:46 +00002413 if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
sewardj45f4e7c2005-09-27 19:20:21 +00002414 seg.dev = dev;
2415 seg.ino = ino;
tomf4c23102005-10-31 17:05:21 +00002416 seg.mode = mode;
sewardj45f4e7c2005-09-27 19:20:21 +00002417 }
njnf76d27a2009-05-28 01:53:07 +00002418 if (name) {
florian4ecd4832015-04-30 17:34:04 +00002419 seg.fnIdx = ML_(am_allocate_segname)( name );
njnf76d27a2009-05-28 01:53:07 +00002420 } else if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
florian4ecd4832015-04-30 17:34:04 +00002421 seg.fnIdx = ML_(am_allocate_segname)( buf );
sewardj45f4e7c2005-09-27 19:20:21 +00002422 }
2423 add_segment( &seg );
2424
2425 AM_SANITY_CHECK;
2426 return sres;
2427}
2428
2429
2430/* Map anonymously at a fixed address for the client, and update
2431 the segment array accordingly. */
2432
2433SysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot )
2434{
2435 SysRes sres;
2436 NSegment seg;
2437 Addr advised;
2438 Bool ok;
2439 MapRequest req;
2440
2441 /* Not allowable. */
2442 if (length == 0 || !VG_IS_PAGE_ALIGNED(start))
2443 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2444
2445 /* Ask for an advisory. If it's negative, fail immediately. */
2446 req.rkind = MFixed;
2447 req.start = start;
2448 req.len = length;
philippe515e2692012-01-08 21:01:02 +00002449 advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
sewardj45f4e7c2005-09-27 19:20:21 +00002450 if (!ok || advised != start)
2451 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2452
2453 /* We have been advised that the mapping is allowable at the
2454 specified address. So hand it off to the kernel, and propagate
2455 any resulting failure immediately. */
njnf76d27a2009-05-28 01:53:07 +00002456 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
sewardj45f4e7c2005-09-27 19:20:21 +00002457 sres = VG_(am_do_mmap_NO_NOTIFY)(
2458 start, length, prot,
2459 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2460 0, 0
2461 );
njncda2f0f2009-05-18 02:12:08 +00002462 if (sr_isError(sres))
sewardj45f4e7c2005-09-27 19:20:21 +00002463 return sres;
2464
njncda2f0f2009-05-18 02:12:08 +00002465 if (sr_Res(sres) != start) {
sewardj45f4e7c2005-09-27 19:20:21 +00002466 /* I don't think this can happen. It means the kernel made a
2467 fixed map succeed but not at the requested location. Try to
2468 repair the damage, then return saying the mapping failed. */
njncda2f0f2009-05-18 02:12:08 +00002469 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
sewardj45f4e7c2005-09-27 19:20:21 +00002470 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2471 }
2472
2473 /* Ok, the mapping succeeded. Now notify the interval map. */
2474 init_nsegment( &seg );
2475 seg.kind = SkAnonC;
2476 seg.start = start;
2477 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2478 seg.hasR = toBool(prot & VKI_PROT_READ);
2479 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2480 seg.hasX = toBool(prot & VKI_PROT_EXEC);
2481 add_segment( &seg );
2482
2483 AM_SANITY_CHECK;
2484 return sres;
2485}
2486
2487
2488/* Map anonymously at an unconstrained address for the client, and
2489 update the segment array accordingly. */
2490
Elliott Hughesa0664b92017-04-18 17:46:52 -07002491static SysRes am_mmap_anon_float_client ( SizeT length, Int prot, Bool isCH )
sewardj45f4e7c2005-09-27 19:20:21 +00002492{
2493 SysRes sres;
2494 NSegment seg;
2495 Addr advised;
2496 Bool ok;
2497 MapRequest req;
2498
2499 /* Not allowable. */
2500 if (length == 0)
2501 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2502
2503 /* Ask for an advisory. If it's negative, fail immediately. */
2504 req.rkind = MAny;
2505 req.start = 0;
2506 req.len = length;
philippe515e2692012-01-08 21:01:02 +00002507 advised = VG_(am_get_advisory)( &req, True/*forClient*/, &ok );
sewardj45f4e7c2005-09-27 19:20:21 +00002508 if (!ok)
2509 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2510
2511 /* We have been advised that the mapping is allowable at the
2512 advised address. So hand it off to the kernel, and propagate
2513 any resulting failure immediately. */
njnf76d27a2009-05-28 01:53:07 +00002514 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
sewardj45f4e7c2005-09-27 19:20:21 +00002515 sres = VG_(am_do_mmap_NO_NOTIFY)(
2516 advised, length, prot,
2517 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2518 0, 0
2519 );
njncda2f0f2009-05-18 02:12:08 +00002520 if (sr_isError(sres))
sewardj45f4e7c2005-09-27 19:20:21 +00002521 return sres;
2522
njncda2f0f2009-05-18 02:12:08 +00002523 if (sr_Res(sres) != advised) {
sewardj45f4e7c2005-09-27 19:20:21 +00002524 /* I don't think this can happen. It means the kernel made a
2525 fixed map succeed but not at the requested location. Try to
2526 repair the damage, then return saying the mapping failed. */
njncda2f0f2009-05-18 02:12:08 +00002527 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
sewardj45f4e7c2005-09-27 19:20:21 +00002528 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2529 }
2530
2531 /* Ok, the mapping succeeded. Now notify the interval map. */
2532 init_nsegment( &seg );
2533 seg.kind = SkAnonC;
2534 seg.start = advised;
2535 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2536 seg.hasR = toBool(prot & VKI_PROT_READ);
2537 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2538 seg.hasX = toBool(prot & VKI_PROT_EXEC);
Elliott Hughesa0664b92017-04-18 17:46:52 -07002539 seg.isCH = isCH;
sewardj45f4e7c2005-09-27 19:20:21 +00002540 add_segment( &seg );
2541
2542 AM_SANITY_CHECK;
2543 return sres;
2544}
2545
Elliott Hughesa0664b92017-04-18 17:46:52 -07002546SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot )
2547{
2548 return am_mmap_anon_float_client (length, prot, False /* isCH */);
2549}
sewardj45f4e7c2005-09-27 19:20:21 +00002550
2551/* Map anonymously at an unconstrained address for V, and update the
2552 segment array accordingly. This is fundamentally how V allocates
2553 itself more address space when needed. */
2554
2555SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length )
2556{
2557 SysRes sres;
2558 NSegment seg;
2559 Addr advised;
2560 Bool ok;
2561 MapRequest req;
2562
2563 /* Not allowable. */
2564 if (length == 0)
2565 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2566
2567 /* Ask for an advisory. If it's negative, fail immediately. */
2568 req.rkind = MAny;
2569 req.start = 0;
2570 req.len = length;
philippe515e2692012-01-08 21:01:02 +00002571 advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
sewardj45f4e7c2005-09-27 19:20:21 +00002572 if (!ok)
2573 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2574
njnf76d27a2009-05-28 01:53:07 +00002575// On Darwin, for anonymous maps you can pass in a tag which is used by
2576// programs like vmmap for statistical purposes.
2577#ifndef VM_TAG_VALGRIND
2578# define VM_TAG_VALGRIND 0
2579#endif
2580
sewardj45f4e7c2005-09-27 19:20:21 +00002581 /* We have been advised that the mapping is allowable at the
2582 specified address. So hand it off to the kernel, and propagate
2583 any resulting failure immediately. */
njnf76d27a2009-05-28 01:53:07 +00002584 /* GrP fixme darwin: use advisory as a hint only, otherwise syscall in
2585 another thread can pre-empt our spot. [At one point on the DARWIN
2586 branch the VKI_MAP_FIXED was commented out; unclear if this is
2587 necessary or not given the second Darwin-only call that immediately
philippe3bf117d2013-08-12 22:17:47 +00002588 follows if this one fails. --njn]
2589 Also, an inner valgrind cannot observe the mmap syscalls done by
2590 the outer valgrind. The outer Valgrind might make the mmap
2591 fail here, as the inner valgrind believes that a segment is free,
2592 while it is in fact used by the outer valgrind.
2593 So, for an inner valgrind, similarly to DARWIN, if the fixed mmap
2594 fails, retry the mmap without map fixed.
2595 This is a kludge which on linux is only activated for the inner.
2596 The state of the inner aspacemgr is not made correct by this kludge
2597 and so a.o. VG_(am_do_sync_check) could fail.
2598 A proper solution implies a better collaboration between the
2599 inner and the outer (e.g. inner VG_(am_get_advisory) should do
2600 a client request to call the outer VG_(am_get_advisory). */
sewardj45f4e7c2005-09-27 19:20:21 +00002601 sres = VG_(am_do_mmap_NO_NOTIFY)(
2602 advised, length,
2603 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
2604 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
njnf76d27a2009-05-28 01:53:07 +00002605 VM_TAG_VALGRIND, 0
sewardj45f4e7c2005-09-27 19:20:21 +00002606 );
philippe3bf117d2013-08-12 22:17:47 +00002607#if defined(VGO_darwin) || defined(ENABLE_INNER)
2608 /* Kludge on Darwin and inner linux if the fixed mmap failed. */
njnf76d27a2009-05-28 01:53:07 +00002609 if (sr_isError(sres)) {
2610 /* try again, ignoring the advisory */
2611 sres = VG_(am_do_mmap_NO_NOTIFY)(
2612 0, length,
2613 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
2614 /*VKI_MAP_FIXED|*/VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
2615 VM_TAG_VALGRIND, 0
2616 );
2617 }
2618#endif
njncda2f0f2009-05-18 02:12:08 +00002619 if (sr_isError(sres))
sewardj45f4e7c2005-09-27 19:20:21 +00002620 return sres;
2621
philippe3bf117d2013-08-12 22:17:47 +00002622#if defined(VGO_linux) && !defined(ENABLE_INNER)
2623 /* Doing the check only in linux not inner, as the below
2624 check can fail when the kludge above has been used. */
njncda2f0f2009-05-18 02:12:08 +00002625 if (sr_Res(sres) != advised) {
sewardj45f4e7c2005-09-27 19:20:21 +00002626 /* I don't think this can happen. It means the kernel made a
2627 fixed map succeed but not at the requested location. Try to
2628 repair the damage, then return saying the mapping failed. */
njncda2f0f2009-05-18 02:12:08 +00002629 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
sewardj45f4e7c2005-09-27 19:20:21 +00002630 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2631 }
njnf76d27a2009-05-28 01:53:07 +00002632#endif
sewardj45f4e7c2005-09-27 19:20:21 +00002633
2634 /* Ok, the mapping succeeded. Now notify the interval map. */
2635 init_nsegment( &seg );
2636 seg.kind = SkAnonV;
njncda2f0f2009-05-18 02:12:08 +00002637 seg.start = sr_Res(sres);
sewardj45f4e7c2005-09-27 19:20:21 +00002638 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2639 seg.hasR = True;
2640 seg.hasW = True;
2641 seg.hasX = True;
2642 add_segment( &seg );
2643
2644 AM_SANITY_CHECK;
2645 return sres;
2646}
2647
2648/* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */
2649
2650void* VG_(am_shadow_alloc)(SizeT size)
2651{
2652 SysRes sres = VG_(am_mmap_anon_float_valgrind)( size );
njncda2f0f2009-05-18 02:12:08 +00002653 return sr_isError(sres) ? NULL : (void*)sr_Res(sres);
sewardj45f4e7c2005-09-27 19:20:21 +00002654}
2655
sewardj45f4e7c2005-09-27 19:20:21 +00002656/* Map a file at an unconstrained address for V, and update the
sewardj3b290482011-05-06 21:02:55 +00002657 segment array accordingly. Use the provided flags */
sewardj45f4e7c2005-09-27 19:20:21 +00002658
sewardj3b290482011-05-06 21:02:55 +00002659static SysRes VG_(am_mmap_file_float_valgrind_flags) ( SizeT length, UInt prot,
2660 UInt flags,
2661 Int fd, Off64T offset )
sewardj45f4e7c2005-09-27 19:20:21 +00002662{
2663 SysRes sres;
2664 NSegment seg;
2665 Addr advised;
2666 Bool ok;
2667 MapRequest req;
sewardj41906002008-08-18 21:47:11 +00002668 ULong dev, ino;
tomf4c23102005-10-31 17:05:21 +00002669 UInt mode;
sewardj45f4e7c2005-09-27 19:20:21 +00002670 HChar buf[VKI_PATH_MAX];
2671
2672 /* Not allowable. */
sewardj274461d2005-10-02 17:01:41 +00002673 if (length == 0 || !VG_IS_PAGE_ALIGNED(offset))
sewardj45f4e7c2005-09-27 19:20:21 +00002674 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2675
2676 /* Ask for an advisory. If it's negative, fail immediately. */
2677 req.rkind = MAny;
2678 req.start = 0;
philippe0eb0d5a2014-02-11 23:50:16 +00002679 #if defined(VGA_arm) || defined(VGA_arm64) \
2680 || defined(VGA_mips32) || defined(VGA_mips64)
philippe53b0d9a2012-02-02 21:33:55 +00002681 aspacem_assert(VKI_SHMLBA >= VKI_PAGE_SIZE);
2682 #else
2683 aspacem_assert(VKI_SHMLBA == VKI_PAGE_SIZE);
2684 #endif
2685 if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags)) {
2686 /* arm-linux only. See ML_(generic_PRE_sys_shmat) and bug 290974 */
2687 req.len = length + VKI_SHMLBA - VKI_PAGE_SIZE;
2688 } else {
2689 req.len = length;
2690 }
philippe515e2692012-01-08 21:01:02 +00002691 advised = VG_(am_get_advisory)( &req, False/*forClient*/, &ok );
sewardj45f4e7c2005-09-27 19:20:21 +00002692 if (!ok)
2693 return VG_(mk_SysRes_Error)( VKI_EINVAL );
philippe53b0d9a2012-02-02 21:33:55 +00002694 if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & flags))
2695 advised = VG_ROUNDUP(advised, VKI_SHMLBA);
sewardj45f4e7c2005-09-27 19:20:21 +00002696
2697 /* We have been advised that the mapping is allowable at the
2698 specified address. So hand it off to the kernel, and propagate
2699 any resulting failure immediately. */
2700 sres = VG_(am_do_mmap_NO_NOTIFY)(
2701 advised, length, prot,
sewardj3b290482011-05-06 21:02:55 +00002702 flags,
sewardj45f4e7c2005-09-27 19:20:21 +00002703 fd, offset
2704 );
njncda2f0f2009-05-18 02:12:08 +00002705 if (sr_isError(sres))
sewardj45f4e7c2005-09-27 19:20:21 +00002706 return sres;
2707
njncda2f0f2009-05-18 02:12:08 +00002708 if (sr_Res(sres) != advised) {
sewardj45f4e7c2005-09-27 19:20:21 +00002709 /* I don't think this can happen. It means the kernel made a
2710 fixed map succeed but not at the requested location. Try to
2711 repair the damage, then return saying the mapping failed. */
njncda2f0f2009-05-18 02:12:08 +00002712 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
sewardj45f4e7c2005-09-27 19:20:21 +00002713 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2714 }
2715
2716 /* Ok, the mapping succeeded. Now notify the interval map. */
2717 init_nsegment( &seg );
2718 seg.kind = SkFileV;
njncda2f0f2009-05-18 02:12:08 +00002719 seg.start = sr_Res(sres);
sewardj45f4e7c2005-09-27 19:20:21 +00002720 seg.end = seg.start + VG_PGROUNDUP(length) - 1;
2721 seg.offset = offset;
2722 seg.hasR = toBool(prot & VKI_PROT_READ);
2723 seg.hasW = toBool(prot & VKI_PROT_WRITE);
2724 seg.hasX = toBool(prot & VKI_PROT_EXEC);
njndad944a2009-05-04 05:55:46 +00002725 if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) {
sewardjcf4ac712005-11-01 00:03:40 +00002726 seg.dev = dev;
2727 seg.ino = ino;
2728 seg.mode = mode;
sewardj45f4e7c2005-09-27 19:20:21 +00002729 }
njndad944a2009-05-04 05:55:46 +00002730 if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
florian4ecd4832015-04-30 17:34:04 +00002731 seg.fnIdx = ML_(am_allocate_segname)( buf );
sewardj45f4e7c2005-09-27 19:20:21 +00002732 }
2733 add_segment( &seg );
2734
2735 AM_SANITY_CHECK;
2736 return sres;
2737}
sewardj3b290482011-05-06 21:02:55 +00002738/* Map privately a file at an unconstrained address for V, and update the
2739 segment array accordingly. This is used by V for transiently
2740 mapping in object files to read their debug info. */
sewardj45f4e7c2005-09-27 19:20:21 +00002741
sewardj3b290482011-05-06 21:02:55 +00002742SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot,
2743 Int fd, Off64T offset )
2744{
2745 return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
2746 VKI_MAP_FIXED|VKI_MAP_PRIVATE,
2747 fd, offset );
2748}
2749
sewardjd6633332012-06-28 19:29:01 +00002750SysRes VG_(am_shared_mmap_file_float_valgrind)
sewardj3b290482011-05-06 21:02:55 +00002751 ( SizeT length, UInt prot, Int fd, Off64T offset )
2752{
2753 return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
2754 VKI_MAP_FIXED|VKI_MAP_SHARED,
2755 fd, offset );
2756}
sewardj45f4e7c2005-09-27 19:20:21 +00002757
Elliott Hughesa0664b92017-04-18 17:46:52 -07002758/* Similar to VG_(am_mmap_anon_float_client) but also
florian2fa66ce2015-03-07 23:01:14 +00002759 marks the segment as containing the client heap. This is for the benefit
2760 of the leak checker which needs to be able to identify such segments
2761 so as not to use them as sources of roots during leak checks. */
2762SysRes VG_(am_mmap_client_heap) ( SizeT length, Int prot )
2763{
Elliott Hughesa0664b92017-04-18 17:46:52 -07002764 return am_mmap_anon_float_client (length, prot, True /* isCH */);
florian2fa66ce2015-03-07 23:01:14 +00002765}
2766
sewardj45f4e7c2005-09-27 19:20:21 +00002767/* --- --- munmap helper --- --- */
2768
2769static
2770SysRes am_munmap_both_wrk ( /*OUT*/Bool* need_discard,
2771 Addr start, SizeT len, Bool forClient )
2772{
2773 Bool d;
2774 SysRes sres;
2775
2776 if (!VG_IS_PAGE_ALIGNED(start))
2777 goto eINVAL;
2778
2779 if (len == 0) {
2780 *need_discard = False;
2781 return VG_(mk_SysRes_Success)( 0 );
2782 }
2783
2784 if (start + len < len)
2785 goto eINVAL;
2786
2787 len = VG_PGROUNDUP(len);
2788 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2789 aspacem_assert(VG_IS_PAGE_ALIGNED(len));
2790
2791 if (forClient) {
2792 if (!VG_(am_is_valid_for_client_or_free_or_resvn)
2793 ( start, len, VKI_PROT_NONE ))
2794 goto eINVAL;
2795 } else {
philippeadfff762014-04-20 22:10:24 +00002796 if (!VG_(am_is_valid_for_valgrind)
2797 ( start, len, VKI_PROT_NONE ))
sewardj45f4e7c2005-09-27 19:20:21 +00002798 goto eINVAL;
2799 }
2800
2801 d = any_Ts_in_range( start, len );
2802
sewardj297f6b02006-10-14 22:25:30 +00002803 sres = ML_(am_do_munmap_NO_NOTIFY)( start, len );
njncda2f0f2009-05-18 02:12:08 +00002804 if (sr_isError(sres))
sewardj45f4e7c2005-09-27 19:20:21 +00002805 return sres;
2806
2807 VG_(am_notify_munmap)( start, len );
2808 AM_SANITY_CHECK;
2809 *need_discard = d;
2810 return sres;
2811
2812 eINVAL:
2813 return VG_(mk_SysRes_Error)( VKI_EINVAL );
2814}
2815
2816/* Unmap the given address range and update the segment array
2817 accordingly. This fails if the range isn't valid for the client.
2818 If *need_discard is True after a successful return, the caller
2819 should immediately discard translations from the specified address
2820 range. */
2821
2822SysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard,
2823 Addr start, SizeT len )
2824{
2825 return am_munmap_both_wrk( need_discard, start, len, True/*client*/ );
2826}
2827
2828/* Unmap the given address range and update the segment array
2829 accordingly. This fails if the range isn't valid for valgrind. */
2830
2831SysRes VG_(am_munmap_valgrind)( Addr start, SizeT len )
2832{
2833 Bool need_discard;
2834 SysRes r = am_munmap_both_wrk( &need_discard,
2835 start, len, False/*valgrind*/ );
2836 /* If this assertion fails, it means we allowed translations to be
2837 made from a V-owned section. Which shouldn't happen. */
njncda2f0f2009-05-18 02:12:08 +00002838 if (!sr_isError(r))
sewardj45f4e7c2005-09-27 19:20:21 +00002839 aspacem_assert(!need_discard);
2840 return r;
2841}
2842
2843/* Let (start,len) denote an area within a single Valgrind-owned
2844 segment (anon or file). Change the ownership of [start, start+len)
2845 to the client instead. Fails if (start,len) does not denote a
2846 suitable segment. */
2847
2848Bool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len )
2849{
2850 Int i, iLo, iHi;
2851
2852 if (len == 0)
2853 return True;
2854 if (start + len < start)
2855 return False;
2856 if (!VG_IS_PAGE_ALIGNED(start) || !VG_IS_PAGE_ALIGNED(len))
2857 return False;
2858
2859 i = find_nsegment_idx(start);
2860 if (nsegments[i].kind != SkFileV && nsegments[i].kind != SkAnonV)
2861 return False;
2862 if (start+len-1 > nsegments[i].end)
2863 return False;
2864
2865 aspacem_assert(start >= nsegments[i].start);
2866 aspacem_assert(start+len-1 <= nsegments[i].end);
2867
2868 /* This scheme is like how mprotect works: split the to-be-changed
2869 range into its own segment(s), then mess with them (it). There
2870 should be only one. */
2871 split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
2872 aspacem_assert(iLo == iHi);
2873 switch (nsegments[iLo].kind) {
2874 case SkFileV: nsegments[iLo].kind = SkFileC; break;
2875 case SkAnonV: nsegments[iLo].kind = SkAnonC; break;
2876 default: aspacem_assert(0); /* can't happen - guarded above */
2877 }
2878
2879 preen_nsegments();
2880 return True;
2881}
2882
florian2fa66ce2015-03-07 23:01:14 +00002883/* Set the 'hasT' bit on the segment containing ADDR indicating that
2884 translations have or may have been taken from this segment. ADDR is
2885 expected to belong to a client segment. */
2886void VG_(am_set_segment_hasT)( Addr addr )
sewardj716f31a2006-10-17 01:23:57 +00002887{
florian2fa66ce2015-03-07 23:01:14 +00002888 Int i = find_nsegment_idx(addr);
2889 SegKind kind = nsegments[i].kind;
2890 aspacem_assert(kind == SkAnonC || kind == SkFileC || kind == SkShmC);
2891 nsegments[i].hasT = True;
sewardj716f31a2006-10-17 01:23:57 +00002892}
2893
sewardj45f4e7c2005-09-27 19:20:21 +00002894
2895/* --- --- --- reservations --- --- --- */
2896
2897/* Create a reservation from START .. START+LENGTH-1, with the given
2898 ShrinkMode. When checking whether the reservation can be created,
2899 also ensure that at least abs(EXTRA) extra free bytes will remain
2900 above (> 0) or below (< 0) the reservation.
2901
2902 The reservation will only be created if it, plus the extra-zone,
2903 falls entirely within a single free segment. The returned Bool
2904 indicates whether the creation succeeded. */
2905
2906Bool VG_(am_create_reservation) ( Addr start, SizeT length,
2907 ShrinkMode smode, SSizeT extra )
2908{
2909 Int startI, endI;
2910 NSegment seg;
2911
2912 /* start and end, not taking into account the extra space. */
2913 Addr start1 = start;
2914 Addr end1 = start + length - 1;
2915
2916 /* start and end, taking into account the extra space. */
2917 Addr start2 = start1;
2918 Addr end2 = end1;
2919
2920 if (extra < 0) start2 += extra; // this moves it down :-)
2921 if (extra > 0) end2 += extra;
2922
2923 aspacem_assert(VG_IS_PAGE_ALIGNED(start));
2924 aspacem_assert(VG_IS_PAGE_ALIGNED(start+length));
2925 aspacem_assert(VG_IS_PAGE_ALIGNED(start2));
2926 aspacem_assert(VG_IS_PAGE_ALIGNED(end2+1));
2927
2928 startI = find_nsegment_idx( start2 );
2929 endI = find_nsegment_idx( end2 );
2930
2931 /* If the start and end points don't fall within the same (free)
2932 segment, we're hosed. This does rely on the assumption that all
2933 mergeable adjacent segments can be merged, but add_segment()
2934 should ensure that. */
2935 if (startI != endI)
2936 return False;
2937
2938 if (nsegments[startI].kind != SkFree)
2939 return False;
2940
2941 /* Looks good - make the reservation. */
2942 aspacem_assert(nsegments[startI].start <= start2);
2943 aspacem_assert(end2 <= nsegments[startI].end);
2944
2945 init_nsegment( &seg );
2946 seg.kind = SkResvn;
2947 seg.start = start1; /* NB: extra space is not included in the
2948 reservation. */
2949 seg.end = end1;
2950 seg.smode = smode;
2951 add_segment( &seg );
2952
2953 AM_SANITY_CHECK;
2954 return True;
2955}
2956
2957
florian888b8152015-02-26 16:07:12 +00002958/* ADDR is the start address of an anonymous client mapping. This fn extends
2959 the mapping by DELTA bytes, taking the space from a reservation section
sewardj45f4e7c2005-09-27 19:20:21 +00002960 which must be adjacent. If DELTA is positive, the segment is
2961 extended forwards in the address space, and the reservation must be
2962 the next one along. If DELTA is negative, the segment is extended
2963 backwards in the address space and the reservation must be the
sewardj6684d2a2005-09-28 01:46:31 +00002964 previous one. DELTA must be page aligned. abs(DELTA) must not
2965 exceed the size of the reservation segment minus one page, that is,
2966 the reservation segment after the operation must be at least one
florian888b8152015-02-26 16:07:12 +00002967 page long. The function returns a pointer to the resized segment. */
sewardj45f4e7c2005-09-27 19:20:21 +00002968
florian888b8152015-02-26 16:07:12 +00002969const NSegment *VG_(am_extend_into_adjacent_reservation_client)( Addr addr,
florian15fa8a22015-03-03 14:56:17 +00002970 SSizeT delta,
2971 Bool *overflow)
sewardj45f4e7c2005-09-27 19:20:21 +00002972{
2973 Int segA, segR;
2974 UInt prot;
2975 SysRes sres;
2976
florian15fa8a22015-03-03 14:56:17 +00002977 *overflow = False;
2978
florian888b8152015-02-26 16:07:12 +00002979 segA = find_nsegment_idx(addr);
2980 aspacem_assert(nsegments[segA].kind == SkAnonC);
sewardj45f4e7c2005-09-27 19:20:21 +00002981
2982 if (delta == 0)
florian888b8152015-02-26 16:07:12 +00002983 return nsegments + segA;
sewardj45f4e7c2005-09-27 19:20:21 +00002984
2985 prot = (nsegments[segA].hasR ? VKI_PROT_READ : 0)
2986 | (nsegments[segA].hasW ? VKI_PROT_WRITE : 0)
2987 | (nsegments[segA].hasX ? VKI_PROT_EXEC : 0);
2988
2989 aspacem_assert(VG_IS_PAGE_ALIGNED(delta<0 ? -delta : delta));
2990
2991 if (delta > 0) {
2992
2993 /* Extending the segment forwards. */
2994 segR = segA+1;
2995 if (segR >= nsegments_used
2996 || nsegments[segR].kind != SkResvn
florian15fa8a22015-03-03 14:56:17 +00002997 || nsegments[segR].smode != SmLower)
2998 return NULL;
2999
3000 if (delta + VKI_PAGE_SIZE
3001 > (nsegments[segR].end - nsegments[segR].start + 1)) {
3002 *overflow = True;
3003 return NULL;
3004 }
sewardj45f4e7c2005-09-27 19:20:21 +00003005
3006 /* Extend the kernel's mapping. */
njnf76d27a2009-05-28 01:53:07 +00003007 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
sewardj45f4e7c2005-09-27 19:20:21 +00003008 sres = VG_(am_do_mmap_NO_NOTIFY)(
3009 nsegments[segR].start, delta,
3010 prot,
3011 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
3012 0, 0
3013 );
njncda2f0f2009-05-18 02:12:08 +00003014 if (sr_isError(sres))
florian888b8152015-02-26 16:07:12 +00003015 return NULL; /* kernel bug if this happens? */
njncda2f0f2009-05-18 02:12:08 +00003016 if (sr_Res(sres) != nsegments[segR].start) {
sewardj45f4e7c2005-09-27 19:20:21 +00003017 /* kernel bug if this happens? */
njncda2f0f2009-05-18 02:12:08 +00003018 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
florian888b8152015-02-26 16:07:12 +00003019 return NULL;
sewardj45f4e7c2005-09-27 19:20:21 +00003020 }
3021
3022 /* Ok, success with the kernel. Update our structures. */
florian3bfb9142015-07-06 20:22:16 +00003023 nsegments[segR].start += delta;
3024 nsegments[segA].end += delta;
3025 aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
sewardj45f4e7c2005-09-27 19:20:21 +00003026
3027 } else {
3028
3029 /* Extending the segment backwards. */
3030 delta = -delta;
3031 aspacem_assert(delta > 0);
3032
3033 segR = segA-1;
3034 if (segR < 0
3035 || nsegments[segR].kind != SkResvn
florian15fa8a22015-03-03 14:56:17 +00003036 || nsegments[segR].smode != SmUpper)
3037 return NULL;
3038
3039 if (delta + VKI_PAGE_SIZE
3040 > (nsegments[segR].end - nsegments[segR].start + 1)) {
3041 *overflow = True;
3042 return NULL;
3043 }
sewardj45f4e7c2005-09-27 19:20:21 +00003044
3045 /* Extend the kernel's mapping. */
njnf76d27a2009-05-28 01:53:07 +00003046 // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
sewardj45f4e7c2005-09-27 19:20:21 +00003047 sres = VG_(am_do_mmap_NO_NOTIFY)(
3048 nsegments[segA].start-delta, delta,
3049 prot,
3050 VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
3051 0, 0
3052 );
njncda2f0f2009-05-18 02:12:08 +00003053 if (sr_isError(sres))
florian888b8152015-02-26 16:07:12 +00003054 return NULL; /* kernel bug if this happens? */
njncda2f0f2009-05-18 02:12:08 +00003055 if (sr_Res(sres) != nsegments[segA].start-delta) {
sewardj45f4e7c2005-09-27 19:20:21 +00003056 /* kernel bug if this happens? */
njncda2f0f2009-05-18 02:12:08 +00003057 (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), delta );
florian888b8152015-02-26 16:07:12 +00003058 return NULL;
sewardj45f4e7c2005-09-27 19:20:21 +00003059 }
3060
3061 /* Ok, success with the kernel. Update our structures. */
florian3bfb9142015-07-06 20:22:16 +00003062 nsegments[segR].end -= delta;
3063 nsegments[segA].start -= delta;
3064 aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
sewardj45f4e7c2005-09-27 19:20:21 +00003065 }
3066
3067 AM_SANITY_CHECK;
florian888b8152015-02-26 16:07:12 +00003068 return nsegments + segA;
sewardj45f4e7c2005-09-27 19:20:21 +00003069}
3070
3071
3072/* --- --- --- resizing/move a mapping --- --- --- */
3073
njnf76d27a2009-05-28 01:53:07 +00003074#if HAVE_MREMAP
3075
floriandd7318b2015-02-25 10:06:06 +00003076/* This function grows a client mapping in place into an adjacent free segment.
3077 ADDR is the client mapping's start address and DELTA, which must be page
3078 aligned, is the growth amount. The function returns a pointer to the
3079 resized segment. The function is used in support of mremap. */
3080const NSegment *VG_(am_extend_map_client)( Addr addr, SizeT delta )
sewardj45f4e7c2005-09-27 19:20:21 +00003081{
3082 Addr xStart;
3083 SysRes sres;
sewardj45f4e7c2005-09-27 19:20:21 +00003084
sewardj63a622f2006-08-16 14:22:29 +00003085 if (0)
3086 VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) BEFORE");
3087
floriandd7318b2015-02-25 10:06:06 +00003088 /* Get the client segment */
3089 Int ix = find_nsegment_idx(addr);
3090 aspacem_assert(ix >= 0 && ix < nsegments_used);
sewardj45f4e7c2005-09-27 19:20:21 +00003091
floriandd7318b2015-02-25 10:06:06 +00003092 NSegment *seg = nsegments + ix;
3093
florian7a5681f2015-05-12 21:52:08 +00003094 aspacem_assert(seg->kind == SkFileC || seg->kind == SkAnonC ||
3095 seg->kind == SkShmC);
floriandd7318b2015-02-25 10:06:06 +00003096 aspacem_assert(delta > 0 && VG_IS_PAGE_ALIGNED(delta)) ;
sewardj45f4e7c2005-09-27 19:20:21 +00003097
3098 xStart = seg->end+1;
floriandd7318b2015-02-25 10:06:06 +00003099 aspacem_assert(xStart + delta >= delta); // no wrap-around
sewardj45f4e7c2005-09-27 19:20:21 +00003100
floriandd7318b2015-02-25 10:06:06 +00003101 /* The segment following the client segment must be a free segment and
3102 it must be large enough to cover the additional memory. */
3103 NSegment *segf = seg + 1;
3104 aspacem_assert(segf->kind == SkFree);
3105 aspacem_assert(segf->start == xStart);
3106 aspacem_assert(xStart + delta - 1 <= segf->end);
3107
3108 SizeT seg_old_len = seg->end + 1 - seg->start;
sewardj45f4e7c2005-09-27 19:20:21 +00003109
3110 AM_SANITY_CHECK;
sewardj297f6b02006-10-14 22:25:30 +00003111 sres = ML_(am_do_extend_mapping_NO_NOTIFY)( seg->start,
3112 seg_old_len,
3113 seg_old_len + delta );
njncda2f0f2009-05-18 02:12:08 +00003114 if (sr_isError(sres)) {
sewardj45f4e7c2005-09-27 19:20:21 +00003115 AM_SANITY_CHECK;
floriandd7318b2015-02-25 10:06:06 +00003116 return NULL;
sewardj63a622f2006-08-16 14:22:29 +00003117 } else {
3118 /* the area must not have moved */
njncda2f0f2009-05-18 02:12:08 +00003119 aspacem_assert(sr_Res(sres) == seg->start);
sewardj45f4e7c2005-09-27 19:20:21 +00003120 }
3121
floriandd7318b2015-02-25 10:06:06 +00003122 NSegment seg_copy = *seg;
sewardj45f4e7c2005-09-27 19:20:21 +00003123 seg_copy.end += delta;
3124 add_segment( &seg_copy );
3125
sewardj63a622f2006-08-16 14:22:29 +00003126 if (0)
3127 VG_(am_show_nsegments)(0, "VG_(am_extend_map_client) AFTER");
3128
sewardj45f4e7c2005-09-27 19:20:21 +00003129 AM_SANITY_CHECK;
floriandd7318b2015-02-25 10:06:06 +00003130 return nsegments + find_nsegment_idx(addr);
sewardj45f4e7c2005-09-27 19:20:21 +00003131}
3132
3133
3134/* Remap the old address range to the new address range. Fails if any
3135 parameter is not page aligned, if the either size is zero, if any
3136 wraparound is implied, if the old address range does not fall
3137 entirely within a single segment, if the new address range overlaps
3138 with the old one, or if the old address range is not a valid client
3139 mapping. If *need_discard is True after a successful return, the
3140 caller should immediately discard translations from both specified
3141 address ranges. */
3142
3143Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
3144 Addr old_addr, SizeT old_len,
3145 Addr new_addr, SizeT new_len )
3146{
3147 Int iLo, iHi;
3148 SysRes sres;
tomfcb3bc92006-05-22 11:20:15 +00003149 NSegment seg;
sewardj45f4e7c2005-09-27 19:20:21 +00003150
3151 if (old_len == 0 || new_len == 0)
3152 return False;
3153
3154 if (!VG_IS_PAGE_ALIGNED(old_addr) || !VG_IS_PAGE_ALIGNED(old_len)
3155 || !VG_IS_PAGE_ALIGNED(new_addr) || !VG_IS_PAGE_ALIGNED(new_len))
3156 return False;
3157
3158 if (old_addr + old_len < old_addr
3159 || new_addr + new_len < new_addr)
3160 return False;
3161
3162 if (old_addr + old_len - 1 < new_addr
3163 || new_addr + new_len - 1 < old_addr) {
3164 /* no overlap */
3165 } else
3166 return False;
3167
3168 iLo = find_nsegment_idx( old_addr );
3169 iHi = find_nsegment_idx( old_addr + old_len - 1 );
3170 if (iLo != iHi)
3171 return False;
3172
florian7a5681f2015-05-12 21:52:08 +00003173 if (nsegments[iLo].kind != SkFileC && nsegments[iLo].kind != SkAnonC &&
3174 nsegments[iLo].kind != SkShmC)
sewardj45f4e7c2005-09-27 19:20:21 +00003175 return False;
3176
sewardj297f6b02006-10-14 22:25:30 +00003177 sres = ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)
3178 ( old_addr, old_len, new_addr, new_len );
njncda2f0f2009-05-18 02:12:08 +00003179 if (sr_isError(sres)) {
sewardj45f4e7c2005-09-27 19:20:21 +00003180 AM_SANITY_CHECK;
3181 return False;
sewardjee2de2c2006-08-16 15:06:53 +00003182 } else {
njncda2f0f2009-05-18 02:12:08 +00003183 aspacem_assert(sr_Res(sres) == new_addr);
sewardj45f4e7c2005-09-27 19:20:21 +00003184 }
3185
3186 *need_discard = any_Ts_in_range( old_addr, old_len )
3187 || any_Ts_in_range( new_addr, new_len );
3188
tomfcb3bc92006-05-22 11:20:15 +00003189 seg = nsegments[iLo];
3190
3191 /* Mark the new area based on the old seg. */
3192 if (seg.kind == SkFileC) {
3193 seg.offset += ((ULong)old_addr) - ((ULong)seg.start);
tomfcb3bc92006-05-22 11:20:15 +00003194 }
3195 seg.start = new_addr;
3196 seg.end = new_addr + new_len - 1;
3197 add_segment( &seg );
sewardj45f4e7c2005-09-27 19:20:21 +00003198
3199 /* Create a free hole in the old location. */
3200 init_nsegment( &seg );
sewardj45f4e7c2005-09-27 19:20:21 +00003201 seg.start = old_addr;
3202 seg.end = old_addr + old_len - 1;
sewardj613a9f22006-08-16 01:48:19 +00003203 /* See comments in VG_(am_notify_munmap) about this SkResvn vs
3204 SkFree thing. */
3205 if (old_addr > aspacem_maxAddr
3206 && /* check previous comparison is meaningful */
3207 aspacem_maxAddr < Addr_MAX)
3208 seg.kind = SkResvn;
3209 else
3210 seg.kind = SkFree;
3211
sewardj45f4e7c2005-09-27 19:20:21 +00003212 add_segment( &seg );
3213
sewardj45f4e7c2005-09-27 19:20:21 +00003214 AM_SANITY_CHECK;
3215 return True;
3216}
3217
njnf76d27a2009-05-28 01:53:07 +00003218#endif // HAVE_MREMAP
3219
3220
bartc401ae72009-08-23 11:17:25 +00003221#if defined(VGO_linux)
3222
sewardj45f4e7c2005-09-27 19:20:21 +00003223/*-----------------------------------------------------------------*/
3224/*--- ---*/
sewardjcb249ab2005-09-28 09:37:16 +00003225/*--- A simple parser for /proc/self/maps on Linux 2.4.X/2.6.X. ---*/
3226/*--- Almost completely independent of the stuff above. The ---*/
3227/*--- only function it 'exports' to the code above this comment ---*/
3228/*--- is parse_procselfmaps. ---*/
3229/*--- ---*/
3230/*-----------------------------------------------------------------*/
3231
sewardj38a21ac2010-01-03 10:14:03 +00003232/*------BEGIN-procmaps-parser-for-Linux--------------------------*/
3233
sewardjcb249ab2005-09-28 09:37:16 +00003234/* Size of a smallish table used to read /proc/self/map entries. */
3235#define M_PROCMAP_BUF 100000
3236
3237/* static ... to keep it out of the stack frame. */
floriandbb35842012-10-27 18:39:11 +00003238static HChar procmap_buf[M_PROCMAP_BUF];
sewardjcb249ab2005-09-28 09:37:16 +00003239
3240/* Records length of /proc/self/maps read into procmap_buf. */
3241static Int buf_n_tot;
3242
3243/* Helper fns. */
3244
floriandbb35842012-10-27 18:39:11 +00003245static Int hexdigit ( HChar c )
sewardjcb249ab2005-09-28 09:37:16 +00003246{
3247 if (c >= '0' && c <= '9') return (Int)(c - '0');
3248 if (c >= 'a' && c <= 'f') return 10 + (Int)(c - 'a');
3249 if (c >= 'A' && c <= 'F') return 10 + (Int)(c - 'A');
3250 return -1;
3251}
3252
floriandbb35842012-10-27 18:39:11 +00003253static Int decdigit ( HChar c )
sewardjcb249ab2005-09-28 09:37:16 +00003254{
3255 if (c >= '0' && c <= '9') return (Int)(c - '0');
3256 return -1;
3257}
3258
floriandbb35842012-10-27 18:39:11 +00003259static Int readchar ( const HChar* buf, HChar* ch )
sewardjcb249ab2005-09-28 09:37:16 +00003260{
3261 if (*buf == 0) return 0;
3262 *ch = *buf;
3263 return 1;
3264}
3265
floriandbb35842012-10-27 18:39:11 +00003266static Int readhex ( const HChar* buf, UWord* val )
sewardjcb249ab2005-09-28 09:37:16 +00003267{
sewardj274461d2005-10-02 17:01:41 +00003268 /* Read a word-sized hex number. */
3269 Int n = 0;
3270 *val = 0;
3271 while (hexdigit(*buf) >= 0) {
3272 *val = (*val << 4) + hexdigit(*buf);
3273 n++; buf++;
3274 }
3275 return n;
3276}
3277
floriandbb35842012-10-27 18:39:11 +00003278static Int readhex64 ( const HChar* buf, ULong* val )
sewardj274461d2005-10-02 17:01:41 +00003279{
3280 /* Read a potentially 64-bit hex number. */
sewardjcb249ab2005-09-28 09:37:16 +00003281 Int n = 0;
3282 *val = 0;
3283 while (hexdigit(*buf) >= 0) {
3284 *val = (*val << 4) + hexdigit(*buf);
3285 n++; buf++;
3286 }
3287 return n;
3288}
3289
floriandbb35842012-10-27 18:39:11 +00003290static Int readdec64 ( const HChar* buf, ULong* val )
sewardjcb249ab2005-09-28 09:37:16 +00003291{
3292 Int n = 0;
3293 *val = 0;
florian54212b62011-12-26 18:30:18 +00003294 while (decdigit(*buf) >= 0) {
sewardjcb249ab2005-09-28 09:37:16 +00003295 *val = (*val * 10) + decdigit(*buf);
3296 n++; buf++;
3297 }
3298 return n;
3299}
3300
3301
3302/* Get the contents of /proc/self/maps into a static buffer. If
3303 there's a syntax error, it won't fit, or other failure, just
3304 abort. */
3305
3306static void read_procselfmaps_into_buf ( void )
3307{
3308 Int n_chunk;
3309 SysRes fd;
3310
3311 /* Read the initial memory mapping from the /proc filesystem. */
sewardj297f6b02006-10-14 22:25:30 +00003312 fd = ML_(am_open)( "/proc/self/maps", VKI_O_RDONLY, 0 );
njncda2f0f2009-05-18 02:12:08 +00003313 if (sr_isError(fd))
sewardj297f6b02006-10-14 22:25:30 +00003314 ML_(am_barf)("can't open /proc/self/maps");
sewardjcb249ab2005-09-28 09:37:16 +00003315
3316 buf_n_tot = 0;
3317 do {
njncda2f0f2009-05-18 02:12:08 +00003318 n_chunk = ML_(am_read)( sr_Res(fd), &procmap_buf[buf_n_tot],
sewardjcb249ab2005-09-28 09:37:16 +00003319 M_PROCMAP_BUF - buf_n_tot );
sewardj297f6b02006-10-14 22:25:30 +00003320 if (n_chunk >= 0)
3321 buf_n_tot += n_chunk;
sewardjcb249ab2005-09-28 09:37:16 +00003322 } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
3323
njncda2f0f2009-05-18 02:12:08 +00003324 ML_(am_close)(sr_Res(fd));
sewardjcb249ab2005-09-28 09:37:16 +00003325
3326 if (buf_n_tot >= M_PROCMAP_BUF-5)
sewardj297f6b02006-10-14 22:25:30 +00003327 ML_(am_barf_toolow)("M_PROCMAP_BUF");
sewardjcb249ab2005-09-28 09:37:16 +00003328 if (buf_n_tot == 0)
sewardj297f6b02006-10-14 22:25:30 +00003329 ML_(am_barf)("I/O error on /proc/self/maps");
sewardjcb249ab2005-09-28 09:37:16 +00003330
3331 procmap_buf[buf_n_tot] = 0;
3332}
3333
3334/* Parse /proc/self/maps. For each map entry, call
3335 record_mapping, passing it, in this order:
3336
3337 start address in memory
3338 length
3339 page protections (using the VKI_PROT_* flags)
3340 mapped file device and inode
3341 offset in file, or zero if no file
3342 filename, zero terminated, or NULL if no file
3343
3344 So the sig of the called fn might be
3345
3346 void (*record_mapping)( Addr start, SizeT size, UInt prot,
3347 UInt dev, UInt info,
3348 ULong foffset, UChar* filename )
3349
3350 Note that the supplied filename is transiently stored; record_mapping
3351 should make a copy if it wants to keep it.
3352
3353 Nb: it is important that this function does not alter the contents of
3354 procmap_buf!
3355*/
3356static void parse_procselfmaps (
3357 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
njnc4431bf2009-01-15 21:29:24 +00003358 ULong dev, ULong ino, Off64T offset,
floriandbb35842012-10-27 18:39:11 +00003359 const HChar* filename ),
sewardjcb249ab2005-09-28 09:37:16 +00003360 void (*record_gap)( Addr addr, SizeT len )
3361 )
3362{
3363 Int i, j, i_eol;
3364 Addr start, endPlusOne, gapStart;
floriandbb35842012-10-27 18:39:11 +00003365 HChar* filename;
3366 HChar rr, ww, xx, pp, ch, tmp;
sewardj41906002008-08-18 21:47:11 +00003367 UInt prot;
3368 UWord maj, min;
3369 ULong foffset, dev, ino;
sewardjcb249ab2005-09-28 09:37:16 +00003370
sewardj4c3faae2006-03-15 11:50:32 +00003371 foffset = ino = 0; /* keep gcc-4.1.0 happy */
3372
sewardjcb249ab2005-09-28 09:37:16 +00003373 read_procselfmaps_into_buf();
3374
3375 aspacem_assert('\0' != procmap_buf[0] && 0 != buf_n_tot);
3376
3377 if (0)
3378 VG_(debugLog)(0, "procselfmaps", "raw:\n%s\n", procmap_buf);
3379
3380 /* Ok, it's safely aboard. Parse the entries. */
3381 i = 0;
3382 gapStart = Addr_MIN;
3383 while (True) {
3384 if (i >= buf_n_tot) break;
3385
3386 /* Read (without fscanf :) the pattern %16x-%16x %c%c%c%c %16x %2x:%2x %d */
3387 j = readhex(&procmap_buf[i], &start);
3388 if (j > 0) i += j; else goto syntaxerror;
3389 j = readchar(&procmap_buf[i], &ch);
3390 if (j == 1 && ch == '-') i += j; else goto syntaxerror;
3391 j = readhex(&procmap_buf[i], &endPlusOne);
3392 if (j > 0) i += j; else goto syntaxerror;
3393
3394 j = readchar(&procmap_buf[i], &ch);
3395 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3396
3397 j = readchar(&procmap_buf[i], &rr);
3398 if (j == 1 && (rr == 'r' || rr == '-')) i += j; else goto syntaxerror;
3399 j = readchar(&procmap_buf[i], &ww);
3400 if (j == 1 && (ww == 'w' || ww == '-')) i += j; else goto syntaxerror;
3401 j = readchar(&procmap_buf[i], &xx);
3402 if (j == 1 && (xx == 'x' || xx == '-')) i += j; else goto syntaxerror;
3403 /* This field is the shared/private flag */
3404 j = readchar(&procmap_buf[i], &pp);
3405 if (j == 1 && (pp == 'p' || pp == '-' || pp == 's'))
3406 i += j; else goto syntaxerror;
3407
3408 j = readchar(&procmap_buf[i], &ch);
3409 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3410
sewardj274461d2005-10-02 17:01:41 +00003411 j = readhex64(&procmap_buf[i], &foffset);
sewardjcb249ab2005-09-28 09:37:16 +00003412 if (j > 0) i += j; else goto syntaxerror;
3413
3414 j = readchar(&procmap_buf[i], &ch);
3415 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3416
3417 j = readhex(&procmap_buf[i], &maj);
3418 if (j > 0) i += j; else goto syntaxerror;
3419 j = readchar(&procmap_buf[i], &ch);
3420 if (j == 1 && ch == ':') i += j; else goto syntaxerror;
3421 j = readhex(&procmap_buf[i], &min);
3422 if (j > 0) i += j; else goto syntaxerror;
3423
3424 j = readchar(&procmap_buf[i], &ch);
3425 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
3426
sewardj41906002008-08-18 21:47:11 +00003427 j = readdec64(&procmap_buf[i], &ino);
sewardjcb249ab2005-09-28 09:37:16 +00003428 if (j > 0) i += j; else goto syntaxerror;
3429
3430 goto read_line_ok;
3431
3432 syntaxerror:
3433 VG_(debugLog)(0, "Valgrind:",
3434 "FATAL: syntax error reading /proc/self/maps\n");
3435 { Int k, m;
3436 HChar buf50[51];
3437 m = 0;
3438 buf50[m] = 0;
3439 k = i - 50;
3440 if (k < 0) k = 0;
3441 for (; k <= i; k++) {
3442 buf50[m] = procmap_buf[k];
3443 buf50[m+1] = 0;
3444 if (m < 50-1) m++;
3445 }
3446 VG_(debugLog)(0, "procselfmaps", "Last 50 chars: '%s'\n", buf50);
3447 }
sewardj297f6b02006-10-14 22:25:30 +00003448 ML_(am_exit)(1);
sewardjcb249ab2005-09-28 09:37:16 +00003449
3450 read_line_ok:
3451
florianbd28c5e2011-12-26 18:35:29 +00003452 aspacem_assert(i < buf_n_tot);
sewardjcb249ab2005-09-28 09:37:16 +00003453
florianbd28c5e2011-12-26 18:35:29 +00003454 /* Try and find the name of the file mapped to this segment, if
3455 it exists. Note that file names can contain spaces. */
3456
3457 // Move i to the next non-space char, which should be either a '/',
3458 // a '[', or a newline.
3459 while (procmap_buf[i] == ' ') i++;
sewardjcb249ab2005-09-28 09:37:16 +00003460
3461 // Move i_eol to the end of the line.
3462 i_eol = i;
florianbd28c5e2011-12-26 18:35:29 +00003463 while (procmap_buf[i_eol] != '\n') i_eol++;
sewardjcb249ab2005-09-28 09:37:16 +00003464
3465 // If there's a filename...
florianbd28c5e2011-12-26 18:35:29 +00003466 if (procmap_buf[i] == '/') {
sewardjcb249ab2005-09-28 09:37:16 +00003467 /* Minor hack: put a '\0' at the filename end for the call to
3468 'record_mapping', then restore the old char with 'tmp'. */
3469 filename = &procmap_buf[i];
3470 tmp = filename[i_eol - i];
3471 filename[i_eol - i] = '\0';
3472 } else {
3473 tmp = 0;
3474 filename = NULL;
3475 foffset = 0;
3476 }
3477
3478 prot = 0;
3479 if (rr == 'r') prot |= VKI_PROT_READ;
3480 if (ww == 'w') prot |= VKI_PROT_WRITE;
3481 if (xx == 'x') prot |= VKI_PROT_EXEC;
3482
tom99ffec42005-11-13 16:52:56 +00003483 /* Linux has two ways to encode a device number when it
3484 is exposed to user space (via fstat etc). The old way
3485 is the traditional unix scheme that produces a 16 bit
3486 device number with the top 8 being the major number and
3487 the bottom 8 the minor number.
3488
3489 The new scheme allows for a 12 bit major number and
3490 a 20 bit minor number by using a 32 bit device number
3491 and putting the top 12 bits of the minor number into
3492 the top 12 bits of the device number thus leaving an
3493 extra 4 bits for the major number.
3494
3495 If the minor and major number are both single byte
3496 values then both schemes give the same result so we
3497 use the new scheme here in case either number is
3498 outside the 0-255 range and then use fstat64 when
3499 available (or fstat on 64 bit systems) so that we
3500 should always have a new style device number and
3501 everything should match. */
3502 dev = (min & 0xff) | (maj << 8) | ((min & ~0xff) << 12);
3503
sewardjcb249ab2005-09-28 09:37:16 +00003504 if (record_gap && gapStart < start)
3505 (*record_gap) ( gapStart, start-gapStart );
3506
sewardje6bbc362007-01-07 02:03:01 +00003507 if (record_mapping && start < endPlusOne)
3508 (*record_mapping) ( start, endPlusOne-start,
3509 prot, dev, ino,
3510 foffset, filename );
sewardjcb249ab2005-09-28 09:37:16 +00003511
3512 if ('\0' != tmp) {
3513 filename[i_eol - i] = tmp;
3514 }
3515
3516 i = i_eol + 1;
3517 gapStart = endPlusOne;
3518 }
3519
sewardj38a21ac2010-01-03 10:14:03 +00003520# if defined(VGP_arm_linux)
3521 /* ARM puts code at the end of memory that contains processor
3522 specific stuff (cmpxchg, getting the thread local storage, etc.)
3523 This isn't specified in /proc/self/maps, so do it here. This
3524 kludgery causes the view of memory, as presented to
3525 record_gap/record_mapping, to actually reflect reality. IMO
3526 (JRS, 2010-Jan-03) the fact that /proc/.../maps does not list
3527 the commpage should be regarded as a bug in the kernel. */
3528 { const Addr commpage_start = ARM_LINUX_FAKE_COMMPAGE_START;
3529 const Addr commpage_end1 = ARM_LINUX_FAKE_COMMPAGE_END1;
3530 if (gapStart < commpage_start) {
3531 if (record_gap)
3532 (*record_gap)( gapStart, commpage_start - gapStart );
3533 if (record_mapping)
3534 (*record_mapping)( commpage_start, commpage_end1 - commpage_start,
3535 VKI_PROT_READ|VKI_PROT_EXEC,
3536 0/*dev*/, 0/*ino*/, 0/*foffset*/,
3537 NULL);
3538 gapStart = commpage_end1;
3539 }
3540 }
3541# endif
3542
sewardjcb249ab2005-09-28 09:37:16 +00003543 if (record_gap && gapStart < Addr_MAX)
3544 (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
3545}
3546
sewardj38a21ac2010-01-03 10:14:03 +00003547/*------END-procmaps-parser-for-Linux----------------------------*/
3548
3549/*------BEGIN-procmaps-parser-for-Darwin-------------------------*/
3550
njnf76d27a2009-05-28 01:53:07 +00003551#elif defined(VGO_darwin)
3552#include <mach/mach.h>
3553#include <mach/mach_vm.h>
3554
3555static unsigned int mach2vki(unsigned int vm_prot)
3556{
3557 return
3558 ((vm_prot & VM_PROT_READ) ? VKI_PROT_READ : 0) |
3559 ((vm_prot & VM_PROT_WRITE) ? VKI_PROT_WRITE : 0) |
3560 ((vm_prot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC : 0) ;
3561}
3562
3563static UInt stats_machcalls = 0;
3564
3565static void parse_procselfmaps (
3566 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
3567 ULong dev, ULong ino, Off64T offset,
floriandbb35842012-10-27 18:39:11 +00003568 const HChar* filename ),
njnf76d27a2009-05-28 01:53:07 +00003569 void (*record_gap)( Addr addr, SizeT len )
3570 )
3571{
3572 vm_address_t iter;
3573 unsigned int depth;
3574 vm_address_t last;
3575
3576 iter = 0;
3577 depth = 0;
3578 last = 0;
3579 while (1) {
3580 mach_vm_address_t addr = iter;
3581 mach_vm_size_t size;
3582 vm_region_submap_short_info_data_64_t info;
3583 kern_return_t kr;
3584
3585 while (1) {
3586 mach_msg_type_number_t info_count
3587 = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
3588 stats_machcalls++;
3589 kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth,
3590 (vm_region_info_t)&info, &info_count);
3591 if (kr)
3592 return;
3593 if (info.is_submap) {
3594 depth++;
3595 continue;
3596 }
3597 break;
3598 }
3599 iter = addr + size;
3600
3601 if (addr > last && record_gap) {
3602 (*record_gap)(last, addr - last);
3603 }
3604 if (record_mapping) {
3605 (*record_mapping)(addr, size, mach2vki(info.protection),
3606 0, 0, info.offset, NULL);
3607 }
3608 last = addr + size;
3609 }
3610
3611 if ((Addr)-1 > last && record_gap)
3612 (*record_gap)(last, (Addr)-1 - last);
3613}
3614
sewardj9edd09f2010-10-07 10:01:40 +00003615// Urr. So much for thread safety.
3616static Bool css_overflowed;
3617static ChangedSeg* css_local;
3618static Int css_size_local;
3619static Int css_used_local;
njnf76d27a2009-05-28 01:53:07 +00003620
sewardje139a462012-03-07 13:28:05 +00003621static Addr Addr__max ( Addr a, Addr b ) { return a > b ? a : b; }
3622static Addr Addr__min ( Addr a, Addr b ) { return a < b ? a : b; }
3623
njnf76d27a2009-05-28 01:53:07 +00003624static void add_mapping_callback(Addr addr, SizeT len, UInt prot,
3625 ULong dev, ULong ino, Off64T offset,
floriandbb35842012-10-27 18:39:11 +00003626 const HChar *filename)
njnf76d27a2009-05-28 01:53:07 +00003627{
3628 // derived from sync_check_mapping_callback()
3629
sewardje139a462012-03-07 13:28:05 +00003630 /* JRS 2012-Mar-07: this all seems very dubious to me. It would be
3631 safer to see if we can find, in V's segment collection, one
3632 single segment that completely covers the range [addr, +len)
3633 (and possibly more), and that has the exact same other
3634 properties (prot, dev, ino, offset, etc) as the data presented
3635 here. If found, we just skip. Otherwise add the data presented
3636 here into css_local[]. */
3637
njnf76d27a2009-05-28 01:53:07 +00003638 Int iLo, iHi, i;
3639
3640 if (len == 0) return;
3641
3642 /* The kernel should not give us wraparounds. */
3643 aspacem_assert(addr <= addr + len - 1);
3644
3645 iLo = find_nsegment_idx( addr );
3646 iHi = find_nsegment_idx( addr + len - 1 );
3647
njnf76d27a2009-05-28 01:53:07 +00003648 /* NSegments iLo .. iHi inclusive should agree with the presented
3649 data. */
3650 for (i = iLo; i <= iHi; i++) {
3651
3652 UInt seg_prot;
3653
3654 if (nsegments[i].kind == SkAnonV || nsegments[i].kind == SkFileV) {
3655 /* Ignore V regions */
3656 continue;
3657 }
3658 else if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn) {
sewardje139a462012-03-07 13:28:05 +00003659 /* Add mapping for SkResvn regions */
njnf76d27a2009-05-28 01:53:07 +00003660 ChangedSeg* cs = &css_local[css_used_local];
njnfd1b4612009-06-24 08:32:42 +00003661 if (css_used_local < css_size_local) {
3662 cs->is_added = True;
3663 cs->start = addr;
3664 cs->end = addr + len - 1;
3665 cs->prot = prot;
3666 cs->offset = offset;
3667 css_used_local++;
3668 } else {
3669 css_overflowed = True;
3670 }
njnf76d27a2009-05-28 01:53:07 +00003671 return;
3672
sewardjf1a9bd22013-09-02 13:02:02 +00003673 }
3674 else if (nsegments[i].kind == SkAnonC ||
3675 nsegments[i].kind == SkFileC ||
3676 nsegments[i].kind == SkShmC)
njnf76d27a2009-05-28 01:53:07 +00003677 {
3678 /* Check permissions on client regions */
3679 // GrP fixme
3680 seg_prot = 0;
3681 if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
3682 if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
3683# if defined(VGA_x86)
3684 // GrP fixme sloppyXcheck
3685 // darwin: kernel X ignored and spuriously changes? (vm_copy)
3686 seg_prot |= (prot & VKI_PROT_EXEC);
3687# else
3688 if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
3689# endif
3690 if (seg_prot != prot) {
3691 if (VG_(clo_trace_syscalls))
sewardj08a63192010-07-01 11:42:22 +00003692 VG_(debugLog)(0,"aspacem","region %p..%p permission "
3693 "mismatch (kernel %x, V %x)\n",
njnf76d27a2009-05-28 01:53:07 +00003694 (void*)nsegments[i].start,
3695 (void*)(nsegments[i].end+1), prot, seg_prot);
sewardjf1a9bd22013-09-02 13:02:02 +00003696 /* Add mapping for regions with protection changes */
3697 ChangedSeg* cs = &css_local[css_used_local];
3698 if (css_used_local < css_size_local) {
3699 cs->is_added = True;
3700 cs->start = addr;
3701 cs->end = addr + len - 1;
3702 cs->prot = prot;
3703 cs->offset = offset;
3704 css_used_local++;
3705 } else {
3706 css_overflowed = True;
3707 }
3708 return;
3709
njnf76d27a2009-05-28 01:53:07 +00003710 }
3711
3712 } else {
3713 aspacem_assert(0);
3714 }
3715 }
3716}
3717
3718static void remove_mapping_callback(Addr addr, SizeT len)
3719{
3720 // derived from sync_check_gap_callback()
3721
3722 Int iLo, iHi, i;
3723
3724 if (len == 0)
3725 return;
3726
3727 /* The kernel should not give us wraparounds. */
3728 aspacem_assert(addr <= addr + len - 1);
3729
3730 iLo = find_nsegment_idx( addr );
3731 iHi = find_nsegment_idx( addr + len - 1 );
3732
3733 /* NSegments iLo .. iHi inclusive should agree with the presented data. */
3734 for (i = iLo; i <= iHi; i++) {
sewardje139a462012-03-07 13:28:05 +00003735 if (nsegments[i].kind != SkFree && nsegments[i].kind != SkResvn) {
3736 /* V has a mapping, kernel doesn't. Add to css_local[],
3737 directives to chop off the part of the V mapping that
3738 falls within the gap that the kernel tells us is
3739 present. */
njnf76d27a2009-05-28 01:53:07 +00003740 ChangedSeg* cs = &css_local[css_used_local];
njnfd1b4612009-06-24 08:32:42 +00003741 if (css_used_local < css_size_local) {
3742 cs->is_added = False;
sewardje139a462012-03-07 13:28:05 +00003743 cs->start = Addr__max(nsegments[i].start, addr);
3744 cs->end = Addr__min(nsegments[i].end, addr + len - 1);
3745 aspacem_assert(VG_IS_PAGE_ALIGNED(cs->start));
3746 aspacem_assert(VG_IS_PAGE_ALIGNED(cs->end+1));
3747 /* I don't think the following should fail. But if it
3748 does, just omit the css_used_local++ in the cases where
3749 it doesn't hold. */
3750 aspacem_assert(cs->start < cs->end);
njnfd1b4612009-06-24 08:32:42 +00003751 cs->prot = 0;
3752 cs->offset = 0;
3753 css_used_local++;
3754 } else {
3755 css_overflowed = True;
3756 }
njnf76d27a2009-05-28 01:53:07 +00003757 }
3758 }
3759}
3760
3761
njnfd1b4612009-06-24 08:32:42 +00003762// Returns False if 'css' wasn't big enough.
3763Bool VG_(get_changed_segments)(
njnf76d27a2009-05-28 01:53:07 +00003764 const HChar* when, const HChar* where, /*OUT*/ChangedSeg* css,
3765 Int css_size, /*OUT*/Int* css_used)
3766{
3767 static UInt stats_synccalls = 1;
3768 aspacem_assert(when && where);
3769
3770 if (0)
3771 VG_(debugLog)(0,"aspacem",
3772 "[%u,%u] VG_(get_changed_segments)(%s, %s)\n",
3773 stats_synccalls++, stats_machcalls, when, where
3774 );
3775
njnfd1b4612009-06-24 08:32:42 +00003776 css_overflowed = False;
njnf76d27a2009-05-28 01:53:07 +00003777 css_local = css;
3778 css_size_local = css_size;
3779 css_used_local = 0;
3780
3781 // Get the list of segs that need to be added/removed.
3782 parse_procselfmaps(&add_mapping_callback, &remove_mapping_callback);
3783
3784 *css_used = css_used_local;
njnfd1b4612009-06-24 08:32:42 +00003785
3786 if (css_overflowed) {
3787 aspacem_assert(css_used_local == css_size_local);
3788 }
3789
3790 return !css_overflowed;
njnf76d27a2009-05-28 01:53:07 +00003791}
3792
sewardj38a21ac2010-01-03 10:14:03 +00003793#endif // defined(VGO_darwin)
bartc401ae72009-08-23 11:17:25 +00003794
sewardj38a21ac2010-01-03 10:14:03 +00003795/*------END-procmaps-parser-for-Darwin---------------------------*/
njn8b68b642009-06-24 00:37:09 +00003796
sewardj8eb8bab2015-07-21 14:44:28 +00003797/*------BEGIN-procmaps-parser-for-Solaris------------------------*/
3798
3799#if defined(VGO_solaris)
3800
3801/* Note: /proc/self/xmap contains extended information about already
3802 materialized mappings whereas /proc/self/rmap contains information about
3803 all mappings including reserved but yet-to-materialize mappings (mmap'ed
3804 with MAP_NORESERVE flag, such as thread stacks). But /proc/self/rmap does
3805 not contain extended information found in /proc/self/xmap. Therefore
3806 information from both sources need to be combined.
3807 */
3808
3809typedef struct
3810{
3811 Addr addr;
3812 SizeT size;
3813 UInt prot;
3814 ULong dev;
3815 ULong ino;
3816 Off64T foffset;
3817 HChar filename[VKI_PATH_MAX];
3818} Mapping;
3819
3820static SizeT read_proc_file(const HChar *filename, HChar *buf,
3821 SizeT buf_size, const HChar *buf_size_name,
3822 SizeT entry_size)
3823{
3824 SysRes res = ML_(am_open)(filename, VKI_O_RDONLY, 0);
3825 if (sr_isError(res)) {
3826 HChar message[100];
3827 ML_(am_sprintf)(message, "Cannot open %s.", filename);
3828 ML_(am_barf)(message);
3829 }
3830 Int fd = sr_Res(res);
3831
3832 Int r = ML_(am_read)(fd, buf, buf_size);
3833 ML_(am_close)(fd);
3834 if (r < 0) {
3835 HChar message[100];
3836 ML_(am_sprintf)(message, "I/O error on %s.", filename);
3837 ML_(am_barf)(message);
3838 }
3839
3840 if (r >= buf_size)
3841 ML_(am_barf_toolow)(buf_size_name);
3842
3843 if (r % entry_size != 0) {
3844 HChar message[100];
3845 ML_(am_sprintf)(message, "Bogus values read from %s.", filename);
3846 ML_(am_barf)(message);
3847 }
3848
3849 return r / entry_size;
3850}
3851
3852static Mapping *next_xmap(const HChar *buffer, SizeT entries, SizeT *idx,
3853 Mapping *mapping)
3854{
3855 aspacem_assert(idx);
3856 aspacem_assert(mapping);
3857
3858 if (*idx >= entries)
3859 return NULL; /* No more entries */
3860
3861 const vki_prxmap_t *map = (const vki_prxmap_t *)buffer + *idx;
3862
3863 mapping->addr = map->pr_vaddr;
3864 mapping->size = map->pr_size;
3865
3866 mapping->prot = 0;
3867 if (map->pr_mflags & VKI_MA_READ)
3868 mapping->prot |= VKI_PROT_READ;
3869 if (map->pr_mflags & VKI_MA_WRITE)
3870 mapping->prot |= VKI_PROT_WRITE;
3871 if (map->pr_mflags & VKI_MA_EXEC)
3872 mapping->prot |= VKI_PROT_EXEC;
3873
3874 if (map->pr_dev != VKI_PRNODEV) {
3875 mapping->dev = map->pr_dev;
3876 mapping->ino = map->pr_ino;
3877 mapping->foffset = map->pr_offset;
3878 }
3879 else {
3880 mapping->dev = 0;
3881 mapping->ino = 0;
3882 mapping->foffset = 0;
3883 }
3884
3885 /* Try to get the filename. */
3886 mapping->filename[0] = '\0';
3887 if (map->pr_mapname[0] != '\0') {
3888 ML_(am_sprintf)(mapping->filename, "/proc/self/path/%s",
3889 map->pr_mapname);
3890 Int r = ML_(am_readlink)(mapping->filename, mapping->filename,
3891 sizeof(mapping->filename) - 1);
3892 if (r == -1) {
3893 /* If Valgrind is executed in a non-global zone and the link in
3894 /proc/self/path/ represents a file that is available through lofs
3895 from a global zone then the kernel may not be able to resolve the
3896 link.
3897
3898 In such a case, return a corresponding /proc/self/object/ file to
3899 allow Valgrind to read the file if it is necessary.
3900
3901 This can create some discrepancy for the sanity check. For
3902 instance, if a client program mmaps some file then the address
3903 space manager will have a correct zone-local name of that file,
3904 but the sanity check will receive a different file name from this
3905 code. This currently does not represent a problem because the
3906 sanity check ignores the file names (it uses device and inode
3907 numbers for the comparison).
3908 */
3909 ML_(am_sprintf)(mapping->filename, "/proc/self/object/%s",
3910 map->pr_mapname);
3911 }
3912 else {
3913 aspacem_assert(r >= 0);
3914 mapping->filename[r] = '\0';
3915 }
3916 }
3917
3918 *idx += 1;
3919 return mapping;
3920}
3921
3922static Mapping *next_rmap(const HChar *buffer, SizeT entries, SizeT *idx,
3923 Mapping *mapping)
3924{
3925 aspacem_assert(idx);
3926 aspacem_assert(mapping);
3927
3928 if (*idx >= entries)
3929 return NULL; /* No more entries */
3930
3931 const vki_prmap_t *map = (const vki_prmap_t *)buffer + *idx;
3932
3933 mapping->addr = map->pr_vaddr;
3934 mapping->size = map->pr_size;
3935
3936 mapping->prot = 0;
3937 if (map->pr_mflags & VKI_MA_READ)
3938 mapping->prot |= VKI_PROT_READ;
3939 if (map->pr_mflags & VKI_MA_WRITE)
3940 mapping->prot |= VKI_PROT_WRITE;
3941 if (map->pr_mflags & VKI_MA_EXEC)
3942 mapping->prot |= VKI_PROT_EXEC;
3943
3944 mapping->dev = 0;
3945 mapping->ino = 0;
3946 mapping->foffset = 0;
3947 mapping->filename[0] = '\0';
3948
3949 *idx += 1;
3950 return mapping;
3951}
3952
3953/* Used for two purposes:
3954 1. Establish initial mappings upon the process startup
3955 2. Check mappings during aspacemgr sanity check
3956 */
3957static void parse_procselfmaps (
3958 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
3959 ULong dev, ULong ino, Off64T offset,
3960 const HChar *filename ),
3961 void (*record_gap)( Addr addr, SizeT len )
3962 )
3963{
3964 Addr start = Addr_MIN;
3965 Addr gap_start = Addr_MIN;
3966
3967#define M_XMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prxmap_t))
3968 /* Static to keep it out of stack frame... */
3969 static HChar xmap_buf[M_XMAP_BUF];
3970 const Mapping *xmap = NULL;
3971 SizeT xmap_index = 0; /* Current entry */
3972 SizeT xmap_entries;
3973 Mapping xmap_mapping;
3974 Bool advance_xmap;
3975
3976#define M_RMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prmap_t))
3977 static HChar rmap_buf[M_RMAP_BUF];
3978 const Mapping *rmap = NULL;
3979 SizeT rmap_index = 0; /* Current entry */
3980 SizeT rmap_entries;
3981 Mapping rmap_mapping;
3982 Bool advance_rmap;
3983
3984 /* Read fully /proc/self/xmap and /proc/self/rmap. */
3985 xmap_entries = read_proc_file("/proc/self/xmap", xmap_buf, M_XMAP_BUF,
3986 "M_XMAP_BUF", sizeof(vki_prxmap_t));
3987
3988 rmap_entries = read_proc_file("/proc/self/rmap", rmap_buf, M_RMAP_BUF,
3989 "M_RMAP_BUF", sizeof(vki_prmap_t));
3990
3991 /* Get the first xmap and rmap. */
3992 advance_xmap = True;
3993 advance_rmap = True;
3994
3995 while (1) {
3996 /* Get next xmap or rmap if necessary. */
3997 if (advance_xmap) {
3998 xmap = next_xmap(xmap_buf, xmap_entries, &xmap_index, &xmap_mapping);
3999 advance_xmap = False;
4000 }
4001 if (advance_rmap) {
4002 rmap = next_rmap(rmap_buf, rmap_entries, &rmap_index, &rmap_mapping);
4003 advance_rmap = False;
4004 }
4005
4006 /* Check if the end has been reached. */
4007 if (rmap == NULL)
4008 break;
4009
4010 /* Invariants */
4011 if (xmap != NULL) {
4012 aspacem_assert(start <= xmap->addr);
4013 aspacem_assert(rmap->addr <= xmap->addr);
4014 }
4015
4016 if (xmap != NULL && start == xmap->addr) {
4017 /* xmap mapping reached. */
4018 aspacem_assert(xmap->addr >= rmap->addr &&
4019 xmap->addr + xmap->size <= rmap->addr + rmap->size);
4020 aspacem_assert(xmap->prot == rmap->prot);
4021
4022 if (record_mapping != NULL)
4023 (*record_mapping)(xmap->addr, xmap->size, xmap->prot, xmap->dev,
4024 xmap->ino, xmap->foffset,
4025 (xmap->filename[0] != '\0') ?
4026 xmap->filename : NULL);
4027
4028 start = xmap->addr + xmap->size;
4029 advance_xmap = True;
4030 }
4031 else if (start >= rmap->addr) {
4032 /* Reserved-only part. */
4033 /* First calculate size until the end of this reserved mapping... */
4034 SizeT size = rmap->addr + rmap->size - start;
4035 /* ... but shrink it if some xmap is in a way. */
4036 if (xmap != NULL && size > xmap->addr - start)
4037 size = xmap->addr - start;
4038
4039 if (record_mapping != NULL)
4040 (*record_mapping)(start, size, rmap->prot, 0, 0, 0, NULL);
4041 start += size;
4042 }
4043 else {
4044 /* Gap. */
4045 if (record_gap != NULL && gap_start < start)
4046 (*record_gap)(gap_start, start - gap_start);
4047 start = rmap->addr;
4048 }
4049
4050 if (rmap->addr + rmap->size <= start)
4051 advance_rmap = True;
4052
4053 gap_start = start;
4054 }
4055
4056 if (record_gap != NULL && gap_start < Addr_MAX)
4057 (*record_gap)(gap_start, Addr_MAX - gap_start + 1);
4058}
4059
Elliott Hughesa0664b92017-04-18 17:46:52 -07004060/* parse_procselfmaps() callbacks do not allow for easy thread safety. */
4061static Addr found_addr;
4062static SizeT found_size;
4063static UInt found_prot;
4064
4065/* Reports a new mapping into variables above. */
4066static void new_segment_found_callback(Addr addr, SizeT len, UInt prot,
4067 ULong dev, ULong ino, Off64T offset, const HChar *filename)
4068{
4069 aspacem_assert(addr <= addr + len - 1);
4070
4071 Int iLo = find_nsegment_idx(addr);
4072 Int iHi = find_nsegment_idx(addr + len - 1);
4073 aspacem_assert(iLo <= iHi);
4074 aspacem_assert(nsegments[iLo].start <= addr);
4075 aspacem_assert(nsegments[iHi].end >= addr + len - 1);
4076
4077 /* Do not perform any sanity checks. That is done in other places.
4078 Just find if a reported mapping is found in aspacemgr's book keeping. */
4079 for (Int i = iLo; i <= iHi; i++) {
4080 if ((nsegments[i].kind == SkFree) || (nsegments[i].kind == SkResvn)) {
4081 found_addr = addr;
4082 found_size = len;
4083 found_prot = prot;
4084 break;
4085 }
4086 }
4087}
4088
4089/* Returns True if a new segment was found. */
4090Bool VG_(am_search_for_new_segment)(Addr *addr, SizeT *size, UInt *prot)
4091{
4092 found_addr = 0;
4093 parse_procselfmaps(new_segment_found_callback, NULL);
4094
4095 if (found_addr != 0) {
4096 *addr = found_addr;
4097 *size = found_size;
4098 *prot = found_prot;
4099 return True;
4100 } else {
4101 return False;
4102 }
4103}
4104
sewardj8eb8bab2015-07-21 14:44:28 +00004105#endif // defined(VGO_solaris)
4106
4107/*------END-procmaps-parser-for-Solaris--------------------------*/
4108
4109#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
njnf76d27a2009-05-28 01:53:07 +00004110
fitzhardinge98abfc72003-12-16 02:05:15 +00004111/*--------------------------------------------------------------------*/
njn945ed2e2005-06-24 03:28:30 +00004112/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +00004113/*--------------------------------------------------------------------*/