From 9d7e13ad2525af53757122d532ac3851e9065471 Mon Sep 17 00:00:00 2001
From: Augustin Cavalier <waddlesplash@gmail.com>
Date: Wed, 11 Feb 2015 10:07:54 -0500
Subject: [PATCH] Merge changes from Haiku's main repo.

Includes some other fixes by me to get the build system fully working.
---
 bfd/config.bfd             |    4 +
 config.sub                 |    3 +
 gdb/Makefile.in            |    2 +-
 gdb/amd64-haiku-nat.c      |   96 +++
 gdb/amd64-haiku-tdep.c     |   61 ++
 gdb/config/i386/haiku.mh   |    7 +
 gdb/config/i386/haiku.mt   |    5 +
 gdb/config/i386/nm-haiku.h |   27 +
 gdb/config/i386/tm-haiku.h |   27 +
 gdb/config/nm-haiku.h      |   25 +
 gdb/config/tm-haiku.h      |   25 +
 gdb/configure.host         |    1 +
 gdb/configure.tgt          |    1 +
 gdb/defs.h                 |    2 +
 gdb/haiku-nat.c            | 1742 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/haiku-nat.h            |   42 ++
 gdb/haiku-tdep.c           |   22 +
 gdb/i386-haiku-nat.c       |   87 +++
 gdb/i386-haiku-tdep.c      |   77 ++
 gdb/osabi.c                |    2 +
 gdb/ser-tcp.c              |    8 +-
 gdb/solib-haiku.c          |  334 +++++++++
 gdb/solib-haiku.h          |   34 +
 libiberty/clock.c          |    2 +-
 readline/histfile.c        |    4 +-
 readline/input.c           |    2 +-
 readline/support/wcwidth.c |    1 +
 27 files changed, 2635 insertions(+), 8 deletions(-)
 create mode 100644 gdb/amd64-haiku-nat.c
 create mode 100644 gdb/amd64-haiku-tdep.c
 create mode 100644 gdb/config/i386/haiku.mh
 create mode 100644 gdb/config/i386/haiku.mt
 create mode 100644 gdb/config/i386/nm-haiku.h
 create mode 100644 gdb/config/i386/tm-haiku.h
 create mode 100644 gdb/config/nm-haiku.h
 create mode 100644 gdb/config/tm-haiku.h
 create mode 100644 gdb/haiku-nat.c
 create mode 100644 gdb/haiku-nat.h
 create mode 100644 gdb/haiku-tdep.c
 create mode 100644 gdb/i386-haiku-nat.c
 create mode 100644 gdb/i386-haiku-tdep.c
 create mode 100644 gdb/solib-haiku.c
 create mode 100644 gdb/solib-haiku.h

diff --git a/bfd/config.bfd b/bfd/config.bfd
index 549397b..c6621f9 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -572,6 +572,10 @@ case "${targ}" in
     targ_defvec=bfd_elf32_i386_vec
     targ_selvecs="i386pe_vec i386pei_vec"
     ;;
+  i[3-7]86-*-haiku*)
+    targ_defvec=bfd_elf32_i386_vec
+    targ_selvecs="i386pe_vec i386pei_vec"
+    ;;
   i[3-7]86-*-interix*)
     targ_defvec=i386pei_vec
     targ_selvecs="i386pe_vec"
diff --git a/config.sub b/config.sub
index edb6b66..36a7851 100755
--- a/config.sub
+++ b/config.sub
@@ -1297,6 +1297,9 @@ case $os in
 	-kaos*)
 		os=-kaos
 		;;
+	-haiku*)
+		os=-haiku
+		;;
 	-none)
 		;;
 	*)
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 966f887..8cbc2ce 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -374,7 +374,7 @@ INSTALLED_LIBS=-lbfd -lreadline -lopcodes -liberty \
 	-lintl -liberty
 CLIBS = $(SIM) $(BFD) $(READLINE) $(OPCODES) $(INTL) $(LIBIBERTY) \
 	$(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ \
-	$(LIBICONV) \
+	$(LIBICONV) -ldebug \
 	$(LIBIBERTY) $(WIN32LIBS)
 CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE) \
 	$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS)
diff --git a/gdb/amd64-haiku-nat.c b/gdb/amd64-haiku-nat.c
new file mode 100644
index 0000000..7a4ae51
--- /dev/null
+++ b/gdb/amd64-haiku-nat.c
@@ -0,0 +1,96 @@
+/* Native-dependent code for Haiku x86_64.
+
+   Copyright 2012 Alex Smith <alex@alex-smith.me.uk>.
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "haiku-nat.h"
+#include "amd64-tdep.h"
+#include "i387-tdep.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "target.h"
+
+/* Offset in `struct debug_cpu_state' where MEMBER is stored.  */
+#define REG_OFFSET(member) offsetof (struct x86_64_debug_cpu_state, member)
+
+/* At kHaikuAMD64RegOffset[REGNUM] you'll find the offset in `struct
+   debug_cpu_state' where the GDB register REGNUM is stored. */
+static int kHaikuAMD64RegOffset[] = {
+	REG_OFFSET (rax),
+	REG_OFFSET (rbx),
+	REG_OFFSET (rcx),
+	REG_OFFSET (rdx),
+	REG_OFFSET (rsi),
+	REG_OFFSET (rdi),
+	REG_OFFSET (rbp),
+	REG_OFFSET (rsp),
+	REG_OFFSET (r8),
+	REG_OFFSET (r9),
+	REG_OFFSET (r10),
+	REG_OFFSET (r11),
+	REG_OFFSET (r12),
+	REG_OFFSET (r13),
+	REG_OFFSET (r14),
+	REG_OFFSET (r15),
+	REG_OFFSET (rip),
+	REG_OFFSET (rflags),
+	REG_OFFSET (cs),
+	REG_OFFSET (ss),
+	REG_OFFSET (ds),
+	REG_OFFSET (es),
+	REG_OFFSET (fs),
+	REG_OFFSET (gs)
+};
+
+
+void
+haiku_supply_registers(int reg, const debug_cpu_state *cpuState)
+{
+	if (reg == -1) {
+		int i;
+		for (i = 0; i < NUM_REGS; i++)
+			haiku_supply_registers(i, cpuState);
+	} else if (reg < AMD64_ST0_REGNUM) {
+		int offset = kHaikuAMD64RegOffset[reg];
+		regcache_raw_supply (current_regcache, reg, (char*)cpuState + offset);
+	} else {
+		amd64_supply_fxsave (current_regcache, -1,
+			&cpuState->extended_registers);
+	}
+}
+
+
+void
+haiku_collect_registers(int reg, debug_cpu_state *cpuState)
+{
+	if (reg == -1) {
+		int i;
+		for (i = 0; i < NUM_REGS; i++)
+			haiku_collect_registers(i, cpuState);
+	} else if (reg < AMD64_ST0_REGNUM) {
+		int offset = kHaikuAMD64RegOffset[reg];
+		regcache_raw_collect (current_regcache, reg, (char*)cpuState + offset);
+	} else {
+		amd64_collect_fxsave (current_regcache, -1,
+			&cpuState->extended_registers);
+	}
+}
+
diff --git a/gdb/amd64-haiku-tdep.c b/gdb/amd64-haiku-tdep.c
new file mode 100644
index 0000000..5923e58
--- /dev/null
+++ b/gdb/amd64-haiku-tdep.c
@@ -0,0 +1,61 @@
+/* Target-dependent code for Haiku x86_64.
+
+   Copyright 2012 Alex Smith <alex@alex-smith.me.uk>.
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbarch.h"
+#include "amd64-tdep.h"
+#include "osabi.h"
+
+
+static void
+amd64_haiku_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+	struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+	amd64_init_abi (info, gdbarch);
+
+	// the offset of the PC in the jmp_buf structure (cf. setjmp(), longjmp())
+	tdep->jb_pc_offset = 0;
+}
+
+
+static enum gdb_osabi
+amd64_haiku_osabi_sniffer (bfd * abfd)
+{ 
+	char *targetName = bfd_get_target (abfd);
+
+	if (strcmp (targetName, "elf64-x86-64") == 0)
+		return GDB_OSABI_HAIKU;
+
+	return GDB_OSABI_UNKNOWN;
+}
+
+
+void
+_initialize_amd64_haiku_tdep (void)
+{
+	gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
+		amd64_haiku_osabi_sniffer);
+
+	gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, GDB_OSABI_HAIKU,
+		amd64_haiku_init_abi);
+}
diff --git a/gdb/config/i386/haiku.mh b/gdb/config/i386/haiku.mh
new file mode 100644
index 0000000..d4212db
--- /dev/null
+++ b/gdb/config/i386/haiku.mh
@@ -0,0 +1,7 @@
+# Host: Intel 586 running Haiku
+
+NAT_FILE= nm-haiku.h
+NATDEPFILES= haiku-nat.o i386-haiku-nat.o inf-child.o fork-child.o
+
+# No core file support yet.
+# corelow.o core-aout.o
diff --git a/gdb/config/i386/haiku.mt b/gdb/config/i386/haiku.mt
new file mode 100644
index 0000000..e60affb
--- /dev/null
+++ b/gdb/config/i386/haiku.mt
@@ -0,0 +1,5 @@
+# Target: Intel 586 running Haiku
+
+TDEPFILES= i386-tdep.o i386-haiku-tdep.o haiku-tdep.o i387-tdep.o \
+	solib.o solib-haiku.o symfile-mem.o
+DEPRECATED_TM_FILE= tm-haiku.h
diff --git a/gdb/config/i386/nm-haiku.h b/gdb/config/i386/nm-haiku.h
new file mode 100644
index 0000000..b392360
--- /dev/null
+++ b/gdb/config/i386/nm-haiku.h
@@ -0,0 +1,27 @@
+/* Native support for Haiku x86.
+
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef NM_HAIKU_H
+#define NM_HAIKU_H
+
+#include "config/nm-haiku.h"
+
+#endif /* nm-haiku.h */
diff --git a/gdb/config/i386/tm-haiku.h b/gdb/config/i386/tm-haiku.h
new file mode 100644
index 0000000..badfc7e
--- /dev/null
+++ b/gdb/config/i386/tm-haiku.h
@@ -0,0 +1,27 @@
+/* Definitions to target GDB to Haiku on 386.
+
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef TM_HAIKU_H
+#define TM_HAIKU_H
+
+#include "config/tm-haiku.h"
+
+#endif /* #ifndef TM_HAIKU_H */
diff --git a/gdb/config/nm-haiku.h b/gdb/config/nm-haiku.h
new file mode 100644
index 0000000..e85a1c2
--- /dev/null
+++ b/gdb/config/nm-haiku.h
@@ -0,0 +1,25 @@
+/* Native support Haiku.
+
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+// #define REALTIME_{LO,HI}?
+
+/* Support for shared libraries.  */
+#include "solib.h"
diff --git a/gdb/config/tm-haiku.h b/gdb/config/tm-haiku.h
new file mode 100644
index 0000000..cdead7b
--- /dev/null
+++ b/gdb/config/tm-haiku.h
@@ -0,0 +1,25 @@
+/* Target support Haiku.
+
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+// #define REALTIME_{LO,HI}?
+
+/* Support for shared libraries.  */
+#include "solib.h"
diff --git a/gdb/configure.host b/gdb/configure.host
index f730891..867bef1 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -86,6 +86,7 @@ i[34567]86-*-unixware*)	gdb_host=i386v4 ;;
 i[34567]86-*-sysv*)	gdb_host=i386v ;;
 i[34567]86-*-isc*)	gdb_host=i386v ;;
 i[34567]86-*-cygwin*)	gdb_host=cygwin ;;
