mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2025-11-19 07:13:20 +00:00
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: Hui Li <lihui@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
|
||
|---|---|---|
| .. | ||
| .gitignore | ||
| access-helper.h | ||
| acpi.c | ||
| alternative.c | ||
| asm-offsets.c | ||
| cacheinfo.c | ||
| cpu-probe.c | ||
| crash_dump.c | ||
| dma.c | ||
| efi-header.S | ||
| efi.c | ||
| elf.c | ||
| entry.S | ||
| env.c | ||
| fpu.S | ||
| ftrace_dyn.c | ||
| ftrace.c | ||
| genex.S | ||
| head.S | ||
| hw_breakpoint.c | ||
| idle.c | ||
| image-vars.h | ||
| inst.c | ||
| io.c | ||
| irq.c | ||
| jump_label.c | ||
| kfpu.c | ||
| kgdb.c | ||
| kprobes.c | ||
| lbt.S | ||
| machine_kexec.c | ||
| Makefile | ||
| mcount_dyn.S | ||
| mcount.S | ||
| mem.c | ||
| module-sections.c | ||
| module.c | ||
| numa.c | ||
| paravirt.c | ||
| perf_event.c | ||
| perf_regs.c | ||
| proc.c | ||
| process.c | ||
| ptrace.c | ||
| relocate_kernel.S | ||
| relocate.c | ||
| reset.c | ||
| rethook_trampoline.S | ||
| rethook.c | ||
| rethook.h | ||
| setup.c | ||
| signal.c | ||
| smp.c | ||
| stacktrace.c | ||
| switch.S | ||
| syscall.c | ||
| sysrq.c | ||
| time.c | ||
| topology.c | ||
| traps.c | ||
| unaligned.c | ||
| unwind_guess.c | ||
| unwind_orc.c | ||
| unwind_prologue.c | ||
| unwind.c | ||
| uprobes.c | ||
| vdso.c | ||
| vmlinux.lds.S | ||