Home | History | Annotate | Download | only in coregrind
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- Stack management.                                 m_stacks.c ---*/
      4 /*--------------------------------------------------------------------*/
      5 
      6 /*
      7    This file is part of Valgrind, a dynamic binary instrumentation
      8    framework.
      9 
     10    Copyright (C) 2000-2013 Julian Seward
     11       jseward (at) acm.org
     12 
     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.
     17 
     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.
     22 
     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.
     27 
     28    The GNU General Public License is contained in the file COPYING.
     29 */
     30 
     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_options.h"
     37 #include "pub_core_stacks.h"
     38 #include "pub_core_tooliface.h"
     39 
     40 // For expensive debugging
     41 #define EDEBUG(fmt, args...) //VG_(debugLog)(2, "stacks", fmt, ## args)
     42 
     43 /*
     44    The stack
     45    ~~~~~~~~~
     46    The stack's segment seems to be dynamically extended downwards by
     47    the kernel as the stack pointer moves down.  Initially, a 1-page
     48    (4k) stack is allocated.  When SP moves below that for the first
     49    time, presumably a page fault occurs.  The kernel detects that the
     50    faulting address is in the range from SP - VG_STACK_REDZONE_SZB
     51    upwards to the current valid stack.  It then extends the stack
     52    segment downwards for enough to cover the faulting address, and
     53    resumes the process (invisibly).  The process is unaware of any of
     54    this.
     55 
     56    That means that Valgrind can't spot when the stack segment is being
     57    extended.  Fortunately, we want to precisely and continuously
     58    update stack permissions around SP, so we need to spot all writes
     59    to SP anyway.
     60 
     61    The deal is: when SP is assigned a lower value, the stack is being
     62    extended.  Create suitably-permissioned pages to fill in any holes
     63    between the old stack ptr and this one, if necessary.  Then mark
     64    all bytes in the area just "uncovered" by this SP change as
     65    write-only.
     66 
     67    When SP goes back up, mark the area receded over as unreadable and
     68    unwritable.
     69 
     70    Just to record the SP boundary conditions somewhere convenient:
     71    SP - VG_STACK_REDZONE_SZB always points to the lowest live byte in
     72    the stack.  All addresses below SP - VG_STACK_REDZONE_SZB are not
     73    live; those at and above it are.
     74 
     75    We do not concern ourselves here with the VG_STACK_REDZONE_SZB
     76    bias; that is handled by new_mem_stack/die_mem_stack.
     77 */
     78 
     79 /*
     80  * This structure holds information about the start and end addresses of
     81  * registered stacks.  There's always at least one stack registered:
     82  * the main process stack.  It will be the first stack registered and
     83  * so will have a stack id of 0.  The user does not need to register
     84  * this stack: Valgrind does it automatically right before it starts
     85  * running the client.  No other stacks are automatically registered by
     86  * Valgrind, however.
     87  */
     88 typedef struct _Stack {
     89    UWord id;
     90    Addr start;
     91    Addr end;
     92    struct _Stack *next;
     93 } Stack;
     94 
     95 static Stack *stacks;
     96 static UWord next_id;  /* Next id we hand out to a newly registered stack */
     97 
     98 /*
     99  * These are the id, start and end values of the current stack.  If the
    100  * stack pointer falls outside the range of the current stack, we search
    101  * the stacks list above for a matching stack.
    102  */
    103 static Stack *current_stack;
    104 
    105 /* Find 'st' in the stacks_list and move it one step closer the the
    106    front of the list, so as to make subsequent searches for it
    107    cheaper. */
    108 static void move_Stack_one_step_forward ( Stack* st )
    109 {
    110    Stack *st0, *st1, *st2;
    111    if (st == stacks)
    112       return; /* already at head of list */
    113    vg_assert(st != NULL);
    114    st0 = stacks;
    115    st1 = NULL;
    116    st2 = NULL;
    117    while (True) {
    118       if (st0 == NULL || st0 == st) break;
    119       st2 = st1;
    120       st1 = st0;
    121       st0 = st0->next;
    122    }
    123    vg_assert(st0 == st);
    124    if (st0 != NULL && st1 != NULL && st2 != NULL) {
    125       Stack* tmp;
    126       /* st0 points to st, st1 to its predecessor, and st2 to st1's
    127          predecessor.  Swap st0 and st1, that is, move st0 one step
    128          closer to the start of the list. */
    129       vg_assert(st2->next == st1);
    130       vg_assert(st1->next == st0);
    131       tmp = st0->next;
    132       st2->next = st0;
    133       st0->next = st1;
    134       st1->next = tmp;
    135    }
    136    else
    137    if (st0 != NULL && st1 != NULL && st2 == NULL) {
    138       /* it's second in the list. */
    139       vg_assert(stacks == st1);
    140       vg_assert(st1->next == st0);
    141       st1->next = st0->next;
    142       st0->next = st1;
    143       stacks = st0;
    144    }
    145 }
    146 
    147 /* Find what stack an address falls into. */
    148 static Stack* find_stack_by_addr(Addr sp)
    149 {
    150    static UWord n_fails = 0;
    151    static UWord n_searches = 0;
    152    static UWord n_steps = 0;
    153    Stack *i = stacks;
    154    n_searches++;
    155    if (0 && 0 == (n_searches % 10000))
    156       VG_(printf)("(hgdev) %lu searches, %lu steps, %lu fails\n",
    157                   n_searches, n_steps+1, n_fails);
    158    /* fast track common case */
    159    if (i && sp >= i->start && sp <= i->end)
    160       return i;
    161    /* else search the list */
    162    while (i) {
    163       n_steps++;
    164       if (sp >= i->start && sp <= i->end) {
    165          if (1 && (n_searches & 0x3F) == 0) {
    166             move_Stack_one_step_forward( i );
    167          }
    168          return i;
    169       }
    170       i = i->next;
    171    }
    172    n_fails++;
    173    return NULL;
    174 }
    175 
    176 /*
    177  * Register a new stack from start - end.  This is invoked from the
    178  * VALGRIND_STACK_REGISTER client request, and is also called just before
    179  * we start the client running, to register the main process stack.
    180  */
    181 UWord VG_(register_stack)(Addr start, Addr end)
    182 {
    183    Stack *i;
    184 
    185    if (start > end) {
    186       Addr t = end;
    187       end = start;
    188       start = t;
    189    }
    190 
    191    i = (Stack *)VG_(arena_malloc)(VG_AR_CORE, "stacks.rs.1", sizeof(Stack));
    192    i->start = start;
    193    i->end = end;
    194    i->id = next_id++;
    195    i->next = stacks;
    196    stacks = i;
    197 
    198    if (i->id == 0) {
    199       current_stack = i;
    200    }
    201 
    202    VG_(debugLog)(2, "stacks", "register %p-%p as stack %lu\n",
    203                     (void*)start, (void*)end, i->id);
    204 
    205    return i->id;
    206 }
    207 
    208 /*
    209  * Deregister a stack.  This is invoked from the VALGRIND_STACK_DEREGISTER
    210  * client request.
    211  */
    212 void VG_(deregister_stack)(UWord id)
    213 {
    214    Stack *i = stacks;
    215    Stack *prev = NULL;
    216 
    217    VG_(debugLog)(2, "stacks", "deregister stack %lu\n", id);
    218 
    219    if (current_stack && current_stack->id == id) {
    220       current_stack = NULL;
    221    }
    222 
    223    while(i) {
    224       if (i->id == id) {
    225          if(prev == NULL) {
    226             stacks = i->next;
    227          } else {
    228             prev->next = i->next;
    229          }
    230          VG_(arena_free)(VG_AR_CORE, i);
    231          return;
    232       }
    233       prev = i;
    234       i = i->next;
    235    }
    236 }
    237 
    238 /*
    239  * Change a stack.  This is invoked from the VALGRIND_STACK_CHANGE client
    240  * request and from the stack growth stuff the signals module when
    241  * extending the main process stack.
    242  */
    243 void VG_(change_stack)(UWord id, Addr start, Addr end)
    244 {
    245    Stack *i = stacks;
    246 
    247    while (i) {
    248       if (i->id == id) {
    249          VG_(debugLog)(2, "stacks", "change stack %lu from %p-%p to %p-%p\n",
    250                        id, (void*)i->start, (void*)i->end,
    251                            (void*)start,    (void*)end);
    252          i->start = start;
    253          i->end = end;
    254          return;
    255       }
    256       i = i->next;
    257    }
    258 }
    259 
    260 /*
    261  * Find the bounds of the stack (if any) which includes the
    262  * specified stack pointer.
    263  */
    264 void VG_(stack_limits)(Addr SP, Addr *start, Addr *end )
    265 {
    266    Stack* stack = find_stack_by_addr(SP);
    267 
    268    if (stack) {
    269       *start = stack->start;
    270       *end = stack->end;
    271    }
    272 }
    273 
    274 
    275 /* complaints_stack_switch reports that SP has changed by more than some
    276    threshold amount (by default, 2MB).  We take this to mean that the
    277    application is switching to a new stack, for whatever reason.
    278 
    279    JRS 20021001: following discussions with John Regehr, if a stack
    280    switch happens, it seems best not to mess at all with memory
    281    permissions.  Seems to work well with Netscape 4.X.  Really the
    282    only remaining difficulty is knowing exactly when a stack switch is
    283    happening. */
    284 __attribute__((noinline))
    285 static void complaints_stack_switch (Addr old_SP, Addr new_SP)
    286 {
    287    static Int complaints = 3;
    288    if (VG_(clo_verbosity) > 0 && complaints > 0 && !VG_(clo_xml)) {
    289       Word delta  = (Word)new_SP - (Word)old_SP;
    290       complaints--;
    291       VG_(message)(Vg_UserMsg,
    292                    "Warning: client switching stacks?  "
    293                    "SP change: 0x%lx --> 0x%lx\n", old_SP, new_SP);
    294       VG_(message)(Vg_UserMsg,
    295                    "         to suppress, use: --max-stackframe=%ld "
    296                    "or greater\n",
    297                    (delta < 0 ? -delta : delta));
    298       if (complaints == 0)
    299          VG_(message)(Vg_UserMsg,
    300                       "         further instances of this message "
    301                       "will not be shown.\n");
    302    }
    303 }
    304 
    305 /* The functions VG_(unknown_SP_update) and VG_(unknown_SP_update_w_ECU)
    306    get called if new_mem_stack and/or die_mem_stack are
    307    tracked by the tool, and one of the specialised cases
    308    (eg. new_mem_stack_4) isn't used in preference.
    309 
    310    These functions are performance critical, so are built with macros. */
    311 
    312 // preamble + check if stack has switched.
    313 #define IF_STACK_SWITCH_SET_current_stack_AND_RETURN                    \
    314    Word delta  = (Word)new_SP - (Word)old_SP;                           \
    315                                                                         \
    316    EDEBUG("current_stack  %p-%p %lu new_SP %p old_SP %p\n",             \
    317           (void *) (current_stack ? current_stack->start : 0x0),        \
    318           (void *) (current_stack ? current_stack->end : 0x0),          \
    319           current_stack ? current_stack->id : 0,                        \
    320           (void *)new_SP, (void *)old_SP);                              \
    321                                                                         \
    322    /* Check if the stack pointer is still in the same stack as before. */ \
    323    if (UNLIKELY(current_stack == NULL ||                                \
    324       new_SP < current_stack->start || new_SP > current_stack->end)) {  \
    325       Stack* new_stack = find_stack_by_addr(new_SP);                    \
    326       if (new_stack                                                     \
    327           && (current_stack == NULL || new_stack->id != current_stack->id)) { \
    328          /* The stack pointer is now in another stack.  Update the current */ \
    329          /* stack information and return without doing anything else. */ \
    330          current_stack = new_stack;                                     \
    331          EDEBUG("new current_stack  %p-%p %lu \n",                      \
    332                 (void *) current_stack->start,                          \
    333                 (void *) current_stack->end,                            \
    334                 current_stack->id);                                     \
    335          return;                                                        \
    336       } else                                                            \
    337          EDEBUG("new current_stack not found\n");                       \
    338    }
    339 
    340 #define IF_BIG_DELTA_complaints_AND_RETURN                              \
    341    if (UNLIKELY(delta < -VG_(clo_max_stackframe)                        \
    342                 || VG_(clo_max_stackframe) < delta)) {                  \
    343       complaints_stack_switch(old_SP, new_SP);                          \
    344       return;                                                           \
    345    }
    346 
    347 #define IF_SMALLER_STACK_die_mem_stack_AND_RETURN                       \
    348    if (delta > 0) {                                                     \
    349       VG_TRACK( die_mem_stack, old_SP,  delta );                        \
    350       return;                                                           \
    351    }
    352 
    353 
    354 VG_REGPARM(3)
    355 void VG_(unknown_SP_update_w_ECU)( Addr old_SP, Addr new_SP, UInt ecu ) {
    356    IF_STACK_SWITCH_SET_current_stack_AND_RETURN;
    357    IF_BIG_DELTA_complaints_AND_RETURN;
    358    IF_SMALLER_STACK_die_mem_stack_AND_RETURN;
    359    if (delta < 0) { // IF_BIGGER_STACK
    360       VG_TRACK( new_mem_stack_w_ECU, new_SP, -delta, ecu );
    361       return;
    362    }
    363    // SAME_STACK. nothing to do.
    364 }
    365 
    366 VG_REGPARM(2)
    367 void VG_(unknown_SP_update)( Addr old_SP, Addr new_SP ) {
    368    IF_STACK_SWITCH_SET_current_stack_AND_RETURN;
    369    IF_BIG_DELTA_complaints_AND_RETURN;
    370    IF_SMALLER_STACK_die_mem_stack_AND_RETURN;
    371    if (delta < 0) { // IF_BIGGER_STACK
    372       VG_TRACK( new_mem_stack,      new_SP, -delta );
    373       return;
    374    }
    375    // SAME_STACK. nothing to do.
    376 }
    377 
    378 /*--------------------------------------------------------------------*/
    379 /*--- end                                                          ---*/
    380 /*--------------------------------------------------------------------*/
    381 
    382