Initial support of de-serializing the KMI of a Linux Kernel Tree
authorDodji Seketeli <dodji@redhat.com>
Fri, 7 Apr 2017 21:06:14 +0000 (23:06 +0200)
committerDodji Seketeli <dodji@redhat.com>
Mon, 3 Jul 2017 15:45:41 +0000 (17:45 +0200)
With this patch, kmidiff knows how to compare a serialized
corpus_group that represents a Kernel Module Interface (a .kmi file)
against either another serialized .kmi file, or against a kernel tree.

The patch extends the abixml reader to make it parse an
'abi-corpus-group' element.  To do that, the patch modifies
read_corpus_from_input to make it be capable of parsing several
'abi-corpus' in a row.  That modified function is then used by a new
read_corpus_group_from_input, which is itself used by the new public
entry points read_corpus_group_from_native_xml_file and
read_corpus_group_from_native_xml.

With that read_corpus_group_from_native_xml_file building block
function, the kmidiff program is modified so that it can take either
two directory trees, two .kmi files or one directory tree and one .kmi
file.

* include/abg-libxml-utils.h (advance_to_next_sibling_element):
Declare new function.
* src/abg-libxml-utils.cc (go_to_next_sibling_element_or_stay)
(advance_to_next_sibling_element): Define new functions.
* include/abg-reader.h (read_corpus_group_from_input)
(read_corpus_group_from_native_xml)
(read_corpus_group_from_native_xml_file): Declare new functions.
* src/abg-reader.cc (read_context::m_corpus_group): New data
member.
(read_context::{get_corpus_group, set_corpus_group}): Define new
member functions.
(read_translation_unit_from_input): Cleanup logic.
(read_corpus_from_input): Don't assume that the document is
starting with an 'abi-corpus' element.  Support the mode where a
caller called the xmlTextReaderExpand function (and so we are
given an expanded xmlNodePtr) and the mode where we need to use
the xmlTextReader API to walk through the 'abi-corpus' element.
Also, if we are building a corpus group, do not clear what used to
be 'per-corpus' data.  That data must be shared by all the corpora
of a given abi-corpus-group.
(read_corpus_group_from_input, read_corpus_group_from_native_xml)
(read_corpus_group_from_native_xml_file): Define new functions.
* include/abg-tools-utils.h (FILE_TYPE_XML_CORPUS_GROUP): New
enumerator of the file_type enum.
* src/abg-tools-utils.cc (operator<<): In the overload for
file_type, add a case for the new FILE_TYPE_XML_CORPUS_GROUP.
(guess_file_type): Dectect abi-corpus-group xml element.
* tools/abidiff.cc (adjust_diff_context_for_kmidiff): Define new
static function.
(main): Adjust to handle the new FILE_TYPE_XML_CORPUS_GROUP.  That
is, compare two FILE_TYPE_XML_CORPUS_GROUP if they are present.
* tools/abilint.cc (main): Likewise.
* tools/kmidiff.cc (main): Detect that one of two .kmi files are
passed.  In that case, load the .kmi file(s), build a corpus_group
of it and use it in the comparison.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
doc/manuals/abidiff.rst
include/abg-libxml-utils.h
include/abg-reader.h
include/abg-tools-utils.h
src/abg-libxml-utils.cc
src/abg-reader.cc
src/abg-tools-utils.cc
tools/abidiff.cc
tools/abilint.cc
tools/kmidiff.cc

index 41bfd2075781a59d8f38f1bdbfa65503bba60f5b..a62d785a2bf37c222c41a13c9412f2bff75999f1 100644 (file)
@@ -8,6 +8,10 @@ abidiff compares the Application Binary Interfaces (ABI) of two shared
 libraries in `ELF`_ format.  It emits a meaningful report describing the
 differences between the two ABIs.
 
+This tool can also compare the textual representations of the ABI of
+two ELF binaries (as emitted by ``abidw``) or an ELF binary against a
+textual representation of another ELF binary.
+
 For a comprehensive ABI change report that includes changes about
 function and variable sub-types, the two input shared libraries must
 be accompanied with their debug information in `DWARF`_ format.
