Harden debug info path management & better error reporting

* include/abg-dwarf-reader.h (enum status): New enum.
	(read_corpus_from_elf): Return an instance of status above, and
	return the corpus by parameter.
	* src/abg-dwarf-reader.cc (create_default_dwfl): Add a comment
	about elfutils wanting the Dwfl_Callbacks::debuginfo_path to be an
	absolute path.
	(read_corpus_from_elf): Return an instance of status above, and
	return the corpus by parameter.
	* tools/abg-tools-utils.h (make_path_absolute): Declare new function.
	* tools/abg-tools-utils.cc (make_path_absolute): New
	implementation.
	* tools/bidiff.cc (options::di_root_path[12]): Make these be
	shared pointers.
	(parse_command_line): ensure the debug info root paths are
	absolute.
	(main): Adjust.  Give meaningful errors when the debug info or
	symbol files couldn't be read.
	* tools/bidw.cc (options::di_root_path): Make this be a shared
	pointer.
	(parse_command_line): Ensure the debug info root path is absolute.
	(main): Adjust.  Give meaningful errors when the debug info or
	symbol files couldn't be read.
	* tools/bilint.cc (options::di_root_path): Make this be a shared
	pointer.
	(parse_command_line): Ensure the debug info root path is absolute.
	(main): Adjust.  Give meaningful errors when the debug info or
	symbol file couldn't be read.
	* tests/test-diff-dwarf.cc (main): Adjust.
	* tests/test-read-dwarf.cc (main): Likewise.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2014-06-04 16:30:18 +02:00
parent 3153f4c83a
commit c4e7f9792d
9 changed files with 234 additions and 63 deletions

View File

