* [PATCH 2/2] Port gdbserver to GNU/Hurd @ 2013-09-03 8:03 ` Yue Lu 2013-09-03 9:38 ` [PATCH 1/2] " Thomas Schwinge 0 siblings, 1 reply; 25+ messages in thread From: Yue Lu @ 2013-09-03 8:03 UTC (permalink / raw) To: gdb-patches, bug-hurd; +Cc: Thomas Schwinge, Luis Machado Hi all, 2013-09-03 Yue Lu <hacklu.newborn@gmail.com> * configure.ac (host_makefile_frag): New rule for GNU/Hurd to load i386gnu.mh. * configure.srv (srv_tgtobj): Add gnu-low.o gnu-i386-low.o for GNU/Hurd. (srv_regobj): Add $(srv_i386_regobj) for GNU/Hurd. (srv_xmlfiles): Add $(srv_i386_xmlfiles) for GNU/Hurd. * configure: Regenerate. * Makefile.in (OBS): Add $(NATDEPFILES). (generated_files): Add $(NAT_GENERATED_FILES). (@host_makefile_frag@): New rule. (MIG): New tools. (AWK): New tools. * exc_request.defs: New file. copy from [gdb]/gdb/exc_request.defs. * gnu-i386-low.c: New file. Modified from [gdb]/gdb/i386gnu-nat.c. * gnu-low.c: New file. The main part for gdbserver on GNU/Hurd. Most of code are borrowed from [gdb]/gdb/gnu-nat.c. * gnu-low.h: New file. Most of code are borrowed from [gdb]/gdb/gnu-nat.h. * hostio.c: Add macro define PATH_MAX 512. * i386gnu.mh: New file. copy from [gdb]/gdb/config/i386/i386gnu.mh and delete unused part. * msg.defs: New file. copy from [gdb]/gdb/msg.defs. * msg_reply.defs: New file. copy from [gdb]/gdb/msg_reply.defs. * notify.defs: New file. copy from [gdb]/gdb/notify.defs. * process_reply.defs: New file. copy from [gdb]/gdb/process_reply.defs. * reply_mid_hack.awk: New file. copy from [gdb]/gdb/reply_mid_hack.awk. * server.h: Add typedef long CORE_ADDR; * utils.c (host_address_to_string): New functions, copy from [gdb]/gdb/utils.c. diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index e8470a8..3250b5a 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -50,6 +50,8 @@ INSTALL_DATA = @INSTALL_DATA@ RANLIB = @RANLIB@ CC = @CC@ +MIG = @MIG@ +AWK = @AWK@ # Dependency tracking information. DEPMODE = @CCDEPMODE@ @@ -172,7 +174,7 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o targ xml-utils.o common-utils.o ptid.o buffer.o format.o filestuff.o \ dll.o notif.o tdesc.o \ $(XML_BUILTIN) \ - $(DEPFILES) $(LIBOBJS) + $(DEPFILES) $(LIBOBJS) $(NATDEPFILES) GDBREPLAY_OBS = gdbreplay.o version.o GDBSERVER_LIBS = @GDBSERVER_LIBS@ XM_CLIBS = @LIBS@ @@ -195,6 +197,10 @@ CLEANDIRS = $(SUBDIRS) # The format here is for the `case' shell command. REQUIRED_SUBDIRS = $(GNULIB_BUILDDIR) +# Host-dependent makefile fragment comes in here. +@host_makefile_frag@ +# End of host-dependent makefile fragment + FLAGS_TO_PASS = \ "prefix=$(prefix)" \ "exec_prefix=$(exec_prefix)" \ @@ -228,7 +234,7 @@ FLAGS_TO_PASS = \ "RUNTESTFLAGS=$(RUNTESTFLAGS)" # All generated files which can be included by another file. -generated_files = config.h $(GNULIB_H) +generated_files = config.h $(GNULIB_H) $(NAT_GENERATED_FILES) .c.o: $(COMPILE) $< diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac index b9928d7..6c0ed20 100644 --- a/gdb/gdbserver/configure.ac +++ b/gdb/gdbserver/configure.ac @@ -456,6 +456,31 @@ if $want_ipa ; then fi fi +frags= +case $host_os in + gnu*) + #Needed for GNU Hurd hosts. + AC_PROG_AWK + AC_CHECK_TOOL(MIG, mig) + if test x"$MIG" = x; then + AC_MSG_ERROR([MIG not found but required for $host hosts]) + fi + host_makefile_frag=${srcdir}/i386gnu.mh + if test ! -f ${host_makefile_frag}; then + AC_MSG_ERROR("*** Gdb does not support native target ${host}") + fi + frags="$frags $host_makefile_frag" + ;; + *) + host_makefile_frag=/dev/null + ;; +esac + +echo "host_makefile_frag=$host_makefile_frag" + echo "frags=$frags" +AC_SUBST_FILE(host_makefile_frag) +AC_SUBST(frags) + AC_SUBST(GDBSERVER_DEPFILES) AC_SUBST(GDBSERVER_LIBS) AC_SUBST(srv_xmlbuiltin) diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index 879d0de..e2a6a08 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -118,6 +118,11 @@ case "${target}" in srv_linux_btrace=yes ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o" ;; + i[34567]86-*-gnu*) srv_regobj="$srv_i386_regobj" + srv_tgtobj="gnu-low.o gnu-i386-low.o" + srv_xmlfiles="$srv_i386_xmlfiles" + ;; + i[34567]86-*-lynxos*) srv_regobj="i386.o" srv_tgtobj="lynx-low.o lynx-i386-low.o" srv_xmlfiles="i386/i386.xml" diff --git a/gdb/gdbserver/exc_request.defs b/gdb/gdbserver/exc_request.defs new file mode 100644 index 0000000..9b5ed2e --- /dev/null +++ b/gdb/gdbserver/exc_request.defs @@ -0,0 +1,51 @@ +/* + * Mach Operating System + * Copyright (c) 1993,1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/* + * Abstract: + * MiG definitions file for Mach exception interface (request half). + */ + +subsystem exc 2400; + +#include <mach/std_types.defs> + +#ifdef USERPREFIX +userprefix USERPREFIX; +#endif + +#ifdef SERVERPREFIX +serverprefix SERVERPREFIX; +#endif + +simpleroutine exception_raise_request ( + exception_port : mach_port_t; + replyport reply : mach_port_send_once_t; + thread : mach_port_t; + task : mach_port_t; + exception : integer_t; + code : integer_t; + subcode : integer_t); diff --git a/gdb/gdbserver/gnu-i386-low.c b/gdb/gdbserver/gnu-i386-low.c new file mode 100644 index 0000000..643b0e9 --- /dev/null +++ b/gdb/gdbserver/gnu-i386-low.c @@ -0,0 +1,296 @@ +/* Low level interface to i386 running the GNU Hurd. + + Copyright (C) 1992-2013 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 3 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, see <http://www.gnu.org/licenses/>. */ +#include "server.h" +#include "target.h" + +#include "gnu-low.h" + +#include <limits.h> +#include <sys/ptrace.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include "gdb_wait.h" +#include <signal.h> + +#include <mach.h> +#include <mach_error.h> +#include <mach/message.h> +#include <mach/exception.h> + +#define I386_NUM_GREGS 16 + +/* Offset to the thread_state_t location where REG is stored. */ +#define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg) + +/* At REG_OFFSET[N] is the offset to the thread_state_t location where + the GDB register N is stored. */ +static int reg_offset[] = { + REG_OFFSET (eax), REG_OFFSET (ecx), REG_OFFSET (edx), REG_OFFSET (ebx), + REG_OFFSET (uesp), REG_OFFSET (ebp), REG_OFFSET (esi), REG_OFFSET (edi), + REG_OFFSET (eip), REG_OFFSET (efl), REG_OFFSET (cs), REG_OFFSET (ss), + REG_OFFSET (ds), REG_OFFSET (es), REG_OFFSET (fs), REG_OFFSET (gs) +}; + +/* Offset to the greg_t location where REG is stored. */ +#define CREG_OFFSET(reg) (REG_##reg * 4) + +/* At CREG_OFFSET[N] is the offset to the greg_t location where + the GDB register N is stored. */ +static int creg_offset[] = { + CREG_OFFSET (EAX), CREG_OFFSET (ECX), CREG_OFFSET (EDX), CREG_OFFSET (EBX), + CREG_OFFSET (UESP), CREG_OFFSET (EBP), CREG_OFFSET (ESI), CREG_OFFSET (EDI), + CREG_OFFSET (EIP), CREG_OFFSET (EFL), CREG_OFFSET (CS), CREG_OFFSET (SS), + CREG_OFFSET (DS), CREG_OFFSET (ES), CREG_OFFSET (FS), CREG_OFFSET (GS) +}; + +#define REG_ADDR(state, regnum) ((char *)(state) + reg_offset[regnum]) +#define CREG_ADDR(state, regnum) ((const char *)(state) + creg_offset[regnum]) + + +/* Get the whole floating-point state of THREAD and record the values + of the corresponding (pseudo) registers. */ + +static void +fetch_fpregs (struct regcache *regcache, struct proc *thread) +{ + gnu_debug ("fetch_fpregs() not support now\n"); +#if 0 + mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT; + struct i386_float_state state; + error_t err; + + err = thread_get_state (thread->port, i386_FLOAT_STATE, + (thread_state_t) & state, &count); + if (err) + { + warning (_("Couldn't fetch floating-point state from %s"), + proc_string (thread)); + return; + } + + if (!state.initialized) + { + /* The floating-point state isn't initialized. */ + i387_supply_fsave (regcache, -1, NULL); + } + else + { + /* Supply the floating-point registers. */ + i387_supply_fsave (regcache, -1, state.hw_state); + } +#endif +} + +extern struct inf *gnu_current_inf; +extern ptid_t inferior_ptid; +/* Fetch register REGNO, or all regs if REGNO is -1. */ +void +gnu_fetch_registers_1 (struct target_ops *ops, + struct regcache *regcache, int regno) +{ + struct proc *thread; + + /* Make sure we know about new threads. */ + inf_update_procs (gnu_current_inf); + + thread = inf_tid_to_thread (gnu_current_inf, TIDGET (inferior_ptid)); + if (!thread) + error (_ + ("[gnu_fetch_registers_1]Can't fetch registers from thread %s: No such thread"), + target_pid_to_str (inferior_ptid)); + + if (regno < I386_NUM_GREGS || regno == -1) + { + thread_state_t state; + + /* This does the dirty work for us. */ + state = proc_get_state (thread, 0); + if (!state) + { + warning (_("Couldn't fetch registers from %s"), + proc_string (thread)); + + return; + } + + if (regno == -1) + { + int i; + + proc_debug (thread, "fetching all register"); + + for (i = 0; i < I386_NUM_GREGS; i++) + /*regcache_raw_supply (regcache, i, REG_ADDR (state, i)); */ + supply_register (regcache, i, REG_ADDR (state, i)); + thread->fetched_regs = ~0; + } + else + { + /*proc_debug (thread, "fetching register %s", */ + /*gdbarch_register_name (get_regcache_arch (regcache), */ + /*regno)); */ + + /*regcache_raw_supply (regcache, regno,REG_ADDR (state, regno)); */ + supply_register (regcache, regno, REG_ADDR (state, regno)); + thread->fetched_regs |= (1 << regno); + } + } + + if (regno >= I386_NUM_GREGS || regno == -1) + { + proc_debug (thread, "fetching floating-point registers"); + + fetch_fpregs (regcache, thread); + } +} + + +/* Store the whole floating-point state into THREAD using information + from the corresponding (pseudo) registers. */ +void +store_fpregs (const struct regcache *regcache, struct proc *thread, int regno) +{ + gnu_debug ("store_fpregs() not support now\n"); +#if 0 + mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT; + struct i386_float_state state; + error_t err; + + err = thread_get_state (thread->port, i386_FLOAT_STATE, + (thread_state_t) & state, &count); + if (err) + { + warning (_("Couldn't fetch floating-point state from %s"), + proc_string (thread)); + return; + } + + /* FIXME: kettenis/2001-07-15: Is this right? Should we somehow + take into account DEPRECATED_REGISTER_VALID like the old code did? */ + i387_collect_fsave (regcache, regno, state.hw_state); + + err = thread_set_state (thread->port, i386_FLOAT_STATE, + (thread_state_t) & state, i386_FLOAT_STATE_COUNT); + if (err) + { + warning (_("Couldn't store floating-point state into %s"), + proc_string (thread)); + return; + } +#endif +} + +/* Store at least register REGNO, or all regs if REGNO == -1. */ +void +gnu_store_registers_1 (struct target_ops *ops, + struct regcache *regcache, int regno) +{ + struct proc *thread; + /*struct gdbarch *gdbarch = get_regcache_arch (regcache); */ + const struct target_desc *gdbarch = regcache->tdesc; + + /* Make sure we know about new threads. */ + inf_update_procs (gnu_current_inf); + + thread = inf_tid_to_thread (gnu_current_inf, TIDGET (inferior_ptid)); + if (!thread) + error (_("Couldn't store registers into thread %s: No such thread"), + target_pid_to_str (inferior_ptid)); + + if (regno < I386_NUM_GREGS || regno == -1) + { + thread_state_t state; + thread_state_data_t old_state; + int was_aborted = thread->aborted; + int was_valid = thread->state_valid; + int trace; + + if (!was_aborted && was_valid) + memcpy (&old_state, &thread->state, sizeof (old_state)); + + state = proc_get_state (thread, 1); + if (!state) + { + warning (_("Couldn't store registers into %s"), + proc_string (thread)); + return; + } + + /* Save the T bit. We might try to restore the %eflags register + below, but changing the T bit would seriously confuse GDB. */ + trace = ((struct i386_thread_state *) state)->efl & 0x100; + + if (!was_aborted && was_valid) + /* See which registers have changed after aborting the thread. */ + { + int check_regno; + + for (check_regno = 0; check_regno < I386_NUM_GREGS; check_regno++) + if ((thread->fetched_regs & (1 << check_regno)) + && memcpy (REG_ADDR (&old_state, check_regno), + REG_ADDR (state, check_regno), + register_size (gdbarch, check_regno))) + /* Register CHECK_REGNO has changed! Ack! */ + { + /*warning (_("Register %s changed after the thread was aborted"), */ + /*gdbarch_register_name (gdbarch, check_regno)); */ + if (regno >= 0 && regno != check_regno) + /* Update GDB's copy of the register. */ + /*regcache_raw_supply (regcache, check_regno,REG_ADDR (state, check_regno)); */ + supply_register (regcache, check_regno, + REG_ADDR (state, check_regno)); + else + warning (_("... also writing this register! " + "Suspicious...")); + } + } + + if (regno == -1) + { + int i; + + proc_debug (thread, "storing all registers"); + + for (i = 0; i < I386_NUM_GREGS; i++) + /*if (REG_VALID == regcache_register_status (regcache, i)) */ + /*regcache_raw_collect (regcache, i, REG_ADDR (state, i)); */ + collect_register (regcache, i, REG_ADDR (state, i)); + } + else + { + /*proc_debug (thread, "storing register %s",gdbarch_register_name (gdbarch, regno)); */ + + /*gdb_assert (REG_VALID == regcache_register_status (regcache, regno)); */ + /*regcache_raw_collect (regcache, regno, REG_ADDR (state, regno)); */ + collect_register (regcache, regno, REG_ADDR (state, regno)); + } + + /* Restore the T bit. */ + ((struct i386_thread_state *) state)->efl &= ~0x100; + ((struct i386_thread_state *) state)->efl |= trace; + } + + if (regno >= I386_NUM_GREGS || regno == -1) + { + proc_debug (thread, "storing floating-point registers"); + + store_fpregs (regcache, thread, regno); + } +} diff --git a/gdb/gdbserver/gnu-low.c b/gdb/gdbserver/gnu-low.c new file mode 100644 index 0000000..3fd1f04 --- /dev/null +++ b/gdb/gdbserver/gnu-low.c @@ -0,0 +1,2327 @@ +/* Copyright (C) 2009-2013 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 3 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, see <http://www.gnu.org/licenses/>. */ + +#include "server.h" +#include "target.h" + +#include "gnu-low.h" + +#include <limits.h> +#include <sys/ptrace.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include "gdb_wait.h" +#include <signal.h> + +#include <mach.h> +#include <mach_error.h> +#include <mach/message.h> +#include <mach/exception.h> + +#include "msg_reply_S.h" +#include "exc_request_S.h" +#include "process_reply_S.h" +#include "notify_S.h" + +/* this should move into gnu-i386-low.c ?*/ +/* Defined in auto-generated file i386.c. */ +extern void init_registers_i386 (void); +extern const struct target_desc *tdesc_i386; + +const struct target_desc *gnu_tdesc; +/* If we've sent a proc_wait_request to the proc server, the pid of the + process we asked about. We can only ever have one outstanding. */ +int proc_wait_pid = 0; + +/* The number of wait requests we've sent, and expect replies from. */ +int proc_waits_pending = 0; + +int using_threads = 1; + +struct inf *gnu_current_inf = NULL; +struct inf *waiting_inf = NULL; +static process_t proc_server = MACH_PORT_NULL; +static int next_thread_id = 1; +ptid_t inferior_ptid; + +/* Evaluate RPC_EXPR in a scope with the variables MSGPORT and REFPORT bound + to INF's msg port and task port respectively. If it has no msg port, + EIEIO is returned. INF must refer to a running process! */ +#define INF_MSGPORT_RPC(inf, rpc_expr) \ + HURD_MSGPORT_RPC (proc_getmsgport (proc_server, inf->pid, &msgport), \ + (refport = inf->task->port, 0), 0, \ + msgport ? (rpc_expr) : EIEIO) + +/* Like INF_MSGPORT_RPC, but will also resume the signal thread to ensure + there's someone around to deal with the RPC (and resuspend things + afterwards). This effects INF's threads' resume_sc count. */ +#define INF_RESUME_MSGPORT_RPC(inf, rpc_expr) \ + (inf_set_threads_resume_sc_for_signal_thread (inf) \ + ? ({ error_t __e; \ + inf_resume (inf); \ + __e = INF_MSGPORT_RPC (inf, rpc_expr); \ + inf_suspend (inf); \ + __e; }) \ + : EIEIO) +static struct target_ops gnu_target_ops; + +struct process_info_private +{ + struct inf *inf; +}; + +int debug_flags = 0; + +void +gnu_debug (char *string, ...) +{ + va_list args; + + if (!debug_flags) + return; + va_start (args, string); + fprintf (stderr, "DEBUG(gnu): "); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); + va_end (args); +} + +/* Set up the thread resume_sc's so that only the signal thread is running + (plus whatever other thread are set to always run). Returns true if we + did so, or false if we can't find a signal thread. */ +int +inf_set_threads_resume_sc_for_signal_thread (struct inf *inf) +{ + if (inf->signal_thread) + { + inf_set_threads_resume_sc (inf, inf->signal_thread, 0); + return 1; + } + else + return 0; +} + +/* Sets the resume_sc of each thread in inf. That of RUN_THREAD is set to 0, + and others are set to their run_sc if RUN_OTHERS is true, and otherwise + their pause_sc. */ +void +inf_set_threads_resume_sc (struct inf *inf, + struct proc *run_thread, int run_others) +{ + struct proc *thread; + + inf_update_procs (inf); + for (thread = inf->threads; thread; thread = thread->next) + if (thread == run_thread) + thread->resume_sc = 0; + else if (run_others) + thread->resume_sc = thread->run_sc; + else + thread->resume_sc = thread->pause_sc; +} + +void +inf_clear_wait (struct inf *inf) +{ + inf_debug (inf, "clearing wait"); + inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS; + inf->wait.thread = 0; + inf->wait.suppress = 0; + if (inf->wait.exc.handler != MACH_PORT_NULL) + { + mach_port_deallocate (mach_task_self (), inf->wait.exc.handler); + inf->wait.exc.handler = MACH_PORT_NULL; + } + if (inf->wait.exc.reply != MACH_PORT_NULL) + { + mach_port_deallocate (mach_task_self (), inf->wait.exc.reply); + inf->wait.exc.reply = MACH_PORT_NULL; + } +} + +int +__proc_pid (struct proc *proc) +{ + return proc->inf->pid; +} + +static ptid_t +gnu_ptid_build (int pid, long lwp, long tid) +{ + return ptid_build (pid, tid, 0); +} + +static long +gnu_get_tid (ptid_t ptid) +{ + return ptid_get_lwp (ptid); +} + +int +proc_update_sc (struct proc *proc) +{ + int running; + int err = 0; + int delta = proc->sc - proc->cur_sc; + + if (delta) + gnu_debug ("sc: %d --> %d", proc->cur_sc, proc->sc); + + if (proc->sc == 0 && proc->state_changed) + /* Since PROC may start running, we must write back any state changes. */ + { + gdb_assert (proc_is_thread (proc)); + err = thread_set_state (proc->port, THREAD_STATE_FLAVOR, + (thread_state_t) & proc->state, + THREAD_STATE_SIZE); + if (!err) + proc->state_changed = 0; + } + + if (delta > 0) + { + while (delta-- > 0 && !err) + { + if (proc_is_task (proc)) + err = task_suspend (proc->port); + else + err = thread_suspend (proc->port); + } + } + else + { + while (delta++ < 0 && !err) + { + if (proc_is_task (proc)) + err = task_resume (proc->port); + else + err = thread_resume (proc->port); + } + } + if (!err) + proc->cur_sc = proc->sc; + + /* If we got an error, then the task/thread has disappeared. */ + running = !err && proc->sc == 0; + + proc_debug (proc, "is %s", + err ? "dead" : running ? "running" : "suspended"); + if (err) + proc_debug (proc, "err = %s", safe_strerror (err)); + + if (running) + { + proc->aborted = 0; + proc->state_valid = proc->state_changed = 0; + proc->fetched_regs = 0; + } + + return running; +} + +error_t +proc_get_exception_port (struct proc * proc, mach_port_t * port) +{ + if (proc_is_task (proc)) + return task_get_exception_port (proc->port, port); + else + return thread_get_exception_port (proc->port, port); +} + +static mach_port_t +_proc_get_exc_port (struct proc *proc) +{ + mach_port_t exc_port; + error_t err = proc_get_exception_port (proc, &exc_port); + + if (err) + /* PROC must be dead. */ + { + if (proc->exc_port) + mach_port_deallocate (mach_task_self (), proc->exc_port); + proc->exc_port = MACH_PORT_NULL; + if (proc->saved_exc_port) + mach_port_deallocate (mach_task_self (), proc->saved_exc_port); + proc->saved_exc_port = MACH_PORT_NULL; + } + + return exc_port; +} + +void +inf_set_traced (struct inf *inf, int on) +{ + if (on == inf->traced) + return; + + if (inf->task && !inf->task->dead) + /* Make it take effect immediately. */ + { + sigset_t mask = on ? ~(sigset_t) 0 : 0; + error_t err = + INF_RESUME_MSGPORT_RPC (inf, msg_set_init_int (msgport, refport, + INIT_TRACEMASK, mask)); + + if (err == EIEIO) + { + /*if (on) */ + /*warning (_("Can't modify tracing state for pid %d: %s"), */ + /*inf->pid, "No signal thread"); */ + inf->traced = on; + } + else if (err) + ; + /*warning (_("Can't modify tracing state for pid %d: %s"), */ + /*inf->pid, safe_strerror (err)); */ + else + inf->traced = on; + } + else + inf->traced = on; +} + +/* Makes all the real suspend count deltas of all the procs in INF + match the desired values. Careful to always do thread/task suspend + counts in the safe order. Returns true if at least one thread is + thought to be running. */ +int +inf_update_suspends (struct inf *inf) +{ + struct proc *task = inf->task; + + /* We don't have to update INF->threads even though we're iterating over it + because we'll change a thread only if it already has an existing proc + entry. */ + inf_debug (inf, "updating suspend counts"); + + if (task) + { + struct proc *thread; + int task_running = (task->sc == 0), thread_running = 0; + + if (task->sc > task->cur_sc) + /* The task is becoming _more_ suspended; do before any threads. */ + task_running = proc_update_sc (task); + + if (inf->pending_execs) + /* When we're waiting for an exec, things may be happening behind our + back, so be conservative. */ + thread_running = 1; + + /* Do all the thread suspend counts. */ + for (thread = inf->threads; thread; thread = thread->next) + thread_running |= proc_update_sc (thread); + + if (task->sc != task->cur_sc) + /* We didn't do the task first, because we wanted to wait for the + threads; do it now. */ + task_running = proc_update_sc (task); + + inf_debug (inf, "%srunning...", + (thread_running && task_running) ? "" : "not "); + + inf->running = thread_running && task_running; + + /* Once any thread has executed some code, we can't depend on the + threads list any more. */ + if (inf->running) + inf->threads_up_to_date = 0; + + return inf->running; + } + + return 0; +} + +void +proc_abort (struct proc *proc, int force) +{ + gdb_assert (proc_is_thread (proc)); + + if (!proc->aborted) + { + struct inf *inf = proc->inf; + int running = (proc->cur_sc == 0 && inf->task->cur_sc == 0); + + if (running && force) + { + proc->sc = 1; + inf_update_suspends (proc->inf); + running = 0; + /*warning (_("Stopped %s."), proc_string (proc)); */ + } + else if (proc == inf->wait.thread && inf->wait.exc.reply && !force) + /* An exception is pending on PROC, which don't mess with. */ + running = 1; + + if (!running) + /* We only abort the thread if it's not actually running. */ + { + thread_abort (proc->port); + proc_debug (proc, "aborted"); + proc->aborted = 1; + } + else + proc_debug (proc, "not aborting"); + } +} + +thread_state_t +proc_get_state (struct proc *proc, int will_modify) +{ + int was_aborted = proc->aborted; + + proc_debug (proc, "updating state info%s", + will_modify ? " (with intention to modify)" : ""); + + proc_abort (proc, will_modify); + + if (!was_aborted && proc->aborted) + /* PROC's state may have changed since we last fetched it. */ + proc->state_valid = 0; + + if (!proc->state_valid) + { + mach_msg_type_number_t state_size = THREAD_STATE_SIZE; + error_t err = thread_get_state (proc->port, THREAD_STATE_FLAVOR, + (thread_state_t) & proc->state, + &state_size); + + proc_debug (proc, "getting thread state"); + proc->state_valid = !err; + } + + if (proc->state_valid) + { + if (will_modify) + proc->state_changed = 1; + return (thread_state_t) & proc->state; + } + else + return 0; +} + +void +proc_steal_exc_port (struct proc *proc, mach_port_t exc_port) +{ + mach_port_t cur_exc_port = _proc_get_exc_port (proc); + + if (cur_exc_port) + { + error_t err = 0; + + proc_debug (proc, "inserting exception port: %d", exc_port); + + if (cur_exc_port != exc_port) + /* Put in our exception port. */ + err = proc_set_exception_port (proc, exc_port); + + if (err || cur_exc_port == proc->exc_port) + /* We previously set the exception port, and it's still set. So we + just keep the old saved port which is what the proc set. */ + { + if (cur_exc_port) + mach_port_deallocate (mach_task_self (), cur_exc_port); + } + else + /* Keep a copy of PROC's old exception port so it can be restored. */ + { + if (proc->saved_exc_port) + mach_port_deallocate (mach_task_self (), proc->saved_exc_port); + proc->saved_exc_port = cur_exc_port; + } + + proc_debug (proc, "saved exception port: %d", proc->saved_exc_port); + + if (!err) + proc->exc_port = exc_port; + /*else */ + /*warning (_("Error setting exception port for %s: %s"), */ + /*proc_string (proc), safe_strerror (err)); */ + } +} + +int +proc_trace (struct proc *proc, int set) +{ + thread_state_t state = proc_get_state (proc, 1); + + if (!state) + return 0; /* The thread must be dead. */ + + proc_debug (proc, "tracing %s", set ? "on" : "off"); + + if (set) + { + /* XXX We don't get the exception unless the thread has its own + exception port???? */ + if (proc->exc_port == MACH_PORT_NULL) + proc_steal_exc_port (proc, proc->inf->event_port); + THREAD_STATE_SET_TRACED (state); + } + else + THREAD_STATE_CLEAR_TRACED (state); + + return 1; +} + +error_t +proc_set_exception_port (struct proc * proc, mach_port_t port) +{ + proc_debug (proc, "setting exception port: %d", port); + if (proc_is_task (proc)) + return task_set_exception_port (proc->port, port); + else + return thread_set_exception_port (proc->port, port); +} + +void +proc_restore_exc_port (struct proc *proc) +{ + mach_port_t cur_exc_port = _proc_get_exc_port (proc); + + if (cur_exc_port) + { + error_t err = 0; + + proc_debug (proc, "restoring real exception port"); + + if (proc->exc_port == cur_exc_port) + /* Our's is still there. */ + err = proc_set_exception_port (proc, proc->saved_exc_port); + + if (proc->saved_exc_port) + mach_port_deallocate (mach_task_self (), proc->saved_exc_port); + proc->saved_exc_port = MACH_PORT_NULL; + + if (!err) + proc->exc_port = MACH_PORT_NULL; + else + gnu_debug ("Error setting exception port\n"); + } +} + +void +inf_set_step_thread (struct inf *inf, struct proc *thread) +{ + gdb_assert (!thread || proc_is_thread (thread)); + + /*if (thread) */ + /*inf_debug (inf, "setting step thread: %d/%d", inf->pid, thread->tid); */ + /*else */ + /*inf_debug (inf, "clearing step thread"); */ + + if (inf->step_thread != thread) + { + if (inf->step_thread && inf->step_thread->port != MACH_PORT_NULL) + if (!proc_trace (inf->step_thread, 0)) + return; + if (thread && proc_trace (thread, 1)) + inf->step_thread = thread; + else + inf->step_thread = 0; + } +} + +struct proc * +_proc_free (struct proc *proc) +{ + struct inf *inf = proc->inf; + struct proc *next = proc->next; + + if (proc == inf->step_thread) + /* Turn off single stepping. */ + inf_set_step_thread (inf, 0); + if (proc == inf->wait.thread) + inf_clear_wait (inf); + if (proc == inf->signal_thread) + inf->signal_thread = 0; + + if (proc->port != MACH_PORT_NULL) + { + if (proc->exc_port != MACH_PORT_NULL) + /* Restore the original exception port. */ + proc_restore_exc_port (proc); + if (proc->cur_sc != 0) + /* Resume the thread/task. */ + { + proc->sc = 0; + proc_update_sc (proc); + } + mach_port_deallocate (mach_task_self (), proc->port); + } + + xfree (proc); + return next; +} + +struct proc * +make_proc (struct inf *inf, mach_port_t port, int tid) +{ + error_t err; + mach_port_t prev_port = MACH_PORT_NULL; + struct proc *proc = xmalloc (sizeof (struct proc)); + + proc->port = port; + proc->tid = tid; + proc->inf = inf; + proc->next = 0; + proc->saved_exc_port = MACH_PORT_NULL; + proc->exc_port = MACH_PORT_NULL; + + proc->sc = 0; + proc->cur_sc = 0; + + /* Note that these are all the values for threads; the task simply uses the + corresponding field in INF directly. */ + proc->run_sc = inf->default_thread_run_sc; + proc->pause_sc = inf->default_thread_pause_sc; + proc->detach_sc = inf->default_thread_detach_sc; + proc->resume_sc = proc->run_sc; + + proc->aborted = 0; + proc->dead = 0; + proc->state_valid = 0; + proc->state_changed = 0; + + proc_debug (proc, "is new"); + + /* Get notified when things die. */ + err = + mach_port_request_notification (mach_task_self (), port, + MACH_NOTIFY_DEAD_NAME, 1, + inf->event_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev_port); + if (err) + warning (_("Couldn't request notification for port %d: %s"), + port, safe_strerror (err)); + else + { + proc_debug (proc, "notifications to: %d", inf->event_port); + if (prev_port != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), prev_port); + } + + if (inf->want_exceptions) + { + if (proc_is_task (proc)) + /* Make the task exception port point to us. */ + proc_steal_exc_port (proc, inf->event_port); + else + /* Just clear thread exception ports -- they default to the + task one. */ + proc_steal_exc_port (proc, MACH_PORT_NULL); + } + + return proc; +} + +void +inf_validate_procs (struct inf *inf) +{ + thread_array_t threads; + mach_msg_type_number_t num_threads, i; + struct proc *task = inf->task; + + /* If no threads are currently running, this function will guarantee that + things are up to date. The exception is if there are zero threads -- + then it is almost certainly in an odd state, and probably some outside + agent will create threads. */ + inf->threads_up_to_date = inf->threads ? !inf->running : 0; + + if (task) + { + error_t err = task_threads (task->port, &threads, &num_threads); + + inf_debug (inf, "fetching threads"); + if (err) + /* TASK must be dead. */ + { + task->dead = 1; + task = 0; + } + } + + if (!task) + { + num_threads = 0; + inf_debug (inf, "no task"); + } + + { + /* Make things normally linear. */ + mach_msg_type_number_t search_start = 0; + /* Which thread in PROCS corresponds to each task thread, & the task. */ + struct proc *matched[num_threads + 1]; + /* The last thread in INF->threads, so we can add to the end. */ + struct proc *last = 0; + /* The current thread we're considering. */ + struct proc *thread = inf->threads; + + memset (matched, 0, sizeof (matched)); + + while (thread) + { + mach_msg_type_number_t left; + + for (i = search_start, left = num_threads; left; i++, left--) + { + if (i >= num_threads) + i -= num_threads; /* I wrapped around. */ + if (thread->port == threads[i]) + /* We already know about this thread. */ + { + matched[i] = thread; + last = thread; + thread = thread->next; + search_start++; + break; + } + } + + if (!left) + { + proc_debug (thread, "died!"); + + ptid_t ptid; + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); + if (find_thread_ptid (ptid)) + remove_thread (find_thread_ptid (ptid)); + + thread->port = MACH_PORT_NULL; + thread = _proc_free (thread); /* THREAD is dead. */ + if (last) + last->next = thread; + else + inf->threads = thread; + } + } + + for (i = 0; i < num_threads; i++) + { + if (matched[i]) + /* Throw away the duplicate send right. */ + mach_port_deallocate (mach_task_self (), threads[i]); + else + /* THREADS[I] is a thread we don't know about yet! */ + { + ptid_t ptid; + + thread = make_proc (inf, threads[i], next_thread_id++); + if (last) + last->next = thread; + else + inf->threads = thread; + last = thread; + proc_debug (thread, "new thread: %d", threads[i]); + + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); + + /* Tell GDB's generic thread code. */ + +#if 0 + if (ptid_equal (inferior_ptid, pid_to_ptid (inf->pid))) + /* This is the first time we're hearing about thread + ids, after a fork-child. */ + thread_change_ptid (inferior_ptid, ptid); + else if (inf->pending_execs != 0) + /* This is a shell thread. */ + add_thread_silent (ptid); + else + add_thread (ptid); +#endif + if (!find_thread_ptid (ptid)) + { + gnu_debug ("New thread, pid=%d, tid=%d\n", inf->pid, + thread->tid); + add_thread (ptid, thread); + inferior_ptid = ptid; // need fix!!!!!!!!!!!!! + } + } + } + + vm_deallocate (mach_task_self (), + (vm_address_t) threads, (num_threads * sizeof (thread_t))); + } +} + +int +inf_update_procs (struct inf *inf) +{ + if (!inf->task) + return 0; + if (!inf->threads_up_to_date) + inf_validate_procs (inf); + return !!inf->task; +} + +void +inf_set_pid (struct inf *inf, pid_t pid) +{ + task_t task_port; + struct proc *task = inf->task; + + inf_debug (inf, "setting pid: %d", pid); + + if (pid < 0) + task_port = MACH_PORT_NULL; + else + { + error_t err = proc_pid2task (proc_server, pid, &task_port); + + if (err) + { + error (_("Error getting task for pid %d: %s"), pid, "XXXX"); + /*pid, safe_strerror (err)); */ + } + } + + inf_debug (inf, "setting task: %d", task_port); + + if (inf->pause_sc) + task_suspend (task_port); + + if (task && task->port != task_port) + { + inf->task = 0; + inf_validate_procs (inf); /* Trash all the threads. */ + _proc_free (task); /* And the task. */ + } + + if (task_port != MACH_PORT_NULL) + { + inf->task = make_proc (inf, task_port, PROC_TID_TASK); + inf->threads_up_to_date = 0; + } + + if (inf->task) + { + inf->pid = pid; + if (inf->pause_sc) + /* Reflect task_suspend above. */ + inf->task->sc = inf->task->cur_sc = 1; + } + else + inf->pid = -1; +} + +void +inf_cleanup (struct inf *inf) +{ + inf_debug (inf, "cleanup"); + + inf_clear_wait (inf); + + inf_set_pid (inf, -1); + inf->pid = 0; + inf->running = 0; + inf->stopped = 0; + inf->nomsg = 1; + inf->traced = 0; + inf->no_wait = 0; + inf->pending_execs = 0; + + if (inf->event_port) + { + mach_port_destroy (mach_task_self (), inf->event_port); + inf->event_port = MACH_PORT_NULL; + } +} + +void +inf_startup (struct inf *inf, int pid) +{ + error_t err; + + inf_debug (inf, "startup: pid = %d", pid); + + inf_cleanup (inf); + + /* Make the port on which we receive all events. */ + err = mach_port_allocate (mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, &inf->event_port); + /*if (err) */ + /*error (_("Error allocating event port: %s"), safe_strerror (err)); */ + + /* Make a send right for it, so we can easily copy it for other people. */ + mach_port_insert_right (mach_task_self (), inf->event_port, + inf->event_port, MACH_MSG_TYPE_MAKE_SEND); + inf_set_pid (inf, pid); +} + +/* Detachs from INF's inferior task, letting it run once again... */ +void +inf_detach (struct inf *inf) +{ + struct proc *task = inf->task; + + inf_debug (inf, "detaching..."); + + inf_clear_wait (inf); + inf_set_step_thread (inf, 0); + + if (task) + { + struct proc *thread; + + inf_validate_procinfo (inf); + + inf_set_traced (inf, 0); + if (inf->stopped) + { + if (inf->nomsg) + inf_continue (inf); + else + inf_signal (inf, GDB_SIGNAL_0); + } + + proc_restore_exc_port (task); + task->sc = inf->detach_sc; + + for (thread = inf->threads; thread; thread = thread->next) + { + proc_restore_exc_port (thread); + thread->sc = thread->detach_sc; + } + + inf_update_suspends (inf); + } + + inf_cleanup (inf); +} + +void +inf_attach (struct inf *inf, int pid) +{ + inf_debug (inf, "attaching: %d", pid); + + if (inf->pid) + { + inf_detach (inf); + } + + inf_startup (inf, pid); +} + +struct inf * +make_inf (void) +{ + struct inf *inf = xmalloc (sizeof (struct inf)); + + inf->task = 0; + inf->threads = 0; + inf->threads_up_to_date = 0; + inf->pid = 0; + inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS; + inf->wait.thread = 0; + inf->wait.exc.handler = MACH_PORT_NULL; + inf->wait.exc.reply = MACH_PORT_NULL; + inf->step_thread = 0; + inf->signal_thread = 0; + inf->event_port = MACH_PORT_NULL; + inf->running = 0; + inf->stopped = 0; + inf->nomsg = 1; + inf->traced = 0; + inf->no_wait = 0; + inf->pending_execs = 0; + inf->pause_sc = 1; + inf->detach_sc = 0; + inf->default_thread_run_sc = 0; + inf->default_thread_pause_sc = 0; + inf->default_thread_detach_sc = 0; + inf->want_signals = 1; /* By default */ + inf->want_exceptions = 1; /* By default */ + + return inf; +} + +static struct inf * +cur_inf (void) +{ + if (!gnu_current_inf) + gnu_current_inf = make_inf (); + return gnu_current_inf; +} + + +static struct process_info * +gnu_add_process (int pid, int attached) +{ + struct process_info *proc; + + proc = add_process (pid, attached); + proc->tdesc = gnu_tdesc; + proc->private = xcalloc (1, sizeof (*proc->private)); + proc->private->inf = cur_inf (); + struct inf *inf = gnu_current_inf; + + inf_attach (inf, pid); + inf->pending_execs = 2; + inf->nomsg = 1; + inf->traced = 1; + + inf_resume (inf); + + return proc; +} + +static int +gnu_create_inferior (char *program, char **allargs) +{ + int pid; + pid = fork (); + if (pid < 0) + perror_with_name ("fork"); + + if (pid == 0) + { + ptrace (PTRACE_TRACEME); + setpgid (0, 0); + execv (program, allargs); + + fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno)); + fflush (stderr); + _exit (0177); + } + + gnu_add_process (pid, 0); + return pid; +} + +/* Fork an inferior process, and start debugging it. */ + +/* Set INFERIOR_PID to the first thread available in the child, if any. */ +static int +inf_pick_first_thread (void) +{ + if (gnu_current_inf->task && gnu_current_inf->threads) + /* The first thread. */ + return gnu_current_inf->threads->tid; + else + /* What may be the next thread. */ + return next_thread_id; +} + +static int +gnu_attach (unsigned long pid) +{ + return -1; //not support now + struct inf *inf = cur_inf (); + /*struct inferior *inferior; */ + + if (pid == getpid ()) /* Trying to masturbate? */ + error (_("I refuse to debug myself!")); + + inf_debug (inf, "attaching to pid: %d", pid); + + inf_attach (inf, pid); + + inf_update_procs (inf); + + inferior_ptid = gnu_ptid_build (pid, 0, inf_pick_first_thread ()); + + inf_validate_procinfo (inf); + inf->signal_thread = inf->threads ? inf->threads->next : 0; + inf_set_traced (inf, inf->want_signals); + + gnu_add_process (pid, 1); + add_thread (inferior_ptid, NULL); + return 0; +} + +static int +gnu_kill (int pid) +{ + struct proc *task = gnu_current_inf->task; + struct process_info *process; + + process = find_process_pid (pid); + + if (task) + { + proc_debug (task, "terminating..."); + task_terminate (task->port); + inf_set_pid (gnu_current_inf, -1); + } + the_target->mourn (process); + return 0; +} + +static int +gnu_detach (int pid) +{ + struct process_info *process; + + process = find_process_pid (pid); + if (process == NULL) + return -1; + + inf_detach (gnu_current_inf); + + inferior_ptid = null_ptid; + the_target->mourn (process); + return 0; +} + + +static void +gnu_mourn (struct process_info *process) +{ + /* Free our private data. */ + free (process->private); + process->private = NULL; + + clear_inferiors (); +} + +static void +gnu_join (int pid) +{ + /* doesn't need */ +} + +static int +gnu_thread_alive (ptid_t ptid) +{ + /* this function is copyed from lynx-low.c */ + return (find_thread_ptid (ptid) != NULL); +} + + +/* Fill in INF's wait field after a task has died without giving us more + detailed information. */ +void +inf_task_died_status (struct inf *inf) +{ + printf ("Pid %d died with unknown exit status, using SIGKILL.", inf->pid); + inf->wait.status.kind = TARGET_WAITKIND_SIGNALLED; + inf->wait.status.value.sig = GDB_SIGNAL_KILL; +} + +struct proc * +inf_tid_to_thread (struct inf *inf, int tid) +{ + struct proc *thread = inf->threads; + + gnu_debug ("[inf_tid_to_thread]:search thread which tid=%d\n", tid); + + while (thread) + if (thread->tid == tid) + return thread; + else + thread = thread->next; + return 0; +} + +/* Validates INF's stopped, nomsg and traced field from the actual + proc server state. Note that the traced field is only updated from + the proc server state if we do not have a message port. If we do + have a message port we'd better look at the tracemask itself. */ +static void +inf_validate_procinfo (struct inf *inf) +{ + char *noise; + mach_msg_type_number_t noise_len = 0; + struct procinfo *pi; + mach_msg_type_number_t pi_len = 0; + int info_flags = 0; + error_t err = proc_getprocinfo (proc_server, inf->pid, &info_flags, + (procinfo_t *) & pi, &pi_len, &noise, + &noise_len); + + if (!err) + { + inf->stopped = !!(pi->state & PI_STOPPED); + inf->nomsg = !!(pi->state & PI_NOMSG); + if (inf->nomsg) + inf->traced = !!(pi->state & PI_TRACED); + vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len); + if (noise_len > 0) + vm_deallocate (mach_task_self (), (vm_address_t) noise, noise_len); + } +} + +/* Deliver signal SIG to INF. If INF is stopped, delivering a signal, even + signal 0, will continue it. INF is assumed to be in a paused state, and + the resume_sc's of INF's threads may be affected. */ +void +inf_signal (struct inf *inf, enum gdb_signal sig) +{ + error_t err = 0; + int host_sig = gdb_signal_to_host (sig); + +#define NAME gdb_signal_to_name (sig) + + if (host_sig >= _NSIG) + /* A mach exception. Exceptions are encoded in the signal space by + putting them after _NSIG; this assumes they're positive (and not + extremely large)! */ + { + struct inf_wait *w = &inf->wait; + + if (w->status.kind == TARGET_WAITKIND_STOPPED + && w->status.value.sig == sig && w->thread && !w->thread->aborted) + /* We're passing through the last exception we received. This is + kind of bogus, because exceptions are per-thread whereas gdb + treats signals as per-process. We just forward the exception to + the correct handler, even it's not for the same thread as TID -- + i.e., we pretend it's global. */ + { + struct exc_state *e = &w->exc; + + inf_debug (inf, "passing through exception:" + " task = %d, thread = %d, exc = %d" + ", code = %d, subcode = %d", + w->thread->port, inf->task->port, + e->exception, e->code, e->subcode); + err = + exception_raise_request (e->handler, + e->reply, MACH_MSG_TYPE_MOVE_SEND_ONCE, + w->thread->port, inf->task->port, + e->exception, e->code, e->subcode); + } + else + error (_("Can't forward spontaneous exception (%s)."), NAME); + } + else + /* A Unix signal. */ + if (inf->stopped) + /* The process is stopped and expecting a signal. Just send off a + request and let it get handled when we resume everything. */ + { + inf_debug (inf, "sending %s to stopped process", NAME); + err = + INF_MSGPORT_RPC (inf, + msg_sig_post_untraced_request (msgport, + inf->event_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + host_sig, 0, + refport)); + if (!err) + /* Posting an untraced signal automatically continues it. + We clear this here rather than when we get the reply + because we'd rather assume it's not stopped when it + actually is, than the reverse. */ + inf->stopped = 0; + } + else + /* It's not expecting it. We have to let just the signal thread + run, and wait for it to get into a reasonable state before we + can continue the rest of the process. When we finally resume the + process the signal we request will be the very first thing that + happens. */ + { + inf_debug (inf, "sending %s to unstopped process" + " (so resuming signal thread)", NAME); + err = + INF_RESUME_MSGPORT_RPC (inf, + msg_sig_post_untraced (msgport, host_sig, + 0, refport)); + } + + if (err == EIEIO) + /* Can't do too much... */ + warning (_("Can't deliver signal %s: No signal thread."), NAME); + else if (err) + warning (_("Delivering signal %s: %s"), NAME, safe_strerror (err)); + +#undef NAME +} + +/* Continue INF without delivering a signal. This is meant to be used + when INF does not have a message port. */ +void +inf_continue (struct inf *inf) +{ + process_t proc; + error_t err = proc_pid2proc (proc_server, inf->pid, &proc); + + if (!err) + { + inf_debug (inf, "continuing process"); + + err = proc_mark_cont (proc); + if (!err) + { + struct proc *thread; + + for (thread = inf->threads; thread; thread = thread->next) + thread_resume (thread->port); + + inf->stopped = 0; + } + } + + if (err) + warning (_("Can't continue process: %s"), safe_strerror (err)); +} + +/* Returns the number of messages queued for the receive right PORT. */ +static mach_port_msgcount_t +port_msgs_queued (mach_port_t port) +{ + struct mach_port_status status; + error_t err = + mach_port_get_receive_status (mach_task_self (), port, &status); + + if (err) + return 0; + else + return status.mps_msgcount; +} + +static void +gnu_resume_1 (struct target_ops *ops, + ptid_t ptid, int step, enum gdb_signal sig) +{ + struct proc *step_thread = 0; + int resume_all; + struct inf *inf = gnu_current_inf; + + inf_debug (inf, "ptid = %s, step = %d, sig = %d", + target_pid_to_str (ptid), step, sig); + + inf_validate_procinfo (inf); + + if (sig != GDB_SIGNAL_0 || inf->stopped) + { + if (sig == GDB_SIGNAL_0 && inf->nomsg) + inf_continue (inf); + else + inf_signal (inf, sig); + } + else if (inf->wait.exc.reply != MACH_PORT_NULL) + /* We received an exception to which we have chosen not to forward, so + abort the faulting thread, which will perhaps retake it. */ + { + proc_abort (inf->wait.thread, 1); + /*warning (_("Aborting %s with unforwarded exception %s."), */ + /*proc_string (inf->wait.thread), */ + /*gdb_signal_to_name (inf->wait.status.value.sig)); */ + } + + if (port_msgs_queued (inf->event_port)) + /* If there are still messages in our event queue, don't bother resuming + the process, as we're just going to stop it right away anyway. */ + return; + + inf_update_procs (inf); + + /* A specific PTID means `step only this process id'. */ + resume_all = ptid_equal (ptid, minus_one_ptid); + + if (resume_all) + /* Allow all threads to run, except perhaps single-stepping one. */ + { + inf_debug (inf, "running all threads; tid = %d", + PIDGET (inferior_ptid)); + ptid = inferior_ptid; /* What to step. */ + inf_set_threads_resume_sc (inf, 0, 1); + } + else + /* Just allow a single thread to run. */ + { + struct proc *thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); + + if (!thread) + error (_("Can't run single thread id %s: no such thread!"), + target_pid_to_str (ptid)); + inf_debug (inf, "running one thread: %s", target_pid_to_str (ptid)); + inf_set_threads_resume_sc (inf, thread, 0); + } + + if (step) + { + step_thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); + if (!step_thread) + warning (_("Can't step thread id %s: no such thread."), + target_pid_to_str (ptid)); + else + inf_debug (inf, "stepping thread: %s", target_pid_to_str (ptid)); + } + if (step_thread != inf->step_thread) + inf_set_step_thread (inf, step_thread); + + inf_debug (inf, "here we go..."); + inf_resume (inf); +} + +static void +gnu_resume (struct thread_resume *resume_info, size_t n) +{ + /* FIXME: Assume for now that n == 1. */ + ptid_t ptid = resume_info[0].thread; + const int step = (resume_info[0].kind == resume_step ? 1 : 0); //1 means step, 0 means contiune + const int signal = resume_info[0].sig; + if (ptid_equal (ptid, minus_one_ptid)) + ptid = thread_to_gdb_id (current_inferior); + + regcache_invalidate (); + + gnu_debug ("in gnu_resume: ptid=%d, step=%d, signal=%d\n", ptid, step, + signal); + + /*my_resume(); */ + /*static void gnu_resume_1 (struct target_ops *ops,ptid_t ptid, int step, enum gdb_signal sig) */ + gnu_resume_1 (NULL, ptid, step, signal); + +} + +void +inf_suspend (struct inf *inf) +{ + struct proc *thread; + + inf_update_procs (inf); + + for (thread = inf->threads; thread; thread = thread->next) + thread->sc = thread->pause_sc; + + if (inf->task) + inf->task->sc = inf->pause_sc; + + inf_update_suspends (inf); +} + +static ptid_t +gnu_wait_1 (ptid_t ptid, struct target_waitstatus *status, int target_options) +{ + struct msg + { + mach_msg_header_t hdr; + mach_msg_type_t type; + int data[8000]; + } msg; + error_t err; + struct proc *thread; + struct inf *inf = gnu_current_inf; + + extern int exc_server (mach_msg_header_t *, mach_msg_header_t *); + extern int msg_reply_server (mach_msg_header_t *, mach_msg_header_t *); + extern int notify_server (mach_msg_header_t *, mach_msg_header_t *); + extern int process_reply_server (mach_msg_header_t *, mach_msg_header_t *); + + gdb_assert (inf->task); + + if (!inf->threads && !inf->pending_execs) + /* No threads! Assume that maybe some outside agency is frobbing our + task, and really look for new threads. If we can't find any, just tell + the user to try again later. */ + { + inf_validate_procs (inf); + if (!inf->threads && !inf->task->dead) + error (_("There are no threads; try again later.")); + } + + waiting_inf = inf; + + inf_debug (inf, "waiting for: %s", target_pid_to_str (ptid)); + +rewait: + if (proc_wait_pid != inf->pid && !inf->no_wait) + /* Always get information on events from the proc server. */ + { + inf_debug (inf, "requesting wait on pid %d", inf->pid); + + if (proc_wait_pid) + /* The proc server is single-threaded, and only allows a single + outstanding wait request, so we have to cancel the previous one. */ + { + inf_debug (inf, "cancelling previous wait on pid %d", + proc_wait_pid); + interrupt_operation (proc_server, 0); + } + + err = + proc_wait_request (proc_server, inf->event_port, inf->pid, WUNTRACED); + if (err) + warning (_("wait request failed: %s"), safe_strerror (err)); + else + { + inf_debug (inf, "waits pending: %d", proc_waits_pending); + proc_wait_pid = inf->pid; + /* Even if proc_waits_pending was > 0 before, we still won't + get any other replies, because it was either from a + different INF, or a different process attached to INF -- + and the event port, which is the wait reply port, changes + when you switch processes. */ + proc_waits_pending = 1; + } + } + + inf_clear_wait (inf); + + /* What can happen? (1) Dead name notification; (2) Exceptions arrive; + (3) wait reply from the proc server. */ + + inf_debug (inf, "waiting for an event..."); + err = mach_msg (&msg.hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT, + 0, sizeof (struct msg), inf->event_port, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + + /* Re-suspend the task. */ + inf_suspend (inf); + + if (!inf->task && inf->pending_execs) + /* When doing an exec, it's possible that the old task wasn't reused + (e.g., setuid execs). So if the task seems to have disappeared, + attempt to refetch it, as the pid should still be the same. */ + inf_set_pid (inf, inf->pid); + + if (err == EMACH_RCV_INTERRUPTED) + printf ("interrupted\n"); + /*inf_debug (inf, "interrupted"); */ + else if (err) + printf ("Couldn't wait for an event:\n"); + /*error (_("Couldn't wait for an event: %s"), safe_strerror (err)); */ + else + { + struct + { + mach_msg_header_t hdr; + mach_msg_type_t err_type; + kern_return_t err; + char noise[200]; + } + reply; + + inf_debug (inf, "event: msgid = %d", msg.hdr.msgh_id); + + /* Handle what we got. */ + if (!notify_server (&msg.hdr, &reply.hdr) + && !exc_server (&msg.hdr, &reply.hdr) + && !process_reply_server (&msg.hdr, &reply.hdr) + && !msg_reply_server (&msg.hdr, &reply.hdr)) + /* Whatever it is, it's something strange. */ + error (_("Got a strange event, msg id = %d."), msg.hdr.msgh_id); + + if (reply.err) + error (_("Handling event, msgid = %d: %s"), + msg.hdr.msgh_id, safe_strerror (reply.err)); + } + + if (inf->pending_execs) + /* We're waiting for the inferior to finish execing. */ + { + struct inf_wait *w = &inf->wait; + enum target_waitkind kind = w->status.kind; + + if (kind == TARGET_WAITKIND_SPURIOUS) + /* Since gdb is actually counting the number of times the inferior + stops, expecting one stop per exec, we only return major events + while execing. */ + { + w->suppress = 1; + inf_debug (inf, "pending_execs = %d, ignoring minor event", + inf->pending_execs); + } + else if (kind == TARGET_WAITKIND_STOPPED + && w->status.value.sig == GDB_SIGNAL_TRAP) + /* Ah hah! A SIGTRAP from the inferior while starting up probably + means we've succesfully completed an exec! */ + { + if (--inf->pending_execs == 0) + /* We're done! */ + { +#if 0 /* do we need this? */ + prune_threads (1); /* Get rid of the old shell + threads. */ + renumber_threads (0); /* Give our threads reasonable + names. */ +#endif + } + inf_debug (inf, "pending exec completed, pending_execs => %d", + inf->pending_execs); + } + else if (kind == TARGET_WAITKIND_STOPPED) + /* It's possible that this signal is because of a crashed process + being handled by the hurd crash server; in this case, the process + will have an extra task suspend, which we need to know about. + Since the code in inf_resume that normally checks for this is + disabled while INF->pending_execs, we do the check here instead. */ + inf_validate_task_sc (inf); + } + + if (inf->wait.suppress) + /* Some totally spurious event happened that we don't consider + worth returning to gdb. Just keep waiting. */ + { + inf_debug (inf, "suppressing return, rewaiting..."); + inf_resume (inf); + goto rewait; + } + + /* Pass back out our results. */ + memcpy (status, &inf->wait.status, sizeof (*status)); + + thread = inf->wait.thread; + if (thread) + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); + else if (ptid_equal (ptid, minus_one_ptid)) + thread = inf_tid_to_thread (inf, -1); + else + thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); + + if (!thread || thread->port == MACH_PORT_NULL) + { + /* TID is dead; try and find a new thread. */ + if (inf_update_procs (inf) && inf->threads) + ptid = gnu_ptid_build (inf->pid, 0, inf->threads->tid); + /* The first + available + thread. */ + else + ptid = inferior_ptid; /* let wait_for_inferior handle exit case */ + } + + if (thread + && !ptid_equal (ptid, minus_one_ptid) + && status->kind != TARGET_WAITKIND_SPURIOUS + && inf->pause_sc == 0 && thread->pause_sc == 0) + /* If something actually happened to THREAD, make sure we + suspend it. */ + { + thread->sc = 1; + inf_update_suspends (inf); + } + + inf_debug (inf, "returning ptid = %s, status = %s (%d)", + target_pid_to_str (ptid), + status->kind == TARGET_WAITKIND_EXITED ? "EXITED" + : status->kind == TARGET_WAITKIND_STOPPED ? "STOPPED" + : status->kind == TARGET_WAITKIND_SIGNALLED ? "SIGNALLED" + : status->kind == TARGET_WAITKIND_LOADED ? "LOADED" + : status->kind == TARGET_WAITKIND_SPURIOUS ? "SPURIOUS" + : "?", status->value.integer); + + inferior_ptid = ptid; + return ptid; +} + +static ptid_t +gnu_wait (ptid_t ptid, struct target_waitstatus *status, int target_options) +{ + ptid_t event_ptid; + gnu_debug ("gnu_wait: [%s]", target_pid_to_str (ptid)); + event_ptid = gnu_wait_1 (ptid, status, target_options); + gnu_debug (" -> (status->kind = %d)\n", status->kind); + return event_ptid; +} + +/* Return printable description of proc. */ +char * +proc_string (struct proc *proc) +{ + static char tid_str[80]; + + if (proc_is_task (proc)) + xsnprintf (tid_str, sizeof (tid_str), "process %d", proc->inf->pid); + else + xsnprintf (tid_str, sizeof (tid_str), "Thread %d.%d", + proc->inf->pid, proc->tid); + return tid_str; +} + +void +gnu_fetch_registers (struct regcache *regcache, int regno) +{ + gnu_debug ("gnu_fetch_registers() regno=%d\n", regno); + return gnu_fetch_registers_1 (NULL, regcache, regno); +} + +void +gnu_store_registers (struct regcache *regcache, int regno) +{ + gnu_debug ("gnu_store_registers() regno=%d\n", regno); + return gnu_store_registers_1 (NULL, regcache, regno); +} + +/* Read inferior task's LEN bytes from ADDR and copy it to MYADDR in + gdb's address space. Return 0 on failure; number of bytes read + otherwise. */ +int +gnu_read_inferior (task_t task, CORE_ADDR addr, unsigned char *myaddr, + int length) +{ + error_t err; + vm_address_t low_address = (vm_address_t) trunc_page (addr); + vm_size_t aligned_length = + (vm_size_t) round_page (addr + length) - low_address; + pointer_t copied; + int copy_count; + + /* Get memory from inferior with page aligned addresses. */ + err = vm_read (task, low_address, aligned_length, &copied, ©_count); + if (err) + return 0; + + err = hurd_safe_copyin (myaddr, (void *) (addr - low_address + copied), + length); + if (err) + { + warning (_("Read from inferior faulted: %s"), safe_strerror (err)); + length = 0; + } + + err = vm_deallocate (mach_task_self (), copied, copy_count); + if (err) + warning (_("gnu_read_inferior vm_deallocate failed: %s"), + safe_strerror (err)); + + return length; +} + +#define CHK_GOTO_OUT(str,ret) \ + do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0) + +struct vm_region_list +{ + struct vm_region_list *next; + vm_prot_t protection; + vm_address_t start; + vm_size_t length; +}; +/*struct obstack region_obstack;*/ + +/* Write gdb's LEN bytes from MYADDR and copy it to ADDR in inferior + task's address space. */ +int +gnu_write_inferior (task_t task, CORE_ADDR addr, const char *myaddr, + int length) +{ + error_t err = 0; + vm_address_t low_address = (vm_address_t) trunc_page (addr); + vm_size_t aligned_length = + (vm_size_t) round_page (addr + length) - low_address; + pointer_t copied; + int copy_count; + int deallocate = 0; + + char *errstr = "Bug in gnu_write_inferior"; + + struct vm_region_list *region_element; + struct vm_region_list *region_head = (struct vm_region_list *) NULL; + + /* Get memory from inferior with page aligned addresses. */ + err = vm_read (task, low_address, aligned_length, &copied, ©_count); + CHK_GOTO_OUT ("gnu_write_inferior vm_read failed", err); + + deallocate++; + + err = hurd_safe_copyout ((void *) (addr - low_address + copied), + myaddr, length); + CHK_GOTO_OUT ("Write to inferior faulted", err); + + /*obstack_init (®ion_obstack); */ + + /* Do writes atomically. + First check for holes and unwritable memory. */ + { + vm_size_t remaining_length = aligned_length; + vm_address_t region_address = low_address; + + struct vm_region_list *scan; + + while (region_address < low_address + aligned_length) + { + vm_prot_t protection; + vm_prot_t max_protection; + vm_inherit_t inheritance; + boolean_t shared; + mach_port_t object_name; + vm_offset_t offset; + vm_size_t region_length = remaining_length; + vm_address_t old_address = region_address; + + err = vm_region (task, + ®ion_address, + ®ion_length, + &protection, + &max_protection, + &inheritance, &shared, &object_name, &offset); + CHK_GOTO_OUT ("vm_region failed", err); + + /* Check for holes in memory. */ + if (old_address != region_address) + { + warning (_("No memory at 0x%x. Nothing written"), old_address); + err = KERN_SUCCESS; + length = 0; + goto out; + } + + if (!(max_protection & VM_PROT_WRITE)) + { + warning (_("Memory at address 0x%x is unwritable. " + "Nothing written"), old_address); + err = KERN_SUCCESS; + length = 0; + goto out; + } + + /* Chain the regions for later use. */ + /*region_element = */ + /*(struct vm_region_list *) */ + /*obstack_alloc (®ion_obstack, sizeof (struct vm_region_list)); */ + region_element = + (struct vm_region_list *) malloc (sizeof (struct vm_region_list)); + + region_element->protection = protection; + region_element->start = region_address; + region_element->length = region_length; + + /* Chain the regions along with protections. */ + region_element->next = region_head; + region_head = region_element; + + region_address += region_length; + remaining_length = remaining_length - region_length; + } + + /* If things fail after this, we give up. + Somebody is messing up inferior_task's mappings. */ + + /* Enable writes to the chained vm regions. */ + for (scan = region_head; scan; scan = scan->next) + { + if (!(scan->protection & VM_PROT_WRITE)) + { + err = vm_protect (task, + scan->start, + scan->length, + FALSE, scan->protection | VM_PROT_WRITE); + CHK_GOTO_OUT ("vm_protect: enable write failed", err); + } + } + + err = vm_write (task, low_address, copied, aligned_length); + CHK_GOTO_OUT ("vm_write failed", err); + + /* Set up the original region protections, if they were changed. */ + for (scan = region_head; scan; scan = scan->next) + { + if (!(scan->protection & VM_PROT_WRITE)) + { + err = vm_protect (task, + scan->start, + scan->length, FALSE, scan->protection); + CHK_GOTO_OUT ("vm_protect: enable write failed", err); + } + } + } + +out: + if (deallocate) + { + /*obstack_free (®ion_obstack, 0); */ + + (void) vm_deallocate (mach_task_self (), copied, copy_count); + } + + if (err != KERN_SUCCESS) + { + warning (_("%s: %s"), errstr, mach_error_string (err)); + return 0; + } + + return length; +} + +static int +gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length) +{ + int ret = 0; + task_t task = (gnu_current_inf + ? (gnu_current_inf->task + ? gnu_current_inf->task->port : 0) : 0); + if (task == MACH_PORT_NULL) + return 0; + ret = gnu_read_inferior (task, addr, myaddr, length); + if (length != ret) + { + gnu_debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret); + return -1; + } + return 0; +} + +static int +gnu_write_memory (CORE_ADDR addr, const unsigned char *myaddr, int length) +{ + int ret = 0; + task_t task = (gnu_current_inf + ? (gnu_current_inf->task + ? gnu_current_inf->task->port : 0) : 0); + if (task == MACH_PORT_NULL) + return 0; + ret = gnu_write_inferior (task, addr, myaddr, length); + if (length != ret) + { + gnu_debug ("gnu_write_inferior,length=%d, but return %d\n", length, + ret); + return -1; + } + return 0; +} + +static void +gnu_request_interrupt (void) +{ + printf ("gnu_request_interrupt not support!\n"); + exit (-1); +} + +/* Helper function for child_wait and the derivatives of child_wait. + HOSTSTATUS is the waitstatus from wait() or the equivalent; store our + translation of that in OURSTATUS. */ +void +store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus) +{ + if (WIFEXITED (hoststatus)) + { + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = WEXITSTATUS (hoststatus); + } + else if (!WIFSTOPPED (hoststatus)) + { + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (hoststatus)); + } + else + { + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (hoststatus)); + } +} + +/* Validates INF's task suspend count. If it's higher than we expect, + verify with the user before `stealing' the extra count. */ +static void +inf_validate_task_sc (struct inf *inf) +{ + char *noise; + mach_msg_type_number_t noise_len = 0; + struct procinfo *pi; + mach_msg_type_number_t pi_len = 0; + int info_flags = PI_FETCH_TASKINFO; + int suspend_count = -1; + error_t err; + +retry: + err = proc_getprocinfo (proc_server, inf->pid, &info_flags, + (procinfo_t *) & pi, &pi_len, &noise, &noise_len); + if (err) + { + inf->task->dead = 1; /* oh well */ + return; + } + + if (inf->task->cur_sc < pi->taskinfo.suspend_count && suspend_count == -1) + { + /* The proc server might have suspended the task while stopping + it. This happens when the task is handling a traced signal. + Refetch the suspend count. The proc server should be + finished stopping the task by now. */ + suspend_count = pi->taskinfo.suspend_count; + goto retry; + } + + suspend_count = pi->taskinfo.suspend_count; + + vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len); + if (noise_len > 0) + vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len); + + if (inf->task->cur_sc < suspend_count) + { +#if 0 + int abort; + + target_terminal_ours (); /* Allow I/O. */ + abort = !query (_("Pid %d has an additional task suspend count of %d;" + " clear it? "), inf->pid, + suspend_count - inf->task->cur_sc); + target_terminal_inferior (); /* Give it back to the child. */ + + if (abort) + error (_("Additional task suspend count left untouched.")); +#endif + + //need fix! + inf->task->cur_sc = suspend_count; + } +} + +void +inf_resume (struct inf *inf) +{ + struct proc *thread; + + inf_update_procs (inf); + + for (thread = inf->threads; thread; thread = thread->next) + thread->sc = thread->resume_sc; + + if (inf->task) + { + if (!inf->pending_execs) + /* Try to make sure our task count is correct -- in the case where + we're waiting for an exec though, things are too volatile, so just + assume things will be reasonable (which they usually will be). */ + inf_validate_task_sc (inf); + inf->task->sc = 0; + } + + inf_update_suspends (inf); +} + +/* Converts a thread port to a struct proc. */ +struct proc * +inf_port_to_thread (struct inf *inf, mach_port_t port) +{ + struct proc *thread = inf->threads; + + while (thread) + if (thread->port == port) + return thread; + else + thread = thread->next; + return 0; +} + +error_t +S_exception_raise_request (mach_port_t port, mach_port_t reply_port, + thread_t thread_port, task_t task_port, + int exception, int code, int subcode) +{ + struct inf *inf = waiting_inf; + struct proc *thread = inf_port_to_thread (inf, thread_port); + + inf_debug (waiting_inf, + "S_exception_raise_request thread = %d, task = %d, exc = %d, code = %d, subcode = %d", + thread_port, task_port, exception, code, subcode); + + if (!thread) + /* We don't know about thread? */ + { + inf_update_procs (inf); + thread = inf_port_to_thread (inf, thread_port); + if (!thread) + /* Give up, the generating thread is gone. */ + return 0; + } + + mach_port_deallocate (mach_task_self (), thread_port); + mach_port_deallocate (mach_task_self (), task_port); + + if (!thread->aborted) + /* THREAD hasn't been aborted since this exception happened (abortion + clears any exception state), so it must be real. */ + { + /* Store away the details; this will destroy any previous info. */ + inf->wait.thread = thread; + + inf->wait.status.kind = TARGET_WAITKIND_STOPPED; + + if (exception == EXC_BREAKPOINT) + /* GDB likes to get SIGTRAP for breakpoints. */ + { + inf->wait.status.value.sig = GDB_SIGNAL_TRAP; + mach_port_deallocate (mach_task_self (), reply_port); + } + else + /* Record the exception so that we can forward it later. */ + { + if (thread->exc_port == port) + { + inf_debug (waiting_inf, "Handler is thread exception port <%d>", + thread->saved_exc_port); + inf->wait.exc.handler = thread->saved_exc_port; + } + else + { + inf_debug (waiting_inf, "Handler is task exception port <%d>", + inf->task->saved_exc_port); + inf->wait.exc.handler = inf->task->saved_exc_port; + gdb_assert (inf->task->exc_port == port); + } + if (inf->wait.exc.handler != MACH_PORT_NULL) + /* Add a reference to the exception handler. */ + mach_port_mod_refs (mach_task_self (), + inf->wait.exc.handler, MACH_PORT_RIGHT_SEND, + 1); + + inf->wait.exc.exception = exception; + inf->wait.exc.code = code; + inf->wait.exc.subcode = subcode; + inf->wait.exc.reply = reply_port; + + /* Exceptions are encoded in the signal space by putting + them after _NSIG; this assumes they're positive (and not + extremely large)! */ + inf->wait.status.value.sig = + gdb_signal_from_host (_NSIG + exception); + } + } + else + /* A supppressed exception, which ignore. */ + { + inf->wait.suppress = 1; + mach_port_deallocate (mach_task_self (), reply_port); + } + return 0; +} + +error_t +S_proc_wait_reply (mach_port_t reply, error_t err, + int status, int sigcode, rusage_t rusage, pid_t pid) +{ + struct inf *inf = waiting_inf; + + inf_debug (inf, + "S_proc_wait_reply err = %s, pid = %d, status = 0x%x, sigcode = %d", + err ? safe_strerror (err) : "0", pid, status, sigcode); + + if (err && proc_wait_pid && (!inf->task || !inf->task->port)) + /* Ack. The task has died, but the task-died notification code didn't + tell anyone because it thought a more detailed reply from the + procserver was forthcoming. However, we now learn that won't + happen... So we have to act like the task just died, and this time, + tell the world. */ + inf_task_died_status (inf); + + if (--proc_waits_pending == 0) + /* PROC_WAIT_PID represents the most recent wait. We will always get + replies in order because the proc server is single threaded. */ + proc_wait_pid = 0; + + inf_debug (inf, "waits pending now: %d", proc_waits_pending); + + if (err) + { + if (err != EINTR) + { + /*warning (_("Can't wait for pid %d: %s"), */ + /*inf->pid, safe_strerror (err)); */ + inf->no_wait = 1; + + /* Since we can't see the inferior's signals, don't trap them. */ + inf_set_traced (inf, 0); + } + } + else if (pid == inf->pid) + { + store_waitstatus (&inf->wait.status, status); + if (inf->wait.status.kind == TARGET_WAITKIND_STOPPED) + /* The process has sent us a signal, and stopped itself in a sane + state pending our actions. */ + { + inf_debug (inf, "process has stopped itself"); + inf->stopped = 1; + } + } + else + inf->wait.suppress = 1; /* Something odd happened. Ignore. */ + + return 0; +} + +error_t +S_msg_sig_post_untraced_reply (mach_port_t reply, error_t err) +{ + struct inf *inf = waiting_inf; + + if (err == EBUSY) + /* EBUSY is what we get when the crash server has grabbed control of the + process and doesn't like what signal we tried to send it. Just act + like the process stopped (using a signal of 0 should mean that the + *next* time the user continues, it will pass signal 0, which the crash + server should like). */ + { + inf->wait.status.kind = TARGET_WAITKIND_STOPPED; + inf->wait.status.value.sig = GDB_SIGNAL_0; + } + else if (err) + warning (_("Signal delivery failed: %s"), safe_strerror (err)); + + if (err) + /* We only get this reply when we've posted a signal to a process which we + thought was stopped, and which we expected to continue after the signal. + Given that the signal has failed for some reason, it's reasonable to + assume it's still stopped. */ + inf->stopped = 1; + else + inf->wait.suppress = 1; + return 0; +} + +error_t +S_msg_sig_post_reply (mach_port_t reply, error_t err) +{ + printf ("bug in S_msg_sig_post_reply!!\n"); + exit (-238); +} + +error_t +do_mach_notify_dead_name (mach_port_t notify, mach_port_t dead_port) +{ + struct inf *inf = waiting_inf; + + inf_debug (waiting_inf, "port = %d", dead_port); + + if (inf->task && inf->task->port == dead_port) + { + proc_debug (inf->task, "is dead"); + inf->task->port = MACH_PORT_NULL; + if (proc_wait_pid == inf->pid) + /* We have a wait outstanding on the process, which will return more + detailed information, so delay until we get that. */ + inf->wait.suppress = 1; + else + /* We never waited for the process (maybe it wasn't a child), so just + pretend it got a SIGKILL. */ + inf_task_died_status (inf); + } + else + { + struct proc *thread = inf_port_to_thread (inf, dead_port); + + if (thread) + { + proc_debug (thread, "is dead"); + thread->port = MACH_PORT_NULL; + } + + if (inf->task->dead) + /* Since the task is dead, its threads are dying with it. */ + inf->wait.suppress = 1; + } + + mach_port_deallocate (mach_task_self (), dead_port); + inf->threads_up_to_date = 0; /* Just in case. */ + + return 0; +} + +static error_t +ill_rpc (char *fun) +{ + warning (_("illegal rpc: %s"), fun); + return 0; +} + +error_t +do_mach_notify_no_senders (mach_port_t notify, mach_port_mscount_t count) +{ + return ill_rpc ("do_mach_notify_no_senders"); +} + +error_t +do_mach_notify_port_deleted (mach_port_t notify, mach_port_t name) +{ + return ill_rpc ("do_mach_notify_port_deleted"); +} + +error_t +do_mach_notify_msg_accepted (mach_port_t notify, mach_port_t name) +{ + return ill_rpc ("do_mach_notify_msg_accepted"); +} + +error_t +do_mach_notify_port_destroyed (mach_port_t notify, mach_port_t name) +{ + return ill_rpc ("do_mach_notify_port_destroyed"); +} + +error_t +do_mach_notify_send_once (mach_port_t notify) +{ + return ill_rpc ("do_mach_notify_send_once"); +} + +error_t +S_proc_setmsgport_reply (mach_port_t reply, error_t err, + mach_port_t old_msg_port) +{ + return ill_rpc ("S_proc_setmsgport_reply"); +} + +error_t +S_proc_getmsgport_reply (mach_port_t reply, error_t err, mach_port_t msg_port) +{ + return ill_rpc ("S_proc_getmsgport_reply"); +} + +static struct target_ops gnu_target_ops = { + gnu_create_inferior, + gnu_attach, + gnu_kill, + gnu_detach, + gnu_mourn, + gnu_join, + gnu_thread_alive, + gnu_resume, + gnu_wait, + gnu_fetch_registers, + gnu_store_registers, + NULL, /* prepare_to_access_memory */ + NULL, /* done_accessing_memory */ + gnu_read_memory, + gnu_write_memory, + NULL, /* look_up_symbols */ + gnu_request_interrupt, + NULL, /* read_auxv */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* read_offsets */ + NULL, /* get_tls_address */ + NULL, /* qxfer_spu */ + NULL, /* hostio_last_error */ + NULL, /* qxfer_osdata */ + NULL, /* qxfer_siginfo */ + NULL, /* supports_non_stop */ + NULL, /* async */ + NULL, /* start_non_stop */ + NULL, /* supports_multi_process */ + NULL, /* handle_monitor_command */ +}; + +void +_initialize_gnu_nat (void) +{ + proc_server = getproc (); +} + +static void +initialize_low_arch () +{ + init_registers_i386 (); + gnu_tdesc = tdesc_i386; +} + +void +initialize_low (void) +{ + set_target_ops (&gnu_target_ops); + initialize_low_arch (); + _initialize_gnu_nat (); +} diff --git a/gdb/gdbserver/gnu-low.h b/gdb/gdbserver/gnu-low.h new file mode 100644 index 0000000..fa211d2 --- /dev/null +++ b/gdb/gdbserver/gnu-low.h @@ -0,0 +1,270 @@ +/* Copyright (C) 2010-2013 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 3 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, see <http://www.gnu.org/licenses/>. */ + +#include "server.h" + +#include <mach.h> +#include <mach_error.h> +#include <mach/exception.h> +#include <mach/message.h> +#include <mach/notify.h> +#include <mach/vm_attributes.h> + +#include <hurd.h> +#include <hurd/interrupt.h> +#include <hurd/msg.h> +#include <hurd/msg_request.h> +#include <hurd/process.h> +/* All info needed to access an architecture/mode's registers. */ + +struct regs_info +{ + /* Regset support bitmap: 1 for registers that are transferred as a part + of a regset, 0 for ones that need to be handled individually. This + can be NULL if all registers are transferred with regsets or regsets + are not supported. */ + unsigned char *regset_bitmap; + + /* Info used when accessing registers with PTRACE_PEEKUSER / + PTRACE_POKEUSER. This can be NULL if all registers are + transferred with regsets .*/ + struct usrregs_info *usrregs; + +#ifdef HAVE_gnu_REGSETS + /* Info used when accessing registers with regsets. */ + struct regsets_info *regsets_info; +#endif +}; + +#define ptid_of(proc) ((proc)->head.id) +#define pid_of(proc) ptid_get_pid ((proc)->head.id) +#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id) + +#define get_lwp(inf) ((struct lwp_info *)(inf)) +#define get_thread_lwp(thr) (get_lwp (inferior_target_data (thr))) +#define get_lwp_thread(proc) ((struct thread_info *) \ + find_inferior_id (&all_threads, \ + get_lwp (proc)->head.id)) + +#define PROC_TID_TASK (-1) +#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE +#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT +#define THREAD_STATE_SET_TRACED(state) \ + ((struct i386_thread_state *) (state))->efl |= 0x100 +#define THREAD_STATE_CLEAR_TRACED(state) \ + ((((struct i386_thread_state *) (state))->efl &= ~0x100), 1) + +#define proc_is_task(proc) ((proc)->tid == PROC_TID_TASK) +#define proc_is_thread(proc) ((proc)->tid != PROC_TID_TASK) + +#ifndef PIDGET +#define PIDGET(PTID) (ptid_get_pid (PTID)) +#define TIDGET(PTID) (ptid_get_lwp (PTID)) +#define MERGEPID(PID, TID) ptid_build (PID, TID, 0) +#endif + +struct exc_state + { + int exception; /* The exception code. */ + int code, subcode; + mach_port_t handler; /* The real exception port to handle this. */ + mach_port_t reply; /* The reply port from the exception call. */ + }; + +/* The results of the last wait an inf did. */ +struct inf_wait + { + struct target_waitstatus status; /* The status returned to gdb. */ + struct exc_state exc; /* The exception that caused us to return. */ + struct proc *thread; /* The thread in question. */ + int suppress; /* Something trivial happened. */ + }; + +struct proc +{ + thread_t port; /* The task or thread port. */ + int tid; /* The GDB pid (actually a thread id). */ + int num; /* An id number for threads, to print. */ + + mach_port_t saved_exc_port; /* The task/thread's real exception port. */ + mach_port_t exc_port; /* Our replacement, which for. */ + + int sc; /* Desired suspend count. */ + int cur_sc; /* Implemented suspend count. */ + int run_sc; /* Default sc when the program is running. */ + int pause_sc; /* Default sc when gdb has control. */ + int resume_sc; /* Sc resulting from the last resume. */ + int detach_sc; /* SC to leave around when detaching + from program. */ + + thread_state_data_t state; /* Registers, &c. */ + int state_valid:1; /* True if STATE is up to date. */ + int state_changed:1; + + int aborted:1; /* True if thread_abort has been called. */ + int dead:1; /* We happen to know it's actually dead. */ + + /* Bit mask of registers fetched by gdb. This is used when we re-fetch + STATE after aborting the thread, to detect that gdb may have out-of-date + information. */ + unsigned long fetched_regs; + + struct inf *inf; /* Where we come from. */ + + struct proc *next; +}; + +struct inf +{ + /* Fields describing the current inferior. */ + + struct proc *task; /* The mach task. */ + struct proc *threads; /* A linked list of all threads in TASK. */ + + /* True if THREADS needn't be validated by querying the task. We + assume that we and the task in question are the only ones + frobbing the thread list, so as long as we don't let any code + run, we don't have to worry about THREADS changing. */ + int threads_up_to_date; + + pid_t pid; /* The real system PID. */ + + struct inf_wait wait; /* What to return from target_wait. */ + + /* One thread proc in INF may be in `single-stepping mode'. This + is it. */ + struct proc *step_thread; + + /* The thread we think is the signal thread. */ + struct proc *signal_thread; + + mach_port_t event_port; /* Where we receive various msgs. */ + + /* True if we think at least one thread in the inferior could currently be + running. */ + unsigned int running:1; + + /* True if the process has stopped (in the proc server sense). Note that + since a proc server `stop' leaves the signal thread running, the inf can + be RUNNING && STOPPED... */ + unsigned int stopped:1; + + /* True if the inferior has no message port. */ + unsigned int nomsg:1; + + /* True if the inferior is traced. */ + unsigned int traced:1; + + /* True if we shouldn't try waiting for the inferior, usually because we + can't for some reason. */ + unsigned int no_wait:1; + + /* When starting a new inferior, we don't try to validate threads until all + the proper execs have been done. This is a count of how many execs we + expect to happen. */ + unsigned pending_execs; + + /* Fields describing global state. */ + + /* The task suspend count used when gdb has control. This is normally 1 to + make things easier for us, but sometimes (like when attaching to vital + system servers) it may be desirable to let the task continue to run + (pausing individual threads as necessary). */ + int pause_sc; + + /* The task suspend count left when detaching from a task. */ + int detach_sc; + + /* The initial values used for the run_sc and pause_sc of newly discovered + threads -- see the definition of those fields in struct proc. */ + int default_thread_run_sc; + int default_thread_pause_sc; + int default_thread_detach_sc; + + /* True if the process should be traced when started/attached. Newly + started processes *must* be traced at first to exec them properly, but + if this is false, tracing is turned off as soon it has done so. */ + int want_signals; + + /* True if exceptions from the inferior process should be trapped. This + must be on to use breakpoints. */ + int want_exceptions; +}; + +/* Forward decls */ +struct inf *make_inf (); +void inf_clear_wait (struct inf *inf); +void inf_cleanup (struct inf *inf); +void inf_startup (struct inf *inf, int pid); +int inf_update_suspends (struct inf *inf); +void inf_set_pid (struct inf *inf, pid_t pid); +void inf_validate_procs (struct inf *inf); +void inf_steal_exc_ports (struct inf *inf); +void inf_restore_exc_ports (struct inf *inf); +struct proc *inf_tid_to_proc (struct inf *inf, int tid); +void inf_set_threads_resume_sc (struct inf *inf, + struct proc *run_thread, + int run_others); +int inf_set_threads_resume_sc_for_signal_thread (struct inf *inf); +void inf_suspend (struct inf *inf); +void inf_resume (struct inf *inf); +void inf_set_step_thread (struct inf *inf, struct proc *proc); +void inf_detach (struct inf *inf); +void inf_attach (struct inf *inf, int pid); +void inf_signal (struct inf *inf, enum gdb_signal sig); +void inf_continue (struct inf *inf); +int inf_update_procs (struct inf *inf); + +void proc_abort (struct proc *proc, int force); +struct proc *make_proc (struct inf *inf, mach_port_t port, int tid); +struct proc *_proc_free (struct proc *proc); +int proc_update_sc (struct proc *proc); +error_t proc_get_exception_port (struct proc *proc, mach_port_t * port); +error_t proc_set_exception_port (struct proc *proc, mach_port_t port); +static mach_port_t _proc_get_exc_port (struct proc *proc); +void proc_steal_exc_port (struct proc *proc, mach_port_t exc_port); +void proc_restore_exc_port (struct proc *proc); +int proc_trace (struct proc *proc, int set); +static void inf_validate_task_sc (struct inf *inf); +static void inf_validate_procinfo (struct inf *inf); + +//gdbserver use ptid_t not the same as gdb does! +static ptid_t gnu_ptid_build(int pid,long lwp,long tid); + +//add for erase warning +extern const char * host_address_to_string (const void *addr); + +extern int debug_flags; +#define inf_debug(_inf, msg, args...) \ + do { struct inf *__inf = (_inf); \ + debug ("{inf %d %s}: " msg, __inf->pid, \ + host_address_to_string (__inf) , ##args); } while (0) + +#define proc_debug(_proc, msg, args...) \ + do { struct proc *__proc = (_proc); \ + debug ("{proc %d/%d %s}: " msg, \ + __proc_pid (__proc), __proc->tid, \ + host_address_to_string (__proc) , ##args); } while (0) + +#define debug(msg, args...) \ + do { if (debug_flags) \ + printf ("%s:%d: " msg "\r\n", \ + __FILE__ , __LINE__ , ##args); } while (0) +#ifndef safe_strerror +#define safe_strerror(err) \ + "XXXX" +#endif diff --git a/gdb/gdbserver/hostio.c b/gdb/gdbserver/hostio.c index df94d31..f3af499 100644 --- a/gdb/gdbserver/hostio.c +++ b/gdb/gdbserver/hostio.c @@ -25,6 +25,10 @@ #include <limits.h> #include <unistd.h> +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + extern int remote_debug; struct fd_list diff --git a/gdb/gdbserver/i386gnu.mh b/gdb/gdbserver/i386gnu.mh new file mode 100644 index 0000000..3bdffe7 --- /dev/null +++ b/gdb/gdbserver/i386gnu.mh @@ -0,0 +1,30 @@ +# Host: Intel 386 running the GNU Hurd +NATDEPFILES= notify_S.o process_reply_S.o msg_reply_S.o \ + exc_request_U.o exc_request_S.o + +# Use our own user stubs for the msg rpcs, so we can make them time out, in +# case the program is fucked, or we guess the wrong signal thread. +msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;' + +# ick +MIGCOM = $(MIG) -cc cat - /dev/null + +# Reply servers need special massaging of the code mig generates, to make +# them work correctly for error returns in some cases. +%_reply_S.h %_reply_S.c: %_reply.defs + $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \ + | $(MIGCOM) -sheader $*_reply_S.h -server $*_reply_S.raw -user /dev/null -header /dev/null \ + && $(AWK) -f $(srcdir)/reply_mig_hack.awk < $*_reply_S.raw > $*_reply_S.c +# Normal servers +%_S.h %_S.c: %.defs + $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \ + | $(MIGCOM) -sheader $*_S.h -server $*_S.c -user /dev/null -header /dev/null +# User rpc stubs +%_U.h %_U.c: %.defs + $(CPP) $(CPPFLAGS) $($*-MIGUFLAGS) -x c $< \ + | $(MIGCOM) -sheader /dev/null -server /dev/null -user $*_U.c -header $*_U.h + +NAT_GENERATED_FILES = notify_S.h notify_S.c \ + process_reply_S.h process_reply_S.c \ + msg_reply_S.h msg_reply_S.c \ + exc_request_U.h exc_request_U.c exc_request_S.h exc_request_S.c diff --git a/gdb/gdbserver/msg.defs b/gdb/gdbserver/msg.defs new file mode 100644 index 0000000..7c9fcd1 --- /dev/null +++ b/gdb/gdbserver/msg.defs @@ -0,0 +1 @@ +#include <hurd/msg.defs> diff --git a/gdb/gdbserver/msg_reply.defs b/gdb/gdbserver/msg_reply.defs new file mode 100644 index 0000000..049bfa8 --- /dev/null +++ b/gdb/gdbserver/msg_reply.defs @@ -0,0 +1 @@ +#include <hurd/msg_reply.defs> diff --git a/gdb/gdbserver/notify.defs b/gdb/gdbserver/notify.defs new file mode 100644 index 0000000..2014be5 --- /dev/null +++ b/gdb/gdbserver/notify.defs @@ -0,0 +1 @@ +#include <mach/notify.defs> diff --git a/gdb/gdbserver/process_reply.defs b/gdb/gdbserver/process_reply.defs new file mode 100644 index 0000000..824b5c6 --- /dev/null +++ b/gdb/gdbserver/process_reply.defs @@ -0,0 +1 @@ +#include <hurd/process_reply.defs> diff --git a/gdb/gdbserver/reply_mig_hack.awk b/gdb/gdbserver/reply_mig_hack.awk new file mode 100644 index 0000000..97e080f --- /dev/null +++ b/gdb/gdbserver/reply_mig_hack.awk @@ -0,0 +1,122 @@ +# Reply server mig-output massager +# +# Copyright (C) 1995-2013 Free Software Foundation, Inc. +# +# Written by Miles Bader <miles@gnu.ai.mit.edu> +# +# 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 3, 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, see <http://www.gnu.org/licenses/>. +# +# This awk script hacks the output of mig-generated reply server code +# so that it allows replies with just the error-code in them (as this is +# how mig returns errors). +# +# It is highly, highly, dependent on the exact format of mig output. Ick. +# + +BEGIN { parse_phase = 0; } + +/^}/ { parse_phase = 0; } + +parse_phase == 0 && /^mig_internal void _X[a-zA-Z0-9_]*_reply/ { + # The start of a mig server routine. Reset everything. Note that we only + # mess with rpcs that have the suffix `_reply'. + num_args = 0; + num_checks = 0; + parse_phase = 1; + print; next; +} + +parse_phase == 1 && /^[\t ]*typedef struct/ { + # The first structure in the server routine should describe the arguments + parse_phase = 2; + print; next; +} + +parse_phase == 2 { + # The message header field in the args structure, which skip. + parse_phase = 3; + print; next; +} + +parse_phase == 3 && /}/ { + # The args structure is over. + if (num_args > 1) + parse_phase = 5; + else + # There's no extra args that could screw up the normal mechanism for + # error returns, so we don't have to insert any new code. + parse_phase = 0; + print; next; +} + +parse_phase == 3 { + # The type field for an argument. + arg_type_code_name[num_args] = $2; + sub (/;$/, "", arg_type_code_name[num_args]) # Get rid of the semi-colon + parse_phase = 4; + print; next; +} + +parse_phase == 4 { + # The value field for an argument. + arg_name[num_args] = $2; + sub (/;$/, "", arg_name[num_args]) # Get rid of the semi-colon + arg_type[num_args] = $1; + num_args++; + parse_phase = 3; + print; next; +} + +parse_phase == 5 && /^[ \t]*(auto|static) const mach_msg_type_t/ { + # The type check structure for an argument. + arg_check_name[num_checks] = $4; + num_checks++; + print; next; +} + +parse_phase == 5 && /^[ \t]*mig_external kern_return_t/ { + # The declaration of the user server function for this rpc. + user_function_name = $3; + print; next; +} + +parse_phase == 5 && /^#if[ \t]TypeCheck/ { + # The first args type checking statement; we need to insert our chunk of + # code that bypasses all the type checks if this is an error return, after + # which we're done until we get to the next function. Handily, the size + # of mig's Reply structure is also the size of the alternate Request + # structure that we want to check for. + print "\tif (In0P->Head.msgh_size == sizeof (Reply)"; + print "\t && ! (In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)"; + print "\t && ! BAD_TYPECHECK(&In0P->" arg_type_code_name[0] ", &" arg_check_name[0] ")"; + print "\t && In0P->" arg_name[0] " != 0)"; + print "\t /* Error return, only the error code argument is passed. */"; + print "\t {"; + # Force the function into a type that only takes the first two args, via + # the temp variable SFUN (is there another way to correctly do this cast?). + # This is possibly bogus, but easier than supplying bogus values for all + # the other args (we can't just pass 0 for them, as they might not be scalar). + printf ("\t kern_return_t (*sfun)(mach_port_t"); + for (i = 0; i < num_args; i++) + printf (", %s", arg_type[i]); + printf (") = %s;\n", user_function_name); + print "\t OutP->RetCode = (*(kern_return_t (*)(mach_port_t, kern_return_t))sfun) (In0P->Head.msgh_request_port, In0P->" arg_name[0] ");"; + print "\t return;"; + print "\t }"; + print ""; + parse_phase = 0; + print; next; +} + +{ print; } diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 18d060c..20e88bf 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -91,7 +91,8 @@ typedef unsigned char gdb_byte; /* FIXME: This should probably be autoconf'd for. It's an integer type at least the size of a (void *). */ -typedef long long CORE_ADDR; +//typedef long long CORE_ADDR; +typedef long CORE_ADDR; typedef long long LONGEST; typedef unsigned long long ULONGEST; diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c index 9706d74..d6dd4f9 100644 --- a/gdb/gdbserver/utils.c +++ b/gdb/gdbserver/utils.c @@ -170,7 +170,6 @@ internal_error (const char *file, int line, const char *fmt, ...) #define CELLSIZE 50 /* Return the next entry in the circular buffer. */ - static char * get_cell (void) { @@ -181,6 +180,15 @@ get_cell (void) return buf[cell]; } +const char * +host_address_to_string (const void *addr) +{ + char *str = get_cell (); + + xsnprintf (str, CELLSIZE, "0x%s", phex_nz ((unsigned long long) addr, sizeof (addr))); + return str; +} + static char * decimal2str (char *sign, ULONGEST addr) { -- Yue Lu (陆岳) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-03 8:03 ` [PATCH 2/2] Port gdbserver to GNU/Hurd Yue Lu @ 2013-09-03 9:38 ` Thomas Schwinge 2013-09-03 11:11 ` Pedro Alves 0 siblings, 1 reply; 25+ messages in thread From: Thomas Schwinge @ 2013-09-03 9:38 UTC (permalink / raw) To: gdb-patches; +Cc: Luis Machado, bug-hurd, Yue Lu [-- Attachment #1: Type: text/plain, Size: 2310 bytes --] Hi! For context, Yue Lu is a student participating in this year's Google Summer of Code program, to port gdbserver to GNU Hurd, and is both a GDB as well as a GNU Hurd newbie. (So, be gentle.) ;-) On Tue, 3 Sep 2013 16:00:32 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote: > This is my patch to port gdbserver to GNU/Hurd. Most of code are > copied from [gdb]/gdb/gnu-nat.c. ... and elsewhere. Our strategy was to first get this into a basic functional state: > Now the gdbserver on GNU/Hurd can set breakpoint and check memory or > register(but without float-register support). So, this initial port just posted is a great milestone! Especially so given your previous lack of experience with both GDB and the Hurd -- both of which are not always easy to grasp. There are lots of things to be polished (Yue, don't worry -- this entirely was to be expected), such as GDB coding standard, and changes that are unrelated to your port, which all has to be cleared out before I can commit this initial port to GDB upstream. There is missing functionality, but we decided this can be enhanced piece by piece once the initial port is accepted. There is the issue of code sharing between GDB proper and gdbserver, a strategy for which has been briefly discussed in <http://news.gmane.org/find-root.php?message_id=%3CCAB8fV%3Djzv_rPHP3-HQVBA-pCNZNat6PNbh%2BOJEU7tZgQdKX3%2Bw%40mail.gmail.com%3E>. Likewise for code sharing between the new Hurd gdbserver port and the existing x86 Linux kernel port. Again I suggest this to be done *after* the initial port is accepted: this will turn into a nice (and easily reviewable) series of cleanup patches à la: remove from GDB proper gdb/gnu-nat.c:[function] and from gdbserver gdb/gdbserver/gnu-low.c:[function], and add gdb/common/gnu-low.c:[function], and so on. Likewise for build infrastructure that can be shared. Does this strategy generally make sense to you GDB maintainers? For the curious, in <http://news.gmane.org/find-root.php?message_id=%3C87ppwqlgot.fsf%40kepler.schwinge.homeip.net%3E> I describe the MIG usage in GDB. (This message also states that ptrace is a system call which it is not; it's a glibc library function using RPC calls to implement its functionality.) Grüße, Thomas [-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-03 9:38 ` [PATCH 1/2] " Thomas Schwinge @ 2013-09-03 11:11 ` Pedro Alves 2013-09-03 13:09 ` Thomas Schwinge ` (2 more replies) 0 siblings, 3 replies; 25+ messages in thread From: Pedro Alves @ 2013-09-03 11:11 UTC (permalink / raw) To: Thomas Schwinge; +Cc: gdb-patches, Luis Machado, bug-hurd, Yue Lu On 09/03/2013 10:38 AM, Thomas Schwinge wrote: > Hi! > > For context, Yue Lu is a student participating in this year's Google > Summer of Code program, to port gdbserver to GNU Hurd, and is both a GDB > as well as a GNU Hurd newbie. (So, be gentle.) ;-) > > On Tue, 3 Sep 2013 16:00:32 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote: >> This is my patch to port gdbserver to GNU/Hurd. Most of code are >> copied from [gdb]/gdb/gnu-nat.c. > > ... and elsewhere. Our strategy was to first get this into a basic > functional state: > >> Now the gdbserver on GNU/Hurd can set breakpoint and check memory or >> register(but without float-register support). > > So, this initial port just posted is a great milestone! Especially so > given your previous lack of experience with both GDB and the Hurd -- both > of which are not always easy to grasp. Indeed! > > There are lots of things to be polished (Yue, don't worry -- this > entirely was to be expected), such as GDB coding standard, and changes > that are unrelated to your port, which all has to be cleared out before I > can commit this initial port to GDB upstream. > > There is missing functionality, but we decided this can be enhanced piece > by piece once the initial port is accepted. > > There is the issue of code sharing between GDB proper and gdbserver, a > strategy for which has been briefly discussed in > <http://news.gmane.org/find-root.php?message_id=%3CCAB8fV%3Djzv_rPHP3-HQVBA-pCNZNat6PNbh%2BOJEU7tZgQdKX3%2Bw%40mail.gmail.com%3E>. That has been further discussed recently: https://sourceware.org/ml/gdb-patches/2013-07/msg00788.html and we ended up with putting native target files under the new gdb/nat/ directory, rather than in gdb/common/: https://sourceware.org/ml/gdb-patches/2013-08/msg00618.html > Likewise for code sharing between the new Hurd gdbserver port and the > existing x86 Linux kernel port. Again I suggest this to be done *after* > the initial port is accepted: this will turn into a nice (and easily > reviewable) series of cleanup patches à la: remove from GDB proper > gdb/gnu-nat.c:[function] and from gdbserver > gdb/gdbserver/gnu-low.c:[function], and add > gdb/common/gnu-low.c:[function], and so on. Likewise for build > infrastructure that can be shared. > > Does this strategy generally make sense to you GDB maintainers? I've been thinking about this this morning, after seeing these patches. For new gdbserver ports, this path just seems to swim further away from a full sharing approach, by adding lots duplication as first step, and actually making it hard to see what exactly needed to be changed/adapted for gdbserver use, and puts the tree in a state where any further changes for the GNU/Hurd target will need to be considered twice going further, exactly what we're fighting against with the existing ports. I think that strategy ultimately is slower to get at where we want to, and is actually more work than an alternative that does things the other way around. I checked out Yue's git branch, and diffed gdb/gnu-nat.c vs gdbserver/gnu-low.c, and gdb/i386gnu-nat.c vs gdbserver/gnu-i386-low.c. I didn't diff the rest of the files, as I assume they'll probably have even less divergence. There are several spurious formatting differences, and some reordering of functions, but for the most port, the code is mostly identical. There's some expected necessary adjustment to GDBserver's interfaces, but it turns out it's not that much. We've been converging gdb's and gdbserver's interfaces throughout the years, and it now shows. So my idea would be, instead of adding the new files under gdbserver, to remove the spurious differences (formatting, reordering, etc.) that were introduced in the gdbserver copies of the files, eliminating the unnecessary divergence, and then fold back the resulting differences into the original gdb/gnu-nat.c etc. files, guarded by #ifdef GDBSERVER. Some cleanups might have been identified and done in the gdbserver files, and it might make sense to do those as preparatory work, in the original files. This should result in smaller patches, and will actually avoid the need for most of the polishing Thomas mentioned, and as consequence review burden -- reviewing the new gnu-low.c etc., for GNU conventions, formatting, or even appropriate use of the Hurd's debug APIs etc., is just unnecessary that way, by design, and we'll be able to focus on the bits that are the real new code -- the glue between the target and gdb, and the target and gdbserver. The current state of the work isn't wasted at all! And I don't think following this direction is that much work. I'd do this my literally moving gdbserver/gnu-low.c on top of gdb/gnu-nat.c (etc.), and use git diff to guide me through, in identifying what would need to be restored, and guarded with #if[n]def GDBSERVER. #ifdef GDBSERVER is how we've adapting shared code under gdb/common/ and gdb/nat/ to work on both programs. Medium/long term, core gdb and core gdbserver target interface differences should converge further, and the #ifdefs disappear, but for now that's a necessary evil. It's fine to leave bits of functionality disabled on gdbserver, wrapped in #ifndef GDBSERVER. After that initial work is committed, we can then easily progress the gdbserver port by just looking for those #ifdefs. It's fine with me to leave the existing native files under gdb/ while doing this; it's probably easier that way. Moving them under gdb/nat/ can be left for a cleanup step further down the road. Could we try that approach? -- Pedro Alves ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-03 11:11 ` Pedro Alves @ 2013-09-03 13:09 ` Thomas Schwinge 2013-09-04 1:47 ` Yue Lu 2013-09-04 1:38 ` Yue Lu 2013-09-05 10:54 ` Yue Lu 2 siblings, 1 reply; 25+ messages in thread From: Thomas Schwinge @ 2013-09-03 13:09 UTC (permalink / raw) To: Pedro Alves, Yue Lu; +Cc: gdb-patches, Luis Machado, bug-hurd [-- Attachment #1: Type: text/plain, Size: 1096 bytes --] Hi! On Tue, 03 Sep 2013 12:11:02 +0100, Pedro Alves <palves@redhat.com> wrote: > On 09/03/2013 10:38 AM, Thomas Schwinge wrote: > > [strategy] > > I've been thinking about this this morning, after seeing these > patches. > > For new gdbserver ports, this path just seems to swim further away from > a full sharing approach, by adding lots duplication as first step, [...] > So my idea would be, [...] Understood, and yes, your argumentation is reasonable. > I'd do this [by] > literally moving gdbserver/gnu-low.c on top of gdb/gnu-nat.c (etc.), and > use git diff to guide me through, in identifying what would need to > be restored, and guarded with #if[n]def GDBSERVER. [...] Yes, that's a nice technique for displaying and integrating the differences between the existing Hurd native port's files and the new gdbserver port's. Yue, does the approach of diffing the files as Pedro described make sense to you? Please tell if you need help with how to use Git to do that, etc. > Could we try that approach? Thanks for the input! Grüße, Thomas [-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-03 13:09 ` Thomas Schwinge @ 2013-09-04 1:47 ` Yue Lu 0 siblings, 0 replies; 25+ messages in thread From: Yue Lu @ 2013-09-04 1:47 UTC (permalink / raw) To: Thomas Schwinge; +Cc: Pedro Alves, gdb-patches, Luis Machado, bug-hurd Hi, On Tue, Sep 3, 2013 at 9:09 PM, Thomas Schwinge <thomas@codesourcery.com> wrote: > Hi! > > On Tue, 03 Sep 2013 12:11:02 +0100, Pedro Alves <palves@redhat.com> wrote: >> On 09/03/2013 10:38 AM, Thomas Schwinge wrote: >> > [strategy] >> >> I've been thinking about this this morning, after seeing these >> patches. >> >> For new gdbserver ports, this path just seems to swim further away from >> a full sharing approach, by adding lots duplication as first step, [...] > >> So my idea would be, [...] > > Understood, and yes, your argumentation is reasonable. > >> I'd do this [by] >> literally moving gdbserver/gnu-low.c on top of gdb/gnu-nat.c (etc.), and >> use git diff to guide me through, in identifying what would need to >> be restored, and guarded with #if[n]def GDBSERVER. [...] > > Yes, that's a nice technique for displaying and integrating the > differences between the existing Hurd native port's files and the new > gdbserver port's. Yue, does the approach of diffing the files as Pedro > described make sense to you? Please tell if you need help with how to > use Git to do that, etc. Yeah, I will do that. But in my understand, I will use diff gnu-low.c ../gnu-nat.c and something like this. But I don't know how to use git do this. Like git diff a.c b.c? BTW, I got these patches by git diff <early_commit> > gdb.patch. Then I edit the patch to two file. When I use git format-patch <early_commit> I will get a patche for each commit after the early_commit. What is the better way you generate patches? -- Yue Lu (陆岳) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-03 11:11 ` Pedro Alves 2013-09-03 13:09 ` Thomas Schwinge @ 2013-09-04 1:38 ` Yue Lu 2013-09-05 10:54 ` Yue Lu 2 siblings, 0 replies; 25+ messages in thread From: Yue Lu @ 2013-09-04 1:38 UTC (permalink / raw) To: Pedro Alves; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd Thanks for your review! On Tue, Sep 3, 2013 at 7:11 PM, Pedro Alves <palves@redhat.com> wrote: > > For new gdbserver ports, this path just seems to swim further away from > a full sharing approach, by adding lots duplication as first step, and > actually making it hard to see what exactly needed to be changed/adapted > for gdbserver use, and puts the tree in a state where any further changes > for the GNU/Hurd target will need to be considered twice going further, > exactly what we're fighting against with the existing ports. I think > that strategy ultimately is slower to get at where we want to, and > is actually more work than an alternative that does things the other > way around. > > I checked out Yue's git branch, and diffed gdb/gnu-nat.c vs > gdbserver/gnu-low.c, and gdb/i386gnu-nat.c vs gdbserver/gnu-i386-low.c. > I didn't diff the rest of the files, as I assume they'll probably have > even less divergence. There are several spurious formatting differences, > and some reordering of functions, but for the most port, the code is The reason is, at first, I plan to write the new file, and then I found one function can be re-use, so I copy it, it call another one, so I copy the another one. One by one, so there are some reordering of functions. The formatting differences comes with "indent program", I found this from GNU_CODIND_STYLE (http://www.gnu.org/prep/standards/standards.html ). > mostly identical. There's some expected necessary adjustment to GDBserver's > interfaces, but it turns out it's not that much. We've been converging > gdb's and gdbserver's interfaces throughout the years, and it now shows. I have found some interfaces which must be adjustment. Like use the lwp as tid in structure ptid_t. > So my idea would be, instead of adding the new files under gdbserver, > to remove the spurious differences (formatting, reordering, etc.) that > were introduced in the gdbserver copies of the files, eliminating the > unnecessary divergence, and then fold back the resulting differences into > the original gdb/gnu-nat.c etc. files, guarded by #ifdef GDBSERVER. Some > cleanups might have been identified and done in the gdbserver files, and > it might make sense to do those as preparatory work, in the original files. > This should result in smaller patches, and will actually avoid > the need for most of the polishing Thomas mentioned, and as consequence > review burden -- reviewing the new gnu-low.c etc., for GNU conventions, > formatting, or even appropriate use of the Hurd's debug APIs etc., is > just unnecessary that way, by design, and we'll be able to focus on the > bits that are the real new code -- the glue between the target and gdb, and > the target and gdbserver. > > The current state of the work isn't wasted at all! And I don't > think following this direction is that much work. I'd do this my > literally moving gdbserver/gnu-low.c on top of gdb/gnu-nat.c (etc.), and > use git diff to guide me through, in identifying what would need to > be restored, and guarded with #if[n]def GDBSERVER. #ifdef GDBSERVER > is how we've adapting shared code under gdb/common/ and gdb/nat/ > to work on both programs. Medium/long term, core gdb and core > gdbserver target interface differences should converge further, and > the #ifdefs disappear, but for now that's a necessary evil. > > It's fine to leave bits of functionality disabled on gdbserver, > wrapped in #ifndef GDBSERVER. After that initial work is committed, > we can then easily progress the gdbserver port by just looking for > those #ifdefs. > > It's fine with me to leave the existing native files under gdb/ while > doing this; it's probably easier that way. Moving them under gdb/nat/ > can be left for a cleanup step further down the road. > > Could we try that approach? Ok, I will try to move the gdbserver/gnu-low.c back into gdb/gnu-nat.c. > -- > Pedro Alves > -- Yue Lu (陆岳) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-03 11:11 ` Pedro Alves 2013-09-03 13:09 ` Thomas Schwinge 2013-09-04 1:38 ` Yue Lu @ 2013-09-05 10:54 ` Yue Lu 2013-09-05 19:29 ` Pedro Alves 2 siblings, 1 reply; 25+ messages in thread From: Yue Lu @ 2013-09-05 10:54 UTC (permalink / raw) To: Pedro Alves; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd Hi, This is the my new patch. On Tue, Sep 3, 2013 at 7:11 PM, Pedro Alves <palves@redhat.com> wrote: > So my idea would be, instead of adding the new files under gdbserver, > to remove the spurious differences (formatting, reordering, etc.) that > were introduced in the gdbserver copies of the files, eliminating the > unnecessary divergence, and then fold back the resulting differences into > the original gdb/gnu-nat.c etc. files, guarded by #ifdef GDBSERVER. Some > cleanups might have been identified and done in the gdbserver files, and > it might make sense to do those as preparatory work, in the original files. > This should result in smaller patches, and will actually avoid > the need for most of the polishing Thomas mentioned, and as consequence > review burden -- reviewing the new gnu-low.c etc., for GNU conventions, > formatting, or even appropriate use of the Hurd's debug APIs etc., is > just unnecessary that way, by design, and we'll be able to focus on the > bits that are the real new code -- the glue between the target and gdb, and > the target and gdbserver. I have put some soft link in directory gdbserver like *.defs which point to [gdb]/gdb/*.defs. 2013-09-03 Yue Lu <hacklu.newborn@gmail.com> gdb * configure.tgt: Set build_gdbserver=yes for GNU/Hurd hosts. * configure: Regenerate. * config/i386/i386gnu.mh: Add #ifdef to determine which rule to use in gdbserver. * i386gnu-nat.c: Add macor GDBSERVER to support build gdbserver. * gnu-nat.h: Add macor GDBSERVER to support build gdbserver. * gnu-nat.c: Add macor GDBSERVER to support build gdbserver. (gnu_debug): New function, use for debug printf. (gnu_wait_1): wait for inferior used in gdbserver. (gnu_resume_1): resume inferior used in gdbserver. (gnu_kill): New function, used in gdbserver. (gnu_mourn): New function, clean up after inferior dies, used in gdbserver. (gnu_create_inferior): New function, use for create inferior in gdbserver. (gnu_attach): New function, a placeholder. (gnu_detach): New function, used in gdbserver detach from inferior. (gnu_thread_alive): New function, call find_thread_ptid(). (gnu_ptid_build): New function, build structure ptid_t from pid, and tid. (gnu_get_tid): New function, return lwp from structure ptid_t, this is different with gdb's behavior. (gnu_add_process): New function, add a new process to process list. (gnu_join): New function, a placeholder. (gnu_resume): New function, a wrap function, just call gnu_resume_1(). (gnu_wait): New function, a wrap function, just call gnu_wait_1(). (gnu_fetch_registers_wrap): New function, a wrap function, just call gnu_fetch_registers(). (gnu_store_registers_wrap): New function, a wrap function, just call gnu_store_registers(). (gnu_read_memory): New function, a wrap function, just call gnu_read_inferior(). (gnu_write_memory): New function, a wrap function, just call gnu_write_inferior(). (gnu_request_interrupt): New function, a placeholder. (store_waitstatus): New function, helper function, copy from [gdb]/gdb/inf-child.c. (initialize_low): New function, use for initialize gdbserver's target_ops. (initialize_low_arch): New function, used by initialize_low(). (_initialize_gnu_nat): New function, used by initialize_low(). diff --git a/gdb/config/i386/i386gnu.mh b/gdb/config/i386/i386gnu.mh index a3ea122..224cf0f 100644 --- a/gdb/config/i386/i386gnu.mh +++ b/gdb/config/i386/i386gnu.mh @@ -1,4 +1,5 @@ # Host: Intel 386 running the GNU Hurd +ifndef GDBSERVER NATDEPFILES= i386gnu-nat.o gnu-nat.o core-regset.o fork-child.o \ notify_S.o process_reply_S.o msg_reply_S.o \ msg_U.o exc_request_U.o exc_request_S.o @@ -12,6 +13,10 @@ XM_CLIBS = -lshouldbeinlibc # Use our own user stubs for the msg rpcs, so we can make them time out, in # case the program is fucked, or we guess the wrong signal thread. msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;' +else +NATDEPFILES= notify_S.o process_reply_S.o msg_reply_S.o \ + exc_request_U.o exc_request_S.o +endif # ick MIGCOM = $(MIG) -cc cat - /dev/null diff --git a/gdb/configure.tgt b/gdb/configure.tgt index b0bee47..3eb2ff7 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -231,6 +231,7 @@ i[34567]86-*-linux*) i[34567]86-*-gnu*) # Target: Intel 386 running the GNU Hurd gdb_target_obs="i386-tdep.o i387-tdep.o i386gnu-tdep.o solib-svr4.o" + build_gdbserver=yes ;; i[34567]86-*-cygwin*) # Target: Intel 386 running win32 diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c index 59d2f23..1cdcd1d 100644 --- a/gdb/gnu-nat.c +++ b/gdb/gnu-nat.c @@ -1,6 +1,7 @@ /* Interface GDB to the GNU Hurd. Copyright (C) 1992-2013 Free Software Foundation, Inc. + This file is part of GDB. Written by Miles Bader <miles@gnu.ai.mit.edu> @@ -20,6 +21,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifndef GDBSERVER #include "defs.h" #include <ctype.h> @@ -31,18 +33,6 @@ #include "gdb_string.h" #include <sys/ptrace.h> -#include <mach.h> -#include <mach_error.h> -#include <mach/exception.h> -#include <mach/message.h> -#include <mach/notify.h> -#include <mach/vm_attributes.h> - -#include <hurd.h> -#include <hurd/interrupt.h> -#include <hurd/msg.h> -#include <hurd/msg_request.h> -#include <hurd/process.h> /* Defined in <hurd/process.h>, but we need forward declarations from <hurd/process_request.h> as well. */ #undef _process_user_ @@ -64,17 +54,55 @@ #include "gdb_assert.h" #include "gdb_obstack.h" -#include "gnu-nat.h" #include "inf-child.h" +#include "exc_request_U.h" +#include "msg_U.h" + +#else /* GDBSERVER */ +#include "server.h" +#include "target.h" + +#include <limits.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include "gdb_wait.h" +#include <signal.h> +#include <sys/ptrace.h> +#endif /* GDBSERVER */ + +#include <mach.h> +#include <mach_error.h> +#include <mach/exception.h> +#include <mach/message.h> + +#include <mach/notify.h> +#include <mach/vm_attributes.h> + +#include <hurd.h> +#include <hurd/interrupt.h> +#include <hurd/msg.h> +#include <hurd/msg_request.h> +#include <hurd/process.h> + +#include "gnu-nat.h" #include "exc_request_S.h" #include "notify_S.h" #include "process_reply_S.h" #include "msg_reply_S.h" -#include "exc_request_U.h" -#include "msg_U.h" static process_t proc_server = MACH_PORT_NULL; +#ifdef GDBSERVER +/* this should move into gnu-i386-low.c ?*/ +/* Defined in auto-generated file i386.c. */ +extern void init_registers_i386 (void); +extern const struct target_desc *tdesc_i386; +const struct target_desc *gnu_tdesc; +int using_threads = 1; +ptid_t inferior_ptid; +static struct target_ops gnu_target_ops; +#endif /* If we've sent a proc_wait_request to the proc server, the pid of the process we asked about. We can only ever have one outstanding. */ @@ -114,6 +142,12 @@ void inf_continue (struct inf *inf); debug ("{inf %d %s}: " msg, __inf->pid, \ host_address_to_string (__inf) , ##args); } while (0) +#ifdef GDBSERVER +static ptid_t gnu_ptid_build (int pid, long lwp, long tid); +static long gnu_get_tid (ptid_t ptid); +static struct process_info * gnu_add_process (int pid, int attached); +#endif + void proc_abort (struct proc *proc, int force); struct proc *make_proc (struct inf *inf, mach_port_t port, int tid); struct proc *_proc_free (struct proc *proc); @@ -145,7 +179,27 @@ int proc_trace (struct proc *proc, int set); __e; }) \ : EIEIO) - +#ifdef GDBSERVER +struct process_info_private +{ + struct inf *inf; +}; + +void +gnu_debug (char *string, ...) +{ + va_list args; + + if (!gnu_debug_flag) + return; + va_start (args, string); + fprintf (stderr, "DEBUG(gnu): "); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); + va_end (args); +} +#endif + /* The state passed by an exception message. */ struct exc_state { @@ -242,14 +296,12 @@ struct inf int want_exceptions; }; - int __proc_pid (struct proc *proc) { return proc->inf->pid; } - /* Update PROC's real suspend count to match it's desired one. Returns true if we think PROC is now in a runnable state. */ int @@ -313,7 +365,6 @@ proc_update_sc (struct proc *proc) return running; } - /* Thread_abort is called on PROC if needed. PROC must be a thread proc. If PROC is deemed `precious', then nothing is done unless FORCE is true. In particular, a thread is precious if it's running (in which case forcing @@ -390,7 +441,6 @@ proc_get_state (struct proc *proc, int will_modify) return 0; } - /* Set PORT to PROC's exception port. */ error_t proc_get_exception_port (struct proc * proc, mach_port_t * port) @@ -506,7 +556,6 @@ proc_restore_exc_port (struct proc *proc) } } - /* Turns hardware tracing in PROC on or off when SET is true or false, respectively. Returns true on success. */ int @@ -533,7 +582,6 @@ proc_trace (struct proc *proc, int set) return 1; } - /* A variable from which to assign new TIDs. */ static int next_thread_id = 1; @@ -610,7 +658,6 @@ _proc_free (struct proc *proc) struct proc *next = proc->next; proc_debug (proc, "freeing..."); - if (proc == inf->step_thread) /* Turn off single stepping. */ inf_set_step_thread (inf, 0); @@ -637,7 +684,6 @@ _proc_free (struct proc *proc) return next; } - struct inf * make_inf (void) { @@ -691,7 +737,6 @@ inf_clear_wait (struct inf *inf) } } - void inf_cleanup (struct inf *inf) { @@ -736,7 +781,6 @@ inf_startup (struct inf *inf, int pid) inf_set_pid (inf, pid); } - /* Close current process, if any, and attach INF to process PORT. */ void inf_set_pid (struct inf *inf, pid_t pid) @@ -786,7 +830,6 @@ inf_set_pid (struct inf *inf, pid_t pid) inf->pid = -1; } - /* Validates INF's stopped, nomsg and traced field from the actual proc server state. Note that the traced field is only updated from the proc server state if we do not have a message port. If we do @@ -855,6 +898,7 @@ inf_validate_task_sc (struct inf *inf) if (inf->task->cur_sc < suspend_count) { +#ifndef GDBSERVER int abort; target_terminal_ours (); /* Allow I/O. */ @@ -865,7 +909,9 @@ inf_validate_task_sc (struct inf *inf) if (abort) error (_("Additional task suspend count left untouched.")); +#endif + //need fix! inf->task->cur_sc = suspend_count; } } @@ -905,7 +951,6 @@ inf_set_traced (struct inf *inf, int on) inf->traced = on; } - /* Makes all the real suspend count deltas of all the procs in INF match the desired values. Careful to always do thread/task suspend counts in the safe order. Returns true if at least one thread is @@ -959,7 +1004,6 @@ inf_update_suspends (struct inf *inf) return 0; } - /* Converts a GDB pid to a struct proc. */ struct proc * inf_tid_to_thread (struct inf *inf, int tid) @@ -988,7 +1032,6 @@ inf_port_to_thread (struct inf *inf, mach_port_t port) return 0; } - /* Make INF's list of threads be consistent with reality of TASK. */ void inf_validate_procs (struct inf *inf) @@ -1056,6 +1099,12 @@ inf_validate_procs (struct inf *inf) if (!left) { proc_debug (thread, "died!"); +#ifdef GDBSERVER + ptid_t ptid; + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); + if (find_thread_ptid (ptid)) + remove_thread (find_thread_ptid (ptid)); +#endif thread->port = MACH_PORT_NULL; thread = _proc_free (thread); /* THREAD is dead. */ if (last) @@ -1083,10 +1132,15 @@ inf_validate_procs (struct inf *inf) last = thread; proc_debug (thread, "new thread: %d", threads[i]); +#ifndef GDBSERVER ptid = ptid_build (inf->pid, 0, thread->tid); +#else + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); +#endif /* Tell GDB's generic thread code. */ +#ifndef GDBSERVER if (ptid_equal (inferior_ptid, pid_to_ptid (inf->pid))) /* This is the first time we're hearing about thread ids, after a fork-child. */ @@ -1096,6 +1150,15 @@ inf_validate_procs (struct inf *inf) add_thread_silent (ptid); else add_thread (ptid); +#else + if (!find_thread_ptid (ptid)) + { + gnu_debug ("New thread, pid=%d, tid=%d\n", inf->pid, + thread->tid); + add_thread (ptid, thread); + inferior_ptid = ptid; // need fix!!!!!!!!!!!!! + } +#endif } } @@ -1104,7 +1167,6 @@ inf_validate_procs (struct inf *inf) } } - /* Makes sure that INF's thread list is synced with the actual process. */ int inf_update_procs (struct inf *inf) @@ -1135,7 +1197,6 @@ inf_set_threads_resume_sc (struct inf *inf, thread->resume_sc = thread->pause_sc; } - /* Cause INF to continue execution immediately; individual threads may still be suspended (but their suspend counts will be updated). */ void @@ -1179,7 +1240,6 @@ inf_suspend (struct inf *inf) inf_update_suspends (inf); } - /* INF has one thread PROC that is in single-stepping mode. This function changes it to be PROC, changing any old step_thread to be a normal one. A PROC of 0 clears any existing value. */ @@ -1205,7 +1265,6 @@ inf_set_step_thread (struct inf *inf, struct proc *thread) } } - /* Set up the thread resume_sc's so that only the signal thread is running (plus whatever other thread are set to always run). Returns true if we did so, or false if we can't find a signal thread. */ @@ -1221,6 +1280,7 @@ inf_set_threads_resume_sc_for_signal_thread (struct inf *inf) return 0; } +#ifndef GDBSERVER static void inf_update_signal_thread (struct inf *inf) { @@ -1229,7 +1289,7 @@ inf_update_signal_thread (struct inf *inf) inf->signal_thread = inf->threads ? inf->threads->next : 0; } - +#endif /* Detachs from INF's inferior task, letting it run once again... */ void inf_detach (struct inf *inf) @@ -1284,7 +1344,7 @@ inf_attach (struct inf *inf, int pid) inf_startup (inf, pid); } - +#ifndef GDBSERVER /* Makes sure that we've got our exception ports entrenched in the process. */ void inf_steal_exc_ports (struct inf *inf) @@ -1314,8 +1374,8 @@ inf_restore_exc_ports (struct inf *inf) for (thread = inf->threads; thread; thread = thread->next) proc_restore_exc_port (thread); } +#endif - /* Deliver signal SIG to INF. If INF is stopped, delivering a signal, even signal 0, will continue it. INF is assumed to be in a paused state, and the resume_sc's of INF's threads may be affected. */ @@ -1404,7 +1464,6 @@ inf_signal (struct inf *inf, enum gdb_signal sig) #undef NAME } - /* Continue INF without delivering a signal. This is meant to be used when INF does not have a message port. */ void @@ -1433,7 +1492,6 @@ inf_continue (struct inf *inf) warning (_("Can't continue process: %s"), safe_strerror (err)); } - /* The inferior used for all gdb target ops. */ struct inf *gnu_current_inf = 0; @@ -1443,8 +1501,13 @@ struct inf *waiting_inf; /* Wait for something to happen in the inferior, returning what in STATUS. */ static ptid_t +#ifdef GDBSERVER +gnu_wait_1 (ptid_t ptid, struct target_waitstatus *status, + int target_options) +#else gnu_wait (struct target_ops *ops, ptid_t ptid, struct target_waitstatus *status, int options) +#endif { struct msg { @@ -1613,19 +1676,29 @@ rewait: thread = inf->wait.thread; if (thread) +#ifndef GDBSERVER ptid = ptid_build (inf->pid, 0, thread->tid); +#else + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); +#endif else if (ptid_equal (ptid, minus_one_ptid)) thread = inf_tid_to_thread (inf, -1); else +#ifndef GDBSERVER thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); +#else + thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); +#endif if (!thread || thread->port == MACH_PORT_NULL) { /* TID is dead; try and find a new thread. */ if (inf_update_procs (inf) && inf->threads) - ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first - available - thread. */ +#ifndef GDBSERVER + ptid = ptid_build (inf->pid, 0, inf->threads->tid); +#else + ptid = gnu_ptid_build (inf->pid, 0, inf->threads->tid); +#endif /* The first available thread*/ else ptid = inferior_ptid; /* let wait_for_inferior handle exit case */ } @@ -1651,10 +1724,12 @@ rewait: : "?", status->value.integer); +#ifdef GDBSERVER + inferior_ptid = ptid; +#endif return ptid; } - /* The rpc handler called by exc_server. */ error_t S_exception_raise_request (mach_port_t port, mach_port_t reply_port, @@ -1736,11 +1811,9 @@ S_exception_raise_request (mach_port_t port, mach_port_t reply_port, inf->wait.suppress = 1; mach_port_deallocate (mach_task_self (), reply_port); } - return 0; } - /* Fill in INF's wait field after a task has died without giving us more detailed information. */ void @@ -1794,7 +1867,6 @@ do_mach_notify_dead_name (mach_port_t notify, mach_port_t dead_port) return 0; } - static error_t ill_rpc (char *fun) { @@ -1832,7 +1904,6 @@ do_mach_notify_send_once (mach_port_t notify) return ill_rpc ("do_mach_notify_send_once"); } - /* Process_reply server routines. We only use process_wait_reply. */ error_t @@ -1901,7 +1972,6 @@ S_proc_getmsgport_reply (mach_port_t reply, error_t err, mach_port_t msg_port) return ill_rpc ("S_proc_getmsgport_reply"); } - /* Msg_reply server routines. We only use msg_sig_post_untraced_reply. */ error_t @@ -1930,7 +2000,6 @@ S_msg_sig_post_untraced_reply (mach_port_t reply, error_t err) inf->stopped = 1; else inf->wait.suppress = 1; - return 0; } @@ -1940,7 +2009,6 @@ S_msg_sig_post_reply (mach_port_t reply, error_t err) return ill_rpc ("S_msg_sig_post_reply"); } - /* Returns the number of messages queued for the receive right PORT. */ static mach_port_msgcount_t port_msgs_queued (mach_port_t port) @@ -1955,7 +2023,6 @@ port_msgs_queued (mach_port_t port) return status.mps_msgcount; } - /* Resume execution of the inferior process. If STEP is nonzero, single-step it. @@ -1973,8 +2040,13 @@ port_msgs_queued (mach_port_t port) in multiple events returned by wait). */ static void +#ifndef GDBSERVER gnu_resume (struct target_ops *ops, ptid_t ptid, int step, enum gdb_signal sig) +#else +gnu_resume_1 (struct target_ops *ops, + ptid_t ptid, int step, enum gdb_signal sig) +#endif { struct proc *step_thread = 0; int resume_all; @@ -1997,9 +2069,11 @@ gnu_resume (struct target_ops *ops, abort the faulting thread, which will perhaps retake it. */ { proc_abort (inf->wait.thread, 1); +#ifndef GDBSERVER warning (_("Aborting %s with unforwarded exception %s."), proc_string (inf->wait.thread), gdb_signal_to_name (inf->wait.status.value.sig)); +#endif } if (port_msgs_queued (inf->event_port)) @@ -2022,7 +2096,12 @@ gnu_resume (struct target_ops *ops, else /* Just allow a single thread to run. */ { +#ifdef GDBSERVER + struct proc *thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); +#else struct proc *thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); +#endif + if (!thread) error (_("Can't run single thread id %s: no such thread!"), @@ -2033,7 +2112,12 @@ gnu_resume (struct target_ops *ops, if (step) { +#ifdef GDBSERVER + step_thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); +#else step_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); +#endif + if (!step_thread) warning (_("Can't step thread id %s: no such thread."), target_pid_to_str (ptid)); @@ -2047,7 +2131,7 @@ gnu_resume (struct target_ops *ops, inf_resume (inf); } - +#ifndef GDBSERVER static void gnu_kill_inferior (struct target_ops *ops) { @@ -2061,8 +2145,29 @@ gnu_kill_inferior (struct target_ops *ops) } target_mourn_inferior (); } +#else +static int +gnu_kill (int pid) +{ + struct proc *task = gnu_current_inf->task; + struct process_info *process; + + process = find_process_pid (pid); + + if (task) + { + proc_debug (task, "terminating..."); + task_terminate (task->port); + inf_set_pid (gnu_current_inf, -1); + } + the_target->mourn (process); + return 0; +} +#endif + /* Clean up after the inferior dies. */ +#ifndef GDBSERVER static void gnu_mourn_inferior (struct target_ops *ops) { @@ -2071,8 +2176,18 @@ gnu_mourn_inferior (struct target_ops *ops) unpush_target (ops); generic_mourn_inferior (); } +#else +static void +gnu_mourn (struct process_info *process) +{ + /* Free our private data. */ + free (process->private); + process->private = NULL; + + clear_inferiors (); +} +#endif - /* Fork an inferior process, and start debugging it. */ /* Set INFERIOR_PID to the first thread available in the child, if any. */ @@ -2095,6 +2210,7 @@ cur_inf (void) return gnu_current_inf; } +#ifndef GDBSERVER static void gnu_create_inferior (struct target_ops *ops, char *exec_file, char *allargs, char **env, @@ -2148,10 +2264,34 @@ gnu_create_inferior (struct target_ops *ops, else inf_restore_exc_ports (inf); } +#else +static int +gnu_create_inferior (char *program, char **allargs) +{ + int pid; + pid = fork (); + if (pid < 0) + perror_with_name ("fork"); + + if (pid == 0) + { + ptrace (PTRACE_TRACEME); + setpgid (0, 0); + execv (program, allargs); + + fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno)); + fflush (stderr); + _exit (0177); + } + + gnu_add_process (pid, 0); + return pid; +} +#endif - /* Attach to process PID, then initialize for debugging it and wait for the trace-trap that results from attaching. */ +#ifndef GDBSERVER static void gnu_attach (struct target_ops *ops, char *args, int from_tty) { @@ -2207,8 +2347,14 @@ gnu_attach (struct target_ops *ops, char *args, int from_tty) renumber_threads (0); /* Give our threads reasonable names. */ #endif } +#else +static int +gnu_attach (unsigned long pid) +{ + return -1; //not support now +} +#endif - /* Take a program previously attached to and detaches it. The program resumes execution and will no longer stop on signals, etc. We'd better not have left any breakpoints @@ -2216,6 +2362,7 @@ gnu_attach (struct target_ops *ops, char *args, int from_tty) to work, it may be necessary for the process to have been previously attached. It *might* work if the program was started via fork. */ +#ifndef GDBSERVER static void gnu_detach (struct target_ops *ops, char *args, int from_tty) { @@ -2255,7 +2402,25 @@ gnu_stop (ptid_t ptid) { error (_("to_stop target function not implemented")); } +#else +static int +gnu_detach (int pid) +{ + struct process_info *process; + + process = find_process_pid (pid); + if (process == NULL) + return -1; + + inf_detach (gnu_current_inf); + inferior_ptid = null_ptid; + the_target->mourn (process); + return 0; +} +#endif + +#ifndef GDBSERVER static int gnu_thread_alive (struct target_ops *ops, ptid_t ptid) { @@ -2263,8 +2428,15 @@ gnu_thread_alive (struct target_ops *ops, ptid_t ptid) return !!inf_tid_to_thread (gnu_current_inf, ptid_get_tid (ptid)); } +#else +static int +gnu_thread_alive (ptid_t ptid) +{ + /* this function is copyed from lynx-low.c */ + return (find_thread_ptid (ptid) != NULL); +} +#endif - /* Read inferior task's LEN bytes from ADDR and copy it to MYADDR in gdb's address space. Return 0 on failure; number of bytes read otherwise. */ @@ -2310,7 +2482,9 @@ struct vm_region_list vm_size_t length; }; +#ifndef GDBSERVER struct obstack region_obstack; +#endif /* Write gdb's LEN bytes from MYADDR and copy it to ADDR in inferior task's address space. */ @@ -2344,7 +2518,9 @@ gnu_write_inferior (task_t task, CORE_ADDR addr, char *myaddr, int length) myaddr, length); CHK_GOTO_OUT ("Write to inferior faulted", err); +#ifndef GDBSERVER obstack_init (®ion_obstack); +#endif /* Do writes atomically. First check for holes and unwritable memory. */ @@ -2399,7 +2575,11 @@ gnu_write_inferior (task_t task, CORE_ADDR addr, char *myaddr, int length) /* Chain the regions for later use. */ region_element = (struct vm_region_list *) +#ifndef GDBSERVER obstack_alloc (®ion_obstack, sizeof (struct vm_region_list)); +#else + malloc (sizeof (struct vm_region_list)); +#endif region_element->protection = protection; region_element->start = region_address; @@ -2454,7 +2634,9 @@ gnu_write_inferior (task_t task, CORE_ADDR addr, char *myaddr, int length) out: if (deallocate) { +#ifndef GDBSERVER obstack_free (®ion_obstack, 0); +#endif (void) vm_deallocate (mach_task_self (), copied, @@ -2470,7 +2652,7 @@ out: return length; } - +#ifndef GDBSERVER /* Return 0 on failure, number of bytes handled otherwise. TARGET is ignored. */ static int @@ -2576,8 +2758,7 @@ gnu_find_memory_regions (find_memory_region_ftype func, void *data) return 0; } - - +#endif /* Return printable description of proc. */ char * proc_string (struct proc *proc) @@ -2592,6 +2773,7 @@ proc_string (struct proc *proc) return tid_str; } +#ifndef GDBSERVER static char * gnu_pid_to_str (struct target_ops *ops, ptid_t ptid) { @@ -3452,3 +3634,214 @@ flush_inferior_icache (CORE_ADDR pc, int amount) warning (_("Error flushing inferior's cache : %s"), safe_strerror (ret)); } #endif /* FLUSH_INFERIOR_CACHE */ + +#else + +static ptid_t +gnu_ptid_build (int pid, long lwp, long tid) +{ + return ptid_build (pid, tid, 0); +} + +static long +gnu_get_tid (ptid_t ptid) +{ + return ptid_get_lwp (ptid); +} + +static struct process_info * +gnu_add_process (int pid, int attached) +{ + struct process_info *proc; + + proc = add_process (pid, attached); + proc->tdesc = gnu_tdesc; + proc->private = xcalloc (1, sizeof (*proc->private)); + proc->private->inf = cur_inf (); + struct inf *inf = gnu_current_inf; + + inf_attach (inf, pid); + inf->pending_execs = 2; + inf->nomsg = 1; + inf->traced = 1; + + inf_resume (inf); + + return proc; +} + +static void +gnu_join (int pid) +{ + /* doesn't need */ +} + +static void +gnu_resume (struct thread_resume *resume_info, size_t n) +{ + /* FIXME: Assume for now that n == 1. */ + ptid_t ptid = resume_info[0].thread; + const int step = (resume_info[0].kind == resume_step ? 1 : 0); //1 means step, 0 means contiune + const int signal = resume_info[0].sig; + if (ptid_equal (ptid, minus_one_ptid)) + ptid = thread_to_gdb_id (current_inferior); + + regcache_invalidate (); + + gnu_debug ("in gnu_resume: ptid=%d, step=%d, signal=%d\n", ptid, step, + signal); + + /*my_resume(); */ + /*static void gnu_resume_1 (struct target_ops *ops,ptid_t ptid, int step, enum gdb_signal sig) */ + gnu_resume_1 (NULL, ptid, step, signal); + +} + +static ptid_t +gnu_wait (ptid_t ptid, struct target_waitstatus *status, int target_options) +{ + ptid_t event_ptid; + gnu_debug ("gnu_wait: [%s]", target_pid_to_str (ptid)); + event_ptid = gnu_wait_1 (ptid, status, target_options); + gnu_debug (" -> (status->kind = %d)\n", status->kind); + return event_ptid; +} + +void +gnu_fetch_registers_wrap (struct regcache *regcache, int regno) +{ + gnu_debug ("gnu_fetch_registers() regno=%d\n", regno); + return gnu_fetch_registers (NULL, regcache, regno); +} + +void +gnu_store_registers_wrap (struct regcache *regcache, int regno) +{ + gnu_debug ("gnu_store_registers() regno=%d\n", regno); + return gnu_store_registers (NULL, regcache, regno); +} + +static int +gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length) +{ + int ret = 0; + task_t task = (gnu_current_inf + ? (gnu_current_inf->task + ? gnu_current_inf->task->port : 0) : 0); + if (task == MACH_PORT_NULL) + return 0; + ret = gnu_read_inferior (task, addr, myaddr, length); + if (length != ret) + { + gnu_debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret); + return -1; + } + return 0; +} + +static int +gnu_write_memory (CORE_ADDR addr, const unsigned char *myaddr, int length) +{ + int ret = 0; + task_t task = (gnu_current_inf + ? (gnu_current_inf->task + ? gnu_current_inf->task->port : 0) : 0); + if (task == MACH_PORT_NULL) + return 0; + ret = gnu_write_inferior (task, addr, myaddr, length); + if (length != ret) + { + gnu_debug ("gnu_write_inferior,length=%d, but return %d\n", length, + ret); + return -1; + } + return 0; +} + +static void +gnu_request_interrupt (void) +{ + printf ("gnu_request_interrupt not support!\n"); + exit (-1); +} + +/* Helper function for child_wait and the derivatives of child_wait. + HOSTSTATUS is the waitstatus from wait() or the equivalent; store our + translation of that in OURSTATUS. */ +void +store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus) +{ + if (WIFEXITED (hoststatus)) + { + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = WEXITSTATUS (hoststatus); + } + else if (!WIFSTOPPED (hoststatus)) + { + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (hoststatus)); + } + else + { + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (hoststatus)); + } +} + +static struct target_ops gnu_target_ops = { + gnu_create_inferior, + gnu_attach, + gnu_kill, + gnu_detach, + gnu_mourn, + gnu_join, + gnu_thread_alive, + gnu_resume, + gnu_wait, + gnu_fetch_registers_wrap, + gnu_store_registers_wrap, + NULL, /* prepare_to_access_memory */ + NULL, /* done_accessing_memory */ + gnu_read_memory, + gnu_write_memory, + NULL, /* look_up_symbols */ + gnu_request_interrupt, + NULL, /* read_auxv */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* read_offsets */ + NULL, /* get_tls_address */ + NULL, /* qxfer_spu */ + NULL, /* hostio_last_error */ + NULL, /* qxfer_osdata */ + NULL, /* qxfer_siginfo */ + NULL, /* supports_non_stop */ + NULL, /* async */ + NULL, /* start_non_stop */ + NULL, /* supports_multi_process */ + NULL, /* handle_monitor_command */ +}; + +void +_initialize_gnu_nat (void) +{ + proc_server = getproc (); +} + +static void +initialize_low_arch () +{ + init_registers_i386 (); + gnu_tdesc = tdesc_i386; +} + +void +initialize_low (void) +{ + set_target_ops (&gnu_target_ops); + initialize_low_arch (); + _initialize_gnu_nat (); +} +#endif diff --git a/gdb/gnu-nat.h b/gdb/gnu-nat.h index f896bd2..84f507d 100644 --- a/gdb/gnu-nat.h +++ b/gdb/gnu-nat.h @@ -93,13 +93,83 @@ extern char *proc_string (struct proc *proc); extern int gnu_debug_flag; +#ifndef GDBSERVER #define debug(msg, args...) \ do { if (gnu_debug_flag) \ fprintf_unfiltered (gdb_stdlog, "%s:%d: " msg "\r\n", \ __FILE__ , __LINE__ , ##args); } while (0) +#else +#define debug(msg, args...) \ + do { if (gnu_debug_flag) \ + printf ("%s:%d: " msg "\r\n", \ + __FILE__ , __LINE__ , ##args); } while (0) +#endif /* Create a prototype generic GNU/Hurd target. The client can override it with local methods. */ struct target_ops *gnu_target (void); +#ifdef GDBSERVER + +/* All info needed to access an architecture/mode's registers. */ + +struct regs_info +{ + /* Regset support bitmap: 1 for registers that are transferred as a part + of a regset, 0 for ones that need to be handled individually. This + can be NULL if all registers are transferred with regsets or regsets + are not supported. */ + unsigned char *regset_bitmap; + + /* Info used when accessing registers with PTRACE_PEEKUSER / + PTRACE_POKEUSER. This can be NULL if all registers are + transferred with regsets .*/ + struct usrregs_info *usrregs; + +#ifdef HAVE_gnu_REGSETS + /* Info used when accessing registers with regsets. */ + struct regsets_info *regsets_info; +#endif +}; + +#define ptid_of(proc) ((proc)->head.id) +#define pid_of(proc) ptid_get_pid ((proc)->head.id) +#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id) + +#define get_lwp(inf) ((struct lwp_info *)(inf)) +#define get_thread_lwp(thr) (get_lwp (inferior_target_data (thr))) +#define get_lwp_thread(proc) ((struct thread_info *) \ + find_inferior_id (&all_threads, \ + get_lwp (proc)->head.id)) + +#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE +#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT +#define THREAD_STATE_SET_TRACED(state) \ + ((struct i386_thread_state *) (state))->efl |= 0x100 +#define THREAD_STATE_CLEAR_TRACED(state) \ + ((((struct i386_thread_state *) (state))->efl &= ~0x100), 1) + + +#ifndef PIDGET +#define PIDGET(PTID) (ptid_get_pid (PTID)) +#define TIDGET(PTID) (ptid_get_lwp (PTID)) +#define MERGEPID(PID, TID) ptid_build (PID, TID, 0) +#endif +//gdbserver use ptid_t not the same as gdb does! +static ptid_t gnu_ptid_build(int pid,long lwp,long tid); + +//add for erase warning +extern const char * host_address_to_string (const void *addr); + +/* Return printable description of proc. */ +extern char *proc_string (struct proc *proc); + + +#ifndef safe_strerror +#define safe_strerror(err) \ + "" +#endif +#endif + #endif /* __GNU_NAT_H__ */ + diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c index 0fd8d91..51ca679 100644 --- a/gdb/i386gnu-nat.c +++ b/gdb/i386gnu-nat.c @@ -17,24 +17,17 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifndef GDBSERVER #include "defs.h" #include "inferior.h" #include "floatformat.h" #include "regcache.h" #include "gdb_assert.h" -#include <errno.h> -#include <stdio.h> #include "gdb_string.h" -#include <mach.h> -#include <mach_error.h> -#include <mach/message.h> -#include <mach/exception.h> - #include "i386-tdep.h" -#include "gnu-nat.h" #include "i387-tdep.h" #ifdef HAVE_SYS_PROCFS_H @@ -42,6 +35,24 @@ # include "gregset.h" #endif +#else /* GDBSERVER */ +#include "server.h" +#include "target.h" +#include "gdb_wait.h" + +#define I386_NUM_GREGS 16 +#endif /* GDBSERVER */ + +#include <errno.h> +#include <stdio.h> + +#include <mach.h> +#include <mach_error.h> +#include <mach/message.h> +#include <mach/exception.h> +#include "gnu-nat.h" +/*#include "gnu-low.h"*/ + /* Offset to the thread_state_t location where REG is stored. */ #define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg) @@ -78,6 +89,7 @@ static int creg_offset[] = static void fetch_fpregs (struct regcache *regcache, struct proc *thread) { +#ifndef GDBSERVER mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT; struct i386_float_state state; error_t err; @@ -101,8 +113,12 @@ fetch_fpregs (struct regcache *regcache, struct proc *thread) /* Supply the floating-point registers. */ i387_supply_fsave (regcache, -1, state.hw_state); } +#else + gnu_debug ("fetch_fpregs() not support now\n"); +#endif } +#ifndef GDBSERVER #ifdef HAVE_SYS_PROCFS_H /* These two calls are used by the core-regset.c code for reading ELF core files. */ @@ -120,9 +136,16 @@ supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregs) i387_supply_fsave (regcache, -1, fpregs); } #endif +#endif +extern struct inf *gnu_current_inf; +extern ptid_t inferior_ptid; /* Fetch register REGNO, or all regs if REGNO is -1. */ +#ifndef GDBSERVER static void +#else +void +#endif gnu_fetch_registers (struct target_ops *ops, struct regcache *regcache, int regno) { @@ -132,7 +155,11 @@ gnu_fetch_registers (struct target_ops *ops, inf_update_procs (gnu_current_inf); thread = inf_tid_to_thread (gnu_current_inf, +#ifndef GDBSERVER ptid_get_tid (inferior_ptid)); +#else + TIDGET (inferior_ptid)); +#endif if (!thread) error (_("Can't fetch registers from thread %s: No such thread"), target_pid_to_str (inferior_ptid)); @@ -157,17 +184,25 @@ gnu_fetch_registers (struct target_ops *ops, proc_debug (thread, "fetching all register"); for (i = 0; i < I386_NUM_GREGS; i++) +#ifndef GDBSERVER regcache_raw_supply (regcache, i, REG_ADDR (state, i)); +#else + supply_register (regcache, i, REG_ADDR (state, i)); +#endif thread->fetched_regs = ~0; } else { +#ifndef GDBSERVER proc_debug (thread, "fetching register %s", gdbarch_register_name (get_regcache_arch (regcache), regno)); regcache_raw_supply (regcache, regno, REG_ADDR (state, regno)); +#else + supply_register (regcache, regno, REG_ADDR (state, regno)); +#endif thread->fetched_regs |= (1 << regno); } } @@ -183,9 +218,14 @@ gnu_fetch_registers (struct target_ops *ops, /* Store the whole floating-point state into THREAD using information from the corresponding (pseudo) registers. */ +#ifndef GDBSERVER static void +#else +void +#endif store_fpregs (const struct regcache *regcache, struct proc *thread, int regno) { +#ifndef GDBSERVER mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT; struct i386_float_state state; error_t err; @@ -211,21 +251,36 @@ store_fpregs (const struct regcache *regcache, struct proc *thread, int regno) proc_string (thread)); return; } +#else + gnu_debug ("store_fpregs() not support now\n"); +#endif } /* Store at least register REGNO, or all regs if REGNO == -1. */ +#ifndef GDBSERVER static void +#else +void +#endif gnu_store_registers (struct target_ops *ops, struct regcache *regcache, int regno) { struct proc *thread; +#ifndef GDBSERVER struct gdbarch *gdbarch = get_regcache_arch (regcache); +#else + const struct target_desc *gdbarch = regcache->tdesc; +#endif /* Make sure we know about new threads. */ inf_update_procs (gnu_current_inf); thread = inf_tid_to_thread (gnu_current_inf, +#ifndef GDBSERVER ptid_get_tid (inferior_ptid)); +#else + TIDGET (inferior_ptid)); +#endif if (!thread) error (_("Couldn't store registers into thread %s: No such thread"), target_pid_to_str (inferior_ptid)); @@ -265,12 +320,19 @@ gnu_store_registers (struct target_ops *ops, register_size (gdbarch, check_regno))) /* Register CHECK_REGNO has changed! Ack! */ { +#ifndef GDBSERVER warning (_("Register %s changed after the thread was aborted"), gdbarch_register_name (gdbarch, check_regno)); +#endif if (regno >= 0 && regno != check_regno) /* Update GDB's copy of the register. */ +#ifndef GDBSERVER regcache_raw_supply (regcache, check_regno, REG_ADDR (state, check_regno)); +#else + supply_register (regcache, check_regno, + REG_ADDR (state, check_regno)); +#endif else warning (_("... also writing this register! " "Suspicious...")); @@ -284,16 +346,24 @@ gnu_store_registers (struct target_ops *ops, proc_debug (thread, "storing all registers"); for (i = 0; i < I386_NUM_GREGS; i++) +#ifndef GDBSERVER if (REG_VALID == regcache_register_status (regcache, i)) regcache_raw_collect (regcache, i, REG_ADDR (state, i)); +#else + collect_register (regcache, i, REG_ADDR (state, i)); +#endif } else { +#ifndef GDBSERVER proc_debug (thread, "storing register %s", gdbarch_register_name (gdbarch, regno)); gdb_assert (REG_VALID == regcache_register_status (regcache, regno)); regcache_raw_collect (regcache, regno, REG_ADDR (state, regno)); +#else + collect_register (regcache, regno, REG_ADDR (state, regno)); +#endif } /* Restore the T bit. */ @@ -309,6 +379,7 @@ gnu_store_registers (struct target_ops *ops, } } +#ifndef GDBSERVER /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_i386gnu_nat; @@ -326,3 +397,4 @@ _initialize_i386gnu_nat (void) /* Register the target. */ add_target (t); } +#endif ====================================================================== gdbserver * configure.ac (host_makefile_frag): New rule for GNU/Hurd to load i386gnu.mh. * configure.srv (srv_tgtobj): Add gnu-nat.o i386gnu-nat.o.o for GNU/Hurd. (srv_regobj): Add $(srv_i386_regobj) for GNU/Hurd. (srv_xmlfiles): Add $(srv_i386_xmlfiles) for GNU/Hurd. * configure: Regenerate. * Makefile.in (OBS): Add $(NATDEPFILES). (generated_files): Add $(NAT_GENERATED_FILES). (@host_makefile_frag@): New rule, add gnui386.mh. (MIG): New tools. (AWK): New tools. * exc_request.defs: New file. Softlink to [gdb]/gdb/exc_request.defs. * i386gnu-nat.c: New file. Softlink to [gdb]/gdb/i386gnu-nat.c. * gnu-low.c: New file. Softlink to [gdb]/gdb/gnu-nat.c. * gnu-low.h: New file. Softlink to [gdb]/gdb/gnu-nat.h. * hostio.c: Add macro define PATH_MAX 512. * i386gnu.mh: New file. Softlink to [gdb]/gdb/config/i386/i386gnu.mh. * msg.defs: New file. Softlink to [gdb]/gdb/msg.defs. * msg_reply.defs: New file. Softlink to [gdb]/gdb/msg_reply.defs. * notify.defs: New file. Softlink to [gdb]/gdb/notify.defs. * process_reply.defs: New file. Softlink to [gdb]/gdb/process_reply.defs. * reply_mid_hack.awk: New file. Softlink to [gdb]/gdb/reply_mid_hack.awk. * server.h: Add typedef long CORE_ADDR; * utils.c (host_address_to_string): New functions, copy from [gdb]/gdb/utils.c. diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index e8470a8..967cf57 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -50,6 +50,8 @@ INSTALL_DATA = @INSTALL_DATA@ RANLIB = @RANLIB@ CC = @CC@ +MIG = @MIG@ +AWK = @AWK@ # Dependency tracking information. DEPMODE = @CCDEPMODE@ @@ -172,7 +174,7 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o targ xml-utils.o common-utils.o ptid.o buffer.o format.o filestuff.o \ dll.o notif.o tdesc.o \ $(XML_BUILTIN) \ - $(DEPFILES) $(LIBOBJS) + $(DEPFILES) $(LIBOBJS) $(NATDEPFILES) GDBREPLAY_OBS = gdbreplay.o version.o GDBSERVER_LIBS = @GDBSERVER_LIBS@ XM_CLIBS = @LIBS@ @@ -195,6 +197,11 @@ CLEANDIRS = $(SUBDIRS) # The format here is for the `case' shell command. REQUIRED_SUBDIRS = $(GNULIB_BUILDDIR) +# Host-dependent makefile fragment comes in here. +GDBSERVER=@GDBSERVER@ +@host_makefile_frag@ +# End of host-dependent makefile fragment + FLAGS_TO_PASS = \ "prefix=$(prefix)" \ "exec_prefix=$(exec_prefix)" \ @@ -228,7 +235,7 @@ FLAGS_TO_PASS = \ "RUNTESTFLAGS=$(RUNTESTFLAGS)" # All generated files which can be included by another file. -generated_files = config.h $(GNULIB_H) +generated_files = config.h $(GNULIB_H) $(NAT_GENERATED_FILES) .c.o: $(COMPILE) $< diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac index b9928d7..21685db 100644 --- a/gdb/gdbserver/configure.ac +++ b/gdb/gdbserver/configure.ac @@ -456,6 +456,31 @@ if $want_ipa ; then fi fi +frags= +GDBSERVER=1 +case $host_os in + gnu*) + #Needed for GNU Hurd hosts. + AC_PROG_AWK + AC_CHECK_TOOL(MIG, mig) + if test x"$MIG" = x; then + AC_MSG_ERROR([MIG not found but required for $host hosts]) + fi + host_makefile_frag=${srcdir}/i386gnu.mh + if test ! -f ${host_makefile_frag}; then + AC_MSG_ERROR("*** Gdb does not support native target ${host}") + fi + frags="$frags $host_makefile_frag" + ;; + *) + host_makefile_frag=/dev/null + ;; +esac + +AC_SUBST_FILE(host_makefile_frag) +AC_SUBST(frags) +AC_SUBST(GDBSERVER) + AC_SUBST(GDBSERVER_DEPFILES) AC_SUBST(GDBSERVER_LIBS) AC_SUBST(srv_xmlbuiltin) diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index 879d0de..1d9bf7a 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -118,6 +118,11 @@ case "${target}" in srv_linux_btrace=yes ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o" ;; + i[34567]86-*-gnu*) srv_regobj="$srv_i386_regobj" + srv_tgtobj="gnu-nat.o i386gnu-nat.o" + srv_xmlfiles="$srv_i386_xmlfiles" + ;; + i[34567]86-*-lynxos*) srv_regobj="i386.o" srv_tgtobj="lynx-low.o lynx-i386-low.o" srv_xmlfiles="i386/i386.xml" diff --git a/gdb/gdbserver/exc_request.defs b/gdb/gdbserver/exc_request.defs new file mode 120000 index 0000000..1b8d3cd --- /dev/null +++ b/gdb/gdbserver/exc_request.defs @@ -0,0 +1 @@ +../exc_request.defs \ No newline at end of file diff --git a/gdb/gdbserver/gnu-nat.c b/gdb/gdbserver/gnu-nat.c new file mode 120000 index 0000000..d72e184 --- /dev/null +++ b/gdb/gdbserver/gnu-nat.c @@ -0,0 +1 @@ +../gnu-nat.c \ No newline at end of file diff --git a/gdb/gdbserver/gnu-nat.h b/gdb/gdbserver/gnu-nat.h new file mode 120000 index 0000000..397c15c --- /dev/null +++ b/gdb/gdbserver/gnu-nat.h @@ -0,0 +1 @@ +../gnu-nat.h \ No newline at end of file diff --git a/gdb/gdbserver/hostio.c b/gdb/gdbserver/hostio.c index df94d31..f3af499 100644 --- a/gdb/gdbserver/hostio.c +++ b/gdb/gdbserver/hostio.c @@ -25,6 +25,10 @@ #include <limits.h> #include <unistd.h> +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + extern int remote_debug; struct fd_list diff --git a/gdb/gdbserver/i386gnu-nat.c b/gdb/gdbserver/i386gnu-nat.c new file mode 120000 index 0000000..c547b9b --- /dev/null +++ b/gdb/gdbserver/i386gnu-nat.c @@ -0,0 +1 @@ +../i386gnu-nat.c \ No newline at end of file diff --git a/gdb/gdbserver/i386gnu.mh b/gdb/gdbserver/i386gnu.mh new file mode 120000 index 0000000..0497c22 --- /dev/null +++ b/gdb/gdbserver/i386gnu.mh @@ -0,0 +1 @@ +../config/i386/i386gnu.mh \ No newline at end of file diff --git a/gdb/gdbserver/msg.defs b/gdb/gdbserver/msg.defs new file mode 120000 index 0000000..a663adb --- /dev/null +++ b/gdb/gdbserver/msg.defs @@ -0,0 +1 @@ +../msg.defs \ No newline at end of file diff --git a/gdb/gdbserver/msg_reply.defs b/gdb/gdbserver/msg_reply.defs new file mode 120000 index 0000000..61e8053 --- /dev/null +++ b/gdb/gdbserver/msg_reply.defs @@ -0,0 +1 @@ +../msg_reply.defs \ No newline at end of file diff --git a/gdb/gdbserver/notify.defs b/gdb/gdbserver/notify.defs new file mode 120000 index 0000000..8a2c79d --- /dev/null +++ b/gdb/gdbserver/notify.defs @@ -0,0 +1 @@ +../notify.defs \ No newline at end of file diff --git a/gdb/gdbserver/process_reply.defs b/gdb/gdbserver/process_reply.defs new file mode 120000 index 0000000..7106ac0 --- /dev/null +++ b/gdb/gdbserver/process_reply.defs @@ -0,0 +1 @@ +../process_reply.defs \ No newline at end of file diff --git a/gdb/gdbserver/reply_mig_hack.awk b/gdb/gdbserver/reply_mig_hack.awk new file mode 120000 index 0000000..fa7d33a --- /dev/null +++ b/gdb/gdbserver/reply_mig_hack.awk @@ -0,0 +1 @@ +../reply_mig_hack.awk \ No newline at end of file diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 18d060c..20e88bf 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -91,7 +91,8 @@ typedef unsigned char gdb_byte; /* FIXME: This should probably be autoconf'd for. It's an integer type at least the size of a (void *). */ -typedef long long CORE_ADDR; +//typedef long long CORE_ADDR; +typedef long CORE_ADDR; typedef long long LONGEST; typedef unsigned long long ULONGEST; diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c index 9706d74..d6dd4f9 100644 --- a/gdb/gdbserver/utils.c +++ b/gdb/gdbserver/utils.c @@ -170,7 +170,6 @@ internal_error (const char *file, int line, const char *fmt, ...) #define CELLSIZE 50 /* Return the next entry in the circular buffer. */ - static char * get_cell (void) { @@ -181,6 +180,15 @@ get_cell (void) return buf[cell]; } +const char * +host_address_to_string (const void *addr) +{ + char *str = get_cell (); + + xsnprintf (str, CELLSIZE, "0x%s", phex_nz ((unsigned long long) addr, sizeof (addr))); + return str; +} + static char * decimal2str (char *sign, ULONGEST addr) { -- Yue Lu (陆岳) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-05 10:54 ` Yue Lu @ 2013-09-05 19:29 ` Pedro Alves 2013-09-05 19:39 ` Joel Brobecker ` (3 more replies) 0 siblings, 4 replies; 25+ messages in thread From: Pedro Alves @ 2013-09-05 19:29 UTC (permalink / raw) To: Yue Lu; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd On 09/05/2013 11:53 AM, Yue Lu wrote: > Hi, > > This is the my new patch. Thanks. Follows a few comments, by no means an in depth review. We'll probably need to iterate a few times. I'm counting on Thomas and others to help as well! I'm actually very excited to see gdb and gdbserver sharing a single target backend, even if we still have many wrinkles in the interfaces to iron out! It does looks like this way results in lots of less work, and makes me believe we can port other targets to gdbserver already without unsurmountable effort. It'd be very useful if you send and maintain along with the patch the rationale for all design divergences between the ports you found necessary. E.g., it seems that gdbserver's task/proc bookkeeping is different from gdb's. Why? > I have put some soft link in directory gdbserver like *.defs which > point to [gdb]/gdb/*.defs. We'll need to adjust the Makefile etc. instead to use the original files instead of that. No symlinks please. > 2013-09-03 Yue Lu <hacklu.newborn@gmail.com> > gdb > * configure.tgt: Set build_gdbserver=yes for GNU/Hurd hosts. > * configure: Regenerate. > * config/i386/i386gnu.mh: Add #ifdef to determine which rule > to use in gdbserver. > * i386gnu-nat.c: Add macor GDBSERVER to support build gdbserver. > * gnu-nat.h: Add macor GDBSERVER to support build gdbserver. > * gnu-nat.c: Add macor GDBSERVER to support build gdbserver. > (gnu_debug): New function, use for debug printf. > (gnu_wait_1): wait for inferior used in gdbserver. > (gnu_resume_1): resume inferior used in gdbserver. > (gnu_kill): New function, used in gdbserver. > (gnu_mourn): New function, clean up after inferior dies, used > in gdbserver. > (gnu_create_inferior): New function, use for create inferior > in gdbserver. > (gnu_attach): New function, a placeholder. > (gnu_detach): New function, used in gdbserver detach from inferior. > (gnu_thread_alive): New function, call find_thread_ptid(). > (gnu_ptid_build): New function, build structure ptid_t from > pid, and tid. > (gnu_get_tid): New function, return lwp from structure ptid_t, > this is different with gdb's behavior. > (gnu_add_process): New function, add a new process to process list. > (gnu_join): New function, a placeholder. > (gnu_resume): New function, a wrap function, just call gnu_resume_1(). > (gnu_wait): New function, a wrap function, just call gnu_wait_1(). > (gnu_fetch_registers_wrap): New function, a wrap function, > just call gnu_fetch_registers(). > (gnu_store_registers_wrap): New function, a wrap function, > just call gnu_store_registers(). > (gnu_read_memory): New function, a wrap function, just call > gnu_read_inferior(). > (gnu_write_memory): New function, a wrap function, just call > gnu_write_inferior(). > (gnu_request_interrupt): New function, a placeholder. > (store_waitstatus): New function, helper function, copy from > [gdb]/gdb/inf-child.c. > (initialize_low): New function, use for initialize gdbserver's > target_ops. > (initialize_low_arch): New function, used by initialize_low(). > (_initialize_gnu_nat): New function, used by initialize_low(). > > diff --git a/gdb/config/i386/i386gnu.mh b/gdb/config/i386/i386gnu.mh > index a3ea122..224cf0f 100644 > --- a/gdb/config/i386/i386gnu.mh > +++ b/gdb/config/i386/i386gnu.mh > @@ -1,4 +1,5 @@ > # Host: Intel 386 running the GNU Hurd > +ifndef GDBSERVER > NATDEPFILES= i386gnu-nat.o gnu-nat.o core-regset.o fork-child.o \ > notify_S.o process_reply_S.o msg_reply_S.o \ > msg_U.o exc_request_U.o exc_request_S.o > @@ -12,6 +13,10 @@ XM_CLIBS = -lshouldbeinlibc > # Use our own user stubs for the msg rpcs, so we can make them time out, in > # case the program is fucked, or we guess the wrong signal thread. > msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;' > +else > +NATDEPFILES= notify_S.o process_reply_S.o msg_reply_S.o \ > + exc_request_U.o exc_request_S.o > +endif > > # ick > MIGCOM = $(MIG) -cc cat - /dev/null > diff --git a/gdb/configure.tgt b/gdb/configure.tgt > index b0bee47..3eb2ff7 100644 > --- a/gdb/configure.tgt > +++ b/gdb/configure.tgt > @@ -231,6 +231,7 @@ i[34567]86-*-linux*) > i[34567]86-*-gnu*) > # Target: Intel 386 running the GNU Hurd > gdb_target_obs="i386-tdep.o i387-tdep.o i386gnu-tdep.o solib-svr4.o" > + build_gdbserver=yes > ;; > i[34567]86-*-cygwin*) > # Target: Intel 386 running win32 > diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c > index 59d2f23..1cdcd1d 100644 > --- a/gdb/gnu-nat.c > +++ b/gdb/gnu-nat.c > @@ -1,6 +1,7 @@ > /* Interface GDB to the GNU Hurd. > Copyright (C) 1992-2013 Free Software Foundation, Inc. > > + > This file is part of GDB. Please go through the patch and remove spurious whitespace changes line these. > > Written by Miles Bader <miles@gnu.ai.mit.edu> > @@ -20,6 +21,7 @@ > You should have received a copy of the GNU General Public License > along with this program. If not, see <http://www.gnu.org/licenses/>. */ > > +#ifndef GDBSERVER > #include "defs.h" > > #include <ctype.h> > @@ -31,18 +33,6 @@ > #include "gdb_string.h" > #include <sys/ptrace.h> > > -#include <mach.h> > -#include <mach_error.h> > -#include <mach/exception.h> > -#include <mach/message.h> > -#include <mach/notify.h> > -#include <mach/vm_attributes.h> > - > -#include <hurd.h> > -#include <hurd/interrupt.h> > -#include <hurd/msg.h> > -#include <hurd/msg_request.h> > -#include <hurd/process.h> > /* Defined in <hurd/process.h>, but we need forward declarations from > <hurd/process_request.h> as well. */ > #undef _process_user_ > @@ -64,17 +54,55 @@ > #include "gdb_assert.h" > #include "gdb_obstack.h" > > -#include "gnu-nat.h" > #include "inf-child.h" > > +#include "exc_request_U.h" > +#include "msg_U.h" > + > +#else /* GDBSERVER */ > +#include "server.h" > +#include "target.h" > + > +#include <limits.h> > +#include <unistd.h> > +#include <sys/ioctl.h> > +#include <sys/types.h> > +#include "gdb_wait.h" > +#include <signal.h> > +#include <sys/ptrace.h> > +#endif /* GDBSERVER */ > + > +#include <mach.h> > +#include <mach_error.h> > +#include <mach/exception.h> > +#include <mach/message.h> > + > +#include <mach/notify.h> > +#include <mach/vm_attributes.h> > + > +#include <hurd.h> > +#include <hurd/interrupt.h> > +#include <hurd/msg.h> > +#include <hurd/msg_request.h> > +#include <hurd/process.h> > + > +#include "gnu-nat.h" > #include "exc_request_S.h" > #include "notify_S.h" > #include "process_reply_S.h" > #include "msg_reply_S.h" > -#include "exc_request_U.h" > -#include "msg_U.h" > > static process_t proc_server = MACH_PORT_NULL; > +#ifdef GDBSERVER > +/* this should move into gnu-i386-low.c ?*/ I guess that means i386gnu-nat.c now, but it sounds like it, yes. > +/* Defined in auto-generated file i386.c. */ > +extern void init_registers_i386 (void); > +extern const struct target_desc *tdesc_i386; > +const struct target_desc *gnu_tdesc; > +int using_threads = 1; > +ptid_t inferior_ptid; > +static struct target_ops gnu_target_ops; > +#endif > > /* If we've sent a proc_wait_request to the proc server, the pid of the > process we asked about. We can only ever have one outstanding. */ > @@ -114,6 +142,12 @@ void inf_continue (struct inf *inf); > debug ("{inf %d %s}: " msg, __inf->pid, \ > host_address_to_string (__inf) , ##args); } while (0) > > +#ifdef GDBSERVER > +static ptid_t gnu_ptid_build (int pid, long lwp, long tid); > +static long gnu_get_tid (ptid_t ptid); These should be used unconditionally throughout, but implemented differently on gdb vs gdbserver. Any other similar case should have a similar solution. The goal should be to have the fewest #ifdefs in the core gnu target code as possible, with the differences being in the interfacing to gdb/gdbserver core. Actually, > +static ptid_t > +gnu_ptid_build (int pid, long lwp, long tid) > +{ > + return ptid_build (pid, tid, 0); > +} > + > +static long > +gnu_get_tid (ptid_t ptid) > +{ > + return ptid_get_lwp (ptid); > +} > + in this case, the difference is that GDB uses the tid field, while gdbserver uses the lwp field. But, (correct me if I'm wrong here), the Hurd's threads are kernel threads, so it'd be better to just make the GDB side use the lwp field too. It's really a simple and mechanic change. Nothing in GDB core actually cares which field is used. So in this case, it'd be better if you send a preparatory patch that does that change (and nothing else), and then rebase the port on top of that patch. > + > +static struct process_info * gnu_add_process (int pid, int attached); > +#endif > + > void proc_abort (struct proc *proc, int force); > struct proc *make_proc (struct inf *inf, mach_port_t port, int tid); > struct proc *_proc_free (struct proc *proc); > @@ -145,7 +179,27 @@ int proc_trace (struct proc *proc, int set); > __e; }) \ > : EIEIO) > > - > +#ifdef GDBSERVER > +struct process_info_private > +{ > + struct inf *inf; > +}; > + > +void > +gnu_debug (char *string, ...) > +{ Sounds like another candidate for always being available, but with minor differences in implementation. > + va_list args; > + > + if (!gnu_debug_flag) > + return; > + va_start (args, string); > + fprintf (stderr, "DEBUG(gnu): "); > + vfprintf (stderr, string, args); > + fprintf (stderr, "\n"); > + va_end (args); > +} > +#endif > + > /* The state passed by an exception message. */ > struct exc_state > { > @@ -242,14 +296,12 @@ struct inf > int want_exceptions; > }; > > - > int > __proc_pid (struct proc *proc) > { > return proc->inf->pid; > } > > - > /* Update PROC's real suspend count to match it's desired one. Returns true > if we think PROC is now in a runnable state. */ > int > @@ -313,7 +365,6 @@ proc_update_sc (struct proc *proc) > return running; > } > > - > /* Thread_abort is called on PROC if needed. PROC must be a thread proc. > If PROC is deemed `precious', then nothing is done unless FORCE is true. > In particular, a thread is precious if it's running (in which case forcing > @@ -390,7 +441,6 @@ proc_get_state (struct proc *proc, int will_modify) > return 0; > } > > - > /* Set PORT to PROC's exception port. */ > error_t > proc_get_exception_port (struct proc * proc, mach_port_t * port) > @@ -506,7 +556,6 @@ proc_restore_exc_port (struct proc *proc) > } > } > > - > /* Turns hardware tracing in PROC on or off when SET is true or false, > respectively. Returns true on success. */ > int > @@ -533,7 +582,6 @@ proc_trace (struct proc *proc, int set) > return 1; > } > > - > /* A variable from which to assign new TIDs. */ > static int next_thread_id = 1; > > @@ -610,7 +658,6 @@ _proc_free (struct proc *proc) > struct proc *next = proc->next; > > proc_debug (proc, "freeing..."); > - > if (proc == inf->step_thread) > /* Turn off single stepping. */ > inf_set_step_thread (inf, 0); > @@ -637,7 +684,6 @@ _proc_free (struct proc *proc) > return next; > } > > - > struct inf * > make_inf (void) > { > @@ -691,7 +737,6 @@ inf_clear_wait (struct inf *inf) > } > } > > - > void > inf_cleanup (struct inf *inf) > { > @@ -736,7 +781,6 @@ inf_startup (struct inf *inf, int pid) > inf_set_pid (inf, pid); > } > > - > /* Close current process, if any, and attach INF to process PORT. */ > void > inf_set_pid (struct inf *inf, pid_t pid) > @@ -786,7 +830,6 @@ inf_set_pid (struct inf *inf, pid_t pid) > inf->pid = -1; > } > > - > /* Validates INF's stopped, nomsg and traced field from the actual > proc server state. Note that the traced field is only updated from > the proc server state if we do not have a message port. If we do > @@ -855,6 +898,7 @@ inf_validate_task_sc (struct inf *inf) > > if (inf->task->cur_sc < suspend_count) > { > +#ifndef GDBSERVER > int abort; > > target_terminal_ours (); /* Allow I/O. */ > @@ -865,7 +909,9 @@ inf_validate_task_sc (struct inf *inf) > > if (abort) > error (_("Additional task suspend count left untouched.")); > +#endif > > + //need fix! What's the plan here? > inf->task->cur_sc = suspend_count; > } > } > @@ -905,7 +951,6 @@ inf_set_traced (struct inf *inf, int on) > inf->traced = on; > } > > - > /* Makes all the real suspend count deltas of all the procs in INF > match the desired values. Careful to always do thread/task suspend > counts in the safe order. Returns true if at least one thread is > @@ -959,7 +1004,6 @@ inf_update_suspends (struct inf *inf) > return 0; > } > > - > /* Converts a GDB pid to a struct proc. */ > struct proc * > inf_tid_to_thread (struct inf *inf, int tid) > @@ -988,7 +1032,6 @@ inf_port_to_thread (struct inf *inf, mach_port_t port) > return 0; > } > > - > /* Make INF's list of threads be consistent with reality of TASK. */ > void > inf_validate_procs (struct inf *inf) > @@ -1056,6 +1099,12 @@ inf_validate_procs (struct inf *inf) > if (!left) > { > proc_debug (thread, "died!"); > +#ifdef GDBSERVER > + ptid_t ptid; > + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); > + if (find_thread_ptid (ptid)) > + remove_thread (find_thread_ptid (ptid)); > +#endif > thread->port = MACH_PORT_NULL; > thread = _proc_free (thread); /* THREAD is dead. */ > if (last) > @@ -1083,10 +1132,15 @@ inf_validate_procs (struct inf *inf) > last = thread; > proc_debug (thread, "new thread: %d", threads[i]); > > +#ifndef GDBSERVER > ptid = ptid_build (inf->pid, 0, thread->tid); > +#else > + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); > +#endif > > /* Tell GDB's generic thread code. */ > > +#ifndef GDBSERVER > if (ptid_equal (inferior_ptid, pid_to_ptid (inf->pid))) > /* This is the first time we're hearing about thread > ids, after a fork-child. */ > @@ -1096,6 +1150,15 @@ inf_validate_procs (struct inf *inf) > add_thread_silent (ptid); > else > add_thread (ptid); > +#else > + if (!find_thread_ptid (ptid)) > + { > + gnu_debug ("New thread, pid=%d, tid=%d\n", inf->pid, > + thread->tid); > + add_thread (ptid, thread); > + inferior_ptid = ptid; // need fix!!!!!!!!!!!!! > + } > +#endif > } > } > > @@ -1104,7 +1167,6 @@ inf_validate_procs (struct inf *inf) > } > } > > - > /* Makes sure that INF's thread list is synced with the actual process. */ > int > inf_update_procs (struct inf *inf) > @@ -1135,7 +1197,6 @@ inf_set_threads_resume_sc (struct inf *inf, > thread->resume_sc = thread->pause_sc; > } > > - > /* Cause INF to continue execution immediately; individual threads may still > be suspended (but their suspend counts will be updated). */ > void > @@ -1179,7 +1240,6 @@ inf_suspend (struct inf *inf) > inf_update_suspends (inf); > } > > - > /* INF has one thread PROC that is in single-stepping mode. This > function changes it to be PROC, changing any old step_thread to be > a normal one. A PROC of 0 clears any existing value. */ > @@ -1205,7 +1265,6 @@ inf_set_step_thread (struct inf *inf, struct proc *thread) > } > } > > - > /* Set up the thread resume_sc's so that only the signal thread is running > (plus whatever other thread are set to always run). Returns true if we > did so, or false if we can't find a signal thread. */ > @@ -1221,6 +1280,7 @@ inf_set_threads_resume_sc_for_signal_thread > (struct inf *inf) > return 0; > } > > +#ifndef GDBSERVER > static void > inf_update_signal_thread (struct inf *inf) > { > @@ -1229,7 +1289,7 @@ inf_update_signal_thread (struct inf *inf) > inf->signal_thread = inf->threads ? inf->threads->next : 0; > } > > - > +#endif > /* Detachs from INF's inferior task, letting it run once again... */ > void > inf_detach (struct inf *inf) > @@ -1284,7 +1344,7 @@ inf_attach (struct inf *inf, int pid) > inf_startup (inf, pid); > } > > - > +#ifndef GDBSERVER > /* Makes sure that we've got our exception ports entrenched in the process. */ > void > inf_steal_exc_ports (struct inf *inf) > @@ -1314,8 +1374,8 @@ inf_restore_exc_ports (struct inf *inf) > for (thread = inf->threads; thread; thread = thread->next) > proc_restore_exc_port (thread); > } > +#endif > > - > /* Deliver signal SIG to INF. If INF is stopped, delivering a signal, even > signal 0, will continue it. INF is assumed to be in a paused state, and > the resume_sc's of INF's threads may be affected. */ > @@ -1404,7 +1464,6 @@ inf_signal (struct inf *inf, enum gdb_signal sig) > #undef NAME > } > > - > /* Continue INF without delivering a signal. This is meant to be used > when INF does not have a message port. */ > void > @@ -1433,7 +1492,6 @@ inf_continue (struct inf *inf) > warning (_("Can't continue process: %s"), safe_strerror (err)); > } > > - > /* The inferior used for all gdb target ops. */ > struct inf *gnu_current_inf = 0; > > @@ -1443,8 +1501,13 @@ struct inf *waiting_inf; > > /* Wait for something to happen in the inferior, returning what in STATUS. */ > static ptid_t > +#ifdef GDBSERVER > +gnu_wait_1 (ptid_t ptid, struct target_waitstatus *status, > + int target_options) > +#else > gnu_wait (struct target_ops *ops, > ptid_t ptid, struct target_waitstatus *status, int options) > +#endif What's the rationale for this, and what's the rationale for doing it only on the gdbserver side? > { > struct msg > { > @@ -1613,19 +1676,29 @@ rewait: > > thread = inf->wait.thread; > if (thread) > +#ifndef GDBSERVER > ptid = ptid_build (inf->pid, 0, thread->tid); > +#else > + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); > +#endif > else if (ptid_equal (ptid, minus_one_ptid)) > thread = inf_tid_to_thread (inf, -1); > else > +#ifndef GDBSERVER > thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); > +#else > + thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); > +#endif > > if (!thread || thread->port == MACH_PORT_NULL) > { > /* TID is dead; try and find a new thread. */ > if (inf_update_procs (inf) && inf->threads) > - ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first > - available > - thread. */ > +#ifndef GDBSERVER > + ptid = ptid_build (inf->pid, 0, inf->threads->tid); > +#else > + ptid = gnu_ptid_build (inf->pid, 0, inf->threads->tid); > +#endif /* The first available thread*/ > else > ptid = inferior_ptid; /* let wait_for_inferior handle exit case */ > } > @@ -1651,10 +1724,12 @@ rewait: > : "?", > status->value.integer); > > +#ifdef GDBSERVER > + inferior_ptid = ptid; > +#endif This is surprising. What's this needed for? > return ptid; > } > > - > /* The rpc handler called by exc_server. */ > error_t > S_exception_raise_request (mach_port_t port, mach_port_t reply_port, > @@ -1736,11 +1811,9 @@ S_exception_raise_request (mach_port_t port, > mach_port_t reply_port, > inf->wait.suppress = 1; > mach_port_deallocate (mach_task_self (), reply_port); > } > - > return 0; > } > > - > /* Fill in INF's wait field after a task has died without giving us more > detailed information. */ > void > @@ -1794,7 +1867,6 @@ do_mach_notify_dead_name (mach_port_t notify, > mach_port_t dead_port) > return 0; > } > > - > static error_t > ill_rpc (char *fun) > { > @@ -1832,7 +1904,6 @@ do_mach_notify_send_once (mach_port_t notify) > return ill_rpc ("do_mach_notify_send_once"); > } > > - > /* Process_reply server routines. We only use process_wait_reply. */ > > error_t > @@ -1901,7 +1972,6 @@ S_proc_getmsgport_reply (mach_port_t reply, > error_t err, mach_port_t msg_port) > return ill_rpc ("S_proc_getmsgport_reply"); > } > > - > /* Msg_reply server routines. We only use msg_sig_post_untraced_reply. */ > > error_t > @@ -1930,7 +2000,6 @@ S_msg_sig_post_untraced_reply (mach_port_t > reply, error_t err) > inf->stopped = 1; > else > inf->wait.suppress = 1; > - > return 0; > } > > @@ -1940,7 +2009,6 @@ S_msg_sig_post_reply (mach_port_t reply, error_t err) > return ill_rpc ("S_msg_sig_post_reply"); > } > > - > /* Returns the number of messages queued for the receive right PORT. */ > static mach_port_msgcount_t > port_msgs_queued (mach_port_t port) > @@ -1955,7 +2023,6 @@ port_msgs_queued (mach_port_t port) > return status.mps_msgcount; > } > > - > /* Resume execution of the inferior process. > > If STEP is nonzero, single-step it. > @@ -1973,8 +2040,13 @@ port_msgs_queued (mach_port_t port) > in multiple events returned by wait). */ > > static void > +#ifndef GDBSERVER > gnu_resume (struct target_ops *ops, > ptid_t ptid, int step, enum gdb_signal sig) > +#else > +gnu_resume_1 (struct target_ops *ops, > + ptid_t ptid, int step, enum gdb_signal sig) > +#endif Again, why is this conditional? > { > struct proc *step_thread = 0; > int resume_all; > @@ -1997,9 +2069,11 @@ gnu_resume (struct target_ops *ops, > abort the faulting thread, which will perhaps retake it. */ > { > proc_abort (inf->wait.thread, 1); > +#ifndef GDBSERVER > warning (_("Aborting %s with unforwarded exception %s."), > proc_string (inf->wait.thread), > gdb_signal_to_name (inf->wait.status.value.sig)); > +#endif Ditto. > } > > if (port_msgs_queued (inf->event_port)) > @@ -2022,7 +2096,12 @@ gnu_resume (struct target_ops *ops, > else > /* Just allow a single thread to run. */ > { > +#ifdef GDBSERVER > + struct proc *thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); > +#else > struct proc *thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); > +#endif > + > > if (!thread) > error (_("Can't run single thread id %s: no such thread!"), > @@ -2033,7 +2112,12 @@ gnu_resume (struct target_ops *ops, > > if (step) > { > +#ifdef GDBSERVER > + step_thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); > +#else > step_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); > +#endif > + > if (!step_thread) > warning (_("Can't step thread id %s: no such thread."), > target_pid_to_str (ptid)); > @@ -2047,7 +2131,7 @@ gnu_resume (struct target_ops *ops, > inf_resume (inf); > } > > - > +#ifndef GDBSERVER > static void > gnu_kill_inferior (struct target_ops *ops) > { > @@ -2061,8 +2145,29 @@ gnu_kill_inferior (struct target_ops *ops) > } > target_mourn_inferior (); > } > +#else > +static int > +gnu_kill (int pid) > +{ > + struct proc *task = gnu_current_inf->task; > + struct process_info *process; > + > + process = find_process_pid (pid); > + > + if (task) > + { > + proc_debug (task, "terminating..."); > + task_terminate (task->port); > + inf_set_pid (gnu_current_inf, -1); > + } > + the_target->mourn (process); > + return 0; > +} Looks like the differences between gdb and gdbserver here are really minor. We should be able to merge them better. > +#endif > + > > /* Clean up after the inferior dies. */ > +#ifndef GDBSERVER > static void > gnu_mourn_inferior (struct target_ops *ops) > { > @@ -2071,8 +2176,18 @@ gnu_mourn_inferior (struct target_ops *ops) > unpush_target (ops); > generic_mourn_inferior (); > } > +#else > +static void > +gnu_mourn (struct process_info *process) > +{ > + /* Free our private data. */ > + free (process->private); > + process->private = NULL; > + > + clear_inferiors (); > +} > +#endif > > - > /* Fork an inferior process, and start debugging it. */ > > /* Set INFERIOR_PID to the first thread available in the child, if any. */ > @@ -2095,6 +2210,7 @@ cur_inf (void) > return gnu_current_inf; > } > > +#ifndef GDBSERVER > static void > gnu_create_inferior (struct target_ops *ops, > char *exec_file, char *allargs, char **env, > @@ -2148,10 +2264,34 @@ gnu_create_inferior (struct target_ops *ops, > else > inf_restore_exc_ports (inf); > } > +#else > +static int > +gnu_create_inferior (char *program, char **allargs) > +{ > + int pid; > + pid = fork (); > + if (pid < 0) > + perror_with_name ("fork"); > + > + if (pid == 0) > + { > + ptrace (PTRACE_TRACEME); > + setpgid (0, 0); > + execv (program, allargs); > + > + fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno)); > + fflush (stderr); > + _exit (0177); > + } > + > + gnu_add_process (pid, 0); > + return pid; > +} > +#endif > > - > /* Attach to process PID, then initialize for debugging it > and wait for the trace-trap that results from attaching. */ > +#ifndef GDBSERVER > static void > gnu_attach (struct target_ops *ops, char *args, int from_tty) > { > @@ -2207,8 +2347,14 @@ gnu_attach (struct target_ops *ops, char *args, > int from_tty) > renumber_threads (0); /* Give our threads reasonable names. */ > #endif > } > +#else > +static int > +gnu_attach (unsigned long pid) > +{ > + return -1; //not support now Doesn't look like this should be hard to get going. > +} > +#endif > > - > /* Take a program previously attached to and detaches it. > The program resumes execution and will no longer stop > on signals, etc. We'd better not have left any breakpoints > @@ -2216,6 +2362,7 @@ gnu_attach (struct target_ops *ops, char *args, > int from_tty) > to work, it may be necessary for the process to have been > previously attached. It *might* work if the program was > started via fork. */ > +#ifndef GDBSERVER > static void > gnu_detach (struct target_ops *ops, char *args, int from_tty) > { > @@ -2255,7 +2402,25 @@ gnu_stop (ptid_t ptid) > { > error (_("to_stop target function not implemented")); > } > +#else > +static int > +gnu_detach (int pid) > +{ Eheh, we have detach but not attach. ;-) > + struct process_info *process; > + > + process = find_process_pid (pid); > + if (process == NULL) > + return -1; > + > + inf_detach (gnu_current_inf); > > + inferior_ptid = null_ptid; I'm seeing inferior_ptid references in the gdbserver side, but gdbserver doesn't have that global. What's that needed for? > + the_target->mourn (process); > + return 0; > +} > +#endif > + > +#ifndef GDBSERVER > static int > gnu_thread_alive (struct target_ops *ops, ptid_t ptid) > { > @@ -2263,8 +2428,15 @@ gnu_thread_alive (struct target_ops *ops, ptid_t ptid) > return !!inf_tid_to_thread (gnu_current_inf, > ptid_get_tid (ptid)); > } > +#else > +static int > +gnu_thread_alive (ptid_t ptid) > +{ > + /* this function is copyed from lynx-low.c */ Why? Why not use the same scheme as the gdb side? > + return (find_thread_ptid (ptid) != NULL); > +} > +#endif > > - > /* Read inferior task's LEN bytes from ADDR and copy it to MYADDR in > gdb's address space. Return 0 on failure; number of bytes read > otherwise. */ > @@ -2310,7 +2482,9 @@ struct vm_region_list > vm_size_t length; > }; > > +#ifndef GDBSERVER > struct obstack region_obstack; > +#endif > > /* Write gdb's LEN bytes from MYADDR and copy it to ADDR in inferior > task's address space. */ > @@ -2344,7 +2518,9 @@ gnu_write_inferior (task_t task, CORE_ADDR addr, > char *myaddr, int length) > myaddr, length); > CHK_GOTO_OUT ("Write to inferior faulted", err); > > +#ifndef GDBSERVER > obstack_init (®ion_obstack); > +#endif > > /* Do writes atomically. > First check for holes and unwritable memory. */ > @@ -2399,7 +2575,11 @@ gnu_write_inferior (task_t task, CORE_ADDR > addr, char *myaddr, int length) > /* Chain the regions for later use. */ > region_element = > (struct vm_region_list *) > +#ifndef GDBSERVER > obstack_alloc (®ion_obstack, sizeof (struct vm_region_list)); > +#else > + malloc (sizeof (struct vm_region_list)); Err, malloc without storing the result anywhere is just a leak. We'll need to do something about this. We could hack/build libiberty's obstack.c on gdbserver, like we vasprintf.c (see Makefile.in), or use struct buffer on both sides. I think the former would be better. We already have too many ways to do the same, and we that would probably allow getting rid of struct buffer. > +#endif > > region_element->protection = protection; > region_element->start = region_address; > @@ -2454,7 +2634,9 @@ gnu_write_inferior (task_t task, CORE_ADDR addr, > char *myaddr, int length) > out: > if (deallocate) > { > +#ifndef GDBSERVER > obstack_free (®ion_obstack, 0); > +#endif > > (void) vm_deallocate (mach_task_self (), > copied, > @@ -2470,7 +2652,7 @@ out: > return length; > } > > - > +#ifndef GDBSERVER > /* Return 0 on failure, number of bytes handled otherwise. TARGET > is ignored. */ > static int > @@ -2576,8 +2758,7 @@ gnu_find_memory_regions > (find_memory_region_ftype func, void *data) > > return 0; > } > - > - > +#endif > /* Return printable description of proc. */ > char * > proc_string (struct proc *proc) > @@ -2592,6 +2773,7 @@ proc_string (struct proc *proc) > return tid_str; > } > > +#ifndef GDBSERVER > static char * > gnu_pid_to_str (struct target_ops *ops, ptid_t ptid) > { > @@ -3452,3 +3634,214 @@ flush_inferior_icache (CORE_ADDR pc, int amount) > warning (_("Error flushing inferior's cache : %s"), safe_strerror (ret)); > } > #endif /* FLUSH_INFERIOR_CACHE */ > + > +#else > + > +static ptid_t > +gnu_ptid_build (int pid, long lwp, long tid) > +{ > + return ptid_build (pid, tid, 0); > +} > + > +static long > +gnu_get_tid (ptid_t ptid) > +{ > + return ptid_get_lwp (ptid); > +} > + > +static struct process_info * > +gnu_add_process (int pid, int attached) > +{ > + struct process_info *proc; > + > + proc = add_process (pid, attached); > + proc->tdesc = gnu_tdesc; > + proc->private = xcalloc (1, sizeof (*proc->private)); > + proc->private->inf = cur_inf (); > + struct inf *inf = gnu_current_inf; > + > + inf_attach (inf, pid); > + inf->pending_execs = 2; > + inf->nomsg = 1; > + inf->traced = 1; > + > + inf_resume (inf); > + > + return proc; > +} > + > +static void > +gnu_join (int pid) > +{ > + /* doesn't need */ > +} > + > +static void > +gnu_resume (struct thread_resume *resume_info, size_t n) > +{ > + /* FIXME: Assume for now that n == 1. */ > + ptid_t ptid = resume_info[0].thread; > + const int step = (resume_info[0].kind == resume_step ? 1 : 0); //1 > means step, 0 means contiune > + const int signal = resume_info[0].sig; > + if (ptid_equal (ptid, minus_one_ptid)) > + ptid = thread_to_gdb_id (current_inferior); > + > + regcache_invalidate (); > + > + gnu_debug ("in gnu_resume: ptid=%d, step=%d, signal=%d\n", ptid, step, > + signal); > + > + /*my_resume(); */ > + /*static void gnu_resume_1 (struct target_ops *ops,ptid_t ptid, int > step, enum gdb_signal sig) */ > + gnu_resume_1 (NULL, ptid, step, signal); > + > +} > + > +static ptid_t > +gnu_wait (ptid_t ptid, struct target_waitstatus *status, int target_options) > +{ > + ptid_t event_ptid; > + gnu_debug ("gnu_wait: [%s]", target_pid_to_str (ptid)); > + event_ptid = gnu_wait_1 (ptid, status, target_options); > + gnu_debug (" -> (status->kind = %d)\n", status->kind); > + return event_ptid; > +} > + > +void > +gnu_fetch_registers_wrap (struct regcache *regcache, int regno) > +{ > + gnu_debug ("gnu_fetch_registers() regno=%d\n", regno); > + return gnu_fetch_registers (NULL, regcache, regno); > +} > + > +void > +gnu_store_registers_wrap (struct regcache *regcache, int regno) > +{ > + gnu_debug ("gnu_store_registers() regno=%d\n", regno); > + return gnu_store_registers (NULL, regcache, regno); > +} > + > +static int > +gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length) > +{ > + int ret = 0; > + task_t task = (gnu_current_inf > + ? (gnu_current_inf->task > + ? gnu_current_inf->task->port : 0) : 0); > + if (task == MACH_PORT_NULL) > + return 0; > + ret = gnu_read_inferior (task, addr, myaddr, length); > + if (length != ret) > + { > + gnu_debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret); > + return -1; > + } > + return 0; > +} > + > +static int > +gnu_write_memory (CORE_ADDR addr, const unsigned char *myaddr, int length) > +{ > + int ret = 0; > + task_t task = (gnu_current_inf > + ? (gnu_current_inf->task > + ? gnu_current_inf->task->port : 0) : 0); > + if (task == MACH_PORT_NULL) > + return 0; > + ret = gnu_write_inferior (task, addr, myaddr, length); > + if (length != ret) > + { > + gnu_debug ("gnu_write_inferior,length=%d, but return %d\n", length, > + ret); > + return -1; > + } > + return 0; > +} > + These should reall be wrappers around a common shared function. I have a patch that I think helps here. I'll post it in soon. > +static void > +gnu_request_interrupt (void) > +{ > + printf ("gnu_request_interrupt not support!\n"); > + exit (-1); That's quite limiting. :-/ Doesn't sending a SIGINT work? > +} > + > +/* Helper function for child_wait and the derivatives of child_wait. > + HOSTSTATUS is the waitstatus from wait() or the equivalent; store our > + translation of that in OURSTATUS. */ > +void > +store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus) > +{ > + if (WIFEXITED (hoststatus)) > + { > + ourstatus->kind = TARGET_WAITKIND_EXITED; > + ourstatus->value.integer = WEXITSTATUS (hoststatus); > + } > + else if (!WIFSTOPPED (hoststatus)) > + { > + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; > + ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (hoststatus)); > + } > + else > + { > + ourstatus->kind = TARGET_WAITKIND_STOPPED; > + ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (hoststatus)); > + } > +} > + > +static struct target_ops gnu_target_ops = { > + gnu_create_inferior, > + gnu_attach, > + gnu_kill, > + gnu_detach, > + gnu_mourn, > + gnu_join, > + gnu_thread_alive, > + gnu_resume, > + gnu_wait, > + gnu_fetch_registers_wrap, > + gnu_store_registers_wrap, > + NULL, /* prepare_to_access_memory */ > + NULL, /* done_accessing_memory */ > + gnu_read_memory, > + gnu_write_memory, > + NULL, /* look_up_symbols */ > + gnu_request_interrupt, > + NULL, /* read_auxv */ > + NULL, /* insert_point */ > + NULL, /* remove_point */ > + NULL, /* stopped_by_watchpoint */ > + NULL, /* stopped_data_address */ > + NULL, /* read_offsets */ > + NULL, /* get_tls_address */ > + NULL, /* qxfer_spu */ > + NULL, /* hostio_last_error */ > + NULL, /* qxfer_osdata */ > + NULL, /* qxfer_siginfo */ > + NULL, /* supports_non_stop */ > + NULL, /* async */ > + NULL, /* start_non_stop */ > + NULL, /* supports_multi_process */ > + NULL, /* handle_monitor_command */ > +}; > + > +void > +_initialize_gnu_nat (void) > +{ > + proc_server = getproc (); > +} > + > +static void > +initialize_low_arch () > +{ > + init_registers_i386 (); > + gnu_tdesc = tdesc_i386; > +} > + > +void > +initialize_low (void) > +{ > + set_target_ops (&gnu_target_ops); > + initialize_low_arch (); > + _initialize_gnu_nat (); > +} > +#endif > diff --git a/gdb/gnu-nat.h b/gdb/gnu-nat.h > index f896bd2..84f507d 100644 > --- a/gdb/gnu-nat.h > +++ b/gdb/gnu-nat.h > @@ -93,13 +93,83 @@ extern char *proc_string (struct proc *proc); > > extern int gnu_debug_flag; > > +#ifndef GDBSERVER > #define debug(msg, args...) \ > do { if (gnu_debug_flag) \ > fprintf_unfiltered (gdb_stdlog, "%s:%d: " msg "\r\n", \ > __FILE__ , __LINE__ , ##args); } while (0) > +#else > +#define debug(msg, args...) \ > + do { if (gnu_debug_flag) \ > + printf ("%s:%d: " msg "\r\n", \ > + __FILE__ , __LINE__ , ##args); } while (0) > +#endif Wasn't there already a gnu_debug function? > > /* Create a prototype generic GNU/Hurd target. The client can > override it with local methods. */ > struct target_ops *gnu_target (void); > > +#ifdef GDBSERVER > + > +/* All info needed to access an architecture/mode's registers. */ > + > +struct regs_info > +{ > + /* Regset support bitmap: 1 for registers that are transferred as a part > + of a regset, 0 for ones that need to be handled individually. This > + can be NULL if all registers are transferred with regsets or regsets > + are not supported. */ > + unsigned char *regset_bitmap; > + > + /* Info used when accessing registers with PTRACE_PEEKUSER / > + PTRACE_POKEUSER. This can be NULL if all registers are > + transferred with regsets .*/ > + struct usrregs_info *usrregs; > + > +#ifdef HAVE_gnu_REGSETS > + /* Info used when accessing registers with regsets. */ > + struct regsets_info *regsets_info; > +#endif Why's all this needed? > +}; > + > +#define ptid_of(proc) ((proc)->head.id) > +#define pid_of(proc) ptid_get_pid ((proc)->head.id) > +#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id) > + > +#define get_lwp(inf) ((struct lwp_info *)(inf)) > +#define get_thread_lwp(thr) (get_lwp (inferior_target_data (thr))) > +#define get_lwp_thread(proc) ((struct thread_info *) \ > + find_inferior_id (&all_threads, \ > + get_lwp (proc)->head.id)) There seems to be some amount of blind copy&paste from the linux target here. struct lwp_info certainly has no business in this port? You should go through every line in the patch, and make sure you're able to justify it. If you can't, or if you're not sure, revert the change. > + > +#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE > +#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT > +#define THREAD_STATE_SET_TRACED(state) \ > + ((struct i386_thread_state *) (state))->efl |= 0x100 > +#define THREAD_STATE_CLEAR_TRACED(state) \ > + ((((struct i386_thread_state *) (state))->efl &= ~0x100), 1) > + > + > +#ifndef PIDGET > +#define PIDGET(PTID) (ptid_get_pid (PTID)) > +#define TIDGET(PTID) (ptid_get_lwp (PTID)) > +#define MERGEPID(PID, TID) ptid_build (PID, TID, 0) > +#endif > +//gdbserver use ptid_t not the same as gdb does! > +static ptid_t gnu_ptid_build(int pid,long lwp,long tid); As said, best would be to make them the same. > + > +//add for erase warning > +extern const char * host_address_to_string (const void *addr); This should be put in a proper place. Probably utils.h, once I commit yesterday's series to split server.h. > + > +/* Return printable description of proc. */ > +extern char *proc_string (struct proc *proc); > + > + > +#ifndef safe_strerror > +#define safe_strerror(err) \ > + "" > +#endif > +#endif > + > #endif /* __GNU_NAT_H__ */ > + > diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c > index 0fd8d91..51ca679 100644 > --- a/gdb/i386gnu-nat.c > +++ b/gdb/i386gnu-nat.c > @@ -17,24 +17,17 @@ > You should have received a copy of the GNU General Public License > along with this program. If not, see <http://www.gnu.org/licenses/>. */ > > +#ifndef GDBSERVER > #include "defs.h" > #include "inferior.h" > #include "floatformat.h" > #include "regcache.h" > > #include "gdb_assert.h" > -#include <errno.h> > -#include <stdio.h> > #include "gdb_string.h" > > -#include <mach.h> > -#include <mach_error.h> > -#include <mach/message.h> > -#include <mach/exception.h> > - > #include "i386-tdep.h" > > -#include "gnu-nat.h" > #include "i387-tdep.h" > > #ifdef HAVE_SYS_PROCFS_H > @@ -42,6 +35,24 @@ > # include "gregset.h" > #endif > > +#else /* GDBSERVER */ > +#include "server.h" > +#include "target.h" > +#include "gdb_wait.h" > + > +#define I386_NUM_GREGS 16 > +#endif /* GDBSERVER */ > + > +#include <errno.h> > +#include <stdio.h> > + > +#include <mach.h> > +#include <mach_error.h> > +#include <mach/message.h> > +#include <mach/exception.h> > +#include "gnu-nat.h" > +/*#include "gnu-low.h"*/ > + > /* Offset to the thread_state_t location where REG is stored. */ > #define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg) > > @@ -78,6 +89,7 @@ static int creg_offset[] = > static void > fetch_fpregs (struct regcache *regcache, struct proc *thread) > { > +#ifndef GDBSERVER > mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT; > struct i386_float_state state; > error_t err; > @@ -101,8 +113,12 @@ fetch_fpregs (struct regcache *regcache, struct > proc *thread) > /* Supply the floating-point registers. */ > i387_supply_fsave (regcache, -1, state.hw_state); > } > +#else > + gnu_debug ("fetch_fpregs() not support now\n"); > +#endif > } > > +#ifndef GDBSERVER > #ifdef HAVE_SYS_PROCFS_H > /* These two calls are used by the core-regset.c code for > reading ELF core files. */ > @@ -120,9 +136,16 @@ supply_fpregset (struct regcache *regcache, const > gdb_fpregset_t *fpregs) > i387_supply_fsave (regcache, -1, fpregs); > } > #endif > +#endif > > +extern struct inf *gnu_current_inf; > +extern ptid_t inferior_ptid; > /* Fetch register REGNO, or all regs if REGNO is -1. */ > +#ifndef GDBSERVER > static void > +#else > +void > +#endif > gnu_fetch_registers (struct target_ops *ops, > struct regcache *regcache, int regno) > { > @@ -132,7 +155,11 @@ gnu_fetch_registers (struct target_ops *ops, > inf_update_procs (gnu_current_inf); > > thread = inf_tid_to_thread (gnu_current_inf, > +#ifndef GDBSERVER > ptid_get_tid (inferior_ptid)); > +#else > + TIDGET (inferior_ptid)); > +#endif > if (!thread) > error (_("Can't fetch registers from thread %s: No such thread"), > target_pid_to_str (inferior_ptid)); > @@ -157,17 +184,25 @@ gnu_fetch_registers (struct target_ops *ops, > proc_debug (thread, "fetching all register"); > > for (i = 0; i < I386_NUM_GREGS; i++) > +#ifndef GDBSERVER > regcache_raw_supply (regcache, i, REG_ADDR (state, i)); > +#else > + supply_register (regcache, i, REG_ADDR (state, i)); > +#endif I think it'd be better to add a wrapper function that adapts the interfaces in one of the directions. > thread->fetched_regs = ~0; > } > else > { > +#ifndef GDBSERVER > proc_debug (thread, "fetching register %s", > gdbarch_register_name (get_regcache_arch (regcache), > regno)); > > regcache_raw_supply (regcache, regno, > REG_ADDR (state, regno)); > +#else > + supply_register (regcache, regno, REG_ADDR (state, regno)); > +#endif > thread->fetched_regs |= (1 << regno); > } > } > @@ -183,9 +218,14 @@ gnu_fetch_registers (struct target_ops *ops, > > /* Store the whole floating-point state into THREAD using information > from the corresponding (pseudo) registers. */ > +#ifndef GDBSERVER > static void > +#else > +void > +#endif > store_fpregs (const struct regcache *regcache, struct proc *thread, int regno) > { > +#ifndef GDBSERVER > mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT; > struct i386_float_state state; > error_t err; > @@ -211,21 +251,36 @@ store_fpregs (const struct regcache *regcache, > struct proc *thread, int regno) > proc_string (thread)); > return; > } > +#else > + gnu_debug ("store_fpregs() not support now\n"); > +#endif > } > > /* Store at least register REGNO, or all regs if REGNO == -1. */ > +#ifndef GDBSERVER > static void > +#else > +void > +#endif > gnu_store_registers (struct target_ops *ops, > struct regcache *regcache, int regno) > { > struct proc *thread; > +#ifndef GDBSERVER > struct gdbarch *gdbarch = get_regcache_arch (regcache); > +#else > + const struct target_desc *gdbarch = regcache->tdesc; > +#endif > > /* Make sure we know about new threads. */ > inf_update_procs (gnu_current_inf); > > thread = inf_tid_to_thread (gnu_current_inf, > +#ifndef GDBSERVER > ptid_get_tid (inferior_ptid)); > +#else > + TIDGET (inferior_ptid)); > +#endif > if (!thread) > error (_("Couldn't store registers into thread %s: No such thread"), > target_pid_to_str (inferior_ptid)); > @@ -265,12 +320,19 @@ gnu_store_registers (struct target_ops *ops, > register_size (gdbarch, check_regno))) > /* Register CHECK_REGNO has changed! Ack! */ > { > +#ifndef GDBSERVER > warning (_("Register %s changed after the thread was aborted"), > gdbarch_register_name (gdbarch, check_regno)); > +#endif > if (regno >= 0 && regno != check_regno) > /* Update GDB's copy of the register. */ > +#ifndef GDBSERVER > regcache_raw_supply (regcache, check_regno, > REG_ADDR (state, check_regno)); > +#else > + supply_register (regcache, check_regno, > + REG_ADDR (state, check_regno)); > +#endif > else > warning (_("... also writing this register! " > "Suspicious...")); > @@ -284,16 +346,24 @@ gnu_store_registers (struct target_ops *ops, > proc_debug (thread, "storing all registers"); > > for (i = 0; i < I386_NUM_GREGS; i++) > +#ifndef GDBSERVER > if (REG_VALID == regcache_register_status (regcache, i)) > regcache_raw_collect (regcache, i, REG_ADDR (state, i)); > +#else > + collect_register (regcache, i, REG_ADDR (state, i)); > +#endif > } > else > { > +#ifndef GDBSERVER > proc_debug (thread, "storing register %s", > gdbarch_register_name (gdbarch, regno)); > > gdb_assert (REG_VALID == regcache_register_status (regcache, regno)); > regcache_raw_collect (regcache, regno, REG_ADDR (state, regno)); > +#else > + collect_register (regcache, regno, REG_ADDR (state, regno)); > +#endif > } > > /* Restore the T bit. */ > @@ -309,6 +379,7 @@ gnu_store_registers (struct target_ops *ops, > } > } > > +#ifndef GDBSERVER > /* Provide a prototype to silence -Wmissing-prototypes. */ > extern initialize_file_ftype _initialize_i386gnu_nat; > > @@ -326,3 +397,4 @@ _initialize_i386gnu_nat (void) > /* Register the target. */ > add_target (t); > } > +#endif > > ====================================================================== > gdbserver > * configure.ac (host_makefile_frag): New rule for GNU/Hurd to load > i386gnu.mh. > * configure.srv (srv_tgtobj): Add gnu-nat.o i386gnu-nat.o.o for > GNU/Hurd. > (srv_regobj): Add $(srv_i386_regobj) for GNU/Hurd. > (srv_xmlfiles): Add $(srv_i386_xmlfiles) for GNU/Hurd. > * configure: Regenerate. > * Makefile.in (OBS): Add $(NATDEPFILES). > (generated_files): Add $(NAT_GENERATED_FILES). > (@host_makefile_frag@): New rule, add gnui386.mh. > (MIG): New tools. > (AWK): New tools. > * exc_request.defs: New file. Softlink to [gdb]/gdb/exc_request.defs. > * i386gnu-nat.c: New file. Softlink to [gdb]/gdb/i386gnu-nat.c. > * gnu-low.c: New file. Softlink to [gdb]/gdb/gnu-nat.c. > * gnu-low.h: New file. Softlink to [gdb]/gdb/gnu-nat.h. > * hostio.c: Add macro define PATH_MAX 512. > * i386gnu.mh: New file. Softlink to [gdb]/gdb/config/i386/i386gnu.mh. > * msg.defs: New file. Softlink to [gdb]/gdb/msg.defs. > * msg_reply.defs: New file. Softlink to [gdb]/gdb/msg_reply.defs. > * notify.defs: New file. Softlink to [gdb]/gdb/notify.defs. > * process_reply.defs: New file. Softlink to > [gdb]/gdb/process_reply.defs. > * reply_mid_hack.awk: New file. Softlink to > [gdb]/gdb/reply_mid_hack.awk. > * server.h: Add typedef long CORE_ADDR; > * utils.c (host_address_to_string): New functions, copy from > [gdb]/gdb/utils.c. > > diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in > index e8470a8..967cf57 100644 > --- a/gdb/gdbserver/Makefile.in > +++ b/gdb/gdbserver/Makefile.in > @@ -50,6 +50,8 @@ INSTALL_DATA = @INSTALL_DATA@ > RANLIB = @RANLIB@ > > CC = @CC@ > +MIG = @MIG@ > +AWK = @AWK@ > > # Dependency tracking information. > DEPMODE = @CCDEPMODE@ > @@ -172,7 +174,7 @@ OBS = agent.o ax.o inferiors.o regcache.o > remote-utils.o server.o signals.o targ > xml-utils.o common-utils.o ptid.o buffer.o format.o filestuff.o \ > dll.o notif.o tdesc.o \ > $(XML_BUILTIN) \ > - $(DEPFILES) $(LIBOBJS) > + $(DEPFILES) $(LIBOBJS) $(NATDEPFILES) > GDBREPLAY_OBS = gdbreplay.o version.o > GDBSERVER_LIBS = @GDBSERVER_LIBS@ > XM_CLIBS = @LIBS@ > @@ -195,6 +197,11 @@ CLEANDIRS = $(SUBDIRS) > # The format here is for the `case' shell command. > REQUIRED_SUBDIRS = $(GNULIB_BUILDDIR) > > +# Host-dependent makefile fragment comes in here. > +GDBSERVER=@GDBSERVER@ > +@host_makefile_frag@ > +# End of host-dependent makefile fragment > + > FLAGS_TO_PASS = \ > "prefix=$(prefix)" \ > "exec_prefix=$(exec_prefix)" \ > @@ -228,7 +235,7 @@ FLAGS_TO_PASS = \ > "RUNTESTFLAGS=$(RUNTESTFLAGS)" > > # All generated files which can be included by another file. > -generated_files = config.h $(GNULIB_H) > +generated_files = config.h $(GNULIB_H) $(NAT_GENERATED_FILES) > > .c.o: > $(COMPILE) $< > diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac > index b9928d7..21685db 100644 > --- a/gdb/gdbserver/configure.ac > +++ b/gdb/gdbserver/configure.ac > @@ -456,6 +456,31 @@ if $want_ipa ; then > fi > fi > > +frags= > +GDBSERVER=1 > +case $host_os in > + gnu*) > + #Needed for GNU Hurd hosts. > + AC_PROG_AWK > + AC_CHECK_TOOL(MIG, mig) > + if test x"$MIG" = x; then > + AC_MSG_ERROR([MIG not found but required for $host hosts]) > + fi > + host_makefile_frag=${srcdir}/i386gnu.mh > + if test ! -f ${host_makefile_frag}; then > + AC_MSG_ERROR("*** Gdb does not support native target ${host}") > + fi > + frags="$frags $host_makefile_frag" > + ;; > + *) > + host_makefile_frag=/dev/null > + ;; > +esac > + > +AC_SUBST_FILE(host_makefile_frag) > +AC_SUBST(frags) > +AC_SUBST(GDBSERVER) > + > AC_SUBST(GDBSERVER_DEPFILES) > AC_SUBST(GDBSERVER_LIBS) > AC_SUBST(srv_xmlbuiltin) > diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv > index 879d0de..1d9bf7a 100644 > --- a/gdb/gdbserver/configure.srv > +++ b/gdb/gdbserver/configure.srv > @@ -118,6 +118,11 @@ case "${target}" in > srv_linux_btrace=yes > ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o" > ;; > + i[34567]86-*-gnu*) srv_regobj="$srv_i386_regobj" > + srv_tgtobj="gnu-nat.o i386gnu-nat.o" > + srv_xmlfiles="$srv_i386_xmlfiles" > + ;; > + > i[34567]86-*-lynxos*) srv_regobj="i386.o" > srv_tgtobj="lynx-low.o lynx-i386-low.o" > srv_xmlfiles="i386/i386.xml" > diff --git a/gdb/gdbserver/exc_request.defs b/gdb/gdbserver/exc_request.defs > new file mode 120000 > index 0000000..1b8d3cd > --- /dev/null > +++ b/gdb/gdbserver/exc_request.defs > @@ -0,0 +1 @@ > +../exc_request.defs > \ No newline at end of file > diff --git a/gdb/gdbserver/gnu-nat.c b/gdb/gdbserver/gnu-nat.c > new file mode 120000 > index 0000000..d72e184 > --- /dev/null > +++ b/gdb/gdbserver/gnu-nat.c > @@ -0,0 +1 @@ > +../gnu-nat.c > \ No newline at end of file > diff --git a/gdb/gdbserver/gnu-nat.h b/gdb/gdbserver/gnu-nat.h > new file mode 120000 > index 0000000..397c15c > --- /dev/null > +++ b/gdb/gdbserver/gnu-nat.h > @@ -0,0 +1 @@ > +../gnu-nat.h > \ No newline at end of file > diff --git a/gdb/gdbserver/hostio.c b/gdb/gdbserver/hostio.c > index df94d31..f3af499 100644 > --- a/gdb/gdbserver/hostio.c > +++ b/gdb/gdbserver/hostio.c > @@ -25,6 +25,10 @@ > #include <limits.h> > #include <unistd.h> > > +#ifndef PATH_MAX > +#define PATH_MAX 512 > +#endif This should not be necessary anymore. If your patch against current mainline? > + > extern int remote_debug; > > struct fd_list > diff --git a/gdb/gdbserver/i386gnu-nat.c b/gdb/gdbserver/i386gnu-nat.c > new file mode 120000 > index 0000000..c547b9b > --- /dev/null > +++ b/gdb/gdbserver/i386gnu-nat.c > @@ -0,0 +1 @@ > +../i386gnu-nat.c > \ No newline at end of file > diff --git a/gdb/gdbserver/i386gnu.mh b/gdb/gdbserver/i386gnu.mh > new file mode 120000 > index 0000000..0497c22 > --- /dev/null > +++ b/gdb/gdbserver/i386gnu.mh > @@ -0,0 +1 @@ > +../config/i386/i386gnu.mh > \ No newline at end of file > diff --git a/gdb/gdbserver/msg.defs b/gdb/gdbserver/msg.defs > new file mode 120000 > index 0000000..a663adb > --- /dev/null > +++ b/gdb/gdbserver/msg.defs > @@ -0,0 +1 @@ > +../msg.defs > \ No newline at end of file > diff --git a/gdb/gdbserver/msg_reply.defs b/gdb/gdbserver/msg_reply.defs > new file mode 120000 > index 0000000..61e8053 > --- /dev/null > +++ b/gdb/gdbserver/msg_reply.defs > @@ -0,0 +1 @@ > +../msg_reply.defs > \ No newline at end of file > diff --git a/gdb/gdbserver/notify.defs b/gdb/gdbserver/notify.defs > new file mode 120000 > index 0000000..8a2c79d > --- /dev/null > +++ b/gdb/gdbserver/notify.defs > @@ -0,0 +1 @@ > +../notify.defs > \ No newline at end of file > diff --git a/gdb/gdbserver/process_reply.defs b/gdb/gdbserver/process_reply.defs > new file mode 120000 > index 0000000..7106ac0 > --- /dev/null > +++ b/gdb/gdbserver/process_reply.defs > @@ -0,0 +1 @@ > +../process_reply.defs > \ No newline at end of file > diff --git a/gdb/gdbserver/reply_mig_hack.awk b/gdb/gdbserver/reply_mig_hack.awk > new file mode 120000 > index 0000000..fa7d33a > --- /dev/null > +++ b/gdb/gdbserver/reply_mig_hack.awk > @@ -0,0 +1 @@ > +../reply_mig_hack.awk > \ No newline at end of file > diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h > index 18d060c..20e88bf 100644 > --- a/gdb/gdbserver/server.h > +++ b/gdb/gdbserver/server.h > @@ -91,7 +91,8 @@ typedef unsigned char gdb_byte; > > /* FIXME: This should probably be autoconf'd for. It's an integer type at > least the size of a (void *). */ > -typedef long long CORE_ADDR; > +//typedef long long CORE_ADDR; > +typedef long CORE_ADDR; > > typedef long long LONGEST; > typedef unsigned long long ULONGEST; > diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c > index 9706d74..d6dd4f9 100644 > --- a/gdb/gdbserver/utils.c > +++ b/gdb/gdbserver/utils.c > @@ -170,7 +170,6 @@ internal_error (const char *file, int line, const > char *fmt, ...) > #define CELLSIZE 50 > > /* Return the next entry in the circular buffer. */ > - > static char * > get_cell (void) > { > @@ -181,6 +180,15 @@ get_cell (void) > return buf[cell]; > } > > +const char * > +host_address_to_string (const void *addr) > +{ > + char *str = get_cell (); > + > + xsnprintf (str, CELLSIZE, "0x%s", phex_nz ((unsigned long long) > addr, sizeof (addr))); > + return str; > +} > + > static char * > decimal2str (char *sign, ULONGEST addr) > { > Thanks, -- Pedro Alves ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-05 19:29 ` Pedro Alves @ 2013-09-05 19:39 ` Joel Brobecker 2013-09-05 21:38 ` Thomas Schwinge ` (2 subsequent siblings) 3 siblings, 0 replies; 25+ messages in thread From: Joel Brobecker @ 2013-09-05 19:39 UTC (permalink / raw) To: Pedro Alves; +Cc: Yue Lu, Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd > I'm actually very excited to see gdb and gdbserver sharing > a single target backend, even if we still have many wrinkles > in the interfaces to iron out! Mee too! -- Joel ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-05 19:29 ` Pedro Alves 2013-09-05 19:39 ` Joel Brobecker @ 2013-09-05 21:38 ` Thomas Schwinge 2013-09-08 13:35 ` Yue Lu 2013-09-22 12:58 ` Yue Lu 2013-09-06 18:53 ` Pedro Alves 2013-09-09 10:21 ` [PATCH 1/2] Port gdbserver to GNU/Hurd Yue Lu 3 siblings, 2 replies; 25+ messages in thread From: Thomas Schwinge @ 2013-09-05 21:38 UTC (permalink / raw) To: Pedro Alves, Yue Lu; +Cc: gdb-patches, Luis Machado, bug-hurd [-- Attachment #1: Type: text/plain, Size: 7195 bytes --] Hi! Just a very quick one; short on time. On Thu, 05 Sep 2013 20:29:43 +0100, Pedro Alves <palves@redhat.com> wrote: > On 09/05/2013 11:53 AM, Yue Lu wrote: > > This is the my new patch. You've received quite some positive feedback, good! :-) > Thanks. Follows a few comments, by no means an in depth review. Thanks for those reviews -- helps a lot. > We'll probably need to iterate a few times. I'm counting on > Thomas and others to help as well! Yes, but unfortunately not immediatelly. Anyway, the more the code converges towards using the present gnu-nat.c code on the one hand (which I'll try to help with) as well as the present gdbserver code on the other hand (which I don't have experience with, but Pedro has already pointed out several items), the easier it will be to review. And, we've made quite a step forward with this revision of the patch, as far as I can tell! > It'd be very useful if you send and maintain along > with the patch the rationale for all design divergences between > the ports you found necessary. E.g., it seems that gdbserver's > task/proc bookkeeping is different from gdb's. Why? Yes, it'd be useful to have some source code comments next to (some of) the »#ifdef GDBSERVER« (as well as elsewhere, of course). > > --- a/gdb/config/i386/i386gnu.mh > > +++ b/gdb/config/i386/i386gnu.mh > > @@ -1,4 +1,5 @@ > > # Host: Intel 386 running the GNU Hurd > > +ifndef GDBSERVER > > NATDEPFILES= i386gnu-nat.o gnu-nat.o core-regset.o fork-child.o \ > > notify_S.o process_reply_S.o msg_reply_S.o \ > > msg_U.o exc_request_U.o exc_request_S.o > > @@ -12,6 +13,10 @@ XM_CLIBS = -lshouldbeinlibc > > # Use our own user stubs for the msg rpcs, so we can make them time out, in > > # case the program is fucked, or we guess the wrong signal thread. > > msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;' > > +else > > +NATDEPFILES= notify_S.o process_reply_S.o msg_reply_S.o \ > > + exc_request_U.o exc_request_S.o > > +endif Pedro, is the idea that this file should also be shared with gdbserver? Well, probably yes (for the moment), and the idea really is to move the shared bits into common/, as with the other shared code. So, I guess this is fine for the moment. > > --- a/gdb/gnu-nat.c > > +++ b/gdb/gnu-nat.c > > @@ -1,6 +1,7 @@ > > /* Interface GDB to the GNU Hurd. > > Copyright (C) 1992-2013 Free Software Foundation, Inc. > > > > + > > This file is part of GDB. > > Please go through the patch and remove spurious whitespace > changes line these. Yes, this is generally good advise -- I (try to...) re-read every patch I'm about to send by email or directly commit, and avoid any such "spurious" changes. GDB (as other GNU projects, too) tend to set a high standard on code quality, which is good, and this also includes such discipline when doing changes to the code. > > +#ifdef GDBSERVER > > +/* this should move into gnu-i386-low.c ?*/ > > I guess that means i386gnu-nat.c now, but it sounds like > it, yes. > > > +/* Defined in auto-generated file i386.c. */ > > +extern void init_registers_i386 (void); > > +extern const struct target_desc *tdesc_i386; Yes, something with a i386 tag in it can't be in the generic gnu-nat.c file. (Not that there'd be any other GNU Hurd ports available, but you get the idea.) > (correct me if > I'm wrong here), the Hurd's threads are kernel threads Correct. > so it'd > be better to just make the GDB side use the lwp field too. > It's really a simple and mechanic change. Nothing in GDB core > actually cares which field is used. So in this case, it'd be > better if you send a preparatory patch Based on the current upstream master branch. > that does that change > (and nothing else) Confirm that you haven't caused any regressions by running the GDB testsuite (natively) without and then with your change (don't forget to apply the testsuite patch I gave you earlier, to avoid the testsuite hanging (known Hurd issue)), and diff the *.sum files to see that there are no (major) differences (post them with your patch). > and then rebase the port on top of that > patch. Please tell if you need help with how to use Git to rebase your current patch onto the upstream master branch. Also, did you figure out your earlier question about how to merge several Git commits into one? > > /* Attach to process PID, then initialize for debugging it > > and wait for the trace-trap that results from attaching. */ > > +#ifndef GDBSERVER > > static void > > gnu_attach (struct target_ops *ops, char *args, int from_tty) > > { > > @@ -2207,8 +2347,14 @@ gnu_attach (struct target_ops *ops, char *args, > > int from_tty) > > renumber_threads (0); /* Give our threads reasonable names. */ > > #endif > > } > > +#else > > +static int > > +gnu_attach (unsigned long pid) > > +{ > > + return -1; //not support now > > Doesn't look like this should be hard to get going. With the native GDB port, there is a known issue when attaching to a running processes (specifically if that process is currently doing a kernel call (Mach RPC)), so I suggested to not spend time on this functionality for the moment, and we can fix (native GDB) and implement (gdbserver) that it later. > > /* Take a program previously attached to and detaches it. > > The program resumes execution and will no longer stop > > on signals, etc. We'd better not have left any breakpoints > > @@ -2216,6 +2362,7 @@ gnu_attach (struct target_ops *ops, char *args, > > int from_tty) > > to work, it may be necessary for the process to have been > > previously attached. It *might* work if the program was > > started via fork. */ > > +#ifndef GDBSERVER > > static void > > gnu_detach (struct target_ops *ops, char *args, int from_tty) > > { > > @@ -2255,7 +2402,25 @@ gnu_stop (ptid_t ptid) > > { > > error (_("to_stop target function not implemented")); > > } > > +#else > > +static int > > +gnu_detach (int pid) > > +{ > > Eheh, we have detach but not attach. ;-) Even if attaching doesn't, detaching from a process started with gdbserver does work. ;-) > > +static void > > +gnu_request_interrupt (void) > > +{ > > + printf ("gnu_request_interrupt not support!\n"); > > + exit (-1); > > That's quite limiting. :-/ Doesn't sending a SIGINT > work? Please give that a try, but if it's more difficult, I again suggest we finish that later. > > --- a/gdb/gnu-nat.h > > +++ b/gdb/gnu-nat.h > > +#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE > > +#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT > > +#define THREAD_STATE_SET_TRACED(state) \ > > + ((struct i386_thread_state *) (state))->efl |= 0x100 > > +#define THREAD_STATE_CLEAR_TRACED(state) \ > > + ((((struct i386_thread_state *) (state))->efl &= ~0x100), 1) That's again for a i386 file. Further review to come later. Now, please try to address the comments raised (especially also Pedro's), and don't hesitate to ask if there are any questions. Grüße, Thomas [-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-05 21:38 ` Thomas Schwinge @ 2013-09-08 13:35 ` Yue Lu 2013-09-09 9:58 ` Thomas Schwinge 2013-09-22 12:58 ` Yue Lu 1 sibling, 1 reply; 25+ messages in thread From: Yue Lu @ 2013-09-08 13:35 UTC (permalink / raw) To: Thomas Schwinge; +Cc: Pedro Alves, gdb-patches, Luis Machado, bug-hurd Hi, On Fri, Sep 6, 2013 at 5:37 AM, Thomas Schwinge <thomas@codesourcery.com> wrote: >> (correct me if >> I'm wrong here), the Hurd's threads are kernel threads > > Correct. > >> so it'd >> be better to just make the GDB side use the lwp field too. >> It's really a simple and mechanic change. Nothing in GDB core >> actually cares which field is used. So in this case, it'd be >> better if you send a preparatory patch > > Based on the current upstream master branch. > Should I change the gdb use lwp filed instead of tid field? There are too many functions use tid. Like make_proc(),inf_tid_to_thread(),ptid_build(), and there is a field named tid in the structure proc also. We can define a macro for gdbserver to use another ptid_build function to use lwp instead of tid, if this, we only need do a little change. Because of there are a lot of place to improve in my patch, I will submit my next patch a little later. Now I have only finished removing the spurious blank and the soft link. -- Yue Lu (陆岳) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-08 13:35 ` Yue Lu @ 2013-09-09 9:58 ` Thomas Schwinge 2013-09-18 12:12 ` Pedro Alves 0 siblings, 1 reply; 25+ messages in thread From: Thomas Schwinge @ 2013-09-09 9:58 UTC (permalink / raw) To: Yue Lu, Pedro Alves; +Cc: gdb-patches, Luis Machado, bug-hurd [-- Attachment #1: Type: text/plain, Size: 2443 bytes --] Hi! On Sun, 8 Sep 2013 21:35:05 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote: > On Fri, Sep 6, 2013 at 5:37 AM, Thomas Schwinge <thomas@codesourcery.com> wrote: > >> (correct me if > >> I'm wrong here), the Hurd's threads are kernel threads > > > > Correct. > > > >> so it'd > >> be better to just make the GDB side use the lwp field too. > >> It's really a simple and mechanic change. Nothing in GDB core > >> actually cares which field is used. So in this case, it'd be In GDB's parlance, a lightweight process (identified by a LWP) is a thread that always has a corresponding kernel thread, and in contrast a "generic" thread (identified by a TID) is not required to always have a corresponding kernel thread, for example, when managed by a run-time library? Then, yes, conceptually the native Hurd port should be switched to using LWPs instead of TIDs. > >> better if you send a preparatory patch > > > > Based on the current upstream master branch. > > Should I change the gdb use lwp filed instead of tid field? There are > too many functions use tid. Like > make_proc(),inf_tid_to_thread(),ptid_build(), and there is a field > named tid in the structure proc also. As you have found, there is a lot of TID usage in gnu-nat.c. TIDs are assigned based on the next_thread_id variable: /* A variable from which to assign new TIDs. */ static int next_thread_id = 1; [...] /* THREADS[I] is a thread we don't know about yet! */ { ptid_t ptid; thread = make_proc (inf, threads[i], next_thread_id++); Five years ago, we've already concluded this is due for some cleanup, <http://www.gnu.org/software/hurd/open_issues/gdb_thread_ids.html>. But I don't want to require this cleanup to happen before/in context of the Google Summer of Code project's code submission discussed here. > We can define a macro for gdbserver to use another ptid_build function > to use lwp instead of tid, if this, we only need do a little change. That seems like a sensible approach to me, for the moment. And then do the cleanup later on. > Because of there are a lot of place to improve in my patch, I will > submit my next patch a little later. Now I have only finished > removing the spurious blank and the soft link. That's fine. Such tasks always takes longer than expected. ;-) Grüße, Thomas [-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-09 9:58 ` Thomas Schwinge @ 2013-09-18 12:12 ` Pedro Alves 2013-09-18 13:48 ` Yue Lu 0 siblings, 1 reply; 25+ messages in thread From: Pedro Alves @ 2013-09-18 12:12 UTC (permalink / raw) To: Thomas Schwinge; +Cc: Yue Lu, gdb-patches, Luis Machado, bug-hurd On 09/09/2013 10:58 AM, Thomas Schwinge wrote: > Hi! > > On Sun, 8 Sep 2013 21:35:05 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote: >> On Fri, Sep 6, 2013 at 5:37 AM, Thomas Schwinge <thomas@codesourcery.com> wrote: >>>> (correct me if >>>> I'm wrong here), the Hurd's threads are kernel threads >>> >>> Correct. >>> >>>> so it'd >>>> be better to just make the GDB side use the lwp field too. >>>> It's really a simple and mechanic change. Nothing in GDB core >>>> actually cares which field is used. So in this case, it'd be > > In GDB's parlance, a lightweight process (identified by a LWP) is a > thread that always has a corresponding kernel thread, and in contrast a > "generic" thread (identified by a TID) is not required to always have a > corresponding kernel thread, for example, when managed by a run-time > library? Then, yes, conceptually the native Hurd port should be switched > to using LWPs instead of TIDs. > >>>> better if you send a preparatory patch >>> >>> Based on the current upstream master branch. >> >> Should I change the gdb use lwp filed instead of tid field? There are >> too many functions use tid. Like >> make_proc(),inf_tid_to_thread(),ptid_build(), and there is a field >> named tid in the structure proc also. > > As you have found, there is a lot of TID usage in gnu-nat.c. TIDs are > assigned based on the next_thread_id variable: > > /* A variable from which to assign new TIDs. */ > static int next_thread_id = 1; > [...] > /* THREADS[I] is a thread we don't know about yet! */ > { > ptid_t ptid; > > thread = make_proc (inf, threads[i], next_thread_id++); > > Five years ago, we've already concluded this is due for some cleanup, > <http://www.gnu.org/software/hurd/open_issues/gdb_thread_ids.html>. But > I don't want to require this cleanup to happen before/in context of the > Google Summer of Code project's code submission discussed here. That's not what I'm suggesting at all. I'm just talking about storing the thread id in the lwpid field. It's always the target that stores and extracts the fields of a ptid -- the ptid_t struct is mostly opaque to the core. It should really be a small change. (while looking at this, I noticed a bug, and fixed it: http://sourceware.org/ml/gdb-patches/2013-09/msg00579.html) /me gives it a try. I grepped for ptid_build and ptid_get_tid in *gnu* files, and adjusted all I found. ----------- Subject: [PATCH] [Hurd/gnu-nat.c] Use ptid_t.lwpid to store thread ids instead of ptid_t.tid. In preparation for reusing gnu-nat.c in gdbserver, switch to storing thread ids in the lwpid field of ptid_t rather than in the tid field. The Hurd's thread model is 1:1, so it doesn't feel wrong anyway. gdb/ 2013-09-18 Pedro Alves <palves@redhat.com> * gnu-nat.c (inf_validate_procs, gnu_wait, gnu_resume) (gnu_create_inferior) (gnu_attach, gnu_thread_alive, gnu_pid_to_str, cur_thread) (set_sig_thread_cmd): Use the lwpid field of ptids to store the thread id instead of the tid field. --- gdb/gnu-nat.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c index fa55b10..b4f99f8 100644 --- a/gdb/gnu-nat.c +++ b/gdb/gnu-nat.c @@ -1083,7 +1083,7 @@ inf_validate_procs (struct inf *inf) last = thread; proc_debug (thread, "new thread: %d", threads[i]); - ptid = ptid_build (inf->pid, 0, thread->tid); + ptid = ptid_build (inf->pid, thread->tid, 0); /* Tell GDB's generic thread code. */ @@ -1613,17 +1613,17 @@ rewait: thread = inf->wait.thread; if (thread) - ptid = ptid_build (inf->pid, 0, thread->tid); + ptid = ptid_build (inf->pid, thread->tid, 0); else if (ptid_equal (ptid, minus_one_ptid)) thread = inf_tid_to_thread (inf, -1); else - thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); + thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid)); if (!thread || thread->port == MACH_PORT_NULL) { /* TID is dead; try and find a new thread. */ if (inf_update_procs (inf) && inf->threads) - ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first + ptid = ptid_build (inf->pid, inf->threads->tid, 0); /* The first available thread. */ else @@ -2022,7 +2022,7 @@ gnu_resume (struct target_ops *ops, else /* Just allow a single thread to run. */ { - struct proc *thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); + struct proc *thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid)); if (!thread) error (_("Can't run single thread id %s: no such thread!"), @@ -2033,7 +2033,7 @@ gnu_resume (struct target_ops *ops, if (step) { - step_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); + step_thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid)); if (!step_thread) warning (_("Can't step thread id %s: no such thread."), target_pid_to_str (ptid)); @@ -2133,7 +2133,7 @@ gnu_create_inferior (struct target_ops *ops, /* We now have thread info. */ thread_change_ptid (inferior_ptid, - ptid_build (inf->pid, 0, inf_pick_first_thread ())); + ptid_build (inf->pid, inf_pick_first_thread (), 0)); startup_inferior (inf->pending_execs); @@ -2190,7 +2190,7 @@ gnu_attach (struct target_ops *ops, char *args, int from_tty) inf_update_procs (inf); - inferior_ptid = ptid_build (pid, 0, inf_pick_first_thread ()); + inferior_ptid = ptid_build (pid, inf_pick_first_thread (), 0); /* We have to initialize the terminal settings now, since the code below might try to restore them. */ @@ -2261,7 +2261,7 @@ gnu_thread_alive (struct target_ops *ops, ptid_t ptid) { inf_update_procs (gnu_current_inf); return !!inf_tid_to_thread (gnu_current_inf, - ptid_get_tid (ptid)); + ptid_get_lwp (ptid)); } \f @@ -2596,7 +2596,7 @@ static char * gnu_pid_to_str (struct target_ops *ops, ptid_t ptid) { struct inf *inf = gnu_current_inf; - int tid = ptid_get_tid (ptid); + int tid = ptid_get_lwp (ptid); struct proc *thread = inf_tid_to_thread (inf, tid); if (thread) @@ -2729,7 +2729,7 @@ cur_thread (void) { struct inf *inf = cur_inf (); struct proc *thread = inf_tid_to_thread (inf, - ptid_get_tid (inferior_ptid)); + ptid_get_lwp (inferior_ptid)); if (!thread) error (_("No current thread.")); return thread; @@ -2928,7 +2928,7 @@ set_sig_thread_cmd (char *args, int from_tty) error (_("Thread ID %s not known. " "Use the \"info threads\" command to\n" "see the IDs of currently known threads."), args); - inf->signal_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); + inf->signal_thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid)); } } -- 1.7.11.7 ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-18 12:12 ` Pedro Alves @ 2013-09-18 13:48 ` Yue Lu 2013-09-18 14:52 ` [Hurd/gnu-nat.c] Use ptid_t.lwpid to store, thread ids instead of ptid_t.tid. (was: Re: [PATCH 1/2] Port gdbserver to GNU/Hurd) Pedro Alves 2013-09-18 14:57 ` [PATCH 1/2] Port gdbserver to GNU/Hurd Pedro Alves 0 siblings, 2 replies; 25+ messages in thread From: Yue Lu @ 2013-09-18 13:48 UTC (permalink / raw) To: Pedro Alves; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd Hi, On Wed, Sep 18, 2013 at 8:11 PM, Pedro Alves <palves@redhat.com> wrote: > On 09/09/2013 10:58 AM, Thomas Schwinge wrote: >> Hi! >> >> On Sun, 8 Sep 2013 21:35:05 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote: >>> On Fri, Sep 6, 2013 at 5:37 AM, Thomas Schwinge <thomas@codesourcery.com> wrote: >>>>> (correct me if >>>>> I'm wrong here), the Hurd's threads are kernel threads >>>> >>>> Correct. >>>> >>>>> so it'd >>>>> be better to just make the GDB side use the lwp field too. >>>>> It's really a simple and mechanic change. Nothing in GDB core >>>>> actually cares which field is used. So in this case, it'd be >> >> In GDB's parlance, a lightweight process (identified by a LWP) is a >> thread that always has a corresponding kernel thread, and in contrast a >> "generic" thread (identified by a TID) is not required to always have a >> corresponding kernel thread, for example, when managed by a run-time >> library? Then, yes, conceptually the native Hurd port should be switched >> to using LWPs instead of TIDs. >> >>>>> better if you send a preparatory patch >>>> >>>> Based on the current upstream master branch. >>> >>> Should I change the gdb use lwp filed instead of tid field? There are >>> too many functions use tid. Like >>> make_proc(),inf_tid_to_thread(),ptid_build(), and there is a field >>> named tid in the structure proc also. >> >> As you have found, there is a lot of TID usage in gnu-nat.c. TIDs are >> assigned based on the next_thread_id variable: >> >> /* A variable from which to assign new TIDs. */ >> static int next_thread_id = 1; >> [...] >> /* THREADS[I] is a thread we don't know about yet! */ >> { >> ptid_t ptid; >> >> thread = make_proc (inf, threads[i], next_thread_id++); >> >> Five years ago, we've already concluded this is due for some cleanup, >> <http://www.gnu.org/software/hurd/open_issues/gdb_thread_ids.html>. But >> I don't want to require this cleanup to happen before/in context of the >> Google Summer of Code project's code submission discussed here. > > That's not what I'm suggesting at all. I'm just talking about storing > the thread id in the lwpid field. It's always the target that > stores and extracts the fields of a ptid -- the ptid_t struct is mostly > opaque to the core. It should really be a small change. > > (while looking at this, I noticed a bug, and fixed it: > http://sourceware.org/ml/gdb-patches/2013-09/msg00579.html) > > /me gives it a try. > > I grepped for ptid_build and ptid_get_tid in *gnu* files, and > adjusted all I found. I have tried this way before, but it doesn't work. After apply your patch, the gdb can't use, it says "Can't fetch registers from thread Thread 29826.3: No such thread". (btw, with unknown reason, I can't patch your patch automatically, I have to modify the gnu-nat.c line by line according to your patch). As before, I thought it is a big problem, so I don't dig into it. Your last email has reminder me, both you and I forgot to patch the i386gnu-nat.c which also used the tid filed. Add this everything is ok. diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c index 0fd8d91..2b93fee 100644 --- a/gdb/i386gnu-nat.c +++ b/gdb/i386gnu-nat.c @@ -132,7 +132,7 @@ gnu_fetch_registers (struct target_ops *ops, inf_update_procs (gnu_current_inf); thread = inf_tid_to_thread (gnu_current_inf, - ptid_get_tid (inferior_ptid)); + ptid_get_lwp (inferior_ptid)); if (!thread) error (_("Can't fetch registers from thread %s: No such thread"), target_pid_to_str (inferior_ptid)); @@ -225,7 +225,7 @@ gnu_store_registers (struct target_ops *ops, inf_update_procs (gnu_current_inf); thread = inf_tid_to_thread (gnu_current_inf, - ptid_get_tid (inferior_ptid)); + ptid_get_lwp (inferior_ptid)); if (!thread) error (_("Couldn't store registers into thread %s: No such thread"), target_pid_to_str (inferior_ptid)); -- Yue Lu (陆岳) ^ permalink raw reply [flat|nested] 25+ messages in thread
* [Hurd/gnu-nat.c] Use ptid_t.lwpid to store, thread ids instead of ptid_t.tid. (was: Re: [PATCH 1/2] Port gdbserver to GNU/Hurd) 2013-09-18 13:48 ` Yue Lu @ 2013-09-18 14:52 ` Pedro Alves 2013-09-18 14:57 ` [PATCH 1/2] Port gdbserver to GNU/Hurd Pedro Alves 1 sibling, 0 replies; 25+ messages in thread From: Pedro Alves @ 2013-09-18 14:52 UTC (permalink / raw) To: Yue Lu; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd On 09/18/2013 02:48 PM, Yue Lu wrote: > On Wed, Sep 18, 2013 at 8:11 PM, Pedro Alves <palves@redhat.com> wrote: >> >> /me gives it a try. >> >> I grepped for ptid_build and ptid_get_tid in *gnu* files, and >> adjusted all I found. > > I have tried this way before, but it doesn't work. > After apply your patch, the gdb can't use, it says "Can't fetch > registers from thread Thread 29826.3: No such thread". ... > As before, I thought it is a big problem, so I don't dig into it. Your > last email has reminder me, both you and I forgot to patch the > i386gnu-nat.c which also used the tid filed. Eh, grep-fail then. > > Add this everything is ok. Nice, thanks. I've merged that in, and applied it. --------- Subject: [Hurd/gnu-nat.c] Use ptid_t.lwpid to store thread ids instead of ptid_t.tid. In preparation for reusing gnu-nat.c in gdbserver, switch to storing thread ids in the lwpid field of ptid_t rather than in the tid field. The Hurd's thread model is 1:1, so it doesn't feel wrong anyway. gdb/ 2013-09-18 Pedro Alves <palves@redhat.com> Yue Lu <hacklu.newborn@gmail.com> * gnu-nat.c (inf_validate_procs, gnu_wait, gnu_resume) (gnu_create_inferior) (gnu_attach, gnu_thread_alive, gnu_pid_to_str, cur_thread) (set_sig_thread_cmd): Use the lwpid field of ptids to store/extract thread ids instead of the tid field. * i386gnu-nat.c (gnu_fetch_registers): Adjust. --- gdb/gnu-nat.c | 24 ++++++++++++------------ gdb/i386gnu-nat.c | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c index fa55b10..b4f99f8 100644 --- a/gdb/gnu-nat.c +++ b/gdb/gnu-nat.c @@ -1083,7 +1083,7 @@ inf_validate_procs (struct inf *inf) last = thread; proc_debug (thread, "new thread: %d", threads[i]); - ptid = ptid_build (inf->pid, 0, thread->tid); + ptid = ptid_build (inf->pid, thread->tid, 0); /* Tell GDB's generic thread code. */ @@ -1613,17 +1613,17 @@ rewait: thread = inf->wait.thread; if (thread) - ptid = ptid_build (inf->pid, 0, thread->tid); + ptid = ptid_build (inf->pid, thread->tid, 0); else if (ptid_equal (ptid, minus_one_ptid)) thread = inf_tid_to_thread (inf, -1); else - thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); + thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid)); if (!thread || thread->port == MACH_PORT_NULL) { /* TID is dead; try and find a new thread. */ if (inf_update_procs (inf) && inf->threads) - ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first + ptid = ptid_build (inf->pid, inf->threads->tid, 0); /* The first available thread. */ else @@ -2022,7 +2022,7 @@ gnu_resume (struct target_ops *ops, else /* Just allow a single thread to run. */ { - struct proc *thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); + struct proc *thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid)); if (!thread) error (_("Can't run single thread id %s: no such thread!"), @@ -2033,7 +2033,7 @@ gnu_resume (struct target_ops *ops, if (step) { - step_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); + step_thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid)); if (!step_thread) warning (_("Can't step thread id %s: no such thread."), target_pid_to_str (ptid)); @@ -2133,7 +2133,7 @@ gnu_create_inferior (struct target_ops *ops, /* We now have thread info. */ thread_change_ptid (inferior_ptid, - ptid_build (inf->pid, 0, inf_pick_first_thread ())); + ptid_build (inf->pid, inf_pick_first_thread (), 0)); startup_inferior (inf->pending_execs); @@ -2190,7 +2190,7 @@ gnu_attach (struct target_ops *ops, char *args, int from_tty) inf_update_procs (inf); - inferior_ptid = ptid_build (pid, 0, inf_pick_first_thread ()); + inferior_ptid = ptid_build (pid, inf_pick_first_thread (), 0); /* We have to initialize the terminal settings now, since the code below might try to restore them. */ @@ -2261,7 +2261,7 @@ gnu_thread_alive (struct target_ops *ops, ptid_t ptid) { inf_update_procs (gnu_current_inf); return !!inf_tid_to_thread (gnu_current_inf, - ptid_get_tid (ptid)); + ptid_get_lwp (ptid)); } \f @@ -2596,7 +2596,7 @@ static char * gnu_pid_to_str (struct target_ops *ops, ptid_t ptid) { struct inf *inf = gnu_current_inf; - int tid = ptid_get_tid (ptid); + int tid = ptid_get_lwp (ptid); struct proc *thread = inf_tid_to_thread (inf, tid); if (thread) @@ -2729,7 +2729,7 @@ cur_thread (void) { struct inf *inf = cur_inf (); struct proc *thread = inf_tid_to_thread (inf, - ptid_get_tid (inferior_ptid)); + ptid_get_lwp (inferior_ptid)); if (!thread) error (_("No current thread.")); return thread; @@ -2928,7 +2928,7 @@ set_sig_thread_cmd (char *args, int from_tty) error (_("Thread ID %s not known. " "Use the \"info threads\" command to\n" "see the IDs of currently known threads."), args); - inf->signal_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); + inf->signal_thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid)); } } diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c index 0fd8d91..2b93fee 100644 --- a/gdb/i386gnu-nat.c +++ b/gdb/i386gnu-nat.c @@ -132,7 +132,7 @@ gnu_fetch_registers (struct target_ops *ops, inf_update_procs (gnu_current_inf); thread = inf_tid_to_thread (gnu_current_inf, - ptid_get_tid (inferior_ptid)); + ptid_get_lwp (inferior_ptid)); if (!thread) error (_("Can't fetch registers from thread %s: No such thread"), target_pid_to_str (inferior_ptid)); @@ -225,7 +225,7 @@ gnu_store_registers (struct target_ops *ops, inf_update_procs (gnu_current_inf); thread = inf_tid_to_thread (gnu_current_inf, - ptid_get_tid (inferior_ptid)); + ptid_get_lwp (inferior_ptid)); if (!thread) error (_("Couldn't store registers into thread %s: No such thread"), target_pid_to_str (inferior_ptid)); -- 1.7.11.7 ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-18 13:48 ` Yue Lu 2013-09-18 14:52 ` [Hurd/gnu-nat.c] Use ptid_t.lwpid to store, thread ids instead of ptid_t.tid. (was: Re: [PATCH 1/2] Port gdbserver to GNU/Hurd) Pedro Alves @ 2013-09-18 14:57 ` Pedro Alves 1 sibling, 0 replies; 25+ messages in thread From: Pedro Alves @ 2013-09-18 14:57 UTC (permalink / raw) To: Yue Lu; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd On 09/18/2013 02:48 PM, Yue Lu wrote: > (btw, with > unknown reason, I can't patch your patch automatically, I have to > modify the gnu-nat.c line by line according to your patch). I'm going to guess you copy/pasted the patch to a new file, and while doing that, something (your editor or mailer?) line-wrapped the patch. I just now tried saving the whole email as an mbox file, and then applied it to a pristine tree with "git am", and saw no issues. -- Pedro Alves ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-05 21:38 ` Thomas Schwinge 2013-09-08 13:35 ` Yue Lu @ 2013-09-22 12:58 ` Yue Lu 1 sibling, 0 replies; 25+ messages in thread From: Yue Lu @ 2013-09-22 12:58 UTC (permalink / raw) To: Thomas Schwinge; +Cc: Pedro Alves, gdb-patches, Luis Machado, bug-hurd Hi! On Thu, Sep 05, 2013 at 11:37:36PM +0200, Thomas Schwinge wrote: > Confirm that you haven't caused any regressions by running the GDB > testsuite (natively) without and then with your change (don't forget to > apply the testsuite patch I gave you earlier, to avoid the testsuite > hanging (known Hurd issue)), and diff the *.sum files to see that there > are no (major) differences (post them with your patch). > These days I have try to run the testcase server times( And I have found there are 5 cases got failed or passed just by chance.) I have found this, when apply my patch, the native gdb seems pass more tests and failed more too :/ What's more, the gdbserver can't finish the testcase, it just just complain make error and stoped. Like this: === gdb Summary === # of expected passes 21731 # of unexpected failures 659 # of unexpected successes 1 # of expected failures 31 # of known failures 75 # of unresolved testcases 12 # of untested testcases 2594 # of unsupported tests 265 /home/hacklu/code/gdb/build.gdbserver/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdbserver/gdb/testsuite/../data-directory make[1]: *** [check-single] Error 1 make[1]: Leaving directory `/home/hacklu/code/gdb/build.gdbserver/gdb/testsuite' make: *** [check] Error 2 I do the check according to native-gdbserver.exp's comment. It is the whole diff file between upstream branch and the one plus my patch below. (ps: the build.git2 contains the upstream one, and build.gdb3 contains the topic one). --- build.git2/gdb/testsuite/gdb.base1/gdb.sum 2013-09-18 21:10:20.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.base1/gdb.sum 2013-09-21 22:01:37.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 20:56:22 2013 +Test Run By hacklu on Sat Sep 21 21:47:36 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -3679,7 +3679,7 @@ PASS: gdb.base/cvexpr.exp: (struct t_struct const * const) PASS: gdb.base/cvexpr.exp: (union t_union const * const) Running ../../../gdb/testsuite/gdb.base/comprdebug.exp ... -ERROR: Couldn't load /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.base/comprdebug0.o into /home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb. +ERROR: Couldn't load /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.base/comprdebug0.o into /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb. UNRESOLVED: gdb.base/comprdebug.exp: file comprdebug0.o Running ../../../gdb/testsuite/gdb.base/call-ar-st.exp ... PASS: gdb.base/call-ar-st.exp: set print sevenbit-strings @@ -4918,5 +4918,5 @@ # of unresolved testcases 1 # of untested testcases 5 # of unsupported tests 16 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.ada/gdb.sum 2013-09-18 21:24:02.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.ada/gdb.sum 2013-09-21 22:15:28.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:23:49 2013 +Test Run By hacklu on Sat Sep 21 22:15:18 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -188,5 +188,5 @@ # of expected passes 10 # of untested testcases 1 # of unsupported tests 80 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.arch/gdb.sum 2013-09-18 21:24:41.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.arch/gdb.sum 2013-09-21 22:16:04.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:24:04 2013 +Test Run By hacklu on Sat Sep 21 22:15:30 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -257,5 +257,5 @@ # of expected passes 144 # of unexpected failures 41 # of known failures 1 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.asm/gdb.sum 2013-09-18 21:28:55.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.asm/gdb.sum 2013-09-21 22:20:20.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:24:42 2013 +Test Run By hacklu on Sat Sep 21 22:16:05 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -41,5 +41,5 @@ # of expected passes 3 # of unexpected failures 25 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.btrace/gdb.sum 2013-09-18 21:28:58.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.btrace/gdb.sum 2013-09-21 22:20:25.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:28:55 2013 +Test Run By hacklu on Sat Sep 21 22:20:21 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -13,5 +13,5 @@ === gdb Summary === -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.cell/gdb.sum 2013-09-18 21:28:59.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.cell/gdb.sum 2013-09-21 22:20:27.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:28:58 2013 +Test Run By hacklu on Sat Sep 21 22:20:26 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -28,5 +28,5 @@ === gdb Summary === -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.cp/gdb.sum 2013-09-18 21:38:20.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.cp/gdb.sum 2013-09-21 22:29:27.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:29:00 2013 +Test Run By hacklu on Sat Sep 21 22:20:28 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -4190,5 +4190,5 @@ # of known failures 20 # of untested testcases 1 # of unsupported tests 1 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.disasm/gdb.sum 2013-09-18 21:38:23.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.disasm/gdb.sum 2013-09-21 22:29:30.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:38:21 2013 +Test Run By hacklu on Sat Sep 21 22:29:28 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -28,5 +28,5 @@ === gdb Summary === -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.dwarf2/gdb.sum 2013-09-18 21:41:30.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.dwarf2/gdb.sum 2013-09-21 22:32:26.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:38:24 2013 +Test Run By hacklu on Sat Sep 21 22:29:31 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -32,7 +32,7 @@ PASS: gdb.dwarf2/dw2-bad-parameter-type.exp: ptype f PASS: gdb.dwarf2/dw2-bad-parameter-type.exp: is alive Running ../../../gdb/testsuite/gdb.dwarf2/dw2-basic.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/dw2-basic.exp: set listsize 1 FAIL: gdb.dwarf2/dw2-basic.exp: list func_cu1 PASS: gdb.dwarf2/dw2-basic.exp: ptype func_cu1 @@ -54,7 +54,7 @@ PASS: gdb.dwarf2/dw2-compdir-oldgcc.exp: list gcc43 PASS: gdb.dwarf2/dw2-compdir-oldgcc.exp: info source gcc43 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-compressed.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/dw2-compressed.exp: set listsize 1 FAIL: gdb.dwarf2/dw2-compressed.exp: list func_cu1 PASS: gdb.dwarf2/dw2-compressed.exp: ptype func_cu1 @@ -328,13 +328,13 @@ PASS: gdb.dwarf2/dw2-inline-param.exp: info addr break_at PASS: gdb.dwarf2/dw2-inline-param.exp: bt Running ../../../gdb/testsuite/gdb.dwarf2/dw2-intercu.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/dw2-intercu.exp: ptype int2 PASS: gdb.dwarf2/dw2-intercu.exp: set listsize 1 FAIL: gdb.dwarf2/dw2-intercu.exp: list func_cu1 PASS: gdb.dwarf2/dw2-intercu.exp: ptype func_cu1 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-intermix.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/dw2-intermix.exp: set listsize 1 FAIL: gdb.dwarf2/dw2-intermix.exp: list func_cu1 PASS: gdb.dwarf2/dw2-intermix.exp: ptype func_cu1 @@ -439,7 +439,7 @@ Running ../../../gdb/testsuite/gdb.dwarf2/dw2-param-error.exp ... PASS: gdb.dwarf2/dw2-param-error.exp: frame Running ../../../gdb/testsuite/gdb.dwarf2/dw2-producer.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/dw2-producer.exp: set listsize 1 FAIL: gdb.dwarf2/dw2-producer.exp: list func_cu1 PASS: gdb.dwarf2/dw2-producer.exp: ptype func_cu1 @@ -547,7 +547,7 @@ Running ../../../gdb/testsuite/gdb.dwarf2/implptrpiece.exp ... PASS: gdb.dwarf2/implptrpiece.exp: print/d p[-1] Running ../../../gdb/testsuite/gdb.dwarf2/mac-fileno.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/mac-fileno.exp: set listsize 1 FAIL: gdb.dwarf2/mac-fileno.exp: list func_cu1 PASS: gdb.dwarf2/mac-fileno.exp: ptype func_cu1 @@ -658,5 +658,5 @@ # of unresolved testcases 6 # of untested testcases 9 # of unsupported tests 1 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.fortran/gdb.sum 2013-09-18 21:42:09.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.fortran/gdb.sum 2013-09-21 22:33:01.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:41:31 2013 +Test Run By hacklu on Sat Sep 21 22:32:27 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -269,5 +269,5 @@ # of expected passes 243 # of unexpected failures 2 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.go/gdb.sum 2013-09-18 21:44:23.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.go/gdb.sum 2013-09-21 22:35:15.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:44:17 2013 +Test Run By hacklu on Sat Sep 21 22:35:10 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -90,5 +90,5 @@ # of expected passes 44 # of expected failures 4 # of untested testcases 9 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.server/gdb.sum 2013-09-18 21:50:17.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.server/gdb.sum 2013-09-21 22:41:15.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:50:16 2013 +Test Run By hacklu on Sat Sep 21 22:40:35 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -8,16 +8,85 @@ Running target unix Running ../../../gdb/testsuite/gdb.server/ext-attach.exp ... +PASS: gdb.server/ext-attach.exp: disconnect +PASS: gdb.server/ext-attach.exp: set remote exec-file +FAIL: gdb.server/ext-attach.exp: attach to remote program 1 +FAIL: gdb.server/ext-attach.exp: backtrace 1 +FAIL: gdb.server/ext-attach.exp: detach (the program is no longer running) +PASS: gdb.server/ext-attach.exp: backtrace with no program +FAIL: gdb.server/ext-attach.exp: attach to remote program 2 +FAIL: gdb.server/ext-attach.exp: backtrace 2 +PASS: gdb.server/ext-attach.exp: kill +PASS: gdb.server/ext-attach.exp: monitor exit Running ../../../gdb/testsuite/gdb.server/ext-run.exp ... +PASS: gdb.server/ext-run.exp: disconnect +PASS: gdb.server/ext-run.exp: set remote exec-file +PASS: gdb.server/ext-run.exp: continue to main +PASS: gdb.server/ext-run.exp: kill +PASS: gdb.server/ext-run.exp: load new file without any gdbserver inferior +PASS: gdb.server/ext-run.exp: monitor exit Running ../../../gdb/testsuite/gdb.server/file-transfer.exp ... +PASS: gdb.server/file-transfer.exp: disconnect +PASS: gdb.server/file-transfer.exp: put binary file +FAIL: gdb.server/file-transfer.exp: get binary file +PASS: gdb.server/file-transfer.exp: compare intermediate binary file +FAIL: gdb.server/file-transfer.exp: compare binary file +FAIL: gdb.server/file-transfer.exp: deleted binary file +FAIL: gdb.server/file-transfer.exp: verified deleted binary file +FAIL: gdb.server/file-transfer.exp: put text file +FAIL: gdb.server/file-transfer.exp: get text file +FAIL: gdb.server/file-transfer.exp: compare intermediate text file +FAIL: gdb.server/file-transfer.exp: compare text file +FAIL: gdb.server/file-transfer.exp: deleted text file +FAIL: gdb.server/file-transfer.exp: verified deleted text file Running ../../../gdb/testsuite/gdb.server/no-thread-db.exp ... +PASS: gdb.server/no-thread-db.exp: successfully compiled posix threads test case +PASS: gdb.server/no-thread-db.exp: disconnect +FAIL: gdb.server/no-thread-db.exp: libthread-db is now unresolvable +PASS: gdb.server/no-thread-db.exp: continue to breakpoint: after tls assignment +FAIL: gdb.server/no-thread-db.exp: print foo Running ../../../gdb/testsuite/gdb.server/server-exec-info.exp ... +PASS: gdb.server/server-exec-info.exp: file +PASS: gdb.server/server-exec-info.exp: set sysroot remote: +FAIL: gdb.server/server-exec-info.exp: info files Running ../../../gdb/testsuite/gdb.server/server-kill.exp ... +PASS: gdb.server/server-kill.exp: disconnect +FAIL: gdb.server/server-kill.exp: tstatus Running ../../../gdb/testsuite/gdb.server/server-mon.exp ... +PASS: gdb.server/server-mon.exp: disconnect +PASS: gdb.server/server-mon.exp: monitor help +PASS: gdb.server/server-mon.exp: monitor +PASS: gdb.server/server-mon.exp: monitor set debug 1 +PASS: gdb.server/server-mon.exp: monitor set debug 0 +PASS: gdb.server/server-mon.exp: monitor set remote-debug 1 +PASS: gdb.server/server-mon.exp: monitor set remote-debug 0 Running ../../../gdb/testsuite/gdb.server/server-run.exp ... +PASS: gdb.server/server-run.exp: disconnect +PASS: gdb.server/server-run.exp: continue to main Running ../../../gdb/testsuite/gdb.server/solib-list.exp ... +PASS: gdb.server/solib-list.exp: non-stop 0: disconnect +PASS: gdb.server/solib-list.exp: non-stop 0: set non-stop 0 +PASS: gdb.server/solib-list.exp: non-stop 0: set target-async 0 +PASS: gdb.server/solib-list.exp: non-stop 0: set displaced-stepping off +PASS: gdb.server/solib-list.exp: non-stop 0: file binfile +PASS: gdb.server/solib-list.exp: non-stop 0: target remote +PASS: gdb.server/solib-list.exp: non-stop 0: continue +PASS: gdb.server/solib-list.exp: non-stop 0: sharedlibrary +PASS: gdb.server/solib-list.exp: non-stop 0: p libvar +PASS: gdb.server/solib-list.exp: non-stop 1: disconnect +PASS: gdb.server/solib-list.exp: non-stop 1: set non-stop 1 +PASS: gdb.server/solib-list.exp: non-stop 1: set target-async 1 +PASS: gdb.server/solib-list.exp: non-stop 1: set displaced-stepping off +PASS: gdb.server/solib-list.exp: non-stop 1: file binfile +PASS: gdb.server/solib-list.exp: non-stop 1: target remote +FAIL: gdb.server/solib-list.exp: non-stop 1: non-stop interior stop (timeout) +FAIL: gdb.server/solib-list.exp: non-stop 1: continue (the program is no longer running) +PASS: gdb.server/solib-list.exp: non-stop 1: sharedlibrary +FAIL: gdb.server/solib-list.exp: non-stop 1: p libvar === gdb Summary === -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +# of expected passes 45 +# of unexpected failures 22 +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.java/gdb.sum 2013-09-18 21:44:26.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.java/gdb.sum 2013-09-21 22:35:18.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:44:24 2013 +Test Run By hacklu on Sat Sep 21 22:35:15 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -84,5 +84,5 @@ # of expected passes 60 # of untested testcases 1 # of unsupported tests 4 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.linespec/gdb.sum 2013-09-18 21:45:13.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.linespec/gdb.sum 2013-09-21 22:35:47.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:44:27 2013 +Test Run By hacklu on Sat Sep 21 22:35:19 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -222,5 +222,5 @@ === gdb Summary === # of expected passes 204 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.mi/gdb.sum 2013-09-18 21:48:21.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.mi/gdb.sum 2013-09-21 22:38:42.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:45:14 2013 +Test Run By hacklu on Sat Sep 21 22:35:48 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -331,6 +331,12 @@ PASS: gdb.mi/mi-eval.exp: eval A+3 PASS: gdb.mi/mi-eval.exp: eval A + 3 Running ../../../gdb/testsuite/gdb.mi/mi-file-transfer.exp ... +PASS: gdb.mi/mi-file-transfer.exp: put binary file +FAIL: gdb.mi/mi-file-transfer.exp: get binary file +PASS: gdb.mi/mi-file-transfer.exp: compare intermediate binary file +FAIL: gdb.mi/mi-file-transfer.exp: compare binary file +FAIL: gdb.mi/mi-file-transfer.exp: deleted binary file +FAIL: gdb.mi/mi-file-transfer.exp: verified deleted binary file Running ../../../gdb/testsuite/gdb.mi/mi-file.exp ... PASS: gdb.mi/mi-file.exp: request path info of current source file (basics.c) PASS: gdb.mi/mi-file.exp: Getting a list of source files. @@ -1779,11 +1785,11 @@ === gdb Summary === -# of expected passes 1654 -# of unexpected failures 29 +# of expected passes 1656 +# of unexpected failures 33 # of unexpected successes 1 # of expected failures 8 # of known failures 6 # of unsupported tests 9 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.modula2/gdb.sum 2013-09-18 21:48:25.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.modula2/gdb.sum 2013-09-21 22:38:46.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:48:22 2013 +Test Run By hacklu on Sat Sep 21 22:38:43 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -20,5 +20,5 @@ === gdb Summary === # of expected passes 8 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.multi/gdb.sum 2013-09-18 21:48:34.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.multi/gdb.sum 2013-09-21 22:38:56.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:48:26 2013 +Test Run By hacklu on Sat Sep 21 22:38:47 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -63,5 +63,5 @@ # of expected passes 31 # of unexpected failures 10 # of untested testcases 2 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.objc/gdb.sum 2013-09-18 21:48:39.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.objc/gdb.sum 2013-09-21 22:39:01.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:48:35 2013 +Test Run By hacklu on Sat Sep 21 22:38:57 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -32,5 +32,5 @@ # of expected passes 13 # of unsupported tests 3 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.opencl/gdb.sum 2013-09-18 21:48:44.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.opencl/gdb.sum 2013-09-21 22:39:05.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:48:40 2013 +Test Run By hacklu on Sat Sep 21 22:39:02 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -15,5 +15,5 @@ === gdb Summary === -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.opt/gdb.sum 2013-09-18 21:49:03.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.opt/gdb.sum 2013-09-21 22:39:23.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:48:45 2013 +Test Run By hacklu on Sat Sep 21 22:39:05 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -115,5 +115,5 @@ # of expected passes 95 # of expected failures 1 # of known failures 1 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.pascal/gdb.sum 2013-09-18 21:49:05.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.pascal/gdb.sum 2013-09-21 22:39:26.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:49:04 2013 +Test Run By hacklu on Sat Sep 21 22:39:24 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -50,5 +50,5 @@ # of known failures 1 # of untested testcases 2 # of unsupported tests 4 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.python/gdb.sum 2013-09-18 21:50:14.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.python/gdb.sum 2013-09-21 22:40:32.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:49:07 2013 +Test Run By hacklu on Sat Sep 21 22:39:26 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -96,5 +96,5 @@ # of expected passes 2 # of unsupported tests 41 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.reverse/gdb.sum 2013-09-18 21:50:16.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.reverse/gdb.sum 2013-09-21 22:40:34.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:50:15 2013 +Test Run By hacklu on Sat Sep 21 22:40:33 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -37,5 +37,5 @@ === gdb Summary === -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.stabs/gdb.sum 2013-09-18 21:50:33.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.stabs/gdb.sum 2013-09-21 22:41:29.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:50:18 2013 +Test Run By hacklu on Sat Sep 21 22:41:16 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -234,5 +234,5 @@ # of expected passes 212 # of expected failures 7 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.threads/gdb.sum 2013-09-18 22:02:21.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.threads/gdb.sum 2013-09-21 22:53:16.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:50:34 2013 +Test Run By hacklu on Sat Sep 21 22:41:30 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -463,5 +463,5 @@ # of unresolved testcases 1 # of untested testcases 3 # of unsupported tests 9 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.trace/gdb.sum 2013-09-18 22:03:51.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.trace/gdb.sum 2013-09-21 22:54:48.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 22:02:21 2013 +Test Run By hacklu on Sat Sep 21 22:53:17 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -300,7 +300,7 @@ PASS: gdb.trace/tracecmd.exp: 1.14: help trace PASS: gdb.trace/tracecmd.exp: Declined to set a fast tracepoint Running ../../../gdb/testsuite/gdb.trace/tspeed.exp ... -gdb compile failed, gcc: error: /home/hacklu/code/gdb/build.git2/gdb/testsuite/../gdbserver/libinproctrace.so: No such file or directory +gdb compile failed, gcc: error: /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../gdbserver/libinproctrace.so: No such file or directory UNTESTED: gdb.trace/tspeed.exp: tspeed.exp Running ../../../gdb/testsuite/gdb.trace/tstatus.exp ... UNSUPPORTED: gdb.trace/tstatus.exp: target does not support trace @@ -343,5 +343,5 @@ # of expected passes 251 # of untested testcases 3 # of unsupported tests 32 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.xml/gdb.sum 2013-09-18 22:03:53.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.xml/gdb.sum 2013-09-21 22:54:51.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 22:03:52 2013 +Test Run By hacklu on Sat Sep 21 22:54:49 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -21,5 +21,5 @@ === gdb Summary === # of unsupported tests 5 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.base2/gdb.sum 2013-09-18 21:23:48.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.base2/gdb.sum 2013-09-21 22:15:17.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:10:21 2013 +Test Run By hacklu on Sat Sep 21 22:01:39 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -4255,5 +4255,5 @@ # of known failures 2 # of untested testcases 7 # of unsupported tests 4 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.gdb/gdb.sum 2013-09-18 21:44:16.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.gdb/gdb.sum 2013-09-21 22:35:09.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 21:42:10 2013 +Test Run By hacklu on Sat Sep 21 22:33:02 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -171,7 +171,7 @@ PASS: gdb.gdb/selftest.exp: Set xgdb prompt PASS: gdb.gdb/selftest.exp: send ^C to child process PASS: gdb.gdb/selftest.exp: send SIGINT signal to child process -PASS: gdb.gdb/selftest.exp: backtrace through signal handler +FAIL: gdb.gdb/selftest.exp: backtrace through signal handler (timeout) Running ../../../gdb/testsuite/gdb.gdb/xfullpath.exp ... PASS: gdb.gdb/xfullpath.exp: breakpoint in captured_main PASS: gdb.gdb/xfullpath.exp: run until breakpoint at captured_main @@ -185,8 +185,8 @@ === gdb Summary === -# of expected passes 165 -# of unexpected failures 3 +# of expected passes 164 +# of unexpected failures 4 # of unsupported tests 1 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory --- build.git2/gdb/testsuite/gdb.sum 2013-09-18 22:04:53.000000000 +0800 +++ build.gdb3/gdb/testsuite/gdb.sum 2013-09-21 22:55:52.000000000 +0800 @@ -1,4 +1,4 @@ -Test Run By hacklu on Wed Sep 18 20:56:22 2013 +Test Run By hacklu on Sat Sep 21 21:47:36 2013 Native configuration is i686-unknown-gnu0.3 === gdb tests === @@ -2231,7 +2231,7 @@ PASS: gdb.base/complex.exp: print complex packed value in C PASS: gdb.base/complex.exp: print complex value in C Running ../../../gdb/testsuite/gdb.base/comprdebug.exp ... -ERROR: Couldn't load /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.base/comprdebug0.o into /home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb. +ERROR: Couldn't load /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.base/comprdebug0.o into /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb. UNRESOLVED: gdb.base/comprdebug.exp: file comprdebug0.o Running ../../../gdb/testsuite/gdb.base/condbreak.exp ... PASS: gdb.base/condbreak.exp: breakpoint function @@ -13833,7 +13833,7 @@ PASS: gdb.dwarf2/dw2-bad-parameter-type.exp: ptype f PASS: gdb.dwarf2/dw2-bad-parameter-type.exp: is alive Running ../../../gdb/testsuite/gdb.dwarf2/dw2-basic.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/dw2-basic.exp: set listsize 1 FAIL: gdb.dwarf2/dw2-basic.exp: list func_cu1 PASS: gdb.dwarf2/dw2-basic.exp: ptype func_cu1 @@ -13855,7 +13855,7 @@ PASS: gdb.dwarf2/dw2-compdir-oldgcc.exp: list gcc43 PASS: gdb.dwarf2/dw2-compdir-oldgcc.exp: info source gcc43 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-compressed.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/dw2-compressed.exp: set listsize 1 FAIL: gdb.dwarf2/dw2-compressed.exp: list func_cu1 PASS: gdb.dwarf2/dw2-compressed.exp: ptype func_cu1 @@ -14129,13 +14129,13 @@ PASS: gdb.dwarf2/dw2-inline-param.exp: info addr break_at PASS: gdb.dwarf2/dw2-inline-param.exp: bt Running ../../../gdb/testsuite/gdb.dwarf2/dw2-intercu.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/dw2-intercu.exp: ptype int2 PASS: gdb.dwarf2/dw2-intercu.exp: set listsize 1 FAIL: gdb.dwarf2/dw2-intercu.exp: list func_cu1 PASS: gdb.dwarf2/dw2-intercu.exp: ptype func_cu1 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-intermix.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/dw2-intermix.exp: set listsize 1 FAIL: gdb.dwarf2/dw2-intermix.exp: list func_cu1 PASS: gdb.dwarf2/dw2-intermix.exp: ptype func_cu1 @@ -14240,7 +14240,7 @@ Running ../../../gdb/testsuite/gdb.dwarf2/dw2-param-error.exp ... PASS: gdb.dwarf2/dw2-param-error.exp: frame Running ../../../gdb/testsuite/gdb.dwarf2/dw2-producer.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/dw2-producer.exp: set listsize 1 FAIL: gdb.dwarf2/dw2-producer.exp: list func_cu1 PASS: gdb.dwarf2/dw2-producer.exp: ptype func_cu1 @@ -14348,7 +14348,7 @@ Running ../../../gdb/testsuite/gdb.dwarf2/implptrpiece.exp ... PASS: gdb.dwarf2/implptrpiece.exp: print/d p[-1] Running ../../../gdb/testsuite/gdb.dwarf2/mac-fileno.exp ... -ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory +ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory UNRESOLVED: gdb.dwarf2/mac-fileno.exp: set listsize 1 FAIL: gdb.dwarf2/mac-fileno.exp: list func_cu1 PASS: gdb.dwarf2/mac-fileno.exp: ptype func_cu1 @@ -14871,7 +14871,7 @@ PASS: gdb.gdb/selftest.exp: Set xgdb prompt PASS: gdb.gdb/selftest.exp: send ^C to child process PASS: gdb.gdb/selftest.exp: send SIGINT signal to child process -PASS: gdb.gdb/selftest.exp: backtrace through signal handler +FAIL: gdb.gdb/selftest.exp: backtrace through signal handler (timeout) Running ../../../gdb/testsuite/gdb.gdb/xfullpath.exp ... PASS: gdb.gdb/xfullpath.exp: breakpoint in captured_main PASS: gdb.gdb/xfullpath.exp: run until breakpoint at captured_main @@ -15866,6 +15866,12 @@ PASS: gdb.mi/mi-file.exp: request path info of current source file (basics.c) PASS: gdb.mi/mi-file.exp: Getting a list of source files. Running ../../../gdb/testsuite/gdb.mi/mi-file-transfer.exp ... +PASS: gdb.mi/mi-file-transfer.exp: put binary file +FAIL: gdb.mi/mi-file-transfer.exp: get binary file +PASS: gdb.mi/mi-file-transfer.exp: compare intermediate binary file +FAIL: gdb.mi/mi-file-transfer.exp: compare binary file +FAIL: gdb.mi/mi-file-transfer.exp: deleted binary file +FAIL: gdb.mi/mi-file-transfer.exp: verified deleted binary file Running ../../../gdb/testsuite/gdb.mi/mi-fill-memory.exp ... PASS: gdb.mi/mi-fill-memory.exp: breakpoint at main PASS: gdb.mi/mi-fill-memory.exp: mi runto main @@ -17344,14 +17350,81 @@ Running ../../../gdb/testsuite/gdb.reverse/watch-precsave.exp ... Running ../../../gdb/testsuite/gdb.reverse/watch-reverse.exp ... Running ../../../gdb/testsuite/gdb.server/ext-attach.exp ... +PASS: gdb.server/ext-attach.exp: disconnect +PASS: gdb.server/ext-attach.exp: set remote exec-file +FAIL: gdb.server/ext-attach.exp: attach to remote program 1 +FAIL: gdb.server/ext-attach.exp: backtrace 1 +FAIL: gdb.server/ext-attach.exp: detach (the program is no longer running) +PASS: gdb.server/ext-attach.exp: backtrace with no program +FAIL: gdb.server/ext-attach.exp: attach to remote program 2 +FAIL: gdb.server/ext-attach.exp: backtrace 2 +PASS: gdb.server/ext-attach.exp: kill +PASS: gdb.server/ext-attach.exp: monitor exit Running ../../../gdb/testsuite/gdb.server/ext-run.exp ... +PASS: gdb.server/ext-run.exp: disconnect +PASS: gdb.server/ext-run.exp: set remote exec-file +PASS: gdb.server/ext-run.exp: continue to main +PASS: gdb.server/ext-run.exp: kill +PASS: gdb.server/ext-run.exp: load new file without any gdbserver inferior +PASS: gdb.server/ext-run.exp: monitor exit Running ../../../gdb/testsuite/gdb.server/file-transfer.exp ... +PASS: gdb.server/file-transfer.exp: disconnect +PASS: gdb.server/file-transfer.exp: put binary file +FAIL: gdb.server/file-transfer.exp: get binary file +PASS: gdb.server/file-transfer.exp: compare intermediate binary file +FAIL: gdb.server/file-transfer.exp: compare binary file +FAIL: gdb.server/file-transfer.exp: deleted binary file +FAIL: gdb.server/file-transfer.exp: verified deleted binary file +FAIL: gdb.server/file-transfer.exp: put text file +FAIL: gdb.server/file-transfer.exp: get text file +FAIL: gdb.server/file-transfer.exp: compare intermediate text file +FAIL: gdb.server/file-transfer.exp: compare text file +FAIL: gdb.server/file-transfer.exp: deleted text file +FAIL: gdb.server/file-transfer.exp: verified deleted text file Running ../../../gdb/testsuite/gdb.server/no-thread-db.exp ... +PASS: gdb.server/no-thread-db.exp: successfully compiled posix threads test case +PASS: gdb.server/no-thread-db.exp: disconnect +FAIL: gdb.server/no-thread-db.exp: libthread-db is now unresolvable +PASS: gdb.server/no-thread-db.exp: continue to breakpoint: after tls assignment +FAIL: gdb.server/no-thread-db.exp: print foo Running ../../../gdb/testsuite/gdb.server/server-exec-info.exp ... +PASS: gdb.server/server-exec-info.exp: file +PASS: gdb.server/server-exec-info.exp: set sysroot remote: +FAIL: gdb.server/server-exec-info.exp: info files Running ../../../gdb/testsuite/gdb.server/server-kill.exp ... +PASS: gdb.server/server-kill.exp: disconnect +FAIL: gdb.server/server-kill.exp: tstatus Running ../../../gdb/testsuite/gdb.server/server-mon.exp ... +PASS: gdb.server/server-mon.exp: disconnect +PASS: gdb.server/server-mon.exp: monitor help +PASS: gdb.server/server-mon.exp: monitor +PASS: gdb.server/server-mon.exp: monitor set debug 1 +PASS: gdb.server/server-mon.exp: monitor set debug 0 +PASS: gdb.server/server-mon.exp: monitor set remote-debug 1 +PASS: gdb.server/server-mon.exp: monitor set remote-debug 0 Running ../../../gdb/testsuite/gdb.server/server-run.exp ... +PASS: gdb.server/server-run.exp: disconnect +PASS: gdb.server/server-run.exp: continue to main Running ../../../gdb/testsuite/gdb.server/solib-list.exp ... +PASS: gdb.server/solib-list.exp: non-stop 0: disconnect +PASS: gdb.server/solib-list.exp: non-stop 0: set non-stop 0 +PASS: gdb.server/solib-list.exp: non-stop 0: set target-async 0 +PASS: gdb.server/solib-list.exp: non-stop 0: set displaced-stepping off +PASS: gdb.server/solib-list.exp: non-stop 0: file binfile +PASS: gdb.server/solib-list.exp: non-stop 0: target remote +PASS: gdb.server/solib-list.exp: non-stop 0: continue +PASS: gdb.server/solib-list.exp: non-stop 0: sharedlibrary +PASS: gdb.server/solib-list.exp: non-stop 0: p libvar +PASS: gdb.server/solib-list.exp: non-stop 1: disconnect +PASS: gdb.server/solib-list.exp: non-stop 1: set non-stop 1 +PASS: gdb.server/solib-list.exp: non-stop 1: set target-async 1 +PASS: gdb.server/solib-list.exp: non-stop 1: set displaced-stepping off +PASS: gdb.server/solib-list.exp: non-stop 1: file binfile +PASS: gdb.server/solib-list.exp: non-stop 1: target remote +FAIL: gdb.server/solib-list.exp: non-stop 1: non-stop interior stop (timeout) +FAIL: gdb.server/solib-list.exp: non-stop 1: continue (the program is no longer running) +PASS: gdb.server/solib-list.exp: non-stop 1: sharedlibrary +FAIL: gdb.server/solib-list.exp: non-stop 1: p libvar Running ../../../gdb/testsuite/gdb.stabs/exclfwd.exp ... PASS: gdb.stabs/exclfwd.exp: ptype v1 PASS: gdb.stabs/exclfwd.exp: ptype v2 @@ -18315,7 +18388,7 @@ PASS: gdb.trace/trace-mt.exp: successfully compiled posix threads test case UNSUPPORTED: gdb.trace/trace-mt.exp: target does not support trace Running ../../../gdb/testsuite/gdb.trace/tspeed.exp ... -gdb compile failed, gcc: error: /home/hacklu/code/gdb/build.git2/gdb/testsuite/../gdbserver/libinproctrace.so: No such file or directory +gdb compile failed, gcc: error: /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../gdbserver/libinproctrace.so: No such file or directory UNTESTED: gdb.trace/tspeed.exp: tspeed.exp Running ../../../gdb/testsuite/gdb.trace/tstatus.exp ... UNSUPPORTED: gdb.trace/tstatus.exp: target does not support trace @@ -18365,13 +18438,13 @@ === gdb Summary === -# of expected passes 16427 -# of unexpected failures 529 +# of expected passes 16473 +# of unexpected failures 556 # of unexpected successes 1 # of expected failures 33 # of known failures 52 # of untested testcases 43 # of unresolved testcases 8 # of unsupported tests 210 -/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory +/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version 7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory -- Yue Lu(éå²³) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-05 19:29 ` Pedro Alves 2013-09-05 19:39 ` Joel Brobecker 2013-09-05 21:38 ` Thomas Schwinge @ 2013-09-06 18:53 ` Pedro Alves 2013-09-12 3:05 ` Yue Lu 2013-09-09 10:21 ` [PATCH 1/2] Port gdbserver to GNU/Hurd Yue Lu 3 siblings, 1 reply; 25+ messages in thread From: Pedro Alves @ 2013-09-06 18:53 UTC (permalink / raw) To: gdb-patches; +Cc: Yue Lu, Thomas Schwinge, Luis Machado, bug-hurd Hi! On 09/05/2013 08:29 PM, Pedro Alves wrote: >> > +static int >> > +gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length) >> > +{ >> > + int ret = 0; >> > + task_t task = (gnu_current_inf >> > + ? (gnu_current_inf->task >> > + ? gnu_current_inf->task->port : 0) : 0); >> > + if (task == MACH_PORT_NULL) >> > + return 0; >> > + ret = gnu_read_inferior (task, addr, myaddr, length); >> > + if (length != ret) >> > + { >> > + gnu_debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret); >> > + return -1; >> > + } >> > + return 0; >> > +} >> > + >> > +static int >> > +gnu_write_memory (CORE_ADDR addr, const unsigned char *myaddr, int length) >> > +{ >> > + int ret = 0; >> > + task_t task = (gnu_current_inf >> > + ? (gnu_current_inf->task >> > + ? gnu_current_inf->task->port : 0) : 0); >> > + if (task == MACH_PORT_NULL) >> > + return 0; >> > + ret = gnu_write_inferior (task, addr, myaddr, length); >> > + if (length != ret) >> > + { >> > + gnu_debug ("gnu_write_inferior,length=%d, but return %d\n", length, >> > + ret); >> > + return -1; >> > + } >> > + return 0; >> > +} >> > + > These should reall be wrappers around a common shared function. I have > a patch that I think helps here. I'll post it in soon. > This is what I meant: https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html I was thinking you'd wrap gnu_xfer_memory. But I have to say I don't really understand the real need for all those: task_t task = (gnu_current_inf ? (gnu_current_inf->task ? gnu_current_inf->task->port : 0) : 0); int res; if (task == MACH_PORT_NULL) return 0; checks in the existing code. I mean, why would we reach here with an invalid inferior/task/port selected? It just reads as workaround for some bug to me. Thanks, -- Pedro Alves ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-06 18:53 ` Pedro Alves @ 2013-09-12 3:05 ` Yue Lu 2013-09-18 12:30 ` Pedro Alves 2013-09-18 12:37 ` Pedro Alves 0 siblings, 2 replies; 25+ messages in thread From: Yue Lu @ 2013-09-12 3:05 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Thomas Schwinge, Luis Machado, bug-hurd Hi, On Sat, Sep 7, 2013 at 2:53 AM, Pedro Alves <palves@redhat.com> wrote: > This is what I meant: > https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html > > I was thinking you'd wrap gnu_xfer_memory. > I have study your patch, but I found there is no to_xfer_partial field or something similar in gdbserver's structure target_obj, how can I do? Please give me more hints, thanks. > But I have to say I don't really understand the real need for > all those: > > task_t task = (gnu_current_inf > ? (gnu_current_inf->task > ? gnu_current_inf->task->port : 0) > : 0); > int res; > > if (task == MACH_PORT_NULL) > return 0; > > checks in the existing code. I mean, why would we reach here with > an invalid inferior/task/port selected? > It just reads as workaround for some bug to me. Honestly to say, I have copied them from function gnu_xfer_memory. But I think, before reference a pointer, check whether it was a NULL seems not a bad way :-). And this is my update patch which is base on the current upstream master branch. ====================================================================== gdbserver * configure.ac (host_makefile_frag): New rule for GNU/Hurd to load i386gnu.mh. * configure.srv (srv_tgtobj): Add gnu-nat.o i386gnu-nat.o. for GNU/Hurd. (srv_regobj): Add $(srv_i386_regobj) for GNU/Hurd. (srv_xmlfiles): Add $(srv_i386_xmlfiles) for GNU/Hurd. * configure: Regenerate. * Makefile.in (OBS): Add $(NATDEPFILES). (generated_files): Add $(NAT_GENERATED_FILES). (@host_makefile_frag@): New rule, add i386gnu.mh. (MIG): New tools. (AWK): New tools. * utils.c (host_address_to_string): New functions, copy from [gdb]/gdb/utils.c. diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 1805e5a..6da44d1 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -50,6 +50,8 @@ INSTALL_DATA = @INSTALL_DATA@ RANLIB = @RANLIB@ CC = @CC@ +MIG = @MIG@ +AWK = @AWK@ # Dependency tracking information. DEPMODE = @CCDEPMODE@ @@ -176,7 +178,7 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o \ target.o waitstatus.o utils.o version.o vec.o gdb_vecs.o \ mem-break.o hostio.o event-loop.o tracepoint.o xml-utils.o \ common-utils.o ptid.o buffer.o format.o filestuff.o dll.o notif.o \ - tdesc.o $(XML_BUILTIN) $(DEPFILES) $(LIBOBJS) + tdesc.o $(XML_BUILTIN) $(DEPFILES) $(LIBOBJS) $(NATDEPFILES) GDBREPLAY_OBS = gdbreplay.o version.o GDBSERVER_LIBS = @GDBSERVER_LIBS@ XM_CLIBS = @LIBS@ @@ -199,6 +201,11 @@ CLEANDIRS = $(SUBDIRS) # The format here is for the `case' shell command. REQUIRED_SUBDIRS = $(GNULIB_BUILDDIR) +# Host-dependent makefile fragment comes in here. +GDBSERVER_HURD=@GDBSERVER_HURD@ +@host_makefile_frag@ +# End of host-dependent makefile fragment + FLAGS_TO_PASS = \ "prefix=$(prefix)" \ "exec_prefix=$(exec_prefix)" \ @@ -232,7 +239,7 @@ FLAGS_TO_PASS = \ "RUNTESTFLAGS=$(RUNTESTFLAGS)" # All generated files which can be included by another file. -generated_files = config.h $(GNULIB_H) +generated_files = config.h $(GNULIB_H) $(NAT_GENERATED_FILES) .c.o: $(COMPILE) $< @@ -522,6 +529,16 @@ mips-linux-watch.o: ../common/mips-linux-watch.c $(COMPILE) $< $(POSTCOMPILE) +ifdef GDBSERVER_HURD +#fixme, if use i386gnu-nat.o here will complain that can't find rule for target i386gnu-gnu.c +i386gnu-nat_foo.o: $(srcdir)/../i386gnu-nat.c + $(COMPILE) $< + $(POSTCOMPILE) +gnu-nat.o: $(srcdir)/../gnu-nat.c + $(COMPILE) $< + $(POSTCOMPILE) +endif + # Native object files rules from ../nat linux-waitpid.o: ../nat/linux-waitpid.c @@ -535,6 +552,9 @@ linux-waitpid.o: ../nat/linux-waitpid.c vasprintf.o: $(srcdir)/../../libiberty/vasprintf.c $(COMPILE) $< -DHAVE_CONFIG_H $(POSTCOMPILE) +obstack.o: $(srcdir)/../../libiberty/obstack.c + $(COMPILE) $< -DHAVE_CONFIG_H + $(POSTCOMPILE) vsnprintf.o: $(srcdir)/../../libiberty/vsnprintf.c $(COMPILE) $< $(POSTCOMPILE) diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac index 456a1f7..7d4eb75 100644 --- a/gdb/gdbserver/configure.ac +++ b/gdb/gdbserver/configure.ac @@ -471,6 +471,31 @@ if $want_ipa ; then fi fi +frags= +GDBSERVER_HURD=1 +case $host_os in + gnu*) + #Needed for GNU Hurd hosts. + AC_PROG_AWK + AC_CHECK_TOOL(MIG, mig) + if test x"$MIG" = x; then + AC_MSG_ERROR([MIG not found but required for $host hosts]) + fi + host_makefile_frag=${srcdir}/../config/i386/i386gnu.mh + if test ! -f ${host_makefile_frag}; then + AC_MSG_ERROR("*** Gdb does not support native target ${host}") + fi + frags="$frags $host_makefile_frag" + ;; + *) + host_makefile_frag=/dev/null + ;; +esac + +AC_SUBST_FILE(host_makefile_frag) +AC_SUBST(frags) +AC_SUBST(GDBSERVER_HURD) + AC_SUBST(GDBSERVER_DEPFILES) AC_SUBST(GDBSERVER_LIBS) AC_SUBST(srv_xmlbuiltin) diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index b3c0421..d370e4a 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -116,6 +116,10 @@ case "${target}" in srv_linux_btrace=yes ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o" ;; + i[34567]86-*-gnu*) srv_regobj="$srv_i386_regobj" + srv_tgtobj="" + srv_xmlfiles="$srv_i386_xmlfiles" + ;; i[34567]86-*-lynxos*) srv_regobj="i386.o" srv_tgtobj="lynx-low.o lynx-i386-low.o" srv_xmlfiles="i386/i386.xml" diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c index 9706d74..a181d06 100644 --- a/gdb/gdbserver/utils.c +++ b/gdb/gdbserver/utils.c @@ -181,6 +181,15 @@ get_cell (void) return buf[cell]; } +const char * +host_address_to_string (const void *addr) +{ + char *str = get_cell (); + + xsnprintf (str, CELLSIZE, "0x%s", phex_nz ((unsigned long long) addr, sizeof (addr))); + return str; +} + static char * decimal2str (char *sign, ULONGEST addr) { ====================================================================== gdb * configure.tgt: Set build_gdbserver=yes for GNU/Hurd hosts. * configure: Regenerate. * config/i386/i386gnu.mh: Add #ifdef to determine which rule to use in gdbserver. * i386gnu-nat.c: Add macor GDBSERVER to support build gdbserver. * gnu-nat.h: Add macor GDBSERVER to support build gdbserver. * gnu-nat.c: Add macor GDBSERVER to support build gdbserver. (gnu_kill): New function, used in gdbserver. (gnu_mourn): New function, clean up after inferior dies, used in gdbserver. (gnu_create_inferior): New function, use for create inferior in gdbserver. (gnu_attach): New function, a placeholder. (gnu_detach): New function, used in gdbserver detach from inferior. (gnu_thread_alive): New function, call find_thread_ptid(). (gnu_ptid_build): New function, build structure ptid_t from pid, and tid when has GDBSERVER defined. (gnu_get_tid): New function, return lwp from structure ptid_t,when has GDBSERVER defined. (gnu_add_process): New function, add a new process to process list. (gnu_join): New function, a placeholder. (gnu_resume_wrap): New function, a wrap function, just call gnu_resume(). (gnu_wait_wrap): New function, a wrap function, just call gnu_wait(). (gnu_fetch_registers_wrap): New function, a wrap function, just call gnu_fetch_registers(). (gnu_store_registers_wrap): New function, a wrap function, just call gnu_store_registers(). (gnu_read_memory): New function, a wrap function, just call gnu_read_inferior(). (gnu_write_memory): New function, a wrap function, just call gnu_write_inferior(). (gnu_request_interrupt): New function, used in gdbserver. (store_waitstatus): New function, helper function, copy from [gdb]/gdb/inf-child.c. (initialize_low): New function, use for initialize gdbserver's target_ops. (initialize_low_arch): New function, used by initialize_low(). (_initialize_gnu_nat): New function, used by initialize_low(). diff --git a/gdb/config/i386/i386gnu.mh b/gdb/config/i386/i386gnu.mh index a3ea122..4b9d64d 100644 --- a/gdb/config/i386/i386gnu.mh +++ b/gdb/config/i386/i386gnu.mh @@ -1,5 +1,6 @@ # Host: Intel 386 running the GNU Hurd -NATDEPFILES= i386gnu-nat.o gnu-nat.o core-regset.o fork-child.o \ +ifndef GDBSERVER_HURD +NATDEPFILES= gnu-nat.o i386gnu-nat.o core-regset.o fork-child.o \ notify_S.o process_reply_S.o msg_reply_S.o \ msg_U.o exc_request_U.o exc_request_S.o HAVE_NATIVE_GCORE_HOST = 1 @@ -12,22 +13,41 @@ XM_CLIBS = -lshouldbeinlibc # Use our own user stubs for the msg rpcs, so we can make them time out, in # case the program is fucked, or we guess the wrong signal thread. msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;' +else +NATDEPFILES= gnu-nat.o i386gnu-nat_foo.o obstack.o notify_S.o process_reply_S.o msg_reply_S.o \ + exc_request_U.o exc_request_S.o +endif # ick MIGCOM = $(MIG) -cc cat - /dev/null # Reply servers need special massaging of the code mig generates, to make # them work correctly for error returns in some cases. +ifndef GDBSERVER_HURD %_reply_S.h %_reply_S.c: %_reply.defs $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \ | $(MIGCOM) -sheader $*_reply_S.h -server $*_reply_S.raw -user /dev/null -header /dev/null \ && $(AWK) -f $(srcdir)/reply_mig_hack.awk < $*_reply_S.raw > $*_reply_S.c +else +%_reply_S.h %_reply_S.c: %_reply.defs + $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \ + | $(MIGCOM) -sheader $*_reply_S.h -server $*_reply_S.raw -user /dev/null -header /dev/null \ + && $(AWK) -f $(srcdir)/../reply_mig_hack.awk < $*_reply_S.raw > $*_reply_S.c +endif # Normal servers +ifndef GDBSERVER_HURD %_S.h %_S.c: %.defs +else +%_S.h %_S.c: $(srcdir)/../%.defs +endif $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \ | $(MIGCOM) -sheader $*_S.h -server $*_S.c -user /dev/null -header /dev/null # User rpc stubs +ifndef GDBSERVER_HURD %_U.h %_U.c: %.defs +else +%_U.h %_U.c: $(srcdir)/../%.defs +endif $(CPP) $(CPPFLAGS) $($*-MIGUFLAGS) -x c $< \ | $(MIGCOM) -sheader /dev/null -server /dev/null -user $*_U.c -header $*_U.h diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 95c7217..e841a9a 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -231,6 +231,7 @@ i[34567]86-*-linux*) i[34567]86-*-gnu*) # Target: Intel 386 running the GNU Hurd gdb_target_obs="i386-tdep.o i387-tdep.o i386gnu-tdep.o solib-svr4.o" + build_gdbserver=yes ;; i[34567]86-*-cygwin*) # Target: Intel 386 running win32 diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c index 59d2f23..9e37e2b 100644 --- a/gdb/gnu-nat.c +++ b/gdb/gnu-nat.c @@ -20,29 +20,16 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifndef GDBSERVER #include "defs.h" #include <ctype.h> #include <errno.h> -#include <limits.h> #include <setjmp.h> #include <signal.h> #include <stdio.h> #include "gdb_string.h" -#include <sys/ptrace.h> - -#include <mach.h> -#include <mach_error.h> -#include <mach/exception.h> -#include <mach/message.h> -#include <mach/notify.h> -#include <mach/vm_attributes.h> -#include <hurd.h> -#include <hurd/interrupt.h> -#include <hurd/msg.h> -#include <hurd/msg_request.h> -#include <hurd/process.h> /* Defined in <hurd/process.h>, but we need forward declarations from <hurd/process_request.h> as well. */ #undef _process_user_ @@ -56,25 +43,63 @@ #include "symtab.h" #include "value.h" #include "language.h" -#include "target.h" -#include "gdb_wait.h" #include "gdbcmd.h" #include "gdbcore.h" #include "gdbthread.h" #include "gdb_assert.h" -#include "gdb_obstack.h" -#include "gnu-nat.h" #include "inf-child.h" +#include "exc_request_U.h" +#include "msg_U.h" + +#else /* GDBSERVER */ +#include "server.h" + +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <signal.h> +#endif /* GDBSERVER */ + +#include "target.h" + +#include <limits.h> +#include <sys/ptrace.h> +#include "gdb_obstack.h" +#include "gdb_wait.h" + +#include <mach.h> +#include <mach_error.h> +#include <mach/exception.h> +#include <mach/message.h> + +#include <mach/notify.h> +#include <mach/vm_attributes.h> + +#include <hurd.h> +#include <hurd/interrupt.h> +#include <hurd/msg.h> +#include <hurd/msg_request.h> +#include <hurd/process.h> + +#include "gnu-nat.h" #include "exc_request_S.h" #include "notify_S.h" #include "process_reply_S.h" #include "msg_reply_S.h" -#include "exc_request_U.h" -#include "msg_U.h" static process_t proc_server = MACH_PORT_NULL; +#ifdef GDBSERVER +/* this should move into i386gnu-nat.c ?*/ +/* Defined in auto-generated file i386.c. */ +extern void init_registers_i386 (void); +extern const struct target_desc *tdesc_i386; +const struct target_desc *gnu_tdesc; +int using_threads = 1; +ptid_t inferior_ptid; +static struct target_ops gnu_target_ops; +#endif /* If we've sent a proc_wait_request to the proc server, the pid of the process we asked about. We can only ever have one outstanding. */ @@ -114,6 +139,9 @@ void inf_continue (struct inf *inf); debug ("{inf %d %s}: " msg, __inf->pid, \ host_address_to_string (__inf) , ##args); } while (0) +#ifdef GDBSERVER +static struct process_info * gnu_add_process (int pid, int attached); +#endif void proc_abort (struct proc *proc, int force); struct proc *make_proc (struct inf *inf, mach_port_t port, int tid); struct proc *_proc_free (struct proc *proc); @@ -145,6 +173,13 @@ int proc_trace (struct proc *proc, int set); __e; }) \ : EIEIO) +#ifdef GDBSERVER +struct process_info_private +{ + struct inf *inf; +}; +#endif + /* The state passed by an exception message. */ struct exc_state @@ -242,6 +277,25 @@ struct inf int want_exceptions; }; +static ptid_t +gnu_ptid_build (int pid, long lwp, long tid) +{ +#ifndef GDBSERVER + return ptid_build (pid, lwp, tid); +#else + return ptid_build (pid, tid, lwp); +#endif +} + +long +gnu_get_tid (ptid_t ptid) +{ +#ifndef GDBSERVER + return ptid_get_tid(ptid); +#else + return ptid_get_lwp (ptid); +#endif +} int __proc_pid (struct proc *proc) @@ -855,6 +909,7 @@ inf_validate_task_sc (struct inf *inf) if (inf->task->cur_sc < suspend_count) { +#ifndef GDBSERVER //need fix, I am not sure whether gdbserver need this or not? int abort; target_terminal_ours (); /* Allow I/O. */ @@ -865,7 +920,7 @@ inf_validate_task_sc (struct inf *inf) if (abort) error (_("Additional task suspend count left untouched.")); - +#endif inf->task->cur_sc = suspend_count; } } @@ -1056,6 +1111,12 @@ inf_validate_procs (struct inf *inf) if (!left) { proc_debug (thread, "died!"); +#ifdef GDBSERVER + ptid_t ptid; + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); + if (find_thread_ptid (ptid)) + remove_thread (find_thread_ptid (ptid)); +#endif thread->port = MACH_PORT_NULL; thread = _proc_free (thread); /* THREAD is dead. */ if (last) @@ -1083,10 +1144,11 @@ inf_validate_procs (struct inf *inf) last = thread; proc_debug (thread, "new thread: %d", threads[i]); - ptid = ptid_build (inf->pid, 0, thread->tid); + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); /* Tell GDB's generic thread code. */ +#ifndef GDBSERVER if (ptid_equal (inferior_ptid, pid_to_ptid (inf->pid))) /* This is the first time we're hearing about thread ids, after a fork-child. */ @@ -1096,6 +1158,15 @@ inf_validate_procs (struct inf *inf) add_thread_silent (ptid); else add_thread (ptid); +#else + if (!find_thread_ptid (ptid)) + { + debug ("New thread, pid=%d, tid=%d\n", inf->pid, + thread->tid); + add_thread (ptid, thread); + //inferior_ptid = ptid; /* need fix; seems this line not need, but I can't explain why*/ + } +#endif } } @@ -1221,6 +1292,7 @@ inf_set_threads_resume_sc_for_signal_thread (struct inf *inf) return 0; } +#ifndef GDBSERVER static void inf_update_signal_thread (struct inf *inf) { @@ -1229,6 +1301,7 @@ inf_update_signal_thread (struct inf *inf) inf->signal_thread = inf->threads ? inf->threads->next : 0; } +#endif /* Detachs from INF's inferior task, letting it run once again... */ void @@ -1284,6 +1357,7 @@ inf_attach (struct inf *inf, int pid) inf_startup (inf, pid); } +#ifndef GDBSERVER /* Makes sure that we've got our exception ports entrenched in the process. */ void @@ -1314,6 +1388,7 @@ inf_restore_exc_ports (struct inf *inf) for (thread = inf->threads; thread; thread = thread->next) proc_restore_exc_port (thread); } +#endif /* Deliver signal SIG to INF. If INF is stopped, delivering a signal, even @@ -1613,19 +1688,17 @@ rewait: thread = inf->wait.thread; if (thread) - ptid = ptid_build (inf->pid, 0, thread->tid); + ptid = gnu_ptid_build (inf->pid, 0, thread->tid); else if (ptid_equal (ptid, minus_one_ptid)) thread = inf_tid_to_thread (inf, -1); else - thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); + thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); if (!thread || thread->port == MACH_PORT_NULL) { /* TID is dead; try and find a new thread. */ if (inf_update_procs (inf) && inf->threads) - ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first - available - thread. */ + ptid = gnu_ptid_build (inf->pid, 0, inf->threads->tid);/* The first available thread*/ else ptid = inferior_ptid; /* let wait_for_inferior handle exit case */ } @@ -1651,6 +1724,12 @@ rewait: : "?", status->value.integer); +#ifdef GDBSERVER + inferior_ptid = ptid; +/* why this? because in gdb, the inferior_ptid is used in all over world, + if gdbserver use another one to do the same thing, we will need a lot of +#ifdef GDBSERVER in this file, so we re-used this in gdbserver */ +#endif return ptid; } @@ -2022,7 +2101,7 @@ gnu_resume (struct target_ops *ops, else /* Just allow a single thread to run. */ { - struct proc *thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); + struct proc *thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); if (!thread) error (_("Can't run single thread id %s: no such thread!"), @@ -2033,7 +2112,7 @@ gnu_resume (struct target_ops *ops, if (step) { - step_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid)); + step_thread = inf_tid_to_thread (inf, gnu_get_tid (ptid)); if (!step_thread) warning (_("Can't step thread id %s: no such thread."), target_pid_to_str (ptid)); @@ -2047,6 +2126,7 @@ gnu_resume (struct target_ops *ops, inf_resume (inf); } +#ifndef GDBSERVER static void gnu_kill_inferior (struct target_ops *ops) @@ -2061,8 +2141,29 @@ gnu_kill_inferior (struct target_ops *ops) } target_mourn_inferior (); } +#else +static int +gnu_kill (int pid) +{ + struct proc *task = gnu_current_inf->task; + struct process_info *process; + + process = find_process_pid (pid); + + if (task) + { + proc_debug (task, "terminating..."); + task_terminate (task->port); + inf_set_pid (gnu_current_inf, -1); + } + the_target->mourn (process); + return 0; +} +#endif + /* Clean up after the inferior dies. */ +#ifndef GDBSERVER static void gnu_mourn_inferior (struct target_ops *ops) { @@ -2071,6 +2172,17 @@ gnu_mourn_inferior (struct target_ops *ops) unpush_target (ops); generic_mourn_inferior (); } +#else +static void +gnu_mourn (struct process_info *process) +{ + /* Free our private data. */ + free (process->private); + process->private = NULL; + + clear_inferiors (); +} +#endif /* Fork an inferior process, and start debugging it. */ @@ -2095,6 +2207,7 @@ cur_inf (void) return gnu_current_inf; } +#ifndef GDBSERVER static void gnu_create_inferior (struct target_ops *ops, char *exec_file, char *allargs, char **env, @@ -2148,10 +2261,35 @@ gnu_create_inferior (struct target_ops *ops, else inf_restore_exc_ports (inf); } +#else +static int +gnu_create_inferior (char *program, char **allargs) +{ + int pid; + pid = fork (); + if (pid < 0) + perror_with_name ("fork"); + + if (pid == 0) + { + ptrace (PTRACE_TRACEME); + setpgid (0, 0); + execv (program, allargs); + + fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno)); + fflush (stderr); + _exit (0177); + } + + gnu_add_process (pid, 0); + return pid; +} +#endif /* Attach to process PID, then initialize for debugging it and wait for the trace-trap that results from attaching. */ +#ifndef GDBSERVER static void gnu_attach (struct target_ops *ops, char *args, int from_tty) { @@ -2207,6 +2345,13 @@ gnu_attach (struct target_ops *ops, char *args, int from_tty) renumber_threads (0); /* Give our threads reasonable names. */ #endif } +#else +static int +gnu_attach (unsigned long pid) +{ + return -1; //not support now +} +#endif /* Take a program previously attached to and detaches it. @@ -2216,6 +2361,7 @@ gnu_attach (struct target_ops *ops, char *args, int from_tty) to work, it may be necessary for the process to have been previously attached. It *might* work if the program was started via fork. */ +#ifndef GDBSERVER static void gnu_detach (struct target_ops *ops, char *args, int from_tty) { @@ -2255,6 +2401,23 @@ gnu_stop (ptid_t ptid) { error (_("to_stop target function not implemented")); } +#else +static int +gnu_detach (int pid) +{ + struct process_info *process; + + process = find_process_pid (pid); + if (process == NULL) + return -1; + + inf_detach (gnu_current_inf); + + inferior_ptid = null_ptid; + the_target->mourn (process); + return 0; +} +#endif static int gnu_thread_alive (struct target_ops *ops, ptid_t ptid) @@ -2454,7 +2617,9 @@ gnu_write_inferior (task_t task, CORE_ADDR addr, char *myaddr, int length) out: if (deallocate) { +#ifdef GDBSERVER obstack_free (®ion_obstack, 0); +#endif (void) vm_deallocate (mach_task_self (), copied, @@ -2470,6 +2635,7 @@ out: return length; } +#ifndef GDBSERVER /* Return 0 on failure, number of bytes handled otherwise. TARGET is ignored. */ @@ -2576,6 +2742,7 @@ gnu_find_memory_regions (find_memory_region_ftype func, void *data) return 0; } +#endif /* Return printable description of proc. */ @@ -2592,6 +2759,7 @@ proc_string (struct proc *proc) return tid_str; } +#ifndef GDBSERVER static char * gnu_pid_to_str (struct target_ops *ops, ptid_t ptid) { @@ -3452,3 +3620,203 @@ flush_inferior_icache (CORE_ADDR pc, int amount) warning (_("Error flushing inferior's cache : %s"), safe_strerror (ret)); } #endif /* FLUSH_INFERIOR_CACHE */ + +#else +static struct process_info * +gnu_add_process (int pid, int attached) +{ + struct process_info *proc; + + proc = add_process (pid, attached); + proc->tdesc = gnu_tdesc; + proc->private = xcalloc (1, sizeof (*proc->private)); + proc->private->inf = cur_inf (); + struct inf *inf = gnu_current_inf; + + inf_attach (inf, pid); + inf->pending_execs = 2; + inf->nomsg = 1; + inf->traced = 1; + + inf_resume (inf); + + return proc; +} + +static void +gnu_join (int pid) +{ + /* doesn't need */ +} + +static void +gnu_resume_wrap (struct thread_resume *resume_info, size_t n) +{ + /* FIXME: Assume for now that n == 1. */ + ptid_t ptid = resume_info[0].thread; + const int step = (resume_info[0].kind == resume_step ? 1 : 0); //1 means step, 0 means contiune + const int signal = resume_info[0].sig; + if (ptid_equal (ptid, minus_one_ptid)) + ptid = thread_to_gdb_id (current_inferior); + + regcache_invalidate (); + + debug ("in gnu_resume: ptid=%d, step=%d, signal=%d\n", ptid, step, + signal); + gnu_resume (NULL, ptid, step, signal); +} + +static ptid_t +gnu_wait_wrap (ptid_t ptid, struct target_waitstatus *status, int target_options) +{ + ptid_t event_ptid; + debug ("gnu_wait: [%s]", target_pid_to_str (ptid)); + event_ptid = gnu_wait (NULL, ptid, status, target_options); + debug (" -> (status->kind = %d)\n", status->kind); + return event_ptid; +} + +void +gnu_fetch_registers_wrap (struct regcache *regcache, int regno) +{ + debug ("gnu_fetch_registers() regno=%d\n", regno); + return gnu_fetch_registers (NULL, regcache, regno); +} + +void +gnu_store_registers_wrap (struct regcache *regcache, int regno) +{ + debug ("gnu_store_registers() regno=%d\n", regno); + return gnu_store_registers (NULL, regcache, regno); +} + +static int +gnu_thread_alive_wrap (ptid_t ptid) +{ + return gnu_thread_alive(NULL, ptid); +} + +static int +gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length) +{ + int ret = 0; + task_t task = (gnu_current_inf + ? (gnu_current_inf->task + ? gnu_current_inf->task->port : 0) : 0); + if (task == MACH_PORT_NULL) + return 0; + ret = gnu_read_inferior (task, addr, myaddr, length); + if (length != ret) + { + debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret); + return -1; + } + return 0; +} + +static int +gnu_write_memory (CORE_ADDR addr, const unsigned char *myaddr, int length) +{ + int ret = 0; + task_t task = (gnu_current_inf + ? (gnu_current_inf->task + ? gnu_current_inf->task->port : 0) : 0); + if (task == MACH_PORT_NULL) + return 0; + ret = gnu_write_inferior (task, addr, myaddr, length); + if (length != ret) + { + debug ("gnu_write_inferior,length=%d, but return %d\n", length, + ret); + return -1; + } + return 0; +} + +static void +gnu_request_interrupt (void) +{ + ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); + kill (ptid_get_pid (inferior_ptid), SIGINT); +} + +/* Helper function for child_wait and the derivatives of child_wait. + HOSTSTATUS is the waitstatus from wait() or the equivalent; store our + translation of that in OURSTATUS. */ +void +store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus) +{ + if (WIFEXITED (hoststatus)) + { + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = WEXITSTATUS (hoststatus); + } + else if (!WIFSTOPPED (hoststatus)) + { + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (hoststatus)); + } + else + { + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (hoststatus)); + } +} + +static struct target_ops gnu_target_ops = { + gnu_create_inferior, + gnu_attach, + gnu_kill, + gnu_detach, + gnu_mourn, + gnu_join, + gnu_thread_alive_wrap, + gnu_resume_wrap, + gnu_wait_wrap, + gnu_fetch_registers_wrap, + gnu_store_registers_wrap, + NULL, /* prepare_to_access_memory */ + NULL, /* done_accessing_memory */ + gnu_read_memory, + gnu_write_memory, + NULL, /* look_up_symbols */ + gnu_request_interrupt, + NULL, /* read_auxv */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* read_offsets */ + NULL, /* get_tls_address */ + NULL, /* qxfer_spu */ + NULL, /* hostio_last_error */ + NULL, /* qxfer_osdata */ + NULL, /* qxfer_siginfo */ + NULL, /* supports_non_stop */ + NULL, /* async */ + NULL, /* start_non_stop */ + NULL, /* supports_multi_process */ + NULL, /* handle_monitor_command */ +}; + +void +_initialize_gnu_nat (void) +{ + proc_server = getproc (); +} + +static void +initialize_low_arch () +{ + init_registers_i386 (); + gnu_tdesc = tdesc_i386; +} + +void +initialize_low (void) +{ + set_target_ops (&gnu_target_ops); + initialize_low_arch (); + _initialize_gnu_nat (); +} +#endif diff --git a/gdb/gnu-nat.h b/gdb/gnu-nat.h index f896bd2..45f2d6b 100644 --- a/gdb/gnu-nat.h +++ b/gdb/gnu-nat.h @@ -93,13 +93,44 @@ extern char *proc_string (struct proc *proc); extern int gnu_debug_flag; +#ifndef GDBSERVER #define debug(msg, args...) \ do { if (gnu_debug_flag) \ fprintf_unfiltered (gdb_stdlog, "%s:%d: " msg "\r\n", \ __FILE__ , __LINE__ , ##args); } while (0) +#else +#define debug(msg, args...) \ + do { if (gnu_debug_flag) \ + printf ("%s:%d: " msg "\r\n", \ + __FILE__ , __LINE__ , ##args); } while (0) +#endif /* Create a prototype generic GNU/Hurd target. The client can override it with local methods. */ struct target_ops *gnu_target (void); +#ifdef GDBSERVER +#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE +#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT +#define THREAD_STATE_SET_TRACED(state) \ + ((struct i386_thread_state *) (state))->efl |= 0x100 +#define THREAD_STATE_CLEAR_TRACED(state) \ + ((((struct i386_thread_state *) (state))->efl &= ~0x100), 1) + +#ifndef PIDGET +#define PIDGET(PTID) (ptid_get_pid (PTID)) +#endif + +static ptid_t gnu_ptid_build(int pid,long lwp,long tid); +long gnu_get_tid (ptid_t ptid); + +/* Return printable description of proc. */ +extern char *proc_string (struct proc *proc); + +#ifndef safe_strerror +#define safe_strerror(err) \ + "" +#endif +#endif + #endif /* __GNU_NAT_H__ */ diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c index 0fd8d91..5d46255 100644 --- a/gdb/i386gnu-nat.c +++ b/gdb/i386gnu-nat.c @@ -17,24 +17,17 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifndef GDBSERVER #include "defs.h" #include "inferior.h" #include "floatformat.h" #include "regcache.h" #include "gdb_assert.h" -#include <errno.h> -#include <stdio.h> #include "gdb_string.h" -#include <mach.h> -#include <mach_error.h> -#include <mach/message.h> -#include <mach/exception.h> - #include "i386-tdep.h" -#include "gnu-nat.h" #include "i387-tdep.h" #ifdef HAVE_SYS_PROCFS_H @@ -42,6 +35,23 @@ # include "gregset.h" #endif +#else /* GDBSERVER */ +#include "server.h" +#include "target.h" +#include "gdb_wait.h" + +#define I386_NUM_GREGS 16 +#endif /* GDBSERVER */ + +#include <errno.h> +#include <stdio.h> + +#include <mach.h> +#include <mach_error.h> +#include <mach/message.h> +#include <mach/exception.h> +#include "gnu-nat.h" + /* Offset to the thread_state_t location where REG is stored. */ #define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg) @@ -78,6 +88,7 @@ static int creg_offset[] = static void fetch_fpregs (struct regcache *regcache, struct proc *thread) { +#ifndef GDBSERVER mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT; struct i386_float_state state; error_t err; @@ -101,8 +112,12 @@ fetch_fpregs (struct regcache *regcache, struct proc *thread) /* Supply the floating-point registers. */ i387_supply_fsave (regcache, -1, state.hw_state); } +#else + debug ("fetch_fpregs() not support now\n"); +#endif } +#ifndef GDBSERVER #ifdef HAVE_SYS_PROCFS_H /* These two calls are used by the core-regset.c code for reading ELF core files. */ @@ -120,9 +135,16 @@ supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregs) i387_supply_fsave (regcache, -1, fpregs); } #endif +#endif +extern struct inf *gnu_current_inf; +extern ptid_t inferior_ptid; /* Fetch register REGNO, or all regs if REGNO is -1. */ +#ifndef GDBSERVER static void +#else +void +#endif gnu_fetch_registers (struct target_ops *ops, struct regcache *regcache, int regno) { @@ -132,7 +154,7 @@ gnu_fetch_registers (struct target_ops *ops, inf_update_procs (gnu_current_inf); thread = inf_tid_to_thread (gnu_current_inf, - ptid_get_tid (inferior_ptid)); + gnu_get_tid (inferior_ptid)); if (!thread) error (_("Can't fetch registers from thread %s: No such thread"), target_pid_to_str (inferior_ptid)); @@ -157,17 +179,25 @@ gnu_fetch_registers (struct target_ops *ops, proc_debug (thread, "fetching all register"); for (i = 0; i < I386_NUM_GREGS; i++) +#ifndef GDBSERVER regcache_raw_supply (regcache, i, REG_ADDR (state, i)); +#else + supply_register (regcache, i, REG_ADDR (state, i)); +#endif thread->fetched_regs = ~0; } else { +#ifndef GDBSERVER proc_debug (thread, "fetching register %s", gdbarch_register_name (get_regcache_arch (regcache), regno)); regcache_raw_supply (regcache, regno, REG_ADDR (state, regno)); +#else + supply_register (regcache, regno, REG_ADDR (state, regno)); +#endif thread->fetched_regs |= (1 << regno); } } @@ -183,9 +213,14 @@ gnu_fetch_registers (struct target_ops *ops, /* Store the whole floating-point state into THREAD using information from the corresponding (pseudo) registers. */ +#ifndef GDBSERVER static void +#else +void +#endif store_fpregs (const struct regcache *regcache, struct proc *thread, int regno) { +#ifndef GDBSERVER mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT; struct i386_float_state state; error_t err; @@ -211,21 +246,32 @@ store_fpregs (const struct regcache *regcache, struct proc *thread, int regno) proc_string (thread)); return; } +#else + debug ("store_fpregs() not support now\n"); +#endif } /* Store at least register REGNO, or all regs if REGNO == -1. */ +#ifndef GDBSERVER static void +#else +void +#endif gnu_store_registers (struct target_ops *ops, struct regcache *regcache, int regno) { struct proc *thread; +#ifndef GDBSERVER struct gdbarch *gdbarch = get_regcache_arch (regcache); +#else + const struct target_desc *gdbarch = regcache->tdesc; +#endif /* Make sure we know about new threads. */ inf_update_procs (gnu_current_inf); thread = inf_tid_to_thread (gnu_current_inf, - ptid_get_tid (inferior_ptid)); + gnu_get_tid (inferior_ptid)); if (!thread) error (_("Couldn't store registers into thread %s: No such thread"), target_pid_to_str (inferior_ptid)); @@ -265,12 +311,19 @@ gnu_store_registers (struct target_ops *ops, register_size (gdbarch, check_regno))) /* Register CHECK_REGNO has changed! Ack! */ { +#ifndef GDBSERVER warning (_("Register %s changed after the thread was aborted"), gdbarch_register_name (gdbarch, check_regno)); +#endif if (regno >= 0 && regno != check_regno) /* Update GDB's copy of the register. */ +#ifndef GDBSERVER regcache_raw_supply (regcache, check_regno, REG_ADDR (state, check_regno)); +#else + supply_register (regcache, check_regno, + REG_ADDR (state, check_regno)); +#endif else warning (_("... also writing this register! " "Suspicious...")); @@ -284,16 +337,24 @@ gnu_store_registers (struct target_ops *ops, proc_debug (thread, "storing all registers"); for (i = 0; i < I386_NUM_GREGS; i++) +#ifndef GDBSERVER if (REG_VALID == regcache_register_status (regcache, i)) regcache_raw_collect (regcache, i, REG_ADDR (state, i)); +#else + collect_register (regcache, i, REG_ADDR (state, i)); +#endif } else { +#ifndef GDBSERVER proc_debug (thread, "storing register %s", gdbarch_register_name (gdbarch, regno)); gdb_assert (REG_VALID == regcache_register_status (regcache, regno)); regcache_raw_collect (regcache, regno, REG_ADDR (state, regno)); +#else + collect_register (regcache, regno, REG_ADDR (state, regno)); +#endif } /* Restore the T bit. */ @@ -309,6 +370,7 @@ gnu_store_registers (struct target_ops *ops, } } +#ifndef GDBSERVER /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_i386gnu_nat; @@ -326,3 +388,4 @@ _initialize_i386gnu_nat (void) /* Register the target. */ add_target (t); } +#endif thanks. -- Yue Lu (陆岳) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-12 3:05 ` Yue Lu @ 2013-09-18 12:30 ` Pedro Alves 2013-09-18 12:37 ` Pedro Alves 1 sibling, 0 replies; 25+ messages in thread From: Pedro Alves @ 2013-09-18 12:30 UTC (permalink / raw) To: Yue Lu; +Cc: Pedro Alves, gdb-patches, Thomas Schwinge, Luis Machado, bug-hurd On 09/12/2013 04:05 AM, Yue Lu wrote: > Honestly to say, I have copied them from function gnu_xfer_memory. But > I think, before reference a pointer, check whether it was a NULL seems > not a bad way :-). We don't go around checking for NULL before _every_ pointer dereference. :-) NULL pointer checks are used when the function's semantics give special meaning to NULL, like for example, for optional parameters. If that's not the function's semantics, and you still may see a NULL pointer, then that tells there's actually a bug that triggered already elsewhere before the function in question was called. IOW, a NULL check in these cases is just masking out a bug in some caller. In some cases, we might add a gdb_assert to catch the bug in a nicer way instead of just crashing. I suspect that what may happen is that at some point it was possible for GDB to select a no-longer-existing-thread (though I can't see how in the current code), and then setting breakpoints, or other operations that require reading memory would crash. -- Pedro Alves ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-12 3:05 ` Yue Lu 2013-09-18 12:30 ` Pedro Alves @ 2013-09-18 12:37 ` Pedro Alves 2013-09-19 7:41 ` Yue Lu 1 sibling, 1 reply; 25+ messages in thread From: Pedro Alves @ 2013-09-18 12:37 UTC (permalink / raw) To: Yue Lu; +Cc: gdb-patches, Thomas Schwinge, Luis Machado, bug-hurd On 09/12/2013 04:05 AM, Yue Lu wrote: > On Sat, Sep 7, 2013 at 2:53 AM, Pedro Alves <palves@redhat.com> wrote: >> This is what I meant: >> https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html >> >> I was thinking you'd wrap gnu_xfer_memory. >> > > I have study your patch, Thanks. Did you try building gdb with it, and does the resulting GDB still work? > but I found there is no to_xfer_partial field > or something similar in gdbserver's structure target_obj, how can I > do? Please give me more hints, thanks. Right, there's no such function in gdbserver today. I mean, instead of: + +static int +gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length) +{ + int ret = 0; + task_t task = (gnu_current_inf + ? (gnu_current_inf->task + ? gnu_current_inf->task->port : 0) : 0); + if (task == MACH_PORT_NULL) + return 0; + ret = gnu_read_inferior (task, addr, myaddr, length); + if (length != ret) + { + debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret); + return -1; + } + return 0; +} you'll have a simpler: static int gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length) { LONGEST res; res = gnu_xfer_memory (...); if (res != length) return -1; return 0; } gnu_xfer_memory already has the task == MACH_PORT_NULL check inside it, so this means there's no need to duplicate it in gnu_read|write_memory. -- Pedro Alves ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-18 12:37 ` Pedro Alves @ 2013-09-19 7:41 ` Yue Lu 2013-09-19 8:30 ` FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) (was: [PATCH 1/2] Port gdbserver to GNU/Hurd) Thomas Schwinge 0 siblings, 1 reply; 25+ messages in thread From: Yue Lu @ 2013-09-19 7:41 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Thomas Schwinge, Luis Machado, bug-hurd Hi, On Wed, Sep 18, 2013 at 8:37 PM, Pedro Alves <palves@redhat.com> wrote: > On 09/12/2013 04:05 AM, Yue Lu wrote: > >> On Sat, Sep 7, 2013 at 2:53 AM, Pedro Alves <palves@redhat.com> wrote: >>> This is what I meant: >>> https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html >>> >>> I was thinking you'd wrap gnu_xfer_memory. >>> >> >> I have study your patch, > > Thanks. Did you try building gdb with it, and does the > resulting GDB still work? First thank you to tell me how to apply patch from email. I used webmail of gmail and directly copy patch from the email which often apply failed, then I had to patch line by line. Now I used mutt to save email to mbox file then apply it, life changed! Before you told me this, I never imaged this, so thanks! I have test your patch, seems need a tiny fix. This is just a spelling mistaken I think. diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c index 07fe603..bc37bb8 100644 --- a/gdb/gnu-nat.c +++ b/gdb/gnu-nat.c @@ -2493,14 +2493,14 @@ gnu_xfer_memory (gdb_byte *readbuf, const char *writebuf, { inf_debug (gnu_current_inf, "writing %s[%s] <-- %s", paddress (target_gdbarch (), memaddr), plongest (len), - host_address_to_string (myaddr)); + host_address_to_string (writebuf)); res = gnu_write_inferior (task, memaddr, writebuf, len); } else { inf_debug (gnu_current_inf, "reading %s[%s] --> %s", paddress (target_gdbarch (), memaddr), plongest (len), - host_address_to_string (myaddr)); + host_address_to_string (readbuf)); res = gnu_read_inferior (task, memaddr, readbuf, len); } if (res == 0) After add this change, the gdb can work. But I have found a little strange from the origin gdb. When I set a breakpoint, then I run the inferior, after hit the breakpoint, I just input next next until the inferior exit, then the gdb will complain this: [Inferior 1 (bogus thread id 0) exited normally] Thread-specific breakpoint -37 deleted - thread 4 is gone. Thread-specific breakpoint -38 deleted - thread 4 is gone. Thread-specific breakpoint -39 deleted - thread 4 is gone. Thread-specific breakpoint 0 deleted - thread 4 is gone. I am not sure why this will output or is reasonable. I got this output like this: $./gdb gdb $b main $r $n $n ... $q (quit the debugged gdb) -- Yue Lu (陆岳) ^ permalink raw reply [flat|nested] 25+ messages in thread
* FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) (was: [PATCH 1/2] Port gdbserver to GNU/Hurd) 2013-09-19 7:41 ` Yue Lu @ 2013-09-19 8:30 ` Thomas Schwinge 2013-09-19 8:44 ` FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) Pedro Alves 0 siblings, 1 reply; 25+ messages in thread From: Thomas Schwinge @ 2013-09-19 8:30 UTC (permalink / raw) To: Yue Lu, Pedro Alves; +Cc: gdb-patches, Luis Machado, bug-hurd [-- Attachment #1: Type: text/plain, Size: 2803 bytes --] Hi! On Thu, 19 Sep 2013 15:40:40 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote: > On Wed, Sep 18, 2013 at 8:37 PM, Pedro Alves <palves@redhat.com> wrote: > > On 09/12/2013 04:05 AM, Yue Lu wrote: > > > >> On Sat, Sep 7, 2013 at 2:53 AM, Pedro Alves <palves@redhat.com> wrote: > >>> https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html > First thank you to tell me how to apply patch from email. I used > webmail of gmail and directly copy patch from the email which often > apply failed, then I had to patch line by line. Now I used mutt to > save email to mbox file then apply it, life changed! Before you told > me this, I never imaged this, so thanks! Well, never assume that we'd use any convoluted procedures, such as manually copying a patch's text. ;-) Never hesitate to ask if you think some process is too complicated to be done manually -- there will always be someone who is happy to tell you about his creative solution. > I have test your patch, seems need a tiny fix. This is just a spelling > mistaken I think. Right; I had come to the same conclusion, see my message in the other thread. > After add this change, the gdb can work. But I have found a little > strange from the origin gdb. > When I set a breakpoint, then I run the inferior, after hit the > breakpoint, I just input next next until the inferior exit, then the > gdb will complain this: > [Inferior 1 (bogus thread id 0) exited normally] > Thread-specific breakpoint -37 deleted - thread 4 is gone. > Thread-specific breakpoint -38 deleted - thread 4 is gone. > Thread-specific breakpoint -39 deleted - thread 4 is gone. > Thread-specific breakpoint 0 deleted - thread 4 is gone. > > I am not sure why this will output or is reasonable. > > I got this output like this: > $./gdb gdb > $b main > $r > $n > $n > ... > $q (quit the debugged gdb) "As of recently", I notice the same behavior for GDB on both x86 GNU/Linux and GNU/Hurd, also resulting in the gdb.base/nextoverexit.exp test failing. So, I don't think this is related to any Hurd patches/behavior, but instead a general issue. Quoting from the x86 GNU/Linux' gdb/testsuite/gdb.base2/gdb.log: Breakpoint 1, main () at ../../../Ferry_Tagscherer/gdb/testsuite/gdb.base/nextoverexit.c:21 21 exit (0); (gdb) next [Inferior 1 (process 25208) exited normally] Thread-specific breakpoint -5 deleted - thread 1 is gone. Thread-specific breakpoint -6 deleted - thread 1 is gone. Thread-specific breakpoint -7 deleted - thread 1 is gone. Thread-specific breakpoint 0 deleted - thread 1 is gone. (gdb) FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) Can others confirm this/is this a known issue? Grüße, Thomas [-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) 2013-09-19 8:30 ` FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) (was: [PATCH 1/2] Port gdbserver to GNU/Hurd) Thomas Schwinge @ 2013-09-19 8:44 ` Pedro Alves 0 siblings, 0 replies; 25+ messages in thread From: Pedro Alves @ 2013-09-19 8:44 UTC (permalink / raw) To: Thomas Schwinge; +Cc: Yue Lu, gdb-patches, Luis Machado, bug-hurd On 09/19/2013 09:30 AM, Thomas Schwinge wrote: > Hi! > > On Thu, 19 Sep 2013 15:40:40 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote: >> On Wed, Sep 18, 2013 at 8:37 PM, Pedro Alves <palves@redhat.com> wrote: >>> On 09/12/2013 04:05 AM, Yue Lu wrote: >>> >>>> On Sat, Sep 7, 2013 at 2:53 AM, Pedro Alves <palves@redhat.com> wrote: >>>>> https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html > >> First thank you to tell me how to apply patch from email. I used >> webmail of gmail and directly copy patch from the email which often >> apply failed, then I had to patch line by line. Now I used mutt to >> save email to mbox file then apply it, life changed! Before you told >> me this, I never imaged this, so thanks! > > Well, never assume that we'd use any convoluted procedures, such as > manually copying a patch's text. ;-) Never hesitate to ask if you think > some process is too complicated to be done manually -- there will always > be someone who is happy to tell you about his creative solution. > >> I have test your patch, seems need a tiny fix. This is just a spelling >> mistaken I think. > > Right; I had come to the same conclusion, see my message in the other > thread. > > >> After add this change, the gdb can work. But I have found a little >> strange from the origin gdb. >> When I set a breakpoint, then I run the inferior, after hit the >> breakpoint, I just input next next until the inferior exit, then the >> gdb will complain this: >> [Inferior 1 (bogus thread id 0) exited normally] >> Thread-specific breakpoint -37 deleted - thread 4 is gone. >> Thread-specific breakpoint -38 deleted - thread 4 is gone. >> Thread-specific breakpoint -39 deleted - thread 4 is gone. >> Thread-specific breakpoint 0 deleted - thread 4 is gone. >> >> I am not sure why this will output or is reasonable. >> >> I got this output like this: >> $./gdb gdb >> $b main >> $r >> $n >> $n >> ... >> $q (quit the debugged gdb) > > "As of recently", I notice the same behavior for GDB on both x86 > GNU/Linux and GNU/Hurd, also resulting in the gdb.base/nextoverexit.exp > test failing. So, I don't think this is related to any Hurd > patches/behavior, but instead a general issue. > > Quoting from the x86 GNU/Linux' gdb/testsuite/gdb.base2/gdb.log: > > Breakpoint 1, main () at ../../../Ferry_Tagscherer/gdb/testsuite/gdb.base/nextoverexit.c:21 > 21 exit (0); > (gdb) next > [Inferior 1 (process 25208) exited normally] > Thread-specific breakpoint -5 deleted - thread 1 is gone. > Thread-specific breakpoint -6 deleted - thread 1 is gone. > Thread-specific breakpoint -7 deleted - thread 1 is gone. > Thread-specific breakpoint 0 deleted - thread 1 is gone. > (gdb) FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) > > Can others confirm this/is this a known issue? Hmm, that message is new, but we shouldn't be seeing it for internal breakpoints... That'll be my fault. I'll take a look. -- Pedro Alves ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd 2013-09-05 19:29 ` Pedro Alves ` (2 preceding siblings ...) 2013-09-06 18:53 ` Pedro Alves @ 2013-09-09 10:21 ` Yue Lu 3 siblings, 0 replies; 25+ messages in thread From: Yue Lu @ 2013-09-09 10:21 UTC (permalink / raw) To: Pedro Alves; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd Hi, On Fri, Sep 6, 2013 at 3:29 AM, Pedro Alves <palves@redhat.com> wrote: > I'm actually very excited to see gdb and gdbserver sharing > a single target backend, even if we still have many wrinkles > in the interfaces to iron out! It does looks like this way > results in lots of less work, and makes me believe we can > port other targets to gdbserver already without unsurmountable > effort. Do you mean there should be only one structure target_obj in both gdb and gdbserver? But I have found that, the structure has been declared different between gdb and gdbserver, How can I integrate them into single one. Or just I have got the wrong understand. -- Yue Lu (陆岳) ^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2013-09-22 12:58 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <CAB8fV=jJ64i91VW52ZmdnEDZhd1ZGTAykDqoFyPJanCP=5beqA@mail.gmail.com>
2013-09-03 8:03 ` [PATCH 2/2] Port gdbserver to GNU/Hurd Yue Lu
2013-09-03 9:38 ` [PATCH 1/2] " Thomas Schwinge
2013-09-03 11:11 ` Pedro Alves
2013-09-03 13:09 ` Thomas Schwinge
2013-09-04 1:47 ` Yue Lu
2013-09-04 1:38 ` Yue Lu
2013-09-05 10:54 ` Yue Lu
2013-09-05 19:29 ` Pedro Alves
2013-09-05 19:39 ` Joel Brobecker
2013-09-05 21:38 ` Thomas Schwinge
2013-09-08 13:35 ` Yue Lu
2013-09-09 9:58 ` Thomas Schwinge
2013-09-18 12:12 ` Pedro Alves
2013-09-18 13:48 ` Yue Lu
2013-09-18 14:52 ` [Hurd/gnu-nat.c] Use ptid_t.lwpid to store, thread ids instead of ptid_t.tid. (was: Re: [PATCH 1/2] Port gdbserver to GNU/Hurd) Pedro Alves
2013-09-18 14:57 ` [PATCH 1/2] Port gdbserver to GNU/Hurd Pedro Alves
2013-09-22 12:58 ` Yue Lu
2013-09-06 18:53 ` Pedro Alves
2013-09-12 3:05 ` Yue Lu
2013-09-18 12:30 ` Pedro Alves
2013-09-18 12:37 ` Pedro Alves
2013-09-19 7:41 ` Yue Lu
2013-09-19 8:30 ` FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) (was: [PATCH 1/2] Port gdbserver to GNU/Hurd) Thomas Schwinge
2013-09-19 8:44 ` FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) Pedro Alves
2013-09-09 10:21 ` [PATCH 1/2] Port gdbserver to GNU/Hurd Yue Lu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox