xref: /aosp_15_r20/external/stg/proto_reader.cc (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright 2022-2024 Google LLC
5 //
6 // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7 // "License"); you may not use this file except in compliance with the
8 // License.  You may obtain a copy of the License at
9 //
10 //     https://llvm.org/LICENSE.txt
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
18 // Author: Siddharth Nayyar
19 
20 #include "proto_reader.h"
21 
22 #include <algorithm>
23 #include <array>
24 #include <cerrno>
25 #include <cstdint>
26 #include <fstream>
27 #include <limits>
28 #include <map>
29 #include <optional>
30 #include <string>
31 #include <string_view>
32 #include <vector>
33 
34 #include <google/protobuf/io/tokenizer.h>
35 #include <google/protobuf/io/zero_copy_stream.h>
36 #include <google/protobuf/io/zero_copy_stream_impl.h>
37 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
38 #include <google/protobuf/repeated_field.h>
39 #include <google/protobuf/repeated_ptr_field.h>
40 #include <google/protobuf/text_format.h>
41 #include "error.h"
42 #include "graph.h"
43 #include "hex.h"
44 #include "runtime.h"
45 #include "stg.pb.h"
46 
47 namespace stg {
48 namespace proto {
49 
50 namespace {
51 
52 struct Transformer {
Transformerstg::proto::__anonc9b4b7de0111::Transformer53   explicit Transformer(Graph& graph) : graph(graph), maker(graph) {}
54 
55   Id Transform(const proto::STG&);
56 
57   Id GetId(uint32_t);
58 
59   template <typename ProtoType>
60   void AddNodes(const google::protobuf::RepeatedPtrField<ProtoType>&);
61   void AddNode(const Void&);
62   void AddNode(const Variadic&);
63   void AddNode(const Special&);
64   void AddNode(const PointerReference&);
65   void AddNode(const PointerToMember&);
66   void AddNode(const Typedef&);
67   void AddNode(const Qualified&);
68   void AddNode(const Primitive&);
69   void AddNode(const Array&);
70   void AddNode(const BaseClass&);
71   void AddNode(const Method&);
72   void AddNode(const Member&);
73   void AddNode(const Variant&);
74   void AddNode(const StructUnion&);
75   void AddNode(const Enumeration&);
76   void AddNode(const VariantMember&);
77   void AddNode(const Function&);
78   void AddNode(const ElfSymbol&);
79   void AddNode(const Symbols&);
80   void AddNode(const Interface&);
81   template <typename STGType, typename... Args>
82   void AddNode(uint32_t, Args&&...);
83 
84   std::vector<Id> Transform(const google::protobuf::RepeatedField<uint32_t>&);
85   template <typename GetKey>
86   std::map<std::string, Id> Transform(GetKey,
87                                       const google::protobuf::RepeatedField<uint32_t>&);
88   stg::Special::Kind Transform(Special::Kind);
89   stg::PointerReference::Kind Transform(PointerReference::Kind);
90   stg::Qualifier Transform(Qualified::Qualifier);
91   stg::Primitive::Encoding Transform(Primitive::Encoding);
92   stg::BaseClass::Inheritance Transform(BaseClass::Inheritance);
93   stg::StructUnion::Kind Transform(StructUnion::Kind);
94   stg::ElfSymbol::SymbolType Transform(ElfSymbol::SymbolType);
95   stg::ElfSymbol::Binding Transform(ElfSymbol::Binding);
96   stg::ElfSymbol::Visibility Transform(ElfSymbol::Visibility);
97   stg::Enumeration::Enumerators Transform(
98       const google::protobuf::RepeatedPtrField<Enumeration::Enumerator>&);
99   template <typename STGType, typename ProtoType>
100   std::optional<STGType> Transform(bool, const ProtoType&);
101   template <typename Type>
102   Type Transform(const Type&);
103 
104   Graph& graph;
105   Maker<Hex<uint32_t>> maker;
106 };
107 
Transform(const proto::STG & x)108 Id Transformer::Transform(const proto::STG& x) {
109   AddNodes(x.void_());  // deprecated
110   AddNodes(x.variadic());  // deprecated
111   AddNodes(x.special());
112   AddNodes(x.pointer_reference());
113   AddNodes(x.pointer_to_member());
114   AddNodes(x.typedef_());
115   AddNodes(x.qualified());
116   AddNodes(x.primitive());
117   AddNodes(x.array());
118   AddNodes(x.base_class());
119   AddNodes(x.method());
120   AddNodes(x.member());
121   AddNodes(x.variant_member());
122   AddNodes(x.struct_union());
123   AddNodes(x.enumeration());
124   AddNodes(x.variant());
125   AddNodes(x.function());
126   AddNodes(x.elf_symbol());
127   AddNodes(x.symbols());
128   AddNodes(x.interface());
129   return GetId(x.root_id());
130 }
131 
GetId(uint32_t id)132 Id Transformer::GetId(uint32_t id) {
133   return maker.Get(Hex(id));
134 }
135 
136 template <typename ProtoType>
AddNodes(const google::protobuf::RepeatedPtrField<ProtoType> & x)137 void Transformer::AddNodes(const google::protobuf::RepeatedPtrField<ProtoType>& x) {
138   for (const ProtoType& proto : x) {
139     AddNode(proto);
140   }
141 }
142 
AddNode(const Void & x)143 void Transformer::AddNode(const Void& x) {
144   AddNode<stg::Special>(x.id(), stg::Special::Kind::VOID);
145 }
146 
AddNode(const Variadic & x)147 void Transformer::AddNode(const Variadic& x) {
148   AddNode<stg::Special>(x.id(), stg::Special::Kind::VARIADIC);
149 }
150 
AddNode(const Special & x)151 void Transformer::AddNode(const Special& x) {
152   AddNode<stg::Special>(x.id(), x.kind());
153 }
154 
AddNode(const PointerReference & x)155 void Transformer::AddNode(const PointerReference& x) {
156   AddNode<stg::PointerReference>(x.id(), x.kind(), GetId(x.pointee_type_id()));
157 }
158 
AddNode(const PointerToMember & x)159 void Transformer::AddNode(const PointerToMember& x) {
160   AddNode<stg::PointerToMember>(x.id(), GetId(x.containing_type_id()),
161                                 GetId(x.pointee_type_id()));
162 }
163 
AddNode(const Typedef & x)164 void Transformer::AddNode(const Typedef& x) {
165   AddNode<stg::Typedef>(x.id(), x.name(), GetId(x.referred_type_id()));
166 }
167 
AddNode(const Qualified & x)168 void Transformer::AddNode(const Qualified& x) {
169   AddNode<stg::Qualified>(x.id(), x.qualifier(), GetId(x.qualified_type_id()));
170 }
171 
AddNode(const Primitive & x)172 void Transformer::AddNode(const Primitive& x) {
173   const auto& encoding =
174       Transform<stg::Primitive::Encoding>(x.has_encoding(), x.encoding());
175   AddNode<stg::Primitive>(x.id(), x.name(), encoding, x.bytesize());
176 }
177 
AddNode(const Array & x)178 void Transformer::AddNode(const Array& x) {
179   AddNode<stg::Array>(x.id(), x.number_of_elements(),
180                       GetId(x.element_type_id()));
181 }
182 
AddNode(const BaseClass & x)183 void Transformer::AddNode(const BaseClass& x) {
184   AddNode<stg::BaseClass>(x.id(), GetId(x.type_id()), x.offset(),
185                           x.inheritance());
186 }
187 
AddNode(const Method & x)188 void Transformer::AddNode(const Method& x) {
189   AddNode<stg::Method>(x.id(), x.mangled_name(), x.name(), x.vtable_offset(),
190                        GetId(x.type_id()));
191 }
192 
AddNode(const Member & x)193 void Transformer::AddNode(const Member& x) {
194   AddNode<stg::Member>(x.id(), x.name(), GetId(x.type_id()), x.offset(),
195                        x.bitsize());
196 }
197 
AddNode(const VariantMember & x)198 void Transformer::AddNode(const VariantMember& x) {
199   const auto& discr_value = x.has_discriminant_value()
200                                 ? std::make_optional(x.discriminant_value())
201                                 : std::nullopt;
202   AddNode<stg::VariantMember>(x.id(), x.name(), discr_value,
203                               GetId(x.type_id()));
204 }
205 
AddNode(const StructUnion & x)206 void Transformer::AddNode(const StructUnion& x) {
207   if (x.has_definition()) {
208     AddNode<stg::StructUnion>(
209         x.id(), x.kind(), x.name(), x.definition().bytesize(),
210         x.definition().base_class_id(), x.definition().method_id(),
211         x.definition().member_id());
212   } else {
213     AddNode<stg::StructUnion>(x.id(), x.kind(), x.name());
214   }
215 }
216 
AddNode(const Enumeration & x)217 void Transformer::AddNode(const Enumeration& x) {
218   if (x.has_definition()) {
219     AddNode<stg::Enumeration>(x.id(), x.name(),
220                               GetId(x.definition().underlying_type_id()),
221                               x.definition().enumerator());
222     return;
223   } else {
224     AddNode<stg::Enumeration>(x.id(), x.name());
225   }
226 }
227 
AddNode(const Variant & x)228 void Transformer::AddNode(const Variant& x) {
229   const auto& discriminant = x.has_discriminant()
230                                  ? std::make_optional(GetId(x.discriminant()))
231                                  : std::nullopt;
232   AddNode<stg::Variant>(x.id(), x.name(), x.bytesize(), discriminant,
233                         x.member_id());
234 }
235 
AddNode(const Function & x)236 void Transformer::AddNode(const Function& x) {
237   AddNode<stg::Function>(x.id(), GetId(x.return_type_id()), x.parameter_id());
238 }
239 
AddNode(const ElfSymbol & x)240 void Transformer::AddNode(const ElfSymbol& x) {
241   auto make_version_info = [](const ElfSymbol::VersionInfo& x) {
242     return std::make_optional(
243         stg::ElfSymbol::VersionInfo{x.is_default(), x.name()});
244   };
245   const std::optional<stg::ElfSymbol::VersionInfo> version_info =
246       x.has_version_info() ? make_version_info(x.version_info()) : std::nullopt;
247   const auto& crc = x.has_crc()
248                         ? std::make_optional<stg::ElfSymbol::CRC>(x.crc())
249                         : std::nullopt;
250   const auto& ns = Transform<std::string>(x.has_namespace_(), x.namespace_());
251   const auto& type_id =
252       x.has_type_id() ? std::make_optional(GetId(x.type_id())) : std::nullopt;
253   const auto& full_name =
254       Transform<std::string>(x.has_full_name(), x.full_name());
255 
256   AddNode<stg::ElfSymbol>(x.id(), x.name(), version_info, x.is_defined(),
257                           x.symbol_type(), x.binding(), x.visibility(), crc, ns,
258                           type_id, full_name);
259 }
260 
AddNode(const Symbols & x)261 void Transformer::AddNode(const Symbols& x) {
262   std::map<std::string, Id> symbols;
263   for (const auto& [symbol, id] : x.symbol()) {
264     symbols.emplace(symbol, GetId(id));
265   }
266   AddNode<stg::Interface>(x.id(), symbols);
267 }
268 
AddNode(const Interface & x)269 void Transformer::AddNode(const Interface& x) {
270   const InterfaceKey get_key(graph);
271   AddNode<stg::Interface>(x.id(), Transform(get_key, x.symbol_id()),
272                           Transform(get_key, x.type_id()));
273 }
274 
275 template <typename STGType, typename... Args>
AddNode(uint32_t id,Args &&...args)276 void Transformer::AddNode(uint32_t id, Args&&... args) {
277   maker.Set<STGType>(Hex(id), Transform(args)...);
278 }
279 
Transform(const google::protobuf::RepeatedField<uint32_t> & ids)280 std::vector<Id> Transformer::Transform(
281     const google::protobuf::RepeatedField<uint32_t>& ids) {
282   std::vector<Id> result;
283   result.reserve(ids.size());
284   for (const uint32_t id : ids) {
285     result.push_back(GetId(id));
286   }
287   return result;
288 }
289 
290 template <typename GetKey>
Transform(GetKey get_key,const google::protobuf::RepeatedField<uint32_t> & ids)291 std::map<std::string, Id> Transformer::Transform(
292     GetKey get_key, const google::protobuf::RepeatedField<uint32_t>& ids) {
293   std::map<std::string, Id> result;
294   for (auto id : ids) {
295     const Id stg_id = GetId(id);
296     const auto [it, inserted] = result.emplace(get_key(stg_id), stg_id);
297     if (!inserted) {
298       Die() << "conflicting interface nodes: " << it->first;
299     }
300   }
301   return result;
302 }
303 
Transform(Special::Kind x)304 stg::Special::Kind Transformer::Transform(Special::Kind x) {
305   switch (x) {
306     case Special::VOID:
307       return stg::Special::Kind::VOID;
308     case Special::VARIADIC:
309       return stg::Special::Kind::VARIADIC;
310     case Special::NULLPTR:
311       return stg::Special::Kind::NULLPTR;
312     default:
313       Die() << "unknown Special::Kind " << x;
314   }
315 }
316 
Transform(PointerReference::Kind x)317 stg::PointerReference::Kind Transformer::Transform(PointerReference::Kind x) {
318   switch (x) {
319     case PointerReference::POINTER:
320       return stg::PointerReference::Kind::POINTER;
321     case PointerReference::LVALUE_REFERENCE:
322       return stg::PointerReference::Kind::LVALUE_REFERENCE;
323     case PointerReference::RVALUE_REFERENCE:
324       return stg::PointerReference::Kind::RVALUE_REFERENCE;
325     default:
326       Die() << "unknown PointerReference::Kind " << x;
327   }
328 }
329 
Transform(Qualified::Qualifier x)330 stg::Qualifier Transformer::Transform(Qualified::Qualifier x) {
331   switch (x) {
332     case Qualified::CONST:
333       return stg::Qualifier::CONST;
334     case Qualified::VOLATILE:
335       return stg::Qualifier::VOLATILE;
336     case Qualified::RESTRICT:
337       return stg::Qualifier::RESTRICT;
338     case Qualified::ATOMIC:
339       return stg::Qualifier::ATOMIC;
340     default:
341       Die() << "unknown Qualified::Qualifier " << x;
342   }
343 }
344 
Transform(Primitive::Encoding x)345 stg::Primitive::Encoding Transformer::Transform(Primitive::Encoding x) {
346   switch (x) {
347     case Primitive::BOOLEAN:
348       return stg::Primitive::Encoding::BOOLEAN;
349     case Primitive::SIGNED_INTEGER:
350       return stg::Primitive::Encoding::SIGNED_INTEGER;
351     case Primitive::UNSIGNED_INTEGER:
352       return stg::Primitive::Encoding::UNSIGNED_INTEGER;
353     case Primitive::SIGNED_CHARACTER:
354       return stg::Primitive::Encoding::SIGNED_CHARACTER;
355     case Primitive::UNSIGNED_CHARACTER:
356       return stg::Primitive::Encoding::UNSIGNED_CHARACTER;
357     case Primitive::REAL_NUMBER:
358       return stg::Primitive::Encoding::REAL_NUMBER;
359     case Primitive::COMPLEX_NUMBER:
360       return stg::Primitive::Encoding::COMPLEX_NUMBER;
361     case Primitive::UTF:
362       return stg::Primitive::Encoding::UTF;
363     default:
364       Die() << "unknown Primitive::Encoding " << x;
365   }
366 }
367 
Transform(BaseClass::Inheritance x)368 stg::BaseClass::Inheritance Transformer::Transform(BaseClass::Inheritance x) {
369   switch (x) {
370     case BaseClass::NON_VIRTUAL:
371       return stg::BaseClass::Inheritance::NON_VIRTUAL;
372     case BaseClass::VIRTUAL:
373       return stg::BaseClass::Inheritance::VIRTUAL;
374     default:
375       Die() << "unknown BaseClass::Inheritance " << x;
376   }
377 }
378 
Transform(StructUnion::Kind x)379 stg::StructUnion::Kind Transformer::Transform(StructUnion::Kind x) {
380   switch (x) {
381     case StructUnion::STRUCT:
382       return stg::StructUnion::Kind::STRUCT;
383     case StructUnion::UNION:
384       return stg::StructUnion::Kind::UNION;
385     default:
386       Die() << "unknown StructUnion::Kind " << x;
387   }
388 }
389 
Transform(ElfSymbol::SymbolType x)390 stg::ElfSymbol::SymbolType Transformer::Transform(ElfSymbol::SymbolType x) {
391   switch (x) {
392     case ElfSymbol::NOTYPE:
393       return stg::ElfSymbol::SymbolType::NOTYPE;
394     case ElfSymbol::OBJECT:
395       return stg::ElfSymbol::SymbolType::OBJECT;
396     case ElfSymbol::FUNCTION:
397       return stg::ElfSymbol::SymbolType::FUNCTION;
398     case ElfSymbol::COMMON:
399       return stg::ElfSymbol::SymbolType::COMMON;
400     case ElfSymbol::TLS:
401       return stg::ElfSymbol::SymbolType::TLS;
402     case ElfSymbol::GNU_IFUNC:
403       return stg::ElfSymbol::SymbolType::GNU_IFUNC;
404     default:
405       Die() << "unknown ElfSymbol::SymbolType " << x;
406   }
407 }
408 
Transform(ElfSymbol::Binding x)409 stg::ElfSymbol::Binding Transformer::Transform(ElfSymbol::Binding x) {
410   switch (x) {
411     case ElfSymbol::GLOBAL:
412       return stg::ElfSymbol::Binding::GLOBAL;
413     case ElfSymbol::LOCAL:
414       return stg::ElfSymbol::Binding::LOCAL;
415     case ElfSymbol::WEAK:
416       return stg::ElfSymbol::Binding::WEAK;
417     case ElfSymbol::GNU_UNIQUE:
418       return stg::ElfSymbol::Binding::GNU_UNIQUE;
419     default:
420       Die() << "unknown ElfSymbol::Binding " << x;
421   }
422 }
423 
Transform(ElfSymbol::Visibility x)424 stg::ElfSymbol::Visibility Transformer::Transform(ElfSymbol::Visibility x) {
425   switch (x) {
426     case ElfSymbol::DEFAULT:
427       return stg::ElfSymbol::Visibility::DEFAULT;
428     case ElfSymbol::PROTECTED:
429       return stg::ElfSymbol::Visibility::PROTECTED;
430     case ElfSymbol::HIDDEN:
431       return stg::ElfSymbol::Visibility::HIDDEN;
432     case ElfSymbol::INTERNAL:
433       return stg::ElfSymbol::Visibility::INTERNAL;
434     default:
435       Die() << "unknown ElfSymbol::Visibility " << x;
436   }
437 }
438 
Transform(const google::protobuf::RepeatedPtrField<Enumeration::Enumerator> & x)439 stg::Enumeration::Enumerators Transformer::Transform(
440     const google::protobuf::RepeatedPtrField<Enumeration::Enumerator>& x) {
441   stg::Enumeration::Enumerators enumerators;
442   enumerators.reserve(x.size());
443   for (const auto& enumerator : x) {
444     enumerators.emplace_back(enumerator.name(), enumerator.value());
445   }
446   return enumerators;
447 }
448 
449 template <typename STGType, typename ProtoType>
Transform(bool has_field,const ProtoType & field)450 std::optional<STGType> Transformer::Transform(bool has_field,
451                                               const ProtoType& field) {
452   return has_field ? std::make_optional<STGType>(Transform(field))
453                    : std::nullopt;
454 }
455 
456 template <typename Type>
Transform(const Type & x)457 Type Transformer::Transform(const Type& x) {
458   return x;
459 }
460 
461 const std::array<uint32_t, 3> kSupportedFormatVersions = {0, 1, 2};
462 
CheckFormatVersion(uint32_t version)463 void CheckFormatVersion(uint32_t version) {
464   Check(std::binary_search(kSupportedFormatVersions.begin(),
465                            kSupportedFormatVersions.end(), version))
466       << "STG format version " << version
467       << " is not supported, minimum supported version: "
468       << kSupportedFormatVersions.front();
469   if (version != kSupportedFormatVersions.back()) {
470     Warn() << "STG format version " << version
471            << " is deprecated, consider upgrading to the latest version ("
472            << kSupportedFormatVersions.back() << ")";
473   }
474 }
475 
476 class ErrorSink : public google::protobuf::io::ErrorCollector {
477  public:
AddError(int line,google::protobuf::io::ColumnNumber column,const std::string & message)478   void AddError(int line, google::protobuf::io::ColumnNumber column,
479                 const std::string& message) final {
480     Moan("error", line, column, message);
481   }
AddWarning(int line,google::protobuf::io::ColumnNumber column,const std::string & message)482   void AddWarning(int line, google::protobuf::io::ColumnNumber column,
483                   const std::string& message) final {
484     Moan("warning", line, column, message);
485   }
486 
487  private:
Moan(std::string_view which,int line,google::protobuf::io::ColumnNumber column,const std::string & message)488   static void Moan(std::string_view which, int line,
489                    google::protobuf::io::ColumnNumber column,
490                    const std::string& message) {
491     Warn() << "google::protobuf::TextFormat " << which << " at line " << (line + 1)
492            << " column " << (column + 1) << ": " << message;
493   }
494 };
495 
ReadHelper(Runtime & runtime,Graph & graph,google::protobuf::io::ZeroCopyInputStream & is)496 Id ReadHelper(Runtime& runtime, Graph& graph,
497               google::protobuf::io::ZeroCopyInputStream& is) {
498   proto::STG stg;
499   {
500     const Time t(runtime, "proto.Parse");
501     ErrorSink error_sink;
502     google::protobuf::TextFormat::Parser parser;
503     parser.RecordErrorsTo(&error_sink);
504     Check(parser.Parse(&is, &stg)) << "failed to parse input as STG";
505   }
506   {
507     const Time t(runtime, "proto.Transform");
508     CheckFormatVersion(stg.version());
509     return Transformer(graph).Transform(stg);
510   }
511 }
512 
513 }  // namespace
514 
Read(Runtime & runtime,Graph & graph,const std::string & path)515 Id Read(Runtime& runtime, Graph& graph, const std::string& path) {
516   std::ifstream ifs(path);
517   Check(ifs.good()) << "error opening file '" << path << "' for reading: "
518                     << Error(errno);
519   google::protobuf::io::IstreamInputStream is(&ifs);
520   return ReadHelper(runtime, graph, is);
521 }
522 
ReadFromString(Runtime & runtime,Graph & graph,std::string_view input)523 Id ReadFromString(Runtime& runtime, Graph& graph, std::string_view input) {
524   Check(input.size() <= std::numeric_limits<int>::max()) << "input too big";
525   google::protobuf::io::ArrayInputStream is(input.data(), static_cast<int>(input.size()));
526   return ReadHelper(runtime, graph, is);
527 }
528 
529 }  // namespace proto
530 }  // namespace stg
531