index a8e66a6cab30c663a99609d715f6d98e6014c4f3..f56e06e1d0862455069e752ad2a0d849d9ad6cdf 100644 (file)
@@ -86,6 +86,9 @@ int get_xml_node_depth(xmlNodePtr);
 #define CHAR_STR(xml_char_str) \
   reinterpret_cast<char*>(xml_char_str.get())
 
+xmlNodePtr
+advance_to_next_sibling_element(xmlNodePtr node);
+
 void
 escape_xml_string(const std::string& str,
                  std::string& escaped);
index e7d23f3f1e3ee7c95e4a7c60195c98a208379fa1..0551af2d1470a5a61f82ea9a002fe38a2f6d6a58 100644 (file)
@@ -85,6 +85,17 @@ read_corpus_from_native_xml_file(const string& path,
 corpus_sptr
 read_corpus_from_input(read_context& ctxt);
 
+corpus_group_sptr
+read_corpus_group_from_input(read_context& ctxt);
+
+corpus_group_sptr
+read_corpus_group_from_native_xml(std::istream* in,
+                                 environment*  env);
+
+corpus_group_sptr
+read_corpus_group_from_native_xml_file(const string& path,
+                                      environment*  env);
+
 void
 add_read_context_suppressions(read_context& ctxt,
                              const suppr::suppressions_type& supprs);
index 28289398a89d0e9b61e5b3a7842a8f0f782b64b0..703dd2aeff07776d809bad6b240208e129416efa 100644 (file)
@@ -149,9 +149,12 @@ enum file_type
   FILE_TYPE_ELF,
   /// An archive (AR) file.
   FILE_TYPE_AR,
-  // A native xml file format representing a corpus of one or several
-  // translation units.
+  // A native abixml file format representing a corpus of one or
+  // several translation units.
   FILE_TYPE_XML_CORPUS,
+  // A native abixml file format representing a corpus group of one or
+  // several corpora.
+  FILE_TYPE_XML_CORPUS_GROUP,
   // A zip file, possibly containing a corpus of one of several
   // translation units.
   FILE_TYPE_ZIP_CORPUS,
index 4673827f40b666fd1afedcbd4828ef570eb3e186..06f7bb3570380c939705ddc1b56d2dd30c50a262 100644 (file)
@@ -428,5 +428,41 @@ unescape_xml_comment(const std::string& str)
   return result;
 }
 
+/// Maybe get the next sibling element node of an XML node, or stay to the sam
+///
+/// If there is no next sibling xml element node, the function returns
+/// the initial node.
+///
+/// @param node the initial node to consider.
+///
+/// @return the next sibling node or the initial node @p node.
+static xmlNodePtr
+go_to_next_sibling_element_or_stay(xmlNodePtr node)
+{
+  xmlNodePtr n;
+  for (n = node; n; n = n->next)
+    {
+      if (n->type == XML_ELEMENT_NODE)
+       break;
+    }
+  return n ? n : node;
+}
+
+/// Get the next sibling element node of an XML node.
+///
+/// If there is no next sibling xml element node, the function returns nil.
+///
+/// @param node the XML node to consider.
+///
+/// @return the next sibling element node or nil.
+xmlNodePtr
+advance_to_next_sibling_element(xmlNodePtr node)
+{
+  xmlNodePtr n = go_to_next_sibling_element_or_stay(node->next);
+  if (n == 0 || n->type != XML_ELEMENT_NODE)
+    return 0;
+  return n;
+}
+
 }//end namespace xml
 }//end namespace abigail
index a3eca13d724e6725601cb5de3b4f7bd9232420df..f0c4f5d1bac1e44703c09118f02c401b58ed3071 100644 (file)
@@ -122,6 +122,7 @@ private:
   xmlNodePtr                                           m_corp_node;
   deque<shared_ptr<decl_base> >                        m_decls_stack;
   corpus_sptr                                          m_corpus;
+  corpus_group_sptr                                    m_corpus_group;
   corpus::exported_decls_builder*                      m_exported_decls_builder;
   suppr::suppressions_type                             m_supprs;
 
@@ -713,6 +714,27 @@ public:
   set_corpus(corpus_sptr c)
   {m_corpus = c;}
 
+  /// Getter of the current corpus group.
+  ///
+  /// @return the current corpus group.n
+  const corpus_group_sptr&
+  get_corpus_group() const
+  {return m_corpus_group;}
+
+  /// Getter of the current corpus group.
+  ///
+  /// @return the current corpus group.
+  corpus_group_sptr&
+  get_corpus_group()
+  {return m_corpus_group;}
+
+  /// Setter of the corpus_group
+  ///
+  /// @param group the new corpus group.
+  void
+  set_corpus_group(const corpus_group_sptr& group)
+  {m_corpus_group = group;}
+
   /// Getter for the object that determines if a given declaration
   /// ought to be put in the set of exported decls of the current
   /// corpus.
@@ -1455,8 +1477,8 @@ read_translation_unit_from_input(read_context&    ctxt)
 {
   translation_unit_sptr tu, nil;
 
-  xmlNodePtr node = 0;
-  if (!ctxt.get_corpus_node())
+  xmlNodePtr node = ctxt.get_corpus_node();
+  if (!node)
     {
       xml::reader_sptr reader = ctxt.get_reader();
       if (!reader)
@@ -1755,45 +1777,90 @@ read_corpus_from_input(read_context& ctxt)
   if (!reader)
     return nil;
 
-  // The document must start with the abi-corpus node.
-  int status = 1;
-  while (status == 1
-        && XML_READER_GET_NODE_TYPE(reader) != XML_READER_TYPE_ELEMENT)
-    status = advance_cursor (ctxt);
+  bool call_reader_next = false;
 
-  if (status != 1 || !xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
-                                  BAD_CAST("abi-corpus")))
-    return nil;
-
-  if (!ctxt.get_corpus())
+  xmlNodePtr node = ctxt.get_corpus_node();
+  if (!node)
     {
-      corpus_sptr c(new corpus(ctxt.get_environment(), ""));
-      ctxt.set_corpus(c);
+      // The document must start with the abi-corpus node.
+      int status = 1;
+      while (status == 1
+            && XML_READER_GET_NODE_TYPE(reader) != XML_READER_TYPE_ELEMENT)
+       status = advance_cursor (ctxt);
+
+      if (status != 1 || !xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
+                                      BAD_CAST("abi-corpus")))
+       return nil;
+
+      if (!ctxt.get_corpus())
+       {
+         corpus_sptr c(new corpus(ctxt.get_environment(), ""));
+         ctxt.set_corpus(c);
+       }
+
+      if (!ctxt.get_corpus_group())
+       ctxt.clear_per_corpus_data();
+
+      corpus& corp = *ctxt.get_corpus();
+      ctxt.set_exported_decls_builder(corp.get_exported_decls_builder().get());
+
+      xml::xml_char_sptr path_str = XML_READER_GET_ATTRIBUTE(reader, "path");
+      if (path_str)
+       corp.set_path(reinterpret_cast<char*>(path_str.get()));
+
+      xml::xml_char_sptr architecture_str =
+       XML_READER_GET_ATTRIBUTE(reader, "architecture");
+      if (architecture_str)
+       corp.set_architecture_name
+         (reinterpret_cast<char*>(architecture_str.get()));
+
+      xml::xml_char_sptr soname_str =
+       XML_READER_GET_ATTRIBUTE(reader, "soname");
+      if (soname_str)
+       corp.set_soname(reinterpret_cast<char*>(soname_str.get()));
+
+      node = xmlTextReaderExpand(reader.get());
+      if (!node)
+       return nil;
+
+      call_reader_next = true;
+
+      ctxt.set_corpus_node(node->children);
     }
+  else
+    {
+      if (!ctxt.get_corpus())
+       {
+         corpus_sptr c(new corpus(ctxt.get_environment(), ""));
+         ctxt.set_corpus(c);
+       }
 
-  ctxt.clear_per_corpus_data();
+      if (!ctxt.get_corpus_group())
+       ctxt.clear_per_corpus_data();
 
-  corpus& corp = *ctxt.get_corpus();
-  ctxt.set_exported_decls_builder(corp.get_exported_decls_builder().get());
+      corpus& corp = *ctxt.get_corpus();
+      ctxt.set_exported_decls_builder(corp.get_exported_decls_builder().get());
 
-  xml::xml_char_sptr path_str = XML_READER_GET_ATTRIBUTE(reader, "path");
-  if (path_str)
-    corp.set_path(reinterpret_cast<char*>(path_str.get()));
+      xml::xml_char_sptr path_str = XML_NODE_GET_ATTRIBUTE(node, "path");
+      if (path_str)
+       corp.set_path(reinterpret_cast<char*>(path_str.get()));
 
-  xml::xml_char_sptr architecture_str =
-    XML_READER_GET_ATTRIBUTE(reader, "architecture");
-  if (architecture_str)
-    corp.set_architecture_name(reinterpret_cast<char*>(architecture_str.get()));
+      xml::xml_char_sptr architecture_str =
+       XML_NODE_GET_ATTRIBUTE(node, "architecture");
+      if (architecture_str)
+       corp.set_architecture_name
+         (reinterpret_cast<char*>(architecture_str.get()));
 
-  xml::xml_char_sptr soname_str = XML_READER_GET_ATTRIBUTE(reader, "soname");
-  if (soname_str)
-    corp.set_soname(reinterpret_cast<char*>(soname_str.get()));
+      xml::xml_char_sptr soname_str =
+       XML_NODE_GET_ATTRIBUTE(node, "soname");
+      if (soname_str)
+       corp.set_soname(reinterpret_cast<char*>(soname_str.get()));
 
-  xmlNodePtr node = xmlTextReaderExpand(reader.get());
-  if (!node)
-    return nil;
+      ctxt.set_corpus_node(node->children);
+    }
+
+  corpus& corp = *ctxt.get_corpus();
 
-  ctxt.set_corpus_node(node->children);
   walk_xml_node_to_map_type_ids(ctxt, node);
 
   // Read the needed element
@@ -1837,13 +1904,125 @@ read_corpus_from_input(read_context& ctxt)
 
   corp.set_origin(corpus::NATIVE_XML_ORIGIN);
 
-  // This is the necessary counter-part of the xmlTextReaderExpand()
-  // call at the beginning of the function.
-  xmlTextReaderNext(reader.get());
+  if (call_reader_next)
+    {
+      // This is the necessary counter-part of the xmlTextReaderExpand()
+      // call at the beginning of the function.
+      xmlTextReaderNext(reader.get());
+    }
+  else
+    {
+      node = ctxt.get_corpus_node();
+      node = xml::advance_to_next_sibling_element(node);
+      if (!node)
+       {
+         node = ctxt.get_corpus_node();
+         node = xml::advance_to_next_sibling_element(node->parent);
+       }
+      ctxt.set_corpus_node(node);
+    }
 
   return ctxt.get_corpus();;
 }
 
