symtab: add support for CRC values from __kcrctab
authorAleksei Vetrov <vvvvvv@google.com>
Fri, 18 Nov 2022 09:09:07 +0000 (09:09 +0000)
committerDodji Seketeli <dodji@redhat.com>
Fri, 18 Nov 2022 14:10:14 +0000 (15:10 +0100)
New kernels changed the format of storing CRC values from absolute
symbol value to the address in __kcrctab or __kcrctab_gpl section.
This change adds support for CRC values described in this format.

* src/abg-elf-helpers.h (get_crc_for_symbol): Defined new
helper function to extract CRC from ELF symbol.
* src/abg-elf-helpers.cc (get_crc_for_symbol): Implemented this
function with support of old and new CRC values format.
* src/abg-symtab-reader.cc (symtab::load_): Used the new
function when building CRC values map.

Change-Id: I7de5c737d5caaef0c5b7b2ea0d448368889a16be
Signed-off-by: Aleksei Vetrov <vvvvvv@google.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
src/abg-elf-helpers.cc
src/abg-elf-helpers.h
src/abg-symtab-reader.cc

index cbcf54287d509abad04c9e5c6bf4fe3e08dc21ac..8c6c4448d08ec40c7e970cb3d534ab0b22a6b806 100644 (file)
@@ -905,6 +905,53 @@ get_version_for_symbol(Elf*                        elf_handle,
   return false;
 }
 
+/// Return the CRC from the "__crc_" symbol.
+///
+/// @param elf_handle the elf handle to use.
+///
+/// @param crc_symbol symbol containing CRC value.
+///
+/// @param crc_value the CRC found for @p crc_symbol.
+///
+/// @return true iff a CRC was found for given @p crc_symbol.
+bool
+get_crc_for_symbol(Elf* elf_handle, GElf_Sym* crc_symbol, uint32_t& crc_value)
+{
+  size_t crc_section_index = crc_symbol->st_shndx;
+  uint64_t crc_symbol_value = crc_symbol->st_value;
+  if (crc_section_index == SHN_ABS)
+    {
+      crc_value = crc_symbol_value;
+      return true;
+    }
+
+  Elf_Scn* kcrctab_section = elf_getscn(elf_handle, crc_section_index);
+  if (kcrctab_section == NULL)
+      return false;
+
+  GElf_Shdr sheader_mem;
+  GElf_Shdr* sheader = gelf_getshdr(kcrctab_section, &sheader_mem);
+  if (sheader == NULL)
+    return false;
+
+  Elf_Data* kcrctab_data = elf_rawdata(kcrctab_section, NULL);
+  if (kcrctab_data == NULL)
+    return false;
+
+  if (crc_symbol_value < sheader->sh_addr)
+    return false;
+
+  size_t offset = crc_symbol_value - sheader->sh_addr;
+  if (offset + sizeof(uint32_t) > kcrctab_data->d_size
+      || offset + sizeof(uint32_t) > sheader->sh_size)
+    return false;
+
+  crc_value = *reinterpret_cast<uint32_t*>(
+      reinterpret_cast<char*>(kcrctab_data->d_buf) + offset);
+
+  return true;
+}
+
 /// Test if the architecture of the current binary is ppc64.
 ///
 /// @param elf_handle the ELF handle to consider.
index e884c6a3d863217e670c406b6895f57ec74cf742..37345e0e8daa0b2641bb424fb250021f1c722f1c 100644 (file)
@@ -141,6 +141,9 @@ get_version_for_symbol(Elf*                 elf_handle,
                       bool                     get_def_version,
                       elf_symbol::version&     version);
 
+bool
+get_crc_for_symbol(Elf* elf_handle, GElf_Sym* crc_symbol, uint32_t& crc_value);
+
 //
 // Architecture specific helpers
 //
index 8a566f8dcc7b0d72efbb2ae27f56617113ba91c1..f9cdfaa15d006e4388cebb4df4756110e0623710 100644 (file)
@@ -314,7 +314,10 @@ symtab::load_(Elf*        elf_handle,
        }
       if (is_kernel && name.rfind("__crc_", 0) == 0)
        {
-         ABG_ASSERT(crc_values.emplace(name.substr(6), sym->st_value).second);
+         uint32_t crc_value;
+         ABG_ASSERT(elf_helpers::get_crc_for_symbol(elf_handle,
+                                                    sym, crc_value));
+         ABG_ASSERT(crc_values.emplace(name.substr(6), crc_value).second);
          continue;
        }
       if (strings_section && is_kernel && name.rfind("__kstrtabns_", 0) == 0)