diff --git a/devel/gdb/Makefile b/devel/gdb/Makefile new file mode 100644 index 00000000..e422dc7a --- /dev/null +++ b/devel/gdb/Makefile @@ -0,0 +1,81 @@ +# Created by: Steven Kreuzer +# $FreeBSD: head/devel/gdb/Makefile 513464 2019-10-01 08:51:39Z pizzamig $ + +PORTNAME= gdb +PORTVERSION= 8.3.1 +CATEGORIES= devel +MASTER_SITES= GNU + +MAINTAINER= pizzamig@FreeBSD.org +COMMENT= GNU GDB of newer version than comes with the system + +LIB_DEPENDS+= libexpat.so:text/libexpat +LIB_DEPENDS+= libgmp.so:math/libgmp +LIB_DEPENDS+= libiconv.so:text/libiconv +LIB_DEPENDS+= libmpfr.so:math/libmpfr +LIB_DEPENDS+= libreadline.so:devel/libreadline + +NOT_FOR_ARCHS= sparc64 + +USES= compiler:c++11-lang cpe gmake libtool pkgconfig tar:xz +USES+= iconv +USES+= readline:port +USES+= iconv:wchar_t +USE_PYTHON= flavors py3kplist + +EXCLUDE= dejagnu expect sim texinfo intl +EXTRACT_AFTER_ARGS= ${EXCLUDE:S/^/--exclude /} + +EXTRA_PATCHES= ${FILESDIR}/commit-1163a4b7a3 \ + ${FILESDIR}/commit-dd6876c91c \ + ${FILESDIR}/commit-6e056c8178 \ + ${FILESDIR}/commit-36c53a0262 \ + ${FILESDIR}/commit-ef0bd2046f \ + ${FILESDIR}/commit-945f3901b5 \ + ${FILESDIR}/commit-f5424cfa7e \ + ${FILESDIR}/commit-ce25aa57a3 \ + ${FILESDIR}/commit-8399425f5f + + +USE_CSTD= gnu89 +GNU_CONFIGURE= yes +CONFIGURE_ENV= CONFIGURED_M4=gm4 CONFIGURED_BISON=byacc +CONFIGURE_ARGS+= --program-suffix=${PORTVERSION:S/.//g} +CONFIGURE_ARGS+= --enable-targets=all --enable-64-bit-bfd +CONFIGURE_ARGS+= --with-separate-debug-dir=/usr/lib/debug +CONFIGURE_ARGS+= --with-expat=yes --with-libexpat-prefix=${LOCALBASE} +CONFIGURE_ARGS+= --without-libunwind-ia64 --with-system-zlib +CFLAGS:= ${CFLAGS:C/ +$//} # blanks at EOL creep in sometimes +CFLAGS+= -DRL_NO_COMPAT -Wno-unused-function -Wno-unused-variable +CFLAGS+= -Wno-unknown-warning-option + + + +CONFIGURE_ARGS+= --with-system-readline +CONFIGURE_ARGS+= --with-system-zlib +CONFIGURE_ARGS+= --without-python + +.include + +.if ${ARCH} == amd64 +CONFIGURE_TARGET= x86_64-portbld-freebsd${OSREL} +.endif + +.if ${CHOSEN_COMPILER_TYPE} == clang +CFLAGS+= -Wno-extended-offsetof +.endif + +post-patch: + ${REINPLACE_CMD} -e 's|$$| [GDB v${PORTVERSION} for FreeBSD]|' \ + ${WRKSRC}/gdb/version.in + +do-install: + ${INSTALL_PROGRAM} ${WRKSRC}/gdb/gdb \ + ${STAGEDIR}${PREFIX}/bin/gdb + ${INSTALL_MAN} ${WRKSRC}/gdb/doc/gdb.1 \ + ${STAGEDIR}${MAN1PREFIX}/man/man1/gdb.1 + cd ${WRKSRC}/gdb/data-directory ; \ + ${SETENV} ${MAKE_ENV} ${MAKE_CMD} ${MAKE_ARGS} install-syscalls + + +.include diff --git a/devel/gdb/distinfo b/devel/gdb/distinfo new file mode 100644 index 00000000..0e15910a --- /dev/null +++ b/devel/gdb/distinfo @@ -0,0 +1,5 @@ +TIMESTAMP = 1569514923 +SHA256 (gdb-8.3.1.tar.xz) = 1e55b4d7cdca7b34be12f4ceae651623aa73b2fd640152313f9f66a7149757c4 +SIZE (gdb-8.3.1.tar.xz) = 20489528 +SHA256 (bsdjhb-libcxx-gdbpy-229610a_GH0.tar.gz) = d4235f98b71c4d5e3f01744de279e64808229dd46c0f00cac6a12fdeb3a998a1 +SIZE (bsdjhb-libcxx-gdbpy-229610a_GH0.tar.gz) = 5299 diff --git a/devel/gdb/files/commit-1163a4b7a3 b/devel/gdb/files/commit-1163a4b7a3 new file mode 100644 index 00000000..143697ee --- /dev/null +++ b/devel/gdb/files/commit-1163a4b7a3 @@ -0,0 +1,419 @@ +commit 1163a4b7a38a79ebd153dc5ee76ce93877d21dbd +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Support the fs_base and gs_base registers on i386. + + As on amd64, these registers hold the base address of the fs and gs + segments, respectively. For i386 these two registers are 32 bits. + + gdb/ChangeLog: + + * amd64-fbsd-nat.c (amd64_fbsd_nat_target::read_description): + Update calls to i386_target_description to add 'segments' + parameter. + * amd64-tdep.c (amd64_init_abi): Set tdep->fsbase_regnum. Don't + add segment base registers. + * arch/i386.c (i386_create_target_description): Add 'segments' + parameter to enable segment base registers. + * arch/i386.h (i386_create_target_description): Likewise. + * features/i386/32bit-segments.xml: New file. + * features/i386/32bit-segments.c: Generate. + * i386-fbsd-nat.c (i386_fbsd_nat_target::read_description): Update + call to i386_target_description to add 'segments' parameter. + * i386-fbsd-tdep.c (i386fbsd_core_read_description): Likewise. + * i386-go32-tdep.c (i386_go32_init_abi): Likewise. + * i386-linux-tdep.c (i386_linux_read_description): Likewise. + * i386-tdep.c (i386_validate_tdesc_p): Add segment base registers + if feature is present. + (i386_gdbarch_init): Pass I386_NUM_REGS to set_gdbarch_num_regs. + Add 'segments' parameter to call to i386_target_description. + (i386_target_description): Add 'segments' parameter to enable + segment base registers. + (_initialize_i386_tdep) [GDB_SELF_TEST]: Add 'segments' parameter + to call to i386_target_description. + * i386-tdep.h (struct gdbarch_tdep): Add 'fsbase_regnum'. + (enum i386_regnum): Add I386_FSBASE_REGNUM and I386_GSBASE_REGNUM. + Define I386_NUM_REGS. + (i386_target_description): Add 'segments' parameter to enable + segment base registers. + + gdb/gdbserver/ChangeLog: + + * linux-x86-tdesc.c (i386_linux_read_description): Update call to + i386_create_target_description for 'segments' parameter. + * lynx-i386-low.c (lynx_i386_arch_setup): Likewise. + * nto-x86-low.c (nto_x86_arch_setup): Likewise. + * win32-i386-low.c (i386_arch_setup): Likewise. + +diff --git gdb/amd64-fbsd-nat.c gdb/amd64-fbsd-nat.c +index 74ef240766..9fff763dd3 100644 +--- gdb/amd64-fbsd-nat.c ++++ gdb/amd64-fbsd-nat.c +@@ -190,13 +190,13 @@ amd64_fbsd_nat_target::read_description () + if (is64) + return amd64_target_description (xcr0, true); + else +- return i386_target_description (xcr0); ++ return i386_target_description (xcr0, false); + } + #endif + if (is64) + return amd64_target_description (X86_XSTATE_SSE_MASK, true); + else +- return i386_target_description (X86_XSTATE_SSE_MASK); ++ return i386_target_description (X86_XSTATE_SSE_MASK, false); + } + + #if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO) +diff --git gdb/amd64-tdep.c gdb/amd64-tdep.c +index 3f61997d66..d5892954d7 100644 +--- gdb/amd64-tdep.c ++++ gdb/amd64-tdep.c +@@ -3107,15 +3107,7 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch, + + if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.segments") != NULL) + { +- const struct tdesc_feature *feature = +- tdesc_find_feature (tdesc, "org.gnu.gdb.i386.segments"); +- struct tdesc_arch_data *tdesc_data_segments = +- (struct tdesc_arch_data *) info.tdep_info; +- +- tdesc_numbered_register (feature, tdesc_data_segments, +- AMD64_FSBASE_REGNUM, "fs_base"); +- tdesc_numbered_register (feature, tdesc_data_segments, +- AMD64_GSBASE_REGNUM, "gs_base"); ++ tdep->fsbase_regnum = AMD64_FSBASE_REGNUM; + } + + if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pkeys") != NULL) +diff --git gdb/arch/i386.c gdb/arch/i386.c +index 7d2901333b..ab24cf71cb 100644 +--- gdb/arch/i386.c ++++ gdb/arch/i386.c +@@ -28,11 +28,12 @@ + #include "../features/i386/32bit-avx512.c" + #include "../features/i386/32bit-mpx.c" + #include "../features/i386/32bit-pkeys.c" ++#include "../features/i386/32bit-segments.c" + + /* Create i386 target descriptions according to XCR0. */ + + target_desc * +-i386_create_target_description (uint64_t xcr0, bool is_linux) ++i386_create_target_description (uint64_t xcr0, bool is_linux, bool segments) + { + target_desc *tdesc = allocate_target_description (); + +@@ -53,6 +54,9 @@ i386_create_target_description (uint64_t xcr0, bool is_linux) + if (is_linux) + regnum = create_feature_i386_32bit_linux (tdesc, regnum); + ++ if (segments) ++ regnum = create_feature_i386_32bit_segments (tdesc, regnum); ++ + if (xcr0 & X86_XSTATE_AVX) + regnum = create_feature_i386_32bit_avx (tdesc, regnum); + +diff --git gdb/arch/i386.h gdb/arch/i386.h +index fa85438080..9a831cea30 100644 +--- gdb/arch/i386.h ++++ gdb/arch/i386.h +@@ -21,6 +21,7 @@ + #include "common/tdesc.h" + #include + +-target_desc *i386_create_target_description (uint64_t xcr0, bool is_linux); ++target_desc *i386_create_target_description (uint64_t xcr0, bool is_linux, ++ bool segments); + + #endif /* ARCH_I386_H */ +diff --git gdb/features/i386/32bit-segments.c gdb/features/i386/32bit-segments.c +new file mode 100644 +index 0000000000..c22c3dfbc3 +--- /dev/null ++++ gdb/features/i386/32bit-segments.c +@@ -0,0 +1,15 @@ ++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: ++ Original: 32bit-segments.xml */ ++ ++#include "common/tdesc.h" ++ ++static int ++create_feature_i386_32bit_segments (struct target_desc *result, long regnum) ++{ ++ struct tdesc_feature *feature; ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.i386.segments"); ++ tdesc_create_reg (feature, "fs_base", regnum++, 1, NULL, 32, "int"); ++ tdesc_create_reg (feature, "gs_base", regnum++, 1, NULL, 32, "int"); ++ return regnum; ++} +diff --git gdb/features/i386/32bit-segments.xml gdb/features/i386/32bit-segments.xml +new file mode 100644 +index 0000000000..098948e5ec +--- /dev/null ++++ gdb/features/i386/32bit-segments.xml +@@ -0,0 +1,12 @@ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git gdb/gdbserver/linux-x86-tdesc.c gdb/gdbserver/linux-x86-tdesc.c +index 04bccc84ed..8f24a3d72d 100644 +--- gdb/gdbserver/linux-x86-tdesc.c ++++ gdb/gdbserver/linux-x86-tdesc.c +@@ -87,7 +87,7 @@ i386_linux_read_description (uint64_t xcr0) + + if (*tdesc == NULL) + { +- *tdesc = i386_create_target_description (xcr0, true); ++ *tdesc = i386_create_target_description (xcr0, true, false); + + init_target_desc (*tdesc, i386_expedite_regs); + } +diff --git gdb/gdbserver/lynx-i386-low.c gdb/gdbserver/lynx-i386-low.c +index bc1027dc52..e47f6b92f6 100644 +--- gdb/gdbserver/lynx-i386-low.c ++++ gdb/gdbserver/lynx-i386-low.c +@@ -331,7 +331,7 @@ static void + lynx_i386_arch_setup (void) + { + struct target_desc *tdesc +- = i386_create_target_description (X86_XSTATE_SSE_MASK, false); ++ = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false); + + init_target_desc (tdesc, i386_expedite_regs); + +diff --git gdb/gdbserver/nto-x86-low.c gdb/gdbserver/nto-x86-low.c +index 1b00f7f6cc..cfbe7ba6d8 100644 +--- gdb/gdbserver/nto-x86-low.c ++++ gdb/gdbserver/nto-x86-low.c +@@ -89,7 +89,7 @@ nto_x86_arch_setup (void) + { + the_low_target.num_regs = 16; + struct target_desc *tdesc +- = i386_create_target_description (X86_XSTATE_SSE_MASK, false); ++ = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false); + + init_target_desc (tdesc, i386_expedite_regs); + +diff --git gdb/gdbserver/win32-i386-low.c gdb/gdbserver/win32-i386-low.c +index 3be75d2bf2..7b187d3bea 100644 +--- gdb/gdbserver/win32-i386-low.c ++++ gdb/gdbserver/win32-i386-low.c +@@ -439,7 +439,7 @@ i386_arch_setup (void) + false, false); + const char **expedite_regs = amd64_expedite_regs; + #else +- tdesc = i386_create_target_description (X86_XSTATE_SSE_MASK, false); ++ tdesc = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false); + const char **expedite_regs = i386_expedite_regs; + #endif + +diff --git gdb/i386-fbsd-nat.c gdb/i386-fbsd-nat.c +index 2309b76506..7106e90801 100644 +--- gdb/i386-fbsd-nat.c ++++ gdb/i386-fbsd-nat.c +@@ -160,7 +160,7 @@ i386_fbsd_nat_target::read_description () + if (x86bsd_xsave_len == 0) + xcr0 = X86_XSTATE_SSE_MASK; + +- return i386_target_description (xcr0); ++ return i386_target_description (xcr0, false); + } + #endif + +diff --git gdb/i386-fbsd-tdep.c gdb/i386-fbsd-tdep.c +index 236edd692a..2f28bad728 100644 +--- gdb/i386-fbsd-tdep.c ++++ gdb/i386-fbsd-tdep.c +@@ -267,7 +267,7 @@ i386fbsd_core_read_description (struct gdbarch *gdbarch, + struct target_ops *target, + bfd *abfd) + { +- return i386_target_description (i386fbsd_core_read_xcr0 (abfd)); ++ return i386_target_description (i386fbsd_core_read_xcr0 (abfd), false); + } + + /* Similar to i386_supply_fpregset, but use XSAVE extended state. */ +diff --git gdb/i386-go32-tdep.c gdb/i386-go32-tdep.c +index 06833c346c..30db72d880 100644 +--- gdb/i386-go32-tdep.c ++++ gdb/i386-go32-tdep.c +@@ -35,7 +35,7 @@ i386_go32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + + /* DJGPP does not support the SSE registers. */ + if (!tdesc_has_registers (info.target_desc)) +- tdep->tdesc = i386_target_description (X86_XSTATE_X87_MASK); ++ tdep->tdesc = i386_target_description (X86_XSTATE_X87_MASK, false); + + /* Native compiler is GCC, which uses the SVR4 register numbering + even in COFF and STABS. See the comment in i386_gdbarch_init, +diff --git gdb/i386-linux-tdep.c gdb/i386-linux-tdep.c +index da81715061..fa6b86f1c8 100644 +--- gdb/i386-linux-tdep.c ++++ gdb/i386-linux-tdep.c +@@ -694,7 +694,7 @@ i386_linux_read_description (uint64_t xcr0) + [(xcr0 & X86_XSTATE_PKRU) ? 1 : 0]; + + if (*tdesc == NULL) +- *tdesc = i386_create_target_description (xcr0, true); ++ *tdesc = i386_create_target_description (xcr0, true, false); + + return *tdesc; + } +diff --git gdb/i386-tdep.c gdb/i386-tdep.c +index bc9ba752ed..4e63832b0e 100644 +--- gdb/i386-tdep.c ++++ gdb/i386-tdep.c +@@ -8175,7 +8175,7 @@ i386_validate_tdesc_p (struct gdbarch_tdep *tdep, + const struct tdesc_feature *feature_core; + + const struct tdesc_feature *feature_sse, *feature_avx, *feature_mpx, +- *feature_avx512, *feature_pkeys; ++ *feature_avx512, *feature_pkeys, *feature_segments; + int i, num_regs, valid_p; + + if (! tdesc_has_registers (tdesc)) +@@ -8198,6 +8198,9 @@ i386_validate_tdesc_p (struct gdbarch_tdep *tdep, + /* Try AVX512 registers. */ + feature_avx512 = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx512"); + ++ /* Try segment base registers. */ ++ feature_segments = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.segments"); ++ + /* Try PKEYS */ + feature_pkeys = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pkeys"); + +@@ -8307,6 +8310,16 @@ i386_validate_tdesc_p (struct gdbarch_tdep *tdep, + tdep->mpx_register_names[i]); + } + ++ if (feature_segments) ++ { ++ if (tdep->fsbase_regnum < 0) ++ tdep->fsbase_regnum = I386_FSBASE_REGNUM; ++ valid_p &= tdesc_numbered_register (feature_segments, tdesc_data, ++ tdep->fsbase_regnum, "fs_base"); ++ valid_p &= tdesc_numbered_register (feature_segments, tdesc_data, ++ tdep->fsbase_regnum + 1, "gs_base"); ++ } ++ + if (feature_pkeys) + { + tdep->xcr0 |= X86_XSTATE_PKRU; +@@ -8543,14 +8556,14 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + /* Even though the default ABI only includes general-purpose registers, + floating-point registers and the SSE registers, we have to leave a + gap for the upper AVX, MPX and AVX512 registers. */ +- set_gdbarch_num_regs (gdbarch, I386_PKEYS_NUM_REGS); ++ set_gdbarch_num_regs (gdbarch, I386_NUM_REGS); + + set_gdbarch_gnu_triplet_regexp (gdbarch, i386_gnu_triplet_regexp); + + /* Get the x86 target description from INFO. */ + tdesc = info.target_desc; + if (! tdesc_has_registers (tdesc)) +- tdesc = i386_target_description (X86_XSTATE_SSE_MASK); ++ tdesc = i386_target_description (X86_XSTATE_SSE_MASK, false); + tdep->tdesc = tdesc; + + tdep->num_core_regs = I386_NUM_GREGS + I387_NUM_REGS; +@@ -8592,6 +8605,9 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + tdep->pkru_regnum = -1; + tdep->num_pkeys_regs = 0; + ++ /* No segment base registers. */ ++ tdep->fsbase_regnum = -1; ++ + tdesc_data = tdesc_data_alloc (); + + set_gdbarch_relocate_instruction (gdbarch, i386_relocate_instruction); +@@ -8717,20 +8733,21 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + /* Return the target description for a specified XSAVE feature mask. */ + + const struct target_desc * +-i386_target_description (uint64_t xcr0) ++i386_target_description (uint64_t xcr0, bool segments) + { + static target_desc *i386_tdescs \ +- [2/*SSE*/][2/*AVX*/][2/*MPX*/][2/*AVX512*/][2/*PKRU*/] = {}; ++ [2/*SSE*/][2/*AVX*/][2/*MPX*/][2/*AVX512*/][2/*PKRU*/][2/*segments*/] = {}; + target_desc **tdesc; + + tdesc = &i386_tdescs[(xcr0 & X86_XSTATE_SSE) ? 1 : 0] + [(xcr0 & X86_XSTATE_AVX) ? 1 : 0] + [(xcr0 & X86_XSTATE_MPX) ? 1 : 0] + [(xcr0 & X86_XSTATE_AVX512) ? 1 : 0] +- [(xcr0 & X86_XSTATE_PKRU) ? 1 : 0]; ++ [(xcr0 & X86_XSTATE_PKRU) ? 1 : 0] ++ [segments ? 1 : 0]; + + if (*tdesc == NULL) +- *tdesc = i386_create_target_description (xcr0, false); ++ *tdesc = i386_create_target_description (xcr0, false, segments); + + return *tdesc; + } +@@ -9072,7 +9089,7 @@ Show Intel Memory Protection Extensions specific variables."), + + for (auto &a : xml_masks) + { +- auto tdesc = i386_target_description (a.mask); ++ auto tdesc = i386_target_description (a.mask, false); + + selftests::record_xml_tdesc (a.xml, tdesc); + } +diff --git gdb/i386-tdep.h gdb/i386-tdep.h +index 2532306e5c..c0d494824c 100644 +--- gdb/i386-tdep.h ++++ gdb/i386-tdep.h +@@ -200,6 +200,10 @@ struct gdbarch_tdep + /* PKEYS register names. */ + const char **pkeys_register_names; + ++ /* Register number for %fsbase. Set this to -1 to indicate the ++ absence of segment base registers. */ ++ int fsbase_regnum; ++ + /* Target description. */ + const struct target_desc *tdesc; + +@@ -296,7 +300,9 @@ enum i386_regnum + I386_K7_REGNUM = I386_K0_REGNUM + 7, + I386_ZMM0H_REGNUM, /* %zmm0h */ + I386_ZMM7H_REGNUM = I386_ZMM0H_REGNUM + 7, +- I386_PKRU_REGNUM ++ I386_PKRU_REGNUM, ++ I386_FSBASE_REGNUM, ++ I386_GSBASE_REGNUM + }; + + /* Register numbers of RECORD_REGMAP. */ +@@ -337,6 +343,7 @@ enum record_i386_regnum + #define I386_MPX_NUM_REGS (I386_BNDSTATUS_REGNUM + 1) + #define I386_AVX512_NUM_REGS (I386_ZMM7H_REGNUM + 1) + #define I386_PKEYS_NUM_REGS (I386_PKRU_REGNUM + 1) ++#define I386_NUM_REGS (I386_GSBASE_REGNUM + 1) + + /* Size of the largest register. */ + #define I386_MAX_REGISTER_SIZE 64 +@@ -440,7 +447,8 @@ extern int i386_svr4_reg_to_regnum (struct gdbarch *gdbarch, int reg); + + extern int i386_process_record (struct gdbarch *gdbarch, + struct regcache *regcache, CORE_ADDR addr); +-extern const struct target_desc *i386_target_description (uint64_t xcr0); ++extern const struct target_desc *i386_target_description (uint64_t xcr0, ++ bool segments); + + /* Return true iff the current target is MPX enabled. */ + extern int i386_mpx_enabled (void); diff --git a/devel/gdb/files/commit-36c53a0262 b/devel/gdb/files/commit-36c53a0262 new file mode 100644 index 00000000..3eaa2ea9 --- /dev/null +++ b/devel/gdb/files/commit-36c53a0262 @@ -0,0 +1,60 @@ +commit 36c53a0262f84ad11d738471789dadfa9c4eb320 +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Remove code disabled since at least 1999 from lookup_struct_elt_type. + + Update the comment above the function to reflect the code removal and + document the existing behavior. + + gdb/ChangeLog: + + * gdbtypes.c (lookup_struct_elt_type): Update comment and + remove disabled code block. + +diff --git gdb/gdbtypes.c gdb/gdbtypes.c +index 09284ef259..5924b15520 100644 +--- gdb/gdbtypes.c ++++ gdb/gdbtypes.c +@@ -1644,8 +1644,7 @@ lookup_template_type (char *name, struct type *type, + return (SYMBOL_TYPE (sym)); + } + +-/* Given a type TYPE, lookup the type of the component of type named +- NAME. ++/* Given a type TYPE, lookup the type of the component named NAME. + + TYPE can be either a struct or union, or a pointer or reference to + a struct or union. If it is a pointer or reference, its target +@@ -1653,8 +1652,8 @@ lookup_template_type (char *name, struct type *type, + as specified for the definitions of the expression element types + STRUCTOP_STRUCT and STRUCTOP_PTR. + +- If NOERR is nonzero, return zero if NAME is not suitably defined. +- If NAME is the name of a baseclass type, return that type. */ ++ If NOERR is nonzero, return NULL if there is no component named ++ NAME. */ + + struct type * + lookup_struct_elt_type (struct type *type, const char *name, int noerr) +@@ -1678,20 +1677,6 @@ lookup_struct_elt_type (struct type *type, const char *name, int noerr) + type_name.c_str ()); + } + +-#if 0 +- /* FIXME: This change put in by Michael seems incorrect for the case +- where the structure tag name is the same as the member name. +- I.e. when doing "ptype bell->bar" for "struct foo { int bar; int +- foo; } bell;" Disabled by fnf. */ +- { +- char *type_name; +- +- type_name = TYPE_NAME (type); +- if (type_name != NULL && strcmp (type_name, name) == 0) +- return type; +- } +-#endif +- + for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + { + const char *t_field_name = TYPE_FIELD_NAME (type, i); diff --git a/devel/gdb/files/commit-6e056c8178 b/devel/gdb/files/commit-6e056c8178 new file mode 100644 index 00000000..591208fc --- /dev/null +++ b/devel/gdb/files/commit-6e056c8178 @@ -0,0 +1,166 @@ +commit 6e056c817845f3d736a1be6b68c69b439c6c6d25 +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Add a new gdbarch method to resolve the address of TLS variables. + + Permit TLS variable addresses to be resolved purely by an ABI rather + than requiring a target method. This doesn't try the target method if + the ABI function is present (even if the ABI function fails) to + simplify error handling. + + gdb/ChangeLog: + + * gdbarch.sh (get_thread_local_address): New method. + * gdbarch.h, gdbarch.c: Regenerate. + * target.c (target_translate_tls_address): Use + gdbarch_get_thread_local_address if present instead of + target::get_thread_local_address. + +diff --git gdb/gdbarch.c gdb/gdbarch.c +index 434ee3bfcf..2b3fcef004 100644 +--- gdb/gdbarch.c ++++ gdb/gdbarch.c +@@ -251,6 +251,7 @@ struct gdbarch + CORE_ADDR deprecated_function_start_offset; + gdbarch_remote_register_number_ftype *remote_register_number; + gdbarch_fetch_tls_load_module_address_ftype *fetch_tls_load_module_address; ++ gdbarch_get_thread_local_address_ftype *get_thread_local_address; + CORE_ADDR frame_args_skip; + gdbarch_unwind_pc_ftype *unwind_pc; + gdbarch_unwind_sp_ftype *unwind_sp; +@@ -613,6 +614,7 @@ verify_gdbarch (struct gdbarch *gdbarch) + /* Skip verify of deprecated_function_start_offset, invalid_p == 0 */ + /* Skip verify of remote_register_number, invalid_p == 0 */ + /* Skip verify of fetch_tls_load_module_address, has predicate. */ ++ /* Skip verify of get_thread_local_address, has predicate. */ + /* Skip verify of frame_args_skip, invalid_p == 0 */ + /* Skip verify of unwind_pc, invalid_p == 0 */ + /* Skip verify of unwind_sp, invalid_p == 0 */ +@@ -1073,6 +1075,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) + fprintf_unfiltered (file, + "gdbarch_dump: get_syscall_number = <%s>\n", + host_address_to_string (gdbarch->get_syscall_number)); ++ fprintf_unfiltered (file, ++ "gdbarch_dump: gdbarch_get_thread_local_address_p() = %d\n", ++ gdbarch_get_thread_local_address_p (gdbarch)); ++ fprintf_unfiltered (file, ++ "gdbarch_dump: get_thread_local_address = <%s>\n", ++ host_address_to_string (gdbarch->get_thread_local_address)); + fprintf_unfiltered (file, + "gdbarch_dump: gnu_triplet_regexp = <%s>\n", + host_address_to_string (gdbarch->gnu_triplet_regexp)); +@@ -3018,6 +3026,30 @@ set_gdbarch_fetch_tls_load_module_address (struct gdbarch *gdbarch, + gdbarch->fetch_tls_load_module_address = fetch_tls_load_module_address; + } + ++int ++gdbarch_get_thread_local_address_p (struct gdbarch *gdbarch) ++{ ++ gdb_assert (gdbarch != NULL); ++ return gdbarch->get_thread_local_address != NULL; ++} ++ ++CORE_ADDR ++gdbarch_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, CORE_ADDR lm_addr, CORE_ADDR offset) ++{ ++ gdb_assert (gdbarch != NULL); ++ gdb_assert (gdbarch->get_thread_local_address != NULL); ++ if (gdbarch_debug >= 2) ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_thread_local_address called\n"); ++ return gdbarch->get_thread_local_address (gdbarch, ptid, lm_addr, offset); ++} ++ ++void ++set_gdbarch_get_thread_local_address (struct gdbarch *gdbarch, ++ gdbarch_get_thread_local_address_ftype get_thread_local_address) ++{ ++ gdbarch->get_thread_local_address = get_thread_local_address; ++} ++ + CORE_ADDR + gdbarch_frame_args_skip (struct gdbarch *gdbarch) + { +diff --git gdb/gdbarch.h gdb/gdbarch.h +index 75618376ab..abb72e752b 100644 +--- gdb/gdbarch.h ++++ gdb/gdbarch.h +@@ -649,6 +649,18 @@ typedef CORE_ADDR (gdbarch_fetch_tls_load_module_address_ftype) (struct objfile + extern CORE_ADDR gdbarch_fetch_tls_load_module_address (struct gdbarch *gdbarch, struct objfile *objfile); + extern void set_gdbarch_fetch_tls_load_module_address (struct gdbarch *gdbarch, gdbarch_fetch_tls_load_module_address_ftype *fetch_tls_load_module_address); + ++/* Return the thread-local address at OFFSET in the thread-local ++ storage for the thread PTID and the shared library or executable ++ file given by LM_ADDR. If that block of thread-local storage hasn't ++ been allocated yet, this function may throw an error. LM_ADDR may ++ be zero for statically linked multithreaded inferiors. */ ++ ++extern int gdbarch_get_thread_local_address_p (struct gdbarch *gdbarch); ++ ++typedef CORE_ADDR (gdbarch_get_thread_local_address_ftype) (struct gdbarch *gdbarch, ptid_t ptid, CORE_ADDR lm_addr, CORE_ADDR offset); ++extern CORE_ADDR gdbarch_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, CORE_ADDR lm_addr, CORE_ADDR offset); ++extern void set_gdbarch_get_thread_local_address (struct gdbarch *gdbarch, gdbarch_get_thread_local_address_ftype *get_thread_local_address); ++ + extern CORE_ADDR gdbarch_frame_args_skip (struct gdbarch *gdbarch); + extern void set_gdbarch_frame_args_skip (struct gdbarch *gdbarch, CORE_ADDR frame_args_skip); + +diff --git gdb/gdbarch.sh gdb/gdbarch.sh +index 48fcebd19a..63bfbad7d9 100755 +--- gdb/gdbarch.sh ++++ gdb/gdbarch.sh +@@ -602,6 +602,14 @@ m;int;remote_register_number;int regno;regno;;default_remote_register_number;;0 + + # Fetch the target specific address used to represent a load module. + F;CORE_ADDR;fetch_tls_load_module_address;struct objfile *objfile;objfile ++ ++# Return the thread-local address at OFFSET in the thread-local ++# storage for the thread PTID and the shared library or executable ++# file given by LM_ADDR. If that block of thread-local storage hasn't ++# been allocated yet, this function may throw an error. LM_ADDR may ++# be zero for statically linked multithreaded inferiors. ++ ++M;CORE_ADDR;get_thread_local_address;ptid_t ptid, CORE_ADDR lm_addr, CORE_ADDR offset;ptid, lm_addr, offset + # + v;CORE_ADDR;frame_args_skip;;;0;;;0 + m;CORE_ADDR;unwind_pc;struct frame_info *next_frame;next_frame;;default_unwind_pc;;0 +diff --git gdb/target.c gdb/target.c +index 8579c19d05..c27157d209 100644 +--- gdb/target.c ++++ gdb/target.c +@@ -698,8 +698,9 @@ target_translate_tls_address (struct objfile *objfile, CORE_ADDR offset) + { + volatile CORE_ADDR addr = 0; + struct target_ops *target = current_top_target (); ++ struct gdbarch *gdbarch = target_gdbarch (); + +- if (gdbarch_fetch_tls_load_module_address_p (target_gdbarch ())) ++ if (gdbarch_fetch_tls_load_module_address_p (gdbarch)) + { + ptid_t ptid = inferior_ptid; + +@@ -708,10 +709,14 @@ target_translate_tls_address (struct objfile *objfile, CORE_ADDR offset) + CORE_ADDR lm_addr; + + /* Fetch the load module address for this objfile. */ +- lm_addr = gdbarch_fetch_tls_load_module_address (target_gdbarch (), ++ lm_addr = gdbarch_fetch_tls_load_module_address (gdbarch, + objfile); + +- addr = target->get_thread_local_address (ptid, lm_addr, offset); ++ if (gdbarch_get_thread_local_address_p (gdbarch)) ++ addr = gdbarch_get_thread_local_address (gdbarch, ptid, lm_addr, ++ offset); ++ else ++ addr = target->get_thread_local_address (ptid, lm_addr, offset); + } + /* If an error occurred, print TLS related messages here. Otherwise, + throw the error to some higher catcher. */ +@@ -766,8 +771,6 @@ target_translate_tls_address (struct objfile *objfile, CORE_ADDR offset) + } + END_CATCH + } +- /* It wouldn't be wrong here to try a gdbarch method, too; finding +- TLS is an ABI-specific thing. But we don't do that yet. */ + else + error (_("Cannot find thread-local variables on this target")); + diff --git a/devel/gdb/files/commit-8399425f5f b/devel/gdb/files/commit-8399425f5f new file mode 100644 index 00000000..6545579f --- /dev/null +++ b/devel/gdb/files/commit-8399425f5f @@ -0,0 +1,69 @@ +commit 8399425f5f472ad8e630bb30ad2dbefeddbb68b7 +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Support TLS variables on FreeBSD/powerpc. + + Derive the pointer to the DTV array from the %r2 register on 32-bit + powerpc and %r13 on 64-bit powerpc. + + gdb/ChangeLog: + + * ppc-fbsd-tdep.c (ppcfbsd_get_thread_local_address): New. + (ppcfbsd_init_abi): Install gdbarch + "fetch_tls_load_module_address" and "get_thread_local_address" + methods. + +diff --git gdb/ppc-fbsd-tdep.c gdb/ppc-fbsd-tdep.c +index c21a52c898..290bd1fd88 100644 +--- gdb/ppc-fbsd-tdep.c ++++ gdb/ppc-fbsd-tdep.c +@@ -279,6 +279,39 @@ ppcfbsd_return_value (struct gdbarch *gdbarch, struct value *function, + regcache, readbuf, writebuf); + } + ++/* Implement the "get_thread_local_address" gdbarch method. */ ++ ++static CORE_ADDR ++ppcfbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, ++ CORE_ADDR lm_addr, CORE_ADDR offset) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ struct regcache *regcache; ++ int tp_offset, tp_regnum; ++ ++ regcache = get_thread_arch_regcache (ptid, gdbarch); ++ ++ if (tdep->wordsize == 4) ++ { ++ tp_offset = 0x7008; ++ tp_regnum = PPC_R0_REGNUM + 2; ++ } ++ else ++ { ++ tp_offset = 0x7010; ++ tp_regnum = PPC_R0_REGNUM + 13; ++ } ++ target_fetch_registers (regcache, tp_regnum); ++ ++ ULONGEST tp; ++ if (regcache->cooked_read (tp_regnum, &tp) != REG_VALID) ++ error (_("Unable to fetch tcb pointer")); ++ ++ /* tp points to the end of the TCB block. The first member of the ++ TCB is the pointer to the DTV array. */ ++ CORE_ADDR dtv_addr = tp - tp_offset; ++ return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset); ++} + + static void + ppcfbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +@@ -322,6 +355,8 @@ ppcfbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + + set_gdbarch_fetch_tls_load_module_address (gdbarch, + svr4_fetch_objfile_link_map); ++ set_gdbarch_get_thread_local_address (gdbarch, ++ ppcfbsd_get_thread_local_address); + } + + void diff --git a/devel/gdb/files/commit-945f3901b5 b/devel/gdb/files/commit-945f3901b5 new file mode 100644 index 00000000..221445b3 --- /dev/null +++ b/devel/gdb/files/commit-945f3901b5 @@ -0,0 +1,224 @@ +commit 945f3901b5889e57edf5a2ee25acb51f0078a719 +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Add a helper function to resolve TLS variable addresses for FreeBSD. + + The fbsd_get_thread_local_address function accepts the base address of + a thread's DTV array and the base address of an object file's link map + and uses this to compute a TLS variable's address. FreeBSD + architectures use an architecture-specific method to determine the + address of the DTV array pointer and call this helper function to + perform the rest of the address calculation. + + * fbsd-tdep.c (fbsd_pspace_data_handle): New variable. + (struct fbsd_pspace_data): New type. + (get_fbsd_pspace_data, fbsd_pspace_data_cleanup) + (fbsd_read_integer_by_name, fbsd_fetch_rtld_offsets) + (fbsd_get_tls_index, fbsd_get_thread_local_address): New function. + (_initialize_fbsd_tdep): Initialize 'fbsd_pspace_data_handle'. + * fbsd-tdep.c (fbsd_get_thread_local_address): New prototype. + +diff --git gdb/fbsd-tdep.c gdb/fbsd-tdep.c +index d971d3a653..f06836216d 100644 +--- gdb/fbsd-tdep.c ++++ gdb/fbsd-tdep.c +@@ -24,6 +24,7 @@ + #include "regcache.h" + #include "regset.h" + #include "gdbthread.h" ++#include "objfiles.h" + #include "xml-syscall.h" + #include + #include +@@ -444,6 +445,41 @@ get_fbsd_gdbarch_data (struct gdbarch *gdbarch) + gdbarch_data (gdbarch, fbsd_gdbarch_data_handle)); + } + ++/* Per-program-space data for FreeBSD architectures. */ ++static const struct program_space_data *fbsd_pspace_data_handle; ++ ++struct fbsd_pspace_data ++{ ++ /* Offsets in the runtime linker's 'Obj_Entry' structure. */ ++ LONGEST off_linkmap; ++ LONGEST off_tlsindex; ++ bool rtld_offsets_valid; ++}; ++ ++static struct fbsd_pspace_data * ++get_fbsd_pspace_data (struct program_space *pspace) ++{ ++ struct fbsd_pspace_data *data; ++ ++ data = ((struct fbsd_pspace_data *) ++ program_space_data (pspace, fbsd_pspace_data_handle)); ++ if (data == NULL) ++ { ++ data = XCNEW (struct fbsd_pspace_data); ++ set_program_space_data (pspace, fbsd_pspace_data_handle, data); ++ } ++ ++ return data; ++} ++ ++/* The cleanup callback for FreeBSD architecture per-program-space data. */ ++ ++static void ++fbsd_pspace_data_cleanup (struct program_space *pspace, void *data) ++{ ++ xfree (data); ++} ++ + /* This is how we want PTIDs from core files to be printed. */ + + static const char * +@@ -1932,6 +1968,121 @@ fbsd_get_syscall_number (struct gdbarch *gdbarch, thread_info *thread) + internal_error (__FILE__, __LINE__, _("fbsd_get_sycall_number called")); + } + ++/* Read an integer symbol value from the current target. */ ++ ++static LONGEST ++fbsd_read_integer_by_name (struct gdbarch *gdbarch, const char *name) ++{ ++ bound_minimal_symbol ms = lookup_minimal_symbol (name, NULL, NULL); ++ if (ms.minsym == NULL) ++ error (_("Unable to resolve symbol '%s'"), name); ++ ++ gdb_byte buf[4]; ++ if (target_read_memory (BMSYMBOL_VALUE_ADDRESS (ms), buf, sizeof buf) != 0) ++ error (_("Unable to read value of '%s'"), name); ++ ++ return extract_signed_integer (buf, sizeof buf, gdbarch_byte_order (gdbarch)); ++} ++ ++/* Lookup offsets of fields in the runtime linker's 'Obj_Entry' ++ structure needed to determine the TLS index of an object file. */ ++ ++static void ++fbsd_fetch_rtld_offsets (struct gdbarch *gdbarch, struct fbsd_pspace_data *data) ++{ ++ TRY ++ { ++ /* Fetch offsets from debug symbols in rtld. */ ++ struct symbol *obj_entry_sym ++ = lookup_symbol_in_language ("Struct_Obj_Entry", NULL, STRUCT_DOMAIN, ++ language_c, NULL).symbol; ++ if (obj_entry_sym == NULL) ++ error (_("Unable to find Struct_Obj_Entry symbol")); ++ data->off_linkmap = lookup_struct_elt (SYMBOL_TYPE(obj_entry_sym), ++ "linkmap", 0).offset / 8; ++ data->off_tlsindex = lookup_struct_elt (SYMBOL_TYPE(obj_entry_sym), ++ "tlsindex", 0).offset / 8; ++ data->rtld_offsets_valid = true; ++ return; ++ } ++ CATCH (e, RETURN_MASK_ERROR) ++ { ++ data->off_linkmap = -1; ++ } ++ END_CATCH ++ ++ TRY ++ { ++ /* Fetch offsets from global variables in libthr. Note that ++ this does not work for single-threaded processes that are not ++ linked against libthr. */ ++ data->off_linkmap = fbsd_read_integer_by_name (gdbarch, ++ "_thread_off_linkmap"); ++ data->off_tlsindex = fbsd_read_integer_by_name (gdbarch, ++ "_thread_off_tlsindex"); ++ data->rtld_offsets_valid = true; ++ return; ++ } ++ CATCH (e, RETURN_MASK_ERROR) ++ { ++ data->off_linkmap = -1; ++ } ++ END_CATCH ++} ++ ++/* Helper function to read the TLS index of an object file associated ++ with a link map entry at LM_ADDR. */ ++ ++static LONGEST ++fbsd_get_tls_index (struct gdbarch *gdbarch, CORE_ADDR lm_addr) ++{ ++ struct fbsd_pspace_data *data = get_fbsd_pspace_data (current_program_space); ++ ++ if (!data->rtld_offsets_valid) ++ fbsd_fetch_rtld_offsets (gdbarch, data); ++ ++ if (data->off_linkmap == -1) ++ throw_error (TLS_GENERIC_ERROR, ++ _("Cannot fetch runtime linker structure offsets")); ++ ++ /* Simulate container_of to convert from LM_ADDR to the Obj_Entry ++ pointer and then compute the offset of the tlsindex member. */ ++ CORE_ADDR tlsindex_addr = lm_addr - data->off_linkmap + data->off_tlsindex; ++ ++ gdb_byte buf[4]; ++ if (target_read_memory (tlsindex_addr, buf, sizeof buf) != 0) ++ throw_error (TLS_GENERIC_ERROR, ++ _("Cannot find thread-local variables on this target")); ++ ++ return extract_signed_integer (buf, sizeof buf, gdbarch_byte_order (gdbarch)); ++} ++ ++/* See fbsd-tdep.h. */ ++ ++CORE_ADDR ++fbsd_get_thread_local_address (struct gdbarch *gdbarch, CORE_ADDR dtv_addr, ++ CORE_ADDR lm_addr, CORE_ADDR offset) ++{ ++ LONGEST tls_index = fbsd_get_tls_index (gdbarch, lm_addr); ++ ++ gdb_byte buf[gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT]; ++ if (target_read_memory (dtv_addr, buf, sizeof buf) != 0) ++ throw_error (TLS_GENERIC_ERROR, ++ _("Cannot find thread-local variables on this target")); ++ ++ const struct builtin_type *builtin = builtin_type (gdbarch); ++ CORE_ADDR addr = gdbarch_pointer_to_address (gdbarch, ++ builtin->builtin_data_ptr, buf); ++ ++ addr += (tls_index + 1) * TYPE_LENGTH (builtin->builtin_data_ptr); ++ if (target_read_memory (addr, buf, sizeof buf) != 0) ++ throw_error (TLS_GENERIC_ERROR, ++ _("Cannot find thread-local variables on this target")); ++ ++ addr = gdbarch_pointer_to_address (gdbarch, builtin->builtin_data_ptr, buf); ++ return addr + offset; ++} ++ + /* To be called from GDB_OSABI_FREEBSD handlers. */ + + void +@@ -1957,4 +2108,6 @@ _initialize_fbsd_tdep (void) + { + fbsd_gdbarch_data_handle = + gdbarch_data_register_post_init (init_fbsd_gdbarch_data); ++ fbsd_pspace_data_handle ++ = register_program_space_data_with_cleanup (NULL, fbsd_pspace_data_cleanup); + } +diff --git gdb/fbsd-tdep.h gdb/fbsd-tdep.h +index efd7c2c78f..0e29508c9f 100644 +--- gdb/fbsd-tdep.h ++++ gdb/fbsd-tdep.h +@@ -60,4 +60,15 @@ extern void fbsd_info_proc_mappings_entry (int addr_bit, ULONGEST kve_start, + int kve_flags, int kve_protection, + const void *kve_path); + ++/* Helper function to fetch the address of a thread-local variable. ++ DTV_ADDR is the base address of the thread's dtv array. LM_ADDR is ++ the address of the link_map structure for the associated object ++ file. OFFSET is the offset of the variable in the object file's ++ thread-local variable block. */ ++ ++extern CORE_ADDR fbsd_get_thread_local_address (struct gdbarch *gdbarch, ++ CORE_ADDR dtv_addr, ++ CORE_ADDR lm_addr, ++ CORE_ADDR offset); ++ + #endif /* fbsd-tdep.h */ diff --git a/devel/gdb/files/commit-b0f87ed032 b/devel/gdb/files/commit-b0f87ed032 new file mode 100644 index 00000000..d43bf667 --- /dev/null +++ b/devel/gdb/files/commit-b0f87ed032 @@ -0,0 +1,60 @@ +commit b0f87ed032bb68a9965de81cbf9fd676a83b9174 +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Support TLS variables on FreeBSD/riscv. + + Derive the pointer to the DTV array from the tp register. + + gdb/ChangeLog: + + * riscv-fbsd-tdep.c (riscv_fbsd_get_thread_local_address): New. + (riscv_fbsd_init_abi): Install gdbarch + "fetch_tls_load_module_address" and "get_thread_local_address" + methods. + +diff --git gdb/riscv-fbsd-tdep.c gdb/riscv-fbsd-tdep.c +index 97ad28f59a..3125a2285e 100644 +--- gdb/riscv-fbsd-tdep.c ++++ gdb/riscv-fbsd-tdep.c +@@ -174,6 +174,28 @@ static const struct tramp_frame riscv_fbsd_sigframe = + riscv_fbsd_sigframe_init + }; + ++/* Implement the "get_thread_local_address" gdbarch method. */ ++ ++static CORE_ADDR ++riscv_fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, ++ CORE_ADDR lm_addr, CORE_ADDR offset) ++{ ++ struct regcache *regcache; ++ ++ regcache = get_thread_arch_regcache (ptid, gdbarch); ++ ++ target_fetch_registers (regcache, RISCV_TP_REGNUM); ++ ++ ULONGEST tp; ++ if (regcache->cooked_read (RISCV_TP_REGNUM, &tp) != REG_VALID) ++ error (_("Unable to fetch %%tp")); ++ ++ /* %tp points to the end of the TCB which contains two pointers. ++ The first pointer in the TCB points to the DTV array. */ ++ CORE_ADDR dtv_addr = tp - (gdbarch_ptr_bit (gdbarch) / 8) * 2; ++ return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset); ++} ++ + /* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ + + static void +@@ -193,6 +215,11 @@ riscv_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + + set_gdbarch_iterate_over_regset_sections + (gdbarch, riscv_fbsd_iterate_over_regset_sections); ++ ++ set_gdbarch_fetch_tls_load_module_address (gdbarch, ++ svr4_fetch_objfile_link_map); ++ set_gdbarch_get_thread_local_address (gdbarch, ++ riscv_fbsd_get_thread_local_address); + } + + void diff --git a/devel/gdb/files/commit-cd250a1898 b/devel/gdb/files/commit-cd250a1898 new file mode 100644 index 00000000..c50c0f57 --- /dev/null +++ b/devel/gdb/files/commit-cd250a1898 @@ -0,0 +1,30 @@ +commit cd250a1898bb6fdb41f4a1063dbcfac04affcd11 +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Update comment for target::get_thread_local_address. + + There isn't an 'objfile' parameter, instead 'load_module_addr' is used + to indicate the executable or shared library. Also, the function + throws errors rather than returning error values. + + gdb/ChangeLog: + + * target.h (target::get_thread_local_address): Update comment. + +diff --git gdb/target.h gdb/target.h +index c95151a404..5fe6aa74b0 100644 +--- gdb/target.h ++++ gdb/target.h +@@ -718,9 +718,9 @@ struct target_ops + TARGET_DEFAULT_NORETURN (tcomplain ()); + /* Return the thread-local address at OFFSET in the + thread-local storage for the thread PTID and the shared library +- or executable file given by OBJFILE. If that block of ++ or executable file given by LOAD_MODULE_ADDR. If that block of + thread-local storage hasn't been allocated yet, this function +- may return an error. LOAD_MODULE_ADDR may be zero for statically ++ may throw an error. LOAD_MODULE_ADDR may be zero for statically + linked multithreaded inferiors. */ + virtual CORE_ADDR get_thread_local_address (ptid_t ptid, + CORE_ADDR load_module_addr, diff --git a/devel/gdb/files/commit-ce25aa57a3 b/devel/gdb/files/commit-ce25aa57a3 new file mode 100644 index 00000000..17e7c705 --- /dev/null +++ b/devel/gdb/files/commit-ce25aa57a3 @@ -0,0 +1,64 @@ +commit ce25aa57a3cdd028be5868423e6e55506ccd1053 +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Support TLS variables on FreeBSD/i386. + + Derive the pointer to the DTV array from the gs_base register. As + with FreeBSD/amd64, gs_base is currently only available via the native + target. + + gdb/ChangeLog: + + * i386-fbsd-tdep.c (i386fbsd_get_thread_local_address): New. + (i386fbsd_init_abi): Install gdbarch + "fetch_tls_load_module_address" and "get_thread_local_address" + methods. + +diff --git gdb/i386-fbsd-tdep.c gdb/i386-fbsd-tdep.c +index ac57e7383d..f274847174 100644 +--- gdb/i386-fbsd-tdep.c ++++ gdb/i386-fbsd-tdep.c +@@ -320,6 +320,30 @@ i386fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, + "XSAVE extended state", cb_data); + } + ++/* Implement the get_thread_local_address gdbarch method. */ ++ ++static CORE_ADDR ++i386fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, ++ CORE_ADDR lm_addr, CORE_ADDR offset) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ struct regcache *regcache; ++ ++ if (tdep->fsbase_regnum == -1) ++ error (_("Unable to fetch %%gsbase")); ++ ++ regcache = get_thread_arch_regcache (ptid, gdbarch); ++ ++ target_fetch_registers (regcache, tdep->fsbase_regnum + 1); ++ ++ ULONGEST gsbase; ++ if (regcache->cooked_read (tdep->fsbase_regnum + 1, &gsbase) != REG_VALID) ++ error (_("Unable to fetch %%gsbase")); ++ ++ CORE_ADDR dtv_addr = gsbase + gdbarch_ptr_bit (gdbarch) / 8; ++ return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset); ++} ++ + static void + i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + { +@@ -418,6 +442,11 @@ i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + + set_gdbarch_core_read_description (gdbarch, + i386fbsd_core_read_description); ++ ++ set_gdbarch_fetch_tls_load_module_address (gdbarch, ++ svr4_fetch_objfile_link_map); ++ set_gdbarch_get_thread_local_address (gdbarch, ++ i386fbsd_get_thread_local_address); + } + + void diff --git a/devel/gdb/files/commit-dd6876c91c b/devel/gdb/files/commit-dd6876c91c new file mode 100644 index 00000000..6204f9d5 --- /dev/null +++ b/devel/gdb/files/commit-dd6876c91c @@ -0,0 +1,237 @@ +commit dd6876c91cd40cc105b1a91f418ca2c80683b314 +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Support fs_base and gs_base on FreeBSD/i386. + + The i386 BSD native target uses the same ptrace operations + (PT_[GS]ET[FG]SBASE) as the amd64 BSD native target to fetch and store + the registers. + + The amd64 BSD native now uses 'tdep->fsbase_regnum' instead of + hardcoding AMD64_FSBASE_REGNUM and AMD64_GSBASE_REGNUM to support + 32-bit targets. In addition, the store operations explicitly zero the + new register value before fetching it from the register cache to + ensure 32-bit values are zero-extended. + + gdb/ChangeLog: + + * amd64-bsd-nat.c (amd64bsd_fetch_inferior_registers): Use + tdep->fsbase_regnum instead of constants for fs_base and gs_base. + (amd64bsd_store_inferior_registers): Likewise. + * amd64-fbsd-nat.c (amd64_fbsd_nat_target::read_description): + Enable segment base registers. + * i386-bsd-nat.c (i386bsd_fetch_inferior_registers): Use + PT_GETFSBASE and PT_GETGSBASE. + (i386bsd_store_inferior_registers): Use PT_SETFSBASE and + PT_SETGSBASE. + * i386-fbsd-nat.c (i386_fbsd_nat_target::read_description): Enable + segment base registers. + * i386-fbsd-tdep.c (i386fbsd_core_read_description): Likewise. + +diff --git gdb/amd64-bsd-nat.c gdb/amd64-bsd-nat.c +index a2a91abb91..35763a5b95 100644 +--- gdb/amd64-bsd-nat.c ++++ gdb/amd64-bsd-nat.c +@@ -43,6 +43,9 @@ amd64bsd_fetch_inferior_registers (struct regcache *regcache, int regnum) + { + struct gdbarch *gdbarch = regcache->arch (); + pid_t pid = get_ptrace_pid (regcache->ptid ()); ++#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE) ++ const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++#endif + + if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum)) + { +@@ -57,27 +60,27 @@ amd64bsd_fetch_inferior_registers (struct regcache *regcache, int regnum) + } + + #ifdef PT_GETFSBASE +- if (regnum == -1 || regnum == AMD64_FSBASE_REGNUM) ++ if (regnum == -1 || regnum == tdep->fsbase_regnum) + { + register_t base; + + if (ptrace (PT_GETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) + perror_with_name (_("Couldn't get segment register fs_base")); + +- regcache->raw_supply (AMD64_FSBASE_REGNUM, &base); ++ regcache->raw_supply (tdep->fsbase_regnum, &base); + if (regnum != -1) + return; + } + #endif + #ifdef PT_GETGSBASE +- if (regnum == -1 || regnum == AMD64_GSBASE_REGNUM) ++ if (regnum == -1 || regnum == tdep->fsbase_regnum + 1) + { + register_t base; + + if (ptrace (PT_GETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) + perror_with_name (_("Couldn't get segment register gs_base")); + +- regcache->raw_supply (AMD64_GSBASE_REGNUM, &base); ++ regcache->raw_supply (tdep->fsbase_regnum + 1, &base); + if (regnum != -1) + return; + } +@@ -116,6 +119,9 @@ amd64bsd_store_inferior_registers (struct regcache *regcache, int regnum) + { + struct gdbarch *gdbarch = regcache->arch (); + pid_t pid = get_ptrace_pid (regcache->ptid ()); ++#if defined(PT_SETFSBASE) || defined(PT_SETGSBASE) ++ const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++#endif + + if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum)) + { +@@ -134,11 +140,13 @@ amd64bsd_store_inferior_registers (struct regcache *regcache, int regnum) + } + + #ifdef PT_SETFSBASE +- if (regnum == -1 || regnum == AMD64_FSBASE_REGNUM) ++ if (regnum == -1 || regnum == tdep->fsbase_regnum) + { + register_t base; + +- regcache->raw_collect (AMD64_FSBASE_REGNUM, &base); ++ /* Clear the full base value to support 32-bit targets. */ ++ base = 0; ++ regcache->raw_collect (tdep->fsbase_regnum, &base); + + if (ptrace (PT_SETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) + perror_with_name (_("Couldn't write segment register fs_base")); +@@ -147,11 +155,13 @@ amd64bsd_store_inferior_registers (struct regcache *regcache, int regnum) + } + #endif + #ifdef PT_SETGSBASE +- if (regnum == -1 || regnum == AMD64_GSBASE_REGNUM) ++ if (regnum == -1 || regnum == tdep->fsbase_regnum + 1) + { + register_t base; + +- regcache->raw_collect (AMD64_GSBASE_REGNUM, &base); ++ /* Clear the full base value to support 32-bit targets. */ ++ base = 0; ++ regcache->raw_collect (tdep->fsbase_regnum + 1, &base); + + if (ptrace (PT_SETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) + perror_with_name (_("Couldn't write segment register gs_base")); +diff --git gdb/amd64-fbsd-nat.c gdb/amd64-fbsd-nat.c +index 9fff763dd3..cc676d3214 100644 +--- gdb/amd64-fbsd-nat.c ++++ gdb/amd64-fbsd-nat.c +@@ -190,13 +190,13 @@ amd64_fbsd_nat_target::read_description () + if (is64) + return amd64_target_description (xcr0, true); + else +- return i386_target_description (xcr0, false); ++ return i386_target_description (xcr0, true); + } + #endif + if (is64) + return amd64_target_description (X86_XSTATE_SSE_MASK, true); + else +- return i386_target_description (X86_XSTATE_SSE_MASK, false); ++ return i386_target_description (X86_XSTATE_SSE_MASK, true); + } + + #if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO) +diff --git gdb/i386-bsd-nat.c gdb/i386-bsd-nat.c +index 009a8dc1b2..a10b496096 100644 +--- gdb/i386-bsd-nat.c ++++ gdb/i386-bsd-nat.c +@@ -144,6 +144,33 @@ i386bsd_fetch_inferior_registers (struct regcache *regcache, int regnum) + return; + } + ++#ifdef PT_GETFSBASE ++ if (regnum == -1 || regnum == I386_FSBASE_REGNUM) ++ { ++ register_t base; ++ ++ if (ptrace (PT_GETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) ++ perror_with_name (_("Couldn't get segment register fs_base")); ++ ++ regcache->raw_supply (I386_FSBASE_REGNUM, &base); ++ if (regnum != -1) ++ return; ++ } ++#endif ++#ifdef PT_GETGSBASE ++ if (regnum == -1 || regnum == I386_GSBASE_REGNUM) ++ { ++ register_t base; ++ ++ if (ptrace (PT_GETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) ++ perror_with_name (_("Couldn't get segment register gs_base")); ++ ++ regcache->raw_supply (I386_GSBASE_REGNUM, &base); ++ if (regnum != -1) ++ return; ++ } ++#endif ++ + if (regnum == -1 || regnum >= I386_ST0_REGNUM) + { + struct fpreg fpregs; +@@ -211,6 +238,33 @@ i386bsd_store_inferior_registers (struct regcache *regcache, int regnum) + return; + } + ++#ifdef PT_SETFSBASE ++ if (regnum == -1 || regnum == I386_FSBASE_REGNUM) ++ { ++ register_t base; ++ ++ regcache->raw_collect (I386_FSBASE_REGNUM, &base); ++ ++ if (ptrace (PT_SETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) ++ perror_with_name (_("Couldn't write segment register fs_base")); ++ if (regnum != -1) ++ return; ++ } ++#endif ++#ifdef PT_SETGSBASE ++ if (regnum == -1 || regnum == I386_GSBASE_REGNUM) ++ { ++ register_t base; ++ ++ regcache->raw_collect (I386_GSBASE_REGNUM, &base); ++ ++ if (ptrace (PT_SETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) ++ perror_with_name (_("Couldn't write segment register gs_base")); ++ if (regnum != -1) ++ return; ++ } ++#endif ++ + if (regnum == -1 || regnum >= I386_ST0_REGNUM) + { + struct fpreg fpregs; +diff --git gdb/i386-fbsd-nat.c gdb/i386-fbsd-nat.c +index 7106e90801..be5d4c67be 100644 +--- gdb/i386-fbsd-nat.c ++++ gdb/i386-fbsd-nat.c +@@ -160,7 +160,7 @@ i386_fbsd_nat_target::read_description () + if (x86bsd_xsave_len == 0) + xcr0 = X86_XSTATE_SSE_MASK; + +- return i386_target_description (xcr0, false); ++ return i386_target_description (xcr0, true); + } + #endif + +diff --git gdb/i386-fbsd-tdep.c gdb/i386-fbsd-tdep.c +index 2f28bad728..ac57e7383d 100644 +--- gdb/i386-fbsd-tdep.c ++++ gdb/i386-fbsd-tdep.c +@@ -267,7 +267,7 @@ i386fbsd_core_read_description (struct gdbarch *gdbarch, + struct target_ops *target, + bfd *abfd) + { +- return i386_target_description (i386fbsd_core_read_xcr0 (abfd), false); ++ return i386_target_description (i386fbsd_core_read_xcr0 (abfd), true); + } + + /* Similar to i386_supply_fpregset, but use XSAVE extended state. */ diff --git a/devel/gdb/files/commit-df22c1e5d5 b/devel/gdb/files/commit-df22c1e5d5 new file mode 100644 index 00000000..70c27c69 --- /dev/null +++ b/devel/gdb/files/commit-df22c1e5d5 @@ -0,0 +1,36 @@ +commit df22c1e5d53c38f38bce6072bb46de240f9e0e2b +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Handle an edge case for minisym TLS variable lookups. + + If a TLS variable is provided by a minisym from a separate debug file, + the separate debug file is passed to + gdbarch_fetch_tls_load_module_address. However, the object files + stored in the shared object list are the original object files, not + the separate debug object files. In this case, + svr4_fetch_objfile_link_map was failing to find the link map entry + since the debug object file is not in its internal list, only the + original object file. + + gdb/ChangeLog: + + * solib-svr4.c (svr4_fetch_objfile_link_map): Look for + objfile->separate_debug_objfile_backlink if not NULL. + +diff --git gdb/solib-svr4.c gdb/solib-svr4.c +index 84693c1766..14a471b6dc 100644 +--- gdb/solib-svr4.c ++++ gdb/solib-svr4.c +@@ -1551,6 +1551,11 @@ svr4_fetch_objfile_link_map (struct objfile *objfile) + if (objfile == symfile_objfile) + return info->main_lm_addr; + ++ /* If OBJFILE is a separate debug object file, look for the ++ original object file. */ ++ if (objfile->separate_debug_objfile_backlink != NULL) ++ objfile = objfile->separate_debug_objfile_backlink; ++ + /* The other link map addresses may be found by examining the list + of shared libraries. */ + for (so = master_so_list (); so; so = so->next) diff --git a/devel/gdb/files/commit-ef0bd2046f b/devel/gdb/files/commit-ef0bd2046f new file mode 100644 index 00000000..464156bc --- /dev/null +++ b/devel/gdb/files/commit-ef0bd2046f @@ -0,0 +1,165 @@ +commit ef0bd2046f58fac69577892c2d3b44b20d027476 +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Add a more general version of lookup_struct_elt_type. + + lookup_struct_elt is a new function which returns a tuple of + information about a component of a structure or union. The returned + tuple contains a pointer to the struct field object for the component + as well as a bit offset of that field within the structure. If the + field names a field in an anonymous substructure, the offset is the + "global" offset relative to the original structure type. If noerr is + set, then the returned tuple will set the field pointer to NULL to + indicate a missing component rather than throwing an error. + + lookup_struct_elt_type is now reimplemented in terms of this new + function. It simply returns the type of the returned field. + + gdb/ChangeLog: + + * gdbtypes.c (lookup_struct_elt): New function. + (lookup_struct_elt_type): Reimplement via lookup_struct_elt. + * gdbtypes.h (struct struct_elt): New type. + (lookup_struct_elt): New prototype. + +diff --git gdb/gdbtypes.c gdb/gdbtypes.c +index 5924b15520..db470dafac 100644 +--- gdb/gdbtypes.c ++++ gdb/gdbtypes.c +@@ -1644,19 +1644,10 @@ lookup_template_type (char *name, struct type *type, + return (SYMBOL_TYPE (sym)); + } + +-/* Given a type TYPE, lookup the type of the component named NAME. ++/* See gdbtypes.h. */ + +- TYPE can be either a struct or union, or a pointer or reference to +- a struct or union. If it is a pointer or reference, its target +- type is automatically used. Thus '.' and '->' are interchangable, +- as specified for the definitions of the expression element types +- STRUCTOP_STRUCT and STRUCTOP_PTR. +- +- If NOERR is nonzero, return NULL if there is no component named +- NAME. */ +- +-struct type * +-lookup_struct_elt_type (struct type *type, const char *name, int noerr) ++struct_elt ++lookup_struct_elt (struct type *type, const char *name, int noerr) + { + int i; + +@@ -1683,39 +1674,47 @@ lookup_struct_elt_type (struct type *type, const char *name, int noerr) + + if (t_field_name && (strcmp_iw (t_field_name, name) == 0)) + { +- return TYPE_FIELD_TYPE (type, i); ++ return {&TYPE_FIELD (type, i), TYPE_FIELD_BITPOS (type, i)}; + } + else if (!t_field_name || *t_field_name == '\0') + { +- struct type *subtype +- = lookup_struct_elt_type (TYPE_FIELD_TYPE (type, i), name, 1); +- +- if (subtype != NULL) +- return subtype; ++ struct_elt elt ++ = lookup_struct_elt (TYPE_FIELD_TYPE (type, i), name, 1); ++ if (elt.field != NULL) ++ { ++ elt.offset += TYPE_FIELD_BITPOS (type, i); ++ return elt; ++ } + } + } + + /* OK, it's not in this class. Recursively check the baseclasses. */ + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + { +- struct type *t; +- +- t = lookup_struct_elt_type (TYPE_BASECLASS (type, i), name, 1); +- if (t != NULL) +- { +- return t; +- } ++ struct_elt elt = lookup_struct_elt (TYPE_BASECLASS (type, i), name, 1); ++ if (elt.field != NULL) ++ return elt; + } + + if (noerr) +- { +- return NULL; +- } ++ return {nullptr, 0}; + + std::string type_name = type_to_string (type); + error (_("Type %s has no component named %s."), type_name.c_str (), name); + } + ++/* See gdbtypes.h. */ ++ ++struct type * ++lookup_struct_elt_type (struct type *type, const char *name, int noerr) ++{ ++ struct_elt elt = lookup_struct_elt (type, name, noerr); ++ if (elt.field != NULL) ++ return FIELD_TYPE (*elt.field); ++ else ++ return NULL; ++} ++ + /* Store in *MAX the largest number representable by unsigned integer type + TYPE. */ + +diff --git gdb/gdbtypes.h gdb/gdbtypes.h +index a6d4f64e9b..66051cf02c 100644 +--- gdb/gdbtypes.h ++++ gdb/gdbtypes.h +@@ -1873,6 +1873,44 @@ extern struct type *allocate_stub_method (struct type *); + + extern const char *type_name_or_error (struct type *type); + ++struct struct_elt ++{ ++ /* The field of the element, or NULL if no element was found. */ ++ struct field *field; ++ ++ /* The bit offset of the element in the parent structure. */ ++ LONGEST offset; ++}; ++ ++/* Given a type TYPE, lookup the field and offset of the component named ++ NAME. ++ ++ TYPE can be either a struct or union, or a pointer or reference to ++ a struct or union. If it is a pointer or reference, its target ++ type is automatically used. Thus '.' and '->' are interchangable, ++ as specified for the definitions of the expression element types ++ STRUCTOP_STRUCT and STRUCTOP_PTR. ++ ++ If NOERR is nonzero, the returned structure will have field set to ++ NULL if there is no component named NAME. ++ ++ If the component NAME is a field in an anonymous substructure of ++ TYPE, the returned offset is a "global" offset relative to TYPE ++ rather than an offset within the substructure. */ ++ ++extern struct_elt lookup_struct_elt (struct type *, const char *, int); ++ ++/* Given a type TYPE, lookup the type of the component named NAME. ++ ++ TYPE can be either a struct or union, or a pointer or reference to ++ a struct or union. If it is a pointer or reference, its target ++ type is automatically used. Thus '.' and '->' are interchangable, ++ as specified for the definitions of the expression element types ++ STRUCTOP_STRUCT and STRUCTOP_PTR. ++ ++ If NOERR is nonzero, return NULL if there is no component named ++ NAME. */ ++ + extern struct type *lookup_struct_elt_type (struct type *, const char *, int); + + extern struct type *make_pointer_type (struct type *, struct type **); diff --git a/devel/gdb/files/commit-f5424cfa7e b/devel/gdb/files/commit-f5424cfa7e new file mode 100644 index 00000000..2dc05f55 --- /dev/null +++ b/devel/gdb/files/commit-f5424cfa7e @@ -0,0 +1,63 @@ +commit f5424cfa7e9337a6cb02a1f83c9feea0995c5350 +Author: John Baldwin +Date: Tue Mar 12 13:39:02 2019 -0700 + + Support TLS variables on FreeBSD/amd64. + + Use the fs_base register to fetch the address of a thread's tcb and + calculate the address of the DTV array. This value is then passed to + fbsd_get_thread_local_address to compute the final variable address. + + Note that fs_base is currently only available via the native target as + core dumps on FreeBSD do not store the value of fs_base. + + gdb/ChangeLog: + + * amd64-fbsd-tdep.c (amd64fbsd_get_thread_local_address): New. + (amd64fbsd_init_abi): Install gdbarch + "fetch_tls_load_module_address" and "get_thread_local_address" + methods. + +diff --git gdb/amd64-fbsd-tdep.c gdb/amd64-fbsd-tdep.c +index 403e65022d..7e2e9edf21 100644 +--- gdb/amd64-fbsd-tdep.c ++++ gdb/amd64-fbsd-tdep.c +@@ -204,6 +204,26 @@ amd64fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, + &amd64fbsd_xstateregset, "XSAVE extended state", cb_data); + } + ++/* Implement the get_thread_local_address gdbarch method. */ ++ ++static CORE_ADDR ++amd64fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, ++ CORE_ADDR lm_addr, CORE_ADDR offset) ++{ ++ struct regcache *regcache; ++ ++ regcache = get_thread_arch_regcache (ptid, gdbarch); ++ ++ target_fetch_registers (regcache, AMD64_FSBASE_REGNUM); ++ ++ ULONGEST fsbase; ++ if (regcache->cooked_read (AMD64_FSBASE_REGNUM, &fsbase) != REG_VALID) ++ error (_("Unable to fetch %%fsbase")); ++ ++ CORE_ADDR dtv_addr = fsbase + gdbarch_ptr_bit (gdbarch) / 8; ++ return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset); ++} ++ + static void + amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + { +@@ -241,6 +261,11 @@ amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + /* FreeBSD uses SVR4-style shared libraries. */ + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_lp64_fetch_link_map_offsets); ++ ++ set_gdbarch_fetch_tls_load_module_address (gdbarch, ++ svr4_fetch_objfile_link_map); ++ set_gdbarch_get_thread_local_address (gdbarch, ++ amd64fbsd_get_thread_local_address); + } + + void diff --git a/devel/gdb/files/extrapatch-guile22 b/devel/gdb/files/extrapatch-guile22 new file mode 100644 index 00000000..f488e20c --- /dev/null +++ b/devel/gdb/files/extrapatch-guile22 @@ -0,0 +1,717 @@ +2018-01-21 Doug Evans + + PR guile/21104 + * configure.ac: Add guile-2.2 back. + * configure: Regenerate. + * guile/scm-ports.c (PORTS_V22): New macro. + (ioscm_memory_port) [!PORTS_V22]: Make read_buf_size,write_buf_size + !PORTS_V22 only. + (port_type_t): New type. + (stdio_port_type): Renamed from stdio_port_desc. + (stdio_port_type_name): Renamed from stdio_port_desc_name. + (memory_port_type): Renamed from memory_port_desc. + (memmory_port_type_name): Renamed from memory_port_desc_name. + (natural_buf_size) [PORTS_V22]: New variable. + (ioscm_open_port): New argument stream. All callers updated. + (ioscm_read, ioscm_write) [PORTS_V22]: New functions. + (ioscm_init_gdb_stdio_port) [PORTS_V22]: Adapt for use in Guile >= 2.2. + (gdbscm_is_stdio_port): New function. + (gdbscm_stdio_port_p): Call it. + (gdbscm_get_natural_buffer_sizes, gdbscm_memory_port_seek) + (gdbscm_memory_port_read, gdbscm_memory_port_write) [PORTS_V22]: New + functions. + (gdbscm_memory_port_print): Adapt for use in Guile >= 2.2. + (ioscm_init_memory_port_type): Ditto. + (ioscm_init_memory_stream): Replaces ioscm_init_memory_port. + (ioscm_init_memory_port_buffers): New function. + (gdbscm_open_memory): Update. + (gdbscm_is_memory_port): Adapt for use in Guile >= 2.2. + (port_functions) [!PORTS_V22]: Only define Guile functions + memory-port-read-buffer-size, set-memory-port-read-buffer-size!, + memory-port-write-buffer-size, set-memory-port-write-buffer-size! + for Guile < 2.2. + (gdbscm_initialize_ports): Only initialize out_of_range_buf_size if + !PORTS_V22. + +--- gdb/configure.orig 2019-06-26 13:50:46 UTC ++++ gdb/configure +@@ -10985,7 +10985,7 @@ fi + + + +-try_guile_versions="guile-2.0" ++try_guile_versions="guile-2.0 guile-2.2" + have_libguile=no + case "${with_guile}" in + no) +--- gdb/guile/scm-ports.c.orig 2019-05-11 18:19:03 UTC ++++ gdb/guile/scm-ports.c +@@ -36,6 +36,13 @@ + #endif + #endif + ++/* Guile ports radically changed in Guile 2.2. ++ Note: We don't support Guile < 2.0. ++ TODO(dje): Suggest deprecating and then removing Guile 2.0 support ++ at some point in the future. */ ++#define PORTS_V22 (SCM_MAJOR_VERSION > 2 \ ++ || SCM_MAJOR_VERSION == 2 && SCM_MINOR_VERSION >= 2) ++ + /* A ui-file for sending output to Guile. */ + + class ioscm_file_port : public ui_file +@@ -66,12 +73,14 @@ typedef struct + This value is always in the range [0, size]. */ + ULONGEST current; + ++#if !PORTS_V22 + /* The size of the internal r/w buffers. + Scheme ports aren't a straightforward mapping to memory r/w. + Generally the user specifies how much to r/w and all access is + unbuffered. We don't try to provide equivalent access, but we allow + the user to specify these values to help get something similar. */ + unsigned read_buf_size, write_buf_size; ++#endif + } ioscm_memory_port; + + /* Copies of the original system input/output/error ports. +@@ -80,11 +89,17 @@ static SCM orig_input_port_scm; + static SCM orig_output_port_scm; + static SCM orig_error_port_scm; + +-/* This is the stdio port descriptor, scm_ptob_descriptor. */ +-static scm_t_bits stdio_port_desc; ++#if PORTS_V22 ++typedef scm_t_port_type *port_type_t; ++#else ++typedef scm_t_bits port_type_t; ++#endif + ++/* This is the stdio port type. */ ++static port_type_t stdio_port_type; ++ + /* Note: scm_make_port_type takes a char * instead of a const char *. */ +-static /*const*/ char stdio_port_desc_name[] = "gdb:stdio-port"; ++static /*const*/ char stdio_port_type_name[] = "gdb:stdio-port"; + + /* Names of each gdb port. */ + static const char input_port_name[] = "gdb:stdin"; +@@ -101,12 +116,19 @@ static SCM error_port_scm; + /* Internal enum for specifying output port. */ + enum oport { GDB_STDOUT, GDB_STDERR }; + +-/* This is the memory port descriptor, scm_ptob_descriptor. */ +-static scm_t_bits memory_port_desc; ++/* This is the memory port type. */ ++static port_type_t memory_port_type; + + /* Note: scm_make_port_type takes a char * instead of a const char *. */ +-static /*const*/ char memory_port_desc_name[] = "gdb:memory-port"; ++static /*const*/ char memory_port_type_name[] = "gdb:memory-port"; + ++#if PORTS_V22 ++ ++/* The maximum values to use for get_natural_buffer_sizes. */ ++static const unsigned natural_buf_size = 16; ++ ++#else ++ + /* The default amount of memory to fetch for each read/write request. + Scheme ports don't provide a way to specify the size of a read, + which is important to us to minimize the number of inferior interactions, +@@ -120,6 +142,8 @@ static const unsigned default_write_buf_size = 16; + static const unsigned min_memory_port_buf_size = 1; + static const unsigned max_memory_port_buf_size = 4096; + ++#endif ++ + /* "out of range" error message for buf sizes. */ + static char *out_of_range_buf_size; + +@@ -132,7 +156,7 @@ static SCM size_keyword; + Newer versions of Guile (2.1.x) have scm_c_make_port. */ + + static SCM +-ioscm_open_port (scm_t_bits port_type, long mode_bits) ++ioscm_open_port (port_type_t port_type, long mode_bits, scm_t_bits stream) + { + SCM port; + +@@ -140,9 +164,12 @@ ioscm_open_port (scm_t_bits port_type, long mode_bits) + scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex); + #endif + ++#if PORTS_V22 ++ port = scm_c_make_port (port_type, mode_bits, stream); ++#else + port = scm_new_port_table_entry (port_type); +- + SCM_SET_CELL_TYPE (port, port_type | mode_bits); ++#endif + + #if 0 /* TODO: Guile doesn't export this. What to do? */ + scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex); +@@ -150,6 +177,23 @@ ioscm_open_port (scm_t_bits port_type, long mode_bits) + + return port; + } ++ ++/* Like fputstrn_filtered, but don't escape characters, except nul. ++ Also like fputs_filtered, but a length is specified. */ ++ ++static void ++fputsn_filtered (const char *s, size_t size, struct ui_file *stream) ++{ ++ size_t i; ++ ++ for (i = 0; i < size; ++i) ++ { ++ if (s[i] == '\0') ++ fputs_filtered ("\\000", stream); ++ else ++ fputc_filtered (s[i], stream); ++ } ++} + + /* Support for connecting Guile's stdio ports to GDB's stdio ports. */ + +@@ -218,6 +262,73 @@ ioscm_input_waiting (SCM port) + } + } + ++#if PORTS_V22 ++ ++static size_t ++ioscm_read (SCM port, SCM dst, size_t start, size_t count) ++{ ++ /* Borrowed from libguile/fports.c. */ ++ auto ptr = reinterpret_cast(SCM_BYTEVECTOR_CONTENTS (dst) + start); ++ ssize_t ret; ++ ++ /* If we're called on stdout,stderr, punt. */ ++ if (! scm_is_eq (port, input_port_scm)) ++ return 0; /* EOF */ ++ ++ gdb_flush (gdb_stdout); ++ gdb_flush (gdb_stderr); ++ ++ retry: ++ ret = ui_file_read (gdb_stdin, ptr, count); ++ if (ret < 0) ++ { ++ if (errno == EINTR) ++ { ++ scm_async_tick (); ++ goto retry; ++ } ++ if (errno == EWOULDBLOCK || errno == EAGAIN) ++ { ++ /* See the discussion of non-blocking I/O in the Guile manual. */ ++ return -1; ++ } ++ scm_syserror ("ioscm_read"); ++ } ++ return ret; ++} ++ ++static size_t ++ioscm_write (SCM port, SCM src, size_t start, size_t count) ++{ ++ /* Borrowed from libguile/fports.c. */ ++ auto ptr = reinterpret_cast(SCM_BYTEVECTOR_CONTENTS (src) + start); ++ ssize_t ret; ++ ++ /* If we're called on stdin, punt. */ ++ if (scm_is_eq (port, input_port_scm)) ++ { ++ errno = EIO; ++ scm_syserror("ioscm_write"); ++ } ++ ++ TRY ++ { ++ if (scm_is_eq (port, error_port_scm)) ++ fputsn_filtered (ptr, count, gdb_stderr); ++ else ++ fputsn_filtered (ptr, count, gdb_stdout); ++ } ++ CATCH (except, RETURN_MASK_ALL) ++ { ++ GDBSCM_HANDLE_GDB_EXCEPTION (except); ++ } ++ END_CATCH ++ ++ return count; ++} ++ ++#else /* !PORTS_V22 */ ++ + /* The scm_t_ptob_descriptor.fill_input "method". */ + + static int +@@ -245,23 +356,6 @@ ioscm_fill_input (SCM port) + return *pt->read_buf; + } + +-/* Like fputstrn_filtered, but don't escape characters, except nul. +- Also like fputs_filtered, but a length is specified. */ +- +-static void +-fputsn_filtered (const char *s, size_t size, struct ui_file *stream) +-{ +- size_t i; +- +- for (i = 0; i < size; ++i) +- { +- if (s[i] == '\0') +- fputs_filtered ("\\000", stream); +- else +- fputc_filtered (s[i], stream); +- } +-} +- + /* Write to gdb's stdout or stderr. */ + + static void +@@ -301,6 +395,8 @@ ioscm_flush (SCM port) + gdb_flush (gdb_stdout); + } + ++#endif ++ + /* Initialize the gdb stdio port type. + + N.B. isatty? will fail on these ports, it is only supported for file +@@ -309,13 +405,23 @@ ioscm_flush (SCM port) + static void + ioscm_init_gdb_stdio_port (void) + { +- stdio_port_desc = scm_make_port_type (stdio_port_desc_name, +- ioscm_fill_input, ioscm_write); ++ stdio_port_type = scm_make_port_type (stdio_port_type_name, ++#if PORTS_V22 ++ ioscm_read, ++#else ++ ioscm_fill_input, ++#endif ++ ioscm_write); + +- scm_set_port_input_waiting (stdio_port_desc, ioscm_input_waiting); +- scm_set_port_flush (stdio_port_desc, ioscm_flush); ++ scm_set_port_input_waiting (stdio_port_type, ioscm_input_waiting); ++ ++#if !PORTS_V22 ++ scm_set_port_flush (stdio_port_type, ioscm_flush); ++#endif + } + ++#if !PORTS_V22 ++ + /* Subroutine of ioscm_make_gdb_stdio_port to simplify it. + Set up the buffers of port PORT. + MODE_BITS are the mode bits of PORT. */ +@@ -358,6 +464,8 @@ ioscm_init_stdio_buffers (SCM port, long mode_bits) + pt->write_end = pt->write_buf + pt->write_buf_size; + } + ++#endif ++ + /* Create a gdb stdio port. */ + + static SCM +@@ -388,23 +496,36 @@ ioscm_make_gdb_stdio_port (int fd) + } + + mode_bits = scm_mode_bits ((char *) mode_str); +- port = ioscm_open_port (stdio_port_desc, mode_bits); ++ port = ioscm_open_port (stdio_port_type, mode_bits, 0); + + scm_set_port_filename_x (port, gdbscm_scm_from_c_string (name)); + ++#if !PORTS_V22 + ioscm_init_stdio_buffers (port, mode_bits); ++#endif + + return port; + } + ++/* Return non-zero if OBJ is a stdio port. */ ++ ++static int ++gdbscm_is_stdio_port (SCM obj) ++{ ++ /* This is copied from SCM_FPORTP. */ ++#if PORTS_V22 ++ return SCM_PORTP (obj) && SCM_PORT_TYPE (obj) == stdio_port_type; ++#else ++ return !SCM_IMP (obj) && SCM_TYP16 (obj) == stdio_port_type; ++#endif ++} ++ + /* (stdio-port? object) -> boolean */ + + static SCM +-gdbscm_stdio_port_p (SCM scm) ++gdbscm_stdio_port_p (SCM obj) + { +- /* This is copied from SCM_FPORTP. */ +- return scm_from_bool (!SCM_IMP (scm) +- && (SCM_TYP16 (scm) == stdio_port_desc)); ++ return scm_from_bool (gdbscm_is_stdio_port (obj)); + } + + /* GDB's ports are accessed via functions to keep them read-only. */ +@@ -567,6 +688,94 @@ ioscm_lseek_address (ioscm_memory_port *iomem, LONGEST + return 1; + } + ++#if PORTS_V22 ++ ++/* The semantics get weird if the buffer size is larger than the port range, ++ so provide a better default buffer size. */ ++ ++static void ++gdbscm_get_natural_buffer_sizes (SCM port, size_t *read_size, ++ size_t *write_size) ++{ ++ ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); ++ ++ size_t size = natural_buf_size; ++ if (iomem->size < size) ++ size = iomem->size; ++ *read_size = *write_size = size; ++} ++ ++static scm_t_off ++gdbscm_memory_port_seek (SCM port, scm_t_off offset, int whence) ++{ ++ ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); ++ scm_t_off result; ++ int rc; ++ ++ if (ioscm_lseek_address (iomem, offset, whence) == 0) ++ { ++ gdbscm_out_of_range_error (FUNC_NAME, 0, ++ gdbscm_scm_from_longest (offset), ++ _("bad seek")); ++ } ++ ++ return iomem->current; ++} ++ ++static size_t ++gdbscm_memory_port_read (SCM port, SCM dst, size_t start, size_t count) ++{ ++ /* Borrowed from libguile/fports.c. */ ++ auto ptr = reinterpret_cast(SCM_BYTEVECTOR_CONTENTS (dst) + start); ++ ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); ++ size_t to_read; ++ ++ /* "current" is the offset of the first byte we want to read. */ ++ gdb_assert (iomem->current <= iomem->size); ++ if (iomem->current == iomem->size) ++ return 0; /* EOF */ ++ ++ /* Don't read outside the allowed memory range. */ ++ to_read = count; ++ if (to_read > iomem->size - iomem->current) ++ to_read = iomem->size - iomem->current; ++ ++ if (target_read_memory (iomem->start + iomem->current, ptr, to_read) != 0) ++ gdbscm_memory_error (FUNC_NAME, _("error reading memory"), SCM_EOL); ++ ++ iomem->current += to_read; ++ return to_read; ++} ++ ++static size_t ++gdbscm_memory_port_write (SCM port, SCM src, size_t start, size_t count) ++{ ++ /* Borrowed from libguile/fports.c. */ ++ auto ptr = reinterpret_cast(SCM_BYTEVECTOR_CONTENTS (src) + ++ start); ++ ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); ++ ssize_t ret; ++ ++ /* "current" is the offset of the first byte we want to read. */ ++ gdb_assert (iomem->current <= iomem->size); ++ ++ /* There's no way to indicate a short write, so if the request goes past ++ the end of the port's memory range, flag an error. */ ++ if (count > iomem->size - iomem->current) ++ { ++ gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (count), ++ _("writing beyond end of memory range")); ++ } ++ ++ if (target_write_memory (iomem->start + iomem->current, ptr, count) != 0) ++ gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL); ++ iomem->current += count; ++ ++ return count; ++} ++ ++#else /* !PORTS_V22 */ ++ + /* "fill_input" method for memory ports. */ + + static int +@@ -850,18 +1059,19 @@ gdbscm_memory_port_free (SCM port) + return 0; + } + ++#endif ++ + /* "print" method for memory ports. */ + + static int + gdbscm_memory_port_print (SCM exp, SCM port, scm_print_state *pstate) + { + ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (exp); +- char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp)); + + scm_puts ("#<", port); + scm_print_port_mode (exp, port); + /* scm_print_port_mode includes a trailing space. */ +- gdbscm_printf (port, "%s %s-%s", type, ++ gdbscm_printf (port, "%s %s-%s", memory_port_type_name, + hex_string (iomem->start), hex_string (iomem->end)); + scm_putc ('>', port); + return 1; +@@ -872,16 +1082,25 @@ gdbscm_memory_port_print (SCM exp, SCM port, scm_print + static void + ioscm_init_memory_port_type (void) + { +- memory_port_desc = scm_make_port_type (memory_port_desc_name, ++ memory_port_type = scm_make_port_type (memory_port_type_name, ++#if PORTS_V22 ++ gdbscm_memory_port_read, ++#else + gdbscm_memory_port_fill_input, ++#endif + gdbscm_memory_port_write); + +- scm_set_port_end_input (memory_port_desc, gdbscm_memory_port_end_input); +- scm_set_port_flush (memory_port_desc, gdbscm_memory_port_flush); +- scm_set_port_seek (memory_port_desc, gdbscm_memory_port_seek); +- scm_set_port_close (memory_port_desc, gdbscm_memory_port_close); +- scm_set_port_free (memory_port_desc, gdbscm_memory_port_free); +- scm_set_port_print (memory_port_desc, gdbscm_memory_port_print); ++#if PORTS_V22 ++ scm_set_port_get_natural_buffer_sizes (memory_port_type, ++ gdbscm_get_natural_buffer_sizes); ++#else ++ scm_set_port_end_input (memory_port_type, gdbscm_memory_port_end_input); ++ scm_set_port_flush (memory_port_type, gdbscm_memory_port_flush); ++ scm_set_port_free (memory_port_type, gdbscm_memory_port_free); ++ scm_set_port_close (memory_port_type, gdbscm_memory_port_close); ++#endif ++ scm_set_port_seek (memory_port_type, gdbscm_memory_port_seek); ++ scm_set_port_print (memory_port_type, gdbscm_memory_port_print); + } + + /* Helper for gdbscm_open_memory to parse the mode bits. +@@ -921,27 +1140,20 @@ ioscm_parse_mode_bits (const char *func_name, const ch + return mode_bits; + } + +-/* Helper for gdbscm_open_memory to finish initializing the port. +- The port has address range [start,end). +- This means that address of 0xff..ff is not accessible. +- I can live with that. */ +- +-static void +-ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end) ++static scm_t_bits ++ioscm_init_memory_stream (bool buffered, CORE_ADDR start, CORE_ADDR end) + { +- scm_t_port *pt; +- ioscm_memory_port *iomem; +- int buffered = (SCM_CELL_WORD_0 (port) & SCM_BUF0) == 0; ++ auto iomem = reinterpret_cast( ++ scm_gc_malloc_pointerless (sizeof (ioscm_memory_port), "memory port")); + + gdb_assert (start <= end); + +- iomem = (ioscm_memory_port *) scm_gc_malloc_pointerless (sizeof (*iomem), +- "memory port"); +- + iomem->start = start; + iomem->end = end; + iomem->size = end - start; + iomem->current = 0; ++ ++#if !PORTS_V22 + if (buffered) + { + iomem->read_buf_size = default_read_buf_size; +@@ -952,7 +1164,25 @@ ioscm_init_memory_port (SCM port, CORE_ADDR start, COR + iomem->read_buf_size = 1; + iomem->write_buf_size = 1; + } ++#endif + ++ return reinterpret_cast(iomem); ++} ++ ++#if !PORTS_V22 ++ ++/* Helper for gdbscm_open_memory to finish initializing the port. ++ The port has address range [start,end). ++ This means that address of 0xff..ff is not accessible. ++ I can live with that. */ ++ ++static void ++ioscm_init_memory_port_buffers (SCM port) ++{ ++ scm_t_port *pt; ++ auto iomem = reinterpret_cast(SCM_STREAM (port)); ++ bool buffered = (SCM_CELL_WORD_0 (port) & SCM_BUF0) == 0; ++ + pt = SCM_PTAB_ENTRY (port); + /* Match the expectation of `binary-port?'. */ + pt->encoding = NULL; +@@ -972,8 +1202,6 @@ ioscm_init_memory_port (SCM port, CORE_ADDR start, COR + pt->read_pos = pt->read_end = pt->read_buf; + pt->write_pos = pt->write_buf; + pt->write_end = pt->write_buf + pt->write_buf_size; +- +- SCM_SETSTREAM (port, iomem); + } + + /* Re-initialize a memory port, updating its read/write buffer sizes. +@@ -1041,6 +1269,8 @@ ioscm_reinit_memory_port (SCM port, size_t read_buf_si + } + } + ++#endif /* !PORTS_V22 */ ++ + /* (open-memory [#:mode string] [#:start address] [#:size integer]) -> port + Return a port that can be used for reading and writing memory. + MODE is a string, and must be one of "r", "w", or "r+". +@@ -1107,10 +1337,19 @@ gdbscm_open_memory (SCM rest) + end = ~(CORE_ADDR) 0; + + mode_bits = ioscm_parse_mode_bits (FUNC_NAME, mode); ++ /* Edge case: empty range -> unbuffered. ++ There's no need to disallow empty ranges, but we need an unbuffered port ++ to get the semantics right. */ ++ if (size == 0) ++ mode_bits |= SCM_BUF0; + +- port = ioscm_open_port (memory_port_desc, mode_bits); ++ bool buffered = (mode_bits & SCM_BUF0) == 0; ++ auto stream = ioscm_init_memory_stream(buffered, start, end); ++ port = ioscm_open_port (memory_port_type, mode_bits, stream); + +- ioscm_init_memory_port (port, start, end); ++#if !PORTS_V22 ++ ioscm_init_memory_port_buffers (port); ++#endif + + scm_dynwind_end (); + +@@ -1123,7 +1362,12 @@ gdbscm_open_memory (SCM rest) + static int + gdbscm_is_memory_port (SCM obj) + { +- return !SCM_IMP (obj) && (SCM_TYP16 (obj) == memory_port_desc); ++ /* This is copied from SCM_FPORTP. */ ++#if PORTS_V22 ++ return SCM_PORTP (obj) && SCM_PORT_TYPE (obj) == memory_port_type; ++#else ++ return !SCM_IMP (obj) && SCM_TYP16 (obj) == memory_port_type; ++#endif + } + + /* (memory-port? obj) -> boolean */ +@@ -1142,13 +1386,15 @@ gdbscm_memory_port_range (SCM port) + ioscm_memory_port *iomem; + + SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME, +- memory_port_desc_name); ++ memory_port_type_name); + + iomem = (ioscm_memory_port *) SCM_STREAM (port); + return scm_list_2 (gdbscm_scm_from_ulongest (iomem->start), + gdbscm_scm_from_ulongest (iomem->end)); + } + ++#if !PORTS_V22 ++ + /* (memory-port-read-buffer-size port) -> integer */ + + static SCM +@@ -1157,7 +1403,7 @@ gdbscm_memory_port_read_buffer_size (SCM port) + ioscm_memory_port *iomem; + + SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME, +- memory_port_desc_name); ++ memory_port_type_name); + + iomem = (ioscm_memory_port *) SCM_STREAM (port); + return scm_from_uint (iomem->read_buf_size); +@@ -1173,7 +1419,7 @@ gdbscm_set_memory_port_read_buffer_size_x (SCM port, S + ioscm_memory_port *iomem; + + SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME, +- memory_port_desc_name); ++ memory_port_type_name); + SCM_ASSERT_TYPE (scm_is_integer (size), size, SCM_ARG2, FUNC_NAME, + _("integer")); + +@@ -1199,7 +1445,7 @@ gdbscm_memory_port_write_buffer_size (SCM port) + ioscm_memory_port *iomem; + + SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME, +- memory_port_desc_name); ++ memory_port_type_name); + + iomem = (ioscm_memory_port *) SCM_STREAM (port); + return scm_from_uint (iomem->write_buf_size); +@@ -1215,7 +1461,7 @@ gdbscm_set_memory_port_write_buffer_size_x (SCM port, + ioscm_memory_port *iomem; + + SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME, +- memory_port_desc_name); ++ memory_port_type_name); + SCM_ASSERT_TYPE (scm_is_integer (size), size, SCM_ARG2, FUNC_NAME, + _("integer")); + +@@ -1232,6 +1478,8 @@ gdbscm_set_memory_port_write_buffer_size_x (SCM port, + + return SCM_UNSPECIFIED; + } ++ ++#endif /* !PORTS_V22 */ + + /* Initialize gdb ports. */ + +@@ -1268,6 +1516,7 @@ Return #t if the object is a memory port." }, + "\ + Return the memory range of the port as (start end)." }, + ++#if !PORTS_V22 + { "memory-port-read-buffer-size", 1, 0, 0, + as_a_scm_t_subr (gdbscm_memory_port_read_buffer_size), + "\ +@@ -1293,6 +1542,7 @@ Set the size of the write buffer for the memory port.\ + \n\ + Arguments: port integer\n\ + Returns: unspecified." }, ++#endif + + END_FUNCTIONS + }; +@@ -1365,9 +1615,11 @@ gdbscm_initialize_ports (void) + start_keyword = scm_from_latin1_keyword ("start"); + size_keyword = scm_from_latin1_keyword ("size"); + ++#if !PORTS_V22 + /* Error message text for "out of range" memory port buffer sizes. */ + + out_of_range_buf_size = xstrprintf ("size not between %u - %u", + min_memory_port_buf_size, + max_memory_port_buf_size); ++#endif + } diff --git a/devel/gdb/files/extrapatch-kgdb b/devel/gdb/files/extrapatch-kgdb new file mode 100644 index 00000000..5ce13579 --- /dev/null +++ b/devel/gdb/files/extrapatch-kgdb @@ -0,0 +1,481 @@ +diff --git gdb/Makefile.in gdb/Makefile.in +index 5614cc3386..b9acc63c3f 100644 +--- gdb/Makefile.in ++++ gdb/Makefile.in +@@ -230,7 +230,8 @@ INCGNU = -I$(srcdir)/gnulib/import -I$(GNULIB_BUILDDIR)/import + + # Generated headers in the gnulib directory. These must be listed + # so that they are generated before other files are compiled. +-GNULIB_H = $(GNULIB_BUILDDIR)/import/string.h @GNULIB_STDINT_H@ ++GNULIB_H = $(GNULIB_BUILDDIR)/import/string.h \ ++ $(GNULIB_BUILDDIR)/import/alloca.h @GNULIB_STDINT_H@ + + # + # CLI sub directory definitons +@@ -632,6 +633,7 @@ TARGET_OBS = @TARGET_OBS@ + # All target-dependent objects files that require 64-bit CORE_ADDR + # (used with --enable-targets=all --enable-64-bit-bfd). + ALL_64_TARGET_OBS = \ ++ aarch64-fbsd-kern.o \ + aarch64-fbsd-tdep.o \ + aarch64-linux-tdep.o \ + aarch64-newlib-tdep.o \ +@@ -646,6 +648,7 @@ ALL_64_TARGET_OBS = \ + amd64-darwin-tdep.o \ + amd64-dicos-tdep.o \ + amd64-fbsd-tdep.o \ ++ amd64fbsd-kern.o \ + amd64-linux-tdep.o \ + amd64-nbsd-tdep.o \ + amd64-obsd-tdep.o \ +@@ -660,6 +663,7 @@ ALL_64_TARGET_OBS = \ + ia64-vms-tdep.o \ + mips64-obsd-tdep.o \ + sparc64-fbsd-tdep.o \ ++ sparc64fbsd-kern.o \ + sparc64-linux-tdep.o \ + sparc64-nbsd-tdep.o \ + sparc64-obsd-tdep.o \ +@@ -676,6 +680,7 @@ ALL_TARGET_OBS = \ + arch/ppc-linux-common.o \ + arch/riscv.o \ + arm-bsd-tdep.o \ ++ arm-fbsd-kern.o \ + arm-fbsd-tdep.o \ + arm-linux-tdep.o \ + arm-nbsd-tdep.o \ +@@ -693,6 +698,8 @@ ALL_TARGET_OBS = \ + csky-linux-tdep.o \ + csky-tdep.o \ + dicos-tdep.o \ ++ fbsd-kld.o \ ++ fbsd-kthr.o \ + fbsd-tdep.o \ + frv-linux-tdep.o \ + frv-tdep.o \ +@@ -709,6 +716,7 @@ ALL_TARGET_OBS = \ + i386-darwin-tdep.o \ + i386-dicos-tdep.o \ + i386-fbsd-tdep.o \ ++ i386fbsd-kern.o \ + i386-gnu-tdep.o \ + i386-go32-tdep.o \ + i386-linux-tdep.o \ +@@ -732,6 +740,7 @@ ALL_TARGET_OBS = \ + mep-tdep.o \ + microblaze-linux-tdep.o \ + microblaze-tdep.o \ ++ mipsfbsd-kern.o \ + mips-fbsd-tdep.o \ + mips-linux-tdep.o \ + mips-nbsd-tdep.o \ +@@ -750,6 +759,7 @@ ALL_TARGET_OBS = \ + or1k-linux-tdep.o \ + or1k-tdep.o \ + ppc-fbsd-tdep.o \ ++ ppcfbsd-kern.o \ + ppc-linux-tdep.o \ + ppc-nbsd-tdep.o \ + ppc-obsd-tdep.o \ +@@ -757,6 +767,7 @@ ALL_TARGET_OBS = \ + ppc-sysv-tdep.o \ + ppc64-tdep.o \ + ravenscar-thread.o \ ++ riscv-fbsd-kern.o \ + riscv-fbsd-tdep.o \ + riscv-linux-tdep.o \ + riscv-tdep.o \ +@@ -1629,7 +1640,7 @@ generated_files = \ + # Flags needed to compile Python code + PYTHON_CFLAGS = @PYTHON_CFLAGS@ + +-all: gdb$(EXEEXT) $(CONFIG_ALL) gdb-gdb.py gdb-gdb.gdb ++all: gdb$(EXEEXT) kgdb$(EXEEXT) $(CONFIG_ALL) gdb-gdb.py gdb-gdb.gdb + @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do + + # Rule for compiling .c files in the top-level gdb directory. +@@ -1894,6 +1905,12 @@ ifneq ($(CODESIGN_CERT),) + $(ECHO_SIGN) $(CODESIGN) -s $(CODESIGN_CERT) gdb$(EXEEXT) + endif + ++kgdb$(EXEEXT): kgdb-main.o $(LIBGDB_OBS) $(ADD_DEPS) $(CDEPS) $(TDEPLIBS) ++ $(SILENCE) rm -f kgdb$(EXEEXT) ++ $(ECHO_CXXLD) $(CC_LD) $(INTERNAL_LDFLAGS) $(WIN32LDAPP) \ ++ -o kgdb$(EXEEXT) kgdb-main.o $(LIBGDB_OBS) \ ++ $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) ++ + # Convenience rule to handle recursion. + $(LIBGNU) $(GNULIB_H): all-lib + all-lib: $(GNULIB_BUILDDIR)/Makefile +@@ -1940,6 +1957,7 @@ clean mostlyclean: $(CONFIG_CLEAN) + rm -f init.c stamp-init version.c stamp-version + rm -f gdb$(EXEEXT) core make.log + rm -f gdb[0-9]$(EXEEXT) ++ rm -f kgdb$(EXEEXT) + rm -f test-cp-name-parser$(EXEEXT) + rm -f xml-builtin.c stamp-xml + rm -f $(DEPDIR)/* +@@ -2154,6 +2172,7 @@ force_update: + MAKEOVERRIDES = + + ALLDEPFILES = \ ++ aarch64-fbsd-kern.c \ + aarch64-fbsd-nat.c \ + aarch64-fbsd-tdep.c \ + aarch64-linux-nat.c \ +@@ -2173,6 +2192,7 @@ ALLDEPFILES = \ + amd64-bsd-nat.c \ + amd64-darwin-tdep.c \ + amd64-dicos-tdep.c \ ++ amd64fbsd-kern.c \ + amd64-fbsd-nat.c \ + amd64-fbsd-tdep.c \ + amd64-linux-nat.c \ +@@ -2187,6 +2207,7 @@ ALLDEPFILES = \ + arc-tdep.c \ + arm.c \ + arm-bsd-tdep.c \ ++ arm-fbsd-kern.c \ + arm-fbsd-nat.c \ + arm-fbsd-tdep.c \ + arm-get-next-pcs.c \ +@@ -2207,6 +2228,9 @@ ALLDEPFILES = \ + csky-tdep.c \ + darwin-nat.c \ + dicos-tdep.c \ ++ fbsd-kld.c \ ++ fbsd-kthr.c \ ++ fbsd-kvm.c \ + fbsd-nat.c \ + fbsd-tdep.c \ + fork-child.c \ +@@ -2228,6 +2252,7 @@ ALLDEPFILES = \ + i386-darwin-nat.c \ + i386-darwin-tdep.c \ + i386-dicos-tdep.c \ ++ i386fbsd-kern.c \ + i386-fbsd-nat.c \ + i386-fbsd-tdep.c \ + i386-gnu-nat.c \ +@@ -2264,6 +2289,7 @@ ALLDEPFILES = \ + microblaze-linux-tdep.c \ + microblaze-tdep.c \ + mingw-hdep.c \ ++ mipsfbsd-kern.c \ + mips-fbsd-nat.c \ + mips-fbsd-tdep.c \ + mips-linux-nat.c \ +@@ -2283,6 +2309,7 @@ ALLDEPFILES = \ + obsd-nat.c \ + obsd-tdep.c \ + posix-hdep.c \ ++ ppcfbsd-kern.c \ + ppc-fbsd-nat.c \ + ppc-fbsd-tdep.c \ + ppc-linux-nat.c \ +@@ -2297,6 +2324,7 @@ ALLDEPFILES = \ + procfs.c \ + ravenscar-thread.c \ + remote-sim.c \ ++ riscv-fbsd-kern.c \ + riscv-fbsd-nat.c \ + riscv-fbsd-tdep.c \ + riscv-linux-nat.c \ +@@ -2333,6 +2361,7 @@ ALLDEPFILES = \ + sparc-sol2-nat.c \ + sparc-sol2-tdep.c \ + sparc-tdep.c \ ++ sparc64fbsd-kern.c \ + sparc64-fbsd-nat.c \ + sparc64-fbsd-tdep.c \ + sparc64-linux-nat.c \ +@@ -2596,7 +2625,7 @@ endif + + # A list of all the objects we might care about in this build, for + # dependency tracking. +-all_object_files = gdb.o $(LIBGDB_OBS) gdbtk-main.o \ ++all_object_files = kgdb-main.o gdb.o $(LIBGDB_OBS) gdbtk-main.o \ + test-cp-name-parser.o + + # All the .deps files to include. +diff --git gdb/config.in gdb/config.in +index ea907d2b56..ee9146fd4e 100644 +--- gdb/config.in ++++ gdb/config.in +@@ -219,6 +219,9 @@ + /* Define to 1 if your system has the kinfo_getvmmap function. */ + #undef HAVE_KINFO_GETVMMAP + ++/* Define to 1 if your system has the kvm_open2 function. */ ++#undef HAVE_KVM_OPEN2 ++ + /* Define if you have and nl_langinfo(CODESET). */ + #undef HAVE_LANGINFO_CODESET + +diff --git gdb/configure gdb/configure +index 854837c50a..1f2da364cf 100755 +--- gdb/configure ++++ gdb/configure +@@ -8107,6 +8107,66 @@ $as_echo "#define HAVE_KINFO_GETFILE 1" >>confdefs.h + fi + + ++# kgdb needs kvm_open2 for cross-debugging ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing kvm_open2" >&5 ++$as_echo_n "checking for library containing kvm_open2... " >&6; } ++if test "${ac_cv_search_kvm_open2+set}" = set; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_func_search_save_LIBS=$LIBS ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char kvm_open2 (); ++int ++main () ++{ ++return kvm_open2 (); ++ ; ++ return 0; ++} ++_ACEOF ++for ac_lib in '' kvm; do ++ if test -z "$ac_lib"; then ++ ac_res="none required" ++ else ++ ac_res=-l$ac_lib ++ LIBS="-l$ac_lib $ac_func_search_save_LIBS" ++ fi ++ if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_search_kvm_open2=$ac_res ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext ++ if test "${ac_cv_search_kvm_open2+set}" = set; then : ++ break ++fi ++done ++if test "${ac_cv_search_kvm_open2+set}" = set; then : ++ ++else ++ ac_cv_search_kvm_open2=no ++fi ++rm conftest.$ac_ext ++LIBS=$ac_func_search_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_kvm_open2" >&5 ++$as_echo "$ac_cv_search_kvm_open2" >&6; } ++ac_res=$ac_cv_search_kvm_open2 ++if test "$ac_res" != no; then : ++ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" ++ ++$as_echo "#define HAVE_KVM_OPEN2 1" >>confdefs.h ++ ++fi ++ ++ + + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" +diff --git gdb/configure.ac gdb/configure.ac +index 1527585839..37e8ce54b0 100644 +--- gdb/configure.ac ++++ gdb/configure.ac +@@ -511,6 +511,11 @@ AC_SEARCH_LIBS(kinfo_getfile, util util-freebsd, + [AC_DEFINE(HAVE_KINFO_GETFILE, 1, + [Define to 1 if your system has the kinfo_getfile function. ])]) + ++# kgdb needs kvm_open2 for cross-debugging ++AC_SEARCH_LIBS(kvm_open2, kvm, ++ [AC_DEFINE(HAVE_KVM_OPEN2, 1, ++ [Define to 1 if your system has the kvm_open2 function. ])]) ++ + AM_ICONV + + # GDB may fork/exec the iconv program to get the list of supported character +diff --git gdb/configure.nat gdb/configure.nat +index 64ee101d83..f32e6328e0 100644 +--- gdb/configure.nat ++++ gdb/configure.nat +@@ -63,7 +63,8 @@ case ${gdb_host} in + LOADLIBES='-ldl $(RDYNAMIC)' + ;; + fbsd*) +- NATDEPFILES='fork-child.o nat/fork-inferior.o inf-ptrace.o fbsd-nat.o' ++ NATDEPFILES='fork-child.o nat/fork-inferior.o inf-ptrace.o fbsd-nat.o \ ++ fbsd-kvm.o' + HAVE_NATIVE_GCORE_HOST=1 + LOADLIBES='-lkvm' + ;; +diff --git gdb/configure.tgt gdb/configure.tgt +index 27f122ad04..5fa0d0179e 100644 +--- gdb/configure.tgt ++++ gdb/configure.tgt +@@ -98,7 +98,7 @@ esac + + case "${targ}" in + *-*-freebsd* | *-*-kfreebsd*-gnu) +- os_obs="fbsd-tdep.o solib-svr4.o";; ++ os_obs="fbsd-tdep.o solib-svr4.o fbsd-kld.o fbsd-kthr.o";; + *-*-netbsd* | *-*-knetbsd*-gnu) + os_obs="nbsd-tdep.o solib-svr4.o";; + *-*-openbsd*) +@@ -115,7 +115,7 @@ aarch64*-*-elf | aarch64*-*-rtems*) + + aarch64*-*-freebsd*) + # Target: FreeBSD/aarch64 +- gdb_target_obs="aarch64-fbsd-tdep.o" ++ gdb_target_obs="aarch64-fbsd-tdep.o aarch64-fbsd-kern.o" + ;; + + aarch64*-*-linux*) +@@ -168,7 +168,7 @@ arm*-*-linux*) + ;; + arm*-*-freebsd*) + # Target: FreeBSD/arm +- gdb_target_obs="arm-fbsd-tdep.o" ++ gdb_target_obs="arm-fbsd-tdep.o arm-fbsd-kern.o" + ;; + arm*-*-netbsd* | arm*-*-knetbsd*-gnu) + # Target: NetBSD/arm +@@ -267,7 +267,11 @@ i[34567]86-*-dicos*) + ;; + i[34567]86-*-freebsd* | i[34567]86-*-kfreebsd*-gnu) + # Target: FreeBSD/i386 +- gdb_target_obs="i386-bsd-tdep.o i386-fbsd-tdep.o " ++ gdb_target_obs="i386-bsd-tdep.o i386-fbsd-tdep.o i386fbsd-kern.o" ++ if test "x$enable_64_bit_bfd" = "xyes"; then ++ # Target: FreeBSD amd64 ++ gdb_target_obs="amd64fbsd-tdep.o amd64fbsd-kern.o ${gdb_target_obs}" ++ fi + ;; + i[34567]86-*-netbsd* | i[34567]86-*-knetbsd*-gnu) + # Target: NetBSD/i386 +@@ -421,7 +425,7 @@ mips*-*-netbsd* | mips*-*-knetbsd*-gnu) + ;; + mips*-*-freebsd*) + # Target: MIPS running FreeBSD +- gdb_target_obs="mips-tdep.o mips-fbsd-tdep.o" ++ gdb_target_obs="mips-tdep.o mips-fbsd-tdep.o mipsfbsd-kern.o" + gdb_sim=../sim/mips/libsim.a + ;; + mips64*-*-openbsd*) +@@ -488,7 +492,7 @@ or1k-*-* | or1knd-*-*) + powerpc*-*-freebsd*) + # Target: FreeBSD/powerpc + gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppc64-tdep.o \ +- ppc-fbsd-tdep.o \ ++ ppc-fbsd-tdep.o ppcfbsd-kern.o \ + ravenscar-thread.o ppc-ravenscar-thread.o" + ;; + +@@ -543,7 +547,7 @@ s390*-*-linux*) + + riscv*-*-freebsd*) + # Target: FreeBSD/riscv +- gdb_target_obs="riscv-fbsd-tdep.o" ++ gdb_target_obs="riscv-fbsd-tdep.o riscv-fbsd-kern.o" + ;; + + riscv*-*-linux*) +@@ -622,6 +626,7 @@ sparc64-*-linux*) + sparc*-*-freebsd* | sparc*-*-kfreebsd*-gnu) + # Target: FreeBSD/sparc64 + gdb_target_obs="sparc-tdep.o sparc64-tdep.o sparc64-fbsd-tdep.o \ ++ sparc64fbsd-kern.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" + ;; + sparc-*-netbsd* | sparc-*-knetbsd*-gnu) +@@ -749,8 +754,8 @@ x86_64-*-linux*) + ;; + x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) + # Target: FreeBSD/amd64 +- gdb_target_obs="amd64-fbsd-tdep.o ${i386_tobjs} \ +- i386-bsd-tdep.o i386-fbsd-tdep.o" ++ gdb_target_obs="amd64-fbsd-tdep.o amd64fbsd-kern.o ${i386_tobjs} \ ++ i386-bsd-tdep.o i386-fbsd-tdep.o i386fbsd-kern.o" + ;; + x86_64-*-mingw* | x86_64-*-cygwin*) + # Target: MingW/amd64 +diff --git gdb/defs.h gdb/defs.h +index a44e186907..c4bfd42073 100644 +--- gdb/defs.h ++++ gdb/defs.h +@@ -484,6 +484,7 @@ enum gdb_osabi + GDB_OSABI_SOLARIS, + GDB_OSABI_LINUX, + GDB_OSABI_FREEBSD, ++ GDB_OSABI_FREEBSD_KERNEL, + GDB_OSABI_NETBSD, + GDB_OSABI_OPENBSD, + GDB_OSABI_WINCE, +diff --git gdb/gnulib/configure gdb/gnulib/configure +index 340c622cb3..bf0c4dd5d9 100644 +--- gdb/gnulib/configure ++++ gdb/gnulib/configure +@@ -18579,6 +18579,7 @@ else + case "$host_os" in + # Guess all is fine on glibc systems. + *-gnu*) gl_cv_func_gettimeofday_clobber="guessing no" ;; ++ freebsd*) gl_cv_func_gettimeofday_clobber="guessing no" ;; + # If we don't know, assume the worst. + *) gl_cv_func_gettimeofday_clobber="guessing yes" ;; + esac +diff --git gdb/osabi.c gdb/osabi.c +index 5d4bbcdff8..a982b22624 100644 +--- gdb/osabi.c ++++ gdb/osabi.c +@@ -66,6 +66,7 @@ static const struct osabi_names gdb_osabi_names[] = + { "Solaris", NULL }, + { "GNU/Linux", "linux(-gnu[^-]*)?" }, + { "FreeBSD", NULL }, ++ { "FreeBSD/kernel", NULL }, + { "NetBSD", NULL }, + { "OpenBSD", NULL }, + { "WindowsCE", NULL }, +diff --git gdb/regcache.c gdb/regcache.c +index 6e3eee9663..49ca1e1535 100644 +--- gdb/regcache.c ++++ gdb/regcache.c +@@ -1003,6 +1003,22 @@ reg_buffer::raw_supply_zeroed (int regnum) + m_register_status[regnum] = REG_VALID; + } + ++void ++reg_buffer::raw_supply_unsigned (int regnum, ULONGEST val) ++{ ++ enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch); ++ gdb_byte *regbuf; ++ size_t regsize; ++ ++ assert_regnum (regnum); ++ ++ regbuf = register_buffer (regnum); ++ regsize = m_descr->sizeof_register[regnum]; ++ ++ store_unsigned_integer (regbuf, regsize, byte_order, val); ++ m_register_status[regnum] = REG_VALID; ++} ++ + /* See common/common-regcache.h. */ + + void +diff --git gdb/regcache.h gdb/regcache.h +index 2b703ea4a4..d06e001957 100644 +--- gdb/regcache.h ++++ gdb/regcache.h +@@ -224,6 +224,8 @@ public: + only LEN, without editing the rest of the register. */ + void raw_supply_part (int regnum, int offset, int len, const gdb_byte *in); + ++ void raw_supply_unsigned (int regnum, ULONGEST val); ++ + void invalidate (int regnum); + + virtual ~reg_buffer () = default; diff --git a/devel/gdb/files/kgdb/aarch64-fbsd-kern.c b/devel/gdb/files/kgdb/aarch64-fbsd-kern.c new file mode 100644 index 00000000..0831be8f --- /dev/null +++ b/devel/gdb/files/kgdb/aarch64-fbsd-kern.c @@ -0,0 +1,201 @@ +/*- + * Copyright (c) 2017 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/devel/gdb/files/kgdb/aarch64-fbsd-kern.c 503200 2019-06-01 00:44:08Z jhb $ + */ + +/* Target-dependent code for FreeBSD/aarch64 kernels. */ + +#include "defs.h" + +#include "aarch64-tdep.h" +#include "frame-unwind.h" +#include "gdbcore.h" +#include "osabi.h" +#include "regcache.h" +#include "regset.h" +#include "solib.h" +#include "target.h" +#include "trad-frame.h" + +#include "kgdb.h" + +static const struct regcache_map_entry aarch64_fbsd_pcbmap[] = + { + { 30, AARCH64_X0_REGNUM, 8 }, /* x0 ... x29 */ + { 1, AARCH64_PC_REGNUM, 8 }, + { 1, REGCACHE_MAP_SKIP, 8 }, + { 1, AARCH64_SP_REGNUM, 8 }, + { 0 } + }; + +static const struct regset aarch64_fbsd_pcbregset = + { + aarch64_fbsd_pcbmap, + regcache_supply_regset, regcache_collect_regset + }; + +static void +aarch64_fbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr) +{ + gdb_byte buf[8 * 33]; + + if (target_read_memory (pcb_addr, buf, sizeof buf) == 0) + regcache_supply_regset (&aarch64_fbsd_pcbregset, regcache, -1, buf, + sizeof (buf)); +} + +static struct trad_frame_cache * +aarch64_fbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct trad_frame_cache *cache; + CORE_ADDR func, pc, sp; + const char *name; + int i; + + if (*this_cache != NULL) + return ((struct trad_frame_cache *)*this_cache); + + cache = trad_frame_cache_zalloc (this_frame); + *this_cache = cache; + + func = get_frame_func (this_frame); + sp = get_frame_register_unsigned (this_frame, AARCH64_SP_REGNUM); + + find_pc_partial_function (func, &name, NULL, NULL); + if (strcmp(name, "fork_trampoline") == 0 && get_frame_pc (this_frame) == func) + { + /* fork_exit hasn't been called (kthread has never run), so SP + hasn't been initialized yet. The stack pointer is stored in + the X2 in the pcb. */ + sp = get_frame_register_unsigned (this_frame, AARCH64_X0_REGNUM + 2); + } + + trad_frame_set_reg_addr (cache, AARCH64_SP_REGNUM, sp); + trad_frame_set_reg_addr (cache, AARCH64_LR_REGNUM, sp + 8); + trad_frame_set_reg_addr (cache, AARCH64_PC_REGNUM, sp + 16); + trad_frame_set_reg_addr (cache, AARCH64_CPSR_REGNUM, sp + 24); + for (i = 0; i < 30; i++) + trad_frame_set_reg_addr (cache, AARCH64_X0_REGNUM + i, sp + 32 + i * 8); + + /* Read $PC from trap frame. */ + pc = read_memory_unsigned_integer (sp + 16, 8, byte_order); + + if (pc == 0 && strcmp(name, "fork_trampoline") == 0) + { + /* Initial frame of a kthread; terminate backtrace. */ + trad_frame_set_id (cache, outer_frame_id); + } + else + { + /* Construct the frame ID using the function start. */ + trad_frame_set_id (cache, frame_id_build (sp + 8 * 34, func)); + } + + return cache; +} + +static void +aarch64_fbsd_trapframe_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + struct trad_frame_cache *cache = + aarch64_fbsd_trapframe_cache (this_frame, this_cache); + + trad_frame_get_id (cache, this_id); +} + +static struct value * +aarch64_fbsd_trapframe_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct trad_frame_cache *cache = + aarch64_fbsd_trapframe_cache (this_frame, this_cache); + + return trad_frame_get_register (cache, this_frame, regnum); +} + +static int +aarch64_fbsd_trapframe_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + const char *name; + + find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL); + return (name && ((strcmp (name, "handle_el1h_sync") == 0) + || (strcmp (name, "handle_el1h_irq") == 0) + || (strcmp (name, "handle_el0_sync") == 0) + || (strcmp (name, "handle_el0_irq") == 0) + || (strcmp (name, "handle_el0_error") == 0) + || (strcmp (name, "fork_trampoline") == 0))); +} + +static const struct frame_unwind aarch64_fbsd_trapframe_unwind = { + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + aarch64_fbsd_trapframe_this_id, + aarch64_fbsd_trapframe_prev_register, + NULL, + aarch64_fbsd_trapframe_sniffer +}; + +/* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ + +static void +aarch64_fbsd_kernel_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + frame_unwind_prepend_unwinder (gdbarch, &aarch64_fbsd_trapframe_unwind); + + set_solib_ops (gdbarch, &kld_so_ops); + + /* Enable longjmp. */ + tdep->jb_pc = 13; + + fbsd_vmcore_set_supply_pcb (gdbarch, aarch64_fbsd_supply_pcb); + fbsd_vmcore_set_cpu_pcb_addr (gdbarch, kgdb_trgt_stop_pcb); + + /* The kernel is linked at a virtual address with the upper 4 bits + set, so all 64 bits of virtual addresses need to be treated as + significant. */ + set_gdbarch_significant_addr_bit (gdbarch, 64); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_aarch64_kgdb_tdep; + +void +_initialize_aarch64_kgdb_tdep (void) +{ + gdbarch_register_osabi_sniffer(bfd_arch_aarch64, + bfd_target_elf_flavour, + fbsd_kernel_osabi_sniffer); + gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_FREEBSD_KERNEL, + aarch64_fbsd_kernel_init_abi); +} diff --git a/devel/gdb/files/kgdb/amd64fbsd-kern.c b/devel/gdb/files/kgdb/amd64fbsd-kern.c new file mode 100644 index 00000000..ecf1f5b0 --- /dev/null +++ b/devel/gdb/files/kgdb/amd64fbsd-kern.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2004 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: head/devel/gdb/files/kgdb/amd64fbsd-kern.c 503200 2019-06-01 00:44:08Z jhb $"); + +#include "defs.h" +#include "frame-unwind.h" +#include "gdbcore.h" +#include "osabi.h" +#include "regcache.h" +#include "solib.h" +#include "stack.h" +#include "symtab.h" +#include "trad-frame.h" +#include "amd64-tdep.h" +#include "common/x86-xstate.h" + +#ifdef __amd64__ +#include +#include +#endif + +#include "kgdb.h" + +static const int amd64fbsd_pcb_offset[] = { + -1, /* %rax */ + 6 * 8, /* %rbx */ + -1, /* %rcx */ + -1, /* %rdx */ + -1, /* %rsi */ + -1, /* %rdi */ + 4 * 8, /* %rbp */ + 5 * 8, /* %rsp */ + -1, /* %r8 ... */ + -1, + -1, + -1, + 3 * 8, + 2 * 8, + 1 * 8, + 0 * 8, /* ... %r15 */ + 7 * 8, /* %rip */ + -1, /* %eflags */ + -1, /* %cs */ + -1, /* %ss */ + -1, /* %ds */ + -1, /* %es */ + -1, /* %fs */ + -1 /* %gs */ +}; + +#define CODE_SEL (4 << 3) +#define DATA_SEL (5 << 3) + +static void +amd64fbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr) +{ + gdb_byte buf[8]; + int i; + + memset(buf, 0, sizeof(buf)); + + /* + * XXX The PCB may have been swapped out. Supply a dummy %rip value + * so as to avoid triggering an exception during stack unwinding. + */ + regcache->raw_supply(AMD64_RIP_REGNUM, buf); + for (i = 0; i < ARRAY_SIZE (amd64fbsd_pcb_offset); i++) + if (amd64fbsd_pcb_offset[i] != -1) { + if (target_read_memory(pcb_addr + amd64fbsd_pcb_offset[i], buf, + sizeof buf) != 0) + continue; + regcache->raw_supply(i, buf); + } + + regcache->raw_supply_unsigned(AMD64_CS_REGNUM, CODE_SEL); + regcache->raw_supply_unsigned(AMD64_SS_REGNUM, DATA_SEL); +} + +static const int amd64fbsd_trapframe_offset[] = { + 6 * 8, /* %rax */ + 7 * 8, /* %rbx */ + 3 * 8, /* %rcx */ + 2 * 8, /* %rdx */ + 1 * 8, /* %rsi */ + 0 * 8, /* %rdi */ + 8 * 8, /* %rbp */ + 22 * 8, /* %rsp */ + 4 * 8, /* %r8 ... */ + 5 * 8, + 9 * 8, + 10 * 8, + 11 * 8, + 12 * 8, + 13 * 8, + 14 * 8, /* ... %r15 */ + 19 * 8, /* %rip */ + 21 * 8, /* %eflags */ + 20 * 8, /* %cs */ + 23 * 8, /* %ss */ + -1, /* %ds */ + -1, /* %es */ + -1, /* %fs */ + -1 /* %gs */ +}; + +#define TRAPFRAME_SIZE 192 + +static struct trad_frame_cache * +amd64fbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct trad_frame_cache *cache; + CORE_ADDR addr, func, pc, sp; + const char *name; + int i; + + if (*this_cache != NULL) + return ((struct trad_frame_cache *)*this_cache); + + cache = trad_frame_cache_zalloc (this_frame); + *this_cache = cache; + + func = get_frame_func (this_frame); + sp = get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM); + + find_pc_partial_function (func, &name, NULL, NULL); + if (strcmp(name, "fork_trampoline") == 0 && get_frame_pc (this_frame) == func) + { + /* fork_exit hasn't been called (kthread has never run), so %rsp + in the pcb points to the trapframe. GDB has auto-adjusted + %rsp for this frame to account for the "call" into + fork_trampoline, so "undo" the adjustment. */ + sp += 8; + } + + for (i = 0; i < ARRAY_SIZE (amd64fbsd_trapframe_offset); i++) + if (amd64fbsd_trapframe_offset[i] != -1) + trad_frame_set_reg_addr (cache, i, sp + amd64fbsd_trapframe_offset[i]); + + /* Read %rip from trap frame. */ + addr = sp + amd64fbsd_trapframe_offset[AMD64_RIP_REGNUM]; + pc = read_memory_unsigned_integer (addr, 8, byte_order); + + if (pc == 0 && strcmp(name, "fork_trampoline") == 0) + { + /* Initial frame of a kthread; terminate backtrace. */ + trad_frame_set_id (cache, outer_frame_id); + } + else + { + /* Construct the frame ID using the function start. */ + trad_frame_set_id (cache, frame_id_build (sp + TRAPFRAME_SIZE, func)); + } + + return cache; +} + +static void +amd64fbsd_trapframe_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + struct trad_frame_cache *cache = + amd64fbsd_trapframe_cache (this_frame, this_cache); + + trad_frame_get_id (cache, this_id); +} + +static struct value * +amd64fbsd_trapframe_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct trad_frame_cache *cache = + amd64fbsd_trapframe_cache (this_frame, this_cache); + + return trad_frame_get_register (cache, this_frame, regnum); +} + +static int +amd64fbsd_trapframe_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + const char *name; + + find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL); + return (name && ((strcmp (name, "calltrap") == 0) + || (strcmp (name, "fast_syscall_common") == 0) + || (strcmp (name, "fork_trampoline") == 0) + || (strcmp (name, "mchk_calltrap") == 0) + || (strcmp (name, "nmi_calltrap") == 0) + || (name[0] == 'X' && name[1] != '_'))); +} + +static const struct frame_unwind amd64fbsd_trapframe_unwind = { + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + amd64fbsd_trapframe_this_id, + amd64fbsd_trapframe_prev_register, + NULL, + amd64fbsd_trapframe_sniffer +}; + +static void +amd64fbsd_kernel_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch) +{ + + amd64_init_abi(info, gdbarch, + amd64_target_description (X86_XSTATE_SSE_MASK, true)); + + frame_unwind_prepend_unwinder(gdbarch, &amd64fbsd_trapframe_unwind); + + set_solib_ops(gdbarch, &kld_so_ops); + + fbsd_vmcore_set_supply_pcb(gdbarch, amd64fbsd_supply_pcb); + fbsd_vmcore_set_cpu_pcb_addr(gdbarch, kgdb_trgt_stop_pcb); +} + +void +_initialize_amd64_kgdb_tdep(void) +{ + gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, + GDB_OSABI_FREEBSD_KERNEL, amd64fbsd_kernel_init_abi); + +#ifdef __amd64__ + gdb_assert(offsetof(struct pcb, pcb_rbx) + == amd64fbsd_pcb_offset[AMD64_RBX_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_rbp) + == amd64fbsd_pcb_offset[AMD64_RBP_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_rsp) + == amd64fbsd_pcb_offset[AMD64_RSP_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_r12) + == amd64fbsd_pcb_offset[AMD64_R12_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_r13) + == amd64fbsd_pcb_offset[AMD64_R13_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_r14) + == amd64fbsd_pcb_offset[AMD64_R14_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_r15) + == amd64fbsd_pcb_offset[AMD64_R15_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_rip) + == amd64fbsd_pcb_offset[AMD64_RIP_REGNUM]); + gdb_assert(CODE_SEL == GSEL(GCODE_SEL, SEL_KPL)); + gdb_assert(DATA_SEL == GSEL(GDATA_SEL, SEL_KPL)); + gdb_assert(sizeof(struct trapframe) == TRAPFRAME_SIZE); + gdb_assert(offsetof(struct trapframe, tf_rax) + == amd64fbsd_trapframe_offset[AMD64_RAX_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_rbx) + == amd64fbsd_trapframe_offset[AMD64_RBX_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_rcx) + == amd64fbsd_trapframe_offset[AMD64_RCX_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_rdx) + == amd64fbsd_trapframe_offset[AMD64_RDX_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_rsi) + == amd64fbsd_trapframe_offset[AMD64_RSI_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_rdi) + == amd64fbsd_trapframe_offset[AMD64_RDI_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_rbp) + == amd64fbsd_trapframe_offset[AMD64_RBP_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_rsp) + == amd64fbsd_trapframe_offset[AMD64_RSP_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_r8) + == amd64fbsd_trapframe_offset[AMD64_R8_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_r9) + == amd64fbsd_trapframe_offset[AMD64_R9_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_r10) + == amd64fbsd_trapframe_offset[AMD64_R10_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_r11) + == amd64fbsd_trapframe_offset[AMD64_R11_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_r12) + == amd64fbsd_trapframe_offset[AMD64_R12_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_r13) + == amd64fbsd_trapframe_offset[AMD64_R13_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_r14) + == amd64fbsd_trapframe_offset[AMD64_R14_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_r15) + == amd64fbsd_trapframe_offset[AMD64_R15_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_rip) + == amd64fbsd_trapframe_offset[AMD64_RIP_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_rflags) + == amd64fbsd_trapframe_offset[AMD64_EFLAGS_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_cs) + == amd64fbsd_trapframe_offset[AMD64_CS_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_ss) + == amd64fbsd_trapframe_offset[AMD64_SS_REGNUM]); +#endif +} diff --git a/devel/gdb/files/kgdb/arm-fbsd-kern.c b/devel/gdb/files/kgdb/arm-fbsd-kern.c new file mode 100644 index 00000000..8516ced3 --- /dev/null +++ b/devel/gdb/files/kgdb/arm-fbsd-kern.c @@ -0,0 +1,199 @@ +/*- + * Copyright (c) 2018 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/devel/gdb/files/kgdb/arm-fbsd-kern.c 475318 2018-07-25 17:28:36Z jhb $ + */ + +/* Target-dependent code for FreeBSD/arm kernels. */ + +#include "defs.h" + +#include "arm-tdep.h" +#include "frame-unwind.h" +#include "gdbcore.h" +#include "osabi.h" +#include "regcache.h" +#include "regset.h" +#include "solib.h" +#include "target.h" +#include "trad-frame.h" + +#include "kgdb.h" + +static const struct regcache_map_entry arm_fbsd_pcbmap[] = + { + { 9, 4, 4 }, /* r4 ... r12 */ + { 1, ARM_SP_REGNUM, 4 }, + { 1, ARM_LR_REGNUM, 4 }, + { 1, ARM_PC_REGNUM, 4 }, + { 0 } + }; + +static const struct regset arm_fbsd_pcbregset = + { + arm_fbsd_pcbmap, + regcache_supply_regset, regcache_collect_regset + }; + +static void +arm_fbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr) +{ + gdb_byte buf[4 * 12]; + + if (target_read_memory (pcb_addr, buf, sizeof buf) == 0) + regcache->supply_regset (&arm_fbsd_pcbregset, -1, buf, sizeof (buf)); + + /* + * XXX: This is a gross hack, but the ARM frame unwinders need the value + * of xPSR to determine if Thumb mode is active. FreeBSD's kernels never + * use Thumb. + */ + regcache->raw_supply_unsigned(ARM_PS_REGNUM, 0); +} + +static struct trad_frame_cache * +arm_fbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct trad_frame_cache *cache; + CORE_ADDR addr, func, pc, sp; + const char *name; + int i; + + if (*this_cache != NULL) + return ((struct trad_frame_cache *)*this_cache); + + cache = trad_frame_cache_zalloc (this_frame); + *this_cache = cache; + + func = get_frame_func (this_frame); + sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); + + find_pc_partial_function (func, &name, NULL, NULL); + + for (i = 0; i <= 12; i++) + trad_frame_set_reg_addr (cache, ARM_A1_REGNUM + i, sp + 4 + i * 4); + trad_frame_set_reg_addr (cache, ARM_SP_REGNUM, sp + 14 * 4); + trad_frame_set_reg_addr (cache, ARM_LR_REGNUM, sp + 15 * 4); + trad_frame_set_reg_addr (cache, ARM_PC_REGNUM, sp + 18 * 4); + trad_frame_set_reg_addr (cache, ARM_PS_REGNUM, sp); + + /* Read $PC from trap frame. */ + pc = read_memory_unsigned_integer (sp + 18 * 4, 4, byte_order); + + if (pc == 0 && strcmp(name, "swi_entry") == 0) + { + /* Initial frame of a kthread; terminate backtrace. */ + trad_frame_set_id (cache, outer_frame_id); + } + else + { + /* Construct the frame ID using the function start. */ + trad_frame_set_id (cache, frame_id_build (sp + 4 * 19, func)); + } + + return cache; +} + +static void +arm_fbsd_trapframe_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + struct trad_frame_cache *cache = + arm_fbsd_trapframe_cache (this_frame, this_cache); + + trad_frame_get_id (cache, this_id); +} + +static struct value * +arm_fbsd_trapframe_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct trad_frame_cache *cache = + arm_fbsd_trapframe_cache (this_frame, this_cache); + + return trad_frame_get_register (cache, this_frame, regnum); +} + +static int +arm_fbsd_trapframe_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + const char *name; + + find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL); + return (name && ((strcmp (name, "data_abort_entry") == 0) + || (strcmp (name, "prefetch_abort_entry") == 0) + || (strcmp (name, "undefined_entry") == 0) + || (strcmp (name, "exception_exit") == 0) + || (strcmp (name, "irq_entry") == 0) + || (strcmp (name, "swi_entry") == 0) + || (strcmp (name, "swi_exit") == 0))); +} + +static const struct frame_unwind arm_fbsd_trapframe_unwind = { + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + arm_fbsd_trapframe_this_id, + arm_fbsd_trapframe_prev_register, + NULL, + arm_fbsd_trapframe_sniffer +}; + +/* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ + +static void +arm_fbsd_kernel_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + frame_unwind_prepend_unwinder (gdbarch, &arm_fbsd_trapframe_unwind); + + set_solib_ops (gdbarch, &kld_so_ops); + + tdep->jb_pc = 24; + tdep->jb_elt_size = 4; + + fbsd_vmcore_set_supply_pcb (gdbarch, arm_fbsd_supply_pcb); + fbsd_vmcore_set_cpu_pcb_addr (gdbarch, kgdb_trgt_stop_pcb); + + /* Single stepping. */ + set_gdbarch_software_single_step (gdbarch, arm_software_single_step); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_arm_kgdb_tdep; + +void +_initialize_arm_kgdb_tdep (void) +{ + gdbarch_register_osabi_sniffer(bfd_arch_arm, + bfd_target_elf_flavour, + fbsd_kernel_osabi_sniffer); + gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_FREEBSD_KERNEL, + arm_fbsd_kernel_init_abi); +} diff --git a/devel/gdb/files/kgdb/fbsd-kld.c b/devel/gdb/files/kgdb/fbsd-kld.c new file mode 100644 index 00000000..ed481c4c --- /dev/null +++ b/devel/gdb/files/kgdb/fbsd-kld.c @@ -0,0 +1,571 @@ +/* + * Copyright (c) 2004 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: head/devel/gdb/files/kgdb/fbsd-kld.c 503200 2019-06-01 00:44:08Z jhb $"); + +#include "defs.h" +#include "command.h" +#include "completer.h" +#include "environ.h" +#include "exec.h" +#include "frame-unwind.h" +#include "inferior.h" +#include "objfiles.h" +#include "gdbcore.h" +#include "language.h" +#include "solib.h" +#include "solist.h" + +#include "kgdb.h" + +struct lm_info_kld : public lm_info_base { + CORE_ADDR base_address; +}; + +struct kld_info { + /* Offsets of fields in linker_file structure. */ + CORE_ADDR off_address, off_filename, off_pathname, off_next; + + /* KVA of 'linker_path' which corresponds to the kern.module_path sysctl .*/ + CORE_ADDR module_path_addr; + CORE_ADDR linker_files_addr; + CORE_ADDR kernel_file_addr; +}; + +struct target_so_ops kld_so_ops; + +/* Per-program-space data key. */ +static const struct program_space_data *kld_pspace_data; + +static void +kld_pspace_data_cleanup (struct program_space *pspace, void *arg) +{ + struct kld_info *info = (struct kld_info *)arg; + + xfree (info); +} + +/* Get the current kld data. If none is found yet, add it now. This + function always returns a valid object. */ + +static struct kld_info * +get_kld_info (void) +{ + struct kld_info *info; + + info = (struct kld_info *) + program_space_data (current_program_space, kld_pspace_data); + if (info != NULL) + return info; + + info = XCNEW (struct kld_info); + set_program_space_data (current_program_space, kld_pspace_data, info); + return info; +} + +static int +kld_ok (char *path) +{ + struct stat sb; + + if (stat(path, &sb) == 0 && S_ISREG(sb.st_mode)) + return (1); + return (0); +} + +/* + * Look for a matching file checking for debug suffixes before the raw file: + * - filename + ".debug" (e.g. foo.ko.debug) + * - filename (e.g. foo.ko) + */ +static const char *kld_suffixes[] = { + ".debug", + ".symbols", + "", + NULL +}; + +static int +check_kld_path (char *path, size_t path_size) +{ + const char **suffix; + char *ep; + + ep = path + strlen(path); + suffix = kld_suffixes; + while (*suffix != NULL) { + if (strlcat(path, *suffix, path_size) < path_size) { + if (kld_ok(path)) + return (1); + } + + /* Restore original path to remove suffix. */ + *ep = '\0'; + suffix++; + } + return (0); +} + +/* + * Try to find the path for a kld by looking in the kernel's directory and + * in the various paths in the module path. + */ +static int +find_kld_path (const char *filename, char *path, size_t path_size) +{ + struct kld_info *info; + gdb::unique_xmalloc_ptr module_path; + char *module_dir, *cp; + int error; + + info = get_kld_info(); + if (exec_bfd) { + std::string kernel_dir = ldirname(bfd_get_filename(exec_bfd)); + if (!kernel_dir.empty()) { + snprintf(path, path_size, "%s/%s", kernel_dir.c_str(), + filename); + if (check_kld_path(path, path_size)) + return (1); + } + } + if (info->module_path_addr != 0) { + target_read_string(info->module_path_addr, &module_path, + PATH_MAX, &error); + if (error == 0) { + cp = module_path.get(); + while ((module_dir = strsep(&cp, ";")) != NULL) { + snprintf(path, path_size, "%s/%s", module_dir, + filename); + if (check_kld_path(path, path_size)) + return (1); + } + } + } + return (0); +} + +/* + * Read a kernel pointer given a KVA in 'address'. + */ +static CORE_ADDR +read_pointer (CORE_ADDR address) +{ + struct type *ptr_type; + gdb_byte ptr_buf[8]; + int arch_size; + + arch_size = bfd_get_arch_size (exec_bfd); + if (arch_size == -1) + return (0); + ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; + if (target_read_memory(address, ptr_buf, arch_size / 8) != 0) + return (0); + return (extract_typed_address (ptr_buf, ptr_type)); +} + +/* + * Try to find this kld in the kernel linker's list of linker files. + */ +static int +find_kld_address (const char *arg, CORE_ADDR *address) +{ + struct kld_info *info; + CORE_ADDR kld; + gdb::unique_xmalloc_ptr kld_filename; + const char *filename; + int error; + + info = get_kld_info(); + if (info->linker_files_addr == 0 || info->off_address == 0 || + info->off_filename == 0 || info->off_next == 0) + return (0); + + filename = lbasename(arg); + for (kld = read_pointer(info->linker_files_addr); kld != 0; + kld = read_pointer(kld + info->off_next)) { + /* Try to read this linker file's filename. */ + target_read_string(read_pointer(kld + info->off_filename), + &kld_filename, PATH_MAX, &error); + if (error) + continue; + + /* Compare this kld's filename against our passed in name. */ + if (strcmp(kld_filename.get(), filename) != 0) + continue; + + /* + * We found a match, use its address as the base + * address if we can read it. + */ + *address = read_pointer(kld + info->off_address); + if (*address == 0) + return (0); + return (1); + } + return (0); +} + +static void +adjust_section_address (struct target_section *sec, CORE_ADDR *curr_base) +{ + struct bfd_section *asect = sec->the_bfd_section; + bfd *abfd = asect->owner; + + if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) { + sec->addr += *curr_base; + sec->endaddr += *curr_base; + return; + } + + *curr_base = align_power(*curr_base, + bfd_get_section_alignment(abfd, asect)); + sec->addr = *curr_base; + sec->endaddr = sec->addr + bfd_section_size(abfd, asect); + *curr_base = sec->endaddr; +} + +static void +load_kld (char *path, CORE_ADDR base_addr, int from_tty) +{ + struct target_section *sections = NULL, *sections_end = NULL, *s; + struct cleanup *cleanup; + gdb_bfd_ref_ptr bfd; + CORE_ADDR curr_addr; + symfile_add_flags add_flags; + int i; + + /* Open the kld. */ + bfd = gdb_bfd_openr(path, gnutarget); + if (bfd == NULL) + error("\"%s\": can't open: %s", path, + bfd_errmsg(bfd_get_error())); + + if (!bfd_check_format(bfd.get(), bfd_object)) + error("\%s\": not an object file", path); + + /* Make sure we have a .text section. */ + if (bfd_get_section_by_name (bfd.get(), ".text") == NULL) + error("\"%s\": can't find text section", path); + + /* Build a section table from the bfd and relocate the sections. */ + if (build_section_table (bfd.get(), §ions, §ions_end)) + error("\"%s\": can't find file sections", path); + cleanup = make_cleanup(xfree, sections); + curr_addr = base_addr; + for (s = sections; s < sections_end; s++) + adjust_section_address(s, &curr_addr); + + /* Build a section addr info to pass to symbol_file_add(). */ + section_addr_info sap + = build_section_addr_info_from_section_table (sections, + sections_end); + + printf_unfiltered("add symbol table from file \"%s\" at\n", path); + for (i = 0; i < sap.size(); i++) + printf_unfiltered("\t%s_addr = %s\n", sap[i].name.c_str(), + paddress(target_gdbarch(), sap[i].addr)); + + if (from_tty && (!query("%s", ""))) + error("Not confirmed."); + + add_flags = 0; + if (from_tty) + add_flags |= SYMFILE_VERBOSE; + symbol_file_add_from_bfd(bfd.get(), path, add_flags, &sap, + OBJF_USERLOADED, NULL); + + do_cleanups(cleanup); +} + +static void +kgdb_add_kld_cmd (const char *arg, int from_tty) +{ + char path[PATH_MAX]; + CORE_ADDR base_addr; + + if (!exec_bfd) + error("No kernel symbol file"); + + /* Try to open the raw path to handle absolute paths first. */ + snprintf(path, sizeof(path), "%s", arg); + if (!check_kld_path(path, sizeof(path))) { + + /* + * If that didn't work, look in the various possible + * paths for the module. + */ + if (!find_kld_path(arg, path, sizeof(path))) { + error("Unable to locate kld"); + return; + } + } + + if (!find_kld_address(arg, &base_addr)) { + error("Unable to find kld in kernel"); + return; + } + + load_kld(path, base_addr, from_tty); + + reinit_frame_cache(); +} + +static void +kld_relocate_section_addresses (struct so_list *so, struct target_section *sec) +{ + lm_info_kld *li = (lm_info_kld *) so->lm_info; + static CORE_ADDR curr_addr; + + if (sec == so->sections) + curr_addr = li->base_address; + + adjust_section_address(sec, &curr_addr); +} + +static void +kld_free_so (struct so_list *so) +{ + lm_info_kld *li = (lm_info_kld *) so->lm_info; + + delete li; +} + +static void +kld_clear_so (struct so_list *so) +{ + lm_info_kld *li = (lm_info_kld *) so->lm_info; + + if (li != NULL) + li->base_address = 0; +} + +static void +kld_clear_solib (void) +{ + struct kld_info *info; + + info = get_kld_info(); + + memset(info, 0, sizeof(*info)); +} + +static void +kld_solib_create_inferior_hook (int from_tty) +{ + struct kld_info *info; + + info = get_kld_info(); + + /* + * Compute offsets of relevant members in struct linker_file + * and the addresses of global variables. Newer kernels + * include constants we can use without requiring debug + * symbols. If those aren't present, fall back to using + * home-grown offsetof() equivalents. + */ + TRY { + info->off_address = parse_and_eval_long("kld_off_address"); + info->off_filename = parse_and_eval_long("kld_off_filename"); + info->off_pathname = parse_and_eval_long("kld_off_pathname"); + info->off_next = parse_and_eval_long("kld_off_next"); + } CATCH(e, RETURN_MASK_ERROR) { + TRY { + info->off_address = parse_and_eval_address( + "&((struct linker_file *)0)->address"); + info->off_filename = parse_and_eval_address( + "&((struct linker_file *)0)->filename"); + info->off_pathname = parse_and_eval_address( + "&((struct linker_file *)0)->pathname"); + info->off_next = parse_and_eval_address( + "&((struct linker_file *)0)->link.tqe_next"); + } CATCH(e2, RETURN_MASK_ERROR) { + return; + } + END_CATCH + } + END_CATCH + + TRY { + info->module_path_addr = parse_and_eval_address("linker_path"); + info->linker_files_addr = kgdb_lookup("linker_files"); + info->kernel_file_addr = kgdb_lookup("linker_kernel_file"); + } CATCH(e, RETURN_MASK_ERROR) { + return; + } + END_CATCH + + solib_add(NULL, from_tty, auto_solib_add); +} + +static struct so_list * +kld_current_sos (void) +{ + struct so_list *head, **prev, *newobj; + struct kld_info *info; + CORE_ADDR kld, kernel; + gdb::unique_xmalloc_ptr path; + int error; + + info = get_kld_info(); + if (info->linker_files_addr == 0 || info->kernel_file_addr == 0 || + info->off_address == 0 || info->off_filename == 0 || + info->off_next == 0) + return (NULL); + + head = NULL; + prev = &head; + + /* + * Walk the list of linker files creating so_list entries for + * each non-kernel file. + */ + kernel = read_pointer(info->kernel_file_addr); + for (kld = read_pointer(info->linker_files_addr); kld != 0; + kld = read_pointer(kld + info->off_next)) { + /* Skip the main kernel file. */ + if (kld == kernel) + continue; + + newobj = XCNEW (struct so_list); + + lm_info_kld *li = new lm_info_kld; + li->base_address = 0; + + newobj->lm_info = li; + + /* Read the base filename and store it in so_original_name. */ + target_read_string(read_pointer(kld + info->off_filename), + &path, sizeof(newobj->so_original_name), &error); + if (error != 0) { + warning("kld_current_sos: Can't read filename: %s\n", + safe_strerror(error)); + free_so(newobj); + continue; + } + strlcpy(newobj->so_original_name, path.get(), + sizeof(newobj->so_original_name)); + + /* + * Try to read the pathname (if it exists) and store + * it in so_name. + */ + if (find_kld_path(newobj->so_original_name, newobj->so_name, + sizeof(newobj->so_name))) { + /* we found the kld */; + } else if (info->off_pathname != 0) { + target_read_string(read_pointer(kld + + info->off_pathname), + &path, sizeof(newobj->so_name), &error); + if (error != 0) { + warning( + "kld_current_sos: Can't read pathname for \"%s\": %s\n", + newobj->so_original_name, + safe_strerror(error)); + strlcpy(newobj->so_name, newobj->so_original_name, + sizeof(newobj->so_name)); + } else { + strlcpy(newobj->so_name, path.get(), + sizeof(newobj->so_name)); + } + } else + strlcpy(newobj->so_name, newobj->so_original_name, + sizeof(newobj->so_name)); + + /* Read this kld's base address. */ + li->base_address = read_pointer(kld + info->off_address); + if (li->base_address == 0) { + warning( + "kld_current_sos: Invalid address for kld \"%s\"", + newobj->so_original_name); + free_so(newobj); + continue; + } + + /* Append to the list. */ + *prev = newobj; + prev = &newobj->next; + } + + return (head); +} + +static int +kld_open_symbol_file_object (int from_tty) +{ + + return (0); +} + +static int +kld_in_dynsym_resolve_code (CORE_ADDR pc) +{ + + return (0); +} + +static int +kld_find_and_open_solib (const char *solib, unsigned o_flags, + gdb::unique_xmalloc_ptr *temp_pathname) +{ + char path[PATH_MAX]; + int fd; + + temp_pathname->reset (NULL); + if (!find_kld_path(solib, path, sizeof(path))) { + errno = ENOENT; + return (-1); + } + fd = open(path, o_flags, 0); + if (fd >= 0) + temp_pathname->reset(xstrdup(path)); + return (fd); +} + +void +_initialize_kld_target(void) +{ + struct cmd_list_element *c; + + kld_so_ops.relocate_section_addresses = kld_relocate_section_addresses; + kld_so_ops.free_so = kld_free_so; + kld_so_ops.clear_so = kld_clear_so; + kld_so_ops.clear_solib = kld_clear_solib; + kld_so_ops.solib_create_inferior_hook = kld_solib_create_inferior_hook; + kld_so_ops.current_sos = kld_current_sos; + kld_so_ops.open_symbol_file_object = kld_open_symbol_file_object; + kld_so_ops.in_dynsym_resolve_code = kld_in_dynsym_resolve_code; + kld_so_ops.bfd_open = solib_bfd_open; + kld_so_ops.find_and_open_solib = kld_find_and_open_solib; + + c = add_com("add-kld", class_files, kgdb_add_kld_cmd, + "Usage: add-kld FILE\n\ +Load the symbols from the kernel loadable module FILE."); + set_cmd_completer(c, filename_completer); + + kld_pspace_data = register_program_space_data_with_cleanup (NULL, + kld_pspace_data_cleanup); +} diff --git a/devel/gdb/files/kgdb/fbsd-kthr.c b/devel/gdb/files/kgdb/fbsd-kthr.c new file mode 100644 index 00000000..2a8b52ba --- /dev/null +++ b/devel/gdb/files/kgdb/fbsd-kthr.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2004 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: head/devel/gdb/files/kgdb/fbsd-kthr.c 503436 2019-06-04 04:17:26Z glebius $"); + +#include +#include +#include + +#include +#include "gdbcore.h" +#include "objfiles.h" +#include "value.h" + +#include "kgdb.h" + +static CORE_ADDR dumppcb; +static LONGEST dumptid; + +static CORE_ADDR stopped_cpus; +static LONGEST mp_maxid; + +static struct kthr *first, *last; +struct kthr *curkthr; + +static int proc_off_p_pid, proc_off_p_comm, proc_off_p_list, proc_off_p_threads; +static int thread_off_td_tid, thread_off_td_oncpu, thread_off_td_pcb; +static int thread_off_td_name, thread_off_td_plist; +static int thread_oncpu_size; + +CORE_ADDR +kgdb_lookup(const char *sym) +{ + struct bound_minimal_symbol msym; + + msym = lookup_minimal_symbol(sym, NULL, NULL); + if (msym.minsym == NULL) + return (0); + return (BMSYMBOL_VALUE_ADDRESS(msym)); +} + +/* + * Perform the equivalent of CPU_ISSET() to see if 'cpu' is set in the + * kernel's stopped_cpus set. The set contains an array of longs. + * This function determines the specific long to read and tests the + * necessary bit in the long. + */ +static bool +cpu_stopped(int cpu) +{ + struct gdbarch *gdbarch = target_gdbarch (); + CORE_ADDR addr; + ULONGEST mask; + int bit, long_bytes, word; + + if (cpu < 0 || cpu > mp_maxid || stopped_cpus == 0) + return (false); + bit = cpu % gdbarch_long_bit (gdbarch); + word = cpu / gdbarch_long_bit (gdbarch); + long_bytes = gdbarch_long_bit (gdbarch) / 8; + addr = stopped_cpus + word * long_bytes; + mask = read_memory_unsigned_integer (addr, long_bytes, + gdbarch_byte_order (gdbarch)); + return (mask & ((ULONGEST)1 << bit)) != 0; +} + +struct kthr * +kgdb_thr_first(void) +{ + return (first); +} + +static void +kgdb_thr_add_procs(CORE_ADDR paddr, CORE_ADDR (*cpu_pcb_addr) (u_int)) +{ + struct gdbarch *gdbarch = target_gdbarch (); + struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr; + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct kthr *kt; + CORE_ADDR pcb, pnext, tdaddr, tdnext; + ULONGEST oncpu; + LONGEST pid, tid; + + while (paddr != 0) { + TRY { + tdaddr = read_memory_typed_address (paddr + + proc_off_p_threads, ptr_type); + pid = read_memory_integer (paddr + proc_off_p_pid, 4, + byte_order); + pnext = read_memory_typed_address (paddr + + proc_off_p_list, ptr_type); + } CATCH(e, RETURN_MASK_ERROR) { + break; + } END_CATCH + while (tdaddr != 0) { + TRY { + tid = read_memory_integer (tdaddr + + thread_off_td_tid, 4, byte_order); + oncpu = read_memory_unsigned_integer (tdaddr + + thread_off_td_oncpu, thread_oncpu_size, + byte_order); + pcb = read_memory_typed_address (tdaddr + + thread_off_td_pcb, ptr_type); + tdnext = read_memory_typed_address (tdaddr + + thread_off_td_plist, ptr_type); + } CATCH(e, RETURN_MASK_ERROR) { + break; + } END_CATCH + kt = XNEW (struct kthr); + if (last == NULL) + first = last = kt; + else + last->next = kt; + kt->next = NULL; + kt->kaddr = tdaddr; + if (tid == dumptid) + kt->pcb = dumppcb; + else if (cpu_stopped(oncpu)) + kt->pcb = cpu_pcb_addr(oncpu); + else + kt->pcb = pcb; + kt->tid = tid; + kt->pid = pid; + kt->paddr = paddr; + kt->cpu = oncpu; + last = kt; + tdaddr = tdnext; + } + paddr = pnext; + } +} + +struct kthr * +kgdb_thr_init(CORE_ADDR (*cpu_pcb_addr) (u_int)) +{ + struct gdbarch *gdbarch = target_gdbarch (); + struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr; + struct kthr *kt; + CORE_ADDR addr, paddr; + + while (first != NULL) { + kt = first; + first = kt->next; + free(kt); + } + last = NULL; + + addr = kgdb_lookup("allproc"); + if (addr == 0) + return (NULL); + TRY { + paddr = read_memory_typed_address (addr, ptr_type); + } CATCH(e, RETURN_MASK_ERROR) { + return (NULL); + } END_CATCH + + dumppcb = kgdb_lookup("dumppcb"); + if (dumppcb == 0) + return (NULL); + + TRY { + dumptid = parse_and_eval_long("dumptid"); + } CATCH(e, RETURN_MASK_ERROR) { + dumptid = -1; + } END_CATCH + + TRY { + mp_maxid = parse_and_eval_long("mp_maxid"); + } CATCH(e, RETURN_MASK_ERROR) { + mp_maxid = 0; + } END_CATCH + stopped_cpus = kgdb_lookup("stopped_cpus"); + + /* + * Newer kernels export a set of global variables with the offsets + * of certain members in struct proc and struct thread. For older + * kernels, try to extract these offsets using debug symbols. If + * that fails, use native values. + */ + TRY { + proc_off_p_pid = parse_and_eval_long("proc_off_p_pid"); + proc_off_p_comm = parse_and_eval_long("proc_off_p_comm"); + proc_off_p_list = parse_and_eval_long("proc_off_p_list"); + proc_off_p_threads = parse_and_eval_long("proc_off_p_threads"); + thread_off_td_tid = parse_and_eval_long("thread_off_td_tid"); + thread_off_td_name = parse_and_eval_long("thread_off_td_name"); + thread_off_td_oncpu = parse_and_eval_long("thread_off_td_oncpu"); + thread_off_td_pcb = parse_and_eval_long("thread_off_td_pcb"); + thread_off_td_plist = parse_and_eval_long("thread_off_td_plist"); + thread_oncpu_size = 4; + } CATCH(e, RETURN_MASK_ERROR) { + TRY { + proc_off_p_pid = parse_and_eval_address( + "&((struct proc *)0)->p_pid"); + proc_off_p_comm = parse_and_eval_address( + "&((struct proc *)0)->p_comm"); + proc_off_p_list = parse_and_eval_address( + "&((struct proc *)0)->p_list"); + proc_off_p_threads = parse_and_eval_address( + "&((struct proc *)0)->p_threads"); + thread_off_td_tid = parse_and_eval_address( + "&((struct thread *)0)->td_tid"); + thread_off_td_name = parse_and_eval_address( + "&((struct thread *)0)->td_name"); + thread_off_td_oncpu = parse_and_eval_address( + "&((struct thread *)0)->td_oncpu"); + thread_off_td_pcb = parse_and_eval_address( + "&((struct thread *)0)->td_pcb"); + thread_off_td_plist = parse_and_eval_address( + "&((struct thread *)0)->td_plist"); + thread_oncpu_size = parse_and_eval_long( + "sizeof(((struct thread *)0)->td_oncpu)"); + } CATCH(e2, RETURN_MASK_ERROR) { + proc_off_p_pid = offsetof(struct proc, p_pid); + proc_off_p_comm = offsetof(struct proc, p_comm); + proc_off_p_list = offsetof(struct proc, p_list); + proc_off_p_threads = offsetof(struct proc, p_threads); + thread_off_td_tid = offsetof(struct thread, td_tid); + thread_off_td_name = offsetof(struct thread, td_name); + thread_off_td_oncpu = offsetof(struct thread, td_oncpu); + thread_off_td_pcb = offsetof(struct thread, td_pcb); + thread_off_td_plist = offsetof(struct thread, td_plist); + thread_oncpu_size = + sizeof(((struct thread *)0)->td_oncpu); + } END_CATCH + } END_CATCH + + kgdb_thr_add_procs(paddr, cpu_pcb_addr); + addr = kgdb_lookup("zombproc"); + if (addr != 0) { + TRY { + paddr = read_memory_typed_address (addr, ptr_type); + kgdb_thr_add_procs(paddr, cpu_pcb_addr); + } CATCH(e, RETURN_MASK_ERROR) { + } END_CATCH + } + curkthr = kgdb_thr_lookup_tid(dumptid); + if (curkthr == NULL) + curkthr = first; + return (first); +} + +struct kthr * +kgdb_thr_lookup_tid(int tid) +{ + struct kthr *kt; + + kt = first; + while (kt != NULL && kt->tid != tid) + kt = kt->next; + return (kt); +} + +struct kthr * +kgdb_thr_lookup_taddr(uintptr_t taddr) +{ + struct kthr *kt; + + kt = first; + while (kt != NULL && kt->kaddr != taddr) + kt = kt->next; + return (kt); +} + +struct kthr * +kgdb_thr_lookup_pid(int pid) +{ + struct kthr *kt; + + kt = first; + while (kt != NULL && kt->pid != pid) + kt = kt->next; + return (kt); +} + +struct kthr * +kgdb_thr_lookup_paddr(uintptr_t paddr) +{ + struct kthr *kt; + + kt = first; + while (kt != NULL && kt->paddr != paddr) + kt = kt->next; + return (kt); +} + +struct kthr * +kgdb_thr_next(struct kthr *kt) +{ + return (kt->next); +} + +const char * +kgdb_thr_extra_thread_info(int tid) +{ + char comm[MAXCOMLEN + 1]; + char td_name[MAXCOMLEN + 1]; + struct kthr *kt; + static char buf[64]; + + kt = kgdb_thr_lookup_tid(tid); + if (kt == NULL) + return (NULL); + snprintf(buf, sizeof(buf), "PID=%d", kt->pid); + TRY { + read_memory_string (kt->paddr + proc_off_p_comm, comm, + sizeof(comm)); + strlcat(buf, ": ", sizeof(buf)); + strlcat(buf, comm, sizeof(buf)); + read_memory_string (kt->kaddr + thread_off_td_name, td_name, + sizeof(td_name)); + if (strcmp(comm, td_name) != 0) { + strlcat(buf, "/", sizeof(buf)); + strlcat(buf, td_name, sizeof(buf)); + } + } CATCH(e, RETURN_MASK_ERROR) { + } END_CATCH + return (buf); +} diff --git a/devel/gdb/files/kgdb/fbsd-kvm.c b/devel/gdb/files/kgdb/fbsd-kvm.c new file mode 100644 index 00000000..0c6ad673 --- /dev/null +++ b/devel/gdb/files/kgdb/fbsd-kvm.c @@ -0,0 +1,647 @@ +/* + * Copyright (c) 2004 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: head/devel/gdb/files/kgdb/fbsd-kvm.c 503200 2019-06-01 00:44:08Z jhb $"); + +#include "defs.h" +#include "command.h" +#include "elf-bfd.h" +#include "filenames.h" +#include "gdbcore.h" +#include "gdbthread.h" +#include "gdb_obstack.h" +#include "inferior.h" +#include "objfiles.h" +#include "osabi.h" +#include "process-stratum-target.h" +#include "solib.h" +#include "target.h" +#include "value.h" +#include "readline/tilde.h" + +#include +#include +#include + +#include "kgdb.h" + +static CORE_ADDR stoppcbs; +static LONGEST pcb_size; + +static char *vmcore; + +/* Per-architecture data key. */ +static struct gdbarch_data *fbsd_vmcore_data; + +struct fbsd_vmcore_ops +{ + /* Supply registers for a pcb to a register cache. */ + void (*supply_pcb)(struct regcache *, CORE_ADDR); + + /* Return address of pcb for thread running on a CPU. */ + CORE_ADDR (*cpu_pcb_addr)(u_int); +}; + +static void * +fbsd_vmcore_init (struct obstack *obstack) +{ + struct fbsd_vmcore_ops *ops; + + ops = OBSTACK_ZALLOC (obstack, struct fbsd_vmcore_ops); + return ops; +} + +/* Set the function that supplies registers from a pcb + for architecture GDBARCH to SUPPLY_PCB. */ + +void +fbsd_vmcore_set_supply_pcb (struct gdbarch *gdbarch, + void (*supply_pcb) (struct regcache *, + CORE_ADDR)) +{ + struct fbsd_vmcore_ops *ops = (struct fbsd_vmcore_ops *) + gdbarch_data (gdbarch, fbsd_vmcore_data); + ops->supply_pcb = supply_pcb; +} + +/* Set the function that returns the address of the pcb for a thread + running on a CPU for + architecture GDBARCH to CPU_PCB_ADDR. */ + +void +fbsd_vmcore_set_cpu_pcb_addr (struct gdbarch *gdbarch, + CORE_ADDR (*cpu_pcb_addr) (u_int)) +{ + struct fbsd_vmcore_ops *ops = (struct fbsd_vmcore_ops *) + gdbarch_data (gdbarch, fbsd_vmcore_data); + ops->cpu_pcb_addr = cpu_pcb_addr; +} + +static CORE_ADDR kernstart; +static kvm_t *kvm; +int kgdb_quiet; + +static ptid_t +fbsd_vmcore_ptid(int tid) +{ + if (kvm == NULL) + /* + * The remote target stores the 'tid' in the lwp + * field. + */ + return ptid_t(inferior_ptid.pid(), tid, 0); + + /* + * This follows the model described in bsd-kvm.c except that + * in kernel tids are used as the tid of the ptid instead of a + * process ID. + */ + return ptid_t(1, 1, tid); +} + +#define MSGBUF_SEQ_TO_POS(size, seq) ((seq) % (size)) + +static void +kgdb_dmesg(void) +{ + CORE_ADDR bufp; + int size, rseq, wseq; + gdb_byte c; + + /* + * Display the unread portion of the message buffer. This gives the + * user a some initial data to work from. + */ + if (kgdb_quiet) + return; + TRY { + bufp = parse_and_eval_address("msgbufp->msg_ptr"); + size = parse_and_eval_long("msgbufp->msg_size"); + rseq = parse_and_eval_long("msgbufp->msg_rseq"); + wseq = parse_and_eval_long("msgbufp->msg_wseq"); + } CATCH(e, RETURN_MASK_ERROR) { + return; + } END_CATCH + rseq = MSGBUF_SEQ_TO_POS(size, rseq); + wseq = MSGBUF_SEQ_TO_POS(size, wseq); + if (rseq == wseq) + return; + + printf("\nUnread portion of the kernel message buffer:\n"); + while (rseq < wseq) { + read_memory(bufp + rseq, &c, 1); + putchar(c); + rseq++; + if (rseq == size) + rseq = 0; + } + if (c != '\n') + putchar('\n'); + putchar('\n'); +} + +#define KERNEL_INTERP "/red/herring" + +enum gdb_osabi +fbsd_kernel_osabi_sniffer(bfd *abfd) +{ + asection *s; + bfd_byte buf[sizeof(KERNEL_INTERP)]; + bfd_byte *bufp; + + /* First, determine if this is a FreeBSD/ELF binary. */ + switch (elf_elfheader(abfd)->e_ident[EI_OSABI]) { + case ELFOSABI_FREEBSD: + break; + case ELFOSABI_NONE: { + enum gdb_osabi osabi = GDB_OSABI_UNKNOWN; + + bfd_map_over_sections (abfd, + generic_elf_osabi_sniff_abi_tag_sections, + &osabi); + + /* + * aarch64 kernels don't have the right note tag for + * kernels so just look for /red/herring anyway. + */ + if (osabi == GDB_OSABI_UNKNOWN && + elf_elfheader(abfd)->e_machine == EM_AARCH64) + break; + if (osabi != GDB_OSABI_FREEBSD) + return (GDB_OSABI_UNKNOWN); + break; + } + default: + return (GDB_OSABI_UNKNOWN); + } + + /* FreeBSD ELF kernels have an interpreter path of "/red/herring". */ + bufp = buf; + s = bfd_get_section_by_name(abfd, ".interp"); + if (s != NULL && bfd_section_size(abfd, s) == sizeof(buf) && + bfd_get_full_section_contents(abfd, s, &bufp) && + memcmp(buf, KERNEL_INTERP, sizeof(buf)) == 0) + return (GDB_OSABI_FREEBSD_KERNEL); + + return (GDB_OSABI_UNKNOWN); +} + +/* The FreeBSD libkvm target. */ + +static const target_info fbsd_kvm_target_info = { + "vmcore", + N_("Kernel core dump file"), + N_("Use a vmcore file as a target.\n\ +If no filename is specified, /dev/mem is used to examine the running kernel.\n\ +target vmcore [-w] [filename]") +}; + +class fbsd_kvm_target final : public process_stratum_target +{ +public: + fbsd_kvm_target () = default; + + const target_info &info () const override + { return fbsd_kvm_target_info; } + + void close () override; + + void fetch_registers (struct regcache *, int) override; + enum target_xfer_status xfer_partial (enum target_object object, + const char *annex, + gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) override; + + void files_info () override; + bool thread_alive (ptid_t ptid) override; + void update_thread_list () override; + const char *pid_to_str (ptid_t) override; + const char *extra_thread_info (thread_info *) override; + + bool has_all_memory () override { return false; } + bool has_memory () override; + bool has_stack () override; + bool has_registers () override; + bool has_execution (ptid_t) override { return false; } +}; + +/* Target ops for libkvm interface. */ +static fbsd_kvm_target fbsd_kvm_ops; + +#ifdef HAVE_KVM_OPEN2 +static int +kgdb_resolve_symbol(const char *name, kvaddr_t *kva) +{ + struct bound_minimal_symbol ms; + + ms = lookup_minimal_symbol (name, NULL, NULL); + if (ms.minsym == NULL) + return (1); + *kva = BMSYMBOL_VALUE_ADDRESS (ms); + return (0); +} +#endif + +static void +fbsd_kvm_target_open (const char *args, int from_tty) +{ + struct fbsd_vmcore_ops *ops = (struct fbsd_vmcore_ops *) + gdbarch_data (target_gdbarch(), fbsd_vmcore_data); + char kvm_err[_POSIX2_LINE_MAX]; + struct inferior *inf; + struct cleanup *old_chain; + struct kthr *kt; + kvm_t *nkvm; + char *temp, *kernel, *filename; + bool writeable; + + if (ops == NULL || ops->supply_pcb == NULL || ops->cpu_pcb_addr == NULL) + error ("ABI doesn't support a vmcore target"); + + target_preopen (from_tty); + kernel = get_exec_file (1); + if (kernel == NULL) + error ("Can't open a vmcore without a kernel"); + + writeable = false; + filename = NULL; + if (args != NULL) { + gdb_argv built_argv (args); + + for (char **argv = built_argv.get (); *argv != NULL; argv++) { + if (**argv == '-') { + if (strcmp (*argv, "-w") == 0) + writeable = true; + else + error (_("Invalid argument")); + } else { + if (filename != NULL) + error (_("Invalid argument")); + + filename = tilde_expand (*argv); + if (!IS_ABSOLUTE_PATH (filename)) { + temp = concat (current_directory, "/", + filename, NULL); + xfree(filename); + filename = temp; + } + } + } + } + + old_chain = make_cleanup (xfree, filename); + +#ifdef HAVE_KVM_OPEN2 + nkvm = kvm_open2(kernel, filename, + writeable ? O_RDWR : O_RDONLY, kvm_err, kgdb_resolve_symbol); +#else + nkvm = kvm_openfiles(kernel, filename, NULL, + writeable ? O_RDWR : O_RDONLY, kvm_err); +#endif + if (nkvm == NULL) + error ("Failed to open vmcore: %s", kvm_err); + + /* Don't free the filename now and close any previous vmcore. */ + discard_cleanups(old_chain); + unpush_target(&fbsd_kvm_ops); + + /* + * Determine the first address in KVA. Newer kernels export + * VM_MAXUSER_ADDRESS and the first kernel address can be + * determined by adding one. Older kernels do not provide a + * symbol that is valid on all platforms, but kernbase is close + * for most platforms. + */ + TRY { + kernstart = parse_and_eval_address("vm_maxuser_address") + 1; + } CATCH(e, RETURN_MASK_ERROR) { + kernstart = kgdb_lookup("kernbase"); + } END_CATCH + + /* + * Lookup symbols needed for stoppcbs[] handling, but don't + * fail if they aren't present. + */ + stoppcbs = kgdb_lookup("stoppcbs"); + TRY { + pcb_size = parse_and_eval_long("pcb_size"); + } CATCH(e, RETURN_MASK_ERROR) { + pcb_size = 0; + } END_CATCH + + if (pcb_size == 0) { + TRY { + pcb_size = parse_and_eval_long("sizeof(struct pcb)"); + } CATCH(e, RETURN_MASK_ERROR) { +#ifdef HAVE_KVM_OPEN2 + if (kvm_native(nkvm)) + pcb_size = sizeof(struct pcb); + else + pcb_size = 0; +#else + pcb_size = sizeof(struct pcb); +#endif + } END_CATCH + } + + kvm = nkvm; + vmcore = filename; + push_target (&fbsd_kvm_ops); + + kgdb_dmesg(); + + inf = current_inferior(); + if (inf->pid == 0) { + inferior_appeared(inf, 1); + inf->fake_pid_p = 1; + } + solib_create_inferior_hook(0); + init_thread_list(); + kt = kgdb_thr_init(ops->cpu_pcb_addr); + while (kt != NULL) { + add_thread_silent(fbsd_vmcore_ptid(kt->tid)); + kt = kgdb_thr_next(kt); + } + if (curkthr != 0) + inferior_ptid = fbsd_vmcore_ptid(curkthr->tid); + + target_fetch_registers (get_current_regcache (), -1); + + reinit_frame_cache (); + print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC, 1); +} + +void +fbsd_kvm_target::close() +{ + + if (kvm != NULL) { + clear_solib(); + if (kvm_close(kvm) != 0) + warning("cannot close \"%s\": %s", vmcore, + kvm_geterr(kvm)); + kvm = NULL; + xfree(vmcore); + vmcore = NULL; + } + + inferior_ptid = null_ptid; +} + +#if 0 +static void +kgdb_trgt_detach(struct target_ops *ops, const char *args, int from_tty) +{ + + if (args) + error ("Too many arguments"); + unpush_target(&kgdb_trgt_ops); + reinit_frame_cache(); + if (from_tty) + printf_filtered("No vmcore file now.\n"); +} +#endif + +const char * +fbsd_kvm_target::extra_thread_info(thread_info *ti) +{ + + return (kgdb_thr_extra_thread_info(ti->ptid.tid())); +} + +bool +fbsd_kvm_target::has_memory () +{ + return (kvm != NULL); +} + +bool +fbsd_kvm_target::has_stack () +{ + return (kvm != NULL); +} + +bool +fbsd_kvm_target::has_registers () +{ + return (kvm != NULL); +} + +void +fbsd_kvm_target::files_info() +{ + + printf_filtered ("\t`%s', ", vmcore); + wrap_here (" "); + printf_filtered ("file type %s.\n", "FreeBSD kernel vmcore"); +} + +void +fbsd_kvm_target::update_thread_list() +{ + /* + * XXX: We should probably rescan the thread list here and update + * it if there are any changes. One nit though is that we'd have + * to detect exited threads. + */ + gdb_assert(kvm != NULL); +#if 0 + prune_threads(); +#endif +#if 0 + struct target_ops *tb; + + if (kvm != NULL) + return; + + tb = find_target_beneath(ops); + if (tb->to_update_thread_list != NULL) + tb->to_update_thread_list(tb); +#endif +} + +const char * +fbsd_kvm_target::pid_to_str(ptid_t ptid) +{ + static char buf[33]; + + snprintf(buf, sizeof(buf), "Thread %ld", ptid.tid()); + return (buf); +} + +bool +fbsd_kvm_target::thread_alive(ptid_t ptid) +{ + return (kgdb_thr_lookup_tid(ptid.tid()) != NULL); +} + +void +fbsd_kvm_target::fetch_registers(struct regcache *regcache, int regnum) +{ + struct fbsd_vmcore_ops *ops = (struct fbsd_vmcore_ops *) + gdbarch_data (target_gdbarch(), fbsd_vmcore_data); + struct kthr *kt; + + if (ops->supply_pcb == NULL) + return; + kt = kgdb_thr_lookup_tid(inferior_ptid.tid()); + if (kt == NULL) + return; + ops->supply_pcb(regcache, kt->pcb); +} + +enum target_xfer_status +fbsd_kvm_target::xfer_partial(enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) +{ + ssize_t nbytes; + + gdb_assert(kvm != NULL); + switch (object) { + case TARGET_OBJECT_MEMORY: + nbytes = len; + if (readbuf != NULL) +#ifdef HAVE_KVM_OPEN2 + nbytes = kvm_read2(kvm, offset, readbuf, len); +#else + nbytes = kvm_read(kvm, offset, readbuf, len); +#endif + if (writebuf != NULL && len > 0) + nbytes = kvm_write(kvm, offset, writebuf, len); + if (nbytes < 0) + return TARGET_XFER_E_IO; + if (nbytes == 0) + return TARGET_XFER_EOF; + *xfered_len = nbytes; + return TARGET_XFER_OK; + default: + return TARGET_XFER_E_IO; + } +} + +#if 0 +static int +kgdb_trgt_insert_breakpoint(struct target_ops *ops, struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) +{ + + return 0; +} + +static int +kgdb_trgt_remove_breakpoint(struct target_ops *ops, struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt, enum remove_bp_reason reason) +{ + + return 0; +} +#endif + +static void +kgdb_switch_to_thread(const char *arg, int tid) +{ + struct thread_info *tp; + + tp = find_thread_ptid (fbsd_vmcore_ptid (tid)); + if (tp == NULL) + error ("invalid tid"); + thread_select (arg, tp); +} + +static void +kgdb_set_proc_cmd (const char *arg, int from_tty) +{ + CORE_ADDR addr; + struct kthr *thr; + + if (!arg) + error_no_arg ("proc address for the new context"); + + if (kvm == NULL) + error ("only supported for core file target"); + + addr = parse_and_eval_address (arg); + + if (addr < kernstart) { + thr = kgdb_thr_lookup_pid((int)addr); + if (thr == NULL) + error ("invalid pid"); + } else { + thr = kgdb_thr_lookup_paddr(addr); + if (thr == NULL) + error("invalid proc address"); + } + kgdb_switch_to_thread(arg, thr->tid); +} + +static void +kgdb_set_tid_cmd (const char *arg, int from_tty) +{ + CORE_ADDR addr; + struct kthr *thr; + + if (!arg) + error_no_arg ("TID or thread address for the new context"); + + addr = (CORE_ADDR) parse_and_eval_address (arg); + + if (kvm != NULL && addr >= kernstart) { + thr = kgdb_thr_lookup_taddr(addr); + if (thr == NULL) + error("invalid thread address"); + addr = thr->tid; + } + kgdb_switch_to_thread(arg, addr); +} + +void +_initialize_kgdb_target(void) +{ + + add_target(fbsd_kvm_target_info, fbsd_kvm_target_open); + + fbsd_vmcore_data = gdbarch_data_register_pre_init(fbsd_vmcore_init); + + add_com ("proc", class_obscure, kgdb_set_proc_cmd, + "Set current process context"); + add_com ("tid", class_obscure, kgdb_set_tid_cmd, + "Set current thread context"); +} + +CORE_ADDR +kgdb_trgt_stop_pcb(u_int cpuid) +{ + + if (stoppcbs == 0 || pcb_size == 0) + return 0; + + return (stoppcbs + pcb_size * cpuid); +} diff --git a/devel/gdb/files/kgdb/i386fbsd-kern.c b/devel/gdb/files/kgdb/i386fbsd-kern.c new file mode 100644 index 00000000..aea4d72a --- /dev/null +++ b/devel/gdb/files/kgdb/i386fbsd-kern.c @@ -0,0 +1,580 @@ +/* + * Copyright (c) 2004 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: head/devel/gdb/files/kgdb/i386fbsd-kern.c 480613 2018-09-24 17:23:35Z jhb $"); + +#include "defs.h" +#include "frame-unwind.h" +#include "gdbcore.h" +#include "inferior.h" +#include "osabi.h" +#include "regcache.h" +#include "progspace.h" +#include "solib.h" +#include "trad-frame.h" +#include "i386-tdep.h" + +#ifdef __i386__ +#include +#include +#include +#include +#include +#endif + +#include "kgdb.h" + +struct i386fbsd_info { + int ofs_fix; +}; + +/* Per-program-space data key. */ +static const struct program_space_data *i386fbsd_pspace_data; + +static void +i386fbsd_pspace_data_cleanup (struct program_space *pspace, void *arg) +{ + struct i386fbsd_info *info = (struct i386fbsd_info *)arg; + + xfree (info); +} + +/* Get the current i386fbsd data. If none is found yet, add it now. This + function always returns a valid object. */ + +static struct i386fbsd_info * +get_i386fbsd_info (void) +{ + struct i386fbsd_info *info; + + info = (struct i386fbsd_info *) + program_space_data (current_program_space, i386fbsd_pspace_data); + if (info != NULL) + return info; + + info = XCNEW (struct i386fbsd_info); + set_program_space_data (current_program_space, i386fbsd_pspace_data, info); + + /* + * In revision 1.117 of i386/i386/exception.S trap handlers + * were changed to pass trapframes by reference rather than + * by value. Detect this by seeing if the first instruction + * at the 'calltrap' label is a "push %esp" which has the + * opcode 0x54. + */ + if (parse_and_eval_long("((char *)calltrap)[0]") == 0x54) + info->ofs_fix = 4; + else + info->ofs_fix = 0; + return info; +} + +/* + * Even though the pcb contains fields for the segment selectors, only + * %gs is updated on each context switch. The other selectors are + * saved in stoppcbs[], but we just hardcode their known values rather + * than handling that special case. + */ +static const int i386fbsd_pcb_offset[] = { + -1, /* %eax */ + -1, /* %ecx */ + -1, /* %edx */ + 4 * 4, /* %ebx */ + 3 * 4, /* %esp */ + 2 * 4, /* %ebp */ + 1 * 4, /* %esi */ + 0 * 4, /* %edi */ + 5 * 4, /* %eip */ + -1, /* %eflags */ + -1, /* %cs */ + -1, /* %ss */ + -1, /* %ds */ + -1, /* %es */ + -1, /* %fs */ + -1, /* %gs */ +}; + +#define CODE_SEL (4 << 3) +#define DATA_SEL (5 << 3) +#define PRIV_SEL (1 << 3) + +static void +i386fbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr) +{ + gdb_byte buf[4]; + int i; + + memset(buf, 0, sizeof(buf)); + + /* + * XXX The PCB may have been swapped out. Supply a dummy %eip value + * so as to avoid triggering an exception during stack unwinding. + */ + regcache->raw_supply(I386_EIP_REGNUM, buf); + for (i = 0; i < ARRAY_SIZE (i386fbsd_pcb_offset); i++) + if (i386fbsd_pcb_offset[i] != -1) { + if (target_read_memory(pcb_addr + i386fbsd_pcb_offset[i], buf, sizeof buf) + != 0) + continue; + regcache->raw_supply(i, buf); + } + regcache->raw_supply_unsigned(I386_CS_REGNUM, CODE_SEL); + regcache->raw_supply_unsigned(I386_DS_REGNUM, DATA_SEL); + regcache->raw_supply_unsigned(I386_ES_REGNUM, DATA_SEL); + regcache->raw_supply_unsigned(I386_FS_REGNUM, PRIV_SEL); + regcache->raw_supply_unsigned(I386_GS_REGNUM, DATA_SEL); + regcache->raw_supply_unsigned(I386_SS_REGNUM, DATA_SEL); +} + +#ifdef __i386__ +/* TODO: Make this cross-debugger friendly. */ +static const int i386fbsd_tss_offset[] = { + 10 * 4, /* %eax */ + 11 * 4, /* %ecx */ + 12 * 4, /* %edx */ + 13 * 4, /* %ebx */ + 14 * 4, /* %esp */ + 15 * 4, /* %ebp */ + 16 * 4, /* %esi */ + 17 * 4, /* %edi */ + 8 * 4, /* %eip */ + 9 * 4, /* %eflags */ + 19 * 4, /* %cs */ + 20 * 4, /* %ss */ + 21 * 4, /* %ds */ + 18 * 4, /* %es */ + 22 * 4, /* %fs */ + 23 * 4, /* %gs */ +}; + +/* + * If the current thread is executing on a CPU, fetch the common_tss + * for that CPU. + * + * This is painful because 'struct pcpu' is variant sized, so we can't + * use it. Instead, we lookup the GDT selector for this CPU and + * extract the base of the TSS from there. + */ +static CORE_ADDR +i386fbsd_fetch_tss(void) +{ + struct kthr *kt; + struct segment_descriptor sd; + CORE_ADDR addr, cpu0prvpage, tss; + + kt = kgdb_thr_lookup_tid(inferior_ptid.tid()); + if (kt == NULL || kt->cpu == NOCPU || kt->cpu < 0) + return (0); + + addr = kgdb_lookup("gdt"); + if (addr == 0) + return (0); + addr += (kt->cpu * NGDT + GPROC0_SEL) * sizeof(sd); + if (target_read_memory(addr, (gdb_byte *)&sd, sizeof(sd)) != 0) + return (0); + if (sd.sd_type != SDT_SYS386BSY) { + warning ("descriptor is not a busy TSS"); + return (0); + } + tss = sd.sd_hibase << 24 | sd.sd_lobase; + + /* + * In SMP kernels, the TSS is stored as part of the per-CPU + * data. On older kernels, the CPU0's private page + * is stored at an address that isn't mapped in minidumps. + * However, the data is mapped at the alternate cpu0prvpage + * address. Thus, if the TSS is at the invalid address, + * change it to be relative to cpu0prvpage instead. + */ + if (trunc_page(tss) == 0xffc00000) { + TRY { + cpu0prvpage = parse_and_eval_address("cpu0prvpage"); + } CATCH(e, RETURN_MASK_ERROR) { + return (0); + } END_CATCH + tss = cpu0prvpage + (tss & PAGE_MASK); + } + return (tss); +} + +static struct trad_frame_cache * +i386fbsd_dblfault_cache (struct frame_info *this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct trad_frame_cache *cache; + CORE_ADDR addr, func, tss; + int i; + + if (*this_cache != NULL) + return (struct trad_frame_cache *)(*this_cache); + + cache = trad_frame_cache_zalloc (this_frame); + *this_cache = cache; + + func = get_frame_func (this_frame); + tss = i386fbsd_fetch_tss (); + + for (i = 0; i < ARRAY_SIZE (i386fbsd_tss_offset); i++) + if (i386fbsd_tss_offset[i] != -1) + trad_frame_set_reg_addr (cache, i, tss + i386fbsd_tss_offset[i]); + + /* Construct the frame ID using the function start. */ + /* XXX: Stack address should be dbfault_stack + PAGE_SIZE. */ + trad_frame_set_id (cache, frame_id_build (tss + sizeof(struct i386tss), + func)); + + return cache; +} + +static void +i386fbsd_dblfault_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + struct trad_frame_cache *cache = + i386fbsd_dblfault_cache (this_frame, this_cache); + + trad_frame_get_id (cache, this_id); +} + +static struct value * +i386fbsd_dblfault_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct trad_frame_cache *cache = + i386fbsd_dblfault_cache (this_frame, this_cache); + + return trad_frame_get_register (cache, this_frame, regnum); +} + +static int +i386fbsd_dblfault_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + const char *name; + + find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL); + return (name && strcmp (name, "dblfault_handler") == 0); +} + +static const struct frame_unwind i386fbsd_dblfault_unwind = { + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + i386fbsd_dblfault_this_id, + i386fbsd_dblfault_prev_register, + NULL, + i386fbsd_dblfault_sniffer +}; +#endif + +static const int i386fbsd_trapframe_offset[] = { + 10 * 4, /* %eax */ + 9 * 4, /* %ecx */ + 8 * 4, /* %edx */ + 7 * 4, /* %ebx */ + 16 * 4, /* %esp */ + 5 * 4, /* %ebp */ + 4 * 4, /* %esi */ + 3 * 4, /* %edi */ + 13 * 4, /* %eip */ + 15 * 4, /* %eflags */ + 14 * 4, /* %cs */ + 17 * 4, /* %ss */ + 2 * 4, /* %ds */ + 1 * 4, /* %es */ + 0 * 4, /* %fs */ + -1 /* %gs */ +}; + +#define TRAPFRAME_SIZE 72 + +static struct trad_frame_cache * +i386fbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct trad_frame_cache *cache; + struct i386fbsd_info *info; + CORE_ADDR addr, cs, func, pc, sp; + const char *name; + int i; + + if (*this_cache != NULL) + return ((struct trad_frame_cache *)*this_cache); + + info = get_i386fbsd_info(); + cache = trad_frame_cache_zalloc (this_frame); + *this_cache = cache; + + func = get_frame_func (this_frame); + sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM); + + find_pc_partial_function (func, &name, NULL, NULL); + if (strcmp(name, "calltrap") == 0 || + strcmp(name, "Xlcall_syscall") == 0 || + strcmp(name, "Xint0x80_syscall") == 0) + /* Traps in later kernels pass the trap frame by reference. */ + sp += info->ofs_fix; + else if (strcmp(name, "Xtimerint") == 0) + /* Timer interrupts also pass the trap frame by reference. */ + sp += info->ofs_fix; + else if (strcmp(name, "Xcpustop") == 0 || + strcmp(name, "Xrendezvous") == 0 || + strcmp(name, "Xipi_intr_bitmap_handler") == 0 || + strcmp(name, "Xlazypmap") == 0) + /* These handlers push a trap frame only. */ + ; + else if (strcmp(name, "fork_trampoline") == 0) + if (get_frame_pc (this_frame) == func) + { + /* fork_exit hasn't been called (kthread has never run), so + %esp in the pcb points to the word above the trapframe. */ + sp += 4; + } + else + { + /* fork_exit has been called, so %esp in fork_exit's + frame is &tf - 12. */ + sp += 12; + } + else { + /* Interrupt frames pass the IDT vector in addition to the trap frame. */ + sp += info->ofs_fix + 4; + } + + addr = sp + i386fbsd_trapframe_offset[I386_CS_REGNUM]; + cs = read_memory_unsigned_integer (addr, 4, byte_order); + for (i = 0; i < ARRAY_SIZE (i386fbsd_trapframe_offset); i++) + { + /* %ss/%esp are only present in the trapframe for a trap from + userland. */ + if ((cs & I386_SEL_RPL) == I386_SEL_KPL) + { + if (i == I386_SS_REGNUM) + continue; + if (i == I386_ESP_REGNUM) + { + trad_frame_set_reg_value (cache, i, sp + TRAPFRAME_SIZE - 8); + continue; + } + } + if (i386fbsd_trapframe_offset[i] != -1) + trad_frame_set_reg_addr (cache, i, sp + i386fbsd_trapframe_offset[i]); + } + + /* Read %eip from trap frame. */ + addr = sp + i386fbsd_trapframe_offset[I386_EIP_REGNUM]; + pc = read_memory_unsigned_integer (addr, 4, byte_order); + + if (pc == 0 && strcmp(name, "fork_trampoline") == 0) + { + /* Initial frame of a kthread; terminate backtrace. */ + trad_frame_set_id (cache, outer_frame_id); + } + else + { + /* Construct the frame ID using the function start. */ + sp += TRAPFRAME_SIZE; + if ((cs & I386_SEL_RPL) == I386_SEL_KPL) + sp -= 8; + trad_frame_set_id (cache, frame_id_build (sp, func)); + } + + return cache; +} + +static void +i386fbsd_trapframe_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + struct trad_frame_cache *cache = + i386fbsd_trapframe_cache (this_frame, this_cache); + + trad_frame_get_id (cache, this_id); +} + +static struct value * +i386fbsd_trapframe_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct trad_frame_cache *cache = + i386fbsd_trapframe_cache (this_frame, this_cache); + + return trad_frame_get_register (cache, this_frame, regnum); +} + +static int +i386fbsd_trapframe_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + const char *name; + + find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL); + return (name && ((strcmp (name, "calltrap") == 0) + || (strcmp (name, "fork_trampoline") == 0) + || (name[0] == 'X' && name[1] != '_'))); +} + +static const struct frame_unwind i386fbsd_trapframe_unwind = { + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + i386fbsd_trapframe_this_id, + i386fbsd_trapframe_prev_register, + NULL, + i386fbsd_trapframe_sniffer +}; + +static void +i386fbsd_kernel_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch) +{ + + i386_elf_init_abi(info, gdbarch); + +#ifdef __i386__ + frame_unwind_prepend_unwinder(gdbarch, &i386fbsd_dblfault_unwind); +#endif + frame_unwind_prepend_unwinder(gdbarch, &i386fbsd_trapframe_unwind); + + set_solib_ops(gdbarch, &kld_so_ops); + + fbsd_vmcore_set_supply_pcb(gdbarch, i386fbsd_supply_pcb); + fbsd_vmcore_set_cpu_pcb_addr(gdbarch, kgdb_trgt_stop_pcb); +} + +void +_initialize_i386_kgdb_tdep(void) +{ + /* This is used for both i386 and amd64, but amd64 always + includes this target, so just include it here. */ + gdbarch_register_osabi_sniffer(bfd_arch_i386, + bfd_target_elf_flavour, + fbsd_kernel_osabi_sniffer); + gdbarch_register_osabi (bfd_arch_i386, 0, + GDB_OSABI_FREEBSD_KERNEL, i386fbsd_kernel_init_abi); + + i386fbsd_pspace_data = register_program_space_data_with_cleanup (NULL, + i386fbsd_pspace_data_cleanup); + +#ifdef __i386__ + /* + * FreeBSD/i386 kernels prior to the introduction of AVX + * support used a different layout for the PCB. If gdb is + * compiled on these systems, these asserts will fail. The + * package builders build packages on older systems which are + * then run on newer systems. These binaries trip over these + * assertions even when debugging user programs and even + * though the running kernel is new enough. To cope, disable + * the assertion checks unless gdb is built against a new + * enough world. Note that this means kgdb is not going to + * parse PCBs correctly on FreeBSD/i386 kernels before AVX was + * merged. + */ +#if __FreeBSD_version >= 1001505 + gdb_assert(offsetof(struct pcb, pcb_ebx) + == i386fbsd_pcb_offset[I386_EBX_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_esp) + == i386fbsd_pcb_offset[I386_ESP_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_ebp) + == i386fbsd_pcb_offset[I386_EBP_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_esi) + == i386fbsd_pcb_offset[I386_ESI_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_edi) + == i386fbsd_pcb_offset[I386_EDI_REGNUM]); + gdb_assert(offsetof(struct pcb, pcb_eip) + == i386fbsd_pcb_offset[I386_EIP_REGNUM]); +#endif + gdb_assert(CODE_SEL == GSEL(GCODE_SEL, SEL_KPL)); + gdb_assert(DATA_SEL == GSEL(GDATA_SEL, SEL_KPL)); + gdb_assert(PRIV_SEL == GSEL(GPRIV_SEL, SEL_KPL)); + gdb_assert(sizeof(struct trapframe) == TRAPFRAME_SIZE); + gdb_assert(offsetof(struct trapframe, tf_eax) + == i386fbsd_trapframe_offset[I386_EAX_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_ecx) + == i386fbsd_trapframe_offset[I386_ECX_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_edx) + == i386fbsd_trapframe_offset[I386_EDX_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_ebx) + == i386fbsd_trapframe_offset[I386_EBX_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_esp) + == i386fbsd_trapframe_offset[I386_ESP_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_ebp) + == i386fbsd_trapframe_offset[I386_EBP_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_esi) + == i386fbsd_trapframe_offset[I386_ESI_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_edi) + == i386fbsd_trapframe_offset[I386_EDI_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_eip) + == i386fbsd_trapframe_offset[I386_EIP_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_eflags) + == i386fbsd_trapframe_offset[I386_EFLAGS_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_cs) + == i386fbsd_trapframe_offset[I386_CS_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_ss) + == i386fbsd_trapframe_offset[I386_SS_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_ds) + == i386fbsd_trapframe_offset[I386_DS_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_es) + == i386fbsd_trapframe_offset[I386_ES_REGNUM]); + gdb_assert(offsetof(struct trapframe, tf_fs) + == i386fbsd_trapframe_offset[I386_FS_REGNUM]); + + gdb_assert(offsetof(struct i386tss, tss_eax) + == i386fbsd_tss_offset[I386_EAX_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_ecx) + == i386fbsd_tss_offset[I386_ECX_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_edx) + == i386fbsd_tss_offset[I386_EDX_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_ebx) + == i386fbsd_tss_offset[I386_EBX_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_esp) + == i386fbsd_tss_offset[I386_ESP_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_ebp) + == i386fbsd_tss_offset[I386_EBP_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_esi) + == i386fbsd_tss_offset[I386_ESI_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_edi) + == i386fbsd_tss_offset[I386_EDI_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_eip) + == i386fbsd_tss_offset[I386_EIP_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_eflags) + == i386fbsd_tss_offset[I386_EFLAGS_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_cs) + == i386fbsd_tss_offset[I386_CS_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_ss) + == i386fbsd_tss_offset[I386_SS_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_ds) + == i386fbsd_tss_offset[I386_DS_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_es) + == i386fbsd_tss_offset[I386_ES_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_fs) + == i386fbsd_tss_offset[I386_FS_REGNUM]); + gdb_assert(offsetof(struct i386tss, tss_gs) + == i386fbsd_tss_offset[I386_GS_REGNUM]); +#endif +} diff --git a/devel/gdb/files/kgdb/kgdb-main.c b/devel/gdb/files/kgdb/kgdb-main.c new file mode 100644 index 00000000..e75c82e9 --- /dev/null +++ b/devel/gdb/files/kgdb/kgdb-main.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2004 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: head/devel/gdb/files/kgdb/kgdb-main.c 480613 2018-09-24 17:23:35Z jhb $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libgdb stuff. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kgdb.h" + +static int verbose; + +static char crashdir[PATH_MAX]; +static char *dumpnr; +static char *kernel; +static char *remote; +static char *vmcore; + +/* + * TODO: + * - test remote kgdb (see if threads and klds work) + * - possibly split kthr.c out into a separate thread_stratum target that + * uses new_objfile test to push itself when a FreeBSD kernel is loaded + * (check for kernel osabi) (probably don't bother with this) + * + test alternate kgdb_lookup() + * + fix kgdb build on amd64 to include i386 cross-debug support + * - propose expanded libkvm interface that supports cross-debug and moves + * MD bits of kgdb into the library (examining PCB's and exporting a + * stable-ABI struct of registers, similarly for trapframe handling and + * stop-pcb stuff + * + use tid's as lwp IDs instead of PIDs in ptid's + */ + +static void +usage(void) +{ + + fprintf(stderr, + "usage: %s [-afqvw] [-b rate] [-d crashdir] [-c core | -n dumpnr | -r device]\n" + "\t[kernel [core]]\n", getprogname()); + exit(1); +} + +static void +kernel_from_dumpnr(const char *nr) +{ + char line[PATH_MAX], path[PATH_MAX]; + FILE *info; + char *dir; + struct stat st; + int l; + + /* + * If there's a kernel image right here in the crash directory, then + * use it. The kernel image is either called kernel. or is in a + * subdirectory kernel. and called kernel. The latter allows us + * to collect the modules in the same place. + */ + snprintf(path, sizeof(path), "%s/kernel.%s", crashdir, nr); + if (stat(path, &st) == 0) { + if (S_ISREG(st.st_mode)) { + kernel = strdup(path); + return; + } + if (S_ISDIR(st.st_mode)) { + snprintf(path, sizeof(path), "%s/kernel.%s/kernel", + crashdir, nr); + if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { + kernel = strdup(path); + return; + } + } + } + + /* + * No kernel image here. Parse the dump header. The kernel object + * directory can be found there and we probably have the kernel + * image still in it. The object directory may also have a kernel + * with debugging info (called either kernel.full or kernel.debug). + * If we have a debug kernel, use it. + */ + snprintf(path, sizeof(path), "%s/info.%s", crashdir, nr); + info = fopen(path, "r"); + if (info == NULL) { + warn("%s", path); + return; + } + while (fgets(line, sizeof(line), info) != NULL) { + l = strlen(line); + if (l > 0 && line[l - 1] == '\n') + line[--l] = '\0'; + if (strncmp(line, " ", 4) == 0) { + fclose(info); + dir = strchr(line, ':'); + dir = (dir == NULL) ? line + 4 : dir + 1; + + /* + * Check for kernel.full first as if it exists + * kernel.debug will also exist, but will only + * contain debug symbols and not be recognized + * as a valid kernel by the osabi sniffer. + */ + snprintf(path, sizeof(path), "%s/kernel.full", dir); + if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { + kernel = strdup(path); + return; + } + snprintf(path, sizeof(path), "%s/kernel.debug", dir); + if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { + kernel = strdup(path); + return; + } + snprintf(path, sizeof(path), "%s/kernel", dir); + if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { + kernel = strdup(path); + return; + } + return; + } + } + fclose(info); +} + +/* + * Remote targets can support any number of syntaxes and we want to + * support them all with one addition: we support specifying a device + * node for a serial device without the "/dev/" prefix. + * + * What we do is to stat(2) the existing remote target first. If that + * fails, we try it with "/dev/" prepended. If that succeeds we use + * the resulting path, otherwise we use the original target. If + * either stat(2) succeeds make sure the file is either a character + * device or a FIFO. + */ +static void +verify_remote(void) +{ + char path[PATH_MAX]; + struct stat st; + + if (stat(remote, &st) != 0) { + snprintf(path, sizeof(path), "/dev/%s", remote); + if (stat(path, &st) != 0) + return; + free(remote); + remote = strdup(path); + } + if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) + errx(1, "%s: not a special file, FIFO or socket", remote); +} + +static void +add_arg(struct captured_main_args *args, char const *arg) +{ + + args->argc++; + args->argv = (char **)reallocf(args->argv, (args->argc + 1) * + sizeof(char *)); + if (args->argv == NULL) + err(1, "Out of memory building argument list"); + args->argv[args->argc] = (char *)arg; +} + +int +main(int argc, char *argv[]) +{ + char path[PATH_MAX]; + struct stat st; + struct captured_main_args args; + char *s; + int a, ch, writeable; + + dumpnr = NULL; + writeable = 0; + + strlcpy(crashdir, "/var/crash", sizeof(crashdir)); + s = getenv("KGDB_CRASH_DIR"); + if (s != NULL) + strlcpy(crashdir, s, sizeof(crashdir)); + + /* Convert long options into short options. */ + for (a = 1; a < argc; a++) { + s = argv[a]; + if (s[0] == '-') { + s++; + /* Long options take either 1 or 2 dashes. */ + if (s[0] == '-') + s++; + if (strcmp(s, "quiet") == 0) + argv[a] = (char *)"-q"; + else if (strcmp(s, "fullname") == 0) + argv[a] = (char *)"-f"; + } + } + + kgdb_quiet = 0; + memset (&args, 0, sizeof args); + args.interpreter_p = INTERP_CONSOLE; + args.argv = (char **)xmalloc(sizeof(char *)); + args.argv[0] = argv[0]; + + while ((ch = getopt(argc, argv, "ab:c:d:fn:qr:vw")) != -1) { + switch (ch) { + case 'a': + annotation_level++; + break; + case 'b': { + int i; + char *p; + + i = strtol(optarg, &p, 0); + if (*p != '\0' || p == optarg) + warnx("warning: could not set baud rate to `%s'.\n", + optarg); + else + baud_rate = i; + break; + } + case 'c': /* use given core file. */ + if (vmcore != NULL) { + warnx("option %c: can only be specified once", + optopt); + usage(); + /* NOTREACHED */ + } + vmcore = strdup(optarg); + break; + case 'd': /* lookup dumps in given directory. */ + strlcpy(crashdir, optarg, sizeof(crashdir)); + break; + case 'f': + annotation_level = 1; + break; + case 'n': /* use dump with given number. */ + dumpnr = optarg; + break; + case 'q': + kgdb_quiet = 1; + add_arg(&args, "-q"); + break; + case 'r': /* use given device for remote session. */ + if (remote != NULL) { + warnx("option %c: can only be specified once", + optopt); + usage(); + /* NOTREACHED */ + } + remote = strdup(optarg); + break; + case 'v': /* increase verbosity. */ + verbose++; + break; + case 'w': /* core file is writeable. */ + writeable = 1; + break; + case '?': + default: + usage(); + } + } + + if (((vmcore != NULL) ? 1 : 0) + ((dumpnr != NULL) ? 1 : 0) + + ((remote != NULL) ? 1 : 0) > 1) { + warnx("options -c, -n and -r are mutually exclusive"); + usage(); + /* NOTREACHED */ + } + + if (verbose > 1) + warnx("using %s as the crash directory", crashdir); + + if (argc > optind) + kernel = strdup(argv[optind++]); + + if (argc > optind && (dumpnr != NULL || remote != NULL)) { + warnx("options -n and -r do not take a core file. Ignored"); + optind = argc; + } + + if (dumpnr != NULL) { + snprintf(path, sizeof(path), "%s/vmcore.%s", crashdir, dumpnr); + if (stat(path, &st) == -1) + err(1, "%s", path); + if (!S_ISREG(st.st_mode)) + errx(1, "%s: not a regular file", path); + vmcore = strdup(path); + } else if (remote != NULL) { + verify_remote(); + } else if (argc > optind) { + if (vmcore == NULL) + vmcore = strdup(argv[optind++]); + if (argc > optind) + warnx("multiple core files specified. Ignored"); + } else if (vmcore == NULL && kernel == NULL) { + vmcore = strdup(_PATH_MEM); + kernel = strdup(getbootfile()); + } + + if (verbose) { + if (vmcore != NULL) + warnx("core file: %s", vmcore); + if (remote != NULL) + warnx("device file: %s", remote); + if (kernel != NULL) + warnx("kernel image: %s", kernel); + } + + /* A remote target requires an explicit kernel argument. */ + if (remote != NULL && kernel == NULL) { + warnx("remote debugging requires a kernel"); + usage(); + /* NOTREACHED */ + } + + /* If we don't have a kernel image yet, try to find one. */ + if (kernel == NULL) { + if (dumpnr != NULL) + kernel_from_dumpnr(dumpnr); + + if (kernel == NULL) + errx(1, "couldn't find a suitable kernel image"); + if (verbose) + warnx("kernel image: %s", kernel); + } + + /* Set an alternate prompt. */ + add_arg(&args, "-iex"); + add_arg(&args, "set prompt (kgdb) "); + + /* Change osabi to assume a FreeBSD kernel. */ + add_arg(&args, "-iex"); + add_arg(&args, "set osabi FreeBSD/kernel"); + + /* Open the vmcore if requested. */ + if (vmcore != NULL) { + add_arg(&args, "-ex"); + if (asprintf(&s, "target vmcore %s%s", writeable ? "-w " : "", + vmcore) < 0) + err(1, "couldn't build command line"); + add_arg(&args, s); + } + + /* Open the remote target if requested. */ + if (remote != NULL) { + add_arg(&args, "-ex"); + if (asprintf(&s, "target remote %s", remote) < 0) + err(1, "couldn't build command line"); + add_arg(&args, s); + } + + add_arg(&args, kernel); + + /* The libgdb code uses optind too. Reset it... */ + optind = 0; + + /* Terminate argv list. */ + add_arg(&args, NULL); + + return (gdb_main(&args)); +} diff --git a/devel/gdb/files/kgdb/kgdb.1 b/devel/gdb/files/kgdb/kgdb.1 new file mode 100644 index 00000000..09209bf6 --- /dev/null +++ b/devel/gdb/files/kgdb/kgdb.1 @@ -0,0 +1,140 @@ +.\" Copyright (c) 2004 Marcel Moolenaar +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: head/devel/gdb/files/kgdb/kgdb.1 440447 2017-05-08 19:02:25Z jhb $ +.\" +.Dd October 11, 2006 +.Dt KGDB 1 +.Os +.Sh NAME +.Nm kgdb +.Nd "kernel debugger" +.Sh SYNOPSIS +.Nm +.Op Fl a | Fl f | Fl fullname +.Op Fl b Ar rate +.Op Fl q | Fl quiet +.Op Fl v +.Op Fl w +.Op Fl d Ar crashdir +.Op Fl c Ar core | Fl n Ar dumpnr | Fl r Ar device +.Op Ar kernel Op Ar core +.Sh DESCRIPTION +The +.Nm +utility is a debugger based on +.Xr gdb 1 +that allows debugging of kernel core files. +.Pp +The options are as follows: +.Bl -tag -width ".Fl d Ar crashdir" +.It Fl a +Increase the annotation level. +An annotation level of 1 features the historical +.Fl fullname +option of +.Xr gdb 1 . +This is useful when running +.Nm +in Emacs. +The +.Fl f +or +.Fl fullname +options are supported for backward compatibility as well. +.It Fl b Ar rate +Set the baudrate to +.Ar rate . +.It Fl q +Suppress printing of the banner when the debugger starts. +The +.Fl quiet +form is supported for compatibility as well. +.It Fl v +Increase verbosity. +.It Fl w +Opens kmem-based targets in read-write mode. +(This is identical to what +.Fl -wcore +used to do in previous +gdb versions for +.Fx . ) +.It Fl d Ar crashdir +Use +.Ar crashdir +instead of the default, +.Pa /var/crash +to locate kernel core dump files in. +The name +.Pa vmcore. +plus the dump number will be appended to determine +the actual dump file name. +.It Fl c Ar core +Explicitly use +.Ar core +as the core dump file. +.It Fl n Ar dumpnr +Use the kernel core dump file numbered +.Ar dumpnr +for debugging. +.It Fl r Ar device +Use +.Ar device +to connect +.Nm +to for a remote debugging session. +.El +.Pp +The +.Fl c , n , +and +.Fl r +options are mutually exclusive. +.Pp +Optionally, the name of the kernel symbol file and +the name of the core dump file can be supplied on the +command-line as positional arguments. +If no kernel symbol file name has been given, the +symbol file of the currently running kernel will be +used. +If no core dump file has been specified through either +of the options or the last command-line argument, +.Pa /dev/mem +will be opened to allow debugging the currently running +kernel. +.Sh FILES +.Bl -tag -width ".Pa /var/crash" +.It Pa /dev/mem +Default memory image to open if no core dump file +has been specified. +.It Pa /var/crash +Default directory to locate kernel core dump files. +.El +.Sh SEE ALSO +.Xr gdb 1 +.Sh HISTORY +The +.Nm +utility first appeared in its current form in +.Fx 5.3 . diff --git a/devel/gdb/files/kgdb/kgdb.h b/devel/gdb/files/kgdb/kgdb.h new file mode 100644 index 00000000..6f87418e --- /dev/null +++ b/devel/gdb/files/kgdb/kgdb.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2004 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/devel/gdb/files/kgdb/kgdb.h 480613 2018-09-24 17:23:35Z jhb $ + */ + +#ifndef _KGDB_H_ +#define _KGDB_H_ + +struct kthr { + struct kthr *next; + CORE_ADDR paddr; + CORE_ADDR kaddr; + CORE_ADDR pcb; + int tid; + int pid; + int cpu; +}; + +extern struct kthr *curkthr; +extern struct target_so_ops kld_so_ops; +extern int kgdb_quiet; + +CORE_ADDR kgdb_trgt_stop_pcb(u_int); + +struct kthr *kgdb_thr_first(void); +struct kthr *kgdb_thr_init(CORE_ADDR (*cpu_pcb_addr) (u_int)); +struct kthr *kgdb_thr_lookup_tid(int); +struct kthr *kgdb_thr_lookup_pid(int); +struct kthr *kgdb_thr_lookup_paddr(uintptr_t); +struct kthr *kgdb_thr_lookup_taddr(uintptr_t); +struct kthr *kgdb_thr_next(struct kthr *); +const char *kgdb_thr_extra_thread_info(int); + +enum gdb_osabi fbsd_kernel_osabi_sniffer(bfd *abfd); +void fbsd_vmcore_set_supply_pcb (struct gdbarch *gdbarch, + void (*supply_pcb) (struct regcache *, + CORE_ADDR)); +void fbsd_vmcore_set_cpu_pcb_addr (struct gdbarch *gdbarch, + CORE_ADDR (*cpu_pcb_addr) (u_int)); + +CORE_ADDR kgdb_lookup(const char *sym); + +#endif /* _KGDB_H_ */ diff --git a/devel/gdb/files/kgdb/mipsfbsd-kern.c b/devel/gdb/files/kgdb/mipsfbsd-kern.c new file mode 100644 index 00000000..80d1527c --- /dev/null +++ b/devel/gdb/files/kgdb/mipsfbsd-kern.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2007 Juniper Networks, Inc. + * Copyright (c) 2004 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * from: src/gnu/usr.bin/gdb/kgdb/trgt_alpha.c,v 1.2.2.1 2005/09/15 05:32:10 marcel + */ + +#include +__FBSDID("$FreeBSD: head/gnu/usr.bin/gdb/kgdb/trgt_mips.c 249878 2013-04-25 04:53:01Z imp $"); + +#include "defs.h" +#include "frame-unwind.h" +#include "osabi.h" +#include "regcache.h" +#include "solib.h" +#include "trad-frame.h" +#include "mips-tdep.h" + +#ifdef __mips__ +#include +#include +#include +#endif + +#include "kgdb.h" + +/* Size of struct trapframe in registers. */ +#define TRAPFRAME_WORDS 74 + +/* From sys/mips/include/pcb.h. Offsets in the pcb_context[] array. */ +#define FBSD_PCB_REG_S0 0 +#define FBSD_PCB_REG_S1 1 +#define FBSD_PCB_REG_S2 2 +#define FBSD_PCB_REG_S3 3 +#define FBSD_PCB_REG_S4 4 +#define FBSD_PCB_REG_S5 5 +#define FBSD_PCB_REG_S6 6 +#define FBSD_PCB_REG_S7 7 +#define FBSD_PCB_REG_SP 8 +#define FBSD_PCB_REG_S8 9 +#define FBSD_PCB_REG_RA 10 +#define FBSD_PCB_REG_SR 11 +#define FBSD_PCB_REG_GP 12 +#define FBSD_PCB_REG_PC 13 + +#ifdef __mips__ +_Static_assert(TRAPFRAME_WORDS * sizeof(register_t) == + sizeof(struct trapframe), "TRAPFRAME_WORDS mismatch"); +_Static_assert(FBSD_PCB_REG_S0 == PCB_REG_S0, "PCB_REG_S0 mismatch"); +_Static_assert(FBSD_PCB_REG_S1 == PCB_REG_S1, "PCB_REG_S1 mismatch"); +_Static_assert(FBSD_PCB_REG_S2 == PCB_REG_S2, "PCB_REG_S2 mismatch"); +_Static_assert(FBSD_PCB_REG_S3 == PCB_REG_S3, "PCB_REG_S3 mismatch"); +_Static_assert(FBSD_PCB_REG_S4 == PCB_REG_S4, "PCB_REG_S4 mismatch"); +_Static_assert(FBSD_PCB_REG_S5 == PCB_REG_S5, "PCB_REG_S5 mismatch"); +_Static_assert(FBSD_PCB_REG_S6 == PCB_REG_S6, "PCB_REG_S6 mismatch"); +_Static_assert(FBSD_PCB_REG_S7 == PCB_REG_S7, "PCB_REG_S7 mismatch"); +_Static_assert(FBSD_PCB_REG_SP == PCB_REG_SP, "PCB_REG_SP mismatch"); +_Static_assert(FBSD_PCB_REG_S8 == PCB_REG_S8, "PCB_REG_S8 mismatch"); +_Static_assert(FBSD_PCB_REG_RA == PCB_REG_RA, "PCB_REG_RA mismatch"); +_Static_assert(FBSD_PCB_REG_SR == PCB_REG_SR, "PCB_REG_SR mismatch"); +_Static_assert(FBSD_PCB_REG_GP == PCB_REG_GP, "PCB_REG_GP mismatch"); +_Static_assert(FBSD_PCB_REG_PC == PCB_REG_PC, "PCB_REG_PC mismatch"); +#endif + +static void +mipsfbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr) +{ + struct gdbarch *gdbarch = regcache->arch (); + size_t regsize = mips_isa_regsize (gdbarch); + gdb_byte buf[regsize * (FBSD_PCB_REG_PC + 1)]; + + /* Read the entire pcb_context[] array in one go. The pcb_context[] + array is after the pcb_regs member which is a trapframe. */ + if (target_read_memory (pcb_addr + TRAPFRAME_WORDS * regsize, buf, + sizeof(buf)) != 0) + return; + + regcache->raw_supply_unsigned (MIPS_ZERO_REGNUM, 0); + regcache->raw_supply (MIPS_S2_REGNUM - 2, + buf + (regsize * FBSD_PCB_REG_S0)); + regcache->raw_supply (MIPS_S2_REGNUM - 1, + buf + (regsize * FBSD_PCB_REG_S1)); + regcache->raw_supply (MIPS_S2_REGNUM, + buf + (regsize * FBSD_PCB_REG_S2)); + regcache->raw_supply (MIPS_S2_REGNUM + 1, + buf + (regsize * FBSD_PCB_REG_S3)); + regcache->raw_supply (MIPS_S2_REGNUM + 2, + buf + (regsize * FBSD_PCB_REG_S4)); + regcache->raw_supply (MIPS_S2_REGNUM + 3, + buf + (regsize * FBSD_PCB_REG_S5)); + regcache->raw_supply (MIPS_S2_REGNUM + 4, + buf + (regsize * FBSD_PCB_REG_S6)); + regcache->raw_supply (MIPS_S2_REGNUM + 5, + buf + (regsize * FBSD_PCB_REG_S7)); + regcache->raw_supply (MIPS_SP_REGNUM, + buf + (regsize * FBSD_PCB_REG_SP)); + regcache->raw_supply (MIPS_S2_REGNUM + 6, + buf + (regsize * FBSD_PCB_REG_S8)); + regcache->raw_supply (MIPS_RA_REGNUM, + buf + (regsize * FBSD_PCB_REG_RA)); + regcache->raw_supply (MIPS_PS_REGNUM, + buf + (regsize * FBSD_PCB_REG_SR)); + regcache->raw_supply (MIPS_GP_REGNUM, + buf + (regsize * FBSD_PCB_REG_GP)); + regcache->raw_supply (MIPS_EMBED_PC_REGNUM, + buf + (regsize * FBSD_PCB_REG_PC)); +} + +static struct trad_frame_cache * +mipsfbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + size_t regsize = mips_isa_regsize (gdbarch); + struct trad_frame_cache *cache; + CORE_ADDR addr, func, sp; + int regnum; + + if (*this_cache != NULL) + return ((struct trad_frame_cache *)*this_cache); + + cache = trad_frame_cache_zalloc (this_frame); + *this_cache = cache; + + func = get_frame_func (this_frame); + sp = get_frame_register_signed (this_frame, + MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch)); + + /* Skip over CALLFRAME_SIZ. */ + addr = sp; + if (regsize == 8) + addr += regsize * 4; + else + addr += regsize * (4 + 2); + + /* GPRs. Skip zero. */ + addr += regsize; + for (regnum = MIPS_AT_REGNUM; regnum <= MIPS_RA_REGNUM; regnum++) + { + trad_frame_set_reg_addr (cache, + regnum + gdbarch_num_regs (gdbarch), + addr); + addr += regsize; + } + + regnum = MIPS_PS_REGNUM; + trad_frame_set_reg_addr (cache, + regnum + gdbarch_num_regs (gdbarch), + addr); + addr += regsize; + + /* HI and LO. */ + regnum = mips_regnum (gdbarch)->lo; + trad_frame_set_reg_addr (cache, + regnum + gdbarch_num_regs (gdbarch), + addr); + addr += regsize; + regnum = mips_regnum (gdbarch)->hi; + trad_frame_set_reg_addr (cache, + regnum + gdbarch_num_regs (gdbarch), + addr); + addr += regsize; + + /* BADVADDR. */ + regnum = mips_regnum (gdbarch)->badvaddr; + trad_frame_set_reg_addr (cache, + regnum + gdbarch_num_regs (gdbarch), + addr); + addr += regsize; + + /* CAUSE. */ + regnum = mips_regnum (gdbarch)->cause; + trad_frame_set_reg_addr (cache, + regnum + gdbarch_num_regs (gdbarch), + addr); + addr += regsize; + + /* PC. */ + regnum = mips_regnum (gdbarch)->pc; + trad_frame_set_reg_addr (cache, + regnum + gdbarch_num_regs (gdbarch), + addr); + + trad_frame_set_id (cache, frame_id_build (sp + TRAPFRAME_WORDS * regsize, + func)); + return cache; +} + +static void +mipsfbsd_trapframe_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + struct trad_frame_cache *cache = + mipsfbsd_trapframe_cache (this_frame, this_cache); + + trad_frame_get_id (cache, this_id); +} + +static struct value * +mipsfbsd_trapframe_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct trad_frame_cache *cache = + mipsfbsd_trapframe_cache (this_frame, this_cache); + + return trad_frame_get_register (cache, this_frame, regnum); +} + +static int +mipsfbsd_trapframe_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + const char *name; + + find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL); + return (name && ((strcmp(name, "MipsKernIntr") == 0) || + (strcmp(name, "MipsKernGenException") == 0) || + (strcmp(name, "MipsTLBInvalidException") == 0))); +} + +static const struct frame_unwind mipsfbsd_trapframe_unwind = { + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + mipsfbsd_trapframe_this_id, + mipsfbsd_trapframe_prev_register, + NULL, + mipsfbsd_trapframe_sniffer +}; + +static void +mipsfbsd_kernel_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + enum mips_abi abi = mips_abi (gdbarch); + + set_gdbarch_software_single_step (gdbarch, mips_software_single_step); + + switch (abi) + { + case MIPS_ABI_O32: + break; + case MIPS_ABI_N32: + set_gdbarch_long_double_bit (gdbarch, 128); + /* These floatformats should probably be renamed. MIPS uses + the same 128-bit IEEE floating point format that IA-64 uses, + except that the quiet/signalling NaN bit is reversed (GDB + does not distinguish between quiet and signalling NaNs). */ + set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad); + break; + case MIPS_ABI_N64: + set_gdbarch_long_double_bit (gdbarch, 128); + /* These floatformats should probably be renamed. MIPS uses + the same 128-bit IEEE floating point format that IA-64 uses, + except that the quiet/signalling NaN bit is reversed (GDB + does not distinguish between quiet and signalling NaNs). */ + set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad); + break; + } + + frame_unwind_prepend_unwinder (gdbarch, &mipsfbsd_trapframe_unwind); + + set_solib_ops (gdbarch, &kld_so_ops); + + fbsd_vmcore_set_supply_pcb (gdbarch, mipsfbsd_supply_pcb); + fbsd_vmcore_set_cpu_pcb_addr (gdbarch, kgdb_trgt_stop_pcb); +} + +void +_initialize_mips_kgdb_tdep (void) +{ + gdbarch_register_osabi_sniffer(bfd_arch_mips, + bfd_target_elf_flavour, + fbsd_kernel_osabi_sniffer); + gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD_KERNEL, + mipsfbsd_kernel_init_abi); +} diff --git a/devel/gdb/files/kgdb/ppcfbsd-kern.c b/devel/gdb/files/kgdb/ppcfbsd-kern.c new file mode 100644 index 00000000..0a3ad866 --- /dev/null +++ b/devel/gdb/files/kgdb/ppcfbsd-kern.c @@ -0,0 +1,248 @@ +/*- + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: head/devel/gdb/files/kgdb/ppcfbsd-kern.c 503200 2019-06-01 00:44:08Z jhb $"); + +#include "defs.h" +#include "frame-unwind.h" +#include "gdbcore.h" +#include "osabi.h" +#include "regcache.h" +#include "solib.h" +#include "symtab.h" +#include "trad-frame.h" +#include "ppc-tdep.h" +#include "ppc64-tdep.h" + +#ifdef __powerpc__ +#include +#include +#endif + +#include "kgdb.h" + +#ifdef __powerpc__ +static void +ppcfbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr) +{ + struct pcb pcb; + struct gdbarch_tdep *tdep; + int i; + + tdep = gdbarch_tdep (regcache->arch ()); + + if (target_read_memory(pcb_addr, (gdb_byte *)&pcb, sizeof(pcb)) != 0) + memset(&pcb, 0, sizeof(pcb)); + + /* + * r14-r31 are saved in the pcb + */ + for (i = 14; i <= 31; i++) { + regcache->raw_supply(tdep->ppc_gp0_regnum + i, + (char *)&pcb.pcb_context[i]); + } + + /* r1 is saved in the sp field */ + regcache->raw_supply(tdep->ppc_gp0_regnum + 1, + (char *)&pcb.pcb_sp); + if (tdep->wordsize == 8) + /* r2 is saved in the toc field */ + regcache->raw_supply(tdep->ppc_gp0_regnum + 2, + (char *)&pcb.pcb_toc); + + regcache->raw_supply(tdep->ppc_lr_regnum, (char *)&pcb.pcb_lr); + regcache->raw_supply(tdep->ppc_cr_regnum, (char *)&pcb.pcb_cr); +} +#endif + +#define OFF_FIXREG 0 +#define OFF_LR 32 +#define OFF_CR 33 +#define OFF_XER 34 +#define OFF_CTR 35 +#define OFF_SRR0 36 +#define TRAPFRAME_SIZE 42 + +#ifdef __powerpc__ +_Static_assert(sizeof(struct trapframe) == TRAPFRAME_SIZE * sizeof(register_t), + "trapframe size"); +_Static_assert(offsetof(struct trapframe, fixreg) + == OFF_FIXREG * sizeof(register_t), "fixreg offset"); +_Static_assert(offsetof(struct trapframe, lr) == OFF_LR * sizeof(register_t), + "lr offset"); +_Static_assert(offsetof(struct trapframe, cr) == OFF_CR * sizeof(register_t), + "cr offset"); +_Static_assert(offsetof(struct trapframe, xer) == OFF_XER * sizeof(register_t), + "xer offset"); +_Static_assert(offsetof(struct trapframe, ctr) == OFF_CTR * sizeof(register_t), + "ctr offset"); +_Static_assert(offsetof(struct trapframe, srr0) + == OFF_SRR0 * sizeof(register_t), "srr0 offset"); +#endif + +static struct trad_frame_cache * +ppcfbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct trad_frame_cache *cache; + CORE_ADDR base; + int i; + + if (*this_cache) + return (struct trad_frame_cache *)*this_cache; + + cache = trad_frame_cache_zalloc (this_frame); + *this_cache = cache; + + base = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch)); + if (tdep->wordsize == 8) + base += 48; + else + base += 8; + + for (i = 0; i < ppc_num_gprs; i++) + trad_frame_set_reg_addr (cache, tdep->ppc_gp0_regnum + i, base + + (OFF_FIXREG + i) * tdep->wordsize); + trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, base + + OFF_LR * tdep->wordsize); + trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, base + + OFF_CR * tdep->wordsize); + trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, base + + OFF_XER * tdep->wordsize); + trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, base + + OFF_CTR * tdep->wordsize); + /* SRR0? */ + trad_frame_set_reg_addr (cache, gdbarch_pc_regnum (gdbarch), base + + OFF_SRR0 * tdep->wordsize); + + /* Construct the frame ID using the function start. */ + trad_frame_set_id (cache, frame_id_build (base, get_frame_func (this_frame))); + + return cache; +} + +static void +ppcfbsd_trapframe_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + struct trad_frame_cache *cache = + ppcfbsd_trapframe_cache (this_frame, this_cache); + + trad_frame_get_id (cache, this_id); +} + +static struct value * +ppcfbsd_trapframe_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct trad_frame_cache *cache = + ppcfbsd_trapframe_cache (this_frame, this_cache); + + return trad_frame_get_register (cache, this_frame, regnum); +} + +static int +ppcfbsd_trapframe_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_cache) +{ + CORE_ADDR pc; + const char *name; + + pc = get_frame_func (this_frame); + find_pc_partial_function (pc, &name, NULL, NULL); + if (name && (strcmp(name, "asttrapexit") == 0 + || strcmp(name, "trapexit") == 0)) + return 1; + + return 0; +} + +static const struct frame_unwind ppcfbsd_trapframe_unwind = +{ + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + ppcfbsd_trapframe_this_id, + ppcfbsd_trapframe_prev_register, + NULL, + ppcfbsd_trapframe_sniffer +}; + +static void +ppcfbsd_kernel_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + frame_unwind_prepend_unwinder(gdbarch, &ppcfbsd_trapframe_unwind); + + set_solib_ops(gdbarch, &kld_so_ops); + +#ifdef __powerpc__ + if (tdep->wordsize == sizeof(register_t)) + { + fbsd_vmcore_set_supply_pcb(gdbarch, ppcfbsd_supply_pcb); + fbsd_vmcore_set_cpu_pcb_addr(gdbarch, kgdb_trgt_stop_pcb); + } +#endif + + /* FreeBSD doesn't support the 128-bit `long double' from the psABI. */ + set_gdbarch_long_double_bit (gdbarch, 64); + set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double); + + if (tdep->wordsize == 4) + { + set_gdbarch_return_value (gdbarch, ppc_sysv_abi_broken_return_value); + } + + if (tdep->wordsize == 8) + { + set_gdbarch_convert_from_func_ptr_addr + (gdbarch, ppc64_convert_from_func_ptr_addr); + set_gdbarch_elf_make_msymbol_special (gdbarch, + ppc64_elf_make_msymbol_special); + } +} + +void +_initialize_ppc_kgdb_tdep(void) +{ + gdbarch_register_osabi_sniffer(bfd_arch_powerpc, + bfd_target_elf_flavour, + fbsd_kernel_osabi_sniffer); + gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc, + GDB_OSABI_FREEBSD_KERNEL, ppcfbsd_kernel_init_abi); + gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc64, + GDB_OSABI_FREEBSD_KERNEL, ppcfbsd_kernel_init_abi); + + /* Not sure about this one. */ + gdbarch_register_osabi_sniffer(bfd_arch_rs6000, + bfd_target_elf_flavour, + fbsd_kernel_osabi_sniffer); + gdbarch_register_osabi (bfd_arch_rs6000, 0, + GDB_OSABI_FREEBSD_KERNEL, ppcfbsd_kernel_init_abi); +} diff --git a/devel/gdb/files/kgdb/riscv-fbsd-kern.c b/devel/gdb/files/kgdb/riscv-fbsd-kern.c new file mode 100644 index 00000000..8df24bd7 --- /dev/null +++ b/devel/gdb/files/kgdb/riscv-fbsd-kern.c @@ -0,0 +1,210 @@ +/*- + * Copyright (c) 2018 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/devel/gdb/files/kgdb/riscv-fbsd-kern.c 503200 2019-06-01 00:44:08Z jhb $ + */ + +/* Target-dependent code for FreeBSD/riscv64 kernels. */ + +#include "defs.h" + +#include "riscv-tdep.h" +#include "frame-unwind.h" +#include "gdbcore.h" +#include "osabi.h" +#include "regcache.h" +#include "regset.h" +#include "solib.h" +#include "target.h" +#include "trad-frame.h" + +#include "kgdb.h" + +static const struct regcache_map_entry riscv_fbsd_pcbmap[] = + { + { 1, RISCV_RA_REGNUM, 0 }, + { 1, RISCV_SP_REGNUM, 0 }, + { 1, RISCV_GP_REGNUM, 0 }, + { 1, RISCV_TP_REGNUM, 0 }, + { 3, 5, 0 }, /* t0 - t2 */ + { 4, 28, 0 }, /* t3 - t6 */ + { 2, RISCV_FP_REGNUM, 0 }, /* s0 - s1 */ + { 10, 18, 0 }, /* s2 - s11 */ + { 8, RISCV_A0_REGNUM, 0 }, /* a0 - a7 */ + { 0 } + }; + +static const struct regset riscv_fbsd_pcbregset = + { + riscv_fbsd_pcbmap, + regcache_supply_regset, regcache_collect_regset + }; + +static void +riscv_fbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr) +{ + gdb_byte buf[31 * 8]; + + /* Always give a value for PC in case the PCB isn't readable. */ + regcache->raw_supply_zeroed (RISCV_PC_REGNUM); + regcache->raw_supply_zeroed (RISCV_ZERO_REGNUM); + if (target_read_memory (pcb_addr, buf, sizeof buf) == 0) + { + regcache->supply_regset (&riscv_fbsd_pcbregset, -1, buf, + sizeof (buf)); + + /* Supply the RA as PC as well to simulate the PC as if the + thread had just returned. */ + regcache->raw_supply (RISCV_PC_REGNUM, buf); + } +} + +static const struct regcache_map_entry riscv_fbsd_tfmap[] = + { + { 1, RISCV_RA_REGNUM, 0 }, + { 1, RISCV_SP_REGNUM, 0 }, + { 1, RISCV_GP_REGNUM, 0 }, + { 1, RISCV_TP_REGNUM, 0 }, + { 3, 5, 0 }, /* t0 - t2 */ + { 4, 28, 0 }, /* t3 - t6 */ + { 2, RISCV_FP_REGNUM, 0 }, /* s0 - s1 */ + { 10, 18, 0 }, /* s2 - s11 */ + { 8, RISCV_A0_REGNUM, 0 }, /* a0 - a7 */ + { 1, RISCV_PC_REGNUM, 0 }, + { 1, RISCV_CSR_SSTATUS_REGNUM, 0 }, + { 1, RISCV_CSR_STVAL_REGNUM, 0 }, + { 1, RISCV_CSR_SCAUSE_REGNUM, 0 }, + { 0 } + }; + +static struct trad_frame_cache * +riscv_fbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct trad_frame_cache *cache; + CORE_ADDR func, pc, sp; + const char *name; + int xlen; + + if (*this_cache != NULL) + return ((struct trad_frame_cache *)*this_cache); + + cache = trad_frame_cache_zalloc (this_frame); + *this_cache = cache; + + sp = get_frame_register_unsigned (this_frame, RISCV_SP_REGNUM); + + xlen = riscv_isa_xlen (gdbarch); + trad_frame_set_reg_regmap (cache, riscv_fbsd_tfmap, sp, 35 * xlen); + + /* Read $PC from trap frame. */ + func = get_frame_func (this_frame); + find_pc_partial_function (func, &name, NULL, NULL); + pc = read_memory_unsigned_integer (sp + 31 * xlen, xlen, byte_order); + + if (pc == 0 && strcmp(name, "fork_trampoline") == 0) + { + /* Initial frame of a kthread; terminate backtrace. */ + trad_frame_set_id (cache, outer_frame_id); + } + else + { + /* Construct the frame ID using the function start. */ + trad_frame_set_id (cache, frame_id_build (sp + 35 * xlen, func)); + } + + return cache; +} + +static void +riscv_fbsd_trapframe_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + struct trad_frame_cache *cache = + riscv_fbsd_trapframe_cache (this_frame, this_cache); + + trad_frame_get_id (cache, this_id); +} + +static struct value * +riscv_fbsd_trapframe_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct trad_frame_cache *cache = + riscv_fbsd_trapframe_cache (this_frame, this_cache); + + return trad_frame_get_register (cache, this_frame, regnum); +} + +static int +riscv_fbsd_trapframe_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + const char *name; + + find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL); + return (name != NULL + && ((strcmp (name, "cpu_exception_handler_user") == 0) || + (strcmp (name, "cpu_exception_handler_supervisor") == 0))); +} + +static const struct frame_unwind riscv_fbsd_trapframe_unwind = { + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + riscv_fbsd_trapframe_this_id, + riscv_fbsd_trapframe_prev_register, + NULL, + riscv_fbsd_trapframe_sniffer +}; + +/* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ + +static void +riscv_fbsd_kernel_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + frame_unwind_prepend_unwinder (gdbarch, &riscv_fbsd_trapframe_unwind); + + set_solib_ops (gdbarch, &kld_so_ops); + + set_gdbarch_software_single_step (gdbarch, riscv_software_single_step); + + fbsd_vmcore_set_supply_pcb (gdbarch, riscv_fbsd_supply_pcb); + fbsd_vmcore_set_cpu_pcb_addr (gdbarch, kgdb_trgt_stop_pcb); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_riscv_kgdb_tdep; + +void +_initialize_riscv_kgdb_tdep (void) +{ + gdbarch_register_osabi_sniffer(bfd_arch_riscv, + bfd_target_elf_flavour, + fbsd_kernel_osabi_sniffer); + gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_FREEBSD_KERNEL, + riscv_fbsd_kernel_init_abi); +} diff --git a/devel/gdb/files/kgdb/sparc64fbsd-kern.c b/devel/gdb/files/kgdb/sparc64fbsd-kern.c new file mode 100644 index 00000000..3ce94352 --- /dev/null +++ b/devel/gdb/files/kgdb/sparc64fbsd-kern.c @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2004 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: head/devel/gdb/files/kgdb/sparc64fbsd-kern.c 464493 2018-03-14 14:33:21Z pizzamig $"); + +#include "defs.h" +#include "gdbcore.h" +#include "osabi.h" +#include "regcache.h" +#include "target.h" +#include "frame-unwind.h" +#include "solib.h" +#include "trad-frame.h" +#include "sparc-tdep.h" +#include "sparc64-tdep.h" + +#ifdef __sparc64__ +#include +#include +#include +#endif + +#include "kgdb.h" + +#ifdef __sparc64__ +static void +sparc64fbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr) +{ + struct pcb pcb; + + if (target_read_memory(pcb_addr, &pcb, sizeof(pcb)) != 0) + memset(&pcb, 0, sizeof(pcb)); + + regcache_raw_supply(regcache, SPARC_SP_REGNUM, (char *)&pcb.pcb_sp); + sparc_supply_rwindow(regcache, pcb.pcb_sp, -1); + regcache_raw_supply(regcache, SPARC64_PC_REGNUM, (char *)&pcb.pcb_pc); + pcb.pcb_pc += 4; + regcache_raw_supply(regcache, SPARC64_NPC_REGNUM, (char *)&pcb.pcb_pc); +} +#endif + +#define OFF_TF_SP (14 * 8) +#define OFF_TF_TPC (25 * 8) +#define OFF_TF_TNPC (24 * 8) +#define OFF_TF_OUT (8 * 8) +#define TRAPFRAME_SIZE (32 * 8) + +#ifdef __sparc64__ +_Static_assert(sizeof(struct trapframe) == TRAPFRAME_SIZE, "trapframe size"); +_Static_assert(offsetof(struct trapframe, tf_sp) == OFF_TF_SP, "tf_sp offset"); +_Static_assert(offsetof(struct trapframe, tf_tpc) == OFF_TF_TPC, + "tf_tpc offset"); +_Static_assert(offsetof(struct trapframe, tf_tnpc) == OFF_TF_TNPC, + "tf_tnpc offset"); +_Static_assert(offsetof(struct trapframe, tf_out) == OFF_TF_OUT, + "tf_out offset"); +#endif + +static struct sparc_frame_cache * +sparc64fbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache) +{ + struct sparc_frame_cache *cache; + CORE_ADDR fp, sp, trapframe_addr; + int regnum; + + if (*this_cache) + return (struct sparc_frame_cache *)*this_cache; + + cache = sparc_frame_cache (this_frame, this_cache); + gdb_assert (cache == *this_cache); + + fp = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM); + trapframe_addr = fp + BIAS - TRAPFRAME_SIZE; + sp = get_frame_register_unsigned (this_frame, SPARC_SP_REGNUM); + + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); + + cache->saved_regs[SPARC_SP_REGNUM].addr = trapframe_addr + OFF_TF_SP; +#ifdef notyet + cache->saved_regs[SPARC64_STATE_REGNUM].addr = trapframe_addr + OFF_TF_TSTATE; +#endif + cache->saved_regs[SPARC64_PC_REGNUM].addr = trapframe_addr + OFF_TF_TPC; + cache->saved_regs[SPARC64_NPC_REGNUM].addr = trapframe_addr + OFF_TF_TNPC; + for (regnum = SPARC_O0_REGNUM; regnum <= SPARC_O7_REGNUM; regnum++) + cache->saved_regs[regnum].addr = + trapframe_addr + OFF_TF_OUT + (regnum - SPARC_O0_REGNUM) * 8; + for (regnum = SPARC_L0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++) + cache->saved_regs[regnum].addr = + sp + BIAS + (regnum - SPARC_L0_REGNUM) * 8; + + return cache; +} + +static void +sparc64fbsd_trapframe_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + struct sparc_frame_cache *cache = + sparc64fbsd_trapframe_cache (this_frame, this_cache); + + (*this_id) = frame_id_build (cache->base, cache->pc); +} + +static struct value * +sparc64fbsd_trapframe_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct sparc_frame_cache *cache = + sparc64fbsd_trapframe_cache (this_frame, this_cache); + + return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum); +} + +static int +sparc64fbsd_trapframe_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_cache) +{ + CORE_ADDR pc; + const char *name; + + pc = get_frame_address_in_block (this_frame); + find_pc_partial_function (pc, &name, NULL, NULL); + if (name && (strcmp(name, "tl0_intr") == 0 + || strcmp(name, "tl0_trap") == 0 + || strcmp(name, "tl1_intr") == 0 + || strcmp(name, "tl1_trap") == 0)) + return 1; + + return 0; +} + +static const struct frame_unwind sparc64fbsd_trapframe_unwind = +{ + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + sparc64fbsd_trapframe_this_id, + sparc64fbsd_trapframe_prev_register, + NULL, + sparc64fbsd_trapframe_sniffer +}; + +#if 0 +struct kgdb_frame_cache { + CORE_ADDR pc; + CORE_ADDR sp; + CORE_ADDR fp; +}; + +static struct kgdb_frame_cache * +kgdb_trgt_frame_cache(struct frame_info *next_frame, void **this_cache) +{ + char buf[MAX_REGISTER_SIZE]; + struct kgdb_frame_cache *cache; + + cache = *this_cache; + if (cache == NULL) { + cache = FRAME_OBSTACK_ZALLOC(struct kgdb_frame_cache); + *this_cache = cache; + cache->pc = frame_func_unwind(next_frame); + frame_unwind_register(next_frame, SPARC_SP_REGNUM, buf); + cache->sp = extract_unsigned_integer(buf, + register_size(current_gdbarch, SPARC_SP_REGNUM)); + frame_unwind_register(next_frame, SPARC_FP_REGNUM, buf); + cache->fp = extract_unsigned_integer(buf, + register_size(current_gdbarch, SPARC_FP_REGNUM)); + cache->fp += BIAS - sizeof(struct trapframe); + } + return (cache); +} + +static void +kgdb_trgt_trapframe_this_id(struct frame_info *next_frame, void **this_cache, + struct frame_id *this_id) +{ + struct kgdb_frame_cache *cache; + + cache = kgdb_trgt_frame_cache(next_frame, this_cache); + *this_id = frame_id_build(cache->sp, cache->pc); +} + +static void +kgdb_trgt_trapframe_prev_register(struct frame_info *next_frame, + void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp, + CORE_ADDR *addrp, int *realnump, void *valuep) +{ + char dummy_valuep[MAX_REGISTER_SIZE]; + struct kgdb_frame_cache *cache; + int ofs, regsz; + + regsz = register_size(current_gdbarch, regnum); + + if (valuep == NULL) + valuep = dummy_valuep; + memset(valuep, 0, regsz); + *optimizedp = 0; + *addrp = 0; + *lvalp = not_lval; + *realnump = -1; + + cache = kgdb_trgt_frame_cache(next_frame, this_cache); + + switch (regnum) { + case SPARC_SP_REGNUM: + ofs = offsetof(struct trapframe, tf_sp); + break; + case SPARC64_PC_REGNUM: + ofs = offsetof(struct trapframe, tf_tpc); + break; + case SPARC64_NPC_REGNUM: + ofs = offsetof(struct trapframe, tf_tnpc); + break; + case SPARC_O0_REGNUM: + case SPARC_O1_REGNUM: + case SPARC_O2_REGNUM: + case SPARC_O3_REGNUM: + case SPARC_O4_REGNUM: + case SPARC_O5_REGNUM: + case SPARC_O7_REGNUM: + ofs = offsetof(struct trapframe, tf_out) + + (regnum - SPARC_O0_REGNUM) * 8; + break; + default: + if (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM) { + ofs = (regnum - SPARC_L0_REGNUM) * 8; + *addrp = cache->sp + BIAS + ofs; + *lvalp = lval_memory; + target_read_memory(*addrp, valuep, regsz); + } + return; + } + + *addrp = cache->fp + ofs; + *lvalp = lval_memory; + target_read_memory(*addrp, valuep, regsz); +} + +static const struct frame_unwind kgdb_trgt_trapframe_unwind = { + UNKNOWN_FRAME, + &kgdb_trgt_trapframe_this_id, + &kgdb_trgt_trapframe_prev_register +}; + +const struct frame_unwind * +kgdb_trgt_trapframe_sniffer(struct frame_info *next_frame) +{ + char *pname; + CORE_ADDR pc; + + pc = frame_func_unwind(next_frame); + pname = NULL; + find_pc_partial_function(pc, &pname, NULL, NULL); + if (pname == NULL) + return (NULL); + if (strcmp(pname, "tl0_intr") == 0 || + strcmp(pname, "tl0_trap") == 0 || + strcmp(pname, "tl1_intr") == 0 || + strcmp(pname, "tl1_trap") == 0) + return (&kgdb_trgt_trapframe_unwind); + /* printf("%s: %lx =%s\n", __func__, pc, pname); */ + return (NULL); +} +#endif + +static void +sparc64fbsd_kernel_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch) +{ + + sparc64_init_abi(info, gdbarch); + + frame_unwind_prepend_unwinder(gdbarch, &sparc64fbsd_trapframe_unwind); + + set_solib_ops(gdbarch, &kld_so_ops); + +#ifdef __sparc64__ + fbsd_vmcore_set_supply_pcb(gdbarch, sparc64fbsd_supply_pcb); + fbsd_vmcore_set_cpu_pcb_addr(gdbarch, kgdb_trgt_stop_pcb); +#endif +} + +void +_initialize_sparc64_kgdb_tdep(void) +{ + gdbarch_register_osabi_sniffer(bfd_arch_sparc, + bfd_target_elf_flavour, + fbsd_kernel_osabi_sniffer); + gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9, + GDB_OSABI_FREEBSD_KERNEL, sparc64fbsd_kernel_init_abi); +} + diff --git a/devel/gdb/files/patch-fixes b/devel/gdb/files/patch-fixes new file mode 100644 index 00000000..1d7714c9 --- /dev/null +++ b/devel/gdb/files/patch-fixes @@ -0,0 +1,10 @@ +--- gdb/compile/compile-loc2c.c.orig 2019-02-26 20:51:50.000000000 -0800 ++++ gdb/compile/compile-loc2c.c 2019-05-24 16:07:42.382379000 -0700 +@@ -657,6 +657,7 @@ do_compile_dwarf_expr_to_c (int indent, string_file *s + uint64_t uoffset, reg; + int64_t offset; + ++ uoffset = 0; + print_spaces (indent - 2, stream); + if (info[op_ptr - base].label) + { diff --git a/devel/gdb/files/patch-gdb_amd64-bsd-nat.c b/devel/gdb/files/patch-gdb_amd64-bsd-nat.c new file mode 100644 index 00000000..1f16ba31 --- /dev/null +++ b/devel/gdb/files/patch-gdb_amd64-bsd-nat.c @@ -0,0 +1,30 @@ +--- gdb/amd64-bsd-nat.c.orig 2017-09-14 09:28:17 UTC ++++ gdb/amd64-bsd-nat.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include "amd64-tdep.h" + #include "amd64-nat.h" +@@ -95,12 +96,19 @@ amd64bsd_store_inferior_registers (struct target_ops *ops, + if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum)) + { + struct reg regs; ++ register_t old_rflags; + + if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) ®s, 0) == -1) + perror_with_name (_("Couldn't get registers")); + ++ old_rflags = regs.r_rflags; + amd64_collect_native_gregset (regcache, ®s, regnum); + ++ /* This is a workaround about the PSL_USERCHANGE posix limitation. */ ++ if ((regs.r_rflags ^ old_rflags ) & ~PSL_USERCHANGE) ++ { ++ regs.r_rflags ^= (regs.r_rflags ^ old_rflags ) & ~PSL_USERCHANGE; ++ } + if (ptrace (PT_SETREGS, pid, (PTRACE_TYPE_ARG3) ®s, 0) == -1) + perror_with_name (_("Couldn't write registers")); + diff --git a/devel/gdb/files/patch-gdb_common_common-defs.h b/devel/gdb/files/patch-gdb_common_common-defs.h new file mode 100644 index 00000000..6d19eeb0 --- /dev/null +++ b/devel/gdb/files/patch-gdb_common_common-defs.h @@ -0,0 +1,18 @@ +--- gdb/common/common-defs.h.orig 2017-09-12 12:25:12 UTC ++++ gdb/common/common-defs.h +@@ -44,9 +44,15 @@ + + Must do this before including any system header, since other system + headers may include stdint.h/inttypes.h. */ ++#ifndef __STDC_CONSTANT_MACROS + #define __STDC_CONSTANT_MACROS 1 ++#endif ++#ifndef __STDC_LIMIT_MACROS + #define __STDC_LIMIT_MACROS 1 ++#endif ++#ifndef __STDC_FORMAT_MACROS + #define __STDC_FORMAT_MACROS 1 ++#endif + + #include + #include diff --git a/devel/gdb/files/patch-gdb_configure b/devel/gdb/files/patch-gdb_configure new file mode 100644 index 00000000..86fde3bb --- /dev/null +++ b/devel/gdb/files/patch-gdb_configure @@ -0,0 +1,16 @@ +--- gdb/configure.orig 2019-05-11 11:19:02.000000000 -0700 ++++ gdb/configure 2019-05-24 16:21:50.559870000 -0700 +@@ -15511,10 +15511,10 @@ fi + + # The options we'll try to enable. + build_warnings="-Wall -Wpointer-arith \ +--Wno-unused -Wunused-value -Wunused-variable -Wunused-function \ ++-Wno-unused \ + -Wno-switch -Wno-char-subscripts \ +--Wempty-body -Wunused-but-set-parameter -Wunused-but-set-variable \ +--Wno-sign-compare -Wno-error=maybe-uninitialized \ ++-Wempty-body \ ++-Wno-sign-compare \ + -Wno-mismatched-tags \ + -Wno-error=deprecated-register \ + -Wsuggest-override \ diff --git a/devel/gdb/files/patch-gdb_fbsd-nat.c b/devel/gdb/files/patch-gdb_fbsd-nat.c new file mode 100644 index 00000000..40fcdf0c --- /dev/null +++ b/devel/gdb/files/patch-gdb_fbsd-nat.c @@ -0,0 +1,17 @@ +--- gdb/fbsd-nat.c.orig 2019-05-11 11:19:03.000000000 -0700 ++++ gdb/fbsd-nat.c 2019-05-24 16:25:52.961523000 -0700 +@@ -1178,6 +1178,14 @@ fbsd_nat_target::resume (ptid_t ptid, int step, enum g + /* If ptid is a specific LWP, suspend all other LWPs in the process. */ + inferior *inf = find_inferior_ptid (ptid); + ++#ifndef PT_LWP_EVENTS ++ /* When LWP events are not supported, a new thread might already be ++ running that has not yet reported an event when GDB wishes to ++ only run a single thread. Force an update of the thread list ++ to ensure that any such threads are suspended before the process ++ is resumed. */ ++ fbsd_add_threads (ptid.pid ()); ++#endif + for (thread_info *tp : inf->non_exited_threads ()) + { + int request; diff --git a/devel/gdb/files/patch-gdb_gdb__wchar.h b/devel/gdb/files/patch-gdb_gdb__wchar.h new file mode 100644 index 00000000..16a58738 --- /dev/null +++ b/devel/gdb/files/patch-gdb_gdb__wchar.h @@ -0,0 +1,20 @@ +--- gdb/gdb_wchar.h.orig 2017-09-14 09:28:17 UTC ++++ gdb/gdb_wchar.h +@@ -59,7 +59,7 @@ + iconvlist. */ + #if defined (HAVE_ICONV) && defined (HAVE_BTOWC) \ + && (defined (__STDC_ISO_10646__) \ +- || (defined (_LIBICONV_VERSION) && _LIBICONV_VERSION >= 0x108)) ++ || (!defined (LIBICONV_PLUG) && defined (_LIBICONV_VERSION) && _LIBICONV_VERSION >= 0x108)) + + typedef wchar_t gdb_wchar_t; + typedef wint_t gdb_wint_t; +@@ -82,7 +82,7 @@ typedef wint_t gdb_wint_t; + #define INTERMEDIATE_ENCODING intermediate_encoding () + const char *intermediate_encoding (void); + +-#elif defined (_LIBICONV_VERSION) && _LIBICONV_VERSION >= 0x108 ++#elif !defined (LIBICONV_PLUG) && defined (_LIBICONV_VERSION) && _LIBICONV_VERSION >= 0x108 + #define INTERMEDIATE_ENCODING "wchar_t" + #else + /* This shouldn't happen, because the earlier #if should have filtered diff --git a/devel/gdb/files/patch-gdb_gnulib_import_stddef.in.h b/devel/gdb/files/patch-gdb_gnulib_import_stddef.in.h new file mode 100644 index 00000000..5cc0aca5 --- /dev/null +++ b/devel/gdb/files/patch-gdb_gnulib_import_stddef.in.h @@ -0,0 +1,11 @@ +--- gdb/gnulib/import/stddef.in.h.orig 2017-09-14 09:28:17 UTC ++++ gdb/gnulib/import/stddef.in.h +@@ -84,7 +84,7 @@ + /* Some platforms lack max_align_t. The check for _GCC_MAX_ALIGN_T is + a hack in case the configure-time test was done with g++ even though + we are currently compiling with gcc. */ +-#if ! (@HAVE_MAX_ALIGN_T@ || defined _GCC_MAX_ALIGN_T) ++#if 0 + /* On the x86, the maximum storage alignment of double, long, etc. is 4, + but GCC's C11 ABI for x86 says that max_align_t has an alignment of 8, + and the C11 standard allows this. Work around this problem by diff --git a/devel/gdb/files/patch-gdb_i386-fbsd-nat.c b/devel/gdb/files/patch-gdb_i386-fbsd-nat.c new file mode 100644 index 00000000..bba42ea4 --- /dev/null +++ b/devel/gdb/files/patch-gdb_i386-fbsd-nat.c @@ -0,0 +1,27 @@ +--- gdb/i386-fbsd-nat.c 2017-09-14 09:28:17 UTC ++++ gdb/i386-fbsd-nat.c +@@ -43,8 +43,6 @@ public: + const struct target_desc *read_description () override; + #endif + +- void resume (ptid_t, int, enum gdb_signal) override; +- + #if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO) + bool supports_stopped_by_hw_breakpoint () override; + #endif +@@ -52,6 +50,7 @@ public: + + static i386_fbsd_nat_target the_i386_fbsd_nat_target; + ++#if 0 + /* Resume execution of the inferior process. If STEP is nonzero, + single-step it. If SIGNAL is nonzero, give it that signal. */ + +@@ -98,6 +97,7 @@ i386_fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signal) + gdb_signal_to_host (signal)) == -1) + perror_with_name (("ptrace")); + } ++#endif + + + /* Support for debugging kernel virtual memory images. */ diff --git a/devel/gdb/files/patch-gdb_python_python-config.py b/devel/gdb/files/patch-gdb_python_python-config.py new file mode 100644 index 00000000..cec2729a --- /dev/null +++ b/devel/gdb/files/patch-gdb_python_python-config.py @@ -0,0 +1,11 @@ +--- gdb/python/python-config.py 2017-09-14 09:28:17 UTC ++++ gdb/python/python-config.py +@@ -59,6 +59,8 @@ for opt in opt_flags: + + elif opt in ('--libs', '--ldflags'): + libs = ['-lpython' + pyver + abiflags] ++ if getvar('LDFLAGS') is not None: ++ libs.extend(getvar('LDFLAGS').split()) + if getvar('LIBS') is not None: + libs.extend(getvar('LIBS').split()) + if getvar('SYSLIBS') is not None: diff --git a/devel/gdb/files/patch-include_libiberty.h b/devel/gdb/files/patch-include_libiberty.h new file mode 100644 index 00000000..26afe105 --- /dev/null +++ b/devel/gdb/files/patch-include_libiberty.h @@ -0,0 +1,11 @@ +--- include/libiberty.h 2017-09-14 09:28:17 UTC ++++ include/libiberty.h +@@ -109,7 +109,7 @@ + || defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) \ + || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (__MINGW32__) \ + || defined (__DragonFly__) || defined (HAVE_DECL_BASENAME) +-extern char *basename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1); ++#include + #else + /* Do not allow basename to be used if there is no prototype seen. We + either need to use the above prototype or have one from diff --git a/devel/gdb/files/patch-libiberty_configure b/devel/gdb/files/patch-libiberty_configure new file mode 100644 index 00000000..fb52c901 --- /dev/null +++ b/devel/gdb/files/patch-libiberty_configure @@ -0,0 +1,12 @@ +--- libiberty/configure.orig 2017-09-12 12:10:11 UTC ++++ libiberty/configure +@@ -4398,8 +4398,7 @@ + ac_libiberty_warn_cflags= + save_CFLAGS="$CFLAGS" + for real_option in -W -Wall -Wwrite-strings -Wc++-compat \ +- -Wstrict-prototypes \ +- -Wshadow=local; do ++ -Wstrict-prototypes ; do + # Do the check with the no- prefix removed since gcc silently + # accepts any -Wno-* option on purpose + case $real_option in diff --git a/devel/gdb/files/patch-unified b/devel/gdb/files/patch-unified new file mode 100644 index 00000000..eed2c26e --- /dev/null +++ b/devel/gdb/files/patch-unified @@ -0,0 +1,16 @@ +--- gdb/gdb.c.orig 2017-09-14 09:28:17 UTC ++++ gdb/gdb.c +@@ -28,6 +28,12 @@ main (int argc, char **argv) + memset (&args, 0, sizeof args); + args.argc = argc; + args.argv = argv; +- args.interpreter_p = INTERP_CONSOLE; ++ if (strncmp(basename(argv[0]), "insight", 7) == 0) { ++ args.interpreter_p = "insight"; ++ } else if (strncmp(basename(argv[0]), "gdbtui", 6) == 0) { ++ args.interpreter_p = INTERP_TUI; ++ } else { ++ args.interpreter_p = INTERP_CONSOLE; ++ } + return gdb_main (&args); + } diff --git a/devel/gdb/pkg-descr b/devel/gdb/pkg-descr new file mode 100644 index 00000000..3a1015f8 --- /dev/null +++ b/devel/gdb/pkg-descr @@ -0,0 +1,6 @@ +GDB is a source-level debugger for Ada, C, C++, Objective-C, Pascal and +many other languages. GDB can target (i.e., debug programs running on) +more than a dozen different processor architectures, and GDB itself can +run on most popular GNU/Linux, Unix and Microsoft Windows variants. + +WWW: http://www.gnu.org/software/gdb/ diff --git a/devel/gdb/pkg-plist b/devel/gdb/pkg-plist new file mode 100644 index 00000000..923e55e3 --- /dev/null +++ b/devel/gdb/pkg-plist @@ -0,0 +1,19 @@ +bin/gdb +man/man1/gdb.1.gz +share/gdb/syscalls/aarch64-linux.xml +share/gdb/syscalls/amd64-linux.xml +share/gdb/syscalls/arm-linux.xml +share/gdb/syscalls/freebsd.xml +share/gdb/syscalls/gdb-syscalls.dtd +share/gdb/syscalls/i386-linux.xml +share/gdb/syscalls/mips-n32-linux.xml +share/gdb/syscalls/mips-n64-linux.xml +share/gdb/syscalls/mips-o32-linux.xml +share/gdb/syscalls/ppc-linux.xml +share/gdb/syscalls/ppc64-linux.xml +share/gdb/syscalls/s390-linux.xml +share/gdb/syscalls/s390x-linux.xml +share/gdb/syscalls/sparc-linux.xml +share/gdb/syscalls/sparc64-linux.xml +@dir share/gdb/syscalls +@dir share/gdb