+/// Parse the input XML document containing an ABI corpus group,
+/// represented by an 'abi-corpus-group' element node, associated to
+/// the current context.
+///
+/// @param ctxt the current input context.
+///
+/// @return the corpus group resulting from the parsing
+corpus_group_sptr
+read_corpus_group_from_input(read_context& ctxt)
+{
+  corpus_group_sptr nil;
+
+  xml::reader_sptr reader = ctxt.get_reader();
+  if (!reader)
+    return nil;
+
+  // The document must start with the abi-corpus-group node.
+  int status = 1;
+  while (status == 1
+        && XML_READER_GET_NODE_TYPE(reader) != XML_READER_TYPE_ELEMENT)
+    status = advance_cursor (ctxt);
+
+  if (status != 1 || !xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
+                                  BAD_CAST("abi-corpus-group")))
+    return nil;
+
+  if (!ctxt.get_corpus_group())
+    {
+      corpus_group_sptr g(new corpus_group(ctxt.get_environment(),
+                                          ctxt.get_path()));
+      ctxt.set_corpus_group(g);
+    }
+
+  corpus_group_sptr group = ctxt.get_corpus_group();
+  xml::xml_char_sptr path_str = XML_READER_GET_ATTRIBUTE(reader, "path");
+  if (path_str)
+    group->set_path(reinterpret_cast<char*>(path_str.get()));
+
+  xmlNodePtr node = xmlTextReaderExpand(reader.get());
+  if (!node)
+    return nil;
+
+  //node = xml::get_first_element_sibling_if_text(node->children);
+  node = xml::advance_to_next_sibling_element(node->children);
+  ctxt.set_corpus_node(node);
+
+  corpus_sptr corp;
+  while (corp = read_corpus_from_input(ctxt))
+    ctxt.get_corpus_group()->add_corpus(corp);
+
+  xmlTextReaderNext(reader.get());
+
+  return ctxt.get_corpus_group();
+}
+
+/// De-serialize an ABI corpus group from an input XML document which
+/// root node is 'abi-corpus-group'.
+///
+/// @param in the input stream to read the XML document from.
+///
+/// @param env the environment to use.  Note that the life time of
+/// this environment must be greater than the lifetime of the
+/// resulting corpus as the corpus uses resources that are allocated
+/// in the environment.
+///
+/// @return the resulting corpus group de-serialized from the parsing.
+/// This is non-null iff the parsing resulted in a valid corpus group.
+corpus_group_sptr
+read_corpus_group_from_native_xml(std::istream* in,
+                                 environment*  env)
+{
+  read_context_sptr read_ctxt = create_native_xml_read_context(in, env);
+  return read_corpus_group_from_input(*read_ctxt);
+}
+
+/// De-serialize an ABI corpus group from an XML document file which
+/// root node is 'abi-corpus-group'.
+///
+/// @param path the path to the input file to read the XML document
+/// from.
+///
+/// @param env the environment to use.  Note that the life time of
+/// this environment must be greater than the lifetime of the
+/// resulting corpus as the corpus uses resources that are allocated
+/// in the environment.
+///
+/// @return the resulting corpus group de-serialized from the parsing.
+/// This is non-null if the parsing successfully resulted in a corpus
+/// group.
+corpus_group_sptr
+read_corpus_group_from_native_xml_file(const string& path,
+                                      environment*  env)
+{
+    read_context_sptr read_ctxt = create_native_xml_read_context(path, env);
+    corpus_group_sptr group = read_corpus_group_from_input(*read_ctxt);
+    return group;
+}
+
 /// Parse an ABI instrumentation file (in XML format) at a given path.
 ///
 /// @param input_file a path to the file containing the xml document
@@ -5497,13 +5676,6 @@ create_native_xml_read_context(std::istream* in, environment* env)
   return result;
 }
 
-/// Read an ABI corpus from a given reading context.
-///
-/// @return the resulting ABI corpus.
-corpus_sptr
-read_corpus_from_native_xml(read_context& ctxt)
-{return read_corpus_from_input(ctxt);}
-
 /// De-serialize an ABI corpus from an input XML document which root
 /// node is 'abi-corpus'.
 ///
index dcb97540fc7becd3b84d62b3d4fcbe44a9ef18d2..6b45dafdc01476fed7cbfe6a8042c365110c1dd6 100644 (file)
@@ -708,6 +708,9 @@ operator<<(ostream& output,
     case FILE_TYPE_XML_CORPUS:
       repr = "native XML corpus file type";
       break;
+    case FILE_TYPE_XML_CORPUS_GROUP:
+      repr = "native XML corpus group file type";
+      break;
     case FILE_TYPE_ZIP_CORPUS:
       repr = "native ZIP corpus file type";
       break;
@@ -786,6 +789,26 @@ guess_file_type(istream& in)
       && buf[10] == ' ')
     return FILE_TYPE_NATIVE_BI;
 
