Compare commits

...

5 Commits

Author SHA1 Message Date
Markus Metzger
d26f3c1041 [wip] gdbserver, x86: support fs_base and gs_base
When debugging over gdbserver fs/gs_base is not updated when changing the
corresponding selector.

For 32-bit inferiors, fs/gs_base are now defined but not fetched.

Change-Id: I5a4d8637324ee5f0c303fdcc5eeb8ca50b96c577
Signed-off-by: Markus Metzger  <markus.t.metzger@intel.com>
2019-12-17 16:04:40 +01:00
Markus Metzger
db18e24c49 testsuite: add m32 board files
Add board files for running tests with 32-bit inferiors on 64-bit kernels.

Signed-off-by: Markus Metzger  <markus.t.metzger@intel.com>

gdb/testsuite/
	* boards/m32.exp: New.
	* boards/native-m32.exp: New.
	* boards/native-gdbserver-m32.exp: New.

Change-Id: I998416e7e431529238b8ebe5ecfd8dee2e0d9e81
2019-12-17 16:04:40 +01:00
Markus Metzger
03bad9e43d gdb, testsuite: test changing FS and GS segment selectors and bases
Signed-off-by: Markus Metzger  <markus.t.metzger@intel.com>

testsuite/
	* lib/gdb.exp (skip_fsgsbase_tests, skip_arch_set_fs_tests)
	(skip_arch_set_gs_tests): New.
	* gdb.arch/x86-fsgs.c: New.
	* gdb.arch/x86-fsgs.exp: New.

Change-Id: I7da32d4b57fd8b34153e7385263ec82318d32a98
2019-12-17 16:04:40 +01:00
Markus Metzger
3e7fa952aa x86: support fs_base and gs_base for 32-bit inferiors on 64-bit kernels
On Linux 64-bit kernels provide fs_base and gs_base also for 32-bit
inferiors.  Add support for those registers.

Also check for HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE consistently.

Signed-off-by: Markus Metzger  <markus.t.metzger@intel.com>

gdb/
	* amd64-linux-nat.c (amd64_linux_gregset32_reg_offset): Add FS_BASE
	and GS_BASE offsets.
	* amd64-linux-tdep.c (amd64_linux_gregset_reg_offset): Check
	HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE.
	(amd64_linux_read_description): Enable segments if
	HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE.
	* i386-linux-tdep.c (i386_linux_gregset_reg_offset): Add -1 for
	FS_BASE and GS_BASE offsets.
	(i386_linux_read_description): Enable segments if
	HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE.
	* i386-linux-tdep.h (I386_LINUX_ORIG_EAX_REGNUM): Update.

Change-Id: I030b500a7a5b087452a78c3e0545d6e6e65146aa
2019-12-17 15:37:30 +01:00
Markus Metzger
9db9f4a7a1 gdb, testsuite: add gdb_continue_to_breakpoint pattern
When setting a breakpoint on a function foo, GDB prints

    Breakpoint 1, foo (...) at ...

Add a gdb_test_multiple pattern in gdb_continue_to_breakpoint to allow
defining the function name as location_pattern.

Signed-off-by: Markus Metzger  <markus.t.metzger@intel.com>

testsuite/
	* lib/gdb.exp (gdb_continue_to_breakpoint): Add pattern.

Change-Id: I07f9389e1c9ff04891869fa223e144ea9d5097f3
2019-12-17 15:37:30 +01:00
13 changed files with 851 additions and 8 deletions

View File

@@ -85,6 +85,11 @@ static int amd64_linux_gregset32_reg_offset[] =
-1, -1, -1, -1, -1, -1, -1, -1, /* k0 ... k7 (AVX512) */
-1, -1, -1, -1, -1, -1, -1, -1, /* zmm0 ... zmm7 (AVX512) */
-1, /* PKEYS register PKRU */
#ifdef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE
FS_BASE * 8, GS_BASE * 8, /* fs_base and gs_base */
#else
-1, -1, /* fs_base and gs_base */
#endif
ORIG_RAX * 8 /* "orig_eax" */
};

View File

