|
From: Nicholas N. <nj...@ca...> - 2002-11-22 11:33:21
|
On Fri, 22 Nov 2002, Julian Seward wrote:
> I have thought of a way to get hold of %eip in helper fns, skin independently
> and without slowing down the normal I-don't-want-to-know-%eip case, but it has
> a high coefficient of horribleness [although is easy to implement].
>
> Basic idea is that we can probably find the return address for the call to the
> helper, lying round on the stack, without outside assistance.
>
> Suppose (as is indeed the case) that %EIP is brought up to date at the
> start of each bb. Now the bb calls a helper fn and you want to know
> what %eip is at the point of the call.
>
> So we're looking for a word on the stack (the RA) that points back into
> the translation. Since we have %EIP for the bb, we can look up in TT
> the location and size of the translation. The word we're looking for
> must have a value in the range: location .. location + size - 1.
> Furthermore, 6 (?) bytes before the word must also be a valid location in the
> translation -- the call insn -- and it must contain the opcode for "call".
> [...]
> Actually I'd guess it's pretty robust, if the above analysis is correct.
Wow. I think it's the sort of idea that if I'd thought of it I would
think it was really cool and worth doing, but because someone else thought
of it I take two steps back and think hmm...
----
Ideally, we want these characteristics:
1a. simple idea
1b. simple effect on existing code (eg. affects only one place)
2. entirely skin-independent
3. maximally efficient, ie. only updates EIP when EIP is actually
recorded (I'm assuming we update EIP between BBs, though)
4. no extra space required
Your suggestion, assuming it works effectively, meets 2 and 3. It fails
1a; as for 1b, the finding-%eip complexity would all be in the one spot,
although it still needs the eip-to-EIP table.
----
Before you mentioned this finding-a-needle-in-a-call-stack idea, I was
leaning back towards the update-EIP-only-when-necessary approach.
%EIP only needs to be up-to-date for a small number of UInstrs:
a. CCALL/CALLM, if the called code records EIP
b. PUT %ESP, if stack change/post_mem_write events are tracked and the
called function records EIP
c. Any extended UInstr that records EIP
There are only two ways skin code can record EIP:
1. Call VG_(get_ExeContext)()
2. Call VG_(get_EIP)()
VG_(get_ExeContext)() could be changed so that it calls VG_(get_EIP)(),
which would essentially reduce the problem to a single point of code.
Using the latest ideas:
a. add a 1-bit field `records_eip' to CCALL and CALLM instructions that
a skin must turn on if the called code can record EIP
b. add a bool argument to the functions VG_(track_new_mem_stack)() etc,
which the skin makes `True' if the called code can record EIP
c. add another function that must be implemented by skins using extended
UCode, SK_(UInstr_record_EIP)()
a,b,c in this list correspond directly to a,b,c the list above.
(Actually, c could be handled by a's mechanism too.)
Any UInstr which could cause an EIP-record would have to be preceded with
a PUTEIP instruction (I agree that sounds better than INCEIP). Actually,
we could keep INCEIP instructions (necessary for determining x86
instruction boundaries), generate no code for them, and the codegen phase
could effectively add the PUTEIP code for UInstrs when the relevant
boolean is set without actually needing an explicit PUTEIP instruction.
This satisfies 1a and 4, isn't too bad for 1b, but fails the others. It
also makes the VG_(track_*) functions non-uniform, which is unfortunate.
----
So, I've criticised the flaws in the current proposals, but haven't come
up with anything better. Harumph.
----
A couple of other random thing that occurred to me:
i. If we do use an eip-to-EIP table, it doesn't need to record entries
for every instruction, just those that can cause an EIP-recording
(CCALL/CALLM/PUT ESP/extended UInstrs).
ii. None of this affects Cachegrind, since it records %eip for every x86
instruction in its cost-centre anyway. At one point I took out all
INCEIPs for Cachegrind, but then put them back in because of the
weird-signals-sometimes issue.
N
|