xscale: fix trace buffer functionality when resuming from a breakpoint
Problem: halt at a breakpoint, enable trace buffer ('xscale trace_buffer enable fill'), then resume. Wait for debug exception when trace buffer fills (if not sooner due to another breakpoint, vector catch, etc). Instead, never halts. When halted explicitly from OpenOCD and trace buffer dumped, it contains only one entry; a branch to the address of the original breakpoint. If the above steps are repeated, except that the breakpoint is removed before resuming, the trace buffer fills and the debug exception is generated, as expected. Cause: related to how a breakpoint is stepped over on resume. The breakpoint is temporarily removed, and a hardware breakpoint is set on the next instruction that will execute. xscale_debug_entry() is called when that breakpoint hits. This function checks if the trace buffer is enabled, and if so reads the trace buffer from the target and then disables the trace (unless multiple trace buffers are specified by the user when trace is enabled). Thus you only trace one instruction before it is disabled. Solution: kind of a hack on top of a hack, but it's simple. Anything better would involve some refactoring. This has been tested and trace now works as intended, except that the very first instruction is not part of the trace when resuming from a breakpoint. TODO: still many issues with trace: doesn't work during single-stepping (trace buffer is flushed each step), 'xscale analyze_trace' works only marginally for a trace captured in 'fill' mode, and not at all for a trace captured in 'wrap' mode. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>__archive__
parent
d60ebc0ab5
commit
33e5dd1272
|
@ -1206,6 +1206,7 @@ static int xscale_resume(struct target *target, int current,
|
|||
if (breakpoint != NULL)
|
||||
{
|
||||
uint32_t next_pc;
|
||||
int saved_trace_buffer_enabled;
|
||||
|
||||
/* there's a breakpoint at the current PC, we have to step over it */
|
||||
LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address);
|
||||
|
@ -1225,15 +1226,8 @@ static int xscale_resume(struct target *target, int current,
|
|||
/* restore banked registers */
|
||||
retval = xscale_restore_banked(target);
|
||||
|
||||
/* send resume request (command 0x30 or 0x31)
|
||||
* clean the trace buffer if it is to be enabled (0x62) */
|
||||
if (xscale->trace.buffer_enabled)
|
||||
{
|
||||
xscale_send_u32(target, 0x62);
|
||||
xscale_send_u32(target, 0x31);
|
||||
}
|
||||
else
|
||||
xscale_send_u32(target, 0x30);
|
||||
/* send resume request */
|
||||
xscale_send_u32(target, 0x30);
|
||||
|
||||
/* send CPSR */
|
||||
xscale_send_u32(target,
|
||||
|
@ -1254,9 +1248,16 @@ static int xscale_resume(struct target *target, int current,
|
|||
LOG_DEBUG("writing PC with value 0x%8.8" PRIx32,
|
||||
buf_get_u32(armv4_5->pc->value, 0, 32));
|
||||
|
||||
/* disable trace data collection in xscale_debug_entry() */
|
||||
saved_trace_buffer_enabled = xscale->trace.buffer_enabled;
|
||||
xscale->trace.buffer_enabled = 0;
|
||||
|
||||
/* wait for and process debug entry */
|
||||
xscale_debug_entry(target);
|
||||
|
||||
/* re-enable trace buffer, if enabled previously */
|
||||
xscale->trace.buffer_enabled = saved_trace_buffer_enabled;
|
||||
|
||||
LOG_DEBUG("disable single-step");
|
||||
xscale_disable_single_step(target);
|
||||
|
||||
|
@ -1276,6 +1277,12 @@ static int xscale_resume(struct target *target, int current,
|
|||
* clean the trace buffer if it is to be enabled (0x62) */
|
||||
if (xscale->trace.buffer_enabled)
|
||||
{
|
||||
/* if trace buffer is set to 'fill' mode, save starting pc */
|
||||
if (xscale->trace.buffer_fill > 0)
|
||||
{
|
||||
xscale->trace.pc_ok = 1;
|
||||
xscale->trace.current_pc = buf_get_u32(armv4_5->pc->value, 0, 32);
|
||||
}
|
||||
xscale_send_u32(target, 0x62);
|
||||
xscale_send_u32(target, 0x31);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue