From patchwork Tue Jun 10 09:37:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 114135 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 7AC1C382C09C for ; Tue, 10 Jun 2025 09:37:58 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7AC1C382C09C Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=XM/uLLXd X-Original-To: libabigail@sourceware.org Delivered-To: libabigail@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id B0D25382C091 for ; Tue, 10 Jun 2025 09:37:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B0D25382C091 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org B0D25382C091 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1749548258; cv=none; b=Uzmyih/WYONmGVnFPi50rKck/WVhaWYqXb1ZCSPbDbVd++uU62z/bNJ6DsISL81agQ9IjpWeUW8qefSrciMA+Iu1gnbeDF8cRg4xhbiGs2HUgX5gV9v1jRjOJgOKR1rBZ6nLk1mQzlGXDruSx3cApM5DpjFnY5zkiQwDK0+0yjc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1749548258; c=relaxed/simple; bh=AkE6dJIFoRGdOovIxIJJcZ5T8Xv8FV4PMdkIlJ8rJfM=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=NWzQDJklTv1uWPV3iJkSf9SX+4d2flpgFMY6GQKHQ8zlUaWCC7+JlW4rLnfElDNqIWqakOHSvBcULjQTX63HUBcZQ5InbepmhlC0/51qbrYNUXTvfuXYf7FBqgO8rAqbY1P7NoYndXRE8cw/B45Rb9+oUFmC5gRaMMOuBQr1xik= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B0D25382C091 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1749548258; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=j0qY/7Zx8bW4SjDvEZC0tbwFCtoy5flekP8HeFAib0Y=; b=XM/uLLXdWcKe28Mu3ufgmpFQ6opNgyVOoXfuVHRKyk6XxVj5HmAXvJx4abqKe2B9V/jS2G LjAu1AAafoFNGYBZXvliHJFKjTbLHSeT/dmdKyB37BPkzG36r83VFm0NEmu95tFZJnhKxr N4XHAC+ucv2TSQbh435PhzchvC05M8U= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-308-IXZerW-uNZC8_P9m8YqO4w-1; Tue, 10 Jun 2025 05:37:37 -0400 X-MC-Unique: IXZerW-uNZC8_P9m8YqO4w-1 X-Mimecast-MFC-AGG-ID: IXZerW-uNZC8_P9m8YqO4w_1749548256 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 435FA18089B6 for ; Tue, 10 Jun 2025 09:37:36 +0000 (UTC) Received: from localhost (unknown [10.44.22.13]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A40D8195608D for ; Tue, 10 Jun 2025 09:37:35 +0000 (UTC) Received: by localhost (Postfix, from userid 1000) id 39FE65077C51; Tue, 10 Jun 2025 11:37:33 +0200 (CEST) From: Dodji Seketeli To: libabigail@sourceware.org Subject: [PATCH, applied] elf-reader: Fix elfutils initialization of debuginfo lookup paths Organization: Red Hat / France X-Operating-System: AlmaLinux 9.6 X-URL: http://www.redhat.com Date: Tue, 10 Jun 2025 11:37:33 +0200 Message-ID: <87cybcq6n6.fsf@redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: F4OPtqkl5M8iMX_q5wEAPbmxMUD_ehaGKPjnzckhQ0U_1749548256 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libabigail@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Mailing list of the Libabigail project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libabigail-bounces~patchwork=sourceware.org@sourceware.org Hello, The ELF reader is doing too much work unnecessarily (and flat out wrong sometimes) to setup the paths to where debug info should be looked for. This prevents libabigail client tools from properly relying on the transparent handling of debuginfod by elfutils when possible. This patch fixes the logic of that initialization by following the comments of dwfl_build_id_find_elf in /usr/include/elfutils/libdwfl.h. * src/abg-elf-reader.cc (find_alt_dwarf_debug_info_path) (find_alt_dwarf_debug_info): Remove static functions. (reader::priv::find_alt_dwarf_debug_info): Remove member function. (reader::priv::{formated_di_root_paths, raw_formated_di_root_paths}): Add new data members. (reader::priv::initialize): Initialize the new data members. (reader::priv::initialize_debug_info_root_paths): Define new member function. (reader::priv::crack_open_elf_file): Invoke the new initialize_debug_info_root_paths above. Adjust the call to elf_helpers::initialize_dwfl_callbacks to pass the new raw_formated_di_root_paths. (reader::priv::locate_dwarf_debug_info): Remove all the unnecessary cruft. Just rely on elfutils finding the debug info, now that it's been properly initialized. Use the dwarf_getalt function that is now always present in the versions of elfutils that we use. Signed-off-by: Dodji Seketeli Applied to the mainline. --- src/abg-elf-reader.cc | 222 ++++++++---------------------------------- 1 file changed, 40 insertions(+), 182 deletions(-) diff --git a/src/abg-elf-reader.cc b/src/abg-elf-reader.cc index a7ba4a87..bf590f8f 100644 --- a/src/abg-elf-reader.cc +++ b/src/abg-elf-reader.cc @@ -100,151 +100,6 @@ find_alt_dwarf_debug_info_link(Dwfl_Module *elf_module, return false; } -/// Find alternate debuginfo file of a given "link" under a set of -/// root directories. -/// -/// The link is a string that is read by the function -/// find_alt_dwarf_debug_info_link(). That link is a path that is relative -/// to a given debug info file, e.g, "../../../.dwz/something.debug". -/// It designates the alternate debug info file associated to a given -/// debug info file. -/// -/// This function will thus try to find the .dwz/something.debug file -/// under some given root directories. -/// -/// @param root_dirs the set of root directories to look from. -/// -/// @param alt_file_name a relative path to the alternate debug info -/// file to look for. -/// -/// @param alt_file_path the resulting absolute path to the alternate -/// debuginfo path denoted by @p alt_file_name and found under one of -/// the directories in @p root_dirs. This is set iff the function -/// returns true. -/// -/// @return true iff the function found the alternate debuginfo file. -static bool -find_alt_dwarf_debug_info_path(const vector root_dirs, - const string &alt_file_name, - string &alt_file_path) -{ - if (alt_file_name.empty()) - return false; - - string altfile_name = tools_utils::trim_leading_string(alt_file_name, "../"); - // In case the alt dwarf debug info file is to be found under - // "/usr/lib/debug", look for it under the provided root directories - // instead. - altfile_name = tools_utils::trim_leading_string(altfile_name, - "/usr/lib/debug/"); - - for (vector::const_iterator i = root_dirs.begin(); - i != root_dirs.end(); - ++i) - if (tools_utils::find_file_under_dir(**i, altfile_name, alt_file_path)) - return true; - - return false; -} - -/// Return the alternate debug info associated to a given main debug -/// info file. -/// -/// @param elf_module the elf module to consider. -/// -/// @param debug_root_dirs a set of root debuginfo directories under -/// which too look for the alternate debuginfo file. -/// -/// @param alt_file_name output parameter. This is set to the file -/// path of the alternate debug info file associated to @p elf_module. -/// This is set iff the function returns a non-null result. -/// -/// @param alt_fd the file descriptor used to access the alternate -/// debug info. If this parameter is set by the function, then the -/// caller needs to fclose it, otherwise the file descriptor is going -/// to be leaked. Note however that on recent versions of elfutils -/// where libdw.h contains the function dwarf_getalt(), this parameter -/// is set to 0, so it doesn't need to be fclosed. -/// -/// Note that the alternate debug info file is a DWARF extension as of -/// DWARF 4 ans is decribed at -/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1. -/// -/// @return the alternate debuginfo, or null. If @p alt_fd is -/// non-zero, then the caller of this function needs to call -/// dwarf_end() on the returned alternate debuginfo pointer, -/// otherwise, it's going to be leaked. -static Dwarf* -find_alt_dwarf_debug_info(Dwfl_Module *elf_module, - const vector debug_root_dirs, - string& alt_file_name, - int& alt_fd) -{ - if (elf_module == 0) - return 0; - - Dwarf* result = 0; - find_alt_dwarf_debug_info_link(elf_module, alt_file_name); - -#ifdef LIBDW_HAS_DWARF_GETALT - // We are on recent versions of elfutils where the function - // dwarf_getalt exists, so let's use it. - Dwarf_Addr bias = 0; - Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias); - result = dwarf_getalt(dwarf); - alt_fd = 0; -#else - // We are on an old version of elfutils where the function - // dwarf_getalt doesn't exist yet, so let's open code its - // functionality - char *alt_name = 0; - const char *file_name = 0; - void **user_data = 0; - Dwarf_Addr low_addr = 0; - char *alt_file = 0; - - file_name = dwfl_module_info(elf_module, &user_data, - &low_addr, 0, 0, 0, 0, 0); - - alt_fd = dwfl_standard_find_debuginfo(elf_module, user_data, - file_name, low_addr, - alt_name, file_name, - 0, &alt_file); - - result = dwarf_begin(alt_fd, DWARF_C_READ); -#endif - - if (result == 0) - { - // So we didn't find the alternate debuginfo file from the - // information that is in the debuginfo file associated to - // elf_module. Maybe the alternate debuginfo file is located - // under one of the directories in debug_root_dirs. So let's - // look in there. - string alt_file_path; - if (!find_alt_dwarf_debug_info_path(debug_root_dirs, - alt_file_name, - alt_file_path)) - return result; - - // If we reach this point it means we have found the path to the - // alternate debuginfo file and it's in alt_file_path. So let's - // open it and read it. - alt_fd = open(alt_file_path.c_str(), O_RDONLY); - if (alt_fd == -1) - return result; - result = dwarf_begin(alt_fd, DWARF_C_READ); - -#ifdef LIBDW_HAS_DWARF_GETALT - Dwarf_Addr bias = 0; - Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias); - dwarf_setalt(dwarf, result); -#endif - } - - return result; -} - /// Private data of the @ref elf::reader type. struct reader::priv { @@ -258,6 +113,14 @@ struct reader::priv mutable symtab_reader::symtab_sptr symt; // Where split debug info is to be searched for on disk. vector debug_info_root_paths; + // The formatted string version of debug_info_root_paths. The + // format is according to what elfutils expects. For the details of + // what elfutils expects, please read the comments of the function + // dwfl_build_id_find_elf in /usr/include/elfutils/libdwfl.h. + string formated_di_root_paths; + // A pointer to where the string held by formated_di_root_paths is. + // This is fed to elfutils. + char* raw_formated_di_root_paths = nullptr; // Some very useful callback functions that elfutils needs to // perform various tasks. Dwfl_Callbacks offline_callbacks; @@ -311,6 +174,8 @@ struct reader::priv dt_needed.clear(); symt.reset(); debug_info_root_paths = debug_info_roots; + formated_di_root_paths.clear(); + raw_formated_di_root_paths = nullptr; memset(&offline_callbacks, 0, sizeof(offline_callbacks)); dwfl_handle.reset(); elf_module = nullptr; @@ -324,6 +189,31 @@ struct reader::priv alt_ctf_fd = 0; } + /// Initialize the debug info root path. The format of this path is + /// described in /usr/include/elfutils/libdwfl.h in the comment for + /// the function dwfl_build_id_find_elf. + /// + /// The string must start with '-' to disable CRC32 checksum + /// validation. Directories must be separated by the ':' character. + /// The search order depends on if each path is absolute or relative + /// as described by that comment. + /// + /// In any case, let's format the debuginfo search path here for + /// elfutils consumption. + void + initialize_debug_info_root_paths() + { + for (auto path : debug_info_root_paths) + { + if (formated_di_root_paths.empty()) + formated_di_root_paths = "-"; + if (*path) + formated_di_root_paths += string(*path) + string (":"); + } + raw_formated_di_root_paths = + const_cast(formated_di_root_paths.c_str()); + } + /// Setup the necessary plumbing to open the ELF file and find all /// the associated split debug info files. /// @@ -333,10 +223,11 @@ struct reader::priv crack_open_elf_file() { // Initialize the callback functions used by elfutils. + initialize_debug_info_root_paths(); elf_helpers::initialize_dwfl_callbacks(offline_callbacks, - debug_info_root_paths.empty() + formated_di_root_paths.empty() ? nullptr - : debug_info_root_paths.front()); + : &raw_formated_di_root_paths); // Create a handle to the DWARF Front End Library that we'll need. dwfl_handle = elf_helpers::create_new_dwfl_handle(offline_callbacks); @@ -358,25 +249,6 @@ struct reader::priv ABG_ASSERT(elf_handle); } - /// Find the alternate debuginfo file associated to a given elf file. - /// - /// @param elf_module represents the elf file to consider. - /// - /// @param alt_file_name the resulting path to the alternate - /// debuginfo file found. This is set iff the function returns a - /// non-nil value. - Dwarf* - find_alt_dwarf_debug_info(Dwfl_Module* elf_module, - string& alt_file_name, - int& alt_fd) - { - Dwarf *result = 0; - result = elf::find_alt_dwarf_debug_info(elf_module, - debug_info_root_paths, - alt_file_name, alt_fd); - return result; - } - /// Clear the resources related to the alternate DWARF data. void clear_alt_dwarf_debug_info_data() @@ -405,24 +277,10 @@ struct reader::priv if (dwarf_handle) return; - // First let's see if the ELF file that was cracked open does have - // some DWARF debug info embedded. Dwarf_Addr bias = 0; dwarf_handle = dwfl_module_getdwarf(elf_module, &bias); - - // If no debug info was found in the binary itself, then look for - // split debuginfo files under multiple possible debuginfo roots. - for (vector::const_iterator i = debug_info_root_paths.begin(); - dwarf_handle == 0 && i != debug_info_root_paths.end(); - ++i) - { - offline_callbacks.debuginfo_path = *i; - dwarf_handle = dwfl_module_getdwarf(elf_module, &bias); - } - - alt_dwarf_handle = find_alt_dwarf_debug_info(elf_module, - alt_dwarf_path, - alt_dwarf_fd); + alt_dwarf_handle = dwarf_getalt(dwarf_handle); + find_alt_dwarf_debug_info_link(elf_module, alt_dwarf_path); } /// Clear the resources related to the alternate CTF data.