X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Flinux-low.c;h=a419a5cdf7c395c3252ff6da6c0b0f6f78192b5b;hb=edd88788349db3bd2af5fc9a38e2ea9cc220757f;hp=3a1a6ae57ea3ddab3fd38ca80d326faebc363310;hpb=9a3c826307ae6ad4dd6fbd72431e7d9d4947f1dd;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 3a1a6ae57e..a419a5cdf7 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -70,16 +70,6 @@ #define O_LARGEFILE 0 #endif -#ifndef W_STOPCODE -#define W_STOPCODE(sig) ((sig) << 8 | 0x7f) -#endif - -/* This is the kernel's hard limit. Not to be confused with - SIGRTMIN. */ -#ifndef __SIGRTMIN -#define __SIGRTMIN 32 -#endif - /* Some targets did not define these ptrace constants from the start, so gdbserver defines them locally here. In the future, these may be removed after they are added to asm/ptrace.h. */ @@ -274,18 +264,30 @@ static int finish_step_over (struct lwp_info *lwp); static int kill_lwp (unsigned long lwpid, int signo); static void enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info); static void complete_ongoing_step_over (void); +static int linux_low_ptrace_options (int attached); /* When the event-loop is doing a step-over, this points at the thread being stepped. */ ptid_t step_over_bkpt; -/* True if the low target can hardware single-step. Such targets - don't need a BREAKPOINT_REINSERT_ADDR callback. */ +/* True if the low target can hardware single-step. */ static int can_hardware_single_step (void) { - return (the_low_target.breakpoint_reinsert_addr == NULL); + if (the_low_target.supports_hardware_single_step != NULL) + return the_low_target.supports_hardware_single_step (); + else + return 0; +} + +/* True if the low target can software single-step. Such targets + implement the GET_NEXT_PCS callback. */ + +static int +can_software_single_step (void) +{ + return (the_low_target.get_next_pcs != NULL); } /* True if the low target supports memory breakpoints. If so, we'll @@ -420,7 +422,7 @@ linux_add_process (int pid, int attached) static CORE_ADDR get_pc (struct lwp_info *lwp); -/* Implement the arch_setup target_ops method. */ +/* Call the target arch_setup function on the current thread. */ static void linux_arch_setup (void) @@ -457,6 +459,8 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) struct thread_info *event_thr = get_lwp_thread (event_lwp); struct lwp_info *new_lwp; + gdb_assert (event_lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE); + if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) || (event == PTRACE_EVENT_CLONE)) { @@ -587,6 +591,12 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) new_lwp->status_pending_p = 1; new_lwp->status_pending = status; } + else if (report_thread_events) + { + new_lwp->waitstatus.kind = TARGET_WAITKIND_THREAD_CREATED; + new_lwp->status_pending_p = 1; + new_lwp->status_pending = status; + } /* Don't report the event. */ return 1; @@ -868,10 +878,6 @@ linux_create_inferior (char *program, char **allargs) close_most_fds (); ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0); -#ifndef __ANDROID__ /* Bionic doesn't use SIGRTMIN the way glibc does. */ - signal (__SIGRTMIN + 1, SIG_DFL); -#endif - setpgid (0, 0); /* If gdbserver is connected to gdb via stdio, redirect the inferior's @@ -910,6 +916,25 @@ linux_create_inferior (char *program, char **allargs) return pid; } +/* Implement the post_create_inferior target_ops method. */ + +static void +linux_post_create_inferior (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + + linux_arch_setup (); + + if (lwp->must_set_ptrace_flags) + { + struct process_info *proc = current_process (); + int options = linux_low_ptrace_options (proc->attached); + + linux_enable_event_reporting (lwpid_of (current_thread), options); + lwp->must_set_ptrace_flags = 0; + } +} + /* Attach to an inferior process. Returns 0 on success, ERRNO on error. */ @@ -1039,12 +1064,16 @@ attach_proc_task_lwp_callback (ptid_t ptid) return 0; } +static void async_file_mark (void); + /* Attach to PID. If PID is the tgid, attach to it and all of its threads. */ static int linux_attach (unsigned long pid) { + struct process_info *proc; + struct thread_info *initial_thread; ptid_t ptid = ptid_build (pid, pid, 0); int err; @@ -1055,17 +1084,12 @@ linux_attach (unsigned long pid) error ("Cannot attach to process %ld: %s", pid, linux_ptrace_attach_fail_reason_string (ptid, err)); - linux_add_process (pid, 1); - - if (!non_stop) - { - struct thread_info *thread; + proc = linux_add_process (pid, 1); - /* Don't ignore the initial SIGSTOP if we just attached to this - process. It will be collected by wait shortly. */ - thread = find_thread_ptid (ptid_build (pid, pid, 0)); - thread->last_resume_kind = resume_stop; - } + /* Don't ignore the initial SIGSTOP if we just attached to this + process. It will be collected by wait shortly. */ + initial_thread = find_thread_ptid (ptid_build (pid, pid, 0)); + initial_thread->last_resume_kind = resume_stop; /* We must attach to every LWP. If /proc is mounted, use that to find them now. On the one hand, the inferior may be using raw @@ -1077,6 +1101,38 @@ linux_attach (unsigned long pid) that once thread_db is loaded, we'll still use it to list threads and associate pthread info with each LWP. */ linux_proc_attach_tgid_threads (pid, attach_proc_task_lwp_callback); + + /* GDB will shortly read the xml target description for this + process, to figure out the process' architecture. But the target + description is only filled in when the first process/thread in + the thread group reports its initial PTRACE_ATTACH SIGSTOP. Do + that now, otherwise, if GDB is fast enough, it could read the + target description _before_ that initial stop. */ + if (non_stop) + { + struct lwp_info *lwp; + int wstat, lwpid; + ptid_t pid_ptid = pid_to_ptid (pid); + + lwpid = linux_wait_for_event_filtered (pid_ptid, pid_ptid, + &wstat, __WALL); + gdb_assert (lwpid > 0); + + lwp = find_lwp_pid (pid_to_ptid (lwpid)); + + if (!WIFSTOPPED (wstat) || WSTOPSIG (wstat) != SIGSTOP) + { + lwp->status_pending_p = 1; + lwp->status_pending = wstat; + } + + initial_thread->last_resume_kind = resume_continue; + + async_file_mark (); + + gdb_assert (proc->tdesc != NULL); + } + return 0; } @@ -1123,13 +1179,12 @@ linux_kill_one_lwp (struct lwp_info *lwp) ptrace(CONT, pid, 0,0) and just resumes the tracee. A better alternative is to kill with SIGKILL. We only need one SIGKILL per process, not one for each thread. But since we still support - linuxthreads, and we also support debugging programs using raw - clone without CLONE_THREAD, we send one for each thread. For - years, we used PTRACE_KILL only, so we're being a bit paranoid - about some old kernels where PTRACE_KILL might work better - (dubious if there are any such, but that's why it's paranoia), so - we try SIGKILL first, PTRACE_KILL second, and so we're fine - everywhere. */ + support debugging programs using raw clone without CLONE_THREAD, + we send one for each thread. For years, we used PTRACE_KILL + only, so we're being a bit paranoid about some old kernels where + PTRACE_KILL might work better (dubious if there are any such, but + that's why it's paranoia), so we try SIGKILL first, PTRACE_KILL + second, and so we're fine everywhere. */ errno = 0; kill_lwp (pid, SIGKILL); @@ -1496,12 +1551,6 @@ thread_still_has_status_pending_p (struct thread_info *thread) if (!lp->status_pending_p) return 0; - /* If we got a `vCont;t', but we haven't reported a stop yet, do - report any status pending the LWP may have. */ - if (thread->last_resume_kind == resume_stop - && thread->last_status.kind != TARGET_WAITKIND_IGNORE) - return 0; - if (thread->last_resume_kind != resume_stop && (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT || lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)) @@ -1558,6 +1607,26 @@ thread_still_has_status_pending_p (struct thread_info *thread) return 1; } +/* Returns true if LWP is resumed from the client's perspective. */ + +static int +lwp_resumed (struct lwp_info *lwp) +{ + struct thread_info *thread = get_lwp_thread (lwp); + + if (thread->last_resume_kind != resume_stop) + return 1; + + /* Did gdb send us a `vCont;t', but we haven't reported the + corresponding stop to gdb yet? If so, the thread is still + resumed/running from gdb's perspective. */ + if (thread->last_resume_kind == resume_stop + && thread->last_status.kind == TARGET_WAITKIND_IGNORE) + return 1; + + return 0; +} + /* Return 1 if this lwp has an interesting status pending. */ static int status_pending_p_callback (struct inferior_list_entry *entry, void *arg) @@ -1571,6 +1640,9 @@ status_pending_p_callback (struct inferior_list_entry *entry, void *arg) if (!ptid_match (ptid_of (thread), ptid)) return 0; + if (!lwp_resumed (lp)) + return 0; + if (lp->status_pending_p && !thread_still_has_status_pending_p (thread)) { @@ -2235,25 +2307,22 @@ linux_low_filter_event (int lwpid, int wstat) { if (debug_threads) debug_printf ("LLFE: %d exited.\n", lwpid); - if (num_lwps (pid_of (thread)) > 1) + /* If there is at least one more LWP, then the exit signal was + not the end of the debugged application and should be + ignored, unless GDB wants to hear about thread exits. */ + if (report_thread_events + || last_thread_of_process_p (pid_of (thread))) { - - /* If there is at least one more LWP, then the exit signal was - not the end of the debugged application and should be - ignored. */ - delete_lwp (child); - return NULL; + /* Since events are serialized to GDB core, and we can't + report this one right now. Leave the status pending for + the next time we're able to report it. */ + mark_lwp_dead (child, wstat); + return child; } else { - /* This was the last lwp in the process. Since events are - serialized to GDB core, and we can't report this one - right now, but GDB core and the other target layers will - want to be notified about the exit code/signal, leave the - status pending for the next time we're able to report - it. */ - mark_lwp_dead (child, wstat); - return child; + delete_lwp (child); + return NULL; } } @@ -2388,7 +2457,6 @@ resume_stopped_resumed_lwps (struct inferior_list_entry *entry) if (lp->stopped && !lp->suspended && !lp->status_pending_p - && thread->last_resume_kind != resume_stop && thread->last_status.kind == TARGET_WAITKIND_IGNORE) { int step = thread->last_resume_kind == resume_step; @@ -2597,18 +2665,6 @@ linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid, current_thread = event_thread; - /* Check for thread exit. */ - if (! WIFSTOPPED (*wstatp)) - { - gdb_assert (last_thread_of_process_p (pid_of (event_thread))); - - if (debug_threads) - debug_printf ("LWP %d is the last lwp of process. " - "Process %ld exiting.\n", - pid_of (event_thread), lwpid_of (event_thread)); - return lwpid_of (event_thread); - } - return lwpid_of (event_thread); } @@ -2878,8 +2934,6 @@ linux_stabilize_threads (void) } } -static void async_file_mark (void); - /* Convenience function that is called when the kernel reports an event that is not passed out to GDB. */ @@ -2895,6 +2949,30 @@ ignore_event (struct target_waitstatus *ourstatus) return null_ptid; } +/* Convenience function that is called when the kernel reports an exit + event. This decides whether to report the event to GDB as a + process exit event, a thread exit event, or to suppress the + event. */ + +static ptid_t +filter_exit_event (struct lwp_info *event_child, + struct target_waitstatus *ourstatus) +{ + struct thread_info *thread = get_lwp_thread (event_child); + ptid_t ptid = ptid_of (thread); + + if (!last_thread_of_process_p (pid_of (thread))) + { + if (report_thread_events) + ourstatus->kind = TARGET_WAITKIND_THREAD_EXITED; + else + ourstatus->kind = TARGET_WAITKIND_IGNORE; + + delete_lwp (event_child); + } + return ptid; +} + /* Wait for process, returns status. */ static ptid_t @@ -2911,6 +2989,7 @@ linux_wait_1 (ptid_t ptid, int report_to_gdb; int trace_event; int in_step_range; + int any_resumed; if (debug_threads) { @@ -2928,6 +3007,18 @@ linux_wait_1 (ptid_t ptid, in_step_range = 0; ourstatus->kind = TARGET_WAITKIND_IGNORE; + /* Find a resumed LWP, if any. */ + if (find_inferior (&all_threads, + status_pending_p_callback, + &minus_one_ptid) != NULL) + any_resumed = 1; + else if ((find_inferior (&all_threads, + not_stopped_callback, + &minus_one_ptid) != NULL)) + any_resumed = 1; + else + any_resumed = 0; + if (ptid_equal (step_over_bkpt, null_ptid)) pid = linux_wait_for_event (ptid, &w, options); else @@ -2938,7 +3029,7 @@ linux_wait_1 (ptid_t ptid, pid = linux_wait_for_event (step_over_bkpt, &w, options & ~WNOHANG); } - if (pid == 0) + if (pid == 0 || (pid == -1 && !any_resumed)) { gdb_assert (target_options & TARGET_WNOHANG); @@ -3000,19 +3091,35 @@ linux_wait_1 (ptid_t ptid, } } + if (ourstatus->kind == TARGET_WAITKIND_EXITED) + return filter_exit_event (event_child, ourstatus); + 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 step-over executes a breakpoint instruction, in the case of a + hardware single step it means a gdb/gdbserver breakpoint had been + planted on top of a permanent breakpoint, in the case of a software + single step it may just mean that gdbserver hit the reinsert breakpoint. + The PC has been adjusted by check_stopped_by_breakpoint to point at + the breakpoint address. + So in the case of the hardware single step advance the PC manually + past the breakpoint and in the case of software single step advance only + if it's not the reinsert_breakpoint we are hitting. + This avoids that a program would keep trapping a permanent breakpoint + forever. */ if (!ptid_equal (step_over_bkpt, null_ptid) - && event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT) + && event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT + && (event_child->stepping + || !reinsert_breakpoint_inserted_here (event_child->stop_pc))) { - unsigned int increment_pc = the_low_target.breakpoint_len; + int increment_pc = 0; + int breakpoint_kind = 0; + CORE_ADDR stop_pc = event_child->stop_pc; + + breakpoint_kind = + the_target->breakpoint_kind_from_current_state (&stop_pc); + the_target->sw_breakpoint_from_kind (breakpoint_kind, &increment_pc); if (debug_threads) { @@ -3208,8 +3315,6 @@ linux_wait_1 (ptid_t ptid, stepping - they may require special handling to skip the signal 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 && ( @@ -3484,6 +3589,9 @@ linux_wait_1 (ptid_t ptid, debug_exit (); } + if (ourstatus->kind == TARGET_WAITKIND_EXITED) + return filter_exit_event (event_child, ourstatus); + return ptid_of (current_thread); } @@ -3548,27 +3656,17 @@ linux_wait (ptid_t ptid, static int kill_lwp (unsigned long lwpid, int signo) { - /* Use tkill, if possible, in case we are using nptl threads. If tkill - fails, then we are not using nptl threads and we should be using kill. */ - -#ifdef __NR_tkill - { - static int tkill_failed; - - if (!tkill_failed) - { - int ret; - - errno = 0; - ret = syscall (__NR_tkill, lwpid, signo); - if (errno != ENOSYS) - return ret; - tkill_failed = 1; - } - } -#endif + int ret; - return kill (lwpid, signo); + errno = 0; + ret = syscall (__NR_tkill, lwpid, signo); + if (errno == ENOSYS) + { + /* If tkill fails, then we are not using nptl threads, a + configuration we no longer support. */ + perror_with_name (("tkill")); + } + return ret; } void @@ -3862,6 +3960,53 @@ enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info) lwp->pending_signals = p_sig; } +/* Install breakpoints for software single stepping. */ + +static void +install_software_single_step_breakpoints (struct lwp_info *lwp) +{ + int i; + CORE_ADDR pc; + struct regcache *regcache = get_thread_regcache (current_thread, 1); + VEC (CORE_ADDR) *next_pcs = NULL; + struct cleanup *old_chain = make_cleanup (VEC_cleanup (CORE_ADDR), &next_pcs); + + pc = get_pc (lwp); + next_pcs = (*the_low_target.get_next_pcs) (pc, regcache); + + for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); ++i) + set_reinsert_breakpoint (pc); + + do_cleanups (old_chain); +} + +/* Single step via hardware or software single step. + Return 1 if hardware single stepping, 0 if software single stepping + or can't single step. */ + +static int +single_step (struct lwp_info* lwp) +{ + int step = 0; + + if (can_hardware_single_step ()) + { + step = 1; + } + else if (can_software_single_step ()) + { + install_software_single_step_breakpoints (lwp); + step = 0; + } + else + { + if (debug_threads) + debug_printf ("stepping is not implemented on this target"); + } + + return step; +} + /* Resume execution of LWP. If STEP is nonzero, single-step it. If SIGNAL is nonzero, give it that signal. */ @@ -3884,6 +4029,8 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, if (lwp->stopped == 0) return; + gdb_assert (lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE); + fast_tp_collecting = lwp->collecting_fast_tracepoint; gdb_assert (!stabilizing_threads || fast_tp_collecting); @@ -4007,13 +4154,13 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, address, continue, and carry on catching this while-stepping action only when that breakpoint is hit. A future enhancement. */ - if (thread->while_stepping != NULL - && can_hardware_single_step ()) + if (thread->while_stepping != NULL) { if (debug_threads) debug_printf ("lwp %ld has a while-stepping action -> forcing step.\n", lwpid_of (thread)); - step = 1; + + step = single_step (lwp); } if (proc->tdesc != NULL && the_low_target.get_pc != NULL) @@ -4419,16 +4566,7 @@ start_step_over (struct lwp_info *lwp) uninsert_breakpoints_at (pc); uninsert_fast_tracepoint_jumps_at (pc); - if (can_hardware_single_step ()) - { - step = 1; - } - else - { - CORE_ADDR raddr = (*the_low_target.breakpoint_reinsert_addr) (); - set_reinsert_breakpoint (raddr); - step = 0; - } + step = single_step (lwp); current_thread = saved_thread; @@ -4692,6 +4830,11 @@ linux_resume (struct thread_resume *resume_info, size_t n) debug_printf ("linux_resume done\n"); debug_exit (); } + + /* We may have events that were pending that can/should be sent to + the client now. Trigger a linux_wait call. */ + if (target_is_async_p ()) + async_file_mark (); } /* This function is called once per thread. We check the thread's @@ -5493,10 +5636,7 @@ linux_look_up_symbols (void) if (proc->priv->thread_db != NULL) return; - /* If the kernel supports tracing clones, then we don't need to - use the magic thread event breakpoint to learn about - threads. */ - thread_db_init (!linux_supports_traceclone ()); + thread_db_init (); #endif } @@ -5622,6 +5762,12 @@ linux_supports_hardware_single_step (void) return can_hardware_single_step (); } +static int +linux_supports_software_single_step (void) +{ + return can_software_single_step (); +} + static int linux_stopped_by_watchpoint (void) { @@ -6133,10 +6279,10 @@ linux_read_loadmap (const char *annex, CORE_ADDR offset, #endif /* defined PT_GETDSBT || defined PTRACE_GETFDPIC */ static void -linux_process_qsupported (const char *query) +linux_process_qsupported (char **features, int count) { if (the_low_target.process_qsupported != NULL) - the_low_target.process_qsupported (query); + the_low_target.process_qsupported (features, count); } static int @@ -6820,7 +6966,7 @@ linux_low_encode_raw (struct buffer *buffer, const gdb_byte *data, static int linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer, - int type) + enum btrace_read_type type) { struct btrace_data btrace; struct btrace_block *block; @@ -6932,9 +7078,42 @@ current_lwp_ptid (void) return ptid_of (current_thread); } +/* Implementation of the target_ops method "breakpoint_kind_from_pc". */ + +static int +linux_breakpoint_kind_from_pc (CORE_ADDR *pcptr) +{ + if (the_low_target.breakpoint_kind_from_pc != NULL) + return (*the_low_target.breakpoint_kind_from_pc) (pcptr); + else + return default_breakpoint_kind_from_pc (pcptr); +} + +/* Implementation of the target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +linux_sw_breakpoint_from_kind (int kind, int *size) +{ + gdb_assert (the_low_target.sw_breakpoint_from_kind != NULL); + + return (*the_low_target.sw_breakpoint_from_kind) (kind, size); +} + +/* Implementation of the target_ops method + "breakpoint_kind_from_current_state". */ + +static int +linux_breakpoint_kind_from_current_state (CORE_ADDR *pcptr) +{ + if (the_low_target.breakpoint_kind_from_current_state != NULL) + return (*the_low_target.breakpoint_kind_from_current_state) (pcptr); + else + return linux_breakpoint_kind_from_pc (pcptr); +} + static struct target_ops linux_target_ops = { linux_create_inferior, - linux_arch_setup, + linux_post_create_inferior, linux_attach, linux_kill, linux_detach, @@ -7026,18 +7205,13 @@ static struct target_ops linux_target_ops = { linux_mntns_open_cloexec, linux_mntns_unlink, linux_mntns_readlink, + linux_breakpoint_kind_from_pc, + linux_sw_breakpoint_from_kind, + linux_proc_tid_get_name, + linux_breakpoint_kind_from_current_state, + linux_supports_software_single_step }; -static void -linux_init_signals () -{ - /* FIXME drow/2002-06-09: As above, we should check with LinuxThreads - to find what the cancel signal actually is. */ -#ifndef __ANDROID__ /* Bionic doesn't use SIGRTMIN the way glibc does. */ - signal (__SIGRTMIN+1, SIG_IGN); -#endif -} - #ifdef HAVE_LINUX_REGSETS void initialize_regsets_info (struct regsets_info *info) @@ -7053,11 +7227,10 @@ void initialize_low (void) { struct sigaction sigchld_action; + memset (&sigchld_action, 0, sizeof (sigchld_action)); set_target_ops (&linux_target_ops); - set_breakpoint_data (the_low_target.breakpoint, - the_low_target.breakpoint_len); - linux_init_signals (); + linux_ptrace_init_warnings (); sigchld_action.sa_handler = sigchld_handler;