From patchwork Wed Jan 27 12:58:45 2021 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: 41846 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 984033972827; Wed, 27 Jan 2021 12:59:37 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 984033972827 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1611752377; bh=BB7rkhQWHrLI3ZRS7W2Gfg1lpUdW13Q1RJames8VjK0=; h=Date:In-Reply-To:References:Subject:To:List-Id:List-Unsubscribe: List-Archive:List-Help:List-Subscribe:From:Reply-To:Cc:From; b=pHsuytpr8nSJHdnqSBQxCZyKGxAvlRMASSCoTrdxMu3Lpe0tzc4kPHkxq7XNZj81g GQFpYqlXtufe6J7JNHaxPF3IO4q9+qK14iFsV4KK7fa3y2WkG1VZUposC4+avmxoaw KUILkxeiUnuS8jKOoBdeBDwK3rnPrKslaYgrTA9k= 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 1AE6C3972827 for ; Wed, 27 Jan 2021 12:59:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 1AE6C3972827 Received: by mail-wr1-x449.google.com with SMTP id n14so910107wru.6 for ; Wed, 27 Jan 2021 04:59:34 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=BB7rkhQWHrLI3ZRS7W2Gfg1lpUdW13Q1RJames8VjK0=; b=fEGC6awxtgPi9JzioDrNPZXHc6/fhABDuubQiSaRRUYtp9raSwc2/8lg+EPDFqi7t0 gco1B2ZLj41Ybd2xlwCQnHpnVFRPx8Fav77WNE3MfUmG/ZfNeILTaktgrwYNxhruaRVZ unv1DbsnZjCtCv77gJSHHnLcLW1BjA/B+ZkctQIwykdNKRgJ82eHKPk/9J42j40ziAnB SnVHNQVhNafjGygN76E3wz+R2Ej6mj5gdrBmzEOYkBVi6ZsCADgx8wwmwXm0YI/Hmpt0 gfI7BWwXs5PgLozoxE0DwnIsid9VeAwShRKfHLrbfWstgQ+mOxdoC/LaSd1CzFw9gmEm fpdg== X-Gm-Message-State: AOAM532llNbb8eA14bTSDV9Tusj80O2pM78HsWl6y3Ur3hwhSs39wkhf Zr/XM3VoG42AhIzZ3X5+a0pilelFYghsrRAPSTwiOoW63rRhgcq8CrtLKVgKuE3TgqqwU2HBJLy jCF738Dam6SqwHPJi1oBEOYz1KhIfal1Xt8Ajcj/mqFwCkWcRsnnwB/mS/MYS2s1wvqLy9x8= X-Google-Smtp-Source: ABdhPJx98fcbZ+REFVEnqOQmYeUUrankvlkvSwJR8KXCMgDQiqqKv0eiSlm/rT1Dr5dms9Y8YJu7SpfGZiI6ZQ== X-Received: from lux.lon.corp.google.com ([2a00:79e0:d:210:7220:84ff:fe09:a3aa]) (user=maennich job=sendgmr) by 2002:a05:600c:258:: with SMTP id 24mr4091531wmj.161.1611752373182; Wed, 27 Jan 2021 04:59:33 -0800 (PST) Date: Wed, 27 Jan 2021 12:58:45 +0000 In-Reply-To: <20210127125853.886677-1-maennich@google.com> Message-Id: <20210127125853.886677-13-maennich@google.com> Mime-Version: 1.0 References: <20200619214305.562-1-maennich@google.com> <20210127125853.886677-1-maennich@google.com> X-Mailer: git-send-email 2.30.0.280.ga3ce27912f-goog Subject: [PATCH 12/20] abg-elf-helpers: migrate ppc64 specific helpers To: libabigail@sourceware.org X-Spam-Status: No, score=-23.2 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 693fae82040e..b2a7144afe9d 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -2141,10 +2141,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 @@ -2325,7 +2321,6 @@ public: elf_handle_ = 0; elf_path_ = elf_path; symtab_section_ = 0; - opd_section_ = 0; cur_tu_die_ = 0; exported_decls_builder_ = 0; @@ -5312,19 +5307,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. /// @@ -5436,152 +5418,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 @@ -5890,13 +5726,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 // @@ -6059,24 +5897,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 @@ -6227,26 +6047,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 5130e5b64f7a..fb9f3af67bfc 100644 --- a/src/abg-elf-helpers.cc +++ b/src/abg-elf-helpers.cc @@ -848,6 +848,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. /// @@ -1012,5 +1159,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 b4f3293d2bd6..a06232738052 100644 --- a/src/abg-elf-helpers.h +++ b/src/abg-elf-helpers.h @@ -12,6 +12,7 @@ #include "config.h" +#include #include #include @@ -133,6 +134,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 // @@ -162,6 +167,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