Support having several debuginfo search dirs for a binary
authorDodji Seketeli <dodji@redhat.com>
Thu, 8 Nov 2018 06:26:14 +0000 (07:26 +0100)
committerDodji Seketeli <dodji@redhat.com>
Thu, 8 Nov 2018 08:03:32 +0000 (09:03 +0100)
There are use cases where the split debuginfo file of a given binary
is under a given root directory and that the split debuginfo file
itself depends on an alternate debuginfo file that is under another
unrelated root directory.

In that case, the dwarf reader must be able to look for the debuginfo
files under several unrelated root directories.  The tools abidiff and
abidw must thus support having several occurences of the option
--debug-info-dir1 (or --debug-info-dir2) meaning that the debuginfo
files for the binary must be looked for under several root
directories.

This is what this patch does.

* doc/manuals/abidiff.rst: Adjust doc for the
--debug-info-dir{1,2} that can now be provided several times.
* include/abg-dwarf-reader.h ({create, reset}_read_context)
(read_corpus_from_elf): Take a vector of debug info root dirs.
* include/abg-tools-utils.h (trim_leading_string)
(find_file_under_dir, make_path_absolute_to_be_freed)
(convert_char_stars_to_char_star_stars): Declare new functions.
* src/abg-dwarf-reader.cc (find_alt_debug_info_link): Renamed
find_alt_debug_info_location into this.
(find_alt_debug_info_path): Define new static function.
(find_alt_debug_info): Take a vector of debug info root dirs.  Use
the new find_alt_debug_info_path to look into the debug info root
dirs for the alt debug info.
(read_context::debug_info_root_paths_): Define new data member.
(read_context::read_context): Take a vector of debug info root
dirs and initialize the new read_context::debug_info_root_paths_.
(read_context::{initialize, create_default_dwfl}): Take a vector
of debug info root dirs and adjust.
(read_context::{add_debug_info_root_paths,
add_debug_info_root_path, find_alt_debug_info}): Define new member
functions.
(read_context::load_debug_info): Look into the debug info roots
for split debug info files.
(create_read_context, read_corpus_from_elf): Take a vector of
debug info root dirs and adjust.
(has_alt_debug_info): Adjust.
* src/abg-tools-utils.cc (trim_leading_string)
(make_path_absolute_to_be_freed, find_file_under_dir)
(convert_char_stars_to_char_star_stars): Define new functions.
(entry_of_file_with_name): Define new static function.
(build_corpus_group_from_kernel_dist_under): Adjust.
* tests/print-diff-tree.cc (main): Adjust.
* tests/test-diff-dwarf.cc (main): Adjust.
* tests/test-ir-walker.cc (main): Adjust.
* tests/test-read-dwarf.cc (main): Adjust.
* tools/abicompat.cc (main): Adjust.
* tools/abidiff.cc (options::di_root_paths{1,2}): Changed
di_root_path{1,2} into this, change their types into vectors of
allocated char*.
(options::prepared_di_root_paths{1,2}): Define new data members.
(options::~options): Define new destructor.
(parse_command_line): Adjust.
(prepare_di_root_paths): Define new static function.
(handle_error): Remove arguments input_file_name,
debug_info_dir{1,2}.  Now just take an instance of options
instead.  Adjust.
(main): Adjust.
* tools/abidw.cc (options::dir_root_paths): Renamed dir_root_path
into this and make it be a vector of allocated char*.
(options::prepared_di_root_paths): Define new data member.
(options::~options): Free the allocated char* in
options::dir_root_paths.
(parse_command_line): Support several --debug-info-dir.
(load_corpus_and_write_abixml): Adjust.
(prepare_di_root_paths): Define static function.
(main): Adjust.
* tools/abilint.cc (main): Adjust.
* tools/abipkgdiff.cc (compare): Adjust.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
15 files changed:
doc/manuals/abidiff.rst
doc/manuals/abidw.rst
include/abg-dwarf-reader.h
include/abg-tools-utils.h
src/abg-dwarf-reader.cc
src/abg-tools-utils.cc
tests/print-diff-tree.cc
tests/test-diff-dwarf.cc
tests/test-ir-walker.cc
tests/test-read-dwarf.cc
tools/abicompat.cc
tools/abidiff.cc
tools/abidw.cc
tools/abilint.cc
tools/abipkgdiff.cc

index 150fbfe..b498161 100644 (file)
@@ -78,6 +78,11 @@ Options
     Red Hat based systems, that directory is usually
     ``<root>/usr/lib/debug``.
 
+    This option can be provided several times with different root
+    directories.  In that case, ``abidiff`` will potentially look into
+    all those root directories to find the split debug info for
+    *first-shared-library*.
+
     Note also that this option is not mandatory for split debug
     information installed by your system's package manager because
     then ``abidiff`` knows where to find it.
@@ -88,6 +93,11 @@ Options
     to find the split debug information for the
     *second-shared-library* file.
 
+    This option can be provided several times with different root
+    directories.  In that case, ``abidiff`` will potentially look into
+    all those root directories to find the split debug info for
+    *second-shared-library*.
+
   * ``--headers-dir1 | --hd1`` <headers-directory-path-1>
 
     Specifies where to find the public headers of the first shared
index c1b740b..4843d00 100644 (file)
@@ -50,6 +50,11 @@ Options
     Red Hat based systems, that directory is usually
     ``<root>/usr/lib/debug``.
 
+    This option can be provided several times with different root
+    directories.  In that case, ``abidw`` will potentially look into
+    all those root directories to find the split debug info for the
+    elf file.
+
     Note that this option is not mandatory for split debug information
     installed by your system's package manager because then
     ``abidw`` knows where to find it.
index a0f85aa..aa3826d 100644 (file)
@@ -102,7 +102,7 @@ typedef shared_ptr<read_context> read_context_sptr;
 
 read_context_sptr
 create_read_context(const std::string& elf_path,
-                   char**              debug_info_root_path,
+                   const vector<char**>& debug_info_root_paths,
                    ir::environment*    environment,
                    bool                read_all_types = false,
                    bool                linux_kernel_mode = false);
