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.
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
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.
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);
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,
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&);
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);
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.
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,
/// @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);
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.
/// 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)
{
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
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;
}
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
/// @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
/// 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);
}
/// @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.
/// 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)
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;
/// 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
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.
///
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_,
///
/// @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.
/// @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;
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)
///
/// @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
/// @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;
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.
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
{
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.
///
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.
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);
<< "/" << 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);
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)
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)
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);
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)))
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())
// 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);
}
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)
{
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)
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(),
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
}
// 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")
}
// 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")
(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.
///
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)
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;
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);
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);
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);
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:
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:
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:
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);
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:
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:
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:
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;
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
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")
{
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 "
{
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)
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[])
{
return 1;
}
+ prepare_di_root_paths(opts);
+
if (!maybe_check_suppression_files(opts))
return 1;
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;
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);
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 "
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())
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);