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 zcmeHQeQX@X6`#HH+2=U^NK8_P0Nxabh9r0PIgZIkldO~2KDYU5K7=VB%ldA8UUI&3 z@AeW0B{U*Hm8M96KWJJ}N~KmHwWvsK|EOpyqaYF_3W+KzT2*a8L4-ovpwcJ>6!*Q^ zd3U>eyJ&! zvO^W^P6@kH!j5E%;FBbOqEGNxA^f=_tbm5PC1q3~$o$Nh+iqCc4GTWWje<`S%fPVX z4Kw{w%G)OFT4bILYmpTmA-U9o8A&Sd3t%U1tzcYU&~4r>%JaJqitr~%No3oZHAZ@S zIb+{o|6RYJ$~m#%Hz`;$Aq z`Qr6onSIY-_xE!7UmiY3d0?5y!GQLnN?gY@Iyi8Jr!nBo_TUcq;75FLEL(=d9j*mH zc7vefee=SZI<#}Mn$`NzTESFRi|S4M;+B=g z{J5@~`zG{6Z$>xOQKL{a)p31%L@)I3VXA|16Ecc=DxXW+C@S3BlqhXnGja@cQ!ko{ zuGn6~9E<6b6ZwLvr(?x^<0JWO5$-xtie@^sWC=EbUR1}+u}lhbLoI=L%EAXX4Xxjx zcE^|X2rt?1D&A9xy$LDQPJjH+Bhb7<>|Mb=vrgeLZ1dEn5IASU>9>LSc^l53a|lAX zXu~lt3T=wQqjhk`drU#L;m#TpBandy0uKZp2s{vYAn-uofxrX*%^vt`^L6hh54{sj z9*Mlx$yoCKDKj*EDtYL+=y85o)5~86czWSkI5)Q|5JMe%7woMw(-0Q^7IplDeCrgb zm|x;gLx)e_kv#l*^3d7y+jjORrV=kCPn_tT1?F>h1O2_xcys%GJb&aLuc$|p53czJ zFp>{O9!9b9qB#euwie@1wfgBZ&Fu%#@VJn`H#mR!2#OmoB@drZKKti&$!9NylhX6a z)0fPvAcIDcL3H}eXmk6v=>2Z{>7B^YVyeK7hgEe?YY0p z9!C2h1Re-H5O^T)K;VJE1Azwu4+I_vJP>#w@Ic^!kJkf|W400cyz|4WaSo5qO`e~g zo`ARlG6`}5BrXHE;oa%!V<0i$947|p?(IyPY?0>AtcxCn(Eyy+!nynNf0>@X0SO!H zS`h1kVeY*vb$l9O%qt7W17N!nfxf1e z2SOVfYx@s{^H3&2K?pn$cp&gV;DNvcfd>K)1Re-H5O^T)!2hxbx?ob32O()K-?zj? zlRo9rUv}xgap|}=5yMPNK!;A@u|}a!i1OwMoz^wa7dmywt`_=9v5uM6b5r`?E=}i= z@_1O`OzIbo)mS>MS)3B-GdPQ}4~1+HvQ5Z2LXs%2ofPXDX-y;VYXXV-uec5p!>264 zE=Cj{Bm9`qsor-AUcHc1K1}!W>zNdMm`vt6-3REtay>25h53I>(7JMW1$xE(9uN}K z2RCe3B`<=N$~Vf1M7$@Skh{COmv!}aEteN<*VA%RGettI`$pj7y}>>|E-)SJ>yVaB zB)SvbjO`J5l9Z8y!Qw>n@1NoLJ#%xmO-#?8tWsEJaT3R#RE6IL273BW-bNRGlc~O+95A`5Z2!r{9FgZ(!^8okIh+ zuxT`#>#$wIR|O9bt9?6m^aE?_mK~7ps!tu(hkgfEo(p)ho8`!BfmO$Xu4Ro(4wL-+ zO@GTlQg-Ci5%?SY5%?RNz<+;1`wpHb!Sm#k^!%pxB+20UEnZ;O^D1~>3U>t0?~X|D zJs5ls2H)S<-}?XU?;H&Jmmf?268pK>pU3S2pnW;|x#aWvh3~1~YjM5%y+MC97#|46 zV_4OgRxth*jK}a#`cL?H3=T><#&@+udEXf7t9o(h9YNBIL-P%D#rwpILvs+5VlKjq zb5z*lAD?0H;^ajd$&bpRy3W5$ovE$|M47nO&YF|JQW>Lq@-=Q8ah@X3CL&DYN0Rf743%MkY0up3%>-X+QV?V3yu;T9Irv9Rl#U< zHbh^6<7;p{42Q7%8AR)G4c~X+_#xpn$Yc@JXY%4%qz2-RQN(Llv?gNYOjaL_gE~X1 z{R4=G<#3YfB`ni@HPWLqi%e>0M0)5UsJ9ehL#;h9{S=Bz>*j@R@>12c|xu!e@U4dEzUdox5arx^lkf=dzQa{f>&W}~$2huY5UVd1Ei%}{Fy zXN_)!BLeNR6Qm?bA2cM?Dm2zo))X2dOF~+Et(uP64dGA3phBy53Aq*|1Ev!_L!tev8eW2`#Vc1!Q z_IYyRHEh3UK9TY~t&?BNrabv|jOKBj{3!F9{|vKwM)Rgl{tQO*uTH$7JWuPyVb;1u zu|qr_hM79q6K^WNx9mn?m=&aVj1z~qo~+m*9uKow<^8PeiD5RIDW3dRM)T%Q{#A_T z%boZf<~3g%hFM11FUZMu78lc1Dts`iIapH^PkCXgo=bb-@v*$=g(KfD zEndoHjoo^7pReKN2ywngV`;+I_%i8nebVr+E>BdsBTOw*$=}Esrrj%+?(~R-Ij^|F z^TIv6U^A%pfGDBr>TE_nX|Aib893bm=BANS3wk!6vR|(gcV4$M&3T>9wCWb&O!x4I zlfW~m_KTBL-8!70Q zdz&*@kBNpgmIhnWEDNiJSr!zBjJ0tCUOO3lm%u5`3$QW+zp^+q^l@mv zR=xP8#Wm9`7$YTUq;LuPNGSukX}L^AHFBfyb`wb>BL#gAX|SELPI2%lMG=NuSg^f{ z|D`CdL+4!vkxN@x;W658+}%S(u0322N*x^VS;4~!VNd&O%K|3>ZTsQ-8H3Evm6O~4W=OgKYt5>}k9x4c}oHV2qUq zsz32a-UF$)7N2w)SDF;|vSrTik-h!`W)DIHt4j7X{&Y;(-zkVxzWe&WF6`F}-o=Q* zV;6;em%z~;dIweh`wn1OFUp@$|B6qzFc^7p2KW7c)MYOVds*01`IL)*u_wX96L7Yd zPvaij1i>1W7Gw})N61qydm2ZZ5R2H$YvzT4yZ%2C_T+!+-!R!SaF<8^7uhi!XTkcD zJ?$^wB3lfccd-X|`7c1C-JZtp6xp)EIS_krm;WnB#5O8^F6D7P+K1lFC!HkDhcw&l zsb73D1|S6DSz1LW{B20UwnOF9xFP+&0`&g};O`d$*^yu00}QX9>}h=Q3{F!(komcC zB72g5ha|gwc^tCKvRPCyVd{?wmddWH6lqI^Lw zXHE7v4`mNjKFPTdA>Sg8#z}7z8Ft{0-WJ@~vs9FCqwwg#K?`x$i^?VbY9ITjg?+ut zz@@T5AN!vstrGC}VGnNmT|V~r;)@M}YKijMZLbM?_jSG|?0Z}Wq>{|~*w6XARpcY( zlC22Y*(E(Y?9``){n2_0y&l94IH=vy`wx?;?O9Cgtn9MnE8;ysX;d!h_?YyvpL46l 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