abidw: add support for CTF

This patch adds support for CTF to the abidw utility.  It depends on
the previous patch that makes abigail::ctf_reader::read_corpus to
return a status code.

	* tools/abidw.cc: Conditionally include abg-ctf-reader.h.
	(load_corpus_and_write_abixml): Do not get a
	dwarf_reader::read_context as an argument.
	(main): Adjust call to load_corpus_and_write_abixml accordingly.
	(struct options): New option use_ctf.
	(options): ... and initialize it.
	(display_usage): Document --ctf.
	(parse_command_line): Handle --ctf.
	* doc/manuals/abidw.rst: Document --ctf.

Signed-off-by: Jose E. Marchesi <jose.marchesi@oracle.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Jose E. Marchesi via Libabigail 2021-11-17 08:39:03 +01:00 committed by Dodji Seketeli
parent 8324a223df
commit 18569fc154
2 changed files with 213 additions and 177 deletions

View File

@ -268,6 +268,11 @@ Options
the --enable-debug-type-canonicalization option.
* ``--ctf``
Extract ABI information from CTF debug information, if present in
the given object.
* ``--annotate``
Annotate the ABIXML output with comments above most elements. The

View File

@ -26,6 +26,9 @@
#include "abg-tools-utils.h"
#include "abg-corpus.h"
#include "abg-dwarf-reader.h"
#ifdef WITH_CTF
#include "abg-ctf-reader.h"
#endif
#include "abg-writer.h"
#include "abg-reader.h"
#include "abg-comparison.h"
@ -64,10 +67,6 @@ using abigail::xml_writer::write_context_sptr;
using abigail::xml_writer::write_corpus;
using abigail::xml_reader::read_corpus_from_native_xml_file;
using abigail::xml_reader::create_native_xml_read_context;
using abigail::dwarf_reader::read_context;
using abigail::dwarf_reader::read_context_sptr;
using abigail::dwarf_reader::read_corpus_from_elf;
using abigail::dwarf_reader::create_read_context;
using namespace abigail;
struct options
@ -99,6 +98,9 @@ struct options
bool corpus_group_for_linux;
bool show_stats;
bool noout;
#ifdef WITH_CTF
bool use_ctf;
#endif
bool show_locs;
bool abidiff;
#ifdef WITH_DEBUG_SELF_COMPARISON
@ -133,6 +135,9 @@ struct options
corpus_group_for_linux(false),
show_stats(),
noout(),
#ifdef WITH_CTF
use_ctf(false),
#endif
show_locs(true),
abidiff(),
#ifdef WITH_DEBUG_SELF_COMPARISON
@ -207,6 +212,9 @@ display_usage(const string& prog_name, ostream& out)
#endif
#ifdef WITH_DEBUG_TYPE_CANONICALIZATION
<< " --debug-tc debug the type canonicalization process\n"
#endif
#ifdef WITH_CTF
<< " --ctf use CTF instead of DWARF in ELF files\n"
#endif
<< " --annotate annotate the ABI artifacts emitted in the output\n"
<< " --stats show statistics about various internal stuff\n"
@ -306,6 +314,10 @@ parse_command_line(int argc, char* argv[], options& opts)
}
else if (!strcmp(argv[i], "--noout"))
opts.noout = true;
#ifdef WITH_CTF
else if (!strcmp(argv[i], "--ctf"))
opts.use_ctf = true;
#endif
else if (!strcmp(argv[i], "--no-architecture"))
opts.write_architecture = false;
else if (!strcmp(argv[i], "--no-corpus-path"))
@ -462,7 +474,7 @@ maybe_check_header_files(const options& opts)
/// @param opts the options where to get the suppression
/// specifications from.
static void
set_suppressions(read_context& read_ctxt, options& opts)
set_suppressions(dwarf_reader::read_context& read_ctxt, options& opts)
{
suppressions_type supprs;
for (vector<string>::const_iterator i = opts.suppression_paths.begin();
@ -498,8 +510,6 @@ set_suppressions(read_context& read_ctxt, options& opts)
///
/// @param env the environment the ABI artifacts are being created in.
///
/// @param context the context of the ELF reading.
///
/// @param opts the options of the program.
///
/// @return the exit code: 0 if everything went fine, non-zero
@ -507,7 +517,6 @@ set_suppressions(read_context& read_ctxt, options& opts)
static int
load_corpus_and_write_abixml(char* argv[],
environment_sptr& env,
read_context_sptr& context,
options& opts)
{
int exit_code = 0;
@ -523,24 +532,90 @@ load_corpus_and_write_abixml(char* argv[],
env->debug_type_canonicalization_is_on(true);
#endif
read_context& ctxt = *context;
// First of all, read a libabigail IR corpus from the file specified
// in OPTS.
corpus_sptr corp;
elf_reader::status s = elf_reader::STATUS_UNKNOWN;
t.start();
corp = read_corpus_from_elf(ctxt, s);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "read corpus from elf file in: " << t << "\n";
#ifdef WITH_CTF
if (opts.use_ctf)
{
abigail::ctf_reader::read_context *ctxt
= abigail::ctf_reader::create_read_context (opts.in_file_path,
env.get());
t.start();
context.reset();
t.stop();
assert (ctxt);
t.start();
corp = abigail::ctf_reader::read_corpus (ctxt, s);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "read corpus from elf file in: " << t << "\n";
}
else
#endif
{
dwarf_reader::read_context_sptr c
= abigail::dwarf_reader::create_read_context(opts.in_file_path,
opts.prepared_di_root_paths,
env.get(),
opts.load_all_types,
opts.linux_kernel_mode);
dwarf_reader::read_context& ctxt = *c;
set_drop_undefined_syms(ctxt, opts.drop_undefined_syms);
set_show_stats(ctxt, opts.show_stats);
set_suppressions(ctxt, opts);
abigail::dwarf_reader::set_do_log(ctxt, opts.do_log);
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "reset read context in: " << t << "\n";
if (opts.check_alt_debug_info_path)
{
bool has_alt_di = false;
string alt_di_path;
abigail::elf_reader::status status =
abigail::dwarf_reader::has_alt_debug_info(ctxt,
has_alt_di,
alt_di_path);
if (status & abigail::elf_reader::STATUS_OK)
{
if (alt_di_path.empty())
;
else
{
cout << "found the alternate debug info file";
if (opts.show_base_name_alt_debug_info_path)
{
tools_utils::base_name(alt_di_path, alt_di_path);
cout << " '" << alt_di_path << "'";
}
cout << "\n";
}
return 0;
}
else
{
emit_prefix(argv[0], cerr)
<< "could not find alternate debug info file\n";
return 1;
}
}
t.start();
corp = dwarf_reader::read_corpus_from_elf(ctxt, s);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "read corpus from elf file in: " << t << "\n";
t.start();
c.reset();
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "reset read context in: " << t << "\n";
}
// If we couldn't create a corpus, emit some (hopefully) useful
// diagnostics and return and error.
if (!corp)
{
if (s == elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
@ -580,122 +655,122 @@ load_corpus_and_write_abixml(char* argv[],
return 1;
}
// Now create a write context and write out an ABI XML description
// of the read corpus.
t.start();
const write_context_sptr& write_ctxt
= create_write_context(corp->get_environment(), cout);
set_common_options(*write_ctxt, opts);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "created & initialized write context in: "
<< t << "\n";
if (opts.abidiff)
{
// Save the abi in abixml format in a temporary file, read
// it back, and compare the ABI of what we've read back
// against the ABI of the input ELF file.
temp_file_sptr tmp_file = temp_file::create();
set_ostream(*write_ctxt, tmp_file->get_stream());
write_corpus(*write_ctxt, corp, 0);
tmp_file->get_stream().flush();
#ifdef WITH_DEBUG_SELF_COMPARISON
if (opts.debug_abidiff)
{
opts.type_id_file_path = tmp_file->get_path() + string(".typeid");
write_canonical_type_ids(*write_ctxt, opts.type_id_file_path);
}
#endif
xml_reader::read_context_sptr read_ctxt =
create_native_xml_read_context(tmp_file->get_path(), env.get());
#ifdef WITH_DEBUG_SELF_COMPARISON
if (opts.debug_abidiff
&& !opts.type_id_file_path.empty())
load_canonical_type_ids(*read_ctxt, opts.type_id_file_path);
#endif
t.start();
corpus_sptr corp2 =
read_corpus_from_input(*read_ctxt);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "Read corpus in: " << t << "\n";
if (!corp2)
{
emit_prefix(argv[0], cerr)
<< "Could not read temporary XML representation of "
"elf file back\n";
return 1;
}
diff_context_sptr ctxt(new diff_context);
set_diff_context(ctxt);
ctxt->show_locs(opts.show_locs);
t.start();
corpus_diff_sptr diff = compute_diff(corp, corp2, ctxt);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "computed diff in: " << t << "\n";
bool has_error = diff->has_changes();
if (has_error)
{
t.start();
diff->report(cerr);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "emitted report in: " << t << "\n";
return 1;
}
return 0;
}
#ifdef WITH_DEBUG_SELF_COMPARISON
if (opts.debug_abidiff
&& !opts.type_id_file_path.empty())
remove(opts.type_id_file_path.c_str());
#endif
if (opts.noout)
return 0;
if (!opts.out_file_path.empty())
{
ofstream of(opts.out_file_path.c_str(), std::ios_base::trunc);
if (!of.is_open())
{
emit_prefix(argv[0], cerr)
<< "could not open output file '"
<< opts.out_file_path << "'\n";
return 1;
}
set_ostream(*write_ctxt, of);
t.start();
write_corpus(*write_ctxt, corp, 0);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "emitted abixml output in: " << t << "\n";
of.close();
return 0;
}
else
{
t.start();
const write_context_sptr& write_ctxt
= create_write_context(corp->get_environment(), cout);
set_common_options(*write_ctxt, opts);
exit_code = !write_corpus(*write_ctxt, corp, 0);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "created & initialized write context in: "
<< t << "\n";
if (opts.abidiff)
{
// Save the abi in abixml format in a temporary file, read
// it back, and compare the ABI of what we've read back
// against the ABI of the input ELF file.
temp_file_sptr tmp_file = temp_file::create();
set_ostream(*write_ctxt, tmp_file->get_stream());
write_corpus(*write_ctxt, corp, 0);
tmp_file->get_stream().flush();
#ifdef WITH_DEBUG_SELF_COMPARISON
if (opts.debug_abidiff)
{
opts.type_id_file_path = tmp_file->get_path() + string(".typeid");
write_canonical_type_ids(*write_ctxt, opts.type_id_file_path);
}
#endif
xml_reader::read_context_sptr read_ctxt =
create_native_xml_read_context(tmp_file->get_path(), env.get());
#ifdef WITH_DEBUG_SELF_COMPARISON
if (opts.debug_abidiff
&& !opts.type_id_file_path.empty())
load_canonical_type_ids(*read_ctxt, opts.type_id_file_path);
#endif
t.start();
corpus_sptr corp2 =
read_corpus_from_input(*read_ctxt);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "Read corpus in: " << t << "\n";
if (!corp2)
{
emit_prefix(argv[0], cerr)
<< "Could not read temporary XML representation of "
"elf file back\n";
return 1;
}
diff_context_sptr ctxt(new diff_context);
set_diff_context(ctxt);
ctxt->show_locs(opts.show_locs);
t.start();
corpus_diff_sptr diff = compute_diff(corp, corp2, ctxt);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "computed diff in: " << t << "\n";
bool has_error = diff->has_changes();
if (has_error)
{
t.start();
diff->report(cerr);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "emitted report in: " << t << "\n";
return 1;
}
return 0;
}
#ifdef WITH_DEBUG_SELF_COMPARISON
if (opts.debug_abidiff
&& !opts.type_id_file_path.empty())
remove(opts.type_id_file_path.c_str());
#endif
if (opts.noout)
return 0;
if (!opts.out_file_path.empty())
{
ofstream of(opts.out_file_path.c_str(), std::ios_base::trunc);
if (!of.is_open())
{
emit_prefix(argv[0], cerr)
<< "could not open output file '"
<< opts.out_file_path << "'\n";
return 1;
}
set_ostream(*write_ctxt, of);
t.start();
write_corpus(*write_ctxt, corp, 0);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "emitted abixml output in: " << t << "\n";
of.close();
return 0;
}
else
{
t.start();
exit_code = !write_corpus(*write_ctxt, corp, 0);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
<< "emitted abixml out in: " << t << "\n";
}
emit_prefix(argv[0], cerr)
<< "emitted abixml out in: " << t << "\n";
}
return exit_code;
@ -884,51 +959,7 @@ main(int argc, char* argv[])
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,
opts.prepared_di_root_paths,
env.get(),
opts.load_all_types,
opts.linux_kernel_mode);
read_context& ctxt = *c;
set_drop_undefined_syms(ctxt, opts.drop_undefined_syms);
set_show_stats(ctxt, opts.show_stats);
set_suppressions(ctxt, opts);
abigail::dwarf_reader::set_do_log(ctxt, opts.do_log);
if (opts.check_alt_debug_info_path)
{
bool has_alt_di = false;
string alt_di_path;
abigail::elf_reader::status status =
abigail::dwarf_reader::has_alt_debug_info(ctxt,
has_alt_di,
alt_di_path);
if (status & abigail::elf_reader::STATUS_OK)
{
if (alt_di_path.empty())
;
else
{
cout << "found the alternate debug info file";
if (opts.show_base_name_alt_debug_info_path)
{
tools_utils::base_name(alt_di_path, alt_di_path);
cout << " '" << alt_di_path << "'";
}
cout << "\n";
}
return 0;
}
else
{
emit_prefix(argv[0], cerr)
<< "could not find alternate debug info file\n";
return 1;
}
}
exit_code = load_corpus_and_write_abixml(argv, env, c, opts);
}
exit_code = load_corpus_and_write_abixml(argv, env, opts);
else
exit_code = load_kernel_corpus_group_and_write_abixml(argv, env, opts);