X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Flinux-low.c;h=9558f46371664d5cd86a3ff8ed44b5229e70e867;hb=b90fc18880972f0c2ed280df20604d89f1d4ec38;hp=8bc73a473a565b230df1006eb34d8756a0dcf668;hpb=734b0e4bda4c56d0003182cdc3f5137d4bea00d4;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 8bc73a473a..9558f46371 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -357,13 +357,13 @@ linux_add_process (int pid, int attached) struct process_info *proc; proc = add_process (pid, attached); - proc->private = xcalloc (1, sizeof (*proc->private)); + proc->priv = xcalloc (1, sizeof (*proc->priv)); /* Set the arch when the first LWP stops. */ - proc->private->new_inferior = 1; + proc->priv->new_inferior = 1; if (the_low_target.new_process != NULL) - proc->private->arch_private = the_low_target.new_process (); + proc->priv->arch_private = the_low_target.new_process (); return proc; } @@ -493,6 +493,9 @@ check_stopped_by_breakpoint (struct lwp_info *lwp) CORE_ADDR pc; CORE_ADDR sw_breakpoint_pc; struct thread_info *saved_thread; +#if USE_SIGTRAP_SIGINFO + siginfo_t siginfo; +#endif if (the_low_target.get_pc == NULL) return 0; @@ -504,17 +507,59 @@ check_stopped_by_breakpoint (struct lwp_info *lwp) saved_thread = current_thread; current_thread = get_lwp_thread (lwp); +#if USE_SIGTRAP_SIGINFO + if (ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread), + (PTRACE_TYPE_ARG3) 0, &siginfo) == 0) + { + if (siginfo.si_signo == SIGTRAP) + { + if (siginfo.si_code == GDB_ARCH_TRAP_BRKPT) + { + if (debug_threads) + { + struct thread_info *thr = get_lwp_thread (lwp); + + debug_printf ("CSBB: Push back software breakpoint for %s\n", + target_pid_to_str (ptid_of (thr))); + } + + /* Back up the PC if necessary. */ + if (pc != sw_breakpoint_pc) + { + struct regcache *regcache + = get_thread_regcache (current_thread, 1); + (*the_low_target.set_pc) (regcache, sw_breakpoint_pc); + } + + lwp->stop_pc = sw_breakpoint_pc; + lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT; + current_thread = saved_thread; + return 1; + } + else if (siginfo.si_code == TRAP_HWBKPT) + { + if (debug_threads) + { + struct thread_info *thr = get_lwp_thread (lwp); + + debug_printf ("CSBB: Push back hardware " + "breakpoint/watchpoint for %s\n", + target_pid_to_str (ptid_of (thr))); + } + + lwp->stop_pc = pc; + lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT; + current_thread = saved_thread; + return 1; + } + } + } +#else /* We may have just stepped a breakpoint instruction. E.g., in non-stop mode, GDB first tells the thread A to step a range, and then the user inserts a breakpoint inside the range. In that - case, we need to report the breakpoint PC. But, when we're - trying to step past one of our own breakpoints, that happens to - have been placed on top of a permanent breakpoint instruction, we - shouldn't adjust the PC, otherwise the program would keep - trapping the permanent breakpoint forever. */ - if ((!lwp->stepping - || (!ptid_equal (ptid_of (current_thread), step_over_bkpt) - && lwp->stop_pc == sw_breakpoint_pc)) + case we need to report the breakpoint PC. */ + if ((!lwp->stepping || lwp->stop_pc == sw_breakpoint_pc) && (*the_low_target.breakpoint_at) (sw_breakpoint_pc)) { if (debug_threads) @@ -534,7 +579,7 @@ check_stopped_by_breakpoint (struct lwp_info *lwp) } lwp->stop_pc = sw_breakpoint_pc; - lwp->stop_reason = LWP_STOPPED_BY_SW_BREAKPOINT; + lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT; current_thread = saved_thread; return 1; } @@ -550,10 +595,11 @@ check_stopped_by_breakpoint (struct lwp_info *lwp) } lwp->stop_pc = pc; - lwp->stop_reason = LWP_STOPPED_BY_HW_BREAKPOINT; + lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT; current_thread = saved_thread; return 1; } +#endif current_thread = saved_thread; return 0; @@ -1173,10 +1219,10 @@ linux_mourn (struct process_info *process) find_inferior (&all_threads, delete_lwp_callback, process); /* Freeing all private data. */ - priv = process->private; + priv = process->priv; free (priv->arch_private); free (priv); - process->private = NULL; + process->priv = NULL; remove_process (process); } @@ -1227,8 +1273,8 @@ thread_still_has_status_pending_p (struct thread_info *thread) return 0; if (thread->last_resume_kind != resume_stop - && (lp->stop_reason == LWP_STOPPED_BY_SW_BREAKPOINT - || lp->stop_reason == LWP_STOPPED_BY_HW_BREAKPOINT)) + && (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT + || lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)) { struct thread_info *saved_thread; CORE_ADDR pc; @@ -1248,7 +1294,9 @@ thread_still_has_status_pending_p (struct thread_info *thread) lwpid_of (thread)); discard = 1; } - else if (lp->stop_reason == LWP_STOPPED_BY_SW_BREAKPOINT + +#if !USE_SIGTRAP_SIGINFO + else if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT && !(*the_low_target.breakpoint_at) (pc)) { if (debug_threads) @@ -1256,7 +1304,7 @@ thread_still_has_status_pending_p (struct thread_info *thread) lwpid_of (thread)); discard = 1; } - else if (lp->stop_reason == LWP_STOPPED_BY_HW_BREAKPOINT + else if (lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT && !hardware_breakpoint_inserted_here (pc)) { if (debug_threads) @@ -1264,6 +1312,7 @@ thread_still_has_status_pending_p (struct thread_info *thread) lwpid_of (thread)); discard = 1; } +#endif current_thread = saved_thread; @@ -1288,9 +1337,8 @@ status_pending_p_callback (struct inferior_list_entry *entry, void *arg) ptid_t ptid = * (ptid_t *) arg; /* Check if we're only interested in events from a specific process - or its lwps. */ - if (!ptid_equal (minus_one_ptid, ptid) - && ptid_get_pid (ptid) != ptid_get_pid (thread->entry.id)) + or a specific LWP. */ + if (!ptid_match (ptid_of (thread), ptid)) return 0; if (lp->status_pending_p @@ -1738,19 +1786,6 @@ dequeue_one_deferred_signal (struct lwp_info *lwp, int *wstat) return 0; } -/* Return true if the event in LP may be caused by breakpoint. */ - -static int -wstatus_maybe_breakpoint (int wstatus) -{ - return (WIFSTOPPED (wstatus) - && (WSTOPSIG (wstatus) == SIGTRAP - /* SIGILL and SIGSEGV are also treated as traps in case a - breakpoint is inserted at the current PC. */ - || WSTOPSIG (wstatus) == SIGILL - || WSTOPSIG (wstatus) == SIGSEGV)); -} - /* Fetch the possibly triggered data watchpoint info and store it in CHILD. @@ -1778,7 +1813,7 @@ check_stopped_by_watchpoint (struct lwp_info *child) if (the_low_target.stopped_by_watchpoint ()) { - child->stop_reason = LWP_STOPPED_BY_WATCHPOINT; + child->stop_reason = TARGET_STOPPED_BY_WATCHPOINT; if (the_low_target.stopped_data_address != NULL) child->stopped_data_address @@ -1790,7 +1825,7 @@ check_stopped_by_watchpoint (struct lwp_info *child) current_thread = saved_thread; } - return child->stop_reason == LWP_STOPPED_BY_WATCHPOINT; + return child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT; } /* Do low-level handling of the event, and check if we should go on @@ -1862,7 +1897,7 @@ linux_low_filter_event (int lwpid, int wstat) is stopped for the first time, but before we access any inferior registers. */ proc = find_process_pid (pid_of (thread)); - if (proc->private->new_inferior) + if (proc->priv->new_inferior) { struct thread_info *saved_thread; @@ -1873,7 +1908,7 @@ linux_low_filter_event (int lwpid, int wstat) current_thread = saved_thread; - proc->private->new_inferior = 0; + proc->priv->new_inferior = 0; } } @@ -1895,15 +1930,24 @@ linux_low_filter_event (int lwpid, int wstat) return NULL; } - if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP - && check_stopped_by_watchpoint (child)) - ; - else if (WIFSTOPPED (wstat) && wstatus_maybe_breakpoint (wstat)) + /* Check first whether this was a SW/HW breakpoint before checking + watchpoints, because at least s390 can't tell the data address of + hardware watchpoint hits, and returns stopped-by-watchpoint as + long as there's a watchpoint set. */ + if (WIFSTOPPED (wstat) && linux_wstatus_maybe_breakpoint (wstat)) { if (check_stopped_by_breakpoint (child)) have_stop_pc = 1; } + /* Note that TRAP_HWBKPT can indicate either a hardware breakpoint + or hardware watchpoint. Check which is which if we got + TARGET_STOPPED_BY_HW_BREAKPOINT. */ + if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP + && (child->stop_reason == TARGET_STOPPED_BY_NO_REASON + || child->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)) + check_stopped_by_watchpoint (child); + if (!have_stop_pc) child->stop_pc = get_pc (child); @@ -2223,8 +2267,7 @@ select_singlestep_lwp_callback (struct inferior_list_entry *entry, void *data) return 0; } -/* Select the Nth LWP that has had a SIGTRAP event that should be - reported to GDB. */ +/* Select the Nth LWP that has had an event. */ static int select_event_lwp_callback (struct inferior_list_entry *entry, void *data) @@ -2277,12 +2320,13 @@ select_event_lwp (struct lwp_info **orig_lp) if (event_thread == NULL) { /* No single-stepping LWP. Select one at random, out of those - which have had SIGTRAP events. */ + which have had events. */ - /* First see how many SIGTRAP events we have. */ + /* First see how many events we have. */ find_inferior (&all_threads, count_events_callback, &num_events); - /* Now randomly pick a LWP out of those that have had a SIGTRAP. */ + /* Now randomly pick a LWP out of those that have had + events. */ random_selector = (int) ((num_events * (double) rand ()) / (RAND_MAX + 1.0)); @@ -2566,6 +2610,36 @@ linux_wait_1 (ptid_t ptid, return ptid_of (current_thread); } + /* If step-over executes a breakpoint instruction, it means a + gdb/gdbserver breakpoint had been planted on top of a permanent + breakpoint. The PC has been adjusted by + check_stopped_by_breakpoint to point at the breakpoint address. + Advance the PC manually past the breakpoint, otherwise the + program would keep trapping the permanent breakpoint forever. */ + if (!ptid_equal (step_over_bkpt, null_ptid) + && event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT) + { + unsigned int increment_pc = the_low_target.breakpoint_len; + + if (debug_threads) + { + debug_printf ("step-over for %s executed software breakpoint\n", + target_pid_to_str (ptid_of (current_thread))); + } + + if (increment_pc != 0) + { + struct regcache *regcache + = get_thread_regcache (current_thread, 1); + + event_child->stop_pc += increment_pc; + (*the_low_target.set_pc) (regcache, event_child->stop_pc); + + if (!(*the_low_target.breakpoint_at) (event_child->stop_pc)) + event_child->stop_reason = TARGET_STOPPED_BY_NO_REASON; + } + } + /* If this event was not handled before, and is not a SIGTRAP, we report it. SIGILL and SIGSEGV are also treated as traps in case a breakpoint is inserted at the current PC. If this target does @@ -2739,21 +2813,23 @@ linux_wait_1 (ptid_t ptid, any that GDB specifically requested we ignore. But never ignore SIGSTOP if we sent it ourselves, and do not ignore signals when stepping - they may require special handling to skip the signal - handler. */ + handler. Also never ignore signals that could be caused by a + breakpoint. */ /* FIXME drow/2002-06-09: Get signal numbers from the inferior's thread library? */ if (WIFSTOPPED (w) && current_thread->last_resume_kind != resume_step && ( #if defined (USE_THREAD_DB) && !defined (__ANDROID__) - (current_process ()->private->thread_db != NULL + (current_process ()->priv->thread_db != NULL && (WSTOPSIG (w) == __SIGRTMIN || WSTOPSIG (w) == __SIGRTMIN + 1)) || #endif (pass_signals[gdb_signal_from_host (WSTOPSIG (w))] && !(WSTOPSIG (w) == SIGSTOP - && current_thread->last_resume_kind == resume_stop)))) + && current_thread->last_resume_kind == resume_stop) + && !linux_wstatus_maybe_breakpoint (w)))) { siginfo_t info, *info_p; @@ -2787,7 +2863,7 @@ linux_wait_1 (ptid_t ptid, report_to_gdb = (!maybe_internal_trap || (current_thread->last_resume_kind == resume_step && !in_step_range) - || event_child->stop_reason == LWP_STOPPED_BY_WATCHPOINT + || event_child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT || (!step_over_finished && !in_step_range && !bp_explains_trap && !trace_event) || (gdb_breakpoint_here (event_child->stop_pc) @@ -2851,7 +2927,7 @@ linux_wait_1 (ptid_t ptid, else if (!lwp_in_step_range (event_child)) debug_printf ("Out of step range, reporting event.\n"); } - if (event_child->stop_reason == LWP_STOPPED_BY_WATCHPOINT) + if (event_child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT) debug_printf ("Stopped by watchpoint.\n"); else if (gdb_breakpoint_here (event_child->stop_pc)) debug_printf ("Stopped by GDB breakpoint.\n"); @@ -2926,8 +3002,10 @@ linux_wait_1 (ptid_t ptid, ourstatus->kind = TARGET_WAITKIND_STOPPED; /* Now that we've selected our final event LWP, un-adjust its PC if - it was a software breakpoint. */ - if (event_child->stop_reason == LWP_STOPPED_BY_SW_BREAKPOINT) + it was a software breakpoint, and the client doesn't know we can + adjust the breakpoint ourselves. */ + if (event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT + && !swbreak_feature) { int decr_pc = the_low_target.decr_pc_after_break; @@ -3204,7 +3282,7 @@ stuck_in_jump_pad_callback (struct inferior_list_entry *entry, void *data) return (supports_fast_tracepoints () && agent_loaded_p () && (gdb_breakpoint_here (lwp->stop_pc) - || lwp->stop_reason == LWP_STOPPED_BY_WATCHPOINT + || lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT || thread->last_resume_kind == resume_step) && linux_fast_tracepoint_collecting (lwp, NULL)); } @@ -3223,7 +3301,7 @@ move_out_of_jump_pad_callback (struct inferior_list_entry *entry) /* Allow debugging the jump pad, gdb_collect, etc. */ if (!gdb_breakpoint_here (lwp->stop_pc) - && lwp->stop_reason != LWP_STOPPED_BY_WATCHPOINT + && lwp->stop_reason != TARGET_STOPPED_BY_WATCHPOINT && thread->last_resume_kind != resume_step && maybe_move_out_of_jump_pad (lwp, wstat)) { @@ -3488,7 +3566,7 @@ linux_resume_one_lwp (struct lwp_info *lwp, regcache_invalidate_thread (thread); errno = 0; lwp->stopped = 0; - lwp->stop_reason = LWP_STOPPED_BY_NO_REASON; + lwp->stop_reason = TARGET_STOPPED_BY_NO_REASON; lwp->stepping = step; ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (thread), (PTRACE_TYPE_ARG3) 0, @@ -4809,7 +4887,7 @@ linux_look_up_symbols (void) #ifdef USE_THREAD_DB struct process_info *proc = current_process (); - if (proc->private->thread_db != NULL) + if (proc->priv->thread_db != NULL) return; /* If the kernel supports tracing clones, then we don't need to @@ -4889,12 +4967,52 @@ linux_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, return 1; } +/* Implement the to_stopped_by_sw_breakpoint target_ops + method. */ + +static int +linux_stopped_by_sw_breakpoint (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + + return (lwp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT); +} + +/* Implement the to_supports_stopped_by_sw_breakpoint target_ops + method. */ + +static int +linux_supports_stopped_by_sw_breakpoint (void) +{ + return USE_SIGTRAP_SIGINFO; +} + +/* Implement the to_stopped_by_hw_breakpoint target_ops + method. */ + +static int +linux_stopped_by_hw_breakpoint (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + + return (lwp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT); +} + +/* Implement the to_supports_stopped_by_hw_breakpoint target_ops + method. */ + +static int +linux_supports_stopped_by_hw_breakpoint (void) +{ + return USE_SIGTRAP_SIGINFO; +} + static int linux_stopped_by_watchpoint (void) { struct lwp_info *lwp = get_thread_lwp (current_thread); - return lwp->stop_reason == LWP_STOPPED_BY_WATCHPOINT; + return lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT; } static CORE_ADDR @@ -5729,7 +5847,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, { char *document; unsigned document_len; - struct process_info_private *const priv = current_process ()->private; + struct process_info_private *const priv = current_process ()->priv; char filename[PATH_MAX]; int pid, is_elf64; @@ -5785,9 +5903,9 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, break; len = sep - annex; - if (len == 5 && strncmp (annex, "start", 5) == 0) + if (len == 5 && startswith (annex, "start")) addrp = &lm_addr; - else if (len == 4 && strncmp (annex, "prev", 4) == 0) + else if (len == 4 && startswith (annex, "prev")) addrp = &lm_prev; else { @@ -5938,13 +6056,13 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, /* See to_enable_btrace target method. */ static struct btrace_target_info * -linux_low_enable_btrace (ptid_t ptid) +linux_low_enable_btrace (ptid_t ptid, const struct btrace_config *conf) { struct btrace_target_info *tinfo; - tinfo = linux_enable_btrace (ptid); + tinfo = linux_enable_btrace (ptid, conf); - if (tinfo != NULL) + if (tinfo != NULL && tinfo->ptr_bits == 0) { struct thread_info *thread = find_thread_ptid (ptid); struct regcache *regcache = get_thread_regcache (thread, 0); @@ -6020,6 +6138,37 @@ linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer, btrace_data_fini (&btrace); return 0; } + +/* See to_btrace_conf target method. */ + +static int +linux_low_btrace_conf (const struct btrace_target_info *tinfo, + struct buffer *buffer) +{ + const struct btrace_config *conf; + + buffer_grow_str (buffer, "\n"); + buffer_grow_str (buffer, "\n"); + + conf = linux_btrace_conf (tinfo); + if (conf != NULL) + { + switch (conf->format) + { + case BTRACE_FORMAT_NONE: + break; + + case BTRACE_FORMAT_BTS: + buffer_xml_printf (buffer, "bts.size); + buffer_xml_printf (buffer, " />\n"); + break; + } + } + + buffer_grow_str0 (buffer, "\n"); + return 0; +} #endif /* HAVE_LINUX_BTRACE */ static struct target_ops linux_target_ops = { @@ -6044,6 +6193,10 @@ static struct target_ops linux_target_ops = { linux_supports_z_point_type, linux_insert_point, linux_remove_point, + linux_stopped_by_sw_breakpoint, + linux_supports_stopped_by_sw_breakpoint, + linux_stopped_by_hw_breakpoint, + linux_supports_stopped_by_hw_breakpoint, linux_stopped_by_watchpoint, linux_stopped_data_address, #if defined(__UCLIBC__) && defined(HAS_NOMMU) \ @@ -6093,11 +6246,13 @@ static struct target_ops linux_target_ops = { linux_low_enable_btrace, linux_low_disable_btrace, linux_low_read_btrace, + linux_low_btrace_conf, #else NULL, NULL, NULL, NULL, + NULL, #endif linux_supports_range_stepping, };