unsigned char valgrind_wait (char *ourstatus) { int pid; unsigned long wptid; ThreadState *tst; enum target_signal sig; int code; pid = VG_(getpid) (); dlog(1, "enter valgrind_wait pid %d\n", pid); regcache_invalidate(); valgrind_update_threads(pid); /* First see if we are done with this process. */ if (exit_status_to_report != 0) { *ourstatus = exit_status_to_report; exit_status_to_report = 0; if (*ourstatus == 'W') { code = exit_code_to_report; exit_code_to_report = 0; dlog(1, "exit valgrind_wait status W exit code %d\n", code); return code; } if (*ourstatus == 'X') { sig = target_signal_from_host(exit_code_to_report); exit_code_to_report = 0; dlog(1, "exit valgrind_wait status X signal %u\n", sig); return sig; } } /* in valgrind, we consider that a wait always succeeds with STOPPED 'T' and with a signal TRAP (i.e. a breakpoint), unless there is a signal to report. */ *ourstatus = 'T'; if (vki_signal_to_report.si_signo == 0) sig = TARGET_SIGNAL_TRAP; else sig = target_signal_from_host(vki_signal_to_report.si_signo); if (vgdb_interrupted_tid != 0) tst = VG_(get_ThreadState) (vgdb_interrupted_tid); else tst = VG_(get_ThreadState) (VG_(running_tid)); wptid = tst->os_state.lwpid; /* we can only change the current_inferior when the wptid references an existing thread. Otherwise, we are still in the init phase. (hack similar to main thread hack in valgrind_update_threads) */ if (tst->os_state.lwpid) current_inferior = gdb_id_to_thread (wptid); stop_pc = (*the_low_target.get_pc) (); dlog(1, "exit valgrind_wait status T ptid %s stop_pc %s signal %u\n", image_ptid (wptid), sym (stop_pc), sig); return sig; }
static void dlog_signal (const HChar *who, const vki_siginfo_t *info, ThreadId tid) { dlog(1, "VG core calling %s " "vki_nr %d %s gdb_nr %u %s tid %u\n", who, info->si_signo, VG_(signame)(info->si_signo), target_signal_from_host (info->si_signo), target_signal_to_name(target_signal_from_host (info->si_signo)), tid); }
Bool VG_(gdbserver_report_signal) (vki_siginfo_t *info, ThreadId tid) { dlog_signal("VG_(gdbserver_report_signal)", info, tid); /* if gdbserver is currently not connected, then signal is to be given to the process */ if (!remote_connected()) { dlog(1, "not connected => pass\n"); return True; } /* if gdb has informed gdbserver that this signal can be passed directly without informing gdb, then signal is to be given to the process. */ if (pass_signals[target_signal_from_host(info->si_signo)]) { dlog(1, "pass_signals => pass\n"); return True; } /* indicate to gdbserver that there is a signal */ gdbserver_signal_encountered (info); /* let gdbserver do some work, e.g. show the signal to the user. User can also decide to ignore the signal or change the signal. */ call_gdbserver (tid, signal_reason); /* ask gdbserver what is the final decision */ if (gdbserver_deliver_signal (info)) { dlog(1, "gdbserver deliver signal\n"); return True; } else { dlog(1, "gdbserver ignore signal\n"); return False; } }
Bool VG_(gdbserver_report_signal) (Int vki_sigNo, ThreadId tid) { dlog(1, "VG core calling VG_(gdbserver_report_signal) " "vki_nr %d %s gdb_nr %d %s tid %d\n", vki_sigNo, VG_(signame)(vki_sigNo), target_signal_from_host (vki_sigNo), target_signal_to_name(target_signal_from_host (vki_sigNo)), tid); /* if gdbserver is currently not connected, then signal is to be given to the process */ if (!remote_connected()) { dlog(1, "not connected => pass\n"); return True; } /* if gdb has informed gdbserver that this signal can be passed directly without informing gdb, then signal is to be given to the process. */ if (pass_signals[target_signal_from_host(vki_sigNo)]) { dlog(1, "pass_signals => pass\n"); return True; } /* indicate to gdbserver that there is a signal */ gdbserver_signal_encountered (vki_sigNo); /* let gdbserver do some work, e.g. show the signal to the user */ call_gdbserver (tid, signal_reason); /* ask gdbserver what is the final decision */ if (gdbserver_deliver_signal (vki_sigNo)) { dlog(1, "gdbserver deliver signal\n"); return True; } else { dlog(1, "gdbserver ignore signal\n"); return False; } }
void VG_(gdbserver_report_fatal_signal) (Int vki_sigNo, ThreadId tid) { dlog(1, "VG core calling VG_(gdbserver_report_fatal_signal) " "vki_nr %d %s gdb_nr %d %s tid %d\n", vki_sigNo, VG_(signame)(vki_sigNo), target_signal_from_host (vki_sigNo), target_signal_to_name(target_signal_from_host (vki_sigNo)), tid); if (remote_connected()) { dlog(1, "already connected, assuming already reported\n"); return; } VG_(umsg)("(action on fatal signal) vgdb me ... \n"); /* indicate to gdbserver that there is a signal */ gdbserver_signal_encountered (vki_sigNo); /* let gdbserver do some work, e.g. show the signal to the user */ call_gdbserver (tid, signal_reason); }
ptid_t child_wait (ptid_t ptid, struct target_waitstatus *ourstatus) { int save_errno; int thread; union wait status; int pid; while (1) { int sig; set_sigint_trap (); /* Causes SIGINT to be passed on to the attached process. */ pid = wait (&status); save_errno = errno; clear_sigint_trap (); if (pid == -1) { if (save_errno == EINTR) continue; fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing: %s.\n", safe_strerror (save_errno)); /* Claim it exited with unknown signal. */ ourstatus->kind = TARGET_WAITKIND_SIGNALLED; ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; return -1; } if (pid != PIDGET (inferior_ptid)) /* Some other process?!? */ continue; thread = status.w_tid; /* Get thread id from status */ /* Initial thread value can only be acquired via wait, so we have to resort to this hack. */ if (TIDGET (inferior_ptid) == 0 && thread != 0) { inferior_ptid = MERGEPID (PIDGET (inferior_ptid), thread); add_thread (inferior_ptid); } ptid = BUILDPID (pid, thread); /* We've become a single threaded process again. */ if (thread == 0) inferior_ptid = ptid; /* Check for thread creation. */ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && !in_thread_list (ptid)) { int realsig; realsig = ptrace (PTRACE_GETTRACESIG, PIDGET (ptid), (PTRACE_ARG3_TYPE) 0, 0); if (realsig == SIGNEWTHREAD) { /* It's a new thread notification. We don't want to much with realsig -- the code in wait_for_inferior expects SIGTRAP. */ ourstatus->kind = TARGET_WAITKIND_SPURIOUS; ourstatus->value.sig = TARGET_SIGNAL_0; return ptid; } else error ("Signal for unknown thread was not SIGNEWTHREAD"); } /* Check for thread termination. */ else if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && in_thread_list (ptid)) { int realsig; realsig = ptrace (PTRACE_GETTRACESIG, PIDGET (ptid), (PTRACE_ARG3_TYPE) 0, 0); if (realsig == SIGTHREADEXIT) { ptrace (PTRACE_CONT, PIDGET (ptid), (PTRACE_ARG3_TYPE) 0, 0); continue; } } #ifdef SPARC /* SPARC Lynx uses an byte reversed wait status; we must use the host macros to access it. These lines just a copy of store_waitstatus. We can't use CHILD_SPECIAL_WAITSTATUS because target.c can't include the Lynx <sys/wait.h>. */ if (WIFEXITED (status)) { ourstatus->kind = TARGET_WAITKIND_EXITED; ourstatus->value.integer = WEXITSTATUS (status); } else if (!WIFSTOPPED (status)) { ourstatus->kind = TARGET_WAITKIND_SIGNALLED; ourstatus->value.sig = target_signal_from_host (WTERMSIG (status)); } else { ourstatus->kind = TARGET_WAITKIND_STOPPED; ourstatus->value.sig = target_signal_from_host (WSTOPSIG (status)); } #else store_waitstatus (ourstatus, status.w_status); #endif return ptid; } }
static ptid_t nto_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int target_options) { sigset_t set; siginfo_t info; procfs_status status; const int trace_mask = (_DEBUG_FLAG_TRACE_EXEC | _DEBUG_FLAG_TRACE_RD | _DEBUG_FLAG_TRACE_WR | _DEBUG_FLAG_TRACE_MODIFY); TRACE ("%s\n", __func__); ourstatus->kind = TARGET_WAITKIND_SPURIOUS; sigemptyset (&set); sigaddset (&set, SIGUSR1); devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); while (!(status.flags & _DEBUG_FLAG_ISTOP)) { sigwaitinfo (&set, &info); devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); } nto_find_new_threads (&nto_inferior); if (status.flags & _DEBUG_FLAG_SSTEP) { TRACE ("SSTEP\n"); ourstatus->kind = TARGET_WAITKIND_STOPPED; ourstatus->value.sig = TARGET_SIGNAL_TRAP; } /* Was it a breakpoint? */ else if (status.flags & trace_mask) { TRACE ("STOPPED\n"); ourstatus->kind = TARGET_WAITKIND_STOPPED; ourstatus->value.sig = TARGET_SIGNAL_TRAP; } else if (status.flags & _DEBUG_FLAG_ISTOP) { TRACE ("ISTOP\n"); switch (status.why) { case _DEBUG_WHY_SIGNALLED: TRACE (" SIGNALLED\n"); ourstatus->kind = TARGET_WAITKIND_STOPPED; ourstatus->value.sig = target_signal_from_host (status.info.si_signo); nto_inferior.exit_signo = ourstatus->value.sig; break; case _DEBUG_WHY_FAULTED: TRACE (" FAULTED\n"); ourstatus->kind = TARGET_WAITKIND_STOPPED; if (status.info.si_signo == SIGTRAP) { ourstatus->value.sig = 0; nto_inferior.exit_signo = 0; } else { ourstatus->value.sig = target_signal_from_host (status.info.si_signo); nto_inferior.exit_signo = ourstatus->value.sig; } break; case _DEBUG_WHY_TERMINATED: { int waitval = 0; TRACE (" TERMINATED\n"); waitpid (ptid_get_pid (ptid), &waitval, WNOHANG); if (nto_inferior.exit_signo) { /* Abnormal death. */ ourstatus->kind = TARGET_WAITKIND_SIGNALLED; ourstatus->value.sig = nto_inferior.exit_signo; } else { /* Normal death. */ ourstatus->kind = TARGET_WAITKIND_EXITED; ourstatus->value.integer = WEXITSTATUS (waitval); } nto_inferior.exit_signo = 0; break; } case _DEBUG_WHY_REQUESTED: TRACE ("REQUESTED\n"); /* We are assuming a requested stop is due to a SIGINT. */ ourstatus->kind = TARGET_WAITKIND_STOPPED; ourstatus->value.sig = TARGET_SIGNAL_INT; nto_inferior.exit_signo = 0; break; } } return ptid_build (status.pid, status.tid, 0); }
static ptid_t gdbsim_wait (ptid_t ptid, struct target_waitstatus *status) { static RETSIGTYPE (*prev_sigint) (); int sigrc = 0; enum sim_stop reason = sim_running; if (sr_get_debug ()) printf_filtered ("gdbsim_wait\n"); #if defined (HAVE_SIGACTION) && defined (SA_RESTART) { struct sigaction sa, osa; sa.sa_handler = gdbsim_cntrl_c; sigemptyset (&sa.sa_mask); sa.sa_flags = 0; sigaction (SIGINT, &sa, &osa); prev_sigint = osa.sa_handler; } #else prev_sigint = signal (SIGINT, gdbsim_cntrl_c); #endif sim_resume (gdbsim_desc, resume_step, target_signal_to_host (resume_siggnal)); signal (SIGINT, prev_sigint); resume_step = 0; sim_stop_reason (gdbsim_desc, &reason, &sigrc); switch (reason) { case sim_exited: status->kind = TARGET_WAITKIND_EXITED; status->value.integer = sigrc; break; case sim_stopped: switch (sigrc) { case SIGABRT: quit (); break; case SIGINT: case SIGTRAP: default: status->kind = TARGET_WAITKIND_STOPPED; /* The signal in sigrc is a host signal. That probably should be fixed. */ status->value.sig = target_signal_from_host (sigrc); break; } break; case sim_signalled: status->kind = TARGET_WAITKIND_SIGNALLED; /* The signal in sigrc is a host signal. That probably should be fixed. */ status->value.sig = target_signal_from_host (sigrc); break; case sim_running: case sim_polling: /* FIXME: Is this correct? */ break; } return inferior_ptid; }
enum target_signal default_target_signal_from_host (struct gdbarch *gdbarch, int signo) { return target_signal_from_host (signo); }
static void core_open (char *filename, int from_tty) { const char *p; int siggy; struct cleanup *old_chain; char *temp; bfd *temp_bfd; int scratch_chan; int flags; target_preopen (from_tty); if (!filename) { if (core_bfd) error (_("No core file specified. (Use `detach' " "to stop debugging a core file.)")); else error (_("No core file specified.")); } filename = tilde_expand (filename); if (!IS_ABSOLUTE_PATH (filename)) { temp = concat (current_directory, "/", filename, (char *) NULL); xfree (filename); filename = temp; } old_chain = make_cleanup (xfree, filename); flags = O_BINARY | O_LARGEFILE; if (write_files) flags |= O_RDWR; else flags |= O_RDONLY; scratch_chan = open (filename, flags, 0); if (scratch_chan < 0) perror_with_name (filename); temp_bfd = bfd_fopen (filename, gnutarget, write_files ? FOPEN_RUB : FOPEN_RB, scratch_chan); if (temp_bfd == NULL) perror_with_name (filename); if (!bfd_check_format (temp_bfd, bfd_core) && !gdb_check_format (temp_bfd)) { /* Do it after the err msg */ /* FIXME: should be checking for errors from bfd_close (for one thing, on error it does not free all the storage associated with the bfd). */ make_cleanup_bfd_close (temp_bfd); error (_("\"%s\" is not a core dump: %s"), filename, bfd_errmsg (bfd_get_error ())); } /* Looks semi-reasonable. Toss the old core file and work on the new. */ discard_cleanups (old_chain); /* Don't free filename any more */ unpush_target (&core_ops); core_bfd = temp_bfd; old_chain = make_cleanup (core_close_cleanup, 0 /*ignore*/); /* FIXME: kettenis/20031023: This is very dangerous. The CORE_GDBARCH that results from this call may very well be different from CURRENT_GDBARCH. However, its methods may only work if it is selected as the current architecture, because they rely on swapped data (see gdbarch.c). We should get rid of that swapped data. */ core_gdbarch = gdbarch_from_bfd (core_bfd); /* Find a suitable core file handler to munch on core_bfd */ core_vec = sniff_core_bfd (core_bfd); validate_files (); core_data = XZALLOC (struct target_section_table); /* Find the data section */ if (build_section_table (core_bfd, &core_data->sections, &core_data->sections_end)) error (_("\"%s\": Can't find sections: %s"), bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ())); /* If we have no exec file, try to set the architecture from the core file. We don't do this unconditionally since an exec file typically contains more information that helps us determine the architecture than a core file. */ if (!exec_bfd) set_gdbarch_from_file (core_bfd); push_target (&core_ops); discard_cleanups (old_chain); /* Do this before acknowledging the inferior, so if post_create_inferior throws (can happen easilly if you're loading a core file with the wrong exec), we aren't left with threads from the previous inferior. */ init_thread_list (); inferior_ptid = null_ptid; core_has_fake_pid = 0; /* Need to flush the register cache (and the frame cache) from a previous debug session. If inferior_ptid ends up the same as the last debug session --- e.g., b foo; run; gcore core1; step; gcore core2; core core1; core core2 --- then there's potential for get_current_regcache to return the cached regcache of the previous session, and the frame cache being stale. */ registers_changed (); /* Build up thread list from BFD sections, and possibly set the current thread to the .reg/NN section matching the .reg section. */ bfd_map_over_sections (core_bfd, add_to_thread_list, bfd_get_section_by_name (core_bfd, ".reg")); if (ptid_equal (inferior_ptid, null_ptid)) { /* Either we found no .reg/NN section, and hence we have a non-threaded core (single-threaded, from gdb's perspective), or for some reason add_to_thread_list couldn't determine which was the "main" thread. The latter case shouldn't usually happen, but we're dealing with input here, which can always be broken in different ways. */ struct thread_info *thread = first_thread_of_process (-1); if (thread == NULL) { inferior_appeared (current_inferior (), CORELOW_PID); inferior_ptid = pid_to_ptid (CORELOW_PID); add_thread_silent (inferior_ptid); } else switch_to_thread (thread->ptid); } post_create_inferior (&core_ops, from_tty); /* Now go through the target stack looking for threads since there may be a thread_stratum target loaded on top of target core by now. The layer above should claim threads found in the BFD sections. */ gdb_target_find_new_threads (); p = bfd_core_file_failing_command (core_bfd); if (p) printf_filtered (_("Core was generated by `%s'.\n"), p); siggy = bfd_core_file_failing_signal (core_bfd); if (siggy > 0) { /* NOTE: target_signal_from_host() converts a target signal value into gdb's internal signal value. Unfortunately gdb's internal value is called ``target_signal'' and this function got the name ..._from_host(). */ enum target_signal sig = (core_gdbarch != NULL ? gdbarch_target_signal_from_host (core_gdbarch, siggy) : target_signal_from_host (siggy)); printf_filtered (_("Program terminated with signal %d, %s.\n"), siggy, target_signal_to_string (sig)); } /* Fetch all registers from core file. */ target_fetch_registers (get_current_regcache (), -1); /* Now, set up the frame cache, and print the top of stack. */ reinit_frame_cache (); print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); }