• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2022 Red Hat, Inc.
5 
6 #include <string>
7 #include <fstream>
8 #include <iostream>
9 #include <cstdlib>
10 #include "abg-dwarf-reader.h"
11 #include "test-utils.h"
12 
13 using std::string;
14 using std::ofstream;
15 using std::cerr;
16 using std::cout;
17 
18 using namespace abigail;
19 
20 ///@file
21 ///
22 /// This example shows how to walk the Internal Representation (IR)
23 /// graph of the ABI of a binary (called an ABI Corpus) and perform
24 /// actions on each node of the graph.
25 ///
26 /// Basically, one has to define a "visitor" which carries member
27 /// functions that are called during the traversal of the graph.
28 ///
29 /// On the visitor, there is potentially one member function pair per
30 /// type of node traversed.  Each time a given node is visited, the
31 /// corresponding member function pair is called by the traversal
32 /// machinery.  In other words, the visitor is notified each time a
33 /// node is traversed.
34 ///
35 /// To define a visitor, one has to create a type which implements
36 /// (inherits) the abigail::ir_node_visitor interface.  The visitor
37 /// must have a pair of node_begin() and node_end() function per type
38 /// of node that we wish to be notified for.
39 ///
40 ///  Once the visitor is defined, we can load an elf file and build an
41 ///  ABI corpus out of it by using the
42 ///  libabigail::dwarf_reader::read_corpus_from_elf() function, for
43 ///  instance.
44 ///
45 ///  Then we enumerate the translation units comprised in
46 ///  that ABI corpus and we invoke their "traverse()" method, using
47 ///  and instance of the visitor that we just defined.
48 ///
49 ///  Enjoy!
50 
51 struct name_printing_visitor : public abigail::ir_node_visitor
52 {
53   unsigned level_;
54 
name_printing_visitorname_printing_visitor55   name_printing_visitor()
56     : level_()
57   {
58     // Using this visitor, the IR walker will visit each type only
59     // once.
60     allow_visiting_already_visited_type_node(false);
61   }
62 
63   void
build_level_prefixname_printing_visitor64   build_level_prefix(string& str)
65   {
66     str.clear();
67     for (unsigned i = 0; i < level_; ++i)
68       str += ' ';
69   }
70 
71   string
build_level_prefixname_printing_visitor72   build_level_prefix()
73   {
74     string prefix;
75     build_level_prefix(prefix);
76     return prefix;
77   }
78 
79   bool
visit_beginname_printing_visitor80   visit_begin(abigail::namespace_decl* ns)
81   {
82     string prefix = build_level_prefix();
83 
84     cout << prefix << ns->get_pretty_representation() << "\n"
85 	 << prefix << "{\n";
86     ++level_;
87     return true;
88   }
89 
90   bool
visit_endname_printing_visitor91   visit_end(abigail::namespace_decl*)
92   {
93     string prefix = build_level_prefix();
94     cout << prefix << "}\n";
95     --level_;
96     return true;
97   }
98 
99   bool
visit_beginname_printing_visitor100   visit_begin(abigail::class_decl* klass)
101   {
102     string prefix = build_level_prefix();
103 
104     cout << prefix << klass->get_pretty_representation() << "\n"
105 	 << prefix << "{\n";
106     ++level_;
107     return true;
108   }
109 
110   bool
visit_endname_printing_visitor111   visit_end(abigail::class_decl*)
112   {
113     string prefix = build_level_prefix();
114     cout << prefix << "}\n";
115     --level_;
116     return true;
117   }
118 
119   bool
visit_beginname_printing_visitor120   visit_begin(abigail::function_decl* f)
121   {
122     string prefix = build_level_prefix();
123     cout << prefix << f->get_pretty_representation() << "\n";
124     ++level_;
125     return true;
126   }
127 
128   bool
visit_endname_printing_visitor129   visit_end(abigail::function_decl*)
130   {
131     --level_;
132     return true;
133   }
134 
135   bool
visit_beginname_printing_visitor136   visit_begin(abigail::var_decl* v)
137   {
138     string prefix = build_level_prefix();
139     cout << prefix << v->get_pretty_representation() << "\n";
140     ++level_;
141     return true;
142   }
143 
144   bool
visit_endname_printing_visitor145   visit_end(abigail::var_decl*)
146   {
147     --level_;
148     return true;
149   }
150 };
151 
152 int
main(int argc,char ** argv)153 main(int argc, char **argv)
154 {
155   if (argc < 2)
156     return 0;
157 
158   string file_name = argv[1];
159 
160   abigail::ir::environment env;
161   abigail::corpus_sptr c;
162   abigail::fe_iface::status status = abigail::fe_iface::STATUS_OK;
163   std::vector<char**> di_roots;
164   if (!(c = dwarf::read_corpus_from_elf(file_name, di_roots, env,
165 					/*load_all_type=*/false,
166 					status)))
167     {
168       cerr << "failed to read " << file_name << "\n";
169       return 1;
170     }
171 
172   name_printing_visitor v;
173   // Now traverse each translation unit of the corpus using our
174   // instance of name_printing_visitor
175   for (abigail::ir::translation_units::const_iterator tu_iterator =
176 	 c->get_translation_units().begin();
177        tu_iterator != c->get_translation_units().end();
178        ++tu_iterator)
179     (*tu_iterator)->traverse(v);
180 }
181