On Wed, May 16, 2018 at 04:04:00PM +0100, Mike Leach wrote:
[...]
- For the program flow from user space to kernel, it might be a system call or a trap, so the script reads ahead 16 instructions to check if includes 'svc' instruction or not. If the prediction includes 'svc' instruction the script prints out the flow until 'svc' instruction, otherwise it only prints the instruction which causes trap.
I do not see how this can be safe.
e.g. tracing a sequence (addresses simplified for illustration:)
0x1000: <instr_block....> 0x1080:
<instr_not_br> <irq> 0x1084: <instr_not_br> <instr_not_br> <instr_svc> <instr_block>
irq: 0x10001000:
<instr_block> 0x10001060: <eret>
svc: 0x20001000:
<instr_block> 0x20001100 <ret>
This will result in the following trace packets: TRACE_ON<context> RANGE<0x1000,0x1080, last instr type = not BR> // PE has executed this range EXCEPTION<IRQ, 0x1084> // PE takes an exception, preferred return address is 0x1084 RANGE<0x10001000,0x10001060, lst instr type = BR, taken> // run irq routine, take branch at end (eret) RETURN_FROM_EXCEPTION<> RANGE<0x1084,0x1088, last instr type = BR taken (svc)> RANGE<20001000,0x20001100, last instr type = br taken (ret)>
Best I can tell, looking at the current branch sample code in perf this results in:-
- first range is ignored as start of trace (no previous packet + taken branch)
- second range would not result in a branch either - previous packet
did not have a taken branch at the end. 3) 3rd range would result in some branch from 0x10001060 to 0x1084
I need to take time to read code to match with this issue, but I did see some suspicious lost packets from disassembler flow.
That is what I would expect in the currnent situation.
Thanks a lot for your explanation, Rob & Mike.
Furthermore, should the instruction @ 0x1080 be a branch that was taken, then the disassembler look-ahead heuristic above would still fail as the exeception is missed in favour of the svc which has not been hit yet,.
Sorry, I don't understand for this point. Could you rephrase for this?
Certainly. reading your script it appears that at present you are detecting a change from application to kernel by a change in dso. You are then idsassembling 16 instructions and trying to see if an SVC instruction is present - if it is you assume that it is the cause of the change. Otherwise you assume a trap/interrupt. This is unsafe. You could have a case where an interrupt occurs before a block containing multiple SVC instructions. You are also assuming that the SVC you find is actually being taken.
Now understand and agree the svc prediction in my code is unsafe.
What appears to be happening is that you are trying to make up for the missing information by applying some algorithm to estimate the reason for the change.
There should be no need to do this - ETM trace has all the information that you need to create accurate trace disassembly. What is needed is code in perf to ensure that this is correctly passed though to the synthesized events processed by the script engine.
Yes, I did experiment to dump the packet info in function cs_etm_decoder__gen_trace_elem_printer() and all packets can be parsed in this function. But as you two suggested, the packet for start tracing and exception packet have been ignored in the function cs_etm__sample() so these packets will _not_ be passed to python script.
When this occurs two things can happen:
- you will be able to simplify your scripts - removing the estimating
algorithm etc. 2) they should then work extremely well in generating accurate trace disassembly.
Totally agree.
I did very little tweaking in the function cs_etm__sample() and now the python script can receive start packet and exception packet, so we can remove the estimating related code in python script.
Will send out new patch series soon for reviewing in today. Please review and if you have better idea for related fixing, I am very glad to test it and use your patch :) I am not sure my fixing can cover all cases.
Thanks a lot for suggestions.
[...]
Thanks, Leo Yan