blob: 22b5446e88fc90f058faaf9f1afd02cae243024d [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00003/*--- Memory-related stuff: segment initialisation and tracking, ---*/
4/*--- stack operations ---*/
sewardjde4a1d02002-03-22 01:27:54 +00005/*--- vg_memory.c ---*/
6/*--------------------------------------------------------------------*/
7
8/*
njnc9539842002-10-02 13:26:35 +00009 This file is part of Valgrind, an extensible x86 protected-mode
10 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +000011
nethercotebb1c9912004-01-04 16:43:23 +000012 Copyright (C) 2000-2004 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000013 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000014
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307, USA.
29
njn25e49d8e72002-09-23 09:36:25 +000030 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000031*/
32
33#include "vg_include.h"
34
fitzhardinge98abfc72003-12-16 02:05:15 +000035#include <stddef.h>
36
sewardja4495682002-10-21 07:29:59 +000037/* Define to debug the memory-leak-detector. */
38/* #define VG_DEBUG_LEAKCHECK */
39
fitzhardinge98abfc72003-12-16 02:05:15 +000040static const Bool mem_debug = False;
41
42static Int addrcmp(const void *ap, const void *bp)
43{
44 Addr a = *(Addr *)ap;
45 Addr b = *(Addr *)bp;
46 Int ret;
47
48 if (a == b)
49 ret = 0;
50 else
51 ret = (a < b) ? -1 : 1;
52
53 return ret;
54}
55
56static Char *straddr(void *p)
57{
58 static Char buf[16];
59
60 VG_(sprintf)(buf, "%p", *(Addr *)p);
61
62 return buf;
63}
64
65static SkipList sk_segments = SKIPLIST_INIT(Segment, addr, addrcmp, straddr, VG_AR_CORE);
66
67/*--------------------------------------------------------------*/
68/*--- Maintain an ordered list of all the client's mappings ---*/
69/*--------------------------------------------------------------*/
70
71Bool VG_(seg_contains)(const Segment *s, Addr p, UInt len)
72{
73 Addr se = s->addr+s->len;
74 Addr pe = p+len;
75
76 vg_assert(pe >= p);
77
78 return (p >= s->addr && pe <= se);
79}
80
81Bool VG_(seg_overlaps)(const Segment *s, Addr p, UInt len)
82{
83 Addr se = s->addr+s->len;
84 Addr pe = p+len;
85
86 vg_assert(pe >= p);
87
88 return (p < se && pe > s->addr);
89}
90
91/* Prepare a Segment structure for recycling by freeing everything
92 hanging off it. */
93static void recycleseg(Segment *s)
94{
95 if (s->flags & SF_CODE)
96 VG_(invalidate_translations)(s->addr, s->len, False);
97
98 if (s->filename != NULL)
99 VG_(arena_free)(VG_AR_CORE, (Char *)s->filename);
100
101 /* keep the SegInfo, if any - it probably still applies */
102}
103
104/* When freeing a Segment, also clean up every one else's ideas of
105 what was going on in that range of memory */
106static void freeseg(Segment *s)
107{
108 recycleseg(s);
109 if (s->symtab != NULL) {
110 VG_(symtab_decref)(s->symtab, s->addr, s->len);
111 s->symtab = NULL;
112 }
113
114 VG_(SkipNode_Free)(&sk_segments, s);
115}
116
fitzhardinge1a303042003-12-22 08:48:50 +0000117/* Split a segment at address a, returning the new segment */
118Segment *VG_(split_segment)(Addr a)
fitzhardinge98abfc72003-12-16 02:05:15 +0000119{
120 Segment *s = VG_(SkipList_Find)(&sk_segments, &a);
121 Segment *ns;
122 Int delta;
123
124 vg_assert((a & (VKI_BYTES_PER_PAGE-1)) == 0);
125
126 /* missed */
127 if (s == NULL)
128 return NULL;
129
130 /* a at or beyond endpoint */
131 if (s->addr == a || a >= (s->addr+s->len))
132 return NULL;
133
134 vg_assert(a > s->addr && a < (s->addr+s->len));
135
136 ns = VG_(SkipNode_Alloc)(&sk_segments);
137
138 *ns = *s;
139
140 delta = a - s->addr;
141 ns->addr += delta;
142 ns->offset += delta;
143 ns->len -= delta;
fitzhardingee3632c62003-12-22 10:58:06 +0000144 s->len = delta;
fitzhardinge98abfc72003-12-16 02:05:15 +0000145
fitzhardinge1a4adf02003-12-22 10:42:59 +0000146 if (s->filename != NULL)
147 ns->filename = VG_(arena_strdup)(VG_AR_CORE, s->filename);
148
fitzhardinge98abfc72003-12-16 02:05:15 +0000149 if (ns->symtab != NULL)
150 VG_(symtab_incref)(ns->symtab);
151
152 VG_(SkipList_Insert)(&sk_segments, ns);
153
154 return ns;
155}
156
157/* This unmaps all the segments in the range [addr, addr+len); any
158 partial mappings at the ends are truncated. */
159void VG_(unmap_range)(Addr addr, UInt len)
160{
161 Segment *s;
162 Segment *next;
fitzhardingee3632c62003-12-22 10:58:06 +0000163 static const Bool debug = False || mem_debug;
fitzhardinge1a4adf02003-12-22 10:42:59 +0000164 Addr end;
fitzhardinge98abfc72003-12-16 02:05:15 +0000165
166 if (len == 0)
167 return;
168
fitzhardinge1a4adf02003-12-22 10:42:59 +0000169 len = PGROUNDUP(len);
170 vg_assert(addr == PGROUNDDN(addr));
171
fitzhardinge98abfc72003-12-16 02:05:15 +0000172 if (debug)
173 VG_(printf)("unmap_range(%p, %d)\n", addr, len);
174
fitzhardinge1a4adf02003-12-22 10:42:59 +0000175 end = addr+len;
fitzhardinge98abfc72003-12-16 02:05:15 +0000176
177 /* Everything must be page-aligned */
178 vg_assert((addr & (VKI_BYTES_PER_PAGE-1)) == 0);
179 vg_assert((len & (VKI_BYTES_PER_PAGE-1)) == 0);
180
181 for(s = VG_(SkipList_Find)(&sk_segments, &addr);
182 s != NULL && s->addr < (addr+len);
183 s = next) {
fitzhardinge1a303042003-12-22 08:48:50 +0000184 Addr seg_end = s->addr + s->len;
fitzhardinge98abfc72003-12-16 02:05:15 +0000185
186 /* fetch next now in case we end up deleting this segment */
187 next = VG_(SkipNode_Next)(&sk_segments, s);
188
189 if (debug)
fitzhardinge1a303042003-12-22 08:48:50 +0000190 VG_(printf)("unmap: addr=%p-%p s=%p ->addr=%p-%p len=%d\n",
fitzhardinge1a4adf02003-12-22 10:42:59 +0000191 addr, end, s, s->addr, seg_end, s->len);
fitzhardinge98abfc72003-12-16 02:05:15 +0000192
fitzhardinge1a303042003-12-22 08:48:50 +0000193 if (!VG_(seg_overlaps)(s, addr, len)) {
194 if (debug)
195 VG_(printf)(" (no overlap)\n");
fitzhardinge98abfc72003-12-16 02:05:15 +0000196 continue;
fitzhardinge1a303042003-12-22 08:48:50 +0000197 }
fitzhardinge98abfc72003-12-16 02:05:15 +0000198
199 /* 4 cases: */
fitzhardinge1a303042003-12-22 08:48:50 +0000200 if (addr > s->addr &&
201 addr < seg_end &&
202 end >= seg_end) {
fitzhardinge98abfc72003-12-16 02:05:15 +0000203 /* this segment's tail is truncated by [addr, addr+len)
204 -> truncate tail
205 */
206 s->len = addr - s->addr;
207
208 if (debug)
209 VG_(printf)(" case 1: s->len=%d\n", s->len);
fitzhardingee3632c62003-12-22 10:58:06 +0000210 } else if (addr <= s->addr && end > s->addr && end < seg_end) {
211 /* this segment's head is truncated by [addr, addr+len)
212 -> truncate head
213 */
214 Int delta = end - s->addr;
215
216 if (debug)
217 VG_(printf)(" case 2: s->addr=%p s->len=%d delta=%d\n", s->addr, s->len, delta);
218
219 s->addr += delta;
220 s->offset += delta;
221 s->len -= delta;
222
223 vg_assert(s->len != 0);
fitzhardinge1a303042003-12-22 08:48:50 +0000224 } else if (addr <= s->addr && end >= seg_end) {
fitzhardinge98abfc72003-12-16 02:05:15 +0000225 /* this segment is completely contained within [addr, addr+len)
226 -> delete segment
227 */
228 Segment *rs = VG_(SkipList_Remove)(&sk_segments, &s->addr);
229 vg_assert(rs == s);
230 freeseg(s);
231
232 if (debug)
fitzhardingee3632c62003-12-22 10:58:06 +0000233 VG_(printf)(" case 3: s==%p deleted\n", s);
fitzhardinge1a303042003-12-22 08:48:50 +0000234 } else if (addr > s->addr && end < seg_end) {
fitzhardinge98abfc72003-12-16 02:05:15 +0000235 /* [addr, addr+len) is contained within a single segment
236 -> split segment into 3, delete middle portion
237 */
238 Segment *middle, *rs;
239
fitzhardinge1a303042003-12-22 08:48:50 +0000240 middle = VG_(split_segment)(addr);
241 VG_(split_segment)(addr+len);
fitzhardinge98abfc72003-12-16 02:05:15 +0000242
243 vg_assert(middle->addr == addr);
244 rs = VG_(SkipList_Remove)(&sk_segments, &addr);
245 vg_assert(rs == middle);
246
247 freeseg(rs);
248
249 if (debug)
250 VG_(printf)(" case 4: subrange %p-%p deleted\n",
251 addr, addr+len);
252 }
253 }
254}
255
fitzhardinge1a4adf02003-12-22 10:42:59 +0000256/* Return true if two segments are adjacent and mergable (s1 is
257 assumed to have a lower ->addr than s2) */
fitzhardinge98abfc72003-12-16 02:05:15 +0000258static inline Bool neighbours(Segment *s1, Segment *s2)
259{
260 if (s1->addr+s1->len != s2->addr)
261 return False;
262
263 if (s1->flags != s2->flags)
264 return False;
265
266 if (s1->prot != s2->prot)
267 return False;
268
269 if (s1->symtab != s2->symtab)
270 return False;
271
272 if (s1->flags & SF_FILE){
273 if ((s1->offset + s1->len) != s2->offset)
274 return False;
275 if (s1->dev != s2->dev)
276 return False;
277 if (s1->ino != s2->ino)
278 return False;
279 }
280
281 return True;
282}
283
fitzhardinge1a4adf02003-12-22 10:42:59 +0000284/* If possible, merge segment with its neighbours - some segments,
285 including s, may be destroyed in the process */
fitzhardinge98abfc72003-12-16 02:05:15 +0000286static void merge_segments(Addr a, UInt len)
287{
288 Segment *s;
289 Segment *next;
290
291 vg_assert((a & (VKI_BYTES_PER_PAGE-1)) == 0);
292 vg_assert((len & (VKI_BYTES_PER_PAGE-1)) == 0);
293
294 a -= VKI_BYTES_PER_PAGE;
295 len += VKI_BYTES_PER_PAGE;
296
297 for(s = VG_(SkipList_Find)(&sk_segments, &a);
298 s != NULL && s->addr < (a+len);) {
299 next = VG_(SkipNode_Next)(&sk_segments, s);
300
301 if (next && neighbours(s, next)) {
302 Segment *rs;
303
304 if (0)
305 VG_(printf)("merge %p-%p with %p-%p\n",
306 s->addr, s->addr+s->len,
307 next->addr, next->addr+next->len);
308 s->len += next->len;
309 s = VG_(SkipNode_Next)(&sk_segments, next);
310
311 rs = VG_(SkipList_Remove)(&sk_segments, &next->addr);
312 vg_assert(next == rs);
313 freeseg(next);
314 } else
315 s = next;
316 }
317}
318
319void VG_(map_file_segment)(Addr addr, UInt len, UInt prot, UInt flags,
320 UInt dev, UInt ino, ULong off, const Char *filename)
321{
322 Segment *s;
323 static const Bool debug = False || mem_debug;
324 Bool recycled;
325
326 if (debug)
327 VG_(printf)("map_file_segment(%p, %d, %x, %x, %4x, %d, %ld, %s)\n",
328 addr, len, prot, flags, dev, ino, off, filename);
329
330 /* Everything must be page-aligned */
331 vg_assert((addr & (VKI_BYTES_PER_PAGE-1)) == 0);
332 len = PGROUNDUP(len);
333
334 /* First look to see what already exists around here */
335 s = VG_(SkipList_Find)(&sk_segments, &addr);
336
337 if (s != NULL && s->addr == addr && s->len == len) {
fitzhardinge98abfc72003-12-16 02:05:15 +0000338 recycled = True;
339 recycleseg(s);
340
341 /* If we had a symtab, but the new mapping is incompatible, then
342 free up the old symtab in preparation for a new one. */
343 if (s->symtab != NULL &&
344 (!(s->flags & SF_FILE) ||
345 !(flags & SF_FILE) ||
346 s->dev != dev ||
347 s->ino != ino ||
348 s->offset != off)) {
349 VG_(symtab_decref)(s->symtab, s->addr, s->len);
350 s->symtab = NULL;
351 }
352 } else {
353 recycled = False;
354 VG_(unmap_range)(addr, len);
355
356 s = VG_(SkipNode_Alloc)(&sk_segments);
357
358 s->addr = addr;
359 s->len = len;
360 s->symtab = NULL;
361 }
362
363 s->flags = flags;
364 s->prot = prot;
365 s->dev = dev;
366 s->ino = ino;
367 s->offset = off;
368
369 if (filename != NULL)
370 s->filename = VG_(arena_strdup)(VG_AR_CORE, filename);
371 else
372 s->filename = NULL;
373
374 if (debug) {
375 Segment *ts;
376 for(ts = VG_(SkipNode_First)(&sk_segments);
377 ts != NULL;
378 ts = VG_(SkipNode_Next)(&sk_segments, ts))
379 VG_(printf)("list: %8p->%8p ->%d (0x%x) prot=%x flags=%x\n",
380 ts, ts->addr, ts->len, ts->len, ts->prot, ts->flags);
381
382 VG_(printf)("inserting s=%p addr=%p len=%d\n",
383 s, s->addr, s->len);
384 }
385
386 if (!recycled)
387 VG_(SkipList_Insert)(&sk_segments, s);
388
389 /* If this mapping is of the beginning of a file, isn't part of
390 Valgrind, is at least readable and seems to contain an object
391 file, then try reading symbols from it. */
392 if ((flags & (SF_MMAP|SF_NOSYMS)) == SF_MMAP &&
393 s->symtab == NULL) {
394 if (off == 0 &&
395 filename != NULL &&
396 (prot & (VKI_PROT_READ|VKI_PROT_EXEC)) == (VKI_PROT_READ|VKI_PROT_EXEC) &&
397 len >= VKI_BYTES_PER_PAGE &&
398 s->symtab == NULL &&
nethercote71980f02004-01-24 18:18:54 +0000399 VG_(is_object_file)((void *)addr))
400 {
401 s->symtab = VG_(read_seg_symbols)(s);
fitzhardinge98abfc72003-12-16 02:05:15 +0000402
nethercote71980f02004-01-24 18:18:54 +0000403 if (s->symtab != NULL) {
404 s->flags |= SF_DYNLIB;
405 }
fitzhardinge98abfc72003-12-16 02:05:15 +0000406 } else if (flags & SF_MMAP) {
407 const SegInfo *info;
408
409 /* Otherwise see if an existing symtab applies to this Segment */
410 for(info = VG_(next_seginfo)(NULL);
411 info != NULL;
412 info = VG_(next_seginfo)(info)) {
nethercote71980f02004-01-24 18:18:54 +0000413 if (VG_(seg_overlaps)(s, VG_(seg_start)(info), VG_(seg_size)(info)))
414 {
fitzhardinge98abfc72003-12-16 02:05:15 +0000415 s->symtab = (SegInfo *)info;
416 VG_(symtab_incref)((SegInfo *)info);
417 }
418 }
419 }
420 }
421
422 /* clean up */
423 merge_segments(addr, len);
424}
425
426void VG_(map_fd_segment)(Addr addr, UInt len, UInt prot, UInt flags,
427 Int fd, ULong off, const Char *filename)
428{
429 struct vki_stat st;
430 Char *name = NULL;
431
432 st.st_dev = 0;
433 st.st_ino = 0;
434
435 if (fd != -1 && (flags & SF_FILE)) {
436 vg_assert((off & (VKI_BYTES_PER_PAGE-1)) == 0);
437
438 if (VG_(fstat)(fd, &st) < 0)
439 flags &= ~SF_FILE;
440 }
441
442 if ((flags & SF_FILE) && filename == NULL && fd != -1)
443 name = VG_(resolve_filename)(fd);
444
445 if (filename == NULL)
446 filename = name;
447
448 VG_(map_file_segment)(addr, len, prot, flags, st.st_dev, st.st_ino, off, filename);
449
450 if (name)
451 VG_(arena_free)(VG_AR_CORE, name);
452}
453
454void VG_(map_segment)(Addr addr, UInt len, UInt prot, UInt flags)
455{
456 flags &= ~SF_FILE;
457
458 VG_(map_file_segment)(addr, len, prot, flags, 0, 0, 0, 0);
459}
460
461/* set new protection flags on an address range */
462void VG_(mprotect_range)(Addr a, UInt len, UInt prot)
463{
464 Segment *s, *next;
465 static const Bool debug = False || mem_debug;
466
467 if (debug)
468 VG_(printf)("mprotect_range(%p, %d, %x)\n", a, len, prot);
469
470 /* Everything must be page-aligned */
471 vg_assert((a & (VKI_BYTES_PER_PAGE-1)) == 0);
fitzhardinge92360792003-12-24 10:11:11 +0000472 len = PGROUNDUP(len);
fitzhardinge98abfc72003-12-16 02:05:15 +0000473
fitzhardinge1a303042003-12-22 08:48:50 +0000474 VG_(split_segment)(a);
475 VG_(split_segment)(a+len);
fitzhardinge98abfc72003-12-16 02:05:15 +0000476
477 for(s = VG_(SkipList_Find)(&sk_segments, &a);
478 s != NULL && s->addr < a+len;
479 s = next)
480 {
481 next = VG_(SkipNode_Next)(&sk_segments, s);
482 if (s->addr < a)
483 continue;
484
485 s->prot = prot;
486 }
487
488 merge_segments(a, len);
489}
490
491Addr VG_(find_map_space)(Addr addr, UInt len, Bool for_client)
492{
fitzhardingee3632c62003-12-22 10:58:06 +0000493 static const Bool debug = False || mem_debug;
fitzhardinge98abfc72003-12-16 02:05:15 +0000494 Segment *s;
495 Addr ret;
nethercotec314eba2004-07-15 12:59:41 +0000496 Addr limit = (for_client ? VG_(client_end) : VG_(valgrind_end));
fitzhardinge98abfc72003-12-16 02:05:15 +0000497
498 if (addr == 0)
499 addr = for_client ? VG_(client_mapbase) : VG_(valgrind_base);
500 else {
501 /* leave space for redzone and still try to get the exact
502 address asked for */
503 addr -= VKI_BYTES_PER_PAGE;
504 }
505 ret = addr;
506
507 /* Everything must be page-aligned */
508 vg_assert((addr & (VKI_BYTES_PER_PAGE-1)) == 0);
509 len = PGROUNDUP(len);
510
511 len += VKI_BYTES_PER_PAGE * 2; /* leave redzone gaps before and after mapping */
512
513 if (debug)
514 VG_(printf)("find_map_space: ret starts as %p-%p client=%d\n",
515 ret, ret+len, for_client);
516
517 for(s = VG_(SkipList_Find)(&sk_segments, &ret);
518 s != NULL && s->addr < (ret+len);
519 s = VG_(SkipNode_Next)(&sk_segments, s))
520 {
521 if (debug)
522 VG_(printf)("s->addr=%p len=%d (%p) ret=%p\n",
523 s->addr, s->len, s->addr+s->len, ret);
524
525 if (s->addr < (ret + len) && (s->addr + s->len) > ret)
526 ret = s->addr+s->len;
527 }
528
529 if (debug) {
530 if (s)
531 VG_(printf)(" s->addr=%p ->len=%d\n", s->addr, s->len);
532 else
533 VG_(printf)(" s == NULL\n");
534 }
535
536 if ((limit - len) < ret)
537 ret = 0; /* no space */
538 else
539 ret += VKI_BYTES_PER_PAGE; /* skip leading redzone */
540
541 if (debug)
542 VG_(printf)("find_map_space(%p, %d, %d) -> %p\n",
543 addr, len, for_client, ret);
544
545 return ret;
546}
547
thughes646c6aa2004-07-16 15:36:45 +0000548/* Pad the entire process address space, from VG_(client_base)
549 to VG_(valgrind_end) by creating an anonymous and inaccessible
550 mapping over any part of the address space which is not covered
551 by an entry in the segment list.
552
553 This is designed for use around system calls which allocate
554 memory in the process address space without providing a way to
nethercoteccc9ecd2004-07-16 17:32:15 +0000555 control its location such as io_setup. By choosing a suitable
thughes646c6aa2004-07-16 15:36:45 +0000556 address with VG_(find_map_space) and then adding a segment for
557 it and padding the address space valgrind can ensure that the
558 kernel has no choice but to put the memory where we want it. */
thughes9aaebc32004-07-15 23:13:37 +0000559void VG_(pad_address_space)(void)
560{
561 Addr addr = VG_(client_base);
562 Segment *s = VG_(SkipNode_First)(&sk_segments);
563 UInt args[6];
564 Addr ret;
565
566 args[2] = 0;
567 args[3] = VKI_MAP_FIXED | VKI_MAP_PRIVATE | VKI_MAP_ANONYMOUS;
568 args[4] = -1;
569 args[5] = 0;
570
571 while (s && addr < VG_(valgrind_end)) {
572 if (addr < s->addr) {
573 args[0] = (UInt)addr;
574 args[1] = s->addr - addr;
575
576 ret = VG_(do_syscall)(__NR_mmap, (UInt)args);
577 }
578
579 addr = s->addr + s->len;
580 s = VG_(SkipNode_Next)(&sk_segments, s);
581 }
582
583 if (addr < VG_(valgrind_end)) {
584 args[0] = (UInt)addr;
585 args[1] = VG_(valgrind_end) - addr;
586
587 ret = VG_(do_syscall)(__NR_mmap, (UInt)args);
588 }
589
590 return;
591}
592
thughes646c6aa2004-07-16 15:36:45 +0000593/* Removed the address space padding added by VG_(pad_address_space)
594 by removing any mappings that it created. */
thughes9aaebc32004-07-15 23:13:37 +0000595void VG_(unpad_address_space)(void)
596{
597 Addr addr = VG_(client_base);
598 Segment *s = VG_(SkipNode_First)(&sk_segments);
599 Int ret;
600
601 while (s && addr < VG_(valgrind_end)) {
602 if (addr < s->addr) {
603 ret = VG_(do_syscall)(__NR_munmap, (UInt)addr, s->addr - addr);
604 }
605
606 addr = s->addr + s->len;
607 s = VG_(SkipNode_Next)(&sk_segments, s);
608 }
609
610 if (addr < VG_(valgrind_end)) {
611 ret = VG_(do_syscall)(__NR_munmap, (UInt)addr, VG_(valgrind_end) - addr);
612 }
613
614 return;
615}
616
fitzhardinge98abfc72003-12-16 02:05:15 +0000617Segment *VG_(find_segment)(Addr a)
618{
619 return VG_(SkipList_Find)(&sk_segments, &a);
620}
621
fitzhardinged65dcad2004-03-13 02:06:58 +0000622Segment *VG_(first_segment)(void)
623{
624 return VG_(SkipNode_First)(&sk_segments);
625}
626
fitzhardinge98abfc72003-12-16 02:05:15 +0000627Segment *VG_(next_segment)(Segment *s)
628{
629 return VG_(SkipNode_Next)(&sk_segments, s);
630}
sewardjde4a1d02002-03-22 01:27:54 +0000631
sewardjde4a1d02002-03-22 01:27:54 +0000632/*------------------------------------------------------------*/
633/*--- Tracking permissions around %esp changes. ---*/
634/*------------------------------------------------------------*/
635
636/*
637 The stack
638 ~~~~~~~~~
639 The stack's segment seems to be dynamically extended downwards
640 by the kernel as the stack pointer moves down. Initially, a
641 1-page (4k) stack is allocated. When %esp moves below that for
642 the first time, presumably a page fault occurs. The kernel
643 detects that the faulting address is in the range from %esp upwards
644 to the current valid stack. It then extends the stack segment
645 downwards for enough to cover the faulting address, and resumes
646 the process (invisibly). The process is unaware of any of this.
647
648 That means that Valgrind can't spot when the stack segment is
649 being extended. Fortunately, we want to precisely and continuously
650 update stack permissions around %esp, so we need to spot all
651 writes to %esp anyway.
652
653 The deal is: when %esp is assigned a lower value, the stack is
654 being extended. Create a secondary maps to fill in any holes
655 between the old stack ptr and this one, if necessary. Then
656 mark all bytes in the area just "uncovered" by this %esp change
657 as write-only.
658
659 When %esp goes back up, mark the area receded over as unreadable
660 and unwritable.
661
662 Just to record the %esp boundary conditions somewhere convenient:
663 %esp always points to the lowest live byte in the stack. All
664 addresses below %esp are not live; those at and above it are.
665*/
666
sewardjde4a1d02002-03-22 01:27:54 +0000667/* Kludgey ... how much does %esp have to change before we reckon that
668 the application is switching stacks ? */
njn9b007f62003-04-07 14:40:25 +0000669#define VG_PLAUSIBLE_STACK_SIZE 8000000
670#define VG_HUGE_DELTA (VG_PLAUSIBLE_STACK_SIZE / 4)
sewardjde4a1d02002-03-22 01:27:54 +0000671
njn9b007f62003-04-07 14:40:25 +0000672/* This function gets called if new_mem_stack and/or die_mem_stack are
673 tracked by the skin, and one of the specialised cases (eg. new_mem_stack_4)
674 isn't used in preference */
675__attribute__((regparm(1)))
676void VG_(unknown_esp_update)(Addr new_ESP)
sewardjde4a1d02002-03-22 01:27:54 +0000677{
njn9b007f62003-04-07 14:40:25 +0000678 Addr old_ESP = VG_(get_archreg)(R_ESP);
679 Int delta = (Int)new_ESP - (Int)old_ESP;
sewardjde4a1d02002-03-22 01:27:54 +0000680
njn9b007f62003-04-07 14:40:25 +0000681 if (delta < -(VG_HUGE_DELTA) || VG_HUGE_DELTA < delta) {
682 /* %esp has changed by more than HUGE_DELTA. We take this to mean
683 that the application is switching to a new stack, for whatever
684 reason.
685
686 JRS 20021001: following discussions with John Regehr, if a stack
687 switch happens, it seems best not to mess at all with memory
688 permissions. Seems to work well with Netscape 4.X. Really the
689 only remaining difficulty is knowing exactly when a stack switch is
690 happening. */
691 if (VG_(clo_verbosity) > 1)
692 VG_(message)(Vg_UserMsg, "Warning: client switching stacks? "
693 "%%esp: %p --> %p", old_ESP, new_ESP);
694 } else if (delta < 0) {
695 VG_TRACK( new_mem_stack, new_ESP, -delta );
sewardjde4a1d02002-03-22 01:27:54 +0000696
njn9b007f62003-04-07 14:40:25 +0000697 } else if (delta > 0) {
698 VG_TRACK( die_mem_stack, old_ESP, delta );
sewardjde4a1d02002-03-22 01:27:54 +0000699 }
700}
701
jsgf855d93d2003-10-13 22:26:55 +0000702static jmp_buf segv_jmpbuf;
703
704static void segv_handler(Int seg)
705{
706 __builtin_longjmp(segv_jmpbuf, 1);
707 VG_(core_panic)("longjmp failed");
708}
709
710/*
711 Test if a piece of memory is addressable by setting up a temporary
712 SIGSEGV handler, then try to touch the memory. No signal = good,
713 signal = bad.
714 */
715Bool VG_(is_addressable)(Addr p, Int size)
716{
717 volatile Char * volatile cp = (volatile Char *)p;
718 volatile Bool ret;
719 vki_ksigaction sa, origsa;
720 vki_ksigset_t mask;
721
722 vg_assert(size > 0);
723
724 sa.ksa_handler = segv_handler;
725 sa.ksa_flags = 0;
726 VG_(ksigfillset)(&sa.ksa_mask);
727 VG_(ksigaction)(VKI_SIGSEGV, &sa, &origsa);
728 VG_(ksigprocmask)(VKI_SIG_SETMASK, NULL, &mask);
729
730 if (__builtin_setjmp(&segv_jmpbuf) == 0) {
731 while(size--)
732 *cp++;
733 ret = True;
734 } else
735 ret = False;
736
737 VG_(ksigaction)(VKI_SIGSEGV, &origsa, NULL);
738 VG_(ksigprocmask)(VKI_SIG_SETMASK, &mask, NULL);
739
740 return ret;
741}
742
sewardjde4a1d02002-03-22 01:27:54 +0000743/*--------------------------------------------------------------------*/
nethercote88a90162004-07-10 16:59:25 +0000744/*--- Manage allocation of memory on behalf of the client ---*/
fitzhardinge98abfc72003-12-16 02:05:15 +0000745/*--------------------------------------------------------------------*/
746
nethercote57e36b32004-07-10 14:56:28 +0000747// Returns 0 on failure.
nethercoteb4250ae2004-07-10 16:50:09 +0000748Addr VG_(client_alloc)(Addr addr, UInt len, UInt prot, UInt sf_flags)
fitzhardinge98abfc72003-12-16 02:05:15 +0000749{
750 len = PGROUNDUP(len);
751
nethercote8e9eab02004-07-11 18:01:06 +0000752 sk_assert(!(sf_flags & SF_FIXED));
753 sk_assert(0 == addr);
fitzhardinge98abfc72003-12-16 02:05:15 +0000754
nethercote8e9eab02004-07-11 18:01:06 +0000755 addr = (Addr)VG_(mmap)((void *)addr, len, prot,
756 VKI_MAP_PRIVATE | VKI_MAP_ANONYMOUS | VKI_MAP_CLIENT,
757 sf_flags | SF_CORE, -1, 0);
758 if ((Addr)-1 != addr)
fitzhardinge98abfc72003-12-16 02:05:15 +0000759 return addr;
nethercote8e9eab02004-07-11 18:01:06 +0000760 else
761 return 0;
fitzhardinge98abfc72003-12-16 02:05:15 +0000762}
763
764void VG_(client_free)(Addr addr)
765{
766 Segment *s = VG_(find_segment)(addr);
767
768 if (s == NULL || s->addr != addr || !(s->flags & SF_CORE)) {
769 VG_(message)(Vg_DebugMsg, "VG_(client_free)(%p) - no CORE memory found there", addr);
770 return;
771 }
772
773 VG_(munmap)((void *)s->addr, s->len);
774}
775
nethercote88a90162004-07-10 16:59:25 +0000776/*--------------------------------------------------------------------*/
777/*--- Querying memory layout ---*/
778/*--------------------------------------------------------------------*/
779
fitzhardinge98abfc72003-12-16 02:05:15 +0000780Bool VG_(is_client_addr)(Addr a)
781{
782 return a >= VG_(client_base) && a < VG_(client_end);
783}
784
785Bool VG_(is_shadow_addr)(Addr a)
786{
787 return a >= VG_(shadow_base) && a < VG_(shadow_end);
788}
789
790Bool VG_(is_valgrind_addr)(Addr a)
791{
792 return a >= VG_(valgrind_base) && a < VG_(valgrind_end);
793}
794
795Addr VG_(get_client_base)(void)
796{
797 return VG_(client_base);
798}
799
800Addr VG_(get_client_end)(void)
801{
802 return VG_(client_end);
803}
804
805Addr VG_(get_client_size)(void)
806{
807 return VG_(client_end)-VG_(client_base);
808}
809
810Addr VG_(get_shadow_base)(void)
811{
812 return VG_(shadow_base);
813}
814
815Addr VG_(get_shadow_end)(void)
816{
817 return VG_(shadow_end);
818}
819
820Addr VG_(get_shadow_size)(void)
821{
822 return VG_(shadow_end)-VG_(shadow_base);
823}
824
nethercote88a90162004-07-10 16:59:25 +0000825/*--------------------------------------------------------------------*/
nethercote2f54e0d2004-07-10 17:27:20 +0000826/*--- Handling shadow memory ---*/
nethercote88a90162004-07-10 16:59:25 +0000827/*--------------------------------------------------------------------*/
fitzhardinge98abfc72003-12-16 02:05:15 +0000828
829void VG_(init_shadow_range)(Addr p, UInt sz, Bool call_init)
830{
831 if (0)
832 VG_(printf)("init_shadow_range(%p, %d)\n", p, sz);
833
834 vg_assert(VG_(needs).shadow_memory);
835 vg_assert(VG_(defined_init_shadow_page)());
836
837 sz = PGROUNDUP(p+sz) - PGROUNDDN(p);
838 p = PGROUNDDN(p);
839
840 VG_(mprotect)((void *)p, sz, VKI_PROT_READ|VKI_PROT_WRITE);
841
842 if (call_init)
843 while(sz) {
844 /* ask the skin to initialize each page */
845 VG_TRACK( init_shadow_page, PGROUNDDN(p) );
846
847 p += VKI_BYTES_PER_PAGE;
848 sz -= VKI_BYTES_PER_PAGE;
849 }
850}
851
852void *VG_(shadow_alloc)(UInt size)
853{
854 static Addr shadow_alloc = 0;
855 void *ret;
856
857 vg_assert(VG_(needs).shadow_memory);
858 vg_assert(!VG_(defined_init_shadow_page)());
859
860 size = PGROUNDUP(size);
861
862 if (shadow_alloc == 0)
863 shadow_alloc = VG_(shadow_base);
864
865 if (shadow_alloc >= VG_(shadow_end))
866 return 0;
867
868 ret = (void *)shadow_alloc;
869 VG_(mprotect)(ret, size, VKI_PROT_READ|VKI_PROT_WRITE);
870
871 shadow_alloc += size;
872
873 return ret;
874}
875
876/*--------------------------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +0000877/*--- end vg_memory.c ---*/
878/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000879