2 /*--------------------------------------------------------------------*/
3 /*--- Stack management. m_stacks.c ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2000-2017 Julian Seward
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
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"
45 // For expensive debugging
46 #define EDEBUG(fmt, args...) //VG_(debugLog)(2, "stacks", fmt, ## args)
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
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
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
72 When SP goes back up, mark the area receded over as unreadable and
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
93 typedef struct _Stack
{
95 Addr start
; // Lowest stack byte, included.
96 Addr end
; // Highest stack byte, included.
98 UWord outer_id
; /* For an inner valgrind, stack id registered in outer
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
115 static void move_Stack_one_step_forward ( Stack
* st
)
117 Stack
*st0
, *st1
, *st2
;
119 return; /* already at head of list */
120 vg_assert(st
!= NULL
);
125 if (st0
== NULL
|| st0
== st
) break;
130 vg_assert(st0
== st
);
131 if (st0
!= NULL
&& st1
!= NULL
&& st2
!= NULL
) {
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
);
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
;
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;
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
)
168 /* else search the list */
171 if (sp
>= i
->start
&& sp
<= i
->end
) {
172 if (1 && (n_searches
& 0x3F) == 0) {
173 move_Stack_one_step_forward( i
);
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
)
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 . */
201 i
= VG_(malloc
)("stacks.rs.1", sizeof(Stack
));
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
));
219 * Deregister a stack. This is invoked from the VALGRIND_STACK_DEREGISTER
222 void VG_(deregister_stack
)(UWord id
)
227 VG_(debugLog
)(2, "stacks", "deregister stack %lu\n", id
);
229 if (current_stack
&& current_stack
->id
== id
) {
230 current_stack
= NULL
;
238 prev
->next
= i
->next
;
240 INNER_REQUEST(VALGRIND_STACK_DEREGISTER(i
->outer_id
));
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
)
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) ??? */
267 INNER_REQUEST(VALGRIND_STACK_CHANGE(i
->outer_id
, start
, end
));
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
);
284 *start
= stack
->start
;
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
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",
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",
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"
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",
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"
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
);
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
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
;
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 "
383 (delta
< 0 ? -delta
: delta
));
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); \
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); \
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); \
434 #define IF_SMALLER_STACK_die_mem_stack_AND_RETURN \
436 VG_TRACK( die_mem_stack, old_SP, delta ); \
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
);
450 // SAME_STACK. nothing to do.
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
);
462 // SAME_STACK. nothing to do.
465 /*--------------------------------------------------------------------*/
467 /*--------------------------------------------------------------------*/