+i[567]86-*-haiku*)	gdb_host=haiku ;;
 
 ia64-*-aix*)		gdb_host=aix ;;
 ia64-*-linux*)		gdb_host=linux ;;
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 0b1f627..93ca8ae 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -98,6 +98,7 @@ i[34567]86-*-netware*)	gdb_target=i386
 			configdirs="${configdirs} nlm" ;;
 i[34567]86-*-cygwin*)	gdb_target=cygwin  ;;
 i[34567]86-*-vxworks*)	gdb_target=vxworks ;;
+i[34567]86-*-haiku*)	gdb_target=haiku ;;
 i[34567]86-*-*)		gdb_target=i386 ;;
 
 ia64-*-aix*)		gdb_target=aix ;;
diff --git a/gdb/defs.h b/gdb/defs.h
index fd96665..21dcda7 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -1052,6 +1052,8 @@ enum gdb_osabi
 
   GDB_OSABI_CYGWIN,
 
+  GDB_OSABI_HAIKU,
+
   GDB_OSABI_INVALID		/* keep this last */
 };
 
diff --git a/gdb/haiku-nat.c b/gdb/haiku-nat.c
new file mode 100644
index 0000000..01bc084
--- /dev/null
+++ b/gdb/haiku-nat.c
@@ -0,0 +1,1742 @@
+/* Haiku native-dependent code common to multiple platforms.
+
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <debugger.h>
+#include <image.h>
+#include <OS.h>
+
+#include <private/debug/debug_support.h>
+
+#include "defs.h"	// include this first -- otherwise "command.h" will choke
+#include "command.h"
+#include "gdbcore.h"
+#include "gdbthread.h"
+#include "haiku-nat.h"
+#include "inferior.h"
+#include "observer.h"
+#include "regcache.h"
+#include "solib-haiku.h"
+#include "symfile.h"
+#include "target.h"
+
+//#define TRACE_HAIKU_NAT
+#ifdef TRACE_HAIKU_NAT
+	#define TRACE(x)	printf x
+#else
+	#define TRACE(x)	while (false) {}
+#endif
+
+static struct target_ops *sHaikuTarget = NULL;
+
+typedef struct debug_event {
+	struct debug_event			*next;
+	debug_debugger_message		message;
+	debug_debugger_message_data	data;
+} debug_event;
+
+typedef struct debug_event_list {
+	debug_event		*head;
+	debug_event		*tail;
+} debug_event_list;
+
+typedef enum {
+	SIGNAL_ARRIVED,		// the signal has actually arrived and is going to be
+						// handled (in any way)
+	SIGNAL_WILL_ARRIVE,	// the signal has not yet been sent, but will be sent
+						// (e.g. an exception occurred and will cause the
+						// signal when not being ignored)
+	SIGNAL_FAKED,		// the signal didn't arrive and won't arrive, we faked
+						// it (often in case of SIGTRAP)
+} pending_signal_status;
+
+typedef struct thread_debug_info {
+	struct thread_debug_info	*next;
+	thread_id					thread;
+	bool						stopped;
+	debug_event					*last_event;		// last debug message from
+													// the thread; valid only,
+													// if stopped
+	int							reprocess_event;	// > 0, the event
+													// shall be processed a
+													// that many times, which
+													// will probably trigger
+													// another target event
+	int							signal;				// only valid, if stopped
+	pending_signal_status		signal_status;
+} thread_debug_info;
+
+typedef struct extended_image_info {
+	haiku_image_info			info;
+	struct extended_image_info	*next;
+} extended_image_info;
+
+typedef struct team_debug_info {
+	team_id				team;
+	port_id				debugger_port;
+	thread_id			nub_thread;
+	debug_context		context;
+	thread_debug_info	*threads;
+	extended_image_info	*images;
+	debug_event_list	events;
+} team_debug_info;
+
+static team_debug_info sTeamDebugInfo;
+
+
+typedef struct signal_map_entry {
+	enum target_signal	target;
+	int					haiku;
+} signal_map_entry;
+
+static const signal_map_entry sSignalMap[] = {
+	{ TARGET_SIGNAL_0,			0 },
+	{ TARGET_SIGNAL_HUP,		SIGHUP },
+	{ TARGET_SIGNAL_INT,		SIGINT },
+	{ TARGET_SIGNAL_QUIT,		SIGQUIT },
+	{ TARGET_SIGNAL_ILL,		SIGILL },
+	{ TARGET_SIGNAL_CHLD,		SIGCHLD },
+	{ TARGET_SIGNAL_ABRT,		SIGABRT },
+	{ TARGET_SIGNAL_PIPE,		SIGPIPE },
+	{ TARGET_SIGNAL_FPE,		SIGFPE },
+	{ TARGET_SIGNAL_KILL,		SIGKILL },
+	{ TARGET_SIGNAL_STOP,		SIGSTOP },
+	{ TARGET_SIGNAL_SEGV,		SIGSEGV },
+	{ TARGET_SIGNAL_CONT,		SIGCONT },
+	{ TARGET_SIGNAL_TSTP,		SIGTSTP },
+	{ TARGET_SIGNAL_ALRM,		SIGALRM },
+	{ TARGET_SIGNAL_TERM,		SIGTERM },
+	{ TARGET_SIGNAL_TTIN,		SIGTTIN },
+	{ TARGET_SIGNAL_TTOU,		SIGTTOU },
+	{ TARGET_SIGNAL_USR1,		SIGUSR1 },
+	{ TARGET_SIGNAL_USR2,		SIGUSR2 },
+	{ TARGET_SIGNAL_WINCH,		SIGWINCH },
+	{ TARGET_SIGNAL_TRAP,		SIGTRAP },
+	{ TARGET_SIGNAL_0,			SIGKILLTHR },	// not debuggable anyway
+	{ -1, -1 }
+};
+
+
+// #pragma mark -
+
+
+static char *haiku_pid_to_str (ptid_t ptid);
+
+
+static int
+target_to_haiku_signal(enum target_signal targetSignal)
+{
+	int i;
+
+	if (targetSignal < 0)
+		return -1;
+
+	for (i = 0; sSignalMap[i].target != -1 || sSignalMap[i].haiku != -1; i++) {
+		if (targetSignal == sSignalMap[i].target)
+			return sSignalMap[i].haiku;
+	}
+
+	return -1;
+}
+
+
+static enum target_signal
+haiku_to_target_signal(int haikuSignal)
+{
+	int i;
+
+	if (haikuSignal < 0)
+		return TARGET_SIGNAL_0;
+
+	for (i = 0; sSignalMap[i].target != -1 || sSignalMap[i].haiku != -1; i++) {
+		if (haikuSignal == sSignalMap[i].haiku)
+			return sSignalMap[i].target;
+	}
+
+	return TARGET_SIGNAL_UNKNOWN;
+}
+
+
+static thread_debug_info *
+haiku_find_thread(team_debug_info *teamDebugInfo, thread_id threadID)
+{
+	thread_debug_info *info;
+	for (info = teamDebugInfo->threads; info; info = info->next) {
+		if (info->thread == threadID)
+			return info;
+	}
+
+	return NULL;
+}
+
+
+static thread_debug_info *
+haiku_add_thread(team_debug_info *teamDebugInfo, thread_id threadID)
+{
+	struct thread_info *gdbThreadInfo;
+	thread_debug_info *threadDebugInfo;
+
+	if (threadID == teamDebugInfo->nub_thread) {
+		error("haiku_thread_added(): Trying to add debug nub thread (%ld)\n",
+			threadID);
+	}
+
+	// find the thread first
+	threadDebugInfo = haiku_find_thread(teamDebugInfo, threadID);
+	if (threadDebugInfo)
+		return threadDebugInfo;
+
+	// allocate a new thread debug info
+	threadDebugInfo = XMALLOC(thread_debug_info);
+	if (!threadDebugInfo)
+		error("haiku_thread_added(): Out of memory!\n");
+
+	// init and add it
+	threadDebugInfo->thread = threadID;
+	threadDebugInfo->next = teamDebugInfo->threads;
+	threadDebugInfo->stopped = false;
+	threadDebugInfo->last_event = NULL;
+	teamDebugInfo->threads = threadDebugInfo;
+
+	// add it to gdb's thread DB
+	gdbThreadInfo = add_thread(ptid_build(teamDebugInfo->team, 0, threadID));
+
+	// Note: In theory we could spare us the whole thread list management, since
+	// gdb's thread DB is doing exactly the same. We could put our data as
+	// thread_info::private. The only catch is that when the thread_info is
+	// freed, xfree() is invoked on the private data directly, but there's no
+	// callback invoked before that would allow us to do cleanup (e.g. free
+	// last_event).
+
+	TRACE(("haiku_add_thread(): team %ld thread %ld added: "
+		"gdb thread info: %p\n", teamDebugInfo->team, threadID, gdbThreadInfo));
+
+	return threadDebugInfo;
+}
+
+
+static void
+haiku_remove_thread(team_debug_info *teamDebugInfo, thread_id threadID)
+{
+	thread_debug_info **info;
+	for (info = &teamDebugInfo->threads; *info; info = &(*info)->next) {
+		if ((*info)->thread == threadID) {
+			thread_debug_info *foundInfo = *info;
+			*info = foundInfo->next;
+			if (foundInfo->last_event)
+				xfree(foundInfo->last_event);
+			xfree(foundInfo);
+
+			// remove it from gdb's thread DB
+			delete_thread(ptid_build(teamDebugInfo->team, 0, threadID));
+
+			return;
+		}
+	}
+}
+
+
+static void
+haiku_init_thread_list(team_debug_info *teamDebugInfo)
+{
+	thread_info threadInfo;
+	int32 cookie = 0;
+
+	// init gdb's thread DB
+	init_thread_list();
+
+	while (get_next_thread_info(teamDebugInfo->team, &cookie, &threadInfo)
+		== B_OK) {
+		if (threadInfo.thread != teamDebugInfo->nub_thread)
+			haiku_add_thread(teamDebugInfo, threadInfo.thread);
+	}
+}
+
+
+static void
+haiku_cleanup_thread_list(team_debug_info *teamDebugInfo)
+{
+	while (teamDebugInfo->threads) {
+		thread_debug_info *thread = teamDebugInfo->threads;
+		teamDebugInfo->threads = thread->next;
+		xfree(thread);
+	}
+
+	// clear gdb's thread DB
+	init_thread_list();
+}
+
+
+// #pragma mark -
+
+static extended_image_info **
+haiku_find_image_insert_location(team_debug_info *teamDebugInfo,
+	image_id imageID)
+{
+	extended_image_info **image;
+
+	for (image = &teamDebugInfo->images; *image; image = &(*image)->next) {
+		if ((*image)->info.id >= imageID)
+			return image;
+	}
+
+	return image;
+}
+
+
+static extended_image_info *
+haiku_find_image(team_debug_info *teamDebugInfo, image_id imageID)
+{
+	extended_image_info *image = *haiku_find_image_insert_location(
+		teamDebugInfo, imageID);
+
+	return (image && image->info.id == imageID ? image : NULL);
+}
+
+
+static extended_image_info *
+haiku_add_image(team_debug_info *teamDebugInfo, image_info *imageInfo)
+{
+	extended_image_info **imageP = haiku_find_image_insert_location(
+		teamDebugInfo, imageInfo->id);
+	extended_image_info *image = *imageP;
+
+	// already known?
+	if (image && image->info.id == imageInfo->id)
+		return image;
+
+	image = XMALLOC(extended_image_info);
+	if (!image)
+		error("haiku_add_image(): Out of memory!");
+
+	image->info.id = imageInfo->id;
+	strncpy(image->info.name, imageInfo->name, sizeof(image->info.name));
+	image->info.name[sizeof(image->info.name) - 1] = '\0';
+		// TODO: This should be the shared objects soname, not the path. We
+		// probably need to extend the debugger API.
+	strncpy(image->info.path, imageInfo->name, sizeof(image->info.path));
+	image->info.path[sizeof(image->info.path) - 1] = '\0';
+	image->info.text_address = (CORE_ADDR)imageInfo->text;
+	image->info.text_size = imageInfo->text_size;
+	image->info.data_address = (CORE_ADDR)imageInfo->data;
+	image->info.data_size = imageInfo->data_size;
+	image->info.is_app_image = (imageInfo->type == B_APP_IMAGE);
+
+	image->next = *imageP;
+	*imageP = image;
+
+	return image;
+}
+
+
+static void
+haiku_remove_image(team_debug_info *teamDebugInfo, image_id imageID)
+{
+	extended_image_info **imageP = haiku_find_image_insert_location(
+		teamDebugInfo, imageID);
+	extended_image_info *image = *imageP;
+
+	if (image && image->info.id == imageID) {
+		*imageP = image->next;
+		xfree(image);
+	}
+}
+
+
+static void
+haiku_init_image_list(team_debug_info *teamDebugInfo)
+{
+	int32 cookie = 0;
+	image_info info;
+	while (get_next_image_info(teamDebugInfo->team, &cookie, &info) == B_OK)
+		haiku_add_image(teamDebugInfo, &info);
+}
+
+
+static void
+haiku_cleanup_image_list(team_debug_info *teamDebugInfo)
+{
+	while (teamDebugInfo->images) {
+		extended_image_info *image = teamDebugInfo->images;
+		teamDebugInfo->images = image->next;
+		xfree(image);
+	}
+}
+
+
+/*
+ * Service function. Call with -1 the first time.
+ */
+struct haiku_image_info *
+haiku_get_next_image_info(int lastID)
+{
+	extended_image_info *image = *haiku_find_image_insert_location(
+		&sTeamDebugInfo, (lastID >= 0 ? lastID : 0));
+
+	if (image && image->info.id == lastID)
+		image = image->next;
+
+	return (image ? &image->info : NULL);
+}
+
+
+// #pragma mark -
+
+static debug_event *
+haiku_enqueue_debug_event(debug_event_list *list, int32 message,
+	debug_debugger_message_data *data, int32 size)
+{
+	debug_event *event = XMALLOC(debug_event);
+
+	if (!event)
+		error("haiku_enqueue_debug_event(): Out of memory!\n");
+
+	// init the event
+	event->next = NULL;
+	event->message = message;
+	memcpy(&event->data, data,
+		(size >= 0 ? size : sizeof(debug_debugger_message_data)));
+
+	// add it to the queue
+	if (list->tail) {
+		list->tail->next = event;
+		list->tail = event;
+	} else {
+		list->head = list->tail = event;
+	}
+
+	return event;
+}
+
+
+static debug_event *
+haiku_dequeue_next_debug_event(debug_event_list *list)
+{
+	debug_event *event = list->head;
+
+	if (event) {
+		// remove it from the queue
+		list->head = event->next;
+		if (list->tail == event)
+			list->tail = NULL;
+
+		event->next = NULL;	// just because we're paranoid
+	}
+
+	return event;
+}
+
+
+static debug_event *
+haiku_remove_debug_event(debug_event_list *list, debug_event *eventToRemove)
+{
+	debug_event **event;
+
+	if (eventToRemove) {
+		for (event = &list->head; *event; event = &(*event)->next) {
+			if (*event == eventToRemove) {
+				*event = (*event)->next;
+				if (eventToRemove == list->tail)
+					list->tail = NULL;
+				return eventToRemove;
+			}
+		}
+	}
+
+	error("haiku_remove_debug_event(): event %p not found in list %p\n",
+		eventToRemove, list);
+
+	return NULL;
+}
+
+
+static void
+haiku_clear_debug_event_list(debug_event_list *list)
+{
+	debug_event *event;
+
+	while ((event = haiku_dequeue_next_debug_event(list)))
+		xfree(event);
+}
+
+
+static debug_event *
+haiku_find_next_debug_event(debug_event_list *list,
+	bool (*predicate)(void *closure, debug_event *event), void *closure)
+{
+	debug_event *event;
+
+	for (event = list->head; event; event = event->next) {
+		if ((*predicate)(closure, event))
+			return event;
+	}
+
+	return NULL;
+}
+
+
+static void
+haiku_read_pending_debug_events(team_debug_info *teamDebugInfo,
+	bool block, bool (*block_predicate)(void *closure, debug_event *event),
+	void *closure)
+{
+	while (true) {
+		// read the next message from the debugger port
+		debug_debugger_message_data message;
+		int32 code;
+		ssize_t bytesRead;
+		debug_event *event;
+
+//		TRACE(("haiku_read_pending_debug_events(): reading from debugger port "
+//			"(%sblocking)...\n", (block ? "" : "non-")));
+
+		do {
+			bytesRead = read_port_etc(teamDebugInfo->debugger_port, &code,
+				&message, sizeof(message), (block ? 0 : B_RELATIVE_TIMEOUT), 0);
+		} while (bytesRead == B_INTERRUPTED);
+
+		if (bytesRead < 0) {
+			if (bytesRead == B_WOULD_BLOCK && !block)
+				break;
+
+			error("Failed to read from debugger port: %s\n",
+				strerror(bytesRead));
+		}
+
+//		TRACE(("haiku_read_pending_debug_events(): got event: %lu, "
+//			"thread: %ld, team: %ld, nub port: %ld\n", code,
+//			message.origin.thread, message.origin.team,
+//			message.origin.nub_port));
+
+		// got a message: queue it
+		event = haiku_enqueue_debug_event(&teamDebugInfo->events, code,
+			&message, bytesRead);
+
+		block = !(*block_predicate)(closure, event);
+	}
+}
+
+
+typedef struct thread_event_closure {
+	team_debug_info	*context;
+	thread_id		thread;
+	debug_event		*event;
+} thread_event_closure;
+
+
+static bool
+haiku_thread_event_predicate(void *_closure, debug_event *event)
+{
+	thread_event_closure *closure = (thread_event_closure*)_closure;
+
+	if (event->message == B_DEBUGGER_MESSAGE_TEAM_DELETED) {
+		if (closure->context->team < 0
+			|| event->data.origin.team == closure->context->team) {
+			closure->event = event;
+		}
+	}
+
+	if (!closure->event) {
+		if (event->data.origin.team == closure->context->team
+			&& (closure->thread < 0
+				|| closure->thread == event->data.origin.thread)) {
+			closure->event = event;
+		}
+	}
+
+	return (closure->event != NULL);
+}
+
+
+// #pragma mark -
+
+static void
+haiku_cleanup_team_debug_info()
+{
+	destroy_debug_context(&sTeamDebugInfo.context);
+	delete_port(sTeamDebugInfo.debugger_port);
+	sTeamDebugInfo.debugger_port = -1;
+	sTeamDebugInfo.team = -1;
+
+	haiku_cleanup_thread_list(&sTeamDebugInfo);
+	haiku_cleanup_image_list(&sTeamDebugInfo);
+}
+
+
+static status_t
+haiku_send_debugger_message(team_debug_info *teamDebugInfo, int32 messageCode,
+	const void *message, int32 messageSize, void *reply, int32 replySize)
+{
+	return send_debug_message(&teamDebugInfo->context, messageCode,
+		message, messageSize, reply, replySize);
+}
+
+
+static void
+haiku_init_child_debugging (thread_id threadID, bool debugThread)
+{
+	thread_info threadInfo;
+	status_t result;
+	port_id nubPort;
+
+	// get a thread info
+	result = get_thread_info(threadID, &threadInfo);
+	if (result != B_OK)
+		error("Thread with ID %ld not found: %s", threadID, strerror(result));
+
+	// init our team debug structure
+	sTeamDebugInfo.team = threadInfo.team;
+	sTeamDebugInfo.debugger_port = -1;
+	sTeamDebugInfo.context.nub_port = -1;
+	sTeamDebugInfo.context.reply_port = -1;
+	sTeamDebugInfo.threads = NULL;
+	sTeamDebugInfo.events.head = NULL;
+	sTeamDebugInfo.events.tail = NULL;
+
+	// create the debugger port
+	sTeamDebugInfo.debugger_port = create_port(10, "gdb debug");
+	if (sTeamDebugInfo.debugger_port < 0) {
+		error("Failed to create debugger port: %s",
+			strerror(sTeamDebugInfo.debugger_port));
+	}
+
+	// install ourselves as the team debugger
+	nubPort = install_team_debugger(sTeamDebugInfo.team,
+		sTeamDebugInfo.debugger_port);
+	if (nubPort < 0) {
+		error("Failed to install ourselves as debugger for team %ld: %s",
+			sTeamDebugInfo.team, strerror(nubPort));
+	}
+
+	// get the nub thread
+	{
+		team_info teamInfo;
+		result = get_team_info(sTeamDebugInfo.team, &teamInfo);
+		if (result != B_OK) {
+			error("Failed to get info for team %ld: %s\n",
+				sTeamDebugInfo.team, strerror(result));
+		}
+
+		sTeamDebugInfo.nub_thread = teamInfo.debugger_nub_thread;
+	}
+
+	// init the debug context
+	result = init_debug_context(&sTeamDebugInfo.context, sTeamDebugInfo.team,
+		nubPort);
+	if (result != B_OK) {
+		error("Failed to init debug context for team %ld: %s\n",
+			sTeamDebugInfo.team, strerror(result));
+	}
+
+	// start debugging the thread
+	if (debugThread) {
+		result = debug_thread(threadID);
+		if (result != B_OK) {
+			error("Failed to start debugging thread %ld: %s", threadID,
+				strerror(result));
+		}
+	}
+
+	// set the team debug flags
+	{
+		debug_nub_set_team_flags message;
+		message.flags = B_TEAM_DEBUG_SIGNALS /*| B_TEAM_DEBUG_PRE_SYSCALL
+			| B_TEAM_DEBUG_POST_SYSCALL*/ | B_TEAM_DEBUG_TEAM_CREATION
+			| B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES;
+			// TODO: We probably don't need all events
+
+		haiku_send_debugger_message(&sTeamDebugInfo,
+			B_DEBUG_MESSAGE_SET_TEAM_FLAGS, &message, sizeof(message), NULL, 0);
+	}
+
+
+	// the fun can start: push the target and init the rest
+	push_target(sHaikuTarget);
+
+	haiku_init_thread_list(&sTeamDebugInfo);
+	haiku_init_image_list(&sTeamDebugInfo);
+
+	disable_breakpoints_in_shlibs (1);
+
+//	child_clear_solibs ();
+		// TODO: Implement? Do we need this?
+
+	clear_proceed_status ();
+	init_wait_for_inferior ();
+
+	target_terminal_init ();
+	target_terminal_inferior ();
+}
+
+
+static void
+haiku_continue_thread(team_debug_info *teamDebugInfo, thread_id threadID,
+	uint32 handleEvent, bool step)
+{
+	debug_nub_continue_thread message;
+	status_t err;
+
+	message.thread = threadID;
+	message.handle_event = handleEvent;
+	message.single_step = step;
+
+	err = haiku_send_debugger_message(teamDebugInfo,
+		B_DEBUG_MESSAGE_CONTINUE_THREAD, &message, sizeof(message), NULL, 0);
+	if (err != B_OK) {
+		printf_unfiltered ("Failed to resume thread %ld: %s\n", threadID,
+			strerror(err));
+	}
+}
+
+
+static status_t
+haiku_stop_thread(team_debug_info *teamDebugInfo, thread_id threadID)
+{
+	// check whether we know the thread
+	status_t err;
+	thread_event_closure threadEventClosure;
+
+	thread_debug_info *threadInfo = haiku_find_thread(teamDebugInfo, threadID);
+	if (!threadInfo)
+		return B_BAD_THREAD_ID;
+
+	// already stopped?
+	if (threadInfo->stopped)
+		return B_OK;
+
+	// debug the thread
+	err = debug_thread(threadID);
+	if (err != B_OK) {
+		TRACE(("haiku_stop_thread(): failed to debug thread %ld: %s\n",
+			threadID, strerror(err)));
+		return err;
+	}
+
+	// wait for the event to hit our port
+
+	// TODO: debug_thread() doesn't guarantee that the thread will enter the
+	// debug loop any time soon. E.g. a wait_for_thread() is (at the moment)
+	// not interruptable, so we block here forever, if we already debug the
+	// thread that is being waited for. We should probably limit the time
+	// we're waiting, and return the info to the caller, which can then try
+	// to deal with the situation in an appropriate way.
+
+	// prepare closure for finding interesting events
+	threadEventClosure.context = teamDebugInfo;
+	threadEventClosure.thread = threadID;
+	threadEventClosure.event = NULL;
+
+	// find the first interesting queued event
+	threadEventClosure.event = haiku_find_next_debug_event(
+		&teamDebugInfo->events, haiku_thread_event_predicate,
+		&threadEventClosure);
+
+	// read all events pending on the port
+	haiku_read_pending_debug_events(teamDebugInfo,
+		(threadEventClosure.event == NULL), haiku_thread_event_predicate,
+		&threadEventClosure);
+
+	// We should check, whether we really got an event for the thread in
+	// question, but the only possible other event is that the team has
+	// been delete, which ends the game anyway.
+
+	// TODO: That's actually not true. We also get messages when an add-on
+	// has been loaded/unloaded, a signal arrives, or a thread calls the
+	// debugger.
+
+	return B_OK;
+}
+
+
+static status_t
+haiku_get_cpu_state(team_debug_info *teamDebugInfo,
+	debug_nub_get_cpu_state_reply *reply)
+{
+	status_t err;
+	thread_id threadID = ptid_get_tid(inferior_ptid);
+	debug_nub_get_cpu_state message;
+
+	// make sure the thread is stopped
+	err = haiku_stop_thread(teamDebugInfo, threadID);
+	if (err != B_OK) {
+		printf_unfiltered ("Failed to stop thread %ld: %s\n",
+			threadID, strerror(err));
+		return err;
+	}
+
+	message.reply_port = teamDebugInfo->context.reply_port;
+	message.thread = threadID;
+
+	err = haiku_send_debugger_message(teamDebugInfo,
+		B_DEBUG_MESSAGE_GET_CPU_STATE, &message, sizeof(message), reply,
+		sizeof(*reply));
+	if (err == B_OK)
+		err = reply->error;
+	if (err != B_OK) {
+		printf_unfiltered ("Failed to get status of thread %ld: %s\n",
+			threadID, strerror(err));
+	}
+
+	return err;
+}
+
+
+// #pragma mark -
+
+static void
+haiku_child_open (char *arg, int from_tty)
+{
+	error ("Use the \"run\" command to start a child process.");
+}
+
+static void
+haiku_child_close (int x)
+{
+	printf_unfiltered ("gdb: child_close, inferior_ptid=%d\n",
+		PIDGET (inferior_ptid));
+}
+
+
+static void
+haiku_child_attach (char *args, int from_tty)
+{
+	extern int stop_after_trap;
+	thread_id threadID;
+	thread_info threadInfo;
+	status_t result;
+
+	TRACE(("haiku_child_attach(`%s', %d)\n", args, from_tty));
+
+	if (!args)
+		error_no_arg ("thread-id to attach");
+
+	// get the thread ID
+	threadID = strtoul (args, 0, 0);
+	if (threadID <= 0)
+		error("The given thread-id %ld is invalid.", threadID);
+
+	haiku_init_child_debugging(threadID, true);
+
+	TRACE(("haiku_child_attach() done\n"));
+}
+
+
+static void
+haiku_child_detach (char *args, int from_tty)
+{
+	int detached = 1;
+	status_t result;
+
+	TRACE(("haiku_child_detach(`%s', %d)\n", args, from_tty));
+
+	result = remove_team_debugger(sTeamDebugInfo.team);
+	if (result != B_OK) {
+		error("Failed to detach process %ld: %s\n", sTeamDebugInfo.team,
+			strerror(result));
+	}
+
+	delete_command (NULL, 0);
+
+	if (from_tty) {
+		char *exec_file = get_exec_file (0);
+		if (exec_file == 0)
+			exec_file = "";
+		printf_unfiltered ("Detaching from program: %s, Pid %ld\n", exec_file,
+			sTeamDebugInfo.team);
+		gdb_flush (gdb_stdout);
+	}
+
+	haiku_cleanup_team_debug_info();
+
+	inferior_ptid = null_ptid;
+	unpush_target (sHaikuTarget);
+}
+
+
+static void
+haiku_resume_thread(team_debug_info *teamDebugInfo, thread_debug_info *thread,
+	int step, enum target_signal sig)
+{
+	thread_id threadID = (thread ? thread->thread : -1);
+	int pendingSignal = -1;
+	int signalToSend = target_to_haiku_signal(sig);
+	uint32 handleEvent = B_THREAD_DEBUG_HANDLE_EVENT;
+
+	if (!thread || !thread->stopped) {
+		TRACE(("haiku_resume_thread(): thread %ld not stopped\n",
+			threadID));
+		return;
+	}
+
+	if (thread->reprocess_event > 0) {
+		TRACE(("haiku_resume_thread(): thread %ld is expected to "
+			"reprocess its current event\n", threadID));
+		return;
+	}
+
+	// get the pending signal
+	if (thread->last_event)
+		pendingSignal = thread->signal;
+
+	// Decide what to do with the event and the pending and passed signal.
+	// We simply adjust signalToSend, pendingSignal and handleEvent.
+	// If signalToSend is set afterwards, we need to send it. pendingSignal we
+	// need to ignore. handleEvent specifies whether to handle/ignore the event.
+	if (signalToSend > 0) {
+		if (pendingSignal > 0) {
+			if (signalToSend == pendingSignal) {
+				// signal to send is the pending signal
+				// we don't need to send it
+				signalToSend = -1;
+				if (thread->signal_status != SIGNAL_WILL_ARRIVE) {
+					// the signal has not yet been sent, so we need to ignore
+					// it only in this case, but not in the other ones
+					pendingSignal = -1;
+				}
+			} else {
+				// signal to send is not the pending signal
+				// If the signal has been sent or will be sent, we need to
+				// ignore the event.
+				if (thread->signal_status != SIGNAL_FAKED)
+					handleEvent = B_THREAD_DEBUG_IGNORE_EVENT;
+				// At any rate we don't need to ignore the signal.
+				pendingSignal = -1;
+				// send the signal
+			}
+		} else {
+			// there's a signal to send, but no pending signal
+			// handle the event
+			// ignore the signal
+			// send the signal
+		}
+	} else {
+		if (pendingSignal > 0) {
+			// there's a pending signal, but no signal to send
+			// Ignore the event, if the signal has been sent or will be sent.
+			if (thread->signal_status != SIGNAL_FAKED)
+				handleEvent = B_THREAD_DEBUG_IGNORE_EVENT;
+		} else {
+			// there're neither signal to send nor pending signal
+			// handle the event
+		}
+	}
+
+	// ignore the pending signal, if necessary
+	if (pendingSignal > 0) {
+		debug_nub_set_signal_masks message;
+		status_t err;
+
+		message.thread = threadID;
+		message.ignore_mask = 0;
+		message.ignore_once_mask = B_DEBUG_SIGNAL_TO_MASK(pendingSignal);
+		message.ignore_op = B_DEBUG_SIGNAL_MASK_OR;
+		message.ignore_once_op = B_DEBUG_SIGNAL_MASK_OR;
+
+		err = haiku_send_debugger_message(teamDebugInfo,
+			B_DEBUG_MESSAGE_SET_SIGNAL_MASKS, &message, sizeof(message),
+			NULL, 0);
+		if (err != B_OK) {
+			printf_unfiltered ("Set signal ignore masks for thread %ld: %s\n",
+				threadID, strerror(err));
+		}
+	}
+
+	// send the signal
+	if (signalToSend > 0) {
+		if (send_signal(threadID, signalToSend) < 0) {
+			printf_unfiltered ("Failed to send signal %d to thread %ld: %s\n",
+				signalToSend, threadID, strerror(errno));
+		}
+	}
+
+	// resume thread
+	haiku_continue_thread(teamDebugInfo, threadID, handleEvent, step);
+	thread->stopped = false;
+}
+
+
+static void
+haiku_child_resume (ptid_t ptid, int step, enum target_signal sig)
+{
+	team_id teamID = ptid_get_pid(ptid);
+	thread_id threadID = ptid_get_tid(ptid);
+	thread_debug_info *thread;
+
+	TRACE(("haiku_child_resume(`%s', step: %d, signal: %d)\n",
+		haiku_pid_to_str(ptid), step, sig));
+
+	if (teamID < 0) {
+		// resume all stopped threads (at least all haiku_wait_child() has
+		// reported to be stopped)
+		for (thread = sTeamDebugInfo.threads; thread; thread = thread->next) {
+			if (thread->stopped)
+				haiku_resume_thread(&sTeamDebugInfo, thread, step, sig);
+		}
+	} else {
+		// resume the thread in question
+		thread = haiku_find_thread(&sTeamDebugInfo, threadID);
+		if (thread) {
+			haiku_resume_thread(&sTeamDebugInfo, thread, step, sig);
+		} else {
+			printf_unfiltered ("haiku_child_resume(): unknown thread %ld\n",
+				threadID);
+		}
+	}
+
+}
+
+
+static ptid_t
+haiku_child_wait_internal (team_debug_info *teamDebugInfo, ptid_t ptid,
+	struct target_waitstatus *ourstatus, bool *ignore, bool *selectThread)
+{
+	team_id teamID = ptid_get_pid(ptid);
+	team_id threadID = ptid_get_tid(ptid);
+	debug_event *event = NULL;
+	ptid_t retval = pid_to_ptid(-1);
+	struct thread_debug_info *thread;
+	int pendingSignal = -1;
+	pending_signal_status pendingSignalStatus = SIGNAL_FAKED;
+	int reprocessEvent = -1;
+
+	*selectThread = false;
+
+	if (teamID < 0 || threadID == 0)
+		threadID = -1;
+
+	// if we're waiting for any thread, search the thread list for already
+	// stopped threads (needed for reprocessing events)
+	if (threadID < 0) {
+		for (thread = teamDebugInfo->threads; thread; thread = thread->next) {
+			if (thread->stopped) {
+				threadID = thread->thread;
+				break;
+			}
+		}
+	}
+
+	// check, if the thread exists and is already stopped
+	if (threadID >= 0
+		&& (thread = haiku_find_thread(teamDebugInfo, threadID)) != NULL
+		&& thread->stopped) {
+		// remove the event that stopped the thread from the thread (we will
+		// add it again, if it shall not be ignored)
+		event = thread->last_event;
+		thread->last_event = NULL;
+		thread->stopped = false;
+		reprocessEvent = thread->reprocess_event;
+
+		TRACE(("haiku_child_wait_internal(): thread %ld already stopped. "
+			"re-digesting the last event (%p).\n", threadID, event));
+	} else {
+		// prepare closure for finding interesting events
+		thread_event_closure threadEventClosure;
+		threadEventClosure.context = teamDebugInfo;
+		threadEventClosure.thread = threadID;
+		threadEventClosure.event = NULL;
+
+		// find the first interesting queued event
+		threadEventClosure.event = haiku_find_next_debug_event(
+			&teamDebugInfo->events, haiku_thread_event_predicate,
+			&threadEventClosure);
+
+		// read all events pending on the port
+		haiku_read_pending_debug_events(teamDebugInfo,
+			(threadEventClosure.event == NULL), haiku_thread_event_predicate,
+			&threadEventClosure);
+
+		// get the event of interest
+		event = haiku_remove_debug_event(&teamDebugInfo->events,
+			threadEventClosure.event);
+
+		if (!event) {
+			TRACE(("haiku_child_wait_internal(): got no event!\n"));
+			return retval;
+		}
+
+		TRACE(("haiku_child_wait_internal(): got event: %u, thread: %ld, "
+			"team: %ld, nub port: %ld\n", event->message,
+			event->data.origin.thread, event->data.origin.team,
+			event->data.origin.nub_port));
+	}
+
+	if (event->data.origin.team != teamDebugInfo->team) {
+		// Spurious debug message. Doesn't concern our team. Ignore.
+		xfree(event);
+		return retval;
+	}
+
+	retval = ptid_build(event->data.origin.team, 0, event->data.origin.thread);
+
+	*ignore = false;
+
+	switch (event->message) {
+		case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
+		{
+			// print the debugger message
+			char debuggerMessage[1024];
+			ssize_t bytesRead = debug_read_string(&teamDebugInfo->context,
+				event->data.debugger_call.message, debuggerMessage,
+				sizeof(debuggerMessage));
+			if (bytesRead > 0) {
+				printf_unfiltered ("Thread %ld called debugger(): %s\n",
+					event->data.origin.thread, debuggerMessage);
+			} else {
+				printf_unfiltered ("Thread %ld called debugger(), but failed"
+					"to get the debugger message.\n",
+					event->data.origin.thread);
+			}
+
+			// fall through...
+		}
+		case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
+		case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
+		case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
+		case B_DEBUGGER_MESSAGE_SINGLE_STEP:
+			ourstatus->kind = TARGET_WAITKIND_STOPPED;
+			ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+			pendingSignal = SIGTRAP;
+			pendingSignalStatus = SIGNAL_FAKED;
+			break;
+
+		case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
+			ourstatus->kind = TARGET_WAITKIND_SYSCALL_ENTRY;
+			ourstatus->value.syscall_id = event->data.pre_syscall.syscall;
+			break;
+
+		case B_DEBUGGER_MESSAGE_POST_SYSCALL:
+			ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
+			ourstatus->value.syscall_id = event->data.post_syscall.syscall;
+			break;
+
+		case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
+			pendingSignal = event->data.signal_received.signal;
+			pendingSignalStatus = SIGNAL_ARRIVED;
+			ourstatus->kind = TARGET_WAITKIND_STOPPED;
+			ourstatus->value.sig = haiku_to_target_signal(pendingSignal);
+			break;
+
+		case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
+		{
+			// print the exception message
+			char exception[1024];
+			get_debug_exception_string(event->data.exception_occurred.exception,
+				exception, sizeof(exception));
+			printf_unfiltered ("Thread %ld caused an exception: %s\n",
+				event->data.origin.thread, exception);
+
+			pendingSignal = event->data.exception_occurred.signal;
+			pendingSignalStatus = SIGNAL_WILL_ARRIVE;
+			ourstatus->kind = TARGET_WAITKIND_STOPPED;
+			ourstatus->value.sig = haiku_to_target_signal(pendingSignal);
+			break;
+		}
+
+		case B_DEBUGGER_MESSAGE_TEAM_CREATED:
+			// ignore
+			*ignore = true;
+			break;
+
+		case B_DEBUGGER_MESSAGE_TEAM_DELETED:
+			ourstatus->kind = TARGET_WAITKIND_EXITED;
+			ourstatus->value.integer = 0;
+				// TODO: Extend the debugger interface?
+			break;
+
+		case B_DEBUGGER_MESSAGE_THREAD_CREATED:
+		{
+			// internal bookkeeping only
+			thread_id newThread = event->data.thread_created.new_thread;
+			if (newThread != teamDebugInfo->nub_thread)
+				haiku_add_thread(teamDebugInfo, newThread);
+			*ignore = true;
+			break;
+		}
+
+		case B_DEBUGGER_MESSAGE_THREAD_DELETED:
+			// internal bookkeeping
+			haiku_remove_thread(teamDebugInfo,
+				event->data.thread_deleted.origin.thread);
+			*ignore = true;
+
+			// TODO: What if this is the current thread?
+			break;
+
+		case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
+			if (reprocessEvent < 0) {
+				// first time we see the event: update our image list
+//				haiku_add_image(teamDebugInfo,
+//					&event->data.image_created.info);
+haiku_cleanup_image_list(teamDebugInfo);
+haiku_init_image_list(teamDebugInfo);
+// TODO: We don't get events when images have been removed in preparation of
+// an exec*() yet.
+			}
+
+			ourstatus->kind = TARGET_WAITKIND_LOADED;
+			ourstatus->value.integer = 0;
+			if (event->data.image_created.info.type == B_APP_IMAGE) {
+				// An app image has been loaded, i.e. the application is now
+				// fully loaded. We need to send a TARGET_WAITKIND_LOADED
+				// first, so that GDB's shared object list is updated correctly.
+				// But we also need to send an TARGET_WAITKIND_EXECD event.
+				// We use the reprocessEvent mechanism here.
+
+				if (reprocessEvent == 2) {
+					// the second time the event is processed: send the `exec'
+					// event
+					if (inferior_ignoring_startup_exec_events > 0) {
+						// we shall not send an exec event, so we skip that
+						// and send the `trap' immediately
+TRACE(("haiku_child_wait_internal(): ignoring exec (%d)\n",
+inferior_ignoring_startup_exec_events));
+						inferior_ignoring_startup_exec_events--;
+						reprocessEvent = 1;
+					}
+				}
+
+				if (reprocessEvent < 0) {
+TRACE(("haiku_child_wait_internal(): B_APP_IMAGE created, reprocess < 0\n"));
+					// the first time the event is processed: send the
+					// `loaded' event
+					reprocessEvent = 2;
+				} else if (reprocessEvent == 2) {
+TRACE(("haiku_child_wait_internal(): B_APP_IMAGE created, reprocess -> exec\n"));
+					// the second time the event is processed: send the `exec'
+					// event
+					ourstatus->kind = TARGET_WAITKIND_EXECD;
+					ourstatus->value.execd_pathname
+						= event->data.image_created.info.name;
+
+					reprocessEvent = 1;
+				} else if (reprocessEvent <= 1) {
+					// the third time the event is processed: send the `trap'
+					// event
+					ourstatus->kind = TARGET_WAITKIND_STOPPED;
+					ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+					pendingSignal = SIGTRAP;
+					pendingSignalStatus = SIGNAL_FAKED;
+
+					reprocessEvent = 0;
+				}
+			}
+
+			// re_enable_breakpoints_in_shlibs ();
+				// TODO: Needed?
+			break;
+
+		case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
+			haiku_remove_image(teamDebugInfo,
+				event->data.image_deleted.info.id);
+
+			// send TARGET_WAITKIND_LOADED here too, it causes the shared
+			// object list to be updated
+			ourstatus->kind = TARGET_WAITKIND_LOADED;
+			ourstatus->value.integer = 0;
+			break;
+
+		case B_DEBUGGER_MESSAGE_HANDED_OVER:
+		{
+TRACE(("haiku_child_wait_internal(): B_DEBUGGER_MESSAGE_HANDED_OVER: causing "
+"thread: %ld\n", event->data.handed_over.causing_thread));
+			// The debugged team has been handed over to us by another debugger
+			// (likely the debug server). This event also tells us, which
+			// thread has caused the original debugger to be installed (if any).
+			// So, if we're not looking for any particular thread, select that
+			// thread.
+			if (threadID < 0 && event->data.handed_over.causing_thread >= 0) {
+				*selectThread = true;
+				retval = ptid_build(event->data.origin.team, 0,
+					event->data.handed_over.causing_thread);
+			}
+			*ignore = true;
+		}
+
+		default:
+			// unknown message, ignore
+			*ignore = true;
+			break;
+	}
+
+	// make the event the thread's last event or delete it
+	if (!*ignore && event->data.origin.thread >= 0) {
+		struct thread_debug_info *thread = haiku_find_thread(teamDebugInfo,
+			event->data.origin.thread);
+		if (thread->last_event)
+			xfree(thread->last_event);
+			thread->last_event = event;
+			thread->stopped = true;
+			thread->signal = pendingSignal;
+			thread->signal_status = pendingSignalStatus;
+			thread->reprocess_event
+				= (reprocessEvent >= 0 ? reprocessEvent : 0);
+	} else {
+		thread_id originThread = event->data.origin.thread;
+		xfree(event);
+
+		// continue the thread
+		if (originThread >= 0) {
+			haiku_continue_thread(teamDebugInfo, originThread,
+				B_THREAD_DEBUG_HANDLE_EVENT, false);
+		}
+
+//		*ignore = true;
+// TODO: This should indeed not be needed. It definitely eats the
+// `team deleted' events.
+	}
+
+	return retval;
+}
+
+
+static ptid_t
+haiku_child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+	ptid_t retval;
+	bool ignore = true;
+	bool selectThread = false;
+
+	TRACE(("haiku_child_wait(`%s', %p)\n",
+		haiku_pid_to_str(ptid), ourstatus));
+
+	do {
+		retval = haiku_child_wait_internal(&sTeamDebugInfo, ptid, ourstatus,
+			&ignore, &selectThread);
+		if (selectThread)
+			ptid = retval;
+	} while (ignore);
+
+	TRACE(("haiku_child_wait() done: `%s'\n", haiku_pid_to_str(retval)));
+
+	return retval;
+}
+
+
+static void
+haiku_child_fetch_inferior_registers (int reg)
+{
+	debug_nub_get_cpu_state_reply reply;
+
+	TRACE(("haiku_child_fetch_inferior_registers(%d)\n", reg));
+
+	// get the CPU state
+	haiku_get_cpu_state(&sTeamDebugInfo, &reply);
+
+// printf("haiku_child_fetch_inferior_registers(): eip: %p, ebp: %p\n",
+// (void*)reply.cpu_state.eip, (void*)reply.cpu_state.ebp);
+
+	// supply the registers (architecture specific)
+	haiku_supply_registers(reg, &reply.cpu_state);
+}
+
+
+static void
+haiku_child_store_inferior_registers (int reg)
+{
+	status_t err;
+	thread_id threadID = ptid_get_tid(inferior_ptid);
+	debug_nub_get_cpu_state_reply reply;
+	debug_nub_set_cpu_state message;
+
+	TRACE(("haiku_child_store_inferior_registers(%d)\n", reg));
+
+	// get the current CPU state
+	haiku_get_cpu_state(&sTeamDebugInfo, &reply);
+
+	// collect the registers (architecture specific)
+	haiku_collect_registers(reg, &reply.cpu_state);
+
+	// set the new CPU state
+	message.thread = threadID;
+	memcpy(&message.cpu_state, &reply.cpu_state, sizeof(debug_cpu_state));
+	err = haiku_send_debugger_message(&sTeamDebugInfo,
+		B_DEBUG_MESSAGE_SET_CPU_STATE, &message, sizeof(message), NULL, 0);
+	if (err != B_OK) {
+		printf_unfiltered ("Failed to set status of thread %ld: %s\n",
+			threadID, strerror(err));
+	}
+}
+
+static void
+haiku_child_prepare_to_store (void)
+{
+	// Since we always fetching the current state in
+	// haiku_child_store_inferior_registers(), this should be a no-op.
+}
+
+static int
+haiku_child_deprecated_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
+	int write, struct mem_attrib *attrib, struct target_ops *target)
+{
+	TRACE(("haiku_child_deprecated_xfer_memory(0x%8lx, %p, %d, %d, %p, %p)\n",
+		(uint32)memaddr, myaddr, len, write, attrib, target));
+
+	if (len <= 0)
+		return 0;
+
+	if (write) {
+		// write
+		debug_nub_write_memory message;
+		debug_nub_write_memory_reply reply;
+		status_t err;
+
+		if (len > B_MAX_READ_WRITE_MEMORY_SIZE)
+			len = B_MAX_READ_WRITE_MEMORY_SIZE;
+
+		message.reply_port = sTeamDebugInfo.context.reply_port;
+		message.address = (void*)memaddr;
+		message.size = len;
+		memcpy(message.data, myaddr, len);
+
+		err = haiku_send_debugger_message(&sTeamDebugInfo,
+			B_DEBUG_MESSAGE_WRITE_MEMORY, &message, sizeof(message), &reply,
+			sizeof(reply));
+		if (err != B_OK || reply.error != B_OK)
+{
+TRACE(("haiku_child_deprecated_xfer_memory() failed: %lx\n",
+(err != B_OK ? err : reply.error)));
+			return 0;
+}
+
+TRACE(("haiku_child_deprecated_xfer_memory(): -> %ld\n", reply.size));
+		return reply.size;
+	} else {
+		// read
+		ssize_t bytesRead = debug_read_memory_partial(&sTeamDebugInfo.context,
+			(const void *)memaddr, myaddr, len);
+		return (bytesRead < 0 ? 0 : bytesRead);
+	}
+
+	return -1;
+}
+
+LONGEST
+haiku_child_xfer_partial (struct target_ops *ops, enum target_object object,
+	const char *annex, void *readbuf, const void *writebuf, ULONGEST offset,
+	LONGEST len)
+{
+	if (!readbuf && !writebuf)
+		return -1;
+
+	switch (object) {
+		case TARGET_OBJECT_MEMORY:
+		{
+			int write = !readbuf;
+			return haiku_child_deprecated_xfer_memory (offset,
+				(write ? (void*)writebuf : readbuf), len, write, NULL, ops);
+		}
+	}
+
+	return -1;
+}
+
+static void
+haiku_child_files_info (struct target_ops *ignore)
+{
+  printf_unfiltered ("\tUsing the running image of %s %s.\n",
+      attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid));
+}
+
+static void
+haiku_child_kill_inferior (void)
+{
+	status_t err;
+	thread_id teamID = ptid_get_pid(inferior_ptid);
+
+	TRACE(("haiku_child_kill_inferior()\n"));
+
+	err = kill_team(teamID);
+	if (err != B_OK) {
+		printf_unfiltered ("Failed to kill team %ld: %s\n", teamID,
+			strerror(err));
+		return;
+	}
+
+	target_mourn_inferior();
+}
+
+static void
+haiku_child_stop_inferior (void)
+{
+	status_t err;
+	thread_id threadID = ptid_get_tid(inferior_ptid);
+
+	TRACE(("haiku_child_stop_inferior()\n"));
+
+	err = debug_thread(threadID);
+	if (err != B_OK) {
+		printf_unfiltered ("Failed to stop thread %ld: %s\n", threadID,
+			strerror(err));
+		return;
+	}
+}
+
+static void
+haiku_init_debug_create_inferior(int pid)
+{
+	extern int stop_after_trap;
+
+	// fix inferior_ptid -- fork_inferior() sets the process ID only
+	inferior_ptid = ptid_build (pid, 0, pid);
+		// team ID == team main thread ID under Haiku
+
+	haiku_init_child_debugging(pid, false);
+
+	// eat the initial `debugged' event caused by wait_for_inferior()
+// TODO: Maybe we should just dequeue the event and continue the thread instead
+// of using gdb's mechanism, since I don't know what undesired side-effects
+// they may have.
+	clear_proceed_status ();
+	init_wait_for_inferior ();
+
+	if (STARTUP_WITH_SHELL)
+		inferior_ignoring_startup_exec_events = 2;
+	else
+		inferior_ignoring_startup_exec_events = 1;
+	inferior_ignoring_leading_exec_events = 0;
+
+	while (true) {
+		thread_debug_info *thread;
+
+		stop_soon = STOP_QUIETLY;
+		wait_for_inferior();
+
+		if (stop_signal == TARGET_SIGNAL_TRAP) {
+			thread = haiku_find_thread(&sTeamDebugInfo, pid);
+
+			if (thread && thread->stopped
+				&& thread->last_event->message
+					== B_DEBUGGER_MESSAGE_IMAGE_CREATED
+				&& thread->last_event->data.image_created.info.type
+					== B_APP_IMAGE
+				&& thread->reprocess_event == 0
+				&& inferior_ignoring_startup_exec_events <= 0) {
+				// This is the trap for the last (second, if started via shell)
+				// `load app image' event. Be done.
+				break;
+			}
+		}
+
+		resume(0, stop_signal);
+	}
+	stop_soon = NO_STOP_QUIETLY;
+
+	// load shared library symbols
+	target_terminal_ours_for_output ();
+	SOLIB_ADD (NULL, 0, &current_target, auto_solib_add);
+	target_terminal_inferior ();
+
+//	startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+
+//while (1) {
+//	stop_after_trap = 1;
+//	wait_for_inferior ();
+//	if (debugThread && stop_signal != TARGET_SIGNAL_TRAP)
+//		resume (0, stop_signal);
+//	else
+//		break;
+//}
+//stop_after_trap = 0;
+
+
+
+//	while (1) {
+//		thread_debug_info *thread;
+//
+//		stop_after_trap = 1;
+//		wait_for_inferior ();
+//// TODO: Catch deadly events, so that we won't block here.
+//
+//		thread = haiku_find_thread(&sTeamDebugInfo, pid);
+//TRACE(("haiku_init_debug_create_inferior(): wait_for_inferior() returned: "
+//"thread: %p (%ld)\n", thread, (thread ? thread->thread : -1)));
+//		if (thread && thread->stopped
+//			&& thread->last_event->message
+//				== B_DEBUGGER_MESSAGE_IMAGE_CREATED
+//			&& thread->last_event->data.image_created.info.type
+//				== B_APP_IMAGE) {
+//TRACE(("haiku_init_debug_create_inferior(): Got an `app image created' "
+//"message\n"));
+//			break;
+//		}
+//
+//		resume (0, stop_signal);
+//	}
+}
+
+static void
+haiku_child_create_inferior (char *exec_file, char *allargs, char **env,
+	int from_tty)
+{
+	TRACE(("haiku_child_create_inferior(`%s', `%s', %p, %d)\n", exec_file,
+		allargs, env, from_tty));
+
+	fork_inferior (exec_file, allargs, env, wait_for_debugger,
+		haiku_init_debug_create_inferior, NULL, NULL);
+
+
+observer_notify_inferior_created (&current_target, from_tty);
+proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
+
+
+	// TODO: Anything more to do here?
+}
+
+static void
+haiku_child_mourn_inferior (void)
+{
+	TRACE(("haiku_child_mourn_inferior()\n"));
+
+	haiku_cleanup_team_debug_info();
+	unpush_target (sHaikuTarget);
+	generic_mourn_inferior ();
+}
+
+static int
+haiku_child_can_run (void)
+{
+	return 1;
+}
+
+static int
+haiku_child_thread_alive (ptid_t ptid)
+{
+	thread_info info;
+
+	TRACE(("haiku_child_thread_alive(`%s')\n", haiku_pid_to_str(ptid)));
+
+	return (get_thread_info(ptid_get_tid(ptid), &info) == B_OK);
+}
+
+static char *
+haiku_pid_to_str (ptid_t ptid)
+{
+	static char buffer[B_OS_NAME_LENGTH + 64 + 64];
+	team_info teamInfo;
+	thread_info threadInfo;
+	status_t error;
+
+	// get the team info for the target team
+	error = get_team_info(ptid_get_pid(ptid), &teamInfo);
+	if (error != B_OK) {
+		sprintf(buffer, "invalid team ID %d", ptid_get_pid(ptid));
+		return buffer;
+	}
+
+	// get the thread info for the target thread
+	error = get_thread_info(ptid_get_tid(ptid), &threadInfo);
+	if (error != B_OK) {
+		sprintf(buffer, "team %.*s (%ld) invalid thread ID %ld",
+			(int)sizeof(teamInfo.args), teamInfo.args, teamInfo.team,
+			ptid_get_tid(ptid));
+		return buffer;
+	}
+
+	sprintf(buffer, "team %.*s (%ld) thread %s (%ld)",
+		(int)sizeof(teamInfo.args), teamInfo.args, teamInfo.team,
+		threadInfo.name, threadInfo.thread);
+
+	return buffer;
+}
+
+char *
+haiku_child_pid_to_exec_file (int pid)
+{
+	static char buffer[B_PATH_NAME_LENGTH];
+
+	// The only way to get the path to the application's executable seems to
+	// be to get an image_info of its image, which also contains a path.
+	// Several images may belong to the team (libraries, add-ons), but only
+	// the one in question should be typed B_APP_IMAGE.
+	image_info info;
+	int32 cookie = 0;
+
+	while (get_next_image_info(0, &cookie, &info) == B_OK) {
+		if (info.type == B_APP_IMAGE) {
+			strncpy(buffer, info.name, B_PATH_NAME_LENGTH - 1);
+			buffer[B_PATH_NAME_LENGTH - 1] = 0;
+			return buffer;
+		}
+	}
+
+	return NULL;
+}
+
+
+void
+_initialize_haiku_nat (void)
+{
+	// child operations
+	struct target_ops *t = XZALLOC (struct target_ops);
+	t->to_shortname = "child";
+	t->to_longname = "Haiku child process";
+	t->to_doc = "Haiku child process (started by the \"run\" command).";
+	t->to_open = haiku_child_open;
+	t->to_close = haiku_child_close;
+	t->to_attach = haiku_child_attach;
+	t->to_detach = haiku_child_detach;
+	t->to_resume = haiku_child_resume;
+	t->to_wait = haiku_child_wait;
+	t->to_fetch_registers = haiku_child_fetch_inferior_registers;
+	t->to_store_registers = haiku_child_store_inferior_registers;
+	t->to_prepare_to_store = haiku_child_prepare_to_store;
+	t->deprecated_xfer_memory = haiku_child_deprecated_xfer_memory;
+	t->to_xfer_partial = haiku_child_xfer_partial;
+	t->to_files_info = haiku_child_files_info;
+
+	t->to_insert_breakpoint = memory_insert_breakpoint;
+	t->to_remove_breakpoint = memory_remove_breakpoint;
+		// TODO: We can do better. If we wanted to.
+
+	// TODO: The following terminal calls are not documented or not yet
+	// understood by me.
+	t->to_terminal_init = terminal_init_inferior;
+	t->to_terminal_inferior = terminal_inferior;
+	t->to_terminal_ours_for_output = terminal_ours_for_output;
+	t->to_terminal_ours = terminal_ours;
+	t->to_terminal_save_ours = terminal_save_ours;
+	t->to_terminal_info = child_terminal_info;
+
+	t->to_kill = haiku_child_kill_inferior;
+	t->to_stop = haiku_child_stop_inferior;
+	t->to_create_inferior = haiku_child_create_inferior;
+	t->to_mourn_inferior = haiku_child_mourn_inferior;
+	t->to_can_run = haiku_child_can_run;
+	t->to_thread_alive = haiku_child_thread_alive;
+// How about to_find_new_threads? Perhaps not necessary, as we could be informed
+// about thread creation/deletion.
+	t->to_pid_to_str = haiku_pid_to_str;
+	t->to_pid_to_exec_file = haiku_child_pid_to_exec_file;
+
+	t->to_stratum = process_stratum;
+	t->to_has_all_memory = 1;
+	t->to_has_memory = 1;
+	t->to_has_stack = 1;
+	t->to_has_registers = 1;
+	t->to_has_execution = 1;
+	t->to_magic = OPS_MAGIC;
+
+	sHaikuTarget = t;
+
+	add_target (t);
+}
diff --git a/gdb/haiku-nat.h b/gdb/haiku-nat.h
new file mode 100644
index 0000000..9f68f59
--- /dev/null
+++ b/gdb/haiku-nat.h
@@ -0,0 +1,42 @@
+/* Haiku native-dependent definitions.
+
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef HAIKU_NAT_H
+#define HAIKU_NAT_H
+
+#include <debugger.h>
+
+/* Required by haiku-nat.c, implemented in <arch>-haiku-nat.c. */
+
+void haiku_supply_registers(int reg, const debug_cpu_state *cpuState);
+void haiku_collect_registers(int reg, debug_cpu_state *cpuState);
+
+
+struct haiku_image_info;
+
+/* Function used by solib-haiku.c to iterate through the list of images of
+   the inferior.
+   TODO: This must go, since it works only in a native debugger. We can
+   probably tunnel these data through the xfer_memory() function.
+*/
+struct haiku_image_info *haiku_get_next_image_info(int lastID);
+
+#endif	/* HAIKU_NAT_H */
diff --git a/gdb/haiku-tdep.c b/gdb/haiku-tdep.c
new file mode 100644
index 0000000..d95255d
--- /dev/null
+++ b/gdb/haiku-tdep.c
@@ -0,0 +1,22 @@
+/* Haiku target-dependent common to multiple platforms.
+
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
diff --git a/gdb/i386-haiku-nat.c b/gdb/i386-haiku-nat.c
new file mode 100644
index 0000000..87ef19e
--- /dev/null
+++ b/gdb/i386-haiku-nat.c
@@ -0,0 +1,87 @@
+/* Native-dependent code for Haiku i386.
+
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "haiku-nat.h"
+#include "i386-tdep.h"
+#include "i387-tdep.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "target.h"
+
+/* Offset in `struct debug_cpu_state' where MEMBER is stored.  */
+#define REG_OFFSET(member) offsetof (struct x86_debug_cpu_state, member)
+
+/* At kHaikuI386RegOffset[REGNUM] you'll find the offset in `struct
+   debug_cpu_state' where the GDB register REGNUM is stored. */
+static int kHaikuI386RegOffset[] = {
+	REG_OFFSET (eax),
+	REG_OFFSET (ecx),
+	REG_OFFSET (edx),
+	REG_OFFSET (ebx),
+	REG_OFFSET (user_esp),
+	REG_OFFSET (ebp),
+	REG_OFFSET (esi),
+	REG_OFFSET (edi),
+	REG_OFFSET (eip),
+	REG_OFFSET (eflags),
+	REG_OFFSET (cs),
+	REG_OFFSET (user_ss),
+	REG_OFFSET (ds),
+	REG_OFFSET (es),
+	REG_OFFSET (fs),
+	REG_OFFSET (gs)
+};
+
+
+void
+haiku_supply_registers(int reg, const debug_cpu_state *cpuState)
+{
+	if (reg == -1) {
+		int i;
+		for (i = 0; i < NUM_REGS; i++)
+			haiku_supply_registers(i, cpuState);
+	} else if (reg < I386_ST0_REGNUM) {
+		int offset = kHaikuI386RegOffset[reg];
+		regcache_raw_supply (current_regcache, reg, (char*)cpuState + offset);
+	} else {
+		i387_supply_fxsave (current_regcache, -1,
+			&cpuState->extended_registers);
+	}
+}
+
+
+void
+haiku_collect_registers(int reg, debug_cpu_state *cpuState)
+{
+	if (reg == -1) {
+		int i;
+		for (i = 0; i < NUM_REGS; i++)
+			haiku_collect_registers(i, cpuState);
+	} else if (reg < I386_ST0_REGNUM) {
+		int offset = kHaikuI386RegOffset[reg];
+		regcache_raw_collect (current_regcache, reg, (char*)cpuState + offset);
+	} else {
+		i387_collect_fxsave (current_regcache, -1,
+			&cpuState->extended_registers);
+	}
+}
+
diff --git a/gdb/i386-haiku-tdep.c b/gdb/i386-haiku-tdep.c
new file mode 100644
index 0000000..eda144d
--- /dev/null
+++ b/gdb/i386-haiku-tdep.c
@@ -0,0 +1,77 @@
+/* Target-dependent code for Haiku i386.
+
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbarch.h"
+#include "i386-tdep.h"
+#include "osabi.h"
+
+//#define TRACE_I386_HAIKU_NAT
+#ifdef TRACE_I386_HAIKU_NAT
+	#define TRACE(x)	printf x
+#else
+	#define TRACE(x)	while (false) {}
+#endif
+
+static void
+i386_haiku_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+	struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+	// Haiku uses ELF.
+	i386_elf_init_abi (info, gdbarch);
+
+	// the offset of the PC in the jmp_buf structure (cf. setjmp(), longjmp())
+	tdep->jb_pc_offset = 20;
+
+// TODO: Signal support.
+//	tdep->sigtramp_p = i386_haiku_sigtramp_p;
+//	tdep->sigcontext_addr = i386_haiku_sigcontext_addr;
+//	tdep->sc_reg_offset = i386_haiku_sc_reg_offset;
+//	tdep->sc_num_regs = ARRAY_SIZE (i386_haiku_sc_reg_offset);
+
+// We don't need this at the moment. The Haiku runtime loader also relocates
+// R_386_JMP_SLOT entries. No lazy resolving is done.
+//	set_gdbarch_skip_solib_resolver (gdbarch, haiku_skip_solib_resolver);
+}
+
+
+static enum gdb_osabi
+i386_haiku_osabi_sniffer (bfd * abfd)
+{ 
+	char *targetName = bfd_get_target (abfd);
+
+	if (strcmp (targetName, "elf32-i386") == 0)
+		return GDB_OSABI_HAIKU;
+
+	return GDB_OSABI_UNKNOWN;
+}
+
+
+void
+_initialize_i386_haiku_tdep (void)
+{
+	gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
+		i386_haiku_osabi_sniffer);
+
+	gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_HAIKU,
+		i386_haiku_init_abi);
+}
diff --git a/gdb/osabi.c b/gdb/osabi.c
index ea84456..f2e7b6c 100644
--- a/gdb/osabi.c
+++ b/gdb/osabi.c
@@ -78,6 +78,8 @@ static const char * const gdb_osabi_names[] =
 
   "Cygwin",
 
+  "Haiku",
+
   "<invalid>"
 };
 
diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c
index de8c428..3e0b3ec 100644
--- a/gdb/ser-tcp.c
+++ b/gdb/ser-tcp.c
@@ -94,14 +94,14 @@ net_open (struct serial *scb, const char *name)
     }
 
   if (use_udp)
-    scb->fd = socket (PF_INET, SOCK_DGRAM, 0);
+    scb->fd = socket (AF_INET, SOCK_DGRAM, 0);
   else
-    scb->fd = socket (PF_INET, SOCK_STREAM, 0);
+    scb->fd = socket (AF_INET, SOCK_STREAM, 0);
 
   if (scb->fd < 0)
     return -1;
   
-  sockaddr.sin_family = PF_INET;
+  sockaddr.sin_family = AF_INET;
   sockaddr.sin_port = htons (port);
   memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
 	  sizeof (struct in_addr));
@@ -178,6 +178,7 @@ net_open (struct serial *scb, const char *name)
   tmp = 0;
   ioctl (scb->fd, FIONBIO, &tmp);
 
+#if (!defined(__BEOS__) && !defined(__HAIKU__))
   if (use_udp == 0)
     {
       /* Disable Nagle algorithm. Needed in some cases. */
