1945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 2945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/*--------------------------------------------------------------------*/ 3945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/*--- Stack management. m_stacks.c ---*/ 4945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/*--------------------------------------------------------------------*/ 5945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 6945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/* 7945ed2e53f6bbe9c84a8173b63881158132d9ca8njn This file is part of Valgrind, a dynamic binary instrumentation 8945ed2e53f6bbe9c84a8173b63881158132d9ca8njn framework. 9945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 100f157ddb404bcde7815a1c5bf2d7e41c114f3d73sewardj Copyright (C) 2000-2013 Julian Seward 11945ed2e53f6bbe9c84a8173b63881158132d9ca8njn jseward@acm.org 12945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 13945ed2e53f6bbe9c84a8173b63881158132d9ca8njn This program is free software; you can redistribute it and/or 14945ed2e53f6bbe9c84a8173b63881158132d9ca8njn modify it under the terms of the GNU General Public License as 15945ed2e53f6bbe9c84a8173b63881158132d9ca8njn published by the Free Software Foundation; either version 2 of the 16945ed2e53f6bbe9c84a8173b63881158132d9ca8njn License, or (at your option) any later version. 17945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 18945ed2e53f6bbe9c84a8173b63881158132d9ca8njn This program is distributed in the hope that it will be useful, but 19945ed2e53f6bbe9c84a8173b63881158132d9ca8njn WITHOUT ANY WARRANTY; without even the implied warranty of 20945ed2e53f6bbe9c84a8173b63881158132d9ca8njn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21945ed2e53f6bbe9c84a8173b63881158132d9ca8njn General Public License for more details. 22945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 23945ed2e53f6bbe9c84a8173b63881158132d9ca8njn You should have received a copy of the GNU General Public License 24945ed2e53f6bbe9c84a8173b63881158132d9ca8njn along with this program; if not, write to the Free Software 25945ed2e53f6bbe9c84a8173b63881158132d9ca8njn Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 02111-1307, USA. 27945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 28945ed2e53f6bbe9c84a8173b63881158132d9ca8njn The GNU General Public License is contained in the file COPYING. 29945ed2e53f6bbe9c84a8173b63881158132d9ca8njn*/ 30945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 31945ed2e53f6bbe9c84a8173b63881158132d9ca8njn#include "pub_core_basics.h" 32de3cf139fb17c01ff6121e7997e4063f4e3bd55btom#include "pub_core_debuglog.h" 3325b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj#include "pub_core_libcassert.h" 34945ed2e53f6bbe9c84a8173b63881158132d9ca8njn#include "pub_core_libcprint.h" 35945ed2e53f6bbe9c84a8173b63881158132d9ca8njn#include "pub_core_mallocfree.h" 363a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#include "pub_core_aspacemgr.h" 37945ed2e53f6bbe9c84a8173b63881158132d9ca8njn#include "pub_core_options.h" 38945ed2e53f6bbe9c84a8173b63881158132d9ca8njn#include "pub_core_stacks.h" 39945ed2e53f6bbe9c84a8173b63881158132d9ca8njn#include "pub_core_tooliface.h" 40945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 414fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe// For expensive debugging 424fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe#define EDEBUG(fmt, args...) //VG_(debugLog)(2, "stacks", fmt, ## args) 434fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe 44945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/* 45945ed2e53f6bbe9c84a8173b63881158132d9ca8njn The stack 46945ed2e53f6bbe9c84a8173b63881158132d9ca8njn ~~~~~~~~~ 47945ed2e53f6bbe9c84a8173b63881158132d9ca8njn The stack's segment seems to be dynamically extended downwards by 48945ed2e53f6bbe9c84a8173b63881158132d9ca8njn the kernel as the stack pointer moves down. Initially, a 1-page 49945ed2e53f6bbe9c84a8173b63881158132d9ca8njn (4k) stack is allocated. When SP moves below that for the first 50945ed2e53f6bbe9c84a8173b63881158132d9ca8njn time, presumably a page fault occurs. The kernel detects that the 51945ed2e53f6bbe9c84a8173b63881158132d9ca8njn faulting address is in the range from SP - VG_STACK_REDZONE_SZB 52945ed2e53f6bbe9c84a8173b63881158132d9ca8njn upwards to the current valid stack. It then extends the stack 53945ed2e53f6bbe9c84a8173b63881158132d9ca8njn segment downwards for enough to cover the faulting address, and 54945ed2e53f6bbe9c84a8173b63881158132d9ca8njn resumes the process (invisibly). The process is unaware of any of 55945ed2e53f6bbe9c84a8173b63881158132d9ca8njn this. 56945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 57945ed2e53f6bbe9c84a8173b63881158132d9ca8njn That means that Valgrind can't spot when the stack segment is being 58945ed2e53f6bbe9c84a8173b63881158132d9ca8njn extended. Fortunately, we want to precisely and continuously 59945ed2e53f6bbe9c84a8173b63881158132d9ca8njn update stack permissions around SP, so we need to spot all writes 60945ed2e53f6bbe9c84a8173b63881158132d9ca8njn to SP anyway. 61945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 62945ed2e53f6bbe9c84a8173b63881158132d9ca8njn The deal is: when SP is assigned a lower value, the stack is being 63945ed2e53f6bbe9c84a8173b63881158132d9ca8njn extended. Create suitably-permissioned pages to fill in any holes 64945ed2e53f6bbe9c84a8173b63881158132d9ca8njn between the old stack ptr and this one, if necessary. Then mark 65945ed2e53f6bbe9c84a8173b63881158132d9ca8njn all bytes in the area just "uncovered" by this SP change as 66945ed2e53f6bbe9c84a8173b63881158132d9ca8njn write-only. 67945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 68945ed2e53f6bbe9c84a8173b63881158132d9ca8njn When SP goes back up, mark the area receded over as unreadable and 69945ed2e53f6bbe9c84a8173b63881158132d9ca8njn unwritable. 70945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 71945ed2e53f6bbe9c84a8173b63881158132d9ca8njn Just to record the SP boundary conditions somewhere convenient: 72945ed2e53f6bbe9c84a8173b63881158132d9ca8njn SP - VG_STACK_REDZONE_SZB always points to the lowest live byte in 73945ed2e53f6bbe9c84a8173b63881158132d9ca8njn the stack. All addresses below SP - VG_STACK_REDZONE_SZB are not 74945ed2e53f6bbe9c84a8173b63881158132d9ca8njn live; those at and above it are. 75945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 76945ed2e53f6bbe9c84a8173b63881158132d9ca8njn We do not concern ourselves here with the VG_STACK_REDZONE_SZB 77945ed2e53f6bbe9c84a8173b63881158132d9ca8njn bias; that is handled by new_mem_stack/die_mem_stack. 78945ed2e53f6bbe9c84a8173b63881158132d9ca8njn*/ 79945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 80945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/* 81945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * This structure holds information about the start and end addresses of 82945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * registered stacks. There's always at least one stack registered: 83945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * the main process stack. It will be the first stack registered and 84945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * so will have a stack id of 0. The user does not need to register 85945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * this stack: Valgrind does it automatically right before it starts 86945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * running the client. No other stacks are automatically registered by 87945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * Valgrind, however. 88945ed2e53f6bbe9c84a8173b63881158132d9ca8njn */ 89945ed2e53f6bbe9c84a8173b63881158132d9ca8njntypedef struct _Stack { 90945ed2e53f6bbe9c84a8173b63881158132d9ca8njn UWord id; 9138a74d2cc4670e3eb559adff51a376cd6ec98005philippe Addr start; // Lowest stack byte, included. 9238a74d2cc4670e3eb559adff51a376cd6ec98005philippe Addr end; // Highest stack byte, included. 93945ed2e53f6bbe9c84a8173b63881158132d9ca8njn struct _Stack *next; 94945ed2e53f6bbe9c84a8173b63881158132d9ca8njn} Stack; 95945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 96945ed2e53f6bbe9c84a8173b63881158132d9ca8njnstatic Stack *stacks; 97945ed2e53f6bbe9c84a8173b63881158132d9ca8njnstatic UWord next_id; /* Next id we hand out to a newly registered stack */ 98945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 99945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/* 100945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * These are the id, start and end values of the current stack. If the 101945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * stack pointer falls outside the range of the current stack, we search 102945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * the stacks list above for a matching stack. 103945ed2e53f6bbe9c84a8173b63881158132d9ca8njn */ 104de3cf139fb17c01ff6121e7997e4063f4e3bd55btomstatic Stack *current_stack; 105945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 10625b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj/* Find 'st' in the stacks_list and move it one step closer the the 10725b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj front of the list, so as to make subsequent searches for it 10825b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj cheaper. */ 10925b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardjstatic void move_Stack_one_step_forward ( Stack* st ) 11025b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj{ 11125b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj Stack *st0, *st1, *st2; 11225b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj if (st == stacks) 11325b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj return; /* already at head of list */ 11425b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj vg_assert(st != NULL); 11525b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj st0 = stacks; 11625b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj st1 = NULL; 11725b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj st2 = NULL; 11825b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj while (True) { 11925b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj if (st0 == NULL || st0 == st) break; 12025b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj st2 = st1; 12125b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj st1 = st0; 12225b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj st0 = st0->next; 12325b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj } 12425b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj vg_assert(st0 == st); 12525b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj if (st0 != NULL && st1 != NULL && st2 != NULL) { 12625b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj Stack* tmp; 12725b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj /* st0 points to st, st1 to its predecessor, and st2 to st1's 12825b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj predecessor. Swap st0 and st1, that is, move st0 one step 12925b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj closer to the start of the list. */ 13025b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj vg_assert(st2->next == st1); 13125b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj vg_assert(st1->next == st0); 13225b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj tmp = st0->next; 13325b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj st2->next = st0; 13425b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj st0->next = st1; 13525b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj st1->next = tmp; 13625b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj } 13725b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj else 13825b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj if (st0 != NULL && st1 != NULL && st2 == NULL) { 13925b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj /* it's second in the list. */ 14025b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj vg_assert(stacks == st1); 14125b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj vg_assert(st1->next == st0); 14225b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj st1->next = st0->next; 14325b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj st0->next = st1; 14425b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj stacks = st0; 14525b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj } 14625b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj} 14725b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj 148945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/* Find what stack an address falls into. */ 1494e72d20f223193fafd7c615f25e4c929ff479741njnstatic Stack* find_stack_by_addr(Addr sp) 150945ed2e53f6bbe9c84a8173b63881158132d9ca8njn{ 15125b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj static UWord n_fails = 0; 15225b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj static UWord n_searches = 0; 15325b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj static UWord n_steps = 0; 154945ed2e53f6bbe9c84a8173b63881158132d9ca8njn Stack *i = stacks; 15525b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj n_searches++; 15625b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj if (0 && 0 == (n_searches % 10000)) 15725b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj VG_(printf)("(hgdev) %lu searches, %lu steps, %lu fails\n", 15825b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj n_searches, n_steps+1, n_fails); 15925b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj /* fast track common case */ 16025b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj if (i && sp >= i->start && sp <= i->end) 16125b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj return i; 16225b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj /* else search the list */ 1634e72d20f223193fafd7c615f25e4c929ff479741njn while (i) { 16425b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj n_steps++; 1654e72d20f223193fafd7c615f25e4c929ff479741njn if (sp >= i->start && sp <= i->end) { 16625b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj if (1 && (n_searches & 0x3F) == 0) { 16725b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj move_Stack_one_step_forward( i ); 16825b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj } 1694e72d20f223193fafd7c615f25e4c929ff479741njn return i; 170945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 171945ed2e53f6bbe9c84a8173b63881158132d9ca8njn i = i->next; 172945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 17325b079cf1bb1da8eaaff6ce0a1f7a9fca4955d48sewardj n_fails++; 1744e72d20f223193fafd7c615f25e4c929ff479741njn return NULL; 175945ed2e53f6bbe9c84a8173b63881158132d9ca8njn} 176945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 177945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/* 178945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * Register a new stack from start - end. This is invoked from the 179945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * VALGRIND_STACK_REGISTER client request, and is also called just before 180945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * we start the client running, to register the main process stack. 181945ed2e53f6bbe9c84a8173b63881158132d9ca8njn */ 182945ed2e53f6bbe9c84a8173b63881158132d9ca8njnUWord VG_(register_stack)(Addr start, Addr end) 183945ed2e53f6bbe9c84a8173b63881158132d9ca8njn{ 184945ed2e53f6bbe9c84a8173b63881158132d9ca8njn Stack *i; 18545f4e7c91119c7d01a59f5e827c67841632c9314sewardj 186945ed2e53f6bbe9c84a8173b63881158132d9ca8njn if (start > end) { 18738a74d2cc4670e3eb559adff51a376cd6ec98005philippe /* If caller provides addresses in reverse order, swap them. 18838a74d2cc4670e3eb559adff51a376cd6ec98005philippe Ugly but not doing that breaks backward compatibility with 18938a74d2cc4670e3eb559adff51a376cd6ec98005philippe (user) code registering stacks with start/end inverted . */ 190945ed2e53f6bbe9c84a8173b63881158132d9ca8njn Addr t = end; 191945ed2e53f6bbe9c84a8173b63881158132d9ca8njn end = start; 192945ed2e53f6bbe9c84a8173b63881158132d9ca8njn start = t; 193945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 194945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 19577eb20b3865e7b17c7695c7e7a526b52935f593eflorian i = VG_(malloc)("stacks.rs.1", sizeof(Stack)); 196945ed2e53f6bbe9c84a8173b63881158132d9ca8njn i->start = start; 197945ed2e53f6bbe9c84a8173b63881158132d9ca8njn i->end = end; 198945ed2e53f6bbe9c84a8173b63881158132d9ca8njn i->id = next_id++; 199945ed2e53f6bbe9c84a8173b63881158132d9ca8njn i->next = stacks; 200945ed2e53f6bbe9c84a8173b63881158132d9ca8njn stacks = i; 201945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 2024e72d20f223193fafd7c615f25e4c929ff479741njn if (i->id == 0) { 203de3cf139fb17c01ff6121e7997e4063f4e3bd55btom current_stack = i; 204945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 205945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 2063a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe VG_(debugLog)(2, "stacks", "register [start-end] [%p-%p] as stack %lu\n", 2074818d73a255b7b474b670feeb37f83a2c17c401bnjn (void*)start, (void*)end, i->id); 208de3cf139fb17c01ff6121e7997e4063f4e3bd55btom 209945ed2e53f6bbe9c84a8173b63881158132d9ca8njn return i->id; 210945ed2e53f6bbe9c84a8173b63881158132d9ca8njn} 211945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 212945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/* 213945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * Deregister a stack. This is invoked from the VALGRIND_STACK_DEREGISTER 214945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * client request. 215945ed2e53f6bbe9c84a8173b63881158132d9ca8njn */ 216945ed2e53f6bbe9c84a8173b63881158132d9ca8njnvoid VG_(deregister_stack)(UWord id) 217945ed2e53f6bbe9c84a8173b63881158132d9ca8njn{ 218945ed2e53f6bbe9c84a8173b63881158132d9ca8njn Stack *i = stacks; 219945ed2e53f6bbe9c84a8173b63881158132d9ca8njn Stack *prev = NULL; 220945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 2214818d73a255b7b474b670feeb37f83a2c17c401bnjn VG_(debugLog)(2, "stacks", "deregister stack %lu\n", id); 222de3cf139fb17c01ff6121e7997e4063f4e3bd55btom 2230edccddc1511cd2479d963adcd1fb4c98247580bsewardj if (current_stack && current_stack->id == id) { 224de3cf139fb17c01ff6121e7997e4063f4e3bd55btom current_stack = NULL; 225945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 226945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 227945ed2e53f6bbe9c84a8173b63881158132d9ca8njn while(i) { 228945ed2e53f6bbe9c84a8173b63881158132d9ca8njn if (i->id == id) { 229945ed2e53f6bbe9c84a8173b63881158132d9ca8njn if(prev == NULL) { 230945ed2e53f6bbe9c84a8173b63881158132d9ca8njn stacks = i->next; 231945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } else { 232945ed2e53f6bbe9c84a8173b63881158132d9ca8njn prev->next = i->next; 233945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 23477eb20b3865e7b17c7695c7e7a526b52935f593eflorian VG_(free)(i); 235945ed2e53f6bbe9c84a8173b63881158132d9ca8njn return; 236945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 237945ed2e53f6bbe9c84a8173b63881158132d9ca8njn prev = i; 238945ed2e53f6bbe9c84a8173b63881158132d9ca8njn i = i->next; 239945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 240945ed2e53f6bbe9c84a8173b63881158132d9ca8njn} 241945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 242945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/* 243945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * Change a stack. This is invoked from the VALGRIND_STACK_CHANGE client 244945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * request and from the stack growth stuff the signals module when 245945ed2e53f6bbe9c84a8173b63881158132d9ca8njn * extending the main process stack. 246945ed2e53f6bbe9c84a8173b63881158132d9ca8njn */ 247945ed2e53f6bbe9c84a8173b63881158132d9ca8njnvoid VG_(change_stack)(UWord id, Addr start, Addr end) 248945ed2e53f6bbe9c84a8173b63881158132d9ca8njn{ 249945ed2e53f6bbe9c84a8173b63881158132d9ca8njn Stack *i = stacks; 250945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 2514e72d20f223193fafd7c615f25e4c929ff479741njn while (i) { 252945ed2e53f6bbe9c84a8173b63881158132d9ca8njn if (i->id == id) { 25338a74d2cc4670e3eb559adff51a376cd6ec98005philippe VG_(debugLog)(2, "stacks", 25438a74d2cc4670e3eb559adff51a376cd6ec98005philippe "change stack %lu from [%p-%p] to [%p-%p]\n", 2554818d73a255b7b474b670feeb37f83a2c17c401bnjn id, (void*)i->start, (void*)i->end, 2564818d73a255b7b474b670feeb37f83a2c17c401bnjn (void*)start, (void*)end); 25738a74d2cc4670e3eb559adff51a376cd6ec98005philippe /* FIXME : swap start/end like VG_(register_stack) ??? */ 258945ed2e53f6bbe9c84a8173b63881158132d9ca8njn i->start = start; 259945ed2e53f6bbe9c84a8173b63881158132d9ca8njn i->end = end; 260945ed2e53f6bbe9c84a8173b63881158132d9ca8njn return; 261945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 262945ed2e53f6bbe9c84a8173b63881158132d9ca8njn i = i->next; 263945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 264945ed2e53f6bbe9c84a8173b63881158132d9ca8njn} 265945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 266690c3c807be3571951400b98d5136437dd957b65tom/* 267690c3c807be3571951400b98d5136437dd957b65tom * Find the bounds of the stack (if any) which includes the 268690c3c807be3571951400b98d5136437dd957b65tom * specified stack pointer. 269690c3c807be3571951400b98d5136437dd957b65tom */ 270690c3c807be3571951400b98d5136437dd957b65tomvoid VG_(stack_limits)(Addr SP, Addr *start, Addr *end ) 271690c3c807be3571951400b98d5136437dd957b65tom{ 272690c3c807be3571951400b98d5136437dd957b65tom Stack* stack = find_stack_by_addr(SP); 2733a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe NSegment const *stackseg = VG_(am_find_nsegment) (SP); 274690c3c807be3571951400b98d5136437dd957b65tom 27593d127f02c9abb9e6373585ee4529ece6dee0503philippe if (LIKELY(stack)) { 276690c3c807be3571951400b98d5136437dd957b65tom *start = stack->start; 277690c3c807be3571951400b98d5136437dd957b65tom *end = stack->end; 278690c3c807be3571951400b98d5136437dd957b65tom } 2793a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 280cda0c2cf073a7fba19e1fb2576446506894facbaphilippe /* SP is assumed to be in a RW segment or in the SkResvn segment of an 281cda0c2cf073a7fba19e1fb2576446506894facbaphilippe extensible stack (normally, only the main thread has an extensible 282cda0c2cf073a7fba19e1fb2576446506894facbaphilippe stack segment). 2833a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe If no such segment is found, assume we have no valid 2843a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe stack for SP, and set *start and *end to 0. 285cda0c2cf073a7fba19e1fb2576446506894facbaphilippe Otherwise, possibly reduce the stack limits using the boundaries of 286cda0c2cf073a7fba19e1fb2576446506894facbaphilippe the RW segment/SkResvn segments containing SP. */ 28793d127f02c9abb9e6373585ee4529ece6dee0503philippe if (UNLIKELY(stackseg == NULL)) { 2883a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe VG_(debugLog)(2, "stacks", 2893a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "no addressable segment for SP %p\n", 2903a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe (void*)SP); 2913a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe *start = 0; 2923a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe *end = 0; 293cda0c2cf073a7fba19e1fb2576446506894facbaphilippe return; 294cda0c2cf073a7fba19e1fb2576446506894facbaphilippe } 295cda0c2cf073a7fba19e1fb2576446506894facbaphilippe 29693d127f02c9abb9e6373585ee4529ece6dee0503philippe if (UNLIKELY((!stackseg->hasR || !stackseg->hasW) 29793d127f02c9abb9e6373585ee4529ece6dee0503philippe && (stackseg->kind != SkResvn || stackseg->smode != SmUpper))) { 2983a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe VG_(debugLog)(2, "stacks", 299cda0c2cf073a7fba19e1fb2576446506894facbaphilippe "segment for SP %p is not RW or not a SmUpper Resvn\n", 3003a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe (void*)SP); 3013a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe *start = 0; 3023a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe *end = 0; 303cda0c2cf073a7fba19e1fb2576446506894facbaphilippe return; 304cda0c2cf073a7fba19e1fb2576446506894facbaphilippe } 3053a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 30693d127f02c9abb9e6373585ee4529ece6dee0503philippe /* SP is in a RW segment, or in the SkResvn of an extensible stack. 30793d127f02c9abb9e6373585ee4529ece6dee0503philippe We can use the seg start as the stack start limit. */ 30893d127f02c9abb9e6373585ee4529ece6dee0503philippe if (UNLIKELY(*start < stackseg->start)) { 309cda0c2cf073a7fba19e1fb2576446506894facbaphilippe VG_(debugLog)(2, "stacks", 310cda0c2cf073a7fba19e1fb2576446506894facbaphilippe "segment for SP %p changed stack start limit" 311cda0c2cf073a7fba19e1fb2576446506894facbaphilippe " from %p to %p\n", 312cda0c2cf073a7fba19e1fb2576446506894facbaphilippe (void*)SP, (void*)*start, (void*)stackseg->start); 313cda0c2cf073a7fba19e1fb2576446506894facbaphilippe *start = stackseg->start; 314cda0c2cf073a7fba19e1fb2576446506894facbaphilippe } 315cda0c2cf073a7fba19e1fb2576446506894facbaphilippe 31693d127f02c9abb9e6373585ee4529ece6dee0503philippe /* Now, determine the stack end limit. If the stackseg is SkResvn, 31793d127f02c9abb9e6373585ee4529ece6dee0503philippe we need to get the neighbour segment (towards higher addresses). 31893d127f02c9abb9e6373585ee4529ece6dee0503philippe This segment must be anonymous and RW. */ 31993d127f02c9abb9e6373585ee4529ece6dee0503philippe if (UNLIKELY(stackseg->kind == SkResvn)) { 320cda0c2cf073a7fba19e1fb2576446506894facbaphilippe stackseg = VG_(am_next_nsegment)(stackseg, /*forward*/ True); 321cda0c2cf073a7fba19e1fb2576446506894facbaphilippe if (!stackseg || !stackseg->hasR || !stackseg->hasW 322cda0c2cf073a7fba19e1fb2576446506894facbaphilippe || stackseg->kind != SkAnonC) { 3233a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe VG_(debugLog)(2, "stacks", 324cda0c2cf073a7fba19e1fb2576446506894facbaphilippe "Next forward segment for SP %p Resvn segment" 325cda0c2cf073a7fba19e1fb2576446506894facbaphilippe " is not RW or not AnonC\n", 326cda0c2cf073a7fba19e1fb2576446506894facbaphilippe (void*)SP); 3273a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe *start = 0; 3283a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe *end = 0; 329cda0c2cf073a7fba19e1fb2576446506894facbaphilippe return; 3303a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe } 3313a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe } 332cda0c2cf073a7fba19e1fb2576446506894facbaphilippe 33393d127f02c9abb9e6373585ee4529ece6dee0503philippe /* Limit the stack end limit, using the found segment. */ 33493d127f02c9abb9e6373585ee4529ece6dee0503philippe if (UNLIKELY(*end > stackseg->end)) { 335cda0c2cf073a7fba19e1fb2576446506894facbaphilippe VG_(debugLog)(2, "stacks", 336cda0c2cf073a7fba19e1fb2576446506894facbaphilippe "segment for SP %p changed stack end limit" 337cda0c2cf073a7fba19e1fb2576446506894facbaphilippe " from %p to %p\n", 338cda0c2cf073a7fba19e1fb2576446506894facbaphilippe (void*)SP, (void*)*end, (void*)stackseg->end); 339cda0c2cf073a7fba19e1fb2576446506894facbaphilippe *end = stackseg->end; 340cda0c2cf073a7fba19e1fb2576446506894facbaphilippe } 341cda0c2cf073a7fba19e1fb2576446506894facbaphilippe 342cda0c2cf073a7fba19e1fb2576446506894facbaphilippe /* If reducing start and/or end to the SP segment gives an 343cda0c2cf073a7fba19e1fb2576446506894facbaphilippe empty range, return 'empty' limits */ 34493d127f02c9abb9e6373585ee4529ece6dee0503philippe if (UNLIKELY(*start > *end)) { 345cda0c2cf073a7fba19e1fb2576446506894facbaphilippe VG_(debugLog)(2, "stacks", 346cda0c2cf073a7fba19e1fb2576446506894facbaphilippe "stack for SP %p start %p after end %p\n", 347cda0c2cf073a7fba19e1fb2576446506894facbaphilippe (void*)SP, (void*)*start, (void*)end); 348cda0c2cf073a7fba19e1fb2576446506894facbaphilippe *start = 0; 349cda0c2cf073a7fba19e1fb2576446506894facbaphilippe *end = 0; 350cda0c2cf073a7fba19e1fb2576446506894facbaphilippe } 351690c3c807be3571951400b98d5136437dd957b65tom} 352690c3c807be3571951400b98d5136437dd957b65tom 353d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe/* complaints_stack_switch reports that SP has changed by more than some 354d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe threshold amount (by default, 2MB). We take this to mean that the 355d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe application is switching to a new stack, for whatever reason. 356d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe 357d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe JRS 20021001: following discussions with John Regehr, if a stack 358d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe switch happens, it seems best not to mess at all with memory 359d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe permissions. Seems to work well with Netscape 4.X. Really the 360d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe only remaining difficulty is knowing exactly when a stack switch is 361d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe happening. */ 362d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe__attribute__((noinline)) 363d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippestatic void complaints_stack_switch (Addr old_SP, Addr new_SP) 364d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe{ 365d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe static Int complaints = 3; 366d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe if (VG_(clo_verbosity) > 0 && complaints > 0 && !VG_(clo_xml)) { 367d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe Word delta = (Word)new_SP - (Word)old_SP; 368d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe complaints--; 369d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe VG_(message)(Vg_UserMsg, 370d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe "Warning: client switching stacks? " 371d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe "SP change: 0x%lx --> 0x%lx\n", old_SP, new_SP); 372d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe VG_(message)(Vg_UserMsg, 373d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe " to suppress, use: --max-stackframe=%ld " 374d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe "or greater\n", 375d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe (delta < 0 ? -delta : delta)); 376d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe if (complaints == 0) 377d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe VG_(message)(Vg_UserMsg, 378d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe " further instances of this message " 379d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe "will not be shown.\n"); 380d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe } 381d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe} 382d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe 383d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe/* The functions VG_(unknown_SP_update) and VG_(unknown_SP_update_w_ECU) 384d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe get called if new_mem_stack and/or die_mem_stack are 385945ed2e53f6bbe9c84a8173b63881158132d9ca8njn tracked by the tool, and one of the specialised cases 386945ed2e53f6bbe9c84a8173b63881158132d9ca8njn (eg. new_mem_stack_4) isn't used in preference. 387d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe 388d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe These functions are performance critical, so are built with macros. */ 389d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe 390d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe// preamble + check if stack has switched. 3919cbe9d79d72020e7f69b4cd3fc9ac312e7aa4037philippe#define IF_STACK_SWITCH_SET_current_stack_AND_RETURN \ 392d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe Word delta = (Word)new_SP - (Word)old_SP; \ 393d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe \ 3944fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe EDEBUG("current_stack %p-%p %lu new_SP %p old_SP %p\n", \ 3954fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe (void *) (current_stack ? current_stack->start : 0x0), \ 3964fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe (void *) (current_stack ? current_stack->end : 0x0), \ 3974fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe current_stack ? current_stack->id : 0, \ 3984fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe (void *)new_SP, (void *)old_SP); \ 3994fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe \ 400d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe /* Check if the stack pointer is still in the same stack as before. */ \ 401d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe if (UNLIKELY(current_stack == NULL || \ 402d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe new_SP < current_stack->start || new_SP > current_stack->end)) { \ 403d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe Stack* new_stack = find_stack_by_addr(new_SP); \ 404d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe if (new_stack \ 405d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe && (current_stack == NULL || new_stack->id != current_stack->id)) { \ 406d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe /* The stack pointer is now in another stack. Update the current */ \ 407d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe /* stack information and return without doing anything else. */ \ 408d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe current_stack = new_stack; \ 4094fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe EDEBUG("new current_stack %p-%p %lu \n", \ 4104fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe (void *) current_stack->start, \ 4114fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe (void *) current_stack->end, \ 4124fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe current_stack->id); \ 413d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe return; \ 4144fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe } else \ 4154fa3d371f8a70bb89e7f6bdf95011c05b3dbc7d4philippe EDEBUG("new current_stack not found\n"); \ 416945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 417945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 418d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe#define IF_BIG_DELTA_complaints_AND_RETURN \ 419d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe if (UNLIKELY(delta < -VG_(clo_max_stackframe) \ 420d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe || VG_(clo_max_stackframe) < delta)) { \ 421d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe complaints_stack_switch(old_SP, new_SP); \ 422d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe return; \ 423d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe } 424d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe 425d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe#define IF_SMALLER_STACK_die_mem_stack_AND_RETURN \ 426d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe if (delta > 0) { \ 427d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe VG_TRACK( die_mem_stack, old_SP, delta ); \ 428d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe return; \ 429d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe } 430d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe 431d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe 432d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippeVG_REGPARM(3) 433d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippevoid VG_(unknown_SP_update_w_ECU)( Addr old_SP, Addr new_SP, UInt ecu ) { 4349cbe9d79d72020e7f69b4cd3fc9ac312e7aa4037philippe IF_STACK_SWITCH_SET_current_stack_AND_RETURN; 435d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe IF_BIG_DELTA_complaints_AND_RETURN; 436d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe IF_SMALLER_STACK_die_mem_stack_AND_RETURN; 437d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe if (delta < 0) { // IF_BIGGER_STACK 4387cf4e6b6aed533af53339f36099ed244dc4a5b7fsewardj VG_TRACK( new_mem_stack_w_ECU, new_SP, -delta, ecu ); 439d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe return; 440d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe } 441d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe // SAME_STACK. nothing to do. 442d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe} 443945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 444d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippeVG_REGPARM(2) 445d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippevoid VG_(unknown_SP_update)( Addr old_SP, Addr new_SP ) { 4469cbe9d79d72020e7f69b4cd3fc9ac312e7aa4037philippe IF_STACK_SWITCH_SET_current_stack_AND_RETURN; 447d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe IF_BIG_DELTA_complaints_AND_RETURN; 448d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe IF_SMALLER_STACK_die_mem_stack_AND_RETURN; 449d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe if (delta < 0) { // IF_BIGGER_STACK 450d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe VG_TRACK( new_mem_stack, new_SP, -delta ); 451d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe return; 452945ed2e53f6bbe9c84a8173b63881158132d9ca8njn } 453d5fb89de7477f1ffc6dd4f511f268ce226ed7d13philippe // SAME_STACK. nothing to do. 454945ed2e53f6bbe9c84a8173b63881158132d9ca8njn} 455945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 456945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/*--------------------------------------------------------------------*/ 457945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/*--- end ---*/ 458945ed2e53f6bbe9c84a8173b63881158132d9ca8njn/*--------------------------------------------------------------------*/ 459945ed2e53f6bbe9c84a8173b63881158132d9ca8njn 460