]>
Commit | Line | Data |
---|---|---|
6de9cd9a | 1 | /* Mudflap: narrow-pointer bounds-checking by tree rewriting. |
23701e90 | 2 | Copyright (C) 2002-2013 Free Software Foundation, Inc. |
6de9cd9a DN |
3 | Contributed by Frank Ch. Eigler <fche@redhat.com> |
4 | and Graydon Hoare <graydon@redhat.com> | |
5 | ||
6 | This file is part of GCC. | |
fb925a51 | 7 | |
6de9cd9a DN |
8 | GCC is free software; you can redistribute it and/or modify it under |
9 | the terms of the GNU General Public License as published by the Free | |
748086b7 | 10 | Software Foundation; either version 3, or (at your option) any later |
6de9cd9a DN |
11 | version. |
12 | ||
6de9cd9a DN |
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
17 | ||
748086b7 JJ |
18 | Under Section 7 of GPL version 3, you are granted additional |
19 | permissions described in the GCC Runtime Library Exception, version | |
20 | 3.1, as published by the Free Software Foundation. | |
6de9cd9a | 21 | |
748086b7 JJ |
22 | You should have received a copy of the GNU General Public License and |
23 | a copy of the GCC Runtime Library Exception along with this program; | |
24 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
25 | <http://www.gnu.org/licenses/>. */ | |
6de9cd9a DN |
26 | |
27 | #include "config.h" | |
28 | ||
29 | #include <stdio.h> | |
30 | ||
31 | #include "mf-runtime.h" | |
32 | #include "mf-impl.h" | |
33 | ||
34 | #ifdef _MUDFLAP | |
35 | #error "Do not compile this file with -fmudflap!" | |
36 | #endif | |
37 | ||
38 | ||
06fb0460 JW |
39 | extern char _end[]; |
40 | extern char ENTRY_POINT[]; | |
6de9cd9a DN |
41 | |
42 | ||
fb925a51 | 43 | /* Run some quick validation of the given region. |
6de9cd9a DN |
44 | Return -1 / 0 / 1 if the access known-invalid, possibly-valid, or known-valid. |
45 | */ | |
fb925a51 | 46 | int |
6de9cd9a DN |
47 | __mf_heuristic_check (uintptr_t ptr, uintptr_t ptr_high) |
48 | { | |
49 | VERBOSE_TRACE ("mf: heuristic check\n"); | |
50 | ||
51 | /* XXX: Disable the stack bounding check for libmudflapth. We do | |
52 | actually have enough information to track stack bounds (see | |
53 | __mf_pthread_info in mf-hooks.c), so with a bit of future work, | |
54 | this heuristic can be turned on. */ | |
55 | #ifndef LIBMUDFLAPTH | |
56 | ||
57 | /* The first heuristic is to check stack bounds. This is a | |
58 | transient condition and quick to check. */ | |
59 | if (__mf_opts.heur_stack_bound) | |
60 | { | |
61 | uintptr_t stack_top_guess = (uintptr_t)__builtin_frame_address(0); | |
62 | #if defined(__i386__) && defined (__linux__) | |
63 | uintptr_t stack_segment_base = 0xC0000000; /* XXX: Bad assumption. */ | |
64 | #else | |
65 | /* Cause tests to fail. */ | |
66 | uintptr_t stack_segment_base = 0; | |
67 | #endif | |
68 | ||
fb925a51 | 69 | VERBOSE_TRACE ("mf: stack estimated as %p-%p\n", |
6de9cd9a DN |
70 | (void *) stack_top_guess, (void *) stack_segment_base); |
71 | ||
72 | if (ptr_high <= stack_segment_base && | |
73 | ptr >= stack_top_guess && | |
74 | ptr_high >= ptr) | |
75 | { | |
76 | return 1; | |
fb925a51 | 77 | } |
6de9cd9a DN |
78 | } |
79 | #endif | |
80 | ||
81 | ||
82 | /* The second heuristic is to scan the range of memory regions | |
83 | listed in /proc/self/maps, a special file provided by the Linux | |
84 | kernel. Its results may be cached, and in fact, a GUESS object | |
85 | may as well be recorded for interesting matching sections. */ | |
86 | if (__mf_opts.heur_proc_map) | |
87 | { | |
88 | /* Keep a record of seen records from /proc/self/map. */ | |
89 | enum { max_entries = 500 }; | |
90 | struct proc_self_map_entry | |
91 | { | |
92 | uintptr_t low; | |
93 | uintptr_t high; | |
94 | }; | |
95 | static struct proc_self_map_entry entry [max_entries]; | |
96 | static unsigned entry_used [max_entries]; | |
97 | ||
98 | /* Look for a known proc_self_map entry that may cover this | |
99 | region. If one exists, then this heuristic has already run, | |
100 | and should not be run again. The check should be allowed to | |
101 | fail. */ | |
102 | unsigned i; | |
103 | unsigned deja_vu = 0; | |
104 | for (i=0; i<max_entries; i++) | |
105 | { | |
106 | if (entry_used[i] && | |
107 | (entry[i].low <= ptr) && | |
108 | (entry[i].high >= ptr_high)) | |
109 | deja_vu = 1; | |
110 | } | |
111 | ||
112 | if (! deja_vu) | |
113 | { | |
114 | /* Time to run the heuristic. Rescan /proc/self/maps; update the | |
fb925a51 | 115 | entry[] array; XXX: remove expired entries, add new ones. |
6de9cd9a DN |
116 | XXX: Consider entries that have grown (e.g., stack). */ |
117 | char buf[512]; | |
118 | char flags[4]; | |
119 | void *low, *high; | |
120 | FILE *fp; | |
fb925a51 | 121 | |
6de9cd9a DN |
122 | fp = fopen ("/proc/self/maps", "r"); |
123 | if (fp) | |
124 | { | |
125 | while (fgets (buf, sizeof(buf), fp)) | |
126 | { | |
127 | if (sscanf (buf, "%p-%p %4c", &low, &high, flags) == 3) | |
128 | { | |
129 | if ((uintptr_t) low <= ptr && | |
130 | (uintptr_t) high >= ptr_high) | |
131 | { | |
132 | for (i=0; i<max_entries; i++) | |
133 | { | |
134 | if (! entry_used[i]) | |
135 | { | |
136 | entry[i].low = (uintptr_t) low; | |
137 | entry[i].high = (uintptr_t) high; | |
138 | entry_used[i] = 1; | |
139 | break; | |
140 | } | |
141 | } | |
fb925a51 | 142 | |
6de9cd9a DN |
143 | VERBOSE_TRACE ("mf: registering region #%d " |
144 | "%p-%p given %s", | |
145 | i, (void *) low, (void *) high, buf); | |
fb925a51 | 146 | |
6de9cd9a | 147 | __mfu_register ((void *) low, (size_t) (high-low), |
fb925a51 | 148 | __MF_TYPE_GUESS, |
6de9cd9a | 149 | "/proc/self/maps segment"); |
fb925a51 | 150 | |
6de9cd9a | 151 | return 0; /* undecided (tending to cachable) */ |
fb925a51 | 152 | } |
6de9cd9a DN |
153 | } |
154 | } | |
155 | fclose (fp); | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | ||
7741b451 MR |
161 | /* The third heuristic is to approve all accesses between _start (or its |
162 | equivalent for the given target) and _end, which should include all | |
163 | text and initialized data. */ | |
6de9cd9a | 164 | if (__mf_opts.heur_start_end) |
7741b451 | 165 | if (ptr >= (uintptr_t) & ENTRY_POINT && ptr_high <= (uintptr_t) & _end) |
6de9cd9a DN |
166 | return 1; /* uncacheable */ |
167 | ||
168 | return 0; /* unknown */ | |
169 | } |