3002 lines
84 KiB
Diff
3002 lines
84 KiB
Diff
From f8ef37b6f0c824c1583278177b81312aef057361 Mon Sep 17 00:00:00 2001
|
|
From: Augustin Cavalier <waddlesplash@gmail.com>
|
|
Date: Sun, 2 Sep 2018 01:12:58 -0400
|
|
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 | 8 +
|
|
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/haiku64.mh | 7 +
|
|
gdb/config/i386/haiku64.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 | 3 +
|
|
gdb/configure.tgt | 2 +
|
|
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 +
|
|
29 files changed, 2654 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/haiku64.mh
|
|
create mode 100644 gdb/config/i386/haiku64.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..79ceda9 100644
|
|
--- a/bfd/config.bfd
|
|
+++ b/bfd/config.bfd
|
|
@@ -532,6 +532,10 @@ case "${targ}" in
|
|
targ_defvec=bfd_elf64_x86_64_vec
|
|
targ_selvecs="bfd_elf32_i386_vec i386coff_vec bfd_efi_app_ia32_vec"
|
|
;;
|
|
+ x86_64-*-haiku*)
|
|
+ targ_defvec=bfd_elf64_x86_64_vec
|
|
+ targ_selvecs="bfd_elf32_i386_vec i386coff_vec bfd_efi_app_ia32_vec"
|
|
+ ;;
|
|
x86_64-*-netbsd* | x86_64-*-openbsd*)
|
|
targ_defvec=bfd_elf64_x86_64_vec
|
|
targ_selvecs="bfd_elf32_i386_vec i386netbsd_vec i386coff_vec bfd_efi_app_ia32_vec"
|
|
@@ -572,6 +576,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..bfe9a41 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/haiku64.mh b/gdb/config/i386/haiku64.mh
|
|
new file mode 100644
|
|
index 0000000..6381f4e
|
|
--- /dev/null
|
|
+++ b/gdb/config/i386/haiku64.mh
|
|
@@ -0,0 +1,7 @@
|
|
+# Host: Intel x86_64 running Haiku
|
|
+
|
|
+NAT_FILE= nm-haiku.h
|
|
+NATDEPFILES= haiku-nat.o amd64-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/haiku64.mt b/gdb/config/i386/haiku64.mt
|
|
new file mode 100644
|
|
index 0000000..cdacbb9
|
|
--- /dev/null
|
|
+++ b/gdb/config/i386/haiku64.mt
|
|
@@ -0,0 +1,5 @@
|
|
+# Target: Intel x86_64 running Haiku
|
|
+
|
|
+TDEPFILES= amd64-tdep.o amd64-haiku-tdep.o haiku-tdep.o i386-haiku-tdep.o \
|
|
+ i386-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..9ae107c 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 ;;
|
|
@@ -149,6 +150,8 @@ vax-*-ultrix*) gdb_host=vax ;;
|
|
x86_64-*-linux*) gdb_host=linux64 ;;
|
|
x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu)
|
|
gdb_host=fbsd64 ;;
|
|
+x86_64-*-haiku*)
|
|
+ gdb_host=haiku64 ;;
|
|
x86_64-*-netbsd* | x86_64-*-knetbsd*-gnu)
|
|
gdb_host=nbsd64 ;;
|
|
x86_64-*-openbsd*) gdb_host=obsd64 ;;
|
|
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
|
|
index 0b1f627..4b75a9a 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 ;;
|
|
@@ -217,6 +218,7 @@ v850*-*-*) gdb_target=v850
|
|
x86_64-*-linux*) gdb_target=linux64
|
|
build_gdbserver=yes
|
|
;;
|
|
+x86_64-*-haiku*) gdb_target=haiku64 ;;
|
|
x86_64-*-netbsd* | x86_64-*-knetbsd*-gnu)
|
|
gdb_target=nbsd64 ;;
|
|
x86_64-*-openbsd*) gdb_target=obsd64 ;;
|
|
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, ¤t_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 (¤t_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.16.4
|
|
|