@@ -98,7 +98,11 @@ int amd64_linux_gregset_reg_offset[] =
-1, /* PKEYS register pkru */
/* End of hardware registers */
#ifdef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE
21 * 8, 22 * 8, /* fs_base and gs_base. */
#else
-1, -1, /* fs_base and gs_base. */
#endif
15 * 8 /* "orig_rax" */
};
@@ -1593,9 +1597,15 @@ amd64_linux_read_description (uint64_t xcr0_features_bit, bool is_x32)
[(xcr0_features_bit & X86_XSTATE_PKRU) ? 1 : 0];
}
#ifdef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE
const bool segment = true;
#else
const bool segment = false;
#endif
if (*tdesc == NULL)
*tdesc = amd64_create_target_description (xcr0_features_bit, is_x32,
true, true);
true, segment);
return *tdesc;
}

View File

@@ -133,7 +133,7 @@ static const int x86_64_regmap[] =
-1, -1, -1, -1, -1, -1, -1, -1,
ORIG_RAX * 8,
#ifdef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE
21 * 8, 22 * 8,
FS_BASE * 8, GS_BASE * 8,
#else
-1, -1,
#endif

View File

@@ -87,7 +87,13 @@ i386_linux_read_description (uint64_t xcr0)
if (*tdesc == NULL)
{
*tdesc = i386_create_target_description (xcr0, true, false);
#ifdef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE
const bool segment = true;
#else
const bool segment = false;
#endif
*tdesc = i386_create_target_description (xcr0, true, segment);
init_target_desc (*tdesc, i386_expedite_regs);
}
@@ -118,7 +124,13 @@ amd64_linux_read_description (uint64_t xcr0, bool is_x32)
if (*tdesc == NULL)
{
*tdesc = amd64_create_target_description (xcr0, is_x32, true, true);
#ifdef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE
const bool segment = true;
#else
const bool segment = false;
#endif
*tdesc = amd64_create_target_description (xcr0, is_x32, true, segment);
init_target_desc (*tdesc, amd64_expedite_regs);
}

View File

@@ -609,6 +609,7 @@ int i386_linux_gregset_reg_offset[] =
-1, -1, -1, -1, -1, -1, -1, -1, /* k0 ... k7 (AVX512) */
-1, -1, -1, -1, -1, -1, -1, -1, /* zmm0 ... zmm7 (AVX512) */
-1, /* PKRU register */
-1, -1, /* fs_base and gs_base. */
11 * 4, /* "orig_eax" */
};
@@ -692,8 +693,14 @@ i386_linux_read_description (uint64_t xcr0)
[(xcr0 & X86_XSTATE_AVX512) ? 1 : 0]
[(xcr0 & X86_XSTATE_PKRU) ? 1 : 0];
#ifdef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE
const bool segment = true;
#else
const bool segment = false;
#endif
if (*tdesc == NULL)
*tdesc = i386_create_target_description (xcr0, true, false);
*tdesc = i386_create_target_description (xcr0, true, segment);
return *tdesc;
}

View File

@@ -29,7 +29,7 @@
/* Register number for the "orig_eax" pseudo-register. If this
pseudo-register contains a value >= 0 it is interpreted as the
system call number that the kernel is supposed to restart. */
#define I386_LINUX_ORIG_EAX_REGNUM (I386_PKRU_REGNUM + 1)
#define I386_LINUX_ORIG_EAX_REGNUM (I386_GSBASE_REGNUM + 1)
/* Total number of registers for GNU/Linux. */
#define I386_LINUX_NUM_REGS (I386_LINUX_ORIG_EAX_REGNUM + 1)

View File

@@ -0,0 +1,17 @@
# Copyright 2019 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set_board_info cflags "-m32"
set_board_info cppflags "-m32"

View File

@@ -0,0 +1,24 @@
# Copyright 2019 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This file is a dejagnu "board file" and is used to run the testsuite
# natively with gdbserver using 32-bit inferiors on 64-bit kernels.
#
# To use this file:
# bash$ cd ${build_dir}/gdb
# bash$ make check RUNTESTFLAGS="--target_board=native-gdbserver-m32"
load_board_description "native-gdbserver"
load_board_description "m32"