@@ -185,6 +186,7 @@ net_open (struct serial *scb, const char *name)
       setsockopt (scb->fd, IPPROTO_TCP, TCP_NODELAY,
 		  (char *)&tmp, sizeof (tmp));
     }
+#endif
 
   /* If we don't do this, then GDB simply exits
      when the remote side dies.  */
diff --git a/gdb/solib-haiku.c b/gdb/solib-haiku.c
new file mode 100644
index 0000000..30af10a
--- /dev/null
+++ b/gdb/solib-haiku.c
@@ -0,0 +1,334 @@
+/* Shared library support for Haiku.
+
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <string.h>
+
+#include "defs.h"
+#include "haiku-nat.h"	// TODO: Needs to be removed. See there!
+#include "inferior.h"
+#include "objfiles.h"
+#include "solib-haiku.h"
+#include "solist.h"
+#include "symfile.h"
+#include "symtab.h"
+#include "target.h"
+#include "elf/common.h"
+#include "elf/internal.h"
+
+//#define TRACE_SOLIB_HAIKU
+#ifdef TRACE_SOLIB_HAIKU
+	#define TRACE(x)	printf x
+#else
+	#define TRACE(x)	while (false) {}
+#endif
+
+
+struct lm_info {
+	CORE_ADDR	text_address;
+	CORE_ADDR	unrelocated_text_address;
+	bool		unrelocated_text_address_initialized;
+};
+
+
+static haiku_image_info *
+haiku_get_app_image()
+{
+	haiku_image_info *image;
+	int lastID = -1;
+
+	while ((image = haiku_get_next_image_info(lastID)) != NULL) {
+		if (image->is_app_image)
+			return image;
+
+		lastID = image->id;
+	}
+
+	return NULL;
+}
+
+
+static Elf_Internal_Phdr *
+read_phdrs(bfd *abfd, int *_count)
+{
+	long size;
+	int count;
+	Elf_Internal_Phdr *phdrs;
+
+	// get the phdrs size
+	size = bfd_get_elf_phdr_upper_bound(abfd);
+	if (size <= 0)
+		return NULL;
+
+	// alloc memory
+	phdrs = (Elf_Internal_Phdr *)xmalloc(size);
+	if (!phdrs)
+		return NULL;
+
+	// read the phdrs
+	count = bfd_get_elf_phdrs(abfd, phdrs);
+	if (count < 0) {
+		xfree(phdrs);
+		return NULL;
+	}
+
+	*_count = count;
+	return phdrs;
+}
+
+
+static CORE_ADDR
+get_bfd_vma(bfd *abfd)
+{
+	int count;
+	Elf_Internal_Phdr *phdrs;
+	int i;
+	CORE_ADDR result = 0;
+
+	// get the phdrs array
+	phdrs = read_phdrs(abfd, &count);
+	if (!phdrs)
+		return 0;
+
+	// iterate through phdrs array and find the first one to load
+	for (i = 0; i < count; i++) {
+		Elf_Internal_Phdr *phdr = phdrs + i;
+		if (phdr->p_type != PT_LOAD)
+			continue;
+
+		// found the first segment to load
+		result = phdr->p_vaddr & ~(B_PAGE_SIZE - 1);
+TRACE(("get_bfd_vma(): found first segment: %p\n", (void*)result));
+		break;
+	}
+
+	xfree(phdrs);
+
+	return result;
+}
+
+
+static CORE_ADDR
+get_unrelocated_text_address(struct so_list *so)
+{
+	if (!so->lm_info->unrelocated_text_address_initialized) {
+		so->lm_info->unrelocated_text_address = get_bfd_vma(so->abfd);
+		so->lm_info->unrelocated_text_address_initialized = true;
+	}
+
+	return so->lm_info->unrelocated_text_address;
+}
+
+
+static void
+relocate_main_executable (void)
+{
+	haiku_image_info *appImageInfo = haiku_get_app_image();
+
+	TRACE(("relocate_main_executable()\n"));
+
+TRACE(("relocate_main_executable(): symfile_objfile: %p\n",
+symfile_objfile));
+TRACE(("relocate_main_executable(): symfile_objfile->obfd: %p\n",
+(symfile_objfile ? symfile_objfile->obfd : NULL)));
+TRACE(("relocate_main_executable(): app image: %p\n", appImageInfo));
+
+	// Relocate the executable here.
+	if (symfile_objfile && symfile_objfile->obfd && appImageInfo) {
+		CORE_ADDR unrelocatedAddress = get_bfd_vma(symfile_objfile->obfd);
+		CORE_ADDR displacement = (CORE_ADDR)appImageInfo->text_address
+			- unrelocatedAddress;
+
+TRACE(("relocate_main_executable(): image text address: %p, "
+"unrelocated address: %p\n", (void*)appImageInfo->text_address,
+(void*)unrelocatedAddress));
+
+		if (displacement != 0) {
+			struct cleanup *old_chain;
+			struct section_offsets *new_offsets;
+			int i, changed;
+
+			changed = 0;
+
+			new_offsets = xcalloc (symfile_objfile->num_sections,
+				sizeof (struct section_offsets));
+			old_chain = make_cleanup (xfree, new_offsets);
+
+			for (i = 0; i < symfile_objfile->num_sections; i++) {
+				if (displacement
+					!= ANOFFSET (symfile_objfile->section_offsets, i)) {
+					changed = 1;
+				}
+				new_offsets->offsets[i] = displacement;
+			}
+
+			if (changed)
+				objfile_relocate (symfile_objfile, new_offsets);
+
+			do_cleanups (old_chain);
+		}
+	}
+}
+
+
+// #pragma mark -
+
+static void
+haiku_relocate_section_addresses (struct so_list *so, struct section_table *sec)
+{
+	CORE_ADDR unrelocatedAddress = get_unrelocated_text_address(so);
+	long relocation = so->lm_info->text_address - unrelocatedAddress;
+
+//	TRACE(("haiku_relocate_section_addresses()\n"));
+
+	sec->addr += relocation;
+	sec->endaddr += relocation;
+}
+
+
+static void
+haiku_free_so (struct so_list *so)
+{
+	xfree (so->lm_info);
+}
+
+
+static void
+haiku_clear_solib (void)
+{
+}
+
+
+static void
+haiku_solib_create_inferior_hook (void)
+{
+	relocate_main_executable();
+}
+
+
+static void
+haiku_special_symbol_handling (void)
+{
+}
+
+
+static struct so_list *
+haiku_current_sos (void)
+{
+	int lastID = -1;
+	haiku_image_info *image;
+	struct so_list *head = 0;
+	struct so_list **link_ptr = &head;
+
+	TRACE(("haiku_current_sos()\n"));
+
+	while ((image = haiku_get_next_image_info(lastID)) != NULL) {
+		struct so_list *object
+			= (struct so_list *) xmalloc (sizeof (struct so_list));
+		struct cleanup *old_chain = make_cleanup (xfree, object);
+
+		lastID = image->id;
+
+		memset (object, 0, sizeof (*object));
+
+		object->lm_info = XMALLOC(struct lm_info);
+		make_cleanup (xfree, object->lm_info);
+		object->lm_info->text_address = image->text_address;
+		object->lm_info->unrelocated_text_address = 0;
+		object->lm_info->unrelocated_text_address_initialized = false;
+
+		// Note: I don't know why, but the other solib implementations seem
+		// to ignore the executable's shared object. We'll just do the same
+		// here.
+		if (image->is_app_image) {
+			free_so (object);
+
+			// Others don't do that, but it helps a lot to relocate the
+			// executable here. Otherwise, when attaching gdb to a running
+			// process it would never be done.
+			relocate_main_executable();
+		} else {
+			strncpy (object->so_name, image->path, SO_NAME_MAX_PATH_SIZE);
+			object->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+			strncpy (object->so_original_name, image->name,
+				SO_NAME_MAX_PATH_SIZE);
+			object->so_original_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+
+			object->next = 0;
+			*link_ptr = object;
+			link_ptr = &object->next;
+		}
+
+		discard_cleanups (old_chain);
+	}
+
+	return head;
+}
+
+
+static int
+haiku_open_symbol_file_object (void *from_ttyp)
+{
+	// Note: I have never seen this function being called. The Sun OS
+	// implementation is a no-op.
+	haiku_image_info *appImage = haiku_get_app_image();
+
+	TRACE(("haiku_open_symbol_file_object(%p)\n", from_ttyp));
+
+	if (!appImage) {
+		TRACE(("haiku_open_symbol_file_object(): No app image!\n"));
+		return 0;
+	}
+
+	symbol_file_add_main (appImage->path, *(int *)from_ttyp);
+
+	return 1;
+}
+
+
+static int
+haiku_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+	// No dynamic resolving implemented in Haiku yet.
+	return 0;
+}
+
+
+// #pragma mark -
+
+static struct target_so_ops haiku_so_ops;
+
+extern initialize_file_ftype _initialize_haiku_solib;
+
+void
+_initialize_haiku_solib (void)
+{
+	haiku_so_ops.relocate_section_addresses = haiku_relocate_section_addresses;
+	haiku_so_ops.free_so = haiku_free_so;
+	haiku_so_ops.clear_solib = haiku_clear_solib;
+	haiku_so_ops.solib_create_inferior_hook = haiku_solib_create_inferior_hook;
+	haiku_so_ops.special_symbol_handling = haiku_special_symbol_handling;
+	haiku_so_ops.current_sos = haiku_current_sos;
+	haiku_so_ops.open_symbol_file_object = haiku_open_symbol_file_object;
+	haiku_so_ops.in_dynsym_resolve_code = haiku_in_dynsym_resolve_code;
+
+	/* FIXME: Don't do this here.  *_gdbarch_init() should set so_ops. */
+	current_target_so_ops = &haiku_so_ops;
+}
diff --git a/gdb/solib-haiku.h b/gdb/solib-haiku.h
new file mode 100644
index 0000000..64ff80f
--- /dev/null
+++ b/gdb/solib-haiku.h
@@ -0,0 +1,34 @@
+/* Shared library support for Haiku.
+
+   Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+
+typedef struct haiku_image_info {
+	int			id;
+	char		name[256];
+	char		path[1024];
+	CORE_ADDR	text_address;
+	int			text_size;
+	CORE_ADDR	data_address;
+	int			data_size;
+	bool		is_app_image;
+} haiku_image_info;
+
diff --git a/libiberty/clock.c b/libiberty/clock.c
index 3ea70c3..02f51cc 100644
--- a/libiberty/clock.c
+++ b/libiberty/clock.c
@@ -66,7 +66,7 @@ number of seconds used.
 
 /* FIXME: should be able to declare as clock_t. */
 
