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