Bug 24431 Read 32bit values when testing for the v4.19 symbol table format
authormaennich@google.com <maennich@google.com>
Fri, 10 May 2019 01:00:40 +0000 (02:00 +0100)
committerDodji Seketeli <dodji@redhat.com>
Fri, 10 May 2019 05:21:24 +0000 (07:21 +0200)
Reading into uint64_t when reading the symbol table values drops the
sign and subsequently offset calculations will only be correct if either
the offset is positive or if the calculation overflows.

Read the relative value as signed int32_t (indepently of the target's
bitness) to allow negative offsets.  That also allows to drop the code
that formerly handled the overflow.

That change fixes an assertion raised when dealing with aarch64 kernel
binaries that have a __ksymtab with 32bit relocations. i.e. Bug #24431

* src/abg-dwarf-reader.cc
(try_reading_first_ksymtab_entry_using_v4_19_format): attempt to
read first __ksymtab entry into int32_t to preserve sign

Signed-off-by: Matthias Maennich <maennich@google.com>
src/abg-dwarf-reader.cc

index 1972777..5396c9b 100644 (file)
@@ -7234,29 +7234,17 @@ public:
     uint8_t *bytes = reinterpret_cast<uint8_t*>(elf_data->d_buf);
     bool is_big_endian = elf_architecture_is_big_endian();
     elf_symbol_sptr symbol;
-    unsigned char symbol_value_size = 4;
-    unsigned char arch_word_size = architecture_word_size();
 
+    int32_t offset = 0;
+    const unsigned char symbol_value_size = sizeof(offset);
     GElf_Addr symbol_address = 0, adjusted_symbol_address = 0;
     ABG_ASSERT(read_int_from_array_of_bytes(bytes,
                                            symbol_value_size,
                                            is_big_endian,
-                                           symbol_address));
+                                           offset));
     GElf_Shdr mem;
     GElf_Shdr *section_header = gelf_getshdr(section, &mem);
-    if (arch_word_size == 4)
-      symbol_address = (uint32_t)(symbol_address + section_header->sh_addr);
-    else if (arch_word_size == 8)
-      {
-       symbol_address = symbol_address + section_header->sh_addr;
-       if (symbol_address < ((uint64_t)1 << 32))
-         // The symbol address is expressed in 32 bits.  So let's
-         // convert it to a 64 bits address with the 4 most
-         // significant bytes set to ff each.
-         symbol_address = ((uint64_t)0xffffffff << 32) | symbol_address;
-      }
-    else
-      ABG_ASSERT_NOT_REACHED;
+    symbol_address = offset + section_header->sh_addr;
 
     adjusted_symbol_address = maybe_adjust_fn_sym_address(symbol_address);
     symbol = lookup_elf_symbol_from_address(adjusted_symbol_address);