• Hui Li's avatar
    LoongArch: Fix multiple hardware watchpoint issues · 3eb2a8b2
    Hui Li authored
    In the current code, if multiple hardware breakpoints/watchpoints in
    a user-space thread, some of them will not be triggered.
    
    When debugging the following code using gdb.
    
    lihui@bogon:~$ cat test.c
      #include <stdio.h>
      int a = 0;
      int main()
      {
        printf("start test\n");
        a = 1;
        printf("a = %d\n", a);
        printf("end test\n");
        return 0;
      }
    lihui@bogon:~$ gcc -g test.c -o test
    lihui@bogon:~$ gdb test
    ...
    (gdb) start
    ...
    Temporary breakpoint 1, main () at test.c:5
    5        printf("start test\n");
    (gdb) watch a
    Hardware watchpoint 2: a
    (gdb) hbreak 8
    Hardware assisted breakpoint 3 at 0x1200006ec: file test.c, line 8.
    (gdb) c
    Continuing.
    start test
    a = 1
    
    Breakpoint 3, main () at test.c:8
    8        printf("end test\n");
    ...
    
    The first hardware watchpoint is not triggered, the root causes are:
    
    1. In hw_breakpoint_control(), The FWPnCFG1.2.4/MWPnCFG1.2.4 register
       settings are not distinguished. They should be set based on hardware
       watchpoint functions (fetch or load/store operations).
    
    2. In breakpoint_handler() and watchpoint_handler(), it doesn't identify
       which watchpoint is triggered. So, all watchpoint-related perf_event
       callbacks are called and siginfo is sent to the user space. This will
       cause user-space unable to determine which watchpoint is triggered.
       The kernel need to identity which watchpoint is triggered via MWPS/
       FWPS registers, and then call the corresponding perf event callbacks
       to report siginfo to the user-space.
    
    Modify the relevant code to solve above issues.
    
    All changes according to the LoongArch Reference Manual:
    https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#control-and-status-registers-related-to-watchpoints
    
    With this patch:
    
    lihui@bogon:~$ gdb test
    ...
    (gdb) start
    ...
    Temporary breakpoint 1, main () at test.c:5
    5        printf("start test\n");
    (gdb) watch a
    Hardware watchpoint 2: a
    (gdb) hbreak 8
    Hardware assisted breakpoint 3 at 0x1200006ec: file test.c, line 8.
    (gdb) c
    Continuing.
    start test
    
    Hardware watchpoint 2: a
    
    Old value = 0
    New value = 1
    main () at test.c:7
    7        printf("a = %d\n", a);
    (gdb) c
    Continuing.
    a = 1
    
    Breakpoint 3, main () at test.c:8
    8        printf("end test\n");
    (gdb) c
    Continuing.
    end test
    [Inferior 1 (process 778) exited normally]
    
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarHui Li <lihui@loongson.cn>
    Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
    3eb2a8b2
hw_breakpoint.c 13.5 KB