-long
+clock_t
 clock ()
 {
 #ifdef HAVE_GETRUSAGE
diff --git a/readline/histfile.c b/readline/histfile.c
index 60a9125..bd64ffb 100644
--- a/readline/histfile.c
+++ b/readline/histfile.c
@@ -32,7 +32,7 @@
 #include <stdio.h>
 
 #include <sys/types.h>
-#ifndef _MINIX
+#if !defined(_MINIX) && !(defined(__BEOS__) || defined(__HAIKU__))
 #  include <sys/file.h>
 #endif
 #include "posixstat.h"
@@ -347,7 +347,7 @@ history_truncate_file (fname, lines)
     {
       write (file, bp, chars_read - (bp - buffer));
 
-#if defined (__BEOS__)
+#if (defined(__BEOS__) || defined(__HAIKU__))
       /* BeOS ignores O_TRUNC. */
       ftruncate (file, chars_read - (bp - buffer));
 #endif
diff --git a/readline/input.c b/readline/input.c
index 841f05d..57fc701 100644
--- a/readline/input.c
+++ b/readline/input.c
@@ -434,7 +434,7 @@ rl_getc (stream)
       if (result == 0)
 	return (EOF);
 
-#if defined (__BEOS__)
+#if (defined(__BEOS__) || defined(__HAIKU__))
       if (errno == EINTR)
 	continue;
 #endif
diff --git a/readline/support/wcwidth.c b/readline/support/wcwidth.c
index ace9a3a..29f5593 100644
--- a/readline/support/wcwidth.c
+++ b/readline/support/wcwidth.c
@@ -6,6 +6,7 @@
  * Markus Kuhn -- 2001-09-08 -- public domain
  */
 
+#include <sys/types.h>
 #include <wchar.h>
 
 struct interval {
-- 
2.2.2

