Support DW_AT_count DWARF attribute

Libabigail's DWARF reader does not support the DW_AT_count attribute
used to specify the number of elements in an array subrange.  Rather,
it uses the DW_AT_lower_bound and DW_AT_upper_bound attributes that
are emitted by GCC.  Recent versions of Clang, on the other hand, use
the DW_AT_count attribute.

This patch adds support for the DW_AT_count attribute too.

	* src/abg-dwarf-reader.cc (get_default_array_lower_bound): Define
	new static function.
	(build_array_type): Support the DW_AT_count attribute.
	* tests/data/test-diff-dwarf/test35-pr19173-libfoo-long-clang.so:
	New test binary input.
	* tests/data/test-diff-dwarf/test35-pr19173-libfoo-long-clang2.so: Likewise.
	* tests/data/test-diff-dwarf/test35-pr19173-libfoo-long-clang-report-0.txt:
	New test reference output.
	* tests/data/test-diff-dwarf/test35-pr19173-libfoo-long-gcc.so:
	New test binary input.
	* tests/data/test-diff-dwarf/test35-pr19173-libfoo-long-gcc2.so:
	New test binary input.
	* tests/data/test-diff-dwarf/test35-pr19173-libfoo-long-gcc-report-0.txt:
	New test reference output.
	* tests/data/test-diff-dwarf/test35-pr19173-libfoo-long.c: Source
	code for the binaries above.
	* tests/data/Makefile.am: Add the new test material to the build
	system.
	* tests/test-diff-dwarf.cc (in_out_specs): Add the new test inputs
	to the harness.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2015-11-07 22:52:10 +01:00
parent ba980025fb
commit 5d24cf87d7
10 changed files with 160 additions and 3 deletions

View File

