Re: [RFA/commit] arm-tdep.c: Do not single-step after hitting a watchpoint

Pedro Alves
2014-09-30T10:07:41Z

On 09/30/2014 10:18 AM, Will Deacon wrote:
> On Tue, Sep 30, 2014 at 10:08:09AM +0100, Pedro Alves wrote:
>> The report that confuses me is Gareth's:
>>
>> https://sourceware.org/ml/gdb/2014-09/msg00013.html
>>
>> As it sounds like he has v7-m hardware that has asynchronous
>> behavior. Gareth, can you confirm this, please?
>
> Running Linux or bare-metal? The hw_breakpoint code in the kernel certainly
> wasn't written with v7-m in mind and I'd be surprised if it even probed
> successfully at boot.

Judging from the black magic probes' description at:
http://www.blacksphere.co.nz/main/blackmagic, definitely bare-metal.

>
>> Still, in any case, from that LKML post:
>>
>> "v6 cores are the opposite; they only generate asynchronous
>> watchpoint exceptions".
>>
>> So, eh!? Does your qemu patch take this into account? Seems
>> like it should.
>
> Hmm, I didn't realise v6 was on the table here.

GDB supports that, and older. Doesn't qemu do v6?

> In that case, you need to signal an async exception and set the WFAR
> register to indicate the watchpointed instruction. Not that Linux uses this...

Yeah, even though Linux doesn't use this, this then must be what bare metal
probes and other OSs will necessarily be using to support watchpoints on < v7.

OK, then on v6 (and earlier), the WFAR will be (as Luis pointed out
elsewhere), from:

(ARM1156T2F-S, IIUC, that's a v6)
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0290g/Bhcdjdcg.html

WFAR - Watchpoint Fault Address Register

The WFAR is updated to indicate the address of the instruction that
accessed the watchpointed address:

- the address of the instruction + 8 in ARM state
- the address of the instruction + 4 in ThumbÂ® state

What wasn't clear to me was whether this meant that the
instruction at the address of the instruction, and
at the the address of the instruction +4/+2 (ARM/Thumb) had
executed completely or not. It's my understanding now that,
yes, both the instruction that caused the watchpoint and the
instruction after that one have already been executed.

I may be missing something, but that page leaves me wondering
what happens if the instruction after the instruction that caused
the watchpoint is a branch. Will the WFAR point still point
at "address + 8" ? Or will it point at the branch destination?

In any case, it sounds like _nothing_ should be unwinding the PC
back -8 nor -4 to help the debugger, as that would make the
program re-execute instructions that had already executed.

For further confirmation, I looked at the v6-m manual I have
handy (DDI 0419C). There, I see:

C1.5.2:

The following are asynchronous debug events:
- Watchpoint debug events, including PC match watchpoints

And then on C1.6.4

The DebugReturnAddress value

DebugReturnAddress is the address of the first instruction to be executed on exit from Debug state. This
address indicates the point in the execution stream where the debug event was invoked. For a hardware or
a software breakpoint, this is the address of the breakpointed instruction. For all other debug events,
including PC match watchpoints, DebugReturnAddress is the address of the first instruction that both:

- in a simple sequential execution of the program, executes after the instruction that caused the debug
event

- has not been executed.

And in C1.7.1

A watchpoint event is asynchronous to the instruction that caused it. The DebugReturnAddress value for a
watchpoint event must be that of an instruction to be executed after the instruction responsible for
generating the watchpoint.

This seems to confirm my current understanding that indeed that +8/+4 offset
in WFAR should _never_ be adjusted, as the instructions at +0 and +4/+2 have
already been executed.

So, my current understanding is that when debugging a < v7 target, GDB
should always treat watchpoints as continuable (asynchronous), as that's
all the hardware supports/supported.

And when debugging a >= v7 target, GDB should treat watchpoints as
synchronous as that's all real hardware supports (even though
the architecture permits both sync and async, in theory).

And if we do this in GDB, then it's be better that qemu likewise
treats watchpoints as asynchronous on < v7, so that GDB doesn't need to
know whether it's talking to real bare-metal and against qemu.

Does that make sense?

> The comment/code above is about finding the address of the memory access
> that triggered the watchpoint, as opposed to the address of the instruction.
> (e.g. if I load from address FOO, then I only get told about FOO in v7.1).

Understood.

Thanks,
Pedro Alves