Don't require all version symbol sections to present

When we need to get the version of a defined symbol, only the
SHT_GNU_versym and SHT_GNU_verdef sections are necessary.
SHT_GNU_verneed is not necessary, for instance.

So do not require that all of the three version-related sections to be
present when we want to get some symbol version information.

Otherwise, we just don't get the version of a defined symbol when the
SHT_GNU_verneed section is not present.  I stumbled upon this while
looking the abidw's output of ld-2.17.so from
glibc-2.17-79.el7_1.x86_64.  The _rtld_global_ro variable's symbol was
being seen as having no symbol version.  In reality it has the
GLIBC_PRIVATE version, but because the binary lacks a SHT_GNU_verneed
section, we were not getting the symbols version information.

I am not adding that library to the test suite because it's too big.
But at least this change doesn't break the existing regression test
suite.

	* src/abg-dwarf-reader.cc (get_symbol_versionning_sections): Allow
	returning just some of the three version-related section, not
	necessarily all of them.  Adjust comment.
	(get_version_for_symbol): Be ready to not necessarily having the
	three version-related sections available.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2016-05-31 11:39:16 +02:00
parent b36ca1501e
commit 5fe6a7404b

View File

@ -1004,13 +1004,16 @@ compare_symbol_name(const string& symbol_name,
///
/// @param elf_handle the elf handle to use.
///
/// @param versym_section the SHT_GNU_versym section found.
/// @param versym_section the SHT_GNU_versym section found. If the
/// section wasn't found, this is set to nil.
///
/// @param verdef_section the SHT_GNU_verdef section found.
/// @param verdef_section the SHT_GNU_verdef section found. If the
/// section wasn't found, this is set to nil.
///
/// @param verneed_section the SHT_GNU_verneed section found.
/// @param verneed_section the SHT_GNU_verneed section found. If the
/// section wasn't found, this is set to nil.
///
/// @return true iff the sections where found.
/// @return true iff at least one of the the sections where found.
static bool
get_symbol_versionning_sections(Elf* elf_handle,
Elf_Scn*& versym_section,
@ -1030,14 +1033,15 @@ get_symbol_versionning_sections(Elf* elf_handle,
verdef = section;
else if (h->sh_type == SHT_GNU_verneed)
verneed = section;
}
if (versym && verdef && verneed)
{
versym_section = versym;
verdef_section = verdef;
verneed_section = verneed;
return true;
}
if (versym || verdef || verneed)
{
// At least one the versionning sections was found. Return it.
versym_section = versym;
verdef_section = verdef;
verneed_section = verneed;
return true;
}
return false;
@ -1206,9 +1210,14 @@ get_version_for_symbol(Elf* elf_handle,
verneed_section))
return false;
Elf_Data* versym_data = elf_getdata(versym_section, NULL);
GElf_Versym versym_mem;
GElf_Versym* versym = gelf_getversym(versym_data, symbol_index, &versym_mem);
Elf_Data* versym_data = (versym_section)
? elf_getdata(versym_section, NULL)
: NULL;
GElf_Versym* versym = (versym_data)
? gelf_getversym(versym_data, symbol_index, &versym_mem)
: NULL;
if (versym == 0 || *versym <= 1)
// I got these value from the code of readelf.c in elfutils.
// Apparently, if the symbol version entry has these values, the
@ -1224,14 +1233,16 @@ get_version_for_symbol(Elf* elf_handle,
// specification.
return false;
if (get_version_definition_for_versym(elf_handle, versym,
verdef_section, version))
if (verdef_section
&& get_version_definition_for_versym(elf_handle, versym,
verdef_section, version))
return true;
}
else
{
if (get_version_needed_for_versym(elf_handle, versym,
verneed_section, version))
if (verneed_section
&& get_version_needed_for_versym(elf_handle, versym,
verneed_section, version))
return true;
}
@ -3372,9 +3383,14 @@ public:
verneed_section))
return false;
Elf_Data* versym_data = elf_getdata(versym_section, NULL);
GElf_Versym versym_mem;
GElf_Versym* versym = gelf_getversym(versym_data, symbol_index, &versym_mem);
Elf_Data* versym_data = (versym_section)
? elf_getdata(versym_section, NULL)
: NULL;
GElf_Versym* versym = (versym_data)
? gelf_getversym(versym_data, symbol_index, &versym_mem)
: NULL;
if (versym == 0 || *versym <= 1)
// I got these value from the code of readelf.c in elfutils.
// Apparently, if the symbol version entry has these values, the
@ -3390,14 +3406,16 @@ public:
// specification.
return false;
if (get_version_definition_for_versym(elf_handle(), versym,
verdef_section, version))
if (verdef_section
&& get_version_definition_for_versym(elf_handle(), versym,
verdef_section, version))
return true;
}
else
{
if (get_version_needed_for_versym(elf_handle(), versym,
verneed_section, version))
if (verneed_section
&& get_version_needed_for_versym(elf_handle(), versym,
verneed_section, version))
return true;
}