@ -144,6 +144,9 @@ maybe_canonicalize_type(Dwarf_Off die_offset,
bool in_alt_di,
read_context& ctxt);
static int
get_default_array_lower_bound(translation_unit::language l);
/// Convert an elf symbol type (given by the ELF{32,64}_ST_TYPE
/// macros) into an elf_symbol::type value.
///
@ -6092,6 +6095,64 @@ dwarf_language_to_tu_language(size_t l)
}
}
/// Get the default array lower bound value as defined by the DWARF
/// specification, version 4, depending on the language of the
/// translation unit.
///
/// @param l the language of the translation unit.
///
/// @return the default array lower bound value.
static int
get_default_array_lower_bound(translation_unit::language l)
{
int value = 0;
switch (l)
{
case translation_unit::LANG_UNKNOWN:
value = 0;
break;
case translation_unit::LANG_Cobol74:
case translation_unit::LANG_Cobol85:
value = 1;
break;
case translation_unit::LANG_C89:
case translation_unit::LANG_C99:
case translation_unit::LANG_C11:
case translation_unit::LANG_C:
case translation_unit::LANG_C_plus_plus_11:
case translation_unit::LANG_C_plus_plus_14:
case translation_unit::LANG_C_plus_plus:
case translation_unit::LANG_ObjC:
case translation_unit::LANG_ObjC_plus_plus:
value = 0;
break;
case translation_unit::LANG_Fortran77:
case translation_unit::LANG_Fortran90:
case translation_unit::LANG_Fortran95:
case translation_unit::LANG_Ada83:
case translation_unit::LANG_Ada95:
case translation_unit::LANG_Pascal83:
case translation_unit::LANG_Modula2:
value = 1;
break;
case translation_unit::LANG_Java:
value = 0;
break;
case translation_unit::LANG_PL1:
value = 1;
break;
case translation_unit::LANG_UPC:
case translation_unit::LANG_D:
case translation_unit::LANG_Python:
case translation_unit::LANG_Go:
case translation_unit::LANG_Mips_Assembler:
value = 0;
break;
}
return value;
}
/// Given a DW_TAG_compile_unit, build and return the corresponding
/// abigail::translation_unit ir node. Note that this function
/// recursively reads the children dies of the current DIE and
@ -7265,7 +7326,11 @@ build_array_type(read_context& ctxt,
Dwarf_Die child;
array_type_def::subranges_type subranges;
size_t upper_bound, lower_bound = 0;
translation_unit::language language =
ctxt.current_translation_unit()->get_language();
size_t upper_bound = 0;
size_t lower_bound = get_default_array_lower_bound(language);
size_t count = 0;
if (dwarf_child(die, &child) == 0)
{
@ -7274,15 +7339,48 @@ build_array_type(read_context& ctxt,
int child_tag = dwarf_tag(&child);
if (child_tag == DW_TAG_subrange_type)
{
// usually not specified for C/C++
// The DWARF 4 specifications says, in [5.11 Subrange
// Type Entries]:
//
// The subrange entry may have the attributes
// DW_AT_lower_bound and DW_AT_upper_bound to
// specify, respectively, the lower and upper bound
// values of the subrange.
//
// So let's look for DW_AT_lower_bound first.
die_unsigned_constant_attribute(&child,
DW_AT_lower_bound,
lower_bound);
// Then, DW_AT_upper_bound.
if (!die_unsigned_constant_attribute(&child,
DW_AT_upper_bound,
upper_bound))
return result;
{
// The DWARF 4 spec says, in [5.11 Subrange Type
// Entries]:
//
// The DW_AT_upper_bound attribute may be replaced
// by a DW_AT_count attribute, whose value
// describes the number of elements in the
// subrange rather than the value of the last
// element."
//
// So, as DW_AT_upper_bound is not present in this
// case, let's see if there is a DW_AT_count.
if (!die_unsigned_constant_attribute(&child,
DW_AT_count,
count))
// We have no information about the number of
// elements of the array. Let's bail out then.
return result;
// We can deduce the upper_bound from the
// lower_bound and the number of elements of the
// array:
if (size_t u = lower_bound + count)
upper_bound = u - 1;
}
array_type_def::subrange_sptr s
(new array_type_def::subrange_type(lower_bound,

View File

@ -249,6 +249,12 @@ test-diff-dwarf/test33-fnref-changes-v1.o \
test-diff-dwarf/test34-pr19173-libfoo.so \
test-diff-dwarf/test34-pr19173-libfoo2.so \
test-diff-dwarf/test34-pr19173-libfoo-report-0.txt \
test-diff-dwarf/test35-pr19173-libfoo-long-gcc.so \
test-diff-dwarf/test35-pr19173-libfoo-long-gcc2.so \
test-diff-dwarf/test35-pr19173-libfoo-long-gcc-report-0.txt \
test-diff-dwarf/test35-pr19173-libfoo-long-clang.so \
test-diff-dwarf/test35-pr19173-libfoo-long-clang2.so \
test-diff-dwarf/test35-pr19173-libfoo-long-clang-report-0.txt \
\
test-read-dwarf/test0 \
test-read-dwarf/test0.abi \

View File

@ -0,0 +1,13 @@
Functions changes summary: 0 Removed, 0 Changed, 0 Added function
Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
1 Changed variable:
[C]'char buggy_symbol[5]' was changed to 'char buggy_symbol[10]':
size of symbol (in bytes) changed from 5 to 10
type of variable changed:
type name changed from 'char[5]' to 'char[10]'
array type size changed from 40 to 80 bits:
array type subrange 1 changed length from 5 to 10

View File

@ -0,0 +1,13 @@
Functions changes summary: 0 Removed, 0 Changed, 0 Added function
Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
1 Changed variable:
[C]'char buggy_symbol[5]' was changed to 'char buggy_symbol[10]':
size of symbol (in bytes) changed from 5 to 10
type of variable changed:
type name changed from 'char[5]' to 'char[10]'
array type size changed from 40 to 80 bits:
array type subrange 1 changed length from 5 to 10

Binary file not shown.

View File

@ -0,0 +1,15 @@
// This file is the source code for 4 binaries.
// It comes from one of the comments of bug libabigail/19173.
// To compile the first two binaries, please do:
// gcc test35-pr19173-libfoo-long.c -shared -fpic -o test35-pr19173-libfoo-long-gcc.so -g
// gcc test35-pr19173-libfoo-long.c -shared -fpic -o test35-pr19173-libfoo-long-gcc2.so -g -DLONG
//
// To compile the next two binaries, please do:
// clang test35-pr19173-libfoo-long.c -shared -fpic -o test35-pr19173-libfoo-long-clang.so -g
// clang test35-pr19173-libfoo-long.c -shared -fpic -o test35-pr19173-libfoo-long-clang2.so -g -DLONG
#ifdef LONG
char buggy_symbol[10];
#else
char buggy_symbol[5];
#endif

View File

@ -272,6 +272,18 @@ InOutSpec in_out_specs[] =
"data/test-diff-dwarf/test34-pr19173-libfoo-report-0.txt",
"output/test-diff-dwarf/test34-pr19173-libfoo-report-0.txt"
},
{
"data/test-diff-dwarf/test35-pr19173-libfoo-long-gcc.so",
"data/test-diff-dwarf/test35-pr19173-libfoo-long-gcc2.so",
"data/test-diff-dwarf/test35-pr19173-libfoo-long-gcc-report-0.txt",
"output/test-diff-dwarf/test35-pr19173-libfoo-long-gcc-report-0.txt"
},
{
"data/test-diff-dwarf/test35-pr19173-libfoo-long-clang.so",
"data/test-diff-dwarf/test35-pr19173-libfoo-long-clang2.so",
"data/test-diff-dwarf/test35-pr19173-libfoo-long-clang-report-0.txt",
"output/test-diff-dwarf/test35-pr19173-libfoo-long-clang-report-0.txt"
},
// This should be the last entry
{NULL, NULL, NULL, NULL}
};