Memory write tracing/logging of an application / Watchpoints in Genode/Fiasco.OC

Martin Stein martin.stein at ...1...
Wed Feb 28 16:02:30 CET 2018


Hi Josef,

During the last weeks I was out of office which is why this answer is a
bit delayed.

El 26/02/18 a las 21:26, Josef Stark escribió:
> Hello,
> 
> I circumvented the problem of finding the correct dataspace by letting
> the pagefault handler open another ROM connection to the binary at its
> instantiation. The ELF file contains the VM address of the code section,
> which allows me to fetch the correct instruction when a pagefault
> happens.

As far as I can see a good idea for static clients. At least this spares
you the duplicated book keeping of guest attachments in your observer
component. However, with dynamic linking or JIT compilation, the
RM-inception approach might be the better choice.

> Then, I can use the instruction decoder (see Vinit @ [1]):
>> bool ldst = Instruction::load_store(instr, writes, state.format,
>>    state.reg);
>> size_t access_size = state.format == Region_map::LSB8 ? 1 :
>>    (state.format == Region_map::LSB16 ? 2 : 4);
> 
> With this information I should be able to emulate the instruction:
>> if(!writes) {
>>     state.value = 0;
>>     memcpy(&state.value,addr + state.addr,access_size);
>>     thread_state.set_gpr(state.reg,state.value);
>> }
>> else {
>>     thread_state.get_gpr(state.reg, state.value);
>>     memcpy(addr + state.addr,&state.value,access_size);
>> }
> (For set_gpr() and get_gpr() see Vinit @ [2])
> 
> I have a simple sample application that for now only reads repeatedly a
> memory value and prints it:
>> unsigned n = 0x12abcdefafter LDR between 
>> while(1) {
>>     log(n, " sheep");
>>     timer.msleep(1000);
>> }
> 
> I let this app run normally for a few seconds and then detach the
> dataspace to see if emulation is working... it isn't.
> 
> The register write - i.e. the simulated load (memory read) instruction -
> results in weird app behavior: The app outputs "0 sheep" - wrong number
> - without pausing 1 second. If I comment out the register write, it
> outputs the same but pauses 1 second like it should.
> The instruction decoder gives the following info (pf IP is 0x1001bb0):
>> instruction: e599116c, load, LSB32, reg: 1
> Which conforms with what objdump tells me:
>> 1001bb0:       e599116c        ldr     r1, [r9, #364]  ; 0x16c
> 
> Still, it doesn't work. By trial and error (going through all regs) I
> found out that writing to r9 instead of r1 (in the pf handler) gives me
> the desired behaviour: Printing the correct number and waiting 1 second.
> 
> But I have no idea why my code above doesn't work (and why r9 does). I
> know the target register number and write the value into it. Vinit also
> seems to do it like this: [3]
> Isn't this exactly what the processor would do?
> What could I be missing?

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.

Cheers,
Martin




More information about the users mailing list