+  if (buf[0]     == '<'
+      && buf[1]  == 'a'
+      && buf[2]  == 'b'
+      && buf[3]  == 'i'
+      && buf[4]  == '-'
+      && buf[5]  == 'c'
+      && buf[6]  == 'o'
+      && buf[7]  == 'r'
+      && buf[8]  == 'p'
+      && buf[9]  == 'u'
+      && buf[10] == 's'
+      && buf[11] == '-'
+      && buf[12] == 'g'
+      && buf[13] == 'r'
+      && buf[14] == 'o'
+      && buf[15] == 'u'
+      && buf[16] == 'p'
+      && buf[17] == ' ')
+    return FILE_TYPE_XML_CORPUS_GROUP;
+
   if (buf[0]     == '<'
       && buf[1]  == 'a'
       && buf[2]  == 'b'
index 5c0204db4338627a7cb2cc824a65f5c662703bce..f9d048158796fa5a56ed0eef477f3d5b01ef0be3 100644 (file)
@@ -44,6 +44,7 @@ using abigail::ir::environment_sptr;
 using abigail::translation_unit;
 using abigail::translation_unit_sptr;
 using abigail::corpus_sptr;
+using abigail::corpus_group_sptr;
 using abigail::comparison::translation_unit_diff_sptr;
 using abigail::comparison::corpus_diff;
 using abigail::comparison::corpus_diff_sptr;
@@ -752,6 +753,20 @@ set_corpus_keep_drop_regex_patterns(options& opts, corpus_sptr c)
     }
 }
 
+/// This function sets diff context options that are specific to
+/// kernel module interface comparison.
+///
+/// @param ctxt the diff context to consider.
+static void
+adjust_diff_context_for_kmidiff(diff_context_sptr &ctxt)
+{
+  ctxt->show_linkage_names(false);
+  ctxt->show_added_fns(false);
+  ctxt->show_added_vars(false);
+  ctxt->show_added_symbols_unreferenced_by_debug_info
+    (false);
+}
+
 int
 main(int argc, char* argv[])
 {
@@ -828,6 +843,7 @@ main(int argc, char* argv[])
        abigail::dwarf_reader::STATUS_OK,
        c2_status = abigail::dwarf_reader::STATUS_OK;
       corpus_sptr c1, c2;
+      corpus_group_sptr g1, g2;
       char *di_dir1 = 0, *di_dir2 = 0;
       bool files_suppressed = false;
 
@@ -881,18 +897,28 @@ main(int argc, char* argv[])
            c1 = abigail::xml_reader::read_corpus_from_input(*ctxt);
          }
          break;
+       case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
+         {
+           abigail::xml_reader::read_context_sptr ctxt =
+             abigail::xml_reader::create_native_xml_read_context(opts.file1,
+                                                                 env.get());
+           assert(ctxt);
+           set_suppressions(*ctxt, opts);
+           g1 = abigail::xml_reader::read_corpus_group_from_input(*ctxt);
+         }
+         break;
        case abigail::tools_utils::FILE_TYPE_ZIP_CORPUS:
 #ifdef WITH_ZIP_ARCHIVE
          c1 = abigail::xml_reader::read_corpus_from_file(opts.file1);
 #endif //WITH_ZIP_ARCHIVE
-          break;
-        case abigail::tools_utils::FILE_TYPE_RPM:
-        case abigail::tools_utils::FILE_TYPE_SRPM:
-        case abigail::tools_utils::FILE_TYPE_DEB:
-        case abigail::tools_utils::FILE_TYPE_DIR:
-        case abigail::tools_utils::FILE_TYPE_TAR:
-          break;
-        }
+         break;
+       case abigail::tools_utils::FILE_TYPE_RPM:
+       case abigail::tools_utils::FILE_TYPE_SRPM:
+       case abigail::tools_utils::FILE_TYPE_DEB:
+       case abigail::tools_utils::FILE_TYPE_DIR:
+       case abigail::tools_utils::FILE_TYPE_TAR:
+         break;
+       }
 
       switch (t2_type)
        {
@@ -932,20 +958,30 @@ main(int argc, char* argv[])
            c2 = abigail::xml_reader::read_corpus_from_input(*ctxt);
          }
          break;