@@ -110,10 +110,10 @@ create_read_context(const std::string&    elf_path,
 void
 reset_read_context(read_context_sptr &ctxt,
                   const std::string&   elf_path,
-                   char**              debug_info_root_path,
-                   ir::environment*    environment,
-                   bool                read_all_types = false,
-                   bool                linux_kernel_mode = false);
+                  const vector<char**>& debug_info_root_paths,
+                  ir::environment*     environment,
+                  bool         read_all_types = false,
+                  bool         linux_kernel_mode = false);
 
 void
 add_read_context_suppressions(read_context& ctxt,
@@ -127,7 +127,7 @@ read_corpus_from_elf(read_context& ctxt, status& stat);
 
 corpus_sptr
 read_corpus_from_elf(const std::string& elf_path,
-                    char**             debug_info_root_path,
+                    const vector<char**>& debug_info_root_paths,
                     ir::environment*   environment,
                     bool               load_all_types,
                     status&);
index d5b291a..8a96189 100644 (file)
@@ -72,6 +72,9 @@ bool execute_command_and_get_output(const string&, vector<string>&);
 bool get_dsos_provided_by_rpm(const string& rpm_path,
                              set<string>& provided_dsos);
 string trim_white_space(const string&);
+string trim_leading_string(const string& from, const string& to_trim);
+void convert_char_stars_to_char_star_stars(const vector<char*>&,
+                                          vector<char**>&);
 suppr::type_suppression_sptr
 gen_suppr_spec_from_headers(const string& hdrs_root_dir);
 
@@ -106,6 +109,11 @@ load_default_system_suppressions(suppr::suppressions_type&);
 void
 load_default_user_suppressions(suppr::suppressions_type&);
 
+bool
+find_file_under_dir(const string& root_dir,
+                   const string& file_path_to_look_for,
+                   string& result);
+
 class temp_file;
 
 /// Convenience typedef for a shared_ptr to @ref temp_file.
@@ -265,6 +273,9 @@ file_is_kernel_debuginfo_package(const string& file_path,
 std::tr1::shared_ptr<char>
 make_path_absolute(const char*p);
 
+char*
+make_path_absolute_to_be_freed(const char*p);
+
 corpus_group_sptr
 build_corpus_group_from_kernel_dist_under(const string&        root,
                                          const string          debug_info_root,
index 983a787..02abc1a 100644 (file)
@@ -1114,9 +1114,9 @@ get_binary_load_address(Elf *elf_handle,
 /// @return true iff the location of the alternate debug info file was
 /// found.
 static bool
-find_alt_debug_info_location(Dwfl_Module *elf_module,
-                            string &alt_file_name,
-                            string &build_id)
+find_alt_debug_info_link(Dwfl_Module *elf_module,
+                        string &alt_file_name,
+                        string &build_id)
 {
   GElf_Addr bias = 0;
   Dwarf *dwarf = dwfl_module_getdwarf(elf_module, &bias);
@@ -1168,11 +1168,56 @@ find_alt_debug_info_location(Dwfl_Module *elf_module,
   return false;
 }
 
+/// Find alternate debuginfo file of a given "link" under a set of
+/// root directories.
+///
+/// The link is a string that is read by the function
+/// find_alt_debug_info_link().  That link is a path that is relative
+/// to a given debug info file, e.g, "../../../.dwz/something.debug".
+/// It designates the alternate debug info file associated to a given
+/// debug info file.
+///
+/// This function will thus try to find the .dwz/something.debug file
+/// under some given root directories.
+///
+/// @param root_dirs the set of root directories to look from.
+///
+/// @param alt_file_name a relative path to the alternate debug info
+/// file to look for.
+///
+/// @param alt_file_path the resulting absolute path to the alternate
+/// debuginfo path denoted by @p alt_file_name and found under one of
+/// the directories in @p root_dirs.  This is set iff the function
+/// returns true.
+///
+/// @return true iff the function found the alternate debuginfo file.
+static bool
+find_alt_debug_info_path(const vector<char**> root_dirs,
+                        const string &alt_file_name,
+                        string &alt_file_path)
+{
+  if (alt_file_name.empty())
+    return false;
+
+  string altfile_name = tools_utils::trim_leading_string(alt_file_name, "../");
+
+  for (vector<char**>::const_iterator i = root_dirs.begin();
+       i != root_dirs.end();
+       ++i)
+    if (tools_utils::find_file_under_dir(**i, altfile_name, alt_file_path))
+      return true;
+
+  return false;
+}
+
 /// Return the alternate debug info associated to a given main debug
 /// info file.
 ///
 /// @param elf_module the elf module to consider.
 ///
+/// @param debug_root_dirs a set of root debuginfo directories under
+/// which too look for the alternate debuginfo file.
+///
 /// @param alt_file_name output parameter.  This is set to the file
 /// path of the alternate debug info file associated to @p elf_module.
 /// This is set iff the function returns a non-null result.
@@ -1194,6 +1239,7 @@ find_alt_debug_info_location(Dwfl_Module *elf_module,
 /// otherwise, it's going to be leaked.
 static Dwarf*
 find_alt_debug_info(Dwfl_Module *elf_module,
+                   const vector<char**> debug_root_dirs,
                    string& alt_file_name,
                    int& alt_fd)
 {
@@ -1202,7 +1248,7 @@ find_alt_debug_info(Dwfl_Module *elf_module,
 
   Dwarf* result = 0;
   string build_id;
-  find_alt_debug_info_location(elf_module, alt_file_name, build_id);
+  find_alt_debug_info_link(elf_module, alt_file_name, build_id);
 
 #ifdef LIBDW_HAS_DWARF_GETALT
   // We are on recent versions of elfutils where the function
@@ -1232,6 +1278,34 @@ find_alt_debug_info(Dwfl_Module *elf_module,
   result = dwarf_begin(alt_fd, DWARF_C_READ);
 #endif
 
+  if (result == 0)
+    {
+      // So we didn't find the alternate debuginfo file from the
+      // information that is in the debuginfo file associated to
+      // elf_module.  Maybe the alternate debuginfo file is located
+      // under one of the directories in debug_root_dirs.  So let's
+      // look in there.
+      string alt_file_path;
+      if (!find_alt_debug_info_path(debug_root_dirs,
+                                   alt_file_name,
+                                   alt_file_path))
+       return result;
+
+      // If we reach this point it means we have found the path to the
+      // alternate debuginfo file and it's in alt_file_path.  So let's
+      // open it and read it.
+      int fd = open(alt_file_path.c_str(), O_RDONLY);
+      if (fd == -1)
+       return result;
+      result = dwarf_begin(fd, DWARF_C_READ);
+
+#ifdef LIBDW_HAS_DWARF_GETALT
+      Dwarf_Addr bias = 0;
+      Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
+      dwarf_setalt(dwarf, result);
+#endif
+    }
+
   return result;
 }
 
@@ -2806,6 +2880,8 @@ public:
   suppr::suppressions_type     supprs_;
   unsigned short               dwarf_version_;
   Dwfl_Callbacks               offline_callbacks_;
+  // The set of directories under which to look for debug info.
+  vector<char**>               debug_info_root_paths_;
   dwfl_sptr                    handle_;
   Dwarf*                       dwarf_;
   // The alternate debug info.  Alternate debug info sections are a
@@ -2940,9 +3016,10 @@ public:
   /// @param elf_path the path to the elf file the context is to be
   /// used for.
   ///
-  /// @param a pointer to the path to the root directory under which
-  /// the debug info is to be found for @p elf_path.  Leave this to
-  /// NULL if the debug info is not in a split file.
+  /// @param debug_info_root_paths a vector of pointers to the path to
+  /// the root directory under which the debug info is to be found for
+  /// @p elf_path.  Leave this empty if the debug info is not in a
+  /// split file.
   ///
   /// @param environment the environment used by the current context.
   /// This environment contains resources needed by the reader and by
@@ -2964,12 +3041,12 @@ public:
   /// linux kernel symbol tables when determining if a symbol is
   /// exported or not.
   read_context(const string&   elf_path,
-              char**           debug_info_root_path,
+              const vector<char**>& debug_info_root_paths,
               ir::environment* environment,
               bool             load_all_types,
               bool             linux_kernel_mode)
   {
-    initialize(elf_path, debug_info_root_path, environment,
+    initialize(elf_path, debug_info_root_paths, environment,
               load_all_types, linux_kernel_mode);
   }
 
@@ -2978,9 +3055,9 @@ public:
   /// @param elf_path the path to the elf file the context is to be
   /// used for.
   ///
-  /// @param debug_info_root_path a pointer to the path to the root
-  /// directory under which the debug info is to be found for @p
-  /// elf_path.  Leave this to NULL if the debug info is not in a
+  /// @param debug_info_root_paths a vector of pointers to the path to
+  /// the root directory under which the debug info is to be found for
+  /// @p elf_path.  Leave this empty if the debug info is not in a
   /// split file.
   ///
   /// @param environment the environment used by the current context.
@@ -3004,7 +3081,7 @@ public:
   /// is exported or not.
   void
   initialize(const string&     elf_path,
-            char**             debug_info_root_path,
+            const vector<char**>& debug_info_root_paths,
             ir::environment* environment,
             bool               load_all_types,
             bool               linux_kernel_mode)
@@ -3086,7 +3163,7 @@ public:
     clear_per_translation_unit_data();
 
     memset(&offline_callbacks_, 0, sizeof(offline_callbacks_));
-    create_default_dwfl(debug_info_root_path);
+    create_default_dwfl(debug_info_root_paths);
     options_.env = environment;
     options_.load_in_linux_kernel_mode = linux_kernel_mode;
     options_.load_all_types = load_all_types;
@@ -3214,26 +3291,29 @@ public:
   /// Constructor for a default Dwfl handle that knows how to load debug
   /// info from a library or executable elf file.
   ///
-  /// @param debug_info_root_path a pointer to the root path under which
-  /// to look for the debug info of the elf files that are later handled
-  /// by the Dwfl.  This for cases where the debug info is split into a
-  /// different file from the binary we want to inspect.  On Red Hat
-  /// compatible systems, this root path is usually /usr/lib/debug by
-  /// default.  If this argument is set to NULL, then "./debug" and
-  /// /usr/lib/debug will be searched for sub-directories containing the
-  /// debug info file.  Note that for now, elfutils wants this path to
-  /// be absolute otherwise things just don't work and the debug info is
-  /// not found.
+  /// @param debug_info_root_paths a vector of pointers to the root
+  /// path under which to look for the debug info of the elf files
+  /// that are later handled by the Dwfl.  This is for cases where the
+  /// debug info is split into a different file from the binary we
+  /// want to inspect.  On Red Hat compatible systems, this root path
+  /// is usually /usr/lib/debug by default.  If this argument is set
+  /// to the empty set, then "./debug" and /usr/lib/debug will be
+  /// searched for sub-directories containing the debug info file.
+  /// Note that for now, elfutils wants this path to be absolute
+  /// otherwise things just don't work and the debug info is not
+  /// found.
   ///
   /// @return the constructed Dwfl handle.
   void
-  create_default_dwfl(char** debug_info_root_path)
+  create_default_dwfl(const vector<char**>& debug_info_root_paths)
   {
     offline_callbacks()->find_debuginfo = dwfl_standard_find_debuginfo;
     offline_callbacks()->section_address = dwfl_offline_section_address;
-    offline_callbacks()->debuginfo_path = debug_info_root_path;
+    offline_callbacks()->debuginfo_path =
+      debug_info_root_paths.empty() ? 0 : debug_info_root_paths.front();
     handle_.reset(dwfl_begin(offline_callbacks()),
                  dwfl_deleter());
+    debug_info_root_paths_ = debug_info_root_paths;
   }
 
   unsigned short
@@ -3306,6 +3386,45 @@ public:
   dwarf_is_splitted() const
   {return dwarf_elf_handle() != elf_handle();}
 
+  /// Add paths to the set of paths under which to look for split
+  /// debuginfo files.
+  ///
+  /// @param debug_info_root_paths the paths to add.
+  void
+  add_debug_info_root_paths(const vector<char **>& debug_info_root_paths)
+  {
+    debug_info_root_paths_.insert(debug_info_root_paths_.end(),
+                                 debug_info_root_paths.begin(),
+                                 debug_info_root_paths.end());
+  }
+
+  /// Add a path to the set of paths under which to look for split
+  /// debuginfo files.
+  ///
+  /// @param debug_info_root_path the path to add.
+  void
+  add_debug_info_root_path(char** debug_info_root_path)
+  {debug_info_root_paths_.push_back(debug_info_root_path);}
+
+  /// Find the alternate debuginfo file associated to a given elf file.
+  ///
+  /// @param elf_module represents the elf file to consider.
+  ///
+  /// @param alt_file_name the resulting path to the alternate
+  /// debuginfo file found.  This is set iff the function returns a
+  /// non-nil value.
+  Dwarf*
+  find_alt_debug_info(Dwfl_Module *elf_module,
+                     string& alt_file_name,
+                     int& alt_fd)
+  {
+    Dwarf *result = 0;
+    result = dwarf_reader::find_alt_debug_info(elf_module,
+                                              debug_info_root_paths_,
+                                              alt_file_name, alt_fd);
+    return result;
+  }
+
   /// Load the debug info associated with an elf file that is at a
   /// given path.
   ///
@@ -3329,6 +3448,16 @@ public:
 
     Dwarf_Addr bias = 0;
     dwarf_ = dwfl_module_getdwarf(elf_module_, &bias);
+    // Look for split debuginfo files under multiple possible
+    // debuginfo roots.
+    for (vector<char**>::const_iterator i = debug_info_root_paths_.begin();
+        dwarf_ == 0 && i != debug_info_root_paths_.end();
+        ++i)
+      {
+       offline_callbacks()->debuginfo_path = *i;
+       dwarf_ = dwfl_module_getdwarf(elf_module_, &bias);
+      }
+
     if (!alt_dwarf_)
       alt_dwarf_ = find_alt_debug_info(elf_module_,
                                       alt_debug_info_path_,
@@ -15916,7 +16045,7 @@ status_to_diagnostic_string(status s)
 ///
 /// @param elf_path the path to the elf file the context is to be used for.
 ///
-/// @param debug_info_root_path a pointer to the path to the root
+/// @param debug_info_root_paths a pointer to the path to the root
 /// directory under which the debug info is to be found for @p
 /// elf_path.  Leave this to NULL if the debug info is not in a split
 /// file.
@@ -15944,14 +16073,14 @@ status_to_diagnostic_string(status s)
 /// @return a smart pointer to the resulting dwarf_reader::read_context.
 read_context_sptr
 create_read_context(const std::string&         elf_path,
-                   char**                      debug_info_root_path,
+                   const vector<char**>&       debug_info_root_paths,
                    ir::environment*            environment,
                    bool                        load_all_types,
                    bool                        linux_kernel_mode)
 {
   // Create a DWARF Front End Library handle to be used by functions
   // of that library.
-  read_context_sptr result(new read_context(elf_path, debug_info_root_path,
+  read_context_sptr result(new read_context(elf_path, debug_info_root_paths,
                                            environment, load_all_types,
                                            linux_kernel_mode));
   return result;
@@ -15994,7 +16123,7 @@ create_read_context(const std::string&          elf_path,
 void
 reset_read_context(read_context_sptr   &ctxt,
                   const std::string&    elf_path,
-                  char**                debug_info_root_path,
+                  const vector<char**>& debug_info_root_path,
                   ir::environment*      environment,
                   bool          read_all_types,
                   bool          linux_kernel_mode)
@@ -16131,14 +16260,14 @@ read_and_add_corpus_to_group_from_elf(read_context& ctxt,
 ///
 /// @param elf_path the path to the elf file.
 ///
-/// @param debug_info_root_path a pointer to the root path under which
-/// to look for the debug info of the elf files that are later handled
-/// by the Dwfl.  This for cases where the debug info is split into a
-/// different file from the binary we want to inspect.  On Red Hat
-/// compatible systems, this root path is usually /usr/lib/debug by
-/// default.  If this argument is set to NULL, then "./debug" and
-/// /usr/lib/debug will be searched for sub-directories containing the
-/// debug info file.
+/// @param debug_info_root_paths a vector of pointers to root paths
+/// under which to look for the debug info of the elf files that are
+/// later handled by the Dwfl.  This for cases where the debug info is
+/// split into a different file from the binary we want to inspect.
+/// On Red Hat compatible systems, this root path is usually
+/// /usr/lib/debug by default.  If this argument is set to NULL, then
+/// "./debug" and /usr/lib/debug will be searched for sub-directories
+/// containing the debug info file.
 ///
 /// @param environment the environment used by the current context.
 /// This environment contains resources needed by the reader and by
@@ -16159,13 +16288,13 @@ read_and_add_corpus_to_group_from_elf(read_context& ctxt,
 /// @return the resulting status.
 corpus_sptr
 read_corpus_from_elf(const std::string& elf_path,
-                    char**             debug_info_root_path,
+                    const vector<char**>& debug_info_root_paths,
                     ir::environment*   environment,
                     bool               load_all_types,
                     status&            status)
 {
   read_context_sptr c = create_read_context(elf_path,
-                                           debug_info_root_path,
+                                           debug_info_root_paths,
                                            environment,
                                            load_all_types);
   read_context& ctxt = *c;
@@ -16355,7 +16484,9 @@ has_alt_debug_info(const string&        elf_path,
                   bool&                has_alt_di,
                   string&              alt_debug_info_path)
 {
-  read_context_sptr c = create_read_context(elf_path, debug_info_root_path, 0);
+  vector<char**> di_roots;
+  di_roots.push_back(debug_info_root_path);
+  read_context_sptr c = create_read_context(elf_path, di_roots, 0);
   read_context& ctxt = *c;
 
   // Load debug info from the elf path.
index 5292870..0bc2f24 100644 (file)
@@ -899,6 +899,47 @@ trim_white_space(const string& str)
   return result;
 }
 
+/// Remove a string of pattern in front of a given string.
+///
+/// For instance, consider this string:
+///    "../../../foo"
+///
+/// The pattern "../" is repeated three times in front of the
+/// sub-string "foo".  Thus, the call:
+///    trim_leading_string("../../../foo", "../")
+/// will return the string "foo".
+///
+/// @param from the string to trim the leading repetition of pattern from.
+///
+/// @param to_trim the pattern to consider (and to trim).
+///
+/// @return the resulting string where the leading patter @p to_trim
+/// has been removed from.
+string
+trim_leading_string(const string& from, const string& to_trim)
+{
+  string str = from;
+
+  while (string_begins_with(str, to_trim))
+    string_suffix(str, to_trim, str);
+  return str;
+}
+
+/// Convert a vector<char*> into a vector<char**>.
+///
+/// @param char_stars the input vector.
+///
+/// @param char_star_stars the output vector.
+void
+convert_char_stars_to_char_star_stars(const vector<char*> &char_stars,
+                                     vector<char**>& char_star_stars)
+{
+  for (vector<char*>::const_iterator i = char_stars.begin();
+       i != char_stars.end();
+       ++i)
+    char_star_stars.push_back(const_cast<char**>(&*i));
+}
+
 /// The private data of the @ref temp_file type.
 struct temp_file::priv
 {
@@ -1445,6 +1486,34 @@ make_path_absolute(const char*p)
   return result;
 }
 
+/// Return a copy of the path given in argument, turning it into an
+/// absolute path by prefixing it with the concatenation of the result
+/// of get_current_dir_name() and the '/' character.
+///
+/// The result being a pointer to an allocated memory region, it must
+/// be freed by the caller.
+///
+/// @param p the path to turn into an absolute path.
+///
+/// @return a pointer to the resulting absolute path.  It must be
+/// freed by the caller.
+char*
+make_path_absolute_to_be_freed(const char*p)
+{
+    char* result = 0;
+
+  if (p && p[0] != '/')
+    {
+      char* pwd = get_current_dir_name();
+      string s = string(pwd) + "/" + p;
+      free(pwd);
+      result = strdup(s.c_str());
+    }
+  else
+    result = strdup(p);
+
+  return result;
+}
 
 /// This is a sub-routine of gen_suppr_spec_from_headers.
 ///
@@ -1698,6 +1767,69 @@ load_default_user_suppressions(suppr::suppressions_type& supprs)
   read_suppressions(default_user_suppr_path, supprs);
 }
 
+/// Test if a given FTSENT* denotes a file with a given name.
+///
+/// @param entry the FTSENT* to consider.
+///
+/// @param fname the file name (or end of path) to consider.
+///
+/// @return true iff @p entry denotes a file which path ends with @p
+/// fname.
+static bool
+entry_of_file_with_name(const FTSENT *entry,
+                       const string& fname)
+{
+  if (entry == NULL
+      || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
+      || entry->fts_info == FTS_ERR
+      || entry->fts_info == FTS_NS)
+    return false;
+
+  string fpath = entry->fts_path;
+  if (string_ends_with(fpath, fname))
+    return true;
+  return false;
+}
+
+/// Find a given file under a root directory and return its absolute
+/// path.
+///
+/// @param root_dir the root directory under which to look for.
+///
+/// @param file_path_to_look_for the file to look for under the
+/// directory @p root_dir.
+///
+/// @param result the resulting path to @p file_path_to_look_for.
+/// This is set iff the file has been found.
+bool
+find_file_under_dir(const string& root_dir,
+                   const string& file_path_to_look_for,
+                   string& result)
+{
+  char* paths[] = {const_cast<char*>(root_dir.c_str()), 0};
+
+  FTS *file_hierarchy = fts_open(paths,
+                                FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
+  if (!file_hierarchy)
+    return false;
+
+  FTSENT *entry;
+  while ((entry = fts_read(file_hierarchy)))
+    {
+      // Skip descendents of symbolic links.
+      if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
+       {
+         fts_set(file_hierarchy, entry, FTS_SKIP);
+         continue;
+       }
+      if (entry_of_file_with_name(entry, file_path_to_look_for))
+       {
+         result = entry->fts_path;
+         return true;
+       }
+    }
+  return false;
+}
 /// If we were given suppression specification files or kabi whitelist
 /// files, this function parses those, come up with suppression
 /// specifications as a result, and set them to the read context.
@@ -2060,12 +2192,14 @@ build_corpus_group_from_kernel_dist_under(const string& root,
       shared_ptr<char> di_root =
        make_path_absolute(debug_info_root.c_str());
       char *di_root_ptr = di_root.get();
+      vector<char**> di_roots;
+      di_roots.push_back(&di_root_ptr);
       abigail::dwarf_reader::status status = abigail::dwarf_reader::STATUS_OK;
       corpus_group_sptr group;
       if (!vmlinux.empty())
        {
          ctxt =
-           dwarf_reader::create_read_context(vmlinux, &di_root_ptr,env.get(),
+           dwarf_reader::create_read_context(vmlinux, di_roots ,env.get(),
                                              /*read_all_types=*/false,
                                              /*linux_kernel_mode=*/true);
 
@@ -2109,7 +2243,7 @@ build_corpus_group_from_kernel_dist_under(const string&   root,
                          << "/" << total_nb_modules
                          << ") ... " << std::flush;
 
-             reset_read_context(ctxt, *m, &di_root_ptr, env.get(),
+             reset_read_context(ctxt, *m, di_roots, env.get(),
                                 /*read_all_types=*/false,
                                 /*linux_kernel_mode=*/true);
 
index 75d5ae5..fc5fc50 100644 (file)
@@ -121,7 +121,8 @@ main(int argc, char* argv[])
       corpus_sptr c1, c2;
 
       environment_sptr env(new environment);
-      c1 = dwarf_reader::read_corpus_from_elf(opts.elf1, 0, env.get(),
+      vector<char**> di_roots;
+      c1 = dwarf_reader::read_corpus_from_elf(opts.elf1, di_roots, env.get(),
                                              /*load_all_types=*/false,
                                              c1_status);
       if (c1_status != dwarf_reader::STATUS_OK)
@@ -130,7 +131,7 @@ main(int argc, char* argv[])
          return 1;
        }
 
-      c2 = dwarf_reader::read_corpus_from_elf(opts.elf2, 0, env.get(),
+      c2 = dwarf_reader::read_corpus_from_elf(opts.elf2, di_roots, env.get(),
                                              /*load_all_types=*/false,
                                              c2_status);
       if (c2_status != dwarf_reader::STATUS_OK)
index 5f459ad..778c547 100644 (file)
@@ -385,16 +385,17 @@ main()
        abigail::dwarf_reader::STATUS_UNKNOWN;
 
       environment_sptr env(new environment);
+      std::vector<char**> di_roots;
       abigail::corpus_sptr corp0 =
        read_corpus_from_elf(in_elfv0_path,
-                            /*debug_info_root_path=*/0,
+                            /*debug_info_root_path=*/di_roots,
                             env.get(),
                             /*load_all_types=*/false,
                             status);
 
       abigail::corpus_sptr corp1 =
        read_corpus_from_elf(in_elfv1_path,
-                            /*debug_info_root_path=*/0,
+                            /*debug_info_root_path=*/di_roots,
                             env.get(),
                             /*load_all_types=*/false,
                             status);
index eebe121..ea26d4d 100644 (file)
@@ -173,8 +173,8 @@ main(int argc, char **argv)
   abigail::ir::environment_sptr env(new abigail::ir::environment);
   abigail::corpus_sptr c;
   abigail::dwarf_reader::status status = abigail::dwarf_reader::STATUS_OK;
-  if (!(c = abigail::dwarf_reader::read_corpus_from_elf(file_name,
-                                                       /*debug_info_path=*/0,
+  std::vector<char**> di_roots;
+  if (!(c = abigail::dwarf_reader::read_corpus_from_elf(file_name, di_roots,
                                                        env.get(),
                                                        /*load_all_type=*/false,
                                                        status)))
index 9b74b9a..357812a 100644 (file)
@@ -290,8 +290,9 @@ struct test_task : public abigail::workers::task
     env.reset(new abigail::ir::environment);
     abigail::dwarf_reader::status status =
     abigail::dwarf_reader::STATUS_UNKNOWN;
+    vector<char**> di_roots;
     read_context_sptr ctxt = create_read_context(in_elf_path,
-                                                /*debug_info_root_path=*/0,
+                                                di_roots,
                                                 env.get());
     assert(ctxt);
     if (!in_suppr_spec_path.empty())
index cd6ceea..2c453ad 100644 (file)
@@ -683,11 +683,13 @@ main(int argc, char* argv[])
 
   // Read the application ELF file.
   char * app_di_root = opts.app_di_root_path.get();
+  vector<char**> app_di_roots;
+  app_di_roots.push_back(&app_di_root);
   status status = abigail::dwarf_reader::STATUS_UNKNOWN;
   environment_sptr env(new environment);
   corpus_sptr app_corpus=
     read_corpus_from_elf(opts.app_path,
-                        &app_di_root, env.get(),
+                        app_di_roots, env.get(),
                         /*load_all_types=*/opts.weak_mode,
                         status);
 
@@ -734,8 +736,10 @@ main(int argc, char* argv[])
     }
 
   char * lib1_di_root = opts.lib1_di_root_path.get();
+  vector<char**> lib1_di_roots;
+  lib1_di_roots.push_back(&lib1_di_root);
   corpus_sptr lib1_corpus = read_corpus_from_elf(opts.lib1_path,
-                                                &lib1_di_root, env.get(),
+                                                lib1_di_roots, env.get(),
                                                 /*load_all_types=*/false,
                                                 status);
   if (status & abigail::dwarf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
@@ -759,9 +763,10 @@ main(int argc, char* argv[])
     {
       assert(!opts.lib2_path.empty());
       char * lib2_di_root = opts.lib2_di_root_path.get();
+      vector<char**> lib2_di_roots;
+      lib2_di_roots.push_back(&lib2_di_root);
       lib2_corpus = read_corpus_from_elf(opts.lib2_path,
-                                        &lib2_di_root,
-                                        env.get(),
+                                        lib2_di_roots, env.get(),
                                         /*load_all_types=*/false,
                                         status);
       if (status & abigail::dwarf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
index 93014fd..7a0859f 100644 (file)
@@ -110,8 +110,10 @@ struct options
   bool                 dump_diff_tree;
   bool                 show_stats;
   bool                 do_log;
-  shared_ptr<char>     di_root_path1;
-  shared_ptr<char>     di_root_path2;
+  vector<char*> di_root_paths1;
+  vector<char*> di_root_paths2;
+  vector<char**> prepared_di_root_paths1;
+  vector<char**> prepared_di_root_paths2;
 
   options()
     : display_usage(),
@@ -148,6 +150,22 @@ struct options
       show_stats(),
       do_log()
   {}
+
+  ~options()
+  {
+    for (vector<char*>::iterator i = di_root_paths1.begin();
+        i != di_root_paths1.end();
+        ++i)
+      free(*i);
+
+    for (vector<char*>::iterator i = di_root_paths2.begin();
+        i != di_root_paths2.end();
+        ++i)
+      free(*i);
+
+    prepared_di_root_paths1.clear();
+    prepared_di_root_paths2.clear();
+  }
 };//end struct options;
 
 static void
@@ -260,8 +278,8 @@ parse_command_line(int argc, char* argv[], options& opts)
            }
          // elfutils wants the root path to the debug info to be
          // absolute.
-         opts.di_root_path1 =
-           abigail::tools_utils::make_path_absolute(argv[j]);
+         opts.di_root_paths1.push_back
+           (abigail::tools_utils::make_path_absolute_to_be_freed(argv[j]));
          ++i;
        }
       else if (!strcmp(argv[i], "--debug-info-dir2")
@@ -276,8 +294,8 @@ parse_command_line(int argc, char* argv[], options& opts)
            }
          // elfutils wants the root path to the debug info to be
          // absolute.
-         opts.di_root_path2 =
-           abigail::tools_utils::make_path_absolute(argv[j]);
+         opts.di_root_paths2.push_back
+           (abigail::tools_utils::make_path_absolute_to_be_freed(argv[j]));
          ++i;
        }
       else if (!strcmp(argv[i], "--headers-dir1")
@@ -794,6 +812,21 @@ adjust_diff_context_for_kmidiff(diff_context_sptr &ctxt)
     (false);
 }
 
+/// Convert options::di_root_paths{1,2} into
+/// options::prepared_di_root_paths{1,2} which is the suitable type
+/// format that the dwarf_reader expects.
+///
+/// @param o the options to consider.
+static void
+prepare_di_root_paths(options& o)
+{
+  abigail::tools_utils::convert_char_stars_to_char_star_stars
+    (o.di_root_paths1, o.prepared_di_root_paths1);
+
+  abigail::tools_utils::convert_char_stars_to_char_star_stars
+    (o.di_root_paths2, o.prepared_di_root_paths2);
+}
+
 /// Emit an appropriate error message if necessary, given an error
 /// code.
 ///
@@ -827,46 +860,64 @@ static abigail::tools_utils::abidiff_status
 handle_error(abigail::dwarf_reader::status status_code,
             const abigail::dwarf_reader::read_context* ctxt,
             const string& prog_name,
-            const string& input_file_name,
-            char** debug_info_dir1,
-            char** debug_info_dir2)
+            const options& opts)
 {
   if (!(status_code & abigail::dwarf_reader::STATUS_OK))
     {
       emit_prefix(prog_name, cerr)
-       << "failed to read input file " << input_file_name << "\n";
+       << "failed to read input file " << opts.file1 << "\n";
 
       if (status_code & abigail::dwarf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
        {
          emit_prefix(prog_name, cerr) <<
            "could not find the debug info\n";
-         if (debug_info_dir1)
-           {
-             if (*debug_info_dir1 == 0)
-               emit_prefix(prog_name, cerr)
-                 << "Maybe you should consider using the "
-                 "--debug-info-dir1 option to tell me about the "
-                 "root directory of the debuginfo? "
-                 "(e.g, --debug-info-dir1 /usr/lib/debug)\n";
-             else
+         {
+           if (opts.prepared_di_root_paths1.empty() == 0)
+             emit_prefix(prog_name, cerr)
+               << "Maybe you should consider using the "
+               "--debug-info-dir1 option to tell me about the "
+               "root directory of the debuginfo? "
+               "(e.g, --debug-info-dir1 /usr/lib/debug)\n";
+           else
+             {
                emit_prefix(prog_name, cerr)
-                 << "Maybe the root path to the debug information '"
-                 << *debug_info_dir1 << "' is wrong?\n";
-           }
+                 << "Maybe the root path to the debug information '";
+               for (vector<char**>::const_iterator i
+                      = opts.prepared_di_root_paths1.begin();
+                    i != opts.prepared_di_root_paths1.end();
+                    ++i)
+                 {
+                   if (i != opts.prepared_di_root_paths1.end())
+                     cerr << ", ";
+                   cerr << **i;
+                 }
+               cerr << "' is wrong?\n";
+             }
+         }
 
-         if (debug_info_dir2)
-           {
-             if (*debug_info_dir2 == 0)
-               emit_prefix(prog_name, cerr)
-                 << "Maybe you should consider using the "
-                 "--debug-info-dir2 option to tell me about the "
-                 "root directory of the debuginfo? "
-                 "(e.g, --debug-info-dir2 /usr/lib/debug)\n";
-             else
+         {
+           if (opts.prepared_di_root_paths2.empty())
+             emit_prefix(prog_name, cerr)
+               << "Maybe you should consider using the "
+               "--debug-info-dir2 option to tell me about the "
+               "root directory of the debuginfo? "
+               "(e.g, --debug-info-dir2 /usr/lib/debug)\n";
+           else
+             {
                emit_prefix(prog_name, cerr)
-                 << "Maybe the root path to the debug information '"
-                 << *debug_info_dir2 << "' is wrong?\n";
-           }
+                 << "Maybe the root path to the debug information '";
+               for (vector<char**>::const_iterator i
+                      = opts.prepared_di_root_paths2.begin();
+                    i != opts.prepared_di_root_paths2.end();
+                    ++i)
+                 {
+                   if (i != opts.prepared_di_root_paths2.end())
+                     cerr << ", ";
+                   cerr << **i;
+                 }
+                 cerr << "' is wrong?\n";
+             }
+         }
        }
 
       if (status_code & abigail::dwarf_reader::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
@@ -887,7 +938,7 @@ handle_error(abigail::dwarf_reader::status status_code,
       if (status_code & abigail::dwarf_reader::STATUS_NO_SYMBOLS_FOUND)
        emit_prefix(prog_name, cerr)
          << "could not find the ELF symbols in the file '"
-         << input_file_name
+         << opts.file1
          << "'\n";
 
       return abigail::tools_utils::ABIDIFF_ERROR;
@@ -934,6 +985,8 @@ main(int argc, char* argv[])
       return 0;
     }
 
+  prepare_di_root_paths(opts);
+
   if (!maybe_check_suppression_files(opts))
     return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
            | abigail::tools_utils::ABIDIFF_ERROR);
@@ -972,7 +1025,6 @@ main(int argc, char* argv[])
        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;
 
       diff_context_sptr ctxt(new diff_context);
@@ -1001,12 +1053,10 @@ main(int argc, char* argv[])
        case abigail::tools_utils::FILE_TYPE_ELF:
        case abigail::tools_utils::FILE_TYPE_AR:
          {
-           di_dir1 = opts.di_root_path1.get();
            abigail::dwarf_reader::read_context_sptr ctxt =
-             abigail::dwarf_reader::create_read_context(opts.file1,
-                                                        &di_dir1, env.get(),
-                                                        /*readalltypes*/false,
-                                                        opts.linux_kernel_mode);
+             abigail::dwarf_reader::create_read_context
+             (opts.file1, opts.prepared_di_root_paths1, env.get(),
+              /*readalltypes*/false, opts.linux_kernel_mode);
            assert(ctxt);
 
            abigail::dwarf_reader::set_show_stats(*ctxt, opts.show_stats);
@@ -1015,9 +1065,7 @@ main(int argc, char* argv[])
            c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
            if (!c1)
              return handle_error(c1_status, ctxt.get(),
-                                 argv[0], opts.file1,
-                                 &di_dir1,
-                                 /*debug_info_dir2=*/0);
+                                 argv[0], opts);
          }
          break;
        case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
@@ -1030,9 +1078,7 @@ main(int argc, char* argv[])
            c1 = abigail::xml_reader::read_corpus_from_input(*ctxt);
            if (!c1)
              return handle_error(c1_status, /*ctxt=*/0,
-                                 argv[0], opts.file1,
-                                 /*debug_info_dir1=*/0,
-                                 /*debug_info_dir2=*/0);
+                                 argv[0], opts);
          }
          break;
        case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
@@ -1045,19 +1091,14 @@ main(int argc, char* argv[])
            g1 = abigail::xml_reader::read_corpus_group_from_input(*ctxt);
            if (!g1)
              return handle_error(c1_status, /*ctxt=*/0,
-                                 argv[0], opts.file1,
-                                 /*debug_info_dir1=*/0,
-                                 /*debug_info_dir2=*/0);
+                                 argv[0], opts);
          }
          break;
        case abigail::tools_utils::FILE_TYPE_ZIP_CORPUS:
 #ifdef WITH_ZIP_ARCHIVE
          c1 = abigail::xml_reader::read_corpus_from_file(opts.file1);
          if (!c1)
-           return handle_error(c1_status, /*ctxt=*/0,
-                               argv[0], opts.file1,
-                               /*debug_info_dir1=*/0,
-                               /*debug_info_dir2=*/0);
+           return handle_error(c1_status, /*ctxt=*/0, argv[0], opts);
 #endif //WITH_ZIP_ARCHIVE
          break;
        case abigail::tools_utils::FILE_TYPE_RPM:
@@ -1082,12 +1123,10 @@ main(int argc, char* argv[])
        case abigail::tools_utils::FILE_TYPE_ELF:
        case abigail::tools_utils::FILE_TYPE_AR:
          {
-           di_dir2 = opts.di_root_path2.get();
            abigail::dwarf_reader::read_context_sptr ctxt =
-             abigail::dwarf_reader::create_read_context(opts.file2,
-                                                        &di_dir2, env.get(),
-                                                        /*readalltypes=*/false,
-                                                        opts.linux_kernel_mode);
+             abigail::dwarf_reader::create_read_context
+             (opts.file2, opts.prepared_di_root_paths2, env.get(),
+              /*readalltypes=*/false, opts.linux_kernel_mode);
            assert(ctxt);
            abigail::dwarf_reader::set_show_stats(*ctxt, opts.show_stats);
            abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
@@ -1095,10 +1134,8 @@ main(int argc, char* argv[])
 
            c2 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c2_status);
            if (!c2)
-             return handle_error(c2_status, ctxt.get(),
-                                 argv[0], opts.file2,
-                                 /*debug_info_dir1=*/0,
-                                 /*debug_info_dir2=*/&di_dir2);
+             return handle_error(c2_status, ctxt.get(), argv[0], opts);
+
          }
          break;
        case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
@@ -1110,10 +1147,8 @@ main(int argc, char* argv[])
            set_suppressions(*ctxt, opts);
            c2 = abigail::xml_reader::read_corpus_from_input(*ctxt);
            if (!c2)
-             return handle_error(c2_status, /*ctxt=*/0,
-                                 argv[0], opts.file2,
-                                 /*debug_info_dir1=*/0,
-                                 /*debug_info_dir2=*/0);
+             return handle_error(c2_status, /*ctxt=*/0, argv[0], opts);
+
          }
          break;
        case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
@@ -1125,20 +1160,14 @@ main(int argc, char* argv[])
            set_suppressions(*ctxt, opts);
            g2 = abigail::xml_reader::read_corpus_group_from_input(*ctxt);
            if (!g2)
-             return handle_error(c2_status, /*ctxt=*/0,
-                                 argv[0], opts.file2,
-                                 /*debug_info_dir1=*/0,
-                                 /*debug_info_dir2=*/0);
+             return handle_error(c2_status, /*ctxt=*/0, argv[0], opts);
          }
          break;
        case abigail::tools_utils::FILE_TYPE_ZIP_CORPUS:
 #ifdef WITH_ZIP_ARCHIVE
          c2 = abigail::xml_reader::read_corpus_from_file(opts.file2);
          if (!c2)
-           return handle_error(c2_status, /*ctxt=*/0,
-                               argv[0], opts.file2,
-                               /*debug_info_dir1=*/0,
-                               /*debug_info_dir2=*/0);
+           return handle_error(c2_status, /*ctxt=*/0, argv[0], opts);
 #endif //WITH_ZIP_ARCHIVE
          break;
        case abigail::tools_utils::FILE_TYPE_RPM:
index dcf1837..89eefae 100644 (file)
@@ -82,7 +82,8 @@ struct options
   string               wrong_option;
   string               in_file_path;
   string               out_file_path;
-  shared_ptr<char>     di_root_path;
+  vector<char*>        di_root_paths;
+  vector<char**>       prepared_di_root_paths;
   string               headers_dir;
   string               vmlinux;
   vector<string>       suppression_paths;
@@ -119,6 +120,16 @@ struct options
       annotate(),
       do_log()
   {}
+
+  ~options()
+  {
+    for (vector<char*>::iterator i = di_root_paths.begin();
+        i != di_root_paths.end();
+        ++i)
+      free(*i);
+
+    prepared_di_root_paths.clear();
+  }
 };
 
 static void
@@ -184,8 +195,8 @@ parse_command_line(int argc, char* argv[], options& opts)
            return false;
          // elfutils wants the root path to the debug info to be
          // absolute.
-         opts.di_root_path =
-           abigail::tools_utils::make_path_absolute(argv[i + 1]);
+         opts.di_root_paths.push_back
+           (abigail::tools_utils::make_path_absolute_to_be_freed(argv[i + 1]));
          ++i;
        }
       else if (!strcmp(argv[i], "--headers-dir")
@@ -392,7 +403,7 @@ load_corpus_and_write_abixml(char* argv[],
     {
       if (s == dwarf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
        {
-         if (opts.di_root_path.get() == 0)
+         if (opts.di_root_paths.empty())
            {
              emit_prefix(argv[0], cerr)
                << "Could not read debug info from "
@@ -408,9 +419,16 @@ load_corpus_and_write_abixml(char* argv[],
            {
              emit_prefix(argv[0], cerr)
                << "Could not read debug info for '" << opts.in_file_path
-               << "' from debug info root directory '"
-               << opts.di_root_path.get()
-               << "'\n";
+               << "' from debug info root directory '";
+             for (vector<char*>::const_iterator i =
+                    opts.di_root_paths.begin();
+                  i != opts.di_root_paths.end();
+                  ++i)
+               {
+                 if (i != opts.di_root_paths.begin())
+                   cerr << ", ";
+                 cerr << *i;
+               }
            }
        }
       else if (s == dwarf_reader::STATUS_NO_SYMBOLS_FOUND)
@@ -560,6 +578,18 @@ load_kernel_corpus_group_and_write_abixml(char* argv[],
   return exit_code;
 }
 
+/// Convert options::di_root_paths into
+/// options::prepared_di_root_paths which is the suitable type format
+/// that the dwarf_reader expects.
+///
+/// @param o the options to consider.
+static void
+prepare_di_root_paths(options& o)
+{
+  tools_utils::convert_char_stars_to_char_star_stars(o.di_root_paths,
+                                                    o.prepared_di_root_paths);
+}
+
 int
 main(int argc, char* argv[])
 {
@@ -596,6 +626,8 @@ main(int argc, char* argv[])
        return 1;
     }
 
+  prepare_di_root_paths(opts);
+
   if (!maybe_check_suppression_files(opts))
     return 1;
 
@@ -610,14 +642,14 @@ main(int argc, char* argv[])
       return 1;
     }
 
-  char* p = opts.di_root_path.get();
   environment_sptr env(new environment);
   int exit_code = 0;
 
   if (tools_utils::is_regular_file(opts.in_file_path))
     {
       read_context_sptr c = create_read_context(opts.in_file_path,
-                                               &p, env.get(),
+                                               opts.prepared_di_root_paths,
+                                               env.get(),
                                                opts.load_all_types,
                                                opts.linux_kernel_mode);
       read_context& ctxt = *c;
index f2f0a19..ad2d0d7 100644 (file)
@@ -326,10 +326,11 @@ main(int argc, char* argv[])
        case abigail::tools_utils::FILE_TYPE_AR:
          {
            di_root_path = opts.di_root_path.get();
+           vector<char**> di_roots;
+           di_roots.push_back(&di_root_path);
            abigail::dwarf_reader::read_context_sptr ctxt =
              abigail::dwarf_reader::create_read_context(opts.file_path,
-                                                        &di_root_path,
-                                                        env.get(),
+                                                        di_roots, env.get(),
                                                         /*load_all_types=*/false);
            assert(ctxt);
            set_suppressions(*ctxt, opts);
index ce07bcb..7755581 100644 (file)
@@ -1241,6 +1241,10 @@ compare(const elf_file& elf1,
   char *di_dir1 = (char*) debug_dir1.c_str(),
        *di_dir2 = (char*) debug_dir2.c_str();
 
+  vector<char**> di_dirs1, di_dirs2;
+  di_dirs1.push_back(&di_dir1);
+  di_dirs2.push_back(&di_dir2);
+
   if (opts.verbose)
     emit_prefix("abipkgdiff", cerr)
       << "Comparing the ABIs of file "
@@ -1291,7 +1295,7 @@ compare(const elf_file& elf1,
 
   corpus_sptr corpus1;
   {
-    read_context_sptr c = create_read_context(elf1.path, &di_dir1, env.get(),
+    read_context_sptr c = create_read_context(elf1.path, di_dirs1, env.get(),
                                              /*load_all_types=*/false);
     add_read_context_suppressions(*c, priv_types_supprs1);
     if (!opts.kabi_suppressions.empty())
@@ -1376,7 +1380,7 @@ compare(const elf_file& elf1,
 
   corpus_sptr corpus2;
   {
-    read_context_sptr c = create_read_context(elf2.path, &di_dir2, env.get(),
+    read_context_sptr c = create_read_context(elf2.path, di_dirs2, env.get(),
                                              /*load_all_types=*/false);
     add_read_context_suppressions(*c, priv_types_supprs2);