annotate libvtv/vtv_rts.cc @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1 /* Copyright (C) 2012-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
2
kono
parents:
diff changeset
3 This file is part of GCC.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 GCC is free software; you can redistribute it and/or modify
kono
parents:
diff changeset
6 it under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
7 the Free Software Foundation; either version 3, or (at your option)
kono
parents:
diff changeset
8 any later version.
kono
parents:
diff changeset
9
kono
parents:
diff changeset
10 GCC is distributed in the hope that it will be useful,
kono
parents:
diff changeset
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
kono
parents:
diff changeset
13 GNU General Public License for more details.
kono
parents:
diff changeset
14
kono
parents:
diff changeset
15 Under Section 7 of GPL version 3, you are granted additional
kono
parents:
diff changeset
16 permissions described in the GCC Runtime Library Exception, version
kono
parents:
diff changeset
17 3.1, as published by the Free Software Foundation.
kono
parents:
diff changeset
18
kono
parents:
diff changeset
19 You should have received a copy of the GNU General Public License and
kono
parents:
diff changeset
20 a copy of the GCC Runtime Library Exception along with this program;
kono
parents:
diff changeset
21 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
kono
parents:
diff changeset
22 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
23
kono
parents:
diff changeset
24 /* This file is part of the vtable security feature implementation.
kono
parents:
diff changeset
25 The vtable security feature is designed to detect when a virtual
kono
parents:
diff changeset
26 call is about to be made through an invalid vtable pointer
kono
parents:
diff changeset
27 (possibly due to data corruption or malicious attacks). The
kono
parents:
diff changeset
28 compiler finds every virtual call, and inserts a verification call
kono
parents:
diff changeset
29 before the virtual call. The verification call takes the actual
kono
parents:
diff changeset
30 vtable pointer value in the object through which the virtual call
kono
parents:
diff changeset
31 is being made, and compares the vtable pointer against a set of all
kono
parents:
diff changeset
32 valid vtable pointers that the object could contain (this set is
kono
parents:
diff changeset
33 based on the declared type of the object). If the pointer is in
kono
parents:
diff changeset
34 the valid set, execution is allowed to continue; otherwise the
kono
parents:
diff changeset
35 program is halted.
kono
parents:
diff changeset
36
kono
parents:
diff changeset
37 There are several pieces needed in order to make this work: 1. For
kono
parents:
diff changeset
38 every virtual class in the program (i.e. a class that contains
kono
parents:
diff changeset
39 virtual methods), we need to build the set of all possible valid
kono
parents:
diff changeset
40 vtables that an object of that class could point to. This includes
kono
parents:
diff changeset
41 vtables for any class(es) that inherit from the class under
kono
parents:
diff changeset
42 consideration. 2. For every such data set we build up, we need a
kono
parents:
diff changeset
43 way to find and reference the data set. This is complicated by the
kono
parents:
diff changeset
44 fact that the real vtable addresses are not known until runtime,
kono
parents:
diff changeset
45 when the program is loaded into memory, but we need to reference the
kono
parents:
diff changeset
46 sets at compile time when we are inserting verification calls into
kono
parents:
diff changeset
47 the program. 3. We need to find every virtual call in the program,
kono
parents:
diff changeset
48 and insert the verification call (with the appropriate arguments)
kono
parents:
diff changeset
49 before the virtual call. 4. We need some runtime library pieces:
kono
parents:
diff changeset
50 the code to build up the data sets at runtime; the code to actually
kono
parents:
diff changeset
51 perform the verification using the data sets; and some code to set
kono
parents:
diff changeset
52 protections on the data sets, so they themselves do not become
kono
parents:
diff changeset
53 hacker targets.
kono
parents:
diff changeset
54
kono
parents:
diff changeset
55 To find and reference the set of valid vtable pointers for any given
kono
parents:
diff changeset
56 virtual class, we create a special global varible for each virtual
kono
parents:
diff changeset
57 class. We refer to this as the "vtable map variable" for that
kono
parents:
diff changeset
58 class. The vtable map variable has the type "void *", and is
kono
parents:
diff changeset
59 initialized by the compiler to NULL. At runtime when the set of
kono
parents:
diff changeset
60 valid vtable pointers for a virtual class, e.g. class Foo, is built,
kono
parents:
diff changeset
61 the vtable map variable for class Foo is made to point to the set.
kono
parents:
diff changeset
62 During compile time, when the compiler is inserting verification
kono
parents:
diff changeset
63 calls into the program, it passes the vtable map variable for the
kono
parents:
diff changeset
64 appropriate class to the verification call, so that at runtime the
kono
parents:
diff changeset
65 verification call can find the appropriate data set.
kono
parents:
diff changeset
66
kono
parents:
diff changeset
67 The actual set of valid vtable pointers for a polymorphic class,
kono
parents:
diff changeset
68 e.g. class Foo, cannot be built until runtime, when the vtables get
kono
parents:
diff changeset
69 loaded into memory and their addresses are known. But the knowledge
kono
parents:
diff changeset
70 about which vtables belong in which class' hierarchy is only known
kono
parents:
diff changeset
71 at compile time. Therefore at compile time we collect class
kono
parents:
diff changeset
72 hierarchy and vtable information about every virtual class, and we
kono
parents:
diff changeset
73 generate calls to build up the data sets at runtime. To build the
kono
parents:
diff changeset
74 data sets, we call one of the functions we add to the runtime
kono
parents:
diff changeset
75 library, __VLTRegisterPair. __VLTRegisterPair takes two arguments,
kono
parents:
diff changeset
76 a vtable map variable and the address of a vtable. If the vtable
kono
parents:
diff changeset
77 map variable is currently NULL, it creates a new data set (hash
kono
parents:
diff changeset
78 table), makes the vtable map variable point to the new data set, and
kono
parents:
diff changeset
79 inserts the vtable address into the data set. If the vtable map
kono
parents:
diff changeset
80 variable is not NULL, it just inserts the vtable address into the
kono
parents:
diff changeset
81 data set. In order to make sure that our data sets are built before
kono
parents:
diff changeset
82 any verification calls happen, we create a special constructor
kono
parents:
diff changeset
83 initialization function for each compilation unit, give it a very
kono
parents:
diff changeset
84 high initialization priority, and insert all of our calls to
kono
parents:
diff changeset
85 __VLTRegisterPair into our special constructor initialization
kono
parents:
diff changeset
86 function. */
kono
parents:
diff changeset
87
kono
parents:
diff changeset
88 /* This file contains the main externally visible runtime library
kono
parents:
diff changeset
89 functions for vtable verification: __VLTChangePermission,
kono
parents:
diff changeset
90 __VLTRegisterPair, and __VLTVerifyVtablePointer. It also contains
kono
parents:
diff changeset
91 debug versions __VLTRegisterPairDebug and
kono
parents:
diff changeset
92 __VLTVerifyVtablePointerDebug, which have extra parameters in order
kono
parents:
diff changeset
93 to make it easier to debug verification failures.
kono
parents:
diff changeset
94
kono
parents:
diff changeset
95 The final piece of functionality implemented in this file is symbol
kono
parents:
diff changeset
96 resolution for multiple instances of the same vtable map variable.
kono
parents:
diff changeset
97 If the same virtual class is used in two different compilation
kono
parents:
diff changeset
98 units, then each compilation unit will create a vtable map variable
kono
parents:
diff changeset
99 for the class. We need all instances of the same vtable map
kono
parents:
diff changeset
100 variable to point to the same (single) set of valid vtable
kono
parents:
diff changeset
101 pointers for the class, so we wrote our own hashtable-based symbol
kono
parents:
diff changeset
102 resolution for vtable map variables (with a tiny optimization in
kono
parents:
diff changeset
103 the case where there is only one instance of the variable).
kono
parents:
diff changeset
104
kono
parents:
diff changeset
105 There are two other important pieces to the runtime for vtable
kono
parents:
diff changeset
106 verification besides the main pieces that go into libstdc++.so: two
kono
parents:
diff changeset
107 special tiny shared libraries, libvtv_init.so and libvtv_stubs.so.
kono
parents:
diff changeset
108 libvtv_init.so is built from vtv_init.cc. It is designed to help
kono
parents:
diff changeset
109 minimize the calls made to mprotect (see the comments in
kono
parents:
diff changeset
110 vtv_init.cc for more details). Anything compiled with
kono
parents:
diff changeset
111 "-fvtable-verify=std" must be linked with libvtv_init.so (the gcc
kono
parents:
diff changeset
112 driver has been modified to do this). vtv_stubs.so is built from
kono
parents:
diff changeset
113 vtv_stubs.cc. It replaces the main runtime functions
kono
parents:
diff changeset
114 (__VLTChangePermissino, __VLTRegisterPair and
kono
parents:
diff changeset
115 __VLTVerifyVtablePointer) with stub functions that do nothing. If
kono
parents:
diff changeset
116 a programmer has a library that was built with verification, but
kono
parents:
diff changeset
117 wishes to not have verification turned on, the programmer can link
kono
parents:
diff changeset
118 in the vtv_stubs.so library. */
kono
parents:
diff changeset
119
kono
parents:
diff changeset
120 #include <stdlib.h>
kono
parents:
diff changeset
121 #include <stdio.h>
kono
parents:
diff changeset
122 #include <string.h>
kono
parents:
diff changeset
123 #if defined (__CYGWIN__) || defined (__MINGW32__)
kono
parents:
diff changeset
124 #include <windows.h>
kono
parents:
diff changeset
125 #include <winternl.h>
kono
parents:
diff changeset
126 #include <psapi.h>
kono
parents:
diff changeset
127 #else
kono
parents:
diff changeset
128 #include <execinfo.h>
kono
parents:
diff changeset
129 #endif
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 #include <unistd.h>
kono
parents:
diff changeset
132 #if !defined (__CYGWIN__) && !defined (__MINGW32__)
kono
parents:
diff changeset
133 #include <sys/mman.h>
kono
parents:
diff changeset
134 #include <link.h>
kono
parents:
diff changeset
135 #endif
kono
parents:
diff changeset
136 #include <errno.h>
kono
parents:
diff changeset
137 #include <fcntl.h>
kono
parents:
diff changeset
138 #include <limits.h>
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 /* For gthreads suppport */
kono
parents:
diff changeset
141 #include <bits/c++config.h>
kono
parents:
diff changeset
142 #include <ext/concurrence.h>
kono
parents:
diff changeset
143
kono
parents:
diff changeset
144 #include "vtv_utils.h"
kono
parents:
diff changeset
145 #include "vtv_malloc.h"
kono
parents:
diff changeset
146 #include "vtv_set.h"
kono
parents:
diff changeset
147 #include "vtv_map.h"
kono
parents:
diff changeset
148 #include "vtv_rts.h"
kono
parents:
diff changeset
149 #include "vtv_fail.h"
kono
parents:
diff changeset
150
kono
parents:
diff changeset
151 #include "vtv-change-permission.h"
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 #ifdef HAVE_GETEXECNAME
kono
parents:
diff changeset
154 const char *program_invocation_name;
kono
parents:
diff changeset
155 #endif
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 #ifdef HAVE___FORTIFY_FAIL
kono
parents:
diff changeset
158 extern "C" {
kono
parents:
diff changeset
159
kono
parents:
diff changeset
160 /* __fortify_fail is a function in glibc that calls __libc_message,
kono
parents:
diff changeset
161 causing it to print out a program termination error message
kono
parents:
diff changeset
162 (including the name of the binary being terminated), a stack
kono
parents:
diff changeset
163 trace where the error occurred, and a memory map dump. Ideally
kono
parents:
diff changeset
164 we would have called __libc_message directly, but that function
kono
parents:
diff changeset
165 does not appear to be accessible to functions outside glibc,
kono
parents:
diff changeset
166 whereas __fortify_fail is. We call __fortify_fail from
kono
parents:
diff changeset
167 __vtv_really_fail. We looked at calling __libc_fatal, which is
kono
parents:
diff changeset
168 externally accessible, but it does not do the back trace and
kono
parents:
diff changeset
169 memory dump. */
kono
parents:
diff changeset
170
kono
parents:
diff changeset
171 extern void __fortify_fail (const char *) __attribute__((noreturn));
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 } /* extern "C" */
kono
parents:
diff changeset
174 #else
kono
parents:
diff changeset
175 #if defined (__CYGWIN__) || defined (__MINGW32__)
kono
parents:
diff changeset
176 // porting: fix link error to libc
kono
parents:
diff changeset
177 void __fortify_fail (const char * msg){
kono
parents:
diff changeset
178 OutputDebugString(msg);
kono
parents:
diff changeset
179 abort();
kono
parents:
diff changeset
180 }
kono
parents:
diff changeset
181 #else
kono
parents:
diff changeset
182 // FIXME: Provide backtrace via libbacktrace?
kono
parents:
diff changeset
183 void __fortify_fail (const char *msg) {
kono
parents:
diff changeset
184 write (2, msg, strlen (msg));
kono
parents:
diff changeset
185 abort ();
kono
parents:
diff changeset
186 }
kono
parents:
diff changeset
187 #endif
kono
parents:
diff changeset
188 #endif
kono
parents:
diff changeset
189
kono
parents:
diff changeset
190 /* The following variables are used only for debugging and performance
kono
parents:
diff changeset
191 tuning purposes. Therefore they do not need to be "protected".
kono
parents:
diff changeset
192 They cannot be used to attack the vtable verification system and if
kono
parents:
diff changeset
193 they become corrupted it will not affect the correctness or
kono
parents:
diff changeset
194 security of any of the rest of the vtable verification feature. */
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 unsigned int num_calls_to_regset = 0;
kono
parents:
diff changeset
197 unsigned int num_calls_to_regpair = 0;
kono
parents:
diff changeset
198 unsigned int num_calls_to_verify_vtable = 0;
kono
parents:
diff changeset
199 unsigned long long regset_cycles = 0;
kono
parents:
diff changeset
200 unsigned long long regpair_cycles = 0;
kono
parents:
diff changeset
201 unsigned long long verify_vtable_cycles = 0;
kono
parents:
diff changeset
202
kono
parents:
diff changeset
203 /* Be careful about initialization of statics in this file. Some of
kono
parents:
diff changeset
204 the routines below are called before any runtime initialization for
kono
parents:
diff changeset
205 statics in this file will be done. For example, dont try to
kono
parents:
diff changeset
206 initialize any of these statics with a runtime call (for ex:
kono
parents:
diff changeset
207 sysconf). The initialization will happen after calls to the routines
kono
parents:
diff changeset
208 to protect/unprotec the vtabla_map variables */
kono
parents:
diff changeset
209
kono
parents:
diff changeset
210 /* No need to mark the following variables with VTV_PROTECTED_VAR.
kono
parents:
diff changeset
211 These are either const or are only used for debugging/tracing.
kono
parents:
diff changeset
212 debugging/tracing will not be ON on production environments */
kono
parents:
diff changeset
213
kono
parents:
diff changeset
214 static const bool debug_hash = HASHTABLE_STATS;
kono
parents:
diff changeset
215
kono
parents:
diff changeset
216 #ifdef VTV_DEBUG
kono
parents:
diff changeset
217 static const int debug_functions = 1;
kono
parents:
diff changeset
218 static const int debug_init = 1;
kono
parents:
diff changeset
219 static const int debug_verify_vtable = 1;
kono
parents:
diff changeset
220 #else
kono
parents:
diff changeset
221 static const int debug_functions = 0;
kono
parents:
diff changeset
222 static const int debug_init = 0;
kono
parents:
diff changeset
223 static const int debug_verify_vtable = 0;
kono
parents:
diff changeset
224 #endif
kono
parents:
diff changeset
225
kono
parents:
diff changeset
226 /* Global file descriptor variables for logging, tracing and debugging. */
kono
parents:
diff changeset
227
kono
parents:
diff changeset
228 static int init_log_fd = -1;
kono
parents:
diff changeset
229 static int verify_vtable_log_fd = -1;
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 /* This holds a formatted error logging message, to be written to the
kono
parents:
diff changeset
232 vtable verify failures log. */
kono
parents:
diff changeset
233 static char debug_log_message[1024];
kono
parents:
diff changeset
234
kono
parents:
diff changeset
235
kono
parents:
diff changeset
236 #ifdef __GTHREAD_MUTEX_INIT
kono
parents:
diff changeset
237 static __gthread_mutex_t change_permissions_lock = __GTHREAD_MUTEX_INIT;
kono
parents:
diff changeset
238 #else
kono
parents:
diff changeset
239 static __gthread_mutex_t change_permissions_lock;
kono
parents:
diff changeset
240 #endif
kono
parents:
diff changeset
241
kono
parents:
diff changeset
242
kono
parents:
diff changeset
243 #ifndef VTV_STATS
kono
parents:
diff changeset
244 #define VTV_STATS 0
kono
parents:
diff changeset
245 #endif
kono
parents:
diff changeset
246
kono
parents:
diff changeset
247 #if VTV_STATS
kono
parents:
diff changeset
248
kono
parents:
diff changeset
249 static inline unsigned long long
kono
parents:
diff changeset
250 get_cycle_count (void)
kono
parents:
diff changeset
251 {
kono
parents:
diff changeset
252 return rdtsc();
kono
parents:
diff changeset
253 }
kono
parents:
diff changeset
254
kono
parents:
diff changeset
255 static inline void
kono
parents:
diff changeset
256 accumulate_cycle_count (unsigned long long *sum, unsigned long long start)
kono
parents:
diff changeset
257 {
kono
parents:
diff changeset
258 unsigned long long end = rdtsc();
kono
parents:
diff changeset
259 *sum = *sum + (end - start);
kono
parents:
diff changeset
260 }
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 static inline void
kono
parents:
diff changeset
263 increment_num_calls (unsigned int *num_calls)
kono
parents:
diff changeset
264 {
kono
parents:
diff changeset
265 *num_calls = *num_calls + 1;
kono
parents:
diff changeset
266 }
kono
parents:
diff changeset
267
kono
parents:
diff changeset
268 #else
kono
parents:
diff changeset
269
kono
parents:
diff changeset
270 static inline unsigned long long
kono
parents:
diff changeset
271 get_cycle_count (void)
kono
parents:
diff changeset
272 {
kono
parents:
diff changeset
273 return (unsigned long long) 0;
kono
parents:
diff changeset
274 }
kono
parents:
diff changeset
275
kono
parents:
diff changeset
276 static inline void
kono
parents:
diff changeset
277 accumulate_cycle_count (unsigned long long *sum __attribute__((__unused__)),
kono
parents:
diff changeset
278 unsigned long long start __attribute__((__unused__)))
kono
parents:
diff changeset
279 {
kono
parents:
diff changeset
280 /* Do nothing. */
kono
parents:
diff changeset
281 }
kono
parents:
diff changeset
282
kono
parents:
diff changeset
283 static inline void
kono
parents:
diff changeset
284 increment_num_calls (unsigned int *num_calls __attribute__((__unused__)))
kono
parents:
diff changeset
285 {
kono
parents:
diff changeset
286 /* Do nothing. */
kono
parents:
diff changeset
287 }
kono
parents:
diff changeset
288
kono
parents:
diff changeset
289 #endif
kono
parents:
diff changeset
290
kono
parents:
diff changeset
291 /* Types needed by insert_only_hash_sets. */
kono
parents:
diff changeset
292 typedef uintptr_t int_vptr;
kono
parents:
diff changeset
293
kono
parents:
diff changeset
294 /* The set of valid vtable pointers for each virtual class is stored
kono
parents:
diff changeset
295 in a hash table. This is the hashing function used for the hash
kono
parents:
diff changeset
296 table. For more information on the implementation of the hash
kono
parents:
diff changeset
297 table, see the class insert_only_hash_sets in vtv_set.h. */
kono
parents:
diff changeset
298
kono
parents:
diff changeset
299 struct vptr_hash
kono
parents:
diff changeset
300 {
kono
parents:
diff changeset
301 /* Hash function, used to convert vtable pointer, V, (a memory
kono
parents:
diff changeset
302 address) into an index into the hash table. */
kono
parents:
diff changeset
303 size_t
kono
parents:
diff changeset
304 operator() (int_vptr v) const
kono
parents:
diff changeset
305 {
kono
parents:
diff changeset
306 const uint32_t x = 0x7a35e4d9;
kono
parents:
diff changeset
307 const int shift = (sizeof (v) == 8) ? 23 : 21;
kono
parents:
diff changeset
308 v = x * v;
kono
parents:
diff changeset
309 return v ^ (v >> shift);
kono
parents:
diff changeset
310 }
kono
parents:
diff changeset
311 };
kono
parents:
diff changeset
312
kono
parents:
diff changeset
313 /* This is the memory allocator used to create the hash table data
kono
parents:
diff changeset
314 sets of valid vtable pointers. We use VTV_malloc in order to keep
kono
parents:
diff changeset
315 track of which pages have been allocated, so we can update the
kono
parents:
diff changeset
316 protections on those pages appropriately. See the class
kono
parents:
diff changeset
317 insert_only_hash_sets in vtv_set.h for more information. */
kono
parents:
diff changeset
318
kono
parents:
diff changeset
319 struct vptr_set_alloc
kono
parents:
diff changeset
320 {
kono
parents:
diff changeset
321 /* Memory allocator operator. N is the number of bytes to be
kono
parents:
diff changeset
322 allocated. */
kono
parents:
diff changeset
323 void *
kono
parents:
diff changeset
324 operator() (size_t n) const
kono
parents:
diff changeset
325 {
kono
parents:
diff changeset
326 return __vtv_malloc (n);
kono
parents:
diff changeset
327 }
kono
parents:
diff changeset
328 };
kono
parents:
diff changeset
329
kono
parents:
diff changeset
330 /* Instantiate the template classes (in vtv_set.h) for our particular
kono
parents:
diff changeset
331 hash table needs. */
kono
parents:
diff changeset
332 typedef insert_only_hash_sets<int_vptr, vptr_hash, vptr_set_alloc> vtv_sets;
kono
parents:
diff changeset
333 typedef vtv_sets::insert_only_hash_set vtv_set;
kono
parents:
diff changeset
334 typedef vtv_set * vtv_set_handle;
kono
parents:
diff changeset
335 typedef vtv_set_handle * vtv_set_handle_handle;
kono
parents:
diff changeset
336
kono
parents:
diff changeset
337 /* Records for caching the section header information that we have
kono
parents:
diff changeset
338 read out of the file(s) on disk (in dl_iterate_phdr_callback), to
kono
parents:
diff changeset
339 avoid having to re-open and re-read the same file multiple
kono
parents:
diff changeset
340 times. */
kono
parents:
diff changeset
341
kono
parents:
diff changeset
342 struct sect_hdr_data
kono
parents:
diff changeset
343 {
kono
parents:
diff changeset
344 #if defined (__CYGWIN__) || defined (__MINGW32__)
kono
parents:
diff changeset
345 uintptr_t dlpi_addr; /* The header address in the INFO record,
kono
parents:
diff changeset
346 passed in from dl_iterate_phdr. */
kono
parents:
diff changeset
347 uintptr_t mp_low; /* Start address of the .vtable_map_vars
kono
parents:
diff changeset
348 section in memory. */
kono
parents:
diff changeset
349 #else
kono
parents:
diff changeset
350 ElfW (Addr) dlpi_addr; /* The header address in the INFO record,
kono
parents:
diff changeset
351 passed in from dl_iterate_phdr. */
kono
parents:
diff changeset
352 ElfW (Addr) mp_low; /* Start address of the .vtable_map_vars
kono
parents:
diff changeset
353 section in memory. */
kono
parents:
diff changeset
354 #endif
kono
parents:
diff changeset
355 size_t mp_size; /* Size of the .vtable_map_vars section in
kono
parents:
diff changeset
356 memory. */
kono
parents:
diff changeset
357 };
kono
parents:
diff changeset
358
kono
parents:
diff changeset
359 /* Array for caching the section header information, read from file,
kono
parents:
diff changeset
360 to avoid re-opening and re-reading the same file over-and-over
kono
parents:
diff changeset
361 again. */
kono
parents:
diff changeset
362
kono
parents:
diff changeset
363 #define MAX_ENTRIES 250
kono
parents:
diff changeset
364 static struct sect_hdr_data vtv_sect_info_cache[MAX_ENTRIES] VTV_PROTECTED_VAR;
kono
parents:
diff changeset
365
kono
parents:
diff changeset
366 unsigned int num_cache_entries VTV_PROTECTED_VAR = 0;
kono
parents:
diff changeset
367
kono
parents:
diff changeset
368 /* This function takes the LOAD_ADDR for an object opened by the
kono
parents:
diff changeset
369 dynamic loader, and checks the array of cached file data to see if
kono
parents:
diff changeset
370 there is an entry with the same addres. If it finds such an entry,
kono
parents:
diff changeset
371 it returns the record for that entry; otherwise it returns
kono
parents:
diff changeset
372 NULL. */
kono
parents:
diff changeset
373
kono
parents:
diff changeset
374 #if defined (__CYGWIN__) || defined (__MINGW32__)
kono
parents:
diff changeset
375 struct sect_hdr_data *
kono
parents:
diff changeset
376 search_cached_file_data (uintptr_t load_addr)
kono
parents:
diff changeset
377 #else
kono
parents:
diff changeset
378 struct sect_hdr_data *
kono
parents:
diff changeset
379 search_cached_file_data (ElfW (Addr) load_addr)
kono
parents:
diff changeset
380 #endif
kono
parents:
diff changeset
381 {
kono
parents:
diff changeset
382 unsigned int i;
kono
parents:
diff changeset
383 for (i = 0; i < num_cache_entries; ++i)
kono
parents:
diff changeset
384 {
kono
parents:
diff changeset
385 if (vtv_sect_info_cache[i].dlpi_addr == load_addr)
kono
parents:
diff changeset
386 return &(vtv_sect_info_cache[i]);
kono
parents:
diff changeset
387 }
kono
parents:
diff changeset
388
kono
parents:
diff changeset
389 return NULL;
kono
parents:
diff changeset
390 }
kono
parents:
diff changeset
391
kono
parents:
diff changeset
392 /* This function tries to read COUNT bytes out of the file referred to
kono
parents:
diff changeset
393 by FD into the buffer BUF. It returns the actual number of bytes
kono
parents:
diff changeset
394 it succeeded in reading. */
kono
parents:
diff changeset
395
kono
parents:
diff changeset
396 static size_t
kono
parents:
diff changeset
397 ReadPersistent (int fd, void *buf, size_t count)
kono
parents:
diff changeset
398 {
kono
parents:
diff changeset
399 char *buf0 = (char *) buf;
kono
parents:
diff changeset
400 size_t num_bytes = 0;
kono
parents:
diff changeset
401 while (num_bytes < count)
kono
parents:
diff changeset
402 {
kono
parents:
diff changeset
403 int len;
kono
parents:
diff changeset
404 len = read (fd, buf0 + num_bytes, count - num_bytes);
kono
parents:
diff changeset
405 if (len < 0)
kono
parents:
diff changeset
406 return -1;
kono
parents:
diff changeset
407 if (len == 0)
kono
parents:
diff changeset
408 break;
kono
parents:
diff changeset
409 num_bytes += len;
kono
parents:
diff changeset
410 }
kono
parents:
diff changeset
411
kono
parents:
diff changeset
412 return num_bytes;
kono
parents:
diff changeset
413 }
kono
parents:
diff changeset
414
kono
parents:
diff changeset
415 /* This function tries to read COUNT bytes, starting at OFFSET from
kono
parents:
diff changeset
416 the file referred to by FD, and put them into BUF. It calls
kono
parents:
diff changeset
417 ReadPersistent to help it do so. It returns the actual number of
kono
parents:
diff changeset
418 bytes read, or -1 if it fails altogether. */
kono
parents:
diff changeset
419
kono
parents:
diff changeset
420 static size_t
kono
parents:
diff changeset
421 ReadFromOffset (int fd, void *buf, const size_t count, const off_t offset)
kono
parents:
diff changeset
422 {
kono
parents:
diff changeset
423 off_t off = lseek (fd, offset, SEEK_SET);
kono
parents:
diff changeset
424 if (off != (off_t) -1)
kono
parents:
diff changeset
425 return ReadPersistent (fd, buf, count);
kono
parents:
diff changeset
426 return -1;
kono
parents:
diff changeset
427 }
kono
parents:
diff changeset
428
kono
parents:
diff changeset
429 /* The function takes a MESSAGE and attempts to write it to the vtable
kono
parents:
diff changeset
430 memory protection log (for debugging purposes). If the file is not
kono
parents:
diff changeset
431 open, it attempts to open the file first. */
kono
parents:
diff changeset
432
kono
parents:
diff changeset
433 static void
kono
parents:
diff changeset
434 log_memory_protection_data (char *message)
kono
parents:
diff changeset
435 {
kono
parents:
diff changeset
436 static int log_fd = -1;
kono
parents:
diff changeset
437
kono
parents:
diff changeset
438 if (log_fd == -1)
kono
parents:
diff changeset
439 log_fd = __vtv_open_log ("vtv_memory_protection_data.log");
kono
parents:
diff changeset
440
kono
parents:
diff changeset
441 __vtv_add_to_log (log_fd, "%s", message);
kono
parents:
diff changeset
442 }
kono
parents:
diff changeset
443
kono
parents:
diff changeset
444 #if defined (__CYGWIN__) || defined (__MINGW32__)
kono
parents:
diff changeset
445 static void
kono
parents:
diff changeset
446 read_section_offset_and_length (char *name,
kono
parents:
diff changeset
447 uintptr_t addr,
kono
parents:
diff changeset
448 const char *sect_name,
kono
parents:
diff changeset
449 int mprotect_flags,
kono
parents:
diff changeset
450 off_t *sect_offset,
kono
parents:
diff changeset
451 WORD *sect_len)
kono
parents:
diff changeset
452 {
kono
parents:
diff changeset
453 bool found = false;
kono
parents:
diff changeset
454 struct sect_hdr_data *cached_data = NULL;
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 /* Check to see if we already have the data for this file. */
kono
parents:
diff changeset
457 cached_data = search_cached_file_data (addr);
kono
parents:
diff changeset
458
kono
parents:
diff changeset
459 if (cached_data)
kono
parents:
diff changeset
460 {
kono
parents:
diff changeset
461 *sect_offset = cached_data->mp_low;
kono
parents:
diff changeset
462 *sect_len = cached_data->mp_size;
kono
parents:
diff changeset
463 return;
kono
parents:
diff changeset
464 }
kono
parents:
diff changeset
465
kono
parents:
diff changeset
466 // check for DOS Header magic bytes
kono
parents:
diff changeset
467 if (*(WORD *)addr == 0x5A4D)
kono
parents:
diff changeset
468 {
kono
parents:
diff changeset
469 int name_len = strlen (sect_name);
kono
parents:
diff changeset
470 int fd = -1;
kono
parents:
diff changeset
471
kono
parents:
diff changeset
472 /* Attempt to open the binary file on disk. */
kono
parents:
diff changeset
473 if (strlen (name) == 0)
kono
parents:
diff changeset
474 {
kono
parents:
diff changeset
475 return;
kono
parents:
diff changeset
476 }
kono
parents:
diff changeset
477 else
kono
parents:
diff changeset
478 fd = open (name, O_RDONLY | O_BINARY);
kono
parents:
diff changeset
479
kono
parents:
diff changeset
480 if (fd != -1)
kono
parents:
diff changeset
481 {
kono
parents:
diff changeset
482 /* Find the section header information in memory. */
kono
parents:
diff changeset
483 PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)addr;
kono
parents:
diff changeset
484 PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((char *)addr
kono
parents:
diff changeset
485 + pDosHeader->e_lfanew);
kono
parents:
diff changeset
486 PIMAGE_FILE_HEADER pFileHeader = &pNtHeaders->FileHeader;
kono
parents:
diff changeset
487
kono
parents:
diff changeset
488 DWORD PointerToStringTable = pFileHeader->PointerToSymbolTable
kono
parents:
diff changeset
489 + (pFileHeader->NumberOfSymbols*0x12);
kono
parents:
diff changeset
490
kono
parents:
diff changeset
491 PIMAGE_SECTION_HEADER sect_hdr =
kono
parents:
diff changeset
492 (PIMAGE_SECTION_HEADER)((char *)&pNtHeaders->OptionalHeader
kono
parents:
diff changeset
493 + pFileHeader->SizeOfOptionalHeader);
kono
parents:
diff changeset
494
kono
parents:
diff changeset
495 /* Loop through all the section headers, looking for one whose
kono
parents:
diff changeset
496 name is ".vtable_map_vars". */
kono
parents:
diff changeset
497
kono
parents:
diff changeset
498 for (int i = 0; i < pFileHeader->NumberOfSections && !found; ++i)
kono
parents:
diff changeset
499 {
kono
parents:
diff changeset
500 char header_name[64];
kono
parents:
diff changeset
501
kono
parents:
diff changeset
502 /* Check if we have to get the section name from the COFF string
kono
parents:
diff changeset
503 table. */
kono
parents:
diff changeset
504 if (sect_hdr[i].Name[0] == '/')
kono
parents:
diff changeset
505 {
kono
parents:
diff changeset
506 if (atoi((const char*)sect_hdr[i].Name+1) == 0)
kono
parents:
diff changeset
507 {
kono
parents:
diff changeset
508 continue;
kono
parents:
diff changeset
509 }
kono
parents:
diff changeset
510
kono
parents:
diff changeset
511 off_t name_offset = PointerToStringTable
kono
parents:
diff changeset
512 + atoi((const char*)sect_hdr[i].Name+1);
kono
parents:
diff changeset
513
kono
parents:
diff changeset
514 size_t bytes_read = ReadFromOffset (fd, &header_name, 64,
kono
parents:
diff changeset
515 name_offset);
kono
parents:
diff changeset
516
kono
parents:
diff changeset
517 VTV_ASSERT (bytes_read > 0);
kono
parents:
diff changeset
518 }
kono
parents:
diff changeset
519 else
kono
parents:
diff changeset
520 {
kono
parents:
diff changeset
521 memcpy (&header_name, sect_hdr[i].Name,
kono
parents:
diff changeset
522 sizeof (sect_hdr[i].Name));
kono
parents:
diff changeset
523 }
kono
parents:
diff changeset
524
kono
parents:
diff changeset
525 if (memcmp (header_name, sect_name, name_len) == 0)
kono
parents:
diff changeset
526 {
kono
parents:
diff changeset
527 /* We found the section; get its load offset and
kono
parents:
diff changeset
528 size. */
kono
parents:
diff changeset
529 *sect_offset = sect_hdr[i].VirtualAddress;
kono
parents:
diff changeset
530 if (sect_hdr[i].Misc.VirtualSize % VTV_PAGE_SIZE != 0)
kono
parents:
diff changeset
531 *sect_len = sect_hdr[i].Misc.VirtualSize + VTV_PAGE_SIZE
kono
parents:
diff changeset
532 - (sect_hdr[i].Misc.VirtualSize % VTV_PAGE_SIZE);
kono
parents:
diff changeset
533 else
kono
parents:
diff changeset
534 *sect_len = sect_hdr[i].Misc.VirtualSize;
kono
parents:
diff changeset
535 found = true;
kono
parents:
diff changeset
536 }
kono
parents:
diff changeset
537 }
kono
parents:
diff changeset
538 close (fd);
kono
parents:
diff changeset
539 }
kono
parents:
diff changeset
540 }
kono
parents:
diff changeset
541
kono
parents:
diff changeset
542 if (*sect_offset != 0 && *sect_len != 0)
kono
parents:
diff changeset
543 {
kono
parents:
diff changeset
544 /* Calculate the page location in memory, making sure the
kono
parents:
diff changeset
545 address is page-aligned. */
kono
parents:
diff changeset
546 uintptr_t start_addr = addr + *sect_offset;
kono
parents:
diff changeset
547 *sect_offset = start_addr & ~(VTV_PAGE_SIZE - 1);
kono
parents:
diff changeset
548 *sect_len = *sect_len - 1;
kono
parents:
diff changeset
549
kono
parents:
diff changeset
550 /* Since we got this far, we must not have found these pages in
kono
parents:
diff changeset
551 the cache, so add them to it. NOTE: We could get here either
kono
parents:
diff changeset
552 while making everything read-only or while making everything
kono
parents:
diff changeset
553 read-write. We will only update the cache if we get here on
kono
parents:
diff changeset
554 a read-write (to make absolutely sure the cache is writable
kono
parents:
diff changeset
555 -- also the read-write pass should come before the read-only
kono
parents:
diff changeset
556 pass). */
kono
parents:
diff changeset
557 if ((mprotect_flags & PROT_WRITE)
kono
parents:
diff changeset
558 && num_cache_entries < MAX_ENTRIES)
kono
parents:
diff changeset
559 {
kono
parents:
diff changeset
560 vtv_sect_info_cache[num_cache_entries].dlpi_addr = addr;
kono
parents:
diff changeset
561 vtv_sect_info_cache[num_cache_entries].mp_low = *sect_offset;
kono
parents:
diff changeset
562 vtv_sect_info_cache[num_cache_entries].mp_size = *sect_len;
kono
parents:
diff changeset
563 num_cache_entries++;
kono
parents:
diff changeset
564 }
kono
parents:
diff changeset
565 }
kono
parents:
diff changeset
566 }
kono
parents:
diff changeset
567 #else
kono
parents:
diff changeset
568 static void
kono
parents:
diff changeset
569 read_section_offset_and_length (struct dl_phdr_info *info,
kono
parents:
diff changeset
570 const char *sect_name,
kono
parents:
diff changeset
571 int mprotect_flags,
kono
parents:
diff changeset
572 off_t *sect_offset,
kono
parents:
diff changeset
573 ElfW (Word) *sect_len)
kono
parents:
diff changeset
574 {
kono
parents:
diff changeset
575 char program_name[PATH_MAX];
kono
parents:
diff changeset
576 char *cptr;
kono
parents:
diff changeset
577 bool found = false;
kono
parents:
diff changeset
578 struct sect_hdr_data *cached_data = NULL;
kono
parents:
diff changeset
579 const ElfW (Phdr) *phdr_info = info->dlpi_phdr;
kono
parents:
diff changeset
580 const ElfW (Ehdr) *ehdr_info =
kono
parents:
diff changeset
581 (const ElfW (Ehdr) *) (info->dlpi_addr + info->dlpi_phdr[0].p_vaddr
kono
parents:
diff changeset
582 - info->dlpi_phdr[0].p_offset);
kono
parents:
diff changeset
583
kono
parents:
diff changeset
584
kono
parents:
diff changeset
585 /* Get the name of the main executable. This may or may not include
kono
parents:
diff changeset
586 arguments passed to the program. Find the first space, assume it
kono
parents:
diff changeset
587 is the start of the argument list, and change it to a '\0'. */
kono
parents:
diff changeset
588 #ifdef HAVE_GETEXECNAME
kono
parents:
diff changeset
589 program_invocation_name = getexecname ();
kono
parents:
diff changeset
590 #endif
kono
parents:
diff changeset
591 snprintf (program_name, sizeof (program_name), program_invocation_name);
kono
parents:
diff changeset
592
kono
parents:
diff changeset
593 /* Check to see if we already have the data for this file. */
kono
parents:
diff changeset
594 cached_data = search_cached_file_data (info->dlpi_addr);
kono
parents:
diff changeset
595
kono
parents:
diff changeset
596 if (cached_data)
kono
parents:
diff changeset
597 {
kono
parents:
diff changeset
598 *sect_offset = cached_data->mp_low;
kono
parents:
diff changeset
599 *sect_len = cached_data->mp_size;
kono
parents:
diff changeset
600 return;
kono
parents:
diff changeset
601 }
kono
parents:
diff changeset
602
kono
parents:
diff changeset
603 /* Find the first non-escaped space in the program name and make it
kono
parents:
diff changeset
604 the end of the string. */
kono
parents:
diff changeset
605 cptr = strchr (program_name, ' ');
kono
parents:
diff changeset
606 if (cptr != NULL && cptr[-1] != '\\')
kono
parents:
diff changeset
607 cptr[0] = '\0';
kono
parents:
diff changeset
608
kono
parents:
diff changeset
609 if ((phdr_info->p_type == PT_PHDR || phdr_info->p_type == PT_LOAD)
kono
parents:
diff changeset
610 && (ehdr_info->e_shoff && ehdr_info->e_shnum))
kono
parents:
diff changeset
611 {
kono
parents:
diff changeset
612 int name_len = strlen (sect_name);
kono
parents:
diff changeset
613 int fd = -1;
kono
parents:
diff changeset
614
kono
parents:
diff changeset
615 /* Attempt to open the binary file on disk. */
kono
parents:
diff changeset
616 if (strlen (info->dlpi_name) == 0)
kono
parents:
diff changeset
617 {
kono
parents:
diff changeset
618 /* If the constructor initialization function was put into
kono
parents:
diff changeset
619 the preinit array, then this function will get called
kono
parents:
diff changeset
620 while handling preinit array stuff, in which case
kono
parents:
diff changeset
621 program_invocation_name has not been initialized. In
kono
parents:
diff changeset
622 that case we can get the filename of the executable from
kono
parents:
diff changeset
623 "/proc/self/exe". */
kono
parents:
diff changeset
624 if (strlen (program_name) > 0)
kono
parents:
diff changeset
625 {
kono
parents:
diff changeset
626 if (phdr_info->p_type == PT_PHDR)
kono
parents:
diff changeset
627 fd = open (program_name, O_RDONLY);
kono
parents:
diff changeset
628 }
kono
parents:
diff changeset
629 else
kono
parents:
diff changeset
630 fd = open ("/proc/self/exe", O_RDONLY);
kono
parents:
diff changeset
631 }
kono
parents:
diff changeset
632 else
kono
parents:
diff changeset
633 fd = open (info->dlpi_name, O_RDONLY);
kono
parents:
diff changeset
634
kono
parents:
diff changeset
635 if (fd != -1)
kono
parents:
diff changeset
636 {
kono
parents:
diff changeset
637 /* Find the section header information in the file. */
kono
parents:
diff changeset
638 ElfW (Half) strtab_idx = ehdr_info->e_shstrndx;
kono
parents:
diff changeset
639 ElfW (Shdr) shstrtab;
kono
parents:
diff changeset
640 off_t shstrtab_offset = ehdr_info->e_shoff +
kono
parents:
diff changeset
641 (ehdr_info->e_shentsize * strtab_idx);
kono
parents:
diff changeset
642 size_t bytes_read = ReadFromOffset (fd, &shstrtab, sizeof (shstrtab),
kono
parents:
diff changeset
643 shstrtab_offset);
kono
parents:
diff changeset
644 VTV_ASSERT (bytes_read == sizeof (shstrtab));
kono
parents:
diff changeset
645
kono
parents:
diff changeset
646 ElfW (Shdr) sect_hdr;
kono
parents:
diff changeset
647
kono
parents:
diff changeset
648 /* This code will be needed once we have crated libvtv.so. */
kono
parents:
diff changeset
649 bool is_libvtv = false;
kono
parents:
diff changeset
650
kono
parents:
diff changeset
651 /*
kono
parents:
diff changeset
652 if (strstr (info->dlpi_name, "libvtv.so"))
kono
parents:
diff changeset
653 is_libvtv = true;
kono
parents:
diff changeset
654 */
kono
parents:
diff changeset
655
kono
parents:
diff changeset
656 /* Loop through all the section headers, looking for one whose
kono
parents:
diff changeset
657 name is ".vtable_map_vars". */
kono
parents:
diff changeset
658
kono
parents:
diff changeset
659 for (int i = 0; i < ehdr_info->e_shnum && !found; ++i)
kono
parents:
diff changeset
660 {
kono
parents:
diff changeset
661 off_t offset = ehdr_info->e_shoff + (ehdr_info->e_shentsize * i);
kono
parents:
diff changeset
662
kono
parents:
diff changeset
663 bytes_read = ReadFromOffset (fd, &sect_hdr, sizeof (sect_hdr),
kono
parents:
diff changeset
664 offset);
kono
parents:
diff changeset
665
kono
parents:
diff changeset
666 VTV_ASSERT (bytes_read == sizeof (sect_hdr));
kono
parents:
diff changeset
667
kono
parents:
diff changeset
668 char header_name[64];
kono
parents:
diff changeset
669 off_t name_offset = shstrtab.sh_offset + sect_hdr.sh_name;
kono
parents:
diff changeset
670
kono
parents:
diff changeset
671 bytes_read = ReadFromOffset (fd, &header_name, 64, name_offset);
kono
parents:
diff changeset
672
kono
parents:
diff changeset
673 VTV_ASSERT (bytes_read > 0);
kono
parents:
diff changeset
674
kono
parents:
diff changeset
675 if (memcmp (header_name, sect_name, name_len) == 0)
kono
parents:
diff changeset
676 {
kono
parents:
diff changeset
677 /* We found the section; get its load offset and
kono
parents:
diff changeset
678 size. */
kono
parents:
diff changeset
679 *sect_offset = sect_hdr.sh_addr;
kono
parents:
diff changeset
680 if (!is_libvtv)
kono
parents:
diff changeset
681 {
kono
parents:
diff changeset
682 VTV_ASSERT (sect_hdr.sh_size - VTV_PAGE_SIZE >= 0);
kono
parents:
diff changeset
683 *sect_len = sect_hdr.sh_size - VTV_PAGE_SIZE;
kono
parents:
diff changeset
684 }
kono
parents:
diff changeset
685 else
kono
parents:
diff changeset
686 *sect_len = sect_hdr.sh_size;
kono
parents:
diff changeset
687 found = true;
kono
parents:
diff changeset
688 }
kono
parents:
diff changeset
689 }
kono
parents:
diff changeset
690 close (fd);
kono
parents:
diff changeset
691 }
kono
parents:
diff changeset
692 }
kono
parents:
diff changeset
693
kono
parents:
diff changeset
694 if (*sect_offset != 0 && *sect_len != 0)
kono
parents:
diff changeset
695 {
kono
parents:
diff changeset
696 /* Calculate the page location in memory, making sure the
kono
parents:
diff changeset
697 address is page-aligned. */
kono
parents:
diff changeset
698 ElfW (Addr) start_addr = (const ElfW (Addr)) info->dlpi_addr
kono
parents:
diff changeset
699 + *sect_offset;
kono
parents:
diff changeset
700 *sect_offset = start_addr & ~(VTV_PAGE_SIZE - 1);
kono
parents:
diff changeset
701 *sect_len = *sect_len - 1;
kono
parents:
diff changeset
702
kono
parents:
diff changeset
703 /* Since we got this far, we must not have found these pages in
kono
parents:
diff changeset
704 the cache, so add them to it. NOTE: We could get here either
kono
parents:
diff changeset
705 while making everything read-only or while making everything
kono
parents:
diff changeset
706 read-write. We will only update the cache if we get here on
kono
parents:
diff changeset
707 a read-write (to make absolutely sure the cache is writable
kono
parents:
diff changeset
708 -- also the read-write pass should come before the read-only
kono
parents:
diff changeset
709 pass). */
kono
parents:
diff changeset
710 if ((mprotect_flags & PROT_WRITE)
kono
parents:
diff changeset
711 && num_cache_entries < MAX_ENTRIES)
kono
parents:
diff changeset
712 {
kono
parents:
diff changeset
713 vtv_sect_info_cache[num_cache_entries].dlpi_addr = info->dlpi_addr;
kono
parents:
diff changeset
714 vtv_sect_info_cache[num_cache_entries].mp_low = *sect_offset;
kono
parents:
diff changeset
715 vtv_sect_info_cache[num_cache_entries].mp_size = *sect_len;
kono
parents:
diff changeset
716 num_cache_entries++;
kono
parents:
diff changeset
717 }
kono
parents:
diff changeset
718 }
kono
parents:
diff changeset
719 }
kono
parents:
diff changeset
720 #endif
kono
parents:
diff changeset
721
kono
parents:
diff changeset
722 #if defined (__CYGWIN__) || defined (__MINGW32__)
kono
parents:
diff changeset
723 /* This function is used to iterate over all loaded modules and searches
kono
parents:
diff changeset
724 for a section called ".vtable_map_vars". The only interaction with
kono
parents:
diff changeset
725 the binary file on disk of the module is to read section names in the
kono
parents:
diff changeset
726 COFF string table. If the module contains a ".vtable_map_vars" section,
kono
parents:
diff changeset
727 read section offset and size from the section header of the loaded module.
kono
parents:
diff changeset
728 Call 'mprotect' on those pages, setting the protection either to
kono
parents:
diff changeset
729 read-only or read-write, depending on what's in data.
kono
parents:
diff changeset
730 The calls to change the protection occur in vtv_unprotect_vtable_vars
kono
parents:
diff changeset
731 and vtv_protect_vtable_vars. */
kono
parents:
diff changeset
732
kono
parents:
diff changeset
733 static int
kono
parents:
diff changeset
734 iterate_modules (void *data)
kono
parents:
diff changeset
735 {
kono
parents:
diff changeset
736 int * mprotect_flags = (int *) data;
kono
parents:
diff changeset
737 off_t map_sect_offset = 0;
kono
parents:
diff changeset
738 WORD map_sect_len = 0;
kono
parents:
diff changeset
739 char buffer[1024];
kono
parents:
diff changeset
740 const char *map_sect_name = VTV_PROTECTED_VARS_SECTION;
kono
parents:
diff changeset
741 HMODULE hMods[1024];
kono
parents:
diff changeset
742 HANDLE hProcess;
kono
parents:
diff changeset
743 DWORD cbNeeded;
kono
parents:
diff changeset
744
kono
parents:
diff changeset
745 hProcess = GetCurrentProcess ();
kono
parents:
diff changeset
746
kono
parents:
diff changeset
747 if (NULL == hProcess)
kono
parents:
diff changeset
748 return 0;
kono
parents:
diff changeset
749
kono
parents:
diff changeset
750 if (EnumProcessModules (hProcess, hMods, sizeof (hMods), &cbNeeded))
kono
parents:
diff changeset
751 {
kono
parents:
diff changeset
752 /* Iterate over all loaded modules. */
kono
parents:
diff changeset
753 for (unsigned int i = 0; i < (cbNeeded / sizeof (HMODULE)); i++)
kono
parents:
diff changeset
754 {
kono
parents:
diff changeset
755 char szModName[MAX_PATH];
kono
parents:
diff changeset
756
kono
parents:
diff changeset
757 if (GetModuleFileNameExA (hProcess, hMods[i], szModName,
kono
parents:
diff changeset
758 sizeof (szModName)))
kono
parents:
diff changeset
759 {
kono
parents:
diff changeset
760 map_sect_offset = 0;
kono
parents:
diff changeset
761 map_sect_len = 0;
kono
parents:
diff changeset
762 read_section_offset_and_length (szModName,
kono
parents:
diff changeset
763 (uintptr_t) hMods[i],
kono
parents:
diff changeset
764 map_sect_name,
kono
parents:
diff changeset
765 *mprotect_flags,
kono
parents:
diff changeset
766 &map_sect_offset,
kono
parents:
diff changeset
767 &map_sect_len);
kono
parents:
diff changeset
768
kono
parents:
diff changeset
769 if (debug_functions)
kono
parents:
diff changeset
770 {
kono
parents:
diff changeset
771 snprintf (buffer, sizeof(buffer),
kono
parents:
diff changeset
772 " Looking at load module %s to change permissions to %s\n",
kono
parents:
diff changeset
773 szModName,
kono
parents:
diff changeset
774 (*mprotect_flags & PROT_WRITE) ? "READ/WRITE" : "READ-ONLY");
kono
parents:
diff changeset
775 log_memory_protection_data (buffer);
kono
parents:
diff changeset
776 }
kono
parents:
diff changeset
777
kono
parents:
diff changeset
778 /* See if we actually found the section. */
kono
parents:
diff changeset
779 if (map_sect_offset && map_sect_len)
kono
parents:
diff changeset
780 {
kono
parents:
diff changeset
781 unsigned long long start;
kono
parents:
diff changeset
782 int result;
kono
parents:
diff changeset
783
kono
parents:
diff changeset
784 if (debug_functions)
kono
parents:
diff changeset
785 {
kono
parents:
diff changeset
786 snprintf (buffer, sizeof (buffer),
kono
parents:
diff changeset
787 " (%s): Protecting %p to %p\n",
kono
parents:
diff changeset
788 szModName,
kono
parents:
diff changeset
789 (void *) map_sect_offset,
kono
parents:
diff changeset
790 (void *) (map_sect_offset + map_sect_len));
kono
parents:
diff changeset
791 log_memory_protection_data (buffer);
kono
parents:
diff changeset
792 }
kono
parents:
diff changeset
793
kono
parents:
diff changeset
794 /* Change the protections on the pages for the section. */
kono
parents:
diff changeset
795
kono
parents:
diff changeset
796 start = get_cycle_count ();
kono
parents:
diff changeset
797 result = mprotect ((void *) map_sect_offset, map_sect_len,
kono
parents:
diff changeset
798 *mprotect_flags);
kono
parents:
diff changeset
799 accumulate_cycle_count (&mprotect_cycles, start);
kono
parents:
diff changeset
800 if (result == -1)
kono
parents:
diff changeset
801 {
kono
parents:
diff changeset
802 if (debug_functions)
kono
parents:
diff changeset
803 {
kono
parents:
diff changeset
804 snprintf (buffer, sizeof (buffer),
kono
parents:
diff changeset
805 "Failed call to mprotect for %s error: ",
kono
parents:
diff changeset
806 (*mprotect_flags & PROT_WRITE) ?
kono
parents:
diff changeset
807 "READ/WRITE" : "READ-ONLY");
kono
parents:
diff changeset
808 log_memory_protection_data (buffer);
kono
parents:
diff changeset
809 perror(NULL);
kono
parents:
diff changeset
810 }
kono
parents:
diff changeset
811 VTV_error();
kono
parents:
diff changeset
812 }
kono
parents:
diff changeset
813 else
kono
parents:
diff changeset
814 {
kono
parents:
diff changeset
815 if (debug_functions)
kono
parents:
diff changeset
816 {
kono
parents:
diff changeset
817 snprintf (buffer, sizeof (buffer),
kono
parents:
diff changeset
818 "mprotect'ed range [%p, %p]\n",
kono
parents:
diff changeset
819 (void *) map_sect_offset,
kono
parents:
diff changeset
820 (char *) map_sect_offset + map_sect_len);
kono
parents:
diff changeset
821 log_memory_protection_data (buffer);
kono
parents:
diff changeset
822 }
kono
parents:
diff changeset
823 }
kono
parents:
diff changeset
824 increment_num_calls (&num_calls_to_mprotect);
kono
parents:
diff changeset
825 num_pages_protected += (map_sect_len + VTV_PAGE_SIZE - 1)
kono
parents:
diff changeset
826 / VTV_PAGE_SIZE;
kono
parents:
diff changeset
827 continue;
kono
parents:
diff changeset
828 }
kono
parents:
diff changeset
829 }
kono
parents:
diff changeset
830 }
kono
parents:
diff changeset
831 }
kono
parents:
diff changeset
832
kono
parents:
diff changeset
833 CloseHandle(hProcess);
kono
parents:
diff changeset
834
kono
parents:
diff changeset
835 return 0;
kono
parents:
diff changeset
836 }
kono
parents:
diff changeset
837 #else
kono
parents:
diff changeset
838 /* This is the callback function used by dl_iterate_phdr (which is
kono
parents:
diff changeset
839 called from vtv_unprotect_vtable_vars and vtv_protect_vtable_vars).
kono
parents:
diff changeset
840 It attempts to find the binary file on disk for the INFO record
kono
parents:
diff changeset
841 that dl_iterate_phdr passes in; open the binary file, and read its
kono
parents:
diff changeset
842 section header information. If the file contains a
kono
parents:
diff changeset
843 ".vtable_map_vars" section, read the section offset and size. Use
kono
parents:
diff changeset
844 the section offset and size, in conjunction with the data in INFO
kono
parents:
diff changeset
845 to locate the pages in memory where the section is. Call
kono
parents:
diff changeset
846 'mprotect' on those pages, setting the protection either to
kono
parents:
diff changeset
847 read-only or read-write, depending on what's in DATA. */
kono
parents:
diff changeset
848
kono
parents:
diff changeset
849 static int
kono
parents:
diff changeset
850 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t, void *data)
kono
parents:
diff changeset
851 {
kono
parents:
diff changeset
852 int * mprotect_flags = (int *) data;
kono
parents:
diff changeset
853 off_t map_sect_offset = 0;
kono
parents:
diff changeset
854 ElfW (Word) map_sect_len = 0;
kono
parents:
diff changeset
855 char buffer[1024];
kono
parents:
diff changeset
856 char program_name[1024];
kono
parents:
diff changeset
857 const char *map_sect_name = VTV_PROTECTED_VARS_SECTION;
kono
parents:
diff changeset
858
kono
parents:
diff changeset
859 /* Check to see if this is the record for the Linux Virtual Dynamic
kono
parents:
diff changeset
860 Shared Object (linux-vdso.so.1), which exists only in memory (and
kono
parents:
diff changeset
861 therefore cannot be read from disk). */
kono
parents:
diff changeset
862
kono
parents:
diff changeset
863 if (strcmp (info->dlpi_name, "linux-vdso.so.1") == 0)
kono
parents:
diff changeset
864 return 0;
kono
parents:
diff changeset
865
kono
parents:
diff changeset
866 if (strlen (info->dlpi_name) == 0
kono
parents:
diff changeset
867 && info->dlpi_addr != 0)
kono
parents:
diff changeset
868 return 0;
kono
parents:
diff changeset
869
kono
parents:
diff changeset
870 /* Get the name of the main executable. This may or may not include
kono
parents:
diff changeset
871 arguments passed to the program. Find the first space, assume it
kono
parents:
diff changeset
872 is the start of the argument list, and change it to a '\0'. */
kono
parents:
diff changeset
873 #ifdef HAVE_GETEXECNAME
kono
parents:
diff changeset
874 program_invocation_name = getexecname ();
kono
parents:
diff changeset
875 #endif
kono
parents:
diff changeset
876 snprintf (program_name, sizeof (program_name), program_invocation_name);
kono
parents:
diff changeset
877
kono
parents:
diff changeset
878 read_section_offset_and_length (info, map_sect_name, *mprotect_flags,
kono
parents:
diff changeset
879 &map_sect_offset, &map_sect_len);
kono
parents:
diff changeset
880
kono
parents:
diff changeset
881 if (debug_functions)
kono
parents:
diff changeset
882 {
kono
parents:
diff changeset
883 snprintf (buffer, sizeof(buffer),
kono
parents:
diff changeset
884 " Looking at load module %s to change permissions to %s\n",
kono
parents:
diff changeset
885 ((strlen (info->dlpi_name) == 0) ? program_name
kono
parents:
diff changeset
886 : info->dlpi_name),
kono
parents:
diff changeset
887 (*mprotect_flags & PROT_WRITE) ? "READ/WRITE" : "READ-ONLY");
kono
parents:
diff changeset
888 log_memory_protection_data (buffer);
kono
parents:
diff changeset
889 }
kono
parents:
diff changeset
890
kono
parents:
diff changeset
891 /* See if we actually found the section. */
kono
parents:
diff changeset
892 if (map_sect_offset && map_sect_len)
kono
parents:
diff changeset
893 {
kono
parents:
diff changeset
894 unsigned long long start;
kono
parents:
diff changeset
895 int result;
kono
parents:
diff changeset
896
kono
parents:
diff changeset
897 if (debug_functions)
kono
parents:
diff changeset
898 {
kono
parents:
diff changeset
899 snprintf (buffer, sizeof (buffer),
kono
parents:
diff changeset
900 " (%s): Protecting %p to %p\n",
kono
parents:
diff changeset
901 ((strlen (info->dlpi_name) == 0) ? program_name
kono
parents:
diff changeset
902 : info->dlpi_name),
kono
parents:
diff changeset
903 (void *) map_sect_offset,
kono
parents:
diff changeset
904 (void *) (map_sect_offset + map_sect_len));
kono
parents:
diff changeset
905 log_memory_protection_data (buffer);
kono
parents:
diff changeset
906 }
kono
parents:
diff changeset
907
kono
parents:
diff changeset
908 /* Change the protections on the pages for the section. */
kono
parents:
diff changeset
909
kono
parents:
diff changeset
910 start = get_cycle_count ();
kono
parents:
diff changeset
911 result = mprotect ((void *) map_sect_offset, map_sect_len,
kono
parents:
diff changeset
912 *mprotect_flags);
kono
parents:
diff changeset
913 accumulate_cycle_count (&mprotect_cycles, start);
kono
parents:
diff changeset
914 if (result == -1)
kono
parents:
diff changeset
915 {
kono
parents:
diff changeset
916 if (debug_functions)
kono
parents:
diff changeset
917 {
kono
parents:
diff changeset
918 snprintf (buffer, sizeof (buffer),
kono
parents:
diff changeset
919 "Failed call to mprotect for %s error: ",
kono
parents:
diff changeset
920 (*mprotect_flags & PROT_WRITE) ?
kono
parents:
diff changeset
921 "READ/WRITE" : "READ-ONLY");
kono
parents:
diff changeset
922 log_memory_protection_data (buffer);
kono
parents:
diff changeset
923 perror(NULL);
kono
parents:
diff changeset
924 }
kono
parents:
diff changeset
925 VTV_error();
kono
parents:
diff changeset
926 }
kono
parents:
diff changeset
927 else
kono
parents:
diff changeset
928 {
kono
parents:
diff changeset
929 if (debug_functions)
kono
parents:
diff changeset
930 {
kono
parents:
diff changeset
931 snprintf (buffer, sizeof (buffer),
kono
parents:
diff changeset
932 "mprotect'ed range [%p, %p]\n",
kono
parents:
diff changeset
933 (void *) map_sect_offset,
kono
parents:
diff changeset
934 (char *) map_sect_offset + map_sect_len);
kono
parents:
diff changeset
935 log_memory_protection_data (buffer);
kono
parents:
diff changeset
936 }
kono
parents:
diff changeset
937 }
kono
parents:
diff changeset
938 increment_num_calls (&num_calls_to_mprotect);
kono
parents:
diff changeset
939 num_pages_protected += (map_sect_len + VTV_PAGE_SIZE - 1) / VTV_PAGE_SIZE;
kono
parents:
diff changeset
940 }
kono
parents:
diff changeset
941
kono
parents:
diff changeset
942 return 0;
kono
parents:
diff changeset
943 }
kono
parents:
diff changeset
944 #endif
kono
parents:
diff changeset
945
kono
parents:
diff changeset
946 /* This function explicitly changes the protection (read-only or read-write)
kono
parents:
diff changeset
947 on the vtv_sect_info_cache, which is used for speeding up look ups in the
kono
parents:
diff changeset
948 function dl_iterate_phdr_callback. This data structure needs to be
kono
parents:
diff changeset
949 explicitly made read-write before any calls to dl_iterate_phdr_callback,
kono
parents:
diff changeset
950 because otherwise it may still be read-only when dl_iterate_phdr_callback
kono
parents:
diff changeset
951 attempts to write to it.
kono
parents:
diff changeset
952
kono
parents:
diff changeset
953 More detailed explanation: dl_iterate_phdr_callback finds all the
kono
parents:
diff changeset
954 .vtable_map_vars sections in all loaded objects (including the main program)
kono
parents:
diff changeset
955 and (depending on where it was called from) either makes all the pages in the
kono
parents:
diff changeset
956 sections read-write or read-only. The vtv_sect_info_cache should be in the
kono
parents:
diff changeset
957 .vtable_map_vars section for libstdc++.so, which means that normally it would
kono
parents:
diff changeset
958 be read-only until libstdc++.so is processed by dl_iterate_phdr_callback
kono
parents:
diff changeset
959 (on the read-write pass), after which it will be writable. But if any loaded
kono
parents:
diff changeset
960 object gets processed before libstdc++.so, it will attempt to update the
kono
parents:
diff changeset
961 data cache, which will still be read-only, and cause a seg fault. Hence
kono
parents:
diff changeset
962 we need a special function, called before dl_iterate_phdr_callback, that
kono
parents:
diff changeset
963 will make the data cache writable. */
kono
parents:
diff changeset
964
kono
parents:
diff changeset
965 static void
kono
parents:
diff changeset
966 change_protections_on_phdr_cache (int protection_flag)
kono
parents:
diff changeset
967 {
kono
parents:
diff changeset
968 char * low_address = (char *) &(vtv_sect_info_cache);
kono
parents:
diff changeset
969 size_t cache_size = MAX_ENTRIES * sizeof (struct sect_hdr_data);
kono
parents:
diff changeset
970
kono
parents:
diff changeset
971 low_address = (char *) ((uintptr_t) low_address & ~(VTV_PAGE_SIZE - 1));
kono
parents:
diff changeset
972
kono
parents:
diff changeset
973 if (mprotect ((void *) low_address, cache_size, protection_flag) == -1)
kono
parents:
diff changeset
974 VTV_error ();
kono
parents:
diff changeset
975 }
kono
parents:
diff changeset
976
kono
parents:
diff changeset
977 /* Unprotect all the vtable map vars and other side data that is used
kono
parents:
diff changeset
978 to keep the core hash_map data. All of these data have been put
kono
parents:
diff changeset
979 into relro sections */
kono
parents:
diff changeset
980
kono
parents:
diff changeset
981 static void
kono
parents:
diff changeset
982 vtv_unprotect_vtable_vars (void)
kono
parents:
diff changeset
983 {
kono
parents:
diff changeset
984 int mprotect_flags;
kono
parents:
diff changeset
985
kono
parents:
diff changeset
986 mprotect_flags = PROT_READ | PROT_WRITE;
kono
parents:
diff changeset
987 change_protections_on_phdr_cache (mprotect_flags);
kono
parents:
diff changeset
988 #if defined (__CYGWIN__) || defined (__MINGW32__)
kono
parents:
diff changeset
989 iterate_modules ((void *) &mprotect_flags);
kono
parents:
diff changeset
990 #else
kono
parents:
diff changeset
991 dl_iterate_phdr (dl_iterate_phdr_callback, (void *) &mprotect_flags);
kono
parents:
diff changeset
992 #endif
kono
parents:
diff changeset
993 }
kono
parents:
diff changeset
994
kono
parents:
diff changeset
995 /* Protect all the vtable map vars and other side data that is used
kono
parents:
diff changeset
996 to keep the core hash_map data. All of these data have been put
kono
parents:
diff changeset
997 into relro sections */
kono
parents:
diff changeset
998
kono
parents:
diff changeset
999 static void
kono
parents:
diff changeset
1000 vtv_protect_vtable_vars (void)
kono
parents:
diff changeset
1001 {
kono
parents:
diff changeset
1002 int mprotect_flags;
kono
parents:
diff changeset
1003
kono
parents:
diff changeset
1004 mprotect_flags = PROT_READ;
kono
parents:
diff changeset
1005 #if defined (__CYGWIN__) || defined (__MINGW32__)
kono
parents:
diff changeset
1006 iterate_modules ((void *) &mprotect_flags);
kono
parents:
diff changeset
1007 #else
kono
parents:
diff changeset
1008 dl_iterate_phdr (dl_iterate_phdr_callback, (void *) &mprotect_flags);
kono
parents:
diff changeset
1009 #endif
kono
parents:
diff changeset
1010 change_protections_on_phdr_cache (mprotect_flags);
kono
parents:
diff changeset
1011 }
kono
parents:
diff changeset
1012
kono
parents:
diff changeset
1013 #ifndef __GTHREAD_MUTEX_INIT
kono
parents:
diff changeset
1014 static void
kono
parents:
diff changeset
1015 initialize_change_permissions_mutexes ()
kono
parents:
diff changeset
1016 {
kono
parents:
diff changeset
1017 __GTHREAD_MUTEX_INIT_FUNCTION (&change_permissions_lock);
kono
parents:
diff changeset
1018 }
kono
parents:
diff changeset
1019 #endif
kono
parents:
diff changeset
1020
kono
parents:
diff changeset
1021 /* Variables needed for getting the statistics about the hashtable set. */
kono
parents:
diff changeset
1022 #if HASHTABLE_STATS
kono
parents:
diff changeset
1023 _AtomicStatCounter stat_contains = 0;
kono
parents:
diff changeset
1024 _AtomicStatCounter stat_insert = 0;
kono
parents:
diff changeset
1025 _AtomicStatCounter stat_resize = 0;
kono
parents:
diff changeset
1026 _AtomicStatCounter stat_create = 0;
kono
parents:
diff changeset
1027 _AtomicStatCounter stat_probes_in_non_trivial_set = 0;
kono
parents:
diff changeset
1028 _AtomicStatCounter stat_contains_size0 = 0;
kono
parents:
diff changeset
1029 _AtomicStatCounter stat_contains_size1 = 0;
kono
parents:
diff changeset
1030 _AtomicStatCounter stat_contains_size2 = 0;
kono
parents:
diff changeset
1031 _AtomicStatCounter stat_contains_size3 = 0;
kono
parents:
diff changeset
1032 _AtomicStatCounter stat_contains_size4 = 0;
kono
parents:
diff changeset
1033 _AtomicStatCounter stat_contains_size5 = 0;
kono
parents:
diff changeset
1034 _AtomicStatCounter stat_contains_size6 = 0;
kono
parents:
diff changeset
1035 _AtomicStatCounter stat_contains_size7 = 0;
kono
parents:
diff changeset
1036 _AtomicStatCounter stat_contains_size8 = 0;
kono
parents:
diff changeset
1037 _AtomicStatCounter stat_contains_size9 = 0;
kono
parents:
diff changeset
1038 _AtomicStatCounter stat_contains_size10 = 0;
kono
parents:
diff changeset
1039 _AtomicStatCounter stat_contains_size11 = 0;
kono
parents:
diff changeset
1040 _AtomicStatCounter stat_contains_size12 = 0;
kono
parents:
diff changeset
1041 _AtomicStatCounter stat_contains_size13_or_more = 0;
kono
parents:
diff changeset
1042 _AtomicStatCounter stat_contains_sizes = 0;
kono
parents:
diff changeset
1043 _AtomicStatCounter stat_grow_from_size0_to_1 = 0;
kono
parents:
diff changeset
1044 _AtomicStatCounter stat_grow_from_size1_to_2 = 0;
kono
parents:
diff changeset
1045 _AtomicStatCounter stat_double_the_number_of_buckets = 0;
kono
parents:
diff changeset
1046 _AtomicStatCounter stat_insert_found_hash_collision = 0;
kono
parents:
diff changeset
1047 _AtomicStatCounter stat_contains_in_non_trivial_set = 0;
kono
parents:
diff changeset
1048 _AtomicStatCounter stat_insert_key_that_was_already_present = 0;
kono
parents:
diff changeset
1049 #endif
kono
parents:
diff changeset
1050 /* Record statistics about the hash table sets, for debugging. */
kono
parents:
diff changeset
1051
kono
parents:
diff changeset
1052 static void
kono
parents:
diff changeset
1053 log_set_stats (void)
kono
parents:
diff changeset
1054 {
kono
parents:
diff changeset
1055 #if HASHTABLE_STATS
kono
parents:
diff changeset
1056 if (set_log_fd == -1)
kono
parents:
diff changeset
1057 set_log_fd = __vtv_open_log ("vtv_set_stats.log");
kono
parents:
diff changeset
1058
kono
parents:
diff changeset
1059 __vtv_add_to_log (set_log_fd, "---\n%s\n",
kono
parents:
diff changeset
1060 insert_only_hash_tables_stats().c_str());
kono
parents:
diff changeset
1061 #endif
kono
parents:
diff changeset
1062 }
kono
parents:
diff changeset
1063
kono
parents:
diff changeset
1064 /* Change the permissions on all the pages we have allocated for the
kono
parents:
diff changeset
1065 data sets and all the ".vtable_map_var" sections in memory (which
kono
parents:
diff changeset
1066 contain our vtable map variables). PERM indicates whether to make
kono
parents:
diff changeset
1067 the permissions read-only or read-write. */
kono
parents:
diff changeset
1068
kono
parents:
diff changeset
1069 extern "C" /* This is only being applied to __VLTChangePermission*/
kono
parents:
diff changeset
1070 void
kono
parents:
diff changeset
1071 __VLTChangePermission (int perm)
kono
parents:
diff changeset
1072 {
kono
parents:
diff changeset
1073 if (debug_functions)
kono
parents:
diff changeset
1074 {
kono
parents:
diff changeset
1075 if (perm == __VLTP_READ_WRITE)
kono
parents:
diff changeset
1076 fprintf (stdout, "Changing VLT permissions to Read-Write.\n");
kono
parents:
diff changeset
1077 else if (perm == __VLTP_READ_ONLY)
kono
parents:
diff changeset
1078 fprintf (stdout, "Changing VLT permissions to Read-Only.\n");
kono
parents:
diff changeset
1079
kono
parents:
diff changeset
1080 else
kono
parents:
diff changeset
1081 fprintf (stdout, "Unrecognized permissions value: %d\n", perm);
kono
parents:
diff changeset
1082 }
kono
parents:
diff changeset
1083
kono
parents:
diff changeset
1084 #ifndef __GTHREAD_MUTEX_INIT
kono
parents:
diff changeset
1085 static __gthread_once_t mutex_once VTV_PROTECTED_VAR = __GTHREAD_ONCE_INIT;
kono
parents:
diff changeset
1086
kono
parents:
diff changeset
1087 __gthread_once (&mutex_once, initialize_change_permissions_mutexes);
kono
parents:
diff changeset
1088 #endif
kono
parents:
diff changeset
1089
kono
parents:
diff changeset
1090 /* Ordering of these unprotect/protect calls is very important.
kono
parents:
diff changeset
1091 You first need to unprotect all the map vars and side
kono
parents:
diff changeset
1092 structures before you do anything with the core data
kono
parents:
diff changeset
1093 structures (hash_maps) */
kono
parents:
diff changeset
1094
kono
parents:
diff changeset
1095 if (perm == __VLTP_READ_WRITE)
kono
parents:
diff changeset
1096 {
kono
parents:
diff changeset
1097 /* TODO: Need to revisit this code for dlopen. It most probably
kono
parents:
diff changeset
1098 is not unlocking the protected vtable vars after for load
kono
parents:
diff changeset
1099 module that is not the first load module. */
kono
parents:
diff changeset
1100 __gthread_mutex_lock (&change_permissions_lock);
kono
parents:
diff changeset
1101
kono
parents:
diff changeset
1102 vtv_unprotect_vtable_vars ();
kono
parents:
diff changeset
1103 __vtv_malloc_init ();
kono
parents:
diff changeset
1104 __vtv_malloc_unprotect ();
kono
parents:
diff changeset
1105
kono
parents:
diff changeset
1106 }
kono
parents:
diff changeset
1107 else if (perm == __VLTP_READ_ONLY)
kono
parents:
diff changeset
1108 {
kono
parents:
diff changeset
1109 if (debug_hash)
kono
parents:
diff changeset
1110 log_set_stats();
kono
parents:
diff changeset
1111
kono
parents:
diff changeset
1112 __vtv_malloc_protect ();
kono
parents:
diff changeset
1113 vtv_protect_vtable_vars ();
kono
parents:
diff changeset
1114
kono
parents:
diff changeset
1115 __gthread_mutex_unlock (&change_permissions_lock);
kono
parents:
diff changeset
1116 }
kono
parents:
diff changeset
1117 }
kono
parents:
diff changeset
1118
kono
parents:
diff changeset
1119 /* This is the memory allocator used to create the hash table that
kono
parents:
diff changeset
1120 maps from vtable map variable name to the data set that vtable map
kono
parents:
diff changeset
1121 variable should point to. This is part of our vtable map variable
kono
parents:
diff changeset
1122 symbol resolution, which is necessary because the same vtable map
kono
parents:
diff changeset
1123 variable may be created by multiple compilation units and we need a
kono
parents:
diff changeset
1124 method to make sure that all vtable map variables for a particular
kono
parents:
diff changeset
1125 class point to the same data set at runtime. */
kono
parents:
diff changeset
1126
kono
parents:
diff changeset
1127 struct insert_only_hash_map_allocator
kono
parents:
diff changeset
1128 {
kono
parents:
diff changeset
1129 /* N is the number of bytes to allocate. */
kono
parents:
diff changeset
1130 void *
kono
parents:
diff changeset
1131 alloc (size_t n) const
kono
parents:
diff changeset
1132 {
kono
parents:
diff changeset
1133 return __vtv_malloc (n);
kono
parents:
diff changeset
1134 }
kono
parents:
diff changeset
1135
kono
parents:
diff changeset
1136 /* P points to the memory to be deallocated; N is the number of
kono
parents:
diff changeset
1137 bytes to deallocate. */
kono
parents:
diff changeset
1138 void
kono
parents:
diff changeset
1139 dealloc (void *p, size_t) const
kono
parents:
diff changeset
1140 {
kono
parents:
diff changeset
1141 __vtv_free (p);
kono
parents:
diff changeset
1142 }
kono
parents:
diff changeset
1143 };
kono
parents:
diff changeset
1144
kono
parents:
diff changeset
1145 /* Explicitly instantiate this class since this file is compiled with
kono
parents:
diff changeset
1146 -fno-implicit-templates. These are for the hash table that is used
kono
parents:
diff changeset
1147 to do vtable map variable symbol resolution. */
kono
parents:
diff changeset
1148 template class insert_only_hash_map <vtv_set_handle *,
kono
parents:
diff changeset
1149 insert_only_hash_map_allocator >;
kono
parents:
diff changeset
1150 typedef insert_only_hash_map <vtv_set_handle *,
kono
parents:
diff changeset
1151 insert_only_hash_map_allocator > s2s;
kono
parents:
diff changeset
1152 typedef const s2s::key_type vtv_symbol_key;
kono
parents:
diff changeset
1153
kono
parents:
diff changeset
1154 static s2s * vtv_symbol_unification_map VTV_PROTECTED_VAR = NULL;
kono
parents:
diff changeset
1155
kono
parents:
diff changeset
1156 const unsigned long SET_HANDLE_HANDLE_BIT = 0x2;
kono
parents:
diff changeset
1157
kono
parents:
diff changeset
1158 /* In the case where a vtable map variable is the only instance of the
kono
parents:
diff changeset
1159 variable we have seen, it points directly to the set of valid
kono
parents:
diff changeset
1160 vtable pointers. All subsequent instances of the 'same' vtable map
kono
parents:
diff changeset
1161 variable point to the first vtable map variable. This function,
kono
parents:
diff changeset
1162 given a vtable map variable PTR, checks a bit to see whether it's
kono
parents:
diff changeset
1163 pointing directly to the data set or to the first vtable map
kono
parents:
diff changeset
1164 variable. */
kono
parents:
diff changeset
1165
kono
parents:
diff changeset
1166 static inline bool
kono
parents:
diff changeset
1167 is_set_handle_handle (void * ptr)
kono
parents:
diff changeset
1168 {
kono
parents:
diff changeset
1169 return ((uintptr_t) ptr & SET_HANDLE_HANDLE_BIT)
kono
parents:
diff changeset
1170 == SET_HANDLE_HANDLE_BIT;
kono
parents:
diff changeset
1171 }
kono
parents:
diff changeset
1172
kono
parents:
diff changeset
1173 /* Returns the actual pointer value of a vtable map variable, PTR (see
kono
parents:
diff changeset
1174 comments for is_set_handle_handle for more details). */
kono
parents:
diff changeset
1175
kono
parents:
diff changeset
1176 static inline vtv_set_handle *
kono
parents:
diff changeset
1177 ptr_from_set_handle_handle (void * ptr)
kono
parents:
diff changeset
1178 {
kono
parents:
diff changeset
1179 return (vtv_set_handle *) ((uintptr_t) ptr & ~SET_HANDLE_HANDLE_BIT);
kono
parents:
diff changeset
1180 }
kono
parents:
diff changeset
1181
kono
parents:
diff changeset
1182 /* Given a vtable map variable, PTR, this function sets the bit that
kono
parents:
diff changeset
1183 says this is the second (or later) instance of a vtable map
kono
parents:
diff changeset
1184 variable. */
kono
parents:
diff changeset
1185
kono
parents:
diff changeset
1186 static inline vtv_set_handle_handle
kono
parents:
diff changeset
1187 set_handle_handle (vtv_set_handle * ptr)
kono
parents:
diff changeset
1188 {
kono
parents:
diff changeset
1189 return (vtv_set_handle_handle) ((uintptr_t) ptr | SET_HANDLE_HANDLE_BIT);
kono
parents:
diff changeset
1190 }
kono
parents:
diff changeset
1191
kono
parents:
diff changeset
1192 static inline void
kono
parents:
diff changeset
1193 register_set_common (void **set_handle_ptr, size_t num_args,
kono
parents:
diff changeset
1194 void **vtable_ptr_array, bool debug)
kono
parents:
diff changeset
1195 {
kono
parents:
diff changeset
1196 /* Now figure out what pointer to use for the set pointer, for the
kono
parents:
diff changeset
1197 inserts. */
kono
parents:
diff changeset
1198 vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
kono
parents:
diff changeset
1199
kono
parents:
diff changeset
1200 if (debug)
kono
parents:
diff changeset
1201 VTV_DEBUG_ASSERT (vtv_symbol_unification_map != NULL);
kono
parents:
diff changeset
1202
kono
parents:
diff changeset
1203 if (!is_set_handle_handle (*set_handle_ptr))
kono
parents:
diff changeset
1204 handle_ptr = (vtv_set_handle *) set_handle_ptr;
kono
parents:
diff changeset
1205 else
kono
parents:
diff changeset
1206 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
kono
parents:
diff changeset
1207
kono
parents:
diff changeset
1208 /* Now we've got the set and it's initialized, add the vtable
kono
parents:
diff changeset
1209 pointers. */
kono
parents:
diff changeset
1210 for (size_t index = 0; index < num_args; ++index)
kono
parents:
diff changeset
1211 {
kono
parents:
diff changeset
1212 int_vptr vtbl_ptr = (int_vptr) vtable_ptr_array[index];
kono
parents:
diff changeset
1213 vtv_sets::insert (vtbl_ptr, handle_ptr);
kono
parents:
diff changeset
1214 }
kono
parents:
diff changeset
1215 }
kono
parents:
diff changeset
1216
kono
parents:
diff changeset
1217 static inline void
kono
parents:
diff changeset
1218 register_pair_common (void **set_handle_ptr, const void *vtable_ptr,
kono
parents:
diff changeset
1219 const char *set_symbol_name, const char *vtable_name,
kono
parents:
diff changeset
1220 bool debug)
kono
parents:
diff changeset
1221 {
kono
parents:
diff changeset
1222 /* Now we've got the set and it's initialized, add the vtable
kono
parents:
diff changeset
1223 pointer (assuming that it's not NULL...It may be NULL, as we may
kono
parents:
diff changeset
1224 have called this function merely to initialize the set
kono
parents:
diff changeset
1225 pointer). */
kono
parents:
diff changeset
1226 int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
kono
parents:
diff changeset
1227 if (vtbl_ptr)
kono
parents:
diff changeset
1228 {
kono
parents:
diff changeset
1229 vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
kono
parents:
diff changeset
1230 if (debug)
kono
parents:
diff changeset
1231 VTV_DEBUG_ASSERT (vtv_symbol_unification_map != NULL);
kono
parents:
diff changeset
1232 if (!is_set_handle_handle (*set_handle_ptr))
kono
parents:
diff changeset
1233 handle_ptr = (vtv_set_handle *) set_handle_ptr;
kono
parents:
diff changeset
1234 else
kono
parents:
diff changeset
1235 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
kono
parents:
diff changeset
1236
kono
parents:
diff changeset
1237 vtv_sets::insert (vtbl_ptr, handle_ptr);
kono
parents:
diff changeset
1238 }
kono
parents:
diff changeset
1239
kono
parents:
diff changeset
1240 if (debug && debug_init)
kono
parents:
diff changeset
1241 {
kono
parents:
diff changeset
1242 if (init_log_fd == -1)
kono
parents:
diff changeset
1243 init_log_fd = __vtv_open_log("vtv_init.log");
kono
parents:
diff changeset
1244
kono
parents:
diff changeset
1245 __vtv_add_to_log(init_log_fd,
kono
parents:
diff changeset
1246 "Registered %s : %s (%p) 2 level deref = %s\n",
kono
parents:
diff changeset
1247 set_symbol_name, vtable_name, vtbl_ptr,
kono
parents:
diff changeset
1248 is_set_handle_handle(*set_handle_ptr) ? "yes" : "no" );
kono
parents:
diff changeset
1249 }
kono
parents:
diff changeset
1250 }
kono
parents:
diff changeset
1251
kono
parents:
diff changeset
1252 /* This routine initializes a set handle to a vtable set. It makes
kono
parents:
diff changeset
1253 sure that there is only one set handle for a particular set by
kono
parents:
diff changeset
1254 using a map from set name to pointer to set handle. Since there
kono
parents:
diff changeset
1255 will be multiple copies of the pointer to the set handle (one per
kono
parents:
diff changeset
1256 compilation unit that uses it), it makes sure to initialize all the
kono
parents:
diff changeset
1257 pointers to the set handle so that the set handle is unique. To
kono
parents:
diff changeset
1258 make this a little more efficient and avoid a level of indirection
kono
parents:
diff changeset
1259 in some cases, the first pointer to handle for a particular handle
kono
parents:
diff changeset
1260 becomes the handle itself and the other pointers will point to the
kono
parents:
diff changeset
1261 set handle. This is the debug version of this function, so it
kono
parents:
diff changeset
1262 outputs extra debugging messages and logging. SET_HANDLE_PTR is
kono
parents:
diff changeset
1263 the address of the vtable map variable, SET_SYMBOL_KEY is the hash
kono
parents:
diff changeset
1264 table key (containing the name of the map variable and the hash
kono
parents:
diff changeset
1265 value) and SIZE_HINT is a guess for the best initial size for the
kono
parents:
diff changeset
1266 set of vtable pointers that SET_HANDLE_POINTER will point to. */
kono
parents:
diff changeset
1267
kono
parents:
diff changeset
1268 static inline void
kono
parents:
diff changeset
1269 init_set_symbol_debug (void **set_handle_ptr, const void *set_symbol_key,
kono
parents:
diff changeset
1270 size_t size_hint)
kono
parents:
diff changeset
1271 {
kono
parents:
diff changeset
1272 VTV_DEBUG_ASSERT (set_handle_ptr);
kono
parents:
diff changeset
1273
kono
parents:
diff changeset
1274 if (vtv_symbol_unification_map == NULL)
kono
parents:
diff changeset
1275 {
kono
parents:
diff changeset
1276 /* TODO: For now we have chosen 1024, but we need to come up with a
kono
parents:
diff changeset
1277 better initial size for this. */
kono
parents:
diff changeset
1278 vtv_symbol_unification_map = s2s::create (1024);
kono
parents:
diff changeset
1279 VTV_DEBUG_ASSERT(vtv_symbol_unification_map);
kono
parents:
diff changeset
1280 }
kono
parents:
diff changeset
1281
kono
parents:
diff changeset
1282 vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
kono
parents:
diff changeset
1283 vtv_symbol_key *symbol_key_ptr = (vtv_symbol_key *) set_symbol_key;
kono
parents:
diff changeset
1284
kono
parents:
diff changeset
1285 const s2s::value_type * map_value_ptr =
kono
parents:
diff changeset
1286 vtv_symbol_unification_map->get (symbol_key_ptr);
kono
parents:
diff changeset
1287 char buffer[200];
kono
parents:
diff changeset
1288 if (map_value_ptr == NULL)
kono
parents:
diff changeset
1289 {
kono
parents:
diff changeset
1290 if (*handle_ptr != NULL)
kono
parents:
diff changeset
1291 {
kono
parents:
diff changeset
1292 snprintf (buffer, sizeof (buffer),
kono
parents:
diff changeset
1293 "*** Found non-NULL local set ptr %p missing for symbol"
kono
parents:
diff changeset
1294 " %.*s",
kono
parents:
diff changeset
1295 *handle_ptr, symbol_key_ptr->n, symbol_key_ptr->bytes);
kono
parents:
diff changeset
1296 __vtv_log_verification_failure (buffer, true);
kono
parents:
diff changeset
1297 VTV_DEBUG_ASSERT (0);
kono
parents:
diff changeset
1298 }
kono
parents:
diff changeset
1299 }
kono
parents:
diff changeset
1300 else if (*handle_ptr != NULL &&
kono
parents:
diff changeset
1301 (handle_ptr != *map_value_ptr &&
kono
parents:
diff changeset
1302 ptr_from_set_handle_handle (*handle_ptr) != *map_value_ptr))
kono
parents:
diff changeset
1303 {
kono
parents:
diff changeset
1304 VTV_DEBUG_ASSERT (*map_value_ptr != NULL);
kono
parents:
diff changeset
1305 snprintf (buffer, sizeof(buffer),
kono
parents:
diff changeset
1306 "*** Found diffence between local set ptr %p and set ptr %p"
kono
parents:
diff changeset
1307 "for symbol %.*s",
kono
parents:
diff changeset
1308 *handle_ptr, *map_value_ptr,
kono
parents:
diff changeset
1309 symbol_key_ptr->n, symbol_key_ptr->bytes);
kono
parents:
diff changeset
1310 __vtv_log_verification_failure (buffer, true);
kono
parents:
diff changeset
1311 VTV_DEBUG_ASSERT (0);
kono
parents:
diff changeset
1312 }
kono
parents:
diff changeset
1313 else if (*handle_ptr == NULL)
kono
parents:
diff changeset
1314 {
kono
parents:
diff changeset
1315 /* Execution should not reach this point. */
kono
parents:
diff changeset
1316 }
kono
parents:
diff changeset
1317
kono
parents:
diff changeset
1318 if (*handle_ptr != NULL)
kono
parents:
diff changeset
1319 {
kono
parents:
diff changeset
1320 if (!is_set_handle_handle (*set_handle_ptr))
kono
parents:
diff changeset
1321 handle_ptr = (vtv_set_handle *) set_handle_ptr;
kono
parents:
diff changeset
1322 else
kono
parents:
diff changeset
1323 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
kono
parents:
diff changeset
1324 vtv_sets::resize (size_hint, handle_ptr);
kono
parents:
diff changeset
1325 return;
kono
parents:
diff changeset
1326 }
kono
parents:
diff changeset
1327
kono
parents:
diff changeset
1328 VTV_DEBUG_ASSERT (*handle_ptr == NULL);
kono
parents:
diff changeset
1329 if (map_value_ptr != NULL)
kono
parents:
diff changeset
1330 {
kono
parents:
diff changeset
1331 if (*map_value_ptr == handle_ptr)
kono
parents:
diff changeset
1332 vtv_sets::resize (size_hint, *map_value_ptr);
kono
parents:
diff changeset
1333 else
kono
parents:
diff changeset
1334 {
kono
parents:
diff changeset
1335 /* The one level handle to the set already exists. So, we
kono
parents:
diff changeset
1336 are adding one level of indirection here and we will
kono
parents:
diff changeset
1337 store a pointer to the one level handle here. */
kono
parents:
diff changeset
1338
kono
parents:
diff changeset
1339 vtv_set_handle_handle * handle_handle_ptr =
kono
parents:
diff changeset
1340 (vtv_set_handle_handle *)handle_ptr;
kono
parents:
diff changeset
1341 *handle_handle_ptr = set_handle_handle(*map_value_ptr);
kono
parents:
diff changeset
1342 VTV_DEBUG_ASSERT(*handle_handle_ptr != NULL);
kono
parents:
diff changeset
1343
kono
parents:
diff changeset
1344 /* The handle can itself be NULL if the set has only
kono
parents:
diff changeset
1345 been initiazlied with size hint == 1. */
kono
parents:
diff changeset
1346 vtv_sets::resize (size_hint, *map_value_ptr);
kono
parents:
diff changeset
1347 }
kono
parents:
diff changeset
1348 }
kono
parents:
diff changeset
1349 else
kono
parents:
diff changeset
1350 {
kono
parents:
diff changeset
1351 /* We will create a new set. So, in this case handle_ptr is the
kono
parents:
diff changeset
1352 one level pointer to the set handle. Create copy of map name
kono
parents:
diff changeset
1353 in case the memory where this comes from gets unmapped by
kono
parents:
diff changeset
1354 dlclose. */
kono
parents:
diff changeset
1355 size_t map_key_len = symbol_key_ptr->n + sizeof (vtv_symbol_key);
kono
parents:
diff changeset
1356 void *map_key = __vtv_malloc (map_key_len);
kono
parents:
diff changeset
1357
kono
parents:
diff changeset
1358 memcpy (map_key, symbol_key_ptr, map_key_len);
kono
parents:
diff changeset
1359
kono
parents:
diff changeset
1360 s2s::value_type *value_ptr;
kono
parents:
diff changeset
1361 vtv_symbol_unification_map =
kono
parents:
diff changeset
1362 vtv_symbol_unification_map->find_or_add_key ((vtv_symbol_key *)map_key,
kono
parents:
diff changeset
1363 &value_ptr);
kono
parents:
diff changeset
1364 *value_ptr = handle_ptr;
kono
parents:
diff changeset
1365
kono
parents:
diff changeset
1366 /* TODO: We should verify the return value. */
kono
parents:
diff changeset
1367 vtv_sets::create (size_hint, handle_ptr);
kono
parents:
diff changeset
1368 VTV_DEBUG_ASSERT (size_hint <= 1 || *handle_ptr != NULL);
kono
parents:
diff changeset
1369 }
kono
parents:
diff changeset
1370
kono
parents:
diff changeset
1371 if (debug_init)
kono
parents:
diff changeset
1372 {
kono
parents:
diff changeset
1373 if (init_log_fd == -1)
kono
parents:
diff changeset
1374 init_log_fd = __vtv_open_log ("vtv_init.log");
kono
parents:
diff changeset
1375
kono
parents:
diff changeset
1376 __vtv_add_to_log (init_log_fd,
kono
parents:
diff changeset
1377 "Init handle:%p for symbol:%.*s hash:%u size_hint:%lu"
kono
parents:
diff changeset
1378 "number of symbols:%lu \n",
kono
parents:
diff changeset
1379 set_handle_ptr, symbol_key_ptr->n,
kono
parents:
diff changeset
1380 symbol_key_ptr->bytes, symbol_key_ptr->hash, size_hint,
kono
parents:
diff changeset
1381 vtv_symbol_unification_map->size ());
kono
parents:
diff changeset
1382 }
kono
parents:
diff changeset
1383 }
kono
parents:
diff changeset
1384
kono
parents:
diff changeset
1385
kono
parents:
diff changeset
1386 /* This routine initializes a set handle to a vtable set. It makes
kono
parents:
diff changeset
1387 sure that there is only one set handle for a particular set by
kono
parents:
diff changeset
1388 using a map from set name to pointer to set handle. Since there
kono
parents:
diff changeset
1389 will be multiple copies of the pointer to the set handle (one per
kono
parents:
diff changeset
1390 compilation unit that uses it), it makes sure to initialize all the
kono
parents:
diff changeset
1391 pointers to the set handle so that the set handle is unique. To
kono
parents:
diff changeset
1392 make this a little more efficient and avoid a level of indirection
kono
parents:
diff changeset
1393 in some cases, the first pointer to handle for a particular handle
kono
parents:
diff changeset
1394 becomes the handle itself and the other pointers will point to the
kono
parents:
diff changeset
1395 set handle. This is the debug version of this function, so it
kono
parents:
diff changeset
1396 outputs extra debugging messages and logging. SET_HANDLE_PTR is
kono
parents:
diff changeset
1397 the address of the vtable map variable, SET_SYMBOL_KEY is the hash
kono
parents:
diff changeset
1398 table key (containing the name of the map variable and the hash
kono
parents:
diff changeset
1399 value) and SIZE_HINT is a guess for the best initial size for the
kono
parents:
diff changeset
1400 set of vtable pointers that SET_HANDLE_POINTER will point to. */
kono
parents:
diff changeset
1401
kono
parents:
diff changeset
1402 void
kono
parents:
diff changeset
1403 __VLTRegisterSetDebug (void **set_handle_ptr, const void *set_symbol_key,
kono
parents:
diff changeset
1404 size_t size_hint, size_t num_args,
kono
parents:
diff changeset
1405 void **vtable_ptr_array)
kono
parents:
diff changeset
1406 {
kono
parents:
diff changeset
1407 unsigned long long start = get_cycle_count ();
kono
parents:
diff changeset
1408 increment_num_calls (&num_calls_to_regset);
kono
parents:
diff changeset
1409
kono
parents:
diff changeset
1410 VTV_DEBUG_ASSERT(set_handle_ptr != NULL);
kono
parents:
diff changeset
1411 init_set_symbol_debug (set_handle_ptr, set_symbol_key, size_hint);
kono
parents:
diff changeset
1412
kono
parents:
diff changeset
1413 register_set_common (set_handle_ptr, num_args, vtable_ptr_array, true);
kono
parents:
diff changeset
1414
kono
parents:
diff changeset
1415 accumulate_cycle_count (&regset_cycles, start);
kono
parents:
diff changeset
1416 }
kono
parents:
diff changeset
1417
kono
parents:
diff changeset
1418 /* This function takes a the address of a vtable map variable
kono
parents:
diff changeset
1419 (SET_HANDLE_PTR), a VTABLE_PTR to add to the data set, the name of
kono
parents:
diff changeset
1420 the vtable map variable (SET_SYMBOL_NAME) and the name of the
kono
parents:
diff changeset
1421 vtable (VTABLE_NAME) being pointed to. If the vtable map variable
kono
parents:
diff changeset
1422 is NULL it creates a new data set and initializes the variable,
kono
parents:
diff changeset
1423 otherwise it uses our symbol unification to find the right data
kono
parents:
diff changeset
1424 set; in either case it then adds the vtable pointer to the set.
kono
parents:
diff changeset
1425 The other two parameters are used for debugging information. */
kono
parents:
diff changeset
1426
kono
parents:
diff changeset
1427 void
kono
parents:
diff changeset
1428 __VLTRegisterPairDebug (void **set_handle_ptr, const void *set_symbol_key,
kono
parents:
diff changeset
1429 size_t size_hint, const void *vtable_ptr,
kono
parents:
diff changeset
1430 const char *set_symbol_name, const char *vtable_name)
kono
parents:
diff changeset
1431 {
kono
parents:
diff changeset
1432 unsigned long long start = get_cycle_count ();
kono
parents:
diff changeset
1433 increment_num_calls (&num_calls_to_regpair);
kono
parents:
diff changeset
1434
kono
parents:
diff changeset
1435 VTV_DEBUG_ASSERT(set_handle_ptr != NULL);
kono
parents:
diff changeset
1436 init_set_symbol_debug (set_handle_ptr, set_symbol_key, size_hint);
kono
parents:
diff changeset
1437
kono
parents:
diff changeset
1438 register_pair_common (set_handle_ptr, vtable_ptr, set_symbol_name, vtable_name,
kono
parents:
diff changeset
1439 true);
kono
parents:
diff changeset
1440
kono
parents:
diff changeset
1441 accumulate_cycle_count (&regpair_cycles, start);
kono
parents:
diff changeset
1442 }
kono
parents:
diff changeset
1443
kono
parents:
diff changeset
1444
kono
parents:
diff changeset
1445 /* This is the debug version of the verification function. It takes
kono
parents:
diff changeset
1446 the address of a vtable map variable (SET_HANDLE_PTR) and a
kono
parents:
diff changeset
1447 VTABLE_PTR to validate, as well as the name of the vtable map
kono
parents:
diff changeset
1448 variable (SET_SYMBOL_NAME) and VTABLE_NAME, which are used for
kono
parents:
diff changeset
1449 debugging messages. It checks to see if VTABLE_PTR is in the set
kono
parents:
diff changeset
1450 pointed to by SET_HANDLE_PTR. If so, it returns VTABLE_PTR,
kono
parents:
diff changeset
1451 otherwise it calls __vtv_verify_fail, which usually logs error
kono
parents:
diff changeset
1452 messages and calls abort. */
kono
parents:
diff changeset
1453
kono
parents:
diff changeset
1454 const void *
kono
parents:
diff changeset
1455 __VLTVerifyVtablePointerDebug (void **set_handle_ptr, const void *vtable_ptr,
kono
parents:
diff changeset
1456 const char *set_symbol_name,
kono
parents:
diff changeset
1457 const char *vtable_name)
kono
parents:
diff changeset
1458 {
kono
parents:
diff changeset
1459 unsigned long long start = get_cycle_count ();
kono
parents:
diff changeset
1460 VTV_DEBUG_ASSERT (set_handle_ptr != NULL && *set_handle_ptr != NULL);
kono
parents:
diff changeset
1461 int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
kono
parents:
diff changeset
1462
kono
parents:
diff changeset
1463 increment_num_calls (&num_calls_to_verify_vtable);
kono
parents:
diff changeset
1464 vtv_set_handle *handle_ptr;
kono
parents:
diff changeset
1465 if (!is_set_handle_handle (*set_handle_ptr))
kono
parents:
diff changeset
1466 handle_ptr = (vtv_set_handle *) set_handle_ptr;
kono
parents:
diff changeset
1467 else
kono
parents:
diff changeset
1468 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
kono
parents:
diff changeset
1469
kono
parents:
diff changeset
1470 if (vtv_sets::contains (vtbl_ptr, handle_ptr))
kono
parents:
diff changeset
1471 {
kono
parents:
diff changeset
1472 if (debug_verify_vtable)
kono
parents:
diff changeset
1473 {
kono
parents:
diff changeset
1474 if (verify_vtable_log_fd == -1)
kono
parents:
diff changeset
1475 __vtv_open_log ("vtv_verify_vtable.log");
kono
parents:
diff changeset
1476 __vtv_add_to_log (verify_vtable_log_fd,
kono
parents:
diff changeset
1477 "Verified %s %s value = %p\n",
kono
parents:
diff changeset
1478 set_symbol_name, vtable_name, vtable_ptr);
kono
parents:
diff changeset
1479 }
kono
parents:
diff changeset
1480 }
kono
parents:
diff changeset
1481 else
kono
parents:
diff changeset
1482 {
kono
parents:
diff changeset
1483 /* We failed to find the vtable pointer in the set of valid
kono
parents:
diff changeset
1484 pointers. Log the error data and call the failure
kono
parents:
diff changeset
1485 function. */
kono
parents:
diff changeset
1486 snprintf (debug_log_message, sizeof (debug_log_message),
kono
parents:
diff changeset
1487 "Looking for %s in %s\n", vtable_name, set_symbol_name);
kono
parents:
diff changeset
1488 __vtv_verify_fail_debug (set_handle_ptr, vtable_ptr, debug_log_message);
kono
parents:
diff changeset
1489
kono
parents:
diff changeset
1490 /* Normally __vtv_verify_fail_debug will call abort, so we won't
kono
parents:
diff changeset
1491 execute the return below. If we get this far, the assumption
kono
parents:
diff changeset
1492 is that the programmer has replaced __vtv_verify_fail_debug
kono
parents:
diff changeset
1493 with some kind of secondary verification AND this secondary
kono
parents:
diff changeset
1494 verification succeeded, so the vtable pointer is valid. */
kono
parents:
diff changeset
1495 }
kono
parents:
diff changeset
1496 accumulate_cycle_count (&verify_vtable_cycles, start);
kono
parents:
diff changeset
1497
kono
parents:
diff changeset
1498 return vtable_ptr;
kono
parents:
diff changeset
1499 }
kono
parents:
diff changeset
1500
kono
parents:
diff changeset
1501 /* This routine initializes a set handle to a vtable set. It makes
kono
parents:
diff changeset
1502 sure that there is only one set handle for a particular set by
kono
parents:
diff changeset
1503 using a map from set name to pointer to set handle. Since there
kono
parents:
diff changeset
1504 will be multiple copies of the pointer to the set handle (one per
kono
parents:
diff changeset
1505 compilation unit that uses it), it makes sure to initialize all the
kono
parents:
diff changeset
1506 pointers to the set handle so that the set handle is unique. To
kono
parents:
diff changeset
1507 make this a little more efficient and avoid a level of indirection
kono
parents:
diff changeset
1508 in some cases, the first pointer to handle for a particular handle
kono
parents:
diff changeset
1509 becomes the handle itself and the other pointers will point to the
kono
parents:
diff changeset
1510 set handle. SET_HANDLE_PTR is the address of the vtable map
kono
parents:
diff changeset
1511 variable, SET_SYMBOL_KEY is the hash table key (containing the name
kono
parents:
diff changeset
1512 of the map variable and the hash value) and SIZE_HINT is a guess
kono
parents:
diff changeset
1513 for the best initial size for the set of vtable pointers that
kono
parents:
diff changeset
1514 SET_HANDLE_POINTER will point to.*/
kono
parents:
diff changeset
1515
kono
parents:
diff changeset
1516 static inline void
kono
parents:
diff changeset
1517 init_set_symbol (void **set_handle_ptr, const void *set_symbol_key,
kono
parents:
diff changeset
1518 size_t size_hint)
kono
parents:
diff changeset
1519 {
kono
parents:
diff changeset
1520 vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
kono
parents:
diff changeset
1521
kono
parents:
diff changeset
1522 if (*handle_ptr != NULL)
kono
parents:
diff changeset
1523 {
kono
parents:
diff changeset
1524 if (!is_set_handle_handle (*set_handle_ptr))
kono
parents:
diff changeset
1525 handle_ptr = (vtv_set_handle *) set_handle_ptr;
kono
parents:
diff changeset
1526 else
kono
parents:
diff changeset
1527 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
kono
parents:
diff changeset
1528 vtv_sets::resize (size_hint, handle_ptr);
kono
parents:
diff changeset
1529 return;
kono
parents:
diff changeset
1530 }
kono
parents:
diff changeset
1531
kono
parents:
diff changeset
1532 if (vtv_symbol_unification_map == NULL)
kono
parents:
diff changeset
1533 vtv_symbol_unification_map = s2s::create (1024);
kono
parents:
diff changeset
1534
kono
parents:
diff changeset
1535 vtv_symbol_key *symbol_key_ptr = (vtv_symbol_key *) set_symbol_key;
kono
parents:
diff changeset
1536 const s2s::value_type *map_value_ptr =
kono
parents:
diff changeset
1537 vtv_symbol_unification_map->get (symbol_key_ptr);
kono
parents:
diff changeset
1538
kono
parents:
diff changeset
1539 if (map_value_ptr != NULL)
kono
parents:
diff changeset
1540 {
kono
parents:
diff changeset
1541 if (*map_value_ptr == handle_ptr)
kono
parents:
diff changeset
1542 vtv_sets::resize (size_hint, *map_value_ptr);
kono
parents:
diff changeset
1543 else
kono
parents:
diff changeset
1544 {
kono
parents:
diff changeset
1545 /* The one level handle to the set already exists. So, we
kono
parents:
diff changeset
1546 are adding one level of indirection here and we will
kono
parents:
diff changeset
1547 store a pointer to the one level pointer here. */
kono
parents:
diff changeset
1548 vtv_set_handle_handle *handle_handle_ptr =
kono
parents:
diff changeset
1549 (vtv_set_handle_handle *) handle_ptr;
kono
parents:
diff changeset
1550 *handle_handle_ptr = set_handle_handle (*map_value_ptr);
kono
parents:
diff changeset
1551 vtv_sets::resize (size_hint, *map_value_ptr);
kono
parents:
diff changeset
1552 }
kono
parents:
diff changeset
1553 }
kono
parents:
diff changeset
1554 else
kono
parents:
diff changeset
1555 {
kono
parents:
diff changeset
1556 /* We will create a new set. So, in this case handle_ptr is the
kono
parents:
diff changeset
1557 one level pointer to the set handle. Create copy of map name
kono
parents:
diff changeset
1558 in case the memory where this comes from gets unmapped by
kono
parents:
diff changeset
1559 dlclose. */
kono
parents:
diff changeset
1560 size_t map_key_len = symbol_key_ptr->n + sizeof (vtv_symbol_key);
kono
parents:
diff changeset
1561 void * map_key = __vtv_malloc (map_key_len);
kono
parents:
diff changeset
1562 memcpy (map_key, symbol_key_ptr, map_key_len);
kono
parents:
diff changeset
1563
kono
parents:
diff changeset
1564 s2s::value_type * value_ptr;
kono
parents:
diff changeset
1565 vtv_symbol_unification_map =
kono
parents:
diff changeset
1566 vtv_symbol_unification_map->find_or_add_key ((vtv_symbol_key *)map_key,
kono
parents:
diff changeset
1567 &value_ptr);
kono
parents:
diff changeset
1568
kono
parents:
diff changeset
1569 *value_ptr = handle_ptr;
kono
parents:
diff changeset
1570
kono
parents:
diff changeset
1571 /* TODO: We should verify the return value. */
kono
parents:
diff changeset
1572 vtv_sets::create (size_hint, handle_ptr);
kono
parents:
diff changeset
1573 }
kono
parents:
diff changeset
1574 }
kono
parents:
diff changeset
1575
kono
parents:
diff changeset
1576 /* This routine initializes a set handle to a vtable set. It makes
kono
parents:
diff changeset
1577 sure that there is only one set handle for a particular set by
kono
parents:
diff changeset
1578 using a map from set name to pointer to set handle. Since there
kono
parents:
diff changeset
1579 will be multiple copies of the pointer to the set handle (one per
kono
parents:
diff changeset
1580 compilation unit that uses it), it makes sure to initialize all the
kono
parents:
diff changeset
1581 pointers to the set handle so that the set handle is unique. To
kono
parents:
diff changeset
1582 make this a little more efficient and avoid a level of indirection
kono
parents:
diff changeset
1583 in some cases, the first pointer to handle for a particular handle
kono
parents:
diff changeset
1584 becomes the handle itself and the other pointers will point to the
kono
parents:
diff changeset
1585 set handle. SET_HANDLE_PTR is the address of the vtable map
kono
parents:
diff changeset
1586 variable, SET_SYMBOL_KEY is the hash table key (containing the name
kono
parents:
diff changeset
1587 of the map variable and the hash value) and SIZE_HINT is a guess
kono
parents:
diff changeset
1588 for the best initial size for the set of vtable pointers that
kono
parents:
diff changeset
1589 SET_HANDLE_POINTER will point to.*/
kono
parents:
diff changeset
1590
kono
parents:
diff changeset
1591
kono
parents:
diff changeset
1592 void
kono
parents:
diff changeset
1593 __VLTRegisterSet (void **set_handle_ptr, const void *set_symbol_key,
kono
parents:
diff changeset
1594 size_t size_hint, size_t num_args, void **vtable_ptr_array)
kono
parents:
diff changeset
1595 {
kono
parents:
diff changeset
1596 unsigned long long start = get_cycle_count ();
kono
parents:
diff changeset
1597 increment_num_calls (&num_calls_to_regset);
kono
parents:
diff changeset
1598
kono
parents:
diff changeset
1599 init_set_symbol (set_handle_ptr, set_symbol_key, size_hint);
kono
parents:
diff changeset
1600 register_set_common (set_handle_ptr, num_args, vtable_ptr_array, false);
kono
parents:
diff changeset
1601
kono
parents:
diff changeset
1602 accumulate_cycle_count (&regset_cycles, start);
kono
parents:
diff changeset
1603 }
kono
parents:
diff changeset
1604
kono
parents:
diff changeset
1605
kono
parents:
diff changeset
1606
kono
parents:
diff changeset
1607 /* This function takes a the address of a vtable map variable
kono
parents:
diff changeset
1608 (SET_HANDLE_PTR) and a VTABLE_PTR. If the vtable map variable is
kono
parents:
diff changeset
1609 NULL it creates a new data set and initializes the variable,
kono
parents:
diff changeset
1610 otherwise it uses our symbol unification to find the right data
kono
parents:
diff changeset
1611 set; in either case it then adds the vtable pointer to the set. */
kono
parents:
diff changeset
1612
kono
parents:
diff changeset
1613 void
kono
parents:
diff changeset
1614 __VLTRegisterPair (void **set_handle_ptr, const void *set_symbol_key,
kono
parents:
diff changeset
1615 size_t size_hint, const void *vtable_ptr)
kono
parents:
diff changeset
1616 {
kono
parents:
diff changeset
1617 unsigned long long start = get_cycle_count ();
kono
parents:
diff changeset
1618 increment_num_calls (&num_calls_to_regpair);
kono
parents:
diff changeset
1619
kono
parents:
diff changeset
1620 init_set_symbol (set_handle_ptr, set_symbol_key, size_hint);
kono
parents:
diff changeset
1621 register_pair_common (set_handle_ptr, vtable_ptr, NULL, NULL, false);
kono
parents:
diff changeset
1622
kono
parents:
diff changeset
1623 accumulate_cycle_count (&regpair_cycles, start);
kono
parents:
diff changeset
1624 }
kono
parents:
diff changeset
1625
kono
parents:
diff changeset
1626 /* This is the main verification function. It takes the address of a
kono
parents:
diff changeset
1627 vtable map variable (SET_HANDLE_PTR) and a VTABLE_PTR to validate.
kono
parents:
diff changeset
1628 It checks to see if VTABLE_PTR is in the set pointed to by
kono
parents:
diff changeset
1629 SET_HANDLE_PTR. If so, it returns VTABLE_PTR, otherwise it calls
kono
parents:
diff changeset
1630 __vtv_verify_fail, which usually logs error messages and calls
kono
parents:
diff changeset
1631 abort. Since this function gets called VERY frequently, it is
kono
parents:
diff changeset
1632 important for it to be as efficient as possible. */
kono
parents:
diff changeset
1633
kono
parents:
diff changeset
1634 const void *
kono
parents:
diff changeset
1635 __VLTVerifyVtablePointer (void ** set_handle_ptr, const void * vtable_ptr)
kono
parents:
diff changeset
1636 {
kono
parents:
diff changeset
1637 unsigned long long start = get_cycle_count ();
kono
parents:
diff changeset
1638 int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
kono
parents:
diff changeset
1639
kono
parents:
diff changeset
1640 vtv_set_handle *handle_ptr;
kono
parents:
diff changeset
1641 increment_num_calls (&num_calls_to_verify_vtable);
kono
parents:
diff changeset
1642 if (!is_set_handle_handle (*set_handle_ptr))
kono
parents:
diff changeset
1643 handle_ptr = (vtv_set_handle *) set_handle_ptr;
kono
parents:
diff changeset
1644 else
kono
parents:
diff changeset
1645 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
kono
parents:
diff changeset
1646
kono
parents:
diff changeset
1647 if (!vtv_sets::contains (vtbl_ptr, handle_ptr))
kono
parents:
diff changeset
1648 {
kono
parents:
diff changeset
1649 __vtv_verify_fail ((void **) handle_ptr, vtable_ptr);
kono
parents:
diff changeset
1650 /* Normally __vtv_verify_fail will call abort, so we won't
kono
parents:
diff changeset
1651 execute the return below. If we get this far, the assumption
kono
parents:
diff changeset
1652 is that the programmer has replaced __vtv_verify_fail with
kono
parents:
diff changeset
1653 some kind of secondary verification AND this secondary
kono
parents:
diff changeset
1654 verification succeeded, so the vtable pointer is valid. */
kono
parents:
diff changeset
1655 }
kono
parents:
diff changeset
1656 accumulate_cycle_count (&verify_vtable_cycles, start);
kono
parents:
diff changeset
1657
kono
parents:
diff changeset
1658 return vtable_ptr;
kono
parents:
diff changeset
1659 }
kono
parents:
diff changeset
1660
kono
parents:
diff changeset
1661 static int page_count_2 = 0;
kono
parents:
diff changeset
1662
kono
parents:
diff changeset
1663 #if !defined (__CYGWIN__) && !defined (__MINGW32__)
kono
parents:
diff changeset
1664 static int
kono
parents:
diff changeset
1665 dl_iterate_phdr_count_pages (struct dl_phdr_info *info,
kono
parents:
diff changeset
1666 size_t unused __attribute__ ((__unused__)),
kono
parents:
diff changeset
1667 void *data)
kono
parents:
diff changeset
1668 {
kono
parents:
diff changeset
1669 int *mprotect_flags = (int *) data;
kono
parents:
diff changeset
1670 off_t map_sect_offset = 0;
kono
parents:
diff changeset
1671 ElfW (Word) map_sect_len = 0;
kono
parents:
diff changeset
1672 const char *map_sect_name = VTV_PROTECTED_VARS_SECTION;
kono
parents:
diff changeset
1673
kono
parents:
diff changeset
1674 /* Check to see if this is the record for the Linux Virtual Dynamic
kono
parents:
diff changeset
1675 Shared Object (linux-vdso.so.1), which exists only in memory (and
kono
parents:
diff changeset
1676 therefore cannot be read from disk). */
kono
parents:
diff changeset
1677
kono
parents:
diff changeset
1678 if (strcmp (info->dlpi_name, "linux-vdso.so.1") == 0)
kono
parents:
diff changeset
1679 return 0;
kono
parents:
diff changeset
1680
kono
parents:
diff changeset
1681 if (strlen (info->dlpi_name) == 0
kono
parents:
diff changeset
1682 && info->dlpi_addr != 0)
kono
parents:
diff changeset
1683 return 0;
kono
parents:
diff changeset
1684
kono
parents:
diff changeset
1685 read_section_offset_and_length (info, map_sect_name, *mprotect_flags,
kono
parents:
diff changeset
1686 &map_sect_offset, &map_sect_len);
kono
parents:
diff changeset
1687
kono
parents:
diff changeset
1688 /* See if we actually found the section. */
kono
parents:
diff changeset
1689 if (map_sect_len)
kono
parents:
diff changeset
1690 page_count_2 += (map_sect_len + VTV_PAGE_SIZE - 1) / VTV_PAGE_SIZE;
kono
parents:
diff changeset
1691
kono
parents:
diff changeset
1692 return 0;
kono
parents:
diff changeset
1693 }
kono
parents:
diff changeset
1694 #endif
kono
parents:
diff changeset
1695
kono
parents:
diff changeset
1696 static void
kono
parents:
diff changeset
1697 count_all_pages (void)
kono
parents:
diff changeset
1698 {
kono
parents:
diff changeset
1699 int mprotect_flags;
kono
parents:
diff changeset
1700
kono
parents:
diff changeset
1701 mprotect_flags = PROT_READ;
kono
parents:
diff changeset
1702 page_count_2 = 0;
kono
parents:
diff changeset
1703
kono
parents:
diff changeset
1704 #if defined (__CYGWIN__) || defined (__MINGW32__)
kono
parents:
diff changeset
1705 iterate_modules ((void *) &mprotect_flags);
kono
parents:
diff changeset
1706 #else
kono
parents:
diff changeset
1707 dl_iterate_phdr (dl_iterate_phdr_count_pages, (void *) &mprotect_flags);
kono
parents:
diff changeset
1708 #endif
kono
parents:
diff changeset
1709 page_count_2 += __vtv_count_mmapped_pages ();
kono
parents:
diff changeset
1710 }
kono
parents:
diff changeset
1711
kono
parents:
diff changeset
1712 void
kono
parents:
diff changeset
1713 __VLTDumpStats (void)
kono
parents:
diff changeset
1714 {
kono
parents:
diff changeset
1715 int log_fd = __vtv_open_log ("vtv-runtime-stats.log");
kono
parents:
diff changeset
1716
kono
parents:
diff changeset
1717 if (log_fd != -1)
kono
parents:
diff changeset
1718 {
kono
parents:
diff changeset
1719 count_all_pages ();
kono
parents:
diff changeset
1720 __vtv_add_to_log (log_fd,
kono
parents:
diff changeset
1721 "Calls: mprotect (%d) regset (%d) regpair (%d)"
kono
parents:
diff changeset
1722 " verify_vtable (%d)\n",
kono
parents:
diff changeset
1723 num_calls_to_mprotect, num_calls_to_regset,
kono
parents:
diff changeset
1724 num_calls_to_regpair, num_calls_to_verify_vtable);
kono
parents:
diff changeset
1725 __vtv_add_to_log (log_fd,
kono
parents:
diff changeset
1726 "Cycles: mprotect (%lld) regset (%lld) "
kono
parents:
diff changeset
1727 "regpair (%lld) verify_vtable (%lld)\n",
kono
parents:
diff changeset
1728 mprotect_cycles, regset_cycles, regpair_cycles,
kono
parents:
diff changeset
1729 verify_vtable_cycles);
kono
parents:
diff changeset
1730 __vtv_add_to_log (log_fd,
kono
parents:
diff changeset
1731 "Pages protected (1): %d\n", num_pages_protected);
kono
parents:
diff changeset
1732 __vtv_add_to_log (log_fd, "Pages protected (2): %d\n", page_count_2);
kono
parents:
diff changeset
1733
kono
parents:
diff changeset
1734 close (log_fd);
kono
parents:
diff changeset
1735 }
kono
parents:
diff changeset
1736 }
kono
parents:
diff changeset
1737
kono
parents:
diff changeset
1738 /* This function is called from __VLTVerifyVtablePointerDebug; it
kono
parents:
diff changeset
1739 sends as much debugging information as it can to the error log
kono
parents:
diff changeset
1740 file, then calls __vtv_verify_fail. SET_HANDLE_PTR is the pointer
kono
parents:
diff changeset
1741 to the set of valid vtable pointers, VTBL_PTR is the pointer that
kono
parents:
diff changeset
1742 was not found in the set, and DEBUG_MSG is the message to be
kono
parents:
diff changeset
1743 written to the log file before failing. n */
kono
parents:
diff changeset
1744
kono
parents:
diff changeset
1745 void
kono
parents:
diff changeset
1746 __vtv_verify_fail_debug (void **set_handle_ptr, const void *vtbl_ptr,
kono
parents:
diff changeset
1747 const char *debug_msg)
kono
parents:
diff changeset
1748 {
kono
parents:
diff changeset
1749 __vtv_log_verification_failure (debug_msg, false);
kono
parents:
diff changeset
1750
kono
parents:
diff changeset
1751 /* Call the public interface in case it has been overwritten by
kono
parents:
diff changeset
1752 user. */
kono
parents:
diff changeset
1753 __vtv_verify_fail (set_handle_ptr, vtbl_ptr);
kono
parents:
diff changeset
1754
kono
parents:
diff changeset
1755 __vtv_log_verification_failure ("Returned from __vtv_verify_fail."
kono
parents:
diff changeset
1756 " Secondary verification succeeded.\n", false);
kono
parents:
diff changeset
1757 }
kono
parents:
diff changeset
1758
kono
parents:
diff changeset
1759 /* This function calls __fortify_fail with a FAILURE_MSG and then
kono
parents:
diff changeset
1760 calls abort. */
kono
parents:
diff changeset
1761
kono
parents:
diff changeset
1762 void
kono
parents:
diff changeset
1763 __vtv_really_fail (const char *failure_msg)
kono
parents:
diff changeset
1764 {
kono
parents:
diff changeset
1765 __fortify_fail (failure_msg);
kono
parents:
diff changeset
1766
kono
parents:
diff changeset
1767 /* We should never get this far; __fortify_fail calls __libc_message
kono
parents:
diff changeset
1768 which prints out a back trace and a memory dump and then is
kono
parents:
diff changeset
1769 supposed to call abort, but let's play it safe anyway and call abort
kono
parents:
diff changeset
1770 ourselves. */
kono
parents:
diff changeset
1771 abort ();
kono
parents:
diff changeset
1772 }
kono
parents:
diff changeset
1773
kono
parents:
diff changeset
1774 /* This function takes an error MSG, a vtable map variable
kono
parents:
diff changeset
1775 (DATA_SET_PTR) and a vtable pointer (VTBL_PTR). It is called when
kono
parents:
diff changeset
1776 an attempt to verify VTBL_PTR with the set pointed to by
kono
parents:
diff changeset
1777 DATA_SET_PTR failed. It outputs a failure message with the
kono
parents:
diff changeset
1778 addresses involved, and calls __vtv_really_fail. */
kono
parents:
diff changeset
1779
kono
parents:
diff changeset
1780 static void
kono
parents:
diff changeset
1781 vtv_fail (const char *msg, void **data_set_ptr, const void *vtbl_ptr)
kono
parents:
diff changeset
1782 {
kono
parents:
diff changeset
1783 char buffer[128];
kono
parents:
diff changeset
1784 int buf_len;
kono
parents:
diff changeset
1785 const char *format_str =
kono
parents:
diff changeset
1786 "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
kono
parents:
diff changeset
1787
kono
parents:
diff changeset
1788 snprintf (buffer, sizeof (buffer), format_str, vtbl_ptr,
kono
parents:
diff changeset
1789 is_set_handle_handle(*data_set_ptr) ?
kono
parents:
diff changeset
1790 ptr_from_set_handle_handle (*data_set_ptr) :
kono
parents:
diff changeset
1791 *data_set_ptr);
kono
parents:
diff changeset
1792 buf_len = strlen (buffer);
kono
parents:
diff changeset
1793 /* Send this to to stderr. */
kono
parents:
diff changeset
1794 write (2, buffer, buf_len);
kono
parents:
diff changeset
1795
kono
parents:
diff changeset
1796 #ifndef VTV_NO_ABORT
kono
parents:
diff changeset
1797 __vtv_really_fail (msg);
kono
parents:
diff changeset
1798 #endif
kono
parents:
diff changeset
1799 }
kono
parents:
diff changeset
1800
kono
parents:
diff changeset
1801 /* Send information about what we were trying to do when verification
kono
parents:
diff changeset
1802 failed to the error log, then call vtv_fail. This function can be
kono
parents:
diff changeset
1803 overwritten/replaced by the user, to implement a secondary
kono
parents:
diff changeset
1804 verification function instead. DATA_SET_PTR is the vtable map
kono
parents:
diff changeset
1805 variable used for the failed verification, and VTBL_PTR is the
kono
parents:
diff changeset
1806 vtable pointer that was not found in the set. */
kono
parents:
diff changeset
1807
kono
parents:
diff changeset
1808 void
kono
parents:
diff changeset
1809 __vtv_verify_fail (void **data_set_ptr, const void *vtbl_ptr)
kono
parents:
diff changeset
1810 {
kono
parents:
diff changeset
1811 char log_msg[256];
kono
parents:
diff changeset
1812 snprintf (log_msg, sizeof (log_msg), "Looking for vtable %p in set %p.\n",
kono
parents:
diff changeset
1813 vtbl_ptr,
kono
parents:
diff changeset
1814 is_set_handle_handle (*data_set_ptr) ?
kono
parents:
diff changeset
1815 ptr_from_set_handle_handle (*data_set_ptr) :
kono
parents:
diff changeset
1816 *data_set_ptr);
kono
parents:
diff changeset
1817 __vtv_log_verification_failure (log_msg, false);
kono
parents:
diff changeset
1818
kono
parents:
diff changeset
1819 const char *format_str =
kono
parents:
diff changeset
1820 "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
kono
parents:
diff changeset
1821 snprintf (log_msg, sizeof (log_msg), format_str, vtbl_ptr, *data_set_ptr);
kono
parents:
diff changeset
1822 __vtv_log_verification_failure (log_msg, false);
kono
parents:
diff changeset
1823 __vtv_log_verification_failure (" Backtrace: \n", true);
kono
parents:
diff changeset
1824
kono
parents:
diff changeset
1825 const char *fail_msg = "Potential vtable pointer corruption detected!!\n";
kono
parents:
diff changeset
1826 vtv_fail (fail_msg, data_set_ptr, vtbl_ptr);
kono
parents:
diff changeset
1827 }