<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Watchpoint in atomic sequences are not supported on arm"
   href="https://bugs.llvm.org/show_bug.cgi?id=35224">35224</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Watchpoint in atomic sequences are not supported on arm
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>lldb
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>unspecified
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>All Bugs
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>lldb-dev@lists.llvm.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>labath@google.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>This example probably illustrates is best:
(lldb) b main
Breakpoint 1: where = a.out`main + 8 at a.cc:4, address = 0x00000000000006a0
(lldb) pr la
Process 28313 launched: '/tmp/a.out' (aarch64)
Process 28313 stopped
* thread #1, name = 'a.out', stop reason = breakpoint 1.1
    frame #0: 0x00000055555556a0 a.out`main at a.cc:4
   1    #include <atomic>
   2    std::atomic<int> X(0);
   3    int main() {
-> 4      return X++;
   5    }
(lldb) watchpoint set variable X
Watchpoint created: Watchpoint 1: addr = 0x5555566008 size = 4 state = enabled
type = w
    declare @ '/tmp/a.cc:2'
    watchpoint spec = 'X'
(lldb) c
Process 28313 resuming

Watchpoint 1 hit:
Process 28313 stopped
* thread #1, name = 'a.out', stop reason = watchpoint 1
    frame #0: 0x00000055555556f4 a.out`std::__atomic_base<int>::operator++(int)
[inlined] std::__atomic_base<int>::fetch_add(__m=memory_order_seq_cst, __i=1,
this=0x0000005555566008) at atomic_base.h:621
   618        _GLIBCXX_ALWAYS_INLINE __int_type
   619        fetch_add(__int_type __i,
   620                  memory_order __m = memory_order_seq_cst) noexcept
-> 621        { return __atomic_fetch_add(&_M_i, __i, __m); }
   622  
   623        _GLIBCXX_ALWAYS_INLINE __int_type
   624        fetch_add(__int_type __i,
(lldb) disassemble -f
a.out`std::__atomic_base<int>::operator++:
    0x55555556bc <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x55555556c0 <+4>:  str    x0, [sp, #0x8]
    0x55555556c4 <+8>:  str    w1, [sp, #0x4]
    0x55555556c8 <+12>: ldr    x0, [sp, #0x8]
    0x55555556cc <+16>: str    x0, [sp, #0x18]
    0x55555556d0 <+20>: mov    w0, #0x1
    0x55555556d4 <+24>: str    w0, [sp, #0x14]
    0x55555556d8 <+28>: mov    w0, #0x5
    0x55555556dc <+32>: str    w0, [sp, #0x10]
    0x55555556e0 <+36>: ldr    x0, [sp, #0x18]
    0x55555556e4 <+40>: ldr    w1, [sp, #0x14]
    0x55555556e8 <+44>: ldaxr  w2, [x0]
    0x55555556ec <+48>: add    w3, w2, w1
    0x55555556f0 <+52>: stlxr  w4, w3, [x0]
->  0x55555556f4 <+56>: cbnz   w4, 0x55555556e8          ; <+44> [inlined]
std::__atomic_base<int>::fetch_add(int, std::memory_order) + 8 at
atomic_base.h:395
    0x55555556f8 <+60>: mov    w0, w2
    0x55555556fc <+64>: nop    
    0x5555555700 <+68>: add    sp, sp, #0x20             ; =0x20 
    0x5555555704 <+72>: ret    
(lldb) c
Process 28313 resuming

Watchpoint 1 hit:
Process 28313 stopped
* thread #1, name = 'a.out', stop reason = watchpoint 1
    frame #0: 0x00000055555556f4 a.out`std::__atomic_base<int>::operator++(int)
[inlined] std::__atomic_base<int>::fetch_add(__m=memory_order_seq_cst, __i=1,
this=0x0000005555566008) at atomic_base.h:621
   618        _GLIBCXX_ALWAYS_INLINE __int_type
   619        fetch_add(__int_type __i,
   620                  memory_order __m = memory_order_seq_cst) noexcept
-> 621        { return __atomic_fetch_add(&_M_i, __i, __m); }
   622  
   623        _GLIBCXX_ALWAYS_INLINE __int_type
   624        fetch_add(__int_type __i,


Even though we report the watchpoint as "hit" the first time, the data is not
actually written to memory because the act of hitting the watchpoint interrupts
the atomic block. Therefore, the inferior enters the atomic sequence again, and
the watchpoint is "hit" again, etc.

In fact the only way to make progress here is for the user to set a breakpoint
after the atomic loop, disable the watchpoint, resume the process, and then
re-enable the watchpoint (if he needs it) after the atomic block.

It would be interesting to try to help the user by automating these actions.
The tricky part would be making sure the atomic loop does not do something
fishy while we are letting it run freely, such as transferring control flow to
a place we're not expecting, or modifying the memory we did not expect it to.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are the assignee for the bug.</li>
      </ul>
    </body>
</html>