blob: 0f4783ba0e7c52110b6bd755e24a663d0d45d352 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2##--------------------------------------------------------------------##
3##--- The core dispatch loop, for jumping to a code address. ---##
4##--- vg_dispatch.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
13 Julian_Seward@muraroa.demon.co.uk
14
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307, USA.
29
30 The GNU General Public License is contained in the file LICENSE.
31*/
32
33#include "vg_constants.h"
34
35
36/*------------------------------------------------------------*/
37/*--- The normal-case dispatch machinery. ---*/
38/*------------------------------------------------------------*/
39
40/* To transfer to an (original) code address, load it into %eax and
41 jump to vg_dispatch. This fragment of code tries to find the
42 address of the corresponding translation by searching the translation
43 table. If it fails, a new translation is made, added to the
44 translation table, and then jumped to. Almost all the hard
45 work is done by C routines; this code simply handles the
46 common case fast -- when the translation address is found in
47 the translation cache.
48
49 At entry, %eax is the only live (real-machine) register; the
50 entire simulated state is tidily saved in vg_m_state.
51*/
52
53
54/* The C world needs a way to get started simulating. So we provide
55 a function void vg_run_innerloop ( void ), which starts running
56 from vg_m_eip, and exits when the counter reaches zero. This loop
57 can also exit if vg_oursignalhandler() catches a non-resumable
58 signal, for example SIGSEGV. It then longjmp()s back past here.
59*/
60
61.globl VG_(run_innerloop)
62VG_(run_innerloop):
63 #OYNK(1000)
sewardj2e93c502002-04-12 11:12:52 +000064
sewardjde4a1d02002-03-22 01:27:54 +000065 # ----- entry point to VG_(run_innerloop) -----
sewardj2e93c502002-04-12 11:12:52 +000066 pushl %ebx
67 pushl %ecx
68 pushl %edx
69 pushl %esi
70 pushl %edi
71 pushl %ebp
72
sewardjde4a1d02002-03-22 01:27:54 +000073 # Set up the baseBlock pointer
74 movl $VG_(baseBlock), %ebp
75
76 # fetch m_eip into %eax
77 movl VGOFF_(m_eip), %esi
78 movl (%ebp, %esi, 4), %eax
79
sewardj2e93c502002-04-12 11:12:52 +000080 # Start off dispatching paranoically, since we no longer have
81 # any indication whether or not this might be a special call/ret
82 # transfer.
83 jmp dispatch_callret_maybe
sewardjde4a1d02002-03-22 01:27:54 +000084
sewardj2e93c502002-04-12 11:12:52 +000085
86dispatch_main:
87 # Jump here to do a new dispatch.
88 # %eax holds destination (original) address.
sewardjde4a1d02002-03-22 01:27:54 +000089 # %ebp indicates further details of the control transfer
90 # requested to the address in %eax. The idea is that we
91 # want to check all jump targets to see if they are either
sewardj2e93c502002-04-12 11:12:52 +000092 # VG_(signalreturn_bogusRA) or VG_(shutdown), both of which
sewardjde4a1d02002-03-22 01:27:54 +000093 # require special treatment. However, testing all branch
94 # targets is expensive, and anyway in most cases JITter knows
95 # that a jump cannot be to either of these two. We therefore
96 # adopt the following trick.
97 #
98 # If ebp == & VG_(baseBlock), which is what it started out as,
99 # this is a jump for which the JITter knows no check need be
100 # made.
101 #
sewardj2e93c502002-04-12 11:12:52 +0000102 # If ebp == VG_EBP_JMP_CALLRET, we had better make
sewardjde4a1d02002-03-22 01:27:54 +0000103 # the check.
104 #
sewardj2e93c502002-04-12 11:12:52 +0000105 # If ebp == VG_EBP_JMP_SYSCALL, do a system call before
106 # continuing at eax.
107 #
108 # If ebp == VG_EBP_JMP_CLIENTREQ, do a client request before
109 # continuing at eax.
110 #
sewardjde4a1d02002-03-22 01:27:54 +0000111 # If %ebp has any other value, we panic.
112 #
113 # What the JITter assumes is that VG_(signalreturn_bogusRA) can
114 # only be arrived at from an x86 ret insn, and dually that
sewardj2e93c502002-04-12 11:12:52 +0000115 # VG_(shutdown) can only be arrived at from an x86 call insn.
sewardjde4a1d02002-03-22 01:27:54 +0000116 # The net effect is that all call and return targets are checked
117 # but straightforward jumps are not.
sewardj2e93c502002-04-12 11:12:52 +0000118
sewardjde4a1d02002-03-22 01:27:54 +0000119 cmpl $VG_(baseBlock), %ebp
sewardj2e93c502002-04-12 11:12:52 +0000120 jnz dispatch_exceptional
sewardjde4a1d02002-03-22 01:27:54 +0000121
sewardj2e93c502002-04-12 11:12:52 +0000122dispatch_boring:
sewardjde4a1d02002-03-22 01:27:54 +0000123 # save the jump address at VG_(baseBlock)[VGOFF_(m_eip)],
sewardjde4a1d02002-03-22 01:27:54 +0000124 movl VGOFF_(m_eip), %esi
125 movl %eax, (%ebp, %esi, 4)
126
sewardj2e93c502002-04-12 11:12:52 +0000127 # do a timeslice check.
128 # are we out of timeslice? If yes, defer to scheduler.
sewardjde4a1d02002-03-22 01:27:54 +0000129 #OYNK(1001)
130 decl VG_(dispatch_ctr)
131 jz counter_is_zero
132
133 #OYNK(1002)
134 # try a fast lookup in the translation cache
135 movl %eax, %ebx
136 andl $VG_TT_FAST_MASK, %ebx
137 # ebx = tt_fast index
138 movl VG_(tt_fast)(,%ebx,4), %ebx
139 # ebx points at a tt entry
140 # now compare target with the tte.orig_addr field (+0)
141 cmpl %eax, (%ebx)
sewardj2e93c502002-04-12 11:12:52 +0000142 jnz fast_lookup_failed
143
sewardjde4a1d02002-03-22 01:27:54 +0000144 # Found a match. Set the tte.mru_epoch field (+8)
145 # and call the tte.trans_addr field (+4)
146 movl VG_(current_epoch), %ecx
147 movl %ecx, 8(%ebx)
148 call *4(%ebx)
sewardj2e93c502002-04-12 11:12:52 +0000149 jmp dispatch_main
sewardjde4a1d02002-03-22 01:27:54 +0000150
sewardj2e93c502002-04-12 11:12:52 +0000151fast_lookup_failed:
152 # %EIP is up to date here since dispatch_boring dominates
153 movl $VG_TRC_INNER_FASTMISS, %eax
154 jmp run_innerloop_exit
sewardjde4a1d02002-03-22 01:27:54 +0000155
sewardjde4a1d02002-03-22 01:27:54 +0000156counter_is_zero:
sewardj2e93c502002-04-12 11:12:52 +0000157 # %EIP is up to date here since dispatch_boring dominates
158 movl $VG_TRC_INNER_COUNTERZERO, %eax
159 jmp run_innerloop_exit
sewardjde4a1d02002-03-22 01:27:54 +0000160
sewardj2e93c502002-04-12 11:12:52 +0000161run_innerloop_exit:
sewardjde4a1d02002-03-22 01:27:54 +0000162 popl %ebp
163 popl %edi
164 popl %esi
165 popl %edx
166 popl %ecx
167 popl %ebx
sewardj2e93c502002-04-12 11:12:52 +0000168 ret
169
170
171
172/* Other ways of getting out of the inner loop. Placed out-of-line to
173 make it look cleaner.
174*/
175dispatch_exceptional:
176 # this is jumped to only, not fallen-through from above
177 cmpl $VG_TRC_EBP_JMP_SPECIAL, %ebp
178 jz dispatch_callret_maybe
179 cmpl $VG_TRC_EBP_JMP_SYSCALL, %ebp
180 jz dispatch_syscall
181 cmpl $VG_TRC_EBP_JMP_CLIENTREQ, %ebp
182 jz dispatch_clientreq
183
184 # ebp has an invalid value ... crap out.
185 pushl $panic_msg_ebp
186 call VG_(panic)
187 # (never returns)
188
189dispatch_syscall:
190 # save %eax in %EIP and defer to sched
191 movl $VG_(baseBlock), %ebp
192 movl VGOFF_(m_eip), %esi
193 movl %eax, (%ebp, %esi, 4)
194 movl $VG_TRC_EBP_JMP_SYSCALL, %eax
195 jmp run_innerloop_exit
sewardjde4a1d02002-03-22 01:27:54 +0000196
sewardj2e93c502002-04-12 11:12:52 +0000197dispatch_clientreq:
198 # save %eax in %EIP and defer to sched
199 movl $VG_(baseBlock), %ebp
200 movl VGOFF_(m_eip), %esi
201 movl %eax, (%ebp, %esi, 4)
202 movl $VG_TRC_EBP_JMP_CLIENTREQ, %eax
203 jmp run_innerloop_exit
204
205dispatch_callret_maybe:
206 # save %eax in %EIP
207 movl $VG_(baseBlock), %ebp
208 movl VGOFF_(m_eip), %esi
209 movl %eax, (%ebp, %esi, 4)
210
211 # see if we need to mess with stack blocks
212 pushl %eax
213 call VG_(delete_client_stack_blocks_following_ESP_change)
214 popl %eax
215 movl $VG_(baseBlock), %ebp
216
217 # is this a call/return which we need to mess with
218 cmpl $VG_(signalreturn_bogusRA), %eax
219 jz dispatch_callret
220 cmpl $VG_(shutdown), %eax
221 jz dispatch_callret
222
223 # ok, its not interesting. Handle the normal way.
224 jmp dispatch_boring
225
226dispatch_callret:
227 # %EIP is up to date here since dispatch_callret_maybe dominates
228 movl $VG_TRC_EBP_JMP_SPECIAL, %eax
229 jmp run_innerloop_exit
230
231
232.data
233panic_msg_ebp:
234.ascii "vg_dispatch: %ebp has invalid value!"
235.byte 0
236.text
237
sewardjde4a1d02002-03-22 01:27:54 +0000238
239##--------------------------------------------------------------------##
240##--- end vg_dispatch.S ---##
241##--------------------------------------------------------------------##