diff options
author | Yao Qi <yao.qi@linaro.org> | 2015-05-08 12:29:13 +0100 |
---|---|---|
committer | Yao Qi <yao.qi@linaro.org> | 2015-05-08 12:29:13 +0100 |
commit | 45614f153407762d83e8ecaf271b9b6e524c62db (patch) | |
tree | c27b88f6867a9ab54836df3232c2ec44567665b5 /gdb/gdbserver/server.c | |
parent | 2492f0d005f0390eabb3deb58aa7db7fcd716763 (diff) | |
download | gdb-45614f153407762d83e8ecaf271b9b6e524c62db.zip gdb-45614f153407762d83e8ecaf271b9b6e524c62db.tar.gz gdb-45614f153407762d83e8ecaf271b9b6e524c62db.tar.bz2 |
[gdbserver] Disable conditional breakpoints on no-hardware-single-step targets
GDBserver steps over breakpoint if the condition is false, but if target
doesn't support hardware single step, the step over is very simple, if
not incorrect, in linux-arm-low.c:
/* We only place breakpoints in empty marker functions, and thread locking
is outside of the function. So rather than importing software single-step,
we can just run until exit. */
static CORE_ADDR
arm_reinsert_addr (void)
{
struct regcache *regcache = get_thread_regcache (current_thread, 1);
unsigned long pc;
collect_register_by_name (regcache, "lr", &pc);
return pc;
}
and linux-mips-low.c does the same. GDBserver sets a breakpoint at the
return address of the current function, resume and wait the program hits
the breakpoint in order to achieve "breakpoint step over". What if
program hits other user breakponits during this "step over"?
It is worse if the arm/thumb interworking is considered. Nowadays,
GDBserver arm backend unconditionally inserts arm breakpoint,
/* Define an ARM-mode breakpoint; we only set breakpoints in the C
library, which is most likely to be ARM. If the kernel supports
clone events, we will never insert a breakpoint, so even a Thumb
C library will work; so will mixing EABI/non-EABI gdbserver and
application. */
(const unsigned char *) &arm_breakpoint,
(const unsigned char *) &arm_eabi_breakpoint,
note that the comments are no longer valid as C library can be compiled
in thumb mode.
When GDBserver steps over a breakpoint in arm mode function, which
returns to thumb mode, GDBserver will insert arm mode breakpoint by
mistake and the program will crash. GDBserver alone is unable to
determine the arm/thumb mode given a PC address. See how GDB does
it in arm-tdep.c:arm_pc_is_thumb.
After thinking about how to teach GDBserver inserting right breakpoint
(arm or thumb) for a while, I reconsider it from a different direction
that it may be unreasonable to run target-side conditional breakpoint for
targets without hardware single step. Pedro also pointed this out here
https://sourceware.org/ml/gdb-patches/2015-04/msg00337.html
This patch is to add a new target_ops hook
supports_conditional_breakpoints, and only reply
";ConditionalBreakpoints+" if it is true. On linux targets,
supports_conditional_breakpoints returns true if target has hardware
single step, on other targets, (win32, lynx, nto, spu), set it to NULL,
because conditional breakpoint is a linux-specific feature.
gdb/gdbserver:
2015-05-08 Yao Qi <yao.qi@linaro.org>
* linux-low.c (linux_supports_conditional_breakpoints): New
function.
(linux_target_ops): Install new target method.
* lynx-low.c (lynx_target_ops): Install NULL hook for
supports_conditional_breakpoints.
* nto-low.c (nto_target_ops): Likewise.
* spu-low.c (spu_target_ops): Likewise.
* win32-low.c (win32_target_ops): Likewise.
* server.c (handle_query): Check
target_supports_conditional_breakpoints.
* target.h (struct target_ops) <supports_conditional_breakpoints>:
New field.
(target_supports_conditional_breakpoints): New macro.
Diffstat (limited to 'gdb/gdbserver/server.c')
-rw-r--r-- | gdb/gdbserver/server.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 62287d4..3f9bb89 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -2107,7 +2107,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) } /* Support target-side breakpoint conditions and commands. */ - strcat (own_buf, ";ConditionalBreakpoints+"); + if (target_supports_conditional_breakpoints ()) + strcat (own_buf, ";ConditionalBreakpoints+"); strcat (own_buf, ";BreakpointCommands+"); if (target_supports_agent ()) |