View File

@@ -0,0 +1,27 @@
# Copyright 2019 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This file is a dejagnu "board file" and is used to run the testsuite
# natively using 32-bit inferiors on 64-bit kernels.
#
# To use this file:
# bash$ cd ${build_dir}/gdb
# bash$ make check RUNTESTFLAGS="--target_board=native-m32"
load_board_description "local-board"
load_board_description "m32"
# The default compiler for this target.
set_board_info compiler "[find_gcc]"

View File

@@ -0,0 +1,262 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2019 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <asm/ldt.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#if HAVE_ARCH_SET_FS || HAVE_ARCH_SET_GS
# include <asm/prctl.h>
# include <sys/prctl.h>
#endif /* HAVE_ARCH_SET_FS || HAVE_ARCH_SET_GS */
struct segs {
int initial;
int other;
int twentythree;
};
static struct segs *segs;
static unsigned int
setup_ldt (unsigned int entry, void *base, size_t size)
{
struct user_desc ud;
int errcode;
memset (&ud, 0, sizeof (ud));
ud.entry_number = entry;
ud.base_addr = (unsigned int) (unsigned long) base;
ud.limit = (unsigned int) size;
/* The base is 32-bit. */
if ((unsigned long) ud.base_addr != (unsigned long) base)
return 0u;
errcode = syscall(SYS_modify_ldt, 1, &ud, sizeof(ud));
if (errcode != 0)
return 0u;
return (ud.entry_number << 3) | 7;
}
int
read_fs (void)
{
int value;
__asm__ volatile ("mov %%fs:0x0, %0" : "=rm"(value) :: "memory");
return value;
}
int
read_gs (void)
{
int value;
__asm__ volatile ("mov %%gs:0x0, %0" : "=rm"(value) :: "memory");
return value;
}
int
switch_fs_read (unsigned int fs)
{
__asm__ volatile ("mov %0, %%fs" :: "rm"(fs) : "memory");
return read_fs ();
}
void
test_fs (unsigned int selector)
{
int value;
value = switch_fs_read (selector); /* l.1 */
value = read_fs (); /* l.2 */
value = read_fs (); /* l.3 */
} /* l.4 */
int
switch_gs_read (unsigned int gs)
{
__asm__ volatile ("mov %0, %%gs" :: "rm"(gs) : "memory");
return read_gs ();
}
void
test_gs (unsigned int selector)
{
int value;
value = switch_gs_read (selector); /* l.1 */
value = read_gs (); /* l.2 */
value = read_gs (); /* l.3 */
} /* l.4 */
#if HAVE_WRFSGSBASE
int
wrfsbase_read (void *fsbase)
{
__asm__ volatile ("wrfsbase %0" :: "r"(fsbase) : "memory");
return read_fs ();
}
static void
test_wrfsbase (void *base)
{
int value;
value = wrfsbase_read (base); /* l.1 */
value = read_fs (); /* l.2 */
value = read_fs (); /* l.3 */
} /* l.4 */
int
wrgsbase_read (void *gsbase)
{
__asm__ volatile ("wrgsbase %0" :: "r"(gsbase) : "memory");
return read_gs ();
}
static void
test_wrgsbase (void *base)
{
int value;
value = wrgsbase_read (base); /* l.1 */
value = read_gs (); /* l.2 */
value = read_gs (); /* l.3 */
} /* l.4 */
#endif /* HAVE_WRFSGSBASE */
#if HAVE_ARCH_SET_FS
int
arch_set_fs_read (void *fsbase)
{
int errcode;
errcode = syscall (SYS_arch_prctl, ARCH_SET_FS, fsbase);
if (errcode != 0)
return 0;
return read_fs ();
}
static void
test_arch_set_fs (void *base)
{
int value;
value = arch_set_fs_read (base); /* l.1 */
value = read_fs (); /* l.2 */
value = read_fs (); /* l.3 */
} /* l.4 */
#endif /* HAVE_ARCH_SET_FS */
#if HAVE_ARCH_SET_GS
int
arch_set_gs_read (void *gsbase)
{
int errcode;
errcode = syscall (SYS_arch_prctl, ARCH_SET_GS, gsbase);
if (errcode != 0)
return 0;
return read_gs ();
}
static void
test_arch_set_gs (void *base)
{
int value;
value = arch_set_gs_read (base); /* l.1 */
value = read_gs (); /* l.2 */
value = read_gs (); /* l.3 */
} /* l.4 */
#endif /* HAVE_ARCH_SET_GS */
int
main (void)
{
unsigned int selector;
segs = mmap (NULL, sizeof (*segs), PROT_READ | PROT_WRITE,
#ifdef __x86_64__
MAP_32BIT |
#endif
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (segs == MAP_FAILED)
{
perror ("failed to mmap 32-bit memory");
abort ();
}
segs->initial = 42;
segs->other = -42;
segs->twentythree = 23;
selector = setup_ldt (0xb7 >> 3, &segs->other, sizeof (segs->other));
if (selector == 0u)
{
perror ("failed to setup LDT[0xb7>>3] = &segs->other");
abort ();
}
selector = setup_ldt (0xa7 >> 3, &segs->initial, sizeof (segs->initial));
if (selector == 0u)
{
perror ("failed to setup LDT[0xa7>>3] = &segs->initial");
abort ();
}
test_fs (selector);
test_gs (selector);
#if HAVE_ARCH_SET_FS
test_arch_set_fs (&segs->initial);
#endif /* HAVE_ARCH_SET_FS */
#if HAVE_ARCH_SET_GS
test_arch_set_gs (&segs->initial);
#endif /* HAVE_ARCH_SET_GS */
#if HAVE_WRFSGSBASE
test_wrfsbase (&segs->initial);
test_wrgsbase (&segs->initial);
#endif /* HAVE_WRFSGSBASE */
return 0;
}

View File

@@ -0,0 +1,191 @@
# Copyright (C) 2019 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
standard_testfile
if { ![istarget x86_64-*-* ] && ![istarget i?86-*-* ] } {
verbose "Skipping ${testfile}."
return
}
if { [skip_modify_ldt_tests] } {
untested "cannot setup LDT"
return
}
set skip_fsgsbase [skip_fsgsbase_tests]
set skip_arch_set_fs [skip_arch_set_fs_tests]
set skip_arch_set_gs [skip_arch_set_gs_tests]
set flags { debug }
set flags [concat $flags additional_flags=-DHAVE_WRFSGSBASE=!$skip_fsgsbase]
set flags [concat $flags additional_flags=-DHAVE_ARCH_SET_FS=!$skip_arch_set_fs]
set flags [concat $flags additional_flags=-DHAVE_ARCH_SET_GS=!$skip_arch_set_gs]
if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} ${flags}] } {
return -1
}
if { ![runto_main] } {
untested "failed to run to main"
return -1
}
proc test_switch { seg } {
global skip_fsgsbase skip_arch_set_fs skip_arch_set_gs
# The inferior provides a new segment selector
gdb_test "p switch_${seg}_read (0xa7)" "= 42"
# The inferior provides the segment base via WRFS/GSBASE.
if { $skip_fsgsbase } {
untested "FSGSBASE"
} else {
gdb_test "p wr${seg}base_read (&segs->twentythree)" "= 23"
}
# The inferior provides the segment base via arch_prctl ().
if { (($seg == "fs" && $skip_arch_set_fs) ||
($seg == "gs" && $skip_arch_set_gs)) } {
untested "arch_prctl(ARCH_SET_FS/GS)"
} else {
gdb_test "p arch_set_${seg}_read (&segs->twentythree)" "= 23"
}
}
proc test { seg } {
global hex gdb_prompt
# Check that the target overrides any garbage we put into FS/GS and
# FS/GSBASE.
gdb_test "p/x \$${seg} = 0xb7" "= 0xb7"
# On 32-bit kernels, FS/GSBASE are not defined
if { ![istarget i?86-*-* ] } {
gdb_test "p/x \$${seg}_base = &segs->twentythree" "= $hex"
}
gdb_test "next" " l\.2 \\\*/"
# Since we want to use the same function for different scenarios, we
# don't check the actual register values but we check the effect.
gdb_test "p value" "= 42"
# Change the segment selector to point to the 'other' segment.
with_test_prefix $seg {
gdb_test "p/x \$${seg} = 0xb7" "= 0xb7"
gdb_test "p/x &segs->other" $hex
# Some kernels are nice enough to update the base for us.
set testname "${seg}_base"
if { ![istarget "x86_64-*-*"] } {
untested $testname
} else {
gdb_test_multiple "p/x \$${seg}_base" $testname {
-re "= 0x0\r\n$gdb_prompt $" {
pass $testname
}
-re "= $hex.*\r\n$gdb_prompt $" {
gdb_test "p (int *)\$${seg}_base == &segs->other" "= 1" \
$testname
}
-re "$gdb_prompt $" {
fail $testname
}
}
}
# Inferior calls will use the 'other' segment.
gdb_test "p read_${seg} ()" "= -42"
# Inferior calls may switch the segment again. This will be
# undone when we restore the register state after returning from
# the inferior call. Test a few different scenarios.
test_switch $seg
# When we resume, we will read from the 'other' segment as we did
# in the inferior call above. We do this check at the end to
# check that inferior calls are not able to override the state.
gdb_test "next" " l\.3 \\\*/"
gdb_test "p value" "= -42"
}
# Only 64-bit kernels provide FS/GSBASE.
if { ![istarget "x86_64-*-*"] } {
untested ${seg}_base
} elseif { [is_ilp32_target] } {
# Even though a 64-bit kernel provides FS/GSBASE for the current
# FS/GS selector, it does not allow changing the base independent
# of the selector.
#
# Trying to do that while setting the selector to zero, as tests
# do below, results in an inferior crash while trying to use that
# zero selector.
untested ${seg}_base
} else {
# Change the segment base to point to 'twentythree'.
with_test_prefix ${seg}_base {
# We also need to set the selector to zero. And we need to do
# so before changing the base.
gdb_test "p/x \$${seg} = 0x0" "= 0x0"
gdb_test "p/x \$${seg}_base = &segs->twentythree" "= $hex"
# Inferior calls will use the 'twentythree' segment.
gdb_test "p read_${seg} ()" "= 23"
# Check inferior calls switching the segment again.
test_switch $seg
# When we resume, we will read from the 'twentythreee' segment
# as we did in the inferior call above. We do this check at
# the end to check that inferior calls are not able to
# override the state.
gdb_test "next" " l\.4 \\\*/"
gdb_test "p value" "= 23"
}
}
}
proc test_one { function seg } {
global decimal
gdb_breakpoint $function
gdb_continue_to_breakpoint $function "$function .* l\.1 \\\*/"
with_test_prefix $function {
test $seg
}
}
test_one test_fs fs
test_one test_gs gs
if { $skip_arch_set_fs } {
untested "arch_prctl(ARCH_SET_FS)"
} else {
test_one test_arch_set_fs fs
}
if { $skip_arch_set_gs } {
untested "arch_prctl(ARCH_SET_GS)"
} else {
test_one test_arch_set_gs gs
}
if { $skip_fsgsbase } {
untested "FSGSBASE"
} else {
test_one test_wrfsbase fs
test_one test_wrgsbase gs
}

