sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 1 | |
| 2 | /*--------------------------------------------------------------------*/ |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 3 | /*--- Memory-related stuff: segment initialisation and tracking, ---*/ |
| 4 | /*--- stack operations ---*/ |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 5 | /*--- vg_memory.c ---*/ |
| 6 | /*--------------------------------------------------------------------*/ |
| 7 | |
| 8 | /* |
njn | c953984 | 2002-10-02 13:26:35 +0000 | [diff] [blame] | 9 | This file is part of Valgrind, an extensible x86 protected-mode |
| 10 | emulator for monitoring program execution on x86-Unixes. |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 11 | |
njn | 0e1b514 | 2003-04-15 14:58:06 +0000 | [diff] [blame] | 12 | Copyright (C) 2000-2003 Julian Seward |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 13 | jseward@acm.org |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 14 | |
| 15 | This program is free software; you can redistribute it and/or |
| 16 | modify it under the terms of the GNU General Public License as |
| 17 | published by the Free Software Foundation; either version 2 of the |
| 18 | License, or (at your option) any later version. |
| 19 | |
| 20 | This program is distributed in the hope that it will be useful, but |
| 21 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 23 | General Public License for more details. |
| 24 | |
| 25 | You should have received a copy of the GNU General Public License |
| 26 | along with this program; if not, write to the Free Software |
| 27 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 28 | 02111-1307, USA. |
| 29 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 30 | The GNU General Public License is contained in the file COPYING. |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 31 | */ |
| 32 | |
| 33 | #include "vg_include.h" |
| 34 | |
sewardj | a449568 | 2002-10-21 07:29:59 +0000 | [diff] [blame] | 35 | /* Define to debug the memory-leak-detector. */ |
| 36 | /* #define VG_DEBUG_LEAKCHECK */ |
| 37 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 38 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 39 | /*--------------------------------------------------------------*/ |
| 40 | /*--- Initialise program data/text etc on program startup. ---*/ |
| 41 | /*--------------------------------------------------------------*/ |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 42 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 43 | typedef |
| 44 | struct _ExeSeg { |
| 45 | Addr start; |
| 46 | UInt size; |
| 47 | struct _ExeSeg* next; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 48 | } |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 49 | ExeSeg; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 50 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 51 | /* The list of current executable segments loaded. Required so that when a |
| 52 | segment is munmap'd, if it's executable we can recognise it as such and |
| 53 | invalidate translations for it, and drop any basic-block specific |
| 54 | information being stored. If symbols are being used, this list will have |
| 55 | the same segments recorded in it as the SegInfo symbols list (but much |
| 56 | less information about each segment). |
| 57 | */ |
| 58 | static ExeSeg* exeSegsHead = NULL; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 59 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 60 | /* Prepend it -- mmaps/munmaps likely to follow a stack pattern(?) so this |
| 61 | is good. |
| 62 | Also check no segments overlap, which would be very bad. Check is linear |
| 63 | for each seg added (quadratic overall) but the total number should be |
| 64 | small (konqueror has around 50 --njn). */ |
njn | 20c25d5 | 2003-05-14 09:08:49 +0000 | [diff] [blame] | 65 | static void add_exe_segment_to_list( Addr a, UInt len ) |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 66 | { |
| 67 | Addr lo = a; |
| 68 | Addr hi = a + len - 1; |
| 69 | ExeSeg* es; |
| 70 | ExeSeg* es2; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 71 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 72 | /* Prepend it */ |
| 73 | es = (ExeSeg*)VG_(arena_malloc)(VG_AR_CORE, sizeof(ExeSeg)); |
| 74 | es->start = a; |
| 75 | es->size = len; |
| 76 | es->next = exeSegsHead; |
| 77 | exeSegsHead = es; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 78 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 79 | /* Check there's no overlap with the rest of the list */ |
| 80 | for (es2 = es->next; es2 != NULL; es2 = es2->next) { |
| 81 | Addr lo2 = es2->start; |
| 82 | Addr hi2 = es2->start + es2->size - 1; |
| 83 | Bool overlap; |
| 84 | vg_assert(lo < hi); |
| 85 | vg_assert(lo2 < hi2); |
| 86 | /* the main assertion */ |
| 87 | overlap = (lo <= lo2 && lo2 <= hi) |
| 88 | || (lo <= hi2 && hi2 <= hi); |
| 89 | if (overlap) { |
| 90 | VG_(printf)("\n\nOVERLAPPING EXE SEGMENTS\n" |
| 91 | " new: start %p, size %d\n" |
| 92 | " old: start %p, size %d\n\n", |
| 93 | es->start, es->size, es2->start, es2->size ); |
| 94 | vg_assert(! overlap); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 95 | } |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 96 | } |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 97 | } |
| 98 | |
njn | fa1016e | 2003-09-25 17:54:11 +0000 | [diff] [blame] | 99 | static Bool remove_if_exeseg_from_list( Addr a ) |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 100 | { |
| 101 | ExeSeg **prev_next_ptr = & exeSegsHead, |
| 102 | *curr = exeSegsHead; |
| 103 | |
| 104 | while (True) { |
| 105 | if (curr == NULL) break; |
| 106 | if (a == curr->start) break; |
| 107 | prev_next_ptr = &curr->next; |
| 108 | curr = curr->next; |
| 109 | } |
| 110 | if (curr == NULL) |
| 111 | return False; |
| 112 | |
| 113 | vg_assert(*prev_next_ptr == curr); |
| 114 | |
| 115 | *prev_next_ptr = curr->next; |
| 116 | |
| 117 | VG_(arena_free)(VG_AR_CORE, curr); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 118 | return True; |
| 119 | } |
| 120 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 121 | /* Records the exe segment in the ExeSeg list (checking for overlaps), and |
| 122 | reads debug info if required. Note the entire /proc/pid/maps file is |
| 123 | read for the debug info, but it just reads symbols for newly added exe |
njn | fa1016e | 2003-09-25 17:54:11 +0000 | [diff] [blame] | 124 | segments. This is required to find out their names if they have one, |
| 125 | because with mmap() we only have the file descriptor, not the name. We |
| 126 | don't use this at startup because we do have the names then. */ |
| 127 | void VG_(new_exeseg_mmap) ( Addr a, UInt len ) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 128 | { |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 129 | add_exe_segment_to_list( a, len ); |
njn | fa1016e | 2003-09-25 17:54:11 +0000 | [diff] [blame] | 130 | VG_(read_all_symbols)(); |
| 131 | } |
| 132 | |
| 133 | /* Like VG_(new_exeseg_mmap)(), but here we do have the name, so we don't |
| 134 | need to grovel through /proc/self/maps to find it. */ |
| 135 | void VG_(new_exeseg_startup) ( Addr a, UInt len, Char rr, Char ww, Char xx, |
| 136 | UInt foffset, UChar* filename ) |
| 137 | { |
| 138 | add_exe_segment_to_list( a, len ); |
| 139 | VG_(read_seg_symbols)( a, len, rr, ww, xx, foffset, filename); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 140 | } |
| 141 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 142 | /* Invalidate translations as necessary (also discarding any basic |
| 143 | block-specific info retained by the skin) and unload any debug |
| 144 | symbols. */ |
njn | fa1016e | 2003-09-25 17:54:11 +0000 | [diff] [blame] | 145 | // Nb: remove_if_exeseg_from_list() and VG_(maybe_unload_symbols)() |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 146 | // both ignore 'len', but that seems that's ok for most programs... see |
| 147 | // comment above vg_syscalls.c:mmap_segment() et al for more details. |
njn | fa1016e | 2003-09-25 17:54:11 +0000 | [diff] [blame] | 148 | void VG_(remove_if_exeseg) ( Addr a, UInt len ) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 149 | { |
njn | fa1016e | 2003-09-25 17:54:11 +0000 | [diff] [blame] | 150 | if (remove_if_exeseg_from_list( a )) { |
sewardj | 97ad552 | 2003-05-04 12:32:56 +0000 | [diff] [blame] | 151 | VG_(invalidate_translations) ( a, len, False ); |
sewardj | 8a77ffb | 2003-07-10 23:31:27 +0000 | [diff] [blame] | 152 | VG_(unload_symbols) ( a, len ); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 153 | } |
| 154 | } |
| 155 | |
| 156 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 157 | static |
| 158 | void startup_segment_callback ( Addr start, UInt size, |
| 159 | Char rr, Char ww, Char xx, |
| 160 | UInt foffset, UChar* filename ) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 161 | { |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 162 | UInt r_esp; |
| 163 | Bool is_stack_segment; |
sewardj | ecf8e10 | 2003-07-12 12:11:39 +0000 | [diff] [blame] | 164 | Bool verbose = False; /* set to True for debugging */ |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 165 | |
sewardj | ecf8e10 | 2003-07-12 12:11:39 +0000 | [diff] [blame] | 166 | if (verbose) |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 167 | VG_(message)(Vg_DebugMsg, |
| 168 | "initial map %8x-%8x %c%c%c? %8x (%d) (%s)", |
| 169 | start,start+size,rr,ww,xx,foffset, |
| 170 | size, filename?filename:(UChar*)"NULL"); |
| 171 | |
| 172 | if (rr != 'r' && xx != 'x' && ww != 'w') { |
sewardj | 6e4234e | 2002-10-06 00:28:21 +0000 | [diff] [blame] | 173 | /* Implausible as it seems, R H 6.2 generates such segments: |
| 174 | 40067000-400ac000 r-xp 00000000 08:05 320686 /usr/X11R6/lib/libXt.so.6.0 |
| 175 | 400ac000-400ad000 ---p 00045000 08:05 320686 /usr/X11R6/lib/libXt.so.6.0 |
| 176 | 400ad000-400b0000 rw-p 00045000 08:05 320686 /usr/X11R6/lib/libXt.so.6.0 |
| 177 | when running xedit. So just ignore them. */ |
| 178 | if (0) |
| 179 | VG_(printf)("No permissions on a segment mapped from %s\n", |
| 180 | filename?filename:(UChar*)"NULL"); |
| 181 | return; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 182 | } |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 183 | |
sewardj | ecf8e10 | 2003-07-12 12:11:39 +0000 | [diff] [blame] | 184 | /* If this segment corresponds to something mmap'd /dev/zero by the |
| 185 | low-level memory manager (vg_malloc2.c), skip it. Clients |
| 186 | should never have access to the segments which hold valgrind |
| 187 | internal data. And access to client data in the VG_AR_CLIENT |
| 188 | arena is mediated by the skin, so we don't want make it |
| 189 | accessible at this stage. */ |
| 190 | if (VG_(is_inside_segment_mmapd_by_low_level_MM)( start )) { |
| 191 | if (verbose) |
| 192 | VG_(message)(Vg_DebugMsg, |
| 193 | " skipping %8x-%8x (owned by our MM)", |
| 194 | start, start+size ); |
| 195 | /* Don't announce it to the skin. */ |
| 196 | return; |
| 197 | } |
| 198 | |
njn | fa1016e | 2003-09-25 17:54:11 +0000 | [diff] [blame] | 199 | /* This is similar to what happens when we mmap some new memory */ |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 200 | if (filename != NULL && xx == 'x') { |
njn | fa1016e | 2003-09-25 17:54:11 +0000 | [diff] [blame] | 201 | VG_(new_exeseg_startup)( start, size, rr, ww, xx, foffset, filename ); |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 202 | } |
sewardj | ecf8e10 | 2003-07-12 12:11:39 +0000 | [diff] [blame] | 203 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 204 | VG_TRACK( new_mem_startup, start, size, rr=='r', ww=='w', xx=='x' ); |
| 205 | |
| 206 | /* If this is the stack segment mark all below %esp as noaccess. */ |
| 207 | r_esp = VG_(baseBlock)[VGOFF_(m_esp)]; |
| 208 | is_stack_segment = start <= r_esp && r_esp < start+size; |
| 209 | if (is_stack_segment) { |
| 210 | if (0) |
| 211 | VG_(message)(Vg_DebugMsg, "invalidating stack area: %x .. %x", |
| 212 | start,r_esp); |
| 213 | VG_TRACK( die_mem_stack, start, r_esp-start ); |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 218 | /* 1. Records startup segments from /proc/pid/maps. Takes special note |
| 219 | of the executable ones, because if they're munmap()ed we need to |
| 220 | discard translations. Also checks there's no exe segment overlaps. |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 221 | |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 222 | Note that `read_from_file' is false; we read /proc/self/maps into a |
| 223 | buffer at the start of VG_(main) so that any superblocks mmap'd by |
| 224 | calls to VG_(malloc)() by SK_({pre,post}_clo_init) aren't erroneously |
| 225 | thought of as being owned by the client. |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 226 | |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 227 | 2. Sets up the end of the data segment so that vg_syscalls.c can make |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 228 | sense of calls to brk(). |
| 229 | */ |
| 230 | void VG_(init_memory) ( void ) |
| 231 | { |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 232 | /* 1 */ |
njn | fa1016e | 2003-09-25 17:54:11 +0000 | [diff] [blame] | 233 | VG_(parse_procselfmaps) ( startup_segment_callback ); |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 234 | |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 235 | /* 2 */ |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 236 | VG_(init_dataseg_end_for_brk)(); |
sewardj | d5815ec | 2003-04-06 12:23:27 +0000 | [diff] [blame] | 237 | |
| 238 | /* kludge: some newer kernels place a "sysinfo" page up high, with |
| 239 | vsyscalls in it, and possibly some other stuff in the future. */ |
| 240 | if (VG_(sysinfo_page_exists)) { |
njn | fa1016e | 2003-09-25 17:54:11 +0000 | [diff] [blame] | 241 | // 2003-Sep-25, njn: Jeremy thinks the sysinfo page probably doesn't |
| 242 | // have any symbols that need to be loaded. So just treat it like |
| 243 | // a non-executable page. |
| 244 | //VG_(new_exeseg_mmap)( VG_(sysinfo_page_addr), 4096 ); |
sewardj | d5815ec | 2003-04-06 12:23:27 +0000 | [diff] [blame] | 245 | VG_TRACK( new_mem_startup, VG_(sysinfo_page_addr), 4096, |
| 246 | True, True, True ); |
| 247 | } |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 248 | } |
| 249 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 250 | /*------------------------------------------------------------*/ |
| 251 | /*--- Tracking permissions around %esp changes. ---*/ |
| 252 | /*------------------------------------------------------------*/ |
| 253 | |
| 254 | /* |
| 255 | The stack |
| 256 | ~~~~~~~~~ |
| 257 | The stack's segment seems to be dynamically extended downwards |
| 258 | by the kernel as the stack pointer moves down. Initially, a |
| 259 | 1-page (4k) stack is allocated. When %esp moves below that for |
| 260 | the first time, presumably a page fault occurs. The kernel |
| 261 | detects that the faulting address is in the range from %esp upwards |
| 262 | to the current valid stack. It then extends the stack segment |
| 263 | downwards for enough to cover the faulting address, and resumes |
| 264 | the process (invisibly). The process is unaware of any of this. |
| 265 | |
| 266 | That means that Valgrind can't spot when the stack segment is |
| 267 | being extended. Fortunately, we want to precisely and continuously |
| 268 | update stack permissions around %esp, so we need to spot all |
| 269 | writes to %esp anyway. |
| 270 | |
| 271 | The deal is: when %esp is assigned a lower value, the stack is |
| 272 | being extended. Create a secondary maps to fill in any holes |
| 273 | between the old stack ptr and this one, if necessary. Then |
| 274 | mark all bytes in the area just "uncovered" by this %esp change |
| 275 | as write-only. |
| 276 | |
| 277 | When %esp goes back up, mark the area receded over as unreadable |
| 278 | and unwritable. |
| 279 | |
| 280 | Just to record the %esp boundary conditions somewhere convenient: |
| 281 | %esp always points to the lowest live byte in the stack. All |
| 282 | addresses below %esp are not live; those at and above it are. |
| 283 | */ |
| 284 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 285 | /* Kludgey ... how much does %esp have to change before we reckon that |
| 286 | the application is switching stacks ? */ |
njn | 9b007f6 | 2003-04-07 14:40:25 +0000 | [diff] [blame] | 287 | #define VG_PLAUSIBLE_STACK_SIZE 8000000 |
| 288 | #define VG_HUGE_DELTA (VG_PLAUSIBLE_STACK_SIZE / 4) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 289 | |
njn | 9b007f6 | 2003-04-07 14:40:25 +0000 | [diff] [blame] | 290 | /* This function gets called if new_mem_stack and/or die_mem_stack are |
| 291 | tracked by the skin, and one of the specialised cases (eg. new_mem_stack_4) |
| 292 | isn't used in preference */ |
| 293 | __attribute__((regparm(1))) |
| 294 | void VG_(unknown_esp_update)(Addr new_ESP) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 295 | { |
njn | 9b007f6 | 2003-04-07 14:40:25 +0000 | [diff] [blame] | 296 | Addr old_ESP = VG_(get_archreg)(R_ESP); |
| 297 | Int delta = (Int)new_ESP - (Int)old_ESP; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 298 | |
njn | 9b007f6 | 2003-04-07 14:40:25 +0000 | [diff] [blame] | 299 | if (delta < -(VG_HUGE_DELTA) || VG_HUGE_DELTA < delta) { |
| 300 | /* %esp has changed by more than HUGE_DELTA. We take this to mean |
| 301 | that the application is switching to a new stack, for whatever |
| 302 | reason. |
| 303 | |
| 304 | JRS 20021001: following discussions with John Regehr, if a stack |
| 305 | switch happens, it seems best not to mess at all with memory |
| 306 | permissions. Seems to work well with Netscape 4.X. Really the |
| 307 | only remaining difficulty is knowing exactly when a stack switch is |
| 308 | happening. */ |
| 309 | if (VG_(clo_verbosity) > 1) |
| 310 | VG_(message)(Vg_UserMsg, "Warning: client switching stacks? " |
| 311 | "%%esp: %p --> %p", old_ESP, new_ESP); |
| 312 | } else if (delta < 0) { |
| 313 | VG_TRACK( new_mem_stack, new_ESP, -delta ); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 314 | |
njn | 9b007f6 | 2003-04-07 14:40:25 +0000 | [diff] [blame] | 315 | } else if (delta > 0) { |
| 316 | VG_TRACK( die_mem_stack, old_ESP, delta ); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 317 | } |
| 318 | } |
| 319 | |
jsgf | 855d93d | 2003-10-13 22:26:55 +0000 | [diff] [blame^] | 320 | static jmp_buf segv_jmpbuf; |
| 321 | |
| 322 | static void segv_handler(Int seg) |
| 323 | { |
| 324 | __builtin_longjmp(segv_jmpbuf, 1); |
| 325 | VG_(core_panic)("longjmp failed"); |
| 326 | } |
| 327 | |
| 328 | /* |
| 329 | Test if a piece of memory is addressable by setting up a temporary |
| 330 | SIGSEGV handler, then try to touch the memory. No signal = good, |
| 331 | signal = bad. |
| 332 | */ |
| 333 | Bool VG_(is_addressable)(Addr p, Int size) |
| 334 | { |
| 335 | volatile Char * volatile cp = (volatile Char *)p; |
| 336 | volatile Bool ret; |
| 337 | vki_ksigaction sa, origsa; |
| 338 | vki_ksigset_t mask; |
| 339 | |
| 340 | vg_assert(size > 0); |
| 341 | |
| 342 | sa.ksa_handler = segv_handler; |
| 343 | sa.ksa_flags = 0; |
| 344 | VG_(ksigfillset)(&sa.ksa_mask); |
| 345 | VG_(ksigaction)(VKI_SIGSEGV, &sa, &origsa); |
| 346 | VG_(ksigprocmask)(VKI_SIG_SETMASK, NULL, &mask); |
| 347 | |
| 348 | if (__builtin_setjmp(&segv_jmpbuf) == 0) { |
| 349 | while(size--) |
| 350 | *cp++; |
| 351 | ret = True; |
| 352 | } else |
| 353 | ret = False; |
| 354 | |
| 355 | VG_(ksigaction)(VKI_SIGSEGV, &origsa, NULL); |
| 356 | VG_(ksigprocmask)(VKI_SIG_SETMASK, &mask, NULL); |
| 357 | |
| 358 | return ret; |
| 359 | } |
| 360 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 361 | /*--------------------------------------------------------------------*/ |
| 362 | /*--- end vg_memory.c ---*/ |
| 363 | /*--------------------------------------------------------------------*/ |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 364 | |