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 | |
| 12 | Copyright (C) 2000-2002 Julian Seward |
| 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). */ |
| 65 | static void add_exe_segment_to_list( a, len ) |
| 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 | |
| 99 | static Bool remove_if_exe_segment_from_list( Addr a, UInt len ) |
| 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 |
| 124 | segments. This is required to find out their names if they have one. So |
| 125 | we don't use this at startup because it's overkill and can screw reading |
| 126 | of /proc/pid/maps. |
| 127 | */ |
| 128 | void VG_(new_exe_segment) ( Addr a, UInt len ) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 129 | { |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 130 | add_exe_segment_to_list( a, len ); |
| 131 | VG_(maybe_read_symbols)(); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 132 | } |
| 133 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 134 | /* Invalidate translations as necessary (also discarding any basic |
| 135 | block-specific info retained by the skin) and unload any debug |
| 136 | symbols. */ |
| 137 | // Nb: remove_if_exe_segment_from_list() and VG_(maybe_unload_symbols)() |
| 138 | // both ignore 'len', but that seems that's ok for most programs... see |
| 139 | // comment above vg_syscalls.c:mmap_segment() et al for more details. |
| 140 | void VG_(remove_if_exe_segment) ( Addr a, UInt len ) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 141 | { |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 142 | if (remove_if_exe_segment_from_list( a, len )) { |
| 143 | VG_(invalidate_translations) ( a, len ); |
| 144 | VG_(maybe_unload_symbols) ( a, len ); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 145 | } |
| 146 | } |
| 147 | |
| 148 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 149 | static |
| 150 | void startup_segment_callback ( Addr start, UInt size, |
| 151 | Char rr, Char ww, Char xx, |
| 152 | UInt foffset, UChar* filename ) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 153 | { |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 154 | UInt r_esp; |
| 155 | Bool is_stack_segment; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 156 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 157 | /* Sanity check ... if this is the executable's text segment, |
| 158 | ensure it is loaded where we think it ought to be. Any file |
| 159 | name which doesn't contain ".so" is assumed to be the |
| 160 | executable. */ |
| 161 | if (filename != NULL |
| 162 | && xx == 'x' |
| 163 | && VG_(strstr(filename, ".so")) == NULL |
| 164 | ) { |
| 165 | /* We assume this is the executable. */ |
| 166 | if (start != VG_ASSUMED_EXE_BASE) { |
| 167 | VG_(message)(Vg_UserMsg, |
| 168 | "FATAL: executable base addr not as assumed."); |
| 169 | VG_(message)(Vg_UserMsg, "name %s, actual %p, assumed %p.", |
| 170 | filename, start, VG_ASSUMED_EXE_BASE); |
| 171 | VG_(message)(Vg_UserMsg, |
| 172 | "One reason this could happen is that you have a shared object"); |
| 173 | VG_(message)(Vg_UserMsg, |
| 174 | " whose name doesn't contain the characters \".so\", so Valgrind "); |
| 175 | VG_(message)(Vg_UserMsg, |
| 176 | "naively assumes it is the executable. "); |
| 177 | VG_(message)(Vg_UserMsg, |
| 178 | "In that case, rename it appropriately."); |
njn | e427a66 | 2002-10-02 11:08:25 +0000 | [diff] [blame] | 179 | VG_(core_panic)("VG_ASSUMED_EXE_BASE doesn't match reality"); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 180 | } |
| 181 | } |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 182 | |
| 183 | if (0) |
| 184 | VG_(message)(Vg_DebugMsg, |
| 185 | "initial map %8x-%8x %c%c%c? %8x (%d) (%s)", |
| 186 | start,start+size,rr,ww,xx,foffset, |
| 187 | size, filename?filename:(UChar*)"NULL"); |
| 188 | |
| 189 | if (rr != 'r' && xx != 'x' && ww != 'w') { |
sewardj | 6e4234e | 2002-10-06 00:28:21 +0000 | [diff] [blame] | 190 | /* Implausible as it seems, R H 6.2 generates such segments: |
| 191 | 40067000-400ac000 r-xp 00000000 08:05 320686 /usr/X11R6/lib/libXt.so.6.0 |
| 192 | 400ac000-400ad000 ---p 00045000 08:05 320686 /usr/X11R6/lib/libXt.so.6.0 |
| 193 | 400ad000-400b0000 rw-p 00045000 08:05 320686 /usr/X11R6/lib/libXt.so.6.0 |
| 194 | when running xedit. So just ignore them. */ |
| 195 | if (0) |
| 196 | VG_(printf)("No permissions on a segment mapped from %s\n", |
| 197 | filename?filename:(UChar*)"NULL"); |
| 198 | return; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 199 | } |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 200 | |
| 201 | /* This parallels what happens when we mmap some new memory */ |
| 202 | if (filename != NULL && xx == 'x') { |
| 203 | VG_(new_exe_segment)( start, size ); |
| 204 | } |
| 205 | VG_TRACK( new_mem_startup, start, size, rr=='r', ww=='w', xx=='x' ); |
| 206 | |
| 207 | /* If this is the stack segment mark all below %esp as noaccess. */ |
| 208 | r_esp = VG_(baseBlock)[VGOFF_(m_esp)]; |
| 209 | is_stack_segment = start <= r_esp && r_esp < start+size; |
| 210 | if (is_stack_segment) { |
| 211 | if (0) |
| 212 | VG_(message)(Vg_DebugMsg, "invalidating stack area: %x .. %x", |
| 213 | start,r_esp); |
| 214 | VG_TRACK( die_mem_stack, start, r_esp-start ); |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | |
| 219 | /* 1. Records exe segments from /proc/pid/maps -- always necessary, because |
| 220 | if they're munmap()ed we need to know if they were executable in order |
| 221 | to discard translations. Also checks there's no exe segment overlaps. |
| 222 | |
| 223 | 2. Marks global variables that might be accessed from generated code; |
| 224 | |
| 225 | 3. Sets up the end of the data segment so that vg_syscalls.c can make |
| 226 | sense of calls to brk(). |
| 227 | */ |
| 228 | void VG_(init_memory) ( void ) |
| 229 | { |
| 230 | /* 1 and 2 */ |
| 231 | VG_(read_procselfmaps) ( startup_segment_callback ); |
| 232 | |
| 233 | /* 3 */ |
| 234 | VG_TRACK( post_mem_write, (Addr) & VG_(running_on_simd_CPU), 1 ); |
| 235 | VG_TRACK( post_mem_write, (Addr) & VG_(clo_trace_malloc), 1 ); |
| 236 | VG_TRACK( post_mem_write, (Addr) & VG_(clo_sloppy_malloc), 1 ); |
| 237 | |
| 238 | /* 4 */ |
| 239 | VG_(init_dataseg_end_for_brk)(); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 240 | } |
| 241 | |
| 242 | |
| 243 | /*------------------------------------------------------------*/ |
| 244 | /*--- Tracking permissions around %esp changes. ---*/ |
| 245 | /*------------------------------------------------------------*/ |
| 246 | |
| 247 | /* |
| 248 | The stack |
| 249 | ~~~~~~~~~ |
| 250 | The stack's segment seems to be dynamically extended downwards |
| 251 | by the kernel as the stack pointer moves down. Initially, a |
| 252 | 1-page (4k) stack is allocated. When %esp moves below that for |
| 253 | the first time, presumably a page fault occurs. The kernel |
| 254 | detects that the faulting address is in the range from %esp upwards |
| 255 | to the current valid stack. It then extends the stack segment |
| 256 | downwards for enough to cover the faulting address, and resumes |
| 257 | the process (invisibly). The process is unaware of any of this. |
| 258 | |
| 259 | That means that Valgrind can't spot when the stack segment is |
| 260 | being extended. Fortunately, we want to precisely and continuously |
| 261 | update stack permissions around %esp, so we need to spot all |
| 262 | writes to %esp anyway. |
| 263 | |
| 264 | The deal is: when %esp is assigned a lower value, the stack is |
| 265 | being extended. Create a secondary maps to fill in any holes |
| 266 | between the old stack ptr and this one, if necessary. Then |
| 267 | mark all bytes in the area just "uncovered" by this %esp change |
| 268 | as write-only. |
| 269 | |
| 270 | When %esp goes back up, mark the area receded over as unreadable |
| 271 | and unwritable. |
| 272 | |
| 273 | Just to record the %esp boundary conditions somewhere convenient: |
| 274 | %esp always points to the lowest live byte in the stack. All |
| 275 | addresses below %esp are not live; those at and above it are. |
| 276 | */ |
| 277 | |
sewardj | 1e8cdc9 | 2002-04-18 11:37:52 +0000 | [diff] [blame] | 278 | /* Does this address look like something in or vaguely near the |
| 279 | current thread's stack? */ |
sewardj | ee588a9 | 2002-10-05 15:28:29 +0000 | [diff] [blame] | 280 | static __attribute__((unused)) |
sewardj | 1e8cdc9 | 2002-04-18 11:37:52 +0000 | [diff] [blame] | 281 | Bool is_plausible_stack_addr ( ThreadState* tst, Addr aa ) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 282 | { |
| 283 | UInt a = (UInt)aa; |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 284 | //PROF_EVENT(100); PPP |
sewardj | 1e8cdc9 | 2002-04-18 11:37:52 +0000 | [diff] [blame] | 285 | if (a <= tst->stack_highest_word && |
| 286 | a > tst->stack_highest_word - VG_PLAUSIBLE_STACK_SIZE) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 287 | return True; |
| 288 | else |
| 289 | return False; |
| 290 | } |
| 291 | |
| 292 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 293 | /* Kludgey ... how much does %esp have to change before we reckon that |
| 294 | the application is switching stacks ? */ |
| 295 | #define VG_HUGE_DELTA (VG_PLAUSIBLE_STACK_SIZE / 4) |
| 296 | |
sewardj | ee588a9 | 2002-10-05 15:28:29 +0000 | [diff] [blame] | 297 | static __attribute__((unused)) |
| 298 | Addr get_page_base ( Addr a ) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 299 | { |
| 300 | return a & ~(VKI_BYTES_PER_PAGE-1); |
| 301 | } |
| 302 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 303 | static void vg_handle_esp_assignment_SLOWLY ( Addr old_esp, Addr new_esp ); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 304 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 305 | __attribute__ ((regparm (1))) |
| 306 | void VG_(handle_esp_assignment) ( Addr new_esp ) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 307 | { |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 308 | UInt old_esp; |
| 309 | Int delta; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 310 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 311 | VGP_MAYBE_PUSHCC(VgpStack); |
| 312 | |
| 313 | old_esp = VG_(baseBlock)[VGOFF_(m_esp)]; |
| 314 | delta = ((Int)new_esp) - ((Int)old_esp); |
| 315 | |
| 316 | /* Update R_ESP */ |
| 317 | VG_(baseBlock)[VGOFF_(m_esp)] = new_esp; |
| 318 | |
| 319 | //PROF_EVENT(101); PPP |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 320 | |
| 321 | # ifndef VG_DEBUG_MEMORY |
| 322 | |
sewardj | 799f521 | 2002-10-01 09:09:23 +0000 | [diff] [blame] | 323 | if (IS_ALIGNED4_ADDR(old_esp) && IS_ALIGNED4_ADDR(new_esp)) { |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 324 | |
| 325 | /* Deal with the most common cases fast. These are ordered in |
| 326 | the sequence most common first. */ |
| 327 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 328 | # ifdef VG_PROFILE_MEMORY |
| 329 | // PPP |
| 330 | if (delta = - 4) PROF_EVENT(102); |
| 331 | else if (delta = 4) PROF_EVENT(103); |
| 332 | else if (delta = -12) PROF_EVENT(104); |
| 333 | else if (delta = - 8) PROF_EVENT(105); |
| 334 | else if (delta = 16) PROF_EVENT(106); |
| 335 | else if (delta = 12) PROF_EVENT(107); |
| 336 | else if (delta = 0) PROF_EVENT(108); |
| 337 | else if (delta = 8) PROF_EVENT(109); |
| 338 | else if (delta = -16) PROF_EVENT(110); |
| 339 | else if (delta = 20) PROF_EVENT(111); |
| 340 | else if (delta = -20) PROF_EVENT(112); |
| 341 | else if (delta = 24) PROF_EVENT(113); |
| 342 | else if (delta = -24) PROF_EVENT(114); |
| 343 | else if (delta > 0) PROF_EVENT(115); // PPP: new: aligned_big_pos |
| 344 | else PROF_EVENT(116); // PPP: new: aligned_big_neg |
| 345 | # endif |
| 346 | |
sewardj | 799f521 | 2002-10-01 09:09:23 +0000 | [diff] [blame] | 347 | if (delta < 0 && delta > -2000) { |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 348 | VG_TRACK(new_mem_stack_aligned, new_esp, -delta); |
sewardj | 799f521 | 2002-10-01 09:09:23 +0000 | [diff] [blame] | 349 | VGP_MAYBE_POPCC(VgpStack); |
| 350 | return; |
| 351 | } |
| 352 | else |
| 353 | if (delta > 0 && delta < 2000) { |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 354 | VG_TRACK(die_mem_stack_aligned, old_esp, delta); |
sewardj | 799f521 | 2002-10-01 09:09:23 +0000 | [diff] [blame] | 355 | VGP_MAYBE_POPCC(VgpStack); |
| 356 | return; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 357 | } |
sewardj | 8afd9fe | 2002-10-02 01:38:40 +0000 | [diff] [blame] | 358 | if (delta == 0) { |
| 359 | VGP_MAYBE_POPCC(VgpStack); |
| 360 | return; |
| 361 | } |
sewardj | 799f521 | 2002-10-01 09:09:23 +0000 | [diff] [blame] | 362 | /* otherwise fall onto the slow-but-general case */ |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 363 | } |
| 364 | |
| 365 | # endif |
| 366 | |
| 367 | /* The above special cases handle 90% to 95% of all the stack |
| 368 | adjustments. The rest we give to the slow-but-general |
| 369 | mechanism. */ |
sewardj | 799f521 | 2002-10-01 09:09:23 +0000 | [diff] [blame] | 370 | /* VG_(printf)("big delta %d\n", delta); */ |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 371 | vg_handle_esp_assignment_SLOWLY ( old_esp, new_esp ); |
| 372 | VGP_MAYBE_POPCC(VgpStack); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 373 | } |
| 374 | |
| 375 | |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 376 | static void vg_handle_esp_assignment_SLOWLY ( Addr old_esp, Addr new_esp ) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 377 | { |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 378 | Int delta; |
| 379 | |
| 380 | delta = ((Int)new_esp) - ((Int)old_esp); |
| 381 | //VG_(printf)("delta %d (%x) %x --> %x\n", delta, delta, old_esp, new_esp); |
| 382 | //PROF_EVENT(120); PPP |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 383 | if (-(VG_HUGE_DELTA) < delta && delta < VG_HUGE_DELTA) { |
| 384 | /* "Ordinary" stack change. */ |
| 385 | if (new_esp < old_esp) { |
| 386 | /* Moving down; the stack is growing. */ |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 387 | //PROF_EVENT(121); PPP |
| 388 | VG_TRACK( new_mem_stack, new_esp, -delta ); |
| 389 | |
| 390 | } else if (new_esp > old_esp) { |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 391 | /* Moving up; the stack is shrinking. */ |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 392 | //PROF_EVENT(122); PPP |
| 393 | VG_TRACK( die_mem_stack, old_esp, delta ); |
| 394 | |
| 395 | } else { |
| 396 | /* when old_esp == new_esp */ |
| 397 | //PROF_EVENT(123); PPP |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 398 | } |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 399 | return; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 400 | } |
| 401 | |
| 402 | /* %esp has changed by more than HUGE_DELTA. We take this to mean |
| 403 | that the application is switching to a new stack, for whatever |
| 404 | reason, and we attempt to initialise the permissions around the |
| 405 | new stack in some plausible way. All pretty kludgey; needed to |
| 406 | make netscape-4.07 run without generating thousands of error |
| 407 | contexts. |
| 408 | |
| 409 | If we appear to be switching back to the main stack, don't mess |
| 410 | with the permissions in the area at and above the stack ptr. |
| 411 | Otherwise, we're switching to an alternative stack; make the |
| 412 | area above %esp readable -- this doesn't seem right -- the right |
| 413 | thing to do would be to make it writable -- but is needed to |
| 414 | avoid huge numbers of errs in netscape. To be investigated. */ |
| 415 | |
sewardj | ee588a9 | 2002-10-05 15:28:29 +0000 | [diff] [blame] | 416 | { |
| 417 | # if 0 |
| 418 | Addr invalid_down_to = get_page_base(new_esp) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 419 | - 0 * VKI_BYTES_PER_PAGE; |
| 420 | Addr valid_up_to = get_page_base(new_esp) + VKI_BYTES_PER_PAGE |
| 421 | + 0 * VKI_BYTES_PER_PAGE; |
sewardj | 1e8cdc9 | 2002-04-18 11:37:52 +0000 | [diff] [blame] | 422 | ThreadState* tst = VG_(get_current_thread_state)(); |
sewardj | ee588a9 | 2002-10-05 15:28:29 +0000 | [diff] [blame] | 423 | # endif |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 424 | //PROF_EVENT(124); PPP |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 425 | if (VG_(clo_verbosity) > 1) |
| 426 | VG_(message)(Vg_UserMsg, "Warning: client switching stacks? " |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 427 | "%%esp: %p --> %p", old_esp, new_esp); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 428 | /* VG_(printf)("na %p, %%esp %p, wr %p\n", |
| 429 | invalid_down_to, new_esp, valid_up_to ); */ |
sewardj | 8afd9fe | 2002-10-02 01:38:40 +0000 | [diff] [blame] | 430 | # if 0 |
| 431 | /* JRS 20021001: following discussions with John Regehr, just |
| 432 | remove this. If a stack switch happens, it seems best not to |
| 433 | mess at all with memory permissions. Seems to work well with |
| 434 | Netscape 4.X. Really the only remaining difficulty is knowing |
| 435 | exactly when a stack switch is happening. */ |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 436 | VG_TRACK( die_mem_stack, invalid_down_to, new_esp - invalid_down_to ); |
sewardj | 1e8cdc9 | 2002-04-18 11:37:52 +0000 | [diff] [blame] | 437 | if (!is_plausible_stack_addr(tst, new_esp)) { |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 438 | VG_TRACK( post_mem_write, new_esp, valid_up_to - new_esp ); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 439 | } |
sewardj | 8afd9fe | 2002-10-02 01:38:40 +0000 | [diff] [blame] | 440 | # endif |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 441 | } |
| 442 | } |
| 443 | |
| 444 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 445 | /*--------------------------------------------------------------------*/ |
sewardj | a449568 | 2002-10-21 07:29:59 +0000 | [diff] [blame^] | 446 | /*--- Support for memory leak detectors ---*/ |
| 447 | /*--------------------------------------------------------------------*/ |
| 448 | |
| 449 | /*------------------------------------------------------------*/ |
| 450 | /*--- Low-level address-space scanning, for the leak ---*/ |
| 451 | /*--- detector. ---*/ |
| 452 | /*------------------------------------------------------------*/ |
| 453 | |
| 454 | static |
| 455 | jmp_buf memscan_jmpbuf; |
| 456 | |
| 457 | |
| 458 | static |
| 459 | void vg_scan_all_valid_memory_sighandler ( Int sigNo ) |
| 460 | { |
| 461 | __builtin_longjmp(memscan_jmpbuf, 1); |
| 462 | } |
| 463 | |
| 464 | |
| 465 | /* Safely (avoiding SIGSEGV / SIGBUS) scan the entire valid address |
| 466 | space and pass the addresses and values of all addressible, |
| 467 | defined, aligned words to notify_word. This is the basis for the |
| 468 | leak detector. Returns the number of calls made to notify_word. |
| 469 | |
| 470 | Addresses are validated 3 ways. First we enquire whether (addr >> |
| 471 | 16) denotes a 64k chunk in use, by asking is_valid_64k_chunk(). If |
| 472 | so, we decide for ourselves whether each x86-level (4 K) page in |
| 473 | the chunk is safe to inspect. If yes, we enquire with |
| 474 | is_valid_address() whether or not each of the 1024 word-locations |
| 475 | on the page is valid. Only if so are that address and its contents |
| 476 | passed to notify_word. |
| 477 | |
| 478 | This is all to avoid duplication of this machinery between the |
| 479 | memcheck and addrcheck skins. |
| 480 | */ |
| 481 | static |
| 482 | UInt vg_scan_all_valid_memory ( Bool is_valid_64k_chunk ( UInt ), |
| 483 | Bool is_valid_address ( Addr ), |
| 484 | void (*notify_word)( Addr, UInt ) ) |
| 485 | { |
| 486 | /* All volatile, because some gccs seem paranoid about longjmp(). */ |
| 487 | volatile Addr pageBase, addr; |
| 488 | volatile UInt res, numPages, page, primaryMapNo; |
| 489 | volatile UInt page_first_word, nWordsNotified; |
| 490 | |
| 491 | vki_ksigaction sigbus_saved; |
| 492 | vki_ksigaction sigbus_new; |
| 493 | vki_ksigaction sigsegv_saved; |
| 494 | vki_ksigaction sigsegv_new; |
| 495 | vki_ksigset_t blockmask_saved; |
| 496 | vki_ksigset_t unblockmask_new; |
| 497 | |
| 498 | /* Temporarily install a new sigsegv and sigbus handler, and make |
| 499 | sure SIGBUS, SIGSEGV and SIGTERM are unblocked. (Perhaps the |
| 500 | first two can never be blocked anyway?) */ |
| 501 | |
| 502 | sigbus_new.ksa_handler = vg_scan_all_valid_memory_sighandler; |
| 503 | sigbus_new.ksa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART; |
| 504 | sigbus_new.ksa_restorer = NULL; |
| 505 | res = VG_(ksigemptyset)( &sigbus_new.ksa_mask ); |
| 506 | sk_assert(res == 0); |
| 507 | |
| 508 | sigsegv_new.ksa_handler = vg_scan_all_valid_memory_sighandler; |
| 509 | sigsegv_new.ksa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART; |
| 510 | sigsegv_new.ksa_restorer = NULL; |
| 511 | res = VG_(ksigemptyset)( &sigsegv_new.ksa_mask ); |
| 512 | sk_assert(res == 0+0); |
| 513 | |
| 514 | res = VG_(ksigemptyset)( &unblockmask_new ); |
| 515 | res |= VG_(ksigaddset)( &unblockmask_new, VKI_SIGBUS ); |
| 516 | res |= VG_(ksigaddset)( &unblockmask_new, VKI_SIGSEGV ); |
| 517 | res |= VG_(ksigaddset)( &unblockmask_new, VKI_SIGTERM ); |
| 518 | sk_assert(res == 0+0+0); |
| 519 | |
| 520 | res = VG_(ksigaction)( VKI_SIGBUS, &sigbus_new, &sigbus_saved ); |
| 521 | sk_assert(res == 0+0+0+0); |
| 522 | |
| 523 | res = VG_(ksigaction)( VKI_SIGSEGV, &sigsegv_new, &sigsegv_saved ); |
| 524 | sk_assert(res == 0+0+0+0+0); |
| 525 | |
| 526 | res = VG_(ksigprocmask)( VKI_SIG_UNBLOCK, &unblockmask_new, &blockmask_saved ); |
| 527 | sk_assert(res == 0+0+0+0+0+0); |
| 528 | |
| 529 | /* The signal handlers are installed. Actually do the memory scan. */ |
| 530 | numPages = 1 << (32-VKI_BYTES_PER_PAGE_BITS); |
| 531 | sk_assert(numPages == 1048576); |
| 532 | sk_assert(4096 == (1 << VKI_BYTES_PER_PAGE_BITS)); |
| 533 | |
| 534 | nWordsNotified = 0; |
| 535 | |
| 536 | for (page = 0; page < numPages; page++) { |
| 537 | |
| 538 | /* Base address of this 4k page. */ |
| 539 | pageBase = page << VKI_BYTES_PER_PAGE_BITS; |
| 540 | |
| 541 | /* Skip if this page is in an unused 64k chunk. */ |
| 542 | primaryMapNo = pageBase >> 16; |
| 543 | if (!is_valid_64k_chunk(primaryMapNo)) |
| 544 | continue; |
| 545 | |
| 546 | /* Ok, we have to prod cautiously at the page and see if it |
| 547 | explodes or not. */ |
| 548 | if (__builtin_setjmp(memscan_jmpbuf) == 0) { |
| 549 | /* try this ... */ |
| 550 | page_first_word = * (volatile UInt*)pageBase; |
| 551 | /* we get here if we didn't get a fault */ |
| 552 | /* Scan the page */ |
| 553 | for (addr = pageBase; addr < pageBase+VKI_BYTES_PER_PAGE; addr += 4) { |
| 554 | if (is_valid_address(addr)) { |
| 555 | nWordsNotified++; |
| 556 | notify_word ( addr, *(UInt*)addr ); |
| 557 | } |
| 558 | } |
| 559 | } else { |
| 560 | /* We get here if reading the first word of the page caused a |
| 561 | fault, which in turn caused the signal handler to longjmp. |
| 562 | Ignore this page. */ |
| 563 | if (0) |
| 564 | VG_(printf)( |
| 565 | "vg_scan_all_valid_memory_sighandler: ignoring page at %p\n", |
| 566 | (void*)pageBase |
| 567 | ); |
| 568 | } |
| 569 | } |
| 570 | |
| 571 | /* Restore signal state to whatever it was before. */ |
| 572 | res = VG_(ksigaction)( VKI_SIGBUS, &sigbus_saved, NULL ); |
| 573 | sk_assert(res == 0 +0); |
| 574 | |
| 575 | res = VG_(ksigaction)( VKI_SIGSEGV, &sigsegv_saved, NULL ); |
| 576 | sk_assert(res == 0 +0 +0); |
| 577 | |
| 578 | res = VG_(ksigprocmask)( VKI_SIG_SETMASK, &blockmask_saved, NULL ); |
| 579 | sk_assert(res == 0 +0 +0 +0); |
| 580 | |
| 581 | return nWordsNotified; |
| 582 | } |
| 583 | |
| 584 | |
| 585 | /*------------------------------------------------------------*/ |
| 586 | /*--- Detecting leaked (unreachable) malloc'd blocks. ---*/ |
| 587 | /*------------------------------------------------------------*/ |
| 588 | |
| 589 | /* A block is either |
| 590 | -- Proper-ly reached; a pointer to its start has been found |
| 591 | -- Interior-ly reached; only an interior pointer to it has been found |
| 592 | -- Unreached; so far, no pointers to any part of it have been found. |
| 593 | */ |
| 594 | typedef |
| 595 | enum { Unreached, Interior, Proper } |
| 596 | Reachedness; |
| 597 | |
| 598 | /* A block record, used for generating err msgs. */ |
| 599 | typedef |
| 600 | struct _LossRecord { |
| 601 | struct _LossRecord* next; |
| 602 | /* Where these lost blocks were allocated. */ |
| 603 | ExeContext* allocated_at; |
| 604 | /* Their reachability. */ |
| 605 | Reachedness loss_mode; |
| 606 | /* Number of blocks and total # bytes involved. */ |
| 607 | UInt total_bytes; |
| 608 | UInt num_blocks; |
| 609 | } |
| 610 | LossRecord; |
| 611 | |
| 612 | |
| 613 | /* Find the i such that ptr points at or inside the block described by |
| 614 | shadows[i]. Return -1 if none found. This assumes that shadows[] |
| 615 | has been sorted on the ->data field. */ |
| 616 | |
| 617 | #ifdef VG_DEBUG_LEAKCHECK |
| 618 | /* Used to sanity-check the fast binary-search mechanism. */ |
| 619 | static |
| 620 | Int find_shadow_for_OLD ( Addr ptr, |
| 621 | ShadowChunk** shadows, |
| 622 | Int n_shadows ) |
| 623 | |
| 624 | { |
| 625 | Int i; |
| 626 | Addr a_lo, a_hi; |
| 627 | PROF_EVENT(70); |
| 628 | for (i = 0; i < n_shadows; i++) { |
| 629 | PROF_EVENT(71); |
| 630 | a_lo = shadows[i]->data; |
| 631 | a_hi = ((Addr)shadows[i]->data) + shadows[i]->size - 1; |
| 632 | if (a_lo <= ptr && ptr <= a_hi) |
| 633 | return i; |
| 634 | } |
| 635 | return -1; |
| 636 | } |
| 637 | #endif |
| 638 | |
| 639 | |
| 640 | static |
| 641 | Int find_shadow_for ( Addr ptr, |
| 642 | ShadowChunk** shadows, |
| 643 | Int n_shadows ) |
| 644 | { |
| 645 | Addr a_mid_lo, a_mid_hi; |
| 646 | Int lo, mid, hi, retVal; |
| 647 | /* VG_(printf)("find shadow for %p = ", ptr); */ |
| 648 | retVal = -1; |
| 649 | lo = 0; |
| 650 | hi = n_shadows-1; |
| 651 | while (True) { |
| 652 | /* invariant: current unsearched space is from lo to hi, |
| 653 | inclusive. */ |
| 654 | if (lo > hi) break; /* not found */ |
| 655 | |
| 656 | mid = (lo + hi) / 2; |
| 657 | a_mid_lo = shadows[mid]->data; |
| 658 | a_mid_hi = ((Addr)shadows[mid]->data) + shadows[mid]->size - 1; |
| 659 | |
| 660 | if (ptr < a_mid_lo) { |
| 661 | hi = mid-1; |
| 662 | continue; |
| 663 | } |
| 664 | if (ptr > a_mid_hi) { |
| 665 | lo = mid+1; |
| 666 | continue; |
| 667 | } |
| 668 | sk_assert(ptr >= a_mid_lo && ptr <= a_mid_hi); |
| 669 | retVal = mid; |
| 670 | break; |
| 671 | } |
| 672 | |
| 673 | # ifdef VG_DEBUG_LEAKCHECK |
| 674 | vg_assert(retVal == find_shadow_for_OLD ( ptr, shadows, n_shadows )); |
| 675 | # endif |
| 676 | /* VG_(printf)("%d\n", retVal); */ |
| 677 | return retVal; |
| 678 | } |
| 679 | |
| 680 | |
| 681 | |
| 682 | static |
| 683 | void sort_malloc_shadows ( ShadowChunk** shadows, UInt n_shadows ) |
| 684 | { |
| 685 | Int incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, |
| 686 | 9841, 29524, 88573, 265720, |
| 687 | 797161, 2391484 }; |
| 688 | Int lo = 0; |
| 689 | Int hi = n_shadows-1; |
| 690 | Int i, j, h, bigN, hp; |
| 691 | ShadowChunk* v; |
| 692 | |
| 693 | bigN = hi - lo + 1; if (bigN < 2) return; |
| 694 | hp = 0; while (incs[hp] < bigN) hp++; hp--; |
| 695 | |
| 696 | for (; hp >= 0; hp--) { |
| 697 | h = incs[hp]; |
| 698 | i = lo + h; |
| 699 | while (1) { |
| 700 | if (i > hi) break; |
| 701 | v = shadows[i]; |
| 702 | j = i; |
| 703 | while (shadows[j-h]->data > v->data) { |
| 704 | shadows[j] = shadows[j-h]; |
| 705 | j = j - h; |
| 706 | if (j <= (lo + h - 1)) break; |
| 707 | } |
| 708 | shadows[j] = v; |
| 709 | i++; |
| 710 | } |
| 711 | } |
| 712 | } |
| 713 | |
| 714 | |
| 715 | /* Globals, for the callback used by VG_(detect_memory_leaks). */ |
| 716 | |
| 717 | static ShadowChunk** vglc_shadows; |
| 718 | static Int vglc_n_shadows; |
| 719 | static Reachedness* vglc_reachedness; |
| 720 | static Addr vglc_min_mallocd_addr; |
| 721 | static Addr vglc_max_mallocd_addr; |
| 722 | |
| 723 | static |
| 724 | void vg_detect_memory_leaks_notify_addr ( Addr a, UInt word_at_a ) |
| 725 | { |
| 726 | Int sh_no; |
| 727 | Addr ptr; |
| 728 | |
| 729 | /* Rule out some known causes of bogus pointers. Mostly these do |
| 730 | not cause much trouble because only a few false pointers can |
| 731 | ever lurk in these places. This mainly stops it reporting that |
| 732 | blocks are still reachable in stupid test programs like this |
| 733 | |
| 734 | int main (void) { char* a = malloc(100); return 0; } |
| 735 | |
| 736 | which people seem inordinately fond of writing, for some reason. |
| 737 | |
| 738 | Note that this is a complete kludge. It would be better to |
| 739 | ignore any addresses corresponding to valgrind.so's .bss and |
| 740 | .data segments, but I cannot think of a reliable way to identify |
| 741 | where the .bss segment has been put. If you can, drop me a |
| 742 | line. |
| 743 | */ |
| 744 | if (VG_(within_stack)(a)) return; |
| 745 | if (VG_(within_m_state_static)(a)) return; |
| 746 | if (a == (Addr)(&vglc_min_mallocd_addr)) return; |
| 747 | if (a == (Addr)(&vglc_max_mallocd_addr)) return; |
| 748 | |
| 749 | /* OK, let's get on and do something Useful for a change. */ |
| 750 | |
| 751 | ptr = (Addr)word_at_a; |
| 752 | if (ptr >= vglc_min_mallocd_addr && ptr <= vglc_max_mallocd_addr) { |
| 753 | /* Might be legitimate; we'll have to investigate further. */ |
| 754 | sh_no = find_shadow_for ( ptr, vglc_shadows, vglc_n_shadows ); |
| 755 | if (sh_no != -1) { |
| 756 | /* Found a block at/into which ptr points. */ |
| 757 | sk_assert(sh_no >= 0 && sh_no < vglc_n_shadows); |
| 758 | sk_assert(ptr < vglc_shadows[sh_no]->data |
| 759 | + vglc_shadows[sh_no]->size); |
| 760 | /* Decide whether Proper-ly or Interior-ly reached. */ |
| 761 | if (ptr == vglc_shadows[sh_no]->data) { |
| 762 | if (0) VG_(printf)("pointer at %p to %p\n", a, word_at_a ); |
| 763 | vglc_reachedness[sh_no] = Proper; |
| 764 | } else { |
| 765 | if (vglc_reachedness[sh_no] == Unreached) |
| 766 | vglc_reachedness[sh_no] = Interior; |
| 767 | } |
| 768 | } |
| 769 | } |
| 770 | } |
| 771 | |
| 772 | |
| 773 | /* Top level entry point to leak detector. Call here, passing in |
| 774 | suitable address-validating functions (see comment at top of |
| 775 | vg_scan_all_valid_memory above). All this is to avoid duplication |
| 776 | of the leak-detection code for the Memcheck and Addrcheck skins. |
| 777 | Also pass in a skin-specific function to extract the .where field |
| 778 | for allocated blocks, an indication of the resolution wanted for |
| 779 | distinguishing different allocation points, and whether or not |
| 780 | reachable blocks should be shown. |
| 781 | */ |
| 782 | void VG_(generic_detect_memory_leaks) ( |
| 783 | Bool is_valid_64k_chunk ( UInt ), |
| 784 | Bool is_valid_address ( Addr ), |
| 785 | ExeContext* get_where ( ShadowChunk* ), |
| 786 | VgRes leak_resolution, |
| 787 | Bool show_reachable |
| 788 | ) |
| 789 | { |
| 790 | Int i; |
| 791 | Int blocks_leaked, bytes_leaked; |
| 792 | Int blocks_dubious, bytes_dubious; |
| 793 | Int blocks_reachable, bytes_reachable; |
| 794 | Int n_lossrecords; |
| 795 | UInt bytes_notified; |
| 796 | |
| 797 | LossRecord* errlist; |
| 798 | LossRecord* p; |
| 799 | |
| 800 | /* VG_(get_malloc_shadows) allocates storage for shadows */ |
| 801 | vglc_shadows = VG_(get_malloc_shadows)( &vglc_n_shadows ); |
| 802 | if (vglc_n_shadows == 0) { |
| 803 | sk_assert(vglc_shadows == NULL); |
| 804 | VG_(message)(Vg_UserMsg, |
| 805 | "No malloc'd blocks -- no leaks are possible.\n"); |
| 806 | return; |
| 807 | } |
| 808 | |
| 809 | VG_(message)(Vg_UserMsg, |
| 810 | "searching for pointers to %d not-freed blocks.", |
| 811 | vglc_n_shadows ); |
| 812 | sort_malloc_shadows ( vglc_shadows, vglc_n_shadows ); |
| 813 | |
| 814 | /* Sanity check; assert that the blocks are now in order and that |
| 815 | they don't overlap. */ |
| 816 | for (i = 0; i < vglc_n_shadows-1; i++) { |
| 817 | sk_assert( ((Addr)vglc_shadows[i]->data) |
| 818 | < ((Addr)vglc_shadows[i+1]->data) ); |
| 819 | sk_assert( ((Addr)vglc_shadows[i]->data) + vglc_shadows[i]->size |
| 820 | < ((Addr)vglc_shadows[i+1]->data) ); |
| 821 | } |
| 822 | |
| 823 | vglc_min_mallocd_addr = ((Addr)vglc_shadows[0]->data); |
| 824 | vglc_max_mallocd_addr = ((Addr)vglc_shadows[vglc_n_shadows-1]->data) |
| 825 | + vglc_shadows[vglc_n_shadows-1]->size - 1; |
| 826 | |
| 827 | vglc_reachedness |
| 828 | = VG_(malloc)( vglc_n_shadows * sizeof(Reachedness) ); |
| 829 | for (i = 0; i < vglc_n_shadows; i++) |
| 830 | vglc_reachedness[i] = Unreached; |
| 831 | |
| 832 | /* Do the scan of memory. */ |
| 833 | bytes_notified |
| 834 | = VKI_BYTES_PER_WORD |
| 835 | * vg_scan_all_valid_memory ( |
| 836 | is_valid_64k_chunk, |
| 837 | is_valid_address, |
| 838 | &vg_detect_memory_leaks_notify_addr |
| 839 | ); |
| 840 | |
| 841 | VG_(message)(Vg_UserMsg, "checked %d bytes.", bytes_notified); |
| 842 | |
| 843 | blocks_leaked = bytes_leaked = 0; |
| 844 | blocks_dubious = bytes_dubious = 0; |
| 845 | blocks_reachable = bytes_reachable = 0; |
| 846 | |
| 847 | for (i = 0; i < vglc_n_shadows; i++) { |
| 848 | if (vglc_reachedness[i] == Unreached) { |
| 849 | blocks_leaked++; |
| 850 | bytes_leaked += vglc_shadows[i]->size; |
| 851 | } |
| 852 | else if (vglc_reachedness[i] == Interior) { |
| 853 | blocks_dubious++; |
| 854 | bytes_dubious += vglc_shadows[i]->size; |
| 855 | } |
| 856 | else if (vglc_reachedness[i] == Proper) { |
| 857 | blocks_reachable++; |
| 858 | bytes_reachable += vglc_shadows[i]->size; |
| 859 | } |
| 860 | } |
| 861 | |
| 862 | VG_(message)(Vg_UserMsg, ""); |
| 863 | VG_(message)(Vg_UserMsg, "definitely lost: %d bytes in %d blocks.", |
| 864 | bytes_leaked, blocks_leaked ); |
| 865 | VG_(message)(Vg_UserMsg, "possibly lost: %d bytes in %d blocks.", |
| 866 | bytes_dubious, blocks_dubious ); |
| 867 | VG_(message)(Vg_UserMsg, "still reachable: %d bytes in %d blocks.", |
| 868 | bytes_reachable, blocks_reachable ); |
| 869 | |
| 870 | |
| 871 | /* Common up the lost blocks so we can print sensible error |
| 872 | messages. */ |
| 873 | |
| 874 | n_lossrecords = 0; |
| 875 | errlist = NULL; |
| 876 | for (i = 0; i < vglc_n_shadows; i++) { |
| 877 | |
| 878 | /* 'where' stored in 'skin_extra' field; extract using function |
| 879 | supplied by the calling skin. */ |
| 880 | ExeContext* where = get_where ( vglc_shadows[i] ); |
| 881 | |
| 882 | for (p = errlist; p != NULL; p = p->next) { |
| 883 | if (p->loss_mode == vglc_reachedness[i] |
| 884 | && VG_(eq_ExeContext) ( leak_resolution, |
| 885 | p->allocated_at, |
| 886 | where) ) { |
| 887 | break; |
| 888 | } |
| 889 | } |
| 890 | if (p != NULL) { |
| 891 | p->num_blocks ++; |
| 892 | p->total_bytes += vglc_shadows[i]->size; |
| 893 | } else { |
| 894 | n_lossrecords ++; |
| 895 | p = VG_(malloc)(sizeof(LossRecord)); |
| 896 | p->loss_mode = vglc_reachedness[i]; |
| 897 | p->allocated_at = where; |
| 898 | p->total_bytes = vglc_shadows[i]->size; |
| 899 | p->num_blocks = 1; |
| 900 | p->next = errlist; |
| 901 | errlist = p; |
| 902 | } |
| 903 | } |
| 904 | |
| 905 | for (i = 0; i < n_lossrecords; i++) { |
| 906 | LossRecord* p_min = NULL; |
| 907 | UInt n_min = 0xFFFFFFFF; |
| 908 | for (p = errlist; p != NULL; p = p->next) { |
| 909 | if (p->num_blocks > 0 && p->total_bytes < n_min) { |
| 910 | n_min = p->total_bytes; |
| 911 | p_min = p; |
| 912 | } |
| 913 | } |
| 914 | sk_assert(p_min != NULL); |
| 915 | |
| 916 | if ( (!show_reachable) && (p_min->loss_mode == Proper)) { |
| 917 | p_min->num_blocks = 0; |
| 918 | continue; |
| 919 | } |
| 920 | |
| 921 | VG_(message)(Vg_UserMsg, ""); |
| 922 | VG_(message)( |
| 923 | Vg_UserMsg, |
| 924 | "%d bytes in %d blocks are %s in loss record %d of %d", |
| 925 | p_min->total_bytes, p_min->num_blocks, |
| 926 | p_min->loss_mode==Unreached ? "definitely lost" : |
| 927 | (p_min->loss_mode==Interior ? "possibly lost" |
| 928 | : "still reachable"), |
| 929 | i+1, n_lossrecords |
| 930 | ); |
| 931 | VG_(pp_ExeContext)(p_min->allocated_at); |
| 932 | p_min->num_blocks = 0; |
| 933 | } |
| 934 | |
| 935 | VG_(message)(Vg_UserMsg, ""); |
| 936 | VG_(message)(Vg_UserMsg, "LEAK SUMMARY:"); |
| 937 | VG_(message)(Vg_UserMsg, " definitely lost: %d bytes in %d blocks.", |
| 938 | bytes_leaked, blocks_leaked ); |
| 939 | VG_(message)(Vg_UserMsg, " possibly lost: %d bytes in %d blocks.", |
| 940 | bytes_dubious, blocks_dubious ); |
| 941 | VG_(message)(Vg_UserMsg, " still reachable: %d bytes in %d blocks.", |
| 942 | bytes_reachable, blocks_reachable ); |
| 943 | if (!show_reachable) { |
| 944 | VG_(message)(Vg_UserMsg, |
| 945 | "Reachable blocks (those to which a pointer was found) are not shown."); |
| 946 | VG_(message)(Vg_UserMsg, |
| 947 | "To see them, rerun with: --show-reachable=yes"); |
| 948 | } |
| 949 | VG_(message)(Vg_UserMsg, ""); |
| 950 | |
| 951 | VG_(free) ( vglc_shadows ); |
| 952 | VG_(free) ( vglc_reachedness ); |
| 953 | } |
| 954 | |
| 955 | |
| 956 | /*--------------------------------------------------------------------*/ |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 957 | /*--- end vg_memory.c ---*/ |
| 958 | /*--------------------------------------------------------------------*/ |
njn25 | e49d8e7 | 2002-09-23 09:36:25 +0000 | [diff] [blame] | 959 | |