mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-04 18:56:10 +00:00
block execution count exceeded, debugging only), restore the signal state before switching back rather than after. I no longer understand why it had to be done afterwards. This simplifies vg_startup.S a bit. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1686
281 lines
8.5 KiB
ArmAsm
281 lines
8.5 KiB
ArmAsm
|
|
##--------------------------------------------------------------------##
|
|
##--- Startup and shutdown code for Valgrind. ---##
|
|
##--- vg_startup.S ---##
|
|
##--------------------------------------------------------------------##
|
|
|
|
/*
|
|
This file is part of Valgrind, an extensible x86 protected-mode
|
|
emulator for monitoring program execution on x86-Unixes.
|
|
|
|
Copyright (C) 2000-2003 Julian Seward
|
|
jseward@acm.org
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307, USA.
|
|
|
|
The GNU General Public License is contained in the file COPYING.
|
|
*/
|
|
|
|
#include "vg_constants.h"
|
|
|
|
|
|
#---------------------------------------------------------------------
|
|
#
|
|
# Startup and shutdown code for Valgrind. Particularly hairy.
|
|
#
|
|
# The dynamic linker, ld.so, will run the contents of the .init
|
|
# section, once it has located, mmap-d and and linked the shared
|
|
# libraries needed by the program. Valgrind is itself a shared
|
|
# library. ld.so then runs code in the .init sections of each
|
|
# library in turn, in order to give them a chance to initialise
|
|
# themselves. We hijack this mechanism. Our startup routine
|
|
# does return -- and execution continues -- except on the
|
|
# synthetic CPU, not the real one. But ld.so, and the program
|
|
# it is starting, cant tell the difference.
|
|
#
|
|
# The management apologise for the lack of apostrophes in these
|
|
# comments. GNU as seems to object to them, for some reason.
|
|
|
|
|
|
.section .init
|
|
call VG_(startup)
|
|
.section .fini
|
|
call VG_(shutdown)
|
|
|
|
.section .data
|
|
valgrind_already_initted:
|
|
.word 0
|
|
|
|
.section .text
|
|
|
|
|
|
.global VG_(startup)
|
|
VG_(startup):
|
|
pushfl
|
|
cmpl $0, valgrind_already_initted
|
|
je really_start_up
|
|
popfl
|
|
ret
|
|
|
|
really_start_up:
|
|
popfl
|
|
movl $1, valgrind_already_initted
|
|
|
|
# Record %esp as it was when we got here. This is because argv/c
|
|
# and envp[] are passed as args to this function, and we need to see
|
|
# envp so we can get at the env var VG_ARGS without help from libc.
|
|
# The stack layout at this point depends on the version of glibc in
|
|
# use. See process_cmd_line_options() in vg_main.c for details.
|
|
movl %esp, VG_(esp_at_startup)
|
|
|
|
# We have control! Save the state of the machine in
|
|
# the simulators state, and switch stacks.
|
|
# Except ... we cant copy the machines registers into their
|
|
# final places in vg_baseBlock, because the offsets to them
|
|
# have not yet been set up. Instead, they are copied to a
|
|
# temporary place (m_state_static). In vg_main.c, once the
|
|
# baseBlock offsets are set up, values are copied into baseBlock.
|
|
movw %cs, VG_(m_state_static)+0
|
|
movw %ss, VG_(m_state_static)+4
|
|
movw %ds, VG_(m_state_static)+8
|
|
movw %es, VG_(m_state_static)+12
|
|
movw %fs, VG_(m_state_static)+16
|
|
movw %gs, VG_(m_state_static)+20
|
|
movl %eax, VG_(m_state_static)+24
|
|
movl %ecx, VG_(m_state_static)+28
|
|
movl %edx, VG_(m_state_static)+32
|
|
movl %ebx, VG_(m_state_static)+36
|
|
movl %esp, VG_(m_state_static)+40
|
|
movl %ebp, VG_(m_state_static)+44
|
|
movl %esi, VG_(m_state_static)+48
|
|
movl %edi, VG_(m_state_static)+52
|
|
pushfl
|
|
popl %eax
|
|
movl %eax, VG_(m_state_static)+56
|
|
|
|
# now weve captured all the integer registers and
|
|
# flags, figure out whether this is an sse-enabled
|
|
# cpu or not.
|
|
movb $0, VG_(have_ssestate) # assume sse-disabled
|
|
movl $0, %eax
|
|
cpuid
|
|
cmpl $1, %eax
|
|
jl get_fpu # we cant do cpuid(1) ?!
|
|
movl $1, %eax
|
|
cpuid
|
|
testl $(1<<25), %edx
|
|
jz get_fpu # edx bit 25 is set iff sse
|
|
# well, it looks like were sse-enabled
|
|
movb $1, VG_(have_ssestate)
|
|
|
|
# next, capture the FPU/SSE state
|
|
get_fpu:
|
|
fwait
|
|
|
|
pushfl
|
|
cmpb $0, VG_(have_ssestate)
|
|
jz qq3nosse
|
|
fxsave VG_(m_state_static)+64
|
|
andl $0x0000FFBF, VG_(m_state_static)+64+24
|
|
fxrstor VG_(m_state_static)+64
|
|
jmp qq3merge
|
|
qq3nosse:
|
|
fnsave VG_(m_state_static)+64
|
|
frstor VG_(m_state_static)+64
|
|
qq3merge:
|
|
popfl
|
|
|
|
# keep the first and last 10 words free to check for overruns
|
|
movl $VG_(stack)+39996 -40, %esp
|
|
|
|
# Now some real magic. We need this procedure to return,
|
|
# since thats what ld.so expects, but running on the
|
|
# simulator. So vg_main starts the simulator running at
|
|
# the insn labelled first_insn_to_simulate.
|
|
|
|
movl $first_insn_to_simulate, VG_(m_state_static)+60
|
|
jmp VG_(main)
|
|
first_insn_to_simulate:
|
|
# Nothing else to do -- just return in the "normal" way.
|
|
ret
|
|
|
|
|
|
|
|
VG_(shutdown):
|
|
# Just return, and ignore any attempt by ld.so to call
|
|
# valgrind.sos exit function. We just run the client all
|
|
# the way to the final exit() syscall. This sidesteps
|
|
# problems caused by ld.so calling the finalisation code
|
|
# of other .sos *after* it shuts down valgrind, which
|
|
# was causing big problems with threads.
|
|
ret
|
|
|
|
|
|
|
|
.global VG_(switch_to_real_CPU)
|
|
VG_(switch_to_real_CPU):
|
|
# Once Valgrind has decided it needs to exit,
|
|
# because the specified number of insns have been completed
|
|
# during a debugging run, it jumps here, which copies the
|
|
# simulators state into the real machine state. Execution
|
|
# of the rest of the program continues on the real CPU,
|
|
# and there is no way for the simulator to regain control
|
|
# after this point.
|
|
|
|
pushfl
|
|
cmpb $0, VG_(have_ssestate)
|
|
jz qq4nosse
|
|
andl $0x0000FFBF, VG_(m_state_static)+64+24
|
|
fxrstor VG_(m_state_static)+64
|
|
jmp qq4merge
|
|
qq4nosse:
|
|
frstor VG_(m_state_static)+64
|
|
qq4merge:
|
|
popfl
|
|
|
|
movl VG_(m_state_static)+56, %eax
|
|
pushl %eax
|
|
popfl
|
|
/* some of these are apparently illegal */
|
|
/* movw VG_(m_state_static)+0, %cs */
|
|
movw VG_(m_state_static)+4, %ss
|
|
movw VG_(m_state_static)+8, %ds
|
|
movw VG_(m_state_static)+12, %es
|
|
movw VG_(m_state_static)+16, %fs
|
|
movw VG_(m_state_static)+20, %gs
|
|
movl VG_(m_state_static)+24, %eax
|
|
movl VG_(m_state_static)+28, %ecx
|
|
movl VG_(m_state_static)+32, %edx
|
|
movl VG_(m_state_static)+36, %ebx
|
|
movl VG_(m_state_static)+40, %esp
|
|
movl VG_(m_state_static)+44, %ebp
|
|
movl VG_(m_state_static)+48, %esi
|
|
movl VG_(m_state_static)+52, %edi
|
|
|
|
jmp *VG_(m_state_static)+60
|
|
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- A function to temporarily copy %ESP/%EBP into ---*/
|
|
/*--- %esp/%ebp and then start up GDB. ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/*
|
|
extern void VG_(swizzle_esp_then_start_GDB) ( Addr m_eip_at_error,
|
|
Addr m_esp_at_error,
|
|
Addr m_ebp_at_error );
|
|
*/
|
|
|
|
/*--- This is clearly not re-entrant! ---*/
|
|
.data
|
|
vg_ebp_saved_over_GDB_start:
|
|
.long 0
|
|
vg_esp_saved_over_GDB_start:
|
|
.long 0
|
|
.text
|
|
|
|
.global VG_(swizzle_esp_then_start_GDB)
|
|
VG_(swizzle_esp_then_start_GDB):
|
|
pushal
|
|
|
|
# remember the simulators current stack/frame pointers
|
|
movl %ebp, vg_ebp_saved_over_GDB_start
|
|
movl %esp, vg_esp_saved_over_GDB_start
|
|
|
|
# get args into regs
|
|
movl 44(%esp), %eax # client %EBP
|
|
movl 40(%esp), %ebx # client %ESP
|
|
movl 36(%esp), %ecx # client %EIP
|
|
|
|
# Now that we dont need to refer to simulators stack any more,
|
|
# put %ESP into %esp
|
|
movl %ebx, %esp
|
|
|
|
### %esp now refers to clients stack
|
|
### mess with the clients stack to make it look as if it
|
|
### called this procedure, since otherwise it will look to gdb
|
|
### as if the top (currently executing) stack frame of the
|
|
### client is missing.
|
|
|
|
# push %EIP. This is a faked-up return address.
|
|
pushl %ecx
|
|
|
|
# push %EBP. This is a faked %ebp-chain pointer.
|
|
pushl %eax
|
|
|
|
movl %esp, %ebp
|
|
|
|
call VG_(start_GDB_whilst_on_client_stack)
|
|
|
|
# restore the simulators stack/frame pointer
|
|
movl vg_ebp_saved_over_GDB_start, %ebp
|
|
movl vg_esp_saved_over_GDB_start, %esp
|
|
|
|
popal
|
|
ret
|
|
|
|
# gcc puts this construction at the end of every function. I think it
|
|
# allows the linker to figure out the size of the function. So we do
|
|
# the same, in the vague hope that it might help GDBs navigation.
|
|
.Lend_of_swizzle:
|
|
.size VG_(swizzle_esp_then_start_GDB), .Lend_of_swizzle-VG_(swizzle_esp_then_start_GDB)
|
|
|
|
|
|
##--------------------------------------------------------------------##
|
|
##--- end vg_startup.S ---##
|
|
##--------------------------------------------------------------------##
|