Re: GDB: etm traces decoding and breakpoints for arm targets

2020-11-03 Thread Zied Guermazi

hi

Thanks Mike for your support, it was very helpful.

to put everything together, on arm, gdb inserts a sw breakpoint by 
patching the code with an undefined instruction ( see comments in  
arm-tdep.c line7687) when a breakpoint is hit, an exception number 9 
"Undefined Instruction exception" is raised and a branch packet with 
this info is generated in etm traces, the trap is get handled by the 
kernel and it sends the appropriate signal to gdb process.


when the user continues the execution, gdb patches back the code and 
executes the instruction. this leads to the instruction traced twice 
with an exception in between, the same happens for next executed instruction


here is the log of decoded packets

[btrace] [ftrace] update insn: fun = main, file = 
./function_call_history.c, level = 0, insn = [1; 2)
cs_etm_decoder_trace_element_callback: elem->elem_type 
OCSD_GEN_TRC_ELEM_INSTR_RANGE */<= first execution attempt that raises 
an undefined instruction exception/*

trace_chan_id: 18
isa: CS_ETM_ISA_T32
start addr = 0x400534
end addr   = 0x400536
instructions count = 1
last_i_type: OCSD_INSTR_OTHER
last_i_subtype: OCSD_S_INSTR_NONE
last instruction was executed
last instruction size: 2
[btrace] [ftrace] update insn: fun = main, file = 
./function_call_history.c, level = 0, insn = [1; 3)
cs_etm_decoder_trace_element_callback: elem->elem_type 
OCSD_GEN_TRC_ELEM_EXCEPTION */<= the exception is traced/*

trace_chan_id: 18
exception number: 9 */<= undefined instruction exception/*
cs_etm_decoder_trace_element_callback: elem->elem_type 
OCSD_GEN_TRC_ELEM_TRACE_ON
cs_etm_decoder_trace_element_callback: elem->elem_type 
OCSD_GEN_TRC_ELEM_PE_CONTEXT
cs_etm_decoder_trace_element_callback: elem->elem_type 
OCSD_GEN_TRC_ELEM_INSTR_RANGE */<= execution of the original instruction/*

trace_chan_id: 18
isa: CS_ETM_ISA_T32
start addr = 0x400534
end addr   = 0x400536
instructions count = 1
last_i_type: OCSD_INSTR_OTHER
last_i_subtype: OCSD_S_INSTR_NONE
last instruction was executed
last instruction size: 2

as the code was changed during execution, it can not be reconstructed 
during traces decoding.


in addition, and for tracing applications running on Linux, we are not 
interested in capturing raised exceptions, we can consider rolling back 
last instruction in ftraces. As this is not obvious, we can consider 
ignoring the repeated instruction as a workaround.


for tracing bare metal software, we need to keep tracing exception, so 
we can have a flag for ignoring exceptions, and activate or dis-activate 
it according to the context.


what do you think about it, shall I go for implementing it as described 
above?



Kind Regards

Zied Guermazi


On 02.11.20 12:59, Mike Leach wrote:

Hi Zeid,

On Sat, 31 Oct 2020 at 23:11, Zied Guermazi  wrote:

hi,

while testing the implementation in gdb of branch tracing on arm
processors using etm, I faced the the situation where a breakpoint was
set, was hit and then the execution of the program was continued.  While
decoding generated traces,  I got the address of the breakpoint
(0x400552) executed twice, and then the following address (0x400554)
also executed twice. the instruction at (0x400554) is a BL ( a function
call) and the second execution corrupts the function history.

here is a dump of generated trace elements


-
trace_chan_id: 18
isa: CS_ETM_ISA_T32
start addr = 0x400552
end addr   = 0x400554
instructions count = 1
last_i_type: OCSD_INSTR_OTHER
last_i_subtype: OCSD_S_INSTR_NONE
last instruction was executed
last instruction size: 2
-
trace_chan_id: 18
isa: CS_ETM_ISA_T32
start addr = 0x400552
end addr   = 0x400554
instructions count = 1
last_i_type: OCSD_INSTR_OTHER
last_i_subtype: OCSD_S_INSTR_NONE
last instruction was executed
last instruction size: 2
-
trace_chan_id: 18
isa: CS_ETM_ISA_T32
start addr = 0x400554
end addr   = 0x400558
instructions count = 1
last_i_type: OCSD_INSTR_BR
last_i_subtype: OCSD_S_INSTR_BR_LINK
last instruction was executed
last instruction size: 4
-
trace_chan_id: 18
isa: CS_ETM_ISA_T32
start addr = 0x400554
end addr   = 0x400558
instructions count = 1
last_i_type: OCSD_INSTR_BR
last_i_subtype: OCSD_S_INSTR_BR_LINK
last instruction was executed
last instruction size: 4

the explanation I have for this behavior is that :

-when setting the software breakpoint, the memory content of the
instruction (at 0x400552) was altered to the instruction BKPT,

-when the breakpoint was hit, the original opcode was set at (0x400552)
and a BKPT was set to the next instruction address (0x400554), then the
execution was continued

-when the second breakpoint (0x400554) was hit, the a BKPT opcode was
set at (0x400552) and the original opcode was set at (0x400554) then the
execution was continued

I am using the function "int target_read_code (CORE_ADDR memaddr,
gdb_byte *myaddr, ssize_t len)" to give program memory content to 

Re: GDB: etm traces decoding and breakpoints for arm targets

2020-11-03 Thread Mike Leach
Hi Zied,

On Mon, 2 Nov 2020 at 15:52, Zied Guermazi  wrote:
>
> hi
>
> Thanks Mike for your support, it was very helpful.
>
> to put everything together, on arm, gdb inserts a sw breakpoint by patching 
> the code with an undefined instruction ( see comments in  arm-tdep.c 
> line7687) when a breakpoint is hit, an exception number 9 "Undefined 
> Instruction exception" is raised and a branch packet with this info is 
> generated in etm traces, the trap is get handled by the kernel and it sends 
> the appropriate signal to gdb process.
>

Looks like that code was designed for very early architectures. I
wonder if it should not use the architected BKPT instruction when
available (arch v5T onwards I think).

> when the user continues the execution, gdb patches back the code and executes 
> the instruction. this leads to the instruction traced twice with an exception 
> in between, the same happens for next executed instruction
>
> here is the log of decoded packets
>
> [btrace] [ftrace] update insn: fun = main, file = ./function_call_history.c, 
> level = 0, insn = [1; 2)
> cs_etm_decoder_trace_element_callback: elem->elem_type 
> OCSD_GEN_TRC_ELEM_INSTR_RANGE <= first execution attempt that raises an 
> undefined instruction exception
> trace_chan_id: 18
> isa: CS_ETM_ISA_T32
> start addr = 0x400534
> end addr   = 0x400536
> instructions count = 1
> last_i_type: OCSD_INSTR_OTHER
> last_i_subtype: OCSD_S_INSTR_NONE
> last instruction was executed
> last instruction size: 2
> [btrace] [ftrace] update insn: fun = main, file = ./function_call_history.c, 
> level = 0, insn = [1; 3)
> cs_etm_decoder_trace_element_callback: elem->elem_type 
> OCSD_GEN_TRC_ELEM_EXCEPTION  <= the exception is traced
> trace_chan_id: 18
> exception number: 9 <= undefined instruction exception
> cs_etm_decoder_trace_element_callback: elem->elem_type 
> OCSD_GEN_TRC_ELEM_TRACE_ON
> cs_etm_decoder_trace_element_callback: elem->elem_type 
> OCSD_GEN_TRC_ELEM_PE_CONTEXT
> cs_etm_decoder_trace_element_callback: elem->elem_type 
> OCSD_GEN_TRC_ELEM_INSTR_RANGE <= execution of the original instruction
> trace_chan_id: 18
> isa: CS_ETM_ISA_T32
> start addr = 0x400534
> end addr   = 0x400536
> instructions count = 1
> last_i_type: OCSD_INSTR_OTHER
> last_i_subtype: OCSD_S_INSTR_NONE
> last instruction was executed
> last instruction size: 2
>
> as the code was changed during execution, it can not be reconstructed during 
> traces decoding.
>
> in addition, and for tracing applications running on Linux, we are not 
> interested in capturing raised exceptions, we can consider rolling back last 
> instruction in ftraces. As this is not obvious, we can consider ignoring the 
> repeated instruction as a workaround.
>
> for tracing bare metal software, we need to keep tracing exception, so we can 
> have a flag for ignoring exceptions, and activate or dis-activate it 
> according to the context.
>
> what do you think about it, shall I go for implementing it as described above?
>
>

I assume that in this scenario, trace collection is ongoing over the
BKPT hit / restart sequence and is decoded at some point later.
Otherwise spotting the breakpoint would be easy.

I cannot think of many circumstances where an instruction would be
executed  - or appear to be executed in the trace twice in succession*
- other than being restarted after an exception. This debug case is
one of those occasions - I would check that there are not other
exceptions that might mimic this.

Other than that it would appear that the execute / exception / execute
again pattern can be used to spot a break and the 1st execute could be
dropped since this was the breakpoint. If it was set on a conditional
then you are interested in the actual trace result which could be
either executed or not.

Regards

Mike

* branch to self might appear like this, as would setting the trace
address filters to a include just single instruction - but there would
be no intervening exceptions in these cases.

> Kind Regards
>
> Zied Guermazi
>
>
>
> On 02.11.20 12:59, Mike Leach wrote:
>
> Hi Zeid,
>
> On Sat, 31 Oct 2020 at 23:11, Zied Guermazi  wrote:
>
> hi,
>
> while testing the implementation in gdb of branch tracing on arm
> processors using etm, I faced the the situation where a breakpoint was
> set, was hit and then the execution of the program was continued.  While
> decoding generated traces,  I got the address of the breakpoint
> (0x400552) executed twice, and then the following address (0x400554)
> also executed twice. the instruction at (0x400554) is a BL ( a function
> call) and the second execution corrupts the function history.
>
> here is a dump of generated trace elements
>
>
> -
> trace_chan_id: 18
> isa: CS_ETM_ISA_T32
> start addr = 0x400552
> end addr   = 0x400554
> instructions count = 1
> last_i_type: OCSD_INSTR_OTHER
> last_i_subtype: OCSD_S_INSTR_NONE
> last instruction was executed
> last instruction size: 2
> -
> t