X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Ffbsd-nat.c;h=5ad0dda5b433dec171d889dd09567d5d2c9a86a9;hb=481695ed5f6e0a8a9c9c50bfac1cdd2b3151e6c9;hp=25952c3a69ba657bc3225bae76c94d5fec3295aa;hpb=4c7bf4f91b7dd3ccbd12be55316fca8817059a24;p=binutils-gdb.git diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index 25952c3a69b..5ad0dda5b43 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -18,6 +18,7 @@ along with this program. If not, see . */ #include "defs.h" +#include "byte-vector.h" #include "gdbcore.h" #include "inferior.h" #include "regcache.h" @@ -28,15 +29,20 @@ #include #include #include +#include #include -#ifdef HAVE_KINFO_GETVMMAP #include +#ifdef HAVE_KINFO_GETVMMAP #include +#else +#include "filestuff.h" #endif #include "elf-bfd.h" #include "fbsd-nat.h" +#include + /* Return the name of a file that can be opened to get the symbols for the child process identified by PID. */ @@ -72,6 +78,14 @@ fbsd_pid_to_exec_file (struct target_ops *self, int pid) } #ifdef HAVE_KINFO_GETVMMAP +/* Deleter for std::unique_ptr that invokes free. */ + +template +struct free_deleter +{ + void operator() (T *ptr) const { free (ptr); } +}; + /* Iterate over all the memory regions in the current inferior, calling FUNC for each memory region. OBFD is passed as the last argument to FUNC. */ @@ -81,20 +95,17 @@ fbsd_find_memory_regions (struct target_ops *self, find_memory_region_ftype func, void *obfd) { pid_t pid = ptid_get_pid (inferior_ptid); - struct kinfo_vmentry *vmentl, *kve; + struct kinfo_vmentry *kve; uint64_t size; - struct cleanup *cleanup; int i, nitems; - vmentl = kinfo_getvmmap (pid, &nitems); + std::unique_ptr> + vmentl (kinfo_getvmmap (pid, &nitems)); if (vmentl == NULL) perror_with_name (_("Couldn't fetch VM map entries.")); - cleanup = make_cleanup (free, vmentl); - for (i = 0; i < nitems; i++) + for (i = 0, kve = vmentl.get (); i < nitems; i++, kve++) { - kve = &vmentl[i]; - /* Skip unreadable segments and those where MAP_NOCORE has been set. */ if (!(kve->kve_protection & KVME_PROT_READ) || kve->kve_flags & KVME_FLAG_NOCOREDUMP) @@ -125,7 +136,6 @@ fbsd_find_memory_regions (struct target_ops *self, kve->kve_protection & KVME_PROT_WRITE, kve->kve_protection & KVME_PROT_EXEC, 1, obfd); } - do_cleanups (cleanup); return 0; } #else @@ -159,26 +169,21 @@ fbsd_find_memory_regions (struct target_ops *self, find_memory_region_ftype func, void *obfd) { pid_t pid = ptid_get_pid (inferior_ptid); - char *mapfilename; - FILE *mapfile; unsigned long start, end, size; char protection[4]; int read, write, exec; - struct cleanup *cleanup; - mapfilename = xstrprintf ("/proc/%ld/map", (long) pid); - cleanup = make_cleanup (xfree, mapfilename); - mapfile = fopen (mapfilename, "r"); + std::string mapfilename = string_printf ("/proc/%ld/map", (long) pid); + gdb_file_up mapfile (fopen (mapfilename.c_str (), "r")); if (mapfile == NULL) - error (_("Couldn't open %s."), mapfilename); - make_cleanup_fclose (mapfile); + error (_("Couldn't open %s."), mapfilename.c_str ()); if (info_verbose) fprintf_filtered (gdb_stdout, - "Reading memory regions from %s\n", mapfilename); + "Reading memory regions from %s\n", mapfilename.c_str ()); /* Now iterate until end-of-file. */ - while (fbsd_read_mapping (mapfile, &start, &end, &protection[0])) + while (fbsd_read_mapping (mapfile.get (), &start, &end, &protection[0])) { size = end - start; @@ -201,7 +206,6 @@ fbsd_find_memory_regions (struct target_ops *self, func (start, size, read, write, exec, 1, obfd); } - do_cleanups (cleanup); return 0; } #endif @@ -216,6 +220,135 @@ static enum target_xfer_status (*super_xfer_partial) (struct target_ops *ops, ULONGEST len, ULONGEST *xfered_len); +#ifdef PT_LWPINFO +/* Return the size of siginfo for the current inferior. */ + +#ifdef __LP64__ +union sigval32 { + int sival_int; + uint32_t sival_ptr; +}; + +/* This structure matches the naming and layout of `siginfo_t' in + . In particular, the `si_foo' macros defined in that + header can be used with both types to copy fields in the `_reason' + union. */ + +struct siginfo32 +{ + int si_signo; + int si_errno; + int si_code; + __pid_t si_pid; + __uid_t si_uid; + int si_status; + uint32_t si_addr; + union sigval32 si_value; + union + { + struct + { + int _trapno; + } _fault; + struct + { + int _timerid; + int _overrun; + } _timer; + struct + { + int _mqd; + } _mesgq; + struct + { + int32_t _band; + } _poll; + struct + { + int32_t __spare1__; + int __spare2__[7]; + } __spare__; + } _reason; +}; +#endif + +static size_t +fbsd_siginfo_size () +{ +#ifdef __LP64__ + struct gdbarch *gdbarch = get_frame_arch (get_current_frame ()); + + /* Is the inferior 32-bit? If so, use the 32-bit siginfo size. */ + if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) + return sizeof (struct siginfo32); +#endif + return sizeof (siginfo_t); +} + +/* Convert a native 64-bit siginfo object to a 32-bit object. Note + that FreeBSD doesn't support writing to $_siginfo, so this only + needs to convert one way. */ + +static void +fbsd_convert_siginfo (siginfo_t *si) +{ +#ifdef __LP64__ + struct gdbarch *gdbarch = get_frame_arch (get_current_frame ()); + + /* Is the inferior 32-bit? If not, nothing to do. */ + if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word != 32) + return; + + struct siginfo32 si32; + + si32.si_signo = si->si_signo; + si32.si_errno = si->si_errno; + si32.si_code = si->si_code; + si32.si_pid = si->si_pid; + si32.si_uid = si->si_uid; + si32.si_status = si->si_status; + si32.si_addr = (uintptr_t) si->si_addr; + + /* If sival_ptr is being used instead of sival_int on a big-endian + platform, then sival_int will be zero since it holds the upper + 32-bits of the pointer value. */ +#if _BYTE_ORDER == _BIG_ENDIAN + if (si->si_value.sival_int == 0) + si32.si_value.sival_ptr = (uintptr_t) si->si_value.sival_ptr; + else + si32.si_value.sival_int = si->si_value.sival_int; +#else + si32.si_value.sival_int = si->si_value.sival_int; +#endif + + /* Always copy the spare fields and then possibly overwrite them for + signal-specific or code-specific fields. */ + si32._reason.__spare__.__spare1__ = si->_reason.__spare__.__spare1__; + for (int i = 0; i < 7; i++) + si32._reason.__spare__.__spare2__[i] = si->_reason.__spare__.__spare2__[i]; + switch (si->si_signo) { + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + si32.si_trapno = si->si_trapno; + break; + } + switch (si->si_code) { + case SI_TIMER: + si32.si_timerid = si->si_timerid; + si32.si_overrun = si->si_overrun; + break; + case SI_MESGQ: + si32.si_mqd = si->si_mqd; + break; + } + + memcpy(si, &si32, sizeof (si32)); +#endif +} +#endif + /* Implement the "to_xfer_partial target_ops" method. */ static enum target_xfer_status @@ -228,10 +361,42 @@ fbsd_xfer_partial (struct target_ops *ops, enum target_object object, switch (object) { +#ifdef PT_LWPINFO + case TARGET_OBJECT_SIGNAL_INFO: + { + struct ptrace_lwpinfo pl; + size_t siginfo_size; + + /* FreeBSD doesn't support writing to $_siginfo. */ + if (writebuf != NULL) + return TARGET_XFER_E_IO; + + if (inferior_ptid.lwp_p ()) + pid = inferior_ptid.lwp (); + + siginfo_size = fbsd_siginfo_size (); + if (offset > siginfo_size) + return TARGET_XFER_E_IO; + + if (ptrace (PT_LWPINFO, pid, (PTRACE_TYPE_ARG3) &pl, sizeof (pl)) == -1) + return TARGET_XFER_E_IO; + + if (!(pl.pl_flags & PL_FLAG_SI)) + return TARGET_XFER_E_IO; + + fbsd_convert_siginfo (&pl.pl_siginfo); + if (offset + len > siginfo_size) + len = siginfo_size - offset; + + memcpy (readbuf, ((gdb_byte *) &pl.pl_siginfo) + offset, len); + *xfered_len = len; + return TARGET_XFER_OK; + } +#endif case TARGET_OBJECT_AUXV: { - struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); - unsigned char *buf; + gdb::byte_vector buf_storage; + gdb_byte *buf; size_t buflen; int mib[4]; @@ -249,8 +414,8 @@ fbsd_xfer_partial (struct target_ops *ops, enum target_object object, else { buflen = offset + len; - buf = XCNEWVEC (unsigned char, buflen); - cleanup = make_cleanup (xfree, buf); + buf_storage.resize (buflen); + buf = buf_storage.data (); } if (sysctl (mib, 4, buf, &buflen, NULL, 0) == 0) { @@ -264,11 +429,9 @@ fbsd_xfer_partial (struct target_ops *ops, enum target_object object, else buflen = 0; } - do_cleanups (cleanup); *xfered_len = buflen; return (buflen == 0) ? TARGET_XFER_EOF : TARGET_XFER_OK; } - do_cleanups (cleanup); return TARGET_XFER_E_IO; } default: @@ -368,7 +531,7 @@ fbsd_thread_alive (struct target_ops *ops, ptid_t ptid) /* Convert PTID to a string. Returns the string in a static buffer. */ -static char * +static const char * fbsd_pid_to_str (struct target_ops *ops, ptid_t ptid) { lwpid_t lwp; @@ -462,8 +625,6 @@ fbsd_enable_proc_events (pid_t pid) static void fbsd_add_threads (pid_t pid) { - struct cleanup *cleanup; - lwpid_t *lwps; int i, nlwps; gdb_assert (!in_thread_list (pid_to_ptid (pid))); @@ -471,10 +632,9 @@ fbsd_add_threads (pid_t pid) if (nlwps == -1) perror_with_name (("ptrace")); - lwps = XCNEWVEC (lwpid_t, nlwps); - cleanup = make_cleanup (xfree, lwps); + gdb::unique_xmalloc_ptr lwps (XCNEWVEC (lwpid_t, nlwps)); - nlwps = ptrace (PT_GETLWPLIST, pid, (caddr_t) lwps, nlwps); + nlwps = ptrace (PT_GETLWPLIST, pid, (caddr_t) lwps.get (), nlwps); if (nlwps == -1) perror_with_name (("ptrace")); @@ -501,7 +661,6 @@ fbsd_add_threads (pid_t pid) add_thread (ptid); } } - do_cleanups (cleanup); } /* Implement the "to_update_thread_list" target_ops method. */ @@ -554,13 +713,7 @@ fbsd_update_thread_list (struct target_ops *ops) sake. FreeBSD versions newer than 9.1 contain both fixes. */ -struct fbsd_fork_info -{ - struct fbsd_fork_info *next; - ptid_t ptid; -}; - -static struct fbsd_fork_info *fbsd_pending_children; +static std::list fbsd_pending_children; /* Record a new child process event that is reported before the corresponding fork event in the parent. */ @@ -568,11 +721,7 @@ static struct fbsd_fork_info *fbsd_pending_children; static void fbsd_remember_child (ptid_t pid) { - struct fbsd_fork_info *info = XCNEW (struct fbsd_fork_info); - - info->ptid = pid; - info->next = fbsd_pending_children; - fbsd_pending_children = info; + fbsd_pending_children.push_front (pid); } /* Check for a previously-recorded new child process event for PID. @@ -581,39 +730,26 @@ fbsd_remember_child (ptid_t pid) static ptid_t fbsd_is_child_pending (pid_t pid) { - struct fbsd_fork_info *info, *prev; - ptid_t ptid; - - prev = NULL; - for (info = fbsd_pending_children; info; prev = info, info = info->next) - { - if (ptid_get_pid (info->ptid) == pid) - { - if (prev == NULL) - fbsd_pending_children = info->next; - else - prev->next = info->next; - ptid = info->ptid; - xfree (info); - return ptid; - } - } + for (auto it = fbsd_pending_children.begin (); + it != fbsd_pending_children.end (); it++) + if (it->pid () == pid) + { + ptid_t ptid = *it; + fbsd_pending_children.erase (it); + return ptid; + } return null_ptid; } #ifndef PTRACE_VFORK -static struct fbsd_fork_info *fbsd_pending_vfork_done; +static std::forward_list fbsd_pending_vfork_done; /* Record a pending vfork done event. */ static void fbsd_add_vfork_done (ptid_t pid) { - struct fbsd_fork_info *info = XCNEW (struct fbsd_fork_info); - - info->ptid = pid; - info->next = fbsd_pending_vfork_done; - fbsd_pending_vfork_done = info; + fbsd_pending_vfork_done.push_front (pid); } /* Check for a pending vfork done event for a specific PID. */ @@ -621,13 +757,10 @@ fbsd_add_vfork_done (ptid_t pid) static int fbsd_is_vfork_done_pending (pid_t pid) { - struct fbsd_fork_info *info; - - for (info = fbsd_pending_vfork_done; info != NULL; info = info->next) - { - if (ptid_get_pid (info->ptid) == pid) - return 1; - } + for (auto it = fbsd_pending_vfork_done.begin (); + it != fbsd_pending_vfork_done.end (); it++) + if (it->pid () == pid) + return 1; return 0; } @@ -637,15 +770,10 @@ fbsd_is_vfork_done_pending (pid_t pid) static ptid_t fbsd_next_vfork_done (void) { - struct fbsd_fork_info *info; - ptid_t ptid; - - if (fbsd_pending_vfork_done != NULL) + if (!fbsd_pending_vfork_done.empty ()) { - info = fbsd_pending_vfork_done; - fbsd_pending_vfork_done = info->next; - ptid = info->ptid; - xfree (info); + ptid_t ptid = fbsd_pending_vfork_done.front (); + fbsd_pending_vfork_done.pop_front (); return ptid; } return null_ptid; @@ -653,38 +781,6 @@ fbsd_next_vfork_done (void) #endif #endif -static int -resume_one_thread_cb (struct thread_info *tp, void *data) -{ - ptid_t *ptid = (ptid_t *) data; - int request; - - if (ptid_get_pid (tp->ptid) != ptid_get_pid (*ptid)) - return 0; - - if (ptid_get_lwp (tp->ptid) == ptid_get_lwp (*ptid)) - request = PT_RESUME; - else - request = PT_SUSPEND; - - if (ptrace (request, ptid_get_lwp (tp->ptid), NULL, 0) == -1) - perror_with_name (("ptrace")); - return 0; -} - -static int -resume_all_threads_cb (struct thread_info *tp, void *data) -{ - ptid_t *filter = (ptid_t *) data; - - if (!ptid_match (tp->ptid, *filter)) - return 0; - - if (ptrace (PT_RESUME, ptid_get_lwp (tp->ptid), NULL, 0) == -1) - perror_with_name (("ptrace")); - return 0; -} - /* Implement the "to_resume" target_ops method. */ static void @@ -711,13 +807,37 @@ fbsd_resume (struct target_ops *ops, if (ptid_lwp_p (ptid)) { /* If ptid is a specific LWP, suspend all other LWPs in the process. */ - iterate_over_threads (resume_one_thread_cb, &ptid); + struct thread_info *tp; + int request; + + ALL_NON_EXITED_THREADS (tp) + { + if (ptid_get_pid (tp->ptid) != ptid_get_pid (ptid)) + continue; + + if (ptid_get_lwp (tp->ptid) == ptid_get_lwp (ptid)) + request = PT_RESUME; + else + request = PT_SUSPEND; + + if (ptrace (request, ptid_get_lwp (tp->ptid), NULL, 0) == -1) + perror_with_name (("ptrace")); + } } else { /* If ptid is a wildcard, resume all matching threads (they won't run until the process is continued however). */ - iterate_over_threads (resume_all_threads_cb, &ptid); + struct thread_info *tp; + + ALL_NON_EXITED_THREADS (tp) + { + if (!ptid_match (tp->ptid, ptid)) + continue; + + if (ptrace (PT_RESUME, ptid_get_lwp (tp->ptid), NULL, 0) == -1) + perror_with_name (("ptrace")); + } ptid = inferior_ptid; } super_resume (ops, ptid, step, signo); @@ -1096,9 +1216,6 @@ fbsd_nat_add_target (struct target_ops *t) add_target (t); } -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_fbsd_nat; - void _initialize_fbsd_nat (void) {