+       case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
+         {
+           abigail::xml_reader::read_context_sptr ctxt =
+             abigail::xml_reader::create_native_xml_read_context(opts.file2,
+                                                                 env.get());
+           assert(ctxt);
+           set_suppressions(*ctxt, opts);
+           g2 = abigail::xml_reader::read_corpus_group_from_input(*ctxt);
+         }
+         break;
        case abigail::tools_utils::FILE_TYPE_ZIP_CORPUS:
 #ifdef WITH_ZIP_ARCHIVE
          c2 = abigail::xml_reader::read_corpus_from_file(opts.file2);
 #endif //WITH_ZIP_ARCHIVE
-          break;
-        case abigail::tools_utils::FILE_TYPE_RPM:
-        case abigail::tools_utils::FILE_TYPE_SRPM:
-        case abigail::tools_utils::FILE_TYPE_DEB:
-        case abigail::tools_utils::FILE_TYPE_DIR:
-        case abigail::tools_utils::FILE_TYPE_TAR:
-          break;
-        }
-
-      if (!t1 && !c1)
+         break;
+       case abigail::tools_utils::FILE_TYPE_RPM:
+       case abigail::tools_utils::FILE_TYPE_SRPM:
+       case abigail::tools_utils::FILE_TYPE_DEB:
+       case abigail::tools_utils::FILE_TYPE_DIR:
+       case abigail::tools_utils::FILE_TYPE_TAR:
+         break;
+       }
+
+      if (!t1 && !c1 && !g1)
        {
          emit_prefix(argv[0], cerr)
            << "failed to read input file " << opts.file1 << "\n";
@@ -977,7 +1013,7 @@ main(int argc, char* argv[])
            }
        }
 
-      if (!t2 && !c2)
+      if (!t2 && !c2 && !g2)
        {
          emit_prefix(argv[0],  cerr)
            << "failed to read input file " << opts.file2 << "\n";
@@ -1010,7 +1046,8 @@ main(int argc, char* argv[])
        }
 
       if (!!c1 != !!c2
-         || !!t1 != !!t2)
+         || !!t1 != !!t2
+         || !!g1 != !!g2)
        {
          emit_prefix(argv[0], cerr)
            << "the two input should be of the same kind\n";
@@ -1061,6 +1098,27 @@ main(int argc, char* argv[])
          if (diff->has_changes())
            diff->report(cout);
        }
+      else if (g1)
+       {
+         if (opts.show_symtabs)
+           {
+             display_symtabs(c1, c2, cout);
+             return abigail::tools_utils::ABIDIFF_OK;
+           }
+
+         adjust_diff_context_for_kmidiff(ctxt);
+         corpus_diff_sptr diff = compute_diff(g1, g2, ctxt);
+
+         if (diff->has_net_changes())
+           status = abigail::tools_utils::ABIDIFF_ABI_CHANGE;
+
+         if (diff->has_incompatible_changes())
+           status |= abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE;
+
+         if (diff->has_changes())
+           diff->report(cout);
+
+       }
       else
        status = abigail::tools_utils::ABIDIFF_ERROR;
     }
index 50c135022699498f53ecf756f4b57748acfadd4f..acfaa8daae0b0ab73ca4aed240f8d9acfc1a3ff5 100644 (file)
@@ -351,18 +351,20 @@ main(int argc, char* argv[])
 #if WITH_ZIP_ARCHIVE
          corp = read_corpus_from_file(opts.file_path);
 #endif