@ -38,9 +38,24 @@ namespace abigail
namespace dwarf_reader
{
corpus_sptr
/// The status of the @ref read_corpus_from_elf() call.
enum status
{
/// This status is for when the call went OK.
STATUS_OK,
/// This satus is for when the debug info could not be read.
STATUS_DEBUG_INFO_NOT_FOUND,
/// This status is for when the symbols of the ELF binaries could
/// not be read.
STATUS_NO_SYMBOLS_FOUND,
};
status
read_corpus_from_elf(const std::string& elf_path,
char** debug_info_root_path);
char** debug_info_root_path,
corpus_sptr& resulting_corp);
bool
lookup_symbol_from_elf(const string& elf_path,

View File

@ -1986,7 +1986,9 @@ build_function_decl(read_context& ctxt,
/// 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.
/// 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.
static Dwfl*
@ -5370,10 +5372,13 @@ build_ir_node_from_die(read_context& ctxt,
/// /usr/lib/debug will be searched for sub-directories containing the
/// debug info file.
///
/// @return a pointer to the resulting @ref abigail::corpus.
corpus_sptr
/// @param resulting_corp a pointer to the resulting abigail::corpus.
///
/// @return the resulting status.
status
read_corpus_from_elf(const std::string& elf_path,
char** debug_info_root_path)
char** debug_info_root_path,
corpus_sptr& resulting_corp)
{
// Create a DWARF Front End Library handle to be used by functions
// of that library.
@ -5383,11 +5388,11 @@ read_corpus_from_elf(const std::string& elf_path,
// Load debug info from the elf path.
if (!ctxt.load_debug_info())
return corpus_sptr();
return STATUS_DEBUG_INFO_NOT_FOUND;
// First read the symbols for publicly defined decls
if (!ctxt.load_symbol_maps())
return corpus_sptr();
return STATUS_NO_SYMBOLS_FOUND;
// Now, read an ABI corpus proper from the debug info we have
// through the dwfl handle.
@ -5398,7 +5403,9 @@ read_corpus_from_elf(const std::string& elf_path,
corp->set_fun_symbol_map(ctxt.fun_syms_sptr());
corp->set_var_symbol_map(ctxt.var_syms_sptr());
return corp;
resulting_corp = corp;
return STATUS_OK;
}
/// Look into the symbol tables of a given elf file and see if we find

View File

@ -149,10 +149,12 @@ main()
continue;
}
corp0 = read_corpus_from_elf(in_elfv0_path,
/*debug_info_root_path=*/0);
corp1 = read_corpus_from_elf(in_elfv1_path,
/*debug_info_root_path=*/0);
read_corpus_from_elf(in_elfv0_path,
/*debug_info_root_path=*/0,
corp0);
read_corpus_from_elf(in_elfv1_path,
/*debug_info_root_path=*/0,
corp1);
if (!corp0)
{

View File

@ -81,9 +81,9 @@ main()
for (InOutSpec* s = in_out_specs; s->in_elf_path; ++s)
{
in_elf_path = abigail::tests::get_src_dir() + "/tests/" + s->in_elf_path;
corp =
abigail::dwarf_reader::read_corpus_from_elf(in_elf_path,
/*debug_info_root_path=*/0);
abigail::dwarf_reader::read_corpus_from_elf(in_elf_path,
/*debug_info_root_path=*/0,
corp);
if (!corp)
{
cerr << "failed to read " << in_elf_path << "\n";

View File

@ -20,6 +20,7 @@
///@file
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <cstdlib>
@ -304,6 +305,44 @@ guess_file_type(const std::string& file_path)
return r;
}
struct malloced_char_star_deleter
{
void
operator()(char* ptr)
{free(ptr);}
};
/// 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 an shared_ptr to char*, it should manage its
/// memory by itself and the user shouldn't need to wory too much for
/// that.
///
/// @param p the path to turn into an absolute path.
///
/// @return a shared pointer to the resulting absolute path.
std::tr1::shared_ptr<char>
make_path_absolute(const char*p)
{
using std::tr1::shared_ptr;
shared_ptr<char> result;
if (p && p[0] != '/')
{
shared_ptr<char> pwd(get_current_dir_name(),
malloced_char_star_deleter());
string s = string(pwd.get()) + "/" + p;
result.reset(strdup(s.c_str()), malloced_char_star_deleter());
}
else
result.reset(strdup(p), malloced_char_star_deleter());
return result;
}
}//end namespace tools
using abigail::function_decl;

View File

@ -20,6 +20,7 @@
///@file
#include <tr1/memory>
#include <string>
#include <ostream>
#include <istream>
@ -64,5 +65,8 @@ enum file_type
file_type guess_file_type(std::istream& in);
file_type guess_file_type(const std::string& file_path);
std::tr1::shared_ptr<char>
make_path_absolute(const char*p);
}// end namespace tools
}//end namespace abigail

View File

@ -36,12 +36,14 @@ using std::string;
using std::ostream;
using std::cout;
using std::cerr;
using std::tr1::shared_ptr;
using abigail::translation_unit;
using abigail::translation_unit_sptr;
using abigail::corpus_sptr;
using abigail::comparison::translation_unit_diff_sptr;
using abigail::comparison::corpus_diff_sptr;
using abigail::comparison::compute_diff;
using namespace abigail::dwarf_reader;
using abigail::tools::check_file;
using abigail::tools::guess_file_type;
@ -66,8 +68,8 @@ struct options
bool show_linkage_names;
bool show_harmful_changes;
bool show_harmless_changes;
char** di_root_path1;
char** di_root_path2;
shared_ptr<char> di_root_path1;
shared_ptr<char> di_root_path2;
options()
: show_stats_only(false),
@ -82,9 +84,7 @@ struct options
show_all_vars(true),
show_linkage_names(true),
show_harmful_changes(true),
show_harmless_changes(false),
di_root_path1(0),
di_root_path2(0)
show_harmless_changes(false)
{}
};//end struct options;
@ -150,7 +150,9 @@ parse_command_line(int argc, char* argv[], options& opts)
int j = i + 1;
if (j >= argc)
return false;
opts.di_root_path1 = &argv[j];
// elfutils wants the root path to the debug info to be
// absolute.
opts.di_root_path1 = abigail::tools::make_path_absolute(argv[j]);
++i;
}
else if (!strcmp(argv[i], "--debug-info-dir2"))
@ -158,7 +160,9 @@ parse_command_line(int argc, char* argv[], options& opts)
int j = i + 1;
if (j >= argc)
return false;
opts.di_root_path2 = &argv[j];
// elfutils wants the root path to the debug info to be
// absolute.
opts.di_root_path2 = abigail::tools::make_path_absolute(argv[j]);
++i;
}
else if (!strcmp(argv[i], "--stat"))
@ -407,7 +411,11 @@ main(int argc, char* argv[])
}
translation_unit_sptr t1, t2;
abigail::dwarf_reader::status c1_status =
abigail::dwarf_reader::STATUS_OK,
c2_status = abigail::dwarf_reader::STATUS_OK;
corpus_sptr c1, c2;
char *di_dir1 = 0, *di_dir2 = 0;
switch (t1_type)
{
@ -420,8 +428,9 @@ main(int argc, char* argv[])
break;
case abigail::tools::FILE_TYPE_ELF:
case abigail::tools::FILE_TYPE_AR:
c1 = abigail::dwarf_reader::read_corpus_from_elf(opts.file1,
opts.di_root_path1);
di_dir1 = opts.di_root_path1.get();
c1_status = abigail::dwarf_reader::read_corpus_from_elf(opts.file1,
&di_dir1, c1);
break;
case abigail::tools::FILE_TYPE_XML_CORPUS:
c1 =
@ -443,8 +452,9 @@ main(int argc, char* argv[])
break;
case abigail::tools::FILE_TYPE_ELF:
case abigail::tools::FILE_TYPE_AR:
c2 = abigail::dwarf_reader::read_corpus_from_elf(opts.file2,
opts.di_root_path2);
di_dir2 = opts.di_root_path2.get();
c2_status = abigail::dwarf_reader::read_corpus_from_elf(opts.file2,
&di_dir2, c2);
break;
case abigail::tools::FILE_TYPE_XML_CORPUS:
c2 =
@ -458,13 +468,64 @@ main(int argc, char* argv[])
if (!t1 && !c1)
{
cerr << "failed to read input file " << opts.file1 << "\n";
return true;
if (c1_status != abigail::dwarf_reader::STATUS_OK)
{
switch (c1_status)
{
case abigail::dwarf_reader::STATUS_DEBUG_INFO_NOT_FOUND:
cerr << "could not find the debug info";
if(di_dir1 == 0)
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
cerr << "Maybe the root path to the debug information '"
<< di_dir1 << "' is wrong?\n";
break;
case abigail::dwarf_reader::STATUS_NO_SYMBOLS_FOUND:
cerr << "could not find the ELF symbols in the file '"
<< opts.file1
<< "'\n";
break;
case abigail::dwarf_reader::STATUS_OK:
// This cannot be!
abort();
}
return true;
}
}
if (!t2 && !c2)
{
cerr << "failed to read input file" << opts.file2 << "\n";
return true;
if (c2_status != abigail::dwarf_reader::STATUS_OK)
{
switch (c2_status)
{
case abigail::dwarf_reader::STATUS_DEBUG_INFO_NOT_FOUND:
cerr << "could not find the debug info";
if(di_dir2 == 0)
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
cerr << "Maybe the root path to the debug information '"
<< di_dir2
<< "' is wrong?\n";
break;
case abigail::dwarf_reader::STATUS_NO_SYMBOLS_FOUND:
cerr << "could not find the ELF symbols in the file '"
<< opts.file2
<< "'\n";
break;
case abigail::dwarf_reader::STATUS_OK:
// This cannot be!
abort();
}
return true;
}
}
if (!!c1 != !!c2

View File

@ -26,6 +26,7 @@
/// DWARF format) and emit it back in a set of "text sections" in native
/// libabigail XML format.
#include <unistd.h>
#include <cassert>
#include <cstring>
#include <cstdio>
@ -33,6 +34,7 @@
#include <string>
#include <iostream>
#include <fstream>
#include <tr1/memory>
#include "abg-tools-utils.h"
#include "abg-corpus.h"
#include "abg-dwarf-reader.h"
@ -43,15 +45,15 @@ using std::cerr;
using std::cout;
using std::ostream;
using std::ofstream;
using std::tr1::shared_ptr;
struct options
{
string in_file_path;
string out_file_path;
char** di_root_path;
string in_file_path;
string out_file_path;
shared_ptr<char> di_root_path;
options()
: di_root_path(0)
{}
};
@ -86,8 +88,9 @@ parse_command_line(int argc, char* argv[], options& opts)
|| argv[i + 1][0] == '-'
|| !opts.out_file_path.empty())
return false;
opts.di_root_path = &argv[i + 1];
// elfutils wants the root path to the debug info to be
// absolute.
opts.di_root_path = abigail::tools::make_path_absolute(argv[i + 1]);
++i;
}
else if (!strcmp(argv[i], "--out-file"))
@ -137,27 +140,38 @@ main(int argc, char* argv[])
using abigail::corpus_sptr;
using abigail::translation_units;
using abigail::dwarf_reader::read_corpus_from_elf;
using namespace abigail;
char* p = opts.di_root_path.get();
corpus_sptr corp;
dwarf_reader::status s = read_corpus_from_elf(opts.in_file_path, &p, corp);
corpus_sptr corp = read_corpus_from_elf(opts.in_file_path,
opts.di_root_path);
if (!corp)
{
if (opts.di_root_path == 0)
if (s == dwarf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
{
cerr <<
"Could not read debug info from "
<< opts.in_file_path << "\n";
if (p == 0)
{
cerr <<
"Could not read debug info from "
<< opts.in_file_path << "\n";
cerr << "You might want to supply the root directory where "
"to search debug info from, using the "
"--debug-info-dir option\n";
}
else
{
cerr << "Could not read debug info for " << opts.in_file_path
<< " from debug info root directory " << *opts.di_root_path
<< "\n";
cerr << "You might want to supply the root directory where "
"to search debug info from, using the "
"--debug-info-dir option "
"(e.g --debug-info-dir /usr/lib/debug)\n";
}
else
{
cerr << "Could not read debug info for '" << opts.in_file_path
<< "' from debug info root directory '" << p
<< "'\n";
}
}
else if (s == dwarf_reader::STATUS_NO_SYMBOLS_FOUND)
cerr << "Could not read ELF symbol information from "
<< opts.in_file_path << "\n";
return 1;
}

View File

@ -64,21 +64,20 @@ using abigail::xml_writer::write_corpus_to_archive;
struct options
{
string file_path;
bool read_from_stdin;
bool read_tu;
bool diff;
bool bidiff;
bool noout;
char** di_root_path;
string file_path;
bool read_from_stdin;
bool read_tu;
bool diff;
bool bidiff;
bool noout;
std::tr1::shared_ptr<char> di_root_path;
options()
: read_from_stdin(false),
read_tu(false),
diff(false),
bidiff(false),
noout(false),
di_root_path(0)
noout(false)
{}
};//end struct options;
@ -124,8 +123,9 @@ parse_command_line(int argc, char* argv[], options& opts)
if (argc <= i + 1
|| argv[i + 1][0] == '-')
return false;
opts.di_root_path = &argv[i + 1];
// elfutils wants the root path to the debug info to be
// absolute.
opts.di_root_path = abigail::tools::make_path_absolute(argv[i + 1]);
++i;
}
else if (!strcmp(argv[i], "--stdin"))
@ -194,6 +194,8 @@ main(int argc, char* argv[])
abigail::translation_unit_sptr tu;
abigail::corpus_sptr corp;
abigail::dwarf_reader::status s = abigail::dwarf_reader::STATUS_OK;
char* di_root_path = 0;
file_type type = guess_file_type(opts.file_path);
switch (type)
@ -206,8 +208,10 @@ main(int argc, char* argv[])
break;
case abigail::tools::FILE_TYPE_ELF:
case abigail::tools::FILE_TYPE_AR:
corp = read_corpus_from_elf(opts.file_path,
opts.di_root_path);
di_root_path = opts.di_root_path.get();
s= read_corpus_from_elf(opts.file_path,
&di_root_path,
corp);
break;
case abigail::tools::FILE_TYPE_XML_CORPUS:
corp = read_corpus_from_native_xml_file(opts.file_path);
@ -220,6 +224,31 @@ main(int argc, char* argv[])
if (!tu && !corp)
{
cerr << "failed to read " << opts.file_path << "\n";
if (s != abigail::dwarf_reader::STATUS_OK)
{
switch (s)
{
case abigail::dwarf_reader::STATUS_DEBUG_INFO_NOT_FOUND:
cerr << "could not find the debug info";
if(di_root_path == 0)
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
cerr << "Maybe the root path to the debug "
"information is wrong?\n";
break;
case abigail::dwarf_reader::STATUS_NO_SYMBOLS_FOUND:
cerr << "could not find the ELF symbols in the file "
<< opts.file_path
<< "\n";
break;
case abigail::dwarf_reader::STATUS_OK:
// This cannot be!
abort();
}
}
return true;
}