mirror of
https://github.com/yann64/haikuports.git
synced 2026-04-10 13:50:08 +02:00
This is the same version we have in-tree, so we can now outsource that version. AFAICT, it works just as well as the version included in the "haiku" package. I've left the static libs in the main package as that seems to be the convention among Linux distros.
2946 lines
82 KiB
Diff
2946 lines
82 KiB
Diff
From 9d7e13ad2525af53757122d532ac3851e9065471 Mon Sep 17 00:00:00 2001
|
|
From: Augustin Cavalier <waddlesplash@gmail.com>
|
|
Date: Wed, 11 Feb 2015 10:07:54 -0500
|
|
Subject: [PATCH] Merge changes from Haiku's main repo.
|
|
|
|
Includes some other fixes by me to get the build system fully working.
|
|
---
|
|
bfd/config.bfd | 4 +
|
|
config.sub | 3 +
|
|
gdb/Makefile.in | 2 +-
|
|
gdb/amd64-haiku-nat.c | 96 +++
|
|
gdb/amd64-haiku-tdep.c | 61 ++
|
|
gdb/config/i386/haiku.mh | 7 +
|
|
gdb/config/i386/haiku.mt | 5 +
|
|
gdb/config/i386/nm-haiku.h | 27 +
|
|
gdb/config/i386/tm-haiku.h | 27 +
|
|
gdb/config/nm-haiku.h | 25 +
|
|
gdb/config/tm-haiku.h | 25 +
|
|
gdb/configure.host | 1 +
|
|
gdb/configure.tgt | 1 +
|
|
gdb/defs.h | 2 +
|
|
gdb/haiku-nat.c | 1742 ++++++++++++++++++++++++++++++++++++++++++++
|
|
gdb/haiku-nat.h | 42 ++
|
|
gdb/haiku-tdep.c | 22 +
|
|
gdb/i386-haiku-nat.c | 87 +++
|
|
gdb/i386-haiku-tdep.c | 77 ++
|
|
gdb/osabi.c | 2 +
|
|
gdb/ser-tcp.c | 8 +-
|
|
gdb/solib-haiku.c | 334 +++++++++
|
|
gdb/solib-haiku.h | 34 +
|
|
libiberty/clock.c | 2 +-
|
|
readline/histfile.c | 4 +-
|
|
readline/input.c | 2 +-
|
|
readline/support/wcwidth.c | 1 +
|
|
27 files changed, 2635 insertions(+), 8 deletions(-)
|
|
create mode 100644 gdb/amd64-haiku-nat.c
|
|
create mode 100644 gdb/amd64-haiku-tdep.c
|
|
create mode 100644 gdb/config/i386/haiku.mh
|
|
create mode 100644 gdb/config/i386/haiku.mt
|
|
create mode 100644 gdb/config/i386/nm-haiku.h
|
|
create mode 100644 gdb/config/i386/tm-haiku.h
|
|
create mode 100644 gdb/config/nm-haiku.h
|
|
create mode 100644 gdb/config/tm-haiku.h
|
|
create mode 100644 gdb/haiku-nat.c
|
|
create mode 100644 gdb/haiku-nat.h
|
|
create mode 100644 gdb/haiku-tdep.c
|
|
create mode 100644 gdb/i386-haiku-nat.c
|
|
create mode 100644 gdb/i386-haiku-tdep.c
|
|
create mode 100644 gdb/solib-haiku.c
|
|
create mode 100644 gdb/solib-haiku.h
|
|
|
|
diff --git a/bfd/config.bfd b/bfd/config.bfd
|
|
index 549397b..c6621f9 100644
|
|
--- a/bfd/config.bfd
|
|
+++ b/bfd/config.bfd
|
|
@@ -572,6 +572,10 @@ case "${targ}" in
|
|
targ_defvec=bfd_elf32_i386_vec
|
|
targ_selvecs="i386pe_vec i386pei_vec"
|
|
;;
|
|
+ i[3-7]86-*-haiku*)
|
|
+ targ_defvec=bfd_elf32_i386_vec
|
|
+ targ_selvecs="i386pe_vec i386pei_vec"
|
|
+ ;;
|
|
i[3-7]86-*-interix*)
|
|
targ_defvec=i386pei_vec
|
|
targ_selvecs="i386pe_vec"
|
|
diff --git a/config.sub b/config.sub
|
|
index edb6b66..36a7851 100755
|
|
--- a/config.sub
|
|
+++ b/config.sub
|
|
@@ -1297,6 +1297,9 @@ case $os in
|
|
-kaos*)
|
|
os=-kaos
|
|
;;
|
|
+ -haiku*)
|
|
+ os=-haiku
|
|
+ ;;
|
|
-none)
|
|
;;
|
|
*)
|
|
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
|
|
index 966f887..8cbc2ce 100644
|
|
--- a/gdb/Makefile.in
|
|
+++ b/gdb/Makefile.in
|
|
@@ -374,7 +374,7 @@ INSTALLED_LIBS=-lbfd -lreadline -lopcodes -liberty \
|
|
-lintl -liberty
|
|
CLIBS = $(SIM) $(BFD) $(READLINE) $(OPCODES) $(INTL) $(LIBIBERTY) \
|
|
$(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ \
|
|
- $(LIBICONV) \
|
|
+ $(LIBICONV) -ldebug \
|
|
$(LIBIBERTY) $(WIN32LIBS)
|
|
CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE) \
|
|
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS)
|
|
diff --git a/gdb/amd64-haiku-nat.c b/gdb/amd64-haiku-nat.c
|
|
new file mode 100644
|
|
index 0000000..7a4ae51
|
|
--- /dev/null
|
|
+++ b/gdb/amd64-haiku-nat.c
|
|
@@ -0,0 +1,96 @@
|
|
+/* Native-dependent code for Haiku x86_64.
|
|
+
|
|
+ Copyright 2012 Alex Smith <alex@alex-smith.me.uk>.
|
|
+ Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
|
|
+
|
|
+ This file is part of GDB.
|
|
+
|
|
+ This program is free software; you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program; if not, write to the Free Software
|
|
+ Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ Boston, MA 02111-1307, USA. */
|
|
+
|
|
+#include "defs.h"
|
|
+#include "haiku-nat.h"
|
|
+#include "amd64-tdep.h"
|
|
+#include "i387-tdep.h"
|
|
+#include "inferior.h"
|
|
+#include "regcache.h"
|
|
+#include "target.h"
|
|
+
|
|
+/* Offset in `struct debug_cpu_state' where MEMBER is stored. */
|
|
+#define REG_OFFSET(member) offsetof (struct x86_64_debug_cpu_state, member)
|
|
+
|
|
+/* At kHaikuAMD64RegOffset[REGNUM] you'll find the offset in `struct
|
|
+ debug_cpu_state' where the GDB register REGNUM is stored. */
|
|
+static int kHaikuAMD64RegOffset[] = {
|
|
+ REG_OFFSET (rax),
|
|
+ REG_OFFSET (rbx),
|
|
+ REG_OFFSET (rcx),
|
|
+ REG_OFFSET (rdx),
|
|
+ REG_OFFSET (rsi),
|
|
+ REG_OFFSET (rdi),
|
|
+ REG_OFFSET (rbp),
|
|
+ REG_OFFSET (rsp),
|
|
+ REG_OFFSET (r8),
|
|
+ REG_OFFSET (r9),
|
|
+ REG_OFFSET (r10),
|
|
+ REG_OFFSET (r11),
|
|
+ REG_OFFSET (r12),
|
|
+ REG_OFFSET (r13),
|
|
+ REG_OFFSET (r14),
|
|
+ REG_OFFSET (r15),
|
|
+ REG_OFFSET (rip),
|
|
+ REG_OFFSET (rflags),
|
|
+ REG_OFFSET (cs),
|
|
+ REG_OFFSET (ss),
|
|
+ REG_OFFSET (ds),
|
|
+ REG_OFFSET (es),
|
|
+ REG_OFFSET (fs),
|
|
+ REG_OFFSET (gs)
|
|
+};
|
|
+
|
|
+
|
|
+void
|
|
+haiku_supply_registers(int reg, const debug_cpu_state *cpuState)
|
|
+{
|
|
+ if (reg == -1) {
|
|
+ int i;
|
|
+ for (i = 0; i < NUM_REGS; i++)
|
|
+ haiku_supply_registers(i, cpuState);
|
|
+ } else if (reg < AMD64_ST0_REGNUM) {
|
|
+ int offset = kHaikuAMD64RegOffset[reg];
|
|
+ regcache_raw_supply (current_regcache, reg, (char*)cpuState + offset);
|
|
+ } else {
|
|
+ amd64_supply_fxsave (current_regcache, -1,
|
|
+ &cpuState->extended_registers);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+haiku_collect_registers(int reg, debug_cpu_state *cpuState)
|
|
+{
|
|
+ if (reg == -1) {
|
|
+ int i;
|
|
+ for (i = 0; i < NUM_REGS; i++)
|
|
+ haiku_collect_registers(i, cpuState);
|
|
+ } else if (reg < AMD64_ST0_REGNUM) {
|
|
+ int offset = kHaikuAMD64RegOffset[reg];
|
|
+ regcache_raw_collect (current_regcache, reg, (char*)cpuState + offset);
|
|
+ } else {
|
|
+ amd64_collect_fxsave (current_regcache, -1,
|
|
+ &cpuState->extended_registers);
|
|
+ }
|
|
+}
|
|
+
|
|
diff --git a/gdb/amd64-haiku-tdep.c b/gdb/amd64-haiku-tdep.c
|
|
new file mode 100644
|
|
index 0000000..5923e58
|
|
--- /dev/null
|
|
+++ b/gdb/amd64-haiku-tdep.c
|
|
@@ -0,0 +1,61 @@
|
|
+/* Target-dependent code for Haiku x86_64.
|
|
+
|
|
+ Copyright 2012 Alex Smith <alex@alex-smith.me.uk>.
|
|
+ Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
|
|
+
|
|
+ This file is part of GDB.
|
|
+
|
|
+ This program is free software; you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program; if not, write to the Free Software
|
|
+ Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ Boston, MA 02111-1307, USA. */
|
|
+
|
|
+#include "defs.h"
|
|
+#include "gdbarch.h"
|
|
+#include "amd64-tdep.h"
|
|
+#include "osabi.h"
|
|
+
|
|
+
|
|
+static void
|
|
+amd64_haiku_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
|
+{
|
|
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
|
+
|
|
+ amd64_init_abi (info, gdbarch);
|
|
+
|
|
+ // the offset of the PC in the jmp_buf structure (cf. setjmp(), longjmp())
|
|
+ tdep->jb_pc_offset = 0;
|
|
+}
|
|
+
|
|
+
|
|
+static enum gdb_osabi
|
|
+amd64_haiku_osabi_sniffer (bfd * abfd)
|
|
+{
|
|
+ char *targetName = bfd_get_target (abfd);
|
|
+
|
|
+ if (strcmp (targetName, "elf64-x86-64") == 0)
|
|
+ return GDB_OSABI_HAIKU;
|
|
+
|
|
+ return GDB_OSABI_UNKNOWN;
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+_initialize_amd64_haiku_tdep (void)
|
|
+{
|
|
+ gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
|
|
+ amd64_haiku_osabi_sniffer);
|
|
+
|
|
+ gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, GDB_OSABI_HAIKU,
|
|
+ amd64_haiku_init_abi);
|
|
+}
|
|
diff --git a/gdb/config/i386/haiku.mh b/gdb/config/i386/haiku.mh
|
|
new file mode 100644
|
|
index 0000000..d4212db
|
|
--- /dev/null
|
|
+++ b/gdb/config/i386/haiku.mh
|
|
@@ -0,0 +1,7 @@
|
|
+# Host: Intel 586 running Haiku
|
|
+
|
|
+NAT_FILE= nm-haiku.h
|
|
+NATDEPFILES= haiku-nat.o i386-haiku-nat.o inf-child.o fork-child.o
|
|
+
|
|
+# No core file support yet.
|
|
+# corelow.o core-aout.o
|
|
diff --git a/gdb/config/i386/haiku.mt b/gdb/config/i386/haiku.mt
|
|
new file mode 100644
|
|
index 0000000..e60affb
|
|
--- /dev/null
|
|
+++ b/gdb/config/i386/haiku.mt
|
|
@@ -0,0 +1,5 @@
|
|
+# Target: Intel 586 running Haiku
|
|
+
|
|
+TDEPFILES= i386-tdep.o i386-haiku-tdep.o haiku-tdep.o i387-tdep.o \
|
|
+ solib.o solib-haiku.o symfile-mem.o
|
|
+DEPRECATED_TM_FILE= tm-haiku.h
|
|
diff --git a/gdb/config/i386/nm-haiku.h b/gdb/config/i386/nm-haiku.h
|
|
new file mode 100644
|
|
index 0000000..b392360
|
|
--- /dev/null
|
|
+++ b/gdb/config/i386/nm-haiku.h
|
|
@@ -0,0 +1,27 @@
|
|
+/* Native support for Haiku x86.
|
|
+
|
|
+ Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
|
|
+
|
|
+ This file is part of GDB.
|
|
+
|
|
+ This program is free software; you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program; if not, write to the Free Software
|
|
+ Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ Boston, MA 02111-1307, USA. */
|
|
+
|
|
+#ifndef NM_HAIKU_H
|
|
+#define NM_HAIKU_H
|
|
+
|
|
+#include "config/nm-haiku.h"
|
|
+
|
|
+#endif /* nm-haiku.h */
|
|
diff --git a/gdb/config/i386/tm-haiku.h b/gdb/config/i386/tm-haiku.h
|
|
new file mode 100644
|
|
index 0000000..badfc7e
|
|
--- /dev/null
|
|
+++ b/gdb/config/i386/tm-haiku.h
|
|
@@ -0,0 +1,27 @@
|
|
+/* Definitions to target GDB to Haiku on 386.
|
|
+
|
|
+ Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
|
|
+
|
|
+ This file is part of GDB.
|
|
+
|
|
+ This program is free software; you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program; if not, write to the Free Software
|
|
+ Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ Boston, MA 02111-1307, USA. */
|
|
+
|
|
+#ifndef TM_HAIKU_H
|
|
+#define TM_HAIKU_H
|
|
+
|
|
+#include "config/tm-haiku.h"
|
|
+
|
|
+#endif /* #ifndef TM_HAIKU_H */
|
|
diff --git a/gdb/config/nm-haiku.h b/gdb/config/nm-haiku.h
|
|
new file mode 100644
|
|
index 0000000..e85a1c2
|
|
--- /dev/null
|
|
+++ b/gdb/config/nm-haiku.h
|
|
@@ -0,0 +1,25 @@
|
|
+/* Native support Haiku.
|
|
+
|
|
+ Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
|
|
+
|
|
+ This file is part of GDB.
|
|
+
|
|
+ This program is free software; you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program; if not, write to the Free Software
|
|
+ Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ Boston, MA 02111-1307, USA. */
|
|
+
|
|
+// #define REALTIME_{LO,HI}?
|
|
+
|
|
+/* Support for shared libraries. */
|
|
+#include "solib.h"
|
|
diff --git a/gdb/config/tm-haiku.h b/gdb/config/tm-haiku.h
|
|
new file mode 100644
|
|
index 0000000..cdead7b
|
|
--- /dev/null
|
|
+++ b/gdb/config/tm-haiku.h
|
|
@@ -0,0 +1,25 @@
|
|
+/* Target support Haiku.
|
|
+
|
|
+ Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
|
|
+
|
|
+ This file is part of GDB.
|
|
+
|
|
+ This program is free software; you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program; if not, write to the Free Software
|
|
+ Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ Boston, MA 02111-1307, USA. */
|
|
+
|
|
+// #define REALTIME_{LO,HI}?
|
|
+
|
|
+/* Support for shared libraries. */
|
|
+#include "solib.h"
|
|
diff --git a/gdb/configure.host b/gdb/configure.host
|
|
index f730891..867bef1 100644
|
|
--- a/gdb/configure.host
|
|
+++ b/gdb/configure.host
|
|
@@ -86,6 +86,7 @@ i[34567]86-*-unixware*) gdb_host=i386v4 ;;
|
|
i[34567]86-*-sysv*) gdb_host=i386v ;;
|
|
i[34567]86-*-isc*) gdb_host=i386v ;;
|
|
i[34567]86-*-cygwin*) gdb_host=cygwin ;;
|
|
+i[567]86-*-haiku*) gdb_host=haiku ;;
|
|
|
|
ia64-*-aix*) gdb_host=aix ;;
|
|
ia64-*-linux*) gdb_host=linux ;;
|
|
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
|
|
index 0b1f627..93ca8ae 100644
|
|
--- a/gdb/configure.tgt
|
|
+++ b/gdb/configure.tgt
|
|
@@ -98,6 +98,7 @@ i[34567]86-*-netware*) gdb_target=i386
|
|
configdirs="${configdirs} nlm" ;;
|
|
i[34567]86-*-cygwin*) gdb_target=cygwin ;;
|
|
i[34567]86-*-vxworks*) gdb_target=vxworks ;;
|
|
+i[34567]86-*-haiku*) gdb_target=haiku ;;
|
|
i[34567]86-*-*) gdb_target=i386 ;;
|
|
|
|
ia64-*-aix*) gdb_target=aix ;;
|
|
diff --git a/gdb/defs.h b/gdb/defs.h
|
|
index fd96665..21dcda7 100644
|
|
--- a/gdb/defs.h
|
|
+++ b/gdb/defs.h
|
|
@@ -1052,6 +1052,8 @@ enum gdb_osabi
|
|
|
|
GDB_OSABI_CYGWIN,
|
|
|
|
+ GDB_OSABI_HAIKU,
|
|
+
|
|
GDB_OSABI_INVALID /* keep this last */
|
|
};
|
|
|
|
diff --git a/gdb/haiku-nat.c b/gdb/haiku-nat.c
|
|
new file mode 100644
|
|
index 0000000..01bc084
|
|
--- /dev/null
|
|
+++ b/gdb/haiku-nat.c
|
|
@@ -0,0 +1,1742 @@
|
|
+/* Haiku native-dependent code common to multiple platforms.
|
|
+
|
|
+ Copyright 2005 Ingo Weinhold <bonefish@cs.tu-berlin.de>.
|
|
+
|
|
+ This file is part of GDB.
|
|
+
|
|
+ This program is free software; you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program; if not, write to the Free Software
|
|
+ Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ Boston, MA 02111-1307, USA. */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include <debugger.h>
|
|
+#include <image.h>
|
|
+#include <OS.h>
|
|
+
|
|
+#include <private/debug/debug_support.h>
|
|
+
|
|
+#include "defs.h" // include this first -- otherwise "command.h" will choke
|
|
+#include "command.h"
|
|
+#include "gdbcore.h"
|
|
+#include "gdbthread.h"
|
|
+#include "haiku-nat.h"
|
|
+#include "inferior.h"
|
|
+#include "observer.h"
|
|
+#include "regcache.h"
|
|
+#include "solib-haiku.h"
|
|
+#include "symfile.h"
|
|
+#include "target.h"
|
|
+
|
|
+//#define TRACE_HAIKU_NAT
|
|
+#ifdef TRACE_HAIKU_NAT
|
|
+ #define TRACE(x) printf x
|
|
+#else
|
|
+ #define TRACE(x) while (false) {}
|
|
+#endif
|
|
+
|
|
+static struct target_ops *sHaikuTarget = NULL;
|
|
+
|
|
+typedef struct debug_event {
|
|
+ struct debug_event *next;
|
|
+ debug_debugger_message message;
|
|
+ debug_debugger_message_data data;
|
|
+} debug_event;
|
|
+
|
|
+typedef struct debug_event_list {
|
|
+ debug_event *head;
|
|
+ debug_event *tail;
|
|
+} debug_event_list;
|
|
+
|
|
+typedef enum {
|
|
+ SIGNAL_ARRIVED, // the signal has actually arrived and is going to be
|
|
+ // handled (in any way)
|
|
+ SIGNAL_WILL_ARRIVE, // the signal has not yet been sent, but will be sent
|
|
+ // (e.g. an exception occurred and will cause the
|
|
+ // signal when not being ignored)
|
|
+ SIGNAL_FAKED, // the signal didn't arrive and won't arrive, we faked
|
|
+ // it (often in case of SIGTRAP)
|
|
+} pending_signal_status;
|
|
+
|
|
+typedef struct thread_debug_info {
|
|
+ struct thread_debug_info *next;
|
|
+ thread_id thread;
|
|
+ bool stopped;
|
|
+ debug_event *last_event; // last debug message from
|
|
+ // the thread; valid only,
|
|
+ // if stopped
|
|
+ int reprocess_event; // > 0, the event
|
|
+ // shall be processed a
|
|
+ // that many times, which
|
|
+ // will probably trigger
|
|
+ // another target event
|
|
+ int signal; // only valid, if stopped
|
|
+ pending_signal_status signal_status;
|
|
+} thread_debug_info;
|
|
+
|
|
+typedef struct extended_image_info {
|
|
+ haiku_image_info info;
|
|
+ struct extended_image_info *next;
|
|
+} extended_image_info;
|
|
+
|
|
+typedef struct team_debug_info {
|
|
+ team_id team;
|
|
+ port_id debugger_port;
|
|
+ thread_id nub_thread;
|
|
+ debug_context context;
|
|
+ thread_debug_info *threads;
|
|
+ extended_image_info *images;
|
|
+ debug_event_list events;
|
|
+} team_debug_info;
|
|
+
|
|
+static team_debug_info sTeamDebugInfo;
|
|
+
|
|
+
|
|
+typedef struct signal_map_entry {
|
|
+ enum target_signal target;
|
|
+ int haiku;
|
|
+} signal_map_entry;
|
|
+
|
|
+static const signal_map_entry sSignalMap[] = {
|
|
+ { TARGET_SIGNAL_0, 0 },
|
|
+ { TARGET_SIGNAL_HUP, SIGHUP },
|
|
+ { TARGET_SIGNAL_INT, SIGINT },
|
|
+ { TARGET_SIGNAL_QUIT, SIGQUIT },
|
|
+ { TARGET_SIGNAL_ILL, SIGILL },
|
|
+ { TARGET_SIGNAL_CHLD, SIGCHLD },
|
|
+ { TARGET_SIGNAL_ABRT, SIGABRT },
|
|
+ { TARGET_SIGNAL_PIPE, SIGPIPE },
|
|
+ { TARGET_SIGNAL_FPE, SIGFPE },
|
|
+ { TARGET_SIGNAL_KILL, SIGKILL },
|
|
+ { TARGET_SIGNAL_STOP, SIGSTOP },
|
|
+ { TARGET_SIGNAL_SEGV, SIGSEGV },
|
|
+ { TARGET_SIGNAL_CONT, SIGCONT },
|
|
+ { TARGET_SIGNAL_TSTP, SIGTSTP },
|
|
+ { TARGET_SIGNAL_ALRM, SIGALRM },
|
|
+ { TARGET_SIGNAL_TERM, SIGTERM },
|
|
+ { TARGET_SIGNAL_TTIN, SIGTTIN },
|
|
+ { TARGET_SIGNAL_TTOU, SIGTTOU },
|
|
+ { TARGET_SIGNAL_USR1, SIGUSR1 },
|
|
+ { TARGET_SIGNAL_USR2, SIGUSR2 },
|
|
+ { TARGET_SIGNAL_WINCH, SIGWINCH },
|
|
+ { TARGET_SIGNAL_TRAP, SIGTRAP },
|
|
+ { TARGET_SIGNAL_0, SIGKILLTHR }, // not debuggable anyway
|
|
+ { -1, -1 }
|
|
+};
|
|
+
|
|
+
|
|
+// #pragma mark -
|
|
+
|
|
+
|
|
+static char *haiku_pid_to_str (ptid_t ptid);
|
|
+
|
|
+
|
|
+static int
|
|
+target_to_haiku_signal(enum target_signal targetSignal)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (targetSignal < 0)
|
|
+ return -1;
|
|
+
|
|
+ for (i = 0; sSignalMap[i].target != -1 || sSignalMap[i].haiku != -1; i++) {
|
|
+ if (targetSignal == sSignalMap[i].target)
|
|
+ return sSignalMap[i].haiku;
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+
|
|
+static enum target_signal
|
|
+haiku_to_target_signal(int haikuSignal)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (haikuSignal < 0)
|
|
+ return TARGET_SIGNAL_0;
|
|
+
|
|
+ for (i = 0; sSignalMap[i].target != -1 || sSignalMap[i].haiku != -1; i++) {
|
|
+ if (haikuSignal == sSignalMap[i].haiku)
|
|
+ return sSignalMap[i].target;
|
|
+ }
|
|
+
|
|
+ return TARGET_SIGNAL_UNKNOWN;
|
|
+}
|
|
+
|
|
+
|
|
+static thread_debug_info *
|
|
+haiku_find_thread(team_debug_info *teamDebugInfo, thread_id threadID)
|
|
+{
|
|
+ thread_debug_info *info;
|
|
+ for (info = teamDebugInfo->threads; info; info = info->next) {
|
|
+ if (info->thread == threadID)
|
|
+ return info;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+static thread_debug_info *
|
|
+haiku_add_thread(team_debug_info *teamDebugInfo, thread_id threadID)
|
|
+{
|
|
+ struct thread_info *gdbThreadInfo;
|
|
+ thread_debug_info *threadDebugInfo;
|
|
+
|
|
+ if (threadID == teamDebugInfo->nub_thread) {
|
|
+ error("haiku_thread_added(): Trying to add debug nub thread (%ld)\n",
|
|
+ threadID);
|
|
+ }
|
|
+
|
|
+ // find the thread first
|
|
+ threadDebugInfo = haiku_find_thread(teamDebugInfo, threadID);
|
|
+ if (threadDebugInfo)
|
|
+ return threadDebugInfo;
|
|
+
|
|
+ // allocate a new thread debug info
|
|
+ threadDebugInfo = XMALLOC(thread_debug_info);
|
|
+ if (!threadDebugInfo)
|
|
+ error("haiku_thread_added(): Out of memory!\n");
|
|
+
|
|
+ // init and add it
|
|
+ threadDebugInfo->thread = threadID;
|
|
+ threadDebugInfo->next = teamDebugInfo->threads;
|
|
+ threadDebugInfo->stopped = false;
|
|
+ threadDebugInfo->last_event = NULL;
|
|
+ teamDebugInfo->threads = threadDebugInfo;
|
|
+
|
|
+ // add it to gdb's thread DB
|
|
+ gdbThreadInfo = add_thread(ptid_build(teamDebugInfo->team, 0, threadID));
|
|
+
|
|
+ // Note: In theory we could spare us the whole thread list management, since
|
|
+ // gdb's thread DB is doing exactly the same. We could put our data as
|
|
+ // thread_info::private. The only catch is that when the thread_info is
|
|
+ // freed, xfree() is invoked on the private data directly, but there's no
|
|
+ // callback invoked before that would allow us to do cleanup (e.g. free
|
|
+ // last_event).
|
|
+
|
|
+ TRACE(("haiku_add_thread(): team %ld thread %ld added: "
|
|
+ "gdb thread info: %p\n", teamDebugInfo->team, threadID, gdbThreadInfo));
|
|
+
|
|
+ return threadDebugInfo;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_remove_thread(team_debug_info *teamDebugInfo, thread_id threadID)
|
|
+{
|
|
+ thread_debug_info **info;
|
|
+ for (info = &teamDebugInfo->threads; *info; info = &(*info)->next) {
|
|
+ if ((*info)->thread == threadID) {
|
|
+ thread_debug_info *foundInfo = *info;
|
|
+ *info = foundInfo->next;
|
|
+ if (foundInfo->last_event)
|
|
+ xfree(foundInfo->last_event);
|
|
+ xfree(foundInfo);
|
|
+
|
|
+ // remove it from gdb's thread DB
|
|
+ delete_thread(ptid_build(teamDebugInfo->team, 0, threadID));
|
|
+
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_init_thread_list(team_debug_info *teamDebugInfo)
|
|
+{
|
|
+ thread_info threadInfo;
|
|
+ int32 cookie = 0;
|
|
+
|
|
+ // init gdb's thread DB
|
|
+ init_thread_list();
|
|
+
|
|
+ while (get_next_thread_info(teamDebugInfo->team, &cookie, &threadInfo)
|
|
+ == B_OK) {
|
|
+ if (threadInfo.thread != teamDebugInfo->nub_thread)
|
|
+ haiku_add_thread(teamDebugInfo, threadInfo.thread);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_cleanup_thread_list(team_debug_info *teamDebugInfo)
|
|
+{
|
|
+ while (teamDebugInfo->threads) {
|
|
+ thread_debug_info *thread = teamDebugInfo->threads;
|
|
+ teamDebugInfo->threads = thread->next;
|
|
+ xfree(thread);
|
|
+ }
|
|
+
|
|
+ // clear gdb's thread DB
|
|
+ init_thread_list();
|
|
+}
|
|
+
|
|
+
|
|
+// #pragma mark -
|
|
+
|
|
+static extended_image_info **
|
|
+haiku_find_image_insert_location(team_debug_info *teamDebugInfo,
|
|
+ image_id imageID)
|
|
+{
|
|
+ extended_image_info **image;
|
|
+
|
|
+ for (image = &teamDebugInfo->images; *image; image = &(*image)->next) {
|
|
+ if ((*image)->info.id >= imageID)
|
|
+ return image;
|
|
+ }
|
|
+
|
|
+ return image;
|
|
+}
|
|
+
|
|
+
|
|
+static extended_image_info *
|
|
+haiku_find_image(team_debug_info *teamDebugInfo, image_id imageID)
|
|
+{
|
|
+ extended_image_info *image = *haiku_find_image_insert_location(
|
|
+ teamDebugInfo, imageID);
|
|
+
|
|
+ return (image && image->info.id == imageID ? image : NULL);
|
|
+}
|
|
+
|
|
+
|
|
+static extended_image_info *
|
|
+haiku_add_image(team_debug_info *teamDebugInfo, image_info *imageInfo)
|
|
+{
|
|
+ extended_image_info **imageP = haiku_find_image_insert_location(
|
|
+ teamDebugInfo, imageInfo->id);
|
|
+ extended_image_info *image = *imageP;
|
|
+
|
|
+ // already known?
|
|
+ if (image && image->info.id == imageInfo->id)
|
|
+ return image;
|
|
+
|
|
+ image = XMALLOC(extended_image_info);
|
|
+ if (!image)
|
|
+ error("haiku_add_image(): Out of memory!");
|
|
+
|
|
+ image->info.id = imageInfo->id;
|
|
+ strncpy(image->info.name, imageInfo->name, sizeof(image->info.name));
|
|
+ image->info.name[sizeof(image->info.name) - 1] = '\0';
|
|
+ // TODO: This should be the shared objects soname, not the path. We
|
|
+ // probably need to extend the debugger API.
|
|
+ strncpy(image->info.path, imageInfo->name, sizeof(image->info.path));
|
|
+ image->info.path[sizeof(image->info.path) - 1] = '\0';
|
|
+ image->info.text_address = (CORE_ADDR)imageInfo->text;
|
|
+ image->info.text_size = imageInfo->text_size;
|
|
+ image->info.data_address = (CORE_ADDR)imageInfo->data;
|
|
+ image->info.data_size = imageInfo->data_size;
|
|
+ image->info.is_app_image = (imageInfo->type == B_APP_IMAGE);
|
|
+
|
|
+ image->next = *imageP;
|
|
+ *imageP = image;
|
|
+
|
|
+ return image;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_remove_image(team_debug_info *teamDebugInfo, image_id imageID)
|
|
+{
|
|
+ extended_image_info **imageP = haiku_find_image_insert_location(
|
|
+ teamDebugInfo, imageID);
|
|
+ extended_image_info *image = *imageP;
|
|
+
|
|
+ if (image && image->info.id == imageID) {
|
|
+ *imageP = image->next;
|
|
+ xfree(image);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_init_image_list(team_debug_info *teamDebugInfo)
|
|
+{
|
|
+ int32 cookie = 0;
|
|
+ image_info info;
|
|
+ while (get_next_image_info(teamDebugInfo->team, &cookie, &info) == B_OK)
|
|
+ haiku_add_image(teamDebugInfo, &info);
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_cleanup_image_list(team_debug_info *teamDebugInfo)
|
|
+{
|
|
+ while (teamDebugInfo->images) {
|
|
+ extended_image_info *image = teamDebugInfo->images;
|
|
+ teamDebugInfo->images = image->next;
|
|
+ xfree(image);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+ * Service function. Call with -1 the first time.
|
|
+ */
|
|
+struct haiku_image_info *
|
|
+haiku_get_next_image_info(int lastID)
|
|
+{
|
|
+ extended_image_info *image = *haiku_find_image_insert_location(
|
|
+ &sTeamDebugInfo, (lastID >= 0 ? lastID : 0));
|
|
+
|
|
+ if (image && image->info.id == lastID)
|
|
+ image = image->next;
|
|
+
|
|
+ return (image ? &image->info : NULL);
|
|
+}
|
|
+
|
|
+
|
|
+// #pragma mark -
|
|
+
|
|
+static debug_event *
|
|
+haiku_enqueue_debug_event(debug_event_list *list, int32 message,
|
|
+ debug_debugger_message_data *data, int32 size)
|
|
+{
|
|
+ debug_event *event = XMALLOC(debug_event);
|
|
+
|
|
+ if (!event)
|
|
+ error("haiku_enqueue_debug_event(): Out of memory!\n");
|
|
+
|
|
+ // init the event
|
|
+ event->next = NULL;
|
|
+ event->message = message;
|
|
+ memcpy(&event->data, data,
|
|
+ (size >= 0 ? size : sizeof(debug_debugger_message_data)));
|
|
+
|
|
+ // add it to the queue
|
|
+ if (list->tail) {
|
|
+ list->tail->next = event;
|
|
+ list->tail = event;
|
|
+ } else {
|
|
+ list->head = list->tail = event;
|
|
+ }
|
|
+
|
|
+ return event;
|
|
+}
|
|
+
|
|
+
|
|
+static debug_event *
|
|
+haiku_dequeue_next_debug_event(debug_event_list *list)
|
|
+{
|
|
+ debug_event *event = list->head;
|
|
+
|
|
+ if (event) {
|
|
+ // remove it from the queue
|
|
+ list->head = event->next;
|
|
+ if (list->tail == event)
|
|
+ list->tail = NULL;
|
|
+
|
|
+ event->next = NULL; // just because we're paranoid
|
|
+ }
|
|
+
|
|
+ return event;
|
|
+}
|
|
+
|
|
+
|
|
+static debug_event *
|
|
+haiku_remove_debug_event(debug_event_list *list, debug_event *eventToRemove)
|
|
+{
|
|
+ debug_event **event;
|
|
+
|
|
+ if (eventToRemove) {
|
|
+ for (event = &list->head; *event; event = &(*event)->next) {
|
|
+ if (*event == eventToRemove) {
|
|
+ *event = (*event)->next;
|
|
+ if (eventToRemove == list->tail)
|
|
+ list->tail = NULL;
|
|
+ return eventToRemove;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ error("haiku_remove_debug_event(): event %p not found in list %p\n",
|
|
+ eventToRemove, list);
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_clear_debug_event_list(debug_event_list *list)
|
|
+{
|
|
+ debug_event *event;
|
|
+
|
|
+ while ((event = haiku_dequeue_next_debug_event(list)))
|
|
+ xfree(event);
|
|
+}
|
|
+
|
|
+
|
|
+static debug_event *
|
|
+haiku_find_next_debug_event(debug_event_list *list,
|
|
+ bool (*predicate)(void *closure, debug_event *event), void *closure)
|
|
+{
|
|
+ debug_event *event;
|
|
+
|
|
+ for (event = list->head; event; event = event->next) {
|
|
+ if ((*predicate)(closure, event))
|
|
+ return event;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_read_pending_debug_events(team_debug_info *teamDebugInfo,
|
|
+ bool block, bool (*block_predicate)(void *closure, debug_event *event),
|
|
+ void *closure)
|
|
+{
|
|
+ while (true) {
|
|
+ // read the next message from the debugger port
|
|
+ debug_debugger_message_data message;
|
|
+ int32 code;
|
|
+ ssize_t bytesRead;
|
|
+ debug_event *event;
|
|
+
|
|
+// TRACE(("haiku_read_pending_debug_events(): reading from debugger port "
|
|
+// "(%sblocking)...\n", (block ? "" : "non-")));
|
|
+
|
|
+ do {
|
|
+ bytesRead = read_port_etc(teamDebugInfo->debugger_port, &code,
|
|
+ &message, sizeof(message), (block ? 0 : B_RELATIVE_TIMEOUT), 0);
|
|
+ } while (bytesRead == B_INTERRUPTED);
|
|
+
|
|
+ if (bytesRead < 0) {
|
|
+ if (bytesRead == B_WOULD_BLOCK && !block)
|
|
+ break;
|
|
+
|
|
+ error("Failed to read from debugger port: %s\n",
|
|
+ strerror(bytesRead));
|
|
+ }
|
|
+
|
|
+// TRACE(("haiku_read_pending_debug_events(): got event: %lu, "
|
|
+// "thread: %ld, team: %ld, nub port: %ld\n", code,
|
|
+// message.origin.thread, message.origin.team,
|
|
+// message.origin.nub_port));
|
|
+
|
|
+ // got a message: queue it
|
|
+ event = haiku_enqueue_debug_event(&teamDebugInfo->events, code,
|
|
+ &message, bytesRead);
|
|
+
|
|
+ block = !(*block_predicate)(closure, event);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+typedef struct thread_event_closure {
|
|
+ team_debug_info *context;
|
|
+ thread_id thread;
|
|
+ debug_event *event;
|
|
+} thread_event_closure;
|
|
+
|
|
+
|
|
+static bool
|
|
+haiku_thread_event_predicate(void *_closure, debug_event *event)
|
|
+{
|
|
+ thread_event_closure *closure = (thread_event_closure*)_closure;
|
|
+
|
|
+ if (event->message == B_DEBUGGER_MESSAGE_TEAM_DELETED) {
|
|
+ if (closure->context->team < 0
|
|
+ || event->data.origin.team == closure->context->team) {
|
|
+ closure->event = event;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!closure->event) {
|
|
+ if (event->data.origin.team == closure->context->team
|
|
+ && (closure->thread < 0
|
|
+ || closure->thread == event->data.origin.thread)) {
|
|
+ closure->event = event;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return (closure->event != NULL);
|
|
+}
|
|
+
|
|
+
|
|
+// #pragma mark -
|
|
+
|
|
+static void
|
|
+haiku_cleanup_team_debug_info()
|
|
+{
|
|
+ destroy_debug_context(&sTeamDebugInfo.context);
|
|
+ delete_port(sTeamDebugInfo.debugger_port);
|
|
+ sTeamDebugInfo.debugger_port = -1;
|
|
+ sTeamDebugInfo.team = -1;
|
|
+
|
|
+ haiku_cleanup_thread_list(&sTeamDebugInfo);
|
|
+ haiku_cleanup_image_list(&sTeamDebugInfo);
|
|
+}
|
|
+
|
|
+
|
|
+static status_t
|
|
+haiku_send_debugger_message(team_debug_info *teamDebugInfo, int32 messageCode,
|
|
+ const void *message, int32 messageSize, void *reply, int32 replySize)
|
|
+{
|
|
+ return send_debug_message(&teamDebugInfo->context, messageCode,
|
|
+ message, messageSize, reply, replySize);
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_init_child_debugging (thread_id threadID, bool debugThread)
|
|
+{
|
|
+ thread_info threadInfo;
|
|
+ status_t result;
|
|
+ port_id nubPort;
|
|
+
|
|
+ // get a thread info
|
|
+ result = get_thread_info(threadID, &threadInfo);
|
|
+ if (result != B_OK)
|
|
+ error("Thread with ID %ld not found: %s", threadID, strerror(result));
|
|
+
|
|
+ // init our team debug structure
|
|
+ sTeamDebugInfo.team = threadInfo.team;
|
|
+ sTeamDebugInfo.debugger_port = -1;
|
|
+ sTeamDebugInfo.context.nub_port = -1;
|
|
+ sTeamDebugInfo.context.reply_port = -1;
|
|
+ sTeamDebugInfo.threads = NULL;
|
|
+ sTeamDebugInfo.events.head = NULL;
|
|
+ sTeamDebugInfo.events.tail = NULL;
|
|
+
|
|
+ // create the debugger port
|
|
+ sTeamDebugInfo.debugger_port = create_port(10, "gdb debug");
|
|
+ if (sTeamDebugInfo.debugger_port < 0) {
|
|
+ error("Failed to create debugger port: %s",
|
|
+ strerror(sTeamDebugInfo.debugger_port));
|
|
+ }
|
|
+
|
|
+ // install ourselves as the team debugger
|
|
+ nubPort = install_team_debugger(sTeamDebugInfo.team,
|
|
+ sTeamDebugInfo.debugger_port);
|
|
+ if (nubPort < 0) {
|
|
+ error("Failed to install ourselves as debugger for team %ld: %s",
|
|
+ sTeamDebugInfo.team, strerror(nubPort));
|
|
+ }
|
|
+
|
|
+ // get the nub thread
|
|
+ {
|
|
+ team_info teamInfo;
|
|
+ result = get_team_info(sTeamDebugInfo.team, &teamInfo);
|
|
+ if (result != B_OK) {
|
|
+ error("Failed to get info for team %ld: %s\n",
|
|
+ sTeamDebugInfo.team, strerror(result));
|
|
+ }
|
|
+
|
|
+ sTeamDebugInfo.nub_thread = teamInfo.debugger_nub_thread;
|
|
+ }
|
|
+
|
|
+ // init the debug context
|
|
+ result = init_debug_context(&sTeamDebugInfo.context, sTeamDebugInfo.team,
|
|
+ nubPort);
|
|
+ if (result != B_OK) {
|
|
+ error("Failed to init debug context for team %ld: %s\n",
|
|
+ sTeamDebugInfo.team, strerror(result));
|
|
+ }
|
|
+
|
|
+ // start debugging the thread
|
|
+ if (debugThread) {
|
|
+ result = debug_thread(threadID);
|
|
+ if (result != B_OK) {
|
|
+ error("Failed to start debugging thread %ld: %s", threadID,
|
|
+ strerror(result));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // set the team debug flags
|
|
+ {
|
|
+ debug_nub_set_team_flags message;
|
|
+ message.flags = B_TEAM_DEBUG_SIGNALS /*| B_TEAM_DEBUG_PRE_SYSCALL
|
|
+ | B_TEAM_DEBUG_POST_SYSCALL*/ | B_TEAM_DEBUG_TEAM_CREATION
|
|
+ | B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES;
|
|
+ // TODO: We probably don't need all events
|
|
+
|
|
+ haiku_send_debugger_message(&sTeamDebugInfo,
|
|
+ B_DEBUG_MESSAGE_SET_TEAM_FLAGS, &message, sizeof(message), NULL, 0);
|
|
+ }
|
|
+
|
|
+
|
|
+ // the fun can start: push the target and init the rest
|
|
+ push_target(sHaikuTarget);
|
|
+
|
|
+ haiku_init_thread_list(&sTeamDebugInfo);
|
|
+ haiku_init_image_list(&sTeamDebugInfo);
|
|
+
|
|
+ disable_breakpoints_in_shlibs (1);
|
|
+
|
|
+// child_clear_solibs ();
|
|
+ // TODO: Implement? Do we need this?
|
|
+
|
|
+ clear_proceed_status ();
|
|
+ init_wait_for_inferior ();
|
|
+
|
|
+ target_terminal_init ();
|
|
+ target_terminal_inferior ();
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_continue_thread(team_debug_info *teamDebugInfo, thread_id threadID,
|
|
+ uint32 handleEvent, bool step)
|
|
+{
|
|
+ debug_nub_continue_thread message;
|
|
+ status_t err;
|
|
+
|
|
+ message.thread = threadID;
|
|
+ message.handle_event = handleEvent;
|
|
+ message.single_step = step;
|
|
+
|
|
+ err = haiku_send_debugger_message(teamDebugInfo,
|
|
+ B_DEBUG_MESSAGE_CONTINUE_THREAD, &message, sizeof(message), NULL, 0);
|
|
+ if (err != B_OK) {
|
|
+ printf_unfiltered ("Failed to resume thread %ld: %s\n", threadID,
|
|
+ strerror(err));
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static status_t
|
|
+haiku_stop_thread(team_debug_info *teamDebugInfo, thread_id threadID)
|
|
+{
|
|
+ // check whether we know the thread
|
|
+ status_t err;
|
|
+ thread_event_closure threadEventClosure;
|
|
+
|
|
+ thread_debug_info *threadInfo = haiku_find_thread(teamDebugInfo, threadID);
|
|
+ if (!threadInfo)
|
|
+ return B_BAD_THREAD_ID;
|
|
+
|
|
+ // already stopped?
|
|
+ if (threadInfo->stopped)
|
|
+ return B_OK;
|
|
+
|
|
+ // debug the thread
|
|
+ err = debug_thread(threadID);
|
|
+ if (err != B_OK) {
|
|
+ TRACE(("haiku_stop_thread(): failed to debug thread %ld: %s\n",
|
|
+ threadID, strerror(err)));
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ // wait for the event to hit our port
|
|
+
|
|
+ // TODO: debug_thread() doesn't guarantee that the thread will enter the
|
|
+ // debug loop any time soon. E.g. a wait_for_thread() is (at the moment)
|
|
+ // not interruptable, so we block here forever, if we already debug the
|
|
+ // thread that is being waited for. We should probably limit the time
|
|
+ // we're waiting, and return the info to the caller, which can then try
|
|
+ // to deal with the situation in an appropriate way.
|
|
+
|
|
+ // prepare closure for finding interesting events
|
|
+ threadEventClosure.context = teamDebugInfo;
|
|
+ threadEventClosure.thread = threadID;
|
|
+ threadEventClosure.event = NULL;
|
|
+
|
|
+ // find the first interesting queued event
|
|
+ threadEventClosure.event = haiku_find_next_debug_event(
|
|
+ &teamDebugInfo->events, haiku_thread_event_predicate,
|
|
+ &threadEventClosure);
|
|
+
|
|
+ // read all events pending on the port
|
|
+ haiku_read_pending_debug_events(teamDebugInfo,
|
|
+ (threadEventClosure.event == NULL), haiku_thread_event_predicate,
|
|
+ &threadEventClosure);
|
|
+
|
|
+ // We should check, whether we really got an event for the thread in
|
|
+ // question, but the only possible other event is that the team has
|
|
+ // been delete, which ends the game anyway.
|
|
+
|
|
+ // TODO: That's actually not true. We also get messages when an add-on
|
|
+ // has been loaded/unloaded, a signal arrives, or a thread calls the
|
|
+ // debugger.
|
|
+
|
|
+ return B_OK;
|
|
+}
|
|
+
|
|
+
|
|
+static status_t
|
|
+haiku_get_cpu_state(team_debug_info *teamDebugInfo,
|
|
+ debug_nub_get_cpu_state_reply *reply)
|
|
+{
|
|
+ status_t err;
|
|
+ thread_id threadID = ptid_get_tid(inferior_ptid);
|
|
+ debug_nub_get_cpu_state message;
|
|
+
|
|
+ // make sure the thread is stopped
|
|
+ err = haiku_stop_thread(teamDebugInfo, threadID);
|
|
+ if (err != B_OK) {
|
|
+ printf_unfiltered ("Failed to stop thread %ld: %s\n",
|
|
+ threadID, strerror(err));
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ message.reply_port = teamDebugInfo->context.reply_port;
|
|
+ message.thread = threadID;
|
|
+
|
|
+ err = haiku_send_debugger_message(teamDebugInfo,
|
|
+ B_DEBUG_MESSAGE_GET_CPU_STATE, &message, sizeof(message), reply,
|
|
+ sizeof(*reply));
|
|
+ if (err == B_OK)
|
|
+ err = reply->error;
|
|
+ if (err != B_OK) {
|
|
+ printf_unfiltered ("Failed to get status of thread %ld: %s\n",
|
|
+ threadID, strerror(err));
|
|
+ }
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+
|
|
+// #pragma mark -
|
|
+
|
|
+static void
|
|
+haiku_child_open (char *arg, int from_tty)
|
|
+{
|
|
+ error ("Use the \"run\" command to start a child process.");
|
|
+}
|
|
+
|
|
+static void
|
|
+haiku_child_close (int x)
|
|
+{
|
|
+ printf_unfiltered ("gdb: child_close, inferior_ptid=%d\n",
|
|
+ PIDGET (inferior_ptid));
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_child_attach (char *args, int from_tty)
|
|
+{
|
|
+ extern int stop_after_trap;
|
|
+ thread_id threadID;
|
|
+ thread_info threadInfo;
|
|
+ status_t result;
|
|
+
|
|
+ TRACE(("haiku_child_attach(`%s', %d)\n", args, from_tty));
|
|
+
|
|
+ if (!args)
|
|
+ error_no_arg ("thread-id to attach");
|
|
+
|
|
+ // get the thread ID
|
|
+ threadID = strtoul (args, 0, 0);
|
|
+ if (threadID <= 0)
|
|
+ error("The given thread-id %ld is invalid.", threadID);
|
|
+
|
|
+ haiku_init_child_debugging(threadID, true);
|
|
+
|
|
+ TRACE(("haiku_child_attach() done\n"));
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_child_detach (char *args, int from_tty)
|
|
+{
|
|
+ int detached = 1;
|
|
+ status_t result;
|
|
+
|
|
+ TRACE(("haiku_child_detach(`%s', %d)\n", args, from_tty));
|
|
+
|
|
+ result = remove_team_debugger(sTeamDebugInfo.team);
|
|
+ if (result != B_OK) {
|
|
+ error("Failed to detach process %ld: %s\n", sTeamDebugInfo.team,
|
|
+ strerror(result));
|
|
+ }
|
|
+
|
|
+ delete_command (NULL, 0);
|
|
+
|
|
+ if (from_tty) {
|
|
+ char *exec_file = get_exec_file (0);
|
|
+ if (exec_file == 0)
|
|
+ exec_file = "";
|
|
+ printf_unfiltered ("Detaching from program: %s, Pid %ld\n", exec_file,
|
|
+ sTeamDebugInfo.team);
|
|
+ gdb_flush (gdb_stdout);
|
|
+ }
|
|
+
|
|
+ haiku_cleanup_team_debug_info();
|
|
+
|
|
+ inferior_ptid = null_ptid;
|
|
+ unpush_target (sHaikuTarget);
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_resume_thread(team_debug_info *teamDebugInfo, thread_debug_info *thread,
|
|
+ int step, enum target_signal sig)
|
|
+{
|
|
+ thread_id threadID = (thread ? thread->thread : -1);
|
|
+ int pendingSignal = -1;
|
|
+ int signalToSend = target_to_haiku_signal(sig);
|
|
+ uint32 handleEvent = B_THREAD_DEBUG_HANDLE_EVENT;
|
|
+
|
|
+ if (!thread || !thread->stopped) {
|
|
+ TRACE(("haiku_resume_thread(): thread %ld not stopped\n",
|
|
+ threadID));
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (thread->reprocess_event > 0) {
|
|
+ TRACE(("haiku_resume_thread(): thread %ld is expected to "
|
|
+ "reprocess its current event\n", threadID));
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // get the pending signal
|
|
+ if (thread->last_event)
|
|
+ pendingSignal = thread->signal;
|
|
+
|
|
+ // Decide what to do with the event and the pending and passed signal.
|
|
+ // We simply adjust signalToSend, pendingSignal and handleEvent.
|
|
+ // If signalToSend is set afterwards, we need to send it. pendingSignal we
|
|
+ // need to ignore. handleEvent specifies whether to handle/ignore the event.
|
|
+ if (signalToSend > 0) {
|
|
+ if (pendingSignal > 0) {
|
|
+ if (signalToSend == pendingSignal) {
|
|
+ // signal to send is the pending signal
|
|
+ // we don't need to send it
|
|
+ signalToSend = -1;
|
|
+ if (thread->signal_status != SIGNAL_WILL_ARRIVE) {
|
|
+ // the signal has not yet been sent, so we need to ignore
|
|
+ // it only in this case, but not in the other ones
|
|
+ pendingSignal = -1;
|
|
+ }
|
|
+ } else {
|
|
+ // signal to send is not the pending signal
|
|
+ // If the signal has been sent or will be sent, we need to
|
|
+ // ignore the event.
|
|
+ if (thread->signal_status != SIGNAL_FAKED)
|
|
+ handleEvent = B_THREAD_DEBUG_IGNORE_EVENT;
|
|
+ // At any rate we don't need to ignore the signal.
|
|
+ pendingSignal = -1;
|
|
+ // send the signal
|
|
+ }
|
|
+ } else {
|
|
+ // there's a signal to send, but no pending signal
|
|
+ // handle the event
|
|
+ // ignore the signal
|
|
+ // send the signal
|
|
+ }
|
|
+ } else {
|
|
+ if (pendingSignal > 0) {
|
|
+ // there's a pending signal, but no signal to send
|
|
+ // Ignore the event, if the signal has been sent or will be sent.
|
|
+ if (thread->signal_status != SIGNAL_FAKED)
|
|
+ handleEvent = B_THREAD_DEBUG_IGNORE_EVENT;
|
|
+ } else {
|
|
+ // there're neither signal to send nor pending signal
|
|
+ // handle the event
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // ignore the pending signal, if necessary
|
|
+ if (pendingSignal > 0) {
|
|
+ debug_nub_set_signal_masks message;
|
|
+ status_t err;
|
|
+
|
|
+ message.thread = threadID;
|
|
+ message.ignore_mask = 0;
|
|
+ message.ignore_once_mask = B_DEBUG_SIGNAL_TO_MASK(pendingSignal);
|
|
+ message.ignore_op = B_DEBUG_SIGNAL_MASK_OR;
|
|
+ message.ignore_once_op = B_DEBUG_SIGNAL_MASK_OR;
|
|
+
|
|
+ err = haiku_send_debugger_message(teamDebugInfo,
|
|
+ B_DEBUG_MESSAGE_SET_SIGNAL_MASKS, &message, sizeof(message),
|
|
+ NULL, 0);
|
|
+ if (err != B_OK) {
|
|
+ printf_unfiltered ("Set signal ignore masks for thread %ld: %s\n",
|
|
+ threadID, strerror(err));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // send the signal
|
|
+ if (signalToSend > 0) {
|
|
+ if (send_signal(threadID, signalToSend) < 0) {
|
|
+ printf_unfiltered ("Failed to send signal %d to thread %ld: %s\n",
|
|
+ signalToSend, threadID, strerror(errno));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // resume thread
|
|
+ haiku_continue_thread(teamDebugInfo, threadID, handleEvent, step);
|
|
+ thread->stopped = false;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_child_resume (ptid_t ptid, int step, enum target_signal sig)
|
|
+{
|
|
+ team_id teamID = ptid_get_pid(ptid);
|
|
+ thread_id threadID = ptid_get_tid(ptid);
|
|
+ thread_debug_info *thread;
|
|
+
|
|
+ TRACE(("haiku_child_resume(`%s', step: %d, signal: %d)\n",
|
|
+ haiku_pid_to_str(ptid), step, sig));
|
|
+
|
|
+ if (teamID < 0) {
|
|
+ // resume all stopped threads (at least all haiku_wait_child() has
|
|
+ // reported to be stopped)
|
|
+ for (thread = sTeamDebugInfo.threads; thread; thread = thread->next) {
|
|
+ if (thread->stopped)
|
|
+ haiku_resume_thread(&sTeamDebugInfo, thread, step, sig);
|
|
+ }
|
|
+ } else {
|
|
+ // resume the thread in question
|
|
+ thread = haiku_find_thread(&sTeamDebugInfo, threadID);
|
|
+ if (thread) {
|
|
+ haiku_resume_thread(&sTeamDebugInfo, thread, step, sig);
|
|
+ } else {
|
|
+ printf_unfiltered ("haiku_child_resume(): unknown thread %ld\n",
|
|
+ threadID);
|
|
+ }
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+
|
|
+static ptid_t
|
|
+haiku_child_wait_internal (team_debug_info *teamDebugInfo, ptid_t ptid,
|
|
+ struct target_waitstatus *ourstatus, bool *ignore, bool *selectThread)
|
|
+{
|
|
+ team_id teamID = ptid_get_pid(ptid);
|
|
+ team_id threadID = ptid_get_tid(ptid);
|
|
+ debug_event *event = NULL;
|
|
+ ptid_t retval = pid_to_ptid(-1);
|
|
+ struct thread_debug_info *thread;
|
|
+ int pendingSignal = -1;
|
|
+ pending_signal_status pendingSignalStatus = SIGNAL_FAKED;
|
|
+ int reprocessEvent = -1;
|
|
+
|
|
+ *selectThread = false;
|
|
+
|
|
+ if (teamID < 0 || threadID == 0)
|
|
+ threadID = -1;
|
|
+
|
|
+ // if we're waiting for any thread, search the thread list for already
|
|
+ // stopped threads (needed for reprocessing events)
|
|
+ if (threadID < 0) {
|
|
+ for (thread = teamDebugInfo->threads; thread; thread = thread->next) {
|
|
+ if (thread->stopped) {
|
|
+ threadID = thread->thread;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // check, if the thread exists and is already stopped
|
|
+ if (threadID >= 0
|
|
+ && (thread = haiku_find_thread(teamDebugInfo, threadID)) != NULL
|
|
+ && thread->stopped) {
|
|
+ // remove the event that stopped the thread from the thread (we will
|
|
+ // add it again, if it shall not be ignored)
|
|
+ event = thread->last_event;
|
|
+ thread->last_event = NULL;
|
|
+ thread->stopped = false;
|
|
+ reprocessEvent = thread->reprocess_event;
|
|
+
|
|
+ TRACE(("haiku_child_wait_internal(): thread %ld already stopped. "
|
|
+ "re-digesting the last event (%p).\n", threadID, event));
|
|
+ } else {
|
|
+ // prepare closure for finding interesting events
|
|
+ thread_event_closure threadEventClosure;
|
|
+ threadEventClosure.context = teamDebugInfo;
|
|
+ threadEventClosure.thread = threadID;
|
|
+ threadEventClosure.event = NULL;
|
|
+
|
|
+ // find the first interesting queued event
|
|
+ threadEventClosure.event = haiku_find_next_debug_event(
|
|
+ &teamDebugInfo->events, haiku_thread_event_predicate,
|
|
+ &threadEventClosure);
|
|
+
|
|
+ // read all events pending on the port
|
|
+ haiku_read_pending_debug_events(teamDebugInfo,
|
|
+ (threadEventClosure.event == NULL), haiku_thread_event_predicate,
|
|
+ &threadEventClosure);
|
|
+
|
|
+ // get the event of interest
|
|
+ event = haiku_remove_debug_event(&teamDebugInfo->events,
|
|
+ threadEventClosure.event);
|
|
+
|
|
+ if (!event) {
|
|
+ TRACE(("haiku_child_wait_internal(): got no event!\n"));
|
|
+ return retval;
|
|
+ }
|
|
+
|
|
+ TRACE(("haiku_child_wait_internal(): got event: %u, thread: %ld, "
|
|
+ "team: %ld, nub port: %ld\n", event->message,
|
|
+ event->data.origin.thread, event->data.origin.team,
|
|
+ event->data.origin.nub_port));
|
|
+ }
|
|
+
|
|
+ if (event->data.origin.team != teamDebugInfo->team) {
|
|
+ // Spurious debug message. Doesn't concern our team. Ignore.
|
|
+ xfree(event);
|
|
+ return retval;
|
|
+ }
|
|
+
|
|
+ retval = ptid_build(event->data.origin.team, 0, event->data.origin.thread);
|
|
+
|
|
+ *ignore = false;
|
|
+
|
|
+ switch (event->message) {
|
|
+ case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
|
|
+ {
|
|
+ // print the debugger message
|
|
+ char debuggerMessage[1024];
|
|
+ ssize_t bytesRead = debug_read_string(&teamDebugInfo->context,
|
|
+ event->data.debugger_call.message, debuggerMessage,
|
|
+ sizeof(debuggerMessage));
|
|
+ if (bytesRead > 0) {
|
|
+ printf_unfiltered ("Thread %ld called debugger(): %s\n",
|
|
+ event->data.origin.thread, debuggerMessage);
|
|
+ } else {
|
|
+ printf_unfiltered ("Thread %ld called debugger(), but failed"
|
|
+ "to get the debugger message.\n",
|
|
+ event->data.origin.thread);
|
|
+ }
|
|
+
|
|
+ // fall through...
|
|
+ }
|
|
+ case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
|
|
+ case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
|
|
+ case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
|
|
+ case B_DEBUGGER_MESSAGE_SINGLE_STEP:
|
|
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
|
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
|
|
+ pendingSignal = SIGTRAP;
|
|
+ pendingSignalStatus = SIGNAL_FAKED;
|
|
+ break;
|
|
+
|
|
+ case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
|
|
+ ourstatus->kind = TARGET_WAITKIND_SYSCALL_ENTRY;
|
|
+ ourstatus->value.syscall_id = event->data.pre_syscall.syscall;
|
|
+ break;
|
|
+
|
|
+ case B_DEBUGGER_MESSAGE_POST_SYSCALL:
|
|
+ ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
|
|
+ ourstatus->value.syscall_id = event->data.post_syscall.syscall;
|
|
+ break;
|
|
+
|
|
+ case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
|
|
+ pendingSignal = event->data.signal_received.signal;
|
|
+ pendingSignalStatus = SIGNAL_ARRIVED;
|
|
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
|
+ ourstatus->value.sig = haiku_to_target_signal(pendingSignal);
|
|
+ break;
|
|
+
|
|
+ case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
|
|
+ {
|
|
+ // print the exception message
|
|
+ char exception[1024];
|
|
+ get_debug_exception_string(event->data.exception_occurred.exception,
|
|
+ exception, sizeof(exception));
|
|
+ printf_unfiltered ("Thread %ld caused an exception: %s\n",
|
|
+ event->data.origin.thread, exception);
|
|
+
|
|
+ pendingSignal = event->data.exception_occurred.signal;
|
|
+ pendingSignalStatus = SIGNAL_WILL_ARRIVE;
|
|
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
|
+ ourstatus->value.sig = haiku_to_target_signal(pendingSignal);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case B_DEBUGGER_MESSAGE_TEAM_CREATED:
|
|
+ // ignore
|
|
+ *ignore = true;
|
|
+ break;
|
|
+
|
|
+ case B_DEBUGGER_MESSAGE_TEAM_DELETED:
|
|
+ ourstatus->kind = TARGET_WAITKIND_EXITED;
|
|
+ ourstatus->value.integer = 0;
|
|
+ // TODO: Extend the debugger interface?
|
|
+ break;
|
|
+
|
|
+ case B_DEBUGGER_MESSAGE_THREAD_CREATED:
|
|
+ {
|
|
+ // internal bookkeeping only
|
|
+ thread_id newThread = event->data.thread_created.new_thread;
|
|
+ if (newThread != teamDebugInfo->nub_thread)
|
|
+ haiku_add_thread(teamDebugInfo, newThread);
|
|
+ *ignore = true;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case B_DEBUGGER_MESSAGE_THREAD_DELETED:
|
|
+ // internal bookkeeping
|
|
+ haiku_remove_thread(teamDebugInfo,
|
|
+ event->data.thread_deleted.origin.thread);
|
|
+ *ignore = true;
|
|
+
|
|
+ // TODO: What if this is the current thread?
|
|
+ break;
|
|
+
|
|
+ case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
|
|
+ if (reprocessEvent < 0) {
|
|
+ // first time we see the event: update our image list
|
|
+// haiku_add_image(teamDebugInfo,
|
|
+// &event->data.image_created.info);
|
|
+haiku_cleanup_image_list(teamDebugInfo);
|
|
+haiku_init_image_list(teamDebugInfo);
|
|
+// TODO: We don't get events when images have been removed in preparation of
|
|
+// an exec*() yet.
|
|
+ }
|
|
+
|
|
+ ourstatus->kind = TARGET_WAITKIND_LOADED;
|
|
+ ourstatus->value.integer = 0;
|
|
+ if (event->data.image_created.info.type == B_APP_IMAGE) {
|
|
+ // An app image has been loaded, i.e. the application is now
|
|
+ // fully loaded. We need to send a TARGET_WAITKIND_LOADED
|
|
+ // first, so that GDB's shared object list is updated correctly.
|
|
+ // But we also need to send an TARGET_WAITKIND_EXECD event.
|
|
+ // We use the reprocessEvent mechanism here.
|
|
+
|
|
+ if (reprocessEvent == 2) {
|
|
+ // the second time the event is processed: send the `exec'
|
|
+ // event
|
|
+ if (inferior_ignoring_startup_exec_events > 0) {
|
|
+ // we shall not send an exec event, so we skip that
|
|
+ // and send the `trap' immediately
|
|
+TRACE(("haiku_child_wait_internal(): ignoring exec (%d)\n",
|
|
+inferior_ignoring_startup_exec_events));
|
|
+ inferior_ignoring_startup_exec_events--;
|
|
+ reprocessEvent = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (reprocessEvent < 0) {
|
|
+TRACE(("haiku_child_wait_internal(): B_APP_IMAGE created, reprocess < 0\n"));
|
|
+ // the first time the event is processed: send the
|
|
+ // `loaded' event
|
|
+ reprocessEvent = 2;
|
|
+ } else if (reprocessEvent == 2) {
|
|
+TRACE(("haiku_child_wait_internal(): B_APP_IMAGE created, reprocess -> exec\n"));
|
|
+ // the second time the event is processed: send the `exec'
|
|
+ // event
|
|
+ ourstatus->kind = TARGET_WAITKIND_EXECD;
|
|
+ ourstatus->value.execd_pathname
|
|
+ = event->data.image_created.info.name;
|
|
+
|
|
+ reprocessEvent = 1;
|
|
+ } else if (reprocessEvent <= 1) {
|
|
+ // the third time the event is processed: send the `trap'
|
|
+ // event
|
|
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
|
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
|
|
+ pendingSignal = SIGTRAP;
|
|
+ pendingSignalStatus = SIGNAL_FAKED;
|
|
+
|
|
+ reprocessEvent = 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // re_enable_breakpoints_in_shlibs ();
|
|
+ // TODO: Needed?
|
|
+ break;
|
|
+
|
|
+ case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
|
|
+ haiku_remove_image(teamDebugInfo,
|
|
+ event->data.image_deleted.info.id);
|
|
+
|
|
+ // send TARGET_WAITKIND_LOADED here too, it causes the shared
|
|
+ // object list to be updated
|
|
+ ourstatus->kind = TARGET_WAITKIND_LOADED;
|
|
+ ourstatus->value.integer = 0;
|
|
+ break;
|
|
+
|
|
+ case B_DEBUGGER_MESSAGE_HANDED_OVER:
|
|
+ {
|
|
+TRACE(("haiku_child_wait_internal(): B_DEBUGGER_MESSAGE_HANDED_OVER: causing "
|
|
+"thread: %ld\n", event->data.handed_over.causing_thread));
|
|
+ // The debugged team has been handed over to us by another debugger
|
|
+ // (likely the debug server). This event also tells us, which
|
|
+ // thread has caused the original debugger to be installed (if any).
|
|
+ // So, if we're not looking for any particular thread, select that
|
|
+ // thread.
|
|
+ if (threadID < 0 && event->data.handed_over.causing_thread >= 0) {
|
|
+ *selectThread = true;
|
|
+ retval = ptid_build(event->data.origin.team, 0,
|
|
+ event->data.handed_over.causing_thread);
|
|
+ }
|
|
+ *ignore = true;
|
|
+ }
|
|
+
|
|
+ default:
|
|
+ // unknown message, ignore
|
|
+ *ignore = true;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ // make the event the thread's last event or delete it
|
|
+ if (!*ignore && event->data.origin.thread >= 0) {
|
|
+ struct thread_debug_info *thread = haiku_find_thread(teamDebugInfo,
|
|
+ event->data.origin.thread);
|
|
+ if (thread->last_event)
|
|
+ xfree(thread->last_event);
|
|
+ thread->last_event = event;
|
|
+ thread->stopped = true;
|
|
+ thread->signal = pendingSignal;
|
|
+ thread->signal_status = pendingSignalStatus;
|
|
+ thread->reprocess_event
|
|
+ = (reprocessEvent >= 0 ? reprocessEvent : 0);
|
|
+ } else {
|
|
+ thread_id originThread = event->data.origin.thread;
|
|
+ xfree(event);
|
|
+
|
|
+ // continue the thread
|
|
+ if (originThread >= 0) {
|
|
+ haiku_continue_thread(teamDebugInfo, originThread,
|
|
+ B_THREAD_DEBUG_HANDLE_EVENT, false);
|
|
+ }
|
|
+
|
|
+// *ignore = true;
|
|
+// TODO: This should indeed not be needed. It definitely eats the
|
|
+// `team deleted' events.
|
|
+ }
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+
|
|
+static ptid_t
|
|
+haiku_child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
|
|
+{
|
|
+ ptid_t retval;
|
|
+ bool ignore = true;
|
|
+ bool selectThread = false;
|
|
+
|
|
+ TRACE(("haiku_child_wait(`%s', %p)\n",
|
|
+ haiku_pid_to_str(ptid), ourstatus));
|
|
+
|
|
+ do {
|
|
+ retval = haiku_child_wait_internal(&sTeamDebugInfo, ptid, ourstatus,
|
|
+ &ignore, &selectThread);
|
|
+ if (selectThread)
|
|
+ ptid = retval;
|
|
+ } while (ignore);
|
|
+
|
|
+ TRACE(("haiku_child_wait() done: `%s'\n", haiku_pid_to_str(retval)));
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_child_fetch_inferior_registers (int reg)
|
|
+{
|
|
+ debug_nub_get_cpu_state_reply reply;
|
|
+
|
|
+ TRACE(("haiku_child_fetch_inferior_registers(%d)\n", reg));
|
|
+
|
|
+ // get the CPU state
|
|
+ haiku_get_cpu_state(&sTeamDebugInfo, &reply);
|
|
+
|
|
+// printf("haiku_child_fetch_inferior_registers(): eip: %p, ebp: %p\n",
|
|
+// (void*)reply.cpu_state.eip, (void*)reply.cpu_state.ebp);
|
|
+
|
|
+ // supply the registers (architecture specific)
|
|
+ haiku_supply_registers(reg, &reply.cpu_state);
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+haiku_child_store_inferior_registers (int reg)
|
|
+{
|
|
+ status_t err;
|
|
+ thread_id threadID = ptid_get_tid(inferior_ptid);
|
|
+ debug_nub_get_cpu_state_reply reply;
|
|
+ debug_nub_set_cpu_state message;
|
|
+
|
|
+ TRACE(("haiku_child_store_inferior_registers(%d)\n", reg));
|
|
+
|
|
+ // get the current CPU state
|
|
+ haiku_get_cpu_state(&sTeamDebugInfo, &reply);
|
|
+
|
|
+ // collect the registers (architecture specific)
|
|
+ haiku_collect_registers(reg, &reply.cpu_state);
|
|
+
|
|
+ // set the new CPU state
|
|
+ message.thread = threadID;
|
|
+ memcpy(&message.cpu_state, &reply.cpu_state, sizeof(debug_cpu_state));
|
|
+ err = haiku_send_debugger_message(&sTeamDebugInfo,
|
|
+ B_DEBUG_MESSAGE_SET_CPU_STATE, &message, sizeof(message), NULL, 0);
|
|
+ if (err != B_OK) {
|
|
+ printf_unfiltered ("Failed to set status of thread %ld: %s\n",
|
|
+ threadID, strerror(err));
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+haiku_child_prepare_to_store (void)
|
|
+{
|
|
+ // Since we always fetching the current state in
|
|
+ // haiku_child_store_inferior_registers(), this should be a no-op.
|
|
+}
|
|
+
|
|
+static int
|
|
+haiku_child_deprecated_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
|
|
+ int write, struct mem_attrib *attrib, struct target_ops *target)
|
|
+{
|
|
+ TRACE(("haiku_child_deprecated_xfer_memory(0x%8lx, %p, %d, %d, %p, %p)\n",
|
|
+ (uint32)memaddr, myaddr, len, write, attrib, target));
|
|
+
|
|
+ if (len <= 0)
|
|
+ return 0;
|
|
+
|
|
+ if (write) {
|
|
+ // write
|
|
+ debug_nub_write_memory message;
|
|
+ debug_nub_write_memory_reply reply;
|
|
+ status_t err;
|
|
+
|
|
+ if (len > B_MAX_READ_WRITE_MEMORY_SIZE)
|
|
+ len = B_MAX_READ_WRITE_MEMORY_SIZE;
|
|
+
|
|
+ message.reply_port = sTeamDebugInfo.context.reply_port;
|
|
+ message.address = (void*)memaddr;
|
|
+ message.size = len;
|
|
+ memcpy(message.data, myaddr, len);
|
|
+
|
|
+ err = haiku_send_debugger_message(&sTeamDebugInfo,
|
|
+ B_DEBUG_MESSAGE_WRITE_MEMORY, &message, sizeof(message), &reply,
|
|
+ sizeof(reply));
|
|
+ if (err != B_OK || reply.error != B_OK)
|
|
+{
|
|
+TRACE(("haiku_child_deprecated_xfer_memory() failed: %lx\n",
|
|
+(err != B_OK ? err : reply.error)));
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+TRACE(("haiku_child_deprecated_xfer_memory(): -> %ld\n", reply.size));
|
|
+ return reply.size;
|
|
+ } else {
|
|
+ // read
|
|
+ ssize_t bytesRead = debug_read_memory_partial(&sTeamDebugInfo.context,
|
|
+ (const void *)memaddr, myaddr, len);
|
|
+ return (bytesRead < 0 ? 0 : bytesRead);
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+LONGEST
|
|
+haiku_child_xfer_partial (struct target_ops *ops, enum target_object object,
|
|
+ const char *annex, void *readbuf, const void *writebuf, ULONGEST offset,
|
|
+ LONGEST len)
|
|
+{
|
|
+ if (!readbuf && !writebuf)
|
|
+ return -1;
|
|
+
|
|
+ switch (object) {
|
|
+ case TARGET_OBJECT_MEMORY:
|
|
+ {
|
|
+ int write = !readbuf;
|
|
+ return haiku_child_deprecated_xfer_memory (offset,
|
|
+ (write ? (void*)writebuf : readbuf), len, write, NULL, ops);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static void
|
|
+haiku_child_files_info (struct target_ops *ignore)
|
|
+{
|
|
+ printf_unfiltered ("\tUsing the running image of %s %s.\n",
|
|
+ attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid));
|
|
+}
|
|
+
|
|
+static void
|
|
+haiku_child_kill_inferior (void)
|
|
+{
|
|
+ status_t err;
|
|
+ thread_id teamID = ptid_get_pid(inferior_ptid);
|
|
+
|
|
+ TRACE(("haiku_child_kill_inferior()\n"));
|
|
+
|
|
+ err = kill_team(teamID);
|
|
+ if (err != B_OK) {
|
|
+ printf_unfiltered ("Failed to kill team %ld: %s\n", teamID,
|
|
+ strerror(err));
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ target_mourn_inferior();
|
|
+}
|
|
+
|
|
+static void
|
|
+haiku_child_stop_inferior (void)
|
|
+{
|
|
+ status_t err;
|
|
+ thread_id threadID = ptid_get_tid(inferior_ptid);
|
|
+
|
|
+ TRACE(("haiku_child_stop_inferior()\n"));
|
|
+
|
|
+ err = debug_thread(threadID);
|
|
+ if (err != B_OK) {
|
|
+ printf_unfiltered ("Failed to stop thread %ld: %s\n", threadID,
|
|
+ strerror(err));
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+haiku_init_debug_create_inferior(int pid)
|
|
+{
|
|
+ extern int stop_after_trap;
|
|
+
|
|
+ // fix inferior_ptid -- fork_inferior() sets the process ID only
|
|
+ inferior_ptid = ptid_build (pid, 0, pid);
|
|
+ // team ID == team main thread ID under Haiku
|
|
+
|
|
+ haiku_init_child_debugging(pid, false);
|
|
+
|
|
+ // eat the initial `debugged' event caused by wait_for_inferior()
|
|
+// TODO: Maybe we should just dequeue the event and continue the thread instead
|
|
+// of using gdb's mechanism, since I don't know what undesired side-effects
|
|
+// they may have.
|
|
+ clear_proceed_status ();
|
|
+ init_wait_for_inferior ();
|
|
+
|
|
+ if (STARTUP_WITH_SHELL)
|
|
+ inferior_ignoring_startup_exec_events = 2;
|
|
+ else
|
|
+ inferior_ignoring_startup_exec_events = 1;
|
|
+ inferior_ignoring_leading_exec_events = 0;
|
|
+
|
|
+ while (true) {
|
|
+ thread_debug_info *thread;
|
|
+
|
|
+ stop_soon = STOP_QUIETLY;
|
|
+ wait_for_inferior();
|
|
+
|
|
+ if (stop_signal == TARGET_SIGNAL_TRAP) {
|
|
+ thread = haiku_find_thread(&sTeamDebugInfo, pid);
|
|
+
|
|
+ if (thread && thread->stopped
|
|
+ && thread->last_event->message
|
|
+ == B_DEBUGGER_MESSAGE_IMAGE_CREATED
|
|
+ && thread->last_event->data.image_created.info.type
|
|
+ == B_APP_IMAGE
|
|
+ && thread->reprocess_event == 0
|
|
+ && inferior_ignoring_startup_exec_events <= 0) {
|
|
+ // This is the trap for the last (second, if started via shell)
|
|
+ // `load app image' event. Be done.
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ resume(0, stop_signal);
|
|
+ }
|
|
+ stop_soon = NO_STOP_QUIETLY;
|
|
+
|
|
+ // load shared library symbols
|
|
+ target_terminal_ours_for_output ();
|
|
+ SOLIB_ADD (NULL, 0, ¤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.2.2
|
|
|