From: Dodji Seketeli Date: Mon, 13 May 2019 12:54:20 +0000 (+0200) Subject: Handle Linux kernel binaries with no __ksymtab section X-Git-Tag: libabigail-1.7~103 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=1930f3caf7bf3d56ceb43c1ce1ecf8a3c5bfe1d2;p=libabigail.git Handle Linux kernel binaries with no __ksymtab section Some Linux kernel binaries can have no __ksymtab section. It's possible that only have a __ksymtab_gpl section or no __ksymtab_gpl either. And apparently they can also have a __ksymtab* section full of zeroes. This patch gets the ELF/DWARF reader prepared to handle these cases. * src/abg-dwarf-reader.cc (find_section): Use elf_getshdrstrndx rather than poking at the elf header on our own. (read_context::find_any_ksymtab_section): Define new member function. (read_context::{get_symtab_format, try_reading_first_ksymtab_entry_using_pre_v4_19_format}): Use the new find_any_ksymtab_section rather than find_ksymtab_section. (read_context::get_nb_ksymtab_entries): Handle the absence of __ksymtab. (read_context::get_nb_ksymtab_gpl_entries): Handle the absence of __ksymtab_gpl. (read_context::load_kernel_symbol_table): Handle the case of zero ksymtab entries. (read_context::{maybe_adjust_address_for_exec_or_dyn, maybe_adjust_fn_sym_address, load_kernel_symbol_table}): Handle an address that is zero. Signed-off-by: Dodji Seketeli --- diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index 7661819b..b7625bfd 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -1035,19 +1035,20 @@ find_symbol_table_section_index(Elf* elf_handle, static Elf_Scn* find_section(Elf* elf_handle, const string& name, Elf64_Word section_type) { - GElf_Ehdr ehmem, *elf_header; - elf_header = gelf_getehdr(elf_handle, &ehmem); + size_t section_header_string_index = 0; + if (elf_getshdrstrndx (elf_handle, §ion_header_string_index) < 0) + return 0; Elf_Scn* section = 0; + GElf_Shdr header_mem, *header; while ((section = elf_nextscn(elf_handle, section)) != 0) { - GElf_Shdr header_mem, *header; header = gelf_getshdr(section, &header_mem); - if (header->sh_type != section_type) - continue; + if (header == NULL || header->sh_type != section_type) + continue; const char* section_name = - elf_strptr(elf_handle, elf_header->e_shstrndx, header->sh_name); + elf_strptr(elf_handle, section_header_string_index, header->sh_name); if (section_name && name == section_name) return section; } @@ -5930,6 +5931,20 @@ public: return ksymtab_gpl_section_; } + /// Return either a __ksymtab or a __ksymtab_gpl section, in case + /// only the __ksymtab_gpl exists. + /// + /// @return the __ksymtab section if it exists, or the + /// __ksymtab_gpl; or NULL if neither is found. + Elf_Scn* + find_any_ksymtab_section() const + { + Elf_Scn *result = find_ksymtab_section(); + if (!result) + result = find_ksymtab_gpl_section(); + return result; + } + /// Return the SHT_GNU_versym, SHT_GNU_verdef and SHT_GNU_verneed /// sections that are involved in symbol versionning. /// @@ -7208,7 +7223,7 @@ public: elf_symbol_sptr try_reading_first_ksymtab_entry_using_pre_v4_19_format() const { - Elf_Scn *section = find_ksymtab_section(); + Elf_Scn *section = find_any_ksymtab_section(); Elf_Data *elf_data = elf_rawdata(section, 0); uint8_t *bytes = reinterpret_cast(elf_data->d_buf); bool is_big_endian = elf_architecture_is_big_endian(); @@ -7237,7 +7252,7 @@ public: elf_symbol_sptr try_reading_first_ksymtab_entry_using_v4_19_format() const { - Elf_Scn *section = find_ksymtab_section(); + Elf_Scn *section = find_any_ksymtab_section(); Elf_Data *elf_data = elf_rawdata(section, 0); uint8_t *bytes = reinterpret_cast(elf_data->d_buf); bool is_big_endian = elf_architecture_is_big_endian(); @@ -7269,7 +7284,7 @@ public: enum ksymtab_format get_ksymtab_format() const { - if (!find_ksymtab_section()) + if (!find_any_ksymtab_section()) ksymtab_format_ = UNDEFINED_KSYMTAB_FORMAT; else { @@ -7342,11 +7357,14 @@ public: if (nb_ksymtab_entries_ == 0) { Elf_Scn *section = find_ksymtab_section(); - GElf_Shdr header_mem; - GElf_Shdr *section_header = gelf_getshdr(section, &header_mem); - size_t entry_size = get_ksymtab_entry_size(); - ABG_ASSERT(entry_size); - nb_ksymtab_entries_ = section_header->sh_size / entry_size; + if (section) + { + GElf_Shdr header_mem; + GElf_Shdr *section_header = gelf_getshdr(section, &header_mem); + size_t entry_size = get_ksymtab_entry_size(); + ABG_ASSERT(entry_size); + nb_ksymtab_entries_ = section_header->sh_size / entry_size; + } } return nb_ksymtab_entries_; } @@ -7362,11 +7380,14 @@ public: if (nb_ksymtab_gpl_entries_ == 0) { Elf_Scn *section = find_ksymtab_gpl_section(); - GElf_Shdr header_mem; - GElf_Shdr *section_header = gelf_getshdr(section, &header_mem); - size_t entry_size = get_ksymtab_entry_size(); - ABG_ASSERT(entry_size); - nb_ksymtab_gpl_entries_ = section_header->sh_size / entry_size; + if (section) + { + GElf_Shdr header_mem; + GElf_Shdr *section_header = gelf_getshdr(section, &header_mem); + size_t entry_size = get_ksymtab_entry_size(); + ABG_ASSERT(entry_size); + nb_ksymtab_gpl_entries_ = section_header->sh_size / entry_size; + } } return nb_ksymtab_gpl_entries_; } @@ -7407,7 +7428,10 @@ public: break; } - if (!linux_exported_vars_set || !linux_exported_fns_set) + if (!linux_exported_vars_set + || !linux_exported_fns_set + || !section + || !nb_entries) return false; // The data of the section. @@ -7459,6 +7483,11 @@ public: // shared object binary. adjusted_symbol_address = maybe_adjust_fn_sym_address(symbol_address); + if (adjusted_symbol_address == 0) + // The resulting symbol address is zero, not sure this + // valid; ignore it. + continue; + // OK now the symbol address should be in a suitable form to // be used to look the symbol up in the usual .symbol section // (aka ELF symbol table). @@ -7704,6 +7733,9 @@ public: Dwarf_Addr maybe_adjust_address_for_exec_or_dyn(Dwarf_Addr addr) const { + if (addr == 0) + return addr; + GElf_Ehdr eh_mem; GElf_Ehdr *elf_header = gelf_getehdr(elf_handle(), &eh_mem); @@ -7754,6 +7786,9 @@ public: Dwarf_Addr maybe_adjust_fn_sym_address(Dwarf_Addr addr) const { + if (addr == 0) + return addr; + Elf* elf = elf_handle(); GElf_Ehdr eh_mem; GElf_Ehdr* elf_header = gelf_getehdr(elf, &eh_mem);