de52b9607d
GDB is currently crashing anytime we try to access the fs_base/gs_base
registers, either to read them, or to write them. This can be observed
under various scenarios:
- Explicit reference to those registers (eg: print $fs_base) --
probably relatively rare;
- Calling a function in the inferior, with the crash happening
because we are trying to read those registers in order to save
their value ahead of making the function call;
- Just a plain "info registers";
The crash was introduced by the following commit:
| commit 48aeef91c2
| Date: Mon Jun 26 18:14:43 2017 -0700
| Subject: Include the fs_base and gs_base registers in amd64 target descriptions.
The Windows-nat implementation was unfortunately not prepared to deal
with those new registers. In particular, the way it fetches registers
is done by using a table where the index is the register number, and
the value at that index is the offset in the area in the thread's CONTEXT
data where the corresponding register value is stored.
For instance, in amd64-windows-nat.c, we can find the mappings static
array containing the following 57 elements in it:
#define context_offset(x) (offsetof (CONTEXT, x))
static const int mappings[] =
{
context_offset (Rax),
[...]
context_offset (FloatSave.MxCsr)
};
That array is then used by windows_fetch_one_register via:
char *context_offset = ((char *) &th->context) + mappings[r];
The problem is that fs_base's register number is 172, which is
well past the end of the mappings array (57 elements in total).
We end up getting an undefined offset, which happens to be so large
that it then causes the address where we try to read the register
value (a little bit later) to be invalid, thus crashing GDB with
a SEGV.
This patch side-steps the issue entirely by removing support for
those registers in GDB on x86_64-windows, because a look at the
CONTEXT structure indicates no support for getting those registers.
A more comprehensive fix would patch the potential buffer overflow
of the mappings array, but this can be done as a separate commit.
gdb/ChangeLog:
* gdb/amd64-tdep.h (amd64_create_target_description): Add
"segments" parameter.
* gdb/amd64-tdep.c (amd64_none_init_abi, amd64_x32_none_init_abi)
(_initialize_amd64_tdep): Update call to
amd64_create_target_description.
(amd64_target_description): Add "segments" parameter. Adjust
the implementation to use it.
* gdb/amd64-linux-tdep.c (amd64_linux_read_description): Update
call to amd64_create_target_description.
* gdb/amd64-windows-tdep.c (amd64_windows_init_abi): Likewise.
* gdb/arch/amd64.h (amd64_create_target_description): Add
"segments" register.
* gdb/arch/amd64.c (amd64_create_target_description): Add
"segments" parameter. Call create_feature_i386_64bit_segments
only if SEGMENTS is true.
* gdb/gdbserver/win32-i386-low.c (i386_arch_setup): Update
call to amd64_create_target_description.
Tested on x86_64-windows using AdaCore's testsuite (by Joel Brobecker
<brobecker at adacore dot com>).
79 lines
2.5 KiB
C
79 lines
2.5 KiB
C
/* Copyright (C) 2017-2018 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 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 "common-defs.h"
|
|
#include "amd64.h"
|
|
#include "x86-xstate.h"
|
|
#include <stdlib.h>
|
|
|
|
#include "../features/i386/64bit-avx.c"
|
|
#include "../features/i386/64bit-avx512.c"
|
|
#include "../features/i386/64bit-core.c"
|
|
#include "../features/i386/64bit-linux.c"
|
|
#include "../features/i386/64bit-mpx.c"
|
|
#include "../features/i386/64bit-pkeys.c"
|
|
#include "../features/i386/64bit-segments.c"
|
|
#include "../features/i386/64bit-sse.c"
|
|
|
|
#include "../features/i386/x32-core.c"
|
|
|
|
/* Create amd64 target descriptions according to XCR0. If IS_X32 is
|
|
true, create the x32 ones. If IS_LINUX is true, create target
|
|
descriptions for Linux. If SEGMENTS is true, then include
|
|
the "org.gnu.gdb.i386.segments" feature registers. */
|
|
|
|
target_desc *
|
|
amd64_create_target_description (uint64_t xcr0, bool is_x32, bool is_linux,
|
|
bool segments)
|
|
{
|
|
target_desc *tdesc = allocate_target_description ();
|
|
|
|
#ifndef IN_PROCESS_AGENT
|
|
set_tdesc_architecture (tdesc, is_x32 ? "i386:x64-32" : "i386:x86-64");
|
|
|
|
if (is_linux)
|
|
set_tdesc_osabi (tdesc, "GNU/Linux");
|
|
#endif
|
|
|
|
long regnum = 0;
|
|
|
|
if (is_x32)
|
|
regnum = create_feature_i386_x32_core (tdesc, regnum);
|
|
else
|
|
regnum = create_feature_i386_64bit_core (tdesc, regnum);
|
|
|
|
regnum = create_feature_i386_64bit_sse (tdesc, regnum);
|
|
if (is_linux)
|
|
regnum = create_feature_i386_64bit_linux (tdesc, regnum);
|
|
if (segments)
|
|
regnum = create_feature_i386_64bit_segments (tdesc, regnum);
|
|
|
|
if (xcr0 & X86_XSTATE_AVX)
|
|
regnum = create_feature_i386_64bit_avx (tdesc, regnum);
|
|
|
|
if ((xcr0 & X86_XSTATE_MPX) && !is_x32)
|
|
regnum = create_feature_i386_64bit_mpx (tdesc, regnum);
|
|
|
|
if (xcr0 & X86_XSTATE_AVX512)
|
|
regnum = create_feature_i386_64bit_avx512 (tdesc, regnum);
|
|
|
|
if ((xcr0 & X86_XSTATE_PKRU) && !is_x32)
|
|
regnum = create_feature_i386_64bit_pkeys (tdesc, regnum);
|
|
|
|
return tdesc;
|
|
}
|