From patchwork Fri Jul 3 16:46:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Matthias_M=C3=A4nnich?= X-Patchwork-Id: 39895 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0DF423844079; Fri, 3 Jul 2020 16:48:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0DF423844079 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1593794888; bh=upPfaD2EOgo1FwS31bYwquvGI92Oe046/3bxYQSNzsE=; h=Date:In-Reply-To:References:Subject:To:List-Id:List-Unsubscribe: List-Archive:List-Help:List-Subscribe:From:Reply-To:Cc:From; b=DUPg9LcjryO9ESVkpONXxV/WvQQYo5K1EuVMJCqja+QuXVu0Ml6wJeiCzg1Avi4lY df0YenHOQNMzTIKbeTC0L1JGngCQQ4VNm3q2CPy/pft+IjA3y3BZ7bStZ81VTohx1L WjidSWgqlbR0/1NEUoTSSKdhT929eODjqbJP0cp8= X-Original-To: libabigail@sourceware.org Delivered-To: libabigail@sourceware.org Received: from mail-wr1-x449.google.com (mail-wr1-x449.google.com [IPv6:2a00:1450:4864:20::449]) by sourceware.org (Postfix) with ESMTPS id 734883844079 for ; Fri, 3 Jul 2020 16:48:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 734883844079 Received: by mail-wr1-x449.google.com with SMTP id y18so12590211wrq.4 for ; Fri, 03 Jul 2020 09:48:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=upPfaD2EOgo1FwS31bYwquvGI92Oe046/3bxYQSNzsE=; b=Yn/0cjSO7Kbf7bHfoH5RLm9NagGAtkY663p40saEKrpR6MICAWJ/VasNDu0AhRnw/m qTE7NSOWbJsrcsJJvjIR5Xcys4/A2DAe1wG/mIquYtpDezJaQOkN2/CSOcuC76gh563U T9KmFJJyRxjwem80CyiMXlidyzoztay7oZtoqe9B4FODl3rKfMnU2RlMTDyBEDCSolcZ nsJ+X0az233fpXTpg8Yp/D3gwaAQjN11qArfY58RZbfjguFhzNZgvtXajKH4B5RFs9LV RvyefQZT+oukRqPNr4huThktUtJgCrwBnVWVhhVdDU3cBswuXEjiMF8ZfXqZ+tyV6oWH 2fQg== X-Gm-Message-State: AOAM530lddSUgj6BUextt13PdVFF/qigxQe4v38MBkQMNKGx9Y+6Xj+P iLW06tahPOODbsgq+zS2emOuuXKPigDXs4GbtSGmq8Q9tpSSg2Xka+jmf/R6nxC/V4NaHxJgm6j v5xbENm4BUhTDYe2LG51u6hnxhjKC8R2apzMqaCAMPlQvY2USjEnr5QcB/v5N/D8s9dNqTAU= X-Google-Smtp-Source: ABdhPJwqqbyLQ7WoOZxAtLOg8sZGoa6hLSRgWh0EICMqcLJ+/SBBnEiDCS6VJlb0McLDEE94zEo/95QJxsG1zA== X-Received: by 2002:a7b:c763:: with SMTP id x3mr28636839wmk.47.1593794883340; Fri, 03 Jul 2020 09:48:03 -0700 (PDT) Date: Fri, 3 Jul 2020 18:46:43 +0200 In-Reply-To: <20200703164651.1510825-1-maennich@google.com> Message-Id: <20200703164651.1510825-14-maennich@google.com> Mime-Version: 1.0 References: <20200619214305.562-1-maennich@google.com> <20200703164651.1510825-1-maennich@google.com> X-Mailer: git-send-email 2.27.0.212.ge8ba1cc988-goog Subject: [PATCH v2 13/21] abg-elf-helpers: migrate ppc64 specific helpers To: libabigail@sourceware.org X-Spam-Status: No, score=-23.3 required=5.0 tests=BAYES_00, DKIMWL_WL_MED, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libabigail@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list of the Libabigail project List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-Patchwork-Original-From: Matthias Maennich via Libabigail From: =?utf-8?q?Matthias_M=C3=A4nnich?= Reply-To: Matthias Maennich Cc: maennich@google.com, kernel-team@android.com Errors-To: libabigail-bounces@sourceware.org Sender: "Libabigail" This migrates more helpers to abg-elf-helpers: lookup_ppc64_elf_fn_entry_point_address with dependencies read_uint64_from_array_of_bytes read_int_from_array_of_bytes address_is_in_opd_section with dependency address_is_in_section read_context::find_opd_section and read_context::opd_section_ are obsolete. * src/abg-dwarf-reader.cc (read_context::opd_section_): Delete. (read_context::find_opd_section): Delete. (read_context::read_uint64_from_array_of_bytes): Delete. (read_context::read_int_from_array_of_bytes): Delete. (read_context::lookup_ppc64_elf_fn_entry_point_address): Delete. (read_context::address_is_in_opd_section): Delete. (read_context::address_is_in_section): Delete. (read_context::load_symbol_maps_from_symtab_section): Adjust. * src/abg-elf-helpers.cc (read_int_from_array_of_bytes): New. (read_uint64_from_array_of_bytes): New. (lookup_ppc64_elf_fn_entry_point_address): New. (address_is_in_section): New. (address_is_in_opd_section): New. * src/abg-elf-helpers.h (lookup_ppc64_elf_fn_entry_point_address): New declaration. (address_is_in_opd_section): New declaration. Reviewed-by: Giuliano Procida Signed-off-by: Matthias Maennich --- src/abg-dwarf-reader.cc | 208 +--------------------------------------- src/abg-elf-helpers.cc | 186 +++++++++++++++++++++++++++++++++++ src/abg-elf-helpers.h | 8 ++ 3 files changed, 198 insertions(+), 204 deletions(-) diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index d90c0a3fe56a..47d561452b05 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -2075,10 +2075,6 @@ public: mutable Elf* elf_handle_; string elf_path_; mutable Elf_Scn* symtab_section_; - // The "Official procedure descriptor section, aka .opd", used in - // ppc64 elf v1 binaries. This section contains the procedure - // descriptors on that platform. - mutable Elf_Scn* opd_section_; Dwarf_Die* cur_tu_die_; mutable dwarf_expr_eval_context dwarf_expr_eval_context_; // A set of maps (one per kind of die source) that associates a decl @@ -2258,7 +2254,6 @@ public: elf_handle_ = 0; elf_path_ = elf_path; symtab_section_ = 0; - opd_section_ = 0; cur_tu_die_ = 0; exported_decls_builder_ = 0; @@ -4934,19 +4929,6 @@ public: return symtab_section_; } - /// Return the "Official Procedure descriptors section." This - /// section is named .opd, and is usually present only on PPC64 - /// ELFv1 binaries. - /// - /// @return the .opd section, if found. Return nil otherwise. - Elf_Scn* - find_opd_section() const - { - if (!opd_section_) - opd_section_ = elf_helpers::find_opd_section(elf_handle()); - return opd_section_; - } - /// Lookup an elf symbol, referred to by its index, from the .symtab /// section. /// @@ -5058,152 +5040,6 @@ public: return sym; } - /// Read 8 bytes and convert their value into an uint64_t. - /// - /// @param bytes the array of bytes to read the next 8 bytes from. - /// Note that this array must be at least 8 bytes long. - /// - /// @param result where to store the resuting uint64_t that was read. - /// - /// @param is_big_endian if true, read the 8 bytes in Big Endian - /// mode, otherwise, read them in Little Endian. - /// - /// @param true if the 8 bytes could be read, false otherwise. - bool - read_uint64_from_array_of_bytes(const uint8_t *bytes, - bool is_big_endian, - uint64_t &result) const - { - return read_int_from_array_of_bytes(bytes, 8, is_big_endian, result); - } - - /// Read N bytes and convert their value into an integer type T. - /// - /// Note that N cannot be bigger than 8 for now. The type passed needs to be - /// at least of the size of number_of_bytes. - /// - /// @param bytes the array of bytes to read the next 8 bytes from. - /// Note that this array must be at least 8 bytes long. - /// - /// @param number_of_bytes the number of bytes to read. This number - /// cannot be bigger than 8. - /// - /// @param is_big_endian if true, read the 8 bytes in Big Endian - /// mode, otherwise, read them in Little Endian. - /// - /// @param result where to store the resuting integer that was read. - /// - /// - /// @param true if the 8 bytes could be read, false otherwise. - template - bool - read_int_from_array_of_bytes(const uint8_t *bytes, - unsigned char number_of_bytes, - bool is_big_endian, - T &result) const - { - if (!bytes) - return false; - - ABG_ASSERT(number_of_bytes <= 8); - ABG_ASSERT(number_of_bytes <= sizeof(T)); - - T res = 0; - - const uint8_t *cur = bytes; - if (is_big_endian) - { - // In Big Endian, the most significant byte is at the lowest - // address. - const uint8_t* msb = cur; - res = *msb; - - // Now read the remaining least significant bytes. - for (uint i = 1; i < number_of_bytes; ++i) - res = (res << 8) | ((T)msb[i]); - } - else - { - // In Little Endian, the least significant byte is at the - // lowest address. - const uint8_t* lsb = cur; - res = *lsb; - // Now read the remaining most significant bytes. - for (uint i = 1; i < number_of_bytes; ++i) - res = res | (((T)lsb[i]) << i * 8); - } - - result = res; - return true; - } - - /// Lookup the address of the function entry point that corresponds - /// to the address of a given function descriptor. - /// - /// On PPC64, a function pointer is the address of a function - /// descriptor. Function descriptors are located in the .opd - /// section. Each function descriptor is a triplet of three - /// addresses, each one on 64 bits. Among those three address only - /// the first one is of any interest to us: the address of the entry - /// point of the function. - /// - /// This function returns the address of the entry point of the - /// function whose descriptor's address is given. - /// - /// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUNC-DES - /// - /// https://www.ibm.com/developerworks/community/blogs/5894415f-be62-4bc0-81c5-3956e82276f3/entry/deeply_understand_64_bit_powerpc_elf_abi_function_descriptors?lang=en - /// - /// @param fn_desc_address the address of the function descriptor to - /// consider. - /// - /// @return the address of the entry point of the function whose - /// descriptor has the address @p fn_desc_address. If there is no - /// .opd section (e.g because we are not on ppc64) or more generally - /// if the function descriptor could not be found then this function - /// just returns the address of the fuction descriptor. - GElf_Addr - lookup_ppc64_elf_fn_entry_point_address(GElf_Addr fn_desc_address) const - { - if (!elf_handle()) - return fn_desc_address; - - if (!architecture_is_ppc64(elf_handle())) - return fn_desc_address; - - bool is_big_endian = architecture_is_big_endian(elf_handle()); - - Elf_Scn *opd_section = find_opd_section(); - if (!opd_section) - return fn_desc_address; - - GElf_Shdr header_mem; - // The section header of the .opd section. - GElf_Shdr *opd_sheader = gelf_getshdr(opd_section, &header_mem); - - // The offset of the function descriptor entry, in the .opd - // section. - size_t fn_desc_offset = fn_desc_address - opd_sheader->sh_addr; - Elf_Data *elf_data = elf_rawdata(opd_section, 0); - - // Ensure that the opd_section has at least 8 bytes, starting from - // the offset we want read the data from. - if (elf_data->d_size <= fn_desc_offset + 8) - return fn_desc_address; - - // A pointer to the data of the .opd section, that we can actually - // do something with. - uint8_t * bytes = (uint8_t*) elf_data->d_buf; - - // The resulting address we are looking for is going to be formed - // in this variable. - GElf_Addr result = 0; - ABG_ASSERT(read_uint64_from_array_of_bytes(bytes + fn_desc_offset, - is_big_endian, result)); - - return result; - } - /// Test if a given function symbol has been exported. /// /// @param symbol_address the address of the symbol we are looking @@ -5513,13 +5349,15 @@ public: // symbol that are in the .opd section. GElf_Addr fn_desc_addr = sym->st_value; GElf_Addr fn_entry_point_addr = - lookup_ppc64_elf_fn_entry_point_address(fn_desc_addr); + lookup_ppc64_elf_fn_entry_point_address( + elf_handle(), fn_desc_addr); addr_elf_symbol_sptr_map_type::const_iterator it2 = fun_entry_addr_sym_map().find(fn_entry_point_addr); if (it2 == fun_entry_addr_sym_map().end()) fun_entry_addr_sym_map()[fn_entry_point_addr] = symbol; - else if (address_is_in_opd_section(fn_desc_addr)) + else if (address_is_in_opd_section(elf_handle(), + fn_desc_addr)) { // Either // @@ -5682,24 +5520,6 @@ public: return true; } - /// Return true if an address is in the ".opd" section that is - /// present on the ppc64 platform. - /// - /// @param addr the address to consider. - /// - /// @return true iff @p addr is designates a word that is in the - /// ".opd" section. - bool - address_is_in_opd_section(Dwarf_Addr addr) - { - Elf_Scn * opd_section = find_opd_section(); - if (!opd_section) - return false; - if (address_is_in_section(addr, opd_section)) - return true; - return false; - } - /// Load the symbol maps if necessary. /// /// @return true iff the symbol maps has been loaded by this @@ -5850,26 +5670,6 @@ public: return addr; } - /// Test if a given address is in a given section. - /// - /// @param addr the address to consider. - /// - /// @param section the section to consider. - bool - address_is_in_section(Dwarf_Addr addr, Elf_Scn* section) const - { - if (!section) - return false; - - GElf_Shdr sheader_mem; - GElf_Shdr* sheader = gelf_getshdr(section, &sheader_mem); - - if (sheader->sh_addr <= addr && addr <= sheader->sh_addr + sheader->sh_size) - return true; - - return false; - } - /// For a relocatable (*.o) elf file, this function expects an /// absolute address, representing a global variable symbol. It /// then extracts the address of the {.data,.data1,.rodata,.bss} diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc index ed768d221d4f..6e2495af1ee0 100644 --- a/src/abg-elf-helpers.cc +++ b/src/abg-elf-helpers.cc @@ -863,6 +863,153 @@ architecture_is_big_endian(Elf* elf_handle) return is_big_endian; } +/// Read N bytes and convert their value into an integer type T. +/// +/// Note that N cannot be bigger than 8 for now. The type passed needs to be at +/// least of the size of number_of_bytes. +/// +/// @param bytes the array of bytes to read the next 8 bytes from. +/// Note that this array must be at least 8 bytes long. +/// +/// @param number_of_bytes the number of bytes to read. This number +/// cannot be bigger than 8. +/// +/// @param is_big_endian if true, read the 8 bytes in Big Endian +/// mode, otherwise, read them in Little Endian. +/// +/// @param result where to store the resuting integer that was read. +/// +/// +/// @param true if the 8 bytes could be read, false otherwise. +template +bool +read_int_from_array_of_bytes(const uint8_t* bytes, + unsigned char number_of_bytes, + bool is_big_endian, + T& result) +{ + if (!bytes) + return false; + + ABG_ASSERT(number_of_bytes <= 8); + ABG_ASSERT(number_of_bytes <= sizeof(T)); + + T res = 0; + + const uint8_t* cur = bytes; + if (is_big_endian) + { + // In Big Endian, the most significant byte is at the lowest + // address. + const uint8_t* msb = cur; + res = *msb; + + // Now read the remaining least significant bytes. + for (uint i = 1; i < number_of_bytes; ++i) + res = (res << 8) | ((T)msb[i]); + } + else + { + // In Little Endian, the least significant byte is at the + // lowest address. + const uint8_t* lsb = cur; + res = *lsb; + // Now read the remaining most significant bytes. + for (uint i = 1; i < number_of_bytes; ++i) + res = res | (((T)lsb[i]) << i * 8); + } + + result = res; + return true; +} + +/// Read 8 bytes and convert their value into an uint64_t. +/// +/// @param bytes the array of bytes to read the next 8 bytes from. +/// Note that this array must be at least 8 bytes long. +/// +/// @param result where to store the resuting uint64_t that was read. +/// +/// @param is_big_endian if true, read the 8 bytes in Big Endian +/// mode, otherwise, read them in Little Endian. +/// +/// @param true if the 8 bytes could be read, false otherwise. +bool +read_uint64_from_array_of_bytes(const uint8_t* bytes, + bool is_big_endian, + uint64_t& result) +{ + return read_int_from_array_of_bytes(bytes, 8, is_big_endian, result); +} + + +/// Lookup the address of the function entry point that corresponds +/// to the address of a given function descriptor. +/// +/// On PPC64, a function pointer is the address of a function +/// descriptor. Function descriptors are located in the .opd +/// section. Each function descriptor is a triplet of three +/// addresses, each one on 64 bits. Among those three address only +/// the first one is of any interest to us: the address of the entry +/// point of the function. +/// +/// This function returns the address of the entry point of the +/// function whose descriptor's address is given. +/// +/// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUNC-DES +/// +/// https://www.ibm.com/developerworks/community/blogs/5894415f-be62-4bc0-81c5-3956e82276f3/entry/deeply_understand_64_bit_powerpc_elf_abi_function_descriptors?lang=en +/// +/// @param fn_desc_address the address of the function descriptor to +/// consider. +/// +/// @return the address of the entry point of the function whose +/// descriptor has the address @p fn_desc_address. If there is no +/// .opd section (e.g because we are not on ppc64) or more generally +/// if the function descriptor could not be found then this function +/// just returns the address of the fuction descriptor. +GElf_Addr +lookup_ppc64_elf_fn_entry_point_address(Elf* elf_handle, GElf_Addr fn_desc_address) +{ + if (!elf_handle) + return fn_desc_address; + + if (!architecture_is_ppc64(elf_handle)) + return fn_desc_address; + + bool is_big_endian = architecture_is_big_endian(elf_handle); + + Elf_Scn* opd_section = find_opd_section(elf_handle); + if (!opd_section) + return fn_desc_address; + + GElf_Shdr header_mem; + // The section header of the .opd section. + GElf_Shdr* opd_sheader = gelf_getshdr(opd_section, &header_mem); + + // The offset of the function descriptor entry, in the .opd + // section. + size_t fn_desc_offset = fn_desc_address - opd_sheader->sh_addr; + Elf_Data* elf_data = elf_rawdata(opd_section, 0); + + // Ensure that the opd_section has at least 8 bytes, starting from + // the offset we want read the data from. + if (elf_data->d_size <= fn_desc_offset + 8) + return fn_desc_address; + + // A pointer to the data of the .opd section, that we can actually + // do something with. + uint8_t* bytes = (uint8_t*)elf_data->d_buf; + + // The resulting address we are looking for is going to be formed + // in this variable. + GElf_Addr result = 0; + ABG_ASSERT(read_uint64_from_array_of_bytes(bytes + fn_desc_offset, + is_big_endian, result)); + + return result; +} + /// Test if the ELF binary denoted by a given ELF handle is a Linux /// Kernel Module. /// @@ -1027,5 +1174,44 @@ maybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym) return addr + section_header.sh_addr; } +/// Test if a given address is in a given section. +/// +/// @param addr the address to consider. +/// +/// @param section the section to consider. +bool +address_is_in_section(Dwarf_Addr addr, Elf_Scn* section) +{ + if (!section) + return false; + + GElf_Shdr sheader_mem; + GElf_Shdr* sheader = gelf_getshdr(section, &sheader_mem); + + if (sheader->sh_addr <= addr && addr <= sheader->sh_addr + sheader->sh_size) + return true; + + return false; +} + +/// Return true if an address is in the ".opd" section that is +/// present on the ppc64 platform. +/// +/// @param addr the address to consider. +/// +/// @return true iff @p addr is designates a word that is in the +/// ".opd" section. +bool +address_is_in_opd_section(Elf* elf_handle, Dwarf_Addr addr) +{ + Elf_Scn * opd_section = find_opd_section(elf_handle); + if (!opd_section) + return false; + if (address_is_in_section(addr, opd_section)) + return true; + return false; +} + + } // end namespace elf_helpers } // end namespace abigail diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h index 647c92703dfa..2046648569a7 100644 --- a/src/abg-elf-helpers.h +++ b/src/abg-elf-helpers.h @@ -27,6 +27,7 @@ #include "config.h" +#include #include #include @@ -148,6 +149,10 @@ architecture_is_ppc64(Elf* elf_handle); bool architecture_is_big_endian(Elf* elf_handle); +GElf_Addr +lookup_ppc64_elf_fn_entry_point_address(Elf* elf_handle, + GElf_Addr fn_desc_address); + // // Helpers for Linux Kernel Binaries // @@ -177,6 +182,9 @@ is_dso(Elf* elf_handle); GElf_Addr maybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym); +bool +address_is_in_opd_section(Elf* elf_handle, Dwarf_Addr addr); + } // end namespace elf_helpers } // end namespace abigail