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