diff options
author | skreuzer <skreuzer@FreeBSD.org> | 2010-11-17 04:39:48 +0800 |
---|---|---|
committer | skreuzer <skreuzer@FreeBSD.org> | 2010-11-17 04:39:48 +0800 |
commit | 7ad431a7e82d57d4afab6d747882ba86070e03cb (patch) | |
tree | aa06ba9a79ad0779c9615dd96d87eab8f5709a44 /devel/gdb | |
parent | 3f5c6ce007882f6ec090afee1555d35647182919 (diff) | |
download | freebsd-ports-gnome-7ad431a7e82d57d4afab6d747882ba86070e03cb.tar.gz freebsd-ports-gnome-7ad431a7e82d57d4afab6d747882ba86070e03cb.tar.zst freebsd-ports-gnome-7ad431a7e82d57d4afab6d747882ba86070e03cb.zip |
GDB is a source-level debugger for Ada, C, C++, Objective-C, Pascal and
many other languages. GDB can target (i.e., debug programs running on)
more than a dozen different processor architectures, and GDB itself can
run on most popular GNU/Linux, Unix and Microsoft Windows variants.
This version of gdb has been modified by jhb@ to recognize freebsd threads
Reviewed by: John Baldwin <jhb@FreeBSD.org>, swell.k@gmail.com
Diffstat (limited to 'devel/gdb')
-rw-r--r-- | devel/gdb/Makefile | 67 | ||||
-rw-r--r-- | devel/gdb/distinfo | 3 | ||||
-rw-r--r-- | devel/gdb/files/fbsd-threads.c | 1530 | ||||
-rw-r--r-- | devel/gdb/files/patch-gdb-Makefile.in | 38 | ||||
-rw-r--r-- | devel/gdb/files/patch-gdb-amd64fbsd-nat.c | 58 | ||||
-rw-r--r-- | devel/gdb/files/patch-gdb-amd64fbsd-tdep.c | 68 | ||||
-rw-r--r-- | devel/gdb/files/patch-gdb-configure.tgt | 20 | ||||
-rw-r--r-- | devel/gdb/files/patch-gdb-i386bsd-nat.c | 20 | ||||
-rw-r--r-- | devel/gdb/files/patch-gdb-i386bsd-nat.h | 15 | ||||
-rw-r--r-- | devel/gdb/files/patch-gdb-i386fbsd-nat.c | 68 | ||||
-rw-r--r-- | devel/gdb/files/patch-gdb-i386fbsd-tdep.c | 68 | ||||
-rw-r--r-- | devel/gdb/files/patch-unified | 25 | ||||
-rw-r--r-- | devel/gdb/pkg-descr | 6 | ||||
-rw-r--r-- | devel/gdb/pkg-plist | 2 |
14 files changed, 1988 insertions, 0 deletions
diff --git a/devel/gdb/Makefile b/devel/gdb/Makefile new file mode 100644 index 000000000000..12f52c7b7055 --- /dev/null +++ b/devel/gdb/Makefile @@ -0,0 +1,67 @@ +# ex:ts=8 +# Ports collection makefile for: GDB 7.1 +# Date created: 16 November 2010 +# Whom: Steven Kreuzer <skreuzer@FreeBSD.org> +# +# $FreeBSD$ +# + +PORTNAME= gdb +PORTVERSION= 7.1 +CATEGORIES= devel +MASTER_SITES= ${MASTER_SITE_GNU:S,$,:gdb,} +MASTER_SITE_SUBDIR=gdb/:gdb +DISTFILES= ${PORTNAME}-${PORTVERSION}${EXTRACT_SUFX}:gdb + +MAINTAINER= skreuzer@FreeBSD.org +COMMENT= GNU GDB of newer version than comes with the system + +LICENSE= GPLv3 + +USE_BZIP2= yes +USE_GMAKE= yes +USE_ICONV= yes +GNU_CONFIGURE= yes +CONFIGURE_ENV+= CONFIGURED_M4=m4 CONFIGURED_BISON=byacc LDFLAGS="${LDFLAGS}" +CONFIGURE_ARGS= --program-suffix=${PORTVERSION:S/.//g} \ + --with-libiconv-prefix=${LOCALBASE} \ + --with-system-readline \ + --without-expat \ + --without-libunwind \ + --without-python \ + --enable-target=all \ + --enable-tui +CFLAGS:= ${CFLAGS:C/ +$//} # blanks at EOL creep in sometimes +CFLAGS+= -I${LOCALBASE}/include +CFLAGS+= -DRL_NO_COMPAT +LDFLAGS+= -L${LOCALBASE}/lib +EXCLUDE= dejagnu expect readline sim texinfo intl +EXTRACT_AFTER_ARGS=| ${TAR} -xf - ${EXCLUDE:S/^/--exclude /} +VER= ${PORTVERSION:S/.//} +PLIST_SUB= VER=${VER} +MAN1= gdb${VER}.1 + +ONLY_FOR_ARCHS= i386 amd64 # untested elsewhere, might work + +.include <bsd.port.pre.mk> + +# XXX: add OSVERSION check after readline is removed from base +.if exists(${LOCALBASE}/lib/libreadline.so) +LIB_DEPENDS+= readline.6:${PORTSDIR}/devel/readline +.endif + +.if ${ARCH} == "amd64" +CONFIGURE_TARGET= x86_64-portbld-freebsd${OSREL} +.endif + +post-patch: + @${REINPLACE_CMD} -e 's/$$/ [GDB v${PORTVERSION} for FreeBSD]/' \ + ${WRKSRC}/gdb/version.in + @${CP} ${FILESDIR}/fbsd-threads.c ${WRKSRC}/gdb + +do-install: + ${INSTALL_PROGRAM} ${WRKSRC}/gdb/gdb ${PREFIX}/bin/gdb${VER} + ${LN} ${PREFIX}/bin/gdb${VER} ${PREFIX}/bin/gdbtui${VER} + ${INSTALL_MAN} ${WRKSRC}/gdb/gdb.1 ${MAN1PREFIX}/man/man1/gdb${VER}.1 + +.include <bsd.port.post.mk> diff --git a/devel/gdb/distinfo b/devel/gdb/distinfo new file mode 100644 index 000000000000..fda099d81969 --- /dev/null +++ b/devel/gdb/distinfo @@ -0,0 +1,3 @@ +MD5 (gdb-7.1.tar.bz2) = 21dce610476c054687b52770d2ddc657 +SHA256 (gdb-7.1.tar.bz2) = 142c27d7970a4e652dc225d61d887777ae00cf22fdd75cd1e8e4e13bfbd85352 +SIZE (gdb-7.1.tar.bz2) = 17977195 diff --git a/devel/gdb/files/fbsd-threads.c b/devel/gdb/files/fbsd-threads.c new file mode 100644 index 000000000000..8331b38b963f --- /dev/null +++ b/devel/gdb/files/fbsd-threads.c @@ -0,0 +1,1530 @@ +/* $FreeBSD: /tmp/pcvs/ports/devel/gdb/files/fbsd-threads.c,v 1.1 2010-11-16 20:39:48 skreuzer Exp $ */ +/* FreeBSD libthread_db assisted debugging support. + Copyright 1999, 2000, 2001 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <dlfcn.h> +#include <sys/types.h> +#include <sys/ptrace.h> +#include <signal.h> + +#include "proc_service.h" +#include "thread_db.h" + +#include "defs.h" +#include "bfd.h" +#include "elf-bfd.h" +#include "gdb_assert.h" +#include "gdbcore.h" +#include "gdbthread.h" +#include "inferior.h" +#include "objfiles.h" +#include "regcache.h" +#include "symfile.h" +#include "symtab.h" +#include "target.h" +#include "observer.h" +#include "gdbcmd.h" +#include "gregset.h" +#ifdef PT_GETXMMREGS +#include "i387-tdep.h" +#endif + +#define LIBTHREAD_DB_SO "libthread_db.so" + +struct ps_prochandle +{ + pid_t pid; +}; + +/* This module's target vectors. */ +static struct target_ops fbsd_thread_ops; + +/* Non-zero if there is a thread module */ +static int fbsd_thread_present; + +/* Non-zero if we're using this module's target vector. */ +static int fbsd_thread_active; + +/* Non-zero if we have to keep this module's target vector active + across re-runs. */ +static int keep_thread_db; + +/* Structure that identifies the child process for the + <proc_service.h> interface. */ +static struct ps_prochandle proc_handle; + +/* Connection to the libthread_db library. */ +static td_thragent_t *thread_agent; + +/* The last thread we are single stepping */ +static ptid_t last_single_step_thread; + +/* Pointers to the libthread_db functions. */ + +static td_err_e (*td_init_p) (void); + +static td_err_e (*td_ta_new_p) (struct ps_prochandle *ps, td_thragent_t **ta); +static td_err_e (*td_ta_delete_p) (td_thragent_t *); +static td_err_e (*td_ta_map_id2thr_p) (const td_thragent_t *ta, thread_t pt, + td_thrhandle_t *__th); +static td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta, lwpid_t lwpid, + td_thrhandle_t *th); +static td_err_e (*td_ta_thr_iter_p) (const td_thragent_t *ta, + td_thr_iter_f *callback, + void *cbdata_p, td_thr_state_e state, + int ti_pri, sigset_t *ti_sigmask_p, + unsigned int ti_user_flags); +static td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta, + td_event_e event, td_notify_t *ptr); +static td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta, + td_thr_events_t *event); +static td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta, + td_event_msg_t *msg); +static td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th, + td_thrinfo_t *infop); +#ifdef PT_GETXMMREGS +static td_err_e (*td_thr_getxmmregs_p) (const td_thrhandle_t *th, + char *regset); +#endif +static td_err_e (*td_thr_getfpregs_p) (const td_thrhandle_t *th, + prfpregset_t *regset); +static td_err_e (*td_thr_getgregs_p) (const td_thrhandle_t *th, + prgregset_t gregs); +#ifdef PT_GETXMMREGS +static td_err_e (*td_thr_setxmmregs_p) (const td_thrhandle_t *th, + const char *fpregs); +#endif +static td_err_e (*td_thr_setfpregs_p) (const td_thrhandle_t *th, + const prfpregset_t *fpregs); +static td_err_e (*td_thr_setgregs_p) (const td_thrhandle_t *th, + prgregset_t gregs); +static td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, int event); + +static td_err_e (*td_thr_sstep_p) (td_thrhandle_t *th, int step); + +static td_err_e (*td_ta_tsd_iter_p) (const td_thragent_t *ta, + td_key_iter_f *func, void *data); +static td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th, + void *map_address, + size_t offset, void **address); +static td_err_e (*td_thr_dbsuspend_p) (const td_thrhandle_t *); +static td_err_e (*td_thr_dbresume_p) (const td_thrhandle_t *); + +static CORE_ADDR td_create_bp_addr; + +/* Location of the thread death event breakpoint. */ +static CORE_ADDR td_death_bp_addr; + +/* Prototypes for local functions. */ +static void fbsd_thread_find_new_threads (struct target_ops *ops); +static int fbsd_thread_alive (struct target_ops *ops, ptid_t ptid); +static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, + const td_thrinfo_t *ti_p, int verbose); +static void fbsd_thread_detach (struct target_ops *ops, char *args, + int from_tty); + +/* Building process ids. */ + +#define GET_PID(ptid) ptid_get_pid (ptid) +#define GET_LWP(ptid) ptid_get_lwp (ptid) +#define GET_THREAD(ptid) ptid_get_tid (ptid) + +#define IS_LWP(ptid) (GET_LWP (ptid) != 0) +#define IS_THREAD(ptid) (GET_THREAD (ptid) != 0) + +#define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0) +#define BUILD_THREAD(tid, pid) ptid_build (pid, 0, tid) + +static char * +thread_db_err_str (td_err_e err) +{ + static char buf[64]; + + switch (err) + { + case TD_OK: + return "generic 'call succeeded'"; + case TD_ERR: + return "generic error"; + case TD_NOTHR: + return "no thread to satisfy query"; + case TD_NOSV: + return "no sync handle to satisfy query"; + case TD_NOLWP: + return "no LWP to satisfy query"; + case TD_BADPH: + return "invalid process handle"; + case TD_BADTH: + return "invalid thread handle"; + case TD_BADSH: + return "invalid synchronization handle"; + case TD_BADTA: + return "invalid thread agent"; + case TD_BADKEY: + return "invalid key"; + case TD_NOMSG: + return "no event message for getmsg"; + case TD_NOFPREGS: + return "FPU register set not available"; + case TD_NOLIBTHREAD: + return "application not linked with libthread"; + case TD_NOEVENT: + return "requested event is not supported"; + case TD_NOCAPAB: + return "capability not available"; + case TD_DBERR: + return "debugger service failed"; + case TD_NOAPLIC: + return "operation not applicable to"; + case TD_NOTSD: + return "no thread-specific data for this thread"; + case TD_MALLOC: + return "malloc failed"; + case TD_PARTIALREG: + return "only part of register set was written/read"; + case TD_NOXREGS: + return "X register set not available for this thread"; + default: + snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err); + return buf; + } +} + +static char * +thread_db_state_str (td_thr_state_e state) +{ + static char buf[64]; + + switch (state) + { + case TD_THR_STOPPED: + return "stopped by debugger"; + case TD_THR_RUN: + return "runnable"; + case TD_THR_ACTIVE: + return "active"; + case TD_THR_ZOMBIE: + return "zombie"; + case TD_THR_SLEEP: + return "sleeping"; + case TD_THR_STOPPED_ASLEEP: + return "stopped by debugger AND blocked"; + default: + snprintf (buf, sizeof (buf), "unknown thread_db state %d", state); + return buf; + } +} + +/* Convert LWP to user-level thread id. */ +static ptid_t +thread_from_lwp (ptid_t ptid, td_thrhandle_t *th, td_thrinfo_t *ti) +{ + td_err_e err; + + gdb_assert (IS_LWP (ptid)); + + if (fbsd_thread_active) + { + err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), th); + if (err == TD_OK) + { + err = td_thr_get_info_p (th, ti); + if (err != TD_OK) + error ("Cannot get thread info: %s", thread_db_err_str (err)); + return BUILD_THREAD (ti->ti_tid, GET_PID (ptid)); + } + } + + /* the LWP is not mapped to user thread */ + return BUILD_LWP (GET_LWP (ptid), GET_PID (ptid)); +} + +static void +fbsd_core_get_first_lwp (bfd *abfd, asection *asect, void *obj) +{ + if (strncmp (bfd_section_name (abfd, asect), ".reg/", 5) != 0) + return; + + if (*(lwpid_t *)obj != 0) + return; + + *(lwpid_t *)obj = atoi (bfd_section_name (abfd, asect) + 5); +} + +static long +get_current_lwp (int pid) +{ + struct ptrace_lwpinfo pl; + lwpid_t lwpid; + + if (!target_has_execution) + { + lwpid = 0; + bfd_map_over_sections (core_bfd, fbsd_core_get_first_lwp, &lwpid); + return lwpid; + } + if (ptrace (PT_LWPINFO, pid, (caddr_t)&pl, sizeof(pl))) + perror_with_name("PT_LWPINFO"); + + return (long)pl.pl_lwpid; +} + +static void +get_current_thread () +{ + td_thrhandle_t th; + td_thrinfo_t ti; + long lwp; + ptid_t tmp, ptid; + + lwp = get_current_lwp (proc_handle.pid); + tmp = BUILD_LWP (lwp, proc_handle.pid); + ptid = thread_from_lwp (tmp, &th, &ti); + if (!in_thread_list (ptid)) + { + attach_thread (ptid, &th, &ti, 1); + } + inferior_ptid = ptid; +} + +static CORE_ADDR +extract_func_ptr(void *value) +{ + + return (extract_typed_address + ((gdb_byte *)value, + builtin_type (target_gdbarch)->builtin_func_ptr)); +} + +static CORE_ADDR +extract_data_ptr(void *value) +{ + + return (extract_typed_address + ((gdb_byte *)value, + builtin_type (target_gdbarch)->builtin_data_ptr)); +} + +static td_err_e +enable_thread_event (td_thragent_t *thread_agent, int event, CORE_ADDR *bp) +{ + td_notify_t notify; + td_err_e err; + + /* Get the breakpoint address for thread EVENT. */ + err = td_ta_event_addr_p (thread_agent, event, ¬ify); + if (err != TD_OK) + return err; + + /* Set up the breakpoint. */ + (*bp) = (gdbarch_convert_from_func_ptr_addr + (target_gdbarch, + extract_func_ptr(¬ify.u.bptaddr), + ¤t_target)); + create_thread_event_breakpoint (target_gdbarch, (*bp)); + + return TD_OK; +} + +static void +enable_thread_event_reporting (void) +{ + td_thr_events_t events; + td_notify_t notify; + td_err_e err; + + /* We cannot use the thread event reporting facility if these + functions aren't available. */ + if (td_ta_event_addr_p == NULL || td_ta_set_event_p == NULL + || td_ta_event_getmsg_p == NULL || td_thr_event_enable_p == NULL) + return; + + /* Set the process wide mask saying which events we're interested in. */ + td_event_emptyset (&events); + td_event_addset (&events, TD_CREATE); + td_event_addset (&events, TD_DEATH); + + err = td_ta_set_event_p (thread_agent, &events); + if (err != TD_OK) + { + warning ("Unable to set global thread event mask: %s", + thread_db_err_str (err)); + return; + } + + /* Delete previous thread event breakpoints, if any. */ + remove_thread_event_breakpoints (); + td_create_bp_addr = 0; + td_death_bp_addr = 0; + + /* Set up the thread creation event. */ + err = enable_thread_event (thread_agent, TD_CREATE, &td_create_bp_addr); + if (err != TD_OK) + { + warning ("Unable to get location for thread creation breakpoint: %s", + thread_db_err_str (err)); + return; + } + + /* Set up the thread death event. */ + err = enable_thread_event (thread_agent, TD_DEATH, &td_death_bp_addr); + if (err != TD_OK) + { + warning ("Unable to get location for thread death breakpoint: %s", + thread_db_err_str (err)); + return; + } +} + +static void +disable_thread_event_reporting (void) +{ + td_thr_events_t events; + + /* Set the process wide mask saying we aren't interested in any + events anymore. */ + td_event_emptyset (&events); + td_ta_set_event_p (thread_agent, &events); + + td_create_bp_addr = 0; + td_death_bp_addr = 0; +} + +static void +fbsd_thread_activate (void) +{ + fbsd_thread_active = 1; + init_thread_list(); + if (target_has_execution) + enable_thread_event_reporting (); + fbsd_thread_find_new_threads (NULL); + get_current_thread (); +} + +static void +fbsd_thread_deactivate (void) +{ + if (target_has_execution) + disable_thread_event_reporting(); + td_ta_delete_p (thread_agent); + + inferior_ptid = pid_to_ptid (proc_handle.pid); + proc_handle.pid = 0; + fbsd_thread_active = 0; + fbsd_thread_present = 0; +} + +static void +check_for_thread_db (void) +{ + td_err_e err; + + if (td_ta_new_p == NULL) + return; + + /* Nothing to do. The thread library was already detected and the + target vector was already activated. */ + if (fbsd_thread_active) + return; + + /* Now, initialize libthread_db. This needs to be done after the + shared libraries are located because it needs information from + the user's thread library. */ + + err = td_init_p (); + if (err != TD_OK) + { + warning ("Cannot initialize libthread_db: %s", thread_db_err_str (err)); + return; + } + + /* Initialize the structure that identifies the child process. Note + that at this point there is no guarantee that we actually have a + child process. */ + proc_handle.pid = GET_PID (inferior_ptid); + + /* Now attempt to open a connection to the thread library. */ + err = td_ta_new_p (&proc_handle, &thread_agent); + switch (err) + { + case TD_NOLIBTHREAD: + /* No thread library was detected. */ + break; + + case TD_OK: + /* The thread library was detected. Activate the thread_db target. */ + push_target(&fbsd_thread_ops); + fbsd_thread_present = 1; + fbsd_thread_activate(); + + break; + + default: + warning ("Cannot initialize thread debugging library: %s", + thread_db_err_str (err)); + break; + } +} + +static void +fbsd_thread_new_objfile (struct objfile *objfile) +{ + if (objfile != NULL) + check_for_thread_db (); +} + +static void +fbsd_thread_detach (struct target_ops *ops, char *args, int from_tty) +{ + struct target_ops *beneath = find_target_beneath (ops); + + fbsd_thread_deactivate (); + + /* Delete thread event breakpoints, if any. */ + remove_thread_event_breakpoints (); + + unpush_target (&fbsd_thread_ops); + + beneath->to_detach (beneath, args, from_tty); +} + +static int +suspend_thread_callback (const td_thrhandle_t *th_p, void *data) +{ + int err = td_thr_dbsuspend_p (th_p); + if (err != 0) + fprintf_filtered(gdb_stderr, "%s %s\n", __func__, thread_db_err_str (err)); + return (err); +} + +static int +resume_thread_callback (const td_thrhandle_t *th_p, void *data) +{ + int err = td_thr_dbresume_p (th_p); + if (err != 0) + fprintf_filtered(gdb_stderr, "%s %s\n", __func__, thread_db_err_str (err)); + return (err); +} + +static void +fbsd_thread_resume (struct target_ops *ops, + ptid_t ptid, int step, enum target_signal signo) +{ + struct target_ops *beneath = find_target_beneath (ops); + td_thrhandle_t th; + td_thrinfo_t ti; + ptid_t work_ptid; + int resume_all, ret; + long lwp, thvalid = 0; + + if (!fbsd_thread_active) + { + // XXX: I don't think this can happen + printf_unfiltered ("%s: called without active threads\n", __func__); + beneath->to_resume (beneath, ptid, step, signo); + return; + } + + if (GET_PID(ptid) != -1 && step != 0) + { + resume_all = 0; + work_ptid = ptid; + } + else + { + resume_all = 1; + work_ptid = inferior_ptid; + } + + lwp = GET_LWP (work_ptid); + if (lwp == 0) + { + /* check user thread */ + ret = td_ta_map_id2thr_p (thread_agent, GET_THREAD(work_ptid), &th); + if (ret) + error ("%s: %s", __func__, thread_db_err_str (ret)); + + /* For M:N thread, we need to tell UTS to set/unset single step + flag at context switch time, the flag will be written into + thread mailbox. This becauses some architecture may not have + machine single step flag in ucontext, so we put the flag in mailbox, + when the thread switches back, kse_switchin restores the single step + state. */ + ret = td_thr_sstep_p (&th, step); + if (ret) + error ("%s: %s", __func__, thread_db_err_str (ret)); + ret = td_thr_get_info_p (&th, &ti); + if (ret) + error ("%s: %s", __func__, thread_db_err_str (ret)); + thvalid = 1; + lwp = ti.ti_lid; + } + + if (lwp) + { + int req = step ? PT_SETSTEP : PT_CLEARSTEP; + if (ptrace (req, (pid_t) lwp, (caddr_t) 1, target_signal_to_host(signo))) + perror_with_name ("PT_SETSTEP/PT_CLEARSTEP"); + } + + if (!ptid_equal (last_single_step_thread, null_ptid)) + { + ret = td_ta_thr_iter_p (thread_agent, resume_thread_callback, NULL, + TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, + TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); + if (ret != TD_OK) + error ("resume error: %s", thread_db_err_str (ret)); + } + + if (!resume_all) + { + ret = td_ta_thr_iter_p (thread_agent, suspend_thread_callback, NULL, + TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, + TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); + if (ret != TD_OK) + error ("suspend error: %s", thread_db_err_str (ret)); + last_single_step_thread = work_ptid; + } + else + last_single_step_thread = null_ptid; + + if (thvalid) + { + ret = td_thr_dbresume_p (&th); + if (ret != TD_OK) + error ("resume error: %s", thread_db_err_str (ret)); + } + else + { + /* it is not necessary, put it here for completness */ + ret = ptrace(PT_RESUME, lwp, 0, 0); + } + + /* now continue the process, suspended thread wont run */ + if (ptrace (PT_CONTINUE, proc_handle.pid , (caddr_t)1, + target_signal_to_host(signo))) + perror_with_name ("PT_CONTINUE"); +} + +static void +attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, + const td_thrinfo_t *ti_p, int verbose) +{ + td_err_e err; + + /* Add the thread to GDB's thread list. */ + if (!in_thread_list (ptid)) + add_thread (ptid); + + if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE) + return; /* A zombie thread -- do not attach. */ + + if (! IS_THREAD(ptid)) + return; + if (!target_has_execution) + return; + /* Enable thread event reporting for this thread. */ + err = td_thr_event_enable_p (th_p, 1); + if (err != TD_OK) + error ("Cannot enable thread event reporting for %s: %s", + target_pid_to_str (ptid), thread_db_err_str (err)); +} + +static void +detach_thread (ptid_t ptid, int verbose) +{ + if (verbose) + printf_unfiltered ("[%s exited]\n", target_pid_to_str (ptid)); +} + +static void +check_event (ptid_t ptid) +{ + struct regcache *regcache = get_thread_regcache (ptid); + struct gdbarch *gdbarch = get_regcache_arch (regcache); + td_event_msg_t msg; + td_thrinfo_t ti; + td_err_e err; + CORE_ADDR stop_pc; + int loop = 0; + + /* Bail out early if we're not at a thread event breakpoint. */ + stop_pc = regcache_read_pc (regcache) + - gdbarch_decr_pc_after_break (gdbarch); + if (stop_pc != td_create_bp_addr && stop_pc != td_death_bp_addr) + return; + loop = 1; + + do + { + err = td_ta_event_getmsg_p (thread_agent, &msg); + if (err != TD_OK) + { + if (err == TD_NOMSG) + return; + error ("Cannot get thread event message: %s", + thread_db_err_str (err)); + } + err = td_thr_get_info_p ((void *)(uintptr_t)msg.th_p, &ti); + if (err != TD_OK) + error ("Cannot get thread info: %s", thread_db_err_str (err)); + ptid = BUILD_THREAD (ti.ti_tid, GET_PID (ptid)); + switch (msg.event) + { + case TD_CREATE: + /* We may already know about this thread, for instance when the + user has issued the `info threads' command before the SIGTRAP + for hitting the thread creation breakpoint was reported. */ + attach_thread (ptid, (void *)(uintptr_t)msg.th_p, &ti, 1); + break; + case TD_DEATH: + if (!in_thread_list (ptid)) + error ("Spurious thread death event."); + detach_thread (ptid, 1); + break; + default: + error ("Spurious thread event."); + } + } + while (loop); +} + +static ptid_t +fbsd_thread_wait (struct target_ops *ops, + ptid_t ptid, struct target_waitstatus *ourstatus, int options) +{ + struct target_ops *beneath = find_target_beneath (ops); + ptid_t ret; + long lwp; + CORE_ADDR stop_pc; + td_thrhandle_t th; + td_thrinfo_t ti; + + ret = beneath->to_wait (beneath, ptid, ourstatus, options); + if (GET_PID(ret) >= 0 && ourstatus->kind == TARGET_WAITKIND_STOPPED) + { + lwp = get_current_lwp (GET_PID(ret)); + ret = thread_from_lwp (BUILD_LWP(lwp, GET_PID(ret)), + &th, &ti); + if (!in_thread_list(ret)) { + /* + * We have to enable event reporting for initial thread + * which was not mapped before. + */ + attach_thread(ret, &th, &ti, 1); + } + if (ourstatus->value.sig == TARGET_SIGNAL_TRAP) + check_event(ret); + /* this is a hack, if an event won't cause gdb to stop, for example, + SIGARLM, gdb resumes the process immediatly without setting + inferior_ptid to the new thread returned here, this is a bug + because inferior_ptid may already not exist there, and passing + a none existing thread to fbsd_thread_resume causes error. */ + if (!fbsd_thread_alive (ops, inferior_ptid)) + { + delete_thread (inferior_ptid); + inferior_ptid = ret; + } + } + + return (ret); +} + +static void +fbsd_lwp_fetch_registers (struct target_ops *ops, + struct regcache *regcache, int regnum) +{ + gregset_t gregs; + fpregset_t fpregs; + lwpid_t lwp; +#ifdef PT_GETXMMREGS + char xmmregs[512]; +#endif + + if (!target_has_execution) + { + struct target_ops *beneath = find_target_beneath (ops); + + beneath->to_fetch_registers (ops, regcache, regnum); + return; + } + + lwp = GET_LWP (inferior_ptid); + + if (ptrace (PT_GETREGS, lwp, (caddr_t) &gregs, 0) == -1) + error ("Cannot get lwp %d registers: %s\n", lwp, safe_strerror (errno)); + supply_gregset (regcache, &gregs); + +#ifdef PT_GETXMMREGS + if (ptrace (PT_GETXMMREGS, lwp, xmmregs, 0) == 0) + { + i387_supply_fxsave (regcache, -1, xmmregs); + } + else + { +#endif + if (ptrace (PT_GETFPREGS, lwp, (caddr_t) &fpregs, 0) == -1) + error ("Cannot get lwp %d registers: %s\n ", lwp, safe_strerror (errno)); + supply_fpregset (regcache, &fpregs); +#ifdef PT_GETXMMREGS + } +#endif +} + +static void +fbsd_thread_fetch_registers (struct target_ops *ops, + struct regcache *regcache, int regnum) +{ + prgregset_t gregset; + prfpregset_t fpregset; + td_thrhandle_t th; + td_err_e err; +#ifdef PT_GETXMMREGS + char xmmregs[512]; +#endif + + if (!IS_THREAD (inferior_ptid)) + { + fbsd_lwp_fetch_registers (ops, regcache, regnum); + return; + } + + err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (inferior_ptid), &th); + if (err != TD_OK) + error ("Cannot find thread %d: Thread ID=%ld, %s", + pid_to_thread_id (inferior_ptid), + GET_THREAD (inferior_ptid), thread_db_err_str (err)); + + err = td_thr_getgregs_p (&th, gregset); + if (err != TD_OK) + error ("Cannot fetch general-purpose registers for thread %d: Thread ID=%ld, %s", + pid_to_thread_id (inferior_ptid), + GET_THREAD (inferior_ptid), thread_db_err_str (err)); +#ifdef PT_GETXMMREGS + err = td_thr_getxmmregs_p (&th, xmmregs); + if (err == TD_OK) + { + i387_supply_fxsave (regcache, -1, xmmregs); + } + else + { +#endif + err = td_thr_getfpregs_p (&th, &fpregset); + if (err != TD_OK) + error ("Cannot get floating-point registers for thread %d: Thread ID=%ld, %s", + pid_to_thread_id (inferior_ptid), + GET_THREAD (inferior_ptid), thread_db_err_str (err)); + supply_fpregset (regcache, &fpregset); +#ifdef PT_GETXMMREGS + } +#endif + + supply_gregset (regcache, gregset); +} + +static void +fbsd_lwp_store_registers (struct target_ops *ops, + struct regcache *regcache, int regnum) +{ + gregset_t gregs; + fpregset_t fpregs; + lwpid_t lwp; +#ifdef PT_GETXMMREGS + char xmmregs[512]; +#endif + + /* FIXME, is it possible ? */ + if (!IS_LWP (inferior_ptid)) + { + struct target_ops *beneath = find_target_beneath (ops); + + beneath->to_store_registers (ops, regcache, regnum); + return ; + } + + lwp = GET_LWP (inferior_ptid); + if (regnum != -1) + if (ptrace (PT_GETREGS, lwp, (caddr_t) &gregs, 0) == -1) + error ("Cannot get lwp %d registers: %s\n", lwp, safe_strerror (errno)); + + fill_gregset (regcache, &gregs, regnum); + if (ptrace (PT_SETREGS, lwp, (caddr_t) &gregs, 0) == -1) + error ("Cannot set lwp %d registers: %s\n", lwp, safe_strerror (errno)); + +#ifdef PT_GETXMMREGS + if (regnum != -1) + if (ptrace (PT_GETXMMREGS, lwp, xmmregs, 0) == -1) + goto noxmm; + + i387_collect_fxsave (regcache, regnum, xmmregs); + if (ptrace (PT_SETXMMREGS, lwp, xmmregs, 0) == -1) + goto noxmm; + + return; + +noxmm: +#endif + + if (regnum != -1) + if (ptrace (PT_GETFPREGS, lwp, (caddr_t) &fpregs, 0) == -1) + error ("Cannot get lwp %d float registers: %s\n", lwp, + safe_strerror (errno)); + + fill_fpregset (regcache, &fpregs, regnum); + if (ptrace (PT_SETFPREGS, lwp, (caddr_t) &fpregs, 0) == -1) + error ("Cannot set lwp %d float registers: %s\n", lwp, + safe_strerror (errno)); +} + +static void +fbsd_thread_store_registers (struct target_ops *ops, + struct regcache *regcache, int regnum) +{ + prgregset_t gregset; + prfpregset_t fpregset; + td_thrhandle_t th; + td_err_e err; +#ifdef PT_GETXMMREGS + char xmmregs[512]; +#endif + + if (!IS_THREAD (inferior_ptid)) + { + fbsd_lwp_store_registers (ops, regcache, regnum); + return; + } + + err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (inferior_ptid), &th); + if (err != TD_OK) + error ("Cannot find thread %d: Thread ID=%ld, %s", + pid_to_thread_id (inferior_ptid), + GET_THREAD (inferior_ptid), + thread_db_err_str (err)); + + if (regnum != -1) + { + char old_value[MAX_REGISTER_SIZE]; + + regcache_raw_collect (regcache, regnum, old_value); + err = td_thr_getgregs_p (&th, gregset); + if (err != TD_OK) + error ("%s: td_thr_getgregs %s", __func__, thread_db_err_str (err)); +#ifdef PT_GETXMMREGS + err = td_thr_getxmmregs_p (&th, xmmregs); + if (err != TD_OK) + { +#endif + err = td_thr_getfpregs_p (&th, &fpregset); + if (err != TD_OK) + error ("%s: td_thr_getfpgregs %s", __func__, thread_db_err_str (err)); +#ifdef PT_GETXMMREGS + } +#endif + regcache_raw_supply (regcache, regnum, old_value); + } + + fill_gregset (regcache, gregset, regnum); + err = td_thr_setgregs_p (&th, gregset); + if (err != TD_OK) + error ("Cannot store general-purpose registers for thread %d: Thread ID=%ld, %s", + pid_to_thread_id (inferior_ptid), GET_THREAD (inferior_ptid), + thread_db_err_str (err)); + +#ifdef PT_GETXMMREGS + i387_collect_fxsave (regcache, regnum, xmmregs); + err = td_thr_setxmmregs_p (&th, xmmregs); + if (err == TD_OK) + return; +#endif + + fill_fpregset (regcache, &fpregset, regnum); + err = td_thr_setfpregs_p (&th, &fpregset); + if (err != TD_OK) + error ("Cannot store floating-point registers for thread %d: Thread ID=%ld, %s", + pid_to_thread_id (inferior_ptid), GET_THREAD (inferior_ptid), + thread_db_err_str (err)); +} + +static void +fbsd_thread_mourn_inferior (struct target_ops *ops) +{ + struct target_ops *beneath = find_target_beneath (ops); + + fbsd_thread_deactivate (); + + beneath->to_mourn_inferior (beneath); + + /* Delete thread event breakpoints, if any. */ + remove_thread_event_breakpoints (); + + unpush_target (ops); +} + +static void +fbsd_core_check_lwp (bfd *abfd, asection *asect, void *obj) +{ + lwpid_t lwp; + + if (strncmp (bfd_section_name (abfd, asect), ".reg/", 5) != 0) + return; + + /* already found */ + if (*(lwpid_t *)obj == 0) + return; + + lwp = atoi (bfd_section_name (abfd, asect) + 5); + if (*(lwpid_t *)obj == lwp) + *(lwpid_t *)obj = 0; +} + +static int +fbsd_thread_alive (struct target_ops *ops, ptid_t ptid) +{ + td_thrhandle_t th; + td_thrinfo_t ti; + td_err_e err; + gregset_t gregs; + lwpid_t lwp; + + if (IS_THREAD (ptid)) + { + err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (ptid), &th); + if (err != TD_OK) + return 0; + + err = td_thr_get_info_p (&th, &ti); + if (err != TD_OK) + return 0; + + /* A zombie thread. */ + if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) + return 0; + + return 1; + } + else if (GET_LWP (ptid) == 0) + { + /* we sometimes are called with lwp == 0 */ + return 1; + } + + if (fbsd_thread_active) + { + err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th); + + /* + * if the lwp was already mapped to user thread, don't use it + * directly, please use user thread id instead. + */ + if (err == TD_OK) + return 0; + } + + if (!target_has_execution) + { + lwp = GET_LWP (ptid); + bfd_map_over_sections (core_bfd, fbsd_core_check_lwp, &lwp); + return (lwp == 0); + } + + /* check lwp in kernel */ + return ptrace (PT_GETREGS, GET_LWP (ptid), (caddr_t)&gregs, 0) == 0; +} + +static int +find_new_threads_callback (const td_thrhandle_t *th_p, void *data) +{ + td_thrinfo_t ti; + td_err_e err; + ptid_t ptid; + + err = td_thr_get_info_p (th_p, &ti); + if (err != TD_OK) + error ("Cannot get thread info: %s", thread_db_err_str (err)); + + /* Ignore zombie */ + if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) + return 0; + + ptid = BUILD_THREAD (ti.ti_tid, proc_handle.pid); + attach_thread (ptid, th_p, &ti, 1); + return 0; +} + +static void +fbsd_thread_find_new_threads (struct target_ops *ops) +{ + td_err_e err; + + /* Iterate over all user-space threads to discover new threads. */ + err = td_ta_thr_iter_p (thread_agent, find_new_threads_callback, NULL, + TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, + TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); + if (err != TD_OK) + error ("Cannot find new threads: %s", thread_db_err_str (err)); +} + +static char * +fbsd_thread_pid_to_str (struct target_ops *ops, ptid_t ptid) +{ + static char buf[64]; + + if (IS_THREAD (ptid)) + { + td_thrhandle_t th; + td_thrinfo_t ti; + td_err_e err; + + err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (ptid), &th); + if (err != TD_OK) + error ("Cannot find thread, Thread ID=%ld, %s", + GET_THREAD (ptid), thread_db_err_str (err)); + + err = td_thr_get_info_p (&th, &ti); + if (err != TD_OK) + error ("Cannot get thread info, Thread ID=%ld, %s", + GET_THREAD (ptid), thread_db_err_str (err)); + + if (ti.ti_lid != 0) + { + snprintf (buf, sizeof (buf), "Thread %llx (LWP %d)", + (unsigned long long)th.th_thread, ti.ti_lid); + } + else + { + snprintf (buf, sizeof (buf), "Thread %llx (%s)", + (unsigned long long)th.th_thread, + thread_db_state_str (ti.ti_state)); + } + + return buf; + } + else if (IS_LWP (ptid)) + { + snprintf (buf, sizeof (buf), "LWP %d", (int) GET_LWP (ptid)); + return buf; + } + return normal_pid_to_str (ptid); +} + +CORE_ADDR +fbsd_thread_get_local_address(struct target_ops *ops, + ptid_t ptid, + CORE_ADDR lm, + CORE_ADDR offset) +{ + td_thrhandle_t th; + void *address; + int ret; + + if (IS_THREAD (ptid)) + { + if (!td_thr_tls_get_addr_p) + error ("Cannot find thread-local interface in thread_db library."); + + ret = td_ta_map_id2thr_p (thread_agent, GET_THREAD(ptid), &th); + + /* get the address of the variable. */ + ret = td_thr_tls_get_addr_p (&th, (void *)lm, offset, &address); + + if (ret != TD_OK) + { + error ("Cannot find thread-local storage for thread %ld\n%s", + (long) GET_THREAD (ptid), thread_db_err_str (ret)); + } + + /* Cast assuming host == target. */ + return extract_data_ptr (&address); + } + return (0); +} + +static int +tsd_cb (thread_key_t key, void (*destructor)(void *), void *ignore) +{ + struct minimal_symbol *ms; + char *name; + + ms = lookup_minimal_symbol_by_pc (extract_func_ptr (&destructor)); + if (!ms) + name = "???"; + else + name = SYMBOL_PRINT_NAME (ms); + + printf_filtered ("Destructor %p <%s>\n", destructor, name); + return 0; +} + +static void +fbsd_thread_tsd_cmd (char *exp, int from_tty) +{ + if (fbsd_thread_active) + td_ta_tsd_iter_p (thread_agent, tsd_cb, NULL); +} + +static void +fbsd_print_sigset (sigset_t *set) +{ + int i; + + for (i = 1; i <= _SIG_MAXSIG; ++i) { + if (sigismember(set, i)) { + if (i < sizeof(sys_signame)/sizeof(sys_signame[0])) + printf_filtered("%s ", sys_signame[i]); + else + printf_filtered("sig%d ", i); + } + } + printf_filtered("\n"); +} + +static void +fbsd_thread_signal_cmd (char *exp, int from_tty) +{ + td_thrhandle_t th; + td_thrinfo_t ti; + td_err_e err; +#ifdef PL_FLAG_SI + const char *code; +#endif + + if (!fbsd_thread_active || !IS_THREAD(inferior_ptid)) + return; + + err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (inferior_ptid), &th); + if (err != TD_OK) + return; + + err = td_thr_get_info_p (&th, &ti); + if (err != TD_OK) + return; + + printf_filtered("signal mask:\n"); + fbsd_print_sigset(&ti.ti_sigmask); + printf_filtered("signal pending:\n"); + fbsd_print_sigset(&ti.ti_pending); +#ifdef PL_FLAG_SI + if (ti.ti_siginfo.si_signo != 0) { + printf_filtered("si_signo %d si_errno %d", ti.ti_siginfo.si_signo, + ti.ti_siginfo.si_errno); + if (ti.ti_siginfo.si_errno != 0) + printf_filtered(" (%s)", strerror(ti.ti_siginfo.si_errno)); + printf_filtered("\n"); + switch (ti.ti_siginfo.si_code) { + case SI_NOINFO: + code = "NOINFO"; + break; + case SI_USER: + code = "USER"; + break; + case SI_QUEUE: + code = "QUEUE"; + break; + case SI_TIMER: + code = "TIMER"; + break; + case SI_ASYNCIO: + code = "ASYNCIO"; + break; + case SI_MESGQ: + code = "MESGQ"; + break; + case SI_KERNEL: + code = "KERNEL"; + break; + default: + code = "UNKNOWN"; + break; + } + printf_filtered("si_code %s si_pid %d si_uid %d si_status %x si_addr %p\n", + code, ti.ti_siginfo.si_pid, ti.ti_siginfo.si_uid, ti.ti_siginfo.si_status, + ti.ti_siginfo.si_addr); + } +#endif +} + +static void +init_fbsd_thread_ops (void) +{ + fbsd_thread_ops.to_shortname = "freebsd-threads"; + fbsd_thread_ops.to_longname = "FreeBSD multithreaded child process."; + fbsd_thread_ops.to_doc = "FreeBSD threads support."; + fbsd_thread_ops.to_detach = fbsd_thread_detach; + fbsd_thread_ops.to_resume = fbsd_thread_resume; + fbsd_thread_ops.to_wait = fbsd_thread_wait; + fbsd_thread_ops.to_fetch_registers = fbsd_thread_fetch_registers; + fbsd_thread_ops.to_store_registers = fbsd_thread_store_registers; + fbsd_thread_ops.to_mourn_inferior = fbsd_thread_mourn_inferior; + fbsd_thread_ops.to_thread_alive = fbsd_thread_alive; + fbsd_thread_ops.to_find_new_threads = fbsd_thread_find_new_threads; + fbsd_thread_ops.to_pid_to_str = fbsd_thread_pid_to_str; + fbsd_thread_ops.to_stratum = thread_stratum; + fbsd_thread_ops.to_get_thread_local_address = fbsd_thread_get_local_address; + fbsd_thread_ops.to_magic = OPS_MAGIC; +} + +static int +thread_db_load (void) +{ + void *handle; + td_err_e err; + + handle = dlopen (LIBTHREAD_DB_SO, RTLD_NOW); + if (handle == NULL) + return 0; + +#define resolve(X) \ + if (!(X##_p = dlsym (handle, #X))) \ + return 0; + + resolve(td_init); + resolve(td_ta_new); + resolve(td_ta_delete); + resolve(td_ta_map_id2thr); + resolve(td_ta_map_lwp2thr); + resolve(td_ta_thr_iter); + resolve(td_thr_get_info); +#ifdef PT_GETXMMREGS + resolve(td_thr_getxmmregs); +#endif + resolve(td_thr_getfpregs); + resolve(td_thr_getgregs); +#ifdef PT_GETXMMREGS + resolve(td_thr_setxmmregs); +#endif + resolve(td_thr_setfpregs); + resolve(td_thr_setgregs); + resolve(td_thr_sstep); + resolve(td_ta_tsd_iter); + resolve(td_thr_dbsuspend); + resolve(td_thr_dbresume); + resolve(td_thr_tls_get_addr); + + /* These are not essential. */ + td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr"); + td_ta_set_event_p = dlsym (handle, "td_ta_set_event"); + td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg"); + td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable"); + td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr"); + + return 1; +} + +void +_initialize_thread_db (void) +{ + + init_fbsd_thread_ops (); + + if (thread_db_load ()) + { + add_target (&fbsd_thread_ops); + + /* "thread tsd" command */ + add_cmd ("tsd", class_run, fbsd_thread_tsd_cmd, + "Show the thread-specific data keys and destructors " + "for the process.\n", + &thread_cmd_list); + + add_cmd ("signal", class_run, fbsd_thread_signal_cmd, + "Show the thread signal info.\n", + &thread_cmd_list); + + /* Hook into new_objfile notification. */ + observer_attach_new_objfile (fbsd_thread_new_objfile); + } + else + { + fprintf_unfiltered (gdb_stderr, + "[GDB will not be able to debug user-mode threads: %s]\n", dlerror()); + } +} + +/* proc service functions */ +void +ps_plog (const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vfprintf_filtered (gdb_stderr, fmt, args); + va_end (args); +} + +ps_err_e +ps_pglobal_lookup (struct ps_prochandle *ph, const char *obj, + const char *name, psaddr_t *sym_addr) +{ + struct minimal_symbol *ms; + CORE_ADDR addr; + + ms = lookup_minimal_symbol (name, NULL, NULL); + if (ms == NULL) + return PS_NOSYM; + + *sym_addr = SYMBOL_VALUE_ADDRESS (ms); + return PS_OK; +} + +ps_err_e +ps_pread (struct ps_prochandle *ph, psaddr_t addr, void *buf, size_t len) +{ + int err = target_read_memory (extract_data_ptr (&addr), buf, len); + return (err == 0 ? PS_OK : PS_ERR); +} + +ps_err_e +ps_pwrite (struct ps_prochandle *ph, psaddr_t addr, const void *buf, + size_t len) +{ + int err = target_write_memory (extract_data_ptr (&addr), (void *)buf, len); + return (err == 0 ? PS_OK : PS_ERR); +} + +ps_err_e +ps_lgetregs (struct ps_prochandle *ph, lwpid_t lwpid, prgregset_t gregset) +{ + struct cleanup *old_chain; + struct regcache *regcache; + + old_chain = save_inferior_ptid (); + + inferior_ptid = BUILD_LWP (lwpid, ph->pid); + regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch); + + target_fetch_registers (regcache, -1); + fill_gregset (regcache, gregset, -1); + do_cleanups (old_chain); + return PS_OK; +} + +ps_err_e +ps_lsetregs (struct ps_prochandle *ph, lwpid_t lwpid, const prgregset_t gregset) +{ + struct cleanup *old_chain; + struct regcache *regcache; + + old_chain = save_inferior_ptid (); + inferior_ptid = BUILD_LWP (lwpid, ph->pid); + regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch); + + supply_gregset (regcache, gregset); + target_store_registers (regcache, -1); + do_cleanups (old_chain); + return PS_OK; +} + +ps_err_e +ps_lgetfpregs (struct ps_prochandle *ph, lwpid_t lwpid, prfpregset_t *fpregset) +{ + struct cleanup *old_chain; + struct regcache *regcache; + + old_chain = save_inferior_ptid (); + inferior_ptid = BUILD_LWP (lwpid, ph->pid); + regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch); + + target_fetch_registers (regcache, -1); + fill_fpregset (regcache, fpregset, -1); + do_cleanups (old_chain); + return PS_OK; +} + +ps_err_e +ps_lsetfpregs (struct ps_prochandle *ph, lwpid_t lwpid, + const prfpregset_t *fpregset) +{ + struct cleanup *old_chain; + struct regcache *regcache; + + old_chain = save_inferior_ptid (); + inferior_ptid = BUILD_LWP (lwpid, ph->pid); + regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch); + + supply_fpregset (regcache, fpregset); + target_store_registers (regcache, -1); + do_cleanups (old_chain); + return PS_OK; +} + +#ifdef PT_GETXMMREGS +ps_err_e +ps_lgetxmmregs (struct ps_prochandle *ph, lwpid_t lwpid, char *xmmregs) +{ + struct cleanup *old_chain; + struct regcache *regcache; + + old_chain = save_inferior_ptid (); + inferior_ptid = BUILD_LWP (lwpid, ph->pid); + regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch); + + target_fetch_registers (regcache, -1); + i387_collect_fxsave (regcache, -1, xmmregs); + do_cleanups (old_chain); + return PS_OK; +} + +ps_err_e +ps_lsetxmmregs (struct ps_prochandle *ph, lwpid_t lwpid, + const char *xmmregs) +{ + struct cleanup *old_chain; + struct regcache *regcache; + + old_chain = save_inferior_ptid (); + inferior_ptid = BUILD_LWP (lwpid, ph->pid); + regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch); + + i387_supply_fxsave (regcache, -1, xmmregs); + target_store_registers (regcache, -1); + do_cleanups (old_chain); + return PS_OK; +} +#endif + +ps_err_e +ps_lstop(struct ps_prochandle *ph, lwpid_t lwpid) +{ + if (ptrace (PT_SUSPEND, lwpid, 0, 0) == -1) + return PS_ERR; + return PS_OK; +} + +ps_err_e +ps_lcontinue(struct ps_prochandle *ph, lwpid_t lwpid) +{ + if (ptrace (PT_RESUME, lwpid, 0, 0) == -1) + return PS_ERR; + return PS_OK; +} + +ps_err_e +ps_linfo(struct ps_prochandle *ph, lwpid_t lwpid, void *info) +{ + if (!target_has_execution) { + /* XXX should verify lwpid and make a pseudo lwp info */ + memset(info, 0, sizeof(struct ptrace_lwpinfo)); + return PS_OK; + } + + if (ptrace (PT_LWPINFO, lwpid, info, sizeof(struct ptrace_lwpinfo)) == -1) + return PS_ERR; + return PS_OK; +} diff --git a/devel/gdb/files/patch-gdb-Makefile.in b/devel/gdb/files/patch-gdb-Makefile.in new file mode 100644 index 000000000000..71edc1b8d95c --- /dev/null +++ b/devel/gdb/files/patch-gdb-Makefile.in @@ -0,0 +1,38 @@ +--- gdb/Makefile.in.orig 2010-02-02 18:16:53.000000000 -0500 ++++ gdb/Makefile.in 2010-10-13 16:09:43.312803000 -0400 +@@ -524,7 +524,7 @@ + xstormy16-tdep.o \ + xtensa-config.o xtensa-tdep.o xtensa-linux-tdep.o \ + glibc-tdep.o \ +- bsd-uthread.o \ ++ fbsd-threads.o \ + nbsd-tdep.o obsd-tdep.o \ + sol2-tdep.o \ + solib-frv.o solib-irix.o solib-svr4.o solib-target.o \ +@@ -720,7 +720,7 @@ + gdbserver/linux-low.h gdbserver/gdb_proc_service.h \ + gdbserver/regcache.h gdbthread.h dwarf2-frame.h nbsd-nat.h dcache.h \ + amd64-nat.h s390-tdep.h arm-linux-tdep.h exceptions.h macroscope.h \ +-gdbarch.h bsd-uthread.h gdb_thread_db.h gdb_stat.h memory-map.h \ ++gdbarch.h gdb_thread_db.h gdb_stat.h memory-map.h \ + mdebugread.h m88k-tdep.h stabsread.h hppa-linux-offsets.h linux-fork.h \ + ser-unix.h scm-lang.h inf-ptrace.h terminal.h ui-out.h frame-base.h \ + f-lang.h dwarf2loc.h value.h sparc-tdep.h defs.h target-descriptions.h \ +@@ -1130,7 +1130,7 @@ + # Removing the old gdb first works better if it is running, at least on SunOS. + gdb$(EXEEXT): gdb.o libgdb.a $(ADD_DEPS) $(CDEPS) $(TDEPLIBS) + rm -f gdb$(EXEEXT) +- $(CC_LD) $(INTERNAL_LDFLAGS) $(WIN32LDAPP) \ ++ $(CC_LD) $(INTERNAL_LDFLAGS) $(WIN32LDAPP) -Wl,-E \ + -o gdb$(EXEEXT) gdb.o libgdb.a \ + $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) + +@@ -1402,7 +1402,7 @@ + arm-linux-nat.c arm-linux-tdep.c arm-tdep.c \ + armnbsd-nat.c armbsd-tdep.c armnbsd-tdep.c armobsd-tdep.c \ + avr-tdep.c \ +- bsd-uthread.c bsd-kvm.c \ ++ fbsd-threads.c bsd-kvm.c \ + core-regset.c corelow.c \ + dcache.c dicos-tdep.c darwin-nat.c \ + exec.c \ diff --git a/devel/gdb/files/patch-gdb-amd64fbsd-nat.c b/devel/gdb/files/patch-gdb-amd64fbsd-nat.c new file mode 100644 index 000000000000..e2a759a084a5 --- /dev/null +++ b/devel/gdb/files/patch-gdb-amd64fbsd-nat.c @@ -0,0 +1,58 @@ +--- gdb/amd64fbsd-nat.c.orig 2010-10-13 14:53:14.425152000 -0400 ++++ gdb/amd64fbsd-nat.c 2010-10-13 15:15:01.080198000 -0400 +@@ -27,6 +27,7 @@ + #include <signal.h> + #include <stddef.h> + #include <sys/types.h> ++#include <sys/procfs.h> + #include <sys/ptrace.h> + #include <sys/sysctl.h> + #include <machine/reg.h> +@@ -92,6 +93,47 @@ + }; + + ++/* Transfering the registers between GDB, inferiors and core files. */ ++ ++/* Fill GDB's register array with the general-purpose register values ++ in *GREGSETP. */ ++ ++void ++supply_gregset (struct regcache *regcache, const gregset_t *gregsetp) ++{ ++ amd64_supply_native_gregset (regcache, gregsetp, -1); ++} ++ ++/* Fill register REGNUM (if it is a general-purpose register) in ++ *GREGSETPS with the value in GDB's register array. If REGNUM is -1, ++ do this for all registers. */ ++ ++void ++fill_gregset (struct regcache *regcache, gregset_t *gregsetp, int regnum) ++{ ++ amd64_collect_native_gregset (regcache, gregsetp, regnum); ++} ++ ++/* Fill GDB's register array with the floating-point register values ++ in *FPREGSETP. */ ++ ++void ++supply_fpregset (struct regcache *regcache, const fpregset_t *fpregsetp) ++{ ++ amd64_supply_fxsave (regcache, -1, fpregsetp); ++} ++ ++/* Fill register REGNUM (if it is a floating-point register) in ++ *FPREGSETP with the value in GDB's register array. If REGNUM is -1, ++ do this for all registers. */ ++ ++void ++fill_fpregset (struct regcache *regcache, fpregset_t *fpregsetp, int regnum) ++{ ++ amd64_collect_fxsave (regcache, regnum, fpregsetp); ++} ++ ++ + /* Support for debugging kernel virtual memory images. */ + + #include <sys/types.h> diff --git a/devel/gdb/files/patch-gdb-amd64fbsd-tdep.c b/devel/gdb/files/patch-gdb-amd64fbsd-tdep.c new file mode 100644 index 000000000000..7f0f87d98a48 --- /dev/null +++ b/devel/gdb/files/patch-gdb-amd64fbsd-tdep.c @@ -0,0 +1,68 @@ +--- gdb/amd64fbsd-tdep.c.orig 2010-09-30 13:31:19.930008000 -0400 ++++ gdb/amd64fbsd-tdep.c 2010-09-30 13:39:30.673331000 -0400 +@@ -29,7 +29,6 @@ + #include "gdb_string.h" + + #include "amd64-tdep.h" +-#include "bsd-uthread.h" + #include "solib-svr4.h" + + /* Support for signal handlers. */ +@@ -142,46 +141,6 @@ + }; + + static void +-amd64fbsd_supply_uthread (struct regcache *regcache, +- int regnum, CORE_ADDR addr) +-{ +- gdb_byte buf[8]; +- int i; +- +- gdb_assert (regnum >= -1); +- +- for (i = 0; i < ARRAY_SIZE (amd64fbsd_jmp_buf_reg_offset); i++) +- { +- if (amd64fbsd_jmp_buf_reg_offset[i] != -1 +- && (regnum == -1 || regnum == i)) +- { +- read_memory (addr + amd64fbsd_jmp_buf_reg_offset[i], buf, 8); +- regcache_raw_supply (regcache, i, buf); +- } +- } +-} +- +-static void +-amd64fbsd_collect_uthread (const struct regcache *regcache, +- int regnum, CORE_ADDR addr) +-{ +- gdb_byte buf[8]; +- int i; +- +- gdb_assert (regnum >= -1); +- +- for (i = 0; i < ARRAY_SIZE (amd64fbsd_jmp_buf_reg_offset); i++) +- { +- if (amd64fbsd_jmp_buf_reg_offset[i] != -1 +- && (regnum == -1 || regnum == i)) +- { +- regcache_raw_collect (regcache, i, buf); +- write_memory (addr + amd64fbsd_jmp_buf_reg_offset[i], buf, 8); +- } +- } +-} +- +-static void + amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +@@ -201,10 +160,6 @@ + tdep->sc_reg_offset = amd64fbsd_sc_reg_offset; + tdep->sc_num_regs = ARRAY_SIZE (amd64fbsd_sc_reg_offset); + +- /* FreeBSD provides a user-level threads implementation. */ +- bsd_uthread_set_supply_uthread (gdbarch, amd64fbsd_supply_uthread); +- bsd_uthread_set_collect_uthread (gdbarch, amd64fbsd_collect_uthread); +- + /* FreeBSD uses SVR4-style shared libraries. */ + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_lp64_fetch_link_map_offsets); diff --git a/devel/gdb/files/patch-gdb-configure.tgt b/devel/gdb/files/patch-gdb-configure.tgt new file mode 100644 index 000000000000..71c875e8e063 --- /dev/null +++ b/devel/gdb/files/patch-gdb-configure.tgt @@ -0,0 +1,20 @@ +--- gdb/configure.tgt.orig 2010-09-30 13:38:12.841406000 -0400 ++++ gdb/configure.tgt 2010-09-30 13:38:49.131127000 -0400 +@@ -169,7 +169,7 @@ + i[34567]86-*-freebsd* | i[34567]86-*-kfreebsd*-gnu) + # Target: FreeBSD/i386 + gdb_target_obs="i386-tdep.o i387-tdep.o i386bsd-tdep.o i386fbsd-tdep.o \ +- bsd-uthread.o corelow.o solib.o solib-svr4.o" ++ fbsd-threads.o corelow.o solib.o solib-svr4.o" + ;; + i[34567]86-*-netbsd* | i[34567]86-*-knetbsd*-gnu) + # Target: NetBSD/i386 +@@ -579,7 +579,7 @@ + # Target: FreeBSD/amd64 + gdb_target_obs="amd64-tdep.o amd64fbsd-tdep.o i386-tdep.o \ + i387-tdep.o i386bsd-tdep.o i386fbsd-tdep.o \ +- bsd-uthread.o corelow.o solib.o solib-svr4.o" ++ fbsd-threads.o corelow.o solib.o solib-svr4.o" + ;; + x86_64-*-mingw*) + # Target: MingW/amd64 diff --git a/devel/gdb/files/patch-gdb-i386bsd-nat.c b/devel/gdb/files/patch-gdb-i386bsd-nat.c new file mode 100644 index 000000000000..979b34715320 --- /dev/null +++ b/devel/gdb/files/patch-gdb-i386bsd-nat.c @@ -0,0 +1,20 @@ +--- gdb/i386bsd-nat.c.orig 2010-10-21 11:18:03.171107000 -0400 ++++ gdb/i386bsd-nat.c 2010-10-21 11:18:18.849642000 -0400 +@@ -88,7 +88,7 @@ + + /* Supply the general-purpose registers in GREGS, to REGCACHE. */ + +-static void ++void + i386bsd_supply_gregset (struct regcache *regcache, const void *gregs) + { + const char *regs = gregs; +@@ -107,7 +107,7 @@ + GREGS. If REGNUM is -1, collect and store all appropriate + registers. */ + +-static void ++void + i386bsd_collect_gregset (const struct regcache *regcache, + void *gregs, int regnum) + { diff --git a/devel/gdb/files/patch-gdb-i386bsd-nat.h b/devel/gdb/files/patch-gdb-i386bsd-nat.h new file mode 100644 index 000000000000..caf5c54fa7a7 --- /dev/null +++ b/devel/gdb/files/patch-gdb-i386bsd-nat.h @@ -0,0 +1,15 @@ +--- gdb/i386bsd-nat.h.orig 2010-10-21 11:18:08.097659000 -0400 ++++ gdb/i386bsd-nat.h 2010-10-21 11:20:49.341989000 -0400 +@@ -35,4 +35,12 @@ + + extern unsigned long i386bsd_dr_get_status (void); + ++/* low level i386 register functions used in i386fbsd-nat.c. */ ++ ++extern void i386bsd_supply_gregset (struct regcache *regcache, ++ const void *gregs); ++ ++extern void i386bsd_collect_gregset (const struct regcache *regcache, ++ void *gregs, int regnum); ++ + #endif /* i386bsd-nat.h */ diff --git a/devel/gdb/files/patch-gdb-i386fbsd-nat.c b/devel/gdb/files/patch-gdb-i386fbsd-nat.c new file mode 100644 index 000000000000..f77a87532ba3 --- /dev/null +++ b/devel/gdb/files/patch-gdb-i386fbsd-nat.c @@ -0,0 +1,68 @@ +--- gdb/i386fbsd-nat.c.orig 2010-01-01 02:31:36.000000000 -0500 ++++ gdb/i386fbsd-nat.c 2010-10-22 13:57:48.705926000 -0400 +@@ -24,6 +24,7 @@ + #include "target.h" + + #include <sys/types.h> ++#include <sys/procfs.h> + #include <sys/ptrace.h> + #include <sys/sysctl.h> + +@@ -81,6 +82,49 @@ + } + + ++/* Transfering the registers between GDB, inferiors and core files. */ ++ ++/* Fill GDB's register array with the general-purpose register values ++ in *GREGSETP. */ ++ ++void ++supply_gregset (struct regcache *regcache, const gregset_t *gregsetp) ++{ ++ i386bsd_supply_gregset (regcache, gregsetp); ++} ++ ++/* Fill register REGNUM (if it is a general-purpose register) in ++ *GREGSETPS with the value in GDB's register array. If REGNUM is -1, ++ do this for all registers. */ ++ ++void ++fill_gregset (struct regcache *regcache, gregset_t *gregsetp, int regnum) ++{ ++ i386bsd_collect_gregset (regcache, gregsetp, regnum); ++} ++ ++#include "i387-tdep.h" ++ ++/* Fill GDB's register array with the floating-point register values ++ in *FPREGSETP. */ ++ ++void ++supply_fpregset (struct regcache *regcache, const fpregset_t *fpregsetp) ++{ ++ i387_supply_fsave (regcache, -1, fpregsetp); ++} ++ ++/* Fill register REGNUM (if it is a floating-point register) in ++ *FPREGSETP with the value in GDB's register array. If REGNUM is -1, ++ do this for all registers. */ ++ ++void ++fill_fpregset (struct regcache *regcache, fpregset_t *fpregsetp, int regnum) ++{ ++ i387_collect_fsave (regcache, regnum, fpregsetp); ++} ++ ++ + /* Support for debugging kernel virtual memory images. */ + + #include <sys/types.h> +@@ -141,7 +185,6 @@ + #endif /* HAVE_PT_GETDBREGS */ + + +- t->to_resume = i386fbsd_resume; + t->to_pid_to_exec_file = fbsd_pid_to_exec_file; + t->to_find_memory_regions = fbsd_find_memory_regions; + t->to_make_corefile_notes = fbsd_make_corefile_notes; diff --git a/devel/gdb/files/patch-gdb-i386fbsd-tdep.c b/devel/gdb/files/patch-gdb-i386fbsd-tdep.c new file mode 100644 index 000000000000..2256796de096 --- /dev/null +++ b/devel/gdb/files/patch-gdb-i386fbsd-tdep.c @@ -0,0 +1,68 @@ +--- gdb/i386fbsd-tdep.c.orig 2010-09-30 13:39:50.654492000 -0400 ++++ gdb/i386fbsd-tdep.c 2010-09-30 13:40:43.858675000 -0400 +@@ -28,7 +28,6 @@ + + #include "i386-tdep.h" + #include "i387-tdep.h" +-#include "bsd-uthread.h" + #include "solib-svr4.h" + + /* FreeBSD 3.0-RELEASE or later. */ +@@ -84,46 +83,6 @@ + }; + + static void +-i386fbsd_supply_uthread (struct regcache *regcache, +- int regnum, CORE_ADDR addr) +-{ +- char buf[4]; +- int i; +- +- gdb_assert (regnum >= -1); +- +- for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++) +- { +- if (i386fbsd_jmp_buf_reg_offset[i] != -1 +- && (regnum == -1 || regnum == i)) +- { +- read_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4); +- regcache_raw_supply (regcache, i, buf); +- } +- } +-} +- +-static void +-i386fbsd_collect_uthread (const struct regcache *regcache, +- int regnum, CORE_ADDR addr) +-{ +- char buf[4]; +- int i; +- +- gdb_assert (regnum >= -1); +- +- for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++) +- { +- if (i386fbsd_jmp_buf_reg_offset[i] != -1 +- && (regnum == -1 || regnum == i)) +- { +- regcache_raw_collect (regcache, i, buf); +- write_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4); +- } +- } +-} +- +-static void + i386fbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +@@ -148,10 +107,6 @@ + /* FreeBSD has a more complete `struct sigcontext'. */ + tdep->sc_reg_offset = i386fbsd_sc_reg_offset; + tdep->sc_num_regs = ARRAY_SIZE (i386fbsd_sc_reg_offset); +- +- /* FreeBSD provides a user-level threads implementation. */ +- bsd_uthread_set_supply_uthread (gdbarch, i386fbsd_supply_uthread); +- bsd_uthread_set_collect_uthread (gdbarch, i386fbsd_collect_uthread); + } + + static void diff --git a/devel/gdb/files/patch-unified b/devel/gdb/files/patch-unified new file mode 100644 index 000000000000..19ef04213ee0 --- /dev/null +++ b/devel/gdb/files/patch-unified @@ -0,0 +1,25 @@ +--- gdb/gdb.c Thu Feb 13 13:07:24 2003 ++++ gdb/gdb.c Wed May 17 00:24:39 2006 +@@ -23,4 +23,5 @@ + #include "gdb_string.h" + #include "interps.h" ++#include <libgen.h> + + int +@@ -31,6 +32,14 @@ + args.argc = argc; + args.argv = argv; +- args.use_windows = 0; +- args.interpreter_p = INTERP_CONSOLE; ++ if (strncmp(basename(argv[0]), "insight", 7) == 0) { ++ args.use_windows = 1; ++ args.interpreter_p = "insight"; ++ } else if (strncmp(basename(argv[0]), "gdbtui", 6) == 0) { ++ args.use_windows = 0; ++ args.interpreter_p = INTERP_TUI; ++ } else { ++ args.use_windows = 0; ++ args.interpreter_p = INTERP_CONSOLE; ++ } + return gdb_main (&args); + } diff --git a/devel/gdb/pkg-descr b/devel/gdb/pkg-descr new file mode 100644 index 000000000000..bb8e26728711 --- /dev/null +++ b/devel/gdb/pkg-descr @@ -0,0 +1,6 @@ +GDB is a source-level debugger for Ada, C, C++, Objective-C, Pascal and +many other languages. GDB can target (i.e., debug programs running on) +more than a dozen different processor architectures, and GDB itself can +run on most popular GNU/Linux, Unix and Microsoft Windows variants. + +WWW: http://www.gnu.org/software/gdb/ diff --git a/devel/gdb/pkg-plist b/devel/gdb/pkg-plist new file mode 100644 index 000000000000..ec79e4c77af9 --- /dev/null +++ b/devel/gdb/pkg-plist @@ -0,0 +1,2 @@ +bin/gdb%%VER%% +bin/gdbtui%%VER%% |