View File

@@ -51,6 +51,22 @@ set pre_corefile_local_array \
set pre_corefile_extern_array \
[capture_command_output "print extern_array" "$print_prefix"]
# On IA, a 64-bit kernel provides fs_base and gs_base for 32-bit inferiors
# via ptrace, yet does not write them into the corefile. Neither does
# GDB.
#
# They will appear '<unavailable>' when reading the corefile back in.
# Adjust the above output to reflect this behaviour.
if { [istarget x86_64-*-* ] && [is_ilp32_target] } {
regsub -all "\(\[fg\]s_base *\)$hex *-?$decimal" $pre_corefile_regs \
"\\1<unavailable>" pre_corefile_regs
verbose -log "adjusted general regs: $pre_corefile_regs"
regsub -all "\(\[fg\]s_base *\)$hex *-?$decimal" $pre_corefile_allregs \
"\\1<unavailable>" pre_corefile_allregs
verbose -log "adjusted all regs: $pre_corefile_allregs"
}
set corefile [standard_output_file gcore.test]
set core_supported [gdb_gcore_cmd "$corefile" "save a corefile"]
if {!$core_supported} {

View File

@@ -630,12 +630,15 @@ proc runto_main { } {
### continue_to_breakpoint should use a NAME which is unique within
### that test file.
proc gdb_continue_to_breakpoint {name {location_pattern .*}} {
global gdb_prompt
global gdb_prompt decimal
set full_name "continue to breakpoint: $name"
set kfail_pattern "Process record does not support instruction 0xfae64 at.*"
gdb_test_multiple "continue" $full_name {
-re "(?:Breakpoint|Temporary breakpoint) .* (at|in) $location_pattern\r\n$gdb_prompt $" {
-re "(?:Breakpoint|Temporary breakpoint) .*(at|in) $location_pattern\r\n$gdb_prompt $" {
pass $full_name
}
-re "(?:Breakpoint|Temporary breakpoint) $decimal, $location_pattern\r\n$gdb_prompt $" {
pass $full_name
}
-re "\[\r\n\]*(?:$kfail_pattern)\[\r\n\]+$gdb_prompt $" {
@@ -6834,5 +6837,274 @@ gdb_caching_proc skip_ctf_tests {
} executable "additional_flags=-gt"]
}
# Run a test on the target to see if it supports WRFSBASE and WRGSBASE.
# Return 0 if so, 1 if it does not.
gdb_caching_proc skip_fsgsbase_tests {
global srcdir subdir gdb_prompt inferior_exited_re
set me "skip_fsgsbase_tests"
# Compile a test program.
set src {
int seg;
int main() {
void *old;
__asm__ volatile ("rdfsbase %0" : "=rm"(old));
__asm__ volatile ("wrfsbase %0" :: "r"(&seg));
__asm__ volatile ("wrfsbase %0" :: "r"(old));
__asm__ volatile ("rdgsbase %0" : "=rm"(old));
__asm__ volatile ("wrgsbase %0" :: "r"(&seg));
__asm__ volatile ("wrgsbase %0" :: "r"(old));
return 0;
}
}
if {![gdb_simple_compile $me $src executable]} {
return 1
}
# No error message, compilation succeeded so now run it via gdb.
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load "$obj"
gdb_run_cmd
gdb_expect {
-re ".*Illegal instruction.*${gdb_prompt} $" {
verbose -log "$me: FSGSBASE support not detected."
set skip_fsgsbase_tests 1
}
-re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
verbose -log "$me: FSGSBASE support detected."
set skip_fsgsbase_tests 0
}
default {
warning "\n$me: default case taken."
set skip_fsgsbase_tests 1
}
}
gdb_exit
remote_file build delete $obj
verbose "$me: returning $skip_fsgsbase_tests" 2
return $skip_fsgsbase_tests
}
# Run a test on the target to see if it supports arch_prctl(ARCH_SET_FS).
# Return 0 if so, 1 if it does not.
gdb_caching_proc skip_arch_set_fs_tests {
global srcdir subdir gdb_prompt inferior_exited_re
set me "skip_arch_set_fs_tests"
# The system call is not available to 32-bit.
if { [is_ilp32_target] } {
return 1
}
# Compile a test program.
set src {
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <asm/prctl.h>
#include <sys/prctl.h>
int seg;
int main() {
unsigned long old;
int errcode;
errcode = syscall (SYS_arch_prctl, ARCH_GET_FS, &old);
assert (errcode == 0);
errcode = syscall (SYS_arch_prctl, ARCH_SET_FS, &seg);
assert (errcode == 0);
errcode = syscall (SYS_arch_prctl, ARCH_SET_FS, old);
assert (errcode == 0);
return 0;
}
}
if {![gdb_simple_compile $me $src executable]} {
return 1
}
# No error message, compilation succeeded so now run it via gdb.
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load "$obj"
gdb_run_cmd
gdb_expect {
-re ".*Assertion `errcode == 0' failed.*${gdb_prompt} $" {
verbose -log "$me: ARCH_SET_FS support not detected."
set skip_arch_set_fs_tests 1
}
-re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
verbose -log "$me: ARCH_SET_FS support detected."
set skip_arch_set_fs_tests 0
}
default {
warning "\n$me: default case taken."
set skip_arch_set_fs_tests 1
}
}
gdb_exit
remote_file build delete $obj
verbose "$me: returning $skip_arch_set_fs_tests" 2
return $skip_arch_set_fs_tests
}
# Run a test on the target to see if it supports arch_prctl(ARCH_SET_GS).
# Return 0 if so, 1 if it does not.
gdb_caching_proc skip_arch_set_gs_tests {
global srcdir subdir gdb_prompt inferior_exited_re
set me "skip_arch_set_gs_tests"
# The system call is not available to 32-bit.
if { [is_ilp32_target] } {
return 1
}
# Compile a test program.
set src {
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <asm/prctl.h>
#include <sys/prctl.h>
int seg;
int main() {
unsigned long old;
int errcode;
errcode = syscall (SYS_arch_prctl, ARCH_GET_GS, &old);
assert (errcode == 0);
errcode = syscall (SYS_arch_prctl, ARCH_SET_GS, &seg);
assert (errcode == 0);
errcode = syscall (SYS_arch_prctl, ARCH_SET_GS, old);
assert (errcode == 0);
return 0;
}
}
if {![gdb_simple_compile $me $src executable]} {
return 1
}
# No error message, compilation succeeded so now run it via gdb.
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load "$obj"
gdb_run_cmd
gdb_expect {
-re ".*Assertion `errcode == 0' failed.*${gdb_prompt} $" {
verbose -log "$me: ARCH_SET_GS support not detected."
set skip_arch_set_gs_tests 1
}
-re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
verbose -log "$me: ARCH_SET_GS support detected."
set skip_arch_set_gs_tests 0
}
default {
warning "\n$me: default case taken."
set skip_arch_set_gs_tests 1
}
}
gdb_exit
remote_file build delete $obj
verbose "$me: returning $skip_arch_set_gs_tests" 2
return $skip_arch_set_gs_tests
}
# Run a test on the target to see if it supports modify_ldt.
# Return 0 if so, 1 if it does not.
gdb_caching_proc skip_modify_ldt_tests {
global srcdir subdir gdb_prompt inferior_exited_re
set me "skip_modify_ldt_tests"
# Compile a test program.
set src {
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <asm/ldt.h>
int seg;
int main() {
struct user_desc ud;
int errcode;
memset (&ud, 0, sizeof (ud));
ud.entry_number = 0xa7u >> 3;
ud.base_addr = (unsigned int) (unsigned long) &seg;
ud.limit = (unsigned int) sizeof (seg);
errcode = syscall (SYS_modify_ldt, 1, &ud, sizeof(ud));
assert (errcode == 0);
return 0;
}
}
if {![gdb_simple_compile $me $src executable]} {
return 1
}
# No error message, compilation succeeded so now run it via gdb.
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load "$obj"
gdb_run_cmd
gdb_expect {
-re ".*Assertion `errcode.*${gdb_prompt} $" {
verbose -log "$me: modify_ldt support not detected."
set skip_modify_ldt_tests 1
}
-re ".*Assertion `ud.base_addr.*${gdb_prompt} $" {
verbose -log "$me: struct user_desc truncates base."
set skip_modify_ldt_tests 1
}
-re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
verbose -log "$me: modify_ldt working."
set skip_modify_ldt_tests 0
}
default {
warning "\n$me: default case taken."
set skip_modify_ldt_tests 1
}
}
gdb_exit
remote_file build delete $obj
verbose "$me: returning $skip_modify_ldt_tests" 2
return $skip_modify_ldt_tests
}
# Always load compatibility stuff.
load_lib future.exp