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) |
| 57 | .section .text |
| 58 | |
| 59 | |
| 60 | |
| 61 | VG_(startup): |
| 62 | # Record %esp as it was when we got here. This is because argv/c |
| 63 | # and envp[] are passed as args to this function, and we need to see |
| 64 | # envp so we can get at the env var VG_ARGS without help from libc. |
| 65 | # The stack layout at this point depends on the version of glibc in |
| 66 | # use. See process_cmd_line_options() in vg_main.c for details. |
| 67 | movl %esp, VG_(esp_at_startup) |
| 68 | |
| 69 | # We have control! Save the state of the machine in |
| 70 | # the simulators state, and switch stacks. |
| 71 | # Except ... we cant copy the machines registers into their |
| 72 | # final places in vg_baseBlock, because the offsets to them |
| 73 | # have not yet been set up. Instead, they are copied to a |
| 74 | # temporary place (m_state_static). In vg_main.c, once the |
| 75 | # baseBlock offsets are set up, values are copied into baseBlock. |
| 76 | movl %eax, VG_(m_state_static)+0 |
| 77 | movl %ecx, VG_(m_state_static)+4 |
| 78 | movl %edx, VG_(m_state_static)+8 |
| 79 | movl %ebx, VG_(m_state_static)+12 |
| 80 | movl %esp, VG_(m_state_static)+16 |
| 81 | movl %ebp, VG_(m_state_static)+20 |
| 82 | movl %esi, VG_(m_state_static)+24 |
| 83 | movl %edi, VG_(m_state_static)+28 |
| 84 | pushfl |
| 85 | popl %eax |
| 86 | movl %eax, VG_(m_state_static)+32 |
| 87 | fwait |
| 88 | fnsave VG_(m_state_static)+40 |
| 89 | frstor VG_(m_state_static)+40 |
| 90 | |
| 91 | # keep the first and last 10 words free to check for overruns |
| 92 | movl $VG_(stack)+39996 -40, %esp |
| 93 | |
| 94 | # Now some real magic. We need this procedure to return, |
| 95 | # since thats what ld.so expects, but running on the |
| 96 | # simulator. So vg_main starts the simulator running at |
| 97 | # the insn labelled first_insn_to_simulate. |
| 98 | |
| 99 | movl $first_insn_to_simulate, VG_(m_state_static)+36 |
| 100 | jmp VG_(main) |
| 101 | first_insn_to_simulate: |
| 102 | # Nothing else to do -- just return in the "normal" way. |
| 103 | ret |
| 104 | |
| 105 | |
| 106 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 107 | VG_(shutdown): |
sewardj | 7e87e38 | 2002-05-03 19:09:05 +0000 | [diff] [blame] | 108 | # Just return, and ignore any attempt by ld.so to call |
| 109 | # valgrind.sos exit function. We just run the client all |
| 110 | # the way to the final exit() syscall. This sidesteps |
| 111 | # problems caused by ld.so calling the finalisation code |
| 112 | # of other .sos *after* it shuts down valgrind, which |
| 113 | # was causing big problems with threads. |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 114 | ret |
sewardj | 7e87e38 | 2002-05-03 19:09:05 +0000 | [diff] [blame] | 115 | |
| 116 | |
sewardj | 54cacf0 | 2002-04-12 23:24:59 +0000 | [diff] [blame] | 117 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 118 | .global VG_(switch_to_real_CPU) |
| 119 | VG_(switch_to_real_CPU): |
sewardj | 7e87e38 | 2002-05-03 19:09:05 +0000 | [diff] [blame] | 120 | # Once Valgrind has decided it needs to exit, |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 121 | # because the specified number of insns have been completed |
| 122 | # during a debugging run, it jumps here, which copies the |
| 123 | # simulators state into the real machine state. Execution |
| 124 | # of the rest of the program continues on the real CPU, |
| 125 | # and there is no way for the simulator to regain control |
| 126 | # after this point. |
| 127 | frstor VG_(m_state_static)+40 |
| 128 | movl VG_(m_state_static)+32, %eax |
| 129 | pushl %eax |
| 130 | popfl |
| 131 | movl VG_(m_state_static)+0, %eax |
| 132 | movl VG_(m_state_static)+4, %ecx |
| 133 | movl VG_(m_state_static)+8, %edx |
| 134 | movl VG_(m_state_static)+12, %ebx |
| 135 | movl VG_(m_state_static)+16, %esp |
| 136 | movl VG_(m_state_static)+20, %ebp |
| 137 | movl VG_(m_state_static)+24, %esi |
| 138 | movl VG_(m_state_static)+28, %edi |
| 139 | |
| 140 | pushal |
| 141 | pushfl |
| 142 | # We hope that vg_sigshutdown_actions does not alter |
| 143 | # the FPU state. |
| 144 | call VG_(sigshutdown_actions) |
| 145 | popfl |
| 146 | popal |
| 147 | # re-restore the FPU state anyway ... |
| 148 | frstor VG_(m_state_static)+40 |
| 149 | jmp *VG_(m_state_static)+36 |
| 150 | |
| 151 | |
| 152 | |
| 153 | /*------------------------------------------------------------*/ |
| 154 | /*--- A function to temporarily copy %ESP/%EBP into ---*/ |
| 155 | /*--- %esp/%ebp and then start up GDB. ---*/ |
| 156 | /*------------------------------------------------------------*/ |
| 157 | |
sewardj | 3580542 | 2002-04-21 13:05:34 +0000 | [diff] [blame] | 158 | /* |
| 159 | extern void VG_(swizzle_esp_then_start_GDB) ( Addr m_eip_at_error, |
| 160 | Addr m_esp_at_error, |
| 161 | Addr m_ebp_at_error ); |
| 162 | */ |
| 163 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 164 | /*--- This is clearly not re-entrant! ---*/ |
| 165 | .data |
| 166 | vg_ebp_saved_over_GDB_start: |
sewardj | 783f0f5 | 2002-04-21 20:26:06 +0000 | [diff] [blame] | 167 | .long 0 |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 168 | vg_esp_saved_over_GDB_start: |
sewardj | 783f0f5 | 2002-04-21 20:26:06 +0000 | [diff] [blame] | 169 | .long 0 |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 170 | .text |
| 171 | |
| 172 | .global VG_(swizzle_esp_then_start_GDB) |
| 173 | VG_(swizzle_esp_then_start_GDB): |
| 174 | pushal |
| 175 | |
| 176 | # remember the simulators current stack/frame pointers |
| 177 | movl %ebp, vg_ebp_saved_over_GDB_start |
| 178 | movl %esp, vg_esp_saved_over_GDB_start |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 179 | |
sewardj | 3580542 | 2002-04-21 13:05:34 +0000 | [diff] [blame] | 180 | # get args into regs |
| 181 | movl 44(%esp), %eax # client %EBP |
| 182 | movl 40(%esp), %ebx # client %ESP |
| 183 | movl 36(%esp), %ecx # client %EIP |
| 184 | |
sewardj | 783f0f5 | 2002-04-21 20:26:06 +0000 | [diff] [blame] | 185 | # Now that we dont need to refer to simulators stack any more, |
sewardj | 3580542 | 2002-04-21 13:05:34 +0000 | [diff] [blame] | 186 | # put %ESP into %esp |
| 187 | movl %ebx, %esp |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 188 | |
| 189 | ### %esp now refers to clients stack |
| 190 | ### mess with the clients stack to make it look as if it |
| 191 | ### called this procedure, since otherwise it will look to gdb |
| 192 | ### as if the top (currently executing) stack frame of the |
| 193 | ### client is missing. |
| 194 | |
sewardj | 3580542 | 2002-04-21 13:05:34 +0000 | [diff] [blame] | 195 | # push %EIP. This is a faked-up return address. |
| 196 | pushl %ecx |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 197 | |
sewardj | 3580542 | 2002-04-21 13:05:34 +0000 | [diff] [blame] | 198 | # push %EBP. This is a faked %ebp-chain pointer. |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 199 | pushl %eax |
| 200 | |
| 201 | movl %esp, %ebp |
| 202 | |
| 203 | call VG_(start_GDB_whilst_on_client_stack) |
| 204 | |
| 205 | # restore the simulators stack/frame pointer |
| 206 | movl vg_ebp_saved_over_GDB_start, %ebp |
| 207 | movl vg_esp_saved_over_GDB_start, %esp |
| 208 | |
| 209 | popal |
| 210 | ret |
| 211 | |
| 212 | # gcc puts this construction at the end of every function. I think it |
| 213 | # allows the linker to figure out the size of the function. So we do |
| 214 | # the same, in the vague hope that it might help GDBs navigation. |
| 215 | .Lend_of_swizzle: |
| 216 | .size VG_(swizzle_esp_then_start_GDB), .Lend_of_swizzle-VG_(swizzle_esp_then_start_GDB) |
| 217 | |
sewardj | 54cacf0 | 2002-04-12 23:24:59 +0000 | [diff] [blame] | 218 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 219 | ##--------------------------------------------------------------------## |
| 220 | ##--- end vg_startup.S ---## |
| 221 | ##--------------------------------------------------------------------## |