-          break;
-        case abigail::tools_utils::FILE_TYPE_RPM:
-          break;
-        case abigail::tools_utils::FILE_TYPE_SRPM:
-          break;
-        case abigail::tools_utils::FILE_TYPE_DEB:
-          break;
-        case abigail::tools_utils::FILE_TYPE_DIR:
-          break;
-        case abigail::tools_utils::FILE_TYPE_TAR:
-          break;
-        }
+         break;
+       case abigail::tools_utils::FILE_TYPE_RPM:
+         break;
+       case abigail::tools_utils::FILE_TYPE_SRPM:
+         break;
+       case abigail::tools_utils::FILE_TYPE_DEB:
+         break;
+       case abigail::tools_utils::FILE_TYPE_DIR:
+         break;
+       case abigail::tools_utils::FILE_TYPE_TAR:
+         break;
+       case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
+         break;
+       }
 
       if (!tu && !corp)
        {
index 2940636cb52c5bdb44c61bb8891e1fecb8e1655e..69e0d1f393d8c4e977e8508ed68abcf0153148ab 100644 (file)
@@ -36,6 +36,7 @@
 #include "abg-tools-utils.h"
 #include "abg-corpus.h"
 #include "abg-dwarf-reader.h"
+#include "abg-reader.h"
 #include "abg-comparison.h"
 
 using std::string;
@@ -58,6 +59,9 @@ using abigail::suppr::suppression_sptr;
 using abigail::suppr::suppressions_type;
 using abigail::suppr::read_suppressions;
 using abigail::tools_utils::gen_suppr_spec_from_kernel_abi_whitelist;
+using abigail::tools_utils::guess_file_type;
+using abigail::tools_utils::file_type;
+using abigail::xml_reader::read_corpus_group_from_native_xml_file;
 
 /// The options of this program.
 struct options
@@ -312,26 +316,43 @@ main(int argc, char* argv[])
   corpus_group_sptr group1, group2;
   if (!opts.kernel_dist_root1.empty())
     {
-      group1 =
-       build_corpus_group_from_kernel_dist_under(opts.kernel_dist_root1,
-                                                 opts.suppression_paths,
-                                                 opts.kabi_whitelist_paths,
-                                                 opts.read_time_supprs,
-                                                 opts.verbose,
-                                                 env);
-      print_kernel_dist_binary_paths_under(opts.kernel_dist_root1, opts);
+      file_type ftype = guess_file_type(opts.kernel_dist_root1);
+      if (ftype == FILE_TYPE_DIR)
+       {
+         group1 =
+           build_corpus_group_from_kernel_dist_under(opts.kernel_dist_root1,
+                                                     opts.suppression_paths,
+                                                     opts.kabi_whitelist_paths,
+                                                     opts.read_time_supprs,
+                                                     opts.verbose,
+                                                     env);
+         print_kernel_dist_binary_paths_under(opts.kernel_dist_root1, opts);
+       }
+      else if (ftype == FILE_TYPE_XML_CORPUS_GROUP)
+       group1 =
+         read_corpus_group_from_native_xml_file(opts.kernel_dist_root1,
+                                                env.get());
+
     }
 
   if (!opts.kernel_dist_root2.empty())
     {
-      group2 =
-       build_corpus_group_from_kernel_dist_under(opts.kernel_dist_root2,
-                                                 opts.suppression_paths,
-                                                 opts.kabi_whitelist_paths,
-                                                 opts.read_time_supprs,
-                                                 opts.verbose,
-                                                 env);
-      print_kernel_dist_binary_paths_under(opts.kernel_dist_root2, opts);
+      file_type ftype = guess_file_type(opts.kernel_dist_root2);
+      if (ftype == FILE_TYPE_DIR)
+       {
+         group2 =
+           build_corpus_group_from_kernel_dist_under(opts.kernel_dist_root2,
+                                                     opts.suppression_paths,
+                                                     opts.kabi_whitelist_paths,
+                                                     opts.read_time_supprs,
+                                                     opts.verbose,
+                                                     env);
+         print_kernel_dist_binary_paths_under(opts.kernel_dist_root2, opts);
+       }
+      else if (ftype == FILE_TYPE_XML_CORPUS_GROUP)
+       group2 =
+         read_corpus_group_from_native_xml_file(opts.kernel_dist_root2,
+                                                env.get());
     }
 
   abidiff_status status = abigail::tools_utils::ABIDIFF_OK;