dwarf2read.c: Check type of string valued attributes prior to decoding.

This change introduces a new function, dwarf2_string_attr(), which is
a wrapper for dwarf2_attr().  dwarf2read.c has been updated to
call dwarf2_string_attr in most instances where a string-valued
attribute is decoded to produce a string value.  In most cases, it
simplifies the code; in some instances, the complexity of the code
remains unchanged.

I performed this change by looking for instances where the
result of DW_STRING was used in an assignment.  Many of these
had a pattern which (roughly) looks something like this:

  struct attribute *attr = NULL;

  attr = dwarf2_attr (die, name, cu);
  if (attr != NULL && DW_STRING (attr))
    {
      const char *str;
      ...
      str = DW_STRING (attr);
      ... /* Use str in some fashion.  */
    }

Code of this form is transformed to look like this instead:

  const char *str;

  str = dwarf2_string_attr (die, name, cu)
  if (str != NULL)
    {
       ...
       /* Use str in some fashion.  */
       ...
    }

In addition to invoking dwarf2_attr() and DW_STRING(),
dwarf2_string_attr() checks to make sure that the attribute's
`form' field matches one of DW_FORM_strp, DW_FORM_string, or
DW_FORM_GNU_strp_alt.  If it does not match one of these forms,
it will return a NULL value in addition to calling complaint().

An earlier version of this patch did this type checking for one
particular instance where a string attribute was being decoded.
The situation that I was attempting to handle in that earlier patch is
this:

The Texas Instruments compiler uses the encoding for
DW_AT_MIPS_linkage_name for other purposes.  TI uses the encoding,
0x2007, for TI_AT_TI_end_line which, unlike DW_AT_MIPS_linkage_name,
does not have a string-typed value.  In this instance, GDB was attempting
to use an integer value as a string pointer, with predictable results.
(GDB would die with a segmentation fault.)

I've added a test which reproduces the problem that I was orignally
wanting to fix.  It uses DW_AT_MIPS_linkage name with an associate
value which is a string, and again, where the value is a small
integer.

My test case causes GDB to segfault in an unpatched GDB.  There
will be two PASSes in a patched GDB.

Unpatched GDB:

(gdb) ptype f
ERROR: Process no longer exists
UNRESOLVED: gdb.dwarf2/dw2-bad-mips-linkage-name.exp: ptype f
ERROR: Couldn't send ptype g to GDB.
UNRESOLVED: gdb.dwarf2/dw2-bad-mips-linkage-name.exp: ptype g

Patched GDB:

(gdb) ptype f
type = bool ()
(gdb) PASS: gdb.dwarf2/dw2-bad-mips-linkage-name.exp: ptype f
ptype g
type = bool ()
(gdb) PASS: gdb.dwarf2/dw2-bad-mips-linkage-name.exp: ptype g

I see no regressions on an x86_64 native target.

gdb/ChangeLog:

	* dwarf2read.c (dwarf2_string_attr): New function.
	(lookup_dwo_unit, process_psymtab_comp_unit_reader)
	(dwarf2_compute_name, dwarf2_physname, find_file_and_directory)
	(read_call_site_scope, namespace_name, guess_full_die_structure_name)
	(anonymous_struct_prefix, prepare_one_comp_unit): Use
	dwarf2_string_attr in place of dwarf2_attr and DW_STRING.

gdb/testsuite/ChangeLog:

	* gdb.dwarf2/dw2-bad-mips-linkage-name.c: New file.
	* gdb.dwarf2/dw2-bad-mips-linkage-name.exp: New file.
This commit is contained in:
Kevin Buettner
2015-08-03 14:17:17 -07:00
parent 07c9aa07cd
commit 7d45c7c3f6
5 changed files with 196 additions and 65 deletions

View File

@ -1,3 +1,12 @@
2015-08-19 Kevin Buettner <kevinb@redhat.com>
* dwarf2read.c (dwarf2_string_attr): New function.
(lookup_dwo_unit, process_psymtab_comp_unit_reader)
(dwarf2_compute_name, dwarf2_physname, find_file_and_directory)
(read_call_site_scope, namespace_name, guess_full_die_structure_name)
(anonymous_struct_prefix, prepare_one_comp_unit): Use
dwarf2_string_attr in place of dwarf2_attr and DW_STRING.
2015-08-18 Doug Evans <dje@google.com> 2015-08-18 Doug Evans <dje@google.com>
Adrian Sendroiu <adrian.sendroiu@freescale.com> Adrian Sendroiu <adrian.sendroiu@freescale.com>

View File

@ -1524,6 +1524,9 @@ static struct attribute *dwarf2_attr (struct die_info *, unsigned int,
static struct attribute *dwarf2_attr_no_follow (struct die_info *, static struct attribute *dwarf2_attr_no_follow (struct die_info *,
unsigned int); unsigned int);
static const char *dwarf2_string_attr (struct die_info *die, unsigned int name,
struct dwarf2_cu *cu);
static int dwarf2_flag_true_p (struct die_info *die, unsigned name, static int dwarf2_flag_true_p (struct die_info *die, unsigned name,
struct dwarf2_cu *cu); struct dwarf2_cu *cu);
@ -5270,13 +5273,8 @@ lookup_dwo_unit (struct dwarf2_per_cu_data *this_cu,
gdb_assert (cu != NULL); gdb_assert (cu != NULL);
/* Yeah, we look dwo_name up again, but it simplifies the code. */ /* Yeah, we look dwo_name up again, but it simplifies the code. */
attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_name, cu); dwo_name = dwarf2_string_attr (comp_unit_die, DW_AT_GNU_dwo_name, cu);
gdb_assert (attr != NULL); comp_dir = dwarf2_string_attr (comp_unit_die, DW_AT_comp_dir, cu);
dwo_name = DW_STRING (attr);
comp_dir = NULL;
attr = dwarf2_attr (comp_unit_die, DW_AT_comp_dir, cu);
if (attr)
comp_dir = DW_STRING (attr);
if (this_cu->is_debug_types) if (this_cu->is_debug_types)
{ {
@ -5938,7 +5936,6 @@ process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
struct objfile *objfile = cu->objfile; struct objfile *objfile = cu->objfile;
struct gdbarch *gdbarch = get_objfile_arch (objfile); struct gdbarch *gdbarch = get_objfile_arch (objfile);
struct dwarf2_per_cu_data *per_cu = cu->per_cu; struct dwarf2_per_cu_data *per_cu = cu->per_cu;
struct attribute *attr;
CORE_ADDR baseaddr; CORE_ADDR baseaddr;
CORE_ADDR best_lowpc = 0, best_highpc = 0; CORE_ADDR best_lowpc = 0, best_highpc = 0;
struct partial_symtab *pst; struct partial_symtab *pst;
@ -5956,18 +5953,14 @@ process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
cu->list_in_scope = &file_symbols; cu->list_in_scope = &file_symbols;
/* Allocate a new partial symbol table structure. */ /* Allocate a new partial symbol table structure. */
attr = dwarf2_attr (comp_unit_die, DW_AT_name, cu); filename = dwarf2_string_attr (comp_unit_die, DW_AT_name, cu);
if (attr == NULL || !DW_STRING (attr)) if (filename == NULL)
filename = ""; filename = "";
else
filename = DW_STRING (attr);
pst = create_partial_symtab (per_cu, filename); pst = create_partial_symtab (per_cu, filename);
/* This must be done before calling dwarf2_build_include_psymtabs. */ /* This must be done before calling dwarf2_build_include_psymtabs. */
attr = dwarf2_attr (comp_unit_die, DW_AT_comp_dir, cu); pst->dirname = dwarf2_string_attr (comp_unit_die, DW_AT_comp_dir, cu);
if (attr != NULL)
pst->dirname = DW_STRING (attr);
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
@ -8451,13 +8444,13 @@ dwarf2_compute_name (const char *name,
to be able to reference. Ideally, we want the user to be able to be able to reference. Ideally, we want the user to be able
to reference this entity using either natural or linkage name, to reference this entity using either natural or linkage name,
but we haven't started looking at this enhancement yet. */ but we haven't started looking at this enhancement yet. */
struct attribute *attr; const char *name;
attr = dwarf2_attr (die, DW_AT_linkage_name, cu); name = dwarf2_string_attr (die, DW_AT_linkage_name, cu);
if (attr == NULL) if (name == NULL)
attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu); name = dwarf2_string_attr (die, DW_AT_MIPS_linkage_name, cu);
if (attr && DW_STRING (attr)) if (name != NULL)
return DW_STRING (attr); return name;
} }
/* These are the only languages we know how to qualify names in. */ /* These are the only languages we know how to qualify names in. */
@ -8710,18 +8703,16 @@ dwarf2_physname (const char *name, struct die_info *die, struct dwarf2_cu *cu)
back_to = make_cleanup (null_cleanup, NULL); back_to = make_cleanup (null_cleanup, NULL);
attr = dwarf2_attr (die, DW_AT_linkage_name, cu); mangled = dwarf2_string_attr (die, DW_AT_linkage_name, cu);
if (!attr) if (mangled == NULL)
attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu); mangled = dwarf2_string_attr (die, DW_AT_MIPS_linkage_name, cu);
/* DW_AT_linkage_name is missing in some cases - depend on what GDB /* DW_AT_linkage_name is missing in some cases - depend on what GDB
has computed. */ has computed. */
if (attr && DW_STRING (attr)) if (mangled != NULL)
{ {
char *demangled; char *demangled;
mangled = DW_STRING (attr);
/* Use DMGL_RET_DROP for C++ template functions to suppress their return /* Use DMGL_RET_DROP for C++ template functions to suppress their return
type. It is easier for GDB users to search for such functions as type. It is easier for GDB users to search for such functions as
`name(params)' than `long name(params)'. In such case the minimal `name(params)' than `long name(params)'. In such case the minimal
@ -9051,24 +9042,14 @@ static void
find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu, find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu,
const char **name, const char **comp_dir) const char **name, const char **comp_dir)
{ {
struct attribute *attr;
*name = NULL;
*comp_dir = NULL;
/* Find the filename. Do not use dwarf2_name here, since the filename /* Find the filename. Do not use dwarf2_name here, since the filename
is not a source language identifier. */ is not a source language identifier. */
attr = dwarf2_attr (die, DW_AT_name, cu); *name = dwarf2_string_attr (die, DW_AT_name, cu);
if (attr) *comp_dir = dwarf2_string_attr (die, DW_AT_comp_dir, cu);
{
*name = DW_STRING (attr);
}
attr = dwarf2_attr (die, DW_AT_comp_dir, cu); if (*comp_dir == NULL
if (attr) && producer_is_gcc_lt_4_3 (cu) && *name != NULL
*comp_dir = DW_STRING (attr); && IS_ABSOLUTE_PATH (*name))
else if (producer_is_gcc_lt_4_3 (cu) && *name != NULL
&& IS_ABSOLUTE_PATH (*name))
{ {
char *d = ldirname (*name); char *d = ldirname (*name);
@ -11710,17 +11691,17 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
gdb_assert (target_cu->objfile == objfile); gdb_assert (target_cu->objfile == objfile);
if (die_is_declaration (target_die, target_cu)) if (die_is_declaration (target_die, target_cu))
{ {
const char *target_physname = NULL; const char *target_physname;
struct attribute *target_attr;
/* Prefer the mangled name; otherwise compute the demangled one. */ /* Prefer the mangled name; otherwise compute the demangled one. */
target_attr = dwarf2_attr (target_die, DW_AT_linkage_name, target_cu); target_physname = dwarf2_string_attr (target_die,
if (target_attr == NULL) DW_AT_linkage_name,
target_attr = dwarf2_attr (target_die, DW_AT_MIPS_linkage_name, target_cu);
target_cu); if (target_physname == NULL)
if (target_attr != NULL && DW_STRING (target_attr) != NULL) target_physname = dwarf2_string_attr (target_die,
target_physname = DW_STRING (target_attr); DW_AT_MIPS_linkage_name,
else target_cu);
if (target_physname == NULL)
target_physname = dwarf2_physname (NULL, target_die, target_cu); target_physname = dwarf2_physname (NULL, target_die, target_cu);
if (target_physname == NULL) if (target_physname == NULL)
complaint (&symfile_complaints, complaint (&symfile_complaints,
@ -14191,10 +14172,8 @@ namespace_name (struct die_info *die, int *is_anonymous, struct dwarf2_cu *cu)
{ {
/* We don't use dwarf2_name here so that we can detect the absence /* We don't use dwarf2_name here so that we can detect the absence
of a name -> anonymous namespace. */ of a name -> anonymous namespace. */
struct attribute *attr = dwarf2_attr (die, DW_AT_name, cu); name = dwarf2_string_attr (die, DW_AT_name, cu);
if (attr != NULL)
name = DW_STRING (attr);
if (name != NULL) if (name != NULL)
break; break;
} }
@ -17097,6 +17076,33 @@ dwarf2_attr_no_follow (struct die_info *die, unsigned int name)
return NULL; return NULL;
} }
/* Return the string associated with a string-typed attribute, or NULL if it
is either not found or is of an incorrect type. */
static const char *
dwarf2_string_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *cu)
{
struct attribute *attr;
const char *str = NULL;
attr = dwarf2_attr (die, name, cu);
if (attr != NULL)
{
if (attr->form == DW_FORM_strp || attr->form == DW_FORM_string
|| attr->form == DW_FORM_GNU_strp_alt)
str = DW_STRING (attr);
else
complaint (&symfile_complaints,
_("string type expected for attribute %s for "
"DIE at 0x%x in module %s"),
dwarf_attr_name (name), die->offset.sect_off,
objfile_name (cu->objfile));
}
return str;
}
/* Return non-zero iff the attribute NAME is defined for the given DIE, /* Return non-zero iff the attribute NAME is defined for the given DIE,
and holds a non-zero value. This function should only be used for and holds a non-zero value. This function should only be used for
DW_FORM_flag or DW_FORM_flag_present attributes. */ DW_FORM_flag or DW_FORM_flag_present attributes. */
@ -19154,16 +19160,17 @@ guess_full_die_structure_name (struct die_info *die, struct dwarf2_cu *cu)
{ {
if (child->tag == DW_TAG_subprogram) if (child->tag == DW_TAG_subprogram)
{ {
struct attribute *attr; const char *linkage_name;
attr = dwarf2_attr (child, DW_AT_linkage_name, cu); linkage_name = dwarf2_string_attr (child, DW_AT_linkage_name, cu);
if (attr == NULL) if (linkage_name == NULL)
attr = dwarf2_attr (child, DW_AT_MIPS_linkage_name, cu); linkage_name = dwarf2_string_attr (child, DW_AT_MIPS_linkage_name,
if (attr != NULL) cu);
if (linkage_name != NULL)
{ {
char *actual_name char *actual_name
= language_class_name_from_physname (cu->language_defn, = language_class_name_from_physname (cu->language_defn,
DW_STRING (attr)); linkage_name);
char *name = NULL; char *name = NULL;
if (actual_name != NULL) if (actual_name != NULL)
@ -19211,8 +19218,7 @@ anonymous_struct_prefix (struct die_info *die, struct dwarf2_cu *cu)
&& die->tag != DW_TAG_structure_type && die->tag != DW_TAG_union_type) && die->tag != DW_TAG_structure_type && die->tag != DW_TAG_union_type)
return NULL; return NULL;
attr = dwarf2_attr (die, DW_AT_name, cu); if (dwarf2_string_attr (die, DW_AT_name, cu) != NULL)
if (attr != NULL && DW_STRING (attr) != NULL)
return NULL; return NULL;
attr = dwarf2_attr (die, DW_AT_linkage_name, cu); attr = dwarf2_attr (die, DW_AT_linkage_name, cu);
@ -22083,9 +22089,7 @@ prepare_one_comp_unit (struct dwarf2_cu *cu, struct die_info *comp_unit_die,
cu->language_defn = language_def (cu->language); cu->language_defn = language_def (cu->language);
} }
attr = dwarf2_attr (comp_unit_die, DW_AT_producer, cu); cu->producer = dwarf2_string_attr (comp_unit_die, DW_AT_producer, cu);
if (attr)
cu->producer = DW_STRING (attr);
} }
/* Release one cached compilation unit, CU. We unlink it from the tree /* Release one cached compilation unit, CU. We unlink it from the tree

View File

@ -1,3 +1,8 @@
2015-08-19 Kevin Buettner <kevinb@redhat.com>
* gdb.dwarf2/dw2-bad-mips-linkage-name.c: New file.
* gdb.dwarf2/dw2-bad-mips-linkage-name.exp: New file.
2015-08-18 Doug Evans <dje@google.com> 2015-08-18 Doug Evans <dje@google.com>
Adrian Sendroiu <adrian.sendroiu@freescale.com> Adrian Sendroiu <adrian.sendroiu@freescale.com>

View File

@ -0,0 +1,41 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2015 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/>. */
/* Dummy main function. */
int
main (void)
{
asm ("main_label: .globl main_label");
return 0;
}
/* dummy f function, DWARF will describe arguments and type differently. */
int
f (char *x)
{
asm (".global f_end_lbl\nf_end_lbl:");
return 0;
}
/* dummy g function, DWARF will describe arguments and type differently. */
int
g (char *x)
{
asm (".global g_end_lbl\ng_end_lbl:");
return 0;
}

View File

@ -0,0 +1,72 @@
# Copyright 2015 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/>.
load_lib dwarf.exp
# This test can only be run on targets which support DWARF-2 and use gas.
if {![dwarf2_support]} {
return 0
}
standard_testfile dw2-bad-mips-linkage-name.c dw2-bad-mips-linkage-name.S
# Set up the DWARF for the test.
set asm_file [standard_output_file $srcfile2]
Dwarf::assemble $asm_file {
cu {} {
DW_TAG_compile_unit {
{DW_AT_language @DW_LANG_C}
{DW_AT_name dw2-bad-mips-linkage-name.c}
{DW_AT_comp_dir /tmp}
} {
declare_labels b_l
b_l: DW_TAG_base_type {
{DW_AT_byte_size 1 DW_FORM_sdata}
{DW_AT_encoding @DW_ATE_signed}
{DW_AT_name bool}
}
DW_TAG_subprogram {
{name f}
{low_pc f addr}
{high_pc f_end_lbl addr}
{type :$b_l}
{DW_AT_MIPS_linkage_name _Z1fv}
}
DW_TAG_subprogram {
{name g}
{low_pc g addr}
{high_pc g_end_lbl addr}
{type :$b_l}
{DW_AT_MIPS_linkage_name 42 DW_FORM_data1}
}
}
}
}
if { [prepare_for_testing ${testfile}.exp ${testfile} \
[list $srcfile $asm_file] {nodebug}] } {
return -1
}
# A successful run will have two PASSes. A GDB that's lacking
# attribute type checking will segfault at some point. It doesn't
# much matter what we test here, so long as we do something to make
# sure that the DWARF is read.
gdb_test "ptype f" " = bool \\(\\)"
gdb_test "ptype g" " = bool \\(\\)"