Memory write tracing/logging of an application / Watchpoints in Genode/Fiasco.OC
Josef Stark
j.stark at ...256...
Mon Mar 12 18:19:43 CET 2018
Hi Martin,
On 02/28/2018 04:02 PM, Martin Stein wrote:
> Hi Josef,
> [...]
> First, I would look at the assembly context at 0x1001bb0 especially what
> is done with R1/R9 in the subsequent instructions. You might also play
> around with explicit register assignment:
>
> register unsigned my_var asm("r1") = n;
>
> or inline assembler to get a better understanding what you're actually
> doing wrong in the perspective of the client.
>
> Maybe the client returns from emulation with a bad IP which you could
> check by adding an assembler instruction with an observable side effect
> directly behind the LDR (or using a debugger).
>
> You could even write an inline assembler snippet that writes the whole
> GPR state after the LDR to RAM when running without emulation. This way,
> you can compare the GPR states of the emulation case (inside observer)
> and the non-emulation case.
I experimented a bit and after comparing the actual register contents of
R0-R15 inside the child application with the contents of the
Thread_state register backup (R0-R15) that is delivered to my fault
handler, it seems like Genode (or Fiasco.OC or the glue code) delivers
the registers in a strange mapping, where some original regs are mapped
to different regs in the backup, and some do not appear at all. The
mapping is like this:
Thread_state | Child | Child - Alternative Possibility
---------------------------------------------------------
R0 | R9 | R7
R1 | R10 | R4
R2 | R11 |
R3 | |
R4 | |
R5 | |
R6 | |
R7 | |
R8 | R0 |
R9 | R1 |
R10 | R2 |
R11 | R3 |
R12 | R12 | R5
R13 | R13 |
R14 | R14 |
R15 | R15 |
| R6 |
| R8 |
(Alternative Possibility means I couldn't tell which of the two is
actually correct due to equal values. The Thread_state registers that
have no mapping contained values that did not match any of the original
register contents; some of those values appeared in two distinct
Thread_state registers. I assured myself that the child didn't modify
the registers before dumping the contents.)
While this looks pretty strange, I verified the 'mapping' on a few
occasions and after incorporating the mapping into the instruction
emulator/the redundant memory writer, it does what it should, at least
for a limited test case (which doesn't access one of the unmapped
registers).
I should mention that we use a slightly modified Fiasco.OC kernel and
kernel interface, since in the unmodified Genode 16.08/Fiasco.OC,
calling Cpu_thread_component::state() [1] internally calls
Platform_thread::state(), which does not return the contents of all
registers. Instead our modified Platform_thread::state() calls our own
method all_regs() [2] which does that. The modified Fiasco.OC kernel
source files are [3] and [4] with modifications marked with a comment
mentioning "rtcr". But no remapping or other strange things are done there.
My guess is that this register magic is not happening in the base-hw
version of Genode (since Vinit instruction emulation is not using any
remapping and still works), but maybe you still have a clue of what is
going on there.
Best regards,
Josef
[1] state() repos/base/src/core/cpu_thread_component.cc
[2] all_regs():
https://github.com/jmstark/cr-genode/blob/red_mem/repos/base-focnados/src/core/platform_thread.cc
[3]
https://github.com/argos-research/foc/blob/checkpointRestore/l4/pkg/l4sys/include/thread.h
[4]
https://github.com/argos-research/foc/blob/checkpointRestore/kernel/fiasco/src/kern/thread_object.cpp
More information about the users
mailing list