public inbox for libabigail@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] ctf-reader: Add support to read CTF information from Linux kernel
@ 2022-03-30 15:35 Guillermo E. Martinez
  2022-04-04 22:49 ` Guillermo Martinez
  2022-04-29 14:16 ` [PATCH v2] " Guillermo E. Martinez
  0 siblings, 2 replies; 10+ messages in thread
From: Guillermo E. Martinez @ 2022-03-30 15:35 UTC (permalink / raw)
  To: libabigail

Hello libabigail team,

This patch is meant to extract CTF information from Linux kernel,
it relies on CTF support in both: GNU toolchain and Linux kernel code
using `CONFIG_CTF' in its configuration.

This path depends in:

https://sourceware.org/pipermail/libabigail/2021q4/003994.html

Please take a look and let me know your comments, I'll really appreciate
them.

Kind regards,
Guillermo

This patch is meant to extract ABI information from CTF stored in
Linux kernel build directory it depends on: vmlinux.ctfa file.

In order to generate CTF information in Linux kernel must be able
to support 'make ctf', which cause the compiler to be run with -gctf
emitting CTF information on the kernel.

The target 'ctf' in Linux Makefile generate a 'vmlinux.ctfa', that
will be used for ctf reader in libabigail. 'vmlinux.ctfa' has multiple
'ctf dictionaries' called: CTF archive members one for built-in kernel
modules (`vmlinux') and one for each out-of-tree kernel module organized
in a parent-child hierarchy. In vmlinux.ctfa file there is a CTF archive
member: `shared_ctf' it is a parent dictionary, containing share symbols
and CTF types used by more than one kernel object. These common types
are stored in 'types_map' in ctf reader, ignoring the ctf dictionary name,
CTF API has the machinery to looking for a share type in parent dictionary
referred in a child dictionary. This CTF layout can be dumped by using
objdump tool.

The basic algorithm used to generate the Linux corpus follow:

   1. Looking for: vmlinux, *.ko objects, and vmlinux.ctfa files. The
   first files are used to extract the ELF symbols, and the last one
   contains the CTF type information for non-static variables and
   functions symbols.

   2. `process_ctf_archive' iterates on public symbols for vmlinux and
   its modules, using the name of the symbol, ctf reader search for CTF
   information in its dictionary, if the information was found it
   builds a `var_decl' or `function_decl' depending of `ctf_type_kind'
   result.

This algorithm is also applied to ELF files (exec, dyn, rel), so instead
of iterating on all ctf_types it uses public symbols as main loop.

	* abg-elf-reader-common.h: Include ctf-api.h file.
	(read_and_add_corpus_to_group_from_elf, set_read_context_corpus_group)
	(reset_read_context, set_vmlinux_ctfa_path, dic_type_key): Declare new
	member functions.
	* include/abg-ir.h (environment::debug_format_type): Add new enum type.
	(environment::debug_format_): Add new member variable.
	(environment::{get_debug_format_type,set_debug_format_type): Add new
	member functions.
	* src/abg-ctf-reader.cc: Include map, algorithms header files.
	(read_context::vmlinux_ctfa_path_): Add new member variable to store
	location of `vmlinux.ctfa'.
	(read_context::type_map): Change from unordered_map to std::map storing
	ctf dictionary name as part of the key.
	(read_context::is_elf_exec): Add new member variable.
	(read_context::{cur_corpus_, cur_corpus_group_}): Likewise.
	(read_context::unknown_types_set): Likewise.
	(read_context::{current_corpus_group, main_corpus_from_current_group,
	has_corpus_group, current_corpus_is_main_corpus_from_current_group,
	should_reuse_type_from_corpus_group}): Add new member functions.
	(read_context::{add_unknown_type, lookup_unknown_type, initialize}):
	Likewise.
	(read_context::{add_type, lookup_type}): Add new `ctf_dict_t' type
	argument.
	(ctf_reader::{process_ctf_typedef, process_ctf_base_type,
	process_ctf_function_type, process_ctf_forward_type,
	process_ctf_struct_type, process_ctf_union_type, process_ctf_array_type,
	process_ctf_qualified_type, process_ctf_enum_type}): Add code to `reuse'
	types already registered in main corpus. Replace function calls to the
	new ctf interface. Add verifier to not build types duplicated by
	recursive calling chain.
	(ctf_reader::process_ctf_type): Add code to return immediately if the
	ctf type is unknown. Add unknown types to `unknown_types_set'.
	(ctf_reader::process_ctf_archive): Change comment.
	Add code to iterate over global symbols, searching by symbol name in the
	ctf dictionary using `ctf_lookup_{variable,by_symbol_name}' depending of
	the ELF file type and corpus type, creating a `{var,fuc}_decl' using the
	return type of `ctf_type_kind'.  Also close the ctf dict and call
	`canonicalize_all_types'.
	(slurp_elf_info): Set `is_elf_exec' depending of ELF type.  Also return
	success if corpus origin is Linux and symbol table was read.
	(ctf_reader::read_corpus): Add current corpus.  Set corpus origin to
	`LINUX_KERNEL_BINARY_ORIGIN' or `CTF_ORIGIN'.  Use `is_linux_kernel' to
	verify the ctf reader status, now the ctf archive is 'opened' using
	`ctf_arc{open,bufopen}' depending of corpus origin value,
	`sort_{function,variables}' is call after extract ctf information and
	`ctf_close' is called.
	(read:context::{set_read_context_corpus_group, reset_read_context,
	read_and_add_corpus_to_group_from_elf, set_vmlinux_ctfa_path,
	dic_type_key): Add new member function implementation.
	* src/abg-ir.cc (environment::environment): Add default value
	`DWARF_FORMAT_TYPE' for `debug_format_'.
	(environment::{get_debug_format_type, set_debug_format_type}): Add new
	member function implementation.
	* src/abg-tools-utils.cc: Use `abg-ctf-reader.h' file.  (is_vmlinux):
	Add new argument.
	(find_vmlinux_and_module_paths): Change to use new `is_vmlinux'
	signature.
	(find_vmlinux_path): Add new argument.  Also change to use
	new `is_vmlinux' signature.
	(get_vmlinux_path_from_kernel_dist): Change to use `find_vmlinux_path'
	signature.
	(get_vmlinux_ctfa_path_from_kernel_dist): Add new function definition.
	(build_corpus_group_from_kernel_dist_under): Add conditional use of
	`debug_format_' if it is `CTF_FORMAT_TYPE' looks for `vmlinux.ctfa',
	re-organise the code to process both debug formats:
	`{DWARF,CTF}_FORMAT_TYPE.
	* tools/abidw.cc (main): Use of --ctf argument to set format debug.
	* tests/test-read-ctf.cc: Add new tests to harness.
	* tests/data/test-read-ctf/test-PR27700.abi: New test expected
	  result.
	* tests/data/test-read-ctf/test-anonymous-fields.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-many.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi: Likewise.
	* tests/data/test-read-common/test-PR26568-2.o: Adjust.
	* tests/data/test-read-ctf/test-PR26568-1.o.abi: Likewise.
	* tests/data/test-read-ctf/test-PR26568-2.o.abi: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.c: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.o: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-array-of-pointers.abi: Likewise.
	* tests/data/test-read-ctf/test-callback.abi: Likewise.
	* tests/data/test-read-ctf/test-callback2.abi: Likewise.
	* tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi:
	Likewise.
	* tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi:
	Likewise.
	* tests/data/test-read-ctf/test-dynamic-array.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-ctf.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-symbol.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum.o.abi: Likewise.
	* tests/data/test-read-ctf/test-forward-type-decl.abi: Likewise.
	* tests/data/test-read-ctf/test-functions-declaration.abi: Likewise.
	* tests/data/test-read-ctf/test-list-struct.abi: Likewise.
	* tests/data/test-read-ctf/test0: Likewise.
	* tests/data/test-read-ctf/test0.abi: Likewise.
	* tests/data/test-read-ctf/test0.c: Likewise.
	* tests/data/test-read-ctf/test0.hash.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test5.o.abi: Likewise.
	* tests/data/test-read-ctf/test7.o.abi: Likewise.
	* tests/data/test-read-ctf/test8.o.abi: Likewise.
	* tests/data/test-read-ctf/test9.o.abi: Likewise.
---
 include/abg-ctf-reader.h                      |  19 +
 include/abg-ir.h                              |  14 +
 src/abg-ctf-reader.cc                         | 467 ++++++++++++++----
 src/abg-ir.cc                                 |  17 +-
 src/abg-tools-utils.cc                        | 272 +++++++---
 tests/data/test-read-common/test-PR26568-2.o  | Bin 3048 -> 3488 bytes
 .../test-read-ctf/PR27700/test-PR27700.abi    |   3 +-
 tests/data/test-read-ctf/test-PR26568-1.o.abi |  10 +-
 tests/data/test-read-ctf/test-PR26568-2.o.abi |  22 +-
 tests/data/test-read-ctf/test-PR27700.abi     |  21 +
 .../test-ambiguous-struct-A.o.hash.abi        |   3 +-
 .../test-read-ctf/test-ambiguous-struct-B.c   |   2 +-
 .../test-read-ctf/test-ambiguous-struct-B.o   | Bin 1344 -> 1344 bytes
 .../test-ambiguous-struct-B.o.hash.abi        |   5 +-
 .../test-read-ctf/test-anonymous-fields.o.abi |  33 ++
 .../test-read-ctf/test-array-of-pointers.abi  |   2 +-
 tests/data/test-read-ctf/test-callback.abi    |  30 +-
 tests/data/test-read-ctf/test-callback2.abi   |   2 +-
 .../test-conflicting-type-syms-a.o.hash.abi   |   4 +-
 .../test-conflicting-type-syms-b.o.hash.abi   |   4 +-
 .../test-read-ctf/test-dynamic-array.o.abi    |   2 +-
 tests/data/test-read-ctf/test-enum-ctf.o.abi  |  24 +
 .../test-enum-many-ctf.o.hash.abi             |  69 +++
 .../test-read-ctf/test-enum-many.o.hash.abi   |   6 +-
 .../test-enum-symbol-ctf.o.hash.abi           |  16 +
 .../test-read-ctf/test-enum-symbol.o.hash.abi |   3 +-
 tests/data/test-read-ctf/test-enum.o.abi      |   6 +-
 .../test-read-ctf/test-forward-type-decl.abi  |   2 +-
 .../test-functions-declaration.abi            |   4 +-
 tests/data/test-read-ctf/test-list-struct.abi |   4 +-
 tests/data/test-read-ctf/test0                | Bin 16656 -> 16896 bytes
 tests/data/test-read-ctf/test0.abi            |  30 +-
 tests/data/test-read-ctf/test0.c              |   6 +
 tests/data/test-read-ctf/test0.hash.abi       |  18 +-
 tests/data/test-read-ctf/test1.so.abi         |  11 +-
 tests/data/test-read-ctf/test1.so.hash.abi    |   7 +-
 tests/data/test-read-ctf/test2.so.abi         |   8 +
 tests/data/test-read-ctf/test2.so.hash.abi    |   8 +
 tests/data/test-read-ctf/test3.so.abi         |   4 +
 tests/data/test-read-ctf/test3.so.hash.abi    |   4 +
 tests/data/test-read-ctf/test4.so.abi         |   6 +
 tests/data/test-read-ctf/test4.so.hash.abi    |   6 +
 tests/data/test-read-ctf/test5.o.abi          |  36 +-
 tests/data/test-read-ctf/test7.o.abi          |  43 +-
 tests/data/test-read-ctf/test8.o.abi          |   2 +-
 tests/data/test-read-ctf/test9.o.abi          |   2 +-
 tests/test-read-ctf.cc                        |  20 +-
 tools/abidw.cc                                |   5 +
 48 files changed, 957 insertions(+), 325 deletions(-)
 create mode 100644 tests/data/test-read-ctf/test-PR27700.abi
 create mode 100644 tests/data/test-read-ctf/test-anonymous-fields.o.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-ctf.o.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi

diff --git a/include/abg-ctf-reader.h b/include/abg-ctf-reader.h
index 3343f0d8..827d1bc2 100644
--- a/include/abg-ctf-reader.h
+++ b/include/abg-ctf-reader.h
@@ -19,6 +19,8 @@
 #include "abg-suppression.h"
 #include "abg-elf-reader-common.h"
 
+#include "ctf-api.h"
+
 namespace abigail
 {
 namespace ctf_reader
@@ -32,8 +34,25 @@ create_read_context(const std::string& elf_path,
                     ir::environment *env);
 corpus_sptr
 read_corpus(read_context *ctxt, elf_reader::status& status);
+
 corpus_sptr
 read_corpus(const read_context_sptr &ctxt, elf_reader::status &status);
+
+corpus_sptr
+read_and_add_corpus_to_group_from_elf(read_context*, corpus_group&, elf_reader::status&);
+
+void
+set_read_context_corpus_group(read_context& ctxt, corpus_group_sptr& group);
+
+void
+reset_read_context(read_context_sptr &ctxt,
+                   const std::string&	elf_path,
+                   ir::environment*	environment);
+void
+set_vmlinux_ctfa_path(read_context& ctxt,
+                      const string& filename);
+std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type);
 } // end namespace ctf_reader
 } // end namespace abigail
 
diff --git a/include/abg-ir.h b/include/abg-ir.h
index a2f4e1a7..033e3708 100644
--- a/include/abg-ir.h
+++ b/include/abg-ir.h
@@ -136,7 +136,16 @@ class environment
 public:
   struct priv;
   std::unique_ptr<priv> priv_;
+  /// The possible debug format types. Default is DWARF_FORMAT_TYPE
+  enum debug_format_type
+  {
+    DWARF_FORMAT_TYPE,
+#ifdef WITH_CTF
+    CTF_FORMAT_TYPE,
+#endif
+  };
 
+  debug_format_type debug_format_;
   /// A convenience typedef for a map of canonical types.  The key is
   /// the pretty representation string of a particular type and the
   /// value is the vector of canonical types that have the same pretty
@@ -236,6 +245,11 @@ public:
   uintptr_t
   get_canonical_type_from_type_id(const char*);
 #endif
+  debug_format_type
+  get_debug_format_type() const;
+
+  void
+  set_debug_format_type(debug_format_type d);
 
   friend class class_or_union;
   friend class class_decl;
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index ec6a5c81..b9b3d939 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -16,6 +16,8 @@
 #include <fcntl.h> /* For open(3) */
 #include <iostream>
 #include <memory>
+#include <map>
+#include <algorithm>
 
 #include "ctf-api.h"
 
@@ -56,15 +58,25 @@ public:
   /// be read from the file then this is NULL.
   ctf_archive_t *ctfa;
 
+  /// The name of the vmlinux file from which the CTF archive got
+  /// extracted.
+  string vmlinux_ctfa_path_;
+
   /// A map associating CTF type ids with libabigail IR types.  This
   /// is used to reuse already generated types.
-  unordered_map<ctf_id_t,type_base_sptr> types_map;
+  std::map<std::string,type_base_sptr> types_map;
+
+  /// A set associating unknown CTF type ids
+  std::set<ctf_id_t> unknown_types_set;
 
   /// libelf handler for the ELF file from which we read the CTF data,
   /// and the corresponding file descriptor.
   Elf *elf_handler;
   int elf_fd;
 
+  /// set when ELF is ET_EXEC
+  bool is_elf_exec;
+
   /// The symtab read from the ELF file.
   symtab_reader::symtab_sptr symtab;
 
@@ -74,26 +86,109 @@ public:
   ctf_sect_t symtab_sect;
   ctf_sect_t strtab_sect;
 
+  corpus_sptr			cur_corpus_;
+  corpus_group_sptr		cur_corpus_group_;
+
+  /// Getter of the current corpus group being constructed.
+  ///
+  /// @return current the current corpus being constructed, if any, or
+  /// nil.
+  const corpus_group_sptr
+  current_corpus_group() const
+  {return cur_corpus_group_;}
+
+  /// Test if there is a corpus group being built.
+  ///
+  /// @return if there is a corpus group being built, false otherwise.
+  bool
+  has_corpus_group() const
+  {return bool(cur_corpus_group_);}
+
+  /// Return the main corpus from the current corpus group, if any.
+  ///
+  /// @return the main corpus of the current corpus group, if any, nil
+  /// if no corpus group is being constructed.
+  corpus_sptr
+  main_corpus_from_current_group()
+  {
+    if (cur_corpus_group_)
+      return cur_corpus_group_->get_main_corpus();
+    return corpus_sptr();
+  }
+
+  /// Test if the current corpus being built is the main corpus of the
+  /// current corpus group.
+  ///
+  /// @return return true iff the current corpus being built is the
+  /// main corpus of the current corpus group.
+  bool
+  current_corpus_is_main_corpus_from_current_group()
+  {
+    corpus_sptr main_corpus = main_corpus_from_current_group();
+
+    if (main_corpus && main_corpus.get() == cur_corpus_.get())
+      return true;
+
+    return false;
+  }
+
+  /// Return true if the current corpus is part of a corpus group
+  /// being built and if it's not the main corpus of the group.
+  ///
+  /// For instance, this would return true if we are loading a linux
+  /// kernel *module* that is part of the current corpus group that is
+  /// being built.  In this case, it means we should re-use types
+  /// coming from the "vmlinux" binary that is the main corpus of the
+  /// group.
+  ///
+  /// @return the corpus group the current corpus belongs to, if the
+  /// current corpus is part of a corpus group being built. Nil otherwise.
+  corpus_sptr
+  should_reuse_type_from_corpus_group()
+  {
+    if (has_corpus_group())
+      if (corpus_sptr main_corpus = main_corpus_from_current_group())
+	if (!current_corpus_is_main_corpus_from_current_group())
+	  return current_corpus_group();
+
+    return corpus_sptr();
+  }
+
   /// Associate a given CTF type ID with a given libabigail IR type.
-  void add_type(ctf_id_t ctf_type, type_base_sptr type)
+  void add_type(ctf_dict_t *dic, ctf_id_t ctf_type, type_base_sptr type)
   {
-    types_map.insert(std::make_pair(ctf_type, type));
+    string key = dic_type_key(dic, ctf_type);
+    types_map.insert(std::make_pair(key, type));
+  }
+
+  /// Insert a given CTF unknown type ID.
+  ///
+  /// @param ctf_type the unknown type ID to be added.
+  void add_unknown_type(ctf_id_t ctf_type)
+  {
+    unknown_types_set.insert(ctf_type);
   }
 
   /// Lookup a given CTF type ID in the types map.
   ///
   /// @param ctf_type the type ID of the type to lookup.
-  type_base_sptr lookup_type(ctf_id_t ctf_type)
+  type_base_sptr lookup_type(ctf_dict_t *dic, ctf_id_t ctf_type)
   {
     type_base_sptr result;
+    std::string key = dic_type_key(dic, ctf_type);
 
-    auto search = types_map.find(ctf_type);
+    auto search = types_map.find(key);
     if (search != types_map.end())
       result = search->second;
 
     return result;
   }
 
+  /// Lookup a given CTF unknown type ID in the unknown set.
+  /// @param ctf_type the unknown type ID to lookup.
+  bool lookup_unknown_type(ctf_id_t ctf_type)
+  { return unknown_types_set.find(ctf_type) != unknown_types_set.end(); }
+
   /// Canonicalize all the types stored in the types map.
   void canonicalize_all_types(void)
   {
@@ -105,19 +200,22 @@ public:
   ///
   /// @param elf_path the path to the ELF file.
   read_context(const string& elf_path, ir::environment *env)
+  {
+    initialize(elf_path, env);
+  }
+
+  void initialize(const string& elf_path, ir::environment *env)
   {
     types_map.clear();
     filename = elf_path;
     ir_env = env;
     elf_handler = NULL;
     elf_fd = -1;
+    is_elf_exec = false;
     ctfa = NULL;
-  }
-
-  /// Destructor of the @ref read_context type.
-  ~read_context()
-  {
-    ctf_close(ctfa);
+    vmlinux_ctfa_path_ = "";
+    symtab.reset();
+    cur_corpus_group_.reset();
   }
 }; // end class read_context.
 
@@ -153,13 +251,18 @@ process_ctf_typedef(read_context *ctxt,
     return result;
 
   const char *typedef_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+  if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+    if (result = lookup_typedef_type(typedef_name, *corp))
+      return result;
+
   type_base_sptr utype = lookup_type(ctxt, corp, tunit,
                                      ctf_dictionary, ctf_utype);
 
   if (!utype)
     return result;
 
-  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_dictionary,
+                                                                ctf_type));
   if (result)
     return result;
 
@@ -180,7 +283,7 @@ process_ctf_typedef(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -225,9 +328,20 @@ process_ctf_base_type(read_context *ctxt,
       type_base_sptr void_type = ctxt->ir_env->get_void_type();
       decl_base_sptr type_declaration = get_type_declaration(void_type);
       result = is_type_decl(type_declaration);
+      canonicalize(result);
     }
   else
     {
+      if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+        {
+          string normalized_type_name = type_name;
+          integral_type int_type;
+          if (parse_integral_type(type_name, int_type))
+            normalized_type_name = int_type.to_string();
+          if (result = lookup_basic_type(normalized_type_name, *corp))
+            return result;
+        }
+
       result = lookup_basic_type(type_name, *corp);
       if (!result)
         result.reset(new type_decl(ctxt->ir_env,
@@ -242,7 +356,7 @@ process_ctf_base_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -303,7 +417,8 @@ process_ctf_function_type(read_context *ctxt,
       function_parms.push_back(parm);
     }
 
-  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_dictionary,
+                                                                 ctf_type));
   if (result)
     return result;
 
@@ -319,7 +434,7 @@ process_ctf_function_type(read_context *ctxt,
       result->set_is_artificial(true);
       decl_base_sptr function_type_decl = get_type_declaration(result);
       add_decl_to_scope(function_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -411,6 +526,11 @@ process_ctf_forward_type(read_context *ctxt,
     }
   else
     {
+      if (!type_is_anonymous)
+        if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+          if (result = lookup_class_type(type_name, *corp))
+            return is_type(result);
+
       class_decl_sptr
        struct_fwd(new class_decl(ctxt->ir_env, type_name,
                                  /*alignment=*/0, /*size=*/0,
@@ -426,7 +546,7 @@ process_ctf_forward_type(read_context *ctxt,
     return is_type(result);
 
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, is_type(result));
+  ctxt->add_type(ctf_dictionary, ctf_type, is_type(result));
 
   return is_type(result);
 }
@@ -450,9 +570,14 @@ process_ctf_struct_type(read_context *ctxt,
 {
   class_decl_sptr result;
   std::string struct_type_name = ctf_type_name_raw(ctf_dictionary,
-                                                 ctf_type);
+                                                   ctf_type);
   bool struct_type_is_anonymous = (struct_type_name == "");
 
+  if (!struct_type_is_anonymous)
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_class_type(struct_type_name, *corp))
+        return result;
+
   /* The libabigail IR encodes C struct types in `class' IR nodes.  */
   result.reset(new class_decl(ctxt->ir_env,
                               struct_type_name,
@@ -471,7 +596,7 @@ process_ctf_struct_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, result);
+  ctxt->add_type(ctf_dictionary, ctf_type, result);
 
   /* Now add the struct members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
@@ -504,6 +629,11 @@ process_ctf_union_type(read_context *ctxt,
                                                    ctf_type);
   bool union_type_is_anonymous = (union_type_name == "");
 
+  if (!union_type_is_anonymous)
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_union_type(union_type_name, *corp))
+        return result;
+
   /* Create the corresponding libabigail union IR node.  */
   result.reset(new union_decl(ctxt->ir_env,
                                 union_type_name,
@@ -520,7 +650,7 @@ process_ctf_union_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, result);
+  ctxt->add_type(ctf_dictionary, ctf_type, result);
 
   /* Now add the union members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
@@ -576,7 +706,8 @@ process_ctf_array_type(read_context *ctxt,
   if (!index_type)
     return result;
 
-  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_dictionary,
+                                                                  ctf_type));
   if (result)
     return result;
 
@@ -615,7 +746,7 @@ process_ctf_array_type(read_context *ctxt,
     {
       decl_base_sptr array_type_decl = get_type_declaration(result);
       add_decl_to_scope(array_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -644,6 +775,11 @@ process_ctf_qualified_type(read_context *ctxt,
   if (!utype)
     return result;
 
+  result = dynamic_pointer_cast<type_base>(ctxt->lookup_type(ctf_dictionary,
+                                                             ctf_type));
+  if (result)
+    return result;
+
   qualified_type_def::CV qualifiers = qualified_type_def::CV_NONE;
   if (type_kind == CTF_K_CONST)
     qualifiers |= qualified_type_def::CV_CONST;
@@ -660,7 +796,7 @@ process_ctf_qualified_type(read_context *ctxt,
     {
       decl_base_sptr qualified_type_decl = get_type_declaration(result);
       add_decl_to_scope(qualified_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -694,7 +830,8 @@ process_ctf_pointer_type(read_context *ctxt,
   if (!target_type)
     return result;
 
-  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_dictionary,
+                                                                    ctf_type));
   if (result)
     return result;
 
@@ -705,7 +842,7 @@ process_ctf_pointer_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -728,6 +865,12 @@ process_ctf_enum_type(read_context *ctxt,
                       ctf_id_t ctf_type)
 {
   enum_type_decl_sptr result;
+  std::string enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+
+  if (!enum_name.empty())
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_enum_type(enum_name, *corp))
+        return result;
 
   /* Build a signed integral type for the type of the enumerators, aka
      the underlying type.  The size of the enumerators in bytes is
@@ -761,13 +904,12 @@ process_ctf_enum_type(read_context *ctxt,
       return result;
     }
 
-  const char *enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
-  result.reset(new enum_type_decl(enum_name, location(),
-                                  utype, enms, enum_name));
+  result.reset(new enum_type_decl(enum_name.c_str(), location(),
+                                  utype, enms, enum_name.c_str()));
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -796,7 +938,10 @@ process_ctf_type(read_context *ctxt,
   int type_kind = ctf_type_kind(ctf_dictionary, ctf_type);
   type_base_sptr result;
 
-  if ((result = ctxt->lookup_type(ctf_type)))
+  if (ctxt->lookup_unknown_type(ctf_type))
+    return nullptr;
+
+  if ((result = ctxt->lookup_type(ctf_dictionary, ctf_type)))
     return result;
 
   switch (type_kind)
@@ -880,7 +1025,10 @@ process_ctf_type(read_context *ctxt,
     }
 
   if (!result)
-    fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+    {
+      fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+      ctxt->add_unknown_type(ctf_type);
+    }
 
   return result;
 }
@@ -904,7 +1052,7 @@ lookup_type(read_context *ctxt, corpus_sptr corp,
             translation_unit_sptr tunit, ctf_dict_t *ctf_dictionary,
             ctf_id_t ctf_type)
 {
-  type_base_sptr result = ctxt->lookup_type(ctf_type);
+  type_base_sptr result = ctxt->lookup_type(ctf_dictionary, ctf_type);
 
   if (!result)
     result = process_ctf_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
@@ -912,8 +1060,8 @@ lookup_type(read_context *ctxt, corpus_sptr corp,
 }
 
 /// Process a CTF archive and create libabigail IR for the types,
-/// variables and function declarations found in the archive.  The IR
-/// is added to the given corpus.
+/// variables and function declarations found in the archive, iterating
+/// over public symbols.  The IR is added to the given corpus.
 ///
 /// @param ctxt the read context containing the CTF archive to
 /// process.
@@ -928,43 +1076,49 @@ process_ctf_archive(read_context *ctxt, corpus_sptr corp)
   ir_translation_unit->set_language(translation_unit::LANG_C);
   corp->add(ir_translation_unit);
 
-  /* Iterate over the CTF dictionaries in the archive.  */
   int ctf_err;
   ctf_dict_t *ctf_dict;
-  ctf_next_t *dict_next = NULL;
-  const char *archive_name;
+  const auto symtab = ctxt->symtab;
+  symtab_reader::symtab_filter filter = symtab->make_filter();
+  filter.set_public_symbols();
+  std::string dict_name;
 
-  while ((ctf_dict = ctf_archive_next(ctxt->ctfa, &dict_next, &archive_name,
-                                      0 /* skip_parent */, &ctf_err)) != NULL)
+  if (corp->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN)
     {
-      /* Iterate over the CTF types stored in this archive.  */
-      ctf_id_t ctf_type;
-      int type_flag;
-      ctf_next_t *type_next = NULL;
+      tools_utils::base_name(ctxt->filename, dict_name);
 
-      while ((ctf_type = ctf_type_next(ctf_dict, &type_next, &type_flag,
-                                       1 /* want_hidden */)) != CTF_ERR)
-        {
-          process_ctf_type(ctxt, corp, ir_translation_unit,
-                            ctf_dict, ctf_type);
-        }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_type_next\n");
+      if (dict_name != "vmlinux")
+        // remove .ko suffix
+        dict_name.erase(dict_name.length() - 3, 3);
 
-      /* Canonicalize all the types generated above.  This must be
-         done "a posteriori" because the processing of types may
-         require other related types to not be already
-         canonicalized.  */
-      ctxt->canonicalize_all_types();
+      std::replace(dict_name.begin(), dict_name.end(), '-', '_');
+    }
 
-      /* Iterate over the CTF variables stored in this archive.  */
+  if ((ctf_dict = ctf_dict_open(ctxt->ctfa,
+                                dict_name.empty() ? NULL : dict_name.c_str(),
+                                &ctf_err)) == NULL)
+    {
+      fprintf(stderr, "ERROR dictionary not found\n");
+      abort();
+    }
+
+  for (const auto& symbol : symtab_reader::filtered_symtab(*symtab, filter))
+    {
+      std::string sym_name = symbol->get_name();
       ctf_id_t ctf_var_type;
-      ctf_next_t *var_next = NULL;
-      const char *var_name;
 
-      while ((ctf_var_type = ctf_variable_next(ctf_dict, &var_next, &var_name))
-             != CTF_ERR)
+      if (corp->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN
+          || ctxt->is_elf_exec)
+        ctf_var_type= ctf_lookup_variable (ctf_dict, sym_name.c_str());
+      else
+        ctf_var_type = ctf_lookup_by_symbol_name(ctf_dict, sym_name.c_str());
+
+      if (ctf_var_type == (ctf_id_t) -1)
+        continue;
+
+      if (ctf_type_kind (ctf_dict, ctf_var_type) != CTF_K_FUNCTION)
         {
+          const char *var_name = sym_name.c_str();
           type_base_sptr var_type = lookup_type(ctxt, corp, ir_translation_unit,
                                                 ctf_dict, ctf_var_type);
           if (!var_type)
@@ -977,50 +1131,38 @@ process_ctf_archive(read_context *ctxt, corpus_sptr corp)
                                              location(),
                                              var_name));
 
+          var_declaration->set_symbol(symbol);
           add_decl_to_scope(var_declaration,
-                             ir_translation_unit->get_global_scope());
+                            ir_translation_unit->get_global_scope());
         }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_variable_next\n");
-
-      /* Iterate over the CTF functions stored in this archive.  */
-      ctf_next_t *func_next = NULL;
-      const char *func_name = NULL;
-      ctf_id_t ctf_sym;
+      else
+        {
+          const char *func_name = sym_name.c_str();
+          ctf_id_t ctf_sym = ctf_var_type;
+          type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
+                                                 ctf_dict, ctf_sym);
+          if (!func_type)
+            /* Ignore function if its type can't be sorted out.  */
+            continue;
 
-      while ((ctf_sym = ctf_symbol_next(ctf_dict, &func_next, &func_name,
-                                        1 /* functions symbols only */) != CTF_ERR))
-      {
-        ctf_id_t ctf_func_type = ctf_lookup_by_name(ctf_dict, func_name);
-        type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
-                                               ctf_dict, ctf_func_type);
-        if (!func_type)
-          /* Ignore function if its type can't be sorted out.  */
-          continue;
-
-        elf_symbols func_elf_symbols = ctxt->symtab->lookup_symbol(func_name);
-        if (func_elf_symbols.size() == 0
-            || func_elf_symbols[0]->get_binding() == elf_symbol::LOCAL_BINDING)
-          /* Ignore local functions.  */
-          continue;
-
-        function_decl_sptr func_declaration;
-        func_declaration.reset(new function_decl(func_name,
-                                                 func_type,
-                                                 0 /* is_inline */,
-                                                 location()));
-
-        add_decl_to_scope(func_declaration,
-                           ir_translation_unit->get_global_scope());
-      }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_symbol_next\n");
+          function_decl_sptr func_declaration;
+          func_declaration.reset(new function_decl(func_name,
+                                                   func_type,
+                                                   0 /* is_inline */,
+                                                   location()));
 
-      ctf_dict_close(ctf_dict);
+          func_declaration->set_symbol(symbol);
+          add_decl_to_scope(func_declaration,
+                            ir_translation_unit->get_global_scope());
+        }
     }
-  if (ctf_err != ECTF_NEXT_END)
-    fprintf(stderr, "ERROR from ctf_archive_next\n");
 
+  ctf_dict_close(ctf_dict);
+  /* Canonicalize all the types generated above.  This must be
+     done "a posteriori" because the processing of types may
+     require other related types to not be already
+     canonicalized.  */
+  ctxt->canonicalize_all_types();
 }
 
 /// Open the ELF file described by the given read context.
@@ -1104,6 +1246,7 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
   /* Set the ELF architecture.  */
   GElf_Ehdr eh_mem;
   GElf_Ehdr *ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem);
+  ctxt->is_elf_exec = (ehdr->e_type == ET_EXEC);
   corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
 
   /* Read the symtab from the ELF file and set it in the corpus.  */
@@ -1112,6 +1255,9 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
                                 0 /* No suppressions.  */);
   corp->set_symtab(ctxt->symtab);
 
+  if (corp->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN)
+    return 1;
+
   /* Get the raw ELF section contents for libctf.  */
   Elf_Scn *ctf_scn = elf_helpers::find_section(ctxt->elf_handler, ".ctf", SHT_PROGBITS);
   Elf_Scn *symtab_scn = elf_helpers::find_symbol_table_section(ctxt->elf_handler);
@@ -1158,6 +1304,7 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
   corpus_sptr corp
     = std::make_shared<corpus>(ctxt->ir_env, ctxt->filename);
 
+  ctxt->cur_corpus_ = corp;
   /* Be optimist.  */
   status = elf_reader::STATUS_OK;
 
@@ -1168,27 +1315,45 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
       return corp;
     }
 
+  bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
   /* Set some properties of the corpus first.  */
-  corp->set_origin(corpus::CTF_ORIGIN);
-  if (!slurp_elf_info(ctxt, corp))
+  if (is_linux_kernel)
+    corp->set_origin(corpus::LINUX_KERNEL_BINARY_ORIGIN);
+  else
+    corp->set_origin(corpus::CTF_ORIGIN);
+
+  if (ctxt->cur_corpus_group_)
+    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
+
+  if (!slurp_elf_info(ctxt, corp) && !is_linux_kernel)
     {
       status = elf_reader::STATUS_NO_SYMBOLS_FOUND;
       return corp;
     }
 
-  /* Build the ctfa from the contents of the relevant ELF sections,
-     and process the CTF archive in the read context, if any.
-     Information about the types, variables, functions, etc contained
-     in the archive are added to the given corpus.  */
   int errp;
-  ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
-                               &ctxt->strtab_sect, &errp);
+  if (corp->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN)
+     ctxt->ctfa = ctf_arc_open(ctxt->vmlinux_ctfa_path_.c_str(), &errp);
+  else
+    /* Build the ctfa from the contents of the relevant ELF sections,
+       and process the CTF archive in the read context, if any.
+       Information about the types, variables, functions, etc contained
+       in the archive are added to the given corpus.  */
+    ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
+                                 &ctxt->strtab_sect, &errp);
+
+  ctxt->ir_env->canonicalization_is_done(false);
   if (ctxt->ctfa == NULL)
     status = elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
   else
     process_ctf_archive(ctxt, corp);
 
+  ctxt->ir_env->canonicalization_is_done(true);
+  ctxt->cur_corpus_->sort_functions();
+  ctxt->cur_corpus_->sort_variables();
+
   /* Cleanup and return.  */
+  ctf_close(ctxt->ctfa);
   close_elf_handler(ctxt);
   return corp;
 }
@@ -1207,5 +1372,93 @@ corpus_sptr
 read_corpus(const read_context_sptr &ctxt, elf_reader::status &status)
 {return read_corpus(ctxt.get(), status);}
 
+/// Set the @ref corpus_group being created to the current read context.
+///
+/// @param ctxt the read_context to consider.
+///
+/// @param group the @ref corpus_group to set.
+void
+set_read_context_corpus_group(read_context& ctxt,
+                              corpus_group_sptr& group)
+{
+  ctxt.cur_corpus_group_ = group;
+}
+//
+/// Read a corpus and add it to a given @ref corpus_group.
+///
+/// @param ctxt the reading context to consider.
+///
+/// @param group the @ref corpus_group to add the new corpus to.
+///
+/// @param status output parameter. The status of the read.  It is set
+/// by this function upon its completion.
+corpus_sptr
+read_and_add_corpus_to_group_from_elf(read_context* ctxt,
+                                      corpus_group& group,
+                                      elf_reader::status& status)
+{
+  corpus_sptr result;
+  corpus_sptr corp = read_corpus(ctxt, status);
+  if (status & elf_reader::STATUS_OK)
+    {
+      if (!corp->get_group())
+        group.add_corpus(corp);
+      result = corp;
+    }
+
+  return result;
+}
+
+/// Re-initialize a read_context so that it can re-used to read
+/// another binary.
+///
+/// @param ctxt the context to re-initialize.
+///
+/// @param elf_path the path to the elf file the context is to be used
+/// for.
+///
+/// @param environment the environment used by the current context.
+/// This environment contains resources needed by the reader and by
+/// the types and declarations that are to be created later.  Note
+/// that ABI artifacts that are to be compared all need to be created
+/// within the same environment.
+///
+/// Please also note that the life time of this environment object
+/// must be greater than the life time of the resulting @ref
+/// read_context the context uses resources that are allocated in the
+/// environment.
+void
+reset_read_context(read_context_sptr	&ctxt,
+                   const std::string&	 elf_path,
+                   ir::environment*	 environment)
+{
+  if (ctxt)
+    ctxt->initialize(elf_path, environment);
+}
+
+/// Set the @ref filename being assigned to the current read context.
+///
+/// @param ctxt the read_context to consider.
+///
+/// @param filename the @ref vmlinux CTFA filename to set.
+void
+set_vmlinux_ctfa_path(read_context& ctxt,
+                      const string& filename)
+{
+  ctxt.vmlinux_ctfa_path_ = filename;
+}
+
+std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type)
+{
+  std::stringstream key;
+
+  if (ctf_type_isparent (dic, ctf_type))
+    key << std::hex << ctf_type;
+  else
+    key << std::hex << ctf_type << '-' << ctf_cuname(dic);
+  return key.str();
+}
+
 } // End of namespace ctf_reader
 } // End of namespace abigail
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 0ef5e8b2..5eebcfa3 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -3165,7 +3165,8 @@ typedef unordered_map<interned_string,
 
 /// Default constructor of the @ref environment type.
 environment::environment()
-  :priv_(new priv)
+  :priv_(new priv),
+  debug_format_(DWARF_FORMAT_TYPE)
 {}
 
 /// Destructor for the @ref environment type.
@@ -3779,6 +3780,20 @@ environment::get_canonical_type_from_type_id(const char* type_id)
   return 0;
 }
 #endif
+
+/// Getter of the debug format of the source.
+///
+/// @return the debug format of the source.
+environment::debug_format_type
+environment::get_debug_format_type() const
+{return debug_format_;}
+
+/// Setter of the debug format of the source.
+///
+/// @param d the new debug format.
+void
+environment::set_debug_format_type(environment::debug_format_type d)
+{debug_format_ = d;}
 // </environment stuff>
 
 // <type_or_decl_base stuff>
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index e94c3003..b73786a8 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -44,6 +44,9 @@
 #include <sstream>
 
 #include "abg-dwarf-reader.h"
+#ifdef WITH_CTF
+#include "abg-ctf-reader.h"
+#endif
 #include "abg-internal.h"
 #include "abg-regex.h"
 
@@ -2234,9 +2237,11 @@ load_generate_apply_suppressions(dwarf_reader::read_context &read_ctxt,
 ///
 /// @param entry the FTSENT to consider.
 ///
+/// @param filename the name of file.
+///
 /// @return true iff @p entry is for a vmlinux binary.
 static bool
-is_vmlinux(const FTSENT *entry)
+is_vmlinux(const FTSENT *entry, const string &filename)
 {
   if (entry == NULL
       || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
@@ -2246,7 +2251,7 @@ is_vmlinux(const FTSENT *entry)
 
   string fname = entry->fts_name;
 
-  if (fname == "vmlinux")
+  if (fname == filename)
     {
       string dirname;
       dir_name(entry->fts_path, dirname);
@@ -2317,7 +2322,7 @@ find_vmlinux_and_module_paths(const string&	from,
 	  continue;
 	}
 
-      if (!found_vmlinux && is_vmlinux(entry))
+      if (!found_vmlinux && is_vmlinux(entry, "vmlinux"))
 	{
 	  vmlinux_path = entry->fts_path;
 	  found_vmlinux = true;
@@ -2337,10 +2342,13 @@ find_vmlinux_and_module_paths(const string&	from,
 ///
 /// @param vmlinux_path output parameter
 ///
+/// @param vmlinux_name output parameter
+///
 /// return true iff the vmlinux binary was found
 static bool
 find_vmlinux_path(const string&	from,
-		  string		&vmlinux_path)
+		  string		&vmlinux_path,
+		  const string		&vmlinux_name)
 {
   char* path[] = {const_cast<char*>(from.c_str()), 0};
 
@@ -2359,7 +2367,7 @@ find_vmlinux_path(const string&	from,
 	  continue;
 	}
 
-      if (!found_vmlinux && is_vmlinux(entry))
+      if (!found_vmlinux && is_vmlinux(entry, vmlinux_name))
 	{
 	  vmlinux_path = entry->fts_path;
 	  found_vmlinux = true;
@@ -2456,12 +2464,37 @@ get_vmlinux_path_from_kernel_dist(const string&	from,
     dist_root += "/lib/modules";
 
   bool found = false;
-  if (find_vmlinux_path(dist_root, vmlinux_path))
+  if (find_vmlinux_path(dist_root, vmlinux_path, "vmlinux"))
     found = true;
 
   return found;
 }
 
+/// Get the paths of the CTF vmlinux archive under given directory.
+///
+/// @param from the directory under which to look for.
+///
+/// @param vmlinux_path output parameter.  The path of the CTF vmlinux
+/// binary that was found.
+///
+/// @return true if at least the path to the vmlinux.ctfa binary was found.
+#ifdef WITH_CTF
+bool
+get_vmlinux_ctfa_path_from_kernel_dist(const string& from,
+                                       string& vmlinux_ctfa_path)
+{
+  if (!dir_exists(from))
+    return false;
+
+  string dist_root = from;
+  bool found = false;
+  if (find_vmlinux_path(dist_root, vmlinux_ctfa_path, "vmlinux.ctfa"))
+    found = true;
+
+  return found;
+}
+#endif
+
 /// Get the paths of the vmlinux and kernel module binaries under
 /// given directory.
 ///
@@ -2543,12 +2576,21 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
   t.start();
   bool got_binary_paths =
     get_binary_paths_from_kernel_dist(root, debug_info_root, vmlinux, modules);
+#ifdef WITH_CTF
+  string vmlinux_ctfa;
+  if (got_binary_paths &&
+      env->get_debug_format_type() == environment::CTF_FORMAT_TYPE)
+    {
+      got_binary_paths = get_vmlinux_ctfa_path_from_kernel_dist(root, vmlinux_ctfa);
+      ABG_ASSERT(!vmlinux_ctfa.empty());
+    }
+#endif
+
   t.stop();
 
   if (verbose)
     std::cerr << "DONE: " << t << "\n";
 
-  dwarf_reader::read_context_sptr ctxt;
   if (got_binary_paths)
     {
       shared_ptr<char> di_root =
@@ -2558,81 +2600,149 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
       di_roots.push_back(&di_root_ptr);
       abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
       corpus_group_sptr group;
-      if (!vmlinux.empty())
-	{
-	  ctxt =
-	    dwarf_reader::create_read_context(vmlinux, di_roots ,env.get(),
-					      /*read_all_types=*/false,
-					      /*linux_kernel_mode=*/true);
-	  dwarf_reader::set_do_log(*ctxt, verbose);
-
-	  t.start();
-	  load_generate_apply_suppressions(*ctxt, suppr_paths,
-					   kabi_wl_paths, supprs);
-	  t.stop();
-
-	  if (verbose)
-	    std::cerr << "loaded white list and generated suppr spec in: "
-		      << t
-		      << "\n";
-
-	  group.reset(new corpus_group(env.get(), root));
-
-	  set_read_context_corpus_group(*ctxt, group);
-
-	  if (verbose)
-	    std::cerr << "reading kernel binary '"
-		      << vmlinux << "' ...\n" << std::flush;
-
-	  // Read the vmlinux corpus and add it to the group.
-	  t.start();
-	  read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
-	  t.stop();
-
-	  if (verbose)
-	    std::cerr << vmlinux
-		      << " reading DONE:"
-		      << t << "\n";
-	}
 
-      if (!group->is_empty())
-	{
-	  // Now add the corpora of the modules to the corpus group.
-	  int total_nb_modules = modules.size();
-	  int cur_module_index = 1;
-	  for (vector<string>::const_iterator m = modules.begin();
-	       m != modules.end();
-	       ++m, ++cur_module_index)
-	    {
-	      if (verbose)
-		std::cerr << "reading module '"
-			  << *m << "' ("
-			  << cur_module_index
-			  << "/" << total_nb_modules
-			  << ") ... " << std::flush;
-
-	      reset_read_context(ctxt, *m, di_roots, env.get(),
-				 /*read_all_types=*/false,
-				 /*linux_kernel_mode=*/true);
-
-	      load_generate_apply_suppressions(*ctxt, suppr_paths,
-					       kabi_wl_paths, supprs);
-
-	      set_read_context_corpus_group(*ctxt, group);
-
-	      t.start();
-	      read_and_add_corpus_to_group_from_elf(*ctxt,
-						    *group, status);
-	      t.stop();
-	      if (verbose)
-		std::cerr << "module '"
-			  << *m
-			  << "' reading DONE: "
-			  << t << "\n";
-	    }
-
-	  result = group;
-	}
+      if (env->get_debug_format_type() == environment::DWARF_FORMAT_TYPE)
+        {
+          dwarf_reader::read_context_sptr ctxt;
+          if (!vmlinux.empty())
+            {
+              ctxt =
+               dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
+                                                 /*read_all_types=*/false,
+                                                 /*linux_kernel_mode=*/true);
+              dwarf_reader::set_do_log(*ctxt, verbose);
+
+              t.start();
+              load_generate_apply_suppressions(*ctxt, suppr_paths,
+                                               kabi_wl_paths, supprs);
+              t.stop();
+
+              if (verbose)
+                std::cerr << "loaded white list and generated suppr spec in: "
+                 << t
+                 << "\n";
+
+              group.reset(new corpus_group(env.get(), root));
+
+              set_read_context_corpus_group(*ctxt, group);
+
+              if (verbose)
+                std::cerr << "reading kernel binary '"
+                 << vmlinux << "' ...\n" << std::flush;
+
+              // Read the vmlinux corpus and add it to the group.
+              t.start();
+              read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
+              t.stop();
+
+              if (verbose)
+                std::cerr << vmlinux
+                 << " reading DONE:"
+                 << t << "\n";
+            }
+
+          if (!group->is_empty())
+            {
+              // Now add the corpora of the modules to the corpus group.
+              int total_nb_modules = modules.size();
+              int cur_module_index = 1;
+              for (vector<string>::const_iterator m = modules.begin();
+                   m != modules.end();
+                   ++m, ++cur_module_index)
+                {
+                  if (verbose)
+                    std::cerr << "reading module '"
+                     << *m << "' ("
+                     << cur_module_index
+                     << "/" << total_nb_modules
+                     << ") ... " << std::flush;
+
+                  reset_read_context(ctxt, *m, di_roots, env.get(),
+                                     /*read_all_types=*/false,
+                                     /*linux_kernel_mode=*/true);
+
+                  load_generate_apply_suppressions(*ctxt, suppr_paths,
+                                                   kabi_wl_paths, supprs);
+
+                  set_read_context_corpus_group(*ctxt, group);
+
+                  t.start();
+                  read_and_add_corpus_to_group_from_elf(*ctxt,
+                                                        *group, status);
+                  t.stop();
+                  if (verbose)
+                    std::cerr << "module '"
+                     << *m
+                     << "' reading DONE: "
+                     << t << "\n";
+                }
+
+              result = group;
+            }
+        }
+#ifdef WITH_CTF
+      else if (env->get_debug_format_type() == environment::CTF_FORMAT_TYPE)
+        {
+          ctf_reader::read_context_sptr ctxt;
+          if (!vmlinux.empty())
+            {
+              ctxt =
+               ctf_reader::create_read_context(vmlinux, env.get());
+              set_vmlinux_ctfa_path(*ctxt, vmlinux_ctfa);
+
+              group.reset(new corpus_group(env.get(), root));
+              set_read_context_corpus_group(*ctxt, group);
+
+              if (verbose)
+                std::cerr << "reading kernel binary '"
+                 << vmlinux << "' ...\n" << std::flush;
+
+              // Read the vmlinux corpus and add it to the group.
+              t.start();
+              read_and_add_corpus_to_group_from_elf(ctxt.get(), *group, status);
+              t.stop();
+
+              if (verbose)
+                std::cerr << vmlinux
+                 << " reading DONE:"
+                 << t << "\n";
+            }
+
+           if (!group->is_empty())
+             {
+               // Now add the corpora of the modules to the corpus group.
+               int total_nb_modules = modules.size();
+               int cur_module_index = 1;
+               for (vector<string>::const_iterator m = modules.begin();
+                    m != modules.end();
+                    ++m, ++cur_module_index)
+                 {
+                   if (verbose)
+                     std::cerr << "reading module '"
+                      << *m << "' ("
+                      << cur_module_index
+                      << "/" << total_nb_modules
+                      << ") ... " << std::flush;
+
+                   reset_read_context(ctxt, *m, env.get());
+                   set_vmlinux_ctfa_path(*ctxt, vmlinux_ctfa);
+                   set_read_context_corpus_group(*ctxt, group);
+
+                   t.start();
+                   read_and_add_corpus_to_group_from_elf(ctxt.get(),
+                                                         *group, status);
+                   t.stop();
+                   if (verbose)
+                     std::cerr << "module '"
+                      << *m
+                      << "' reading DONE: "
+                      << t << "\n";
+                 }
+
+               result = group;
+             }
+        }
+#endif
     }
 
   return result;
diff --git a/tests/data/test-read-common/test-PR26568-2.o b/tests/data/test-read-common/test-PR26568-2.o
index b192d52132766d4f95136e23f93de43a64d8cc2e..a6706e8cf508ab89927b0fccecd0268d27111ed9 100644
GIT binary patch
delta 1078
zcmZuwJ#Q015Z%3R+XNC4+rf~Wtw;eB%$Z17uE0<rBAO5pQBj=FADpo7f_)Bl6-1ZL
zWGcFpL83uvC{3skO-dR>8YF6d0W;^l$g=#T(agS?dAmD%_cwibb#Nn{HP|`IVN_-*
zmVAHz`rg0aiWKFRqCj{BJsEYAeL@S+bhImI1kPB7YSeJW7>OZA(1_29CDoC}EE<7w
zsFR{tqeK}CFQZ3+WdmmP^q!2X1vG><a*WfqD3v0Dy2fxZJc8>5tjC(Z*T_=XXAjt}
z?^ap8>oM!4->O-aex+~uZQE(qtWMjpnr_9exDDHF=DRzcpk1?DR#58%`Hoe!1A7!B
zTg^LutL1wmVsmS~c(+)}uitjUGkmTeaY###a!yds<{P6;&yUgdUU~i-FRVO%A=#X(
z@LEpFGSh{RlZR`{0vyU3p8->G4^#sN$`0Q;=IRA5qc9}2U+_o!rrts&jvez*)(z<y
zhq%6+DH2IrOblko;Y44x?_h?eUPc?osd&1fAm`B&6{#!={vrBl@{jSw2nX<8H*?z<
zO{+Q+RTgX*D@)VPF%XYjfQ^Kyx}-xlj9sGd0P!4Rx@lK2n$|rO-Mz4uF}g(@ZSodf
z<mh|_v~kqME)ML+%*<O%g;i0zC_R<oB(|CxL}@`s?g^a?u|^{52aLiiNV^K&Bn6B5
zZ0;kH^#6!)U^GHcv=+iCenpb@pR76(RVCPuuiTtAhZ2b+qF19i%t11-Hg_g^e};Md
Wwcu&OlD??$E^#lmDcXL}kpBaNjDTqX

delta 508
zcmZvYJ4*vW6oqH@mA%=G1lhO&i`^hZLkd#{K}{MFY|?3G0>KAJj1W*_wN`>n^!NiJ
zq)4A4oum?*^g<f#EN$)F*&Rj1f#J-(ocZRS=`X&!y%l$8u%A_lP8F76&h6&%=#dXO
zot(A~{o_`L;XvIQP1OeH8s4;wsxm_=NwtKcqdVy9dz|p8pK~@kGi;8l#0+(Ff<9?z
zlA|0kbSV!%EC=Ki>RLR*Bo;Ows%V+A&PrWJgIxNM)g7wIC4r-B9=BEzkjHoMKyJa;
z<6cR+1v3%uzsx3bA#*GVy9i8=??;51BwYL=&_9GWa+XVTN^Gm4YI*z;4a-&P3c6OF
z-$aI)G!!Gly?9nJ)bP(1&@<C~fSm1;sm7EN0z1rRJ5-jPa+GZ>Cd)j_$-e(ZWJ_ae
b7pX1XF9?zz{8U!i*07e^pjUb2Nd)`?0Gw2F

diff --git a/tests/data/test-read-ctf/PR27700/test-PR27700.abi b/tests/data/test-read-ctf/PR27700/test-PR27700.abi
index 62df1017..fe3a897d 100644
--- a/tests/data/test-read-ctf/PR27700/test-PR27700.abi
+++ b/tests/data/test-read-ctf/PR27700/test-PR27700.abi
@@ -11,9 +11,8 @@
       <enumerator name='foo_e2' value='2'/>
       <enumerator name='foo_e3' value='3'/>
     </enum-decl>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <pointer-type-def type-id='022218d8' size-in-bits='64' alignment-in-bits='64' id='8750e847'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
       <parameter type-id='8750e847'/>
       <return type-id='48b5725f'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR26568-1.o.abi b/tests/data/test-read-ctf/test-PR26568-1.o.abi
index d62474ec..cfb8a50c 100644
--- a/tests/data/test-read-ctf/test-PR26568-1.o.abi
+++ b/tests/data/test-read-ctf/test-PR26568-1.o.abi
@@ -20,14 +20,14 @@
         <var-decl name='y' type-id='type-id-6' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-5'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
+        <var-decl name='y' type-id='type-id-6' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-5'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
+        <var-decl name='x' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
@@ -47,7 +47,7 @@
       </data-member>
     </union-decl>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fun'>
       <parameter type-id='type-id-7'/>
       <return type-id='type-id-8'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR26568-2.o.abi b/tests/data/test-read-ctf/test-PR26568-2.o.abi
index a934d15b..1163f085 100644
--- a/tests/data/test-read-ctf/test-PR26568-2.o.abi
+++ b/tests/data/test-read-ctf/test-PR26568-2.o.abi
@@ -3,34 +3,34 @@
     <elf-symbol name='fun' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-2' visibility='default'/>
+        <var-decl name='y' type-id='type-id-2' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-4' visibility='default'/>
+        <var-decl name='x' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-2'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <union-decl name='A' size-in-bits='64' visibility='default' id='type-id-5'>
       <data-member access='public'>
-        <var-decl name='' type-id='type-id-1' visibility='default'/>
+        <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='x' type-id='type-id-2' visibility='default'/>
+        <var-decl name='x' type-id='type-id-4' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
+        <var-decl name='' type-id='type-id-1' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='y' type-id='type-id-4' visibility='default'/>
+        <var-decl name='y' type-id='type-id-2' visibility='default'/>
       </data-member>
     </union-decl>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fun'>
       <parameter type-id='type-id-6'/>
       <return type-id='type-id-7'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR27700.abi b/tests/data/test-read-ctf/test-PR27700.abi
new file mode 100644
index 00000000..fe3a897d
--- /dev/null
+++ b/tests/data/test-read-ctf/test-PR27700.abi
@@ -0,0 +1,21 @@
+<abi-corpus version='2.1' path='data/test-read-common/PR27700/test-PR27700.o'>
+  <elf-function-symbols>
+    <elf-symbol name='foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-function-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='foo' linkage-name='foo' id='022218d8'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='foo_e0' value='0'/>
+      <enumerator name='foo_e1' value='1'/>
+      <enumerator name='foo_e2' value='2'/>
+      <enumerator name='foo_e3' value='3'/>
+    </enum-decl>
+    <pointer-type-def type-id='022218d8' size-in-bits='64' alignment-in-bits='64' id='8750e847'/>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='8750e847'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi b/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
index 922a1daf..12050a5b 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
@@ -30,7 +30,6 @@
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='7359adad'/>
     <pointer-type-def type-id='3ed987a4' size-in-bits='64' alignment-in-bits='64' id='84d5ac12'/>
     <pointer-type-def type-id='1c12b755' size-in-bits='64' alignment-in-bits='64' id='55cd64e8'/>
-    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default'/>
-    <var-decl name='foo' type-id='55cd64e8' mangled-name='foo' visibility='default'/>
+    <var-decl name='foo' type-id='55cd64e8' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.c b/tests/data/test-read-ctf/test-ambiguous-struct-B.c
index 95a93469..e592529b 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-B.c
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-B.c
@@ -2,4 +2,4 @@ struct A;
 struct B { struct A *a; };
 struct A { struct B b; int foo; struct B b2; };
 
-static struct A a __attribute__((__used__));
+struct A a __attribute__((__used__));
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.o b/tests/data/test-read-ctf/test-ambiguous-struct-B.o
index 06bd0f502a874ad4a10c4beb5788eaace44c2bf9..40a11fcbd4ae19b78a943812f69606cdc6c9fc15 100644
GIT binary patch
delta 20
ccmX@Wb%1Nb8%9RK&2Jg^GchtvUdu8W08_UIfB*mh

delta 20
ccmX@Wb%1Nb8%9RP&2Jg^GchtxUdu8W08;!1aR2}S

diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi b/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
index 28291eb5..83d21919 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-ctf/test-ambiguous-struct-B.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='a' size='24' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
   <abi-instr address-size='64' language='LANG_C'>
     <class-decl name='A' size-in-bits='192' alignment-in-bits='64' is-struct='yes' visibility='default' id='3ed987a4'>
       <data-member access='public' layout-offset-in-bits='0'>
@@ -18,6 +21,6 @@
     </class-decl>
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
     <pointer-type-def type-id='3ed987a4' size-in-bits='64' alignment-in-bits='64' id='84d5ac12'/>
-    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default'/>
+    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default' elf-symbol-id='a'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-anonymous-fields.o.abi b/tests/data/test-read-ctf/test-anonymous-fields.o.abi
new file mode 100644
index 00000000..0419c29c
--- /dev/null
+++ b/tests/data/test-read-ctf/test-anonymous-fields.o.abi
@@ -0,0 +1,33 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-anonymous-fields.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='t' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='vaddr' type-id='type-id-2' visibility='default'/>
+      </data-member>
+    </class-decl>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='dup_xol_work' type-id='type-id-4' visibility='default'/>
+      </data-member>
+    </class-decl>
+    <class-decl name='uprobe_task' size-in-bits='64' alignment-in-bits='64' is-struct='yes' visibility='default' id='type-id-5'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='' type-id='type-id-6' visibility='default'/>
+      </data-member>
+    </class-decl>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <union-decl name='' size-in-bits='64' is-anonymous='yes' visibility='default' id='type-id-6'>
+      <data-member access='public'>
+        <var-decl name='' type-id='type-id-1' visibility='default'/>
+      </data-member>
+      <data-member access='public'>
+        <var-decl name='' type-id='type-id-3' visibility='default'/>
+      </data-member>
+    </union-decl>
+    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
+    <var-decl name='t' type-id='type-id-5' mangled-name='t' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-array-of-pointers.abi b/tests/data/test-read-ctf/test-array-of-pointers.abi
index 920da28b..195361df 100644
--- a/tests/data/test-read-ctf/test-array-of-pointers.abi
+++ b/tests/data/test-read-ctf/test-array-of-pointers.abi
@@ -31,6 +31,6 @@
     <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
     <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-11'/>
-    <var-decl name='t' type-id='type-id-11' mangled-name='t' visibility='default'/>
+    <var-decl name='t' type-id='type-id-11' mangled-name='t' visibility='default' elf-symbol-id='t'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-callback.abi b/tests/data/test-read-ctf/test-callback.abi
index 704c4971..7f9b6c5f 100644
--- a/tests/data/test-read-ctf/test-callback.abi
+++ b/tests/data/test-read-ctf/test-callback.abi
@@ -4,28 +4,16 @@
     <elf-symbol name='f2' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='test' size-in-bits='64' alignment-in-bits='64' is-struct='yes' visibility='default' id='type-id-1'>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='fn1' type-id='type-id-2' visibility='default'/>
-      </data-member>
-    </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
-    <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
-    <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <function-decl name='assign' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <return type-id='type-id-7'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
+    <function-decl name='assign' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='assign'>
+      <return type-id='type-id-3'/>
     </function-decl>
-    <function-decl name='f2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-3'/>
-      <parameter type-id='type-id-4'/>
-      <return type-id='type-id-7'/>
+    <function-decl name='f2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='f2'>
+      <parameter type-id='type-id-1'/>
+      <parameter type-id='type-id-2'/>
+      <return type-id='type-id-3'/>
     </function-decl>
-    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-6'>
-      <parameter type-id='type-id-3'/>
-      <parameter type-id='type-id-4'/>
-      <return type-id='type-id-7'/>
-    </function-type>
-    <type-decl name='void' id='type-id-7'/>
+    <type-decl name='void' id='type-id-3'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-callback2.abi b/tests/data/test-read-ctf/test-callback2.abi
index bdd4ad33..ddc3e493 100644
--- a/tests/data/test-read-ctf/test-callback2.abi
+++ b/tests/data/test-read-ctf/test-callback2.abi
@@ -11,7 +11,7 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
-    <var-decl name='s0' type-id='type-id-5' mangled-name='s0' visibility='default'/>
+    <var-decl name='s0' type-id='type-id-5' mangled-name='s0' visibility='default' elf-symbol-id='s0'/>
     <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-4'>
       <parameter type-id='type-id-5'/>
       <return type-id='type-id-3'/>
diff --git a/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi b/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
index 03dd56b3..8d5c3e36 100644
--- a/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
+++ b/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
@@ -8,7 +8,7 @@
     <typedef-decl name='a_t' type-id='bd54fe1a' id='40acc204'/>
     <typedef-decl name='b_t' type-id='bd54fe1a' id='b3d2db81'/>
     <pointer-type-def type-id='40acc204' size-in-bits='64' alignment-in-bits='64' id='c6fd4117'/>
-    <var-decl name='a' type-id='c6fd4117' mangled-name='a' visibility='default'/>
-    <var-decl name='ignore2' type-id='b3d2db81' mangled-name='ignore2' visibility='default'/>
+    <var-decl name='a' type-id='c6fd4117' mangled-name='a' visibility='default' elf-symbol-id='a'/>
+    <var-decl name='ignore2' type-id='b3d2db81' mangled-name='ignore2' visibility='default' elf-symbol-id='ignore2'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi b/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
index 35bcac7a..992b669d 100644
--- a/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
+++ b/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
@@ -7,7 +7,7 @@
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='bd54fe1a'/>
     <typedef-decl name='a_t' type-id='bd54fe1a' id='40acc204'/>
     <typedef-decl name='b_t' type-id='bd54fe1a' id='b3d2db81'/>
-    <var-decl name='b' type-id='40acc204' mangled-name='b' visibility='default'/>
-    <var-decl name='ignore1' type-id='b3d2db81' mangled-name='ignore1' visibility='default'/>
+    <var-decl name='b' type-id='40acc204' mangled-name='b' visibility='default' elf-symbol-id='b'/>
+    <var-decl name='ignore1' type-id='b3d2db81' mangled-name='ignore1' visibility='default' elf-symbol-id='ignore1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-dynamic-array.o.abi b/tests/data/test-read-ctf/test-dynamic-array.o.abi
index 02b22811..a9849d49 100644
--- a/tests/data/test-read-ctf/test-dynamic-array.o.abi
+++ b/tests/data/test-read-ctf/test-dynamic-array.o.abi
@@ -21,7 +21,7 @@
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-3'/>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <function-decl name='use_struct_s' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='use_struct_s' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='use_struct_s'>
       <parameter type-id='type-id-7'/>
       <return type-id='type-id-8'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-enum-ctf.o.abi b/tests/data/test-read-ctf/test-enum-ctf.o.abi
new file mode 100644
index 00000000..f36f3fad
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-ctf.o.abi
@@ -0,0 +1,24 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='bar' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='foo' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
+    <enum-decl name='e' linkage-name='e' id='type-id-2'>
+      <underlying-type type-id='type-id-1'/>
+      <enumerator name='ENUMSAMPLE_1' value='0'/>
+      <enumerator name='ENUMSAMPLE_2' value='1'/>
+    </enum-decl>
+    <enum-decl name='ie' linkage-name='ie' id='type-id-3'>
+      <underlying-type type-id='type-id-1'/>
+      <enumerator name='IENUMSAMPLE_1' value='-10'/>
+      <enumerator name='IENUMSAMPLE_2' value='-9'/>
+      <enumerator name='IENUMSAMPLE_3' value='-8'/>
+    </enum-decl>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
+    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default'/>
+    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi b/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
new file mode 100644
index 00000000..67a958a7
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
@@ -0,0 +1,69 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-many-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='bar' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='foo' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='e' linkage-name='e' id='a6c2eddf'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='ENUMSAMPLE_1' value='0'/>
+      <enumerator name='ENUMSAMPLE_2' value='1'/>
+    </enum-decl>
+    <enum-decl name='ie' linkage-name='ie' id='1ee696ca'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='IE_0' value='-10'/>
+      <enumerator name='IE_1' value='-9'/>
+      <enumerator name='IE_2' value='-8'/>
+      <enumerator name='IE_3' value='-7'/>
+      <enumerator name='IE_4' value='-6'/>
+      <enumerator name='IE_5' value='-5'/>
+      <enumerator name='IE_6' value='-4'/>
+      <enumerator name='IE_7' value='-3'/>
+      <enumerator name='IE_8' value='-2'/>
+      <enumerator name='IE_9' value='-1'/>
+      <enumerator name='IE_A' value='0'/>
+      <enumerator name='IE_B' value='1'/>
+      <enumerator name='IE_C' value='2'/>
+      <enumerator name='IE_D' value='3'/>
+      <enumerator name='IE_E' value='4'/>
+      <enumerator name='IE_F' value='5'/>
+      <enumerator name='IE_10' value='6'/>
+      <enumerator name='IE_11' value='7'/>
+      <enumerator name='IE_12' value='8'/>
+      <enumerator name='IE_13' value='9'/>
+      <enumerator name='IE_14' value='10'/>
+      <enumerator name='IE_15' value='11'/>
+      <enumerator name='IE_16' value='12'/>
+      <enumerator name='IE_17' value='13'/>
+      <enumerator name='IE_18' value='14'/>
+      <enumerator name='IE_19' value='15'/>
+      <enumerator name='IE_1A' value='16'/>
+      <enumerator name='IE_1B' value='17'/>
+      <enumerator name='IE_1C' value='18'/>
+      <enumerator name='IE_1D' value='19'/>
+      <enumerator name='IE_1E' value='20'/>
+      <enumerator name='IE_1F' value='21'/>
+      <enumerator name='IE_20' value='22'/>
+      <enumerator name='IE_21' value='23'/>
+      <enumerator name='IE_22' value='24'/>
+      <enumerator name='IE_23' value='25'/>
+      <enumerator name='IE_24' value='26'/>
+      <enumerator name='IE_25' value='27'/>
+      <enumerator name='IE_26' value='28'/>
+      <enumerator name='IE_27' value='29'/>
+      <enumerator name='IE_28' value='30'/>
+      <enumerator name='IE_29' value='31'/>
+      <enumerator name='IE_2A' value='32'/>
+      <enumerator name='IE_2B' value='33'/>
+      <enumerator name='IE_2C' value='34'/>
+      <enumerator name='IE_2D' value='35'/>
+      <enumerator name='IE_2E' value='36'/>
+      <enumerator name='IE_2F' value='37'/>
+    </enum-decl>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
+    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default'/>
+    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-many.o.hash.abi b/tests/data/test-read-ctf/test-enum-many.o.hash.abi
index 26bc048c..116325f9 100644
--- a/tests/data/test-read-ctf/test-enum-many.o.hash.abi
+++ b/tests/data/test-read-ctf/test-enum-many.o.hash.abi
@@ -61,9 +61,7 @@
       <enumerator name='IE_2E' value='36'/>
       <enumerator name='IE_2F' value='37'/>
     </enum-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
-    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default'/>
-    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default'/>
+    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
+    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default' elf-symbol-id='bar'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi b/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi
new file mode 100644
index 00000000..fea6eb8b
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi
@@ -0,0 +1,16 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-symbol-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='primary1' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='' is-anonymous='yes' id='08f5ca17'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='red1' value='0'/>
+      <enumerator name='green1' value='1'/>
+      <enumerator name='blue1' value='2'/>
+    </enum-decl>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
+    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi b/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
index d128b5b1..f4911bc4 100644
--- a/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
+++ b/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
@@ -10,7 +10,6 @@
       <enumerator name='green1' value='1'/>
       <enumerator name='blue1' value='2'/>
     </enum-decl>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
-    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default'/>
+    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default' elf-symbol-id='primary1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum.o.abi b/tests/data/test-read-ctf/test-enum.o.abi
index 88e6ad61..bd3a55be 100644
--- a/tests/data/test-read-ctf/test-enum.o.abi
+++ b/tests/data/test-read-ctf/test-enum.o.abi
@@ -16,9 +16,7 @@
       <enumerator name='IENUMSAMPLE_2' value='-9'/>
       <enumerator name='IENUMSAMPLE_3' value='-8'/>
     </enum-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
-    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default'/>
-    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default'/>
+    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
+    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default' elf-symbol-id='bar'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-forward-type-decl.abi b/tests/data/test-read-ctf/test-forward-type-decl.abi
index 21bb45c8..026e7d32 100644
--- a/tests/data/test-read-ctf/test-forward-type-decl.abi
+++ b/tests/data/test-read-ctf/test-forward-type-decl.abi
@@ -24,6 +24,6 @@
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-3'/>
     <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='addr' type-id='type-id-5' mangled-name='addr' visibility='default'/>
+    <var-decl name='addr' type-id='type-id-5' mangled-name='addr' visibility='default' elf-symbol-id='addr'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-functions-declaration.abi b/tests/data/test-read-ctf/test-functions-declaration.abi
index 9ef05e44..7eb57d26 100644
--- a/tests/data/test-read-ctf/test-functions-declaration.abi
+++ b/tests/data/test-read-ctf/test-functions-declaration.abi
@@ -7,11 +7,11 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
-    <function-decl name='attribute_container_add_device' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='attribute_container_add_device' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='attribute_container_add_device'>
       <parameter type-id='type-id-4'/>
       <return type-id='type-id-5'/>
     </function-decl>
-    <function-decl name='attribute_container_device_trigger' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='attribute_container_device_trigger' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='attribute_container_device_trigger'>
       <parameter type-id='type-id-4'/>
       <return type-id='type-id-5'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-list-struct.abi b/tests/data/test-read-ctf/test-list-struct.abi
index 196a79a1..deb6a4a1 100644
--- a/tests/data/test-read-ctf/test-list-struct.abi
+++ b/tests/data/test-read-ctf/test-list-struct.abi
@@ -14,7 +14,7 @@
     </class-decl>
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='n1' type-id='type-id-1' mangled-name='n1' visibility='default'/>
-    <var-decl name='n2' type-id='type-id-1' mangled-name='n2' visibility='default'/>
+    <var-decl name='n1' type-id='type-id-1' mangled-name='n1' visibility='default' elf-symbol-id='n1'/>
+    <var-decl name='n2' type-id='type-id-1' mangled-name='n2' visibility='default' elf-symbol-id='n2'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test0 b/tests/data/test-read-ctf/test0
index aca7fbacdfff7ad2caf0142390710373a8da72a1..90aa8a39a2e1326a5cb5faaa9e854fc344caaa52 100755
GIT binary patch
delta 1886
zcmah~L2MgE6rEkWZra+(ZUVNWHnG!6kSdbB4pp+Tz+NFxdrBKokU<E`3NA_s+0=1R
z!hsZ2LDU1-`4W{lz<~poN(}_6o**g+6(K-AQK3qlDyTRVq*5i9m^ZV3s^AM>djHSN
zd;ibh8SlFBwsHP~(HKr_=EVc^gezjg69eK<vp6(*(+n6LyI2@P3<F6yP|@SqTr2Ef
zl@x3>-2C<akjol3<f&C1(`qI}nm)_)Rb@(vl_gf{_&~`STwXkLyZ*8q|L+c**G1dL
z4@cxgW?8@<;P~XT!aOfF<(dJ&=o@or;}3H+`nh#uFt^0*{Ik>cCEMV+OqRCA^GGli
z>$IIInx!!1vl-J3)7k7`$O(J&cW80VdGA07&*>>?n$G1?dj~K!MU=jF68%x}p%rjS
z05{6)U9bt^c>!xMeHzgay_Cwy+>9NtOp13EYtzZxal@iZxop2JP89yD`B7>5=r>fb
zh1bE}QKfpQXEf3Ou)y|eu3azM=tbv6uyK*>U=M?}M4WuEG4X9jZ%4t}B0(RIW{o)g
ztb7~FZu}sEUGyzq<Xy6l$rHHDyJ+?jvt_VxG0d#VEq<wX>8AHp?loq0|C=(`#L0t=
ziZq}62-7#gTIleuVkf!(1I*r0l@pXYCiitZD&s=c)13s1jE+0)4%m&AW2eoP6DW8M
z#YTYVF^&Uo0S^IJ033+;4u}FRzy@vsG2nMVHgpf@15DJ|i#Q9wBJy?hfI+OoBJ$AE
zfW>o!M+8J>1B<W-8dLAZCu%ApQU^Zt4mslo?J}=&8DpAW952VN2CJe6@hiG9K4QE{
z_r|~2bH?|}Ir`K+5`L{RGe_UM&I@9pUa2oGI2?1LUR|h{E45l>IT%j+a|`ugcxKkG
z@NnLrnX6Z8!FmlTwV7$AUiW7!^_kf!nG;V(UzuCX%-8(+YOTJ!;Z5u_=v3a?pA31b
z!(@og=Eq_#Pt`|*rb2yd1#4go3VCqy`K6Uuq`pW}M4Nf*sJtrq(reWctCsk?m6WNl
z2)<~Em8USe-){R_tv?$LRv%JYs5#2Z+HI4V$jjCF>%7}K=gV%S$-WIh=W`c_#dBDc
zT3uj^3v6)#m(Jx=D=$IO-qj|)R9F$h;WtdTr=zZ><Ezl_?8<jJ-{t(YEC%arGguW*
ziZ?KlT3xWj1xj4NVWn=M<2l6zYCc{xE>a7=LG}|x;{%$4|A?CKm#GDRmFz;%xK2~>
zKT)&rXuoVnnyx1Q4W#`-Eog3$T`U^6X$t;NYQq0TE%<G+y;N6%50I{mCFztmY#gLz
O&);`_A}FyV&-Gt@S^P)<

delta 1541
zcmZ9MO-NKx6vxlKZ?tqYpOznE<-FXa2=ifIqf@>+MHB?NX;F)iHf3#0R0<+&`XH#N
z(X+7HWF#?*pbraz7G=z0T7=Llf`~Sev~ZQw#_8Pq&Mlh@@7#Cp?|;rc_r81Ih07v$
zQRF(B-Cp?H6r>;w3O2y{34c@fpbUuZSF_NeK15HRd0r~=v_CP~SN%(4YQLO`PfHC2
z))b`DgHVvzD%<e1EZ||sn;ms-)L<@@d*&9~lHaA$68O1X8Zs}AGF^qS0E6sTvhU&V
zm@kVC_Qqo}@8GF;n=|bw%!bA$6F0+>CR0Z0;czm#Y9qZ%2;=KSb0iFR-GCVZnQo?w
zM4LdVfC|Qks25O=(WH)z)d!RzTs73i{^UMUhf~RT#D)ER|7+eGO#^<R3@)fLx?obR
z!Mg6|$U30ujc-i@mC-<z`$QX|rHr-{b)gZ5h}J-%thP>~_0WX(y5ph|=Z!6qvKGJ#
zX3?Kgw`)90e2d<JM?8zAQ%nblHbMte8HB<MGfOSrGO;h2GK4oeR?^NB4THx!-^KVN
zQI{%QH1r_XA7;8>GB;s#tDZMemYF`NSzSNTYD%N*l%`)3(An{=ha|p{q4Cp{Y@X2Z
zKvt<ww4&!N`+Bh+J<r)EIgmzPVW09*sQ|axXYQQ)pX*`WV)~>WF|SZbxhr*YaTI5E
z4Ajm9!%#>4BXm<;;w<h=J;$X~J8tZWS0!L%^w{XwND?3R?44cik%CsRYBKFs|GRG3
zn%-VpkjkVoHx0i!Yw=0i?c7FV`rhb@b+dQtI}fx3!%%@wW6k49@|H@aA*%*Q1)T5l
z2CL>?@7v0jCP#lT8}D(v$MO4FtoK82j*aIk+F=h3YOPIRulgV-Na3b*bo>A*N-N5o
z=4qx`Wq%CzhhekX{xHQauZYice4gVy;<}ZW8H~biI6-gvjM#)lPEh0o30B$y%GL?P
znBC=zGdM@~Jc>SFT*3_5>zE~b2j|E>K;ir1F=oiV!mPhJVwYvJ=@Y110q02b4u$f?
o2h5QDh*`3qagOXa6q%?P!TXsgs!WGy#gmz#s<xgW_J`ikKQHOTvj6}9

diff --git a/tests/data/test-read-ctf/test0.abi b/tests/data/test-read-ctf/test0.abi
index 50ca26f4..fc61f2ac 100644
--- a/tests/data/test-read-ctf/test0.abi
+++ b/tests/data/test-read-ctf/test0.abi
@@ -39,16 +39,26 @@
     </array-type-def>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-10'/>
     <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='type-id-11'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='type-id-12'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-13'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-14'/>
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='type-id-15'/>
-    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-16'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
-    <qualified-type-def type-id='type-id-3' const='yes' id='type-id-18'/>
-    <pointer-type-def type-id='type-id-10' size-in-bits='64' alignment-in-bits='64' id='type-id-19'/>
-    <qualified-type-def type-id='type-id-19' restrict='yes' id='type-id-20'/>
-    <qualified-type-def type-id='type-id-11' volatile='yes' id='type-id-21'/>
+    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-12'/>
+    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-13'/>
+    <qualified-type-def type-id='type-id-3' const='yes' id='type-id-14'/>
+    <pointer-type-def type-id='type-id-10' size-in-bits='64' alignment-in-bits='64' id='type-id-15'/>
+    <qualified-type-def type-id='type-id-15' restrict='yes' id='type-id-16'/>
+    <qualified-type-def type-id='type-id-11' volatile='yes' id='type-id-17'/>
+    <var-decl name='status' type-id='type-id-5' mangled-name='status' visibility='default' elf-symbol-id='status'/>
+    <var-decl name='test_pointer' type-id='type-id-13' mangled-name='test_pointer' visibility='default' elf-symbol-id='test_pointer'/>
+    <var-decl name='test_const' type-id='type-id-14' mangled-name='test_const' visibility='default' elf-symbol-id='test_const'/>
+    <var-decl name='test_float' type-id='type-id-6' mangled-name='test_float' visibility='default' elf-symbol-id='test_float'/>
+    <function-decl name='foo_1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo_1'>
+      <parameter type-id='type-id-12'/>
+      <return type-id='type-id-4'/>
+    </function-decl>
+    <function-decl name='main' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='main'>
+      <return type-id='type-id-4'/>
+    </function-decl>
+    <var-decl name='test_array' type-id='type-id-7' mangled-name='test_array' visibility='default' elf-symbol-id='test_array'/>
+    <var-decl name='test_restrict' type-id='type-id-16' mangled-name='test_restrict' visibility='default' elf-symbol-id='test_restrict'/>
+    <var-decl name='test_volatile' type-id='type-id-17' mangled-name='test_volatile' visibility='default' elf-symbol-id='test_volatile'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test0.c b/tests/data/test-read-ctf/test0.c
index eb702312..fdefd57c 100644
--- a/tests/data/test-read-ctf/test0.c
+++ b/tests/data/test-read-ctf/test0.c
@@ -1,3 +1,9 @@
+/*
+ * ELF EXEC files must use -Wl,--ctf-variables -Bdynimic options
+ * to export an ABI and store CTF symbols information.
+ *
+ * ctf-gcc -gctf -Wl,--ctf-variables -Bdynamic test0.c -o test0
+ */
 
 #include <stdio.h>
 
diff --git a/tests/data/test-read-ctf/test0.hash.abi b/tests/data/test-read-ctf/test0.hash.abi
index b58520ab..eff32228 100644
--- a/tests/data/test-read-ctf/test0.hash.abi
+++ b/tests/data/test-read-ctf/test0.hash.abi
@@ -39,16 +39,26 @@
     </array-type-def>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='bd54fe1a'/>
     <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='a2185560'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='28577a57'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='002ac4a6'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='7359adad'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='8efea9e5'/>
     <pointer-type-def type-id='50d9a3fa' size-in-bits='64' alignment-in-bits='64' id='fd01f598'/>
     <pointer-type-def type-id='a84c031d' size-in-bits='64' alignment-in-bits='64' id='26a90f95'/>
     <qualified-type-def type-id='50d9a3fa' const='yes' id='0fb3b55d'/>
     <pointer-type-def type-id='bd54fe1a' size-in-bits='64' alignment-in-bits='64' id='3ccc2590'/>
     <qualified-type-def type-id='3ccc2590' restrict='yes' id='af4b1b38'/>
     <qualified-type-def type-id='a2185560' volatile='yes' id='ec67e496'/>
+    <var-decl name='status' type-id='e7f43f72' mangled-name='status' visibility='default' elf-symbol-id='status'/>
+    <var-decl name='test_pointer' type-id='26a90f95' mangled-name='test_pointer' visibility='default' elf-symbol-id='test_pointer'/>
+    <var-decl name='test_const' type-id='0fb3b55d' mangled-name='test_const' visibility='default' elf-symbol-id='test_const'/>
+    <var-decl name='test_float' type-id='a6c45d85' mangled-name='test_float' visibility='default' elf-symbol-id='test_float'/>
+    <function-decl name='foo_1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo_1'>
+      <parameter type-id='fd01f598'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <function-decl name='main' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='main'>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <var-decl name='test_array' type-id='b7bd1749' mangled-name='test_array' visibility='default' elf-symbol-id='test_array'/>
+    <var-decl name='test_restrict' type-id='af4b1b38' mangled-name='test_restrict' visibility='default' elf-symbol-id='test_restrict'/>
+    <var-decl name='test_volatile' type-id='ec67e496' mangled-name='test_volatile' visibility='default' elf-symbol-id='test_volatile'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test1.so.abi b/tests/data/test-read-ctf/test1.so.abi
index 5b3caf63..416bd39d 100644
--- a/tests/data/test-read-ctf/test1.so.abi
+++ b/tests/data/test-read-ctf/test1.so.abi
@@ -16,8 +16,13 @@
     </enum-decl>
     <typedef-decl name='opaque_enum' type-id='type-id-4' id='type-id-3'/>
     <typedef-decl name='opaque_struct' type-id='type-id-2' id='type-id-5'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
-    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
+    <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
+    <function-decl name='fn' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fn'>
+      <parameter type-id='type-id-7'/>
+      <parameter type-id='type-id-6'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-8'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test1.so.hash.abi b/tests/data/test-read-ctf/test1.so.hash.abi
index 8019cb54..b3620e75 100644
--- a/tests/data/test-read-ctf/test1.so.hash.abi
+++ b/tests/data/test-read-ctf/test1.so.hash.abi
@@ -16,8 +16,13 @@
     </enum-decl>
     <typedef-decl name='opaque_enum' type-id='55763a91' id='99fcd3a5'/>
     <typedef-decl name='opaque_struct' type-id='6cde5052' id='dae69ca1'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <pointer-type-def type-id='99fcd3a5' size-in-bits='64' alignment-in-bits='64' id='0e0526e0'/>
     <pointer-type-def type-id='dae69ca1' size-in-bits='64' alignment-in-bits='64' id='3f6e71d0'/>
+    <function-decl name='fn' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fn'>
+      <parameter type-id='3f6e71d0'/>
+      <parameter type-id='0e0526e0'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test2.so.abi b/tests/data/test-read-ctf/test2.so.abi
index eb6aff3e..67f802f9 100644
--- a/tests/data/test-read-ctf/test2.so.abi
+++ b/tests/data/test-read-ctf/test2.so.abi
@@ -20,6 +20,14 @@
     <qualified-type-def type-id='type-id-8' const='yes' id='type-id-9'/>
     <pointer-type-def type-id='type-id-9' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <pointer-type-def type-id='type-id-8' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
+      <parameter type-id='type-id-7'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='type-id-6'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
     <type-decl name='void' id='type-id-8'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test2.so.hash.abi b/tests/data/test-read-ctf/test2.so.hash.abi
index 6e57333b..6bbf347e 100644
--- a/tests/data/test-read-ctf/test2.so.hash.abi
+++ b/tests/data/test-read-ctf/test2.so.hash.abi
@@ -20,6 +20,14 @@
     <qualified-type-def type-id='48b5725f' const='yes' id='8581546e'/>
     <pointer-type-def type-id='8581546e' size-in-bits='64' alignment-in-bits='64' id='6e97a70c'/>
     <pointer-type-def type-id='48b5725f' size-in-bits='64' alignment-in-bits='64' id='eaa32e2f'/>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
+      <parameter type-id='5e30a4f9'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='842ea234'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
     <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test3.so.abi b/tests/data/test-read-ctf/test3.so.abi
index 9d55fec5..3d2f6326 100644
--- a/tests/data/test-read-ctf/test3.so.abi
+++ b/tests/data/test-read-ctf/test3.so.abi
@@ -8,5 +8,9 @@
     <elf-symbol name='foo__' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
+    <function-decl name='__foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='__foo'>
+      <return type-id='type-id-1'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test3.so.hash.abi b/tests/data/test-read-ctf/test3.so.hash.abi
index 9d55fec5..1c69e2e1 100644
--- a/tests/data/test-read-ctf/test3.so.hash.abi
+++ b/tests/data/test-read-ctf/test3.so.hash.abi
@@ -8,5 +8,9 @@
     <elf-symbol name='foo__' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
+    <function-decl name='__foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='__foo'>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test4.so.abi b/tests/data/test-read-ctf/test4.so.abi
index b8e0ead3..dc18e191 100644
--- a/tests/data/test-read-ctf/test4.so.abi
+++ b/tests/data/test-read-ctf/test4.so.abi
@@ -10,5 +10,11 @@
     <qualified-type-def type-id='type-id-1' const='yes' id='type-id-5'/>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
     <qualified-type-def type-id='type-id-6' restrict='yes' id='type-id-7'/>
+    <function-decl name='cpy' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='cpy'>
+      <parameter type-id='type-id-4'/>
+      <parameter type-id='type-id-7'/>
+      <parameter type-id='type-id-2'/>
+      <return type-id='type-id-3'/>
+    </function-decl>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test4.so.hash.abi b/tests/data/test-read-ctf/test4.so.hash.abi
index dbe34d9c..dc428592 100644
--- a/tests/data/test-read-ctf/test4.so.hash.abi
+++ b/tests/data/test-read-ctf/test4.so.hash.abi
@@ -10,5 +10,11 @@
     <qualified-type-def type-id='a84c031d' const='yes' id='9b45d938'/>
     <pointer-type-def type-id='9b45d938' size-in-bits='64' alignment-in-bits='64' id='80f4b756'/>
     <qualified-type-def type-id='80f4b756' restrict='yes' id='9d26089a'/>
+    <function-decl name='cpy' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='cpy'>
+      <parameter type-id='266fe297'/>
+      <parameter type-id='9d26089a'/>
+      <parameter type-id='f0981eeb'/>
+      <return type-id='26a90f95'/>
+    </function-decl>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test5.o.abi b/tests/data/test-read-ctf/test5.o.abi
index eb30cf6a..f7bcdeb1 100644
--- a/tests/data/test-read-ctf/test5.o.abi
+++ b/tests/data/test-read-ctf/test5.o.abi
@@ -17,34 +17,32 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <type-decl name='long long int' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <type-decl name='long long unsigned int' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <typedef-decl name='long_long' type-id='type-id-6' id='type-id-8'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-9'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-10'/>
-    <qualified-type-def type-id='type-id-4' const='yes' id='type-id-11'/>
-    <qualified-type-def type-id='type-id-5' const='yes' id='type-id-12'/>
-    <qualified-type-def type-id='type-id-12' volatile='yes' id='type-id-13'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-10'/>
-      <parameter type-id='type-id-13'/>
+    <typedef-decl name='long_long' type-id='type-id-6' id='type-id-7'/>
+    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <qualified-type-def type-id='type-id-4' const='yes' id='type-id-9'/>
+    <qualified-type-def type-id='type-id-5' const='yes' id='type-id-10'/>
+    <qualified-type-def type-id='type-id-10' volatile='yes' id='type-id-11'/>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='type-id-8'/>
+      <parameter type-id='type-id-11'/>
       <return type-id='type-id-5'/>
     </function-decl>
-    <function-decl name='baz2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='baz2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='baz2'>
       <parameter type-id='type-id-4'/>
-      <return type-id='type-id-8'/>
+      <return type-id='type-id-7'/>
     </function-decl>
-    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
       <parameter is-variadic='yes'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <function-decl name='bar2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar2'>
       <parameter type-id='type-id-3'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <function-decl name='baz' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='baz' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='baz'>
       <parameter type-id='type-id-4'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <type-decl name='void' id='type-id-14'/>
+    <type-decl name='void' id='type-id-12'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test7.o.abi b/tests/data/test-read-ctf/test7.o.abi
index b744fac5..a13af174 100644
--- a/tests/data/test-read-ctf/test7.o.abi
+++ b/tests/data/test-read-ctf/test7.o.abi
@@ -3,40 +3,31 @@
     <elf-symbol name='first_type_constructor' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <type-decl name='char' size-in-bits='8' alignment-in-bits='8' id='type-id-1'/>
-    <class-decl name='first_type' size-in-bits='128' alignment-in-bits='32' is-struct='yes' visibility='default' id='type-id-2'>
+    <class-decl name='first_type' size-in-bits='128' alignment-in-bits='32' is-struct='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='member0' type-id='type-id-3' visibility='default'/>
+        <var-decl name='member0' type-id='type-id-2' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='32'>
-        <var-decl name='member1' type-id='type-id-4' visibility='default'/>
+        <var-decl name='member1' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='64'>
-        <var-decl name='ctor' type-id='type-id-5' visibility='default'/>
+        <var-decl name='ctor' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <type-decl name='long long int' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
-    <type-decl name='long long unsigned int' size-in-bits='64' alignment-in-bits='64' id='type-id-9'/>
-    <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='type-id-10'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='type-id-11'/>
-    <typedef-decl name='character' type-id='type-id-12' id='type-id-4'/>
-    <typedef-decl name='constructor' type-id='type-id-13' id='type-id-5'/>
-    <typedef-decl name='integer' type-id='type-id-6' id='type-id-3'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-12'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-14'/>
-    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-15'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='type-id-16'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
-    <pointer-type-def type-id='type-id-18' size-in-bits='64' alignment-in-bits='64' id='type-id-13'/>
-    <function-decl name='first_type_constructor' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-17'/>
-      <return type-id='type-id-19'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
+    <typedef-decl name='character' type-id='type-id-6' id='type-id-3'/>
+    <typedef-decl name='constructor' type-id='type-id-7' id='type-id-4'/>
+    <typedef-decl name='integer' type-id='type-id-5' id='type-id-2'/>
+    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-6'/>
+    <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-9' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
+    <function-decl name='first_type_constructor' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='first_type_constructor'>
+      <parameter type-id='type-id-8'/>
+      <return type-id='type-id-10'/>
     </function-decl>
-    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-18'>
-      <return type-id='type-id-19'/>
+    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-9'>
+      <return type-id='type-id-10'/>
     </function-type>
-    <type-decl name='void' id='type-id-19'/>
+    <type-decl name='void' id='type-id-10'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test8.o.abi b/tests/data/test-read-ctf/test8.o.abi
index 68b3af06..b6996c29 100644
--- a/tests/data/test-read-ctf/test8.o.abi
+++ b/tests/data/test-read-ctf/test8.o.abi
@@ -4,7 +4,7 @@
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
       <parameter type-id='type-id-2'/>
       <return type-id='type-id-1'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test9.o.abi b/tests/data/test-read-ctf/test9.o.abi
index 746dd77b..08704d79 100644
--- a/tests/data/test-read-ctf/test9.o.abi
+++ b/tests/data/test-read-ctf/test9.o.abi
@@ -49,7 +49,7 @@
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-16' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
     <pointer-type-def type-id='type-id-18' size-in-bits='64' alignment-in-bits='64' id='type-id-20'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
       <parameter type-id='type-id-22'/>
       <return type-id='type-id-16'/>
     </function-decl>
diff --git a/tests/test-read-ctf.cc b/tests/test-read-ctf.cc
index 8ed8ac1a..7c9afa6d 100644
--- a/tests/test-read-ctf.cc
+++ b/tests/test-read-ctf.cc
@@ -261,20 +261,28 @@ static InOutSpec in_out_specs[] =
     "output/test-read-ctf/test-list-struct.abi",
   },
   {
-    "data/test-read-ctf/test-callback2.o",
+    "data/test-read-common/test-PR26568-1.o",
     "",
     "",
     SEQUENCE_TYPE_ID_STYLE,
-    "data/test-read-ctf/test-callback2.abi",
-    "output/test-read-ctf/test-callback2.abi",
+    "data/test-read-ctf/test-PR26568-1.o.abi",
+    "output/test-read-ctf/test-PR26568-1.o.abi",
   },
   {
-    "data/test-read-ctf/test-forward-undefine-type-decl.o",
+    "data/test-read-common/test-PR26568-2.o",
     "",
     "",
     SEQUENCE_TYPE_ID_STYLE,
-    "data/test-read-ctf/test-forward-undefine-type-decl.abi",
-    "output/test-read-ctf/test-forward-undefine-type-decl.abi",
+    "data/test-read-ctf/test-PR26568-2.o.abi",
+    "output/test-read-ctf/test-PR26568-2.o.abi",
+  },
+  {
+    "data/test-read-ctf/test-callback2.o",
+    "",
+    "",
+    SEQUENCE_TYPE_ID_STYLE,
+    "data/test-read-ctf/test-callback2.abi",
+    "output/test-read-ctf/test-callback2.abi",
   },
   // This should be the last entry.
   {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
diff --git a/tools/abidw.cc b/tools/abidw.cc
index f7a8937d..f9287b47 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -958,6 +958,11 @@ main(int argc, char* argv[])
   environment_sptr env(new environment);
   int exit_code = 0;
 
+#ifdef WITH_CTF
+  if (opts.use_ctf)
+    env->set_debug_format_type(environment::CTF_FORMAT_TYPE);
+#endif
+
   if (tools_utils::is_regular_file(opts.in_file_path))
     exit_code = load_corpus_and_write_abixml(argv, env, opts);
   else
-- 
2.35.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ctf-reader: Add support to read CTF information from Linux kernel
  2022-03-30 15:35 [PATCH] ctf-reader: Add support to read CTF information from Linux kernel Guillermo E. Martinez
@ 2022-04-04 22:49 ` Guillermo Martinez
  2022-04-29 14:16 ` [PATCH v2] " Guillermo E. Martinez
  1 sibling, 0 replies; 10+ messages in thread
From: Guillermo Martinez @ 2022-04-04 22:49 UTC (permalink / raw)
  To: libabigail

Hello libabigail team,

Any comment for this patch?

Thanks,
Guillermo

On Wednesday, March 30, 2022 9:35:31 AM CDT Guillermo E. Martinez wrote:
> Hello libabigail team,
> 
> This patch is meant to extract CTF information from Linux kernel,
> it relies on CTF support in both: GNU toolchain and Linux kernel code
> using `CONFIG_CTF' in its configuration.
> 
> This path depends in:
> 
> https://sourceware.org/pipermail/libabigail/2021q4/003994.html
> 
> Please take a look and let me know your comments, I'll really appreciate
> them.
> 
> Kind regards,
> Guillermo
> 
>[...]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2] ctf-reader: Add support to read CTF information from Linux kernel
  2022-03-30 15:35 [PATCH] ctf-reader: Add support to read CTF information from Linux kernel Guillermo E. Martinez
  2022-04-04 22:49 ` Guillermo Martinez
@ 2022-04-29 14:16 ` Guillermo E. Martinez
  2022-05-03 15:32   ` Dodji Seketeli
  1 sibling, 1 reply; 10+ messages in thread
From: Guillermo E. Martinez @ 2022-04-29 14:16 UTC (permalink / raw)
  To: libabigail

Hello libabigail team,

This is the v2 patch meant to read CTF information from Linux. Changes
from v1:

   * rebase and update from its dependency:

https://sourceware.org/pipermail/libabigail/2022q2/004308.html

Please take a look and let me know your comments, I'll really appreciate
them.

Kind regards,
Guillermo


This patch is meant to extract ABI information from CTF stored in
Linux kernel build directory it depends on: vmlinux.ctfa file.

In order to generate CTF information in Linux kernel must be able
to support 'make ctf', which cause the compiler to be run with -gctf
emitting CTF information on the kernel.

The target 'ctf' in Linux Makefile generate a 'vmlinux.ctfa', that
will be used for ctf reader in libabigail. 'vmlinux.ctfa' has multiple
'ctf dictionaries' called: CTF archive members one for built-in kernel
modules (`vmlinux') and one for each out-of-tree kernel module organized
in a parent-child hierarchy. In vmlinux.ctfa file there is a CTF archive
member: `shared_ctf' it is a parent dictionary, containing share symbols
and CTF types used by more than one kernel object. These common types
are stored in 'types_map' in ctf reader, ignoring the ctf dictionary name,
CTF API has the machinery to looking for a share type in parent dictionary
referred in a child dictionary. This CTF layout can be dumped by using
objdump tool.

The basic algorithm used to generate the Linux corpus follow:

   1. Looking for: vmlinux, *.ko objects, and vmlinux.ctfa files. The
   first files are used to extract the ELF symbols, and the last one
   contains the CTF type information for non-static variables and
   functions symbols.

   2. `process_ctf_archive' iterates on public symbols for vmlinux and
   its modules, using the name of the symbol, ctf reader search for CTF
   information in its dictionary, if the information was found it
   builds a `var_decl' or `function_decl' depending of `ctf_type_kind'
   result.

This algorithm is also applied to ELF files (exec, dyn, rel), so instead
of iterating on all ctf_types it uses public symbols as main loop.

	* abg-elf-reader-common.h: Include ctf-api.h file.
	(read_and_add_corpus_to_group_from_elf, set_read_context_corpus_group)
	(reset_read_context, set_vmlinux_ctfa_path, dic_type_key): Declare new
	member functions.
	* include/abg-ir.h (environment::debug_format_type): Add new enum type.
	(environment::debug_format_): Add new member variable.
	(environment::{get_debug_format_type,set_debug_format_type): Add new
	member functions.
	* src/abg-ctf-reader.cc: Include map, algorithms header files.
	(read_context::vmlinux_ctfa_path_): Add new member variable to store
	location of `vmlinux.ctfa'.
	(read_context::type_map): Change from unordered_map to std::map storing
	ctf dictionary name as part of the key.
	(read_context::is_elf_exec): Add new member variable.
	(read_context::{cur_corpus_, cur_corpus_group_}): Likewise.
	(read_context::unknown_types_set): Likewise.
	(read_context::{current_corpus_group, main_corpus_from_current_group,
	has_corpus_group, current_corpus_is_main_corpus_from_current_group,
	should_reuse_type_from_corpus_group}): Add new member functions.
	(read_context::{add_unknown_type, lookup_unknown_type, initialize}):
	Likewise.
	(read_context::{add_type, lookup_type}): Add new `ctf_dict_t' type
	argument.
	(ctf_reader::{process_ctf_typedef, process_ctf_base_type,
	process_ctf_function_type, process_ctf_forward_type,
	process_ctf_struct_type, process_ctf_union_type, process_ctf_array_type,
	process_ctf_qualified_type, process_ctf_enum_type}): Add code to `reuse'
	types already registered in main corpus. Replace function calls to the
	new ctf interface. Add verifier to not build types duplicated by
	recursive calling chain.
	(ctf_reader::process_ctf_type): Add code to return immediately if the
	ctf type is unknown. Add unknown types to `unknown_types_set'.
	(ctf_reader::process_ctf_archive): Change comment.
	Add code to iterate over global symbols, searching by symbol name in the
	ctf dictionary using `ctf_lookup_{variable,by_symbol_name}' depending of
	the ELF file type and corpus type, creating a `{var,fuc}_decl' using the
	return type of `ctf_type_kind'.  Also close the ctf dict and call
	`canonicalize_all_types'.
	(slurp_elf_info): Set `is_elf_exec' depending of ELF type.  Also return
	success if corpus origin is Linux and symbol table was read.
	(ctf_reader::read_corpus): Add current corpus.  Set corpus origin to
	`LINUX_KERNEL_BINARY_ORIGIN' or `CTF_ORIGIN'.  Use `is_linux_kernel' to
	verify the ctf reader status, now the ctf archive is 'opened' using
	`ctf_arc{open,bufopen}' depending of corpus origin value,
	`sort_{function,variables}' is call after extract ctf information and
	`ctf_close' is called.
	(read:context::{set_read_context_corpus_group, reset_read_context,
	read_and_add_corpus_to_group_from_elf, set_vmlinux_ctfa_path,
	dic_type_key): Add new member function implementation.
	* src/abg-ir.cc (environment::environment): Add default value
	`DWARF_FORMAT_TYPE' for `debug_format_'.
	(environment::{get_debug_format_type, set_debug_format_type}): Add new
	member function implementation.
	* src/abg-tools-utils.cc: Use `abg-ctf-reader.h' file.  (is_vmlinux):
	Add new argument.
	(find_vmlinux_and_module_paths): Change to use new `is_vmlinux'
	signature.
	(find_vmlinux_path): Add new argument.  Also change to use
	new `is_vmlinux' signature.
	(get_vmlinux_path_from_kernel_dist): Change to use `find_vmlinux_path'
	signature.
	(get_vmlinux_ctfa_path_from_kernel_dist): Add new function definition.
	(build_corpus_group_from_kernel_dist_under): Add conditional use of
	`debug_format_' if it is `CTF_FORMAT_TYPE' looks for `vmlinux.ctfa',
	re-organise the code to process both debug formats:
	`{DWARF,CTF}_FORMAT_TYPE.
	* tools/abidw.cc (main): Use of --ctf argument to set format debug.
	* tests/test-read-ctf.cc: Add new tests to harness.
	* tests/data/test-read-ctf/test-PR27700.abi: New test expected
	  result.
	* tests/data/test-read-ctf/test-anonymous-fields.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-many.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi: Likewise.
	* tests/data/test-read-common/test-PR26568-2.o: Adjust.
	* tests/data/test-read-ctf/test-PR26568-1.o.abi: Likewise.
	* tests/data/test-read-ctf/test-PR26568-2.o.abi: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.c: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.o: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-array-of-pointers.abi: Likewise.
	* tests/data/test-read-ctf/test-callback.abi: Likewise.
	* tests/data/test-read-ctf/test-callback2.abi: Likewise.
	* tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi:
	Likewise.
	* tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi:
	Likewise.
	* tests/data/test-read-ctf/test-dynamic-array.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-ctf.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-symbol.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum.o.abi: Likewise.
	* tests/data/test-read-ctf/test-forward-type-decl.abi: Likewise.
	* tests/data/test-read-ctf/test-functions-declaration.abi: Likewise.
	* tests/data/test-read-ctf/test-list-struct.abi: Likewise.
	* tests/data/test-read-ctf/test0: Likewise.
	* tests/data/test-read-ctf/test0.abi: Likewise.
	* tests/data/test-read-ctf/test0.c: Likewise.
	* tests/data/test-read-ctf/test0.hash.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test5.o.abi: Likewise.
	* tests/data/test-read-ctf/test7.o.abi: Likewise.
	* tests/data/test-read-ctf/test8.o.abi: Likewise.
	* tests/data/test-read-ctf/test9.o.abi: Likewise.
---
 include/abg-ctf-reader.h                      |  19 +
 include/abg-ir.h                              |  14 +
 src/abg-ctf-reader.cc                         | 467 ++++++++++++++----
 src/abg-ir.cc                                 |  17 +-
 src/abg-tools-utils.cc                        | 272 +++++++---
 tests/data/test-read-common/test-PR26568-2.o  | Bin 3048 -> 3488 bytes
 .../test-read-ctf/PR27700/test-PR27700.abi    |   3 +-
 tests/data/test-read-ctf/test-PR26568-1.o.abi |  34 +-
 tests/data/test-read-ctf/test-PR26568-2.o.abi |  22 +-
 tests/data/test-read-ctf/test-PR27700.abi     |  21 +
 .../test-ambiguous-struct-A.o.hash.abi        |   3 +-
 .../test-read-ctf/test-ambiguous-struct-B.c   |   2 +-
 .../test-read-ctf/test-ambiguous-struct-B.o   | Bin 1344 -> 1344 bytes
 .../test-ambiguous-struct-B.o.hash.abi        |   5 +-
 .../test-read-ctf/test-anonymous-fields.o.abi |  18 +-
 .../test-read-ctf/test-array-of-pointers.abi  |   2 +-
 tests/data/test-read-ctf/test-callback.abi    |  30 +-
 tests/data/test-read-ctf/test-callback2.abi   |   2 +-
 .../test-conflicting-type-syms-a.o.hash.abi   |   4 +-
 .../test-conflicting-type-syms-b.o.hash.abi   |   4 +-
 .../test-read-ctf/test-dynamic-array.o.abi    |   2 +-
 tests/data/test-read-ctf/test-enum-ctf.o.abi  |  24 +
 .../test-enum-many-ctf.o.hash.abi             |  69 +++
 .../test-read-ctf/test-enum-many.o.hash.abi   |   6 +-
 .../test-enum-symbol-ctf.o.hash.abi           |  16 +
 .../test-read-ctf/test-enum-symbol.o.hash.abi |   3 +-
 tests/data/test-read-ctf/test-enum.o.abi      |   6 +-
 .../test-read-ctf/test-forward-type-decl.abi  |   2 +-
 .../test-functions-declaration.abi            |   4 +-
 tests/data/test-read-ctf/test-list-struct.abi |   4 +-
 tests/data/test-read-ctf/test0                | Bin 16656 -> 16896 bytes
 tests/data/test-read-ctf/test0.abi            |  30 +-
 tests/data/test-read-ctf/test0.c              |   6 +
 tests/data/test-read-ctf/test0.hash.abi       |  18 +-
 tests/data/test-read-ctf/test1.so.abi         |  11 +-
 tests/data/test-read-ctf/test1.so.hash.abi    |   7 +-
 tests/data/test-read-ctf/test2.so.abi         |   8 +
 tests/data/test-read-ctf/test2.so.hash.abi    |   8 +
 tests/data/test-read-ctf/test3.so.abi         |   4 +
 tests/data/test-read-ctf/test3.so.hash.abi    |   4 +
 tests/data/test-read-ctf/test4.so.abi         |   6 +
 tests/data/test-read-ctf/test4.so.hash.abi    |   6 +
 tests/data/test-read-ctf/test5.o.abi          |  36 +-
 tests/data/test-read-ctf/test7.o.abi          |  43 +-
 tests/data/test-read-ctf/test8.o.abi          |   2 +-
 tests/data/test-read-ctf/test9.o.abi          |   2 +-
 tests/test-read-ctf.cc                        |  20 +-
 tools/abidw.cc                                |   5 +
 48 files changed, 933 insertions(+), 358 deletions(-)
 create mode 100644 tests/data/test-read-ctf/test-PR27700.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-ctf.o.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi

diff --git a/include/abg-ctf-reader.h b/include/abg-ctf-reader.h
index 3343f0d8..827d1bc2 100644
--- a/include/abg-ctf-reader.h
+++ b/include/abg-ctf-reader.h
@@ -19,6 +19,8 @@
 #include "abg-suppression.h"
 #include "abg-elf-reader-common.h"
 
+#include "ctf-api.h"
+
 namespace abigail
 {
 namespace ctf_reader
@@ -32,8 +34,25 @@ create_read_context(const std::string& elf_path,
                     ir::environment *env);
 corpus_sptr
 read_corpus(read_context *ctxt, elf_reader::status& status);
+
 corpus_sptr
 read_corpus(const read_context_sptr &ctxt, elf_reader::status &status);
+
+corpus_sptr
+read_and_add_corpus_to_group_from_elf(read_context*, corpus_group&, elf_reader::status&);
+
+void
+set_read_context_corpus_group(read_context& ctxt, corpus_group_sptr& group);
+
+void
+reset_read_context(read_context_sptr &ctxt,
+                   const std::string&	elf_path,
+                   ir::environment*	environment);
+void
+set_vmlinux_ctfa_path(read_context& ctxt,
+                      const string& filename);
+std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type);
 } // end namespace ctf_reader
 } // end namespace abigail
 
diff --git a/include/abg-ir.h b/include/abg-ir.h
index a2f4e1a7..033e3708 100644
--- a/include/abg-ir.h
+++ b/include/abg-ir.h
@@ -136,7 +136,16 @@ class environment
 public:
   struct priv;
   std::unique_ptr<priv> priv_;
+  /// The possible debug format types. Default is DWARF_FORMAT_TYPE
+  enum debug_format_type
+  {
+    DWARF_FORMAT_TYPE,
+#ifdef WITH_CTF
+    CTF_FORMAT_TYPE,
+#endif
+  };
 
+  debug_format_type debug_format_;
   /// A convenience typedef for a map of canonical types.  The key is
   /// the pretty representation string of a particular type and the
   /// value is the vector of canonical types that have the same pretty
@@ -236,6 +245,11 @@ public:
   uintptr_t
   get_canonical_type_from_type_id(const char*);
 #endif
+  debug_format_type
+  get_debug_format_type() const;
+
+  void
+  set_debug_format_type(debug_format_type d);
 
   friend class class_or_union;
   friend class class_decl;
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 2c6839cb..dcc65d4e 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -16,6 +16,8 @@
 #include <fcntl.h> /* For open(3) */
 #include <iostream>
 #include <memory>
+#include <map>
+#include <algorithm>
 
 #include "ctf-api.h"
 
@@ -56,15 +58,25 @@ public:
   /// be read from the file then this is NULL.
   ctf_archive_t *ctfa;
 
+  /// The name of the vmlinux file from which the CTF archive got
+  /// extracted.
+  string vmlinux_ctfa_path_;
+
   /// A map associating CTF type ids with libabigail IR types.  This
   /// is used to reuse already generated types.
-  unordered_map<ctf_id_t,type_base_sptr> types_map;
+  std::map<std::string,type_base_sptr> types_map;
+
+  /// A set associating unknown CTF type ids
+  std::set<ctf_id_t> unknown_types_set;
 
   /// libelf handler for the ELF file from which we read the CTF data,
   /// and the corresponding file descriptor.
   Elf *elf_handler;
   int elf_fd;
 
+  /// set when ELF is ET_EXEC
+  bool is_elf_exec;
+
   /// The symtab read from the ELF file.
   symtab_reader::symtab_sptr symtab;
 
@@ -74,26 +86,109 @@ public:
   ctf_sect_t symtab_sect;
   ctf_sect_t strtab_sect;
 
+  corpus_sptr			cur_corpus_;
+  corpus_group_sptr		cur_corpus_group_;
+
+  /// Getter of the current corpus group being constructed.
+  ///
+  /// @return current the current corpus being constructed, if any, or
+  /// nil.
+  const corpus_group_sptr
+  current_corpus_group() const
+  {return cur_corpus_group_;}
+
+  /// Test if there is a corpus group being built.
+  ///
+  /// @return if there is a corpus group being built, false otherwise.
+  bool
+  has_corpus_group() const
+  {return bool(cur_corpus_group_);}
+
+  /// Return the main corpus from the current corpus group, if any.
+  ///
+  /// @return the main corpus of the current corpus group, if any, nil
+  /// if no corpus group is being constructed.
+  corpus_sptr
+  main_corpus_from_current_group()
+  {
+    if (cur_corpus_group_)
+      return cur_corpus_group_->get_main_corpus();
+    return corpus_sptr();
+  }
+
+  /// Test if the current corpus being built is the main corpus of the
+  /// current corpus group.
+  ///
+  /// @return return true iff the current corpus being built is the
+  /// main corpus of the current corpus group.
+  bool
+  current_corpus_is_main_corpus_from_current_group()
+  {
+    corpus_sptr main_corpus = main_corpus_from_current_group();
+
+    if (main_corpus && main_corpus.get() == cur_corpus_.get())
+      return true;
+
+    return false;
+  }
+
+  /// Return true if the current corpus is part of a corpus group
+  /// being built and if it's not the main corpus of the group.
+  ///
+  /// For instance, this would return true if we are loading a linux
+  /// kernel *module* that is part of the current corpus group that is
+  /// being built.  In this case, it means we should re-use types
+  /// coming from the "vmlinux" binary that is the main corpus of the
+  /// group.
+  ///
+  /// @return the corpus group the current corpus belongs to, if the
+  /// current corpus is part of a corpus group being built. Nil otherwise.
+  corpus_sptr
+  should_reuse_type_from_corpus_group()
+  {
+    if (has_corpus_group())
+      if (corpus_sptr main_corpus = main_corpus_from_current_group())
+	if (!current_corpus_is_main_corpus_from_current_group())
+	  return current_corpus_group();
+
+    return corpus_sptr();
+  }
+
   /// Associate a given CTF type ID with a given libabigail IR type.
-  void add_type(ctf_id_t ctf_type, type_base_sptr type)
+  void add_type(ctf_dict_t *dic, ctf_id_t ctf_type, type_base_sptr type)
   {
-    types_map.insert(std::make_pair(ctf_type, type));
+    string key = dic_type_key(dic, ctf_type);
+    types_map.insert(std::make_pair(key, type));
+  }
+
+  /// Insert a given CTF unknown type ID.
+  ///
+  /// @param ctf_type the unknown type ID to be added.
+  void add_unknown_type(ctf_id_t ctf_type)
+  {
+    unknown_types_set.insert(ctf_type);
   }
 
   /// Lookup a given CTF type ID in the types map.
   ///
   /// @param ctf_type the type ID of the type to lookup.
-  type_base_sptr lookup_type(ctf_id_t ctf_type)
+  type_base_sptr lookup_type(ctf_dict_t *dic, ctf_id_t ctf_type)
   {
     type_base_sptr result;
+    std::string key = dic_type_key(dic, ctf_type);
 
-    auto search = types_map.find(ctf_type);
+    auto search = types_map.find(key);
     if (search != types_map.end())
       result = search->second;
 
     return result;
   }
 
+  /// Lookup a given CTF unknown type ID in the unknown set.
+  /// @param ctf_type the unknown type ID to lookup.
+  bool lookup_unknown_type(ctf_id_t ctf_type)
+  { return unknown_types_set.find(ctf_type) != unknown_types_set.end(); }
+
   /// Canonicalize all the types stored in the types map.
   void canonicalize_all_types(void)
   {
@@ -105,19 +200,22 @@ public:
   ///
   /// @param elf_path the path to the ELF file.
   read_context(const string& elf_path, ir::environment *env)
+  {
+    initialize(elf_path, env);
+  }
+
+  void initialize(const string& elf_path, ir::environment *env)
   {
     types_map.clear();
     filename = elf_path;
     ir_env = env;
     elf_handler = NULL;
     elf_fd = -1;
+    is_elf_exec = false;
     ctfa = NULL;
-  }
-
-  /// Destructor of the @ref read_context type.
-  ~read_context()
-  {
-    ctf_close(ctfa);
+    vmlinux_ctfa_path_ = "";
+    symtab.reset();
+    cur_corpus_group_.reset();
   }
 }; // end class read_context.
 
@@ -153,13 +251,18 @@ process_ctf_typedef(read_context *ctxt,
     return result;
 
   const char *typedef_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+  if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+    if (result = lookup_typedef_type(typedef_name, *corp))
+      return result;
+
   type_base_sptr utype = lookup_type(ctxt, corp, tunit,
                                      ctf_dictionary, ctf_utype);
 
   if (!utype)
     return result;
 
-  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_dictionary,
+                                                                ctf_type));
   if (result)
     return result;
 
@@ -180,7 +283,7 @@ process_ctf_typedef(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -225,9 +328,20 @@ process_ctf_base_type(read_context *ctxt,
       type_base_sptr void_type = ctxt->ir_env->get_void_type();
       decl_base_sptr type_declaration = get_type_declaration(void_type);
       result = is_type_decl(type_declaration);
+      canonicalize(result);
     }
   else
     {
+      if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+        {
+          string normalized_type_name = type_name;
+          integral_type int_type;
+          if (parse_integral_type(type_name, int_type))
+            normalized_type_name = int_type.to_string();
+          if (result = lookup_basic_type(normalized_type_name, *corp))
+            return result;
+        }
+
       result = lookup_basic_type(type_name, *corp);
       if (!result)
         result.reset(new type_decl(ctxt->ir_env,
@@ -242,7 +356,7 @@ process_ctf_base_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -303,7 +417,8 @@ process_ctf_function_type(read_context *ctxt,
       function_parms.push_back(parm);
     }
 
-  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_dictionary,
+                                                                 ctf_type));
   if (result)
     return result;
 
@@ -319,7 +434,7 @@ process_ctf_function_type(read_context *ctxt,
       result->set_is_artificial(true);
       decl_base_sptr function_type_decl = get_type_declaration(result);
       add_decl_to_scope(function_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -419,6 +534,11 @@ process_ctf_forward_type(read_context *ctxt,
     }
   else
     {
+      if (!type_is_anonymous)
+        if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+          if (result = lookup_class_type(type_name, *corp))
+            return is_type(result);
+
       class_decl_sptr
        struct_fwd(new class_decl(ctxt->ir_env, type_name,
                                  /*alignment=*/0, /*size=*/0,
@@ -434,7 +554,7 @@ process_ctf_forward_type(read_context *ctxt,
     return is_type(result);
 
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, is_type(result));
+  ctxt->add_type(ctf_dictionary, ctf_type, is_type(result));
 
   return is_type(result);
 }
@@ -458,9 +578,14 @@ process_ctf_struct_type(read_context *ctxt,
 {
   class_decl_sptr result;
   std::string struct_type_name = ctf_type_name_raw(ctf_dictionary,
-                                                 ctf_type);
+                                                   ctf_type);
   bool struct_type_is_anonymous = (struct_type_name == "");
 
+  if (!struct_type_is_anonymous)
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_class_type(struct_type_name, *corp))
+        return result;
+
   /* The libabigail IR encodes C struct types in `class' IR nodes.  */
   result.reset(new class_decl(ctxt->ir_env,
                               struct_type_name,
@@ -479,7 +604,7 @@ process_ctf_struct_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, result);
+  ctxt->add_type(ctf_dictionary, ctf_type, result);
 
   /* Now add the struct members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
@@ -512,6 +637,11 @@ process_ctf_union_type(read_context *ctxt,
                                                    ctf_type);
   bool union_type_is_anonymous = (union_type_name == "");
 
+  if (!union_type_is_anonymous)
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_union_type(union_type_name, *corp))
+        return result;
+
   /* Create the corresponding libabigail union IR node.  */
   result.reset(new union_decl(ctxt->ir_env,
                                 union_type_name,
@@ -528,7 +658,7 @@ process_ctf_union_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, result);
+  ctxt->add_type(ctf_dictionary, ctf_type, result);
 
   /* Now add the union members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
@@ -584,7 +714,8 @@ process_ctf_array_type(read_context *ctxt,
   if (!index_type)
     return result;
 
-  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_dictionary,
+                                                                  ctf_type));
   if (result)
     return result;
 
@@ -623,7 +754,7 @@ process_ctf_array_type(read_context *ctxt,
     {
       decl_base_sptr array_type_decl = get_type_declaration(result);
       add_decl_to_scope(array_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -652,6 +783,11 @@ process_ctf_qualified_type(read_context *ctxt,
   if (!utype)
     return result;
 
+  result = dynamic_pointer_cast<type_base>(ctxt->lookup_type(ctf_dictionary,
+                                                             ctf_type));
+  if (result)
+    return result;
+
   qualified_type_def::CV qualifiers = qualified_type_def::CV_NONE;
   if (type_kind == CTF_K_CONST)
     qualifiers |= qualified_type_def::CV_CONST;
@@ -668,7 +804,7 @@ process_ctf_qualified_type(read_context *ctxt,
     {
       decl_base_sptr qualified_type_decl = get_type_declaration(result);
       add_decl_to_scope(qualified_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -702,7 +838,8 @@ process_ctf_pointer_type(read_context *ctxt,
   if (!target_type)
     return result;
 
-  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_dictionary,
+                                                                    ctf_type));
   if (result)
     return result;
 
@@ -713,7 +850,7 @@ process_ctf_pointer_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -736,6 +873,12 @@ process_ctf_enum_type(read_context *ctxt,
                       ctf_id_t ctf_type)
 {
   enum_type_decl_sptr result;
+  std::string enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+
+  if (!enum_name.empty())
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_enum_type(enum_name, *corp))
+        return result;
 
   /* Build a signed integral type for the type of the enumerators, aka
      the underlying type.  The size of the enumerators in bytes is
@@ -769,13 +912,12 @@ process_ctf_enum_type(read_context *ctxt,
       return result;
     }
 
-  const char *enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
-  result.reset(new enum_type_decl(enum_name, location(),
-                                  utype, enms, enum_name));
+  result.reset(new enum_type_decl(enum_name.c_str(), location(),
+                                  utype, enms, enum_name.c_str()));
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -804,7 +946,10 @@ process_ctf_type(read_context *ctxt,
   int type_kind = ctf_type_kind(ctf_dictionary, ctf_type);
   type_base_sptr result;
 
-  if ((result = ctxt->lookup_type(ctf_type)))
+  if (ctxt->lookup_unknown_type(ctf_type))
+    return nullptr;
+
+  if ((result = ctxt->lookup_type(ctf_dictionary, ctf_type)))
     return result;
 
   switch (type_kind)
@@ -889,7 +1034,10 @@ process_ctf_type(read_context *ctxt,
     }
 
   if (!result)
-    fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+    {
+      fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+      ctxt->add_unknown_type(ctf_type);
+    }
 
   return result;
 }
@@ -913,7 +1061,7 @@ lookup_type(read_context *ctxt, corpus_sptr corp,
             translation_unit_sptr tunit, ctf_dict_t *ctf_dictionary,
             ctf_id_t ctf_type)
 {
-  type_base_sptr result = ctxt->lookup_type(ctf_type);
+  type_base_sptr result = ctxt->lookup_type(ctf_dictionary, ctf_type);
 
   if (!result)
     result = process_ctf_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
@@ -921,8 +1069,8 @@ lookup_type(read_context *ctxt, corpus_sptr corp,
 }
 
 /// Process a CTF archive and create libabigail IR for the types,
-/// variables and function declarations found in the archive.  The IR
-/// is added to the given corpus.
+/// variables and function declarations found in the archive, iterating
+/// over public symbols.  The IR is added to the given corpus.
 ///
 /// @param ctxt the read context containing the CTF archive to
 /// process.
@@ -937,43 +1085,49 @@ process_ctf_archive(read_context *ctxt, corpus_sptr corp)
   ir_translation_unit->set_language(translation_unit::LANG_C);
   corp->add(ir_translation_unit);
 
-  /* Iterate over the CTF dictionaries in the archive.  */
   int ctf_err;
   ctf_dict_t *ctf_dict;
-  ctf_next_t *dict_next = NULL;
-  const char *archive_name;
+  const auto symtab = ctxt->symtab;
+  symtab_reader::symtab_filter filter = symtab->make_filter();
+  filter.set_public_symbols();
+  std::string dict_name;
 
-  while ((ctf_dict = ctf_archive_next(ctxt->ctfa, &dict_next, &archive_name,
-                                      0 /* skip_parent */, &ctf_err)) != NULL)
+  if (corp->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN)
     {
-      /* Iterate over the CTF types stored in this archive.  */
-      ctf_id_t ctf_type;
-      int type_flag;
-      ctf_next_t *type_next = NULL;
+      tools_utils::base_name(ctxt->filename, dict_name);
 
-      while ((ctf_type = ctf_type_next(ctf_dict, &type_next, &type_flag,
-                                       1 /* want_hidden */)) != CTF_ERR)
-        {
-          process_ctf_type(ctxt, corp, ir_translation_unit,
-                            ctf_dict, ctf_type);
-        }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_type_next\n");
+      if (dict_name != "vmlinux")
+        // remove .ko suffix
+        dict_name.erase(dict_name.length() - 3, 3);
 
-      /* Canonicalize all the types generated above.  This must be
-         done "a posteriori" because the processing of types may
-         require other related types to not be already
-         canonicalized.  */
-      ctxt->canonicalize_all_types();
+      std::replace(dict_name.begin(), dict_name.end(), '-', '_');
+    }
 
-      /* Iterate over the CTF variables stored in this archive.  */
+  if ((ctf_dict = ctf_dict_open(ctxt->ctfa,
+                                dict_name.empty() ? NULL : dict_name.c_str(),
+                                &ctf_err)) == NULL)
+    {
+      fprintf(stderr, "ERROR dictionary not found\n");
+      abort();
+    }
+
+  for (const auto& symbol : symtab_reader::filtered_symtab(*symtab, filter))
+    {
+      std::string sym_name = symbol->get_name();
       ctf_id_t ctf_var_type;
-      ctf_next_t *var_next = NULL;
-      const char *var_name;
 
-      while ((ctf_var_type = ctf_variable_next(ctf_dict, &var_next, &var_name))
-             != CTF_ERR)
+      if (corp->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN
+          || ctxt->is_elf_exec)
+        ctf_var_type= ctf_lookup_variable (ctf_dict, sym_name.c_str());
+      else
+        ctf_var_type = ctf_lookup_by_symbol_name(ctf_dict, sym_name.c_str());
+
+      if (ctf_var_type == (ctf_id_t) -1)
+        continue;
+
+      if (ctf_type_kind (ctf_dict, ctf_var_type) != CTF_K_FUNCTION)
         {
+          const char *var_name = sym_name.c_str();
           type_base_sptr var_type = lookup_type(ctxt, corp, ir_translation_unit,
                                                 ctf_dict, ctf_var_type);
           if (!var_type)
@@ -986,50 +1140,38 @@ process_ctf_archive(read_context *ctxt, corpus_sptr corp)
                                              location(),
                                              var_name));
 
+          var_declaration->set_symbol(symbol);
           add_decl_to_scope(var_declaration,
-                             ir_translation_unit->get_global_scope());
+                            ir_translation_unit->get_global_scope());
         }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_variable_next\n");
-
-      /* Iterate over the CTF functions stored in this archive.  */
-      ctf_next_t *func_next = NULL;
-      const char *func_name = NULL;
-      ctf_id_t ctf_sym;
+      else
+        {
+          const char *func_name = sym_name.c_str();
+          ctf_id_t ctf_sym = ctf_var_type;
+          type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
+                                                 ctf_dict, ctf_sym);
+          if (!func_type)
+            /* Ignore function if its type can't be sorted out.  */
+            continue;
 
-      while ((ctf_sym = ctf_symbol_next(ctf_dict, &func_next, &func_name,
-                                        1 /* functions symbols only */) != CTF_ERR))
-      {
-        ctf_id_t ctf_func_type = ctf_lookup_by_name(ctf_dict, func_name);
-        type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
-                                               ctf_dict, ctf_func_type);
-        if (!func_type)
-          /* Ignore function if its type can't be sorted out.  */
-          continue;
-
-        elf_symbols func_elf_symbols = ctxt->symtab->lookup_symbol(func_name);
-        if (func_elf_symbols.size() == 0
-            || func_elf_symbols[0]->get_binding() == elf_symbol::LOCAL_BINDING)
-          /* Ignore local functions.  */
-          continue;
-
-        function_decl_sptr func_declaration;
-        func_declaration.reset(new function_decl(func_name,
-                                                 func_type,
-                                                 0 /* is_inline */,
-                                                 location()));
-
-        add_decl_to_scope(func_declaration,
-                           ir_translation_unit->get_global_scope());
-      }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_symbol_next\n");
+          function_decl_sptr func_declaration;
+          func_declaration.reset(new function_decl(func_name,
+                                                   func_type,
+                                                   0 /* is_inline */,
+                                                   location()));
 
-      ctf_dict_close(ctf_dict);
+          func_declaration->set_symbol(symbol);
+          add_decl_to_scope(func_declaration,
+                            ir_translation_unit->get_global_scope());
+        }
     }
-  if (ctf_err != ECTF_NEXT_END)
-    fprintf(stderr, "ERROR from ctf_archive_next\n");
 
+  ctf_dict_close(ctf_dict);
+  /* Canonicalize all the types generated above.  This must be
+     done "a posteriori" because the processing of types may
+     require other related types to not be already
+     canonicalized.  */
+  ctxt->canonicalize_all_types();
 }
 
 /// Open the ELF file described by the given read context.
@@ -1113,6 +1255,7 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
   /* Set the ELF architecture.  */
   GElf_Ehdr eh_mem;
   GElf_Ehdr *ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem);
+  ctxt->is_elf_exec = (ehdr->e_type == ET_EXEC);
   corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
 
   /* Read the symtab from the ELF file and set it in the corpus.  */
@@ -1121,6 +1264,9 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
                                 0 /* No suppressions.  */);
   corp->set_symtab(ctxt->symtab);
 
+  if (corp->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN)
+    return 1;
+
   /* Get the raw ELF section contents for libctf.  */
   Elf_Scn *ctf_scn = elf_helpers::find_section(ctxt->elf_handler, ".ctf", SHT_PROGBITS);
   Elf_Scn *symtab_scn = elf_helpers::find_symbol_table_section(ctxt->elf_handler);
@@ -1167,6 +1313,7 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
   corpus_sptr corp
     = std::make_shared<corpus>(ctxt->ir_env, ctxt->filename);
 
+  ctxt->cur_corpus_ = corp;
   /* Be optimist.  */
   status = elf_reader::STATUS_OK;
 
@@ -1177,27 +1324,45 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
       return corp;
     }
 
+  bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
   /* Set some properties of the corpus first.  */
-  corp->set_origin(corpus::CTF_ORIGIN);
-  if (!slurp_elf_info(ctxt, corp))
+  if (is_linux_kernel)
+    corp->set_origin(corpus::LINUX_KERNEL_BINARY_ORIGIN);
+  else
+    corp->set_origin(corpus::CTF_ORIGIN);
+
+  if (ctxt->cur_corpus_group_)
+    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
+
+  if (!slurp_elf_info(ctxt, corp) && !is_linux_kernel)
     {
       status = elf_reader::STATUS_NO_SYMBOLS_FOUND;
       return corp;
     }
 
-  /* Build the ctfa from the contents of the relevant ELF sections,
-     and process the CTF archive in the read context, if any.
-     Information about the types, variables, functions, etc contained
-     in the archive are added to the given corpus.  */
   int errp;
-  ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
-                               &ctxt->strtab_sect, &errp);
+  if (corp->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN)
+     ctxt->ctfa = ctf_arc_open(ctxt->vmlinux_ctfa_path_.c_str(), &errp);
+  else
+    /* Build the ctfa from the contents of the relevant ELF sections,
+       and process the CTF archive in the read context, if any.
+       Information about the types, variables, functions, etc contained
+       in the archive are added to the given corpus.  */
+    ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
+                                 &ctxt->strtab_sect, &errp);
+
+  ctxt->ir_env->canonicalization_is_done(false);
   if (ctxt->ctfa == NULL)
     status = elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
   else
     process_ctf_archive(ctxt, corp);
 
+  ctxt->ir_env->canonicalization_is_done(true);
+  ctxt->cur_corpus_->sort_functions();
+  ctxt->cur_corpus_->sort_variables();
+
   /* Cleanup and return.  */
+  ctf_close(ctxt->ctfa);
   close_elf_handler(ctxt);
   return corp;
 }
@@ -1216,5 +1381,93 @@ corpus_sptr
 read_corpus(const read_context_sptr &ctxt, elf_reader::status &status)
 {return read_corpus(ctxt.get(), status);}
 
+/// Set the @ref corpus_group being created to the current read context.
+///
+/// @param ctxt the read_context to consider.
+///
+/// @param group the @ref corpus_group to set.
+void
+set_read_context_corpus_group(read_context& ctxt,
+                              corpus_group_sptr& group)
+{
+  ctxt.cur_corpus_group_ = group;
+}
+//
+/// Read a corpus and add it to a given @ref corpus_group.
+///
+/// @param ctxt the reading context to consider.
+///
+/// @param group the @ref corpus_group to add the new corpus to.
+///
+/// @param status output parameter. The status of the read.  It is set
+/// by this function upon its completion.
+corpus_sptr
+read_and_add_corpus_to_group_from_elf(read_context* ctxt,
+                                      corpus_group& group,
+                                      elf_reader::status& status)
+{
+  corpus_sptr result;
+  corpus_sptr corp = read_corpus(ctxt, status);
+  if (status & elf_reader::STATUS_OK)
+    {
+      if (!corp->get_group())
+        group.add_corpus(corp);
+      result = corp;
+    }
+
+  return result;
+}
+
+/// Re-initialize a read_context so that it can re-used to read
+/// another binary.
+///
+/// @param ctxt the context to re-initialize.
+///
+/// @param elf_path the path to the elf file the context is to be used
+/// for.
+///
+/// @param environment the environment used by the current context.
+/// This environment contains resources needed by the reader and by
+/// the types and declarations that are to be created later.  Note
+/// that ABI artifacts that are to be compared all need to be created
+/// within the same environment.
+///
+/// Please also note that the life time of this environment object
+/// must be greater than the life time of the resulting @ref
+/// read_context the context uses resources that are allocated in the
+/// environment.
+void
+reset_read_context(read_context_sptr	&ctxt,
+                   const std::string&	 elf_path,
+                   ir::environment*	 environment)
+{
+  if (ctxt)
+    ctxt->initialize(elf_path, environment);
+}
+
+/// Set the @ref filename being assigned to the current read context.
+///
+/// @param ctxt the read_context to consider.
+///
+/// @param filename the @ref vmlinux CTFA filename to set.
+void
+set_vmlinux_ctfa_path(read_context& ctxt,
+                      const string& filename)
+{
+  ctxt.vmlinux_ctfa_path_ = filename;
+}
+
+std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type)
+{
+  std::stringstream key;
+
+  if (ctf_type_isparent (dic, ctf_type))
+    key << std::hex << ctf_type;
+  else
+    key << std::hex << ctf_type << '-' << ctf_cuname(dic);
+  return key.str();
+}
+
 } // End of namespace ctf_reader
 } // End of namespace abigail
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 0ef5e8b2..5eebcfa3 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -3165,7 +3165,8 @@ typedef unordered_map<interned_string,
 
 /// Default constructor of the @ref environment type.
 environment::environment()
-  :priv_(new priv)
+  :priv_(new priv),
+  debug_format_(DWARF_FORMAT_TYPE)
 {}
 
 /// Destructor for the @ref environment type.
@@ -3779,6 +3780,20 @@ environment::get_canonical_type_from_type_id(const char* type_id)
   return 0;
 }
 #endif
+
+/// Getter of the debug format of the source.
+///
+/// @return the debug format of the source.
+environment::debug_format_type
+environment::get_debug_format_type() const
+{return debug_format_;}
+
+/// Setter of the debug format of the source.
+///
+/// @param d the new debug format.
+void
+environment::set_debug_format_type(environment::debug_format_type d)
+{debug_format_ = d;}
 // </environment stuff>
 
 // <type_or_decl_base stuff>
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index e94c3003..b73786a8 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -44,6 +44,9 @@
 #include <sstream>
 
 #include "abg-dwarf-reader.h"
+#ifdef WITH_CTF
+#include "abg-ctf-reader.h"
+#endif
 #include "abg-internal.h"
 #include "abg-regex.h"
 
@@ -2234,9 +2237,11 @@ load_generate_apply_suppressions(dwarf_reader::read_context &read_ctxt,
 ///
 /// @param entry the FTSENT to consider.
 ///
+/// @param filename the name of file.
+///
 /// @return true iff @p entry is for a vmlinux binary.
 static bool
-is_vmlinux(const FTSENT *entry)
+is_vmlinux(const FTSENT *entry, const string &filename)
 {
   if (entry == NULL
       || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
@@ -2246,7 +2251,7 @@ is_vmlinux(const FTSENT *entry)
 
   string fname = entry->fts_name;
 
-  if (fname == "vmlinux")
+  if (fname == filename)
     {
       string dirname;
       dir_name(entry->fts_path, dirname);
@@ -2317,7 +2322,7 @@ find_vmlinux_and_module_paths(const string&	from,
 	  continue;
 	}
 
-      if (!found_vmlinux && is_vmlinux(entry))
+      if (!found_vmlinux && is_vmlinux(entry, "vmlinux"))
 	{
 	  vmlinux_path = entry->fts_path;
 	  found_vmlinux = true;
@@ -2337,10 +2342,13 @@ find_vmlinux_and_module_paths(const string&	from,
 ///
 /// @param vmlinux_path output parameter
 ///
+/// @param vmlinux_name output parameter
+///
 /// return true iff the vmlinux binary was found
 static bool
 find_vmlinux_path(const string&	from,
-		  string		&vmlinux_path)
+		  string		&vmlinux_path,
+		  const string		&vmlinux_name)
 {
   char* path[] = {const_cast<char*>(from.c_str()), 0};
 
@@ -2359,7 +2367,7 @@ find_vmlinux_path(const string&	from,
 	  continue;
 	}
 
-      if (!found_vmlinux && is_vmlinux(entry))
+      if (!found_vmlinux && is_vmlinux(entry, vmlinux_name))
 	{
 	  vmlinux_path = entry->fts_path;
 	  found_vmlinux = true;
@@ -2456,12 +2464,37 @@ get_vmlinux_path_from_kernel_dist(const string&	from,
     dist_root += "/lib/modules";
 
   bool found = false;
-  if (find_vmlinux_path(dist_root, vmlinux_path))
+  if (find_vmlinux_path(dist_root, vmlinux_path, "vmlinux"))
     found = true;
 
   return found;
 }
 
+/// Get the paths of the CTF vmlinux archive under given directory.
+///
+/// @param from the directory under which to look for.
+///
+/// @param vmlinux_path output parameter.  The path of the CTF vmlinux
+/// binary that was found.
+///
+/// @return true if at least the path to the vmlinux.ctfa binary was found.
+#ifdef WITH_CTF
+bool
+get_vmlinux_ctfa_path_from_kernel_dist(const string& from,
+                                       string& vmlinux_ctfa_path)
+{
+  if (!dir_exists(from))
+    return false;
+
+  string dist_root = from;
+  bool found = false;
+  if (find_vmlinux_path(dist_root, vmlinux_ctfa_path, "vmlinux.ctfa"))
+    found = true;
+
+  return found;
+}
+#endif
+
 /// Get the paths of the vmlinux and kernel module binaries under
 /// given directory.
 ///
@@ -2543,12 +2576,21 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
   t.start();
   bool got_binary_paths =
     get_binary_paths_from_kernel_dist(root, debug_info_root, vmlinux, modules);
+#ifdef WITH_CTF
+  string vmlinux_ctfa;
+  if (got_binary_paths &&
+      env->get_debug_format_type() == environment::CTF_FORMAT_TYPE)
+    {
+      got_binary_paths = get_vmlinux_ctfa_path_from_kernel_dist(root, vmlinux_ctfa);
+      ABG_ASSERT(!vmlinux_ctfa.empty());
+    }
+#endif
+
   t.stop();
 
   if (verbose)
     std::cerr << "DONE: " << t << "\n";
 
-  dwarf_reader::read_context_sptr ctxt;
   if (got_binary_paths)
     {
       shared_ptr<char> di_root =
@@ -2558,81 +2600,149 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
       di_roots.push_back(&di_root_ptr);
       abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
       corpus_group_sptr group;
-      if (!vmlinux.empty())
-	{
-	  ctxt =
-	    dwarf_reader::create_read_context(vmlinux, di_roots ,env.get(),
-					      /*read_all_types=*/false,
-					      /*linux_kernel_mode=*/true);
-	  dwarf_reader::set_do_log(*ctxt, verbose);
-
-	  t.start();
-	  load_generate_apply_suppressions(*ctxt, suppr_paths,
-					   kabi_wl_paths, supprs);
-	  t.stop();
-
-	  if (verbose)
-	    std::cerr << "loaded white list and generated suppr spec in: "
-		      << t
-		      << "\n";
-
-	  group.reset(new corpus_group(env.get(), root));
-
-	  set_read_context_corpus_group(*ctxt, group);
-
-	  if (verbose)
-	    std::cerr << "reading kernel binary '"
-		      << vmlinux << "' ...\n" << std::flush;
-
-	  // Read the vmlinux corpus and add it to the group.
-	  t.start();
-	  read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
-	  t.stop();
-
-	  if (verbose)
-	    std::cerr << vmlinux
-		      << " reading DONE:"
-		      << t << "\n";
-	}
 
-      if (!group->is_empty())
-	{
-	  // Now add the corpora of the modules to the corpus group.
-	  int total_nb_modules = modules.size();
-	  int cur_module_index = 1;
-	  for (vector<string>::const_iterator m = modules.begin();
-	       m != modules.end();
-	       ++m, ++cur_module_index)
-	    {
-	      if (verbose)
-		std::cerr << "reading module '"
-			  << *m << "' ("
-			  << cur_module_index
-			  << "/" << total_nb_modules
-			  << ") ... " << std::flush;
-
-	      reset_read_context(ctxt, *m, di_roots, env.get(),
-				 /*read_all_types=*/false,
-				 /*linux_kernel_mode=*/true);
-
-	      load_generate_apply_suppressions(*ctxt, suppr_paths,
-					       kabi_wl_paths, supprs);
-
-	      set_read_context_corpus_group(*ctxt, group);
-
-	      t.start();
-	      read_and_add_corpus_to_group_from_elf(*ctxt,
-						    *group, status);
-	      t.stop();
-	      if (verbose)
-		std::cerr << "module '"
-			  << *m
-			  << "' reading DONE: "
-			  << t << "\n";
-	    }
-
-	  result = group;
-	}
+      if (env->get_debug_format_type() == environment::DWARF_FORMAT_TYPE)
+        {
+          dwarf_reader::read_context_sptr ctxt;
+          if (!vmlinux.empty())
+            {
+              ctxt =
+               dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
+                                                 /*read_all_types=*/false,
+                                                 /*linux_kernel_mode=*/true);
+              dwarf_reader::set_do_log(*ctxt, verbose);
+
+              t.start();
+              load_generate_apply_suppressions(*ctxt, suppr_paths,
+                                               kabi_wl_paths, supprs);
+              t.stop();
+
+              if (verbose)
+                std::cerr << "loaded white list and generated suppr spec in: "
+                 << t
+                 << "\n";
+
+              group.reset(new corpus_group(env.get(), root));
+
+              set_read_context_corpus_group(*ctxt, group);
+
+              if (verbose)
+                std::cerr << "reading kernel binary '"
+                 << vmlinux << "' ...\n" << std::flush;
+
+              // Read the vmlinux corpus and add it to the group.
+              t.start();
+              read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
+              t.stop();
+
+              if (verbose)
+                std::cerr << vmlinux
+                 << " reading DONE:"
+                 << t << "\n";
+            }
+
+          if (!group->is_empty())
+            {
+              // Now add the corpora of the modules to the corpus group.
+              int total_nb_modules = modules.size();
+              int cur_module_index = 1;
+              for (vector<string>::const_iterator m = modules.begin();
+                   m != modules.end();
+                   ++m, ++cur_module_index)
+                {
+                  if (verbose)
+                    std::cerr << "reading module '"
+                     << *m << "' ("
+                     << cur_module_index
+                     << "/" << total_nb_modules
+                     << ") ... " << std::flush;
+
+                  reset_read_context(ctxt, *m, di_roots, env.get(),
+                                     /*read_all_types=*/false,
+                                     /*linux_kernel_mode=*/true);
+
+                  load_generate_apply_suppressions(*ctxt, suppr_paths,
+                                                   kabi_wl_paths, supprs);
+
+                  set_read_context_corpus_group(*ctxt, group);
+
+                  t.start();
+                  read_and_add_corpus_to_group_from_elf(*ctxt,
+                                                        *group, status);
+                  t.stop();
+                  if (verbose)
+                    std::cerr << "module '"
+                     << *m
+                     << "' reading DONE: "
+                     << t << "\n";
+                }
+
+              result = group;
+            }
+        }
+#ifdef WITH_CTF
+      else if (env->get_debug_format_type() == environment::CTF_FORMAT_TYPE)
+        {
+          ctf_reader::read_context_sptr ctxt;
+          if (!vmlinux.empty())
+            {
+              ctxt =
+               ctf_reader::create_read_context(vmlinux, env.get());
+              set_vmlinux_ctfa_path(*ctxt, vmlinux_ctfa);
+
+              group.reset(new corpus_group(env.get(), root));
+              set_read_context_corpus_group(*ctxt, group);
+
+              if (verbose)
+                std::cerr << "reading kernel binary '"
+                 << vmlinux << "' ...\n" << std::flush;
+
+              // Read the vmlinux corpus and add it to the group.
+              t.start();
+              read_and_add_corpus_to_group_from_elf(ctxt.get(), *group, status);
+              t.stop();
+
+              if (verbose)
+                std::cerr << vmlinux
+                 << " reading DONE:"
+                 << t << "\n";
+            }
+
+           if (!group->is_empty())
+             {
+               // Now add the corpora of the modules to the corpus group.
+               int total_nb_modules = modules.size();
+               int cur_module_index = 1;
+               for (vector<string>::const_iterator m = modules.begin();
+                    m != modules.end();
+                    ++m, ++cur_module_index)
+                 {
+                   if (verbose)
+                     std::cerr << "reading module '"
+                      << *m << "' ("
+                      << cur_module_index
+                      << "/" << total_nb_modules
+                      << ") ... " << std::flush;
+
+                   reset_read_context(ctxt, *m, env.get());
+                   set_vmlinux_ctfa_path(*ctxt, vmlinux_ctfa);
+                   set_read_context_corpus_group(*ctxt, group);
+
+                   t.start();
+                   read_and_add_corpus_to_group_from_elf(ctxt.get(),
+                                                         *group, status);
+                   t.stop();
+                   if (verbose)
+                     std::cerr << "module '"
+                      << *m
+                      << "' reading DONE: "
+                      << t << "\n";
+                 }
+
+               result = group;
+             }
+        }
+#endif
     }
 
   return result;
diff --git a/tests/data/test-read-common/test-PR26568-2.o b/tests/data/test-read-common/test-PR26568-2.o
index b192d52132766d4f95136e23f93de43a64d8cc2e..a6706e8cf508ab89927b0fccecd0268d27111ed9 100644
GIT binary patch
delta 1078
zcmZuwJ#Q015Z%3R+XNC4+rf~Wtw;eB%$Z17uE0<rBAO5pQBj=FADpo7f_)Bl6-1ZL
zWGcFpL83uvC{3skO-dR>8YF6d0W;^l$g=#T(agS?dAmD%_cwibb#Nn{HP|`IVN_-*
zmVAHz`rg0aiWKFRqCj{BJsEYAeL@S+bhImI1kPB7YSeJW7>OZA(1_29CDoC}EE<7w
zsFR{tqeK}CFQZ3+WdmmP^q!2X1vG><a*WfqD3v0Dy2fxZJc8>5tjC(Z*T_=XXAjt}
z?^ap8>oM!4->O-aex+~uZQE(qtWMjpnr_9exDDHF=DRzcpk1?DR#58%`Hoe!1A7!B
zTg^LutL1wmVsmS~c(+)}uitjUGkmTeaY###a!yds<{P6;&yUgdUU~i-FRVO%A=#X(
z@LEpFGSh{RlZR`{0vyU3p8->G4^#sN$`0Q;=IRA5qc9}2U+_o!rrts&jvez*)(z<y
zhq%6+DH2IrOblko;Y44x?_h?eUPc?osd&1fAm`B&6{#!={vrBl@{jSw2nX<8H*?z<
zO{+Q+RTgX*D@)VPF%XYjfQ^Kyx}-xlj9sGd0P!4Rx@lK2n$|rO-Mz4uF}g(@ZSodf
z<mh|_v~kqME)ML+%*<O%g;i0zC_R<oB(|CxL}@`s?g^a?u|^{52aLiiNV^K&Bn6B5
zZ0;kH^#6!)U^GHcv=+iCenpb@pR76(RVCPuuiTtAhZ2b+qF19i%t11-Hg_g^e};Md
Wwcu&OlD??$E^#lmDcXL}kpBaNjDTqX

delta 508
zcmZvYJ4*vW6oqH@mA%=G1lhO&i`^hZLkd#{K}{MFY|?3G0>KAJj1W*_wN`>n^!NiJ
zq)4A4oum?*^g<f#EN$)F*&Rj1f#J-(ocZRS=`X&!y%l$8u%A_lP8F76&h6&%=#dXO
zot(A~{o_`L;XvIQP1OeH8s4;wsxm_=NwtKcqdVy9dz|p8pK~@kGi;8l#0+(Ff<9?z
zlA|0kbSV!%EC=Ki>RLR*Bo;Ows%V+A&PrWJgIxNM)g7wIC4r-B9=BEzkjHoMKyJa;
z<6cR+1v3%uzsx3bA#*GVy9i8=??;51BwYL=&_9GWa+XVTN^Gm4YI*z;4a-&P3c6OF
z-$aI)G!!Gly?9nJ)bP(1&@<C~fSm1;sm7EN0z1rRJ5-jPa+GZ>Cd)j_$-e(ZWJ_ae
b7pX1XF9?zz{8U!i*07e^pjUb2Nd)`?0Gw2F

diff --git a/tests/data/test-read-ctf/PR27700/test-PR27700.abi b/tests/data/test-read-ctf/PR27700/test-PR27700.abi
index 62df1017..fe3a897d 100644
--- a/tests/data/test-read-ctf/PR27700/test-PR27700.abi
+++ b/tests/data/test-read-ctf/PR27700/test-PR27700.abi
@@ -11,9 +11,8 @@
       <enumerator name='foo_e2' value='2'/>
       <enumerator name='foo_e3' value='3'/>
     </enum-decl>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <pointer-type-def type-id='022218d8' size-in-bits='64' alignment-in-bits='64' id='8750e847'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
       <parameter type-id='8750e847'/>
       <return type-id='48b5725f'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR26568-1.o.abi b/tests/data/test-read-ctf/test-PR26568-1.o.abi
index d62474ec..832dc1bd 100644
--- a/tests/data/test-read-ctf/test-PR26568-1.o.abi
+++ b/tests/data/test-read-ctf/test-PR26568-1.o.abi
@@ -7,47 +7,29 @@
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='' type-id='type-id-2' visibility='default'/>
       </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='' type-id='type-id-5' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
-      </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
+        <var-decl name='y' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-5'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-5'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
+        <var-decl name='x' type-id='type-id-6' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
     <union-decl name='' size-in-bits='64' is-anonymous='yes' visibility='default' id='type-id-2'>
-      <data-member access='public'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
-      </data-member>
-      <data-member access='public'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
-      </data-member>
       <data-member access='public'>
         <var-decl name='' type-id='type-id-5' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
+        <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
     </union-decl>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fun'>
       <parameter type-id='type-id-7'/>
       <return type-id='type-id-8'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR26568-2.o.abi b/tests/data/test-read-ctf/test-PR26568-2.o.abi
index a934d15b..70e0772f 100644
--- a/tests/data/test-read-ctf/test-PR26568-2.o.abi
+++ b/tests/data/test-read-ctf/test-PR26568-2.o.abi
@@ -3,34 +3,28 @@
     <elf-symbol name='fun' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-2' visibility='default'/>
+        <var-decl name='y' type-id='type-id-2' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-4' visibility='default'/>
+        <var-decl name='x' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-2'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <union-decl name='A' size-in-bits='64' visibility='default' id='type-id-5'>
-      <data-member access='public'>
-        <var-decl name='' type-id='type-id-1' visibility='default'/>
-      </data-member>
-      <data-member access='public'>
-        <var-decl name='x' type-id='type-id-2' visibility='default'/>
-      </data-member>
       <data-member access='public'>
         <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='y' type-id='type-id-4' visibility='default'/>
+        <var-decl name='' type-id='type-id-1' visibility='default'/>
       </data-member>
     </union-decl>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fun'>
       <parameter type-id='type-id-6'/>
       <return type-id='type-id-7'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR27700.abi b/tests/data/test-read-ctf/test-PR27700.abi
new file mode 100644
index 00000000..fe3a897d
--- /dev/null
+++ b/tests/data/test-read-ctf/test-PR27700.abi
@@ -0,0 +1,21 @@
+<abi-corpus version='2.1' path='data/test-read-common/PR27700/test-PR27700.o'>
+  <elf-function-symbols>
+    <elf-symbol name='foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-function-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='foo' linkage-name='foo' id='022218d8'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='foo_e0' value='0'/>
+      <enumerator name='foo_e1' value='1'/>
+      <enumerator name='foo_e2' value='2'/>
+      <enumerator name='foo_e3' value='3'/>
+    </enum-decl>
+    <pointer-type-def type-id='022218d8' size-in-bits='64' alignment-in-bits='64' id='8750e847'/>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='8750e847'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi b/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
index 922a1daf..12050a5b 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
@@ -30,7 +30,6 @@
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='7359adad'/>
     <pointer-type-def type-id='3ed987a4' size-in-bits='64' alignment-in-bits='64' id='84d5ac12'/>
     <pointer-type-def type-id='1c12b755' size-in-bits='64' alignment-in-bits='64' id='55cd64e8'/>
-    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default'/>
-    <var-decl name='foo' type-id='55cd64e8' mangled-name='foo' visibility='default'/>
+    <var-decl name='foo' type-id='55cd64e8' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.c b/tests/data/test-read-ctf/test-ambiguous-struct-B.c
index 95a93469..e592529b 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-B.c
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-B.c
@@ -2,4 +2,4 @@ struct A;
 struct B { struct A *a; };
 struct A { struct B b; int foo; struct B b2; };
 
-static struct A a __attribute__((__used__));
+struct A a __attribute__((__used__));
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.o b/tests/data/test-read-ctf/test-ambiguous-struct-B.o
index 06bd0f502a874ad4a10c4beb5788eaace44c2bf9..40a11fcbd4ae19b78a943812f69606cdc6c9fc15 100644
GIT binary patch
delta 20
ccmX@Wb%1Nb8%9RK&2Jg^GchtvUdu8W08_UIfB*mh

delta 20
ccmX@Wb%1Nb8%9RP&2Jg^GchtxUdu8W08;!1aR2}S

diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi b/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
index 28291eb5..83d21919 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-ctf/test-ambiguous-struct-B.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='a' size='24' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
   <abi-instr address-size='64' language='LANG_C'>
     <class-decl name='A' size-in-bits='192' alignment-in-bits='64' is-struct='yes' visibility='default' id='3ed987a4'>
       <data-member access='public' layout-offset-in-bits='0'>
@@ -18,6 +21,6 @@
     </class-decl>
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
     <pointer-type-def type-id='3ed987a4' size-in-bits='64' alignment-in-bits='64' id='84d5ac12'/>
-    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default'/>
+    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default' elf-symbol-id='a'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-anonymous-fields.o.abi b/tests/data/test-read-ctf/test-anonymous-fields.o.abi
index 0419c29c..2134a86d 100644
--- a/tests/data/test-read-ctf/test-anonymous-fields.o.abi
+++ b/tests/data/test-read-ctf/test-anonymous-fields.o.abi
@@ -3,14 +3,14 @@
     <elf-symbol name='t' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-variable-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='vaddr' type-id='type-id-2' visibility='default'/>
+        <var-decl name='dup_xol_work' type-id='type-id-2' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='dup_xol_work' type-id='type-id-4' visibility='default'/>
+        <var-decl name='vaddr' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
     <class-decl name='uprobe_task' size-in-bits='64' alignment-in-bits='64' is-struct='yes' visibility='default' id='type-id-5'>
@@ -18,16 +18,16 @@
         <var-decl name='' type-id='type-id-6' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-2'/>
     <union-decl name='' size-in-bits='64' is-anonymous='yes' visibility='default' id='type-id-6'>
       <data-member access='public'>
-        <var-decl name='' type-id='type-id-1' visibility='default'/>
+        <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
+        <var-decl name='' type-id='type-id-1' visibility='default'/>
       </data-member>
     </union-decl>
-    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='t' type-id='type-id-5' mangled-name='t' visibility='default'/>
+    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
+    <var-decl name='t' type-id='type-id-5' mangled-name='t' visibility='default' elf-symbol-id='t'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-array-of-pointers.abi b/tests/data/test-read-ctf/test-array-of-pointers.abi
index 920da28b..195361df 100644
--- a/tests/data/test-read-ctf/test-array-of-pointers.abi
+++ b/tests/data/test-read-ctf/test-array-of-pointers.abi
@@ -31,6 +31,6 @@
     <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
     <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-11'/>
-    <var-decl name='t' type-id='type-id-11' mangled-name='t' visibility='default'/>
+    <var-decl name='t' type-id='type-id-11' mangled-name='t' visibility='default' elf-symbol-id='t'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-callback.abi b/tests/data/test-read-ctf/test-callback.abi
index 704c4971..7f9b6c5f 100644
--- a/tests/data/test-read-ctf/test-callback.abi
+++ b/tests/data/test-read-ctf/test-callback.abi
@@ -4,28 +4,16 @@
     <elf-symbol name='f2' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='test' size-in-bits='64' alignment-in-bits='64' is-struct='yes' visibility='default' id='type-id-1'>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='fn1' type-id='type-id-2' visibility='default'/>
-      </data-member>
-    </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
-    <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
-    <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <function-decl name='assign' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <return type-id='type-id-7'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
+    <function-decl name='assign' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='assign'>
+      <return type-id='type-id-3'/>
     </function-decl>
-    <function-decl name='f2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-3'/>
-      <parameter type-id='type-id-4'/>
-      <return type-id='type-id-7'/>
+    <function-decl name='f2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='f2'>
+      <parameter type-id='type-id-1'/>
+      <parameter type-id='type-id-2'/>
+      <return type-id='type-id-3'/>
     </function-decl>
-    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-6'>
-      <parameter type-id='type-id-3'/>
-      <parameter type-id='type-id-4'/>
-      <return type-id='type-id-7'/>
-    </function-type>
-    <type-decl name='void' id='type-id-7'/>
+    <type-decl name='void' id='type-id-3'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-callback2.abi b/tests/data/test-read-ctf/test-callback2.abi
index bdd4ad33..ddc3e493 100644
--- a/tests/data/test-read-ctf/test-callback2.abi
+++ b/tests/data/test-read-ctf/test-callback2.abi
@@ -11,7 +11,7 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
-    <var-decl name='s0' type-id='type-id-5' mangled-name='s0' visibility='default'/>
+    <var-decl name='s0' type-id='type-id-5' mangled-name='s0' visibility='default' elf-symbol-id='s0'/>
     <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-4'>
       <parameter type-id='type-id-5'/>
       <return type-id='type-id-3'/>
diff --git a/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi b/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
index 03dd56b3..8d5c3e36 100644
--- a/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
+++ b/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
@@ -8,7 +8,7 @@
     <typedef-decl name='a_t' type-id='bd54fe1a' id='40acc204'/>
     <typedef-decl name='b_t' type-id='bd54fe1a' id='b3d2db81'/>
     <pointer-type-def type-id='40acc204' size-in-bits='64' alignment-in-bits='64' id='c6fd4117'/>
-    <var-decl name='a' type-id='c6fd4117' mangled-name='a' visibility='default'/>
-    <var-decl name='ignore2' type-id='b3d2db81' mangled-name='ignore2' visibility='default'/>
+    <var-decl name='a' type-id='c6fd4117' mangled-name='a' visibility='default' elf-symbol-id='a'/>
+    <var-decl name='ignore2' type-id='b3d2db81' mangled-name='ignore2' visibility='default' elf-symbol-id='ignore2'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi b/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
index 35bcac7a..992b669d 100644
--- a/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
+++ b/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
@@ -7,7 +7,7 @@
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='bd54fe1a'/>
     <typedef-decl name='a_t' type-id='bd54fe1a' id='40acc204'/>
     <typedef-decl name='b_t' type-id='bd54fe1a' id='b3d2db81'/>
-    <var-decl name='b' type-id='40acc204' mangled-name='b' visibility='default'/>
-    <var-decl name='ignore1' type-id='b3d2db81' mangled-name='ignore1' visibility='default'/>
+    <var-decl name='b' type-id='40acc204' mangled-name='b' visibility='default' elf-symbol-id='b'/>
+    <var-decl name='ignore1' type-id='b3d2db81' mangled-name='ignore1' visibility='default' elf-symbol-id='ignore1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-dynamic-array.o.abi b/tests/data/test-read-ctf/test-dynamic-array.o.abi
index 02b22811..a9849d49 100644
--- a/tests/data/test-read-ctf/test-dynamic-array.o.abi
+++ b/tests/data/test-read-ctf/test-dynamic-array.o.abi
@@ -21,7 +21,7 @@
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-3'/>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <function-decl name='use_struct_s' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='use_struct_s' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='use_struct_s'>
       <parameter type-id='type-id-7'/>
       <return type-id='type-id-8'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-enum-ctf.o.abi b/tests/data/test-read-ctf/test-enum-ctf.o.abi
new file mode 100644
index 00000000..f36f3fad
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-ctf.o.abi
@@ -0,0 +1,24 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='bar' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='foo' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
+    <enum-decl name='e' linkage-name='e' id='type-id-2'>
+      <underlying-type type-id='type-id-1'/>
+      <enumerator name='ENUMSAMPLE_1' value='0'/>
+      <enumerator name='ENUMSAMPLE_2' value='1'/>
+    </enum-decl>
+    <enum-decl name='ie' linkage-name='ie' id='type-id-3'>
+      <underlying-type type-id='type-id-1'/>
+      <enumerator name='IENUMSAMPLE_1' value='-10'/>
+      <enumerator name='IENUMSAMPLE_2' value='-9'/>
+      <enumerator name='IENUMSAMPLE_3' value='-8'/>
+    </enum-decl>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
+    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default'/>
+    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi b/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
new file mode 100644
index 00000000..67a958a7
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
@@ -0,0 +1,69 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-many-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='bar' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='foo' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='e' linkage-name='e' id='a6c2eddf'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='ENUMSAMPLE_1' value='0'/>
+      <enumerator name='ENUMSAMPLE_2' value='1'/>
+    </enum-decl>
+    <enum-decl name='ie' linkage-name='ie' id='1ee696ca'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='IE_0' value='-10'/>
+      <enumerator name='IE_1' value='-9'/>
+      <enumerator name='IE_2' value='-8'/>
+      <enumerator name='IE_3' value='-7'/>
+      <enumerator name='IE_4' value='-6'/>
+      <enumerator name='IE_5' value='-5'/>
+      <enumerator name='IE_6' value='-4'/>
+      <enumerator name='IE_7' value='-3'/>
+      <enumerator name='IE_8' value='-2'/>
+      <enumerator name='IE_9' value='-1'/>
+      <enumerator name='IE_A' value='0'/>
+      <enumerator name='IE_B' value='1'/>
+      <enumerator name='IE_C' value='2'/>
+      <enumerator name='IE_D' value='3'/>
+      <enumerator name='IE_E' value='4'/>
+      <enumerator name='IE_F' value='5'/>
+      <enumerator name='IE_10' value='6'/>
+      <enumerator name='IE_11' value='7'/>
+      <enumerator name='IE_12' value='8'/>
+      <enumerator name='IE_13' value='9'/>
+      <enumerator name='IE_14' value='10'/>
+      <enumerator name='IE_15' value='11'/>
+      <enumerator name='IE_16' value='12'/>
+      <enumerator name='IE_17' value='13'/>
+      <enumerator name='IE_18' value='14'/>
+      <enumerator name='IE_19' value='15'/>
+      <enumerator name='IE_1A' value='16'/>
+      <enumerator name='IE_1B' value='17'/>
+      <enumerator name='IE_1C' value='18'/>
+      <enumerator name='IE_1D' value='19'/>
+      <enumerator name='IE_1E' value='20'/>
+      <enumerator name='IE_1F' value='21'/>
+      <enumerator name='IE_20' value='22'/>
+      <enumerator name='IE_21' value='23'/>
+      <enumerator name='IE_22' value='24'/>
+      <enumerator name='IE_23' value='25'/>
+      <enumerator name='IE_24' value='26'/>
+      <enumerator name='IE_25' value='27'/>
+      <enumerator name='IE_26' value='28'/>
+      <enumerator name='IE_27' value='29'/>
+      <enumerator name='IE_28' value='30'/>
+      <enumerator name='IE_29' value='31'/>
+      <enumerator name='IE_2A' value='32'/>
+      <enumerator name='IE_2B' value='33'/>
+      <enumerator name='IE_2C' value='34'/>
+      <enumerator name='IE_2D' value='35'/>
+      <enumerator name='IE_2E' value='36'/>
+      <enumerator name='IE_2F' value='37'/>
+    </enum-decl>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
+    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default'/>
+    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-many.o.hash.abi b/tests/data/test-read-ctf/test-enum-many.o.hash.abi
index 26bc048c..116325f9 100644
--- a/tests/data/test-read-ctf/test-enum-many.o.hash.abi
+++ b/tests/data/test-read-ctf/test-enum-many.o.hash.abi
@@ -61,9 +61,7 @@
       <enumerator name='IE_2E' value='36'/>
       <enumerator name='IE_2F' value='37'/>
     </enum-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
-    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default'/>
-    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default'/>
+    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
+    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default' elf-symbol-id='bar'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi b/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi
new file mode 100644
index 00000000..fea6eb8b
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi
@@ -0,0 +1,16 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-symbol-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='primary1' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='' is-anonymous='yes' id='08f5ca17'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='red1' value='0'/>
+      <enumerator name='green1' value='1'/>
+      <enumerator name='blue1' value='2'/>
+    </enum-decl>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
+    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi b/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
index d128b5b1..f4911bc4 100644
--- a/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
+++ b/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
@@ -10,7 +10,6 @@
       <enumerator name='green1' value='1'/>
       <enumerator name='blue1' value='2'/>
     </enum-decl>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
-    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default'/>
+    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default' elf-symbol-id='primary1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum.o.abi b/tests/data/test-read-ctf/test-enum.o.abi
index 88e6ad61..bd3a55be 100644
--- a/tests/data/test-read-ctf/test-enum.o.abi
+++ b/tests/data/test-read-ctf/test-enum.o.abi
@@ -16,9 +16,7 @@
       <enumerator name='IENUMSAMPLE_2' value='-9'/>
       <enumerator name='IENUMSAMPLE_3' value='-8'/>
     </enum-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
-    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default'/>
-    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default'/>
+    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
+    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default' elf-symbol-id='bar'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-forward-type-decl.abi b/tests/data/test-read-ctf/test-forward-type-decl.abi
index 21bb45c8..026e7d32 100644
--- a/tests/data/test-read-ctf/test-forward-type-decl.abi
+++ b/tests/data/test-read-ctf/test-forward-type-decl.abi
@@ -24,6 +24,6 @@
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-3'/>
     <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='addr' type-id='type-id-5' mangled-name='addr' visibility='default'/>
+    <var-decl name='addr' type-id='type-id-5' mangled-name='addr' visibility='default' elf-symbol-id='addr'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-functions-declaration.abi b/tests/data/test-read-ctf/test-functions-declaration.abi
index 9ef05e44..7eb57d26 100644
--- a/tests/data/test-read-ctf/test-functions-declaration.abi
+++ b/tests/data/test-read-ctf/test-functions-declaration.abi
@@ -7,11 +7,11 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
-    <function-decl name='attribute_container_add_device' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='attribute_container_add_device' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='attribute_container_add_device'>
       <parameter type-id='type-id-4'/>
       <return type-id='type-id-5'/>
     </function-decl>
-    <function-decl name='attribute_container_device_trigger' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='attribute_container_device_trigger' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='attribute_container_device_trigger'>
       <parameter type-id='type-id-4'/>
       <return type-id='type-id-5'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-list-struct.abi b/tests/data/test-read-ctf/test-list-struct.abi
index 196a79a1..deb6a4a1 100644
--- a/tests/data/test-read-ctf/test-list-struct.abi
+++ b/tests/data/test-read-ctf/test-list-struct.abi
@@ -14,7 +14,7 @@
     </class-decl>
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='n1' type-id='type-id-1' mangled-name='n1' visibility='default'/>
-    <var-decl name='n2' type-id='type-id-1' mangled-name='n2' visibility='default'/>
+    <var-decl name='n1' type-id='type-id-1' mangled-name='n1' visibility='default' elf-symbol-id='n1'/>
+    <var-decl name='n2' type-id='type-id-1' mangled-name='n2' visibility='default' elf-symbol-id='n2'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test0 b/tests/data/test-read-ctf/test0
index aca7fbacdfff7ad2caf0142390710373a8da72a1..90aa8a39a2e1326a5cb5faaa9e854fc344caaa52 100755
GIT binary patch
delta 1886
zcmah~L2MgE6rEkWZra+(ZUVNWHnG!6kSdbB4pp+Tz+NFxdrBKokU<E`3NA_s+0=1R
z!hsZ2LDU1-`4W{lz<~poN(}_6o**g+6(K-AQK3qlDyTRVq*5i9m^ZV3s^AM>djHSN
zd;ibh8SlFBwsHP~(HKr_=EVc^gezjg69eK<vp6(*(+n6LyI2@P3<F6yP|@SqTr2Ef
zl@x3>-2C<akjol3<f&C1(`qI}nm)_)Rb@(vl_gf{_&~`STwXkLyZ*8q|L+c**G1dL
z4@cxgW?8@<;P~XT!aOfF<(dJ&=o@or;}3H+`nh#uFt^0*{Ik>cCEMV+OqRCA^GGli
z>$IIInx!!1vl-J3)7k7`$O(J&cW80VdGA07&*>>?n$G1?dj~K!MU=jF68%x}p%rjS
z05{6)U9bt^c>!xMeHzgay_Cwy+>9NtOp13EYtzZxal@iZxop2JP89yD`B7>5=r>fb
zh1bE}QKfpQXEf3Ou)y|eu3azM=tbv6uyK*>U=M?}M4WuEG4X9jZ%4t}B0(RIW{o)g
ztb7~FZu}sEUGyzq<Xy6l$rHHDyJ+?jvt_VxG0d#VEq<wX>8AHp?loq0|C=(`#L0t=
ziZq}62-7#gTIleuVkf!(1I*r0l@pXYCiitZD&s=c)13s1jE+0)4%m&AW2eoP6DW8M
z#YTYVF^&Uo0S^IJ033+;4u}FRzy@vsG2nMVHgpf@15DJ|i#Q9wBJy?hfI+OoBJ$AE
zfW>o!M+8J>1B<W-8dLAZCu%ApQU^Zt4mslo?J}=&8DpAW952VN2CJe6@hiG9K4QE{
z_r|~2bH?|}Ir`K+5`L{RGe_UM&I@9pUa2oGI2?1LUR|h{E45l>IT%j+a|`ugcxKkG
z@NnLrnX6Z8!FmlTwV7$AUiW7!^_kf!nG;V(UzuCX%-8(+YOTJ!;Z5u_=v3a?pA31b
z!(@og=Eq_#Pt`|*rb2yd1#4go3VCqy`K6Uuq`pW}M4Nf*sJtrq(reWctCsk?m6WNl
z2)<~Em8USe-){R_tv?$LRv%JYs5#2Z+HI4V$jjCF>%7}K=gV%S$-WIh=W`c_#dBDc
zT3uj^3v6)#m(Jx=D=$IO-qj|)R9F$h;WtdTr=zZ><Ezl_?8<jJ-{t(YEC%arGguW*
ziZ?KlT3xWj1xj4NVWn=M<2l6zYCc{xE>a7=LG}|x;{%$4|A?CKm#GDRmFz;%xK2~>
zKT)&rXuoVnnyx1Q4W#`-Eog3$T`U^6X$t;NYQq0TE%<G+y;N6%50I{mCFztmY#gLz
O&);`_A}FyV&-Gt@S^P)<

delta 1541
zcmZ9MO-NKx6vxlKZ?tqYpOznE<-FXa2=ifIqf@>+MHB?NX;F)iHf3#0R0<+&`XH#N
z(X+7HWF#?*pbraz7G=z0T7=Llf`~Sev~ZQw#_8Pq&Mlh@@7#Cp?|;rc_r81Ih07v$
zQRF(B-Cp?H6r>;w3O2y{34c@fpbUuZSF_NeK15HRd0r~=v_CP~SN%(4YQLO`PfHC2
z))b`DgHVvzD%<e1EZ||sn;ms-)L<@@d*&9~lHaA$68O1X8Zs}AGF^qS0E6sTvhU&V
zm@kVC_Qqo}@8GF;n=|bw%!bA$6F0+>CR0Z0;czm#Y9qZ%2;=KSb0iFR-GCVZnQo?w
zM4LdVfC|Qks25O=(WH)z)d!RzTs73i{^UMUhf~RT#D)ER|7+eGO#^<R3@)fLx?obR
z!Mg6|$U30ujc-i@mC-<z`$QX|rHr-{b)gZ5h}J-%thP>~_0WX(y5ph|=Z!6qvKGJ#
zX3?Kgw`)90e2d<JM?8zAQ%nblHbMte8HB<MGfOSrGO;h2GK4oeR?^NB4THx!-^KVN
zQI{%QH1r_XA7;8>GB;s#tDZMemYF`NSzSNTYD%N*l%`)3(An{=ha|p{q4Cp{Y@X2Z
zKvt<ww4&!N`+Bh+J<r)EIgmzPVW09*sQ|axXYQQ)pX*`WV)~>WF|SZbxhr*YaTI5E
z4Ajm9!%#>4BXm<;;w<h=J;$X~J8tZWS0!L%^w{XwND?3R?44cik%CsRYBKFs|GRG3
zn%-VpkjkVoHx0i!Yw=0i?c7FV`rhb@b+dQtI}fx3!%%@wW6k49@|H@aA*%*Q1)T5l
z2CL>?@7v0jCP#lT8}D(v$MO4FtoK82j*aIk+F=h3YOPIRulgV-Na3b*bo>A*N-N5o
z=4qx`Wq%CzhhekX{xHQauZYice4gVy;<}ZW8H~biI6-gvjM#)lPEh0o30B$y%GL?P
znBC=zGdM@~Jc>SFT*3_5>zE~b2j|E>K;ir1F=oiV!mPhJVwYvJ=@Y110q02b4u$f?
o2h5QDh*`3qagOXa6q%?P!TXsgs!WGy#gmz#s<xgW_J`ikKQHOTvj6}9

diff --git a/tests/data/test-read-ctf/test0.abi b/tests/data/test-read-ctf/test0.abi
index 50ca26f4..fc61f2ac 100644
--- a/tests/data/test-read-ctf/test0.abi
+++ b/tests/data/test-read-ctf/test0.abi
@@ -39,16 +39,26 @@
     </array-type-def>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-10'/>
     <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='type-id-11'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='type-id-12'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-13'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-14'/>
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='type-id-15'/>
-    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-16'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
-    <qualified-type-def type-id='type-id-3' const='yes' id='type-id-18'/>
-    <pointer-type-def type-id='type-id-10' size-in-bits='64' alignment-in-bits='64' id='type-id-19'/>
-    <qualified-type-def type-id='type-id-19' restrict='yes' id='type-id-20'/>
-    <qualified-type-def type-id='type-id-11' volatile='yes' id='type-id-21'/>
+    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-12'/>
+    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-13'/>
+    <qualified-type-def type-id='type-id-3' const='yes' id='type-id-14'/>
+    <pointer-type-def type-id='type-id-10' size-in-bits='64' alignment-in-bits='64' id='type-id-15'/>
+    <qualified-type-def type-id='type-id-15' restrict='yes' id='type-id-16'/>
+    <qualified-type-def type-id='type-id-11' volatile='yes' id='type-id-17'/>
+    <var-decl name='status' type-id='type-id-5' mangled-name='status' visibility='default' elf-symbol-id='status'/>
+    <var-decl name='test_pointer' type-id='type-id-13' mangled-name='test_pointer' visibility='default' elf-symbol-id='test_pointer'/>
+    <var-decl name='test_const' type-id='type-id-14' mangled-name='test_const' visibility='default' elf-symbol-id='test_const'/>
+    <var-decl name='test_float' type-id='type-id-6' mangled-name='test_float' visibility='default' elf-symbol-id='test_float'/>
+    <function-decl name='foo_1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo_1'>
+      <parameter type-id='type-id-12'/>
+      <return type-id='type-id-4'/>
+    </function-decl>
+    <function-decl name='main' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='main'>
+      <return type-id='type-id-4'/>
+    </function-decl>
+    <var-decl name='test_array' type-id='type-id-7' mangled-name='test_array' visibility='default' elf-symbol-id='test_array'/>
+    <var-decl name='test_restrict' type-id='type-id-16' mangled-name='test_restrict' visibility='default' elf-symbol-id='test_restrict'/>
+    <var-decl name='test_volatile' type-id='type-id-17' mangled-name='test_volatile' visibility='default' elf-symbol-id='test_volatile'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test0.c b/tests/data/test-read-ctf/test0.c
index eb702312..fdefd57c 100644
--- a/tests/data/test-read-ctf/test0.c
+++ b/tests/data/test-read-ctf/test0.c
@@ -1,3 +1,9 @@
+/*
+ * ELF EXEC files must use -Wl,--ctf-variables -Bdynimic options
+ * to export an ABI and store CTF symbols information.
+ *
+ * ctf-gcc -gctf -Wl,--ctf-variables -Bdynamic test0.c -o test0
+ */
 
 #include <stdio.h>
 
diff --git a/tests/data/test-read-ctf/test0.hash.abi b/tests/data/test-read-ctf/test0.hash.abi
index b58520ab..eff32228 100644
--- a/tests/data/test-read-ctf/test0.hash.abi
+++ b/tests/data/test-read-ctf/test0.hash.abi
@@ -39,16 +39,26 @@
     </array-type-def>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='bd54fe1a'/>
     <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='a2185560'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='28577a57'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='002ac4a6'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='7359adad'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='8efea9e5'/>
     <pointer-type-def type-id='50d9a3fa' size-in-bits='64' alignment-in-bits='64' id='fd01f598'/>
     <pointer-type-def type-id='a84c031d' size-in-bits='64' alignment-in-bits='64' id='26a90f95'/>
     <qualified-type-def type-id='50d9a3fa' const='yes' id='0fb3b55d'/>
     <pointer-type-def type-id='bd54fe1a' size-in-bits='64' alignment-in-bits='64' id='3ccc2590'/>
     <qualified-type-def type-id='3ccc2590' restrict='yes' id='af4b1b38'/>
     <qualified-type-def type-id='a2185560' volatile='yes' id='ec67e496'/>
+    <var-decl name='status' type-id='e7f43f72' mangled-name='status' visibility='default' elf-symbol-id='status'/>
+    <var-decl name='test_pointer' type-id='26a90f95' mangled-name='test_pointer' visibility='default' elf-symbol-id='test_pointer'/>
+    <var-decl name='test_const' type-id='0fb3b55d' mangled-name='test_const' visibility='default' elf-symbol-id='test_const'/>
+    <var-decl name='test_float' type-id='a6c45d85' mangled-name='test_float' visibility='default' elf-symbol-id='test_float'/>
+    <function-decl name='foo_1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo_1'>
+      <parameter type-id='fd01f598'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <function-decl name='main' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='main'>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <var-decl name='test_array' type-id='b7bd1749' mangled-name='test_array' visibility='default' elf-symbol-id='test_array'/>
+    <var-decl name='test_restrict' type-id='af4b1b38' mangled-name='test_restrict' visibility='default' elf-symbol-id='test_restrict'/>
+    <var-decl name='test_volatile' type-id='ec67e496' mangled-name='test_volatile' visibility='default' elf-symbol-id='test_volatile'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test1.so.abi b/tests/data/test-read-ctf/test1.so.abi
index 5b3caf63..416bd39d 100644
--- a/tests/data/test-read-ctf/test1.so.abi
+++ b/tests/data/test-read-ctf/test1.so.abi
@@ -16,8 +16,13 @@
     </enum-decl>
     <typedef-decl name='opaque_enum' type-id='type-id-4' id='type-id-3'/>
     <typedef-decl name='opaque_struct' type-id='type-id-2' id='type-id-5'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
-    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
+    <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
+    <function-decl name='fn' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fn'>
+      <parameter type-id='type-id-7'/>
+      <parameter type-id='type-id-6'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-8'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test1.so.hash.abi b/tests/data/test-read-ctf/test1.so.hash.abi
index 8019cb54..b3620e75 100644
--- a/tests/data/test-read-ctf/test1.so.hash.abi
+++ b/tests/data/test-read-ctf/test1.so.hash.abi
@@ -16,8 +16,13 @@
     </enum-decl>
     <typedef-decl name='opaque_enum' type-id='55763a91' id='99fcd3a5'/>
     <typedef-decl name='opaque_struct' type-id='6cde5052' id='dae69ca1'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <pointer-type-def type-id='99fcd3a5' size-in-bits='64' alignment-in-bits='64' id='0e0526e0'/>
     <pointer-type-def type-id='dae69ca1' size-in-bits='64' alignment-in-bits='64' id='3f6e71d0'/>
+    <function-decl name='fn' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fn'>
+      <parameter type-id='3f6e71d0'/>
+      <parameter type-id='0e0526e0'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test2.so.abi b/tests/data/test-read-ctf/test2.so.abi
index eb6aff3e..67f802f9 100644
--- a/tests/data/test-read-ctf/test2.so.abi
+++ b/tests/data/test-read-ctf/test2.so.abi
@@ -20,6 +20,14 @@
     <qualified-type-def type-id='type-id-8' const='yes' id='type-id-9'/>
     <pointer-type-def type-id='type-id-9' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <pointer-type-def type-id='type-id-8' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
+      <parameter type-id='type-id-7'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='type-id-6'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
     <type-decl name='void' id='type-id-8'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test2.so.hash.abi b/tests/data/test-read-ctf/test2.so.hash.abi
index 6e57333b..6bbf347e 100644
--- a/tests/data/test-read-ctf/test2.so.hash.abi
+++ b/tests/data/test-read-ctf/test2.so.hash.abi
@@ -20,6 +20,14 @@
     <qualified-type-def type-id='48b5725f' const='yes' id='8581546e'/>
     <pointer-type-def type-id='8581546e' size-in-bits='64' alignment-in-bits='64' id='6e97a70c'/>
     <pointer-type-def type-id='48b5725f' size-in-bits='64' alignment-in-bits='64' id='eaa32e2f'/>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
+      <parameter type-id='5e30a4f9'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='842ea234'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
     <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test3.so.abi b/tests/data/test-read-ctf/test3.so.abi
index 9d55fec5..3d2f6326 100644
--- a/tests/data/test-read-ctf/test3.so.abi
+++ b/tests/data/test-read-ctf/test3.so.abi
@@ -8,5 +8,9 @@
     <elf-symbol name='foo__' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
+    <function-decl name='__foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='__foo'>
+      <return type-id='type-id-1'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test3.so.hash.abi b/tests/data/test-read-ctf/test3.so.hash.abi
index 9d55fec5..1c69e2e1 100644
--- a/tests/data/test-read-ctf/test3.so.hash.abi
+++ b/tests/data/test-read-ctf/test3.so.hash.abi
@@ -8,5 +8,9 @@
     <elf-symbol name='foo__' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
+    <function-decl name='__foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='__foo'>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test4.so.abi b/tests/data/test-read-ctf/test4.so.abi
index b8e0ead3..dc18e191 100644
--- a/tests/data/test-read-ctf/test4.so.abi
+++ b/tests/data/test-read-ctf/test4.so.abi
@@ -10,5 +10,11 @@
     <qualified-type-def type-id='type-id-1' const='yes' id='type-id-5'/>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
     <qualified-type-def type-id='type-id-6' restrict='yes' id='type-id-7'/>
+    <function-decl name='cpy' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='cpy'>
+      <parameter type-id='type-id-4'/>
+      <parameter type-id='type-id-7'/>
+      <parameter type-id='type-id-2'/>
+      <return type-id='type-id-3'/>
+    </function-decl>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test4.so.hash.abi b/tests/data/test-read-ctf/test4.so.hash.abi
index dbe34d9c..dc428592 100644
--- a/tests/data/test-read-ctf/test4.so.hash.abi
+++ b/tests/data/test-read-ctf/test4.so.hash.abi
@@ -10,5 +10,11 @@
     <qualified-type-def type-id='a84c031d' const='yes' id='9b45d938'/>
     <pointer-type-def type-id='9b45d938' size-in-bits='64' alignment-in-bits='64' id='80f4b756'/>
     <qualified-type-def type-id='80f4b756' restrict='yes' id='9d26089a'/>
+    <function-decl name='cpy' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='cpy'>
+      <parameter type-id='266fe297'/>
+      <parameter type-id='9d26089a'/>
+      <parameter type-id='f0981eeb'/>
+      <return type-id='26a90f95'/>
+    </function-decl>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test5.o.abi b/tests/data/test-read-ctf/test5.o.abi
index eb30cf6a..f7bcdeb1 100644
--- a/tests/data/test-read-ctf/test5.o.abi
+++ b/tests/data/test-read-ctf/test5.o.abi
@@ -17,34 +17,32 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <type-decl name='long long int' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <type-decl name='long long unsigned int' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <typedef-decl name='long_long' type-id='type-id-6' id='type-id-8'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-9'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-10'/>
-    <qualified-type-def type-id='type-id-4' const='yes' id='type-id-11'/>
-    <qualified-type-def type-id='type-id-5' const='yes' id='type-id-12'/>
-    <qualified-type-def type-id='type-id-12' volatile='yes' id='type-id-13'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-10'/>
-      <parameter type-id='type-id-13'/>
+    <typedef-decl name='long_long' type-id='type-id-6' id='type-id-7'/>
+    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <qualified-type-def type-id='type-id-4' const='yes' id='type-id-9'/>
+    <qualified-type-def type-id='type-id-5' const='yes' id='type-id-10'/>
+    <qualified-type-def type-id='type-id-10' volatile='yes' id='type-id-11'/>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='type-id-8'/>
+      <parameter type-id='type-id-11'/>
       <return type-id='type-id-5'/>
     </function-decl>
-    <function-decl name='baz2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='baz2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='baz2'>
       <parameter type-id='type-id-4'/>
-      <return type-id='type-id-8'/>
+      <return type-id='type-id-7'/>
     </function-decl>
-    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
       <parameter is-variadic='yes'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <function-decl name='bar2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar2'>
       <parameter type-id='type-id-3'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <function-decl name='baz' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='baz' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='baz'>
       <parameter type-id='type-id-4'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <type-decl name='void' id='type-id-14'/>
+    <type-decl name='void' id='type-id-12'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test7.o.abi b/tests/data/test-read-ctf/test7.o.abi
index b744fac5..a13af174 100644
--- a/tests/data/test-read-ctf/test7.o.abi
+++ b/tests/data/test-read-ctf/test7.o.abi
@@ -3,40 +3,31 @@
     <elf-symbol name='first_type_constructor' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <type-decl name='char' size-in-bits='8' alignment-in-bits='8' id='type-id-1'/>
-    <class-decl name='first_type' size-in-bits='128' alignment-in-bits='32' is-struct='yes' visibility='default' id='type-id-2'>
+    <class-decl name='first_type' size-in-bits='128' alignment-in-bits='32' is-struct='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='member0' type-id='type-id-3' visibility='default'/>
+        <var-decl name='member0' type-id='type-id-2' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='32'>
-        <var-decl name='member1' type-id='type-id-4' visibility='default'/>
+        <var-decl name='member1' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='64'>
-        <var-decl name='ctor' type-id='type-id-5' visibility='default'/>
+        <var-decl name='ctor' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <type-decl name='long long int' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
-    <type-decl name='long long unsigned int' size-in-bits='64' alignment-in-bits='64' id='type-id-9'/>
-    <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='type-id-10'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='type-id-11'/>
-    <typedef-decl name='character' type-id='type-id-12' id='type-id-4'/>
-    <typedef-decl name='constructor' type-id='type-id-13' id='type-id-5'/>
-    <typedef-decl name='integer' type-id='type-id-6' id='type-id-3'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-12'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-14'/>
-    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-15'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='type-id-16'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
-    <pointer-type-def type-id='type-id-18' size-in-bits='64' alignment-in-bits='64' id='type-id-13'/>
-    <function-decl name='first_type_constructor' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-17'/>
-      <return type-id='type-id-19'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
+    <typedef-decl name='character' type-id='type-id-6' id='type-id-3'/>
+    <typedef-decl name='constructor' type-id='type-id-7' id='type-id-4'/>
+    <typedef-decl name='integer' type-id='type-id-5' id='type-id-2'/>
+    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-6'/>
+    <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-9' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
+    <function-decl name='first_type_constructor' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='first_type_constructor'>
+      <parameter type-id='type-id-8'/>
+      <return type-id='type-id-10'/>
     </function-decl>
-    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-18'>
-      <return type-id='type-id-19'/>
+    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-9'>
+      <return type-id='type-id-10'/>
     </function-type>
-    <type-decl name='void' id='type-id-19'/>
+    <type-decl name='void' id='type-id-10'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test8.o.abi b/tests/data/test-read-ctf/test8.o.abi
index 68b3af06..b6996c29 100644
--- a/tests/data/test-read-ctf/test8.o.abi
+++ b/tests/data/test-read-ctf/test8.o.abi
@@ -4,7 +4,7 @@
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
       <parameter type-id='type-id-2'/>
       <return type-id='type-id-1'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test9.o.abi b/tests/data/test-read-ctf/test9.o.abi
index 746dd77b..08704d79 100644
--- a/tests/data/test-read-ctf/test9.o.abi
+++ b/tests/data/test-read-ctf/test9.o.abi
@@ -49,7 +49,7 @@
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-16' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
     <pointer-type-def type-id='type-id-18' size-in-bits='64' alignment-in-bits='64' id='type-id-20'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
       <parameter type-id='type-id-22'/>
       <return type-id='type-id-16'/>
     </function-decl>
diff --git a/tests/test-read-ctf.cc b/tests/test-read-ctf.cc
index fdf49e90..215ed8d6 100644
--- a/tests/test-read-ctf.cc
+++ b/tests/test-read-ctf.cc
@@ -269,20 +269,28 @@ static InOutSpec in_out_specs[] =
     "output/test-read-ctf/test-list-struct.abi",
   },
   {
-    "data/test-read-ctf/test-callback2.o",
+    "data/test-read-common/test-PR26568-1.o",
     "",
     "",
     SEQUENCE_TYPE_ID_STYLE,
-    "data/test-read-ctf/test-callback2.abi",
-    "output/test-read-ctf/test-callback2.abi",
+    "data/test-read-ctf/test-PR26568-1.o.abi",
+    "output/test-read-ctf/test-PR26568-1.o.abi",
   },
   {
-    "data/test-read-ctf/test-forward-undefine-type-decl.o",
+    "data/test-read-common/test-PR26568-2.o",
     "",
     "",
     SEQUENCE_TYPE_ID_STYLE,
-    "data/test-read-ctf/test-forward-undefine-type-decl.abi",
-    "output/test-read-ctf/test-forward-undefine-type-decl.abi",
+    "data/test-read-ctf/test-PR26568-2.o.abi",
+    "output/test-read-ctf/test-PR26568-2.o.abi",
+  },
+  {
+    "data/test-read-ctf/test-callback2.o",
+    "",
+    "",
+    SEQUENCE_TYPE_ID_STYLE,
+    "data/test-read-ctf/test-callback2.abi",
+    "output/test-read-ctf/test-callback2.abi",
   },
   // This should be the last entry.
   {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
diff --git a/tools/abidw.cc b/tools/abidw.cc
index f7a8937d..f9287b47 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -958,6 +958,11 @@ main(int argc, char* argv[])
   environment_sptr env(new environment);
   int exit_code = 0;
 
+#ifdef WITH_CTF
+  if (opts.use_ctf)
+    env->set_debug_format_type(environment::CTF_FORMAT_TYPE);
+#endif
+
   if (tools_utils::is_regular_file(opts.in_file_path))
     exit_code = load_corpus_and_write_abixml(argv, env, opts);
   else
-- 
2.35.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] ctf-reader: Add support to read CTF information from Linux kernel
  2022-04-29 14:16 ` [PATCH v2] " Guillermo E. Martinez
@ 2022-05-03 15:32   ` Dodji Seketeli
  2022-05-04 12:48     ` Guillermo E. Martinez
  2022-05-04 22:29     ` [PATCH v3] " Guillermo E. Martinez
  0 siblings, 2 replies; 10+ messages in thread
From: Dodji Seketeli @ 2022-05-03 15:32 UTC (permalink / raw)
  To: Guillermo E. Martinez via Libabigail

Hello Guillermo,

Thanks a lot for this patch!  I like it.

I do have some comments however.
Please find them below.

[...]

diff --git a/include/abg-ir.h b/include/abg-ir.h
index a2f4e1a7..033e3708 100644
--- a/include/abg-ir.h
+++ b/include/abg-ir.h
@@ -136,7 +136,16 @@ class environment
 public:
   struct priv;
   std::unique_ptr<priv> priv_;
+  /// The possible debug format types. Default is DWARF_FORMAT_TYPE
+  enum debug_format_type
+  {
+    DWARF_FORMAT_TYPE,
+#ifdef WITH_CTF
+    CTF_FORMAT_TYPE,
+#endif
+  };

I'd prefer abg-ir.h to stay agnostic from front-end considerations
such as the kind of input (DWARF, CTF etc) as much as possible.  Those
considerations are handled in abg-corpus.h with the
abigail::corpus::origin enum, which is currently defined as:

  /// This abstracts where the corpus comes from.  That is, either it
  /// has been read from the native xml format, from DWARF or built
  /// artificially using the library's API.
  enum origin
  {
    ARTIFICIAL_ORIGIN = 0,
    NATIVE_XML_ORIGIN,
    DWARF_ORIGIN,
    CTF_ORIGIN,
    LINUX_KERNEL_BINARY_ORIGIN
  };

You can modify it to make it be a bitmap defined as:

  enum origin
  {
    ARTIFICIAL_ORIGIN = 0,
    NATIVE_XML_ORIGIN = 1,
    DWARF_ORIGIN = 1 << 1,
    CTF_ORIGIN = 1 << 2,
    LINUX_KERNEL_BINARY_ORIGIN = 1 << 3
  };

That way, you can modify abg-{ctf-reader,dwarf-reader,ir}.cc so that
instead of saying:

    if (corp->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN)
      // blah

it would instead say:

    if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
      // blah

or even:

    if (corp->get_origin()
	& corpus::LINUX_KERNEL_BINARY_ORIGIN
	& corpus:: CTF_ORIGIN)
      // blah

The different parts of the code that test for return of
corpus::get_origin() should be updated to take into account that the
value returned is now a bitmap.

Of course, in abg-ctf-reader.cc, the origin of the corpus would be set by doing:

    corp->set_origin(corpus::LINUX_KERNEL_BINARY_ORIGIN
		     | corpus::CTF_ORIGIN);

and in abg-dwarf-reader.cc, the origin of the corpus would be set by
doing: 

    ctxt.current_corpus()->set_origin(corpus::LINUX_KERNEL_BINARY_ORIGIN
				      | corpus::DWARF_ORIGIN);

[...]

+  debug_format_type debug_format_;

So, the abigail::ir::environment type should not have a debug_format_
data member.  If anything, all the data members are hidden in the
abigail::ir::environment::priv_, which is a pointer to
abigail::ir::environment::priv, defined in abg-ir-priv.h.  But I think
it's not neccessary to add anything there.  More on that below.

[...]

diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 2c6839cb..dcc65d4e 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc

[...]

+  void initialize(const string& elf_path, ir::environment *env)
   {

Please, add a doxygen comment to this function.

[...]

+std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type)
+{

Likewise.

diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 0ef5e8b2..5eebcfa3 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -3165,7 +3165,8 @@ typedef unordered_map<interned_string,
 
 /// Default constructor of the @ref environment type.
 environment::environment()
-  :priv_(new priv)
+  :priv_(new priv),
+  debug_format_(DWARF_FORMAT_TYPE)
 {}

As said above, the debug_format_ data member should not be added to
the environment type.

[...]

diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index 1f0f6fa8..faa7243f 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc

[...]

@@ -2543,12 +2576,21 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
   t.start();
   bool got_binary_paths =
     get_binary_paths_from_kernel_dist(root, debug_info_root, vmlinux, modules);
+#ifdef WITH_CTF
+  string vmlinux_ctfa;
+  if (got_binary_paths &&
+      env->get_debug_format_type() == environment::CTF_FORMAT_TYPE)
+    {
+      got_binary_paths = get_vmlinux_ctfa_path_from_kernel_dist(root, vmlinux_ctfa);
+      ABG_ASSERT(!vmlinux_ctfa.empty());
+    }
+#endif
+

I think, rather than calling env->get_debug_format_type()
build_corpus_group_from_kernel_dist_under can be passed an additional
'corpus_origin' parameter of type corpus::origin.  The parameter would
have corpus::DWARF_ORIGIN as default argument, for instance.

Also, I think the rest of this function that follows could be
encapsulated into two functions that would be called:

    maybe_load_vmlinux_dwarf_corpus()

This function would load the vmlinux corpus from the ELF information.
That function would contain the code that is inside the block:

+      if (env->get_debug_format_type() == environment::DWARF_FORMAT_TYPE)
+        {

The new condition inside the function would rather be something like:

    if (corpus_origin & corpus::DWARF_ORIGIN)
      {
         //blah
      }
The function wouldn't do anything if the origin of the corpus is not DWARF.


The second function would be this one:

maybe_load_vmlinux_ctf_corpus()

it's invocation would be protected by an #ifdef WITH_CTF and its body
would be inside an if-block that would read:

    if (corpus_origin & corpus::CTF_ORIGIN)
      {
        // blah

I hope this all makes sense.  If not, please do not hesitate to discuss
it.

Thanks again.

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] ctf-reader: Add support to read CTF information from Linux kernel
  2022-05-03 15:32   ` Dodji Seketeli
@ 2022-05-04 12:48     ` Guillermo E. Martinez
  2022-05-12  8:50       ` Dodji Seketeli
  2022-05-04 22:29     ` [PATCH v3] " Guillermo E. Martinez
  1 sibling, 1 reply; 10+ messages in thread
From: Guillermo E. Martinez @ 2022-05-04 12:48 UTC (permalink / raw)
  To: Guillermo E. Martinez via Libabigail, Dodji Seketeli

On Tuesday, May 3, 2022 10:32:53 AM CDT Dodji Seketeli wrote:
> Hello Guillermo,
> 
> Thanks a lot for this patch!  I like it.
oohh, thanks!!
> I do have some comments however.
> Please find them below.
great,
> [...]
> 
> diff --git a/include/abg-ir.h b/include/abg-ir.h
> index a2f4e1a7..033e3708 100644
> --- a/include/abg-ir.h
> +++ b/include/abg-ir.h
> @@ -136,7 +136,16 @@ class environment
>  public:
>    struct priv;
>    std::unique_ptr<priv> priv_;
> +  /// The possible debug format types. Default is DWARF_FORMAT_TYPE
> +  enum debug_format_type
> +  {
> +    DWARF_FORMAT_TYPE,
> +#ifdef WITH_CTF
> +    CTF_FORMAT_TYPE,
> +#endif
> +  };
I added this enum to handle the options::use_ctf (--ctf) from command line,
this option is passed thought abigail::ir::environment instance to know which
reader needs to be instantiated:

if (opts.use_ctf)
    env->set_debug_format_type(environment::CTF_FORMAT_TYPE);

if (env->get_debug_format_type() == environment::DWARF_FORMAT_TYPE)
  {
     // dwarf reader
  }
else if (env->get_debug_format_type() == environment::CTF_FORMAT_TYPE)
  { 
     // ctf reader
  }

By default is environment::DWARF_FORMAT_TYPE in include/abg-ir.h

Otherwise I think that we need to change the arguments in 
`build_corpus_group_from_kernel_dist_under'. For sure I can do this :-).

> I'd prefer abg-ir.h to stay agnostic from front-end considerations
> such as the kind of input (DWARF, CTF etc) as much as possible.  Those
> considerations are handled in abg-corpus.h with the
> abigail::corpus::origin enum, which is currently defined as:
> 
>   /// This abstracts where the corpus comes from.  That is, either it
>   /// has been read from the native xml format, from DWARF or built
>   /// artificially using the library's API.
>   enum origin
>   {
>     ARTIFICIAL_ORIGIN = 0,
>     NATIVE_XML_ORIGIN,
>     DWARF_ORIGIN,
>     CTF_ORIGIN,
>     LINUX_KERNEL_BINARY_ORIGIN
>   };
> 
> You can modify it to make it be a bitmap defined as:
> 
>   enum origin
>   {
>     ARTIFICIAL_ORIGIN = 0,
>     NATIVE_XML_ORIGIN = 1,
>     DWARF_ORIGIN = 1 << 1,
>     CTF_ORIGIN = 1 << 2,
>     LINUX_KERNEL_BINARY_ORIGIN = 1 << 3
>   };
> 
> That way, you can modify abg-{ctf-reader,dwarf-reader,ir}.cc so that
> instead of saying:
> 
>     if (corp->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN)
>       // blah
> 
> it would instead say:
> 
>     if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
>       // blah
> 
> or even:
> 
>     if (corp->get_origin()
> 	& corpus::LINUX_KERNEL_BINARY_ORIGIN
> 	& corpus:: CTF_ORIGIN)
>       // blah
> 
> The different parts of the code that test for return of
> corpus::get_origin() should be updated to take into account that the
> value returned is now a bitmap.
> 
> Of course, in abg-ctf-reader.cc, the origin of the corpus would be set by doing:
> 
>     corp->set_origin(corpus::LINUX_KERNEL_BINARY_ORIGIN
> 		     | corpus::CTF_ORIGIN);
> 
> and in abg-dwarf-reader.cc, the origin of the corpus would be set by
> doing: 
> 
>     ctxt.current_corpus()->set_origin(corpus::LINUX_KERNEL_BINARY_ORIGIN
> 				      | corpus::DWARF_ORIGIN);
> 
> [...]
ok, totally agree.
> +  debug_format_type debug_format_;
It is used to know which reader should be instantiated depending of command line.

> So, the abigail::ir::environment type should not have a debug_format_
> data member.  If anything, all the data members are hidden in the
> abigail::ir::environment::priv_, which is a pointer to
> abigail::ir::environment::priv, defined in abg-ir-priv.h.  But I think
> it's not neccessary to add anything there.  More on that below.
> 
> [...]
> 
> diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
> index 2c6839cb..dcc65d4e 100644
> --- a/src/abg-ctf-reader.cc
> +++ b/src/abg-ctf-reader.cc
> 
> [...]
> 
> +  void initialize(const string& elf_path, ir::environment *env)
>    {
> 
> Please, add a doxygen comment to this function.
ok.
> [...]
> 
> +std::string
> +dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type)
> +{
> 
> Likewise.
ok.
> diff --git a/src/abg-ir.cc b/src/abg-ir.cc
> index 0ef5e8b2..5eebcfa3 100644
> --- a/src/abg-ir.cc
> +++ b/src/abg-ir.cc
> @@ -3165,7 +3165,8 @@ typedef unordered_map<interned_string,
>  
>  /// Default constructor of the @ref environment type.
>  environment::environment()
> -  :priv_(new priv)
> +  :priv_(new priv),
> +  debug_format_(DWARF_FORMAT_TYPE)
>  {}
> 
> As said above, the debug_format_ data member should not be added to
> the environment type.
> 
> [...]
> 
> diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
> index 1f0f6fa8..faa7243f 100644
> --- a/src/abg-tools-utils.cc
> +++ b/src/abg-tools-utils.cc
> 
> [...]
> 
> @@ -2543,12 +2576,21 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
>    t.start();
>    bool got_binary_paths =
>      get_binary_paths_from_kernel_dist(root, debug_info_root, vmlinux, modules);
> +#ifdef WITH_CTF
> +  string vmlinux_ctfa;
> +  if (got_binary_paths &&
> +      env->get_debug_format_type() == environment::CTF_FORMAT_TYPE)
> +    {
> +      got_binary_paths = get_vmlinux_ctfa_path_from_kernel_dist(root, vmlinux_ctfa);
> +      ABG_ASSERT(!vmlinux_ctfa.empty());
> +    }
> +#endif
> +
> 
> I think, rather than calling env->get_debug_format_type()
> build_corpus_group_from_kernel_dist_under can be passed an additional
> 'corpus_origin' parameter of type corpus::origin.  The parameter would
> have corpus::DWARF_ORIGIN as default argument, for instance.
great!. So, consider it done.
> Also, I think the rest of this function that follows could be
> encapsulated into two functions that would be called:
> 
>     maybe_load_vmlinux_dwarf_corpus()
ok.
> This function would load the vmlinux corpus from the ELF information.
> That function would contain the code that is inside the block:
> 
> +      if (env->get_debug_format_type() == environment::DWARF_FORMAT_TYPE)
> +        {
> 
> The new condition inside the function would rather be something like:
> 
>     if (corpus_origin & corpus::DWARF_ORIGIN)
>       {
>          //blah
>       }
> The function wouldn't do anything if the origin of the corpus is not DWARF.
> 
> 
> The second function would be this one:
> 
> maybe_load_vmlinux_ctf_corpus()
> 
> it's invocation would be protected by an #ifdef WITH_CTF and its body
> would be inside an if-block that would read:
> 
>     if (corpus_origin & corpus::CTF_ORIGIN)
>       {
>         // blah
nice!.
> I hope this all makes sense.  If not, please do not hesitate to discuss
> it.
All make sense,
> Thanks again.
Thanks for these useful comments!!. I will send soon the patch v2 :-)

I was thinking to merge here the patch: 
https://sourceware.org/pipermail/libabigail/2022q2/004310.html[1]

Dodji, What do you think?

> Cheers,
Kind regards, 
Guillermo 



--------
[1] https://sourceware.org/pipermail/libabigail/2022q2/004310.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3] ctf-reader: Add support to read CTF information from Linux kernel
  2022-05-03 15:32   ` Dodji Seketeli
  2022-05-04 12:48     ` Guillermo E. Martinez
@ 2022-05-04 22:29     ` Guillermo E. Martinez
  2022-05-12 16:51       ` Dodji Seketeli
  2022-05-13  7:18       ` Dodji Seketeli
  1 sibling, 2 replies; 10+ messages in thread
From: Guillermo E. Martinez @ 2022-05-04 22:29 UTC (permalink / raw)
  To: libabigail

Hello libabigail team,

This is the v3 patch meant to read CTF information from Linux. Changes
from v2 are:

   * Fix code according to comments:
	     https://sourceware.org/pipermail/libabigail/2022q2/004331.html
	 * Merge patch to improve performace in ctf-reader in this one:
	 		https://sourceware.org/pipermail/libabigail/2022q2/004310.html

Please take a look and let me know your comments, I'll really
appreciate them.

Kind regards,
Guillermo

This patch is meant to extract ABI information from CTF stored in
Linux kernel build directory it depends on: vmlinux.ctfa file.

In order to generate CTF information in Linux kernel must be able
to support 'make ctf', which cause the compiler to be run with -gctf
emitting CTF information on the kernel.

The target 'ctf' in Linux Makefile generate a 'vmlinux.ctfa', that
will be used for ctf reader in libabigail. 'vmlinux.ctfa' has multiple
'ctf dictionaries' called: CTF archive members one for built-in kernel
modules (in `vmlinux') and one for each out-of-tree kernel module organized
in a parent-child hierarchy. In vmlinux.ctfa file there is a CTF archive
member: `shared_ctf' it is a parent dictionary, containing share symbols
and CTF types used by more than one kernel object. These common types
are stored in 'types_map' in ctf reader, ignoring the ctf dictionary name,
CTF API has the machinery to looking for a share type in parent dictionary
referred in a child dictionary. This CTF layout can be dumped by using
objdump tool.

Due to _same_ ctf archive is used to built vmlinux corpus and the
corpora for kernel module belongs to a group, open/close the CTF archive
is hight time consuming during ctf extraction.  So, performance is
improved up to 300% (from ~2m:50s to ~50s), keeping open per _group_
`ctf_archive_t' pointer from vmlinux (the
main_corpus_from_current_group), since this ctf archive file contains
the information for kernel modules as well, then it's reused by each
module to be processed in the group, invoking to `reset_read_context'
ctf reader function.  Doing so, `read_context::ctfa` member should be
updated iff `LINUX_KERNEL_BINARY_ORIGIN' is set in corpus::origin member
and the file to be process is not 'vmlinux', otherwise it must contain
valid information from the main element in the corpus group, `ctf_close'
must be called after processing all group's members, it is executed
from `reader_context' destructor.

The basic algorithm used to generate the Linux corpus follow:

   1. Looking for: vmlinux, *.ko objects, and vmlinux.ctfa files. The
   first files are used to extract the ELF symbols, and the last one
   contains the CTF type information for non-static variables and
   functions symbols.

   2. `process_ctf_archive' iterates on public symbols for vmlinux and
   its modules, using the name of the symbol, ctf reader search for CTF
   information in its dictionary, if the information was found it
   builds a `var_decl' or `function_decl' depending of `ctf_type_kind'
   result.

This algorithm is also applied to ELF files (exec, dyn, rel), so instead
of iterating on all ctf_types it uses public symbols as main loop.

	* abg-elf-reader-common.h: Include ctf-api.h file.
	(read_and_add_corpus_to_group_from_elf, set_read_context_corpus_group)
	(reset_read_context, dic_type_key): Declare new member functions.
	* include/abg-ir.cc (types_defined_same_linux_kernel_corpus_public): Use
	bitwise to know the corpus `origin'.
	* src/abg-ctf-reader.cc: Include map, algorithms header files.
	(read_context::type_map): Change from unordered_map to std::map storing
	ctf dictionary name as part of the key.
	(read_context::is_elf_exec): Add new member variable.
	(read_context::{cur_corpus_, cur_corpus_group_}): Likewise.
	(read_context::unknown_types_set): Likewise.
	(read_context::{current_corpus_group, main_corpus_from_current_group,
	has_corpus_group, current_corpus_is_main_corpus_from_current_group,
	should_reuse_type_from_corpus_group}): Add new member functions.
	(read_context::{add_unknown_type, lookup_unknown_type, initialize}):
	Likewise.
	(read_context::{add_type, lookup_type}): Add new `ctf_dict_t' type
	argument.
	(ctf_reader::{process_ctf_typedef, process_ctf_base_type,
	process_ctf_function_type, process_ctf_forward_type,
	process_ctf_struct_type, process_ctf_union_type, process_ctf_array_type,
	process_ctf_qualified_type, process_ctf_enum_type}): Add code to `reuse'
	types already registered in main corpus `should_reuse_type_from_corpus_group'.
	Use new `lookup_type' and `add_type' operations on `read_context::types_map'.
	Replace function calls to the new ctf interface. Add verifier to not build
	types duplicated by recursive calling chain.
	(ctf_reader::process_ctf_type): Add code to return immediately if the
	ctf type is unknown. Add unknown types to `unknown_types_set'.
	(ctf_reader::process_ctf_archive): Change comment.
	Add code to iterate over global symbols, searching by symbol name in the
	ctf dictionary using `ctf_lookup_{variable,by_symbol_name}' depending of
	the ELF file type and corpus type, creating a `{var,fuc}_decl' using the
	return type of `ctf_type_kind'.  Also close the ctf dict and call
	`canonicalize_all_types'.
	(slurp_elf_info): Set `is_elf_exec' depending of ELF type.  Also return
	success if corpus origin is Linux and symbol table was read.
	(ctf_reader::read_corpus): Add current corpus.  Set corpus origin to
	`LINUX_KERNEL_BINARY_ORIGIN' if `is_linux_kernel' returns true.  Verify
	the ctf reader status, now the ctf archive is 'opened' using
	`ctf_arc{open,bufopen}' depending if the corpus origin has
	`corpus::LINUX_KERNEL_BINARY_ORIGIN' bit set. Use
	`sort_{function,variables}' calls after extract ctf information.
	`ctf_close' is called from `read_context' destructor.
	(read:context::{set_read_context_corpus_group, reset_read_context,
	read_and_add_corpus_to_group_from_elf, dic_type_key): Add new member
	function implementation.
	* include/abg-tools-utils.h (build_corpus_group_from_kernel_dist_under):
	Add `origin' parameter with default `corpus::DWARF_ORIGIN'.
	* src/abg-tools-utils.cc: Use `abg-ctf-reader.h' file.
	(maybe_load_vmlinux_dwarf_corpus): Add new function.
	(maybe_load_vmlinux_ctf_corpus): Likewise.
	(build_corpus_group_from_kernel_dist_under): Update comments.
	Add new `origin' argument. Use `maybe_load_vmlinux_dwarf_corpus'
	or `maybe_load_vmlinux_ctf_corpus' according to `origin' value.
	* src/abg-corpus.h (corpus::origin): Update `origin' type
	values in enum.
	* src/abg-corpus-priv.h (corpus::priv): Replace `origin' type
	from `corpus::origin' to `uint32_t'.
	* src/abg-corpus.cc (corpus::{get,set}_origin): Replace data
	type from `corpus::origin' to `uint32_t'.
	* tools/abidw.cc (main): Use of --ctf argument to set format debug.
	* tests/test-read-ctf.cc: Add new tests to harness.
	* tests/data/test-read-ctf/test-PR27700.abi: New test expected
	  result.
	* tests/data/test-read-ctf/test-anonymous-fields.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-many.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi: Likewise.
	* tests/data/test-read-common/test-PR26568-2.o: Adjust.
	* tests/data/test-read-ctf/test-PR26568-1.o.abi: Likewise.
	* tests/data/test-read-ctf/test-PR26568-2.o.abi: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.c: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.o: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-array-of-pointers.abi: Likewise.
	* tests/data/test-read-ctf/test-callback.abi: Likewise.
	* tests/data/test-read-ctf/test-callback2.abi: Likewise.
	* tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi:
	Likewise.
	* tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi:
	Likewise.
	* tests/data/test-read-ctf/test-dynamic-array.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-ctf.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-symbol.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum.o.abi: Likewise.
	* tests/data/test-read-ctf/test-forward-type-decl.abi: Likewise.
	* tests/data/test-read-ctf/test-functions-declaration.abi: Likewise.
	* tests/data/test-read-ctf/test-list-struct.abi: Likewise.
	* tests/data/test-read-ctf/test0: Likewise.
	* tests/data/test-read-ctf/test0.abi: Likewise.
	* tests/data/test-read-ctf/test0.c: Likewise.
	* tests/data/test-read-ctf/test0.hash.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test5.o.abi: Likewise.
	* tests/data/test-read-ctf/test7.o.abi: Likewise.
	* tests/data/test-read-ctf/test8.o.abi: Likewise.
	* tests/data/test-read-ctf/test9.o.abi: Likewise.

Signed-off-by: Guillermo E. Martinez <guillermo.e.martinez@oracle.com>
---
 include/abg-corpus.h                          |  12 +-
 include/abg-ctf-reader.h                      |  16 +
 include/abg-tools-utils.h                     |   3 +-
 src/abg-corpus-priv.h                         |   2 +-
 src/abg-corpus.cc                             |   4 +-
 src/abg-ctf-reader.cc                         | 492 ++++++++++++++----
 src/abg-dwarf-reader.cc                       |   8 +-
 src/abg-ir.cc                                 |   2 +-
 src/abg-tools-utils.cc                        | 317 ++++++++---
 tests/data/test-read-common/test-PR26568-2.o  | Bin 3048 -> 3488 bytes
 .../test-read-ctf/PR27700/test-PR27700.abi    |   3 +-
 tests/data/test-read-ctf/test-PR26568-1.o.abi |  34 +-
 tests/data/test-read-ctf/test-PR26568-2.o.abi |  22 +-
 tests/data/test-read-ctf/test-PR27700.abi     |  21 +
 .../test-ambiguous-struct-A.o.hash.abi        |   3 +-
 .../test-read-ctf/test-ambiguous-struct-B.c   |   2 +-
 .../test-read-ctf/test-ambiguous-struct-B.o   | Bin 1344 -> 1344 bytes
 .../test-ambiguous-struct-B.o.hash.abi        |   5 +-
 .../test-read-ctf/test-anonymous-fields.o.abi |  18 +-
 .../test-read-ctf/test-array-of-pointers.abi  |   2 +-
 tests/data/test-read-ctf/test-callback.abi    |  30 +-
 tests/data/test-read-ctf/test-callback2.abi   |   2 +-
 .../test-conflicting-type-syms-a.o.hash.abi   |   4 +-
 .../test-conflicting-type-syms-b.o.hash.abi   |   4 +-
 .../test-read-ctf/test-dynamic-array.o.abi    |   2 +-
 tests/data/test-read-ctf/test-enum-ctf.o.abi  |  24 +
 .../test-enum-many-ctf.o.hash.abi             |  69 +++
 .../test-read-ctf/test-enum-many.o.hash.abi   |   6 +-
 .../test-enum-symbol-ctf.o.hash.abi           |  16 +
 .../test-read-ctf/test-enum-symbol.o.hash.abi |   3 +-
 tests/data/test-read-ctf/test-enum.o.abi      |   6 +-
 .../test-read-ctf/test-forward-type-decl.abi  |   2 +-
 .../test-functions-declaration.abi            |   4 +-
 tests/data/test-read-ctf/test-list-struct.abi |   4 +-
 tests/data/test-read-ctf/test0                | Bin 16656 -> 16896 bytes
 tests/data/test-read-ctf/test0.abi            |  30 +-
 tests/data/test-read-ctf/test0.c              |   6 +
 tests/data/test-read-ctf/test0.hash.abi       |  18 +-
 tests/data/test-read-ctf/test1.so.abi         |  11 +-
 tests/data/test-read-ctf/test1.so.hash.abi    |   7 +-
 tests/data/test-read-ctf/test2.so.abi         |   8 +
 tests/data/test-read-ctf/test2.so.hash.abi    |   8 +
 tests/data/test-read-ctf/test3.so.abi         |   4 +
 tests/data/test-read-ctf/test3.so.hash.abi    |   4 +
 tests/data/test-read-ctf/test4.so.abi         |   6 +
 tests/data/test-read-ctf/test4.so.hash.abi    |   6 +
 tests/data/test-read-ctf/test5.o.abi          |  36 +-
 tests/data/test-read-ctf/test7.o.abi          |  43 +-
 tests/data/test-read-ctf/test8.o.abi          |   2 +-
 tests/data/test-read-ctf/test9.o.abi          |   2 +-
 tests/test-read-ctf.cc                        |  20 +-
 tools/abidw.cc                                |   7 +-
 52 files changed, 990 insertions(+), 370 deletions(-)
 create mode 100644 tests/data/test-read-ctf/test-PR27700.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-ctf.o.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi

diff --git a/include/abg-corpus.h b/include/abg-corpus.h
index 652a8294..690edba5 100644
--- a/include/abg-corpus.h
+++ b/include/abg-corpus.h
@@ -44,10 +44,10 @@ public:
   enum origin
   {
     ARTIFICIAL_ORIGIN = 0,
-    NATIVE_XML_ORIGIN,
-    DWARF_ORIGIN,
-    CTF_ORIGIN,
-    LINUX_KERNEL_BINARY_ORIGIN
+    NATIVE_XML_ORIGIN = 1,
+    DWARF_ORIGIN      = 1 << 1,
+    CTF_ORIGIN        = 1 << 2,
+    LINUX_KERNEL_BINARY_ORIGIN = 1 << 3
   };
 
 private:
@@ -115,11 +115,11 @@ public:
   corpus_group*
   get_group();
 
-  origin
+  uint32_t
   get_origin() const;
 
   void
-  set_origin(origin);
+  set_origin(uint32_t);
 
   string&
   get_format_major_version_number() const;
diff --git a/include/abg-ctf-reader.h b/include/abg-ctf-reader.h
index 3343f0d8..ba7289aa 100644
--- a/include/abg-ctf-reader.h
+++ b/include/abg-ctf-reader.h
@@ -19,6 +19,8 @@
 #include "abg-suppression.h"
 #include "abg-elf-reader-common.h"
 
+#include "ctf-api.h"
+
 namespace abigail
 {
 namespace ctf_reader
@@ -32,8 +34,22 @@ create_read_context(const std::string& elf_path,
                     ir::environment *env);
 corpus_sptr
 read_corpus(read_context *ctxt, elf_reader::status& status);
+
 corpus_sptr
 read_corpus(const read_context_sptr &ctxt, elf_reader::status &status);
+
+corpus_sptr
+read_and_add_corpus_to_group_from_elf(read_context*, corpus_group&, elf_reader::status&);
+
+void
+set_read_context_corpus_group(read_context& ctxt, corpus_group_sptr& group);
+
+void
+reset_read_context(read_context_sptr &ctxt,
+                   const std::string&	elf_path,
+                   ir::environment*	environment);
+std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type);
 } // end namespace ctf_reader
 } // end namespace abigail
 
diff --git a/include/abg-tools-utils.h b/include/abg-tools-utils.h
index 68e54028..f7dccb24 100644
--- a/include/abg-tools-utils.h
+++ b/include/abg-tools-utils.h
@@ -311,7 +311,8 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  vector<string>&	kabi_wl_paths,
 					  suppr::suppressions_type&	supprs,
 					  bool				verbose,
-					  environment_sptr&		env);
+					  environment_sptr&		env,
+					  corpus::origin	origin = corpus::DWARF_ORIGIN);
 }// end namespace tools_utils
 
 /// A macro that expands to aborting the program when executed.
diff --git a/src/abg-corpus-priv.h b/src/abg-corpus-priv.h
index 778e3365..28fd1d9b 100644
--- a/src/abg-corpus-priv.h
+++ b/src/abg-corpus-priv.h
@@ -670,7 +670,7 @@ struct corpus::priv
   environment*					env;
   corpus_group*				group;
   corpus::exported_decls_builder_sptr		exported_decls_builder;
-  origin					origin_;
+  uint32_t					origin_;
   vector<string>				regex_patterns_fns_to_suppress;
   vector<string>				regex_patterns_vars_to_suppress;
   vector<string>				regex_patterns_fns_to_keep;
diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
index a517f384..94f2268c 100644
--- a/src/abg-corpus.cc
+++ b/src/abg-corpus.cc
@@ -851,7 +851,7 @@ corpus::init_format_version()
 /// Getter for the origin of the corpus.
 ///
 /// @return the origin of the corpus.
-corpus::origin
+uint32_t
 corpus::get_origin() const
 {return priv_->origin_;}
 
@@ -859,7 +859,7 @@ corpus::get_origin() const
 ///
 /// @param o the new origin for the corpus.
 void
-corpus::set_origin(origin o)
+corpus::set_origin(uint32_t o)
 {priv_->origin_ = o;}
 
 /// Getter of the major version number of the abixml serialization
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 2c6839cb..030f8fc8 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -16,6 +16,8 @@
 #include <fcntl.h> /* For open(3) */
 #include <iostream>
 #include <memory>
+#include <map>
+#include <algorithm>
 
 #include "ctf-api.h"
 
@@ -58,13 +60,19 @@ public:
 
   /// A map associating CTF type ids with libabigail IR types.  This
   /// is used to reuse already generated types.
-  unordered_map<ctf_id_t,type_base_sptr> types_map;
+  std::map<std::string,type_base_sptr> types_map;
+
+  /// A set associating unknown CTF type ids
+  std::set<ctf_id_t> unknown_types_set;
 
   /// libelf handler for the ELF file from which we read the CTF data,
   /// and the corresponding file descriptor.
   Elf *elf_handler;
   int elf_fd;
 
+  /// set when ELF is ET_EXEC
+  bool is_elf_exec;
+
   /// The symtab read from the ELF file.
   symtab_reader::symtab_sptr symtab;
 
@@ -74,26 +82,109 @@ public:
   ctf_sect_t symtab_sect;
   ctf_sect_t strtab_sect;
 
+  corpus_sptr			cur_corpus_;
+  corpus_group_sptr		cur_corpus_group_;
+
+  /// Getter of the current corpus group being constructed.
+  ///
+  /// @return current the current corpus being constructed, if any, or
+  /// nil.
+  const corpus_group_sptr
+  current_corpus_group() const
+  {return cur_corpus_group_;}
+
+  /// Test if there is a corpus group being built.
+  ///
+  /// @return if there is a corpus group being built, false otherwise.
+  bool
+  has_corpus_group() const
+  {return bool(cur_corpus_group_);}
+
+  /// Return the main corpus from the current corpus group, if any.
+  ///
+  /// @return the main corpus of the current corpus group, if any, nil
+  /// if no corpus group is being constructed.
+  corpus_sptr
+  main_corpus_from_current_group()
+  {
+    if (cur_corpus_group_)
+      return cur_corpus_group_->get_main_corpus();
+    return corpus_sptr();
+  }
+
+  /// Test if the current corpus being built is the main corpus of the
+  /// current corpus group.
+  ///
+  /// @return return true iff the current corpus being built is the
+  /// main corpus of the current corpus group.
+  bool
+  current_corpus_is_main_corpus_from_current_group()
+  {
+    corpus_sptr main_corpus = main_corpus_from_current_group();
+
+    if (main_corpus && main_corpus.get() == cur_corpus_.get())
+      return true;
+
+    return false;
+  }
+
+  /// Return true if the current corpus is part of a corpus group
+  /// being built and if it's not the main corpus of the group.
+  ///
+  /// For instance, this would return true if we are loading a linux
+  /// kernel *module* that is part of the current corpus group that is
+  /// being built.  In this case, it means we should re-use types
+  /// coming from the "vmlinux" binary that is the main corpus of the
+  /// group.
+  ///
+  /// @return the corpus group the current corpus belongs to, if the
+  /// current corpus is part of a corpus group being built. Nil otherwise.
+  corpus_sptr
+  should_reuse_type_from_corpus_group()
+  {
+    if (has_corpus_group())
+      if (corpus_sptr main_corpus = main_corpus_from_current_group())
+	if (!current_corpus_is_main_corpus_from_current_group())
+	  return current_corpus_group();
+
+    return corpus_sptr();
+  }
+
   /// Associate a given CTF type ID with a given libabigail IR type.
-  void add_type(ctf_id_t ctf_type, type_base_sptr type)
+  void add_type(ctf_dict_t *dic, ctf_id_t ctf_type, type_base_sptr type)
   {
-    types_map.insert(std::make_pair(ctf_type, type));
+    string key = dic_type_key(dic, ctf_type);
+    types_map.insert(std::make_pair(key, type));
+  }
+
+  /// Insert a given CTF unknown type ID.
+  ///
+  /// @param ctf_type the unknown type ID to be added.
+  void add_unknown_type(ctf_id_t ctf_type)
+  {
+    unknown_types_set.insert(ctf_type);
   }
 
   /// Lookup a given CTF type ID in the types map.
   ///
   /// @param ctf_type the type ID of the type to lookup.
-  type_base_sptr lookup_type(ctf_id_t ctf_type)
+  type_base_sptr lookup_type(ctf_dict_t *dic, ctf_id_t ctf_type)
   {
     type_base_sptr result;
+    std::string key = dic_type_key(dic, ctf_type);
 
-    auto search = types_map.find(ctf_type);
+    auto search = types_map.find(key);
     if (search != types_map.end())
       result = search->second;
 
     return result;
   }
 
+  /// Lookup a given CTF unknown type ID in the unknown set.
+  /// @param ctf_type the unknown type ID to lookup.
+  bool lookup_unknown_type(ctf_id_t ctf_type)
+  { return unknown_types_set.find(ctf_type) != unknown_types_set.end(); }
+
   /// Canonicalize all the types stored in the types map.
   void canonicalize_all_types(void)
   {
@@ -103,18 +194,42 @@ public:
 
   /// Constructor.
   ///
+  /// ctfa data member can be used per courpus group.
+  ///
   /// @param elf_path the path to the ELF file.
-  read_context(const string& elf_path, ir::environment *env)
+  read_context(const string& elf_path, ir::environment *env) :
+    ctfa(NULL)
+  {
+    initialize(elf_path, env);
+  }
+
+  /// Initializer of read_context.
+  ///
+  /// @param elf_path the path to the elf file the context is to be
+  /// used for.
+  ///
+  /// @param environment the environment used by the current context.
+  /// This environment contains resources needed by the reader and by
+  /// the types and declarations that are to be created later.  Note
+  /// that ABI artifacts that are to be compared all need to be
+  /// created within the same environment.
+  ///
+  /// Please also note that the life time of this environment object
+  /// must be greater than the life time of the resulting @ref
+  /// read_context the context uses resources that are allocated in
+  /// the environment.
+  void initialize(const string& elf_path, ir::environment *env)
   {
     types_map.clear();
     filename = elf_path;
     ir_env = env;
     elf_handler = NULL;
     elf_fd = -1;
-    ctfa = NULL;
+    is_elf_exec = false;
+    symtab.reset();
+    cur_corpus_group_.reset();
   }
 
-  /// Destructor of the @ref read_context type.
   ~read_context()
   {
     ctf_close(ctfa);
@@ -153,13 +268,18 @@ process_ctf_typedef(read_context *ctxt,
     return result;
 
   const char *typedef_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+  if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+    if (result = lookup_typedef_type(typedef_name, *corp))
+      return result;
+
   type_base_sptr utype = lookup_type(ctxt, corp, tunit,
                                      ctf_dictionary, ctf_utype);
 
   if (!utype)
     return result;
 
-  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_dictionary,
+                                                                ctf_type));
   if (result)
     return result;
 
@@ -180,7 +300,7 @@ process_ctf_typedef(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -225,9 +345,20 @@ process_ctf_base_type(read_context *ctxt,
       type_base_sptr void_type = ctxt->ir_env->get_void_type();
       decl_base_sptr type_declaration = get_type_declaration(void_type);
       result = is_type_decl(type_declaration);
+      canonicalize(result);
     }
   else
     {
+      if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+        {
+          string normalized_type_name = type_name;
+          integral_type int_type;
+          if (parse_integral_type(type_name, int_type))
+            normalized_type_name = int_type.to_string();
+          if (result = lookup_basic_type(normalized_type_name, *corp))
+            return result;
+        }
+
       result = lookup_basic_type(type_name, *corp);
       if (!result)
         result.reset(new type_decl(ctxt->ir_env,
@@ -242,7 +373,7 @@ process_ctf_base_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -303,7 +434,8 @@ process_ctf_function_type(read_context *ctxt,
       function_parms.push_back(parm);
     }
 
-  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_dictionary,
+                                                                 ctf_type));
   if (result)
     return result;
 
@@ -319,7 +451,7 @@ process_ctf_function_type(read_context *ctxt,
       result->set_is_artificial(true);
       decl_base_sptr function_type_decl = get_type_declaration(result);
       add_decl_to_scope(function_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -419,6 +551,11 @@ process_ctf_forward_type(read_context *ctxt,
     }
   else
     {
+      if (!type_is_anonymous)
+        if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+          if (result = lookup_class_type(type_name, *corp))
+            return is_type(result);
+
       class_decl_sptr
        struct_fwd(new class_decl(ctxt->ir_env, type_name,
                                  /*alignment=*/0, /*size=*/0,
@@ -434,7 +571,7 @@ process_ctf_forward_type(read_context *ctxt,
     return is_type(result);
 
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, is_type(result));
+  ctxt->add_type(ctf_dictionary, ctf_type, is_type(result));
 
   return is_type(result);
 }
@@ -458,9 +595,14 @@ process_ctf_struct_type(read_context *ctxt,
 {
   class_decl_sptr result;
   std::string struct_type_name = ctf_type_name_raw(ctf_dictionary,
-                                                 ctf_type);
+                                                   ctf_type);
   bool struct_type_is_anonymous = (struct_type_name == "");
 
+  if (!struct_type_is_anonymous)
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_class_type(struct_type_name, *corp))
+        return result;
+
   /* The libabigail IR encodes C struct types in `class' IR nodes.  */
   result.reset(new class_decl(ctxt->ir_env,
                               struct_type_name,
@@ -479,7 +621,7 @@ process_ctf_struct_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, result);
+  ctxt->add_type(ctf_dictionary, ctf_type, result);
 
   /* Now add the struct members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
@@ -512,6 +654,11 @@ process_ctf_union_type(read_context *ctxt,
                                                    ctf_type);
   bool union_type_is_anonymous = (union_type_name == "");
 
+  if (!union_type_is_anonymous)
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_union_type(union_type_name, *corp))
+        return result;
+
   /* Create the corresponding libabigail union IR node.  */
   result.reset(new union_decl(ctxt->ir_env,
                                 union_type_name,
@@ -528,7 +675,7 @@ process_ctf_union_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, result);
+  ctxt->add_type(ctf_dictionary, ctf_type, result);
 
   /* Now add the union members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
@@ -584,7 +731,8 @@ process_ctf_array_type(read_context *ctxt,
   if (!index_type)
     return result;
 
-  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_dictionary,
+                                                                  ctf_type));
   if (result)
     return result;
 
@@ -623,7 +771,7 @@ process_ctf_array_type(read_context *ctxt,
     {
       decl_base_sptr array_type_decl = get_type_declaration(result);
       add_decl_to_scope(array_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -652,6 +800,11 @@ process_ctf_qualified_type(read_context *ctxt,
   if (!utype)
     return result;
 
+  result = dynamic_pointer_cast<type_base>(ctxt->lookup_type(ctf_dictionary,
+                                                             ctf_type));
+  if (result)
+    return result;
+
   qualified_type_def::CV qualifiers = qualified_type_def::CV_NONE;
   if (type_kind == CTF_K_CONST)
     qualifiers |= qualified_type_def::CV_CONST;
@@ -668,7 +821,7 @@ process_ctf_qualified_type(read_context *ctxt,
     {
       decl_base_sptr qualified_type_decl = get_type_declaration(result);
       add_decl_to_scope(qualified_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -702,7 +855,8 @@ process_ctf_pointer_type(read_context *ctxt,
   if (!target_type)
     return result;
 
-  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_dictionary,
+                                                                    ctf_type));
   if (result)
     return result;
 
@@ -713,7 +867,7 @@ process_ctf_pointer_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -736,6 +890,12 @@ process_ctf_enum_type(read_context *ctxt,
                       ctf_id_t ctf_type)
 {
   enum_type_decl_sptr result;
+  std::string enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+
+  if (!enum_name.empty())
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_enum_type(enum_name, *corp))
+        return result;
 
   /* Build a signed integral type for the type of the enumerators, aka
      the underlying type.  The size of the enumerators in bytes is
@@ -769,13 +929,12 @@ process_ctf_enum_type(read_context *ctxt,
       return result;
     }
 
-  const char *enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
-  result.reset(new enum_type_decl(enum_name, location(),
-                                  utype, enms, enum_name));
+  result.reset(new enum_type_decl(enum_name.c_str(), location(),
+                                  utype, enms, enum_name.c_str()));
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -804,7 +963,10 @@ process_ctf_type(read_context *ctxt,
   int type_kind = ctf_type_kind(ctf_dictionary, ctf_type);
   type_base_sptr result;
 
-  if ((result = ctxt->lookup_type(ctf_type)))
+  if (ctxt->lookup_unknown_type(ctf_type))
+    return nullptr;
+
+  if ((result = ctxt->lookup_type(ctf_dictionary, ctf_type)))
     return result;
 
   switch (type_kind)
@@ -889,7 +1051,10 @@ process_ctf_type(read_context *ctxt,
     }
 
   if (!result)
-    fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+    {
+      fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+      ctxt->add_unknown_type(ctf_type);
+    }
 
   return result;
 }
@@ -913,7 +1078,7 @@ lookup_type(read_context *ctxt, corpus_sptr corp,
             translation_unit_sptr tunit, ctf_dict_t *ctf_dictionary,
             ctf_id_t ctf_type)
 {
-  type_base_sptr result = ctxt->lookup_type(ctf_type);
+  type_base_sptr result = ctxt->lookup_type(ctf_dictionary, ctf_type);
 
   if (!result)
     result = process_ctf_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
@@ -921,8 +1086,8 @@ lookup_type(read_context *ctxt, corpus_sptr corp,
 }
 
 /// Process a CTF archive and create libabigail IR for the types,
-/// variables and function declarations found in the archive.  The IR
-/// is added to the given corpus.
+/// variables and function declarations found in the archive, iterating
+/// over public symbols.  The IR is added to the given corpus.
 ///
 /// @param ctxt the read context containing the CTF archive to
 /// process.
@@ -937,43 +1102,49 @@ process_ctf_archive(read_context *ctxt, corpus_sptr corp)
   ir_translation_unit->set_language(translation_unit::LANG_C);
   corp->add(ir_translation_unit);
 
-  /* Iterate over the CTF dictionaries in the archive.  */
   int ctf_err;
   ctf_dict_t *ctf_dict;
-  ctf_next_t *dict_next = NULL;
-  const char *archive_name;
+  const auto symtab = ctxt->symtab;
+  symtab_reader::symtab_filter filter = symtab->make_filter();
+  filter.set_public_symbols();
+  std::string dict_name;
 
-  while ((ctf_dict = ctf_archive_next(ctxt->ctfa, &dict_next, &archive_name,
-                                      0 /* skip_parent */, &ctf_err)) != NULL)
+  if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
     {
-      /* Iterate over the CTF types stored in this archive.  */
-      ctf_id_t ctf_type;
-      int type_flag;
-      ctf_next_t *type_next = NULL;
+      tools_utils::base_name(ctxt->filename, dict_name);
 
-      while ((ctf_type = ctf_type_next(ctf_dict, &type_next, &type_flag,
-                                       1 /* want_hidden */)) != CTF_ERR)
-        {
-          process_ctf_type(ctxt, corp, ir_translation_unit,
-                            ctf_dict, ctf_type);
-        }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_type_next\n");
+      if (dict_name != "vmlinux")
+        // remove .ko suffix
+        dict_name.erase(dict_name.length() - 3, 3);
 
-      /* Canonicalize all the types generated above.  This must be
-         done "a posteriori" because the processing of types may
-         require other related types to not be already
-         canonicalized.  */
-      ctxt->canonicalize_all_types();
+      std::replace(dict_name.begin(), dict_name.end(), '-', '_');
+    }
 
-      /* Iterate over the CTF variables stored in this archive.  */
+  if ((ctf_dict = ctf_dict_open(ctxt->ctfa,
+                                dict_name.empty() ? NULL : dict_name.c_str(),
+                                &ctf_err)) == NULL)
+    {
+      fprintf(stderr, "ERROR dictionary not found\n");
+      abort();
+    }
+
+  for (const auto& symbol : symtab_reader::filtered_symtab(*symtab, filter))
+    {
+      std::string sym_name = symbol->get_name();
       ctf_id_t ctf_var_type;
-      ctf_next_t *var_next = NULL;
-      const char *var_name;
 
-      while ((ctf_var_type = ctf_variable_next(ctf_dict, &var_next, &var_name))
-             != CTF_ERR)
+      if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+          || ctxt->is_elf_exec)
+        ctf_var_type= ctf_lookup_variable (ctf_dict, sym_name.c_str());
+      else
+        ctf_var_type = ctf_lookup_by_symbol_name(ctf_dict, sym_name.c_str());
+
+      if (ctf_var_type == (ctf_id_t) -1)
+        continue;
+
+      if (ctf_type_kind (ctf_dict, ctf_var_type) != CTF_K_FUNCTION)
         {
+          const char *var_name = sym_name.c_str();
           type_base_sptr var_type = lookup_type(ctxt, corp, ir_translation_unit,
                                                 ctf_dict, ctf_var_type);
           if (!var_type)
@@ -986,50 +1157,38 @@ process_ctf_archive(read_context *ctxt, corpus_sptr corp)
                                              location(),
                                              var_name));
 
+          var_declaration->set_symbol(symbol);
           add_decl_to_scope(var_declaration,
-                             ir_translation_unit->get_global_scope());
+                            ir_translation_unit->get_global_scope());
         }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_variable_next\n");
+      else
+        {
+          const char *func_name = sym_name.c_str();
+          ctf_id_t ctf_sym = ctf_var_type;
+          type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
+                                                 ctf_dict, ctf_sym);
+          if (!func_type)
+            /* Ignore function if its type can't be sorted out.  */
+            continue;
 
-      /* Iterate over the CTF functions stored in this archive.  */
-      ctf_next_t *func_next = NULL;
-      const char *func_name = NULL;
-      ctf_id_t ctf_sym;
+          function_decl_sptr func_declaration;
+          func_declaration.reset(new function_decl(func_name,
+                                                   func_type,
+                                                   0 /* is_inline */,
+                                                   location()));
 
-      while ((ctf_sym = ctf_symbol_next(ctf_dict, &func_next, &func_name,
-                                        1 /* functions symbols only */) != CTF_ERR))
-      {
-        ctf_id_t ctf_func_type = ctf_lookup_by_name(ctf_dict, func_name);
-        type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
-                                               ctf_dict, ctf_func_type);
-        if (!func_type)
-          /* Ignore function if its type can't be sorted out.  */
-          continue;
-
-        elf_symbols func_elf_symbols = ctxt->symtab->lookup_symbol(func_name);
-        if (func_elf_symbols.size() == 0
-            || func_elf_symbols[0]->get_binding() == elf_symbol::LOCAL_BINDING)
-          /* Ignore local functions.  */
-          continue;
-
-        function_decl_sptr func_declaration;
-        func_declaration.reset(new function_decl(func_name,
-                                                 func_type,
-                                                 0 /* is_inline */,
-                                                 location()));
-
-        add_decl_to_scope(func_declaration,
-                           ir_translation_unit->get_global_scope());
-      }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_symbol_next\n");
-
-      ctf_dict_close(ctf_dict);
+          func_declaration->set_symbol(symbol);
+          add_decl_to_scope(func_declaration,
+                            ir_translation_unit->get_global_scope());
+        }
     }
-  if (ctf_err != ECTF_NEXT_END)
-    fprintf(stderr, "ERROR from ctf_archive_next\n");
 
+  ctf_dict_close(ctf_dict);
+  /* Canonicalize all the types generated above.  This must be
+     done "a posteriori" because the processing of types may
+     require other related types to not be already
+     canonicalized.  */
+  ctxt->canonicalize_all_types();
 }
 
 /// Open the ELF file described by the given read context.
@@ -1113,6 +1272,7 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
   /* Set the ELF architecture.  */
   GElf_Ehdr eh_mem;
   GElf_Ehdr *ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem);
+  ctxt->is_elf_exec = (ehdr->e_type == ET_EXEC);
   corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
 
   /* Read the symtab from the ELF file and set it in the corpus.  */
@@ -1121,6 +1281,9 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
                                 0 /* No suppressions.  */);
   corp->set_symtab(ctxt->symtab);
 
+  if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+    return 1;
+
   /* Get the raw ELF section contents for libctf.  */
   Elf_Scn *ctf_scn = elf_helpers::find_section(ctxt->elf_handler, ".ctf", SHT_PROGBITS);
   Elf_Scn *symtab_scn = elf_helpers::find_symbol_table_section(ctxt->elf_handler);
@@ -1167,6 +1330,7 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
   corpus_sptr corp
     = std::make_shared<corpus>(ctxt->ir_env, ctxt->filename);
 
+  ctxt->cur_corpus_ = corp;
   /* Be optimist.  */
   status = elf_reader::STATUS_OK;
 
@@ -1177,25 +1341,52 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
       return corp;
     }
 
-  /* Set some properties of the corpus first.  */
-  corp->set_origin(corpus::CTF_ORIGIN);
-  if (!slurp_elf_info(ctxt, corp))
+  bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
+  uint32_t origin = corpus::CTF_ORIGIN;
+
+  if (is_linux_kernel)
+    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
+  corp->set_origin(origin);
+
+  if (ctxt->cur_corpus_group_)
+    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
+
+  if (!slurp_elf_info(ctxt, corp) && !is_linux_kernel)
     {
       status = elf_reader::STATUS_NO_SYMBOLS_FOUND;
       return corp;
     }
 
-  /* Build the ctfa from the contents of the relevant ELF sections,
-     and process the CTF archive in the read context, if any.
-     Information about the types, variables, functions, etc contained
-     in the archive are added to the given corpus.  */
   int errp;
-  ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
-                               &ctxt->strtab_sect, &errp);
+  if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+    {
+      std::string filename;
+      if (tools_utils::base_name(ctxt->filename, filename)
+          && filename == "vmlinux")
+        {
+          std::string vmlinux_ctfa_path = ctxt->filename + ".ctfa";
+          ctxt->ctfa = ctf_arc_open(vmlinux_ctfa_path.c_str(), &errp);
+        }
+    }
+  else
+    /* Build the ctfa from the contents of the relevant ELF sections,
+       and process the CTF archive in the read context, if any.
+       Information about the types, variables, functions, etc contained
+       in the archive are added to the given corpus.  */
+    ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
+                                 &ctxt->strtab_sect, &errp);
+
+  ctxt->ir_env->canonicalization_is_done(false);
   if (ctxt->ctfa == NULL)
     status = elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
   else
-    process_ctf_archive(ctxt, corp);
+    {
+      process_ctf_archive(ctxt, corp);
+      ctxt->cur_corpus_->sort_functions();
+      ctxt->cur_corpus_->sort_variables();
+    }
+
+  ctxt->ir_env->canonicalization_is_done(true);
 
   /* Cleanup and return.  */
   close_elf_handler(ctxt);
@@ -1216,5 +1407,94 @@ corpus_sptr
 read_corpus(const read_context_sptr &ctxt, elf_reader::status &status)
 {return read_corpus(ctxt.get(), status);}
 
+/// Set the @ref corpus_group being created to the current read context.
+///
+/// @param ctxt the read_context to consider.
+///
+/// @param group the @ref corpus_group to set.
+void
+set_read_context_corpus_group(read_context& ctxt,
+                              corpus_group_sptr& group)
+{
+  ctxt.cur_corpus_group_ = group;
+}
+
+/// Read a corpus and add it to a given @ref corpus_group.
+///
+/// @param ctxt the reading context to consider.
+///
+/// @param group the @ref corpus_group to add the new corpus to.
+///
+/// @param status output parameter. The status of the read.  It is set
+/// by this function upon its completion.
+corpus_sptr
+read_and_add_corpus_to_group_from_elf(read_context* ctxt,
+                                      corpus_group& group,
+                                      elf_reader::status& status)
+{
+  corpus_sptr result;
+  corpus_sptr corp = read_corpus(ctxt, status);
+  if (status & elf_reader::STATUS_OK)
+    {
+      if (!corp->get_group())
+        group.add_corpus(corp);
+      result = corp;
+    }
+
+  return result;
+}
+
+/// Re-initialize a read_context so that it can re-used to read
+/// another binary.
+///
+/// @param ctxt the context to re-initialize.
+///
+/// @param elf_path the path to the elf file the context is to be used
+/// for.
+///
+/// @param environment the environment used by the current context.
+/// This environment contains resources needed by the reader and by
+/// the types and declarations that are to be created later.  Note
+/// that ABI artifacts that are to be compared all need to be created
+/// within the same environment.
+///
+/// Please also note that the life time of this environment object
+/// must be greater than the life time of the resulting @ref
+/// read_context the context uses resources that are allocated in the
+/// environment.
+void
+reset_read_context(read_context_sptr	&ctxt,
+                   const std::string&	 elf_path,
+                   ir::environment*	 environment)
+{
+  if (ctxt)
+    ctxt->initialize(elf_path, environment);
+}
+
+/// Returns a key to be use in types_map dict conformed by
+/// dictionary id and the CTF type id for a given type.
+///
+/// CTF id types are unique by child dictionary, but CTF id
+/// types in parent dictionary are unique across the all
+/// dictionaries in the CTF archive, to differentiate
+/// one each other this member function relies in
+/// ctf_type_isparent function.
+///
+/// @param dic the pointer to CTF dictionary where the @p type
+/// was found.
+///
+/// @param type the id for given CTF type.
+std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type)
+{
+  std::stringstream key;
+
+  if (ctf_type_isparent (dic, ctf_type))
+    key << std::hex << ctf_type;
+  else
+    key << std::hex << ctf_type << '-' << ctf_cuname(dic);
+  return key.str();
+}
+
 } // End of namespace ctf_reader
 } // End of namespace abigail
diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index dc82cf3b..949161e2 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -14444,10 +14444,12 @@ read_debug_info_into_corpus(read_context& ctxt)
   // First set some mundane properties of the corpus gathered from
   // ELF.
   ctxt.current_corpus()->set_path(ctxt.elf_path());
+
+  uint32_t origin = corpus::DWARF_ORIGIN;
   if (is_linux_kernel(ctxt.elf_handle()))
-    ctxt.current_corpus()->set_origin(corpus::LINUX_KERNEL_BINARY_ORIGIN);
-  else
-    ctxt.current_corpus()->set_origin(corpus::DWARF_ORIGIN);
+    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
+  ctxt.current_corpus()->set_origin(origin);
+
   ctxt.current_corpus()->set_soname(ctxt.dt_soname());
   ctxt.current_corpus()->set_needed(ctxt.dt_needed());
   ctxt.current_corpus()->set_architecture_name(ctxt.elf_architecture());
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 0ef5e8b2..4e907620 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -13498,7 +13498,7 @@ types_defined_same_linux_kernel_corpus_public(const type_base& t1,
   /// kernel corpus, let's move on.  Otherwise bail out.
   if (!(t1_corpus && t2_corpus
 	&& t1_corpus == t2_corpus
-	&& (t1_corpus->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN)
+	&& (t1_corpus->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
 	&& (is_class_or_union_type(&t1)
 	    || is_enum_type(&t1))))
     return false;
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index 1f0f6fa8..f30c3f1d 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -44,6 +44,9 @@
 #include <sstream>
 
 #include "abg-dwarf-reader.h"
+#ifdef WITH_CTF
+#include "abg-ctf-reader.h"
+#endif
 #include "abg-internal.h"
 #include "abg-regex.h"
 
@@ -2486,6 +2489,223 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
 					   module_paths);
 }
 
+/// If the @ref origin is DWARF_ORIGIN it build a @ref corpus_group
+/// made of vmlinux kernel file and the linux kernel modules found
+/// under @p root directory and under its sub-directories, recursively.
+///
+/// @param origin the debug type information in vmlinux kernel and
+/// the linux kernel modules to be used to build the corpora @p group.
+///
+/// @param the group @ref corpus_group to be built.
+///
+/// @param vmlinux the path to the vmlinux binary.
+///
+/// @param modules a vector with the paths to the linux kernel
+/// modules.
+///
+/// @param root the path of the directory under which the kernel
+/// kernel modules were found.
+///
+/// @param di_root the directory in aboslute path which debug
+/// info is to be found for binaries under director @p root
+///
+/// @param suppr_paths the paths to the suppression specifications to
+/// apply while loading the binaries.
+///
+/// @param kabi_wl_path the paths to the kabi whitelist files to take
+/// into account while loading the binaries.
+///
+/// @param supprs the suppressions resulting from parsing the
+/// suppression specifications at @p suppr_paths.  This is set by this
+/// function.
+///
+/// @param verbose true if the function has to emit some verbose
+/// messages.
+///
+/// @param t time to trace time spent in each step.
+///
+/// @param env the environment to create the corpus_group in.
+static void
+maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
+                                corpus_group_sptr&  group,
+                                const string&       vmlinux,
+                                vector<string>&     modules,
+                                const string&       root,
+                                vector<char**>&     di_roots,
+                                vector<string>&     suppr_paths,
+                                vector<string>&     kabi_wl_paths,
+                                suppressions_type&  supprs,
+                                bool                verbose,
+                                timer&              t,
+                                environment_sptr&   env)
+{
+  if (!(origin & corpus::DWARF_ORIGIN))
+    return;
+
+  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
+  dwarf_reader::read_context_sptr ctxt;
+  ctxt =
+   dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
+                                     /*read_all_types=*/false,
+                                     /*linux_kernel_mode=*/true);
+  dwarf_reader::set_do_log(*ctxt, verbose);
+
+  t.start();
+  load_generate_apply_suppressions(*ctxt, suppr_paths,
+                                   kabi_wl_paths, supprs);
+  t.stop();
+
+  if (verbose)
+    std::cerr << "loaded white list and generated suppr spec in: "
+     << t
+     << "\n";
+
+  group.reset(new corpus_group(env.get(), root));
+
+  set_read_context_corpus_group(*ctxt, group);
+
+  if (verbose)
+    std::cerr << "reading kernel binary '"
+     << vmlinux << "' ...\n" << std::flush;
+
+  // Read the vmlinux corpus and add it to the group.
+  t.start();
+  read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
+  t.stop();
+
+  if (verbose)
+    std::cerr << vmlinux
+     << " reading DONE:"
+     << t << "\n";
+
+  if (group->is_empty())
+    return;
+
+  // Now add the corpora of the modules to the corpus group.
+  int total_nb_modules = modules.size();
+  int cur_module_index = 1;
+  for (vector<string>::const_iterator m = modules.begin();
+       m != modules.end();
+       ++m, ++cur_module_index)
+    {
+      if (verbose)
+        std::cerr << "reading module '"
+         << *m << "' ("
+         << cur_module_index
+         << "/" << total_nb_modules
+         << ") ... " << std::flush;
+
+      reset_read_context(ctxt, *m, di_roots, env.get(),
+                         /*read_all_types=*/false,
+                         /*linux_kernel_mode=*/true);
+
+      load_generate_apply_suppressions(*ctxt, suppr_paths,
+                                       kabi_wl_paths, supprs);
+
+      set_read_context_corpus_group(*ctxt, group);
+
+      t.start();
+      read_and_add_corpus_to_group_from_elf(*ctxt,
+                                            *group, status);
+      t.stop();
+      if (verbose)
+        std::cerr << "module '"
+         << *m
+         << "' reading DONE: "
+         << t << "\n";
+    }
+}
+
+/// If the @ref origin is CTF_ORIGIN it build a @ref corpus_group
+/// made of vmlinux kernel file and the linux kernel modules found
+/// under @p root directory and under its sub-directories, recursively.
+///
+/// @param origin the debug type information in vmlinux kernel and
+/// the linux kernel modules to be used to build the corpora @p group.
+///
+/// @param group the @ref corpus_group to be built.
+///
+/// @param vmlinux the path to the vmlinux binary.
+///
+/// @param modules a vector with the paths to the linux kernel
+/// modules.
+///
+/// @param root the path of the directory under which the kernel
+/// kernel modules were found.
+///
+/// @param verbose true if the function has to emit some verbose
+/// messages.
+///
+/// @param t time to trace time spent in each step.
+///
+/// @param env the environment to create the corpus_group in.
+#ifdef WITH_CTF
+static void
+maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
+                              corpus_group_sptr&  group,
+                              const string&       vmlinux,
+                              vector<string>&     modules,
+                              const string&       root,
+                              bool                verbose,
+                              timer&              t,
+                              environment_sptr&   env)
+{
+  if (!(origin & corpus::CTF_ORIGIN))
+    return;
+
+  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
+  ctf_reader::read_context_sptr ctxt;
+  ctxt = ctf_reader::create_read_context(vmlinux, env.get());
+  group.reset(new corpus_group(env.get(), root));
+  set_read_context_corpus_group(*ctxt, group);
+
+  if (verbose)
+    std::cerr << "reading kernel binary '"
+     << vmlinux << "' ...\n" << std::flush;
+
+  // Read the vmlinux corpus and add it to the group.
+  t.start();
+  read_and_add_corpus_to_group_from_elf(ctxt.get(), *group, status);
+  t.stop();
+
+  if (verbose)
+    std::cerr << vmlinux
+     << " reading DONE:"
+     << t << "\n";
+
+  if (group->is_empty())
+    return;
+
+  // Now add the corpora of the modules to the corpus group.
+  int total_nb_modules = modules.size();
+  int cur_module_index = 1;
+  for (vector<string>::const_iterator m = modules.begin();
+       m != modules.end();
+       ++m, ++cur_module_index)
+    {
+      if (verbose)
+        std::cerr << "reading module '"
+         << *m << "' ("
+         << cur_module_index
+         << "/" << total_nb_modules
+         << ") ... " << std::flush;
+
+      reset_read_context(ctxt, *m, env.get());
+      set_read_context_corpus_group(*ctxt, group);
+
+      t.start();
+      read_and_add_corpus_to_group_from_elf(ctxt.get(),
+                                            *group, status);
+      t.stop();
+      if (verbose)
+        std::cerr << "module '"
+         << *m
+         << "' reading DONE: "
+         << t << "\n";
+    }
+}
+#endif
+
 /// Walk a given directory and build an instance of @ref corpus_group
 /// from the vmlinux kernel binary and the linux kernel modules found
 /// under that directory and under its sub-directories, recursively.
@@ -2493,6 +2713,11 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
 /// The main corpus of the @ref corpus_group is made of the vmlinux
 /// binary.  The other corpora are made of the linux kernel binaries.
 ///
+/// Depending of the @ref origin it delegates the corpus build @p group
+/// to:
+///     @ref maybe_load_vmlinux_dwarf_corpus
+///     @ref maybe_load_vmlinux_ctf_corpus
+///
 /// @param root the path of the directory under which the kernel
 /// kernel modules are to be found.  The vmlinux can also be found
 /// somewhere under that directory, but if it's not in there, its path
@@ -2528,10 +2753,11 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  vector<string>&	kabi_wl_paths,
 					  suppressions_type&	supprs,
 					  bool			verbose,
-					  environment_sptr&	env)
+					  environment_sptr&	env,
+					  corpus::origin	origin)
 {
   string vmlinux = vmlinux_path;
-  corpus_group_sptr result;
+  corpus_group_sptr group;
   vector<string> modules;
 
   if (verbose)
@@ -2548,7 +2774,6 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
   if (verbose)
     std::cerr << "DONE: " << t << "\n";
 
-  dwarf_reader::read_context_sptr ctxt;
   if (got_binary_paths)
     {
       shared_ptr<char> di_root =
@@ -2556,86 +2781,18 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
       char *di_root_ptr = di_root.get();
       vector<char**> di_roots;
       di_roots.push_back(&di_root_ptr);
-      abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
-      corpus_group_sptr group;
-      if (!vmlinux.empty())
-	{
-	  ctxt =
-	    dwarf_reader::create_read_context(vmlinux, di_roots ,env.get(),
-					      /*read_all_types=*/false,
-					      /*linux_kernel_mode=*/true);
-	  dwarf_reader::set_do_log(*ctxt, verbose);
-
-	  t.start();
-	  load_generate_apply_suppressions(*ctxt, suppr_paths,
-					   kabi_wl_paths, supprs);
-	  t.stop();
-
-	  if (verbose)
-	    std::cerr << "loaded white list and generated suppr spec in: "
-		      << t
-		      << "\n";
-
-	  group.reset(new corpus_group(env.get(), root));
-
-	  set_read_context_corpus_group(*ctxt, group);
-
-	  if (verbose)
-	    std::cerr << "reading kernel binary '"
-		      << vmlinux << "' ...\n" << std::flush;
-
-	  // Read the vmlinux corpus and add it to the group.
-	  t.start();
-	  read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
-	  t.stop();
-
-	  if (verbose)
-	    std::cerr << vmlinux
-		      << " reading DONE:"
-		      << t << "\n";
-	}
 
-      if (!group->is_empty())
-	{
-	  // Now add the corpora of the modules to the corpus group.
-	  int total_nb_modules = modules.size();
-	  int cur_module_index = 1;
-	  for (vector<string>::const_iterator m = modules.begin();
-	       m != modules.end();
-	       ++m, ++cur_module_index)
-	    {
-	      if (verbose)
-		std::cerr << "reading module '"
-			  << *m << "' ("
-			  << cur_module_index
-			  << "/" << total_nb_modules
-			  << ") ... " << std::flush;
-
-	      reset_read_context(ctxt, *m, di_roots, env.get(),
-				 /*read_all_types=*/false,
-				 /*linux_kernel_mode=*/true);
-
-	      load_generate_apply_suppressions(*ctxt, suppr_paths,
-					       kabi_wl_paths, supprs);
-
-	      set_read_context_corpus_group(*ctxt, group);
-
-	      t.start();
-	      read_and_add_corpus_to_group_from_elf(*ctxt,
-						    *group, status);
-	      t.stop();
-	      if (verbose)
-		std::cerr << "module '"
-			  << *m
-			  << "' reading DONE: "
-			  << t << "\n";
-	    }
-
-	  result = group;
-	}
+      maybe_load_vmlinux_dwarf_corpus(origin, group, vmlinux,
+                                      modules, root, di_roots,
+                                      suppr_paths, kabi_wl_paths,
+                                      supprs, verbose, t, env);
+#ifdef WITH_CTF
+      maybe_load_vmlinux_ctf_corpus(origin, group, vmlinux,
+                                    modules, root, verbose, t, env);
+#endif
     }
 
-  return result;
+  return group;
 }
 
 }//end namespace tools_utils
diff --git a/tests/data/test-read-common/test-PR26568-2.o b/tests/data/test-read-common/test-PR26568-2.o
index b192d52132766d4f95136e23f93de43a64d8cc2e..a6706e8cf508ab89927b0fccecd0268d27111ed9 100644
GIT binary patch
delta 1078
zcmZuwJ#Q015Z%3R+XNC4+rf~Wtw;eB%$Z17uE0<rBAO5pQBj=FADpo7f_)Bl6-1ZL
zWGcFpL83uvC{3skO-dR>8YF6d0W;^l$g=#T(agS?dAmD%_cwibb#Nn{HP|`IVN_-*
zmVAHz`rg0aiWKFRqCj{BJsEYAeL@S+bhImI1kPB7YSeJW7>OZA(1_29CDoC}EE<7w
zsFR{tqeK}CFQZ3+WdmmP^q!2X1vG><a*WfqD3v0Dy2fxZJc8>5tjC(Z*T_=XXAjt}
z?^ap8>oM!4->O-aex+~uZQE(qtWMjpnr_9exDDHF=DRzcpk1?DR#58%`Hoe!1A7!B
zTg^LutL1wmVsmS~c(+)}uitjUGkmTeaY###a!yds<{P6;&yUgdUU~i-FRVO%A=#X(
z@LEpFGSh{RlZR`{0vyU3p8->G4^#sN$`0Q;=IRA5qc9}2U+_o!rrts&jvez*)(z<y
zhq%6+DH2IrOblko;Y44x?_h?eUPc?osd&1fAm`B&6{#!={vrBl@{jSw2nX<8H*?z<
zO{+Q+RTgX*D@)VPF%XYjfQ^Kyx}-xlj9sGd0P!4Rx@lK2n$|rO-Mz4uF}g(@ZSodf
z<mh|_v~kqME)ML+%*<O%g;i0zC_R<oB(|CxL}@`s?g^a?u|^{52aLiiNV^K&Bn6B5
zZ0;kH^#6!)U^GHcv=+iCenpb@pR76(RVCPuuiTtAhZ2b+qF19i%t11-Hg_g^e};Md
Wwcu&OlD??$E^#lmDcXL}kpBaNjDTqX

delta 508
zcmZvYJ4*vW6oqH@mA%=G1lhO&i`^hZLkd#{K}{MFY|?3G0>KAJj1W*_wN`>n^!NiJ
zq)4A4oum?*^g<f#EN$)F*&Rj1f#J-(ocZRS=`X&!y%l$8u%A_lP8F76&h6&%=#dXO
zot(A~{o_`L;XvIQP1OeH8s4;wsxm_=NwtKcqdVy9dz|p8pK~@kGi;8l#0+(Ff<9?z
zlA|0kbSV!%EC=Ki>RLR*Bo;Ows%V+A&PrWJgIxNM)g7wIC4r-B9=BEzkjHoMKyJa;
z<6cR+1v3%uzsx3bA#*GVy9i8=??;51BwYL=&_9GWa+XVTN^Gm4YI*z;4a-&P3c6OF
z-$aI)G!!Gly?9nJ)bP(1&@<C~fSm1;sm7EN0z1rRJ5-jPa+GZ>Cd)j_$-e(ZWJ_ae
b7pX1XF9?zz{8U!i*07e^pjUb2Nd)`?0Gw2F

diff --git a/tests/data/test-read-ctf/PR27700/test-PR27700.abi b/tests/data/test-read-ctf/PR27700/test-PR27700.abi
index 62df1017..fe3a897d 100644
--- a/tests/data/test-read-ctf/PR27700/test-PR27700.abi
+++ b/tests/data/test-read-ctf/PR27700/test-PR27700.abi
@@ -11,9 +11,8 @@
       <enumerator name='foo_e2' value='2'/>
       <enumerator name='foo_e3' value='3'/>
     </enum-decl>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <pointer-type-def type-id='022218d8' size-in-bits='64' alignment-in-bits='64' id='8750e847'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
       <parameter type-id='8750e847'/>
       <return type-id='48b5725f'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR26568-1.o.abi b/tests/data/test-read-ctf/test-PR26568-1.o.abi
index d62474ec..832dc1bd 100644
--- a/tests/data/test-read-ctf/test-PR26568-1.o.abi
+++ b/tests/data/test-read-ctf/test-PR26568-1.o.abi
@@ -7,47 +7,29 @@
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='' type-id='type-id-2' visibility='default'/>
       </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='' type-id='type-id-5' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
-      </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
+        <var-decl name='y' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-5'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-5'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
+        <var-decl name='x' type-id='type-id-6' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
     <union-decl name='' size-in-bits='64' is-anonymous='yes' visibility='default' id='type-id-2'>
-      <data-member access='public'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
-      </data-member>
-      <data-member access='public'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
-      </data-member>
       <data-member access='public'>
         <var-decl name='' type-id='type-id-5' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
+        <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
     </union-decl>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fun'>
       <parameter type-id='type-id-7'/>
       <return type-id='type-id-8'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR26568-2.o.abi b/tests/data/test-read-ctf/test-PR26568-2.o.abi
index a934d15b..70e0772f 100644
--- a/tests/data/test-read-ctf/test-PR26568-2.o.abi
+++ b/tests/data/test-read-ctf/test-PR26568-2.o.abi
@@ -3,34 +3,28 @@
     <elf-symbol name='fun' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-2' visibility='default'/>
+        <var-decl name='y' type-id='type-id-2' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-4' visibility='default'/>
+        <var-decl name='x' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-2'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <union-decl name='A' size-in-bits='64' visibility='default' id='type-id-5'>
-      <data-member access='public'>
-        <var-decl name='' type-id='type-id-1' visibility='default'/>
-      </data-member>
-      <data-member access='public'>
-        <var-decl name='x' type-id='type-id-2' visibility='default'/>
-      </data-member>
       <data-member access='public'>
         <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='y' type-id='type-id-4' visibility='default'/>
+        <var-decl name='' type-id='type-id-1' visibility='default'/>
       </data-member>
     </union-decl>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fun'>
       <parameter type-id='type-id-6'/>
       <return type-id='type-id-7'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR27700.abi b/tests/data/test-read-ctf/test-PR27700.abi
new file mode 100644
index 00000000..fe3a897d
--- /dev/null
+++ b/tests/data/test-read-ctf/test-PR27700.abi
@@ -0,0 +1,21 @@
+<abi-corpus version='2.1' path='data/test-read-common/PR27700/test-PR27700.o'>
+  <elf-function-symbols>
+    <elf-symbol name='foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-function-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='foo' linkage-name='foo' id='022218d8'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='foo_e0' value='0'/>
+      <enumerator name='foo_e1' value='1'/>
+      <enumerator name='foo_e2' value='2'/>
+      <enumerator name='foo_e3' value='3'/>
+    </enum-decl>
+    <pointer-type-def type-id='022218d8' size-in-bits='64' alignment-in-bits='64' id='8750e847'/>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='8750e847'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi b/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
index 922a1daf..12050a5b 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
@@ -30,7 +30,6 @@
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='7359adad'/>
     <pointer-type-def type-id='3ed987a4' size-in-bits='64' alignment-in-bits='64' id='84d5ac12'/>
     <pointer-type-def type-id='1c12b755' size-in-bits='64' alignment-in-bits='64' id='55cd64e8'/>
-    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default'/>
-    <var-decl name='foo' type-id='55cd64e8' mangled-name='foo' visibility='default'/>
+    <var-decl name='foo' type-id='55cd64e8' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.c b/tests/data/test-read-ctf/test-ambiguous-struct-B.c
index 95a93469..e592529b 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-B.c
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-B.c
@@ -2,4 +2,4 @@ struct A;
 struct B { struct A *a; };
 struct A { struct B b; int foo; struct B b2; };
 
-static struct A a __attribute__((__used__));
+struct A a __attribute__((__used__));
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.o b/tests/data/test-read-ctf/test-ambiguous-struct-B.o
index 06bd0f502a874ad4a10c4beb5788eaace44c2bf9..40a11fcbd4ae19b78a943812f69606cdc6c9fc15 100644
GIT binary patch
delta 20
ccmX@Wb%1Nb8%9RK&2Jg^GchtvUdu8W08_UIfB*mh

delta 20
ccmX@Wb%1Nb8%9RP&2Jg^GchtxUdu8W08;!1aR2}S

diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi b/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
index 28291eb5..83d21919 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-ctf/test-ambiguous-struct-B.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='a' size='24' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
   <abi-instr address-size='64' language='LANG_C'>
     <class-decl name='A' size-in-bits='192' alignment-in-bits='64' is-struct='yes' visibility='default' id='3ed987a4'>
       <data-member access='public' layout-offset-in-bits='0'>
@@ -18,6 +21,6 @@
     </class-decl>
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
     <pointer-type-def type-id='3ed987a4' size-in-bits='64' alignment-in-bits='64' id='84d5ac12'/>
-    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default'/>
+    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default' elf-symbol-id='a'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-anonymous-fields.o.abi b/tests/data/test-read-ctf/test-anonymous-fields.o.abi
index 0419c29c..2134a86d 100644
--- a/tests/data/test-read-ctf/test-anonymous-fields.o.abi
+++ b/tests/data/test-read-ctf/test-anonymous-fields.o.abi
@@ -3,14 +3,14 @@
     <elf-symbol name='t' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-variable-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='vaddr' type-id='type-id-2' visibility='default'/>
+        <var-decl name='dup_xol_work' type-id='type-id-2' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='dup_xol_work' type-id='type-id-4' visibility='default'/>
+        <var-decl name='vaddr' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
     <class-decl name='uprobe_task' size-in-bits='64' alignment-in-bits='64' is-struct='yes' visibility='default' id='type-id-5'>
@@ -18,16 +18,16 @@
         <var-decl name='' type-id='type-id-6' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-2'/>
     <union-decl name='' size-in-bits='64' is-anonymous='yes' visibility='default' id='type-id-6'>
       <data-member access='public'>
-        <var-decl name='' type-id='type-id-1' visibility='default'/>
+        <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
+        <var-decl name='' type-id='type-id-1' visibility='default'/>
       </data-member>
     </union-decl>
-    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='t' type-id='type-id-5' mangled-name='t' visibility='default'/>
+    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
+    <var-decl name='t' type-id='type-id-5' mangled-name='t' visibility='default' elf-symbol-id='t'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-array-of-pointers.abi b/tests/data/test-read-ctf/test-array-of-pointers.abi
index 920da28b..195361df 100644
--- a/tests/data/test-read-ctf/test-array-of-pointers.abi
+++ b/tests/data/test-read-ctf/test-array-of-pointers.abi
@@ -31,6 +31,6 @@
     <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
     <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-11'/>
-    <var-decl name='t' type-id='type-id-11' mangled-name='t' visibility='default'/>
+    <var-decl name='t' type-id='type-id-11' mangled-name='t' visibility='default' elf-symbol-id='t'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-callback.abi b/tests/data/test-read-ctf/test-callback.abi
index 704c4971..7f9b6c5f 100644
--- a/tests/data/test-read-ctf/test-callback.abi
+++ b/tests/data/test-read-ctf/test-callback.abi
@@ -4,28 +4,16 @@
     <elf-symbol name='f2' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='test' size-in-bits='64' alignment-in-bits='64' is-struct='yes' visibility='default' id='type-id-1'>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='fn1' type-id='type-id-2' visibility='default'/>
-      </data-member>
-    </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
-    <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
-    <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <function-decl name='assign' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <return type-id='type-id-7'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
+    <function-decl name='assign' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='assign'>
+      <return type-id='type-id-3'/>
     </function-decl>
-    <function-decl name='f2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-3'/>
-      <parameter type-id='type-id-4'/>
-      <return type-id='type-id-7'/>
+    <function-decl name='f2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='f2'>
+      <parameter type-id='type-id-1'/>
+      <parameter type-id='type-id-2'/>
+      <return type-id='type-id-3'/>
     </function-decl>
-    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-6'>
-      <parameter type-id='type-id-3'/>
-      <parameter type-id='type-id-4'/>
-      <return type-id='type-id-7'/>
-    </function-type>
-    <type-decl name='void' id='type-id-7'/>
+    <type-decl name='void' id='type-id-3'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-callback2.abi b/tests/data/test-read-ctf/test-callback2.abi
index bdd4ad33..ddc3e493 100644
--- a/tests/data/test-read-ctf/test-callback2.abi
+++ b/tests/data/test-read-ctf/test-callback2.abi
@@ -11,7 +11,7 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
-    <var-decl name='s0' type-id='type-id-5' mangled-name='s0' visibility='default'/>
+    <var-decl name='s0' type-id='type-id-5' mangled-name='s0' visibility='default' elf-symbol-id='s0'/>
     <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-4'>
       <parameter type-id='type-id-5'/>
       <return type-id='type-id-3'/>
diff --git a/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi b/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
index 03dd56b3..8d5c3e36 100644
--- a/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
+++ b/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
@@ -8,7 +8,7 @@
     <typedef-decl name='a_t' type-id='bd54fe1a' id='40acc204'/>
     <typedef-decl name='b_t' type-id='bd54fe1a' id='b3d2db81'/>
     <pointer-type-def type-id='40acc204' size-in-bits='64' alignment-in-bits='64' id='c6fd4117'/>
-    <var-decl name='a' type-id='c6fd4117' mangled-name='a' visibility='default'/>
-    <var-decl name='ignore2' type-id='b3d2db81' mangled-name='ignore2' visibility='default'/>
+    <var-decl name='a' type-id='c6fd4117' mangled-name='a' visibility='default' elf-symbol-id='a'/>
+    <var-decl name='ignore2' type-id='b3d2db81' mangled-name='ignore2' visibility='default' elf-symbol-id='ignore2'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi b/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
index 35bcac7a..992b669d 100644
--- a/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
+++ b/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
@@ -7,7 +7,7 @@
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='bd54fe1a'/>
     <typedef-decl name='a_t' type-id='bd54fe1a' id='40acc204'/>
     <typedef-decl name='b_t' type-id='bd54fe1a' id='b3d2db81'/>
-    <var-decl name='b' type-id='40acc204' mangled-name='b' visibility='default'/>
-    <var-decl name='ignore1' type-id='b3d2db81' mangled-name='ignore1' visibility='default'/>
+    <var-decl name='b' type-id='40acc204' mangled-name='b' visibility='default' elf-symbol-id='b'/>
+    <var-decl name='ignore1' type-id='b3d2db81' mangled-name='ignore1' visibility='default' elf-symbol-id='ignore1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-dynamic-array.o.abi b/tests/data/test-read-ctf/test-dynamic-array.o.abi
index 02b22811..a9849d49 100644
--- a/tests/data/test-read-ctf/test-dynamic-array.o.abi
+++ b/tests/data/test-read-ctf/test-dynamic-array.o.abi
@@ -21,7 +21,7 @@
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-3'/>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <function-decl name='use_struct_s' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='use_struct_s' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='use_struct_s'>
       <parameter type-id='type-id-7'/>
       <return type-id='type-id-8'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-enum-ctf.o.abi b/tests/data/test-read-ctf/test-enum-ctf.o.abi
new file mode 100644
index 00000000..f36f3fad
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-ctf.o.abi
@@ -0,0 +1,24 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='bar' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='foo' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
+    <enum-decl name='e' linkage-name='e' id='type-id-2'>
+      <underlying-type type-id='type-id-1'/>
+      <enumerator name='ENUMSAMPLE_1' value='0'/>
+      <enumerator name='ENUMSAMPLE_2' value='1'/>
+    </enum-decl>
+    <enum-decl name='ie' linkage-name='ie' id='type-id-3'>
+      <underlying-type type-id='type-id-1'/>
+      <enumerator name='IENUMSAMPLE_1' value='-10'/>
+      <enumerator name='IENUMSAMPLE_2' value='-9'/>
+      <enumerator name='IENUMSAMPLE_3' value='-8'/>
+    </enum-decl>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
+    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default'/>
+    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi b/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
new file mode 100644
index 00000000..67a958a7
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
@@ -0,0 +1,69 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-many-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='bar' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='foo' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='e' linkage-name='e' id='a6c2eddf'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='ENUMSAMPLE_1' value='0'/>
+      <enumerator name='ENUMSAMPLE_2' value='1'/>
+    </enum-decl>
+    <enum-decl name='ie' linkage-name='ie' id='1ee696ca'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='IE_0' value='-10'/>
+      <enumerator name='IE_1' value='-9'/>
+      <enumerator name='IE_2' value='-8'/>
+      <enumerator name='IE_3' value='-7'/>
+      <enumerator name='IE_4' value='-6'/>
+      <enumerator name='IE_5' value='-5'/>
+      <enumerator name='IE_6' value='-4'/>
+      <enumerator name='IE_7' value='-3'/>
+      <enumerator name='IE_8' value='-2'/>
+      <enumerator name='IE_9' value='-1'/>
+      <enumerator name='IE_A' value='0'/>
+      <enumerator name='IE_B' value='1'/>
+      <enumerator name='IE_C' value='2'/>
+      <enumerator name='IE_D' value='3'/>
+      <enumerator name='IE_E' value='4'/>
+      <enumerator name='IE_F' value='5'/>
+      <enumerator name='IE_10' value='6'/>
+      <enumerator name='IE_11' value='7'/>
+      <enumerator name='IE_12' value='8'/>
+      <enumerator name='IE_13' value='9'/>
+      <enumerator name='IE_14' value='10'/>
+      <enumerator name='IE_15' value='11'/>
+      <enumerator name='IE_16' value='12'/>
+      <enumerator name='IE_17' value='13'/>
+      <enumerator name='IE_18' value='14'/>
+      <enumerator name='IE_19' value='15'/>
+      <enumerator name='IE_1A' value='16'/>
+      <enumerator name='IE_1B' value='17'/>
+      <enumerator name='IE_1C' value='18'/>
+      <enumerator name='IE_1D' value='19'/>
+      <enumerator name='IE_1E' value='20'/>
+      <enumerator name='IE_1F' value='21'/>
+      <enumerator name='IE_20' value='22'/>
+      <enumerator name='IE_21' value='23'/>
+      <enumerator name='IE_22' value='24'/>
+      <enumerator name='IE_23' value='25'/>
+      <enumerator name='IE_24' value='26'/>
+      <enumerator name='IE_25' value='27'/>
+      <enumerator name='IE_26' value='28'/>
+      <enumerator name='IE_27' value='29'/>
+      <enumerator name='IE_28' value='30'/>
+      <enumerator name='IE_29' value='31'/>
+      <enumerator name='IE_2A' value='32'/>
+      <enumerator name='IE_2B' value='33'/>
+      <enumerator name='IE_2C' value='34'/>
+      <enumerator name='IE_2D' value='35'/>
+      <enumerator name='IE_2E' value='36'/>
+      <enumerator name='IE_2F' value='37'/>
+    </enum-decl>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
+    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default'/>
+    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-many.o.hash.abi b/tests/data/test-read-ctf/test-enum-many.o.hash.abi
index 26bc048c..116325f9 100644
--- a/tests/data/test-read-ctf/test-enum-many.o.hash.abi
+++ b/tests/data/test-read-ctf/test-enum-many.o.hash.abi
@@ -61,9 +61,7 @@
       <enumerator name='IE_2E' value='36'/>
       <enumerator name='IE_2F' value='37'/>
     </enum-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
-    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default'/>
-    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default'/>
+    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
+    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default' elf-symbol-id='bar'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi b/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi
new file mode 100644
index 00000000..fea6eb8b
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi
@@ -0,0 +1,16 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-symbol-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='primary1' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='' is-anonymous='yes' id='08f5ca17'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='red1' value='0'/>
+      <enumerator name='green1' value='1'/>
+      <enumerator name='blue1' value='2'/>
+    </enum-decl>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
+    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi b/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
index d128b5b1..f4911bc4 100644
--- a/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
+++ b/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
@@ -10,7 +10,6 @@
       <enumerator name='green1' value='1'/>
       <enumerator name='blue1' value='2'/>
     </enum-decl>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
-    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default'/>
+    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default' elf-symbol-id='primary1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum.o.abi b/tests/data/test-read-ctf/test-enum.o.abi
index 88e6ad61..bd3a55be 100644
--- a/tests/data/test-read-ctf/test-enum.o.abi
+++ b/tests/data/test-read-ctf/test-enum.o.abi
@@ -16,9 +16,7 @@
       <enumerator name='IENUMSAMPLE_2' value='-9'/>
       <enumerator name='IENUMSAMPLE_3' value='-8'/>
     </enum-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
-    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default'/>
-    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default'/>
+    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
+    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default' elf-symbol-id='bar'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-forward-type-decl.abi b/tests/data/test-read-ctf/test-forward-type-decl.abi
index 21bb45c8..026e7d32 100644
--- a/tests/data/test-read-ctf/test-forward-type-decl.abi
+++ b/tests/data/test-read-ctf/test-forward-type-decl.abi
@@ -24,6 +24,6 @@
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-3'/>
     <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='addr' type-id='type-id-5' mangled-name='addr' visibility='default'/>
+    <var-decl name='addr' type-id='type-id-5' mangled-name='addr' visibility='default' elf-symbol-id='addr'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-functions-declaration.abi b/tests/data/test-read-ctf/test-functions-declaration.abi
index 9ef05e44..7eb57d26 100644
--- a/tests/data/test-read-ctf/test-functions-declaration.abi
+++ b/tests/data/test-read-ctf/test-functions-declaration.abi
@@ -7,11 +7,11 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
-    <function-decl name='attribute_container_add_device' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='attribute_container_add_device' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='attribute_container_add_device'>
       <parameter type-id='type-id-4'/>
       <return type-id='type-id-5'/>
     </function-decl>
-    <function-decl name='attribute_container_device_trigger' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='attribute_container_device_trigger' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='attribute_container_device_trigger'>
       <parameter type-id='type-id-4'/>
       <return type-id='type-id-5'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-list-struct.abi b/tests/data/test-read-ctf/test-list-struct.abi
index 196a79a1..deb6a4a1 100644
--- a/tests/data/test-read-ctf/test-list-struct.abi
+++ b/tests/data/test-read-ctf/test-list-struct.abi
@@ -14,7 +14,7 @@
     </class-decl>
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='n1' type-id='type-id-1' mangled-name='n1' visibility='default'/>
-    <var-decl name='n2' type-id='type-id-1' mangled-name='n2' visibility='default'/>
+    <var-decl name='n1' type-id='type-id-1' mangled-name='n1' visibility='default' elf-symbol-id='n1'/>
+    <var-decl name='n2' type-id='type-id-1' mangled-name='n2' visibility='default' elf-symbol-id='n2'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test0 b/tests/data/test-read-ctf/test0
index aca7fbacdfff7ad2caf0142390710373a8da72a1..90aa8a39a2e1326a5cb5faaa9e854fc344caaa52 100755
GIT binary patch
delta 1886
zcmah~L2MgE6rEkWZra+(ZUVNWHnG!6kSdbB4pp+Tz+NFxdrBKokU<E`3NA_s+0=1R
z!hsZ2LDU1-`4W{lz<~poN(}_6o**g+6(K-AQK3qlDyTRVq*5i9m^ZV3s^AM>djHSN
zd;ibh8SlFBwsHP~(HKr_=EVc^gezjg69eK<vp6(*(+n6LyI2@P3<F6yP|@SqTr2Ef
zl@x3>-2C<akjol3<f&C1(`qI}nm)_)Rb@(vl_gf{_&~`STwXkLyZ*8q|L+c**G1dL
z4@cxgW?8@<;P~XT!aOfF<(dJ&=o@or;}3H+`nh#uFt^0*{Ik>cCEMV+OqRCA^GGli
z>$IIInx!!1vl-J3)7k7`$O(J&cW80VdGA07&*>>?n$G1?dj~K!MU=jF68%x}p%rjS
z05{6)U9bt^c>!xMeHzgay_Cwy+>9NtOp13EYtzZxal@iZxop2JP89yD`B7>5=r>fb
zh1bE}QKfpQXEf3Ou)y|eu3azM=tbv6uyK*>U=M?}M4WuEG4X9jZ%4t}B0(RIW{o)g
ztb7~FZu}sEUGyzq<Xy6l$rHHDyJ+?jvt_VxG0d#VEq<wX>8AHp?loq0|C=(`#L0t=
ziZq}62-7#gTIleuVkf!(1I*r0l@pXYCiitZD&s=c)13s1jE+0)4%m&AW2eoP6DW8M
z#YTYVF^&Uo0S^IJ033+;4u}FRzy@vsG2nMVHgpf@15DJ|i#Q9wBJy?hfI+OoBJ$AE
zfW>o!M+8J>1B<W-8dLAZCu%ApQU^Zt4mslo?J}=&8DpAW952VN2CJe6@hiG9K4QE{
z_r|~2bH?|}Ir`K+5`L{RGe_UM&I@9pUa2oGI2?1LUR|h{E45l>IT%j+a|`ugcxKkG
z@NnLrnX6Z8!FmlTwV7$AUiW7!^_kf!nG;V(UzuCX%-8(+YOTJ!;Z5u_=v3a?pA31b
z!(@og=Eq_#Pt`|*rb2yd1#4go3VCqy`K6Uuq`pW}M4Nf*sJtrq(reWctCsk?m6WNl
z2)<~Em8USe-){R_tv?$LRv%JYs5#2Z+HI4V$jjCF>%7}K=gV%S$-WIh=W`c_#dBDc
zT3uj^3v6)#m(Jx=D=$IO-qj|)R9F$h;WtdTr=zZ><Ezl_?8<jJ-{t(YEC%arGguW*
ziZ?KlT3xWj1xj4NVWn=M<2l6zYCc{xE>a7=LG}|x;{%$4|A?CKm#GDRmFz;%xK2~>
zKT)&rXuoVnnyx1Q4W#`-Eog3$T`U^6X$t;NYQq0TE%<G+y;N6%50I{mCFztmY#gLz
O&);`_A}FyV&-Gt@S^P)<

delta 1541
zcmZ9MO-NKx6vxlKZ?tqYpOznE<-FXa2=ifIqf@>+MHB?NX;F)iHf3#0R0<+&`XH#N
z(X+7HWF#?*pbraz7G=z0T7=Llf`~Sev~ZQw#_8Pq&Mlh@@7#Cp?|;rc_r81Ih07v$
zQRF(B-Cp?H6r>;w3O2y{34c@fpbUuZSF_NeK15HRd0r~=v_CP~SN%(4YQLO`PfHC2
z))b`DgHVvzD%<e1EZ||sn;ms-)L<@@d*&9~lHaA$68O1X8Zs}AGF^qS0E6sTvhU&V
zm@kVC_Qqo}@8GF;n=|bw%!bA$6F0+>CR0Z0;czm#Y9qZ%2;=KSb0iFR-GCVZnQo?w
zM4LdVfC|Qks25O=(WH)z)d!RzTs73i{^UMUhf~RT#D)ER|7+eGO#^<R3@)fLx?obR
z!Mg6|$U30ujc-i@mC-<z`$QX|rHr-{b)gZ5h}J-%thP>~_0WX(y5ph|=Z!6qvKGJ#
zX3?Kgw`)90e2d<JM?8zAQ%nblHbMte8HB<MGfOSrGO;h2GK4oeR?^NB4THx!-^KVN
zQI{%QH1r_XA7;8>GB;s#tDZMemYF`NSzSNTYD%N*l%`)3(An{=ha|p{q4Cp{Y@X2Z
zKvt<ww4&!N`+Bh+J<r)EIgmzPVW09*sQ|axXYQQ)pX*`WV)~>WF|SZbxhr*YaTI5E
z4Ajm9!%#>4BXm<;;w<h=J;$X~J8tZWS0!L%^w{XwND?3R?44cik%CsRYBKFs|GRG3
zn%-VpkjkVoHx0i!Yw=0i?c7FV`rhb@b+dQtI}fx3!%%@wW6k49@|H@aA*%*Q1)T5l
z2CL>?@7v0jCP#lT8}D(v$MO4FtoK82j*aIk+F=h3YOPIRulgV-Na3b*bo>A*N-N5o
z=4qx`Wq%CzhhekX{xHQauZYice4gVy;<}ZW8H~biI6-gvjM#)lPEh0o30B$y%GL?P
znBC=zGdM@~Jc>SFT*3_5>zE~b2j|E>K;ir1F=oiV!mPhJVwYvJ=@Y110q02b4u$f?
o2h5QDh*`3qagOXa6q%?P!TXsgs!WGy#gmz#s<xgW_J`ikKQHOTvj6}9

diff --git a/tests/data/test-read-ctf/test0.abi b/tests/data/test-read-ctf/test0.abi
index 50ca26f4..fc61f2ac 100644
--- a/tests/data/test-read-ctf/test0.abi
+++ b/tests/data/test-read-ctf/test0.abi
@@ -39,16 +39,26 @@
     </array-type-def>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-10'/>
     <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='type-id-11'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='type-id-12'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-13'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-14'/>
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='type-id-15'/>
-    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-16'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
-    <qualified-type-def type-id='type-id-3' const='yes' id='type-id-18'/>
-    <pointer-type-def type-id='type-id-10' size-in-bits='64' alignment-in-bits='64' id='type-id-19'/>
-    <qualified-type-def type-id='type-id-19' restrict='yes' id='type-id-20'/>
-    <qualified-type-def type-id='type-id-11' volatile='yes' id='type-id-21'/>
+    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-12'/>
+    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-13'/>
+    <qualified-type-def type-id='type-id-3' const='yes' id='type-id-14'/>
+    <pointer-type-def type-id='type-id-10' size-in-bits='64' alignment-in-bits='64' id='type-id-15'/>
+    <qualified-type-def type-id='type-id-15' restrict='yes' id='type-id-16'/>
+    <qualified-type-def type-id='type-id-11' volatile='yes' id='type-id-17'/>
+    <var-decl name='status' type-id='type-id-5' mangled-name='status' visibility='default' elf-symbol-id='status'/>
+    <var-decl name='test_pointer' type-id='type-id-13' mangled-name='test_pointer' visibility='default' elf-symbol-id='test_pointer'/>
+    <var-decl name='test_const' type-id='type-id-14' mangled-name='test_const' visibility='default' elf-symbol-id='test_const'/>
+    <var-decl name='test_float' type-id='type-id-6' mangled-name='test_float' visibility='default' elf-symbol-id='test_float'/>
+    <function-decl name='foo_1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo_1'>
+      <parameter type-id='type-id-12'/>
+      <return type-id='type-id-4'/>
+    </function-decl>
+    <function-decl name='main' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='main'>
+      <return type-id='type-id-4'/>
+    </function-decl>
+    <var-decl name='test_array' type-id='type-id-7' mangled-name='test_array' visibility='default' elf-symbol-id='test_array'/>
+    <var-decl name='test_restrict' type-id='type-id-16' mangled-name='test_restrict' visibility='default' elf-symbol-id='test_restrict'/>
+    <var-decl name='test_volatile' type-id='type-id-17' mangled-name='test_volatile' visibility='default' elf-symbol-id='test_volatile'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test0.c b/tests/data/test-read-ctf/test0.c
index eb702312..fdefd57c 100644
--- a/tests/data/test-read-ctf/test0.c
+++ b/tests/data/test-read-ctf/test0.c
@@ -1,3 +1,9 @@
+/*
+ * ELF EXEC files must use -Wl,--ctf-variables -Bdynimic options
+ * to export an ABI and store CTF symbols information.
+ *
+ * ctf-gcc -gctf -Wl,--ctf-variables -Bdynamic test0.c -o test0
+ */
 
 #include <stdio.h>
 
diff --git a/tests/data/test-read-ctf/test0.hash.abi b/tests/data/test-read-ctf/test0.hash.abi
index b58520ab..eff32228 100644
--- a/tests/data/test-read-ctf/test0.hash.abi
+++ b/tests/data/test-read-ctf/test0.hash.abi
@@ -39,16 +39,26 @@
     </array-type-def>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='bd54fe1a'/>
     <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='a2185560'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='28577a57'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='002ac4a6'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='7359adad'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='8efea9e5'/>
     <pointer-type-def type-id='50d9a3fa' size-in-bits='64' alignment-in-bits='64' id='fd01f598'/>
     <pointer-type-def type-id='a84c031d' size-in-bits='64' alignment-in-bits='64' id='26a90f95'/>
     <qualified-type-def type-id='50d9a3fa' const='yes' id='0fb3b55d'/>
     <pointer-type-def type-id='bd54fe1a' size-in-bits='64' alignment-in-bits='64' id='3ccc2590'/>
     <qualified-type-def type-id='3ccc2590' restrict='yes' id='af4b1b38'/>
     <qualified-type-def type-id='a2185560' volatile='yes' id='ec67e496'/>
+    <var-decl name='status' type-id='e7f43f72' mangled-name='status' visibility='default' elf-symbol-id='status'/>
+    <var-decl name='test_pointer' type-id='26a90f95' mangled-name='test_pointer' visibility='default' elf-symbol-id='test_pointer'/>
+    <var-decl name='test_const' type-id='0fb3b55d' mangled-name='test_const' visibility='default' elf-symbol-id='test_const'/>
+    <var-decl name='test_float' type-id='a6c45d85' mangled-name='test_float' visibility='default' elf-symbol-id='test_float'/>
+    <function-decl name='foo_1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo_1'>
+      <parameter type-id='fd01f598'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <function-decl name='main' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='main'>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <var-decl name='test_array' type-id='b7bd1749' mangled-name='test_array' visibility='default' elf-symbol-id='test_array'/>
+    <var-decl name='test_restrict' type-id='af4b1b38' mangled-name='test_restrict' visibility='default' elf-symbol-id='test_restrict'/>
+    <var-decl name='test_volatile' type-id='ec67e496' mangled-name='test_volatile' visibility='default' elf-symbol-id='test_volatile'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test1.so.abi b/tests/data/test-read-ctf/test1.so.abi
index 5b3caf63..416bd39d 100644
--- a/tests/data/test-read-ctf/test1.so.abi
+++ b/tests/data/test-read-ctf/test1.so.abi
@@ -16,8 +16,13 @@
     </enum-decl>
     <typedef-decl name='opaque_enum' type-id='type-id-4' id='type-id-3'/>
     <typedef-decl name='opaque_struct' type-id='type-id-2' id='type-id-5'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
-    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
+    <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
+    <function-decl name='fn' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fn'>
+      <parameter type-id='type-id-7'/>
+      <parameter type-id='type-id-6'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-8'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test1.so.hash.abi b/tests/data/test-read-ctf/test1.so.hash.abi
index 8019cb54..b3620e75 100644
--- a/tests/data/test-read-ctf/test1.so.hash.abi
+++ b/tests/data/test-read-ctf/test1.so.hash.abi
@@ -16,8 +16,13 @@
     </enum-decl>
     <typedef-decl name='opaque_enum' type-id='55763a91' id='99fcd3a5'/>
     <typedef-decl name='opaque_struct' type-id='6cde5052' id='dae69ca1'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <pointer-type-def type-id='99fcd3a5' size-in-bits='64' alignment-in-bits='64' id='0e0526e0'/>
     <pointer-type-def type-id='dae69ca1' size-in-bits='64' alignment-in-bits='64' id='3f6e71d0'/>
+    <function-decl name='fn' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fn'>
+      <parameter type-id='3f6e71d0'/>
+      <parameter type-id='0e0526e0'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test2.so.abi b/tests/data/test-read-ctf/test2.so.abi
index eb6aff3e..67f802f9 100644
--- a/tests/data/test-read-ctf/test2.so.abi
+++ b/tests/data/test-read-ctf/test2.so.abi
@@ -20,6 +20,14 @@
     <qualified-type-def type-id='type-id-8' const='yes' id='type-id-9'/>
     <pointer-type-def type-id='type-id-9' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <pointer-type-def type-id='type-id-8' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
+      <parameter type-id='type-id-7'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='type-id-6'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
     <type-decl name='void' id='type-id-8'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test2.so.hash.abi b/tests/data/test-read-ctf/test2.so.hash.abi
index 6e57333b..6bbf347e 100644
--- a/tests/data/test-read-ctf/test2.so.hash.abi
+++ b/tests/data/test-read-ctf/test2.so.hash.abi
@@ -20,6 +20,14 @@
     <qualified-type-def type-id='48b5725f' const='yes' id='8581546e'/>
     <pointer-type-def type-id='8581546e' size-in-bits='64' alignment-in-bits='64' id='6e97a70c'/>
     <pointer-type-def type-id='48b5725f' size-in-bits='64' alignment-in-bits='64' id='eaa32e2f'/>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
+      <parameter type-id='5e30a4f9'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='842ea234'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
     <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test3.so.abi b/tests/data/test-read-ctf/test3.so.abi
index 9d55fec5..3d2f6326 100644
--- a/tests/data/test-read-ctf/test3.so.abi
+++ b/tests/data/test-read-ctf/test3.so.abi
@@ -8,5 +8,9 @@
     <elf-symbol name='foo__' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
+    <function-decl name='__foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='__foo'>
+      <return type-id='type-id-1'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test3.so.hash.abi b/tests/data/test-read-ctf/test3.so.hash.abi
index 9d55fec5..1c69e2e1 100644
--- a/tests/data/test-read-ctf/test3.so.hash.abi
+++ b/tests/data/test-read-ctf/test3.so.hash.abi
@@ -8,5 +8,9 @@
     <elf-symbol name='foo__' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
+    <function-decl name='__foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='__foo'>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test4.so.abi b/tests/data/test-read-ctf/test4.so.abi
index b8e0ead3..dc18e191 100644
--- a/tests/data/test-read-ctf/test4.so.abi
+++ b/tests/data/test-read-ctf/test4.so.abi
@@ -10,5 +10,11 @@
     <qualified-type-def type-id='type-id-1' const='yes' id='type-id-5'/>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
     <qualified-type-def type-id='type-id-6' restrict='yes' id='type-id-7'/>
+    <function-decl name='cpy' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='cpy'>
+      <parameter type-id='type-id-4'/>
+      <parameter type-id='type-id-7'/>
+      <parameter type-id='type-id-2'/>
+      <return type-id='type-id-3'/>
+    </function-decl>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test4.so.hash.abi b/tests/data/test-read-ctf/test4.so.hash.abi
index dbe34d9c..dc428592 100644
--- a/tests/data/test-read-ctf/test4.so.hash.abi
+++ b/tests/data/test-read-ctf/test4.so.hash.abi
@@ -10,5 +10,11 @@
     <qualified-type-def type-id='a84c031d' const='yes' id='9b45d938'/>
     <pointer-type-def type-id='9b45d938' size-in-bits='64' alignment-in-bits='64' id='80f4b756'/>
     <qualified-type-def type-id='80f4b756' restrict='yes' id='9d26089a'/>
+    <function-decl name='cpy' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='cpy'>
+      <parameter type-id='266fe297'/>
+      <parameter type-id='9d26089a'/>
+      <parameter type-id='f0981eeb'/>
+      <return type-id='26a90f95'/>
+    </function-decl>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test5.o.abi b/tests/data/test-read-ctf/test5.o.abi
index eb30cf6a..f7bcdeb1 100644
--- a/tests/data/test-read-ctf/test5.o.abi
+++ b/tests/data/test-read-ctf/test5.o.abi
@@ -17,34 +17,32 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <type-decl name='long long int' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <type-decl name='long long unsigned int' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <typedef-decl name='long_long' type-id='type-id-6' id='type-id-8'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-9'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-10'/>
-    <qualified-type-def type-id='type-id-4' const='yes' id='type-id-11'/>
-    <qualified-type-def type-id='type-id-5' const='yes' id='type-id-12'/>
-    <qualified-type-def type-id='type-id-12' volatile='yes' id='type-id-13'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-10'/>
-      <parameter type-id='type-id-13'/>
+    <typedef-decl name='long_long' type-id='type-id-6' id='type-id-7'/>
+    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <qualified-type-def type-id='type-id-4' const='yes' id='type-id-9'/>
+    <qualified-type-def type-id='type-id-5' const='yes' id='type-id-10'/>
+    <qualified-type-def type-id='type-id-10' volatile='yes' id='type-id-11'/>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='type-id-8'/>
+      <parameter type-id='type-id-11'/>
       <return type-id='type-id-5'/>
     </function-decl>
-    <function-decl name='baz2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='baz2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='baz2'>
       <parameter type-id='type-id-4'/>
-      <return type-id='type-id-8'/>
+      <return type-id='type-id-7'/>
     </function-decl>
-    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
       <parameter is-variadic='yes'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <function-decl name='bar2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar2'>
       <parameter type-id='type-id-3'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <function-decl name='baz' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='baz' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='baz'>
       <parameter type-id='type-id-4'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <type-decl name='void' id='type-id-14'/>
+    <type-decl name='void' id='type-id-12'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test7.o.abi b/tests/data/test-read-ctf/test7.o.abi
index b744fac5..a13af174 100644
--- a/tests/data/test-read-ctf/test7.o.abi
+++ b/tests/data/test-read-ctf/test7.o.abi
@@ -3,40 +3,31 @@
     <elf-symbol name='first_type_constructor' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <type-decl name='char' size-in-bits='8' alignment-in-bits='8' id='type-id-1'/>
-    <class-decl name='first_type' size-in-bits='128' alignment-in-bits='32' is-struct='yes' visibility='default' id='type-id-2'>
+    <class-decl name='first_type' size-in-bits='128' alignment-in-bits='32' is-struct='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='member0' type-id='type-id-3' visibility='default'/>
+        <var-decl name='member0' type-id='type-id-2' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='32'>
-        <var-decl name='member1' type-id='type-id-4' visibility='default'/>
+        <var-decl name='member1' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='64'>
-        <var-decl name='ctor' type-id='type-id-5' visibility='default'/>
+        <var-decl name='ctor' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <type-decl name='long long int' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
-    <type-decl name='long long unsigned int' size-in-bits='64' alignment-in-bits='64' id='type-id-9'/>
-    <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='type-id-10'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='type-id-11'/>
-    <typedef-decl name='character' type-id='type-id-12' id='type-id-4'/>
-    <typedef-decl name='constructor' type-id='type-id-13' id='type-id-5'/>
-    <typedef-decl name='integer' type-id='type-id-6' id='type-id-3'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-12'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-14'/>
-    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-15'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='type-id-16'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
-    <pointer-type-def type-id='type-id-18' size-in-bits='64' alignment-in-bits='64' id='type-id-13'/>
-    <function-decl name='first_type_constructor' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-17'/>
-      <return type-id='type-id-19'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
+    <typedef-decl name='character' type-id='type-id-6' id='type-id-3'/>
+    <typedef-decl name='constructor' type-id='type-id-7' id='type-id-4'/>
+    <typedef-decl name='integer' type-id='type-id-5' id='type-id-2'/>
+    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-6'/>
+    <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-9' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
+    <function-decl name='first_type_constructor' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='first_type_constructor'>
+      <parameter type-id='type-id-8'/>
+      <return type-id='type-id-10'/>
     </function-decl>
-    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-18'>
-      <return type-id='type-id-19'/>
+    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-9'>
+      <return type-id='type-id-10'/>
     </function-type>
-    <type-decl name='void' id='type-id-19'/>
+    <type-decl name='void' id='type-id-10'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test8.o.abi b/tests/data/test-read-ctf/test8.o.abi
index 68b3af06..b6996c29 100644
--- a/tests/data/test-read-ctf/test8.o.abi
+++ b/tests/data/test-read-ctf/test8.o.abi
@@ -4,7 +4,7 @@
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
       <parameter type-id='type-id-2'/>
       <return type-id='type-id-1'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test9.o.abi b/tests/data/test-read-ctf/test9.o.abi
index 746dd77b..08704d79 100644
--- a/tests/data/test-read-ctf/test9.o.abi
+++ b/tests/data/test-read-ctf/test9.o.abi
@@ -49,7 +49,7 @@
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-16' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
     <pointer-type-def type-id='type-id-18' size-in-bits='64' alignment-in-bits='64' id='type-id-20'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
       <parameter type-id='type-id-22'/>
       <return type-id='type-id-16'/>
     </function-decl>
diff --git a/tests/test-read-ctf.cc b/tests/test-read-ctf.cc
index fdf49e90..215ed8d6 100644
--- a/tests/test-read-ctf.cc
+++ b/tests/test-read-ctf.cc
@@ -269,20 +269,28 @@ static InOutSpec in_out_specs[] =
     "output/test-read-ctf/test-list-struct.abi",
   },
   {
-    "data/test-read-ctf/test-callback2.o",
+    "data/test-read-common/test-PR26568-1.o",
     "",
     "",
     SEQUENCE_TYPE_ID_STYLE,
-    "data/test-read-ctf/test-callback2.abi",
-    "output/test-read-ctf/test-callback2.abi",
+    "data/test-read-ctf/test-PR26568-1.o.abi",
+    "output/test-read-ctf/test-PR26568-1.o.abi",
   },
   {
-    "data/test-read-ctf/test-forward-undefine-type-decl.o",
+    "data/test-read-common/test-PR26568-2.o",
     "",
     "",
     SEQUENCE_TYPE_ID_STYLE,
-    "data/test-read-ctf/test-forward-undefine-type-decl.abi",
-    "output/test-read-ctf/test-forward-undefine-type-decl.abi",
+    "data/test-read-ctf/test-PR26568-2.o.abi",
+    "output/test-read-ctf/test-PR26568-2.o.abi",
+  },
+  {
+    "data/test-read-ctf/test-callback2.o",
+    "",
+    "",
+    SEQUENCE_TYPE_ID_STYLE,
+    "data/test-read-ctf/test-callback2.abi",
+    "output/test-read-ctf/test-callback2.abi",
   },
   // This should be the last entry.
   {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
diff --git a/tools/abidw.cc b/tools/abidw.cc
index f7a8937d..32d055f5 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -811,13 +811,18 @@ load_kernel_corpus_group_and_write_abixml(char* argv[],
 
   global_timer.start();
   t.start();
+corpus::origin origin =
+#ifdef WITH_CTF
+    opts.use_ctf ? corpus::CTF_ORIGIN :
+#endif
+    corpus::DWARF_ORIGIN;
   corpus_group_sptr group =
     build_corpus_group_from_kernel_dist_under(opts.in_file_path,
 					      /*debug_info_root=*/"",
 					      opts.vmlinux,
 					      opts.suppression_paths,
 					      opts.kabi_whitelist_paths,
-					      supprs, opts.do_log, env);
+					      supprs, opts.do_log, env, origin);
   t.stop();
 
   if (opts.do_log)

base-commit: c96463e1ad974b7c4561886d7a3aa8a3c9a35607
-- 
2.35.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] ctf-reader: Add support to read CTF information from Linux kernel
  2022-05-04 12:48     ` Guillermo E. Martinez
@ 2022-05-12  8:50       ` Dodji Seketeli
  0 siblings, 0 replies; 10+ messages in thread
From: Dodji Seketeli @ 2022-05-12  8:50 UTC (permalink / raw)
  To: Guillermo E. Martinez; +Cc: Guillermo E. Martinez via Libabigail

"Guillermo E. Martinez" <guillermo.e.martinez@oracle.com> a écrit:


> Thanks for these useful comments!!. I will send soon the patch v2 :-)

Thank *you*!

> I was thinking to merge here the patch: 
> https://sourceware.org/pipermail/libabigail/2022q2/004310.html[1]
>
> Dodji, What do you think?

That would make sense, yes.  Thanks.

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3] ctf-reader: Add support to read CTF information from Linux kernel
  2022-05-04 22:29     ` [PATCH v3] " Guillermo E. Martinez
@ 2022-05-12 16:51       ` Dodji Seketeli
  2022-05-16 16:03         ` Guillermo E. Martinez
  2022-05-13  7:18       ` Dodji Seketeli
  1 sibling, 1 reply; 10+ messages in thread
From: Dodji Seketeli @ 2022-05-12 16:51 UTC (permalink / raw)
  To: Guillermo E. Martinez via Libabigail

Hello Guillermo,

"Guillermo E. Martinez via Libabigail" <libabigail@sourceware.org> a
écrit:

So, I have applied the patch to the master branch, thanks!

I made some few cosmetic changes, though.

So please read the comments about the changes I made belows.


[...]

> diff --git a/include/abg-corpus.h b/include/abg-corpus.h
> index 652a8294..690edba5 100644
> --- a/include/abg-corpus.h
> +++ b/include/abg-corpus.h
> @@ -44,10 +44,10 @@ public:
>    enum origin
>    {
>      ARTIFICIAL_ORIGIN = 0,
> -    NATIVE_XML_ORIGIN,
> -    DWARF_ORIGIN,
> -    CTF_ORIGIN,
> -    LINUX_KERNEL_BINARY_ORIGIN
> +    NATIVE_XML_ORIGIN = 1,
> +    DWARF_ORIGIN      = 1 << 1,
> +    CTF_ORIGIN        = 1 << 2,
> +    LINUX_KERNEL_BINARY_ORIGIN = 1 << 3
>    };
>  
>  private:
> @@ -115,11 +115,11 @@ public:
>    corpus_group*
>    get_group();
>  
> -  origin
> +  uint32_t
>    get_origin() const;
>  
>    void
> -  set_origin(origin);
> +  set_origin(uint32_t);
>  
>    string&
>    get_format_major_version_number() const;

These corpus::{get_origin, set_origin} accessors should return/take a
corpus::origin type, for the sake of having a strongly typed system.
But I think I understand why you changed them to return/take a
corpus::origin.  It's because of ...

[...]

diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 2c6839cb..030f8fc8 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc

[...]

-  /* Set some properties of the corpus first.  */
-  corp->set_origin(corpus::CTF_ORIGIN);
-  if (!slurp_elf_info(ctxt, corp))
+  bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
+  uint32_t origin = corpus::CTF_ORIGIN;
+
+  if (is_linux_kernel)
+    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;

... this, right?

I think the C++ compiler wasn't happy by the fact that "origin" is set
to the result of the |= operator, which returns an integer, by
default, right?

In that case, you need to declare a new '|=' operator that takes two
corpus::origin operands and return a corpus::origin.  That way, that
line can just compile fine.

I did just that for you. That is, in abg-corpus.h, I declared these:

    corpus::origin
    operator|(corpus::origin l, corpus::origin r);

    corpus::origin
    operator|=(corpus::origin &l, corpus::origin r);

    corpus::origin
    operator&(corpus::origin l, corpus::origin r);

    corpus::origin
    operator&=(corpus::origin &l, corpus::origin r);

These are defined in abg-corpus.cc, so things should just work as
intended, hopefully.

[...]

diff --git a/src/abg-corpus-priv.h b/src/abg-corpus-priv.h
index 778e3365..28fd1d9b 100644
--- a/src/abg-corpus-priv.h
+++ b/src/abg-corpus-priv.h
@@ -670,7 +670,7 @@ struct corpus::priv
   environment*					env;
   corpus_group*				group;
   corpus::exported_decls_builder_sptr		exported_decls_builder;
-  origin					origin_;
+  uint32_t					origin_;

I reverted this change as per what I said above.

[...]

diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
index a517f384..94f2268c 100644
--- a/src/abg-corpus.cc
+++ b/src/abg-corpus.cc
@@ -851,7 +851,7 @@ corpus::init_format_version()
 /// Getter for the origin of the corpus.
 ///
 /// @return the origin of the corpus.
-corpus::origin
+uint32_t
 corpus::get_origin() const
 {return priv_->origin_;}
 
@@ -859,7 +859,7 @@ corpus::get_origin() const
 ///
 /// @param o the new origin for the corpus.
 void
-corpus::set_origin(origin o)
+corpus::set_origin(uint32_t o)
 {priv_->origin_ = o;}

Likewise.

[...]

diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 2c6839cb..030f8fc8 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -16,6 +16,8 @@
 #include <fcntl.h> /* For open(3) */
 #include <iostream>
 #include <memory>
+#include <map>
+#include <algorithm>
 
 #include "ctf-api.h"
 
@@ -58,13 +60,19 @@ public:
 
   /// A map associating CTF type ids with libabigail IR types.  This
   /// is used to reuse already generated types.
-  unordered_map<ctf_id_t,type_base_sptr> types_map;
+  std::map<std::string,type_base_sptr> types_map;

Any reason why don't use
    unordered_map<string, type_base_sptr> types_map ?

I am asking just because an unordered_map is much faster than just a
map.

There is nothing wrong, though, with using a map.

[...]

   /// Associate a given CTF type ID with a given libabigail IR type.
-  void add_type(ctf_id_t ctf_type, type_base_sptr type)
+  void add_type(ctf_dict_t *dic, ctf_id_t ctf_type, type_base_sptr type)
   {

I have added a doxygen description for the function parameters.

I have also added a newline between the return type (void) and the
function name, to comply with the rest of the project.  I did so with
a few other member function definitions in there as well.

[...]

   /// Lookup a given CTF type ID in the types map.
   ///
   /// @param ctf_type the type ID of the type to lookup.
-  type_base_sptr lookup_type(ctf_id_t ctf_type)
+  type_base_sptr lookup_type(ctf_dict_t *dic, ctf_id_t ctf_type)
   {

Likewise.


Please find below the patch that I committed.


From 07aa48b87dd54b9ca1385247bac697a890e8d305 Mon Sep 17 00:00:00 2001
From: "Guillermo E. Martinez" <guillermo.e.martinez@oracle.com>
Date: Wed, 4 May 2022 17:29:30 -0500
Subject: [PATCH] ctf-reader: Add support to read CTF information from the
 Linux Kernel

This patch is meant to extract ABI information from the CTF data
stored in the Linux kernel build directory.  It depends on the
vmlinux.ctfa archive file.

In order to generate the CTF information, the Linux Kernel build
system must support the 'make ctf' command, which causes the compiler
to be run with -gctf, thus emitting the CTF information for the
Kernel.

The target 'ctf' in the Linux Makefile generates a 'vmlinux.ctfa' file
that will be used by the ctf reader in libabigail. The 'vmlinux.ctfa'
archive has multiple 'ctf dictionaries' called "CTF archive members".

There is one CTF archive member for built-in kernel modules (in
`vmlinux') and one for each out-of-tree kernel module organized in a
parent-child hierarchy.

There also a CTF archive member called `shared_ctf' which is a parent
dictionary containing shared symbols and CTF types used by more than
one kernel object.  These common types are stored in 'types_map' in
the ctf reader, ignoring the ctf dictionary name.  The CTF API has the
machinery for looking for a shared type in the parent dictionary
referred to in a given child dictionary. This CTF layout can be dumped
by using the objdump tool.

Due to the fact that the _same_ ctf archive is used to build the
vmlinux corpus the corpora of the kernel module (which, by the way,
all belong to the same corpus group), the high number of open/close on
the CTF archive is very time consuming during the ctf extraction.

So, the performance is improved up to 300% (from ~2m:50s to ~50s) by
keeping the ctf archive open for a given group, and thus, by using the
same ctf_archive_t pointer while building all the various corpora.

We just invoke `reset_read_context' for each new corpus.  Note that
the `read_context::ctfa` data member should be updated if the
corpus::origin data member is set to `LINUX_KERNEL_BINARY_ORIGIN' and
the file to be process is not 'vmlinux'.

Note that `ctf_close' must be called after processing all group's
members so it is executed from the destructor of `reader_context'.

The basic algorithm used to generate the Linux corpus is the
following:

   1. Looking for: vmlinux, *.ko objects, and vmlinux.ctfa files. The
   first files are used to extract the ELF symbols, and the last one
   contains the CTF type information for non-static variables and
   functions symbols.

   2. `process_ctf_archive' iterates on public symbols for vmlinux and
   its modules, using the name of the symbol, ctf reader search for CTF
   information in its dictionary, if the information was found it
   builds a `var_decl' or `function_decl' depending of `ctf_type_kind'
   result.

This algorithm is also applied to ELF files (exec, dyn, rel), so
instead of iterating on all ctf_types it just loops on the public
symbols.

	* abg-elf-reader-common.h: Include ctf-api.h file.
	(read_and_add_corpus_to_group_from_elf, set_read_context_corpus_group)
	(reset_read_context, dic_type_key): Declare new member functions.
	* include/abg-ir.cc (types_defined_same_linux_kernel_corpus_public): Use
	bitwise to know the corpus `origin'.
	* src/abg-ctf-reader.cc: Include map, algorithms header files.
	(read_context::type_map): Change from unordered_map to std::map storing
	ctf dictionary name as part of the key.
	(read_context::is_elf_exec): Add new member variable.
	(read_context::{cur_corpus_, cur_corpus_group_}): Likewise.
	(read_context::unknown_types_set): Likewise.
	(read_context::{current_corpus_group, main_corpus_from_current_group,
	has_corpus_group, current_corpus_is_main_corpus_from_current_group,
	should_reuse_type_from_corpus_group}): Add new member functions.
	(read_context::{add_unknown_type, lookup_unknown_type, initialize}):
	Likewise.
	(read_context::{add_type, lookup_type}): Add new `ctf_dict_t' type
	argument.
	(ctf_reader::{process_ctf_typedef, process_ctf_base_type,
	process_ctf_function_type, process_ctf_forward_type,
	process_ctf_struct_type, process_ctf_union_type, process_ctf_array_type,
	process_ctf_qualified_type, process_ctf_enum_type}): Add code to `reuse'
	types already registered in main corpus `should_reuse_type_from_corpus_group'.
	Use new `lookup_type' and `add_type' operations on `read_context::types_map'.
	Replace function calls to the new ctf interface. Add verifier to not build
	types duplicated by recursive calling chain.
	(ctf_reader::process_ctf_type): Add code to return immediately if the
	ctf type is unknown. Add unknown types to `unknown_types_set'.
	(ctf_reader::process_ctf_archive): Change comment.
	Add code to iterate over global symbols, searching by symbol name in the
	ctf dictionary using `ctf_lookup_{variable,by_symbol_name}' depending of
	the ELF file type and corpus type, creating a `{var,fuc}_decl' using the
	return type of `ctf_type_kind'.  Also close the ctf dict and call
	`canonicalize_all_types'.
	(slurp_elf_info): Set `is_elf_exec' depending of ELF type.  Also return
	success if corpus origin is Linux and symbol table was read.
	(ctf_reader::read_corpus): Add current corpus.  Set corpus origin to
	`LINUX_KERNEL_BINARY_ORIGIN' if `is_linux_kernel' returns true.  Verify
	the ctf reader status, now the ctf archive is 'opened' using
	`ctf_arc{open,bufopen}' depending if the corpus origin has
	`corpus::LINUX_KERNEL_BINARY_ORIGIN' bit set. Use
	`sort_{function,variables}' calls after extract ctf information.
	`ctf_close' is called from `read_context' destructor.
	(read:context::{set_read_context_corpus_group, reset_read_context,
	read_and_add_corpus_to_group_from_elf, dic_type_key): Add new member
	function implementation.
	* include/abg-tools-utils.h (build_corpus_group_from_kernel_dist_under):
	Add `origin' parameter with default `corpus::DWARF_ORIGIN'.
	* src/abg-tools-utils.cc: Use `abg-ctf-reader.h' file.
	(maybe_load_vmlinux_dwarf_corpus): Add new function.
	(maybe_load_vmlinux_ctf_corpus): Likewise.
	(build_corpus_group_from_kernel_dist_under): Update comments.
	Add new `origin' argument. Use `maybe_load_vmlinux_dwarf_corpus'
	or `maybe_load_vmlinux_ctf_corpus' according to `origin' value.
	* src/abg-corpus.h (corpus::origin): Update `origin' type
	values in enum.
	* src/abg-corpus-priv.h (corpus::priv): Replace `origin' type
	from `corpus::origin' to `uint32_t'.
	* src/abg-corpus.cc (corpus::{get,set}_origin): Replace data
	type from `corpus::origin' to `uint32_t'.
	* tools/abidw.cc (main): Use of --ctf argument to set format debug.
	* tests/test-read-ctf.cc: Add new tests to harness.
	* tests/data/test-read-ctf/test-PR27700.abi: New test expected
	  result.
	* tests/data/test-read-ctf/test-anonymous-fields.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-many.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi: Likewise.
	* tests/data/test-read-common/test-PR26568-2.o: Adjust.
	* tests/data/test-read-ctf/test-PR26568-1.o.abi: Likewise.
	* tests/data/test-read-ctf/test-PR26568-2.o.abi: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.c: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.o: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-array-of-pointers.abi: Likewise.
	* tests/data/test-read-ctf/test-callback.abi: Likewise.
	* tests/data/test-read-ctf/test-callback2.abi: Likewise.
	* tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi:
	Likewise.
	* tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi:
	Likewise.
	* tests/data/test-read-ctf/test-dynamic-array.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-ctf.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-symbol.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum.o.abi: Likewise.
	* tests/data/test-read-ctf/test-forward-type-decl.abi: Likewise.
	* tests/data/test-read-ctf/test-functions-declaration.abi: Likewise.
	* tests/data/test-read-ctf/test-list-struct.abi: Likewise.
	* tests/data/test-read-ctf/test0: Likewise.
	* tests/data/test-read-ctf/test0.abi: Likewise.
	* tests/data/test-read-ctf/test0.c: Likewise.
	* tests/data/test-read-ctf/test0.hash.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test5.o.abi: Likewise.
	* tests/data/test-read-ctf/test7.o.abi: Likewise.
	* tests/data/test-read-ctf/test8.o.abi: Likewise.
	* tests/data/test-read-ctf/test9.o.abi: Likewise.

Signed-off-by: Guillermo E. Martinez <guillermo.e.martinez@oracle.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 include/abg-corpus.h                          |  20 +-
 include/abg-ctf-reader.h                      |  16 +
 include/abg-tools-utils.h                     |   3 +-
 src/abg-corpus-priv.h                         |   2 +-
 src/abg-corpus.cc                             |  56 ++
 src/abg-ctf-reader.cc                         | 507 ++++++++++++++----
 src/abg-dwarf-reader.cc                       |   8 +-
 src/abg-ir.cc                                 |   2 +-
 src/abg-tools-utils.cc                        | 317 ++++++++---
 tests/data/test-read-common/test-PR26568-2.o  | Bin 3048 -> 3488 bytes
 .../test-read-ctf/PR27700/test-PR27700.abi    |   3 +-
 tests/data/test-read-ctf/test-PR26568-1.o.abi |  34 +-
 tests/data/test-read-ctf/test-PR26568-2.o.abi |  22 +-
 tests/data/test-read-ctf/test-PR27700.abi     |  21 +
 .../test-ambiguous-struct-A.o.hash.abi        |   3 +-
 .../test-read-ctf/test-ambiguous-struct-B.c   |   2 +-
 .../test-read-ctf/test-ambiguous-struct-B.o   | Bin 1344 -> 1344 bytes
 .../test-ambiguous-struct-B.o.hash.abi        |   5 +-
 .../test-read-ctf/test-anonymous-fields.o.abi |  18 +-
 .../test-read-ctf/test-array-of-pointers.abi  |   2 +-
 tests/data/test-read-ctf/test-callback.abi    |  30 +-
 tests/data/test-read-ctf/test-callback2.abi   |   2 +-
 .../test-conflicting-type-syms-a.o.hash.abi   |   4 +-
 .../test-conflicting-type-syms-b.o.hash.abi   |   4 +-
 .../test-read-ctf/test-dynamic-array.o.abi    |   2 +-
 tests/data/test-read-ctf/test-enum-ctf.o.abi  |  24 +
 .../test-enum-many-ctf.o.hash.abi             |  69 +++
 .../test-read-ctf/test-enum-many.o.hash.abi   |   6 +-
 .../test-enum-symbol-ctf.o.hash.abi           |  16 +
 .../test-read-ctf/test-enum-symbol.o.hash.abi |   3 +-
 tests/data/test-read-ctf/test-enum.o.abi      |   6 +-
 .../test-read-ctf/test-forward-type-decl.abi  |   2 +-
 .../test-functions-declaration.abi            |   4 +-
 tests/data/test-read-ctf/test-list-struct.abi |   4 +-
 tests/data/test-read-ctf/test0                | Bin 16656 -> 16896 bytes
 tests/data/test-read-ctf/test0.abi            |  30 +-
 tests/data/test-read-ctf/test0.c              |   6 +
 tests/data/test-read-ctf/test0.hash.abi       |  18 +-
 tests/data/test-read-ctf/test1.so.abi         |  11 +-
 tests/data/test-read-ctf/test1.so.hash.abi    |   7 +-
 tests/data/test-read-ctf/test2.so.abi         |   8 +
 tests/data/test-read-ctf/test2.so.hash.abi    |   8 +
 tests/data/test-read-ctf/test3.so.abi         |   4 +
 tests/data/test-read-ctf/test3.so.hash.abi    |   4 +
 tests/data/test-read-ctf/test4.so.abi         |   6 +
 tests/data/test-read-ctf/test4.so.hash.abi    |   6 +
 tests/data/test-read-ctf/test5.o.abi          |  36 +-
 tests/data/test-read-ctf/test7.o.abi          |  43 +-
 tests/data/test-read-ctf/test8.o.abi          |   2 +-
 tests/data/test-read-ctf/test9.o.abi          |   2 +-
 tests/test-read-ctf.cc                        |  20 +-
 tools/abidw.cc                                |   7 +-
 52 files changed, 1068 insertions(+), 367 deletions(-)
 create mode 100644 tests/data/test-read-ctf/test-PR27700.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-ctf.o.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi

diff --git a/include/abg-corpus.h b/include/abg-corpus.h
index 652a8294..4ea82f5b 100644
--- a/include/abg-corpus.h
+++ b/include/abg-corpus.h
@@ -44,10 +44,10 @@ public:
   enum origin
   {
     ARTIFICIAL_ORIGIN = 0,
-    NATIVE_XML_ORIGIN,
-    DWARF_ORIGIN,
-    CTF_ORIGIN,
-    LINUX_KERNEL_BINARY_ORIGIN
+    NATIVE_XML_ORIGIN = 1,
+    DWARF_ORIGIN      = 1 << 1,
+    CTF_ORIGIN        = 1 << 2,
+    LINUX_KERNEL_BINARY_ORIGIN = 1 << 3
   };
 
 private:
@@ -280,6 +280,18 @@ public:
   friend class corpus_group;
 };// end class corpus.
 
+corpus::origin
+operator|(corpus::origin l, corpus::origin r);
+
+corpus::origin
+operator|=(corpus::origin &l, corpus::origin r);
+
+corpus::origin
+operator&(corpus::origin l, corpus::origin r);
+
+corpus::origin
+operator&=(corpus::origin &l, corpus::origin r);
+
 /// Abstracts the building of the set of exported variables and
 /// functions.
 ///
diff --git a/include/abg-ctf-reader.h b/include/abg-ctf-reader.h
index 3343f0d8..ba7289aa 100644
--- a/include/abg-ctf-reader.h
+++ b/include/abg-ctf-reader.h
@@ -19,6 +19,8 @@
 #include "abg-suppression.h"
 #include "abg-elf-reader-common.h"
 
+#include "ctf-api.h"
+
 namespace abigail
 {
 namespace ctf_reader
@@ -32,8 +34,22 @@ create_read_context(const std::string& elf_path,
                     ir::environment *env);
 corpus_sptr
 read_corpus(read_context *ctxt, elf_reader::status& status);
+
 corpus_sptr
 read_corpus(const read_context_sptr &ctxt, elf_reader::status &status);
+
+corpus_sptr
+read_and_add_corpus_to_group_from_elf(read_context*, corpus_group&, elf_reader::status&);
+
+void
+set_read_context_corpus_group(read_context& ctxt, corpus_group_sptr& group);
+
+void
+reset_read_context(read_context_sptr &ctxt,
+                   const std::string&	elf_path,
+                   ir::environment*	environment);
+std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type);
 } // end namespace ctf_reader
 } // end namespace abigail
 
diff --git a/include/abg-tools-utils.h b/include/abg-tools-utils.h
index 68e54028..f7dccb24 100644
--- a/include/abg-tools-utils.h
+++ b/include/abg-tools-utils.h
@@ -311,7 +311,8 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  vector<string>&	kabi_wl_paths,
 					  suppr::suppressions_type&	supprs,
 					  bool				verbose,
-					  environment_sptr&		env);
+					  environment_sptr&		env,
+					  corpus::origin	origin = corpus::DWARF_ORIGIN);
 }// end namespace tools_utils
 
 /// A macro that expands to aborting the program when executed.
diff --git a/src/abg-corpus-priv.h b/src/abg-corpus-priv.h
index 778e3365..d4b9ba32 100644
--- a/src/abg-corpus-priv.h
+++ b/src/abg-corpus-priv.h
@@ -670,7 +670,7 @@ struct corpus::priv
   environment*					env;
   corpus_group*				group;
   corpus::exported_decls_builder_sptr		exported_decls_builder;
-  origin					origin_;
+  corpus::origin				origin_;
   vector<string>				regex_patterns_fns_to_suppress;
   vector<string>				regex_patterns_vars_to_suppress;
   vector<string>				regex_patterns_fns_to_keep;
diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
index a517f384..09047a80 100644
--- a/src/abg-corpus.cc
+++ b/src/abg-corpus.cc
@@ -1560,6 +1560,62 @@ corpus::get_exported_decls_builder() const
   return priv_->exported_decls_builder;
 }
 
+/// Bitwise | operator for the corpus::origin type.
+///
+/// @param l the left-hand side operand of the | operation.
+///
+/// @param r the right-hand side operand of the | operation.
+///
+/// @return the result of the operation.
+corpus::origin
+operator|(corpus::origin l, corpus::origin r)
+{
+  return static_cast<corpus::origin>
+    (static_cast<uint32_t>(l) |  static_cast<uint32_t>(r));
+}
+
+/// Bitwise |= operator for the corpus::origin type.
+///
+/// @param l the left-hand side operand for the |= operation.
+///
+/// @param r the right-hand side operand for the |= operation.
+///
+/// @return the result of the operation.
+corpus::origin
+operator|=(corpus::origin &l, corpus::origin r)
+{
+  l = l | r;
+  return l;
+}
+
+/// Bitwise & operator for the corpus::origin type.
+///
+/// @param l the left-hand side operand of the & operation.
+///
+/// @param r the right-hand side operand of the & operation.
+///
+/// @return the result of the operation.
+corpus::origin
+operator&(corpus::origin l, corpus::origin r)
+{
+    return static_cast<corpus::origin>
+    (static_cast<uint32_t>(l) & static_cast<uint32_t>(r));
+}
+
+/// Bitwise &= operator for the corpus::origin type.
+///
+/// @param l the left-hand side operand of the &= operation.
+///
+/// @param r the right-hand side operand of the &= operation.
+///
+/// @return the result of the operation.
+corpus::origin
+operator&=(corpus::origin &l, corpus::origin r)
+{
+  l = l & r;
+  return l;
+}
+
 // </corpus stuff>
 
 // <corpus_group stuff>
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 2c6839cb..95c81f0e 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -16,6 +16,8 @@
 #include <fcntl.h> /* For open(3) */
 #include <iostream>
 #include <memory>
+#include <map>
+#include <algorithm>
 
 #include "ctf-api.h"
 
@@ -58,13 +60,19 @@ public:
 
   /// A map associating CTF type ids with libabigail IR types.  This
   /// is used to reuse already generated types.
-  unordered_map<ctf_id_t,type_base_sptr> types_map;
+  unordered_map<string,type_base_sptr> types_map;
+
+  /// A set associating unknown CTF type ids
+  std::set<ctf_id_t> unknown_types_set;
 
   /// libelf handler for the ELF file from which we read the CTF data,
   /// and the corresponding file descriptor.
   Elf *elf_handler;
   int elf_fd;
 
+  /// set when ELF is ET_EXEC
+  bool is_elf_exec;
+
   /// The symtab read from the ELF file.
   symtab_reader::symtab_sptr symtab;
 
@@ -74,28 +82,124 @@ public:
   ctf_sect_t symtab_sect;
   ctf_sect_t strtab_sect;
 
+  corpus_sptr			cur_corpus_;
+  corpus_group_sptr		cur_corpus_group_;
+
+  /// Getter of the current corpus group being constructed.
+  ///
+  /// @return current the current corpus being constructed, if any, or
+  /// nil.
+  const corpus_group_sptr
+  current_corpus_group() const
+  {return cur_corpus_group_;}
+
+  /// Test if there is a corpus group being built.
+  ///
+  /// @return if there is a corpus group being built, false otherwise.
+  bool
+  has_corpus_group() const
+  {return bool(cur_corpus_group_);}
+
+  /// Return the main corpus from the current corpus group, if any.
+  ///
+  /// @return the main corpus of the current corpus group, if any, nil
+  /// if no corpus group is being constructed.
+  corpus_sptr
+  main_corpus_from_current_group()
+  {
+    if (cur_corpus_group_)
+      return cur_corpus_group_->get_main_corpus();
+    return corpus_sptr();
+  }
+
+  /// Test if the current corpus being built is the main corpus of the
+  /// current corpus group.
+  ///
+  /// @return return true iff the current corpus being built is the
+  /// main corpus of the current corpus group.
+  bool
+  current_corpus_is_main_corpus_from_current_group()
+  {
+    corpus_sptr main_corpus = main_corpus_from_current_group();
+
+    if (main_corpus && main_corpus.get() == cur_corpus_.get())
+      return true;
+
+    return false;
+  }
+
+  /// Return true if the current corpus is part of a corpus group
+  /// being built and if it's not the main corpus of the group.
+  ///
+  /// For instance, this would return true if we are loading a linux
+  /// kernel *module* that is part of the current corpus group that is
+  /// being built.  In this case, it means we should re-use types
+  /// coming from the "vmlinux" binary that is the main corpus of the
+  /// group.
+  ///
+  /// @return the corpus group the current corpus belongs to, if the
+  /// current corpus is part of a corpus group being built. Nil otherwise.
+  corpus_sptr
+  should_reuse_type_from_corpus_group()
+  {
+    if (has_corpus_group())
+      if (corpus_sptr main_corpus = main_corpus_from_current_group())
+	if (!current_corpus_is_main_corpus_from_current_group())
+	  return current_corpus_group();
+
+    return corpus_sptr();
+  }
+
   /// Associate a given CTF type ID with a given libabigail IR type.
-  void add_type(ctf_id_t ctf_type, type_base_sptr type)
+  ///
+  /// @param dic the dictionnary the type belongs to.
+  ///
+  /// @param ctf_type the type ID.
+  ///
+  /// @param type the type to associate to the ID.
+  void
+  add_type(ctf_dict_t *dic, ctf_id_t ctf_type, type_base_sptr type)
+  {
+    string key = dic_type_key(dic, ctf_type);
+    types_map.insert(std::make_pair(key, type));
+  }
+
+  /// Insert a given CTF unknown type ID.
+  ///
+  /// @param ctf_type the unknown type ID to be added.
+  void
+  add_unknown_type(ctf_id_t ctf_type)
   {
-    types_map.insert(std::make_pair(ctf_type, type));
+    unknown_types_set.insert(ctf_type);
   }
 
   /// Lookup a given CTF type ID in the types map.
   ///
+  /// @param dic the dictionnary the type belongs to.
+  ///
   /// @param ctf_type the type ID of the type to lookup.
-  type_base_sptr lookup_type(ctf_id_t ctf_type)
+  type_base_sptr
+  lookup_type(ctf_dict_t *dic, ctf_id_t ctf_type)
   {
     type_base_sptr result;
+    std::string key = dic_type_key(dic, ctf_type);
 
-    auto search = types_map.find(ctf_type);
+    auto search = types_map.find(key);
     if (search != types_map.end())
       result = search->second;
 
     return result;
   }
 
+  /// Lookup a given CTF unknown type ID in the unknown set.
+  /// @param ctf_type the unknown type ID to lookup.
+  bool
+  lookup_unknown_type(ctf_id_t ctf_type)
+  { return unknown_types_set.find(ctf_type) != unknown_types_set.end(); }
+
   /// Canonicalize all the types stored in the types map.
-  void canonicalize_all_types(void)
+  void
+  canonicalize_all_types(void)
   {
     for (auto t = types_map.begin(); t != types_map.end(); t++)
       canonicalize (t->second);
@@ -103,18 +207,42 @@ public:
 
   /// Constructor.
   ///
+  /// ctfa data member can be used per courpus group.
+  ///
   /// @param elf_path the path to the ELF file.
-  read_context(const string& elf_path, ir::environment *env)
+  read_context(const string& elf_path, ir::environment *env) :
+    ctfa(NULL)
+  {
+    initialize(elf_path, env);
+  }
+
+  /// Initializer of read_context.
+  ///
+  /// @param elf_path the path to the elf file the context is to be
+  /// used for.
+  ///
+  /// @param environment the environment used by the current context.
+  /// This environment contains resources needed by the reader and by
+  /// the types and declarations that are to be created later.  Note
+  /// that ABI artifacts that are to be compared all need to be
+  /// created within the same environment.
+  ///
+  /// Please also note that the life time of this environment object
+  /// must be greater than the life time of the resulting @ref
+  /// read_context the context uses resources that are allocated in
+  /// the environment.
+  void initialize(const string& elf_path, ir::environment *env)
   {
     types_map.clear();
     filename = elf_path;
     ir_env = env;
     elf_handler = NULL;
     elf_fd = -1;
-    ctfa = NULL;
+    is_elf_exec = false;
+    symtab.reset();
+    cur_corpus_group_.reset();
   }
 
-  /// Destructor of the @ref read_context type.
   ~read_context()
   {
     ctf_close(ctfa);
@@ -153,13 +281,18 @@ process_ctf_typedef(read_context *ctxt,
     return result;
 
   const char *typedef_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+  if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+    if (result = lookup_typedef_type(typedef_name, *corp))
+      return result;
+
   type_base_sptr utype = lookup_type(ctxt, corp, tunit,
                                      ctf_dictionary, ctf_utype);
 
   if (!utype)
     return result;
 
-  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_dictionary,
+                                                                ctf_type));
   if (result)
     return result;
 
@@ -180,7 +313,7 @@ process_ctf_typedef(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -225,9 +358,20 @@ process_ctf_base_type(read_context *ctxt,
       type_base_sptr void_type = ctxt->ir_env->get_void_type();
       decl_base_sptr type_declaration = get_type_declaration(void_type);
       result = is_type_decl(type_declaration);
+      canonicalize(result);
     }
   else
     {
+      if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+        {
+          string normalized_type_name = type_name;
+          integral_type int_type;
+          if (parse_integral_type(type_name, int_type))
+            normalized_type_name = int_type.to_string();
+          if (result = lookup_basic_type(normalized_type_name, *corp))
+            return result;
+        }
+
       result = lookup_basic_type(type_name, *corp);
       if (!result)
         result.reset(new type_decl(ctxt->ir_env,
@@ -242,7 +386,7 @@ process_ctf_base_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -303,7 +447,8 @@ process_ctf_function_type(read_context *ctxt,
       function_parms.push_back(parm);
     }
 
-  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_dictionary,
+                                                                 ctf_type));
   if (result)
     return result;
 
@@ -319,7 +464,7 @@ process_ctf_function_type(read_context *ctxt,
       result->set_is_artificial(true);
       decl_base_sptr function_type_decl = get_type_declaration(result);
       add_decl_to_scope(function_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -419,6 +564,11 @@ process_ctf_forward_type(read_context *ctxt,
     }
   else
     {
+      if (!type_is_anonymous)
+        if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+          if (result = lookup_class_type(type_name, *corp))
+            return is_type(result);
+
       class_decl_sptr
        struct_fwd(new class_decl(ctxt->ir_env, type_name,
                                  /*alignment=*/0, /*size=*/0,
@@ -434,7 +584,7 @@ process_ctf_forward_type(read_context *ctxt,
     return is_type(result);
 
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, is_type(result));
+  ctxt->add_type(ctf_dictionary, ctf_type, is_type(result));
 
   return is_type(result);
 }
@@ -458,9 +608,14 @@ process_ctf_struct_type(read_context *ctxt,
 {
   class_decl_sptr result;
   std::string struct_type_name = ctf_type_name_raw(ctf_dictionary,
-                                                 ctf_type);
+                                                   ctf_type);
   bool struct_type_is_anonymous = (struct_type_name == "");
 
+  if (!struct_type_is_anonymous)
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_class_type(struct_type_name, *corp))
+        return result;
+
   /* The libabigail IR encodes C struct types in `class' IR nodes.  */
   result.reset(new class_decl(ctxt->ir_env,
                               struct_type_name,
@@ -479,7 +634,7 @@ process_ctf_struct_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, result);
+  ctxt->add_type(ctf_dictionary, ctf_type, result);
 
   /* Now add the struct members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
@@ -512,6 +667,11 @@ process_ctf_union_type(read_context *ctxt,
                                                    ctf_type);
   bool union_type_is_anonymous = (union_type_name == "");
 
+  if (!union_type_is_anonymous)
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_union_type(union_type_name, *corp))
+        return result;
+
   /* Create the corresponding libabigail union IR node.  */
   result.reset(new union_decl(ctxt->ir_env,
                                 union_type_name,
@@ -528,7 +688,7 @@ process_ctf_union_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, result);
+  ctxt->add_type(ctf_dictionary, ctf_type, result);
 
   /* Now add the union members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
@@ -584,7 +744,8 @@ process_ctf_array_type(read_context *ctxt,
   if (!index_type)
     return result;
 
-  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_dictionary,
+                                                                  ctf_type));
   if (result)
     return result;
 
@@ -623,7 +784,7 @@ process_ctf_array_type(read_context *ctxt,
     {
       decl_base_sptr array_type_decl = get_type_declaration(result);
       add_decl_to_scope(array_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -652,6 +813,11 @@ process_ctf_qualified_type(read_context *ctxt,
   if (!utype)
     return result;
 
+  result = dynamic_pointer_cast<type_base>(ctxt->lookup_type(ctf_dictionary,
+                                                             ctf_type));
+  if (result)
+    return result;
+
   qualified_type_def::CV qualifiers = qualified_type_def::CV_NONE;
   if (type_kind == CTF_K_CONST)
     qualifiers |= qualified_type_def::CV_CONST;
@@ -668,7 +834,7 @@ process_ctf_qualified_type(read_context *ctxt,
     {
       decl_base_sptr qualified_type_decl = get_type_declaration(result);
       add_decl_to_scope(qualified_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -702,7 +868,8 @@ process_ctf_pointer_type(read_context *ctxt,
   if (!target_type)
     return result;
 
-  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_dictionary,
+                                                                    ctf_type));
   if (result)
     return result;
 
@@ -713,7 +880,7 @@ process_ctf_pointer_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -736,6 +903,12 @@ process_ctf_enum_type(read_context *ctxt,
                       ctf_id_t ctf_type)
 {
   enum_type_decl_sptr result;
+  std::string enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+
+  if (!enum_name.empty())
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_enum_type(enum_name, *corp))
+        return result;
 
   /* Build a signed integral type for the type of the enumerators, aka
      the underlying type.  The size of the enumerators in bytes is
@@ -769,13 +942,12 @@ process_ctf_enum_type(read_context *ctxt,
       return result;
     }
 
-  const char *enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
-  result.reset(new enum_type_decl(enum_name, location(),
-                                  utype, enms, enum_name));
+  result.reset(new enum_type_decl(enum_name.c_str(), location(),
+                                  utype, enms, enum_name.c_str()));
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -804,7 +976,10 @@ process_ctf_type(read_context *ctxt,
   int type_kind = ctf_type_kind(ctf_dictionary, ctf_type);
   type_base_sptr result;
 
-  if ((result = ctxt->lookup_type(ctf_type)))
+  if (ctxt->lookup_unknown_type(ctf_type))
+    return nullptr;
+
+  if ((result = ctxt->lookup_type(ctf_dictionary, ctf_type)))
     return result;
 
   switch (type_kind)
@@ -889,7 +1064,10 @@ process_ctf_type(read_context *ctxt,
     }
 
   if (!result)
-    fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+    {
+      fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+      ctxt->add_unknown_type(ctf_type);
+    }
 
   return result;
 }
@@ -913,7 +1091,7 @@ lookup_type(read_context *ctxt, corpus_sptr corp,
             translation_unit_sptr tunit, ctf_dict_t *ctf_dictionary,
             ctf_id_t ctf_type)
 {
-  type_base_sptr result = ctxt->lookup_type(ctf_type);
+  type_base_sptr result = ctxt->lookup_type(ctf_dictionary, ctf_type);
 
   if (!result)
     result = process_ctf_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
@@ -921,8 +1099,8 @@ lookup_type(read_context *ctxt, corpus_sptr corp,
 }
 
 /// Process a CTF archive and create libabigail IR for the types,
-/// variables and function declarations found in the archive.  The IR
-/// is added to the given corpus.
+/// variables and function declarations found in the archive, iterating
+/// over public symbols.  The IR is added to the given corpus.
 ///
 /// @param ctxt the read context containing the CTF archive to
 /// process.
@@ -937,43 +1115,49 @@ process_ctf_archive(read_context *ctxt, corpus_sptr corp)
   ir_translation_unit->set_language(translation_unit::LANG_C);
   corp->add(ir_translation_unit);
 
-  /* Iterate over the CTF dictionaries in the archive.  */
   int ctf_err;
   ctf_dict_t *ctf_dict;
-  ctf_next_t *dict_next = NULL;
-  const char *archive_name;
+  const auto symtab = ctxt->symtab;
+  symtab_reader::symtab_filter filter = symtab->make_filter();
+  filter.set_public_symbols();
+  std::string dict_name;
 
-  while ((ctf_dict = ctf_archive_next(ctxt->ctfa, &dict_next, &archive_name,
-                                      0 /* skip_parent */, &ctf_err)) != NULL)
+  if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
     {
-      /* Iterate over the CTF types stored in this archive.  */
-      ctf_id_t ctf_type;
-      int type_flag;
-      ctf_next_t *type_next = NULL;
+      tools_utils::base_name(ctxt->filename, dict_name);
 
-      while ((ctf_type = ctf_type_next(ctf_dict, &type_next, &type_flag,
-                                       1 /* want_hidden */)) != CTF_ERR)
-        {
-          process_ctf_type(ctxt, corp, ir_translation_unit,
-                            ctf_dict, ctf_type);
-        }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_type_next\n");
+      if (dict_name != "vmlinux")
+        // remove .ko suffix
+        dict_name.erase(dict_name.length() - 3, 3);
+
+      std::replace(dict_name.begin(), dict_name.end(), '-', '_');
+    }
 
-      /* Canonicalize all the types generated above.  This must be
-         done "a posteriori" because the processing of types may
-         require other related types to not be already
-         canonicalized.  */
-      ctxt->canonicalize_all_types();
+  if ((ctf_dict = ctf_dict_open(ctxt->ctfa,
+                                dict_name.empty() ? NULL : dict_name.c_str(),
+                                &ctf_err)) == NULL)
+    {
+      fprintf(stderr, "ERROR dictionary not found\n");
+      abort();
+    }
 
-      /* Iterate over the CTF variables stored in this archive.  */
+  for (const auto& symbol : symtab_reader::filtered_symtab(*symtab, filter))
+    {
+      std::string sym_name = symbol->get_name();
       ctf_id_t ctf_var_type;
-      ctf_next_t *var_next = NULL;
-      const char *var_name;
 
-      while ((ctf_var_type = ctf_variable_next(ctf_dict, &var_next, &var_name))
-             != CTF_ERR)
+      if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+          || ctxt->is_elf_exec)
+        ctf_var_type= ctf_lookup_variable (ctf_dict, sym_name.c_str());
+      else
+        ctf_var_type = ctf_lookup_by_symbol_name(ctf_dict, sym_name.c_str());
+
+      if (ctf_var_type == (ctf_id_t) -1)
+        continue;
+
+      if (ctf_type_kind (ctf_dict, ctf_var_type) != CTF_K_FUNCTION)
         {
+          const char *var_name = sym_name.c_str();
           type_base_sptr var_type = lookup_type(ctxt, corp, ir_translation_unit,
                                                 ctf_dict, ctf_var_type);
           if (!var_type)
@@ -986,50 +1170,38 @@ process_ctf_archive(read_context *ctxt, corpus_sptr corp)
                                              location(),
                                              var_name));
 
+          var_declaration->set_symbol(symbol);
           add_decl_to_scope(var_declaration,
-                             ir_translation_unit->get_global_scope());
+                            ir_translation_unit->get_global_scope());
         }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_variable_next\n");
+      else
+        {
+          const char *func_name = sym_name.c_str();
+          ctf_id_t ctf_sym = ctf_var_type;
+          type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
+                                                 ctf_dict, ctf_sym);
+          if (!func_type)
+            /* Ignore function if its type can't be sorted out.  */
+            continue;
 
-      /* Iterate over the CTF functions stored in this archive.  */
-      ctf_next_t *func_next = NULL;
-      const char *func_name = NULL;
-      ctf_id_t ctf_sym;
+          function_decl_sptr func_declaration;
+          func_declaration.reset(new function_decl(func_name,
+                                                   func_type,
+                                                   0 /* is_inline */,
+                                                   location()));
 
-      while ((ctf_sym = ctf_symbol_next(ctf_dict, &func_next, &func_name,
-                                        1 /* functions symbols only */) != CTF_ERR))
-      {
-        ctf_id_t ctf_func_type = ctf_lookup_by_name(ctf_dict, func_name);
-        type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
-                                               ctf_dict, ctf_func_type);
-        if (!func_type)
-          /* Ignore function if its type can't be sorted out.  */
-          continue;
-
-        elf_symbols func_elf_symbols = ctxt->symtab->lookup_symbol(func_name);
-        if (func_elf_symbols.size() == 0
-            || func_elf_symbols[0]->get_binding() == elf_symbol::LOCAL_BINDING)
-          /* Ignore local functions.  */
-          continue;
-
-        function_decl_sptr func_declaration;
-        func_declaration.reset(new function_decl(func_name,
-                                                 func_type,
-                                                 0 /* is_inline */,
-                                                 location()));
-
-        add_decl_to_scope(func_declaration,
-                           ir_translation_unit->get_global_scope());
-      }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_symbol_next\n");
-
-      ctf_dict_close(ctf_dict);
+          func_declaration->set_symbol(symbol);
+          add_decl_to_scope(func_declaration,
+                            ir_translation_unit->get_global_scope());
+        }
     }
-  if (ctf_err != ECTF_NEXT_END)
-    fprintf(stderr, "ERROR from ctf_archive_next\n");
 
+  ctf_dict_close(ctf_dict);
+  /* Canonicalize all the types generated above.  This must be
+     done "a posteriori" because the processing of types may
+     require other related types to not be already
+     canonicalized.  */
+  ctxt->canonicalize_all_types();
 }
 
 /// Open the ELF file described by the given read context.
@@ -1113,6 +1285,7 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
   /* Set the ELF architecture.  */
   GElf_Ehdr eh_mem;
   GElf_Ehdr *ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem);
+  ctxt->is_elf_exec = (ehdr->e_type == ET_EXEC);
   corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
 
   /* Read the symtab from the ELF file and set it in the corpus.  */
@@ -1121,6 +1294,9 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
                                 0 /* No suppressions.  */);
   corp->set_symtab(ctxt->symtab);
 
+  if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+    return 1;
+
   /* Get the raw ELF section contents for libctf.  */
   Elf_Scn *ctf_scn = elf_helpers::find_section(ctxt->elf_handler, ".ctf", SHT_PROGBITS);
   Elf_Scn *symtab_scn = elf_helpers::find_symbol_table_section(ctxt->elf_handler);
@@ -1167,6 +1343,7 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
   corpus_sptr corp
     = std::make_shared<corpus>(ctxt->ir_env, ctxt->filename);
 
+  ctxt->cur_corpus_ = corp;
   /* Be optimist.  */
   status = elf_reader::STATUS_OK;
 
@@ -1177,25 +1354,52 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
       return corp;
     }
 
-  /* Set some properties of the corpus first.  */
-  corp->set_origin(corpus::CTF_ORIGIN);
-  if (!slurp_elf_info(ctxt, corp))
+  bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
+  corpus::origin origin = corpus::CTF_ORIGIN;
+
+  if (is_linux_kernel)
+    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
+  corp->set_origin(origin);
+
+  if (ctxt->cur_corpus_group_)
+    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
+
+  if (!slurp_elf_info(ctxt, corp) && !is_linux_kernel)
     {
       status = elf_reader::STATUS_NO_SYMBOLS_FOUND;
       return corp;
     }
 
-  /* Build the ctfa from the contents of the relevant ELF sections,
-     and process the CTF archive in the read context, if any.
-     Information about the types, variables, functions, etc contained
-     in the archive are added to the given corpus.  */
   int errp;
-  ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
-                               &ctxt->strtab_sect, &errp);
+  if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+    {
+      std::string filename;
+      if (tools_utils::base_name(ctxt->filename, filename)
+          && filename == "vmlinux")
+        {
+          std::string vmlinux_ctfa_path = ctxt->filename + ".ctfa";
+          ctxt->ctfa = ctf_arc_open(vmlinux_ctfa_path.c_str(), &errp);
+        }
+    }
+  else
+    /* Build the ctfa from the contents of the relevant ELF sections,
+       and process the CTF archive in the read context, if any.
+       Information about the types, variables, functions, etc contained
+       in the archive are added to the given corpus.  */
+    ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
+                                 &ctxt->strtab_sect, &errp);
+
+  ctxt->ir_env->canonicalization_is_done(false);
   if (ctxt->ctfa == NULL)
     status = elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
   else
-    process_ctf_archive(ctxt, corp);
+    {
+      process_ctf_archive(ctxt, corp);
+      ctxt->cur_corpus_->sort_functions();
+      ctxt->cur_corpus_->sort_variables();
+    }
+
+  ctxt->ir_env->canonicalization_is_done(true);
 
   /* Cleanup and return.  */
   close_elf_handler(ctxt);
@@ -1216,5 +1420,94 @@ corpus_sptr
 read_corpus(const read_context_sptr &ctxt, elf_reader::status &status)
 {return read_corpus(ctxt.get(), status);}
 
+/// Set the @ref corpus_group being created to the current read context.
+///
+/// @param ctxt the read_context to consider.
+///
+/// @param group the @ref corpus_group to set.
+void
+set_read_context_corpus_group(read_context& ctxt,
+                              corpus_group_sptr& group)
+{
+  ctxt.cur_corpus_group_ = group;
+}
+
+/// Read a corpus and add it to a given @ref corpus_group.
+///
+/// @param ctxt the reading context to consider.
+///
+/// @param group the @ref corpus_group to add the new corpus to.
+///
+/// @param status output parameter. The status of the read.  It is set
+/// by this function upon its completion.
+corpus_sptr
+read_and_add_corpus_to_group_from_elf(read_context* ctxt,
+                                      corpus_group& group,
+                                      elf_reader::status& status)
+{
+  corpus_sptr result;
+  corpus_sptr corp = read_corpus(ctxt, status);
+  if (status & elf_reader::STATUS_OK)
+    {
+      if (!corp->get_group())
+        group.add_corpus(corp);
+      result = corp;
+    }
+
+  return result;
+}
+
+/// Re-initialize a read_context so that it can re-used to read
+/// another binary.
+///
+/// @param ctxt the context to re-initialize.
+///
+/// @param elf_path the path to the elf file the context is to be used
+/// for.
+///
+/// @param environment the environment used by the current context.
+/// This environment contains resources needed by the reader and by
+/// the types and declarations that are to be created later.  Note
+/// that ABI artifacts that are to be compared all need to be created
+/// within the same environment.
+///
+/// Please also note that the life time of this environment object
+/// must be greater than the life time of the resulting @ref
+/// read_context the context uses resources that are allocated in the
+/// environment.
+void
+reset_read_context(read_context_sptr	&ctxt,
+                   const std::string&	 elf_path,
+                   ir::environment*	 environment)
+{
+  if (ctxt)
+    ctxt->initialize(elf_path, environment);
+}
+
+/// Returns a key to be use in types_map dict conformed by
+/// dictionary id and the CTF type id for a given type.
+///
+/// CTF id types are unique by child dictionary, but CTF id
+/// types in parent dictionary are unique across the all
+/// dictionaries in the CTF archive, to differentiate
+/// one each other this member function relies in
+/// ctf_type_isparent function.
+///
+/// @param dic the pointer to CTF dictionary where the @p type
+/// was found.
+///
+/// @param type the id for given CTF type.
+std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type)
+{
+  std::stringstream key;
+
+  if (ctf_type_isparent (dic, ctf_type))
+    key << std::hex << ctf_type;
+  else
+    key << std::hex << ctf_type << '-' << ctf_cuname(dic);
+  return key.str();
+}
+
 } // End of namespace ctf_reader
 } // End of namespace abigail
diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index dc82cf3b..7bf2375d 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -14444,10 +14444,12 @@ read_debug_info_into_corpus(read_context& ctxt)
   // First set some mundane properties of the corpus gathered from
   // ELF.
   ctxt.current_corpus()->set_path(ctxt.elf_path());
+
+  corpus::origin origin = corpus::DWARF_ORIGIN;
   if (is_linux_kernel(ctxt.elf_handle()))
-    ctxt.current_corpus()->set_origin(corpus::LINUX_KERNEL_BINARY_ORIGIN);
-  else
-    ctxt.current_corpus()->set_origin(corpus::DWARF_ORIGIN);
+    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
+  ctxt.current_corpus()->set_origin(origin);
+
   ctxt.current_corpus()->set_soname(ctxt.dt_soname());
   ctxt.current_corpus()->set_needed(ctxt.dt_needed());
   ctxt.current_corpus()->set_architecture_name(ctxt.elf_architecture());
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 0ef5e8b2..4e907620 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -13498,7 +13498,7 @@ types_defined_same_linux_kernel_corpus_public(const type_base& t1,
   /// kernel corpus, let's move on.  Otherwise bail out.
   if (!(t1_corpus && t2_corpus
 	&& t1_corpus == t2_corpus
-	&& (t1_corpus->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN)
+	&& (t1_corpus->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
 	&& (is_class_or_union_type(&t1)
 	    || is_enum_type(&t1))))
     return false;
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index 1f0f6fa8..f30c3f1d 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -44,6 +44,9 @@
 #include <sstream>
 
 #include "abg-dwarf-reader.h"
+#ifdef WITH_CTF
+#include "abg-ctf-reader.h"
+#endif
 #include "abg-internal.h"
 #include "abg-regex.h"
 
@@ -2486,6 +2489,223 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
 					   module_paths);
 }
 
+/// If the @ref origin is DWARF_ORIGIN it build a @ref corpus_group
+/// made of vmlinux kernel file and the linux kernel modules found
+/// under @p root directory and under its sub-directories, recursively.
+///
+/// @param origin the debug type information in vmlinux kernel and
+/// the linux kernel modules to be used to build the corpora @p group.
+///
+/// @param the group @ref corpus_group to be built.
+///
+/// @param vmlinux the path to the vmlinux binary.
+///
+/// @param modules a vector with the paths to the linux kernel
+/// modules.
+///
+/// @param root the path of the directory under which the kernel
+/// kernel modules were found.
+///
+/// @param di_root the directory in aboslute path which debug
+/// info is to be found for binaries under director @p root
+///
+/// @param suppr_paths the paths to the suppression specifications to
+/// apply while loading the binaries.
+///
+/// @param kabi_wl_path the paths to the kabi whitelist files to take
+/// into account while loading the binaries.
+///
+/// @param supprs the suppressions resulting from parsing the
+/// suppression specifications at @p suppr_paths.  This is set by this
+/// function.
+///
+/// @param verbose true if the function has to emit some verbose
+/// messages.
+///
+/// @param t time to trace time spent in each step.
+///
+/// @param env the environment to create the corpus_group in.
+static void
+maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
+                                corpus_group_sptr&  group,
+                                const string&       vmlinux,
+                                vector<string>&     modules,
+                                const string&       root,
+                                vector<char**>&     di_roots,
+                                vector<string>&     suppr_paths,
+                                vector<string>&     kabi_wl_paths,
+                                suppressions_type&  supprs,
+                                bool                verbose,
+                                timer&              t,
+                                environment_sptr&   env)
+{
+  if (!(origin & corpus::DWARF_ORIGIN))
+    return;
+
+  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
+  dwarf_reader::read_context_sptr ctxt;
+  ctxt =
+   dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
+                                     /*read_all_types=*/false,
+                                     /*linux_kernel_mode=*/true);
+  dwarf_reader::set_do_log(*ctxt, verbose);
+
+  t.start();
+  load_generate_apply_suppressions(*ctxt, suppr_paths,
+                                   kabi_wl_paths, supprs);
+  t.stop();
+
+  if (verbose)
+    std::cerr << "loaded white list and generated suppr spec in: "
+     << t
+     << "\n";
+
+  group.reset(new corpus_group(env.get(), root));
+
+  set_read_context_corpus_group(*ctxt, group);
+
+  if (verbose)
+    std::cerr << "reading kernel binary '"
+     << vmlinux << "' ...\n" << std::flush;
+
+  // Read the vmlinux corpus and add it to the group.
+  t.start();
+  read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
+  t.stop();
+
+  if (verbose)
+    std::cerr << vmlinux
+     << " reading DONE:"
+     << t << "\n";
+
+  if (group->is_empty())
+    return;
+
+  // Now add the corpora of the modules to the corpus group.
+  int total_nb_modules = modules.size();
+  int cur_module_index = 1;
+  for (vector<string>::const_iterator m = modules.begin();
+       m != modules.end();
+       ++m, ++cur_module_index)
+    {
+      if (verbose)
+        std::cerr << "reading module '"
+         << *m << "' ("
+         << cur_module_index
+         << "/" << total_nb_modules
+         << ") ... " << std::flush;
+
+      reset_read_context(ctxt, *m, di_roots, env.get(),
+                         /*read_all_types=*/false,
+                         /*linux_kernel_mode=*/true);
+
+      load_generate_apply_suppressions(*ctxt, suppr_paths,
+                                       kabi_wl_paths, supprs);
+
+      set_read_context_corpus_group(*ctxt, group);
+
+      t.start();
+      read_and_add_corpus_to_group_from_elf(*ctxt,
+                                            *group, status);
+      t.stop();
+      if (verbose)
+        std::cerr << "module '"
+         << *m
+         << "' reading DONE: "
+         << t << "\n";
+    }
+}
+
+/// If the @ref origin is CTF_ORIGIN it build a @ref corpus_group
+/// made of vmlinux kernel file and the linux kernel modules found
+/// under @p root directory and under its sub-directories, recursively.
+///
+/// @param origin the debug type information in vmlinux kernel and
+/// the linux kernel modules to be used to build the corpora @p group.
+///
+/// @param group the @ref corpus_group to be built.
+///
+/// @param vmlinux the path to the vmlinux binary.
+///
+/// @param modules a vector with the paths to the linux kernel
+/// modules.
+///
+/// @param root the path of the directory under which the kernel
+/// kernel modules were found.
+///
+/// @param verbose true if the function has to emit some verbose
+/// messages.
+///
+/// @param t time to trace time spent in each step.
+///
+/// @param env the environment to create the corpus_group in.
+#ifdef WITH_CTF
+static void
+maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
+                              corpus_group_sptr&  group,
+                              const string&       vmlinux,
+                              vector<string>&     modules,
+                              const string&       root,
+                              bool                verbose,
+                              timer&              t,
+                              environment_sptr&   env)
+{
+  if (!(origin & corpus::CTF_ORIGIN))
+    return;
+
+  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
+  ctf_reader::read_context_sptr ctxt;
+  ctxt = ctf_reader::create_read_context(vmlinux, env.get());
+  group.reset(new corpus_group(env.get(), root));
+  set_read_context_corpus_group(*ctxt, group);
+
+  if (verbose)
+    std::cerr << "reading kernel binary '"
+     << vmlinux << "' ...\n" << std::flush;
+
+  // Read the vmlinux corpus and add it to the group.
+  t.start();
+  read_and_add_corpus_to_group_from_elf(ctxt.get(), *group, status);
+  t.stop();
+
+  if (verbose)
+    std::cerr << vmlinux
+     << " reading DONE:"
+     << t << "\n";
+
+  if (group->is_empty())
+    return;
+
+  // Now add the corpora of the modules to the corpus group.
+  int total_nb_modules = modules.size();
+  int cur_module_index = 1;
+  for (vector<string>::const_iterator m = modules.begin();
+       m != modules.end();
+       ++m, ++cur_module_index)
+    {
+      if (verbose)
+        std::cerr << "reading module '"
+         << *m << "' ("
+         << cur_module_index
+         << "/" << total_nb_modules
+         << ") ... " << std::flush;
+
+      reset_read_context(ctxt, *m, env.get());
+      set_read_context_corpus_group(*ctxt, group);
+
+      t.start();
+      read_and_add_corpus_to_group_from_elf(ctxt.get(),
+                                            *group, status);
+      t.stop();
+      if (verbose)
+        std::cerr << "module '"
+         << *m
+         << "' reading DONE: "
+         << t << "\n";
+    }
+}
+#endif
+
 /// Walk a given directory and build an instance of @ref corpus_group
 /// from the vmlinux kernel binary and the linux kernel modules found
 /// under that directory and under its sub-directories, recursively.
@@ -2493,6 +2713,11 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
 /// The main corpus of the @ref corpus_group is made of the vmlinux
 /// binary.  The other corpora are made of the linux kernel binaries.
 ///
+/// Depending of the @ref origin it delegates the corpus build @p group
+/// to:
+///     @ref maybe_load_vmlinux_dwarf_corpus
+///     @ref maybe_load_vmlinux_ctf_corpus
+///
 /// @param root the path of the directory under which the kernel
 /// kernel modules are to be found.  The vmlinux can also be found
 /// somewhere under that directory, but if it's not in there, its path
@@ -2528,10 +2753,11 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  vector<string>&	kabi_wl_paths,
 					  suppressions_type&	supprs,
 					  bool			verbose,
-					  environment_sptr&	env)
+					  environment_sptr&	env,
+					  corpus::origin	origin)
 {
   string vmlinux = vmlinux_path;
-  corpus_group_sptr result;
+  corpus_group_sptr group;
   vector<string> modules;
 
   if (verbose)
@@ -2548,7 +2774,6 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
   if (verbose)
     std::cerr << "DONE: " << t << "\n";
 
-  dwarf_reader::read_context_sptr ctxt;
   if (got_binary_paths)
     {
       shared_ptr<char> di_root =
@@ -2556,86 +2781,18 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
       char *di_root_ptr = di_root.get();
       vector<char**> di_roots;
       di_roots.push_back(&di_root_ptr);
-      abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
-      corpus_group_sptr group;
-      if (!vmlinux.empty())
-	{
-	  ctxt =
-	    dwarf_reader::create_read_context(vmlinux, di_roots ,env.get(),
-					      /*read_all_types=*/false,
-					      /*linux_kernel_mode=*/true);
-	  dwarf_reader::set_do_log(*ctxt, verbose);
-
-	  t.start();
-	  load_generate_apply_suppressions(*ctxt, suppr_paths,
-					   kabi_wl_paths, supprs);
-	  t.stop();
-
-	  if (verbose)
-	    std::cerr << "loaded white list and generated suppr spec in: "
-		      << t
-		      << "\n";
-
-	  group.reset(new corpus_group(env.get(), root));
-
-	  set_read_context_corpus_group(*ctxt, group);
-
-	  if (verbose)
-	    std::cerr << "reading kernel binary '"
-		      << vmlinux << "' ...\n" << std::flush;
-
-	  // Read the vmlinux corpus and add it to the group.
-	  t.start();
-	  read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
-	  t.stop();
-
-	  if (verbose)
-	    std::cerr << vmlinux
-		      << " reading DONE:"
-		      << t << "\n";
-	}
 
-      if (!group->is_empty())
-	{
-	  // Now add the corpora of the modules to the corpus group.
-	  int total_nb_modules = modules.size();
-	  int cur_module_index = 1;
-	  for (vector<string>::const_iterator m = modules.begin();
-	       m != modules.end();
-	       ++m, ++cur_module_index)
-	    {
-	      if (verbose)
-		std::cerr << "reading module '"
-			  << *m << "' ("
-			  << cur_module_index
-			  << "/" << total_nb_modules
-			  << ") ... " << std::flush;
-
-	      reset_read_context(ctxt, *m, di_roots, env.get(),
-				 /*read_all_types=*/false,
-				 /*linux_kernel_mode=*/true);
-
-	      load_generate_apply_suppressions(*ctxt, suppr_paths,
-					       kabi_wl_paths, supprs);
-
-	      set_read_context_corpus_group(*ctxt, group);
-
-	      t.start();
-	      read_and_add_corpus_to_group_from_elf(*ctxt,
-						    *group, status);
-	      t.stop();
-	      if (verbose)
-		std::cerr << "module '"
-			  << *m
-			  << "' reading DONE: "
-			  << t << "\n";
-	    }
-
-	  result = group;
-	}
+      maybe_load_vmlinux_dwarf_corpus(origin, group, vmlinux,
+                                      modules, root, di_roots,
+                                      suppr_paths, kabi_wl_paths,
+                                      supprs, verbose, t, env);
+#ifdef WITH_CTF
+      maybe_load_vmlinux_ctf_corpus(origin, group, vmlinux,
+                                    modules, root, verbose, t, env);
+#endif
     }
 
-  return result;
+  return group;
 }
 
 }//end namespace tools_utils
diff --git a/tests/data/test-read-common/test-PR26568-2.o b/tests/data/test-read-common/test-PR26568-2.o
index b192d52132766d4f95136e23f93de43a64d8cc2e..a6706e8cf508ab89927b0fccecd0268d27111ed9 100644
GIT binary patch
delta 1078
zcmZuwJ#Q015Z%3R+XNC4+rf~Wtw;eB%$Z17uE0<rBAO5pQBj=FADpo7f_)Bl6-1ZL
zWGcFpL83uvC{3skO-dR>8YF6d0W;^l$g=#T(agS?dAmD%_cwibb#Nn{HP|`IVN_-*
zmVAHz`rg0aiWKFRqCj{BJsEYAeL@S+bhImI1kPB7YSeJW7>OZA(1_29CDoC}EE<7w
zsFR{tqeK}CFQZ3+WdmmP^q!2X1vG><a*WfqD3v0Dy2fxZJc8>5tjC(Z*T_=XXAjt}
z?^ap8>oM!4->O-aex+~uZQE(qtWMjpnr_9exDDHF=DRzcpk1?DR#58%`Hoe!1A7!B
zTg^LutL1wmVsmS~c(+)}uitjUGkmTeaY###a!yds<{P6;&yUgdUU~i-FRVO%A=#X(
z@LEpFGSh{RlZR`{0vyU3p8->G4^#sN$`0Q;=IRA5qc9}2U+_o!rrts&jvez*)(z<y
zhq%6+DH2IrOblko;Y44x?_h?eUPc?osd&1fAm`B&6{#!={vrBl@{jSw2nX<8H*?z<
zO{+Q+RTgX*D@)VPF%XYjfQ^Kyx}-xlj9sGd0P!4Rx@lK2n$|rO-Mz4uF}g(@ZSodf
z<mh|_v~kqME)ML+%*<O%g;i0zC_R<oB(|CxL}@`s?g^a?u|^{52aLiiNV^K&Bn6B5
zZ0;kH^#6!)U^GHcv=+iCenpb@pR76(RVCPuuiTtAhZ2b+qF19i%t11-Hg_g^e};Md
Wwcu&OlD??$E^#lmDcXL}kpBaNjDTqX

delta 508
zcmZvYJ4*vW6oqH@mA%=G1lhO&i`^hZLkd#{K}{MFY|?3G0>KAJj1W*_wN`>n^!NiJ
zq)4A4oum?*^g<f#EN$)F*&Rj1f#J-(ocZRS=`X&!y%l$8u%A_lP8F76&h6&%=#dXO
zot(A~{o_`L;XvIQP1OeH8s4;wsxm_=NwtKcqdVy9dz|p8pK~@kGi;8l#0+(Ff<9?z
zlA|0kbSV!%EC=Ki>RLR*Bo;Ows%V+A&PrWJgIxNM)g7wIC4r-B9=BEzkjHoMKyJa;
z<6cR+1v3%uzsx3bA#*GVy9i8=??;51BwYL=&_9GWa+XVTN^Gm4YI*z;4a-&P3c6OF
z-$aI)G!!Gly?9nJ)bP(1&@<C~fSm1;sm7EN0z1rRJ5-jPa+GZ>Cd)j_$-e(ZWJ_ae
b7pX1XF9?zz{8U!i*07e^pjUb2Nd)`?0Gw2F

diff --git a/tests/data/test-read-ctf/PR27700/test-PR27700.abi b/tests/data/test-read-ctf/PR27700/test-PR27700.abi
index 62df1017..fe3a897d 100644
--- a/tests/data/test-read-ctf/PR27700/test-PR27700.abi
+++ b/tests/data/test-read-ctf/PR27700/test-PR27700.abi
@@ -11,9 +11,8 @@
       <enumerator name='foo_e2' value='2'/>
       <enumerator name='foo_e3' value='3'/>
     </enum-decl>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <pointer-type-def type-id='022218d8' size-in-bits='64' alignment-in-bits='64' id='8750e847'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
       <parameter type-id='8750e847'/>
       <return type-id='48b5725f'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR26568-1.o.abi b/tests/data/test-read-ctf/test-PR26568-1.o.abi
index d62474ec..832dc1bd 100644
--- a/tests/data/test-read-ctf/test-PR26568-1.o.abi
+++ b/tests/data/test-read-ctf/test-PR26568-1.o.abi
@@ -7,47 +7,29 @@
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='' type-id='type-id-2' visibility='default'/>
       </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='' type-id='type-id-5' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
-      </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
+        <var-decl name='y' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-5'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-5'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
+        <var-decl name='x' type-id='type-id-6' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
     <union-decl name='' size-in-bits='64' is-anonymous='yes' visibility='default' id='type-id-2'>
-      <data-member access='public'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
-      </data-member>
-      <data-member access='public'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
-      </data-member>
       <data-member access='public'>
         <var-decl name='' type-id='type-id-5' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
+        <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
     </union-decl>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fun'>
       <parameter type-id='type-id-7'/>
       <return type-id='type-id-8'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR26568-2.o.abi b/tests/data/test-read-ctf/test-PR26568-2.o.abi
index a934d15b..70e0772f 100644
--- a/tests/data/test-read-ctf/test-PR26568-2.o.abi
+++ b/tests/data/test-read-ctf/test-PR26568-2.o.abi
@@ -3,34 +3,28 @@
     <elf-symbol name='fun' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-2' visibility='default'/>
+        <var-decl name='y' type-id='type-id-2' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-4' visibility='default'/>
+        <var-decl name='x' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-2'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <union-decl name='A' size-in-bits='64' visibility='default' id='type-id-5'>
-      <data-member access='public'>
-        <var-decl name='' type-id='type-id-1' visibility='default'/>
-      </data-member>
-      <data-member access='public'>
-        <var-decl name='x' type-id='type-id-2' visibility='default'/>
-      </data-member>
       <data-member access='public'>
         <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='y' type-id='type-id-4' visibility='default'/>
+        <var-decl name='' type-id='type-id-1' visibility='default'/>
       </data-member>
     </union-decl>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fun'>
       <parameter type-id='type-id-6'/>
       <return type-id='type-id-7'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR27700.abi b/tests/data/test-read-ctf/test-PR27700.abi
new file mode 100644
index 00000000..fe3a897d
--- /dev/null
+++ b/tests/data/test-read-ctf/test-PR27700.abi
@@ -0,0 +1,21 @@
+<abi-corpus version='2.1' path='data/test-read-common/PR27700/test-PR27700.o'>
+  <elf-function-symbols>
+    <elf-symbol name='foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-function-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='foo' linkage-name='foo' id='022218d8'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='foo_e0' value='0'/>
+      <enumerator name='foo_e1' value='1'/>
+      <enumerator name='foo_e2' value='2'/>
+      <enumerator name='foo_e3' value='3'/>
+    </enum-decl>
+    <pointer-type-def type-id='022218d8' size-in-bits='64' alignment-in-bits='64' id='8750e847'/>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='8750e847'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi b/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
index 922a1daf..12050a5b 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
@@ -30,7 +30,6 @@
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='7359adad'/>
     <pointer-type-def type-id='3ed987a4' size-in-bits='64' alignment-in-bits='64' id='84d5ac12'/>
     <pointer-type-def type-id='1c12b755' size-in-bits='64' alignment-in-bits='64' id='55cd64e8'/>
-    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default'/>
-    <var-decl name='foo' type-id='55cd64e8' mangled-name='foo' visibility='default'/>
+    <var-decl name='foo' type-id='55cd64e8' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.c b/tests/data/test-read-ctf/test-ambiguous-struct-B.c
index 95a93469..e592529b 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-B.c
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-B.c
@@ -2,4 +2,4 @@ struct A;
 struct B { struct A *a; };
 struct A { struct B b; int foo; struct B b2; };
 
-static struct A a __attribute__((__used__));
+struct A a __attribute__((__used__));
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.o b/tests/data/test-read-ctf/test-ambiguous-struct-B.o
index 06bd0f502a874ad4a10c4beb5788eaace44c2bf9..40a11fcbd4ae19b78a943812f69606cdc6c9fc15 100644
GIT binary patch
delta 20
ccmX@Wb%1Nb8%9RK&2Jg^GchtvUdu8W08_UIfB*mh

delta 20
ccmX@Wb%1Nb8%9RP&2Jg^GchtxUdu8W08;!1aR2}S

diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi b/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
index 28291eb5..83d21919 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-ctf/test-ambiguous-struct-B.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='a' size='24' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
   <abi-instr address-size='64' language='LANG_C'>
     <class-decl name='A' size-in-bits='192' alignment-in-bits='64' is-struct='yes' visibility='default' id='3ed987a4'>
       <data-member access='public' layout-offset-in-bits='0'>
@@ -18,6 +21,6 @@
     </class-decl>
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
     <pointer-type-def type-id='3ed987a4' size-in-bits='64' alignment-in-bits='64' id='84d5ac12'/>
-    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default'/>
+    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default' elf-symbol-id='a'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-anonymous-fields.o.abi b/tests/data/test-read-ctf/test-anonymous-fields.o.abi
index 0419c29c..2134a86d 100644
--- a/tests/data/test-read-ctf/test-anonymous-fields.o.abi
+++ b/tests/data/test-read-ctf/test-anonymous-fields.o.abi
@@ -3,14 +3,14 @@
     <elf-symbol name='t' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-variable-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='vaddr' type-id='type-id-2' visibility='default'/>
+        <var-decl name='dup_xol_work' type-id='type-id-2' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='dup_xol_work' type-id='type-id-4' visibility='default'/>
+        <var-decl name='vaddr' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
     <class-decl name='uprobe_task' size-in-bits='64' alignment-in-bits='64' is-struct='yes' visibility='default' id='type-id-5'>
@@ -18,16 +18,16 @@
         <var-decl name='' type-id='type-id-6' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-2'/>
     <union-decl name='' size-in-bits='64' is-anonymous='yes' visibility='default' id='type-id-6'>
       <data-member access='public'>
-        <var-decl name='' type-id='type-id-1' visibility='default'/>
+        <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
+        <var-decl name='' type-id='type-id-1' visibility='default'/>
       </data-member>
     </union-decl>
-    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='t' type-id='type-id-5' mangled-name='t' visibility='default'/>
+    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
+    <var-decl name='t' type-id='type-id-5' mangled-name='t' visibility='default' elf-symbol-id='t'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-array-of-pointers.abi b/tests/data/test-read-ctf/test-array-of-pointers.abi
index 920da28b..195361df 100644
--- a/tests/data/test-read-ctf/test-array-of-pointers.abi
+++ b/tests/data/test-read-ctf/test-array-of-pointers.abi
@@ -31,6 +31,6 @@
     <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
     <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-11'/>
-    <var-decl name='t' type-id='type-id-11' mangled-name='t' visibility='default'/>
+    <var-decl name='t' type-id='type-id-11' mangled-name='t' visibility='default' elf-symbol-id='t'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-callback.abi b/tests/data/test-read-ctf/test-callback.abi
index 704c4971..7f9b6c5f 100644
--- a/tests/data/test-read-ctf/test-callback.abi
+++ b/tests/data/test-read-ctf/test-callback.abi
@@ -4,28 +4,16 @@
     <elf-symbol name='f2' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='test' size-in-bits='64' alignment-in-bits='64' is-struct='yes' visibility='default' id='type-id-1'>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='fn1' type-id='type-id-2' visibility='default'/>
-      </data-member>
-    </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
-    <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
-    <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <function-decl name='assign' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <return type-id='type-id-7'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
+    <function-decl name='assign' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='assign'>
+      <return type-id='type-id-3'/>
     </function-decl>
-    <function-decl name='f2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-3'/>
-      <parameter type-id='type-id-4'/>
-      <return type-id='type-id-7'/>
+    <function-decl name='f2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='f2'>
+      <parameter type-id='type-id-1'/>
+      <parameter type-id='type-id-2'/>
+      <return type-id='type-id-3'/>
     </function-decl>
-    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-6'>
-      <parameter type-id='type-id-3'/>
-      <parameter type-id='type-id-4'/>
-      <return type-id='type-id-7'/>
-    </function-type>
-    <type-decl name='void' id='type-id-7'/>
+    <type-decl name='void' id='type-id-3'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-callback2.abi b/tests/data/test-read-ctf/test-callback2.abi
index bdd4ad33..ddc3e493 100644
--- a/tests/data/test-read-ctf/test-callback2.abi
+++ b/tests/data/test-read-ctf/test-callback2.abi
@@ -11,7 +11,7 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
-    <var-decl name='s0' type-id='type-id-5' mangled-name='s0' visibility='default'/>
+    <var-decl name='s0' type-id='type-id-5' mangled-name='s0' visibility='default' elf-symbol-id='s0'/>
     <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-4'>
       <parameter type-id='type-id-5'/>
       <return type-id='type-id-3'/>
diff --git a/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi b/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
index 03dd56b3..8d5c3e36 100644
--- a/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
+++ b/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
@@ -8,7 +8,7 @@
     <typedef-decl name='a_t' type-id='bd54fe1a' id='40acc204'/>
     <typedef-decl name='b_t' type-id='bd54fe1a' id='b3d2db81'/>
     <pointer-type-def type-id='40acc204' size-in-bits='64' alignment-in-bits='64' id='c6fd4117'/>
-    <var-decl name='a' type-id='c6fd4117' mangled-name='a' visibility='default'/>
-    <var-decl name='ignore2' type-id='b3d2db81' mangled-name='ignore2' visibility='default'/>
+    <var-decl name='a' type-id='c6fd4117' mangled-name='a' visibility='default' elf-symbol-id='a'/>
+    <var-decl name='ignore2' type-id='b3d2db81' mangled-name='ignore2' visibility='default' elf-symbol-id='ignore2'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi b/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
index 35bcac7a..992b669d 100644
--- a/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
+++ b/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
@@ -7,7 +7,7 @@
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='bd54fe1a'/>
     <typedef-decl name='a_t' type-id='bd54fe1a' id='40acc204'/>
     <typedef-decl name='b_t' type-id='bd54fe1a' id='b3d2db81'/>
-    <var-decl name='b' type-id='40acc204' mangled-name='b' visibility='default'/>
-    <var-decl name='ignore1' type-id='b3d2db81' mangled-name='ignore1' visibility='default'/>
+    <var-decl name='b' type-id='40acc204' mangled-name='b' visibility='default' elf-symbol-id='b'/>
+    <var-decl name='ignore1' type-id='b3d2db81' mangled-name='ignore1' visibility='default' elf-symbol-id='ignore1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-dynamic-array.o.abi b/tests/data/test-read-ctf/test-dynamic-array.o.abi
index 02b22811..a9849d49 100644
--- a/tests/data/test-read-ctf/test-dynamic-array.o.abi
+++ b/tests/data/test-read-ctf/test-dynamic-array.o.abi
@@ -21,7 +21,7 @@
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-3'/>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <function-decl name='use_struct_s' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='use_struct_s' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='use_struct_s'>
       <parameter type-id='type-id-7'/>
       <return type-id='type-id-8'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-enum-ctf.o.abi b/tests/data/test-read-ctf/test-enum-ctf.o.abi
new file mode 100644
index 00000000..f36f3fad
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-ctf.o.abi
@@ -0,0 +1,24 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='bar' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='foo' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
+    <enum-decl name='e' linkage-name='e' id='type-id-2'>
+      <underlying-type type-id='type-id-1'/>
+      <enumerator name='ENUMSAMPLE_1' value='0'/>
+      <enumerator name='ENUMSAMPLE_2' value='1'/>
+    </enum-decl>
+    <enum-decl name='ie' linkage-name='ie' id='type-id-3'>
+      <underlying-type type-id='type-id-1'/>
+      <enumerator name='IENUMSAMPLE_1' value='-10'/>
+      <enumerator name='IENUMSAMPLE_2' value='-9'/>
+      <enumerator name='IENUMSAMPLE_3' value='-8'/>
+    </enum-decl>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
+    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default'/>
+    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi b/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
new file mode 100644
index 00000000..67a958a7
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
@@ -0,0 +1,69 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-many-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='bar' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='foo' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='e' linkage-name='e' id='a6c2eddf'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='ENUMSAMPLE_1' value='0'/>
+      <enumerator name='ENUMSAMPLE_2' value='1'/>
+    </enum-decl>
+    <enum-decl name='ie' linkage-name='ie' id='1ee696ca'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='IE_0' value='-10'/>
+      <enumerator name='IE_1' value='-9'/>
+      <enumerator name='IE_2' value='-8'/>
+      <enumerator name='IE_3' value='-7'/>
+      <enumerator name='IE_4' value='-6'/>
+      <enumerator name='IE_5' value='-5'/>
+      <enumerator name='IE_6' value='-4'/>
+      <enumerator name='IE_7' value='-3'/>
+      <enumerator name='IE_8' value='-2'/>
+      <enumerator name='IE_9' value='-1'/>
+      <enumerator name='IE_A' value='0'/>
+      <enumerator name='IE_B' value='1'/>
+      <enumerator name='IE_C' value='2'/>
+      <enumerator name='IE_D' value='3'/>
+      <enumerator name='IE_E' value='4'/>
+      <enumerator name='IE_F' value='5'/>
+      <enumerator name='IE_10' value='6'/>
+      <enumerator name='IE_11' value='7'/>
+      <enumerator name='IE_12' value='8'/>
+      <enumerator name='IE_13' value='9'/>
+      <enumerator name='IE_14' value='10'/>
+      <enumerator name='IE_15' value='11'/>
+      <enumerator name='IE_16' value='12'/>
+      <enumerator name='IE_17' value='13'/>
+      <enumerator name='IE_18' value='14'/>
+      <enumerator name='IE_19' value='15'/>
+      <enumerator name='IE_1A' value='16'/>
+      <enumerator name='IE_1B' value='17'/>
+      <enumerator name='IE_1C' value='18'/>
+      <enumerator name='IE_1D' value='19'/>
+      <enumerator name='IE_1E' value='20'/>
+      <enumerator name='IE_1F' value='21'/>
+      <enumerator name='IE_20' value='22'/>
+      <enumerator name='IE_21' value='23'/>
+      <enumerator name='IE_22' value='24'/>
+      <enumerator name='IE_23' value='25'/>
+      <enumerator name='IE_24' value='26'/>
+      <enumerator name='IE_25' value='27'/>
+      <enumerator name='IE_26' value='28'/>
+      <enumerator name='IE_27' value='29'/>
+      <enumerator name='IE_28' value='30'/>
+      <enumerator name='IE_29' value='31'/>
+      <enumerator name='IE_2A' value='32'/>
+      <enumerator name='IE_2B' value='33'/>
+      <enumerator name='IE_2C' value='34'/>
+      <enumerator name='IE_2D' value='35'/>
+      <enumerator name='IE_2E' value='36'/>
+      <enumerator name='IE_2F' value='37'/>
+    </enum-decl>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
+    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default'/>
+    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-many.o.hash.abi b/tests/data/test-read-ctf/test-enum-many.o.hash.abi
index 26bc048c..116325f9 100644
--- a/tests/data/test-read-ctf/test-enum-many.o.hash.abi
+++ b/tests/data/test-read-ctf/test-enum-many.o.hash.abi
@@ -61,9 +61,7 @@
       <enumerator name='IE_2E' value='36'/>
       <enumerator name='IE_2F' value='37'/>
     </enum-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
-    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default'/>
-    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default'/>
+    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
+    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default' elf-symbol-id='bar'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi b/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi
new file mode 100644
index 00000000..fea6eb8b
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi
@@ -0,0 +1,16 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-symbol-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='primary1' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='' is-anonymous='yes' id='08f5ca17'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='red1' value='0'/>
+      <enumerator name='green1' value='1'/>
+      <enumerator name='blue1' value='2'/>
+    </enum-decl>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
+    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi b/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
index d128b5b1..f4911bc4 100644
--- a/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
+++ b/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
@@ -10,7 +10,6 @@
       <enumerator name='green1' value='1'/>
       <enumerator name='blue1' value='2'/>
     </enum-decl>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
-    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default'/>
+    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default' elf-symbol-id='primary1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum.o.abi b/tests/data/test-read-ctf/test-enum.o.abi
index 88e6ad61..bd3a55be 100644
--- a/tests/data/test-read-ctf/test-enum.o.abi
+++ b/tests/data/test-read-ctf/test-enum.o.abi
@@ -16,9 +16,7 @@
       <enumerator name='IENUMSAMPLE_2' value='-9'/>
       <enumerator name='IENUMSAMPLE_3' value='-8'/>
     </enum-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
-    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default'/>
-    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default'/>
+    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
+    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default' elf-symbol-id='bar'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-forward-type-decl.abi b/tests/data/test-read-ctf/test-forward-type-decl.abi
index 21bb45c8..026e7d32 100644
--- a/tests/data/test-read-ctf/test-forward-type-decl.abi
+++ b/tests/data/test-read-ctf/test-forward-type-decl.abi
@@ -24,6 +24,6 @@
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-3'/>
     <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='addr' type-id='type-id-5' mangled-name='addr' visibility='default'/>
+    <var-decl name='addr' type-id='type-id-5' mangled-name='addr' visibility='default' elf-symbol-id='addr'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-functions-declaration.abi b/tests/data/test-read-ctf/test-functions-declaration.abi
index 9ef05e44..7eb57d26 100644
--- a/tests/data/test-read-ctf/test-functions-declaration.abi
+++ b/tests/data/test-read-ctf/test-functions-declaration.abi
@@ -7,11 +7,11 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
-    <function-decl name='attribute_container_add_device' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='attribute_container_add_device' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='attribute_container_add_device'>
       <parameter type-id='type-id-4'/>
       <return type-id='type-id-5'/>
     </function-decl>
-    <function-decl name='attribute_container_device_trigger' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='attribute_container_device_trigger' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='attribute_container_device_trigger'>
       <parameter type-id='type-id-4'/>
       <return type-id='type-id-5'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-list-struct.abi b/tests/data/test-read-ctf/test-list-struct.abi
index 196a79a1..deb6a4a1 100644
--- a/tests/data/test-read-ctf/test-list-struct.abi
+++ b/tests/data/test-read-ctf/test-list-struct.abi
@@ -14,7 +14,7 @@
     </class-decl>
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='n1' type-id='type-id-1' mangled-name='n1' visibility='default'/>
-    <var-decl name='n2' type-id='type-id-1' mangled-name='n2' visibility='default'/>
+    <var-decl name='n1' type-id='type-id-1' mangled-name='n1' visibility='default' elf-symbol-id='n1'/>
+    <var-decl name='n2' type-id='type-id-1' mangled-name='n2' visibility='default' elf-symbol-id='n2'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test0 b/tests/data/test-read-ctf/test0
index aca7fbacdfff7ad2caf0142390710373a8da72a1..90aa8a39a2e1326a5cb5faaa9e854fc344caaa52 100755
GIT binary patch
delta 1886
zcmah~L2MgE6rEkWZra+(ZUVNWHnG!6kSdbB4pp+Tz+NFxdrBKokU<E`3NA_s+0=1R
z!hsZ2LDU1-`4W{lz<~poN(}_6o**g+6(K-AQK3qlDyTRVq*5i9m^ZV3s^AM>djHSN
zd;ibh8SlFBwsHP~(HKr_=EVc^gezjg69eK<vp6(*(+n6LyI2@P3<F6yP|@SqTr2Ef
zl@x3>-2C<akjol3<f&C1(`qI}nm)_)Rb@(vl_gf{_&~`STwXkLyZ*8q|L+c**G1dL
z4@cxgW?8@<;P~XT!aOfF<(dJ&=o@or;}3H+`nh#uFt^0*{Ik>cCEMV+OqRCA^GGli
z>$IIInx!!1vl-J3)7k7`$O(J&cW80VdGA07&*>>?n$G1?dj~K!MU=jF68%x}p%rjS
z05{6)U9bt^c>!xMeHzgay_Cwy+>9NtOp13EYtzZxal@iZxop2JP89yD`B7>5=r>fb
zh1bE}QKfpQXEf3Ou)y|eu3azM=tbv6uyK*>U=M?}M4WuEG4X9jZ%4t}B0(RIW{o)g
ztb7~FZu}sEUGyzq<Xy6l$rHHDyJ+?jvt_VxG0d#VEq<wX>8AHp?loq0|C=(`#L0t=
ziZq}62-7#gTIleuVkf!(1I*r0l@pXYCiitZD&s=c)13s1jE+0)4%m&AW2eoP6DW8M
z#YTYVF^&Uo0S^IJ033+;4u}FRzy@vsG2nMVHgpf@15DJ|i#Q9wBJy?hfI+OoBJ$AE
zfW>o!M+8J>1B<W-8dLAZCu%ApQU^Zt4mslo?J}=&8DpAW952VN2CJe6@hiG9K4QE{
z_r|~2bH?|}Ir`K+5`L{RGe_UM&I@9pUa2oGI2?1LUR|h{E45l>IT%j+a|`ugcxKkG
z@NnLrnX6Z8!FmlTwV7$AUiW7!^_kf!nG;V(UzuCX%-8(+YOTJ!;Z5u_=v3a?pA31b
z!(@og=Eq_#Pt`|*rb2yd1#4go3VCqy`K6Uuq`pW}M4Nf*sJtrq(reWctCsk?m6WNl
z2)<~Em8USe-){R_tv?$LRv%JYs5#2Z+HI4V$jjCF>%7}K=gV%S$-WIh=W`c_#dBDc
zT3uj^3v6)#m(Jx=D=$IO-qj|)R9F$h;WtdTr=zZ><Ezl_?8<jJ-{t(YEC%arGguW*
ziZ?KlT3xWj1xj4NVWn=M<2l6zYCc{xE>a7=LG}|x;{%$4|A?CKm#GDRmFz;%xK2~>
zKT)&rXuoVnnyx1Q4W#`-Eog3$T`U^6X$t;NYQq0TE%<G+y;N6%50I{mCFztmY#gLz
O&);`_A}FyV&-Gt@S^P)<

delta 1541
zcmZ9MO-NKx6vxlKZ?tqYpOznE<-FXa2=ifIqf@>+MHB?NX;F)iHf3#0R0<+&`XH#N
z(X+7HWF#?*pbraz7G=z0T7=Llf`~Sev~ZQw#_8Pq&Mlh@@7#Cp?|;rc_r81Ih07v$
zQRF(B-Cp?H6r>;w3O2y{34c@fpbUuZSF_NeK15HRd0r~=v_CP~SN%(4YQLO`PfHC2
z))b`DgHVvzD%<e1EZ||sn;ms-)L<@@d*&9~lHaA$68O1X8Zs}AGF^qS0E6sTvhU&V
zm@kVC_Qqo}@8GF;n=|bw%!bA$6F0+>CR0Z0;czm#Y9qZ%2;=KSb0iFR-GCVZnQo?w
zM4LdVfC|Qks25O=(WH)z)d!RzTs73i{^UMUhf~RT#D)ER|7+eGO#^<R3@)fLx?obR
z!Mg6|$U30ujc-i@mC-<z`$QX|rHr-{b)gZ5h}J-%thP>~_0WX(y5ph|=Z!6qvKGJ#
zX3?Kgw`)90e2d<JM?8zAQ%nblHbMte8HB<MGfOSrGO;h2GK4oeR?^NB4THx!-^KVN
zQI{%QH1r_XA7;8>GB;s#tDZMemYF`NSzSNTYD%N*l%`)3(An{=ha|p{q4Cp{Y@X2Z
zKvt<ww4&!N`+Bh+J<r)EIgmzPVW09*sQ|axXYQQ)pX*`WV)~>WF|SZbxhr*YaTI5E
z4Ajm9!%#>4BXm<;;w<h=J;$X~J8tZWS0!L%^w{XwND?3R?44cik%CsRYBKFs|GRG3
zn%-VpkjkVoHx0i!Yw=0i?c7FV`rhb@b+dQtI}fx3!%%@wW6k49@|H@aA*%*Q1)T5l
z2CL>?@7v0jCP#lT8}D(v$MO4FtoK82j*aIk+F=h3YOPIRulgV-Na3b*bo>A*N-N5o
z=4qx`Wq%CzhhekX{xHQauZYice4gVy;<}ZW8H~biI6-gvjM#)lPEh0o30B$y%GL?P
znBC=zGdM@~Jc>SFT*3_5>zE~b2j|E>K;ir1F=oiV!mPhJVwYvJ=@Y110q02b4u$f?
o2h5QDh*`3qagOXa6q%?P!TXsgs!WGy#gmz#s<xgW_J`ikKQHOTvj6}9

diff --git a/tests/data/test-read-ctf/test0.abi b/tests/data/test-read-ctf/test0.abi
index 50ca26f4..fc61f2ac 100644
--- a/tests/data/test-read-ctf/test0.abi
+++ b/tests/data/test-read-ctf/test0.abi
@@ -39,16 +39,26 @@
     </array-type-def>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-10'/>
     <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='type-id-11'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='type-id-12'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-13'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-14'/>
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='type-id-15'/>
-    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-16'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
-    <qualified-type-def type-id='type-id-3' const='yes' id='type-id-18'/>
-    <pointer-type-def type-id='type-id-10' size-in-bits='64' alignment-in-bits='64' id='type-id-19'/>
-    <qualified-type-def type-id='type-id-19' restrict='yes' id='type-id-20'/>
-    <qualified-type-def type-id='type-id-11' volatile='yes' id='type-id-21'/>
+    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-12'/>
+    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-13'/>
+    <qualified-type-def type-id='type-id-3' const='yes' id='type-id-14'/>
+    <pointer-type-def type-id='type-id-10' size-in-bits='64' alignment-in-bits='64' id='type-id-15'/>
+    <qualified-type-def type-id='type-id-15' restrict='yes' id='type-id-16'/>
+    <qualified-type-def type-id='type-id-11' volatile='yes' id='type-id-17'/>
+    <var-decl name='status' type-id='type-id-5' mangled-name='status' visibility='default' elf-symbol-id='status'/>
+    <var-decl name='test_pointer' type-id='type-id-13' mangled-name='test_pointer' visibility='default' elf-symbol-id='test_pointer'/>
+    <var-decl name='test_const' type-id='type-id-14' mangled-name='test_const' visibility='default' elf-symbol-id='test_const'/>
+    <var-decl name='test_float' type-id='type-id-6' mangled-name='test_float' visibility='default' elf-symbol-id='test_float'/>
+    <function-decl name='foo_1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo_1'>
+      <parameter type-id='type-id-12'/>
+      <return type-id='type-id-4'/>
+    </function-decl>
+    <function-decl name='main' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='main'>
+      <return type-id='type-id-4'/>
+    </function-decl>
+    <var-decl name='test_array' type-id='type-id-7' mangled-name='test_array' visibility='default' elf-symbol-id='test_array'/>
+    <var-decl name='test_restrict' type-id='type-id-16' mangled-name='test_restrict' visibility='default' elf-symbol-id='test_restrict'/>
+    <var-decl name='test_volatile' type-id='type-id-17' mangled-name='test_volatile' visibility='default' elf-symbol-id='test_volatile'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test0.c b/tests/data/test-read-ctf/test0.c
index eb702312..fdefd57c 100644
--- a/tests/data/test-read-ctf/test0.c
+++ b/tests/data/test-read-ctf/test0.c
@@ -1,3 +1,9 @@
+/*
+ * ELF EXEC files must use -Wl,--ctf-variables -Bdynimic options
+ * to export an ABI and store CTF symbols information.
+ *
+ * ctf-gcc -gctf -Wl,--ctf-variables -Bdynamic test0.c -o test0
+ */
 
 #include <stdio.h>
 
diff --git a/tests/data/test-read-ctf/test0.hash.abi b/tests/data/test-read-ctf/test0.hash.abi
index b58520ab..eff32228 100644
--- a/tests/data/test-read-ctf/test0.hash.abi
+++ b/tests/data/test-read-ctf/test0.hash.abi
@@ -39,16 +39,26 @@
     </array-type-def>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='bd54fe1a'/>
     <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='a2185560'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='28577a57'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='002ac4a6'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='7359adad'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='8efea9e5'/>
     <pointer-type-def type-id='50d9a3fa' size-in-bits='64' alignment-in-bits='64' id='fd01f598'/>
     <pointer-type-def type-id='a84c031d' size-in-bits='64' alignment-in-bits='64' id='26a90f95'/>
     <qualified-type-def type-id='50d9a3fa' const='yes' id='0fb3b55d'/>
     <pointer-type-def type-id='bd54fe1a' size-in-bits='64' alignment-in-bits='64' id='3ccc2590'/>
     <qualified-type-def type-id='3ccc2590' restrict='yes' id='af4b1b38'/>
     <qualified-type-def type-id='a2185560' volatile='yes' id='ec67e496'/>
+    <var-decl name='status' type-id='e7f43f72' mangled-name='status' visibility='default' elf-symbol-id='status'/>
+    <var-decl name='test_pointer' type-id='26a90f95' mangled-name='test_pointer' visibility='default' elf-symbol-id='test_pointer'/>
+    <var-decl name='test_const' type-id='0fb3b55d' mangled-name='test_const' visibility='default' elf-symbol-id='test_const'/>
+    <var-decl name='test_float' type-id='a6c45d85' mangled-name='test_float' visibility='default' elf-symbol-id='test_float'/>
+    <function-decl name='foo_1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo_1'>
+      <parameter type-id='fd01f598'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <function-decl name='main' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='main'>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <var-decl name='test_array' type-id='b7bd1749' mangled-name='test_array' visibility='default' elf-symbol-id='test_array'/>
+    <var-decl name='test_restrict' type-id='af4b1b38' mangled-name='test_restrict' visibility='default' elf-symbol-id='test_restrict'/>
+    <var-decl name='test_volatile' type-id='ec67e496' mangled-name='test_volatile' visibility='default' elf-symbol-id='test_volatile'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test1.so.abi b/tests/data/test-read-ctf/test1.so.abi
index 5b3caf63..416bd39d 100644
--- a/tests/data/test-read-ctf/test1.so.abi
+++ b/tests/data/test-read-ctf/test1.so.abi
@@ -16,8 +16,13 @@
     </enum-decl>
     <typedef-decl name='opaque_enum' type-id='type-id-4' id='type-id-3'/>
     <typedef-decl name='opaque_struct' type-id='type-id-2' id='type-id-5'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
-    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
+    <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
+    <function-decl name='fn' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fn'>
+      <parameter type-id='type-id-7'/>
+      <parameter type-id='type-id-6'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-8'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test1.so.hash.abi b/tests/data/test-read-ctf/test1.so.hash.abi
index 8019cb54..b3620e75 100644
--- a/tests/data/test-read-ctf/test1.so.hash.abi
+++ b/tests/data/test-read-ctf/test1.so.hash.abi
@@ -16,8 +16,13 @@
     </enum-decl>
     <typedef-decl name='opaque_enum' type-id='55763a91' id='99fcd3a5'/>
     <typedef-decl name='opaque_struct' type-id='6cde5052' id='dae69ca1'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <pointer-type-def type-id='99fcd3a5' size-in-bits='64' alignment-in-bits='64' id='0e0526e0'/>
     <pointer-type-def type-id='dae69ca1' size-in-bits='64' alignment-in-bits='64' id='3f6e71d0'/>
+    <function-decl name='fn' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fn'>
+      <parameter type-id='3f6e71d0'/>
+      <parameter type-id='0e0526e0'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test2.so.abi b/tests/data/test-read-ctf/test2.so.abi
index eb6aff3e..67f802f9 100644
--- a/tests/data/test-read-ctf/test2.so.abi
+++ b/tests/data/test-read-ctf/test2.so.abi
@@ -20,6 +20,14 @@
     <qualified-type-def type-id='type-id-8' const='yes' id='type-id-9'/>
     <pointer-type-def type-id='type-id-9' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <pointer-type-def type-id='type-id-8' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
+      <parameter type-id='type-id-7'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='type-id-6'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
     <type-decl name='void' id='type-id-8'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test2.so.hash.abi b/tests/data/test-read-ctf/test2.so.hash.abi
index 6e57333b..6bbf347e 100644
--- a/tests/data/test-read-ctf/test2.so.hash.abi
+++ b/tests/data/test-read-ctf/test2.so.hash.abi
@@ -20,6 +20,14 @@
     <qualified-type-def type-id='48b5725f' const='yes' id='8581546e'/>
     <pointer-type-def type-id='8581546e' size-in-bits='64' alignment-in-bits='64' id='6e97a70c'/>
     <pointer-type-def type-id='48b5725f' size-in-bits='64' alignment-in-bits='64' id='eaa32e2f'/>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
+      <parameter type-id='5e30a4f9'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='842ea234'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
     <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test3.so.abi b/tests/data/test-read-ctf/test3.so.abi
index 9d55fec5..3d2f6326 100644
--- a/tests/data/test-read-ctf/test3.so.abi
+++ b/tests/data/test-read-ctf/test3.so.abi
@@ -8,5 +8,9 @@
     <elf-symbol name='foo__' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
+    <function-decl name='__foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='__foo'>
+      <return type-id='type-id-1'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test3.so.hash.abi b/tests/data/test-read-ctf/test3.so.hash.abi
index 9d55fec5..1c69e2e1 100644
--- a/tests/data/test-read-ctf/test3.so.hash.abi
+++ b/tests/data/test-read-ctf/test3.so.hash.abi
@@ -8,5 +8,9 @@
     <elf-symbol name='foo__' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
+    <function-decl name='__foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='__foo'>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test4.so.abi b/tests/data/test-read-ctf/test4.so.abi
index b8e0ead3..dc18e191 100644
--- a/tests/data/test-read-ctf/test4.so.abi
+++ b/tests/data/test-read-ctf/test4.so.abi
@@ -10,5 +10,11 @@
     <qualified-type-def type-id='type-id-1' const='yes' id='type-id-5'/>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
     <qualified-type-def type-id='type-id-6' restrict='yes' id='type-id-7'/>
+    <function-decl name='cpy' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='cpy'>
+      <parameter type-id='type-id-4'/>
+      <parameter type-id='type-id-7'/>
+      <parameter type-id='type-id-2'/>
+      <return type-id='type-id-3'/>
+    </function-decl>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test4.so.hash.abi b/tests/data/test-read-ctf/test4.so.hash.abi
index dbe34d9c..dc428592 100644
--- a/tests/data/test-read-ctf/test4.so.hash.abi
+++ b/tests/data/test-read-ctf/test4.so.hash.abi
@@ -10,5 +10,11 @@
     <qualified-type-def type-id='a84c031d' const='yes' id='9b45d938'/>
     <pointer-type-def type-id='9b45d938' size-in-bits='64' alignment-in-bits='64' id='80f4b756'/>
     <qualified-type-def type-id='80f4b756' restrict='yes' id='9d26089a'/>
+    <function-decl name='cpy' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='cpy'>
+      <parameter type-id='266fe297'/>
+      <parameter type-id='9d26089a'/>
+      <parameter type-id='f0981eeb'/>
+      <return type-id='26a90f95'/>
+    </function-decl>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test5.o.abi b/tests/data/test-read-ctf/test5.o.abi
index eb30cf6a..f7bcdeb1 100644
--- a/tests/data/test-read-ctf/test5.o.abi
+++ b/tests/data/test-read-ctf/test5.o.abi
@@ -17,34 +17,32 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <type-decl name='long long int' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <type-decl name='long long unsigned int' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <typedef-decl name='long_long' type-id='type-id-6' id='type-id-8'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-9'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-10'/>
-    <qualified-type-def type-id='type-id-4' const='yes' id='type-id-11'/>
-    <qualified-type-def type-id='type-id-5' const='yes' id='type-id-12'/>
-    <qualified-type-def type-id='type-id-12' volatile='yes' id='type-id-13'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-10'/>
-      <parameter type-id='type-id-13'/>
+    <typedef-decl name='long_long' type-id='type-id-6' id='type-id-7'/>
+    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <qualified-type-def type-id='type-id-4' const='yes' id='type-id-9'/>
+    <qualified-type-def type-id='type-id-5' const='yes' id='type-id-10'/>
+    <qualified-type-def type-id='type-id-10' volatile='yes' id='type-id-11'/>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='type-id-8'/>
+      <parameter type-id='type-id-11'/>
       <return type-id='type-id-5'/>
     </function-decl>
-    <function-decl name='baz2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='baz2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='baz2'>
       <parameter type-id='type-id-4'/>
-      <return type-id='type-id-8'/>
+      <return type-id='type-id-7'/>
     </function-decl>
-    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
       <parameter is-variadic='yes'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <function-decl name='bar2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar2'>
       <parameter type-id='type-id-3'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <function-decl name='baz' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='baz' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='baz'>
       <parameter type-id='type-id-4'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <type-decl name='void' id='type-id-14'/>
+    <type-decl name='void' id='type-id-12'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test7.o.abi b/tests/data/test-read-ctf/test7.o.abi
index b744fac5..a13af174 100644
--- a/tests/data/test-read-ctf/test7.o.abi
+++ b/tests/data/test-read-ctf/test7.o.abi
@@ -3,40 +3,31 @@
     <elf-symbol name='first_type_constructor' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <type-decl name='char' size-in-bits='8' alignment-in-bits='8' id='type-id-1'/>
-    <class-decl name='first_type' size-in-bits='128' alignment-in-bits='32' is-struct='yes' visibility='default' id='type-id-2'>
+    <class-decl name='first_type' size-in-bits='128' alignment-in-bits='32' is-struct='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='member0' type-id='type-id-3' visibility='default'/>
+        <var-decl name='member0' type-id='type-id-2' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='32'>
-        <var-decl name='member1' type-id='type-id-4' visibility='default'/>
+        <var-decl name='member1' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='64'>
-        <var-decl name='ctor' type-id='type-id-5' visibility='default'/>
+        <var-decl name='ctor' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <type-decl name='long long int' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
-    <type-decl name='long long unsigned int' size-in-bits='64' alignment-in-bits='64' id='type-id-9'/>
-    <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='type-id-10'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='type-id-11'/>
-    <typedef-decl name='character' type-id='type-id-12' id='type-id-4'/>
-    <typedef-decl name='constructor' type-id='type-id-13' id='type-id-5'/>
-    <typedef-decl name='integer' type-id='type-id-6' id='type-id-3'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-12'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-14'/>
-    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-15'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='type-id-16'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
-    <pointer-type-def type-id='type-id-18' size-in-bits='64' alignment-in-bits='64' id='type-id-13'/>
-    <function-decl name='first_type_constructor' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-17'/>
-      <return type-id='type-id-19'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
+    <typedef-decl name='character' type-id='type-id-6' id='type-id-3'/>
+    <typedef-decl name='constructor' type-id='type-id-7' id='type-id-4'/>
+    <typedef-decl name='integer' type-id='type-id-5' id='type-id-2'/>
+    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-6'/>
+    <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-9' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
+    <function-decl name='first_type_constructor' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='first_type_constructor'>
+      <parameter type-id='type-id-8'/>
+      <return type-id='type-id-10'/>
     </function-decl>
-    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-18'>
-      <return type-id='type-id-19'/>
+    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-9'>
+      <return type-id='type-id-10'/>
     </function-type>
-    <type-decl name='void' id='type-id-19'/>
+    <type-decl name='void' id='type-id-10'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test8.o.abi b/tests/data/test-read-ctf/test8.o.abi
index 68b3af06..b6996c29 100644
--- a/tests/data/test-read-ctf/test8.o.abi
+++ b/tests/data/test-read-ctf/test8.o.abi
@@ -4,7 +4,7 @@
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
       <parameter type-id='type-id-2'/>
       <return type-id='type-id-1'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test9.o.abi b/tests/data/test-read-ctf/test9.o.abi
index 746dd77b..08704d79 100644
--- a/tests/data/test-read-ctf/test9.o.abi
+++ b/tests/data/test-read-ctf/test9.o.abi
@@ -49,7 +49,7 @@
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-16' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
     <pointer-type-def type-id='type-id-18' size-in-bits='64' alignment-in-bits='64' id='type-id-20'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
       <parameter type-id='type-id-22'/>
       <return type-id='type-id-16'/>
     </function-decl>
diff --git a/tests/test-read-ctf.cc b/tests/test-read-ctf.cc
index fdf49e90..215ed8d6 100644
--- a/tests/test-read-ctf.cc
+++ b/tests/test-read-ctf.cc
@@ -269,20 +269,28 @@ static InOutSpec in_out_specs[] =
     "output/test-read-ctf/test-list-struct.abi",
   },
   {
-    "data/test-read-ctf/test-callback2.o",
+    "data/test-read-common/test-PR26568-1.o",
     "",
     "",
     SEQUENCE_TYPE_ID_STYLE,
-    "data/test-read-ctf/test-callback2.abi",
-    "output/test-read-ctf/test-callback2.abi",
+    "data/test-read-ctf/test-PR26568-1.o.abi",
+    "output/test-read-ctf/test-PR26568-1.o.abi",
   },
   {
-    "data/test-read-ctf/test-forward-undefine-type-decl.o",
+    "data/test-read-common/test-PR26568-2.o",
     "",
     "",
     SEQUENCE_TYPE_ID_STYLE,
-    "data/test-read-ctf/test-forward-undefine-type-decl.abi",
-    "output/test-read-ctf/test-forward-undefine-type-decl.abi",
+    "data/test-read-ctf/test-PR26568-2.o.abi",
+    "output/test-read-ctf/test-PR26568-2.o.abi",
+  },
+  {
+    "data/test-read-ctf/test-callback2.o",
+    "",
+    "",
+    SEQUENCE_TYPE_ID_STYLE,
+    "data/test-read-ctf/test-callback2.abi",
+    "output/test-read-ctf/test-callback2.abi",
   },
   // This should be the last entry.
   {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
diff --git a/tools/abidw.cc b/tools/abidw.cc
index f7a8937d..32d055f5 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -811,13 +811,18 @@ load_kernel_corpus_group_and_write_abixml(char* argv[],
 
   global_timer.start();
   t.start();
+corpus::origin origin =
+#ifdef WITH_CTF
+    opts.use_ctf ? corpus::CTF_ORIGIN :
+#endif
+    corpus::DWARF_ORIGIN;
   corpus_group_sptr group =
     build_corpus_group_from_kernel_dist_under(opts.in_file_path,
 					      /*debug_info_root=*/"",
 					      opts.vmlinux,
 					      opts.suppression_paths,
 					      opts.kabi_whitelist_paths,
-					      supprs, opts.do_log, env);
+					      supprs, opts.do_log, env, origin);
   t.stop();
 
   if (opts.do_log)
-- 
2.35.0.rc2


Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3] ctf-reader: Add support to read CTF information from Linux kernel
  2022-05-04 22:29     ` [PATCH v3] " Guillermo E. Martinez
  2022-05-12 16:51       ` Dodji Seketeli
@ 2022-05-13  7:18       ` Dodji Seketeli
  1 sibling, 0 replies; 10+ messages in thread
From: Dodji Seketeli @ 2022-05-13  7:18 UTC (permalink / raw)
  To: Guillermo E. Martinez via Libabigail

Hello,

"Guillermo E. Martinez via Libabigail" <libabigail@sourceware.org> a
écrit:

[...]

I have applied the great patch to the master branch.  I have however
made some slight (mostly cosmetic) changes that I discuss below.

Many thanks for the great work!

[...]

> diff --git a/include/abg-corpus.h b/include/abg-corpus.h
> index 652a8294..690edba5 100644
> --- a/include/abg-corpus.h
> +++ b/include/abg-corpus.h
> @@ -44,10 +44,10 @@ public:
>    enum origin
>    {
>      ARTIFICIAL_ORIGIN = 0,
> -    NATIVE_XML_ORIGIN,
> -    DWARF_ORIGIN,
> -    CTF_ORIGIN,
> -    LINUX_KERNEL_BINARY_ORIGIN
> +    NATIVE_XML_ORIGIN = 1,
> +    DWARF_ORIGIN      = 1 << 1,
> +    CTF_ORIGIN        = 1 << 2,
> +    LINUX_KERNEL_BINARY_ORIGIN = 1 << 3
>    };
>  
>  private:
> @@ -115,11 +115,11 @@ public:
>    corpus_group*
>    get_group();
>  
> -  origin
> +  uint32_t
>    get_origin() const;
>  
>    void
> -  set_origin(origin);
> +  set_origin(uint32_t);
>  
>    string&
>    get_format_major_version_number() const;

These corpus::{get_origin, set_origin} accessors should return/take a
corpus::origin type, for the sake of having a strongly typed system.

But I think I understand why you changed them to return/take a uint32_t.
I guess it's because of ...

[...]

diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 2c6839cb..030f8fc8 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc

[...]

-  /* Set some properties of the corpus first.  */
-  corp->set_origin(corpus::CTF_ORIGIN);
-  if (!slurp_elf_info(ctxt, corp))
+  bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
+  uint32_t origin = corpus::CTF_ORIGIN;
+
+  if (is_linux_kernel)
+    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;

... this, right?

I think the C++ compiler wasn't happy by the fact that "origin" is set
to the result of the |= operator, which returns an integer (not an
instance of corpus::origin), by default, right?

In that case, you need to declare a new '|=' operator that takes two
corpus::origin operands and return a corpus::origin.  That way, that
line can just compile fine.

I did just that for you. That is, in abg-corpus.h, I declared these:

    corpus::origin
    operator|(corpus::origin l, corpus::origin r);

    corpus::origin
    operator|=(corpus::origin &l, corpus::origin r);

    corpus::origin
    operator&(corpus::origin l, corpus::origin r);

    corpus::origin
    operator&=(corpus::origin &l, corpus::origin r);

These are defined in abg-corpus.cc, so things should just work as
intended, hopefully.

[...]

diff --git a/src/abg-corpus-priv.h b/src/abg-corpus-priv.h
index 778e3365..28fd1d9b 100644
--- a/src/abg-corpus-priv.h
+++ b/src/abg-corpus-priv.h
@@ -670,7 +670,7 @@ struct corpus::priv
   environment*					env;
   corpus_group*				group;
   corpus::exported_decls_builder_sptr		exported_decls_builder;
-  origin					origin_;
+  uint32_t					origin_;

I reverted this change as per what I said above.

[...]

diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
index a517f384..94f2268c 100644
--- a/src/abg-corpus.cc
+++ b/src/abg-corpus.cc
@@ -851,7 +851,7 @@ corpus::init_format_version()
 /// Getter for the origin of the corpus.
 ///
 /// @return the origin of the corpus.
-corpus::origin
+uint32_t
 corpus::get_origin() const
 {return priv_->origin_;}
 
@@ -859,7 +859,7 @@ corpus::get_origin() const
 ///
 /// @param o the new origin for the corpus.
 void
-corpus::set_origin(origin o)
+corpus::set_origin(uint32_t o)
 {priv_->origin_ = o;}

Likewise.

[...]

diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 2c6839cb..030f8fc8 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -16,6 +16,8 @@
 #include <fcntl.h> /* For open(3) */
 #include <iostream>
 #include <memory>
+#include <map>
+#include <algorithm>
 
 #include "ctf-api.h"
 
@@ -58,13 +60,19 @@ public:
 
   /// A map associating CTF type ids with libabigail IR types.  This
   /// is used to reuse already generated types.
-  unordered_map<ctf_id_t,type_base_sptr> types_map;
+  std::map<std::string,type_base_sptr> types_map;

Any reason why you don't use
    unordered_map<string, type_base_sptr> types_map ?

I am asking just because an unordered_map is much faster than just a
map.

There is nothing wrong, though, with using a map.

[...]

   /// Associate a given CTF type ID with a given libabigail IR type.
-  void add_type(ctf_id_t ctf_type, type_base_sptr type)
+  void add_type(ctf_dict_t *dic, ctf_id_t ctf_type, type_base_sptr type)
   {

I have added a doxygen description for the function parameters.

I have also added a newline between the return type (void) and the
function name, to comply with the rest of the project.  I did so with
a few other member function definitions in there as well.

[...]

   /// Lookup a given CTF type ID in the types map.
   ///
   /// @param ctf_type the type ID of the type to lookup.
-  type_base_sptr lookup_type(ctf_id_t ctf_type)
+  type_base_sptr lookup_type(ctf_dict_t *dic, ctf_id_t ctf_type)
   {

Likewise.

I have also slightly re-worded the introductory text of the patch.

As a result, please find below the patch that is applied.

From e64d32bee317837d3b5209fdc087309d58a6f16d Mon Sep 17 00:00:00 2001
From: "Guillermo E. Martinez" <guillermo.e.martinez@oracle.com>
Date: Wed, 4 May 2022 17:29:30 -0500
Subject: [PATCH] ctf-reader: Add support to read CTF information from the Linux Kernel

This patch is meant to extract ABI information from the CTF data
stored in the Linux kernel build directory.  It depends on the
vmlinux.ctfa archive file.

In order to generate the CTF information, the Linux Kernel build
system must support the 'make ctf' command, which causes the compiler
to be run with -gctf, thus emitting the CTF information for the
Kernel.

The target 'ctf' in the Linux Makefile generates a 'vmlinux.ctfa' file
that will be used by the ctf reader in libabigail. The 'vmlinux.ctfa'
archive has multiple 'ctf dictionaries' called "CTF archive members".

There is one CTF archive member for built-in kernel modules (in
`vmlinux') and one for each out-of-tree kernel module organized in a
parent-child hierarchy.

There is also a CTF archive member called `shared_ctf' which is a
parent dictionary containing shared symbols and CTF types used by more
than one kernel object.  These common types are stored in 'types_map'
in the ctf reader, ignoring the ctf dictionary name.  The CTF API has
the machinery for looking for a shared type in the parent dictionary
referred to in a given child dictionary. This CTF layout can be dumped
by using the objdump tool.

Due to the fact that the _same_ ctf archive is used to build the
vmlinux corpus the corpora of the kernel module (which, by the way,
all belong to the same corpus group), the high number of open/close on
the CTF archive is very time consuming during the ctf extraction.

So, the performance is improved up to 300% (from ~2m:50s to ~50s) by
keeping the ctf archive open for a given group, and thus, by using the
same ctf_archive_t pointer while building all the various corpora.

We just invoke `reset_read_context' for each new corpus.  Note that
the `read_context::ctfa` data member should be updated if the
corpus::origin data member is set to `LINUX_KERNEL_BINARY_ORIGIN' and
the file to be process is not 'vmlinux'.

Note that `ctf_close' must be called after processing all group's
members so it is executed from the destructor of `reader_context'.

The basic algorithm used to generate the Linux corpus is the
following:

   1. Looking for: vmlinux, *.ko objects, and vmlinux.ctfa files. The
   first files are used to extract the ELF symbols, and the last one
   contains the CTF type information for non-static variables and
   functions symbols.

   2. `process_ctf_archive' iterates on public symbols for vmlinux and
   its modules, using the name of the symbol, ctf reader search for CTF
   information in its dictionary, if the information was found it
   builds a `var_decl' or `function_decl' depending of `ctf_type_kind'
   result.

This algorithm is also applied to ELF files (exec, dyn, rel), so
instead of iterating on all ctf_types it just loops on the public
symbols.

	* abg-elf-reader-common.h: Include ctf-api.h file.
	(read_and_add_corpus_to_group_from_elf, set_read_context_corpus_group)
	(reset_read_context, dic_type_key): Declare new member functions.
	* include/abg-ir.cc (types_defined_same_linux_kernel_corpus_public): Use
	bitwise to know the corpus `origin'.
	* src/abg-ctf-reader.cc: Include map, algorithms header files.
	(read_context::type_map): Change from unordered_map to std::map storing
	ctf dictionary name as part of the key.
	(read_context::is_elf_exec): Add new member variable.
	(read_context::{cur_corpus_, cur_corpus_group_}): Likewise.
	(read_context::unknown_types_set): Likewise.
	(read_context::{current_corpus_group, main_corpus_from_current_group,
	has_corpus_group, current_corpus_is_main_corpus_from_current_group,
	should_reuse_type_from_corpus_group}): Add new member functions.
	(read_context::{add_unknown_type, lookup_unknown_type, initialize}):
	Likewise.
	(read_context::{add_type, lookup_type}): Add new `ctf_dict_t' type
	argument.
	(ctf_reader::{process_ctf_typedef, process_ctf_base_type,
	process_ctf_function_type, process_ctf_forward_type,
	process_ctf_struct_type, process_ctf_union_type, process_ctf_array_type,
	process_ctf_qualified_type, process_ctf_enum_type}): Add code to `reuse'
	types already registered in main corpus `should_reuse_type_from_corpus_group'.
	Use new `lookup_type' and `add_type' operations on `read_context::types_map'.
	Replace function calls to the new ctf interface. Add verifier to not build
	types duplicated by recursive calling chain.
	(ctf_reader::process_ctf_type): Add code to return immediately if the
	ctf type is unknown. Add unknown types to `unknown_types_set'.
	(ctf_reader::process_ctf_archive): Change comment.
	Add code to iterate over global symbols, searching by symbol name in the
	ctf dictionary using `ctf_lookup_{variable,by_symbol_name}' depending of
	the ELF file type and corpus type, creating a `{var,fuc}_decl' using the
	return type of `ctf_type_kind'.  Also close the ctf dict and call
	`canonicalize_all_types'.
	(slurp_elf_info): Set `is_elf_exec' depending of ELF type.  Also return
	success if corpus origin is Linux and symbol table was read.
	(ctf_reader::read_corpus): Add current corpus.  Set corpus origin to
	`LINUX_KERNEL_BINARY_ORIGIN' if `is_linux_kernel' returns true.  Verify
	the ctf reader status, now the ctf archive is 'opened' using
	`ctf_arc{open,bufopen}' depending if the corpus origin has
	`corpus::LINUX_KERNEL_BINARY_ORIGIN' bit set. Use
	`sort_{function,variables}' calls after extract ctf information.
	`ctf_close' is called from `read_context' destructor.
	(read:context::{set_read_context_corpus_group, reset_read_context,
	read_and_add_corpus_to_group_from_elf, dic_type_key): Add new member
	function implementation.
	* include/abg-tools-utils.h (build_corpus_group_from_kernel_dist_under):
	Add `origin' parameter with default `corpus::DWARF_ORIGIN'.
	* src/abg-tools-utils.cc: Use `abg-ctf-reader.h' file.
	(maybe_load_vmlinux_dwarf_corpus): Add new function.
	(maybe_load_vmlinux_ctf_corpus): Likewise.
	(build_corpus_group_from_kernel_dist_under): Update comments.
	Add new `origin' argument. Use `maybe_load_vmlinux_dwarf_corpus'
	or `maybe_load_vmlinux_ctf_corpus' according to `origin' value.
	* src/abg-corpus.h (corpus::origin): Update `origin' type
	values in enum.
	* src/abg-corpus-priv.h (corpus::priv): Replace `origin' type
	from `corpus::origin' to `uint32_t'.
	* src/abg-corpus.cc (corpus::{get,set}_origin): Replace data
	type from `corpus::origin' to `uint32_t'.
	* tools/abidw.cc (main): Use of --ctf argument to set format debug.
	* tests/test-read-ctf.cc: Add new tests to harness.
	* tests/data/test-read-ctf/test-PR27700.abi: New test expected
	  result.
	* tests/data/test-read-ctf/test-anonymous-fields.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-many.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi: Likewise.
	* tests/data/test-read-common/test-PR26568-2.o: Adjust.
	* tests/data/test-read-ctf/test-PR26568-1.o.abi: Likewise.
	* tests/data/test-read-ctf/test-PR26568-2.o.abi: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.c: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.o: Likewise.
	* tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-array-of-pointers.abi: Likewise.
	* tests/data/test-read-ctf/test-callback.abi: Likewise.
	* tests/data/test-read-ctf/test-callback2.abi: Likewise.
	* tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi:
	Likewise.
	* tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi:
	Likewise.
	* tests/data/test-read-ctf/test-dynamic-array.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-ctf.o.abi: Likewise.
	* tests/data/test-read-ctf/test-enum-symbol.o.hash.abi: Likewise.
	* tests/data/test-read-ctf/test-enum.o.abi: Likewise.
	* tests/data/test-read-ctf/test-forward-type-decl.abi: Likewise.
	* tests/data/test-read-ctf/test-functions-declaration.abi: Likewise.
	* tests/data/test-read-ctf/test-list-struct.abi: Likewise.
	* tests/data/test-read-ctf/test0: Likewise.
	* tests/data/test-read-ctf/test0.abi: Likewise.
	* tests/data/test-read-ctf/test0.c: Likewise.
	* tests/data/test-read-ctf/test0.hash.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test5.o.abi: Likewise.
	* tests/data/test-read-ctf/test7.o.abi: Likewise.
	* tests/data/test-read-ctf/test8.o.abi: Likewise.
	* tests/data/test-read-ctf/test9.o.abi: Likewise.

Signed-off-by: Guillermo E. Martinez <guillermo.e.martinez@oracle.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 include/abg-corpus.h                          |  20 +-
 include/abg-ctf-reader.h                      |  16 +
 include/abg-tools-utils.h                     |   3 +-
 src/abg-corpus-priv.h                         |   2 +-
 src/abg-corpus.cc                             |  56 ++
 src/abg-ctf-reader.cc                         | 507 ++++++++++++++----
 src/abg-dwarf-reader.cc                       |   8 +-
 src/abg-ir.cc                                 |   2 +-
 src/abg-tools-utils.cc                        | 317 ++++++++---
 tests/data/test-read-common/test-PR26568-2.o  | Bin 3048 -> 3488 bytes
 .../test-read-ctf/PR27700/test-PR27700.abi    |   3 +-
 tests/data/test-read-ctf/test-PR26568-1.o.abi |  34 +-
 tests/data/test-read-ctf/test-PR26568-2.o.abi |  22 +-
 tests/data/test-read-ctf/test-PR27700.abi     |  21 +
 .../test-ambiguous-struct-A.o.hash.abi        |   3 +-
 .../test-read-ctf/test-ambiguous-struct-B.c   |   2 +-
 .../test-read-ctf/test-ambiguous-struct-B.o   | Bin 1344 -> 1344 bytes
 .../test-ambiguous-struct-B.o.hash.abi        |   5 +-
 .../test-read-ctf/test-anonymous-fields.o.abi |  18 +-
 .../test-read-ctf/test-array-of-pointers.abi  |   2 +-
 tests/data/test-read-ctf/test-callback.abi    |  30 +-
 tests/data/test-read-ctf/test-callback2.abi   |   2 +-
 .../test-conflicting-type-syms-a.o.hash.abi   |   4 +-
 .../test-conflicting-type-syms-b.o.hash.abi   |   4 +-
 .../test-read-ctf/test-dynamic-array.o.abi    |   2 +-
 tests/data/test-read-ctf/test-enum-ctf.o.abi  |  24 +
 .../test-enum-many-ctf.o.hash.abi             |  69 +++
 .../test-read-ctf/test-enum-many.o.hash.abi   |   6 +-
 .../test-enum-symbol-ctf.o.hash.abi           |  16 +
 .../test-read-ctf/test-enum-symbol.o.hash.abi |   3 +-
 tests/data/test-read-ctf/test-enum.o.abi      |   6 +-
 .../test-read-ctf/test-forward-type-decl.abi  |   2 +-
 .../test-functions-declaration.abi            |   4 +-
 tests/data/test-read-ctf/test-list-struct.abi |   4 +-
 tests/data/test-read-ctf/test0                | Bin 16656 -> 16896 bytes
 tests/data/test-read-ctf/test0.abi            |  30 +-
 tests/data/test-read-ctf/test0.c              |   6 +
 tests/data/test-read-ctf/test0.hash.abi       |  18 +-
 tests/data/test-read-ctf/test1.so.abi         |  11 +-
 tests/data/test-read-ctf/test1.so.hash.abi    |   7 +-
 tests/data/test-read-ctf/test2.so.abi         |   8 +
 tests/data/test-read-ctf/test2.so.hash.abi    |   8 +
 tests/data/test-read-ctf/test3.so.abi         |   4 +
 tests/data/test-read-ctf/test3.so.hash.abi    |   4 +
 tests/data/test-read-ctf/test4.so.abi         |   6 +
 tests/data/test-read-ctf/test4.so.hash.abi    |   6 +
 tests/data/test-read-ctf/test5.o.abi          |  36 +-
 tests/data/test-read-ctf/test7.o.abi          |  43 +-
 tests/data/test-read-ctf/test8.o.abi          |   2 +-
 tests/data/test-read-ctf/test9.o.abi          |   2 +-
 tests/test-read-ctf.cc                        |  20 +-
 tools/abidw.cc                                |   7 +-
 52 files changed, 1068 insertions(+), 367 deletions(-)
 create mode 100644 tests/data/test-read-ctf/test-PR27700.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-ctf.o.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
 create mode 100644 tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi

diff --git a/include/abg-corpus.h b/include/abg-corpus.h
index 652a8294..4ea82f5b 100644
--- a/include/abg-corpus.h
+++ b/include/abg-corpus.h
@@ -44,10 +44,10 @@ public:
   enum origin
   {
     ARTIFICIAL_ORIGIN = 0,
-    NATIVE_XML_ORIGIN,
-    DWARF_ORIGIN,
-    CTF_ORIGIN,
-    LINUX_KERNEL_BINARY_ORIGIN
+    NATIVE_XML_ORIGIN = 1,
+    DWARF_ORIGIN      = 1 << 1,
+    CTF_ORIGIN        = 1 << 2,
+    LINUX_KERNEL_BINARY_ORIGIN = 1 << 3
   };
 
 private:
@@ -280,6 +280,18 @@ public:
   friend class corpus_group;
 };// end class corpus.
 
+corpus::origin
+operator|(corpus::origin l, corpus::origin r);
+
+corpus::origin
+operator|=(corpus::origin &l, corpus::origin r);
+
+corpus::origin
+operator&(corpus::origin l, corpus::origin r);
+
+corpus::origin
+operator&=(corpus::origin &l, corpus::origin r);
+
 /// Abstracts the building of the set of exported variables and
 /// functions.
 ///
diff --git a/include/abg-ctf-reader.h b/include/abg-ctf-reader.h
index 3343f0d8..ba7289aa 100644
--- a/include/abg-ctf-reader.h
+++ b/include/abg-ctf-reader.h
@@ -19,6 +19,8 @@
 #include "abg-suppression.h"
 #include "abg-elf-reader-common.h"
 
+#include "ctf-api.h"
+
 namespace abigail
 {
 namespace ctf_reader
@@ -32,8 +34,22 @@ create_read_context(const std::string& elf_path,
                     ir::environment *env);
 corpus_sptr
 read_corpus(read_context *ctxt, elf_reader::status& status);
+
 corpus_sptr
 read_corpus(const read_context_sptr &ctxt, elf_reader::status &status);
+
+corpus_sptr
+read_and_add_corpus_to_group_from_elf(read_context*, corpus_group&, elf_reader::status&);
+
+void
+set_read_context_corpus_group(read_context& ctxt, corpus_group_sptr& group);
+
+void
+reset_read_context(read_context_sptr &ctxt,
+                   const std::string&	elf_path,
+                   ir::environment*	environment);
+std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type);
 } // end namespace ctf_reader
 } // end namespace abigail
 
diff --git a/include/abg-tools-utils.h b/include/abg-tools-utils.h
index 68e54028..f7dccb24 100644
--- a/include/abg-tools-utils.h
+++ b/include/abg-tools-utils.h
@@ -311,7 +311,8 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  vector<string>&	kabi_wl_paths,
 					  suppr::suppressions_type&	supprs,
 					  bool				verbose,
-					  environment_sptr&		env);
+					  environment_sptr&		env,
+					  corpus::origin	origin = corpus::DWARF_ORIGIN);
 }// end namespace tools_utils
 
 /// A macro that expands to aborting the program when executed.
diff --git a/src/abg-corpus-priv.h b/src/abg-corpus-priv.h
index 778e3365..d4b9ba32 100644
--- a/src/abg-corpus-priv.h
+++ b/src/abg-corpus-priv.h
@@ -670,7 +670,7 @@ struct corpus::priv
   environment*					env;
   corpus_group*				group;
   corpus::exported_decls_builder_sptr		exported_decls_builder;
-  origin					origin_;
+  corpus::origin				origin_;
   vector<string>				regex_patterns_fns_to_suppress;
   vector<string>				regex_patterns_vars_to_suppress;
   vector<string>				regex_patterns_fns_to_keep;
diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
index a517f384..09047a80 100644
--- a/src/abg-corpus.cc
+++ b/src/abg-corpus.cc
@@ -1560,6 +1560,62 @@ corpus::get_exported_decls_builder() const
   return priv_->exported_decls_builder;
 }
 
+/// Bitwise | operator for the corpus::origin type.
+///
+/// @param l the left-hand side operand of the | operation.
+///
+/// @param r the right-hand side operand of the | operation.
+///
+/// @return the result of the operation.
+corpus::origin
+operator|(corpus::origin l, corpus::origin r)
+{
+  return static_cast<corpus::origin>
+    (static_cast<uint32_t>(l) |  static_cast<uint32_t>(r));
+}
+
+/// Bitwise |= operator for the corpus::origin type.
+///
+/// @param l the left-hand side operand for the |= operation.
+///
+/// @param r the right-hand side operand for the |= operation.
+///
+/// @return the result of the operation.
+corpus::origin
+operator|=(corpus::origin &l, corpus::origin r)
+{
+  l = l | r;
+  return l;
+}
+
+/// Bitwise & operator for the corpus::origin type.
+///
+/// @param l the left-hand side operand of the & operation.
+///
+/// @param r the right-hand side operand of the & operation.
+///
+/// @return the result of the operation.
+corpus::origin
+operator&(corpus::origin l, corpus::origin r)
+{
+    return static_cast<corpus::origin>
+    (static_cast<uint32_t>(l) & static_cast<uint32_t>(r));
+}
+
+/// Bitwise &= operator for the corpus::origin type.
+///
+/// @param l the left-hand side operand of the &= operation.
+///
+/// @param r the right-hand side operand of the &= operation.
+///
+/// @return the result of the operation.
+corpus::origin
+operator&=(corpus::origin &l, corpus::origin r)
+{
+  l = l & r;
+  return l;
+}
+
 // </corpus stuff>
 
 // <corpus_group stuff>
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 2c6839cb..95c81f0e 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -16,6 +16,8 @@
 #include <fcntl.h> /* For open(3) */
 #include <iostream>
 #include <memory>
+#include <map>
+#include <algorithm>
 
 #include "ctf-api.h"
 
@@ -58,13 +60,19 @@ public:
 
   /// A map associating CTF type ids with libabigail IR types.  This
   /// is used to reuse already generated types.
-  unordered_map<ctf_id_t,type_base_sptr> types_map;
+  unordered_map<string,type_base_sptr> types_map;
+
+  /// A set associating unknown CTF type ids
+  std::set<ctf_id_t> unknown_types_set;
 
   /// libelf handler for the ELF file from which we read the CTF data,
   /// and the corresponding file descriptor.
   Elf *elf_handler;
   int elf_fd;
 
+  /// set when ELF is ET_EXEC
+  bool is_elf_exec;
+
   /// The symtab read from the ELF file.
   symtab_reader::symtab_sptr symtab;
 
@@ -74,28 +82,124 @@ public:
   ctf_sect_t symtab_sect;
   ctf_sect_t strtab_sect;
 
+  corpus_sptr			cur_corpus_;
+  corpus_group_sptr		cur_corpus_group_;
+
+  /// Getter of the current corpus group being constructed.
+  ///
+  /// @return current the current corpus being constructed, if any, or
+  /// nil.
+  const corpus_group_sptr
+  current_corpus_group() const
+  {return cur_corpus_group_;}
+
+  /// Test if there is a corpus group being built.
+  ///
+  /// @return if there is a corpus group being built, false otherwise.
+  bool
+  has_corpus_group() const
+  {return bool(cur_corpus_group_);}
+
+  /// Return the main corpus from the current corpus group, if any.
+  ///
+  /// @return the main corpus of the current corpus group, if any, nil
+  /// if no corpus group is being constructed.
+  corpus_sptr
+  main_corpus_from_current_group()
+  {
+    if (cur_corpus_group_)
+      return cur_corpus_group_->get_main_corpus();
+    return corpus_sptr();
+  }
+
+  /// Test if the current corpus being built is the main corpus of the
+  /// current corpus group.
+  ///
+  /// @return return true iff the current corpus being built is the
+  /// main corpus of the current corpus group.
+  bool
+  current_corpus_is_main_corpus_from_current_group()
+  {
+    corpus_sptr main_corpus = main_corpus_from_current_group();
+
+    if (main_corpus && main_corpus.get() == cur_corpus_.get())
+      return true;
+
+    return false;
+  }
+
+  /// Return true if the current corpus is part of a corpus group
+  /// being built and if it's not the main corpus of the group.
+  ///
+  /// For instance, this would return true if we are loading a linux
+  /// kernel *module* that is part of the current corpus group that is
+  /// being built.  In this case, it means we should re-use types
+  /// coming from the "vmlinux" binary that is the main corpus of the
+  /// group.
+  ///
+  /// @return the corpus group the current corpus belongs to, if the
+  /// current corpus is part of a corpus group being built. Nil otherwise.
+  corpus_sptr
+  should_reuse_type_from_corpus_group()
+  {
+    if (has_corpus_group())
+      if (corpus_sptr main_corpus = main_corpus_from_current_group())
+	if (!current_corpus_is_main_corpus_from_current_group())
+	  return current_corpus_group();
+
+    return corpus_sptr();
+  }
+
   /// Associate a given CTF type ID with a given libabigail IR type.
-  void add_type(ctf_id_t ctf_type, type_base_sptr type)
+  ///
+  /// @param dic the dictionnary the type belongs to.
+  ///
+  /// @param ctf_type the type ID.
+  ///
+  /// @param type the type to associate to the ID.
+  void
+  add_type(ctf_dict_t *dic, ctf_id_t ctf_type, type_base_sptr type)
+  {
+    string key = dic_type_key(dic, ctf_type);
+    types_map.insert(std::make_pair(key, type));
+  }
+
+  /// Insert a given CTF unknown type ID.
+  ///
+  /// @param ctf_type the unknown type ID to be added.
+  void
+  add_unknown_type(ctf_id_t ctf_type)
   {
-    types_map.insert(std::make_pair(ctf_type, type));
+    unknown_types_set.insert(ctf_type);
   }
 
   /// Lookup a given CTF type ID in the types map.
   ///
+  /// @param dic the dictionnary the type belongs to.
+  ///
   /// @param ctf_type the type ID of the type to lookup.
-  type_base_sptr lookup_type(ctf_id_t ctf_type)
+  type_base_sptr
+  lookup_type(ctf_dict_t *dic, ctf_id_t ctf_type)
   {
     type_base_sptr result;
+    std::string key = dic_type_key(dic, ctf_type);
 
-    auto search = types_map.find(ctf_type);
+    auto search = types_map.find(key);
     if (search != types_map.end())
       result = search->second;
 
     return result;
   }
 
+  /// Lookup a given CTF unknown type ID in the unknown set.
+  /// @param ctf_type the unknown type ID to lookup.
+  bool
+  lookup_unknown_type(ctf_id_t ctf_type)
+  { return unknown_types_set.find(ctf_type) != unknown_types_set.end(); }
+
   /// Canonicalize all the types stored in the types map.
-  void canonicalize_all_types(void)
+  void
+  canonicalize_all_types(void)
   {
     for (auto t = types_map.begin(); t != types_map.end(); t++)
       canonicalize (t->second);
@@ -103,18 +207,42 @@ public:
 
   /// Constructor.
   ///
+  /// ctfa data member can be used per courpus group.
+  ///
   /// @param elf_path the path to the ELF file.
-  read_context(const string& elf_path, ir::environment *env)
+  read_context(const string& elf_path, ir::environment *env) :
+    ctfa(NULL)
+  {
+    initialize(elf_path, env);
+  }
+
+  /// Initializer of read_context.
+  ///
+  /// @param elf_path the path to the elf file the context is to be
+  /// used for.
+  ///
+  /// @param environment the environment used by the current context.
+  /// This environment contains resources needed by the reader and by
+  /// the types and declarations that are to be created later.  Note
+  /// that ABI artifacts that are to be compared all need to be
+  /// created within the same environment.
+  ///
+  /// Please also note that the life time of this environment object
+  /// must be greater than the life time of the resulting @ref
+  /// read_context the context uses resources that are allocated in
+  /// the environment.
+  void initialize(const string& elf_path, ir::environment *env)
   {
     types_map.clear();
     filename = elf_path;
     ir_env = env;
     elf_handler = NULL;
     elf_fd = -1;
-    ctfa = NULL;
+    is_elf_exec = false;
+    symtab.reset();
+    cur_corpus_group_.reset();
   }
 
-  /// Destructor of the @ref read_context type.
   ~read_context()
   {
     ctf_close(ctfa);
@@ -153,13 +281,18 @@ process_ctf_typedef(read_context *ctxt,
     return result;
 
   const char *typedef_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+  if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+    if (result = lookup_typedef_type(typedef_name, *corp))
+      return result;
+
   type_base_sptr utype = lookup_type(ctxt, corp, tunit,
                                      ctf_dictionary, ctf_utype);
 
   if (!utype)
     return result;
 
-  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_dictionary,
+                                                                ctf_type));
   if (result)
     return result;
 
@@ -180,7 +313,7 @@ process_ctf_typedef(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -225,9 +358,20 @@ process_ctf_base_type(read_context *ctxt,
       type_base_sptr void_type = ctxt->ir_env->get_void_type();
       decl_base_sptr type_declaration = get_type_declaration(void_type);
       result = is_type_decl(type_declaration);
+      canonicalize(result);
     }
   else
     {
+      if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+        {
+          string normalized_type_name = type_name;
+          integral_type int_type;
+          if (parse_integral_type(type_name, int_type))
+            normalized_type_name = int_type.to_string();
+          if (result = lookup_basic_type(normalized_type_name, *corp))
+            return result;
+        }
+
       result = lookup_basic_type(type_name, *corp);
       if (!result)
         result.reset(new type_decl(ctxt->ir_env,
@@ -242,7 +386,7 @@ process_ctf_base_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -303,7 +447,8 @@ process_ctf_function_type(read_context *ctxt,
       function_parms.push_back(parm);
     }
 
-  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_dictionary,
+                                                                 ctf_type));
   if (result)
     return result;
 
@@ -319,7 +464,7 @@ process_ctf_function_type(read_context *ctxt,
       result->set_is_artificial(true);
       decl_base_sptr function_type_decl = get_type_declaration(result);
       add_decl_to_scope(function_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -419,6 +564,11 @@ process_ctf_forward_type(read_context *ctxt,
     }
   else
     {
+      if (!type_is_anonymous)
+        if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+          if (result = lookup_class_type(type_name, *corp))
+            return is_type(result);
+
       class_decl_sptr
        struct_fwd(new class_decl(ctxt->ir_env, type_name,
                                  /*alignment=*/0, /*size=*/0,
@@ -434,7 +584,7 @@ process_ctf_forward_type(read_context *ctxt,
     return is_type(result);
 
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, is_type(result));
+  ctxt->add_type(ctf_dictionary, ctf_type, is_type(result));
 
   return is_type(result);
 }
@@ -458,9 +608,14 @@ process_ctf_struct_type(read_context *ctxt,
 {
   class_decl_sptr result;
   std::string struct_type_name = ctf_type_name_raw(ctf_dictionary,
-                                                 ctf_type);
+                                                   ctf_type);
   bool struct_type_is_anonymous = (struct_type_name == "");
 
+  if (!struct_type_is_anonymous)
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_class_type(struct_type_name, *corp))
+        return result;
+
   /* The libabigail IR encodes C struct types in `class' IR nodes.  */
   result.reset(new class_decl(ctxt->ir_env,
                               struct_type_name,
@@ -479,7 +634,7 @@ process_ctf_struct_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, result);
+  ctxt->add_type(ctf_dictionary, ctf_type, result);
 
   /* Now add the struct members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
@@ -512,6 +667,11 @@ process_ctf_union_type(read_context *ctxt,
                                                    ctf_type);
   bool union_type_is_anonymous = (union_type_name == "");
 
+  if (!union_type_is_anonymous)
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_union_type(union_type_name, *corp))
+        return result;
+
   /* Create the corresponding libabigail union IR node.  */
   result.reset(new union_decl(ctxt->ir_env,
                                 union_type_name,
@@ -528,7 +688,7 @@ process_ctf_union_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_type, result);
+  ctxt->add_type(ctf_dictionary, ctf_type, result);
 
   /* Now add the union members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
@@ -584,7 +744,8 @@ process_ctf_array_type(read_context *ctxt,
   if (!index_type)
     return result;
 
-  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_dictionary,
+                                                                  ctf_type));
   if (result)
     return result;
 
@@ -623,7 +784,7 @@ process_ctf_array_type(read_context *ctxt,
     {
       decl_base_sptr array_type_decl = get_type_declaration(result);
       add_decl_to_scope(array_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -652,6 +813,11 @@ process_ctf_qualified_type(read_context *ctxt,
   if (!utype)
     return result;
 
+  result = dynamic_pointer_cast<type_base>(ctxt->lookup_type(ctf_dictionary,
+                                                             ctf_type));
+  if (result)
+    return result;
+
   qualified_type_def::CV qualifiers = qualified_type_def::CV_NONE;
   if (type_kind == CTF_K_CONST)
     qualifiers |= qualified_type_def::CV_CONST;
@@ -668,7 +834,7 @@ process_ctf_qualified_type(read_context *ctxt,
     {
       decl_base_sptr qualified_type_decl = get_type_declaration(result);
       add_decl_to_scope(qualified_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -702,7 +868,8 @@ process_ctf_pointer_type(read_context *ctxt,
   if (!target_type)
     return result;
 
-  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_type));
+  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_dictionary,
+                                                                    ctf_type));
   if (result)
     return result;
 
@@ -713,7 +880,7 @@ process_ctf_pointer_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -736,6 +903,12 @@ process_ctf_enum_type(read_context *ctxt,
                       ctf_id_t ctf_type)
 {
   enum_type_decl_sptr result;
+  std::string enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+
+  if (!enum_name.empty())
+    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (result = lookup_enum_type(enum_name, *corp))
+        return result;
 
   /* Build a signed integral type for the type of the enumerators, aka
      the underlying type.  The size of the enumerators in bytes is
@@ -769,13 +942,12 @@ process_ctf_enum_type(read_context *ctxt,
       return result;
     }
 
-  const char *enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
-  result.reset(new enum_type_decl(enum_name, location(),
-                                  utype, enms, enum_name));
+  result.reset(new enum_type_decl(enum_name.c_str(), location(),
+                                  utype, enms, enum_name.c_str()));
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_type, result);
+      ctxt->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -804,7 +976,10 @@ process_ctf_type(read_context *ctxt,
   int type_kind = ctf_type_kind(ctf_dictionary, ctf_type);
   type_base_sptr result;
 
-  if ((result = ctxt->lookup_type(ctf_type)))
+  if (ctxt->lookup_unknown_type(ctf_type))
+    return nullptr;
+
+  if ((result = ctxt->lookup_type(ctf_dictionary, ctf_type)))
     return result;
 
   switch (type_kind)
@@ -889,7 +1064,10 @@ process_ctf_type(read_context *ctxt,
     }
 
   if (!result)
-    fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+    {
+      fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+      ctxt->add_unknown_type(ctf_type);
+    }
 
   return result;
 }
@@ -913,7 +1091,7 @@ lookup_type(read_context *ctxt, corpus_sptr corp,
             translation_unit_sptr tunit, ctf_dict_t *ctf_dictionary,
             ctf_id_t ctf_type)
 {
-  type_base_sptr result = ctxt->lookup_type(ctf_type);
+  type_base_sptr result = ctxt->lookup_type(ctf_dictionary, ctf_type);
 
   if (!result)
     result = process_ctf_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
@@ -921,8 +1099,8 @@ lookup_type(read_context *ctxt, corpus_sptr corp,
 }
 
 /// Process a CTF archive and create libabigail IR for the types,
-/// variables and function declarations found in the archive.  The IR
-/// is added to the given corpus.
+/// variables and function declarations found in the archive, iterating
+/// over public symbols.  The IR is added to the given corpus.
 ///
 /// @param ctxt the read context containing the CTF archive to
 /// process.
@@ -937,43 +1115,49 @@ process_ctf_archive(read_context *ctxt, corpus_sptr corp)
   ir_translation_unit->set_language(translation_unit::LANG_C);
   corp->add(ir_translation_unit);
 
-  /* Iterate over the CTF dictionaries in the archive.  */
   int ctf_err;
   ctf_dict_t *ctf_dict;
-  ctf_next_t *dict_next = NULL;
-  const char *archive_name;
+  const auto symtab = ctxt->symtab;
+  symtab_reader::symtab_filter filter = symtab->make_filter();
+  filter.set_public_symbols();
+  std::string dict_name;
 
-  while ((ctf_dict = ctf_archive_next(ctxt->ctfa, &dict_next, &archive_name,
-                                      0 /* skip_parent */, &ctf_err)) != NULL)
+  if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
     {
-      /* Iterate over the CTF types stored in this archive.  */
-      ctf_id_t ctf_type;
-      int type_flag;
-      ctf_next_t *type_next = NULL;
+      tools_utils::base_name(ctxt->filename, dict_name);
 
-      while ((ctf_type = ctf_type_next(ctf_dict, &type_next, &type_flag,
-                                       1 /* want_hidden */)) != CTF_ERR)
-        {
-          process_ctf_type(ctxt, corp, ir_translation_unit,
-                            ctf_dict, ctf_type);
-        }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_type_next\n");
+      if (dict_name != "vmlinux")
+        // remove .ko suffix
+        dict_name.erase(dict_name.length() - 3, 3);
+
+      std::replace(dict_name.begin(), dict_name.end(), '-', '_');
+    }
 
-      /* Canonicalize all the types generated above.  This must be
-         done "a posteriori" because the processing of types may
-         require other related types to not be already
-         canonicalized.  */
-      ctxt->canonicalize_all_types();
+  if ((ctf_dict = ctf_dict_open(ctxt->ctfa,
+                                dict_name.empty() ? NULL : dict_name.c_str(),
+                                &ctf_err)) == NULL)
+    {
+      fprintf(stderr, "ERROR dictionary not found\n");
+      abort();
+    }
 
-      /* Iterate over the CTF variables stored in this archive.  */
+  for (const auto& symbol : symtab_reader::filtered_symtab(*symtab, filter))
+    {
+      std::string sym_name = symbol->get_name();
       ctf_id_t ctf_var_type;
-      ctf_next_t *var_next = NULL;
-      const char *var_name;
 
-      while ((ctf_var_type = ctf_variable_next(ctf_dict, &var_next, &var_name))
-             != CTF_ERR)
+      if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+          || ctxt->is_elf_exec)
+        ctf_var_type= ctf_lookup_variable (ctf_dict, sym_name.c_str());
+      else
+        ctf_var_type = ctf_lookup_by_symbol_name(ctf_dict, sym_name.c_str());
+
+      if (ctf_var_type == (ctf_id_t) -1)
+        continue;
+
+      if (ctf_type_kind (ctf_dict, ctf_var_type) != CTF_K_FUNCTION)
         {
+          const char *var_name = sym_name.c_str();
           type_base_sptr var_type = lookup_type(ctxt, corp, ir_translation_unit,
                                                 ctf_dict, ctf_var_type);
           if (!var_type)
@@ -986,50 +1170,38 @@ process_ctf_archive(read_context *ctxt, corpus_sptr corp)
                                              location(),
                                              var_name));
 
+          var_declaration->set_symbol(symbol);
           add_decl_to_scope(var_declaration,
-                             ir_translation_unit->get_global_scope());
+                            ir_translation_unit->get_global_scope());
         }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_variable_next\n");
+      else
+        {
+          const char *func_name = sym_name.c_str();
+          ctf_id_t ctf_sym = ctf_var_type;
+          type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
+                                                 ctf_dict, ctf_sym);
+          if (!func_type)
+            /* Ignore function if its type can't be sorted out.  */
+            continue;
 
-      /* Iterate over the CTF functions stored in this archive.  */
-      ctf_next_t *func_next = NULL;
-      const char *func_name = NULL;
-      ctf_id_t ctf_sym;
+          function_decl_sptr func_declaration;
+          func_declaration.reset(new function_decl(func_name,
+                                                   func_type,
+                                                   0 /* is_inline */,
+                                                   location()));
 
-      while ((ctf_sym = ctf_symbol_next(ctf_dict, &func_next, &func_name,
-                                        1 /* functions symbols only */) != CTF_ERR))
-      {
-        ctf_id_t ctf_func_type = ctf_lookup_by_name(ctf_dict, func_name);
-        type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
-                                               ctf_dict, ctf_func_type);
-        if (!func_type)
-          /* Ignore function if its type can't be sorted out.  */
-          continue;
-
-        elf_symbols func_elf_symbols = ctxt->symtab->lookup_symbol(func_name);
-        if (func_elf_symbols.size() == 0
-            || func_elf_symbols[0]->get_binding() == elf_symbol::LOCAL_BINDING)
-          /* Ignore local functions.  */
-          continue;
-
-        function_decl_sptr func_declaration;
-        func_declaration.reset(new function_decl(func_name,
-                                                 func_type,
-                                                 0 /* is_inline */,
-                                                 location()));
-
-        add_decl_to_scope(func_declaration,
-                           ir_translation_unit->get_global_scope());
-      }
-      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
-        fprintf(stderr, "ERROR from ctf_symbol_next\n");
-
-      ctf_dict_close(ctf_dict);
+          func_declaration->set_symbol(symbol);
+          add_decl_to_scope(func_declaration,
+                            ir_translation_unit->get_global_scope());
+        }
     }
-  if (ctf_err != ECTF_NEXT_END)
-    fprintf(stderr, "ERROR from ctf_archive_next\n");
 
+  ctf_dict_close(ctf_dict);
+  /* Canonicalize all the types generated above.  This must be
+     done "a posteriori" because the processing of types may
+     require other related types to not be already
+     canonicalized.  */
+  ctxt->canonicalize_all_types();
 }
 
 /// Open the ELF file described by the given read context.
@@ -1113,6 +1285,7 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
   /* Set the ELF architecture.  */
   GElf_Ehdr eh_mem;
   GElf_Ehdr *ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem);
+  ctxt->is_elf_exec = (ehdr->e_type == ET_EXEC);
   corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
 
   /* Read the symtab from the ELF file and set it in the corpus.  */
@@ -1121,6 +1294,9 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
                                 0 /* No suppressions.  */);
   corp->set_symtab(ctxt->symtab);
 
+  if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+    return 1;
+
   /* Get the raw ELF section contents for libctf.  */
   Elf_Scn *ctf_scn = elf_helpers::find_section(ctxt->elf_handler, ".ctf", SHT_PROGBITS);
   Elf_Scn *symtab_scn = elf_helpers::find_symbol_table_section(ctxt->elf_handler);
@@ -1167,6 +1343,7 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
   corpus_sptr corp
     = std::make_shared<corpus>(ctxt->ir_env, ctxt->filename);
 
+  ctxt->cur_corpus_ = corp;
   /* Be optimist.  */
   status = elf_reader::STATUS_OK;
 
@@ -1177,25 +1354,52 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
       return corp;
     }
 
-  /* Set some properties of the corpus first.  */
-  corp->set_origin(corpus::CTF_ORIGIN);
-  if (!slurp_elf_info(ctxt, corp))
+  bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
+  corpus::origin origin = corpus::CTF_ORIGIN;
+
+  if (is_linux_kernel)
+    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
+  corp->set_origin(origin);
+
+  if (ctxt->cur_corpus_group_)
+    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
+
+  if (!slurp_elf_info(ctxt, corp) && !is_linux_kernel)
     {
       status = elf_reader::STATUS_NO_SYMBOLS_FOUND;
       return corp;
     }
 
-  /* Build the ctfa from the contents of the relevant ELF sections,
-     and process the CTF archive in the read context, if any.
-     Information about the types, variables, functions, etc contained
-     in the archive are added to the given corpus.  */
   int errp;
-  ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
-                               &ctxt->strtab_sect, &errp);
+  if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+    {
+      std::string filename;
+      if (tools_utils::base_name(ctxt->filename, filename)
+          && filename == "vmlinux")
+        {
+          std::string vmlinux_ctfa_path = ctxt->filename + ".ctfa";
+          ctxt->ctfa = ctf_arc_open(vmlinux_ctfa_path.c_str(), &errp);
+        }
+    }
+  else
+    /* Build the ctfa from the contents of the relevant ELF sections,
+       and process the CTF archive in the read context, if any.
+       Information about the types, variables, functions, etc contained
+       in the archive are added to the given corpus.  */
+    ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
+                                 &ctxt->strtab_sect, &errp);
+
+  ctxt->ir_env->canonicalization_is_done(false);
   if (ctxt->ctfa == NULL)
     status = elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
   else
-    process_ctf_archive(ctxt, corp);
+    {
+      process_ctf_archive(ctxt, corp);
+      ctxt->cur_corpus_->sort_functions();
+      ctxt->cur_corpus_->sort_variables();
+    }
+
+  ctxt->ir_env->canonicalization_is_done(true);
 
   /* Cleanup and return.  */
   close_elf_handler(ctxt);
@@ -1216,5 +1420,94 @@ corpus_sptr
 read_corpus(const read_context_sptr &ctxt, elf_reader::status &status)
 {return read_corpus(ctxt.get(), status);}
 
+/// Set the @ref corpus_group being created to the current read context.
+///
+/// @param ctxt the read_context to consider.
+///
+/// @param group the @ref corpus_group to set.
+void
+set_read_context_corpus_group(read_context& ctxt,
+                              corpus_group_sptr& group)
+{
+  ctxt.cur_corpus_group_ = group;
+}
+
+/// Read a corpus and add it to a given @ref corpus_group.
+///
+/// @param ctxt the reading context to consider.
+///
+/// @param group the @ref corpus_group to add the new corpus to.
+///
+/// @param status output parameter. The status of the read.  It is set
+/// by this function upon its completion.
+corpus_sptr
+read_and_add_corpus_to_group_from_elf(read_context* ctxt,
+                                      corpus_group& group,
+                                      elf_reader::status& status)
+{
+  corpus_sptr result;
+  corpus_sptr corp = read_corpus(ctxt, status);
+  if (status & elf_reader::STATUS_OK)
+    {
+      if (!corp->get_group())
+        group.add_corpus(corp);
+      result = corp;
+    }
+
+  return result;
+}
+
+/// Re-initialize a read_context so that it can re-used to read
+/// another binary.
+///
+/// @param ctxt the context to re-initialize.
+///
+/// @param elf_path the path to the elf file the context is to be used
+/// for.
+///
+/// @param environment the environment used by the current context.
+/// This environment contains resources needed by the reader and by
+/// the types and declarations that are to be created later.  Note
+/// that ABI artifacts that are to be compared all need to be created
+/// within the same environment.
+///
+/// Please also note that the life time of this environment object
+/// must be greater than the life time of the resulting @ref
+/// read_context the context uses resources that are allocated in the
+/// environment.
+void
+reset_read_context(read_context_sptr	&ctxt,
+                   const std::string&	 elf_path,
+                   ir::environment*	 environment)
+{
+  if (ctxt)
+    ctxt->initialize(elf_path, environment);
+}
+
+/// Returns a key to be use in types_map dict conformed by
+/// dictionary id and the CTF type id for a given type.
+///
+/// CTF id types are unique by child dictionary, but CTF id
+/// types in parent dictionary are unique across the all
+/// dictionaries in the CTF archive, to differentiate
+/// one each other this member function relies in
+/// ctf_type_isparent function.
+///
+/// @param dic the pointer to CTF dictionary where the @p type
+/// was found.
+///
+/// @param type the id for given CTF type.
+std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type)
+{
+  std::stringstream key;
+
+  if (ctf_type_isparent (dic, ctf_type))
+    key << std::hex << ctf_type;
+  else
+    key << std::hex << ctf_type << '-' << ctf_cuname(dic);
+  return key.str();
+}
+
 } // End of namespace ctf_reader
 } // End of namespace abigail
diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index dc82cf3b..7bf2375d 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -14444,10 +14444,12 @@ read_debug_info_into_corpus(read_context& ctxt)
   // First set some mundane properties of the corpus gathered from
   // ELF.
   ctxt.current_corpus()->set_path(ctxt.elf_path());
+
+  corpus::origin origin = corpus::DWARF_ORIGIN;
   if (is_linux_kernel(ctxt.elf_handle()))
-    ctxt.current_corpus()->set_origin(corpus::LINUX_KERNEL_BINARY_ORIGIN);
-  else
-    ctxt.current_corpus()->set_origin(corpus::DWARF_ORIGIN);
+    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
+  ctxt.current_corpus()->set_origin(origin);
+
   ctxt.current_corpus()->set_soname(ctxt.dt_soname());
   ctxt.current_corpus()->set_needed(ctxt.dt_needed());
   ctxt.current_corpus()->set_architecture_name(ctxt.elf_architecture());
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 0ef5e8b2..4e907620 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -13498,7 +13498,7 @@ types_defined_same_linux_kernel_corpus_public(const type_base& t1,
   /// kernel corpus, let's move on.  Otherwise bail out.
   if (!(t1_corpus && t2_corpus
 	&& t1_corpus == t2_corpus
-	&& (t1_corpus->get_origin() == corpus::LINUX_KERNEL_BINARY_ORIGIN)
+	&& (t1_corpus->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
 	&& (is_class_or_union_type(&t1)
 	    || is_enum_type(&t1))))
     return false;
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index 1f0f6fa8..f30c3f1d 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -44,6 +44,9 @@
 #include <sstream>
 
 #include "abg-dwarf-reader.h"
+#ifdef WITH_CTF
+#include "abg-ctf-reader.h"
+#endif
 #include "abg-internal.h"
 #include "abg-regex.h"
 
@@ -2486,6 +2489,223 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
 					   module_paths);
 }
 
+/// If the @ref origin is DWARF_ORIGIN it build a @ref corpus_group
+/// made of vmlinux kernel file and the linux kernel modules found
+/// under @p root directory and under its sub-directories, recursively.
+///
+/// @param origin the debug type information in vmlinux kernel and
+/// the linux kernel modules to be used to build the corpora @p group.
+///
+/// @param the group @ref corpus_group to be built.
+///
+/// @param vmlinux the path to the vmlinux binary.
+///
+/// @param modules a vector with the paths to the linux kernel
+/// modules.
+///
+/// @param root the path of the directory under which the kernel
+/// kernel modules were found.
+///
+/// @param di_root the directory in aboslute path which debug
+/// info is to be found for binaries under director @p root
+///
+/// @param suppr_paths the paths to the suppression specifications to
+/// apply while loading the binaries.
+///
+/// @param kabi_wl_path the paths to the kabi whitelist files to take
+/// into account while loading the binaries.
+///
+/// @param supprs the suppressions resulting from parsing the
+/// suppression specifications at @p suppr_paths.  This is set by this
+/// function.
+///
+/// @param verbose true if the function has to emit some verbose
+/// messages.
+///
+/// @param t time to trace time spent in each step.
+///
+/// @param env the environment to create the corpus_group in.
+static void
+maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
+                                corpus_group_sptr&  group,
+                                const string&       vmlinux,
+                                vector<string>&     modules,
+                                const string&       root,
+                                vector<char**>&     di_roots,
+                                vector<string>&     suppr_paths,
+                                vector<string>&     kabi_wl_paths,
+                                suppressions_type&  supprs,
+                                bool                verbose,
+                                timer&              t,
+                                environment_sptr&   env)
+{
+  if (!(origin & corpus::DWARF_ORIGIN))
+    return;
+
+  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
+  dwarf_reader::read_context_sptr ctxt;
+  ctxt =
+   dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
+                                     /*read_all_types=*/false,
+                                     /*linux_kernel_mode=*/true);
+  dwarf_reader::set_do_log(*ctxt, verbose);
+
+  t.start();
+  load_generate_apply_suppressions(*ctxt, suppr_paths,
+                                   kabi_wl_paths, supprs);
+  t.stop();
+
+  if (verbose)
+    std::cerr << "loaded white list and generated suppr spec in: "
+     << t
+     << "\n";
+
+  group.reset(new corpus_group(env.get(), root));
+
+  set_read_context_corpus_group(*ctxt, group);
+
+  if (verbose)
+    std::cerr << "reading kernel binary '"
+     << vmlinux << "' ...\n" << std::flush;
+
+  // Read the vmlinux corpus and add it to the group.
+  t.start();
+  read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
+  t.stop();
+
+  if (verbose)
+    std::cerr << vmlinux
+     << " reading DONE:"
+     << t << "\n";
+
+  if (group->is_empty())
+    return;
+
+  // Now add the corpora of the modules to the corpus group.
+  int total_nb_modules = modules.size();
+  int cur_module_index = 1;
+  for (vector<string>::const_iterator m = modules.begin();
+       m != modules.end();
+       ++m, ++cur_module_index)
+    {
+      if (verbose)
+        std::cerr << "reading module '"
+         << *m << "' ("
+         << cur_module_index
+         << "/" << total_nb_modules
+         << ") ... " << std::flush;
+
+      reset_read_context(ctxt, *m, di_roots, env.get(),
+                         /*read_all_types=*/false,
+                         /*linux_kernel_mode=*/true);
+
+      load_generate_apply_suppressions(*ctxt, suppr_paths,
+                                       kabi_wl_paths, supprs);
+
+      set_read_context_corpus_group(*ctxt, group);
+
+      t.start();
+      read_and_add_corpus_to_group_from_elf(*ctxt,
+                                            *group, status);
+      t.stop();
+      if (verbose)
+        std::cerr << "module '"
+         << *m
+         << "' reading DONE: "
+         << t << "\n";
+    }
+}
+
+/// If the @ref origin is CTF_ORIGIN it build a @ref corpus_group
+/// made of vmlinux kernel file and the linux kernel modules found
+/// under @p root directory and under its sub-directories, recursively.
+///
+/// @param origin the debug type information in vmlinux kernel and
+/// the linux kernel modules to be used to build the corpora @p group.
+///
+/// @param group the @ref corpus_group to be built.
+///
+/// @param vmlinux the path to the vmlinux binary.
+///
+/// @param modules a vector with the paths to the linux kernel
+/// modules.
+///
+/// @param root the path of the directory under which the kernel
+/// kernel modules were found.
+///
+/// @param verbose true if the function has to emit some verbose
+/// messages.
+///
+/// @param t time to trace time spent in each step.
+///
+/// @param env the environment to create the corpus_group in.
+#ifdef WITH_CTF
+static void
+maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
+                              corpus_group_sptr&  group,
+                              const string&       vmlinux,
+                              vector<string>&     modules,
+                              const string&       root,
+                              bool                verbose,
+                              timer&              t,
+                              environment_sptr&   env)
+{
+  if (!(origin & corpus::CTF_ORIGIN))
+    return;
+
+  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
+  ctf_reader::read_context_sptr ctxt;
+  ctxt = ctf_reader::create_read_context(vmlinux, env.get());
+  group.reset(new corpus_group(env.get(), root));
+  set_read_context_corpus_group(*ctxt, group);
+
+  if (verbose)
+    std::cerr << "reading kernel binary '"
+     << vmlinux << "' ...\n" << std::flush;
+
+  // Read the vmlinux corpus and add it to the group.
+  t.start();
+  read_and_add_corpus_to_group_from_elf(ctxt.get(), *group, status);
+  t.stop();
+
+  if (verbose)
+    std::cerr << vmlinux
+     << " reading DONE:"
+     << t << "\n";
+
+  if (group->is_empty())
+    return;
+
+  // Now add the corpora of the modules to the corpus group.
+  int total_nb_modules = modules.size();
+  int cur_module_index = 1;
+  for (vector<string>::const_iterator m = modules.begin();
+       m != modules.end();
+       ++m, ++cur_module_index)
+    {
+      if (verbose)
+        std::cerr << "reading module '"
+         << *m << "' ("
+         << cur_module_index
+         << "/" << total_nb_modules
+         << ") ... " << std::flush;
+
+      reset_read_context(ctxt, *m, env.get());
+      set_read_context_corpus_group(*ctxt, group);
+
+      t.start();
+      read_and_add_corpus_to_group_from_elf(ctxt.get(),
+                                            *group, status);
+      t.stop();
+      if (verbose)
+        std::cerr << "module '"
+         << *m
+         << "' reading DONE: "
+         << t << "\n";
+    }
+}
+#endif
+
 /// Walk a given directory and build an instance of @ref corpus_group
 /// from the vmlinux kernel binary and the linux kernel modules found
 /// under that directory and under its sub-directories, recursively.
@@ -2493,6 +2713,11 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
 /// The main corpus of the @ref corpus_group is made of the vmlinux
 /// binary.  The other corpora are made of the linux kernel binaries.
 ///
+/// Depending of the @ref origin it delegates the corpus build @p group
+/// to:
+///     @ref maybe_load_vmlinux_dwarf_corpus
+///     @ref maybe_load_vmlinux_ctf_corpus
+///
 /// @param root the path of the directory under which the kernel
 /// kernel modules are to be found.  The vmlinux can also be found
 /// somewhere under that directory, but if it's not in there, its path
@@ -2528,10 +2753,11 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  vector<string>&	kabi_wl_paths,
 					  suppressions_type&	supprs,
 					  bool			verbose,
-					  environment_sptr&	env)
+					  environment_sptr&	env,
+					  corpus::origin	origin)
 {
   string vmlinux = vmlinux_path;
-  corpus_group_sptr result;
+  corpus_group_sptr group;
   vector<string> modules;
 
   if (verbose)
@@ -2548,7 +2774,6 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
   if (verbose)
     std::cerr << "DONE: " << t << "\n";
 
-  dwarf_reader::read_context_sptr ctxt;
   if (got_binary_paths)
     {
       shared_ptr<char> di_root =
@@ -2556,86 +2781,18 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
       char *di_root_ptr = di_root.get();
       vector<char**> di_roots;
       di_roots.push_back(&di_root_ptr);
-      abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
-      corpus_group_sptr group;
-      if (!vmlinux.empty())
-	{
-	  ctxt =
-	    dwarf_reader::create_read_context(vmlinux, di_roots ,env.get(),
-					      /*read_all_types=*/false,
-					      /*linux_kernel_mode=*/true);
-	  dwarf_reader::set_do_log(*ctxt, verbose);
-
-	  t.start();
-	  load_generate_apply_suppressions(*ctxt, suppr_paths,
-					   kabi_wl_paths, supprs);
-	  t.stop();
-
-	  if (verbose)
-	    std::cerr << "loaded white list and generated suppr spec in: "
-		      << t
-		      << "\n";
-
-	  group.reset(new corpus_group(env.get(), root));
-
-	  set_read_context_corpus_group(*ctxt, group);
-
-	  if (verbose)
-	    std::cerr << "reading kernel binary '"
-		      << vmlinux << "' ...\n" << std::flush;
-
-	  // Read the vmlinux corpus and add it to the group.
-	  t.start();
-	  read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
-	  t.stop();
-
-	  if (verbose)
-	    std::cerr << vmlinux
-		      << " reading DONE:"
-		      << t << "\n";
-	}
 
-      if (!group->is_empty())
-	{
-	  // Now add the corpora of the modules to the corpus group.
-	  int total_nb_modules = modules.size();
-	  int cur_module_index = 1;
-	  for (vector<string>::const_iterator m = modules.begin();
-	       m != modules.end();
-	       ++m, ++cur_module_index)
-	    {
-	      if (verbose)
-		std::cerr << "reading module '"
-			  << *m << "' ("
-			  << cur_module_index
-			  << "/" << total_nb_modules
-			  << ") ... " << std::flush;
-
-	      reset_read_context(ctxt, *m, di_roots, env.get(),
-				 /*read_all_types=*/false,
-				 /*linux_kernel_mode=*/true);
-
-	      load_generate_apply_suppressions(*ctxt, suppr_paths,
-					       kabi_wl_paths, supprs);
-
-	      set_read_context_corpus_group(*ctxt, group);
-
-	      t.start();
-	      read_and_add_corpus_to_group_from_elf(*ctxt,
-						    *group, status);
-	      t.stop();
-	      if (verbose)
-		std::cerr << "module '"
-			  << *m
-			  << "' reading DONE: "
-			  << t << "\n";
-	    }
-
-	  result = group;
-	}
+      maybe_load_vmlinux_dwarf_corpus(origin, group, vmlinux,
+                                      modules, root, di_roots,
+                                      suppr_paths, kabi_wl_paths,
+                                      supprs, verbose, t, env);
+#ifdef WITH_CTF
+      maybe_load_vmlinux_ctf_corpus(origin, group, vmlinux,
+                                    modules, root, verbose, t, env);
+#endif
     }
 
-  return result;
+  return group;
 }
 
 }//end namespace tools_utils
diff --git a/tests/data/test-read-common/test-PR26568-2.o b/tests/data/test-read-common/test-PR26568-2.o
index b192d52132766d4f95136e23f93de43a64d8cc2e..a6706e8cf508ab89927b0fccecd0268d27111ed9 100644
GIT binary patch
delta 1078
zcmZuwJ#Q015Z%3R+XNC4+rf~Wtw;eB%$Z17uE0<rBAO5pQBj=FADpo7f_)Bl6-1ZL
zWGcFpL83uvC{3skO-dR>8YF6d0W;^l$g=#T(agS?dAmD%_cwibb#Nn{HP|`IVN_-*
zmVAHz`rg0aiWKFRqCj{BJsEYAeL@S+bhImI1kPB7YSeJW7>OZA(1_29CDoC}EE<7w
zsFR{tqeK}CFQZ3+WdmmP^q!2X1vG><a*WfqD3v0Dy2fxZJc8>5tjC(Z*T_=XXAjt}
z?^ap8>oM!4->O-aex+~uZQE(qtWMjpnr_9exDDHF=DRzcpk1?DR#58%`Hoe!1A7!B
zTg^LutL1wmVsmS~c(+)}uitjUGkmTeaY###a!yds<{P6;&yUgdUU~i-FRVO%A=#X(
z@LEpFGSh{RlZR`{0vyU3p8->G4^#sN$`0Q;=IRA5qc9}2U+_o!rrts&jvez*)(z<y
zhq%6+DH2IrOblko;Y44x?_h?eUPc?osd&1fAm`B&6{#!={vrBl@{jSw2nX<8H*?z<
zO{+Q+RTgX*D@)VPF%XYjfQ^Kyx}-xlj9sGd0P!4Rx@lK2n$|rO-Mz4uF}g(@ZSodf
z<mh|_v~kqME)ML+%*<O%g;i0zC_R<oB(|CxL}@`s?g^a?u|^{52aLiiNV^K&Bn6B5
zZ0;kH^#6!)U^GHcv=+iCenpb@pR76(RVCPuuiTtAhZ2b+qF19i%t11-Hg_g^e};Md
Wwcu&OlD??$E^#lmDcXL}kpBaNjDTqX

delta 508
zcmZvYJ4*vW6oqH@mA%=G1lhO&i`^hZLkd#{K}{MFY|?3G0>KAJj1W*_wN`>n^!NiJ
zq)4A4oum?*^g<f#EN$)F*&Rj1f#J-(ocZRS=`X&!y%l$8u%A_lP8F76&h6&%=#dXO
zot(A~{o_`L;XvIQP1OeH8s4;wsxm_=NwtKcqdVy9dz|p8pK~@kGi;8l#0+(Ff<9?z
zlA|0kbSV!%EC=Ki>RLR*Bo;Ows%V+A&PrWJgIxNM)g7wIC4r-B9=BEzkjHoMKyJa;
z<6cR+1v3%uzsx3bA#*GVy9i8=??;51BwYL=&_9GWa+XVTN^Gm4YI*z;4a-&P3c6OF
z-$aI)G!!Gly?9nJ)bP(1&@<C~fSm1;sm7EN0z1rRJ5-jPa+GZ>Cd)j_$-e(ZWJ_ae
b7pX1XF9?zz{8U!i*07e^pjUb2Nd)`?0Gw2F

diff --git a/tests/data/test-read-ctf/PR27700/test-PR27700.abi b/tests/data/test-read-ctf/PR27700/test-PR27700.abi
index 62df1017..fe3a897d 100644
--- a/tests/data/test-read-ctf/PR27700/test-PR27700.abi
+++ b/tests/data/test-read-ctf/PR27700/test-PR27700.abi
@@ -11,9 +11,8 @@
       <enumerator name='foo_e2' value='2'/>
       <enumerator name='foo_e3' value='3'/>
     </enum-decl>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <pointer-type-def type-id='022218d8' size-in-bits='64' alignment-in-bits='64' id='8750e847'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
       <parameter type-id='8750e847'/>
       <return type-id='48b5725f'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR26568-1.o.abi b/tests/data/test-read-ctf/test-PR26568-1.o.abi
index d62474ec..832dc1bd 100644
--- a/tests/data/test-read-ctf/test-PR26568-1.o.abi
+++ b/tests/data/test-read-ctf/test-PR26568-1.o.abi
@@ -7,47 +7,29 @@
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='' type-id='type-id-2' visibility='default'/>
       </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='' type-id='type-id-5' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
-      </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
+        <var-decl name='y' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-5'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-5'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
+        <var-decl name='x' type-id='type-id-6' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
     <union-decl name='' size-in-bits='64' is-anonymous='yes' visibility='default' id='type-id-2'>
-      <data-member access='public'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
-      </data-member>
-      <data-member access='public'>
-        <var-decl name='x' type-id='type-id-4' visibility='default'/>
-      </data-member>
       <data-member access='public'>
         <var-decl name='' type-id='type-id-5' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='y' type-id='type-id-6' visibility='default'/>
+        <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
     </union-decl>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fun'>
       <parameter type-id='type-id-7'/>
       <return type-id='type-id-8'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR26568-2.o.abi b/tests/data/test-read-ctf/test-PR26568-2.o.abi
index a934d15b..70e0772f 100644
--- a/tests/data/test-read-ctf/test-PR26568-2.o.abi
+++ b/tests/data/test-read-ctf/test-PR26568-2.o.abi
@@ -3,34 +3,28 @@
     <elf-symbol name='fun' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='x' type-id='type-id-2' visibility='default'/>
+        <var-decl name='y' type-id='type-id-2' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='y' type-id='type-id-4' visibility='default'/>
+        <var-decl name='x' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-2'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <union-decl name='A' size-in-bits='64' visibility='default' id='type-id-5'>
-      <data-member access='public'>
-        <var-decl name='' type-id='type-id-1' visibility='default'/>
-      </data-member>
-      <data-member access='public'>
-        <var-decl name='x' type-id='type-id-2' visibility='default'/>
-      </data-member>
       <data-member access='public'>
         <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='y' type-id='type-id-4' visibility='default'/>
+        <var-decl name='' type-id='type-id-1' visibility='default'/>
       </data-member>
     </union-decl>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='fun' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fun'>
       <parameter type-id='type-id-6'/>
       <return type-id='type-id-7'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-PR27700.abi b/tests/data/test-read-ctf/test-PR27700.abi
new file mode 100644
index 00000000..fe3a897d
--- /dev/null
+++ b/tests/data/test-read-ctf/test-PR27700.abi
@@ -0,0 +1,21 @@
+<abi-corpus version='2.1' path='data/test-read-common/PR27700/test-PR27700.o'>
+  <elf-function-symbols>
+    <elf-symbol name='foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-function-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='foo' linkage-name='foo' id='022218d8'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='foo_e0' value='0'/>
+      <enumerator name='foo_e1' value='1'/>
+      <enumerator name='foo_e2' value='2'/>
+      <enumerator name='foo_e3' value='3'/>
+    </enum-decl>
+    <pointer-type-def type-id='022218d8' size-in-bits='64' alignment-in-bits='64' id='8750e847'/>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='8750e847'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi b/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
index 922a1daf..12050a5b 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi
@@ -30,7 +30,6 @@
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='7359adad'/>
     <pointer-type-def type-id='3ed987a4' size-in-bits='64' alignment-in-bits='64' id='84d5ac12'/>
     <pointer-type-def type-id='1c12b755' size-in-bits='64' alignment-in-bits='64' id='55cd64e8'/>
-    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default'/>
-    <var-decl name='foo' type-id='55cd64e8' mangled-name='foo' visibility='default'/>
+    <var-decl name='foo' type-id='55cd64e8' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.c b/tests/data/test-read-ctf/test-ambiguous-struct-B.c
index 95a93469..e592529b 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-B.c
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-B.c
@@ -2,4 +2,4 @@ struct A;
 struct B { struct A *a; };
 struct A { struct B b; int foo; struct B b2; };
 
-static struct A a __attribute__((__used__));
+struct A a __attribute__((__used__));
diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.o b/tests/data/test-read-ctf/test-ambiguous-struct-B.o
index 06bd0f502a874ad4a10c4beb5788eaace44c2bf9..40a11fcbd4ae19b78a943812f69606cdc6c9fc15 100644
GIT binary patch
delta 20
ccmX@Wb%1Nb8%9RK&2Jg^GchtvUdu8W08_UIfB*mh

delta 20
ccmX@Wb%1Nb8%9RP&2Jg^GchtxUdu8W08;!1aR2}S

diff --git a/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi b/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
index 28291eb5..83d21919 100644
--- a/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
+++ b/tests/data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-ctf/test-ambiguous-struct-B.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='a' size='24' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
   <abi-instr address-size='64' language='LANG_C'>
     <class-decl name='A' size-in-bits='192' alignment-in-bits='64' is-struct='yes' visibility='default' id='3ed987a4'>
       <data-member access='public' layout-offset-in-bits='0'>
@@ -18,6 +21,6 @@
     </class-decl>
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
     <pointer-type-def type-id='3ed987a4' size-in-bits='64' alignment-in-bits='64' id='84d5ac12'/>
-    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default'/>
+    <var-decl name='a' type-id='3ed987a4' mangled-name='a' visibility='default' elf-symbol-id='a'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-anonymous-fields.o.abi b/tests/data/test-read-ctf/test-anonymous-fields.o.abi
index 0419c29c..2134a86d 100644
--- a/tests/data/test-read-ctf/test-anonymous-fields.o.abi
+++ b/tests/data/test-read-ctf/test-anonymous-fields.o.abi
@@ -3,14 +3,14 @@
     <elf-symbol name='t' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-variable-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
+    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='vaddr' type-id='type-id-2' visibility='default'/>
+        <var-decl name='dup_xol_work' type-id='type-id-2' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='' size-in-bits='32' alignment-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
+    <class-decl name='' size-in-bits='64' alignment-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' id='type-id-3'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='dup_xol_work' type-id='type-id-4' visibility='default'/>
+        <var-decl name='vaddr' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
     <class-decl name='uprobe_task' size-in-bits='64' alignment-in-bits='64' is-struct='yes' visibility='default' id='type-id-5'>
@@ -18,16 +18,16 @@
         <var-decl name='' type-id='type-id-6' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-2'/>
     <union-decl name='' size-in-bits='64' is-anonymous='yes' visibility='default' id='type-id-6'>
       <data-member access='public'>
-        <var-decl name='' type-id='type-id-1' visibility='default'/>
+        <var-decl name='' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public'>
-        <var-decl name='' type-id='type-id-3' visibility='default'/>
+        <var-decl name='' type-id='type-id-1' visibility='default'/>
       </data-member>
     </union-decl>
-    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='t' type-id='type-id-5' mangled-name='t' visibility='default'/>
+    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
+    <var-decl name='t' type-id='type-id-5' mangled-name='t' visibility='default' elf-symbol-id='t'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-array-of-pointers.abi b/tests/data/test-read-ctf/test-array-of-pointers.abi
index 920da28b..195361df 100644
--- a/tests/data/test-read-ctf/test-array-of-pointers.abi
+++ b/tests/data/test-read-ctf/test-array-of-pointers.abi
@@ -31,6 +31,6 @@
     <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
     <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-11'/>
-    <var-decl name='t' type-id='type-id-11' mangled-name='t' visibility='default'/>
+    <var-decl name='t' type-id='type-id-11' mangled-name='t' visibility='default' elf-symbol-id='t'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-callback.abi b/tests/data/test-read-ctf/test-callback.abi
index 704c4971..7f9b6c5f 100644
--- a/tests/data/test-read-ctf/test-callback.abi
+++ b/tests/data/test-read-ctf/test-callback.abi
@@ -4,28 +4,16 @@
     <elf-symbol name='f2' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <class-decl name='test' size-in-bits='64' alignment-in-bits='64' is-struct='yes' visibility='default' id='type-id-1'>
-      <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='fn1' type-id='type-id-2' visibility='default'/>
-      </data-member>
-    </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
-    <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
-    <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <function-decl name='assign' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <return type-id='type-id-7'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
+    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
+    <function-decl name='assign' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='assign'>
+      <return type-id='type-id-3'/>
     </function-decl>
-    <function-decl name='f2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-3'/>
-      <parameter type-id='type-id-4'/>
-      <return type-id='type-id-7'/>
+    <function-decl name='f2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='f2'>
+      <parameter type-id='type-id-1'/>
+      <parameter type-id='type-id-2'/>
+      <return type-id='type-id-3'/>
     </function-decl>
-    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-6'>
-      <parameter type-id='type-id-3'/>
-      <parameter type-id='type-id-4'/>
-      <return type-id='type-id-7'/>
-    </function-type>
-    <type-decl name='void' id='type-id-7'/>
+    <type-decl name='void' id='type-id-3'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-callback2.abi b/tests/data/test-read-ctf/test-callback2.abi
index bdd4ad33..ddc3e493 100644
--- a/tests/data/test-read-ctf/test-callback2.abi
+++ b/tests/data/test-read-ctf/test-callback2.abi
@@ -11,7 +11,7 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
-    <var-decl name='s0' type-id='type-id-5' mangled-name='s0' visibility='default'/>
+    <var-decl name='s0' type-id='type-id-5' mangled-name='s0' visibility='default' elf-symbol-id='s0'/>
     <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-4'>
       <parameter type-id='type-id-5'/>
       <return type-id='type-id-3'/>
diff --git a/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi b/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
index 03dd56b3..8d5c3e36 100644
--- a/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
+++ b/tests/data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi
@@ -8,7 +8,7 @@
     <typedef-decl name='a_t' type-id='bd54fe1a' id='40acc204'/>
     <typedef-decl name='b_t' type-id='bd54fe1a' id='b3d2db81'/>
     <pointer-type-def type-id='40acc204' size-in-bits='64' alignment-in-bits='64' id='c6fd4117'/>
-    <var-decl name='a' type-id='c6fd4117' mangled-name='a' visibility='default'/>
-    <var-decl name='ignore2' type-id='b3d2db81' mangled-name='ignore2' visibility='default'/>
+    <var-decl name='a' type-id='c6fd4117' mangled-name='a' visibility='default' elf-symbol-id='a'/>
+    <var-decl name='ignore2' type-id='b3d2db81' mangled-name='ignore2' visibility='default' elf-symbol-id='ignore2'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi b/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
index 35bcac7a..992b669d 100644
--- a/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
+++ b/tests/data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi
@@ -7,7 +7,7 @@
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='bd54fe1a'/>
     <typedef-decl name='a_t' type-id='bd54fe1a' id='40acc204'/>
     <typedef-decl name='b_t' type-id='bd54fe1a' id='b3d2db81'/>
-    <var-decl name='b' type-id='40acc204' mangled-name='b' visibility='default'/>
-    <var-decl name='ignore1' type-id='b3d2db81' mangled-name='ignore1' visibility='default'/>
+    <var-decl name='b' type-id='40acc204' mangled-name='b' visibility='default' elf-symbol-id='b'/>
+    <var-decl name='ignore1' type-id='b3d2db81' mangled-name='ignore1' visibility='default' elf-symbol-id='ignore1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-dynamic-array.o.abi b/tests/data/test-read-ctf/test-dynamic-array.o.abi
index 02b22811..a9849d49 100644
--- a/tests/data/test-read-ctf/test-dynamic-array.o.abi
+++ b/tests/data/test-read-ctf/test-dynamic-array.o.abi
@@ -21,7 +21,7 @@
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-3'/>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <function-decl name='use_struct_s' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='use_struct_s' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='use_struct_s'>
       <parameter type-id='type-id-7'/>
       <return type-id='type-id-8'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-enum-ctf.o.abi b/tests/data/test-read-ctf/test-enum-ctf.o.abi
new file mode 100644
index 00000000..f36f3fad
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-ctf.o.abi
@@ -0,0 +1,24 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='bar' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='foo' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
+    <enum-decl name='e' linkage-name='e' id='type-id-2'>
+      <underlying-type type-id='type-id-1'/>
+      <enumerator name='ENUMSAMPLE_1' value='0'/>
+      <enumerator name='ENUMSAMPLE_2' value='1'/>
+    </enum-decl>
+    <enum-decl name='ie' linkage-name='ie' id='type-id-3'>
+      <underlying-type type-id='type-id-1'/>
+      <enumerator name='IENUMSAMPLE_1' value='-10'/>
+      <enumerator name='IENUMSAMPLE_2' value='-9'/>
+      <enumerator name='IENUMSAMPLE_3' value='-8'/>
+    </enum-decl>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
+    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default'/>
+    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi b/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
new file mode 100644
index 00000000..67a958a7
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-many-ctf.o.hash.abi
@@ -0,0 +1,69 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-many-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='bar' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='foo' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='e' linkage-name='e' id='a6c2eddf'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='ENUMSAMPLE_1' value='0'/>
+      <enumerator name='ENUMSAMPLE_2' value='1'/>
+    </enum-decl>
+    <enum-decl name='ie' linkage-name='ie' id='1ee696ca'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='IE_0' value='-10'/>
+      <enumerator name='IE_1' value='-9'/>
+      <enumerator name='IE_2' value='-8'/>
+      <enumerator name='IE_3' value='-7'/>
+      <enumerator name='IE_4' value='-6'/>
+      <enumerator name='IE_5' value='-5'/>
+      <enumerator name='IE_6' value='-4'/>
+      <enumerator name='IE_7' value='-3'/>
+      <enumerator name='IE_8' value='-2'/>
+      <enumerator name='IE_9' value='-1'/>
+      <enumerator name='IE_A' value='0'/>
+      <enumerator name='IE_B' value='1'/>
+      <enumerator name='IE_C' value='2'/>
+      <enumerator name='IE_D' value='3'/>
+      <enumerator name='IE_E' value='4'/>
+      <enumerator name='IE_F' value='5'/>
+      <enumerator name='IE_10' value='6'/>
+      <enumerator name='IE_11' value='7'/>
+      <enumerator name='IE_12' value='8'/>
+      <enumerator name='IE_13' value='9'/>
+      <enumerator name='IE_14' value='10'/>
+      <enumerator name='IE_15' value='11'/>
+      <enumerator name='IE_16' value='12'/>
+      <enumerator name='IE_17' value='13'/>
+      <enumerator name='IE_18' value='14'/>
+      <enumerator name='IE_19' value='15'/>
+      <enumerator name='IE_1A' value='16'/>
+      <enumerator name='IE_1B' value='17'/>
+      <enumerator name='IE_1C' value='18'/>
+      <enumerator name='IE_1D' value='19'/>
+      <enumerator name='IE_1E' value='20'/>
+      <enumerator name='IE_1F' value='21'/>
+      <enumerator name='IE_20' value='22'/>
+      <enumerator name='IE_21' value='23'/>
+      <enumerator name='IE_22' value='24'/>
+      <enumerator name='IE_23' value='25'/>
+      <enumerator name='IE_24' value='26'/>
+      <enumerator name='IE_25' value='27'/>
+      <enumerator name='IE_26' value='28'/>
+      <enumerator name='IE_27' value='29'/>
+      <enumerator name='IE_28' value='30'/>
+      <enumerator name='IE_29' value='31'/>
+      <enumerator name='IE_2A' value='32'/>
+      <enumerator name='IE_2B' value='33'/>
+      <enumerator name='IE_2C' value='34'/>
+      <enumerator name='IE_2D' value='35'/>
+      <enumerator name='IE_2E' value='36'/>
+      <enumerator name='IE_2F' value='37'/>
+    </enum-decl>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
+    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default'/>
+    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-many.o.hash.abi b/tests/data/test-read-ctf/test-enum-many.o.hash.abi
index 26bc048c..116325f9 100644
--- a/tests/data/test-read-ctf/test-enum-many.o.hash.abi
+++ b/tests/data/test-read-ctf/test-enum-many.o.hash.abi
@@ -61,9 +61,7 @@
       <enumerator name='IE_2E' value='36'/>
       <enumerator name='IE_2F' value='37'/>
     </enum-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='95e97e5e'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
-    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default'/>
-    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default'/>
+    <var-decl name='foo' type-id='a6c2eddf' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
+    <var-decl name='bar' type-id='1ee696ca' mangled-name='bar' visibility='default' elf-symbol-id='bar'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi b/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi
new file mode 100644
index 00000000..fea6eb8b
--- /dev/null
+++ b/tests/data/test-read-ctf/test-enum-symbol-ctf.o.hash.abi
@@ -0,0 +1,16 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-enum-symbol-ctf.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='primary1' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='811c9dc5'/>
+    <enum-decl name='' is-anonymous='yes' id='08f5ca17'>
+      <underlying-type type-id='811c9dc5'/>
+      <enumerator name='red1' value='0'/>
+      <enumerator name='green1' value='1'/>
+      <enumerator name='blue1' value='2'/>
+    </enum-decl>
+    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
+    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi b/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
index d128b5b1..f4911bc4 100644
--- a/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
+++ b/tests/data/test-read-ctf/test-enum-symbol.o.hash.abi
@@ -10,7 +10,6 @@
       <enumerator name='green1' value='1'/>
       <enumerator name='blue1' value='2'/>
     </enum-decl>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
-    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default'/>
+    <var-decl name='primary1' type-id='08f5ca17' mangled-name='primary1' visibility='default' elf-symbol-id='primary1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-enum.o.abi b/tests/data/test-read-ctf/test-enum.o.abi
index 88e6ad61..bd3a55be 100644
--- a/tests/data/test-read-ctf/test-enum.o.abi
+++ b/tests/data/test-read-ctf/test-enum.o.abi
@@ -16,9 +16,7 @@
       <enumerator name='IENUMSAMPLE_2' value='-9'/>
       <enumerator name='IENUMSAMPLE_3' value='-8'/>
     </enum-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
-    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default'/>
-    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default'/>
+    <var-decl name='foo' type-id='type-id-2' mangled-name='foo' visibility='default' elf-symbol-id='foo'/>
+    <var-decl name='bar' type-id='type-id-3' mangled-name='bar' visibility='default' elf-symbol-id='bar'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-forward-type-decl.abi b/tests/data/test-read-ctf/test-forward-type-decl.abi
index 21bb45c8..026e7d32 100644
--- a/tests/data/test-read-ctf/test-forward-type-decl.abi
+++ b/tests/data/test-read-ctf/test-forward-type-decl.abi
@@ -24,6 +24,6 @@
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <pointer-type-def type-id='type-id-4' size-in-bits='64' alignment-in-bits='64' id='type-id-3'/>
     <pointer-type-def type-id='type-id-6' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='addr' type-id='type-id-5' mangled-name='addr' visibility='default'/>
+    <var-decl name='addr' type-id='type-id-5' mangled-name='addr' visibility='default' elf-symbol-id='addr'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test-functions-declaration.abi b/tests/data/test-read-ctf/test-functions-declaration.abi
index 9ef05e44..7eb57d26 100644
--- a/tests/data/test-read-ctf/test-functions-declaration.abi
+++ b/tests/data/test-read-ctf/test-functions-declaration.abi
@@ -7,11 +7,11 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
-    <function-decl name='attribute_container_add_device' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='attribute_container_add_device' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='attribute_container_add_device'>
       <parameter type-id='type-id-4'/>
       <return type-id='type-id-5'/>
     </function-decl>
-    <function-decl name='attribute_container_device_trigger' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='attribute_container_device_trigger' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='attribute_container_device_trigger'>
       <parameter type-id='type-id-4'/>
       <return type-id='type-id-5'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test-list-struct.abi b/tests/data/test-read-ctf/test-list-struct.abi
index 196a79a1..deb6a4a1 100644
--- a/tests/data/test-read-ctf/test-list-struct.abi
+++ b/tests/data/test-read-ctf/test-list-struct.abi
@@ -14,7 +14,7 @@
     </class-decl>
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <var-decl name='n1' type-id='type-id-1' mangled-name='n1' visibility='default'/>
-    <var-decl name='n2' type-id='type-id-1' mangled-name='n2' visibility='default'/>
+    <var-decl name='n1' type-id='type-id-1' mangled-name='n1' visibility='default' elf-symbol-id='n1'/>
+    <var-decl name='n2' type-id='type-id-1' mangled-name='n2' visibility='default' elf-symbol-id='n2'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test0 b/tests/data/test-read-ctf/test0
index aca7fbacdfff7ad2caf0142390710373a8da72a1..90aa8a39a2e1326a5cb5faaa9e854fc344caaa52 100755
GIT binary patch
delta 1886
zcmah~L2MgE6rEkWZra+(ZUVNWHnG!6kSdbB4pp+Tz+NFxdrBKokU<E`3NA_s+0=1R
z!hsZ2LDU1-`4W{lz<~poN(}_6o**g+6(K-AQK3qlDyTRVq*5i9m^ZV3s^AM>djHSN
zd;ibh8SlFBwsHP~(HKr_=EVc^gezjg69eK<vp6(*(+n6LyI2@P3<F6yP|@SqTr2Ef
zl@x3>-2C<akjol3<f&C1(`qI}nm)_)Rb@(vl_gf{_&~`STwXkLyZ*8q|L+c**G1dL
z4@cxgW?8@<;P~XT!aOfF<(dJ&=o@or;}3H+`nh#uFt^0*{Ik>cCEMV+OqRCA^GGli
z>$IIInx!!1vl-J3)7k7`$O(J&cW80VdGA07&*>>?n$G1?dj~K!MU=jF68%x}p%rjS
z05{6)U9bt^c>!xMeHzgay_Cwy+>9NtOp13EYtzZxal@iZxop2JP89yD`B7>5=r>fb
zh1bE}QKfpQXEf3Ou)y|eu3azM=tbv6uyK*>U=M?}M4WuEG4X9jZ%4t}B0(RIW{o)g
ztb7~FZu}sEUGyzq<Xy6l$rHHDyJ+?jvt_VxG0d#VEq<wX>8AHp?loq0|C=(`#L0t=
ziZq}62-7#gTIleuVkf!(1I*r0l@pXYCiitZD&s=c)13s1jE+0)4%m&AW2eoP6DW8M
z#YTYVF^&Uo0S^IJ033+;4u}FRzy@vsG2nMVHgpf@15DJ|i#Q9wBJy?hfI+OoBJ$AE
zfW>o!M+8J>1B<W-8dLAZCu%ApQU^Zt4mslo?J}=&8DpAW952VN2CJe6@hiG9K4QE{
z_r|~2bH?|}Ir`K+5`L{RGe_UM&I@9pUa2oGI2?1LUR|h{E45l>IT%j+a|`ugcxKkG
z@NnLrnX6Z8!FmlTwV7$AUiW7!^_kf!nG;V(UzuCX%-8(+YOTJ!;Z5u_=v3a?pA31b
z!(@og=Eq_#Pt`|*rb2yd1#4go3VCqy`K6Uuq`pW}M4Nf*sJtrq(reWctCsk?m6WNl
z2)<~Em8USe-){R_tv?$LRv%JYs5#2Z+HI4V$jjCF>%7}K=gV%S$-WIh=W`c_#dBDc
zT3uj^3v6)#m(Jx=D=$IO-qj|)R9F$h;WtdTr=zZ><Ezl_?8<jJ-{t(YEC%arGguW*
ziZ?KlT3xWj1xj4NVWn=M<2l6zYCc{xE>a7=LG}|x;{%$4|A?CKm#GDRmFz;%xK2~>
zKT)&rXuoVnnyx1Q4W#`-Eog3$T`U^6X$t;NYQq0TE%<G+y;N6%50I{mCFztmY#gLz
O&);`_A}FyV&-Gt@S^P)<

delta 1541
zcmZ9MO-NKx6vxlKZ?tqYpOznE<-FXa2=ifIqf@>+MHB?NX;F)iHf3#0R0<+&`XH#N
z(X+7HWF#?*pbraz7G=z0T7=Llf`~Sev~ZQw#_8Pq&Mlh@@7#Cp?|;rc_r81Ih07v$
zQRF(B-Cp?H6r>;w3O2y{34c@fpbUuZSF_NeK15HRd0r~=v_CP~SN%(4YQLO`PfHC2
z))b`DgHVvzD%<e1EZ||sn;ms-)L<@@d*&9~lHaA$68O1X8Zs}AGF^qS0E6sTvhU&V
zm@kVC_Qqo}@8GF;n=|bw%!bA$6F0+>CR0Z0;czm#Y9qZ%2;=KSb0iFR-GCVZnQo?w
zM4LdVfC|Qks25O=(WH)z)d!RzTs73i{^UMUhf~RT#D)ER|7+eGO#^<R3@)fLx?obR
z!Mg6|$U30ujc-i@mC-<z`$QX|rHr-{b)gZ5h}J-%thP>~_0WX(y5ph|=Z!6qvKGJ#
zX3?Kgw`)90e2d<JM?8zAQ%nblHbMte8HB<MGfOSrGO;h2GK4oeR?^NB4THx!-^KVN
zQI{%QH1r_XA7;8>GB;s#tDZMemYF`NSzSNTYD%N*l%`)3(An{=ha|p{q4Cp{Y@X2Z
zKvt<ww4&!N`+Bh+J<r)EIgmzPVW09*sQ|axXYQQ)pX*`WV)~>WF|SZbxhr*YaTI5E
z4Ajm9!%#>4BXm<;;w<h=J;$X~J8tZWS0!L%^w{XwND?3R?44cik%CsRYBKFs|GRG3
zn%-VpkjkVoHx0i!Yw=0i?c7FV`rhb@b+dQtI}fx3!%%@wW6k49@|H@aA*%*Q1)T5l
z2CL>?@7v0jCP#lT8}D(v$MO4FtoK82j*aIk+F=h3YOPIRulgV-Na3b*bo>A*N-N5o
z=4qx`Wq%CzhhekX{xHQauZYice4gVy;<}ZW8H~biI6-gvjM#)lPEh0o30B$y%GL?P
znBC=zGdM@~Jc>SFT*3_5>zE~b2j|E>K;ir1F=oiV!mPhJVwYvJ=@Y110q02b4u$f?
o2h5QDh*`3qagOXa6q%?P!TXsgs!WGy#gmz#s<xgW_J`ikKQHOTvj6}9

diff --git a/tests/data/test-read-ctf/test0.abi b/tests/data/test-read-ctf/test0.abi
index 50ca26f4..fc61f2ac 100644
--- a/tests/data/test-read-ctf/test0.abi
+++ b/tests/data/test-read-ctf/test0.abi
@@ -39,16 +39,26 @@
     </array-type-def>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-10'/>
     <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='type-id-11'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='type-id-12'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-13'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-14'/>
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='type-id-15'/>
-    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-16'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
-    <qualified-type-def type-id='type-id-3' const='yes' id='type-id-18'/>
-    <pointer-type-def type-id='type-id-10' size-in-bits='64' alignment-in-bits='64' id='type-id-19'/>
-    <qualified-type-def type-id='type-id-19' restrict='yes' id='type-id-20'/>
-    <qualified-type-def type-id='type-id-11' volatile='yes' id='type-id-21'/>
+    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-12'/>
+    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-13'/>
+    <qualified-type-def type-id='type-id-3' const='yes' id='type-id-14'/>
+    <pointer-type-def type-id='type-id-10' size-in-bits='64' alignment-in-bits='64' id='type-id-15'/>
+    <qualified-type-def type-id='type-id-15' restrict='yes' id='type-id-16'/>
+    <qualified-type-def type-id='type-id-11' volatile='yes' id='type-id-17'/>
+    <var-decl name='status' type-id='type-id-5' mangled-name='status' visibility='default' elf-symbol-id='status'/>
+    <var-decl name='test_pointer' type-id='type-id-13' mangled-name='test_pointer' visibility='default' elf-symbol-id='test_pointer'/>
+    <var-decl name='test_const' type-id='type-id-14' mangled-name='test_const' visibility='default' elf-symbol-id='test_const'/>
+    <var-decl name='test_float' type-id='type-id-6' mangled-name='test_float' visibility='default' elf-symbol-id='test_float'/>
+    <function-decl name='foo_1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo_1'>
+      <parameter type-id='type-id-12'/>
+      <return type-id='type-id-4'/>
+    </function-decl>
+    <function-decl name='main' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='main'>
+      <return type-id='type-id-4'/>
+    </function-decl>
+    <var-decl name='test_array' type-id='type-id-7' mangled-name='test_array' visibility='default' elf-symbol-id='test_array'/>
+    <var-decl name='test_restrict' type-id='type-id-16' mangled-name='test_restrict' visibility='default' elf-symbol-id='test_restrict'/>
+    <var-decl name='test_volatile' type-id='type-id-17' mangled-name='test_volatile' visibility='default' elf-symbol-id='test_volatile'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test0.c b/tests/data/test-read-ctf/test0.c
index eb702312..fdefd57c 100644
--- a/tests/data/test-read-ctf/test0.c
+++ b/tests/data/test-read-ctf/test0.c
@@ -1,3 +1,9 @@
+/*
+ * ELF EXEC files must use -Wl,--ctf-variables -Bdynimic options
+ * to export an ABI and store CTF symbols information.
+ *
+ * ctf-gcc -gctf -Wl,--ctf-variables -Bdynamic test0.c -o test0
+ */
 
 #include <stdio.h>
 
diff --git a/tests/data/test-read-ctf/test0.hash.abi b/tests/data/test-read-ctf/test0.hash.abi
index b58520ab..eff32228 100644
--- a/tests/data/test-read-ctf/test0.hash.abi
+++ b/tests/data/test-read-ctf/test0.hash.abi
@@ -39,16 +39,26 @@
     </array-type-def>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='bd54fe1a'/>
     <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='a2185560'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='28577a57'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='002ac4a6'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='7359adad'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='8efea9e5'/>
     <pointer-type-def type-id='50d9a3fa' size-in-bits='64' alignment-in-bits='64' id='fd01f598'/>
     <pointer-type-def type-id='a84c031d' size-in-bits='64' alignment-in-bits='64' id='26a90f95'/>
     <qualified-type-def type-id='50d9a3fa' const='yes' id='0fb3b55d'/>
     <pointer-type-def type-id='bd54fe1a' size-in-bits='64' alignment-in-bits='64' id='3ccc2590'/>
     <qualified-type-def type-id='3ccc2590' restrict='yes' id='af4b1b38'/>
     <qualified-type-def type-id='a2185560' volatile='yes' id='ec67e496'/>
+    <var-decl name='status' type-id='e7f43f72' mangled-name='status' visibility='default' elf-symbol-id='status'/>
+    <var-decl name='test_pointer' type-id='26a90f95' mangled-name='test_pointer' visibility='default' elf-symbol-id='test_pointer'/>
+    <var-decl name='test_const' type-id='0fb3b55d' mangled-name='test_const' visibility='default' elf-symbol-id='test_const'/>
+    <var-decl name='test_float' type-id='a6c45d85' mangled-name='test_float' visibility='default' elf-symbol-id='test_float'/>
+    <function-decl name='foo_1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo_1'>
+      <parameter type-id='fd01f598'/>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <function-decl name='main' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='main'>
+      <return type-id='95e97e5e'/>
+    </function-decl>
+    <var-decl name='test_array' type-id='b7bd1749' mangled-name='test_array' visibility='default' elf-symbol-id='test_array'/>
+    <var-decl name='test_restrict' type-id='af4b1b38' mangled-name='test_restrict' visibility='default' elf-symbol-id='test_restrict'/>
+    <var-decl name='test_volatile' type-id='ec67e496' mangled-name='test_volatile' visibility='default' elf-symbol-id='test_volatile'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test1.so.abi b/tests/data/test-read-ctf/test1.so.abi
index 5b3caf63..416bd39d 100644
--- a/tests/data/test-read-ctf/test1.so.abi
+++ b/tests/data/test-read-ctf/test1.so.abi
@@ -16,8 +16,13 @@
     </enum-decl>
     <typedef-decl name='opaque_enum' type-id='type-id-4' id='type-id-3'/>
     <typedef-decl name='opaque_struct' type-id='type-id-2' id='type-id-5'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
-    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-3' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
+    <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
+    <function-decl name='fn' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fn'>
+      <parameter type-id='type-id-7'/>
+      <parameter type-id='type-id-6'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-8'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test1.so.hash.abi b/tests/data/test-read-ctf/test1.so.hash.abi
index 8019cb54..b3620e75 100644
--- a/tests/data/test-read-ctf/test1.so.hash.abi
+++ b/tests/data/test-read-ctf/test1.so.hash.abi
@@ -16,8 +16,13 @@
     </enum-decl>
     <typedef-decl name='opaque_enum' type-id='55763a91' id='99fcd3a5'/>
     <typedef-decl name='opaque_struct' type-id='6cde5052' id='dae69ca1'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='f0981eeb'/>
     <pointer-type-def type-id='99fcd3a5' size-in-bits='64' alignment-in-bits='64' id='0e0526e0'/>
     <pointer-type-def type-id='dae69ca1' size-in-bits='64' alignment-in-bits='64' id='3f6e71d0'/>
+    <function-decl name='fn' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='fn'>
+      <parameter type-id='3f6e71d0'/>
+      <parameter type-id='0e0526e0'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test2.so.abi b/tests/data/test-read-ctf/test2.so.abi
index eb6aff3e..67f802f9 100644
--- a/tests/data/test-read-ctf/test2.so.abi
+++ b/tests/data/test-read-ctf/test2.so.abi
@@ -20,6 +20,14 @@
     <qualified-type-def type-id='type-id-8' const='yes' id='type-id-9'/>
     <pointer-type-def type-id='type-id-9' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <pointer-type-def type-id='type-id-8' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
+      <parameter type-id='type-id-7'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='type-id-6'/>
+      <return type-id='type-id-8'/>
+    </function-decl>
     <type-decl name='void' id='type-id-8'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test2.so.hash.abi b/tests/data/test-read-ctf/test2.so.hash.abi
index 6e57333b..6bbf347e 100644
--- a/tests/data/test-read-ctf/test2.so.hash.abi
+++ b/tests/data/test-read-ctf/test2.so.hash.abi
@@ -20,6 +20,14 @@
     <qualified-type-def type-id='48b5725f' const='yes' id='8581546e'/>
     <pointer-type-def type-id='8581546e' size-in-bits='64' alignment-in-bits='64' id='6e97a70c'/>
     <pointer-type-def type-id='48b5725f' size-in-bits='64' alignment-in-bits='64' id='eaa32e2f'/>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
+      <parameter type-id='5e30a4f9'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='842ea234'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
     <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test3.so.abi b/tests/data/test-read-ctf/test3.so.abi
index 9d55fec5..3d2f6326 100644
--- a/tests/data/test-read-ctf/test3.so.abi
+++ b/tests/data/test-read-ctf/test3.so.abi
@@ -8,5 +8,9 @@
     <elf-symbol name='foo__' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
+    <function-decl name='__foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='__foo'>
+      <return type-id='type-id-1'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-1'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test3.so.hash.abi b/tests/data/test-read-ctf/test3.so.hash.abi
index 9d55fec5..1c69e2e1 100644
--- a/tests/data/test-read-ctf/test3.so.hash.abi
+++ b/tests/data/test-read-ctf/test3.so.hash.abi
@@ -8,5 +8,9 @@
     <elf-symbol name='foo__' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
+    <function-decl name='__foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='__foo'>
+      <return type-id='48b5725f'/>
+    </function-decl>
+    <type-decl name='void' id='48b5725f'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test4.so.abi b/tests/data/test-read-ctf/test4.so.abi
index b8e0ead3..dc18e191 100644
--- a/tests/data/test-read-ctf/test4.so.abi
+++ b/tests/data/test-read-ctf/test4.so.abi
@@ -10,5 +10,11 @@
     <qualified-type-def type-id='type-id-1' const='yes' id='type-id-5'/>
     <pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
     <qualified-type-def type-id='type-id-6' restrict='yes' id='type-id-7'/>
+    <function-decl name='cpy' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='cpy'>
+      <parameter type-id='type-id-4'/>
+      <parameter type-id='type-id-7'/>
+      <parameter type-id='type-id-2'/>
+      <return type-id='type-id-3'/>
+    </function-decl>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test4.so.hash.abi b/tests/data/test-read-ctf/test4.so.hash.abi
index dbe34d9c..dc428592 100644
--- a/tests/data/test-read-ctf/test4.so.hash.abi
+++ b/tests/data/test-read-ctf/test4.so.hash.abi
@@ -10,5 +10,11 @@
     <qualified-type-def type-id='a84c031d' const='yes' id='9b45d938'/>
     <pointer-type-def type-id='9b45d938' size-in-bits='64' alignment-in-bits='64' id='80f4b756'/>
     <qualified-type-def type-id='80f4b756' restrict='yes' id='9d26089a'/>
+    <function-decl name='cpy' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='cpy'>
+      <parameter type-id='266fe297'/>
+      <parameter type-id='9d26089a'/>
+      <parameter type-id='f0981eeb'/>
+      <return type-id='26a90f95'/>
+    </function-decl>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test5.o.abi b/tests/data/test-read-ctf/test5.o.abi
index eb30cf6a..f7bcdeb1 100644
--- a/tests/data/test-read-ctf/test5.o.abi
+++ b/tests/data/test-read-ctf/test5.o.abi
@@ -17,34 +17,32 @@
     <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-4'/>
     <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-5'/>
     <type-decl name='long long int' size-in-bits='64' alignment-in-bits='64' id='type-id-6'/>
-    <type-decl name='long long unsigned int' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <typedef-decl name='long_long' type-id='type-id-6' id='type-id-8'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-9'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-10'/>
-    <qualified-type-def type-id='type-id-4' const='yes' id='type-id-11'/>
-    <qualified-type-def type-id='type-id-5' const='yes' id='type-id-12'/>
-    <qualified-type-def type-id='type-id-12' volatile='yes' id='type-id-13'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-10'/>
-      <parameter type-id='type-id-13'/>
+    <typedef-decl name='long_long' type-id='type-id-6' id='type-id-7'/>
+    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <qualified-type-def type-id='type-id-4' const='yes' id='type-id-9'/>
+    <qualified-type-def type-id='type-id-5' const='yes' id='type-id-10'/>
+    <qualified-type-def type-id='type-id-10' volatile='yes' id='type-id-11'/>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
+      <parameter type-id='type-id-8'/>
+      <parameter type-id='type-id-11'/>
       <return type-id='type-id-5'/>
     </function-decl>
-    <function-decl name='baz2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='baz2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='baz2'>
       <parameter type-id='type-id-4'/>
-      <return type-id='type-id-8'/>
+      <return type-id='type-id-7'/>
     </function-decl>
-    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
       <parameter is-variadic='yes'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <function-decl name='bar2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar2' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar2'>
       <parameter type-id='type-id-3'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <function-decl name='baz' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='baz' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='baz'>
       <parameter type-id='type-id-4'/>
-      <return type-id='type-id-14'/>
+      <return type-id='type-id-12'/>
     </function-decl>
-    <type-decl name='void' id='type-id-14'/>
+    <type-decl name='void' id='type-id-12'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test7.o.abi b/tests/data/test-read-ctf/test7.o.abi
index b744fac5..a13af174 100644
--- a/tests/data/test-read-ctf/test7.o.abi
+++ b/tests/data/test-read-ctf/test7.o.abi
@@ -3,40 +3,31 @@
     <elf-symbol name='first_type_constructor' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
-    <type-decl name='char' size-in-bits='8' alignment-in-bits='8' id='type-id-1'/>
-    <class-decl name='first_type' size-in-bits='128' alignment-in-bits='32' is-struct='yes' visibility='default' id='type-id-2'>
+    <class-decl name='first_type' size-in-bits='128' alignment-in-bits='32' is-struct='yes' visibility='default' id='type-id-1'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='member0' type-id='type-id-3' visibility='default'/>
+        <var-decl name='member0' type-id='type-id-2' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='32'>
-        <var-decl name='member1' type-id='type-id-4' visibility='default'/>
+        <var-decl name='member1' type-id='type-id-3' visibility='default'/>
       </data-member>
       <data-member access='public' layout-offset-in-bits='64'>
-        <var-decl name='ctor' type-id='type-id-5' visibility='default'/>
+        <var-decl name='ctor' type-id='type-id-4' visibility='default'/>
       </data-member>
     </class-decl>
-    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-6'/>
-    <type-decl name='long int' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
-    <type-decl name='long long int' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
-    <type-decl name='long long unsigned int' size-in-bits='64' alignment-in-bits='64' id='type-id-9'/>
-    <type-decl name='short int' size-in-bits='16' alignment-in-bits='16' id='type-id-10'/>
-    <type-decl name='signed char' size-in-bits='8' alignment-in-bits='8' id='type-id-11'/>
-    <typedef-decl name='character' type-id='type-id-12' id='type-id-4'/>
-    <typedef-decl name='constructor' type-id='type-id-13' id='type-id-5'/>
-    <typedef-decl name='integer' type-id='type-id-6' id='type-id-3'/>
-    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-12'/>
-    <type-decl name='unsigned int' size-in-bits='32' alignment-in-bits='32' id='type-id-14'/>
-    <type-decl name='unsigned long int' size-in-bits='64' alignment-in-bits='64' id='type-id-15'/>
-    <type-decl name='unsigned short int' size-in-bits='16' alignment-in-bits='16' id='type-id-16'/>
-    <pointer-type-def type-id='type-id-2' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
-    <pointer-type-def type-id='type-id-18' size-in-bits='64' alignment-in-bits='64' id='type-id-13'/>
-    <function-decl name='first_type_constructor' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
-      <parameter type-id='type-id-17'/>
-      <return type-id='type-id-19'/>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
+    <typedef-decl name='character' type-id='type-id-6' id='type-id-3'/>
+    <typedef-decl name='constructor' type-id='type-id-7' id='type-id-4'/>
+    <typedef-decl name='integer' type-id='type-id-5' id='type-id-2'/>
+    <type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-6'/>
+    <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-9' size-in-bits='64' alignment-in-bits='64' id='type-id-7'/>
+    <function-decl name='first_type_constructor' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='first_type_constructor'>
+      <parameter type-id='type-id-8'/>
+      <return type-id='type-id-10'/>
     </function-decl>
-    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-18'>
-      <return type-id='type-id-19'/>
+    <function-type size-in-bits='64' alignment-in-bits='8' id='type-id-9'>
+      <return type-id='type-id-10'/>
     </function-type>
-    <type-decl name='void' id='type-id-19'/>
+    <type-decl name='void' id='type-id-10'/>
   </abi-instr>
 </abi-corpus>
diff --git a/tests/data/test-read-ctf/test8.o.abi b/tests/data/test-read-ctf/test8.o.abi
index 68b3af06..b6996c29 100644
--- a/tests/data/test-read-ctf/test8.o.abi
+++ b/tests/data/test-read-ctf/test8.o.abi
@@ -4,7 +4,7 @@
   </elf-function-symbols>
   <abi-instr address-size='64' language='LANG_C'>
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
-    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='bar' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='bar'>
       <parameter type-id='type-id-2'/>
       <return type-id='type-id-1'/>
     </function-decl>
diff --git a/tests/data/test-read-ctf/test9.o.abi b/tests/data/test-read-ctf/test9.o.abi
index 746dd77b..08704d79 100644
--- a/tests/data/test-read-ctf/test9.o.abi
+++ b/tests/data/test-read-ctf/test9.o.abi
@@ -49,7 +49,7 @@
     <pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-2'/>
     <pointer-type-def type-id='type-id-16' size-in-bits='64' alignment-in-bits='64' id='type-id-17'/>
     <pointer-type-def type-id='type-id-18' size-in-bits='64' alignment-in-bits='64' id='type-id-20'/>
-    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8'>
+    <function-decl name='foo' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='8' elf-symbol-id='foo'>
       <parameter type-id='type-id-22'/>
       <return type-id='type-id-16'/>
     </function-decl>
diff --git a/tests/test-read-ctf.cc b/tests/test-read-ctf.cc
index fdf49e90..215ed8d6 100644
--- a/tests/test-read-ctf.cc
+++ b/tests/test-read-ctf.cc
@@ -269,20 +269,28 @@ static InOutSpec in_out_specs[] =
     "output/test-read-ctf/test-list-struct.abi",
   },
   {
-    "data/test-read-ctf/test-callback2.o",
+    "data/test-read-common/test-PR26568-1.o",
     "",
     "",
     SEQUENCE_TYPE_ID_STYLE,
-    "data/test-read-ctf/test-callback2.abi",
-    "output/test-read-ctf/test-callback2.abi",
+    "data/test-read-ctf/test-PR26568-1.o.abi",
+    "output/test-read-ctf/test-PR26568-1.o.abi",
   },
   {
-    "data/test-read-ctf/test-forward-undefine-type-decl.o",
+    "data/test-read-common/test-PR26568-2.o",
     "",
     "",
     SEQUENCE_TYPE_ID_STYLE,
-    "data/test-read-ctf/test-forward-undefine-type-decl.abi",
-    "output/test-read-ctf/test-forward-undefine-type-decl.abi",
+    "data/test-read-ctf/test-PR26568-2.o.abi",
+    "output/test-read-ctf/test-PR26568-2.o.abi",
+  },
+  {
+    "data/test-read-ctf/test-callback2.o",
+    "",
+    "",
+    SEQUENCE_TYPE_ID_STYLE,
+    "data/test-read-ctf/test-callback2.abi",
+    "output/test-read-ctf/test-callback2.abi",
   },
   // This should be the last entry.
   {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
diff --git a/tools/abidw.cc b/tools/abidw.cc
index f7a8937d..32d055f5 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -811,13 +811,18 @@ load_kernel_corpus_group_and_write_abixml(char* argv[],
 
   global_timer.start();
   t.start();
+corpus::origin origin =
+#ifdef WITH_CTF
+    opts.use_ctf ? corpus::CTF_ORIGIN :
+#endif
+    corpus::DWARF_ORIGIN;
   corpus_group_sptr group =
     build_corpus_group_from_kernel_dist_under(opts.in_file_path,
 					      /*debug_info_root=*/"",
 					      opts.vmlinux,
 					      opts.suppression_paths,
 					      opts.kabi_whitelist_paths,
-					      supprs, opts.do_log, env);
+					      supprs, opts.do_log, env, origin);
   t.stop();
 
   if (opts.do_log)
-- 
2.35.0.rc2

Cheers,



-- 
		Dodji

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3] ctf-reader: Add support to read CTF information from Linux kernel
  2022-05-12 16:51       ` Dodji Seketeli
@ 2022-05-16 16:03         ` Guillermo E. Martinez
  0 siblings, 0 replies; 10+ messages in thread
From: Guillermo E. Martinez @ 2022-05-16 16:03 UTC (permalink / raw)
  To: Guillermo E. Martinez via Libabigail, Dodji Seketeli

On Thursday, May 12, 2022 11:51:08 AM CDT Dodji Seketeli wrote:

> Hello Guillermo,
Hello Dodji
 
> "Guillermo E. Martinez via Libabigail" <libabigail@sourceware.org> a
> écrit:
> 
> So, I have applied the patch to the master branch, thanks!
> 
> I made some few cosmetic changes, though.
> 
> So please read the comments about the changes I made belows.
> 
> 
> [...]
> 
> > diff --git a/include/abg-corpus.h b/include/abg-corpus.h
> > index 652a8294..690edba5 100644
> > --- a/include/abg-corpus.h
> > +++ b/include/abg-corpus.h
> > @@ -44,10 +44,10 @@ public:
> >    enum origin
> >    {
> >      ARTIFICIAL_ORIGIN = 0,
> > -    NATIVE_XML_ORIGIN,
> > -    DWARF_ORIGIN,
> > -    CTF_ORIGIN,
> > -    LINUX_KERNEL_BINARY_ORIGIN
> > +    NATIVE_XML_ORIGIN = 1,
> > +    DWARF_ORIGIN      = 1 << 1,
> > +    CTF_ORIGIN        = 1 << 2,
> > +    LINUX_KERNEL_BINARY_ORIGIN = 1 << 3
> >    };
> >  
> >  private:
> > @@ -115,11 +115,11 @@ public:
> >    corpus_group*
> >    get_group();
> >  
> > -  origin
> > +  uint32_t
> >    get_origin() const;
> >  
> >    void
> > -  set_origin(origin);
> > +  set_origin(uint32_t);
> >  
> >    string&
> >    get_format_major_version_number() const;
> 
> These corpus::{get_origin, set_origin} accessors should return/take a
> corpus::origin type, for the sake of having a strongly typed system.
> But I think I understand why you changed them to return/take a
> corpus::origin.  It's because of ...
> 
> [...]
> 
> diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
> index 2c6839cb..030f8fc8 100644
> --- a/src/abg-ctf-reader.cc
> +++ b/src/abg-ctf-reader.cc
> 
> [...]
> 
> -  /* Set some properties of the corpus first.  */
> -  corp->set_origin(corpus::CTF_ORIGIN);
> -  if (!slurp_elf_info(ctxt, corp))
> +  bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
> +  uint32_t origin = corpus::CTF_ORIGIN;
> +
> +  if (is_linux_kernel)
> +    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
> 
> ... this, right?
Yes, it is correct, because we can use the corpus::{get_origin, set_origin}
with oring corpus::origin values.

> I think the C++ compiler wasn't happy by the fact that "origin" is set
> to the result of the |= operator, which returns an integer, by
> default, right?
That's right!

> In that case, you need to declare a new '|=' operator that takes two
> corpus::origin operands and return a corpus::origin.  That way, that
> line can just compile fine.
> 
> I did just that for you. That is, in abg-corpus.h, I declared these:
> 
>     corpus::origin
>     operator|(corpus::origin l, corpus::origin r);
> 
>     corpus::origin
>     operator|=(corpus::origin &l, corpus::origin r);
> 
>     corpus::origin
>     operator&(corpus::origin l, corpus::origin r);
> 
>     corpus::origin
>     operator&=(corpus::origin &l, corpus::origin r);
> 
> These are defined in abg-corpus.cc, so things should just work as
> intended, hopefully.
it's more elegant. thanks!

> [...]
> 
> diff --git a/src/abg-corpus-priv.h b/src/abg-corpus-priv.h
> index 778e3365..28fd1d9b 100644
> --- a/src/abg-corpus-priv.h
> +++ b/src/abg-corpus-priv.h
> @@ -670,7 +670,7 @@ struct corpus::priv
>    environment*					env;
>    corpus_group*				group;
>    corpus::exported_decls_builder_sptr		exported_decls_builder;
> -  origin					origin_;
> +  uint32_t					origin_;
> 
> I reverted this change as per what I said above.
> 
> [...]
> 
> diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
> index a517f384..94f2268c 100644
> --- a/src/abg-corpus.cc
> +++ b/src/abg-corpus.cc
> @@ -851,7 +851,7 @@ corpus::init_format_version()
>  /// Getter for the origin of the corpus.
>  ///
>  /// @return the origin of the corpus.
> -corpus::origin
> +uint32_t
>  corpus::get_origin() const
>  {return priv_->origin_;}
>  
> @@ -859,7 +859,7 @@ corpus::get_origin() const
>  ///
>  /// @param o the new origin for the corpus.
>  void
> -corpus::set_origin(origin o)
> +corpus::set_origin(uint32_t o)
>  {priv_->origin_ = o;}
> 
> Likewise.
> 
> [...]
> 
> diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
> index 2c6839cb..030f8fc8 100644
> --- a/src/abg-ctf-reader.cc
> +++ b/src/abg-ctf-reader.cc
> @@ -16,6 +16,8 @@
>  #include <fcntl.h> /* For open(3) */
>  #include <iostream>
>  #include <memory>
> +#include <map>
> +#include <algorithm>
>  
>  #include "ctf-api.h"
>  
> @@ -58,13 +60,19 @@ public:
>  
>    /// A map associating CTF type ids with libabigail IR types.  This
>    /// is used to reuse already generated types.
> -  unordered_map<ctf_id_t,type_base_sptr> types_map;
> +  std::map<std::string,type_base_sptr> types_map;
> 
> Any reason why don't use
>     unordered_map<string, type_base_sptr> types_map ?
> 
> I am asking just because an unordered_map is much faster than just a
> map.
oohh, let then change it for a unordered_map, thanks !.
> There is nothing wrong, though, with using a map.
> 
> [...]
> 
>    /// Associate a given CTF type ID with a given libabigail IR type.
> -  void add_type(ctf_id_t ctf_type, type_base_sptr type)
> +  void add_type(ctf_dict_t *dic, ctf_id_t ctf_type, type_base_sptr type)
>    {
> 
> I have added a doxygen description for the function parameters.
> 
> I have also added a newline between the return type (void) and the
> function name, to comply with the rest of the project.  I did so with
> a few other member function definitions in there as well.
> 
> [...]
> 
>    /// Lookup a given CTF type ID in the types map.
>    ///
>    /// @param ctf_type the type ID of the type to lookup.
> -  type_base_sptr lookup_type(ctf_id_t ctf_type)
> +  type_base_sptr lookup_type(ctf_dict_t *dic, ctf_id_t ctf_type)
>    {
> 
> Likewise.
> 
> 
> Please find below the patch that I committed.
> [...]

It looks much better!
Thanks so much Dodji!




^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2022-05-16 16:03 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-30 15:35 [PATCH] ctf-reader: Add support to read CTF information from Linux kernel Guillermo E. Martinez
2022-04-04 22:49 ` Guillermo Martinez
2022-04-29 14:16 ` [PATCH v2] " Guillermo E. Martinez
2022-05-03 15:32   ` Dodji Seketeli
2022-05-04 12:48     ` Guillermo E. Martinez
2022-05-12  8:50       ` Dodji Seketeli
2022-05-04 22:29     ` [PATCH v3] " Guillermo E. Martinez
2022-05-12 16:51       ` Dodji Seketeli
2022-05-16 16:03         ` Guillermo E. Martinez
2022-05-13  7:18       ` Dodji Seketeli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).