1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2020 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 ///@file
19 ///
20 /// This example shows how to walk the Internal Representation (IR)
21 /// graph of the ABI of a binary (called an ABI Corpus) and perform
22 /// actions on each node of the graph.
23 ///
24 /// Basically, one has to define a "visitor" which carries member
25 /// functions that are called during the traversal of the graph.
26 ///
27 /// On the visitor, there is potentially one member function pair per
28 /// type of node traversed.  Each time a given node is visited, the
29 /// corresponding member function pair is called by the traversal
30 /// machinery.  In other words, the visitor is notified each time a
31 /// node is traversed.
32 ///
33 /// To define a visitor, one has to create a type which implements
34 /// (inherits) the abigail::ir_node_visitor interface.  The visitor
35 /// must have a pair of node_begin() and node_end() function per type
36 /// of node that we wish to be notified for.
37 ///
38 ///  Once the visitor is defined, we can load an elf file and build an
39 ///  ABI corpus out of it by using the
40 ///  libabigail::dwarf_reader::read_corpus_from_elf() function, for
41 ///  instance.
42 ///
43 ///  Then we enumerate the translation units comprised in
44 ///  that ABI corpus and we invoke their "traverse()" method, using
45 ///  and instance of the visitor that we just defined.
46 ///
47 ///  Enjoy!
48 
49 struct name_printing_visitor : public abigail::ir_node_visitor
50 {
51   unsigned level_;
52 
name_printing_visitorname_printing_visitor53   name_printing_visitor()
54     : level_()
55   {
56     // Using this visitor, the IR walker will visit each type only
57     // once.
58     allow_visiting_already_visited_type_node(false);
59   }
60 
61   void
build_level_prefixname_printing_visitor62   build_level_prefix(string& str)
63   {
64     str.clear();
65     for (unsigned i = 0; i < level_; ++i)
66       str += ' ';
67   }
68 
69   string
build_level_prefixname_printing_visitor70   build_level_prefix()
71   {
72     string prefix;
73     build_level_prefix(prefix);
74     return prefix;
75   }
76 
77   bool
visit_beginname_printing_visitor78   visit_begin(abigail::namespace_decl* ns)
79   {
80     string prefix = build_level_prefix();
81 
82     cout << prefix << ns->get_pretty_representation() << "\n"
83 	 << prefix << "{\n";
84     ++level_;
85     return true;
86   }
87 
88   bool
visit_endname_printing_visitor89   visit_end(abigail::namespace_decl*)
90   {
91     string prefix = build_level_prefix();
92     cout << prefix << "}\n";
93     --level_;
94     return true;
95   }
96 
97   bool
visit_beginname_printing_visitor98   visit_begin(abigail::class_decl* klass)
99   {
100     string prefix = build_level_prefix();
101 
102     cout << prefix << klass->get_pretty_representation() << "\n"
103 	 << prefix << "{\n";
104     ++level_;
105     return true;
106   }
107 
108   bool
visit_endname_printing_visitor109   visit_end(abigail::class_decl*)
110   {
111     string prefix = build_level_prefix();
112     cout << prefix << "}\n";
113     --level_;
114     return true;
115   }
116 
117   bool
visit_beginname_printing_visitor118   visit_begin(abigail::function_decl* f)
119   {
120     string prefix = build_level_prefix();
121     cout << prefix << f->get_pretty_representation() << "\n";
122     ++level_;
123     return true;
124   }
125 
126   bool
visit_endname_printing_visitor127   visit_end(abigail::function_decl*)
128   {
129     --level_;
130     return true;
131   }
132 
133   bool
visit_beginname_printing_visitor134   visit_begin(abigail::var_decl* v)
135   {
136     string prefix = build_level_prefix();
137     cout << prefix << v->get_pretty_representation() << "\n";
138     ++level_;
139     return true;
140   }
141 
142   bool
visit_endname_printing_visitor143   visit_end(abigail::var_decl*)
144   {
145     --level_;
146     return true;
147   }
148 };
149 
150 int
main(int argc,char ** argv)151 main(int argc, char **argv)
152 {
153   if (argc < 2)
154     return 0;
155 
156   string file_name = argv[1];
157 
158   abigail::ir::environment_sptr env(new abigail::ir::environment);
159   abigail::corpus_sptr c;
160   abigail::dwarf_reader::status status = abigail::dwarf_reader::STATUS_OK;
161   std::vector<char**> di_roots;
162   if (!(c = abigail::dwarf_reader::read_corpus_from_elf(file_name, di_roots,
163 							env.get(),
164 							/*load_all_type=*/false,
165 							status)))
166     {
167       cerr << "failed to read " << file_name << "\n";
168       return 1;
169     }
170 
171   name_printing_visitor v;
172   // Now traverse each translation unit of the corpus using our
173   // instance of name_printing_visitor
174   for (abigail::ir::translation_units::const_iterator tu_iterator =
175 	 c->get_translation_units().begin();
176        tu_iterator != c->get_translation_units().end();
177        ++tu_iterator)
178     (*tu_iterator)->traverse(v);
179 }
180