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