drd/tests: Fix remaining gcc 8 compiler warnings
[valgrind.git] / coregrind / m_stacks.c
blob560c75611af606c57abfc280a51ce79a7e61384f
2 /*--------------------------------------------------------------------*/
3 /*--- Stack management. m_stacks.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2000-2017 Julian Seward
11 jseward@acm.org
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
28 The GNU General Public License is contained in the file COPYING.
31 #include "pub_core_basics.h"
32 #include "pub_core_debuglog.h"
33 #include "pub_core_libcassert.h"
34 #include "pub_core_libcprint.h"
35 #include "pub_core_mallocfree.h"
36 #include "pub_core_aspacemgr.h"
37 #include "pub_core_options.h"
38 #include "pub_core_stacks.h"
39 #include "pub_core_tooliface.h"
40 #include "pub_core_inner.h"
41 #if defined(ENABLE_INNER_CLIENT_REQUEST)
42 #include "pub_core_clreq.h"
43 #endif
45 // For expensive debugging
46 #define EDEBUG(fmt, args...) //VG_(debugLog)(2, "stacks", fmt, ## args)
49 The stack
50 ~~~~~~~~~
51 The stack's segment seems to be dynamically extended downwards by
52 the kernel as the stack pointer moves down. Initially, a 1-page
53 (4k) stack is allocated. When SP moves below that for the first
54 time, presumably a page fault occurs. The kernel detects that the
55 faulting address is in the range from SP - VG_STACK_REDZONE_SZB
56 upwards to the current valid stack. It then extends the stack
57 segment downwards for enough to cover the faulting address, and
58 resumes the process (invisibly). The process is unaware of any of
59 this.
61 That means that Valgrind can't spot when the stack segment is being
62 extended. Fortunately, we want to precisely and continuously
63 update stack permissions around SP, so we need to spot all writes
64 to SP anyway.
66 The deal is: when SP is assigned a lower value, the stack is being
67 extended. Create suitably-permissioned pages to fill in any holes
68 between the old stack ptr and this one, if necessary. Then mark
69 all bytes in the area just "uncovered" by this SP change as
70 write-only.
72 When SP goes back up, mark the area receded over as unreadable and
73 unwritable.
75 Just to record the SP boundary conditions somewhere convenient:
76 SP - VG_STACK_REDZONE_SZB always points to the lowest live byte in
77 the stack. All addresses below SP - VG_STACK_REDZONE_SZB are not
78 live; those at and above it are.
80 We do not concern ourselves here with the VG_STACK_REDZONE_SZB
81 bias; that is handled by new_mem_stack/die_mem_stack.
85 * This structure holds information about the start and end addresses of
86 * registered stacks. There's always at least one stack registered:
87 * the main process stack. It will be the first stack registered and
88 * so will have a stack id of 0. The user does not need to register
89 * this stack: Valgrind does it automatically right before it starts
90 * running the client. No other stacks are automatically registered by
91 * Valgrind, however.
93 typedef struct _Stack {
94 UWord id;
95 Addr start; // Lowest stack byte, included.
96 Addr end; // Highest stack byte, included.
97 struct _Stack *next;
98 UWord outer_id; /* For an inner valgrind, stack id registered in outer
99 valgrind. */
100 } Stack;
102 static Stack *stacks;
103 static UWord next_id; /* Next id we hand out to a newly registered stack */
106 * These are the id, start and end values of the current stack. If the
107 * stack pointer falls outside the range of the current stack, we search
108 * the stacks list above for a matching stack.
110 static Stack *current_stack;
112 /* Find 'st' in the stacks_list and move it one step closer to the
113 front of the list, so as to make subsequent searches for it
114 cheaper. */
115 static void move_Stack_one_step_forward ( Stack* st )
117 Stack *st0, *st1, *st2;
118 if (st == stacks)
119 return; /* already at head of list */
120 vg_assert(st != NULL);
121 st0 = stacks;
122 st1 = NULL;
123 st2 = NULL;
124 while (True) {
125 if (st0 == NULL || st0 == st) break;
126 st2 = st1;
127 st1 = st0;
128 st0 = st0->next;
130 vg_assert(st0 == st);
131 if (st0 != NULL && st1 != NULL && st2 != NULL) {
132 Stack* tmp;
133 /* st0 points to st, st1 to its predecessor, and st2 to st1's
134 predecessor. Swap st0 and st1, that is, move st0 one step
135 closer to the start of the list. */
136 vg_assert(st2->next == st1);
137 vg_assert(st1->next == st0);
138 tmp = st0->next;
139 st2->next = st0;
140 st0->next = st1;
141 st1->next = tmp;
143 else
144 if (st0 != NULL && st1 != NULL && st2 == NULL) {
145 /* it's second in the list. */
146 vg_assert(stacks == st1);
147 vg_assert(st1->next == st0);
148 st1->next = st0->next;
149 st0->next = st1;
150 stacks = st0;
154 /* Find what stack an address falls into. */
155 static Stack* find_stack_by_addr(Addr sp)
157 static UWord n_fails = 0;
158 static UWord n_searches = 0;
159 static UWord n_steps = 0;
160 Stack *i = stacks;
161 n_searches++;
162 if (0 && 0 == (n_searches % 10000))
163 VG_(printf)("(hgdev) %lu searches, %lu steps, %lu fails\n",
164 n_searches, n_steps+1, n_fails);
165 /* fast track common case */
166 if (i && sp >= i->start && sp <= i->end)
167 return i;
168 /* else search the list */
169 while (i) {
170 n_steps++;
171 if (sp >= i->start && sp <= i->end) {
172 if (1 && (n_searches & 0x3F) == 0) {
173 move_Stack_one_step_forward( i );
175 return i;
177 i = i->next;
179 n_fails++;
180 return NULL;
184 * Register a new stack from start - end. This is invoked from the
185 * VALGRIND_STACK_REGISTER client request, and is also called just before
186 * we start the client running, to register the main process stack.
188 UWord VG_(register_stack)(Addr start, Addr end)
190 Stack *i;
192 if (start > end) {
193 /* If caller provides addresses in reverse order, swap them.
194 Ugly but not doing that breaks backward compatibility with
195 (user) code registering stacks with start/end inverted . */
196 Addr t = end;
197 end = start;
198 start = t;
201 i = VG_(malloc)("stacks.rs.1", sizeof(Stack));
202 i->start = start;
203 i->end = end;
204 i->id = next_id++;
205 i->next = stacks;
206 stacks = i;
208 if (i->id == 0) {
209 current_stack = i;
212 VG_(debugLog)(2, "stacks", "register [start-end] [%p-%p] as stack %lu\n",
213 (void*)start, (void*)end, i->id);
214 INNER_REQUEST(i->outer_id = VALGRIND_STACK_REGISTER(start, end));
215 return i->id;
219 * Deregister a stack. This is invoked from the VALGRIND_STACK_DEREGISTER
220 * client request.
222 void VG_(deregister_stack)(UWord id)
224 Stack *i = stacks;
225 Stack *prev = NULL;
227 VG_(debugLog)(2, "stacks", "deregister stack %lu\n", id);
229 if (current_stack && current_stack->id == id) {
230 current_stack = NULL;
233 while(i) {
234 if (i->id == id) {
235 if(prev == NULL) {
236 stacks = i->next;
237 } else {
238 prev->next = i->next;
240 INNER_REQUEST(VALGRIND_STACK_DEREGISTER(i->outer_id));
241 VG_(free)(i);
242 return;
244 prev = i;
245 i = i->next;
250 * Change a stack. This is invoked from the VALGRIND_STACK_CHANGE client
251 * request and from the stack growth stuff the signals module when
252 * extending the main process stack.
254 void VG_(change_stack)(UWord id, Addr start, Addr end)
256 Stack *i = stacks;
258 while (i) {
259 if (i->id == id) {
260 VG_(debugLog)(2, "stacks",
261 "change stack %lu from [%p-%p] to [%p-%p]\n",
262 id, (void*)i->start, (void*)i->end,
263 (void*)start, (void*)end);
264 /* FIXME : swap start/end like VG_(register_stack) ??? */
265 i->start = start;
266 i->end = end;
267 INNER_REQUEST(VALGRIND_STACK_CHANGE(i->outer_id, start, end));
268 return;
270 i = i->next;
275 * Find the bounds of the stack (if any) which includes the
276 * specified stack pointer.
278 void VG_(stack_limits)(Addr SP, Addr *start, Addr *end )
280 Stack* stack = find_stack_by_addr(SP);
281 NSegment const *stackseg = VG_(am_find_nsegment) (SP);
283 if (LIKELY(stack)) {
284 *start = stack->start;
285 *end = stack->end;
288 /* SP is assumed to be in a RW segment or in the SkResvn segment of an
289 extensible stack (normally, only the main thread has an extensible
290 stack segment).
291 If no such segment is found, assume we have no valid
292 stack for SP, and set *start and *end to 0.
293 Otherwise, possibly reduce the stack limits using the boundaries of
294 the RW segment/SkResvn segments containing SP. */
295 if (UNLIKELY(stackseg == NULL)) {
296 VG_(debugLog)(2, "stacks",
297 "no addressable segment for SP %p\n",
298 (void*)SP);
299 *start = 0;
300 *end = 0;
301 return;
304 if (UNLIKELY((!stackseg->hasR || !stackseg->hasW)
305 && (stackseg->kind != SkResvn || stackseg->smode != SmUpper))) {
306 VG_(debugLog)(2, "stacks",
307 "segment for SP %p is not RW or not a SmUpper Resvn\n",
308 (void*)SP);
309 *start = 0;
310 *end = 0;
311 return;
314 /* SP is in a RW segment, or in the SkResvn of an extensible stack.
315 We can use the seg start as the stack start limit. */
316 if (UNLIKELY(*start < stackseg->start)) {
317 VG_(debugLog)(2, "stacks",
318 "segment for SP %p changed stack start limit"
319 " from %p to %p\n",
320 (void*)SP, (void*)*start, (void*)stackseg->start);
321 *start = stackseg->start;
324 /* Now, determine the stack end limit. If the stackseg is SkResvn,
325 we need to get the neighbour segment (towards higher addresses).
326 This segment must be anonymous and RW. */
327 if (UNLIKELY(stackseg->kind == SkResvn)) {
328 stackseg = VG_(am_next_nsegment)(stackseg, /*forward*/ True);
329 if (!stackseg || !stackseg->hasR || !stackseg->hasW
330 || stackseg->kind != SkAnonC) {
331 VG_(debugLog)(2, "stacks",
332 "Next forward segment for SP %p Resvn segment"
333 " is not RW or not AnonC\n",
334 (void*)SP);
335 *start = 0;
336 *end = 0;
337 return;
341 /* Limit the stack end limit, using the found segment. */
342 if (UNLIKELY(*end > stackseg->end)) {
343 VG_(debugLog)(2, "stacks",
344 "segment for SP %p changed stack end limit"
345 " from %p to %p\n",
346 (void*)SP, (void*)*end, (void*)stackseg->end);
347 *end = stackseg->end;
350 /* If reducing start and/or end to the SP segment gives an
351 empty range, return 'empty' limits */
352 if (UNLIKELY(*start > *end)) {
353 VG_(debugLog)(2, "stacks",
354 "stack for SP %p start %p after end %p\n",
355 (void*)SP, (void*)*start, (void*)end);
356 *start = 0;
357 *end = 0;
361 /* complaints_stack_switch reports that SP has changed by more than some
362 threshold amount (by default, 2MB). We take this to mean that the
363 application is switching to a new stack, for whatever reason.
365 JRS 20021001: following discussions with John Regehr, if a stack
366 switch happens, it seems best not to mess at all with memory
367 permissions. Seems to work well with Netscape 4.X. Really the
368 only remaining difficulty is knowing exactly when a stack switch is
369 happening. */
370 __attribute__((noinline))
371 static void complaints_stack_switch (Addr old_SP, Addr new_SP)
373 static Int complaints = 3;
374 if (VG_(clo_verbosity) > 0 && complaints > 0 && !VG_(clo_xml)) {
375 Word delta = (Word)new_SP - (Word)old_SP;
376 complaints--;
377 VG_(message)(Vg_UserMsg,
378 "Warning: client switching stacks? "
379 "SP change: 0x%lx --> 0x%lx\n", old_SP, new_SP);
380 VG_(message)(Vg_UserMsg,
381 " to suppress, use: --max-stackframe=%ld "
382 "or greater\n",
383 (delta < 0 ? -delta : delta));
384 if (complaints == 0)
385 VG_(message)(Vg_UserMsg,
386 " further instances of this message "
387 "will not be shown.\n");
391 /* The functions VG_(unknown_SP_update) and VG_(unknown_SP_update_w_ECU)
392 get called if new_mem_stack and/or die_mem_stack are
393 tracked by the tool, and one of the specialised cases
394 (eg. new_mem_stack_4) isn't used in preference.
396 These functions are performance critical, so are built with macros. */
398 // preamble + check if stack has switched.
399 #define IF_STACK_SWITCH_SET_current_stack_AND_RETURN \
400 Word delta = (Word)new_SP - (Word)old_SP; \
402 EDEBUG("current_stack %p-%p %lu new_SP %p old_SP %p\n", \
403 (void *) (current_stack ? current_stack->start : 0x0), \
404 (void *) (current_stack ? current_stack->end : 0x0), \
405 current_stack ? current_stack->id : 0, \
406 (void *)new_SP, (void *)old_SP); \
408 /* Check if the stack pointer is still in the same stack as before. */ \
409 if (UNLIKELY(current_stack == NULL || \
410 new_SP < current_stack->start || new_SP > current_stack->end)) { \
411 Stack* new_stack = find_stack_by_addr(new_SP); \
412 if (new_stack \
413 && (current_stack == NULL || new_stack->id != current_stack->id)) { \
414 /* The stack pointer is now in another stack. Update the current */ \
415 /* stack information and return without doing anything else. */ \
416 current_stack = new_stack; \
417 EDEBUG("new current_stack %p-%p %lu \n", \
418 (void *) current_stack->start, \
419 (void *) current_stack->end, \
420 current_stack->id); \
421 return; \
422 } else { \
423 EDEBUG("new current_stack not found\n"); \
427 #define IF_BIG_DELTA_complaints_AND_RETURN \
428 if (UNLIKELY(delta < -VG_(clo_max_stackframe) \
429 || VG_(clo_max_stackframe) < delta)) { \
430 complaints_stack_switch(old_SP, new_SP); \
431 return; \
434 #define IF_SMALLER_STACK_die_mem_stack_AND_RETURN \
435 if (delta > 0) { \
436 VG_TRACK( die_mem_stack, old_SP, delta ); \
437 return; \
441 VG_REGPARM(3)
442 void VG_(unknown_SP_update_w_ECU)( Addr old_SP, Addr new_SP, UInt ecu ) {
443 IF_STACK_SWITCH_SET_current_stack_AND_RETURN;
444 IF_BIG_DELTA_complaints_AND_RETURN;
445 IF_SMALLER_STACK_die_mem_stack_AND_RETURN;
446 if (delta < 0) { // IF_BIGGER_STACK
447 VG_TRACK( new_mem_stack_w_ECU, new_SP, -delta, ecu );
448 return;
450 // SAME_STACK. nothing to do.
453 VG_REGPARM(2)
454 void VG_(unknown_SP_update)( Addr old_SP, Addr new_SP ) {
455 IF_STACK_SWITCH_SET_current_stack_AND_RETURN;
456 IF_BIG_DELTA_complaints_AND_RETURN;
457 IF_SMALLER_STACK_die_mem_stack_AND_RETURN;
458 if (delta < 0) { // IF_BIGGER_STACK
459 VG_TRACK( new_mem_stack, new_SP, -delta );
460 return;
462 // SAME_STACK. nothing to do.
465 /*--------------------------------------------------------------------*/
466 /*--- end ---*/
467 /*--------------------------------------------------------------------*/