sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 1 | |
| 2 | ##--------------------------------------------------------------------## |
| 3 | ##--- Startup and shutdown code for Valgrind. ---## |
| 4 | ##--- vg_startup.S ---## |
| 5 | ##--------------------------------------------------------------------## |
| 6 | |
| 7 | /* |
| 8 | This file is part of Valgrind, an x86 protected-mode emulator |
| 9 | designed for debugging and profiling binaries on x86-Unixes. |
| 10 | |
| 11 | Copyright (C) 2000-2002 Julian Seward |
| 12 | jseward@acm.org |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 13 | |
| 14 | This program is free software; you can redistribute it and/or |
| 15 | modify it under the terms of the GNU General Public License as |
| 16 | published by the Free Software Foundation; either version 2 of the |
| 17 | License, or (at your option) any later version. |
| 18 | |
| 19 | This program is distributed in the hope that it will be useful, but |
| 20 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 22 | General Public License for more details. |
| 23 | |
| 24 | You should have received a copy of the GNU General Public License |
| 25 | along with this program; if not, write to the Free Software |
| 26 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 27 | 02111-1307, USA. |
| 28 | |
| 29 | The GNU General Public License is contained in the file LICENSE. |
| 30 | */ |
| 31 | |
| 32 | #include "vg_constants.h" |
| 33 | |
| 34 | |
| 35 | #--------------------------------------------------------------------- |
| 36 | # |
| 37 | # Startup and shutdown code for Valgrind. Particularly hairy. |
| 38 | # |
| 39 | # The dynamic linker, ld.so, will run the contents of the .init |
| 40 | # section, once it has located, mmap-d and and linked the shared |
| 41 | # libraries needed by the program. Valgrind is itself a shared |
| 42 | # library. ld.so then runs code in the .init sections of each |
| 43 | # library in turn, in order to give them a chance to initialise |
| 44 | # themselves. We hijack this mechanism. Our startup routine |
| 45 | # does return -- and execution continues -- except on the |
| 46 | # synthetic CPU, not the real one. But ld.so, and the program |
| 47 | # it is starting, cant tell the difference. |
| 48 | # |
| 49 | # The management apologise for the lack of apostrophes in these |
| 50 | # comments. GNU as seems to object to them, for some reason. |
| 51 | |
| 52 | |
| 53 | .section .init |
| 54 | call VG_(startup) |
| 55 | .section .fini |
| 56 | call VG_(shutdown) |
sewardj | 68b2dd9 | 2002-05-10 21:03:56 +0000 | [diff] [blame] | 57 | |
| 58 | .section .data |
| 59 | valgrind_already_initted: |
| 60 | .word 0 |
| 61 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 62 | .section .text |
| 63 | |
| 64 | |
sewardj | 68b2dd9 | 2002-05-10 21:03:56 +0000 | [diff] [blame] | 65 | .global VG_(startup) |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 66 | VG_(startup): |
sewardj | 68b2dd9 | 2002-05-10 21:03:56 +0000 | [diff] [blame] | 67 | cmpl $0, valgrind_already_initted |
| 68 | je really_start_up |
| 69 | ret |
| 70 | |
| 71 | really_start_up: |
| 72 | movl $1, valgrind_already_initted |
| 73 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 74 | # Record %esp as it was when we got here. This is because argv/c |
| 75 | # and envp[] are passed as args to this function, and we need to see |
| 76 | # envp so we can get at the env var VG_ARGS without help from libc. |
| 77 | # The stack layout at this point depends on the version of glibc in |
| 78 | # use. See process_cmd_line_options() in vg_main.c for details. |
| 79 | movl %esp, VG_(esp_at_startup) |
| 80 | |
| 81 | # We have control! Save the state of the machine in |
| 82 | # the simulators state, and switch stacks. |
| 83 | # Except ... we cant copy the machines registers into their |
| 84 | # final places in vg_baseBlock, because the offsets to them |
| 85 | # have not yet been set up. Instead, they are copied to a |
| 86 | # temporary place (m_state_static). In vg_main.c, once the |
| 87 | # baseBlock offsets are set up, values are copied into baseBlock. |
| 88 | movl %eax, VG_(m_state_static)+0 |
| 89 | movl %ecx, VG_(m_state_static)+4 |
| 90 | movl %edx, VG_(m_state_static)+8 |
| 91 | movl %ebx, VG_(m_state_static)+12 |
| 92 | movl %esp, VG_(m_state_static)+16 |
| 93 | movl %ebp, VG_(m_state_static)+20 |
| 94 | movl %esi, VG_(m_state_static)+24 |
| 95 | movl %edi, VG_(m_state_static)+28 |
| 96 | pushfl |
| 97 | popl %eax |
| 98 | movl %eax, VG_(m_state_static)+32 |
| 99 | fwait |
| 100 | fnsave VG_(m_state_static)+40 |
| 101 | frstor VG_(m_state_static)+40 |
| 102 | |
| 103 | # keep the first and last 10 words free to check for overruns |
| 104 | movl $VG_(stack)+39996 -40, %esp |
| 105 | |
| 106 | # Now some real magic. We need this procedure to return, |
| 107 | # since thats what ld.so expects, but running on the |
| 108 | # simulator. So vg_main starts the simulator running at |
| 109 | # the insn labelled first_insn_to_simulate. |
| 110 | |
| 111 | movl $first_insn_to_simulate, VG_(m_state_static)+36 |
| 112 | jmp VG_(main) |
| 113 | first_insn_to_simulate: |
| 114 | # Nothing else to do -- just return in the "normal" way. |
| 115 | ret |
| 116 | |
| 117 | |
| 118 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 119 | VG_(shutdown): |
sewardj | 7e87e38 | 2002-05-03 19:09:05 +0000 | [diff] [blame] | 120 | # Just return, and ignore any attempt by ld.so to call |
| 121 | # valgrind.sos exit function. We just run the client all |
| 122 | # the way to the final exit() syscall. This sidesteps |
| 123 | # problems caused by ld.so calling the finalisation code |
| 124 | # of other .sos *after* it shuts down valgrind, which |
| 125 | # was causing big problems with threads. |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 126 | ret |
sewardj | 7e87e38 | 2002-05-03 19:09:05 +0000 | [diff] [blame] | 127 | |
| 128 | |
sewardj | 54cacf0 | 2002-04-12 23:24:59 +0000 | [diff] [blame] | 129 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 130 | .global VG_(switch_to_real_CPU) |
| 131 | VG_(switch_to_real_CPU): |
sewardj | 7e87e38 | 2002-05-03 19:09:05 +0000 | [diff] [blame] | 132 | # Once Valgrind has decided it needs to exit, |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 133 | # because the specified number of insns have been completed |
| 134 | # during a debugging run, it jumps here, which copies the |
| 135 | # simulators state into the real machine state. Execution |
| 136 | # of the rest of the program continues on the real CPU, |
| 137 | # and there is no way for the simulator to regain control |
| 138 | # after this point. |
| 139 | frstor VG_(m_state_static)+40 |
| 140 | movl VG_(m_state_static)+32, %eax |
| 141 | pushl %eax |
| 142 | popfl |
| 143 | movl VG_(m_state_static)+0, %eax |
| 144 | movl VG_(m_state_static)+4, %ecx |
| 145 | movl VG_(m_state_static)+8, %edx |
| 146 | movl VG_(m_state_static)+12, %ebx |
| 147 | movl VG_(m_state_static)+16, %esp |
| 148 | movl VG_(m_state_static)+20, %ebp |
| 149 | movl VG_(m_state_static)+24, %esi |
| 150 | movl VG_(m_state_static)+28, %edi |
| 151 | |
| 152 | pushal |
| 153 | pushfl |
| 154 | # We hope that vg_sigshutdown_actions does not alter |
| 155 | # the FPU state. |
| 156 | call VG_(sigshutdown_actions) |
| 157 | popfl |
| 158 | popal |
| 159 | # re-restore the FPU state anyway ... |
| 160 | frstor VG_(m_state_static)+40 |
| 161 | jmp *VG_(m_state_static)+36 |
| 162 | |
| 163 | |
| 164 | |
| 165 | /*------------------------------------------------------------*/ |
| 166 | /*--- A function to temporarily copy %ESP/%EBP into ---*/ |
| 167 | /*--- %esp/%ebp and then start up GDB. ---*/ |
| 168 | /*------------------------------------------------------------*/ |
| 169 | |
sewardj | 3580542 | 2002-04-21 13:05:34 +0000 | [diff] [blame] | 170 | /* |
| 171 | extern void VG_(swizzle_esp_then_start_GDB) ( Addr m_eip_at_error, |
| 172 | Addr m_esp_at_error, |
| 173 | Addr m_ebp_at_error ); |
| 174 | */ |
| 175 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 176 | /*--- This is clearly not re-entrant! ---*/ |
| 177 | .data |
| 178 | vg_ebp_saved_over_GDB_start: |
sewardj | 783f0f5 | 2002-04-21 20:26:06 +0000 | [diff] [blame] | 179 | .long 0 |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 180 | vg_esp_saved_over_GDB_start: |
sewardj | 783f0f5 | 2002-04-21 20:26:06 +0000 | [diff] [blame] | 181 | .long 0 |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 182 | .text |
| 183 | |
| 184 | .global VG_(swizzle_esp_then_start_GDB) |
| 185 | VG_(swizzle_esp_then_start_GDB): |
| 186 | pushal |
| 187 | |
| 188 | # remember the simulators current stack/frame pointers |
| 189 | movl %ebp, vg_ebp_saved_over_GDB_start |
| 190 | movl %esp, vg_esp_saved_over_GDB_start |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 191 | |
sewardj | 3580542 | 2002-04-21 13:05:34 +0000 | [diff] [blame] | 192 | # get args into regs |
| 193 | movl 44(%esp), %eax # client %EBP |
| 194 | movl 40(%esp), %ebx # client %ESP |
| 195 | movl 36(%esp), %ecx # client %EIP |
| 196 | |
sewardj | 783f0f5 | 2002-04-21 20:26:06 +0000 | [diff] [blame] | 197 | # Now that we dont need to refer to simulators stack any more, |
sewardj | 3580542 | 2002-04-21 13:05:34 +0000 | [diff] [blame] | 198 | # put %ESP into %esp |
| 199 | movl %ebx, %esp |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 200 | |
| 201 | ### %esp now refers to clients stack |
| 202 | ### mess with the clients stack to make it look as if it |
| 203 | ### called this procedure, since otherwise it will look to gdb |
| 204 | ### as if the top (currently executing) stack frame of the |
| 205 | ### client is missing. |
| 206 | |
sewardj | 3580542 | 2002-04-21 13:05:34 +0000 | [diff] [blame] | 207 | # push %EIP. This is a faked-up return address. |
| 208 | pushl %ecx |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 209 | |
sewardj | 3580542 | 2002-04-21 13:05:34 +0000 | [diff] [blame] | 210 | # push %EBP. This is a faked %ebp-chain pointer. |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 211 | pushl %eax |
| 212 | |
| 213 | movl %esp, %ebp |
| 214 | |
| 215 | call VG_(start_GDB_whilst_on_client_stack) |
| 216 | |
| 217 | # restore the simulators stack/frame pointer |
| 218 | movl vg_ebp_saved_over_GDB_start, %ebp |
| 219 | movl vg_esp_saved_over_GDB_start, %esp |
| 220 | |
| 221 | popal |
| 222 | ret |
| 223 | |
| 224 | # gcc puts this construction at the end of every function. I think it |
| 225 | # allows the linker to figure out the size of the function. So we do |
| 226 | # the same, in the vague hope that it might help GDBs navigation. |
| 227 | .Lend_of_swizzle: |
| 228 | .size VG_(swizzle_esp_then_start_GDB), .Lend_of_swizzle-VG_(swizzle_esp_then_start_GDB) |
| 229 | |
sewardj | 54cacf0 | 2002-04-12 23:24:59 +0000 | [diff] [blame] | 230 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 231 | ##--------------------------------------------------------------------## |
| 232 | ##--- end vg_startup.S ---## |
| 233 | ##--------------------------------------------------------------------## |