// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -*- Mode: C++ -*- // // Copyright (C) 2013-2020 Red Hat, Inc. #include #include #include #include #include "abg-dwarf-reader.h" #include "test-utils.h" using std::string; using std::ofstream; using std::cerr; using std::cout; ///@file /// /// This example shows how to walk the Internal Representation (IR) /// graph of the ABI of a binary (called an ABI Corpus) and perform /// actions on each node of the graph. /// /// Basically, one has to define a "visitor" which carries member /// functions that are called during the traversal of the graph. /// /// On the visitor, there is potentially one member function pair per /// type of node traversed. Each time a given node is visited, the /// corresponding member function pair is called by the traversal /// machinery. In other words, the visitor is notified each time a /// node is traversed. /// /// To define a visitor, one has to create a type which implements /// (inherits) the abigail::ir_node_visitor interface. The visitor /// must have a pair of node_begin() and node_end() function per type /// of node that we wish to be notified for. /// /// Once the visitor is defined, we can load an elf file and build an /// ABI corpus out of it by using the /// libabigail::dwarf_reader::read_corpus_from_elf() function, for /// instance. /// /// Then we enumerate the translation units comprised in /// that ABI corpus and we invoke their "traverse()" method, using /// and instance of the visitor that we just defined. /// /// Enjoy! struct name_printing_visitor : public abigail::ir_node_visitor { unsigned level_; name_printing_visitor() : level_() { // Using this visitor, the IR walker will visit each type only // once. allow_visiting_already_visited_type_node(false); } void build_level_prefix(string& str) { str.clear(); for (unsigned i = 0; i < level_; ++i) str += ' '; } string build_level_prefix() { string prefix; build_level_prefix(prefix); return prefix; } bool visit_begin(abigail::namespace_decl* ns) { string prefix = build_level_prefix(); cout << prefix << ns->get_pretty_representation() << "\n" << prefix << "{\n"; ++level_; return true; } bool visit_end(abigail::namespace_decl*) { string prefix = build_level_prefix(); cout << prefix << "}\n"; --level_; return true; } bool visit_begin(abigail::class_decl* klass) { string prefix = build_level_prefix(); cout << prefix << klass->get_pretty_representation() << "\n" << prefix << "{\n"; ++level_; return true; } bool visit_end(abigail::class_decl*) { string prefix = build_level_prefix(); cout << prefix << "}\n"; --level_; return true; } bool visit_begin(abigail::function_decl* f) { string prefix = build_level_prefix(); cout << prefix << f->get_pretty_representation() << "\n"; ++level_; return true; } bool visit_end(abigail::function_decl*) { --level_; return true; } bool visit_begin(abigail::var_decl* v) { string prefix = build_level_prefix(); cout << prefix << v->get_pretty_representation() << "\n"; ++level_; return true; } bool visit_end(abigail::var_decl*) { --level_; return true; } }; int main(int argc, char **argv) { if (argc < 2) return 0; string file_name = argv[1]; abigail::ir::environment_sptr env(new abigail::ir::environment); abigail::corpus_sptr c; abigail::dwarf_reader::status status = abigail::dwarf_reader::STATUS_OK; std::vector di_roots; if (!(c = abigail::dwarf_reader::read_corpus_from_elf(file_name, di_roots, env.get(), /*load_all_type=*/false, status))) { cerr << "failed to read " << file_name << "\n"; return 1; } name_printing_visitor v; // Now traverse each translation unit of the corpus using our // instance of name_printing_visitor for (abigail::ir::translation_units::const_iterator tu_iterator = c->get_translation_units().begin(); tu_iterator != c->get_translation_units().end(); ++tu_iterator) (*tu_iterator)->traverse(v); }