xref: /aosp_15_r20/external/stg/stg.cc (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
1*9e3b08aeSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2*9e3b08aeSAndroid Build Coastguard Worker // -*- mode: C++ -*-
3*9e3b08aeSAndroid Build Coastguard Worker //
4*9e3b08aeSAndroid Build Coastguard Worker // Copyright 2022-2023 Google LLC
5*9e3b08aeSAndroid Build Coastguard Worker //
6*9e3b08aeSAndroid Build Coastguard Worker // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7*9e3b08aeSAndroid Build Coastguard Worker // "License"); you may not use this file except in compliance with the
8*9e3b08aeSAndroid Build Coastguard Worker // License.  You may obtain a copy of the License at
9*9e3b08aeSAndroid Build Coastguard Worker //
10*9e3b08aeSAndroid Build Coastguard Worker //     https://llvm.org/LICENSE.txt
11*9e3b08aeSAndroid Build Coastguard Worker //
12*9e3b08aeSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
13*9e3b08aeSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
14*9e3b08aeSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*9e3b08aeSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
16*9e3b08aeSAndroid Build Coastguard Worker // limitations under the License.
17*9e3b08aeSAndroid Build Coastguard Worker //
18*9e3b08aeSAndroid Build Coastguard Worker // Author: Giuliano Procida
19*9e3b08aeSAndroid Build Coastguard Worker 
20*9e3b08aeSAndroid Build Coastguard Worker #include <fcntl.h>
21*9e3b08aeSAndroid Build Coastguard Worker #include <getopt.h>
22*9e3b08aeSAndroid Build Coastguard Worker #include <sys/stat.h>
23*9e3b08aeSAndroid Build Coastguard Worker 
24*9e3b08aeSAndroid Build Coastguard Worker #include <cstring>
25*9e3b08aeSAndroid Build Coastguard Worker #include <iostream>
26*9e3b08aeSAndroid Build Coastguard Worker #include <map>
27*9e3b08aeSAndroid Build Coastguard Worker #include <memory>
28*9e3b08aeSAndroid Build Coastguard Worker #include <string>
29*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
30*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
31*9e3b08aeSAndroid Build Coastguard Worker 
32*9e3b08aeSAndroid Build Coastguard Worker #include <google/protobuf/io/zero_copy_stream_impl.h>
33*9e3b08aeSAndroid Build Coastguard Worker #include "deduplication.h"
34*9e3b08aeSAndroid Build Coastguard Worker #include "error.h"
35*9e3b08aeSAndroid Build Coastguard Worker #include "file_descriptor.h"
36*9e3b08aeSAndroid Build Coastguard Worker #include "filter.h"
37*9e3b08aeSAndroid Build Coastguard Worker #include "fingerprint.h"
38*9e3b08aeSAndroid Build Coastguard Worker #include "graph.h"
39*9e3b08aeSAndroid Build Coastguard Worker #include "input.h"
40*9e3b08aeSAndroid Build Coastguard Worker #include "proto_writer.h"
41*9e3b08aeSAndroid Build Coastguard Worker #include "reader_options.h"
42*9e3b08aeSAndroid Build Coastguard Worker #include "runtime.h"
43*9e3b08aeSAndroid Build Coastguard Worker #include "type_resolution.h"
44*9e3b08aeSAndroid Build Coastguard Worker #include "unification.h"
45*9e3b08aeSAndroid Build Coastguard Worker 
46*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
47*9e3b08aeSAndroid Build Coastguard Worker namespace {
48*9e3b08aeSAndroid Build Coastguard Worker 
49*9e3b08aeSAndroid Build Coastguard Worker struct GetInterface {
operator ()stg::__anon115c60660111::GetInterface50*9e3b08aeSAndroid Build Coastguard Worker   Interface& operator()(Interface& x) const {
51*9e3b08aeSAndroid Build Coastguard Worker     return x;
52*9e3b08aeSAndroid Build Coastguard Worker   }
53*9e3b08aeSAndroid Build Coastguard Worker 
54*9e3b08aeSAndroid Build Coastguard Worker   template <typename Node>
operator ()stg::__anon115c60660111::GetInterface55*9e3b08aeSAndroid Build Coastguard Worker   Interface& operator()(Node&) const {
56*9e3b08aeSAndroid Build Coastguard Worker     Die() << "expected an Interface root node";
57*9e3b08aeSAndroid Build Coastguard Worker   }
58*9e3b08aeSAndroid Build Coastguard Worker };
59*9e3b08aeSAndroid Build Coastguard Worker 
Merge(Runtime & runtime,Graph & graph,const std::vector<Id> & roots)60*9e3b08aeSAndroid Build Coastguard Worker Id Merge(Runtime& runtime, Graph& graph, const std::vector<Id>& roots) {
61*9e3b08aeSAndroid Build Coastguard Worker   bool failed = false;
62*9e3b08aeSAndroid Build Coastguard Worker   // this rewrites the graph on destruction
63*9e3b08aeSAndroid Build Coastguard Worker   Unification unification(runtime, graph, Id(0));
64*9e3b08aeSAndroid Build Coastguard Worker   unification.Reserve(graph.Limit());
65*9e3b08aeSAndroid Build Coastguard Worker   std::map<std::string, Id> symbols;
66*9e3b08aeSAndroid Build Coastguard Worker   std::map<std::string, Id> types;
67*9e3b08aeSAndroid Build Coastguard Worker   const GetInterface get;
68*9e3b08aeSAndroid Build Coastguard Worker   for (auto root : roots) {
69*9e3b08aeSAndroid Build Coastguard Worker     const auto& interface = graph.Apply(get, root);
70*9e3b08aeSAndroid Build Coastguard Worker     for (const auto& x : interface.symbols) {
71*9e3b08aeSAndroid Build Coastguard Worker       if (!symbols.insert(x).second) {
72*9e3b08aeSAndroid Build Coastguard Worker         Warn() << "duplicate symbol during merge: " << x.first;
73*9e3b08aeSAndroid Build Coastguard Worker         failed = true;
74*9e3b08aeSAndroid Build Coastguard Worker       }
75*9e3b08aeSAndroid Build Coastguard Worker     }
76*9e3b08aeSAndroid Build Coastguard Worker     // TODO: test type roots merge
77*9e3b08aeSAndroid Build Coastguard Worker     for (const auto& x : interface.types) {
78*9e3b08aeSAndroid Build Coastguard Worker       const auto [it, inserted] = types.insert(x);
79*9e3b08aeSAndroid Build Coastguard Worker       if (!inserted && !unification.Unify(x.second, it->second)) {
80*9e3b08aeSAndroid Build Coastguard Worker         Warn() << "type conflict during merge: " << x.first;
81*9e3b08aeSAndroid Build Coastguard Worker         failed = true;
82*9e3b08aeSAndroid Build Coastguard Worker       }
83*9e3b08aeSAndroid Build Coastguard Worker     }
84*9e3b08aeSAndroid Build Coastguard Worker     graph.Remove(root);
85*9e3b08aeSAndroid Build Coastguard Worker   }
86*9e3b08aeSAndroid Build Coastguard Worker   if (failed) {
87*9e3b08aeSAndroid Build Coastguard Worker     Die() << "merge failed";
88*9e3b08aeSAndroid Build Coastguard Worker   }
89*9e3b08aeSAndroid Build Coastguard Worker   return graph.Add<Interface>(symbols, types);
90*9e3b08aeSAndroid Build Coastguard Worker }
91*9e3b08aeSAndroid Build Coastguard Worker 
FilterSymbols(Graph & graph,Id root,const Filter & filter)92*9e3b08aeSAndroid Build Coastguard Worker void FilterSymbols(Graph& graph, Id root, const Filter& filter) {
93*9e3b08aeSAndroid Build Coastguard Worker   std::map<std::string, Id> symbols;
94*9e3b08aeSAndroid Build Coastguard Worker   GetInterface get;
95*9e3b08aeSAndroid Build Coastguard Worker   auto& interface = graph.Apply(get, root);
96*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& x : interface.symbols) {
97*9e3b08aeSAndroid Build Coastguard Worker     if (filter(x.first)) {
98*9e3b08aeSAndroid Build Coastguard Worker       symbols.insert(x);
99*9e3b08aeSAndroid Build Coastguard Worker     }
100*9e3b08aeSAndroid Build Coastguard Worker   }
101*9e3b08aeSAndroid Build Coastguard Worker   std::swap(interface.symbols, symbols);
102*9e3b08aeSAndroid Build Coastguard Worker }
103*9e3b08aeSAndroid Build Coastguard Worker 
Write(Runtime & runtime,const Graph & graph,Id root,const char * output,bool annotate)104*9e3b08aeSAndroid Build Coastguard Worker void Write(Runtime& runtime, const Graph& graph, Id root, const char* output,
105*9e3b08aeSAndroid Build Coastguard Worker            bool annotate) {
106*9e3b08aeSAndroid Build Coastguard Worker   const FileDescriptor output_fd(
107*9e3b08aeSAndroid Build Coastguard Worker       output, O_CREAT | O_WRONLY | O_TRUNC,
108*9e3b08aeSAndroid Build Coastguard Worker       S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
109*9e3b08aeSAndroid Build Coastguard Worker   google::protobuf::io::FileOutputStream os(output_fd.Value());
110*9e3b08aeSAndroid Build Coastguard Worker   {
111*9e3b08aeSAndroid Build Coastguard Worker     const Time x(runtime, "write");
112*9e3b08aeSAndroid Build Coastguard Worker     proto::Writer writer(graph);
113*9e3b08aeSAndroid Build Coastguard Worker     writer.Write(root, os, annotate);
114*9e3b08aeSAndroid Build Coastguard Worker     Check(os.Flush()) << "error writing to '" << output
115*9e3b08aeSAndroid Build Coastguard Worker                       << "': " << os.GetErrno();
116*9e3b08aeSAndroid Build Coastguard Worker   }
117*9e3b08aeSAndroid Build Coastguard Worker }
118*9e3b08aeSAndroid Build Coastguard Worker 
119*9e3b08aeSAndroid Build Coastguard Worker }  // namespace
120*9e3b08aeSAndroid Build Coastguard Worker }  // namespace stg
121*9e3b08aeSAndroid Build Coastguard Worker 
main(int argc,char * argv[])122*9e3b08aeSAndroid Build Coastguard Worker int main(int argc, char* argv[]) {
123*9e3b08aeSAndroid Build Coastguard Worker   // Process arguments.
124*9e3b08aeSAndroid Build Coastguard Worker   bool opt_metrics = false;
125*9e3b08aeSAndroid Build Coastguard Worker   bool opt_keep_duplicates = false;
126*9e3b08aeSAndroid Build Coastguard Worker   std::unique_ptr<stg::Filter> opt_file_filter;
127*9e3b08aeSAndroid Build Coastguard Worker   std::unique_ptr<stg::Filter> opt_symbol_filter;
128*9e3b08aeSAndroid Build Coastguard Worker   stg::ReadOptions opt_read_options;
129*9e3b08aeSAndroid Build Coastguard Worker   stg::InputFormat opt_input_format = stg::InputFormat::ABI;
130*9e3b08aeSAndroid Build Coastguard Worker   std::vector<std::pair<stg::InputFormat, const char*>> inputs;
131*9e3b08aeSAndroid Build Coastguard Worker   std::vector<const char*> outputs;
132*9e3b08aeSAndroid Build Coastguard Worker   bool opt_annotate = false;
133*9e3b08aeSAndroid Build Coastguard Worker   static option opts[] = {
134*9e3b08aeSAndroid Build Coastguard Worker       {"metrics",         no_argument,       nullptr, 'm'},
135*9e3b08aeSAndroid Build Coastguard Worker       {"keep-duplicates", no_argument,       nullptr, 'd'},
136*9e3b08aeSAndroid Build Coastguard Worker       {"types",           no_argument,       nullptr, 't'},
137*9e3b08aeSAndroid Build Coastguard Worker       {"files",           required_argument, nullptr, 'F'},
138*9e3b08aeSAndroid Build Coastguard Worker       {"file-filter",     required_argument, nullptr, 'F'},
139*9e3b08aeSAndroid Build Coastguard Worker       {"symbols",         required_argument, nullptr, 'S'},
140*9e3b08aeSAndroid Build Coastguard Worker       {"symbol-filter",   required_argument, nullptr, 'S'},
141*9e3b08aeSAndroid Build Coastguard Worker       {"abi",             no_argument,       nullptr, 'a'},
142*9e3b08aeSAndroid Build Coastguard Worker       {"btf",             no_argument,       nullptr, 'b'},
143*9e3b08aeSAndroid Build Coastguard Worker       {"elf",             no_argument,       nullptr, 'e'},
144*9e3b08aeSAndroid Build Coastguard Worker       {"stg",             no_argument,       nullptr, 's'},
145*9e3b08aeSAndroid Build Coastguard Worker       {"output",          required_argument, nullptr, 'o'},
146*9e3b08aeSAndroid Build Coastguard Worker       {"annotate",        no_argument,       nullptr, 'A'},
147*9e3b08aeSAndroid Build Coastguard Worker       {nullptr,           0,                 nullptr, 0  },
148*9e3b08aeSAndroid Build Coastguard Worker   };
149*9e3b08aeSAndroid Build Coastguard Worker   auto usage = [&]() {
150*9e3b08aeSAndroid Build Coastguard Worker     std::cerr << "usage: " << argv[0] << '\n'
151*9e3b08aeSAndroid Build Coastguard Worker               << "  [-m|--metrics]\n"
152*9e3b08aeSAndroid Build Coastguard Worker               << "  [-d|--keep-duplicates]\n"
153*9e3b08aeSAndroid Build Coastguard Worker               << "  [-t|--types]\n"
154*9e3b08aeSAndroid Build Coastguard Worker               << "  [-F|--files|--file-filter <filter>]\n"
155*9e3b08aeSAndroid Build Coastguard Worker               << "  [-S|--symbols|--symbol-filter <filter>]\n"
156*9e3b08aeSAndroid Build Coastguard Worker               << "  [-a|--abi|-b|--btf|-e|--elf|-s|--stg] [file] ...\n"
157*9e3b08aeSAndroid Build Coastguard Worker               << "  [{-o|--output} {filename|-}] ...\n"
158*9e3b08aeSAndroid Build Coastguard Worker               << "  [-A|--annotate]\n"
159*9e3b08aeSAndroid Build Coastguard Worker               << "implicit defaults: --abi\n";
160*9e3b08aeSAndroid Build Coastguard Worker     stg::FilterUsage(std::cerr);
161*9e3b08aeSAndroid Build Coastguard Worker     return 1;
162*9e3b08aeSAndroid Build Coastguard Worker   };
163*9e3b08aeSAndroid Build Coastguard Worker   while (true) {
164*9e3b08aeSAndroid Build Coastguard Worker     int ix;
165*9e3b08aeSAndroid Build Coastguard Worker     const int c = getopt_long(argc, argv, "-mdtS:F:abeso:A", opts, &ix);
166*9e3b08aeSAndroid Build Coastguard Worker     if (c == -1) {
167*9e3b08aeSAndroid Build Coastguard Worker       break;
168*9e3b08aeSAndroid Build Coastguard Worker     }
169*9e3b08aeSAndroid Build Coastguard Worker     const char* argument = optarg;
170*9e3b08aeSAndroid Build Coastguard Worker     switch (c) {
171*9e3b08aeSAndroid Build Coastguard Worker       case 'm':
172*9e3b08aeSAndroid Build Coastguard Worker         opt_metrics = true;
173*9e3b08aeSAndroid Build Coastguard Worker         break;
174*9e3b08aeSAndroid Build Coastguard Worker       case 'd':
175*9e3b08aeSAndroid Build Coastguard Worker         opt_keep_duplicates = true;
176*9e3b08aeSAndroid Build Coastguard Worker         break;
177*9e3b08aeSAndroid Build Coastguard Worker       case 't':
178*9e3b08aeSAndroid Build Coastguard Worker         opt_read_options.Set(stg::ReadOptions::TYPE_ROOTS);
179*9e3b08aeSAndroid Build Coastguard Worker         break;
180*9e3b08aeSAndroid Build Coastguard Worker       case 'F':
181*9e3b08aeSAndroid Build Coastguard Worker         opt_file_filter = stg::MakeFilter(argument);
182*9e3b08aeSAndroid Build Coastguard Worker         break;
183*9e3b08aeSAndroid Build Coastguard Worker       case 'S':
184*9e3b08aeSAndroid Build Coastguard Worker         opt_symbol_filter = stg::MakeFilter(argument);
185*9e3b08aeSAndroid Build Coastguard Worker         break;
186*9e3b08aeSAndroid Build Coastguard Worker       case 'a':
187*9e3b08aeSAndroid Build Coastguard Worker         opt_input_format = stg::InputFormat::ABI;
188*9e3b08aeSAndroid Build Coastguard Worker         break;
189*9e3b08aeSAndroid Build Coastguard Worker       case 'b':
190*9e3b08aeSAndroid Build Coastguard Worker         opt_input_format = stg::InputFormat::BTF;
191*9e3b08aeSAndroid Build Coastguard Worker         break;
192*9e3b08aeSAndroid Build Coastguard Worker       case 'e':
193*9e3b08aeSAndroid Build Coastguard Worker         opt_input_format = stg::InputFormat::ELF;
194*9e3b08aeSAndroid Build Coastguard Worker         break;
195*9e3b08aeSAndroid Build Coastguard Worker       case 's':
196*9e3b08aeSAndroid Build Coastguard Worker         opt_input_format = stg::InputFormat::STG;
197*9e3b08aeSAndroid Build Coastguard Worker         break;
198*9e3b08aeSAndroid Build Coastguard Worker       case 1:
199*9e3b08aeSAndroid Build Coastguard Worker         inputs.emplace_back(opt_input_format, argument);
200*9e3b08aeSAndroid Build Coastguard Worker         break;
201*9e3b08aeSAndroid Build Coastguard Worker       case 'o':
202*9e3b08aeSAndroid Build Coastguard Worker         if (strcmp(argument, "-") == 0) {
203*9e3b08aeSAndroid Build Coastguard Worker           argument = "/dev/stdout";
204*9e3b08aeSAndroid Build Coastguard Worker         }
205*9e3b08aeSAndroid Build Coastguard Worker         outputs.push_back(argument);
206*9e3b08aeSAndroid Build Coastguard Worker         break;
207*9e3b08aeSAndroid Build Coastguard Worker       case 'A':
208*9e3b08aeSAndroid Build Coastguard Worker         opt_annotate = true;
209*9e3b08aeSAndroid Build Coastguard Worker         break;
210*9e3b08aeSAndroid Build Coastguard Worker       default:
211*9e3b08aeSAndroid Build Coastguard Worker         return usage();
212*9e3b08aeSAndroid Build Coastguard Worker     }
213*9e3b08aeSAndroid Build Coastguard Worker   }
214*9e3b08aeSAndroid Build Coastguard Worker 
215*9e3b08aeSAndroid Build Coastguard Worker   try {
216*9e3b08aeSAndroid Build Coastguard Worker     stg::Graph graph;
217*9e3b08aeSAndroid Build Coastguard Worker     stg::Runtime runtime(std::cerr, opt_metrics);
218*9e3b08aeSAndroid Build Coastguard Worker     std::vector<stg::Id> roots;
219*9e3b08aeSAndroid Build Coastguard Worker     roots.reserve(inputs.size());
220*9e3b08aeSAndroid Build Coastguard Worker     for (auto& [format, input] : inputs) {
221*9e3b08aeSAndroid Build Coastguard Worker       roots.push_back(stg::Read(runtime, graph, format, input, opt_read_options,
222*9e3b08aeSAndroid Build Coastguard Worker                                 opt_file_filter));
223*9e3b08aeSAndroid Build Coastguard Worker     }
224*9e3b08aeSAndroid Build Coastguard Worker     stg::Id root =
225*9e3b08aeSAndroid Build Coastguard Worker         roots.size() == 1 ? roots[0] : stg::Merge(runtime, graph, roots);
226*9e3b08aeSAndroid Build Coastguard Worker     if (opt_symbol_filter) {
227*9e3b08aeSAndroid Build Coastguard Worker       stg::FilterSymbols(graph, root, *opt_symbol_filter);
228*9e3b08aeSAndroid Build Coastguard Worker     }
229*9e3b08aeSAndroid Build Coastguard Worker     if (!opt_keep_duplicates) {
230*9e3b08aeSAndroid Build Coastguard Worker       {
231*9e3b08aeSAndroid Build Coastguard Worker         stg::Unification unification(runtime, graph, stg::Id(0));
232*9e3b08aeSAndroid Build Coastguard Worker         unification.Reserve(graph.Limit());
233*9e3b08aeSAndroid Build Coastguard Worker         stg::ResolveTypes(runtime, graph, unification, {root});
234*9e3b08aeSAndroid Build Coastguard Worker         unification.Update(root);
235*9e3b08aeSAndroid Build Coastguard Worker       }
236*9e3b08aeSAndroid Build Coastguard Worker       const auto hashes = stg::Fingerprint(runtime, graph, root);
237*9e3b08aeSAndroid Build Coastguard Worker       root = stg::Deduplicate(runtime, graph, root, hashes);
238*9e3b08aeSAndroid Build Coastguard Worker     }
239*9e3b08aeSAndroid Build Coastguard Worker     for (auto output : outputs) {
240*9e3b08aeSAndroid Build Coastguard Worker       stg::Write(runtime, graph, root, output, opt_annotate);
241*9e3b08aeSAndroid Build Coastguard Worker     }
242*9e3b08aeSAndroid Build Coastguard Worker     return 0;
243*9e3b08aeSAndroid Build Coastguard Worker   } catch (const stg::Exception& e) {
244*9e3b08aeSAndroid Build Coastguard Worker     std::cerr << e.what();
245*9e3b08aeSAndroid Build Coastguard Worker     return 1;
246*9e3b08aeSAndroid Build Coastguard Worker   }
247*9e3b08aeSAndroid Build Coastguard Worker }
248