diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0bd86ee26d..0b3ba3c785 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2019-03-28 Sandra Loosemore + + * nios2-tdep.h (struct gdbarch_tdep): Add is_kernel_helper. + * nios2-tdep.c (nios2_get_next_pc): Skip over kernel helpers. + * nios2-linux-tdep.c (nios2_linux_is_kernel_helper): New. + (nios2_linux_init_abi): Install it. + 2019-03-28 Alan Hayward * aarch64-tdep.c (aarch64_vnv_type): Use vector types. diff --git a/gdb/nios2-linux-tdep.c b/gdb/nios2-linux-tdep.c index e4482d73f0..2d38e603c0 100644 --- a/gdb/nios2-linux-tdep.c +++ b/gdb/nios2-linux-tdep.c @@ -200,6 +200,17 @@ nios2_linux_syscall_next_pc (struct frame_info *frame, return pc + op->size; } +/* Return true if PC is a kernel helper, a function mapped by the kernel + into user space on an unwritable page. Currently the only such function + is __kuser_cmpxchg at 0x1004. See arch/nios2/kernel/entry.S in the Linux + kernel sources and sysdeps/unix/sysv/linux/nios2/atomic-machine.h in + GLIBC. */ +static bool +nios2_linux_is_kernel_helper (CORE_ADDR pc) +{ + return pc == 0x1004; +} + /* Hook function for gdbarch_register_osabi. */ static void @@ -230,6 +241,7 @@ nios2_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) &nios2_r1_linux_rt_sigreturn_tramp_frame); tdep->syscall_next_pc = nios2_linux_syscall_next_pc; + tdep->is_kernel_helper = nios2_linux_is_kernel_helper; /* Index of target address word in glibc jmp_buf. */ tdep->jb_pc = 10; diff --git a/gdb/nios2-tdep.c b/gdb/nios2-tdep.c index ee45db98af..0866454113 100644 --- a/gdb/nios2-tdep.c +++ b/gdb/nios2-tdep.c @@ -2169,13 +2169,32 @@ nios2_get_next_pc (struct regcache *regcache, CORE_ADDR pc) } } - else if (nios2_match_jmpi (insn, op, mach, &uimm) - || nios2_match_calli (insn, op, mach, &uimm)) + else if (nios2_match_jmpi (insn, op, mach, &uimm)) pc = (pc & 0xf0000000) | uimm; + else if (nios2_match_calli (insn, op, mach, &uimm)) + { + CORE_ADDR callto = (pc & 0xf0000000) | uimm; + if (tdep->is_kernel_helper != NULL + && tdep->is_kernel_helper (callto)) + /* Step over call to kernel helper, which we cannot debug + from user space. */ + pc += op->size; + else + pc = callto; + } - else if (nios2_match_jmpr (insn, op, mach, &ra) - || nios2_match_callr (insn, op, mach, &ra)) + else if (nios2_match_jmpr (insn, op, mach, &ra)) pc = regcache_raw_get_unsigned (regcache, ra); + else if (nios2_match_callr (insn, op, mach, &ra)) + { + CORE_ADDR callto = regcache_raw_get_unsigned (regcache, ra); + if (tdep->is_kernel_helper != NULL + && tdep->is_kernel_helper (callto)) + /* Step over call to kernel helper. */ + pc += op->size; + else + pc = callto; + } else if (nios2_match_ldwm (insn, op, mach, &uimm, &ra, &imm, &wb, &id, &ret) && ret) diff --git a/gdb/nios2-tdep.h b/gdb/nios2-tdep.h index a2f0163ac5..275dcd74ae 100644 --- a/gdb/nios2-tdep.h +++ b/gdb/nios2-tdep.h @@ -74,6 +74,9 @@ struct gdbarch_tdep CORE_ADDR (*syscall_next_pc) (struct frame_info *frame, const struct nios2_opcode *op); + /* Returns true if PC points to a kernel helper function. */ + bool (*is_kernel_helper) (CORE_ADDR pc); + /* Offset to PC value in jump buffer. If this is negative, longjmp support will be disabled. */ int jb_pc; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index ba97fc3925..9f0065b016 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-03-28 Sandra Loosemore + + * gdb.threads/watchpoint-fork.exp (test): Use large timeout + factor when no hardware watchpoint support. + 2019-03-28 Alan Hayward Pedro Alves diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork.exp b/gdb/testsuite/gdb.threads/watchpoint-fork.exp index 878f784b7e..49a6167ed1 100644 --- a/gdb/testsuite/gdb.threads/watchpoint-fork.exp +++ b/gdb/testsuite/gdb.threads/watchpoint-fork.exp @@ -39,6 +39,12 @@ proc test {type symbol} { if [target_info exists gdb,no_hardware_watchpoints] { # The software watchpoint functionality is in GDB an unrelated test. gdb_test_no_output "set can-use-hw-watchpoints 0" + # Software watchpoints can be quite slow on remote targets + # on this test because it ends up single-stepping through + # code to initialize dynamic libraries, etc. + set factor 20 + } else { + set factor 1 } gdb_test "show detach-on-fork" "Whether gdb will detach the child of a fork is on\\." @@ -63,19 +69,21 @@ proc test {type symbol} { gdb_breakpoint "mark_exit" - gdb_test "continue" \ - "reakpoint \[0-9\]+, marker.*" "hardware breakpoints work" - gdb_test "continue" \ - "atchpoint \[0-9\]+: var.*Old value = 0.*New value = 1.*forkoff *\\(1\\).*" "watchpoints work" - gdb_test "continue" \ - "reakpoint \[0-9\]+, marker.*" "breakpoint after the first fork" - gdb_test "continue" \ - "atchpoint \[0-9\]+: var.*Old value = 1.*New value = 2.*forkoff *\\(2\\).*" "watchpoint after the first fork" - gdb_test "continue" \ - "reakpoint \[0-9\]+, marker.*" "breakpoint after the second fork" - gdb_test "continue" \ - "atchpoint \[0-9\]+: var.*Old value = 2.*New value = 3.*mark_exit \\(\\);" "watchpoint after the second fork" - gdb_test "continue" "Continuing\\..*\r\n(Thread .* hit )?Breakpoint \[0-9\]+, mark_exit .*" "finish" + with_timeout_factor $factor { + gdb_test "continue" \ + "reakpoint \[0-9\]+, marker.*" "hardware breakpoints work" + gdb_test "continue" \ + "atchpoint \[0-9\]+: var.*Old value = 0.*New value = 1.*forkoff *\\(1\\).*" "watchpoints work" + gdb_test "continue" \ + "reakpoint \[0-9\]+, marker.*" "breakpoint after the first fork" + gdb_test "continue" \ + "atchpoint \[0-9\]+: var.*Old value = 1.*New value = 2.*forkoff *\\(2\\).*" "watchpoint after the first fork" + gdb_test "continue" \ + "reakpoint \[0-9\]+, marker.*" "breakpoint after the second fork" + gdb_test "continue" \ + "atchpoint \[0-9\]+: var.*Old value = 2.*New value = 3.*mark_exit \\(\\);" "watchpoint after the second fork" + gdb_test "continue" "Continuing\\..*\r\n(Thread .* hit )?Breakpoint \[0-9\]+, mark_exit .*" "finish" + } } # threads