
The current code checks for the presence of a SVE target description by comparing the number of registers. This is a bit fragile since the number of registers can change whenever we add new sets. Like PAC, for example. If the comparison breaks, then we're left with SVE registers in the description, but gdbserver doesn't send the registers to GDB, which in turn displays stale information to the user. The following patch changes the check to use the SVE feature string instead, which hopefully should be more stable. gdb/gdbserver/ChangeLog: 2019-11-20 Luis Machado <luis.machado@linaro.org> * linux-aarch64-low.c (is_sve_tdesc): Check against target feature instead of register count. * tdesc.c (tdesc_contains_feature): New function. * tdesc.h (tdesc_contains_feature): New prototype. Change-Id: I28b782cb1677560ca9a06a1be442974b25aabae4
204 lines
4.5 KiB
C
204 lines
4.5 KiB
C
/* Copyright (C) 2012-2019 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 "server.h"
|
|
#include "tdesc.h"
|
|
#include "regdef.h"
|
|
|
|
#ifndef IN_PROCESS_AGENT
|
|
|
|
target_desc::~target_desc ()
|
|
{
|
|
xfree ((char *) arch);
|
|
xfree ((char *) osabi);
|
|
}
|
|
|
|
bool target_desc::operator== (const target_desc &other) const
|
|
{
|
|
if (reg_defs != other.reg_defs)
|
|
return false;
|
|
|
|
/* Compare expedite_regs. */
|
|
int i = 0;
|
|
for (; expedite_regs[i] != NULL; i++)
|
|
{
|
|
if (strcmp (expedite_regs[i], other.expedite_regs[i]) != 0)
|
|
return false;
|
|
}
|
|
if (other.expedite_regs[i] != NULL)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif
|
|
|
|
void target_desc::accept (tdesc_element_visitor &v) const
|
|
{
|
|
#ifndef IN_PROCESS_AGENT
|
|
v.visit_pre (this);
|
|
|
|
for (const tdesc_feature_up &feature : features)
|
|
feature->accept (v);
|
|
|
|
v.visit_post (this);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
init_target_desc (struct target_desc *tdesc,
|
|
const char **expedite_regs)
|
|
{
|
|
int offset = 0;
|
|
|
|
/* Go through all the features and populate reg_defs. */
|
|
for (const tdesc_feature_up &feature : tdesc->features)
|
|
for (const tdesc_reg_up &treg : feature->registers)
|
|
{
|
|
int regnum = treg->target_regnum;
|
|
|
|
/* Register number will increase (possibly with gaps) or be zero. */
|
|
gdb_assert (regnum == 0 || regnum >= tdesc->reg_defs.size ());
|
|
|
|
if (regnum != 0)
|
|
tdesc->reg_defs.resize (regnum, reg (offset));
|
|
|
|
tdesc->reg_defs.emplace_back (treg->name.c_str (), offset,
|
|
treg->bitsize);
|
|
offset += treg->bitsize;
|
|
}
|
|
|
|
tdesc->registers_size = offset / 8;
|
|
|
|
/* Make sure PBUFSIZ is large enough to hold a full register
|
|
packet. */
|
|
gdb_assert (2 * tdesc->registers_size + 32 <= PBUFSIZ);
|
|
|
|
#ifndef IN_PROCESS_AGENT
|
|
tdesc->expedite_regs = expedite_regs;
|
|
#endif
|
|
}
|
|
|
|
struct target_desc *
|
|
allocate_target_description (void)
|
|
{
|
|
return new target_desc ();
|
|
}
|
|
|
|
#ifndef IN_PROCESS_AGENT
|
|
|
|
static const struct target_desc default_description {};
|
|
|
|
void
|
|
copy_target_description (struct target_desc *dest,
|
|
const struct target_desc *src)
|
|
{
|
|
dest->reg_defs = src->reg_defs;
|
|
dest->expedite_regs = src->expedite_regs;
|
|
dest->registers_size = src->registers_size;
|
|
dest->xmltarget = src->xmltarget;
|
|
}
|
|
|
|
const struct target_desc *
|
|
current_target_desc (void)
|
|
{
|
|
if (current_thread == NULL)
|
|
return &default_description;
|
|
|
|
return current_process ()->tdesc;
|
|
}
|
|
|
|
/* See gdbsupport/tdesc.h. */
|
|
|
|
const char *
|
|
tdesc_architecture_name (const struct target_desc *target_desc)
|
|
{
|
|
return target_desc->arch;
|
|
}
|
|
|
|
/* See gdbsupport/tdesc.h. */
|
|
|
|
void
|
|
set_tdesc_architecture (struct target_desc *target_desc,
|
|
const char *name)
|
|
{
|
|
target_desc->arch = xstrdup (name);
|
|
}
|
|
|
|
/* See gdbsupport/tdesc.h. */
|
|
|
|
const char *
|
|
tdesc_osabi_name (const struct target_desc *target_desc)
|
|
{
|
|
return target_desc->osabi;
|
|
}
|
|
|
|
/* See gdbsupport/tdesc.h. */
|
|
|
|
void
|
|
set_tdesc_osabi (struct target_desc *target_desc, const char *name)
|
|
{
|
|
target_desc->osabi = xstrdup (name);
|
|
}
|
|
|
|
/* See gdbsupport/tdesc.h. */
|
|
|
|
const char *
|
|
tdesc_get_features_xml (const target_desc *tdesc)
|
|
{
|
|
/* Either .xmltarget or .features is not NULL. */
|
|
gdb_assert (tdesc->xmltarget != NULL
|
|
|| (!tdesc->features.empty ()
|
|
&& tdesc->arch != NULL));
|
|
|
|
if (tdesc->xmltarget == NULL)
|
|
{
|
|
std::string buffer ("@");
|
|
print_xml_feature v (&buffer);
|
|
tdesc->accept (v);
|
|
tdesc->xmltarget = xstrdup (buffer.c_str ());
|
|
}
|
|
|
|
return tdesc->xmltarget;
|
|
}
|
|
#endif
|
|
|
|
/* See gdbsupport/tdesc.h. */
|
|
|
|
struct tdesc_feature *
|
|
tdesc_create_feature (struct target_desc *tdesc, const char *name)
|
|
{
|
|
struct tdesc_feature *new_feature = new tdesc_feature (name);
|
|
tdesc->features.emplace_back (new_feature);
|
|
return new_feature;
|
|
}
|
|
|
|
/* See gdbsupport/tdesc.h. */
|
|
|
|
bool
|
|
tdesc_contains_feature (const target_desc *tdesc, const std::string &feature)
|
|
{
|
|
gdb_assert (tdesc != nullptr);
|
|
|
|
for (const tdesc_feature_up &f : tdesc->features)
|
|
{
|
|
if (f->name == feature)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|