From patchwork Thu Mar 14 16:59:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 87202 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 829A53857704 for ; Thu, 14 Mar 2024 16:59:45 +0000 (GMT) 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.129.124]) by sourceware.org (Postfix) with ESMTPS id 30AF63858C3A for ; Thu, 14 Mar 2024 16:59:39 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 30AF63858C3A Authentication-Results: sourceware.org; dmarc=pass (p=none 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 30AF63858C3A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1710435581; cv=none; b=bwgFA4fW0uoI928wjsB09JNs7mwKXRs4MTFlsXAo/X0DSHz3h1nhrVOWhBzgy/Yk/Ya6oczaSWMQ4w3zfx2mjoqvYwAQbJuKj8dP0HgDs6iNYTsGNaO4UylE/F43qqPLlIThI2KoKv8ebBgwT4dPTa+yec/Rtx0Q15AkwWdcYFk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1710435581; c=relaxed/simple; bh=x9f8E0NF0oBvHTCTDJFYjgkNJ5XxJrcClGOADCoAe04=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Evy3V/d2YycsO+NI0pqiayM52BjfFYkr+A/YxXhwYZvo1EwxcmlYzA0tDHK9sGbcDwbXgFCr5xjhY/qDYiR3ZC23QUsP+IjAUXfNwnsrPb6fpnogVO+N+Fdh4PozoMIUSNSAMuCZ9hFBxogNgMJV6p+pF2xKnKF5m19blS424HQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1710435578; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=tBa2C+Mj7Nhbp0YQQMOHey3DrCPTrPBAIZF0AlS+K5c=; b=Tx0zNoKmUl+r7BdxHVb4zCHZ4B5joyjRQnoFwjSgFJ5KsYytov9ig+mu3sVbDdvtZng/re wFnCIxPuUePjnXzN5HfblLWmqsB03a7cu0l8uUk427YX/XNxWGYfoo+O+i7GAoFxkgHqh1 A4HrPyDlJCQHSXzlpGyS1GoaNaDyjcg= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-159-WtSaaRHiOn6tic-13bdT7w-1; Thu, 14 Mar 2024 12:59:36 -0400 X-MC-Unique: WtSaaRHiOn6tic-13bdT7w-1 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-413f625c65cso3980125e9.3 for ; Thu, 14 Mar 2024 09:59:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710435574; x=1711040374; h=mime-version:user-agent:message-id:in-reply-to:date:references :organization:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=tBa2C+Mj7Nhbp0YQQMOHey3DrCPTrPBAIZF0AlS+K5c=; b=PJh+TS9wjiQ5w19Efs7m63M+IcPr3K6o1WhqZ1Dn1SNufTzVkbgq01fz1oRUNDg8Lx BJAqPy3JKTg1a4Ycv8mycYEZlgLwAOLsDNmMuIChcp4sXessiF2WGjGfQsJQO3pOFdGc t/C4/xJlN79e1R9kkdSWdaaOSrMCDHMtjzD6Skm9O5Q5cPfuMn1d73c64SdZ8i19hQtp iVwn+1vH7Lw2B+4rD1xe52SRyjMFy3ndyKm7D9XEz17nf0c4+3DOIT4/WghRtigNIA+c fYS8WC4Zi8Naf8YoNH+FhFLLpvZKqsMXnQyMKhWtBz/k5yprCqZ9YSl1+RPZiuAHpcP0 4ffw== X-Gm-Message-State: AOJu0Yy0t+No2thhz8A41FdxyjUsfjbHxEuh2006BLxd5nZ4Eb1ajz7u lztaOJ176YseYXROhncE4N4cwObTKKd+RWzcaLohmo1W2I3rodipyx8Rm4wAWtsDfYwNTVNmWMR IU6wrQ0HAAgEVDzpBtT9WJaaAmBwkNIWasTgBRW+nNdLWpAeyRP2F0xrDsulK34i5Uw== X-Received: by 2002:a05:600c:1f8c:b0:413:f2c6:df3d with SMTP id je12-20020a05600c1f8c00b00413f2c6df3dmr442522wmb.13.1710435574581; Thu, 14 Mar 2024 09:59:34 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFEqhh33nKC7DGN4YqzCvkzOAivjjqQSpWdCtx136YBPgiga2qWqawOGFwJvSzNrujpKh3yng== X-Received: by 2002:a05:600c:1f8c:b0:413:f2c6:df3d with SMTP id je12-20020a05600c1f8c00b00413f2c6df3dmr442512wmb.13.1710435574158; Thu, 14 Mar 2024 09:59:34 -0700 (PDT) Received: from localhost ([78.243.217.51]) by smtp.gmail.com with ESMTPSA id m36-20020a05600c3b2400b00412b6fbb9b5sm6189851wms.8.2024.03.14.09.59.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 Mar 2024 09:59:33 -0700 (PDT) Received: by localhost (Postfix, from userid 1000) id CB2055071022; Thu, 14 Mar 2024 17:59:32 +0100 (CET) From: Dodji Seketeli To: dodji@redhat.com Cc: libabigail@sourceware.org Subject: [PATCH 2/4] Factorize elf-reader::{variable,function}_symbol_is_exported into symtab Organization: Red Hat / France References: <87ttl83gaw.fsf@redhat.com> X-Operating-System: AlmaLinux 9.3 X-URL: http://www.redhat.com Date: Thu, 14 Mar 2024 17:59:32 +0100 In-Reply-To: <87ttl83gaw.fsf@redhat.com> (Dodji Seketeli's message of "Thu, 14 Mar 2024 17:54:15 +0100") Message-ID: <87le6k3g23.fsf@redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.2 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_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE 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, Move the code of elf-reader::{variable,function}_symbol_is_exported into symtab::{variable,function}_symbol_is_exported (where it belongs) and make the former use the later. * src/abg-elf-reader.cc (reader::function_symbol_is_exported): Use the new symtab::function_symbol_is_exported. (reader::variable_symbol_is_exported): Use the new symtab::variable_symbol_is_exported. * src/abg-symtab-reader.cc (symtab::{function,variable}_symbol_is_exported): Factorize elf::reader::{function,variable}_symbol_is_exported into this. * src/abg-symtab-reader.h (symtab::{function,variable}_symbol_is_exported): Declare new member functions. Signed-off-by: Dodji Seketeli --- src/abg-elf-reader.cc | 59 ++++++++++++--------------- src/abg-symtab-reader.cc | 87 ++++++++++++++++++++++++++++++++++++++++ src/abg-symtab-reader.h | 12 ++++++ 3 files changed, 124 insertions(+), 34 deletions(-) diff --git a/src/abg-elf-reader.cc b/src/abg-elf-reader.cc index afb038ff..14f8ce6a 100644 --- a/src/abg-elf-reader.cc +++ b/src/abg-elf-reader.cc @@ -788,13 +788,12 @@ reader::symtab() const elf_symbol_sptr reader::function_symbol_is_exported(GElf_Addr symbol_address) const { - elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address); + + elf_symbol_sptr symbol = + symtab()->function_symbol_is_exported(symbol_address); if (!symbol) return symbol; - if (!symbol->is_function() || !symbol->is_public()) - return elf_symbol_sptr(); - address_set_sptr set; bool looking_at_linux_kernel_binary = load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle()); @@ -820,13 +819,11 @@ reader::function_symbol_is_exported(GElf_Addr symbol_address) const elf_symbol_sptr reader::variable_symbol_is_exported(GElf_Addr symbol_address) const { - elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address); + elf_symbol_sptr symbol = + symtab()->variable_symbol_is_exported(symbol_address); if (!symbol) return symbol; - if (!symbol->is_variable() || !symbol->is_public()) - return elf_symbol_sptr(); - address_set_sptr set; bool looking_at_linux_kernel_binary = load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle()); @@ -849,23 +846,20 @@ reader::variable_symbol_is_exported(GElf_Addr symbol_address) const elf_symbol_sptr reader::function_symbol_is_exported(const string& name) const { - const elf_symbols& syms = symtab()->lookup_symbol(name); - for (auto s : syms) + const elf_symbol_sptr s = symtab()->function_symbol_is_exported(name); + if (s && s->is_function() && s->is_public()) { - if (s->is_function() && s->is_public()) - { - bool looking_at_linux_kernel_binary = - (load_in_linux_kernel_mode() - && elf_helpers::is_linux_kernel(elf_handle())); + bool looking_at_linux_kernel_binary = + (load_in_linux_kernel_mode() + && elf_helpers::is_linux_kernel(elf_handle())); - if (looking_at_linux_kernel_binary) - { - if (s->is_in_ksymtab()) - return s; - } - else + if (looking_at_linux_kernel_binary) + { + if (s->is_in_ksymtab()) return s; } + else + return s; } return elf_symbol_sptr(); } @@ -879,23 +873,20 @@ reader::function_symbol_is_exported(const string& name) const elf_symbol_sptr reader::variable_symbol_is_exported(const string& name) const { - const elf_symbols& syms = symtab()->lookup_symbol(name); - for (auto s : syms) + const elf_symbol_sptr s = symtab()->variable_symbol_is_exported(name); + if (s->is_variable() && s->is_public()) { - if (s->is_variable() && s->is_public()) - { - bool looking_at_linux_kernel_binary = - (load_in_linux_kernel_mode() - && elf_helpers::is_linux_kernel(elf_handle())); + bool looking_at_linux_kernel_binary = + (load_in_linux_kernel_mode() + && elf_helpers::is_linux_kernel(elf_handle())); - if (looking_at_linux_kernel_binary) - { - if (s->is_in_ksymtab()) - return s; - } - else + if (looking_at_linux_kernel_binary) + { + if (s->is_in_ksymtab()) return s; } + else + return s; } return elf_symbol_sptr(); } diff --git a/src/abg-symtab-reader.cc b/src/abg-symtab-reader.cc index 2eebc282..51177369 100644 --- a/src/abg-symtab-reader.cc +++ b/src/abg-symtab-reader.cc @@ -166,6 +166,93 @@ symtab::lookup_undefined_variable_symbol(const std::string& sym_name) return result; } +/// Test if a given function symbol has been exported. +/// +/// Note that this doesn't test if the symbol is defined or not, but +/// assumes the symbol is defined. +/// +/// @param name the name of the symbol we are looking for. +/// +/// @return the elf symbol if found, or nil otherwise. +elf_symbol_sptr +symtab::function_symbol_is_exported(const string& name) +{ + const elf_symbols& syms = lookup_symbol(name); + for (auto s : syms) + if (s->is_function() && s->is_public()) + return s; + + return elf_symbol_sptr(); +} + +/// Test if a given function symbol has been exported. +/// +/// Note that this doesn't test if the symbol is defined or not, but +/// assumes the symbol is defined. +/// +/// @param symbol_address the address of the symbol we are looking +/// for. Note that this address must be a relative offset from the +/// beginning of the .text section, just like the kind of addresses +/// that are present in the .symtab section. +/// +/// @return the elf symbol if found, or nil otherwise. +elf_symbol_sptr +symtab::function_symbol_is_exported(const GElf_Addr symbol_address) +{ + elf_symbol_sptr symbol = lookup_symbol(symbol_address); + if (!symbol) + return symbol; + + if (!symbol->is_function() || !symbol->is_public()) + return elf_symbol_sptr(); + + return symbol; +} + +/// Test if a given variable symbol has been exported. +/// +/// Note that this assumes the symbol is exported but doesn't test for +/// it. +/// +/// @param name the name of the symbol we are looking +/// for. +/// +/// @return the elf symbol if found, or nil otherwise. +elf_symbol_sptr +symtab::variable_symbol_is_exported(const string& name) +{ + const elf_symbols& syms = lookup_symbol(name); + for (auto s : syms) + if (s->is_variable() && s->is_public()) + return s; + + return elf_symbol_sptr(); +} + +/// Test if a given variable symbol has been exported. +/// +/// Note that this assumes the symbol is exported but doesn't test for +/// it. +/// +/// @param symbol_address the address of the symbol we are looking +/// for. Note that this address must be a relative offset from the +/// beginning of the .text section, just like the kind of addresses +/// that are present in the .symtab section. +/// +/// @return the elf symbol if found, or nil otherwise. +elf_symbol_sptr +symtab::variable_symbol_is_exported(const GElf_Addr symbol_address) +{ + elf_symbol_sptr symbol = lookup_symbol(symbol_address); + if (!symbol) + return symbol; + + if (!symbol->is_variable() || !symbol->is_public()) + return elf_symbol_sptr(); + + return symbol; +} + /// Test if a name is a the name of an undefined function symbol. /// /// @param sym_name the symbol name to consider. diff --git a/src/abg-symtab-reader.h b/src/abg-symtab-reader.h index cc284453..43b40b79 100644 --- a/src/abg-symtab-reader.h +++ b/src/abg-symtab-reader.h @@ -248,6 +248,18 @@ public: const elf_symbol_sptr lookup_undefined_variable_symbol(const std::string& name); + elf_symbol_sptr + function_symbol_is_exported(const string&); + + elf_symbol_sptr + function_symbol_is_exported(const GElf_Addr symbol_address); + + elf_symbol_sptr + variable_symbol_is_exported(const string&); + + elf_symbol_sptr + variable_symbol_is_exported(const GElf_Addr symbol_address); + bool function_symbol_is_undefined(const string&); From patchwork Thu Mar 14 17:00:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 87203 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 904FB3857739 for ; Thu, 14 Mar 2024 17:00:32 +0000 (GMT) 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 ESMTPS id BEC383858C3A for ; Thu, 14 Mar 2024 17:00:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BEC383858C3A Authentication-Results: sourceware.org; dmarc=pass (p=none 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 BEC383858C3A 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=1710435626; cv=none; b=wfSXS7irQ1tGdxv6PDz7TlWoZJEcEydoYPyUNrJA2/TgAuRZWmMGALdZCU3LYQbSeFnkqRQzH2MwiEsnuwpQdPZ2IgP9PVOwexfVEXwtMHsSrgl5jf7lMvhlK8vf3D+Z3XXv5i62xtG6ZyGPdSRZ4CkjC/SHmdTZkWWYn/lVjBQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1710435626; c=relaxed/simple; bh=3hxGlXTYr9h6bHDSPCwIxwSzTdRqZaYqIf7zh/3vKKg=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=xpwpZogwFaC2JaEuc/UzFmv8IayyzGJ0Wmc0486PFUef2kD5pO8gIiP1XKXGZMBEbzO8AQx10d+4r1kFH/0u4Y57jkNVVJ+mp7VFRxZlfuZcrISHooW1ea7A/6Z1WcRPkS1NNhFDEv4OTeQg3RvH5NKQGKAj4cif8ADE7yxq1Eo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1710435622; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=hMgCQFQ0R1avoiigBB4KzDDGKFBJBx9+e5Hn3FuolFw=; b=EXl49+sV/NdVhsG3VZv8ppQZq6getdfBZprbnBLynkevBlmo/CNZJGplZjEcj1XRSh8esx FOrFx5Lp5oj/mIxeWz9l4kO9APs29kvPw7X5C+nuJIdw+hkEVl/emJGuO04+dlfMEbqLh+ ik21Jk7pLq9F4Lypw59vF2juALWtTAU= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-622-Jbboj7h1MKC-YB_9W-DnHg-1; Thu, 14 Mar 2024 13:00:19 -0400 X-MC-Unique: Jbboj7h1MKC-YB_9W-DnHg-1 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-412dd54cc17so6875185e9.1 for ; Thu, 14 Mar 2024 10:00:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710435618; x=1711040418; h=mime-version:user-agent:message-id:in-reply-to:date:references :organization:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=hMgCQFQ0R1avoiigBB4KzDDGKFBJBx9+e5Hn3FuolFw=; b=Niv9HUBP1bbxCB/x8qwHGHgz8nlLzsbiXCatC7jAEamkU3n5OOS55rA6lB78pFQxY2 X5VywS3oMM8AWuSazt1tPVYOdR737BZPZwkTKNICTz3mFF0n/ZMeOpOCGeNIxYBxE2Oo DRBY1GXP0TkP4+ZvJAm4/YbXuSorm/Ax4SALPttk+wsIpZsQAUrOEEP4ClOAGPIdxNSs fpjPQQl76H3nvKbe5xxWleLtShhizqQ0d1FEY+Jyk9f15mal5mS7pi7XKcRyy+bhmd5J 6YLy2hsJsWjlepTexqiEltaJ9nyymESUztHxig7ZcFfp7ZBBLrmFDkA4udfHQTfSf3GF KF1w== X-Gm-Message-State: AOJu0YwRLF0yNDhtYJ7erhnBehQI7IiEieSV5sqPazZWNr0cfT4XVlTV T/q63CfFWou3s4InhUM1TRE19taTyZnFaLX5JzNewQd16XcJSGZwEWrKSAZLcel4zBn5aJtrNOQ 8qDUTLY/ilicTTJC8+QJFRim5JCWHSJXuULTYTL5FWVXz2tLgbEXs1YFK+/vr9sX7TQ== X-Received: by 2002:a5d:6a4b:0:b0:33e:67c7:e2c0 with SMTP id t11-20020a5d6a4b000000b0033e67c7e2c0mr578904wrw.38.1710435617368; Thu, 14 Mar 2024 10:00:17 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEcSLdgeAaW7iLa9ASnpOwQq0N/jawNuj3BGLxWU1eL8sojaF5qBtMcnTshmQ1lNYR+E3Wl9Q== X-Received: by 2002:a5d:6a4b:0:b0:33e:67c7:e2c0 with SMTP id t11-20020a5d6a4b000000b0033e67c7e2c0mr578856wrw.38.1710435616554; Thu, 14 Mar 2024 10:00:16 -0700 (PDT) Received: from localhost ([78.243.217.51]) by smtp.gmail.com with ESMTPSA id ay25-20020a5d6f19000000b0033e3cb02cefsm1148949wrb.86.2024.03.14.10.00.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 Mar 2024 10:00:16 -0700 (PDT) Received: by localhost (Postfix, from userid 1000) id EAAE95071022; Thu, 14 Mar 2024 18:00:14 +0100 (CET) From: Dodji Seketeli To: Dodji Seketeli Cc: libabigail@sourceware.org Subject: [PATCH 3/4] Add support for undefined symbols in the BTF reader Organization: Red Hat / France References: <87ttl83gaw.fsf@redhat.com> X-Operating-System: AlmaLinux 9.3 X-URL: http://www.redhat.com Date: Thu, 14 Mar 2024 18:00:14 +0100 In-Reply-To: <87ttl83gaw.fsf@redhat.com> (Dodji Seketeli's message of "Thu, 14 Mar 2024 17:54:15 +0100") Message-ID: <87h6h83g0x.fsf@redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_LOTSOFHASH, LIKELY_SPAM_BODY, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE 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, This patch teaches the BTF reader how to construct an IR for undefined interfaces. The patch also updates the abicompat tool for BTF support. * doc/manuals/abicompat.rst: Update documentation for the --btf option of abicompat. * include/abg-elf-reader.h (elf::reader::{function,variable}_symbol_is_undefined): Declare new member functions. * src/abg-btf-reader.cc (reader::read_debug_info_into_corpus): Sort functions & variables after canonicalization. (reader::build_ir_node_from_btf_type): Always call fe_iface::add_{fn,var}_to_exported_or_undefined_decls with the decl that was constructed. (reader::build_function_decl): Support setting an undefined symbol to the function decl. (reader::build_var_decl): Likewise, support setting undefined symbol the variable decl. * src/abg-elf-reader.cc ((elf::reader::{function,variable}_symbol_is_undefined): Declare new member functions.): Define new member functions. * src/abg-symtab-reader.cc (symtab::{function,variable}_symbol_is_undefined): Return the undefined symbol that was found. * src/abg-symtab-reader.h (symtab::{function,variable}_symbol_is_undefined): Return an undefined symbol rather than just a boolean value. * tools/abicompat.cc: Add support for BTF here. (options::use_btf): Define new data member ... (options::options): ... and initialize it. (display_usage): Add a help string for the --btf option. (parse_command_line): Parse the --btf option. * tests/data/test-abicompat/test7-fn-changed-report-0.1.txt: New reference test output file. * tests/data/test-abicompat/test7-fn-changed-report-2.1.txt: Likewise. * tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v0.so: New binary input file. * tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v1.so: Likewise. * tests/data/test-abicompat/test7-fn-changed-app.btf: Likewise. * tests/data/Makefile.am: Add the new test material to source distribution. * tests/test-abicompat.cc (in_out_specs): Add the new test input to the test harness. * tests/data/test-abicompat/test7-fn-changed-app.c: Adjust. * tests/data/test-abicompat/test7-fn-changed-libapp-v0.c: Likewise. * tests/data/test-abicompat/test7-fn-changed-libapp-v1.c: Likewise Signed-off-by: Dodji Seketeli --- doc/manuals/abicompat.rst | 5 +++ include/abg-elf-reader.h | 6 ++++ src/abg-btf-reader.cc | 25 +++++++-------- src/abg-elf-reader.cc | 19 +++++++++++ src/abg-symtab-reader.cc | 30 +++++++++++++----- src/abg-symtab-reader.h | 4 +-- tests/data/Makefile.am | 5 +++ .../libtest7-fn-changed-libapp-btf-v0.so | Bin 0 -> 16560 bytes .../libtest7-fn-changed-libapp-btf-v1.so | Bin 0 -> 16584 bytes .../test-abicompat/test7-fn-changed-app.btf | Bin 0 -> 17536 bytes .../test-abicompat/test7-fn-changed-app.c | 2 ++ .../test7-fn-changed-libapp-v0.c | 2 ++ .../test7-fn-changed-libapp-v1.c | 3 ++ .../test7-fn-changed-report-0.1.txt | 19 +++++++++++ .../test7-fn-changed-report-2.1.txt | 16 ++++++++++ tests/test-abicompat.cc | 22 +++++++++++++ tools/abicompat.cc | 18 +++++++++++ 17 files changed, 153 insertions(+), 23 deletions(-) create mode 100755 tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v0.so create mode 100755 tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v1.so create mode 100755 tests/data/test-abicompat/test7-fn-changed-app.btf create mode 100644 tests/data/test-abicompat/test7-fn-changed-report-0.1.txt create mode 100644 tests/data/test-abicompat/test7-fn-changed-report-2.1.txt new file mode 100755 index 0000000000000000000000000000000000000000..8970d55a2ea6ae8718997c2b639ea8787647de68 GIT binary patch literal 16584 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 F{{zL+8D;sort_functions(); + corpus()->sort_variables(); return corpus(); } @@ -504,15 +505,9 @@ public: associate_artifact_to_btf_type_id(result, type_id); if (function_decl_sptr fn = is_function_decl(result)) - { - if (fn->get_is_in_public_symbol_table()) - add_fn_to_exported_or_undefined_decls(fn.get()); - } + add_fn_to_exported_or_undefined_decls(fn.get()); else if (var_decl_sptr var = is_var_decl(result)) - { - if (var->get_is_in_public_symbol_table()) - add_var_to_exported_or_undefined_decls(var.get()); - } + add_var_to_exported_or_undefined_decls(var.get()); return result; } @@ -1021,10 +1016,12 @@ public: location(), /*linkage_name=*/fn_name)); elf_symbol_sptr fn_sym; - if ((fn_sym = function_symbol_is_exported(fn_name))) + if ((fn_sym = function_symbol_is_exported(fn_name)) + || (fn_sym = function_symbol_is_undefined(fn_name))) { result->set_symbol(fn_sym); - result->set_is_in_public_symbol_table(true); + if (fn_sym->is_defined()) + result->set_is_in_public_symbol_table(true); } return result; } @@ -1055,10 +1052,12 @@ public: /*linkage_name=*/var_name)); elf_symbol_sptr var_sym; - if ((var_sym = variable_symbol_is_exported(var_name))) + if ((var_sym = variable_symbol_is_exported(var_name)) + || (var_sym = variable_symbol_is_undefined(var_name))) { result->set_symbol(var_sym); - result->set_is_in_public_symbol_table(true); + if (var_sym->is_defined()) + result->set_is_in_public_symbol_table(true); } return result; } diff --git a/src/abg-elf-reader.cc b/src/abg-elf-reader.cc index 14f8ce6a..cbb20dd4 100644 --- a/src/abg-elf-reader.cc +++ b/src/abg-elf-reader.cc @@ -890,6 +890,25 @@ reader::variable_symbol_is_exported(const string& name) const } return elf_symbol_sptr(); } + +/// Test if a name is the name of an undefined function symbol. +/// +/// @param name the symbol name to consider. +/// +/// @return the undefined function symbol or nil if none was found. +elf_symbol_sptr +reader::function_symbol_is_undefined(const string& name) const +{return symtab()->function_symbol_is_undefined(name);} + +/// Test if a name is the name of an undefined variable symbol. +/// +/// @param name the symbol name to consider. +/// +/// @return the undefined variable symbol or nil if none was found. +elf_symbol_sptr +reader::variable_symbol_is_undefined(const string& name) const +{return symtab()->variable_symbol_is_undefined(name);} + /// Load the DT_NEEDED and DT_SONAME elf TAGS. void reader::load_dt_soname_and_needed() diff --git a/src/abg-symtab-reader.cc b/src/abg-symtab-reader.cc index 51177369..fc0cac59 100644 --- a/src/abg-symtab-reader.cc +++ b/src/abg-symtab-reader.cc @@ -257,26 +257,40 @@ symtab::variable_symbol_is_exported(const GElf_Addr symbol_address) /// /// @param sym_name the symbol name to consider. /// -/// @return true iff @p sym_name is the name of a an undefined -/// function symbol. -bool +/// @return the undefined symbol if found, nil otherwise. +elf_symbol_sptr symtab::function_symbol_is_undefined(const string& sym_name) { collect_undefined_fns_and_vars_linkage_names(); - return undefined_function_linkage_names_.count(sym_name); + if (undefined_function_linkage_names_.count(sym_name)) + { + elf_symbol_sptr sym = lookup_undefined_function_symbol(sym_name); + ABG_ASSERT(sym); + ABG_ASSERT(sym->is_function()); + ABG_ASSERT(!sym->is_defined()); + return sym; + } + return elf_symbol_sptr(); } /// Test if a name is a the name of an undefined variable symbol. /// /// @param sym_name the symbol name to consider. /// -/// @return true iff @p sym_name is the name of a an undefined -/// variable symbol. -bool +// @return the undefined symbol if found, nil otherwise. +elf_symbol_sptr symtab::variable_symbol_is_undefined(const string& sym_name) { collect_undefined_fns_and_vars_linkage_names(); - return undefined_variable_linkage_names_.count(sym_name); + if (undefined_variable_linkage_names_.count(sym_name)) + { + elf_symbol_sptr sym = lookup_undefined_variable_symbol(sym_name); + ABG_ASSERT(sym); + ABG_ASSERT(sym->is_variable()); + ABG_ASSERT(!sym->is_defined()); + return sym; + } + return elf_symbol_sptr(); } /// A symbol sorting functor. diff --git a/src/abg-symtab-reader.h b/src/abg-symtab-reader.h index 43b40b79..390ee874 100644 --- a/src/abg-symtab-reader.h +++ b/src/abg-symtab-reader.h @@ -260,10 +260,10 @@ public: elf_symbol_sptr variable_symbol_is_exported(const GElf_Addr symbol_address); - bool + elf_symbol_sptr function_symbol_is_undefined(const string&); - bool + elf_symbol_sptr variable_symbol_is_undefined(const string&); static symtab_ptr diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 3e175209..5bf01528 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -2097,16 +2097,21 @@ test-abicompat/test6-var-changed-report-0.txt \ test-abicompat/test6-var-changed-report-1.txt \ test-abicompat/test6-var-changed-report-2.txt \ test-abicompat/libtest7-fn-changed-libapp-v0.so \ +test-abicompat/libtest7-fn-changed-libapp-btf-v0.so \ test-abicompat/libtest7-fn-changed-libapp-v1.so \ +test-abicompat/libtest7-fn-changed-libapp-btf-v1.so \ test-abicompat/test7-fn-changed-app \ +test-abicompat/test7-fn-changed-app.btf \ test-abicompat/test7-fn-changed-app.c \ test-abicompat/test7-fn-changed-libapp-v0.c \ test-abicompat/test7-fn-changed-libapp-v0.h \ test-abicompat/test7-fn-changed-libapp-v1.c \ test-abicompat/test7-fn-changed-libapp-v1.h \ test-abicompat/test7-fn-changed-report-0.txt \ +test-abicompat/test7-fn-changed-report-0.1.txt \ test-abicompat/test7-fn-changed-report-1.txt \ test-abicompat/test7-fn-changed-report-2.txt \ +test-abicompat/test7-fn-changed-report-2.1.txt \ test-abicompat/libtest8-fn-changed-libapp-v0.so \ test-abicompat/libtest8-fn-changed-libapp-v1.so \ test-abicompat/test8-fn-changed-app \ diff --git a/tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v0.so b/tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v0.so new file mode 100755 index 0000000000000000000000000000000000000000..a61749662ff7d29cdfd9be39d5faf9cb95782909 GIT binary patch literal 16560 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 literal 0 HcmV?d00001 diff --git a/tests/data/test-abicompat/test7-fn-changed-app.c b/tests/data/test-abicompat/test7-fn-changed-app.c --- a/tests/data/test-abicompat/test7-fn-changed-app.c +++ b/tests/data/test-abicompat/test7-fn-changed-app.c @@ -1,5 +1,7 @@ // Compile this with: // gcc -g -o test7-fn-changed-app -L. -ltest7-fn-changed-libapp-v0 test7-fn-changed-app.c +// Or, for BTF debug info, with: +// gcc -gbtf -o test7-fn-changed-app.btf -L. -ltest7-fn-changed-libapp-v0 test7-fn-changed-app.c #include #include "test7-fn-changed-libapp-v0.h" diff --git a/tests/data/test-abicompat/test7-fn-changed-libapp-v0.c b/tests/data/test-abicompat/test7-fn-changed-libapp-v0.c index 8c3581e2..c36993ce 100644 --- a/tests/data/test-abicompat/test7-fn-changed-libapp-v0.c +++ b/tests/data/test-abicompat/test7-fn-changed-libapp-v0.c @@ -1,5 +1,7 @@ // Compile this with: // gcc -g -Wall -fPIC -shared -o libtest7-fn-changed-libapp-v0.so test7-fn-changed-libapp-v0.c +// Or, for BTF debug info with: +// gcc -gbtf -Wall -fPIC -shared -o libtest7-fn-changed-libapp-btf-v0.so test7-fn-changed-libapp-v0.c #include #include "test7-fn-changed-libapp-v0.h" diff --git a/tests/data/test-abicompat/test7-fn-changed-libapp-v1.c b/tests/data/test-abicompat/test7-fn-changed-libapp-v1.c index 92c44394..822efa0c 100644 --- a/tests/data/test-abicompat/test7-fn-changed-libapp-v1.c +++ b/tests/data/test-abicompat/test7-fn-changed-libapp-v1.c @@ -1,5 +1,8 @@ // Compile this with: // gcc -g -Wall -fPIC -shared -o libtest7-fn-changed-libapp-v1.so test7-fn-changed-libapp-v1.c +// Or, for BTF debug info, with: +// gcc -gbtf -Wall -fPIC -shared -o libtest7-fn-changed-libapp-btf-v1.so test7-fn-changed-libapp-v1.c + #include #include "test7-fn-changed-libapp-v1.h" diff --git a/tests/data/test-abicompat/test7-fn-changed-report-0.1.txt b/tests/data/test-abicompat/test7-fn-changed-report-0.1.txt new file mode 100644 index 00000000..39b69d8f --- /dev/null +++ b/tests/data/test-abicompat/test7-fn-changed-report-0.1.txt @@ -0,0 +1,19 @@ +ELF file 'test7-fn-changed-app.btf' might not be ABI compatible with 'libtest7-fn-changed-libapp-btf-v1.so' due to differences with 'libtest7-fn-changed-libapp-btf-v0.so' below: +Functions changes summary: 0 Removed, 2 Changed, 0 Added functions +Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + +2 functions with some indirect sub-type change: + + [C] 'function float add(float, float)' has some indirect sub-type changes: + return type changed: + type name changed from 'float' to 'int' + type size hasn't changed + mangled name changed from 'float' to int + + [C] 'function void print(const Student)' has some indirect sub-type changes: + parameter 1 of type 'const Student' has sub-type changes: + in unqualified underlying type 'struct Student': + type size changed from 128 to 192 (in bits) + 1 data member insertion: + 'float percentage', at offset 128 (in bits) + diff --git a/tests/data/test-abicompat/test7-fn-changed-report-2.1.txt b/tests/data/test-abicompat/test7-fn-changed-report-2.1.txt new file mode 100644 index 00000000..4645006e --- /dev/null +++ b/tests/data/test-abicompat/test7-fn-changed-report-2.1.txt @@ -0,0 +1,16 @@ +functions defined in library 'libtest7-fn-changed-libapp-btf-v1.so' +have sub-types that are different from what application 'test7-fn-changed-app.btf' expects: + + function float add(float, float): + return type changed: + type name changed from 'float' to 'int' + type size hasn't changed + mangled name changed from 'float' to int + + function void print(const Student): + parameter 1 of type 'const Student' has sub-type changes: + in unqualified underlying type 'struct Student': + type size changed from 128 to 192 (in bits) + 1 data member insertion: + 'float percentage', at offset 128 (in bits) + diff --git a/tests/test-abicompat.cc b/tests/test-abicompat.cc index e992454c..320436c3 100644 --- a/tests/test-abicompat.cc +++ b/tests/test-abicompat.cc @@ -168,6 +168,17 @@ InOutSpec in_out_specs[] = "data/test-abicompat/test7-fn-changed-report-0.txt", "output/test-abicompat/test7-fn-changed-report-0.txt", }, +#ifdef WITH_BTF + { + "data/test-abicompat/test7-fn-changed-app.btf", + "data/test-abicompat/libtest7-fn-changed-libapp-btf-v0.so", + "data/test-abicompat/libtest7-fn-changed-libapp-btf-v1.so", + "", + "--show-base-names --no-show-locs --no-redundant --btf", + "data/test-abicompat/test7-fn-changed-report-0.1.txt", + "output/test-abicompat/test7-fn-changed-report-0.1.txt", + }, +#endif { "data/test-abicompat/test7-fn-changed-app", "data/test-abicompat/libtest7-fn-changed-libapp-v1.so", @@ -186,6 +197,17 @@ InOutSpec in_out_specs[] = "data/test-abicompat/test7-fn-changed-report-2.txt", "output/test-abicompat/test7-fn-changed-report-2.txt", }, +#ifdef WITH_BTF + { + "data/test-abicompat/test7-fn-changed-app.btf", + "data/test-abicompat/libtest7-fn-changed-libapp-btf-v1.so", + "", + "", + "--show-base-names --no-show-locs --weak-mode", + "data/test-abicompat/test7-fn-changed-report-2.1.txt", + "output/test-abicompat/test7-fn-changed-report-2.1.txt", + }, +#endif { "data/test-abicompat/test8-fn-changed-app", "data/test-abicompat/libtest8-fn-changed-libapp-v1.so", diff --git a/tools/abicompat.cc b/tools/abicompat.cc index 4e5a8e22..9c4771c9 100644 --- a/tools/abicompat.cc +++ b/tools/abicompat.cc @@ -34,6 +34,7 @@ #include #include #include +#include "config.h" #include "abg-config.h" #include "abg-tools-utils.h" #include "abg-corpus.h" @@ -44,6 +45,9 @@ #ifdef WITH_CTF #include "abg-ctf-reader.h" #endif +#ifdef WITH_BTF +#include "abg-btf-reader.h" +#endif using std::string; using std::cerr; @@ -111,6 +115,9 @@ public: #ifdef WITH_CTF bool use_ctf; #endif +#ifdef WITH_BTF + bool use_btf; +#endif options(const char* program_name) :prog_name(program_name), @@ -128,6 +135,10 @@ public: #ifdef WITH_CTF , use_ctf() +#endif +#ifdef WITH_BTF + , + use_btf() #endif {} }; // end struct options @@ -237,6 +248,9 @@ display_usage(const string& prog_name, ostream& out) "just one version of the library.\n" #ifdef WITH_CTF << " --ctf use CTF instead of DWARF in ELF files\n" +#endif +#ifdef WITH_BTF + << " --btf use BTF instead of DWARF in ELF files\n" #endif ; } @@ -344,6 +358,10 @@ parse_command_line(int argc, char* argv[], options& opts) #ifdef WITH_CTF else if (!strcmp(argv[i], "--ctf")) opts.use_ctf = true; +#endif +#ifdef WITH_BTF + else if (!strcmp(argv[i], "--btf")) + opts.use_btf = true; #endif else { From patchwork Thu Mar 14 17:00:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 87205 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 514BB3864859 for ; Thu, 14 Mar 2024 17:01:45 +0000 (GMT) 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 ESMTPS id 913873857B86 for ; Thu, 14 Mar 2024 17:00:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 913873857B86 Authentication-Results: sourceware.org; dmarc=pass (p=none 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 913873857B86 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=1710435667; cv=none; b=MUkjlLbWIedsDISJqwC028L7KT05KupshgCtLFwf2SqeLVwMZI41Ng3XJYZtwAz8MNNscB3o8Qun+0iz0ClKx0vr/8d0AHZaLhDIkY3+fLPTRmL8b0nNYNZ50uES6197cBiF3e+CvzH+/mC1XKIe6K+pt758mfIxzYlhJfM52co= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1710435667; c=relaxed/simple; bh=MyxVvcbXioGsS1SXKxTbVxPyUS7zhPudMNM9eD+DDKU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=LqwyK42wgfPJtFSVni668FP2CFhm6Q3/VvbLjXvpkCFUODOAxmhL6ERCKCd/1U+JNyyw4TjegGxoeWcFdyhPI2ZPe7Ndn/SOu8m8H7nAxFr7YlmXVKuJbUsq+4kxSUuy74koJfVibk1DOJX+9Bhb2wqMikNHbmZBaw0qLTUTw2o= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1710435659; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=6xnr5DSE4xuLfG1OCjaASMa2S73kTBoMlljT0Mfupc8=; b=A36/CXpoZQ26J5YTuuHcb0Mbc0ALtp4PCYlhjNW2Snfxmqwxs77VNf++xhPHV1ij7VhOCJ SmQ+n2DWhD7epc12luKu1meoGyvNrgS649pYunJ7ZaETBK4jt9efo+qY4Fkvvz9atGv1Tk nB7L5/BWSWhuu6JaleLIQgTZT8yQx6Y= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-112-YckA6PtvOAW3OQ7grLLc1A-1; Thu, 14 Mar 2024 13:00:56 -0400 X-MC-Unique: YckA6PtvOAW3OQ7grLLc1A-1 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-33ec0700091so727408f8f.0 for ; Thu, 14 Mar 2024 10:00:56 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710435655; x=1711040455; h=mime-version:user-agent:message-id:in-reply-to:date:references :organization:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6xnr5DSE4xuLfG1OCjaASMa2S73kTBoMlljT0Mfupc8=; b=RwA0/uI/57tDITFUtR/UU1Tz6SSTghmJqaCSJ9HrQWQKT5/bbyMHymEh7pMMkTOD/k Bss/vJCMwr4t9vGs36vrE1Sq6aNa9f/ebhAW8JGXcvSuCsUZhyxOS9oNAX7Vr0megVTR vraVcjgPuG4msMpDsSjyQDg7x3YB+n1OpCbv1hCK+rLQNbhtckGVXJR+i8g0U6DNB8il 9nAwudY7FKrvny7E/tyoZmZWNGl0vEUQJx3t+ZECT/C8iAzZKg4+nSn9FVKC06S0ONrG R0keQRYC9fz+72ocWVPZJPKLudfQEsRRIaFZ9kdMiGVDfy2ju2X7n2QRrGY/PF7kM7cC 9iGA== X-Gm-Message-State: AOJu0Yztd3ifZA4Y6lE9n2NA0Pk3u/klXiqF6nkR6Deijy+QONECfLcb fAwt+oYp5nSAO08jG6PtDAXlr5OZJqzffEJFQL9zIlUL0ctW1FwqZbDD4YPQINFhrf19AsuAAjf ixdj9iqTbYgdbafj4D9avcSQw2TdOCW1Q9j+21de84l2jKq/gpu9imMZKYKONJbw7kQ== X-Received: by 2002:a5d:518e:0:b0:33e:c3fd:1430 with SMTP id k14-20020a5d518e000000b0033ec3fd1430mr1516587wrv.59.1710435653227; Thu, 14 Mar 2024 10:00:53 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGrSw89BfuFHJ5e5MQJny3Y+SAEIpqtqFzrLvP4Yy6sO1Awh5/N8ZpGsndy8aVAK2Ys0tMQxQ== X-Received: by 2002:a5d:518e:0:b0:33e:c3fd:1430 with SMTP id k14-20020a5d518e000000b0033ec3fd1430mr1516526wrv.59.1710435651564; Thu, 14 Mar 2024 10:00:51 -0700 (PDT) Received: from localhost ([78.243.217.51]) by smtp.gmail.com with ESMTPSA id n6-20020a5d4006000000b0033e699fc6b4sm1160153wrp.69.2024.03.14.10.00.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 Mar 2024 10:00:51 -0700 (PDT) Received: by localhost (Postfix, from userid 1000) id D79845071022; Thu, 14 Mar 2024 18:00:49 +0100 (CET) From: Dodji Seketeli To: Dodji Seketeli Cc: libabigail@sourceware.org Subject: [PATCH 4/4] Emit & read undefined interfaces to & from ABIXML Organization: Red Hat / France References: <87ttl83gaw.fsf@redhat.com> X-Operating-System: AlmaLinux 9.3 X-URL: http://www.redhat.com Date: Thu, 14 Mar 2024 18:00:49 +0100 In-Reply-To: <87ttl83gaw.fsf@redhat.com> (Dodji Seketeli's message of "Thu, 14 Mar 2024 17:54:15 +0100") Message-ID: <87cyrw3fzy.fsf@redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.5 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_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_FILL_THIS_FORM_SHORT, T_SCC_BODY_TEXT_LINE 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, This patch teaches the ABIXML writer to emit information about undefined interfaces. It also teaches the ABIXML reader to read information about undefined interfaces. It introduces two new ABIXML elements: 'undefined-elf-function-symbols' and 'undefined-elf-variable-symbols' to represent undefined function and variable symbols. Then, in the 'abi-instr' element functions and variables that reference undefined elf symbols now have an 'elf-symbol-id' attribute referencing the undefined symbol listed in the new 'undefined-elf-variable-symbols' or 'undefined-elf-function-symbols' element. The patch introduces tests that perform compatibility checks done on ABIXML files. * include/abg-writer.h (set_write_undefined_symbols): Declare new function. (set_common_options): Use the new set_write_undefined_symbols in this function template. * src/abg-dwarf-reader.cc (reader::{get_die_language, die_is_in_c, die_is_in_cplus_plus, die_is_in_c_or_cplusplus}): Move these member functions into ... (get_die_language, die_is_in_c, die_is_in_cplus_plus) (die_is_in_c_or_cplusplus): ... these static non-member functions. (fn_die_equal_by_linkage_name): Adjust and remove the now useless reader parameter. (compare_dies, get_scope_die, function_is_suppressed) (variable_is_suppressed): Adjust. (build_translation_unit_and_add_to_ir): When we are asked to load undefined symbol, make sure to also analyze top-level class types and if we are in C++, also analyze top-level unions and structs as these might also have some undefined interfaces. * src/abg-reader.cc (build_elf_symbol_db): Let's not construct and return the symbol DB anymore. Rather, let's let the caller construct it, so we can just update it with the input gathered. (read_symbol_db_from_input): Support getting undefined function and variable symbols from the new undefined-elf-function-symbols and undefined-elf-variable-symbols elements. Note that undefined and defined function symbols go into the same symbol DB whereas undefined and defined variable symbols go into another symbol DB. Now, we suppose that the variable & symbol DBs are allocated by the caller. We pass it down to build_elf_symbol_db that populates it. Maybe we should rename build_elf_symbol_db into populate_elf_symbol_db. (reader::read_corpus): Allocate the function and variable symbol DB and let read_symbol_db_from_input populate it. Sort functions and variables after reading the whole ABIXML. * src/abg-writer.cc (write_context::write_context): Define new data member. (write_context::write_context): Initialize it. (write_context::{get,set}::write_undefined_symbols): Define accessors. (set_write_undefined_symbols): Define a new function. (write_context::decl_is_emitted): Add a new overload. (write_elf_symbol_reference): Add a writer context and a corpus parameter. If the symbol is not in the corpus or if the symbol is undefined and we were not asked to emit undefined symbols then do not emit any reference to it. (write_translation_unit): Emit the undefined functions and variables that belong to the current translation unit, along with their reference to the undefined ELF symbol they are associated to. (write_var_decl, write_function_decl): Let write_elf_symbol_reference decide whether it should emit the reference to ELF symbol or not, as it now know how to make that decision. (write_corpus): Write the undefined function & variable ELF symbol data bases. These in the new 'undefined-elf-function-symbols' and 'undefined-elf-variable-symbols' elements. * tools/abidw.cc (options::load_undefined_interfaces): Define new data member. (options:options): Initialize it. (display_usage): Add a help string for the --no-load-undefined-interfaces option. (parse_command_line): Parse the --no-load-undefined-interfaces option. (set_generic_options): Set the fe_iface::option_type::load_undefined_interfaces option. * doc/manuals/abidw.rst: Document the new --no-load-undefined-interfaces of abidw. * tests/data/test-abicompat/test10/libtest10-with-exported-symbols.so: New binary input file. * tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so: New binary input file. * tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi: New abixml input file. * tests/data/test-abicompat/test10/test10-app-with-undefined-symbols: New binary input file. * tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.abi: New abixml input file. * tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc: New source file for binary test input * tests/data/test-abicompat/test10/test10-fn-changed-report-0.txt: New source file for binary test input * tests/data/test-abicompat/test10/test10-fn-changed-report-1.txt: New source file for binary test input * tests/data/test-abicompat/test10/test10-fn-changed-report-2.txt: New source file for binary test input * tests/data/test-abicompat/test10/test10-fn-changed-report-3.txt: New source file for binary test input * tests/data/test-abicompat/test10/test10-fn-changed-report-4.txt: New source file for binary test input * tests/data/test-abicompat/test10/test10-with-exported-symbols.cc: New source file for binary test input * tests/data/test-abicompat/test10/test10-with-exported-symbols.h: New source file for binary test input * tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc: New source file for binary test input * tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h: New source file for binary test input. * tests/data/Makefile.am: Add new test input files to source distribution. * tests/test-abicompat.cc (in_out_specs): Add the new test inputs to this test harness. * tests/test-annotate.cc (main): Use the new --no-load-undefined-interfaces option of abidw to keep the old behavior. * tests/test-read-common.cc (test_task::serialize_corpus): Do not emit undefined symbols. * tests/test-read-dwarf.cc (test_task_dwarf::perform): Likewise. Signed-off-by: Dodji Seketeli --- doc/manuals/abidw.rst | 10 + include/abg-writer.h | 4 + ...-undefined-interfaces-to-from-ABIXML.patch | 1051 +++++++++++++++++ src/abg-dwarf-reader.cc | 189 +-- src/abg-reader.cc | 81 +- src/abg-writer.cc | 152 ++- tests/data/Makefile.am | 15 + .../test10/libtest10-with-exported-symbols.so | Bin 0 -> 18288 bytes ...st10-with-incompatible-exported-symbols.so | Bin 0 -> 18336 bytes ...-with-incompatible-exported-symbols.so.abi | 65 + .../test10/test10-app-with-undefined-symbols | Bin 0 -> 26072 bytes .../test10-app-with-undefined-symbols.abi | 55 + .../test10-app-with-undefined-symbols.cc | 13 + .../test10/test10-fn-changed-report-0.txt | 0 .../test10/test10-fn-changed-report-1.txt | 13 + .../test10/test10-fn-changed-report-2.txt | 13 + .../test10/test10-fn-changed-report-3.txt | 13 + .../test10/test10-fn-changed-report-4.txt | 13 + .../test10/test10-with-exported-symbols.cc | 20 + .../test10/test10-with-exported-symbols.h | 14 + ...st10-with-incompatible-exported-symbols.cc | 20 + ...est10-with-incompatible-exported-symbols.h | 14 + tests/test-abicompat.cc | 54 + tests/test-annotate.cc | 2 +- tests/test-read-common.cc | 1 + tests/test-read-dwarf.cc | 2 +- tools/abidw.cc | 7 + 27 files changed, 1698 insertions(+), 123 deletions(-) create mode 100644 patches/0001-WIP-Emit-read-undefined-interfaces-to-from-ABIXML.patch create mode 100755 tests/data/test-abicompat/test10/libtest10-with-exported-symbols.so create mode 100755 tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so create mode 100644 tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi create mode 100755 tests/data/test-abicompat/test10/test10-app-with-undefined-symbols create mode 100644 tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.abi create mode 100644 tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-0.txt create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-1.txt create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-2.txt create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-3.txt create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-4.txt create mode 100644 tests/data/test-abicompat/test10/test10-with-exported-symbols.cc create mode 100644 tests/data/test-abicompat/test10/test10-with-exported-symbols.h create mode 100644 tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc create mode 100644 tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h new file mode 100755 index 0000000000000000000000000000000000000000..d63e70b4677ab56154d66bb64da943bbc100e15a GIT binary patch literal 18336 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 +Date: Wed, 6 Mar 2024 13:47:14 +0100 +Subject: [PATCH] WIP: Emit & read undefined interfaces to & from ABIXML + +This work-in-progress patch teaches the ABIXML writer to emit +information about undefined interfaces. It also teaches the ABIXML +reader to read information about undefined interfaces. + +It introduces two new ABIXML elements: +'undefined-elf-function-symbols' and 'undefined-elf-variable-symbols' +to represent undefined function and variable symbols. + +Then, in the 'abi-instr' element functions and variables that +reference undefined elf symbols now have an 'elf-symbol-id' attribute +referencing the undefined symbol listed in the new +'undefined-elf-variable-symbols' or 'undefined-elf-function-symbols' +element. + +This work-in-progress branch comes on top of the users/dodji/abidb +branch and should be merged into it at some point. + +TODO: add some tests. + + * include/abg-writer.h (set_write_undefined_symbols): Declare new + function. + (set_common_options): Use the new set_write_undefined_symbols in + this function template. + * src/abg-corpus.cc (corpus::lookup_{function,variable}_symbol): + Lookup the symbol also among undefined symbols, not just among + defined symbols. + * src/abg-dwarf-reader.cc (reader::{get_die_language, die_is_in_c, + die_is_in_cplus_plus, die_is_in_c_or_cplusplus}): Move these + member functions into ... + (get_die_language, die_is_in_c, die_is_in_cplus_plus) + (die_is_in_c_or_cplusplus): ... these static non-member functions. + (fn_die_equal_by_linkage_name): Adjust and remove the now useless + reader parameter. + (compare_dies, get_scope_die, function_is_suppressed) + (variable_is_suppressed): Adjust. + (build_translation_unit_and_add_to_ir): When we are asked to load + undefined symbol, make sure to also analyze top-level class types + and if we are in C++, also analyze top-level unions and structs as + these might also have some undefined interfaces. + * src/abg-reader.cc (build_elf_symbol_db): Let's not construct and + return the symbol DB anymore. Rather, let's let the caller + construct it, so we can just update it with the input gathered. + (read_symbol_db_from_input): Support getting undefined function + and variable symbols from the new undefined-elf-function-symbols + and undefined-elf-variable-symbols elements. Note that undefined + and defined function symbols go into the same symbol DB whereas + undefined and defined variable symbols go into another symbol DB. + Now, we suppose that the variable & symbol DBs are allocated by + the caller. We pass it down to build_elf_symbol_db that populates + it. Maybe we should rename build_elf_symbol_db into + populate_elf_symbol_db. + (reader::read_corpus): Allocate the function + and variable symbol DB and let read_symbol_db_from_input populate + it. Sort functions and variables after reading the whole ABIXML. + * src/abg-writer.cc (write_context::write_context): Define new + data member. + (write_context::write_context): Initialize it. + (write_context::{get,set}::write_undefined_symbols): Define + accessors. + (set_write_undefined_symbols): Define a new function. + (write_context::decl_is_emitted): Add a new overload. + (write_elf_symbol_reference): Add a writer context and a corpus + parameter. If the symbol is not in the corpus or if the symbol is + undefined and we were not asked to emit undefined symbols then do + not emit any reference to it. + (write_translation_unit): Emit the undefined functions and + variables that belong to the current translation unit, along with + their reference to the undefined ELF symbol they are associated + to. + (write_var_decl, write_function_decl): Let + write_elf_symbol_reference decide whether it should emit the + reference to ELF symbol or not, as it now know how to make that + decision. + (write_corpus): Write the undefined function & variable ELF symbol + data bases. These in the new 'undefined-elf-function-symbols' and + 'undefined-elf-variable-symbols' elements. + * tools/abidw.cc (options::load_undefined_interfaces): Define new + data member. + (options:options): Initialize it. + (display_usage): Add a help string for the + --no-load-undefined-interfaces option. + (parse_command_line): Parse the --no-load-undefined-interfaces + option. + (set_generic_options): Set the + fe_iface::option_type::load_undefined_interfaces option. + * doc/manuals/abidw.rst: Document the new + --no-load-undefined-interfaces of abidw. + +Signed-off-by: Dodji Seketeli +--- + doc/manuals/abidw.rst | 10 +++ + include/abg-writer.h | 4 + + src/abg-corpus.cc | 38 +++++--- + src/abg-dwarf-reader.cc | 189 +++++++++++++++++++++------------------ + src/abg-reader.cc | 81 +++++++++++------ + src/abg-writer.cc | 152 +++++++++++++++++++++++++++++-- + tests/test-annotate.cc | 2 +- + tests/test-read-dwarf.cc | 2 +- + tools/abidw.cc | 7 ++ + 9 files changed, 350 insertions(+), 135 deletions(-) + +diff --git a/doc/manuals/abidw.rst b/doc/manuals/abidw.rst +index 1e308e66..6c399675 100644 +--- a/doc/manuals/abidw.rst ++++ b/doc/manuals/abidw.rst +@@ -329,6 +329,16 @@ Options + makes ``abidw`` load *all* the types defined in the binaries, even + those that are not reachable from public declarations. + ++ * ``--no-load-undefined-interfaces`` ++ ++ By default, ``libabigail`` (and thus ``abidw``) loads information ++ about undefined function and variable symbols as well as functions ++ and variables that are associated with those undefined symbols. ++ Those are called undefined interfaces. This option however makes ++ makes ``abidw`` avoid loading information about undefined ++ interfaces. The resulting XML file thus doesn't contain ++ information about those undefined interfaces. ++ + * ``--abidiff`` + + Load the ABI of the ELF binary given in argument, save it in +diff --git a/include/abg-writer.h b/include/abg-writer.h +index 540487e0..45508544 100644 +--- a/include/abg-writer.h ++++ b/include/abg-writer.h +@@ -57,6 +57,9 @@ set_write_comp_dir(write_context& ctxt, bool flag); + void + set_write_elf_needed(write_context& ctxt, bool flag); + ++void ++set_write_undefined_symbols(write_context& ctxt, bool flag); ++ + void + set_write_default_sizes(write_context& ctxt, bool flag); + +@@ -88,6 +91,7 @@ set_common_options(write_context& ctxt, const OPTS& opts) + set_write_corpus_path(ctxt, opts.write_corpus_path); + set_write_comp_dir(ctxt, opts.write_comp_dir); + set_write_elf_needed(ctxt, opts.write_elf_needed); ++ set_write_undefined_symbols(ctxt, opts.load_undefined_interfaces); + set_write_parameter_names(ctxt, opts.write_parameter_names); + set_short_locs(ctxt, opts.short_locs); + set_write_default_sizes(ctxt, opts.default_sizes); +diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc +index e99b23fe..76c6bbb1 100644 +--- a/src/abg-corpus.cc ++++ b/src/abg-corpus.cc +@@ -1208,13 +1208,16 @@ corpus::get_undefined_var_symbol_map() const + const elf_symbol_sptr + corpus::lookup_function_symbol(const string& n) const + { +- if (get_fun_symbol_map().empty()) ++ if (get_fun_symbol_map().empty() && get_undefined_fun_symbol_map().empty()) + return elf_symbol_sptr(); + +- string_elf_symbols_map_type::const_iterator it = +- get_fun_symbol_map().find(n); ++ string_elf_symbols_map_type::const_iterator it = get_fun_symbol_map().find(n); + if ( it == get_fun_symbol_map().end()) +- return elf_symbol_sptr(); ++ { ++ it = get_undefined_fun_symbol_map().find(n); ++ if (it == get_undefined_fun_symbol_map().end()) ++ return elf_symbol_sptr(); ++ } + return it->second[0]; + } + +@@ -1275,13 +1278,17 @@ const elf_symbol_sptr + corpus::lookup_function_symbol(const string& symbol_name, + const elf_symbol::version& version) const + { +- if (get_fun_symbol_map().empty()) ++ if (get_fun_symbol_map().empty() && get_undefined_fun_symbol_map().empty()) + return elf_symbol_sptr(); + + string_elf_symbols_map_type::const_iterator it = + get_fun_symbol_map().find(symbol_name); + if ( it == get_fun_symbol_map().end()) +- return elf_symbol_sptr(); ++ { ++ it = get_undefined_fun_symbol_map().find(symbol_name); ++ if (it == get_undefined_fun_symbol_map().end()) ++ return elf_symbol_sptr(); ++ } + + return find_symbol_by_version(version, it->second); + } +@@ -1304,13 +1311,16 @@ corpus::lookup_function_symbol(const elf_symbol& symbol) const + const elf_symbol_sptr + corpus::lookup_variable_symbol(const string& n) const + { +- if (get_var_symbol_map().empty()) ++ if (get_var_symbol_map().empty() && get_undefined_var_symbol_map().empty()) + return elf_symbol_sptr(); + +- string_elf_symbols_map_type::const_iterator it = +- get_var_symbol_map().find(n); ++ string_elf_symbols_map_type::const_iterator it = get_var_symbol_map().find(n); + if ( it == get_var_symbol_map().end()) +- return elf_symbol_sptr(); ++ { ++ it = get_undefined_var_symbol_map().find(n); ++ if (it == get_undefined_var_symbol_map().end()) ++ return elf_symbol_sptr(); ++ } + return it->second[0]; + } + +@@ -1326,13 +1336,17 @@ const elf_symbol_sptr + corpus::lookup_variable_symbol(const string& symbol_name, + const elf_symbol::version& version) const + { +- if (get_var_symbol_map().empty()) ++ if (get_var_symbol_map().empty() && get_undefined_var_symbol_map().empty()) + return elf_symbol_sptr(); + + string_elf_symbols_map_type::const_iterator it = + get_var_symbol_map().find(symbol_name); + if ( it == get_var_symbol_map().end()) +- return elf_symbol_sptr(); ++ { ++ it = get_undefined_var_symbol_map().find(symbol_name); ++ if (it == get_undefined_var_symbol_map().end()) ++ return elf_symbol_sptr(); ++ } + + return find_symbol_by_version(version, it->second); + } +diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc +index d0aa8c29..89c7be3b 100644 +--- a/src/abg-dwarf-reader.cc ++++ b/src/abg-dwarf-reader.cc +@@ -379,6 +379,18 @@ get_scope_die(const reader& rdr, + size_t where_offset, + Dwarf_Die& scope_die); + ++static bool ++get_die_language(const Dwarf_Die *die, translation_unit::language &lang) ; ++ ++static bool ++die_is_in_c(const Dwarf_Die *die); ++ ++static bool ++die_is_in_cplus_plus(const Dwarf_Die *die); ++ ++static bool ++die_is_in_c_or_cplusplus(const Dwarf_Die *die); ++ + static bool + die_is_anonymous(const Dwarf_Die* die); + +@@ -654,6 +666,75 @@ compare_dies_during_canonicalization(reader& rdr, + static bool + get_member_child_die(const Dwarf_Die *die, Dwarf_Die *child); + ++/// Get the language used to generate a given DIE. ++/// ++/// @param die the DIE to consider. ++/// ++/// @param lang the resulting language. ++/// ++/// @return true iff the language of the DIE was found. ++static bool ++get_die_language(const Dwarf_Die *die, translation_unit::language &lang) ++{ ++ Dwarf_Die cu_die; ++ ABG_ASSERT(dwarf_diecu(const_cast(die), &cu_die, 0, 0)); ++ ++ uint64_t l = 0; ++ if (!die_unsigned_constant_attribute(&cu_die, DW_AT_language, l)) ++ return false; ++ ++ lang = dwarf_language_to_tu_language(l); ++ return true; ++} ++ ++/// Test if a given DIE originates from a program written in the C ++/// language. ++/// ++/// @param die the DIE to consider. ++/// ++/// @return true iff @p die originates from a program in the C ++/// language. ++static bool ++die_is_in_c(const Dwarf_Die *die) ++{ ++ translation_unit::language l = translation_unit::LANG_UNKNOWN; ++ if (!get_die_language(die, l)) ++ return false; ++ return is_c_language(l); ++} ++ ++/// Test if a given DIE originates from a program written in the C++ ++/// language. ++/// ++/// @param die the DIE to consider. ++/// ++/// @return true iff @p die originates from a program in the C++ ++/// language. ++static bool ++die_is_in_cplus_plus(const Dwarf_Die *die) ++{ ++ translation_unit::language l = translation_unit::LANG_UNKNOWN; ++ if (!get_die_language(die, l)) ++ return false; ++ return is_cplus_plus_language(l); ++} ++ ++/// Test if a given DIE originates from a program written either in ++/// C or C++. ++/// ++/// @param die the DIE to consider. ++/// ++/// @return true iff @p die originates from a program written either in ++/// C or C++. ++static bool ++die_is_in_c_or_cplusplus(const Dwarf_Die *die) ++{ ++ translation_unit::language l = translation_unit::LANG_UNKNOWN; ++ if (!get_die_language(die, l)) ++ return false; ++ return (is_cplus_plus_language(l) || is_c_language(l)); ++} ++ + /// Compare a symbol name against another name, possibly demangling + /// the symbol_name before performing the comparison. + /// +@@ -3320,75 +3401,6 @@ public: + return i->second; + } + +- /// Get the language used to generate a given DIE. +- /// +- /// @param die the DIE to consider. +- /// +- /// @param lang the resulting language. +- /// +- /// @return true iff the language of the DIE was found. +- bool +- get_die_language(const Dwarf_Die *die, translation_unit::language &lang) const +- { +- Dwarf_Die cu_die; +- ABG_ASSERT(dwarf_diecu(const_cast(die), &cu_die, 0, 0)); +- +- uint64_t l = 0; +- if (!die_unsigned_constant_attribute(&cu_die, DW_AT_language, l)) +- return false; +- +- lang = dwarf_language_to_tu_language(l); +- return true; +- } +- +- /// Test if a given DIE originates from a program written in the C +- /// language. +- /// +- /// @param die the DIE to consider. +- /// +- /// @return true iff @p die originates from a program in the C +- /// language. +- bool +- die_is_in_c(const Dwarf_Die *die) const +- { +- translation_unit::language l = translation_unit::LANG_UNKNOWN; +- if (!get_die_language(die, l)) +- return false; +- return is_c_language(l); +- } +- +- /// Test if a given DIE originates from a program written in the C++ +- /// language. +- /// +- /// @param die the DIE to consider. +- /// +- /// @return true iff @p die originates from a program in the C++ +- /// language. +- bool +- die_is_in_cplus_plus(const Dwarf_Die *die) const +- { +- translation_unit::language l = translation_unit::LANG_UNKNOWN; +- if (!get_die_language(die, l)) +- return false; +- return is_cplus_plus_language(l); +- } +- +- /// Test if a given DIE originates from a program written either in +- /// C or C++. +- /// +- /// @param die the DIE to consider. +- /// +- /// @return true iff @p die originates from a program written either in +- /// C or C++. +- bool +- die_is_in_c_or_cplusplus(const Dwarf_Die *die) const +- { +- translation_unit::language l = translation_unit::LANG_UNKNOWN; +- if (!get_die_language(die, l)) +- return false; +- return (is_cplus_plus_language(l) || is_c_language(l)); +- } +- + /// Check if we can assume the One Definition Rule[1] to be relevant + /// for the current translation unit. + /// +@@ -9818,7 +9830,7 @@ die_function_signature(const reader& rdr, + + translation_unit::language lang; + bool has_lang = false; +- if ((has_lang = rdr.get_die_language(fn_die, lang))) ++ if ((has_lang = get_die_language(fn_die, lang))) + { + // In a binary originating from the C language, it's OK to use + // the linkage name of the function as a key for the map which +@@ -10324,8 +10336,6 @@ compare_as_decl_and_type_dies(const reader &rdr, + /// in C++ for instance, that doesn't imply that the two functions are + /// equal. + /// +-/// @param rdr the @ref reader to consider. +-/// + /// @param l the first function DIE to consider. + /// + /// @param r the second function DIE to consider. +@@ -10333,8 +10343,7 @@ compare_as_decl_and_type_dies(const reader &rdr, + /// @return true iff the function represented by @p l have the same + /// linkage name as the function represented by @p r. + static bool +-fn_die_equal_by_linkage_name(const reader &rdr, +- const Dwarf_Die *l, ++fn_die_equal_by_linkage_name(const Dwarf_Die *l, + const Dwarf_Die *r) + { + if (!!l != !!r) +@@ -10352,8 +10361,8 @@ fn_die_equal_by_linkage_name(const reader &rdr, + string llinkage_name = die_linkage_name(l), + rlinkage_name = die_linkage_name(r); + +- if (rdr.die_is_in_c_or_cplusplus(l) +- && rdr.die_is_in_c_or_cplusplus(r)) ++ if (die_is_in_c_or_cplusplus(l) ++ && die_is_in_c_or_cplusplus(r)) + { + if (!llinkage_name.empty() && !rlinkage_name.empty()) + return llinkage_name == rlinkage_name; +@@ -11277,19 +11286,18 @@ compare_dies(const reader& rdr, + rdr.compare_count_++; + + if (l_tag == DW_TAG_subprogram +- && !fn_die_equal_by_linkage_name(rdr, l, r)) ++ && !fn_die_equal_by_linkage_name(l, r)) + { + SET_RESULT_TO_FALSE(result, l, r); + break; + } + else if (l_tag == DW_TAG_subprogram +- && rdr.die_is_in_c(l) && rdr.die_is_in_c(r) +- /*&& fn_die_equal_by_linkage_name(rdr, l, r)*/) ++ && die_is_in_c(l) && die_is_in_c(r)) + { + result = COMPARISON_RESULT_EQUAL; + break; + } +- else if (!rdr.die_is_in_c(l) && !rdr.die_is_in_c(r)) ++ else if (!die_is_in_c(l) && !die_is_in_c(r)) + { + // In C, we cannot have two different functions with the + // same linkage name in a given binary. But here we are +@@ -11914,7 +11922,7 @@ get_scope_die(const reader& rdr, + memcpy(&origin_die_mem, dye, sizeof(origin_die_mem)); + + translation_unit::language die_lang = translation_unit::LANG_UNKNOWN; +- rdr.get_die_language(die, die_lang); ++ get_die_language(die, die_lang); + if (is_c_language(die_lang) + || rdr.die_parent_map(rdr.get_die_source(die)).empty()) + { +@@ -11974,7 +11982,7 @@ get_scope_for_die(reader& rdr, + const die_source source_of_die = rdr.get_die_source(die); + + translation_unit::language die_lang = translation_unit::LANG_UNKNOWN; +- rdr.get_die_language(die, die_lang); ++ get_die_language(die, die_lang); + if (is_c_language(die_lang) + || rdr.die_parent_map(source_of_die).empty()) + { +@@ -12342,10 +12350,17 @@ build_translation_unit_and_add_to_ir(reader& rdr, + return result; + + result->set_is_constructed(false); +- ++ int tag = dwarf_tag(&child); + do + if (rdr.load_undefined_interfaces() +- && rdr.is_decl_die_with_undefined_symbol(&child)) ++ && (rdr.is_decl_die_with_undefined_symbol(&child) ++ || tag == DW_TAG_class_type // Top-level classes might ++ // have undefined interfaces ++ // that need to be ++ // represented, so let's ++ // analyze them as well. ++ || ((tag == DW_TAG_union_type || tag == DW_TAG_structure_type) ++ && die_is_in_cplus_plus(&child)))) + { + // Analyze undefined functions & variables for the purpose of + // analyzing compatibility matters. +@@ -15013,7 +15028,7 @@ function_is_suppressed(const reader& rdr, + + string fname = die_string_attribute(function_die, DW_AT_name); + string flinkage_name = die_linkage_name(function_die); +- if (flinkage_name.empty() && rdr.die_is_in_c(function_die)) ++ if (flinkage_name.empty() && die_is_in_c(function_die)) + flinkage_name = fname; + string qualified_name = build_qualified_name(scope, fname); + +@@ -15190,7 +15205,7 @@ variable_is_suppressed(const reader& rdr, + + string name = die_string_attribute(variable_die, DW_AT_name); + string linkage_name = die_linkage_name(variable_die); +- if (linkage_name.empty() && rdr.die_is_in_c(variable_die)) ++ if (linkage_name.empty() && die_is_in_c(variable_die)) + linkage_name = name; + string qualified_name = build_qualified_name(scope, name); + +@@ -16049,7 +16064,7 @@ build_ir_node_from_die(reader& rdr, + bool var_is_cloned = false; + + if (tag == DW_TAG_member) +- ABG_ASSERT(!rdr.die_is_in_c(die)); ++ ABG_ASSERT(!die_is_in_c(die)); + + if (die_die_attribute(die, DW_AT_specification, spec_die, false) + || (var_is_cloned = die_die_attribute(die, DW_AT_abstract_origin, +diff --git a/src/abg-reader.cc b/src/abg-reader.cc +index b525a137..a91cfaf4 100644 +--- a/src/abg-reader.cc ++++ b/src/abg-reader.cc +@@ -1270,7 +1270,8 @@ public: + if (!needed.empty()) + corp.set_needed(needed); + +- string_elf_symbols_map_sptr fn_sym_db, var_sym_db; ++ string_elf_symbols_map_sptr fn_sym_db(new string_elf_symbols_map_type), ++ var_sym_db(new string_elf_symbols_map_type); + + // Read the symbol databases. + read_symbol_db_from_input(*this, fn_sym_db, var_sym_db); +@@ -1338,6 +1339,9 @@ public: + set_corpus_node(node); + } + ++ corpus()->sort_functions(); ++ corpus()->sort_variables(); ++ + status = STATUS_OK; + return corpus(); + } +@@ -1389,8 +1393,9 @@ build_elf_symbol(reader&, const xmlNodePtr, bool); + static elf_symbol_sptr + build_elf_symbol_from_reference(reader&, const xmlNodePtr); + +-static string_elf_symbols_map_sptr +-build_elf_symbol_db(reader&, const xmlNodePtr, bool); ++static bool ++build_elf_symbol_db(reader&, const xmlNodePtr, bool, ++ string_elf_symbols_map_sptr&); + + static function_decl::parameter_sptr + build_function_parameter (reader&, const xmlNodePtr); +@@ -1898,9 +1903,9 @@ read_translation_unit_from_input(fe_iface& iface) + /// + /// @return true upon successful parsing, false otherwise. + static bool +-read_symbol_db_from_input(reader& rdr, +- string_elf_symbols_map_sptr& fn_symdb, +- string_elf_symbols_map_sptr& var_symdb) ++read_symbol_db_from_input(reader& rdr, ++ string_elf_symbols_map_sptr& fn_symdb, ++ string_elf_symbols_map_sptr& var_symdb) + { + xml::reader_sptr reader = rdr.get_libxml_reader(); + if (!reader) +@@ -1917,13 +1922,20 @@ read_symbol_db_from_input(reader& rdr, + if (status != 1) + return false; + +- bool has_fn_syms = false, has_var_syms = false; ++ bool has_fn_syms = false, has_undefined_fn_syms = false, ++ has_var_syms = false, has_undefined_var_syms = false; + if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(), + BAD_CAST("elf-function-symbols"))) + has_fn_syms = true; + else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(), + BAD_CAST("elf-variable-symbols"))) + has_var_syms = true; ++ else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(), ++ BAD_CAST("undefined-elf-function-symbols"))) ++ has_undefined_fn_syms = true; ++ else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(), ++ BAD_CAST("undefined-elf-variable-symbols"))) ++ has_undefined_var_syms = true; + else + break; + +@@ -1932,20 +1944,30 @@ read_symbol_db_from_input(reader& rdr, + return false; + + if (has_fn_syms) +- fn_symdb = build_elf_symbol_db(rdr, node, true); ++ build_elf_symbol_db(rdr, node, /*function_sym=*/true, fn_symdb); ++ else if (has_undefined_fn_syms) ++ build_elf_symbol_db(rdr, node, /*function_sym=*/true, fn_symdb); + else if (has_var_syms) +- var_symdb = build_elf_symbol_db(rdr, node, false); ++ build_elf_symbol_db(rdr, node, /*function_sym=*/false, var_symdb); ++ else if (has_undefined_var_syms) ++ build_elf_symbol_db(rdr, node, /*function_sym=*/false, var_symdb); + + xmlTextReaderNext(reader.get()); + } + else + for (xmlNodePtr n = rdr.get_corpus_node(); n; n = xmlNextElementSibling(n)) + { +- bool has_fn_syms = false, has_var_syms = false; ++ bool has_fn_syms = false, has_undefined_fn_syms = false, ++ has_var_syms = false, has_undefined_var_syms = false; + if (xmlStrEqual(n->name, BAD_CAST("elf-function-symbols"))) + has_fn_syms = true; ++ else if (xmlStrEqual(n->name, BAD_CAST("undefined-elf-function-symbols"))) ++ has_undefined_fn_syms = true; + else if (xmlStrEqual(n->name, BAD_CAST("elf-variable-symbols"))) + has_var_syms = true; ++ else if (xmlStrEqual(n->name, ++ BAD_CAST("undefined-elf-variable-symbols"))) ++ has_undefined_var_syms = true; + else + { + rdr.set_corpus_node(n); +@@ -1953,9 +1975,13 @@ read_symbol_db_from_input(reader& rdr, + } + + if (has_fn_syms) +- fn_symdb = build_elf_symbol_db(rdr, n, true); ++ build_elf_symbol_db(rdr, n, /*function_sym=*/true, fn_symdb); ++ else if (has_undefined_fn_syms) ++ build_elf_symbol_db(rdr, n, /*function_sym=*/true, fn_symdb); + else if (has_var_syms) +- var_symdb = build_elf_symbol_db(rdr, n, false); ++ build_elf_symbol_db(rdr, n, /*function_sym=*/false, var_symdb); ++ else if (has_undefined_var_syms) ++ build_elf_symbol_db(rdr, n, /*function_sym=*/false, var_symdb); + else + break; + } +@@ -3300,24 +3326,30 @@ build_elf_symbol_from_reference(reader& rdr, const xmlNodePtr node) + /// @param function_syms true if we should look for a function symbols + /// data base, false if we should look for a variable symbols data + /// base. +-static string_elf_symbols_map_sptr +-build_elf_symbol_db(reader& rdr, +- const xmlNodePtr node, +- bool function_syms) ++/// ++/// @param map a pointer to the map to fill with the symbol database. ++/// ++/// @return true if some elf symbols were found. ++static bool ++build_elf_symbol_db(reader& rdr, ++ const xmlNodePtr node, ++ bool function_syms, ++ string_elf_symbols_map_sptr& map) + { +- string_elf_symbols_map_sptr map, nil; + string_elf_symbol_sptr_map_type id_sym_map; + + if (!node) +- return nil; ++ return false; + + if (function_syms +- && !xmlStrEqual(node->name, BAD_CAST("elf-function-symbols"))) +- return nil; ++ && !xmlStrEqual(node->name, BAD_CAST("elf-function-symbols")) ++ && !xmlStrEqual(node->name, BAD_CAST("undefined-elf-function-symbols"))) ++ return false; + + if (!function_syms +- && !xmlStrEqual(node->name, BAD_CAST("elf-variable-symbols"))) +- return nil; ++ && !xmlStrEqual(node->name, BAD_CAST("elf-variable-symbols")) ++ && !xmlStrEqual(node->name, BAD_CAST("undefined-elf-variable-symbols"))) ++ return false; + + rdr.set_corpus_node(node); + +@@ -3336,9 +3368,8 @@ build_elf_symbol_db(reader& rdr, + } + + if (id_sym_map.empty()) +- return nil; ++ return false; + +- map.reset(new string_elf_symbols_map_type); + string_elf_symbols_map_type::iterator it; + for (string_elf_symbol_sptr_map_type::const_iterator i = id_sym_map.begin(); + i != id_sym_map.end(); +@@ -3374,7 +3405,7 @@ build_elf_symbol_db(reader& rdr, + } + } + +- return map; ++ return true; + } + + /// Build a function parameter from a 'parameter' xml element node. +diff --git a/src/abg-writer.cc b/src/abg-writer.cc +index 408623ab..dafe706c 100644 +--- a/src/abg-writer.cc ++++ b/src/abg-writer.cc +@@ -214,6 +214,7 @@ class write_context + bool m_write_corpus_path; + bool m_write_comp_dir; + bool m_write_elf_needed; ++ bool m_write_undefined_symbols; + bool m_write_parameter_names; + bool m_short_locs; + bool m_write_default_sizes; +@@ -252,6 +253,7 @@ public: + m_write_corpus_path(true), + m_write_comp_dir(true), + m_write_elf_needed(true), ++ m_write_undefined_symbols(true), + m_write_parameter_names(true), + m_short_locs(false), + m_write_default_sizes(true), +@@ -325,6 +327,20 @@ public: + set_write_elf_needed(bool f) + {m_write_elf_needed = f;} + ++ /// Getter of the "undefined-symbols" option. ++ /// ++ /// @return true iff undefined symbols shall be emitted. ++ bool ++ get_write_undefined_symbols() const ++ {return m_write_undefined_symbols;} ++ ++ /// Setter of the "undefined-symbols" option. ++ /// ++ /// @param f true iff undefined symbols shall be emitted. ++ void ++ set_write_undefined_symbols(bool f) ++ {m_write_undefined_symbols = f;} ++ + /// Getter of the default-sizes option. + /// + /// @return true iff default size-in-bits needs to be emitted +@@ -793,6 +809,20 @@ public: + type_is_emitted(const type_base_sptr& t) const + {return type_is_emitted(t.get());} + ++ /// Test if a given decl has been written out to the XML output. ++ /// ++ /// @param the decl to consider. ++ /// ++ /// @return true if the decl has already been emitted, false ++ /// otherwise. ++ bool ++ decl_is_emitted(const decl_base& decl) const ++ { ++ string repr = decl.get_pretty_representation(true); ++ interned_string irepr = decl.get_environment().intern(repr); ++ return m_emitted_decls_set.find(irepr) != m_emitted_decls_set.end(); ++ } ++ + /// Test if a given decl has been written out to the XML output. + /// + /// @param the decl to consider. +@@ -901,8 +931,14 @@ static void write_voffset(function_decl_sptr, ostream&); + static void write_elf_symbol_type(elf_symbol::type, ostream&); + static void write_elf_symbol_binding(elf_symbol::binding, ostream&); + static bool write_elf_symbol_aliases(const elf_symbol&, ostream&); +-static bool write_elf_symbol_reference(const elf_symbol&, ostream&); +-static bool write_elf_symbol_reference(const elf_symbol_sptr, ostream&); ++static bool write_elf_symbol_reference(write_context&, ++ const elf_symbol&, ++ const corpus& abi, ++ ostream&); ++static bool write_elf_symbol_reference(write_context&, ++ const elf_symbol_sptr, ++ const corpus& abi, ++ ostream&); + static void write_is_declaration_only(const decl_base_sptr&, ostream&); + static void write_is_struct(const class_decl_sptr&, ostream&); + static void write_is_anonymous(const decl_base_sptr&, ostream&); +@@ -1766,14 +1802,36 @@ write_elf_symbol_aliases(const elf_symbol& sym, ostream& out) + /// Write an XML attribute for the reference to a symbol for the + /// current decl. + /// ++/// ++/// @param ctxt the current write context to consider. ++/// + /// @param sym the symbol to consider. + /// ++/// @param abi the ABI corpus the symbol @p sym is supposed to belong ++/// to. If the symbol doesn't belong to that corpus, then the ++/// reference is not be emitted. ++/// + /// @param o the output stream to write the attribute to. + /// + /// @return true upon successful completion. + static bool +-write_elf_symbol_reference(const elf_symbol& sym, ostream& o) ++write_elf_symbol_reference(write_context& ctxt, ++ const elf_symbol& sym, ++ const corpus& abi, ++ ostream& o) + { ++ elf_symbol_sptr s = abi.lookup_function_symbol(sym); ++ if (!s) ++ s = abi.lookup_variable_symbol(sym); ++ ++ if (// If that symbol wasn't found in the current corpus ... ++ !s ++ // ... or we were NOT asked to represent undefined symbols and ++ // yet that symbol is undefined ... ++ || (!ctxt.get_write_undefined_symbols() && !s->is_defined())) ++ // Then do not emit this symbol reference. ++ return false; ++ + const elf_symbol* main = sym.get_main_symbol().get(); + const elf_symbol* alias = &sym; + bool found = !alias->is_suppressed(); +@@ -1804,18 +1862,27 @@ write_elf_symbol_reference(const elf_symbol& sym, ostream& o) + /// Write an XML attribute for the reference to a symbol for the + /// current decl. + /// ++/// @param ctxt the write context to consider. ++/// + /// @param sym the symbol to consider. + /// ++/// @param abi the ABI corpus the symbol @p sym is supposed to belong ++/// to. If the symbol doesn't belong to that corpus, then the ++/// reference is not be emitted. ++/// + /// @param o the output stream to write the attribute to. + /// + /// @return true upon successful completion. + static bool +-write_elf_symbol_reference(const elf_symbol_sptr sym, ostream& o) ++write_elf_symbol_reference(write_context& ctxt, ++ const elf_symbol_sptr sym, ++ const corpus& abi, ++ ostream& o) + { + if (!sym) + return false; + +- return write_elf_symbol_reference(*sym, o); ++ return write_elf_symbol_reference(ctxt, *sym, abi, o); + } + + /// Serialize the attributes "constructor", "destructor" or "static" +@@ -2255,6 +2322,18 @@ void + set_write_elf_needed(write_context& ctxt, bool flag) + {ctxt.set_write_elf_needed(flag);} + ++/// Set the 'undefined-symbols' flag. ++/// ++/// When this flag is set then the XML writer will emit corpus ++/// information about the undefined function and variable symbols. ++/// ++/// @param ctxt the context to set this flag on to. ++/// ++/// @param flag the new value of the 'undefined-symbols' flag. ++void ++set_write_undefined_symbols(write_context& ctxt, bool flag) ++{ctxt.set_write_undefined_symbols(flag);} ++ + /// Set the 'default-sizes' flag. + /// + /// When this flag is set then the XML writer will emit default +@@ -2549,6 +2628,32 @@ write_translation_unit(write_context& ctxt, + } + } + ++ // Write the undefined functions that belong to this translation ++ // unit ++ if (const abigail::ir::corpus* abi = tu.get_corpus()) ++ for (auto undefined_function : abi->get_sorted_undefined_functions()) ++ { ++ function_decl_sptr f(const_cast(undefined_function), ++ noop_deleter()); ++ if (f->get_translation_unit() != &tu || ctxt.decl_is_emitted(f)) ++ continue; ++ ++ write_decl(f, ctxt, indent + c.get_xml_element_indent()); ++ } ++ ++ // Write the undefined variables that belong to this translation ++ // unit ++ if (const abigail::ir::corpus* abi = tu.get_corpus()) ++ for (auto undefined_var : abi->get_sorted_undefined_variables()) ++ { ++ var_decl_sptr v(const_cast(undefined_var), ++ noop_deleter()); ++ if (v->get_translation_unit() != &tu || ctxt.decl_is_emitted(v)) ++ continue; ++ ++ write_decl(v, ctxt, indent + c.get_xml_element_indent()); ++ } ++ + write_referenced_types(ctxt, tu, indent, is_last); + + // Now handle all function types that were not only referenced by +@@ -3468,8 +3573,8 @@ write_var_decl(const var_decl_sptr& decl, write_context& ctxt, + write_location(decl, ctxt); + + if (elf_symbol_sptr sym = decl->get_symbol()) +- if (sym->is_defined()) +- write_elf_symbol_reference(decl->get_symbol(), o); ++ if (corpus* abi = decl->get_corpus()) ++ write_elf_symbol_reference(ctxt, decl->get_symbol(), *abi, o); + + o << "/>\n"; + +@@ -3526,8 +3631,8 @@ write_function_decl(const function_decl_sptr& decl, write_context& ctxt, + : decl->get_translation_unit()->get_address_size()), + 0); + if (elf_symbol_sptr sym = decl->get_symbol()) +- if (sym->is_defined()) +- write_elf_symbol_reference(decl->get_symbol(), o); ++ if (corpus* abi = decl->get_corpus()) ++ write_elf_symbol_reference(ctxt, decl->get_symbol(), *abi, o); + + o << ">\n"; + +@@ -4734,6 +4839,35 @@ write_corpus(write_context& ctxt, + out << "\n"; + } + ++ // Write the undefined function symbols database. ++ if (ctxt.get_write_undefined_symbols() ++ && !corpus->get_sorted_undefined_fun_symbols().empty()) ++ { ++ do_indent_to_level(ctxt, indent, 1); ++ out << "\n"; ++ ++ write_elf_symbols_table(corpus->get_sorted_undefined_fun_symbols(), ctxt, ++ get_indent_to_level(ctxt, indent, 2)); ++ ++ do_indent_to_level(ctxt, indent, 1); ++ out << "\n"; ++ } ++ ++ ++ // Write the undefined variable symbols database. ++ if (ctxt.get_write_undefined_symbols() ++ && !corpus->get_sorted_undefined_var_symbols().empty()) ++ { ++ do_indent_to_level(ctxt, indent, 1); ++ out << "\n"; ++ ++ write_elf_symbols_table(corpus->get_sorted_undefined_var_symbols(), ctxt, ++ get_indent_to_level(ctxt, indent, 2)); ++ ++ do_indent_to_level(ctxt, indent, 1); ++ out << "\n"; ++ } ++ + // Now write the translation units. + unsigned nb_tus = corpus->get_translation_units().size(), n = 0; + for (translation_units::const_iterator i = +diff --git a/tests/test-annotate.cc b/tests/test-annotate.cc +index cb9c8af6..8ddd93fb 100644 +--- a/tests/test-annotate.cc ++++ b/tests/test-annotate.cc +@@ -158,7 +158,7 @@ main() + string abidw; + + abidw = string(get_build_dir()) + "/tools/abidw " +- "--annotate --no-corpus-path --no-architecture"; ++ "--annotate --no-corpus-path --no-architecture --no-load-undefined-interfaces"; + for (InOutSpec* s = in_out_specs; s->in_elf_path; ++s) + { + bool is_ok = true; +diff --git a/tests/test-read-dwarf.cc b/tests/test-read-dwarf.cc +index 8570d774..a391c0f1 100644 +--- a/tests/test-read-dwarf.cc ++++ b/tests/test-read-dwarf.cc +@@ -651,7 +651,7 @@ test_task_dwarf::perform() + if (spec.type_id_style == HASH_TYPE_ID_STYLE) + type_id_style = "hash"; + +- string cmd = abidw + " --no-architecture " ++ string cmd = abidw + " --no-architecture --no-load-undefined-interfaces" + + " --type-id-style " + type_id_style + + " --no-corpus-path " + + drop_private_types + " " + in_elf_path +diff --git a/tools/abidw.cc b/tools/abidw.cc +index c8a44dda..7ea12908 100644 +--- a/tools/abidw.cc ++++ b/tools/abidw.cc +@@ -109,6 +109,7 @@ struct options + bool short_locs; + bool default_sizes; + bool load_all_types; ++ bool load_undefined_interfaces; + bool linux_kernel_mode; + bool corpus_group_for_linux; + bool show_stats; +@@ -155,6 +156,7 @@ struct options + short_locs(false), + default_sizes(true), + load_all_types(), ++ load_undefined_interfaces(true), + linux_kernel_mode(true), + corpus_group_for_linux(false), + show_stats(), +@@ -233,6 +235,8 @@ display_usage(const string& prog_name, ostream& out) + "debug info of , and show its base name\n" + << " --load-all-types read all types including those not reachable from " + "exported declarations\n" ++ << " --no-load-undefined-interfaces do not consider undefined " ++ "interfaces from the binary" + << " --no-linux-kernel-mode don't consider the input binary as " + "a Linux Kernel binary\n" + << " --kmi-whitelist|-w path to a linux kernel " +@@ -445,6 +449,8 @@ parse_command_line(int argc, char* argv[], options& opts) + } + else if (!strcmp(argv[i], "--load-all-types")) + opts.load_all_types = true; ++ else if (!strcmp(argv[i], "--no-load-undefined-interfaces")) ++ opts.load_undefined_interfaces = false; + else if (!strcmp(argv[i], "--drop-private-types")) + opts.drop_private_types = true; + else if (!strcmp(argv[i], "--drop-undefined-syms")) +@@ -614,6 +620,7 @@ set_generic_options(abigail::elf_based_reader& rdr, options& opts) + opts.leverage_dwarf_factorization; + rdr.options().assume_odr_for_cplusplus = + opts.assume_odr_for_cplusplus; ++ rdr.options().load_undefined_interfaces = opts.load_undefined_interfaces; + } + + /// Load an ABI @ref corpus (the internal representation of the ABI of +-- +2.39.3 + diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index c1ae31ba..5d5353ea 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -379,6 +379,18 @@ get_scope_die(const reader& rdr, size_t where_offset, Dwarf_Die& scope_die); +static bool +get_die_language(const Dwarf_Die *die, translation_unit::language &lang) ; + +static bool +die_is_in_c(const Dwarf_Die *die); + +static bool +die_is_in_cplus_plus(const Dwarf_Die *die); + +static bool +die_is_in_c_or_cplusplus(const Dwarf_Die *die); + static bool die_is_anonymous(const Dwarf_Die* die); @@ -654,6 +666,75 @@ compare_dies_during_canonicalization(reader& rdr, static bool get_member_child_die(const Dwarf_Die *die, Dwarf_Die *child); +/// Get the language used to generate a given DIE. +/// +/// @param die the DIE to consider. +/// +/// @param lang the resulting language. +/// +/// @return true iff the language of the DIE was found. +static bool +get_die_language(const Dwarf_Die *die, translation_unit::language &lang) +{ + Dwarf_Die cu_die; + ABG_ASSERT(dwarf_diecu(const_cast(die), &cu_die, 0, 0)); + + uint64_t l = 0; + if (!die_unsigned_constant_attribute(&cu_die, DW_AT_language, l)) + return false; + + lang = dwarf_language_to_tu_language(l); + return true; +} + +/// Test if a given DIE originates from a program written in the C +/// language. +/// +/// @param die the DIE to consider. +/// +/// @return true iff @p die originates from a program in the C +/// language. +static bool +die_is_in_c(const Dwarf_Die *die) +{ + translation_unit::language l = translation_unit::LANG_UNKNOWN; + if (!get_die_language(die, l)) + return false; + return is_c_language(l); +} + +/// Test if a given DIE originates from a program written in the C++ +/// language. +/// +/// @param die the DIE to consider. +/// +/// @return true iff @p die originates from a program in the C++ +/// language. +static bool +die_is_in_cplus_plus(const Dwarf_Die *die) +{ + translation_unit::language l = translation_unit::LANG_UNKNOWN; + if (!get_die_language(die, l)) + return false; + return is_cplus_plus_language(l); +} + +/// Test if a given DIE originates from a program written either in +/// C or C++. +/// +/// @param die the DIE to consider. +/// +/// @return true iff @p die originates from a program written either in +/// C or C++. +static bool +die_is_in_c_or_cplusplus(const Dwarf_Die *die) +{ + translation_unit::language l = translation_unit::LANG_UNKNOWN; + if (!get_die_language(die, l)) + return false; + return (is_cplus_plus_language(l) || is_c_language(l)); +} + /// Compare a symbol name against another name, possibly demangling /// the symbol_name before performing the comparison. /// @@ -3320,75 +3401,6 @@ public: return i->second; } - /// Get the language used to generate a given DIE. - /// - /// @param die the DIE to consider. - /// - /// @param lang the resulting language. - /// - /// @return true iff the language of the DIE was found. - bool - get_die_language(const Dwarf_Die *die, translation_unit::language &lang) const - { - Dwarf_Die cu_die; - ABG_ASSERT(dwarf_diecu(const_cast(die), &cu_die, 0, 0)); - - uint64_t l = 0; - if (!die_unsigned_constant_attribute(&cu_die, DW_AT_language, l)) - return false; - - lang = dwarf_language_to_tu_language(l); - return true; - } - - /// Test if a given DIE originates from a program written in the C - /// language. - /// - /// @param die the DIE to consider. - /// - /// @return true iff @p die originates from a program in the C - /// language. - bool - die_is_in_c(const Dwarf_Die *die) const - { - translation_unit::language l = translation_unit::LANG_UNKNOWN; - if (!get_die_language(die, l)) - return false; - return is_c_language(l); - } - - /// Test if a given DIE originates from a program written in the C++ - /// language. - /// - /// @param die the DIE to consider. - /// - /// @return true iff @p die originates from a program in the C++ - /// language. - bool - die_is_in_cplus_plus(const Dwarf_Die *die) const - { - translation_unit::language l = translation_unit::LANG_UNKNOWN; - if (!get_die_language(die, l)) - return false; - return is_cplus_plus_language(l); - } - - /// Test if a given DIE originates from a program written either in - /// C or C++. - /// - /// @param die the DIE to consider. - /// - /// @return true iff @p die originates from a program written either in - /// C or C++. - bool - die_is_in_c_or_cplusplus(const Dwarf_Die *die) const - { - translation_unit::language l = translation_unit::LANG_UNKNOWN; - if (!get_die_language(die, l)) - return false; - return (is_cplus_plus_language(l) || is_c_language(l)); - } - /// Check if we can assume the One Definition Rule[1] to be relevant /// for the current translation unit. /// @@ -9818,7 +9830,7 @@ die_function_signature(const reader& rdr, translation_unit::language lang; bool has_lang = false; - if ((has_lang = rdr.get_die_language(fn_die, lang))) + if ((has_lang = get_die_language(fn_die, lang))) { // In a binary originating from the C language, it's OK to use // the linkage name of the function as a key for the map which @@ -10324,8 +10336,6 @@ compare_as_decl_and_type_dies(const reader &rdr, /// in C++ for instance, that doesn't imply that the two functions are /// equal. /// -/// @param rdr the @ref reader to consider. -/// /// @param l the first function DIE to consider. /// /// @param r the second function DIE to consider. @@ -10333,8 +10343,7 @@ compare_as_decl_and_type_dies(const reader &rdr, /// @return true iff the function represented by @p l have the same /// linkage name as the function represented by @p r. static bool -fn_die_equal_by_linkage_name(const reader &rdr, - const Dwarf_Die *l, +fn_die_equal_by_linkage_name(const Dwarf_Die *l, const Dwarf_Die *r) { if (!!l != !!r) @@ -10352,8 +10361,8 @@ fn_die_equal_by_linkage_name(const reader &rdr, string llinkage_name = die_linkage_name(l), rlinkage_name = die_linkage_name(r); - if (rdr.die_is_in_c_or_cplusplus(l) - && rdr.die_is_in_c_or_cplusplus(r)) + if (die_is_in_c_or_cplusplus(l) + && die_is_in_c_or_cplusplus(r)) { if (!llinkage_name.empty() && !rlinkage_name.empty()) return llinkage_name == rlinkage_name; @@ -11277,19 +11286,18 @@ compare_dies(const reader& rdr, rdr.compare_count_++; if (l_tag == DW_TAG_subprogram - && !fn_die_equal_by_linkage_name(rdr, l, r)) + && !fn_die_equal_by_linkage_name(l, r)) { SET_RESULT_TO_FALSE(result, l, r); break; } else if (l_tag == DW_TAG_subprogram - && rdr.die_is_in_c(l) && rdr.die_is_in_c(r) - /*&& fn_die_equal_by_linkage_name(rdr, l, r)*/) + && die_is_in_c(l) && die_is_in_c(r)) { result = COMPARISON_RESULT_EQUAL; break; } - else if (!rdr.die_is_in_c(l) && !rdr.die_is_in_c(r)) + else if (!die_is_in_c(l) && !die_is_in_c(r)) { // In C, we cannot have two different functions with the // same linkage name in a given binary. But here we are @@ -11914,7 +11922,7 @@ get_scope_die(const reader& rdr, memcpy(&origin_die_mem, dye, sizeof(origin_die_mem)); translation_unit::language die_lang = translation_unit::LANG_UNKNOWN; - rdr.get_die_language(die, die_lang); + get_die_language(die, die_lang); if (is_c_language(die_lang) || rdr.die_parent_map(rdr.get_die_source(die)).empty()) { @@ -11974,7 +11982,7 @@ get_scope_for_die(reader& rdr, const die_source source_of_die = rdr.get_die_source(die); translation_unit::language die_lang = translation_unit::LANG_UNKNOWN; - rdr.get_die_language(die, die_lang); + get_die_language(die, die_lang); if (is_c_language(die_lang) || rdr.die_parent_map(source_of_die).empty()) { @@ -12342,10 +12350,17 @@ build_translation_unit_and_add_to_ir(reader& rdr, return result; result->set_is_constructed(false); - + int tag = dwarf_tag(&child); do if (rdr.load_undefined_interfaces() - && rdr.is_decl_die_with_undefined_symbol(&child)) + && (rdr.is_decl_die_with_undefined_symbol(&child) + || tag == DW_TAG_class_type // Top-level classes might + // have undefined interfaces + // that need to be + // represented, so let's + // analyze them as well. + || ((tag == DW_TAG_union_type || tag == DW_TAG_structure_type) + && die_is_in_cplus_plus(&child)))) { // Analyze undefined functions & variables for the purpose of // analyzing compatibility matters. @@ -15013,7 +15028,7 @@ function_is_suppressed(const reader& rdr, string fname = die_string_attribute(function_die, DW_AT_name); string flinkage_name = die_linkage_name(function_die); - if (flinkage_name.empty() && rdr.die_is_in_c(function_die)) + if (flinkage_name.empty() && die_is_in_c(function_die)) flinkage_name = fname; string qualified_name = build_qualified_name(scope, fname); @@ -15190,7 +15205,7 @@ variable_is_suppressed(const reader& rdr, string name = die_string_attribute(variable_die, DW_AT_name); string linkage_name = die_linkage_name(variable_die); - if (linkage_name.empty() && rdr.die_is_in_c(variable_die)) + if (linkage_name.empty() && die_is_in_c(variable_die)) linkage_name = name; string qualified_name = build_qualified_name(scope, name); @@ -16050,7 +16065,7 @@ build_ir_node_from_die(reader& rdr, bool var_is_cloned = false; if (tag == DW_TAG_member) - ABG_ASSERT(!rdr.die_is_in_c(die)); + ABG_ASSERT(!die_is_in_c(die)); if (die_die_attribute(die, DW_AT_specification, spec_die, false) || (var_is_cloned = die_die_attribute(die, DW_AT_abstract_origin, diff --git a/src/abg-reader.cc b/src/abg-reader.cc index b525a137..a91cfaf4 100644 --- a/src/abg-reader.cc +++ b/src/abg-reader.cc @@ -1270,7 +1270,8 @@ public: if (!needed.empty()) corp.set_needed(needed); - string_elf_symbols_map_sptr fn_sym_db, var_sym_db; + string_elf_symbols_map_sptr fn_sym_db(new string_elf_symbols_map_type), + var_sym_db(new string_elf_symbols_map_type); // Read the symbol databases. read_symbol_db_from_input(*this, fn_sym_db, var_sym_db); @@ -1338,6 +1339,9 @@ public: set_corpus_node(node); } + corpus()->sort_functions(); + corpus()->sort_variables(); + status = STATUS_OK; return corpus(); } @@ -1389,8 +1393,9 @@ build_elf_symbol(reader&, const xmlNodePtr, bool); static elf_symbol_sptr build_elf_symbol_from_reference(reader&, const xmlNodePtr); -static string_elf_symbols_map_sptr -build_elf_symbol_db(reader&, const xmlNodePtr, bool); +static bool +build_elf_symbol_db(reader&, const xmlNodePtr, bool, + string_elf_symbols_map_sptr&); static function_decl::parameter_sptr build_function_parameter (reader&, const xmlNodePtr); @@ -1898,9 +1903,9 @@ read_translation_unit_from_input(fe_iface& iface) /// /// @return true upon successful parsing, false otherwise. static bool -read_symbol_db_from_input(reader& rdr, - string_elf_symbols_map_sptr& fn_symdb, - string_elf_symbols_map_sptr& var_symdb) +read_symbol_db_from_input(reader& rdr, + string_elf_symbols_map_sptr& fn_symdb, + string_elf_symbols_map_sptr& var_symdb) { xml::reader_sptr reader = rdr.get_libxml_reader(); if (!reader) @@ -1917,13 +1922,20 @@ read_symbol_db_from_input(reader& rdr, if (status != 1) return false; - bool has_fn_syms = false, has_var_syms = false; + bool has_fn_syms = false, has_undefined_fn_syms = false, + has_var_syms = false, has_undefined_var_syms = false; if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(), BAD_CAST("elf-function-symbols"))) has_fn_syms = true; else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(), BAD_CAST("elf-variable-symbols"))) has_var_syms = true; + else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(), + BAD_CAST("undefined-elf-function-symbols"))) + has_undefined_fn_syms = true; + else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(), + BAD_CAST("undefined-elf-variable-symbols"))) + has_undefined_var_syms = true; else break; @@ -1932,20 +1944,30 @@ read_symbol_db_from_input(reader& rdr, return false; if (has_fn_syms) - fn_symdb = build_elf_symbol_db(rdr, node, true); + build_elf_symbol_db(rdr, node, /*function_sym=*/true, fn_symdb); + else if (has_undefined_fn_syms) + build_elf_symbol_db(rdr, node, /*function_sym=*/true, fn_symdb); else if (has_var_syms) - var_symdb = build_elf_symbol_db(rdr, node, false); + build_elf_symbol_db(rdr, node, /*function_sym=*/false, var_symdb); + else if (has_undefined_var_syms) + build_elf_symbol_db(rdr, node, /*function_sym=*/false, var_symdb); xmlTextReaderNext(reader.get()); } else for (xmlNodePtr n = rdr.get_corpus_node(); n; n = xmlNextElementSibling(n)) { - bool has_fn_syms = false, has_var_syms = false; + bool has_fn_syms = false, has_undefined_fn_syms = false, + has_var_syms = false, has_undefined_var_syms = false; if (xmlStrEqual(n->name, BAD_CAST("elf-function-symbols"))) has_fn_syms = true; + else if (xmlStrEqual(n->name, BAD_CAST("undefined-elf-function-symbols"))) + has_undefined_fn_syms = true; else if (xmlStrEqual(n->name, BAD_CAST("elf-variable-symbols"))) has_var_syms = true; + else if (xmlStrEqual(n->name, + BAD_CAST("undefined-elf-variable-symbols"))) + has_undefined_var_syms = true; else { rdr.set_corpus_node(n); @@ -1953,9 +1975,13 @@ read_symbol_db_from_input(reader& rdr, } if (has_fn_syms) - fn_symdb = build_elf_symbol_db(rdr, n, true); + build_elf_symbol_db(rdr, n, /*function_sym=*/true, fn_symdb); + else if (has_undefined_fn_syms) + build_elf_symbol_db(rdr, n, /*function_sym=*/true, fn_symdb); else if (has_var_syms) - var_symdb = build_elf_symbol_db(rdr, n, false); + build_elf_symbol_db(rdr, n, /*function_sym=*/false, var_symdb); + else if (has_undefined_var_syms) + build_elf_symbol_db(rdr, n, /*function_sym=*/false, var_symdb); else break; } @@ -3300,24 +3326,30 @@ build_elf_symbol_from_reference(reader& rdr, const xmlNodePtr node) /// @param function_syms true if we should look for a function symbols /// data base, false if we should look for a variable symbols data /// base. -static string_elf_symbols_map_sptr -build_elf_symbol_db(reader& rdr, - const xmlNodePtr node, - bool function_syms) +/// +/// @param map a pointer to the map to fill with the symbol database. +/// +/// @return true if some elf symbols were found. +static bool +build_elf_symbol_db(reader& rdr, + const xmlNodePtr node, + bool function_syms, + string_elf_symbols_map_sptr& map) { - string_elf_symbols_map_sptr map, nil; string_elf_symbol_sptr_map_type id_sym_map; if (!node) - return nil; + return false; if (function_syms - && !xmlStrEqual(node->name, BAD_CAST("elf-function-symbols"))) - return nil; + && !xmlStrEqual(node->name, BAD_CAST("elf-function-symbols")) + && !xmlStrEqual(node->name, BAD_CAST("undefined-elf-function-symbols"))) + return false; if (!function_syms - && !xmlStrEqual(node->name, BAD_CAST("elf-variable-symbols"))) - return nil; + && !xmlStrEqual(node->name, BAD_CAST("elf-variable-symbols")) + && !xmlStrEqual(node->name, BAD_CAST("undefined-elf-variable-symbols"))) + return false; rdr.set_corpus_node(node); @@ -3336,9 +3368,8 @@ build_elf_symbol_db(reader& rdr, } if (id_sym_map.empty()) - return nil; + return false; - map.reset(new string_elf_symbols_map_type); string_elf_symbols_map_type::iterator it; for (string_elf_symbol_sptr_map_type::const_iterator i = id_sym_map.begin(); i != id_sym_map.end(); @@ -3374,7 +3405,7 @@ build_elf_symbol_db(reader& rdr, } } - return map; + return true; } /// Build a function parameter from a 'parameter' xml element node. diff --git a/src/abg-writer.cc b/src/abg-writer.cc index 408623ab..dafe706c 100644 --- a/src/abg-writer.cc +++ b/src/abg-writer.cc @@ -214,6 +214,7 @@ class write_context bool m_write_corpus_path; bool m_write_comp_dir; bool m_write_elf_needed; + bool m_write_undefined_symbols; bool m_write_parameter_names; bool m_short_locs; bool m_write_default_sizes; @@ -252,6 +253,7 @@ public: m_write_corpus_path(true), m_write_comp_dir(true), m_write_elf_needed(true), + m_write_undefined_symbols(true), m_write_parameter_names(true), m_short_locs(false), m_write_default_sizes(true), @@ -325,6 +327,20 @@ public: set_write_elf_needed(bool f) {m_write_elf_needed = f;} + /// Getter of the "undefined-symbols" option. + /// + /// @return true iff undefined symbols shall be emitted. + bool + get_write_undefined_symbols() const + {return m_write_undefined_symbols;} + + /// Setter of the "undefined-symbols" option. + /// + /// @param f true iff undefined symbols shall be emitted. + void + set_write_undefined_symbols(bool f) + {m_write_undefined_symbols = f;} + /// Getter of the default-sizes option. /// /// @return true iff default size-in-bits needs to be emitted @@ -793,6 +809,20 @@ public: type_is_emitted(const type_base_sptr& t) const {return type_is_emitted(t.get());} + /// Test if a given decl has been written out to the XML output. + /// + /// @param the decl to consider. + /// + /// @return true if the decl has already been emitted, false + /// otherwise. + bool + decl_is_emitted(const decl_base& decl) const + { + string repr = decl.get_pretty_representation(true); + interned_string irepr = decl.get_environment().intern(repr); + return m_emitted_decls_set.find(irepr) != m_emitted_decls_set.end(); + } + /// Test if a given decl has been written out to the XML output. /// /// @param the decl to consider. @@ -901,8 +931,14 @@ static void write_voffset(function_decl_sptr, ostream&); static void write_elf_symbol_type(elf_symbol::type, ostream&); static void write_elf_symbol_binding(elf_symbol::binding, ostream&); static bool write_elf_symbol_aliases(const elf_symbol&, ostream&); -static bool write_elf_symbol_reference(const elf_symbol&, ostream&); -static bool write_elf_symbol_reference(const elf_symbol_sptr, ostream&); +static bool write_elf_symbol_reference(write_context&, + const elf_symbol&, + const corpus& abi, + ostream&); +static bool write_elf_symbol_reference(write_context&, + const elf_symbol_sptr, + const corpus& abi, + ostream&); static void write_is_declaration_only(const decl_base_sptr&, ostream&); static void write_is_struct(const class_decl_sptr&, ostream&); static void write_is_anonymous(const decl_base_sptr&, ostream&); @@ -1766,14 +1802,36 @@ write_elf_symbol_aliases(const elf_symbol& sym, ostream& out) /// Write an XML attribute for the reference to a symbol for the /// current decl. /// +/// +/// @param ctxt the current write context to consider. +/// /// @param sym the symbol to consider. /// +/// @param abi the ABI corpus the symbol @p sym is supposed to belong +/// to. If the symbol doesn't belong to that corpus, then the +/// reference is not be emitted. +/// /// @param o the output stream to write the attribute to. /// /// @return true upon successful completion. static bool -write_elf_symbol_reference(const elf_symbol& sym, ostream& o) +write_elf_symbol_reference(write_context& ctxt, + const elf_symbol& sym, + const corpus& abi, + ostream& o) { + elf_symbol_sptr s = abi.lookup_function_symbol(sym); + if (!s) + s = abi.lookup_variable_symbol(sym); + + if (// If that symbol wasn't found in the current corpus ... + !s + // ... or we were NOT asked to represent undefined symbols and + // yet that symbol is undefined ... + || (!ctxt.get_write_undefined_symbols() && !s->is_defined())) + // Then do not emit this symbol reference. + return false; + const elf_symbol* main = sym.get_main_symbol().get(); const elf_symbol* alias = &sym; bool found = !alias->is_suppressed(); @@ -1804,18 +1862,27 @@ write_elf_symbol_reference(const elf_symbol& sym, ostream& o) /// Write an XML attribute for the reference to a symbol for the /// current decl. /// +/// @param ctxt the write context to consider. +/// /// @param sym the symbol to consider. /// +/// @param abi the ABI corpus the symbol @p sym is supposed to belong +/// to. If the symbol doesn't belong to that corpus, then the +/// reference is not be emitted. +/// /// @param o the output stream to write the attribute to. /// /// @return true upon successful completion. static bool -write_elf_symbol_reference(const elf_symbol_sptr sym, ostream& o) +write_elf_symbol_reference(write_context& ctxt, + const elf_symbol_sptr sym, + const corpus& abi, + ostream& o) { if (!sym) return false; - return write_elf_symbol_reference(*sym, o); + return write_elf_symbol_reference(ctxt, *sym, abi, o); } /// Serialize the attributes "constructor", "destructor" or "static" @@ -2255,6 +2322,18 @@ void set_write_elf_needed(write_context& ctxt, bool flag) {ctxt.set_write_elf_needed(flag);} +/// Set the 'undefined-symbols' flag. +/// +/// When this flag is set then the XML writer will emit corpus +/// information about the undefined function and variable symbols. +/// +/// @param ctxt the context to set this flag on to. +/// +/// @param flag the new value of the 'undefined-symbols' flag. +void +set_write_undefined_symbols(write_context& ctxt, bool flag) +{ctxt.set_write_undefined_symbols(flag);} + /// Set the 'default-sizes' flag. /// /// When this flag is set then the XML writer will emit default @@ -2549,6 +2628,32 @@ write_translation_unit(write_context& ctxt, } } + // Write the undefined functions that belong to this translation + // unit + if (const abigail::ir::corpus* abi = tu.get_corpus()) + for (auto undefined_function : abi->get_sorted_undefined_functions()) + { + function_decl_sptr f(const_cast(undefined_function), + noop_deleter()); + if (f->get_translation_unit() != &tu || ctxt.decl_is_emitted(f)) + continue; + + write_decl(f, ctxt, indent + c.get_xml_element_indent()); + } + + // Write the undefined variables that belong to this translation + // unit + if (const abigail::ir::corpus* abi = tu.get_corpus()) + for (auto undefined_var : abi->get_sorted_undefined_variables()) + { + var_decl_sptr v(const_cast(undefined_var), + noop_deleter()); + if (v->get_translation_unit() != &tu || ctxt.decl_is_emitted(v)) + continue; + + write_decl(v, ctxt, indent + c.get_xml_element_indent()); + } + write_referenced_types(ctxt, tu, indent, is_last); // Now handle all function types that were not only referenced by @@ -3468,8 +3573,8 @@ write_var_decl(const var_decl_sptr& decl, write_context& ctxt, write_location(decl, ctxt); if (elf_symbol_sptr sym = decl->get_symbol()) - if (sym->is_defined()) - write_elf_symbol_reference(decl->get_symbol(), o); + if (corpus* abi = decl->get_corpus()) + write_elf_symbol_reference(ctxt, decl->get_symbol(), *abi, o); o << "/>\n"; @@ -3526,8 +3631,8 @@ write_function_decl(const function_decl_sptr& decl, write_context& ctxt, : decl->get_translation_unit()->get_address_size()), 0); if (elf_symbol_sptr sym = decl->get_symbol()) - if (sym->is_defined()) - write_elf_symbol_reference(decl->get_symbol(), o); + if (corpus* abi = decl->get_corpus()) + write_elf_symbol_reference(ctxt, decl->get_symbol(), *abi, o); o << ">\n"; @@ -4734,6 +4839,35 @@ write_corpus(write_context& ctxt, out << "\n"; } + // Write the undefined function symbols database. + if (ctxt.get_write_undefined_symbols() + && !corpus->get_sorted_undefined_fun_symbols().empty()) + { + do_indent_to_level(ctxt, indent, 1); + out << "\n"; + + write_elf_symbols_table(corpus->get_sorted_undefined_fun_symbols(), ctxt, + get_indent_to_level(ctxt, indent, 2)); + + do_indent_to_level(ctxt, indent, 1); + out << "\n"; + } + + + // Write the undefined variable symbols database. + if (ctxt.get_write_undefined_symbols() + && !corpus->get_sorted_undefined_var_symbols().empty()) + { + do_indent_to_level(ctxt, indent, 1); + out << "\n"; + + write_elf_symbols_table(corpus->get_sorted_undefined_var_symbols(), ctxt, + get_indent_to_level(ctxt, indent, 2)); + + do_indent_to_level(ctxt, indent, 1); + out << "\n"; + } + // Now write the translation units. unsigned nb_tus = corpus->get_translation_units().size(), n = 0; for (translation_units::const_iterator i = diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 5bf01528..da37f56c 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -2130,6 +2130,21 @@ test-abicompat/test9-fn-changed-v1.cc \ test-abicompat/test9-fn-changed-v1.h \ test-abicompat/test9-fn-changed-app \ test-abicompat/test9-fn-changed-report-0.txt \ +test-abicompat/test10/libtest10-with-exported-symbols.so \ +test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so \ +test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi \ +test-abicompat/test10/test10-app-with-undefined-symbols \ +test-abicompat/test10/test10-app-with-undefined-symbols.abi \ +test-abicompat/test10/test10-app-with-undefined-symbols.cc \ +test-abicompat/test10/test10-with-exported-symbols.cc \ +test-abicompat/test10/test10-with-exported-symbols.h \ +test-abicompat/test10/test10-with-incompatible-exported-symbols.cc \ +test-abicompat/test10/test10-with-incompatible-exported-symbols.h \ +test-abicompat/test10/test10-fn-changed-report-0.txt \ +test-abicompat/test10/test10-fn-changed-report-1.txt \ +test-abicompat/test10/test10-fn-changed-report-2.txt \ +test-abicompat/test10/test10-fn-changed-report-3.txt \ +test-abicompat/test10/test10-fn-changed-report-4.txt \ \ test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64.rpm \ test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm \ diff --git a/tests/data/test-abicompat/test10/libtest10-with-exported-symbols.so b/tests/data/test-abicompat/test10/libtest10-with-exported-symbols.so new file mode 100755 index 0000000000000000000000000000000000000000..8eb1fa58d0c85b1813eadaa56367fdc9d7762ec3 GIT binary patch literal 18288 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 literal 0 HcmV?d00001 diff --git a/tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so b/tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so diff --git a/tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi b/tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi new file mode 100644 index 00000000..82653e42 --- /dev/null +++ b/tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols b/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols new file mode 100755 index 0000000000000000000000000000000000000000..4d5f6c32c8e72a0d549648f96c477710060e2d7c GIT binary patch literal 26072 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 M;N!4F2I;o{2cRGJzW@LL literal 0 HcmV?d00001 diff --git a/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.abi b/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.abi --- /dev/null +++ b/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.abi @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc b/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc new file mode 100644 index 00000000..07d223e6 --- /dev/null +++ b/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc @@ -0,0 +1,13 @@ +// Compile with: +// +// g++ -g -L. -ltest10-with-exported-symbols -o test10-app-with-undefined-symbols test10-app-with-undefined-symbols.cc +// + +#include "test10-with-exported-symbols.h" + +int +main() +{ + some_type s; + return s.get_first_member() + s.get_second_member(); +} diff --git a/tests/data/test-abicompat/test10/test10-fn-changed-report-0.txt b/tests/data/test-abicompat/test10/test10-fn-changed-report-0.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/data/test-abicompat/test10/test10-fn-changed-report-1.txt b/tests/data/test-abicompat/test10/test10-fn-changed-report-1.txt new file mode 100644 index 00000000..3824b9e3 --- /dev/null +++ b/tests/data/test-abicompat/test10/test10-fn-changed-report-1.txt @@ -0,0 +1,13 @@ +functions defined in library 'libtest10-with-incompatible-exported-symbols.so' +have sub-types that are different from what application 'test10-app-with-undefined-symbols' expects: + + method int some_type::get_first_member(): + return type changed: + entity changed from 'int' to 'int*' + type size changed from 32 to 64 (in bits) + + method char some_type::get_second_member(): + return type changed: + entity changed from 'char' to 'char*' + type size changed from 8 to 64 (in bits) + diff --git a/tests/data/test-abicompat/test10/test10-fn-changed-report-2.txt b/tests/data/test-abicompat/test10/test10-fn-changed-report-2.txt new file mode 100644 index 00000000..d5ae6534 --- /dev/null +++ b/tests/data/test-abicompat/test10/test10-fn-changed-report-2.txt @@ -0,0 +1,13 @@ +functions defined in library 'libtest10-with-incompatible-exported-symbols.so.abi' +have sub-types that are different from what application 'test10-app-with-undefined-symbols' expects: + + method int some_type::get_first_member(): + return type changed: + entity changed from 'int' to 'int*' + type size changed from 32 to 64 (in bits) + + method char some_type::get_second_member(): + return type changed: + entity changed from 'char' to 'char*' + type size changed from 8 to 64 (in bits) + diff --git a/tests/data/test-abicompat/test10/test10-fn-changed-report-3.txt b/tests/data/test-abicompat/test10/test10-fn-changed-report-3.txt new file mode 100644 index 00000000..3df28e7c --- /dev/null +++ b/tests/data/test-abicompat/test10/test10-fn-changed-report-3.txt @@ -0,0 +1,13 @@ +functions defined in library 'libtest10-with-incompatible-exported-symbols.so' +have sub-types that are different from what application 'test10-app-with-undefined-symbols.abi' expects: + + method int some_type::get_first_member(): + return type changed: + entity changed from 'int' to 'int*' + type size changed from 32 to 64 (in bits) + + method char some_type::get_second_member(): + return type changed: + entity changed from 'char' to 'char*' + type size changed from 8 to 64 (in bits) + diff --git a/tests/data/test-abicompat/test10/test10-fn-changed-report-4.txt b/tests/data/test-abicompat/test10/test10-fn-changed-report-4.txt new file mode 100644 index 00000000..8ea5b16c --- /dev/null +++ b/tests/data/test-abicompat/test10/test10-fn-changed-report-4.txt @@ -0,0 +1,13 @@ +functions defined in library 'libtest10-with-incompatible-exported-symbols.so.abi' +have sub-types that are different from what application 'test10-app-with-undefined-symbols.abi' expects: + + method int some_type::get_first_member(): + return type changed: + entity changed from 'int' to 'int*' + type size changed from 32 to 64 (in bits) + + method char some_type::get_second_member(): + return type changed: + entity changed from 'char' to 'char*' + type size changed from 8 to 64 (in bits) + diff --git a/tests/data/test-abicompat/test10/test10-with-exported-symbols.cc b/tests/data/test-abicompat/test10/test10-with-exported-symbols.cc new file mode 100644 index 00000000..b2be7eac --- /dev/null +++ b/tests/data/test-abicompat/test10/test10-with-exported-symbols.cc @@ -0,0 +1,20 @@ +// Build this with: +// g++ -g -Wall -shared -o libtest10-with-exported-symbols.so test10-with-exported-symbols.cc + +#include "test10-with-exported-symbols.h" + +int +some_type::get_first_member() +{return first_member;} + +void +some_type::set_first_member(int v) +{first_member = v;} + +char +some_type::get_second_member() +{return second_member;} + +void +some_type::set_second_member(char v) +{second_member = v;} diff --git a/tests/data/test-abicompat/test10/test10-with-exported-symbols.h b/tests/data/test-abicompat/test10/test10-with-exported-symbols.h new file mode 100644 index 00000000..ce206570 --- /dev/null +++ b/tests/data/test-abicompat/test10/test10-with-exported-symbols.h @@ -0,0 +1,14 @@ +class some_type +{ + public: + + int get_first_member(); + void set_first_member(int); + + char get_second_member(); + void set_second_member(char); + + private: + int first_member = 0; + char second_member = 0; +}; diff --git a/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc b/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc new file mode 100644 index 00000000..f93a5458 --- /dev/null +++ b/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc @@ -0,0 +1,20 @@ +// Build this with: +// g++ -g -Wall -shared -o libtest10-with-incompatible-exported-symbols.so test10-with-incompatible-exported-symbols.cc + +#include "test10-with-incompatible-exported-symbols.h" + +int* +some_type::get_first_member() +{return &first_member;} + +void +some_type::set_first_member(int v) +{first_member = v;} + +char* +some_type::get_second_member() +{return &second_member;} + +void +some_type::set_second_member(char v) +{second_member = v;} diff --git a/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h b/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h new file mode 100644 index 00000000..bfed108d --- /dev/null +++ b/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h @@ -0,0 +1,14 @@ +class some_type +{ + public: + + int* get_first_member(); + void set_first_member(int); + + char* get_second_member(); + void set_second_member(char); + + private: + int first_member = 0; + char second_member = 0; +}; diff --git a/tests/test-abicompat.cc b/tests/test-abicompat.cc index 320436c3..a7fcc520 100644 --- a/tests/test-abicompat.cc +++ b/tests/test-abicompat.cc @@ -226,6 +226,60 @@ InOutSpec in_out_specs[] = "data/test-abicompat/test9-fn-changed-report-0.txt", "output/test-abicompat/test9-fn-changed-report-0.txt", }, + { + "data/test-abicompat/test10/test10-app-with-undefined-symbols", + "data/test-abicompat/test10/libtest10-with-exported-symbols.so", + "", + "", + "--show-base-names", + "data/test-abicompat/test10/test10-fn-changed-report-0.txt", + "output/test-abicompat/test10/test10-fn-changed-report-0.txt", + }, + { + "data/test-abicompat/test10/test10-app-with-undefined-symbols.abi", + "data/test-abicompat/test10/libtest10-with-exported-symbols.so", + "", + "", + "--show-base-names", + "data/test-abicompat/test10/test10-fn-changed-report-0.txt", + "output/test-abicompat/test10/test10-fn-changed-report-0.txt", + }, + { + "data/test-abicompat/test10/test10-app-with-undefined-symbols", + "data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so", + "", + "", + "--show-base-names", + "data/test-abicompat/test10/test10-fn-changed-report-1.txt", + "output/test-abicompat/test10/test10-fn-changed-report-1.txt", + }, + { + "data/test-abicompat/test10/test10-app-with-undefined-symbols", + "data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi", + "", + "", + "--show-base-names", + "data/test-abicompat/test10/test10-fn-changed-report-2.txt", + "output/test-abicompat/test10/test10-fn-changed-report-2.txt", + }, + { + "data/test-abicompat/test10/test10-app-with-undefined-symbols.abi", + "data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so", + "", + "", + "--show-base-names", + "data/test-abicompat/test10/test10-fn-changed-report-3.txt", + "output/test-abicompat/test10/test10-fn-changed-report-3.txt", + }, + { + "data/test-abicompat/test10/test10-app-with-undefined-symbols.abi", + "data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi", + "", + "", + "--show-base-names", + "data/test-abicompat/test10/test10-fn-changed-report-4.txt", + "output/test-abicompat/test10/test10-fn-changed-report-4.txt", + }, // This entry must be the last one. {0, 0, 0, 0, 0, 0, 0} }; diff --git a/tests/test-annotate.cc b/tests/test-annotate.cc index cb9c8af6..8ddd93fb 100644 --- a/tests/test-annotate.cc +++ b/tests/test-annotate.cc @@ -158,7 +158,7 @@ main() string abidw; abidw = string(get_build_dir()) + "/tools/abidw " - "--annotate --no-corpus-path --no-architecture"; + "--annotate --no-corpus-path --no-architecture --no-load-undefined-interfaces"; for (InOutSpec* s = in_out_specs; s->in_elf_path; ++s) { bool is_ok = true; diff --git a/tests/test-read-common.cc b/tests/test-read-common.cc index 1d70b3d0..8c682b1c 100644 --- a/tests/test-read-common.cc +++ b/tests/test-read-common.cc @@ -74,6 +74,7 @@ test_task::serialize_corpus(const string& out_abi_path, write_context_sptr write_ctxt = create_write_context(corp->get_environment(), of); set_type_id_style(*write_ctxt, spec.type_id_style); + set_write_undefined_symbols(*write_ctxt, false); is_ok = write_corpus(*write_ctxt, corp, /*indent=*/0); of.close(); diff --git a/tests/test-read-dwarf.cc b/tests/test-read-dwarf.cc index 8570d774..a391c0f1 100644 --- a/tests/test-read-dwarf.cc +++ b/tests/test-read-dwarf.cc @@ -651,7 +651,7 @@ test_task_dwarf::perform() if (spec.type_id_style == HASH_TYPE_ID_STYLE) type_id_style = "hash"; - string cmd = abidw + " --no-architecture " + string cmd = abidw + " --no-architecture --no-load-undefined-interfaces" + " --type-id-style " + type_id_style + " --no-corpus-path " + drop_private_types + " " + in_elf_path diff --git a/tools/abidw.cc b/tools/abidw.cc index fe977b1d..c6cc0562 100644 --- a/tools/abidw.cc +++ b/tools/abidw.cc @@ -109,6 +109,7 @@ struct options bool short_locs; bool default_sizes; bool load_all_types; + bool load_undefined_interfaces; bool linux_kernel_mode; bool corpus_group_for_linux; bool show_stats; @@ -155,6 +156,7 @@ struct options short_locs(false), default_sizes(true), load_all_types(), + load_undefined_interfaces(true), linux_kernel_mode(true), corpus_group_for_linux(false), show_stats(), @@ -233,6 +235,8 @@ display_usage(const string& prog_name, ostream& out) "debug info of , and show its base name\n" << " --load-all-types read all types including those not reachable from " "exported declarations\n" + << " --no-load-undefined-interfaces do not consider undefined " + "interfaces from the binary" << " --no-linux-kernel-mode don't consider the input binary as " "a Linux Kernel binary\n" << " --kmi-whitelist|-w path to a linux kernel " @@ -446,6 +450,8 @@ parse_command_line(int argc, char* argv[], options& opts) } else if (!strcmp(argv[i], "--load-all-types")) opts.load_all_types = true; + else if (!strcmp(argv[i], "--no-load-undefined-interfaces")) + opts.load_undefined_interfaces = false; else if (!strcmp(argv[i], "--drop-private-types")) opts.drop_private_types = true; else if (!strcmp(argv[i], "--drop-undefined-syms")) @@ -615,6 +621,7 @@ set_generic_options(abigail::elf_based_reader& rdr, options& opts) opts.leverage_dwarf_factorization; rdr.options().assume_odr_for_cplusplus = opts.assume_odr_for_cplusplus; + rdr.options().load_undefined_interfaces = opts.load_undefined_interfaces; } /// Load an ABI @ref corpus (the internal representation of the ABI of