mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
Compare commits
5 Commits
gdb-16.2-r
...
users/mmet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d26f3c1041 | ||
|
|
db18e24c49 | ||
|
|
03bad9e43d | ||
|
|
3e7fa952aa | ||
|
|
9db9f4a7a1 |
@@ -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" */
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
17
gdb/testsuite/boards/m32.exp
Normal file
17
gdb/testsuite/boards/m32.exp
Normal 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"
|
||||
24
gdb/testsuite/boards/native-gdbserver-m32.exp
Normal file
24
gdb/testsuite/boards/native-gdbserver-m32.exp
Normal 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"
|
||||
27
gdb/testsuite/boards/native-m32.exp
Normal file
27
gdb/testsuite/boards/native-m32.exp
Normal 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]"
|
||||
262
gdb/testsuite/gdb.arch/x86-fsgs.c
Normal file
262
gdb/testsuite/gdb.arch/x86-fsgs.c
Normal 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;
|
||||
}
|
||||
191
gdb/testsuite/gdb.arch/x86-fsgs.exp
Normal file
191
gdb/testsuite/gdb.arch/x86-fsgs.exp
Normal 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
|
||||
}
|
||||
@@ -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} {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user