blob: f8bfaf98035c1138bb690558b354655812e83df0 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
njnc9539842002-10-02 13:26:35 +00002##--------------------------------------------------------------------##
3##--- The core dispatch loop, for jumping to a code address. ---##
4##--- vg_dispatch.S ---##
5##--------------------------------------------------------------------##
sewardjde4a1d02002-03-22 01:27:54 +00006
7/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +000010
njn0e1b5142003-04-15 14:58:06 +000011 Copyright (C) 2000-2003 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000012 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
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
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
32#include "vg_constants.h"
33
34
35/*------------------------------------------------------------*/
36/*--- The normal-case dispatch machinery. ---*/
37/*------------------------------------------------------------*/
38
39/* To transfer to an (original) code address, load it into %eax and
40 jump to vg_dispatch. This fragment of code tries to find the
41 address of the corresponding translation by searching the translation
42 table. If it fails, a new translation is made, added to the
43 translation table, and then jumped to. Almost all the hard
44 work is done by C routines; this code simply handles the
45 common case fast -- when the translation address is found in
46 the translation cache.
47
48 At entry, %eax is the only live (real-machine) register; the
49 entire simulated state is tidily saved in vg_m_state.
50*/
51
52
sewardj22854b92002-11-30 14:00:47 +000053#define TT_LOOKUP(reg, fail) \
54 movl %eax, reg; \
55 andl $VG_TT_FAST_MASK, reg; \
56 movl VG_(tt_fast)(,reg,4), reg; \
57 cmpl %eax, (reg); \
58 jnz fail
59
sewardjde4a1d02002-03-22 01:27:54 +000060/* The C world needs a way to get started simulating. So we provide
61 a function void vg_run_innerloop ( void ), which starts running
62 from vg_m_eip, and exits when the counter reaches zero. This loop
63 can also exit if vg_oursignalhandler() catches a non-resumable
64 signal, for example SIGSEGV. It then longjmp()s back past here.
65*/
sewardj22854b92002-11-30 14:00:47 +000066
sewardjde4a1d02002-03-22 01:27:54 +000067.globl VG_(run_innerloop)
68VG_(run_innerloop):
njn25e49d8e72002-09-23 09:36:25 +000069 /* OYNK(1000) */
sewardj2e93c502002-04-12 11:12:52 +000070
njn25e49d8e72002-09-23 09:36:25 +000071 /* ----- entry point to VG_(run_innerloop) ----- */
sewardj2e93c502002-04-12 11:12:52 +000072 pushl %ebx
73 pushl %ecx
74 pushl %edx
75 pushl %esi
76 pushl %edi
77 pushl %ebp
78
fitzhardinge98abfc72003-12-16 02:05:15 +000079 /* check to see if we're doing pointer checking */
80 movl VG_(clo_pointercheck), %eax
81 testl %eax,%eax
82 jz 1f
83
84 pushl %fs /* save %fs */
85 mov $(VG_POINTERCHECK_SEGIDX << 3) + 7, %eax /* load new %fs */
86 movw %ax,%fs
87
881:
njn25e49d8e72002-09-23 09:36:25 +000089 /* Set up the baseBlock pointer */
sewardjde4a1d02002-03-22 01:27:54 +000090 movl $VG_(baseBlock), %ebp
91
njn25e49d8e72002-09-23 09:36:25 +000092 /* fetch m_eip into %eax */
sewardjde4a1d02002-03-22 01:27:54 +000093 movl VGOFF_(m_eip), %esi
94 movl (%ebp, %esi, 4), %eax
95
sewardj2e93c502002-04-12 11:12:52 +000096dispatch_main:
njn25e49d8e72002-09-23 09:36:25 +000097 /* Jump here to do a new dispatch.
98 %eax holds destination (original) address.
99 %ebp indicates further details of the control transfer
100 requested to the address in %eax.
sewardj2e93c502002-04-12 11:12:52 +0000101
njn25e49d8e72002-09-23 09:36:25 +0000102 If ebp == & VG_(baseBlock), just jump next to %eax.
103
104 If ebp == VG_EBP_JMP_SYSCALL, do a system call before
105 continuing at eax.
106
107 If ebp == VG_EBP_JMP_CLIENTREQ, do a client request before
108 continuing at eax.
109
110 If %ebp has any other value, we panic.
111 */
112 cmpl $VG_(baseBlock), %ebp
113 jnz dispatch_exceptional
114 /* fall into main loop */
115
116
117dispatch_boring:
118 /* save the jump address at VG_(baseBlock)[VGOFF_(m_eip)] */
119 movl VGOFF_(m_eip), %esi
120 movl %eax, (%ebp, %esi, 4)
sewardj6c3769f2002-11-29 01:02:45 +0000121
njn25e49d8e72002-09-23 09:36:25 +0000122 /* Are we out of timeslice? If yes, defer to scheduler. */
sewardj22854b92002-11-30 14:00:47 +0000123 cmpl $0, VG_(dispatch_ctr)
sewardjde4a1d02002-03-22 01:27:54 +0000124 jz counter_is_zero
njn25e49d8e72002-09-23 09:36:25 +0000125 /* try a fast lookup in the translation cache */
sewardj22854b92002-11-30 14:00:47 +0000126 TT_LOOKUP(%ebx, fast_lookup_failed)
sewardj6c3769f2002-11-29 01:02:45 +0000127
sewardj22854b92002-11-30 14:00:47 +0000128 /* Found a match. Call the tce.payload field (+VG_CODE_OFFSET) */
129 addl $VG_CODE_OFFSET, %ebx
130 incl VG_(unchained_jumps_done) /* update stats */
sewardj6c3769f2002-11-29 01:02:45 +0000131 call *%ebx
132
njn25e49d8e72002-09-23 09:36:25 +0000133 cmpl $VG_(baseBlock), %ebp
134 jz dispatch_boring
135
136 jmp dispatch_exceptional
137
sewardjde4a1d02002-03-22 01:27:54 +0000138
sewardj2e93c502002-04-12 11:12:52 +0000139fast_lookup_failed:
njn25e49d8e72002-09-23 09:36:25 +0000140 /* %EIP is up to date here since dispatch_boring dominates */
sewardj2e93c502002-04-12 11:12:52 +0000141 movl $VG_TRC_INNER_FASTMISS, %eax
142 jmp run_innerloop_exit
sewardjde4a1d02002-03-22 01:27:54 +0000143
sewardjde4a1d02002-03-22 01:27:54 +0000144counter_is_zero:
njn25e49d8e72002-09-23 09:36:25 +0000145 /* %EIP is up to date here since dispatch_boring dominates */
sewardj2e93c502002-04-12 11:12:52 +0000146 movl $VG_TRC_INNER_COUNTERZERO, %eax
147 jmp run_innerloop_exit
sewardjde4a1d02002-03-22 01:27:54 +0000148
sewardj2e93c502002-04-12 11:12:52 +0000149run_innerloop_exit:
fitzhardinge98abfc72003-12-16 02:05:15 +0000150 movl VG_(clo_pointercheck), %ebx
151 testl %ebx,%ebx
152 jz 1f
153
154 /* restore %fs */
155 popl %fs
156
1571: popl %ebp
sewardjde4a1d02002-03-22 01:27:54 +0000158 popl %edi
159 popl %esi
160 popl %edx
161 popl %ecx
162 popl %ebx
sewardj2e93c502002-04-12 11:12:52 +0000163 ret
164
165
166
167/* Other ways of getting out of the inner loop. Placed out-of-line to
168 make it look cleaner.
169*/
170dispatch_exceptional:
njn25e49d8e72002-09-23 09:36:25 +0000171 /* this is jumped to only, not fallen-through from above */
sewardj2e93c502002-04-12 11:12:52 +0000172 cmpl $VG_TRC_EBP_JMP_SYSCALL, %ebp
173 jz dispatch_syscall
174 cmpl $VG_TRC_EBP_JMP_CLIENTREQ, %ebp
175 jz dispatch_clientreq
sewardj22854b92002-11-30 14:00:47 +0000176 cmpl $VG_TRC_INNER_COUNTERZERO, %ebp
177 jz counter_is_zero
178
njn25e49d8e72002-09-23 09:36:25 +0000179 /* ebp has an invalid value ... crap out. */
sewardj2e93c502002-04-12 11:12:52 +0000180 pushl $panic_msg_ebp
njne427a662002-10-02 11:08:25 +0000181 call VG_(core_panic)
njn25e49d8e72002-09-23 09:36:25 +0000182 /* (never returns) */
sewardj2e93c502002-04-12 11:12:52 +0000183
184dispatch_syscall:
njn25e49d8e72002-09-23 09:36:25 +0000185 /* save %eax in %EIP and defer to sched */
sewardj2e93c502002-04-12 11:12:52 +0000186 movl $VG_(baseBlock), %ebp
187 movl VGOFF_(m_eip), %esi
188 movl %eax, (%ebp, %esi, 4)
189 movl $VG_TRC_EBP_JMP_SYSCALL, %eax
190 jmp run_innerloop_exit
sewardjde4a1d02002-03-22 01:27:54 +0000191
sewardj2e93c502002-04-12 11:12:52 +0000192dispatch_clientreq:
njn25e49d8e72002-09-23 09:36:25 +0000193 /* save %eax in %EIP and defer to sched */
sewardj2e93c502002-04-12 11:12:52 +0000194 movl $VG_(baseBlock), %ebp
195 movl VGOFF_(m_eip), %esi
196 movl %eax, (%ebp, %esi, 4)
197 movl $VG_TRC_EBP_JMP_CLIENTREQ, %eax
198 jmp run_innerloop_exit
199
sewardj22854b92002-11-30 14:00:47 +0000200
sewardj83f11862002-12-01 02:07:08 +0000201/*
202 This is the translation chainer, our run-time linker, if you like.
203
204 VG_(patch_me) patches the call instruction in the jump site
205 with a jump to the generated code for the branch target. %eax
206 contains the original program's EIP - if we get a hit in
207 tt_fast, then the call is patched into a jump; otherwise it
208 simply drops back into the dispatch loop for normal
209 processing.
210
211 The callsite is expected to look like:
212 call VG_(patch_me)
213 it will be transformed into
214 jmp $TARGETADDR
215
216 The environment we're expecting on entry is:
217 %eax = branch target address (original code EIP)
218 *(%esp) = just after call
sewardj22854b92002-11-30 14:00:47 +0000219*/
220.globl VG_(patch_me)
221VG_(patch_me):
222 /* try a fast lookup in the translation cache */
223 TT_LOOKUP(%ebx, 1f)
224
225 /* Patch call instruction at callsite into a chained jmp */
226 popl %eax /* eax = just after (VG_PATCHME_CALLSZ byte) call */
227 addl $VG_CODE_OFFSET, %ebx /* ebx = target eip */
228 subl %eax, %ebx /* ebx = delta */
229 movb $0xE9, -(VG_PATCHME_CALLSZ-0)(%eax) /* 0xe9 = jmp */
230 movl %ebx, -(VG_PATCHME_CALLSZ-1)(%eax) /* store delta */
231 addl %eax, %ebx
232 incl VG_(bb_enchain_count) /* update stats */
233 jmp *%ebx /* jmp to dest */
234
235 /* tt_fast miss: return into main dispatch loop */
2361: addl $4, %esp /* remove our call address */
237 ret /* return into main dispatch loop above */
238
sewardj2e93c502002-04-12 11:12:52 +0000239.data
240panic_msg_ebp:
241.ascii "vg_dispatch: %ebp has invalid value!"
242.byte 0
243.text
244
sewardjde4a1d02002-03-22 01:27:54 +0000245
njnc9539842002-10-02 13:26:35 +0000246##--------------------------------------------------------------------##
247##--- end vg_dispatch.S ---##
248##--------------------------------------------------------------------##