• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <map>
28 #include <optional>
29 #include <string>
30 #include <string_view>
31 #include <unordered_map>
32 #include <vector>
33 
34 #include <google/protobuf/io/zero_copy_stream_impl.h>
35 #include <google/protobuf/repeated_field.h>
36 #include <google/protobuf/repeated_ptr_field.h>
37 #include <google/protobuf/text_format.h>
38 #include "error.h"
39 #include "graph.h"
40 #include "stg.pb.h"
41 
42 namespace stg {
43 namespace proto {
44 
45 namespace {
46 
47 struct Transformer {
Transformerstg::proto::__anond87b5a3c0111::Transformer48   explicit Transformer(Graph& graph) : graph(graph) {}
49 
50   Id Transform(const proto::STG&);
51 
52   Id GetId(uint32_t);
53 
54   template <typename ProtoType>
55   void AddNodes(const google::protobuf::RepeatedPtrField<ProtoType>&);
56   void AddNode(const Void&);
57   void AddNode(const Variadic&);
58   void AddNode(const Special&);
59   void AddNode(const PointerReference&);
60   void AddNode(const PointerToMember&);
61   void AddNode(const Typedef&);
62   void AddNode(const Qualified&);
63   void AddNode(const Primitive&);
64   void AddNode(const Array&);
65   void AddNode(const BaseClass&);
66   void AddNode(const Method&);
67   void AddNode(const Member&);
68   void AddNode(const Variant&);
69   void AddNode(const StructUnion&);
70   void AddNode(const Enumeration&);
71   void AddNode(const VariantMember&);
72   void AddNode(const Function&);
73   void AddNode(const ElfSymbol&);
74   void AddNode(const Symbols&);
75   void AddNode(const Interface&);
76   template <typename STGType, typename... Args>
77   void AddNode(Args&&...);
78 
79   std::vector<Id> Transform(const google::protobuf::RepeatedField<uint32_t>&);
80   template <typename GetKey>
81   std::map<std::string, Id> Transform(GetKey,
82                                       const google::protobuf::RepeatedField<uint32_t>&);
83   stg::Special::Kind Transform(Special::Kind);
84   stg::PointerReference::Kind Transform(PointerReference::Kind);
85   stg::Qualifier Transform(Qualified::Qualifier);
86   stg::Primitive::Encoding Transform(Primitive::Encoding);
87   stg::BaseClass::Inheritance Transform(BaseClass::Inheritance);
88   stg::StructUnion::Kind Transform(StructUnion::Kind);
89   stg::ElfSymbol::SymbolType Transform(ElfSymbol::SymbolType);
90   stg::ElfSymbol::Binding Transform(ElfSymbol::Binding);
91   stg::ElfSymbol::Visibility Transform(ElfSymbol::Visibility);
92   stg::Enumeration::Enumerators Transform(
93       const google::protobuf::RepeatedPtrField<Enumeration::Enumerator>&);
94   template <typename STGType, typename ProtoType>
95   std::optional<STGType> Transform(bool, const ProtoType&);
96   template <typename Type>
97   Type Transform(const Type&);
98 
99   Graph& graph;
100   std::unordered_map<uint32_t, Id> id_map;
101 };
102 
Transform(const proto::STG & x)103 Id Transformer::Transform(const proto::STG& x) {
104   AddNodes(x.void_());  // deprecated
105   AddNodes(x.variadic());  // deprecated
106   AddNodes(x.special());
107   AddNodes(x.pointer_reference());
108   AddNodes(x.pointer_to_member());
109   AddNodes(x.typedef_());
110   AddNodes(x.qualified());
111   AddNodes(x.primitive());
112   AddNodes(x.array());
113   AddNodes(x.base_class());
114   AddNodes(x.method());
115   AddNodes(x.member());
116   AddNodes(x.variant_member());
117   AddNodes(x.struct_union());
118   AddNodes(x.enumeration());
119   AddNodes(x.variant());
120   AddNodes(x.function());
121   AddNodes(x.elf_symbol());
122   AddNodes(x.symbols());
123   AddNodes(x.interface());
124   return GetId(x.root_id());
125 }
126 
GetId(uint32_t id)127 Id Transformer::GetId(uint32_t id) {
128   auto [it, inserted] = id_map.emplace(id, 0);
129   if (inserted) {
130     it->second = graph.Allocate();
131   }
132   return it->second;
133 }
134 
135 template <typename ProtoType>
AddNodes(const google::protobuf::RepeatedPtrField<ProtoType> & x)136 void Transformer::AddNodes(const google::protobuf::RepeatedPtrField<ProtoType>& x) {
137   for (const ProtoType& proto : x) {
138     AddNode(proto);
139   }
140 }
141 
AddNode(const Void & x)142 void Transformer::AddNode(const Void& x) {
143   AddNode<stg::Special>(GetId(x.id()), stg::Special::Kind::VOID);
144 }
145 
AddNode(const Variadic & x)146 void Transformer::AddNode(const Variadic& x) {
147   AddNode<stg::Special>(GetId(x.id()), stg::Special::Kind::VARIADIC);
148 }
149 
AddNode(const Special & x)150 void Transformer::AddNode(const Special& x) {
151   AddNode<stg::Special>(GetId(x.id()), x.kind());
152 }
153 
AddNode(const PointerReference & x)154 void Transformer::AddNode(const PointerReference& x) {
155   AddNode<stg::PointerReference>(GetId(x.id()), x.kind(),
156                                  GetId(x.pointee_type_id()));
157 }
158 
AddNode(const PointerToMember & x)159 void Transformer::AddNode(const PointerToMember& x) {
160   AddNode<stg::PointerToMember>(GetId(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>(GetId(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>(GetId(x.id()), x.qualifier(),
170                           GetId(x.qualified_type_id()));
171 }
172 
AddNode(const Primitive & x)173 void Transformer::AddNode(const Primitive& x) {
174   const auto& encoding =
175       Transform<stg::Primitive::Encoding>(x.has_encoding(), x.encoding());
176   AddNode<stg::Primitive>(GetId(x.id()), x.name(), encoding, x.bytesize());
177 }
178 
AddNode(const Array & x)179 void Transformer::AddNode(const Array& x) {
180   AddNode<stg::Array>(GetId(x.id()), x.number_of_elements(),
181                       GetId(x.element_type_id()));
182 }
183 
AddNode(const BaseClass & x)184 void Transformer::AddNode(const BaseClass& x) {
185   AddNode<stg::BaseClass>(GetId(x.id()), GetId(x.type_id()), x.offset(),
186                           x.inheritance());
187 }
188 
AddNode(const Method & x)189 void Transformer::AddNode(const Method& x) {
190   AddNode<stg::Method>(GetId(x.id()), x.mangled_name(), x.name(),
191                        x.vtable_offset(), GetId(x.type_id()));
192 }
193 
AddNode(const Member & x)194 void Transformer::AddNode(const Member& x) {
195   AddNode<stg::Member>(GetId(x.id()), x.name(), GetId(x.type_id()), x.offset(),
196                        x.bitsize());
197 }
198 
AddNode(const VariantMember & x)199 void Transformer::AddNode(const VariantMember& x) {
200   const auto& discr_value = x.has_discriminant_value()
201                                 ? std::make_optional(x.discriminant_value())
202                                 : std::nullopt;
203   AddNode<stg::VariantMember>(GetId(x.id()), x.name(), discr_value,
204                               GetId(x.type_id()));
205 }
206 
AddNode(const StructUnion & x)207 void Transformer::AddNode(const StructUnion& x) {
208   if (x.has_definition()) {
209     AddNode<stg::StructUnion>(
210         GetId(x.id()), x.kind(), x.name(), x.definition().bytesize(),
211         x.definition().base_class_id(), x.definition().method_id(),
212         x.definition().member_id());
213   } else {
214     AddNode<stg::StructUnion>(GetId(x.id()), x.kind(), x.name());
215   }
216 }
217 
AddNode(const Enumeration & x)218 void Transformer::AddNode(const Enumeration& x) {
219   if (x.has_definition()) {
220     AddNode<stg::Enumeration>(GetId(x.id()), x.name(),
221                               GetId(x.definition().underlying_type_id()),
222                               x.definition().enumerator());
223     return;
224   } else {
225     AddNode<stg::Enumeration>(GetId(x.id()), x.name());
226   }
227 }
228 
AddNode(const Variant & x)229 void Transformer::AddNode(const Variant& x) {
230   const auto& discriminant = x.has_discriminant()
231                                  ? std::make_optional(GetId(x.discriminant()))
232                                  : std::nullopt;
233   AddNode<stg::Variant>(GetId(x.id()), x.name(), x.bytesize(), discriminant,
234                         x.member_id());
235 }
236 
AddNode(const Function & x)237 void Transformer::AddNode(const Function& x) {
238   AddNode<stg::Function>(GetId(x.id()), GetId(x.return_type_id()),
239                          x.parameter_id());
240 }
241 
AddNode(const ElfSymbol & x)242 void Transformer::AddNode(const ElfSymbol& x) {
243   auto make_version_info = [](const ElfSymbol::VersionInfo& x) {
244     return std::make_optional(
245         stg::ElfSymbol::VersionInfo{x.is_default(), x.name()});
246   };
247   std::optional<stg::ElfSymbol::VersionInfo> version_info =
248       x.has_version_info() ? make_version_info(x.version_info()) : std::nullopt;
249   const auto& crc = x.has_crc()
250                         ? std::make_optional<stg::ElfSymbol::CRC>(x.crc())
251                         : std::nullopt;
252   const auto& ns = Transform<std::string>(x.has_namespace_(), x.namespace_());
253   const auto& type_id =
254       x.has_type_id() ? std::make_optional(GetId(x.type_id())) : std::nullopt;
255   const auto& full_name =
256       Transform<std::string>(x.has_full_name(), x.full_name());
257 
258   AddNode<stg::ElfSymbol>(GetId(x.id()), x.name(), version_info, x.is_defined(),
259                           x.symbol_type(), x.binding(), x.visibility(), crc, ns,
260                           type_id, full_name);
261 }
262 
AddNode(const Symbols & x)263 void Transformer::AddNode(const Symbols& x) {
264   std::map<std::string, Id> symbols;
265   for (const auto& [symbol, id] : x.symbol()) {
266     symbols.emplace(symbol, GetId(id));
267   }
268   AddNode<stg::Interface>(GetId(x.id()), symbols);
269 }
270 
AddNode(const Interface & x)271 void Transformer::AddNode(const Interface& x) {
272   const InterfaceKey get_key(graph);
273   AddNode<stg::Interface>(GetId(x.id()), Transform(get_key, x.symbol_id()),
274                           Transform(get_key, x.type_id()));
275 }
276 
277 template <typename STGType, typename... Args>
AddNode(Args &&...args)278 void Transformer::AddNode(Args&&... args) {
279   graph.Set<STGType>(Transform(args)...);
280 }
281 
Transform(const google::protobuf::RepeatedField<uint32_t> & ids)282 std::vector<Id> Transformer::Transform(
283     const google::protobuf::RepeatedField<uint32_t>& ids) {
284   std::vector<Id> result;
285   result.reserve(ids.size());
286   for (uint32_t id : ids) {
287     result.push_back(GetId(id));
288   }
289   return result;
290 }
291 
292 template <typename GetKey>
Transform(GetKey get_key,const google::protobuf::RepeatedField<uint32_t> & ids)293 std::map<std::string, Id> Transformer::Transform(
294     GetKey get_key, const google::protobuf::RepeatedField<uint32_t>& ids) {
295   std::map<std::string, Id> result;
296   for (auto id : ids) {
297     const Id stg_id = GetId(id);
298     const auto [it, inserted] = result.emplace(get_key(stg_id), stg_id);
299     if (!inserted) {
300       Die() << "conflicting interface nodes: " << it->first;
301     }
302   }
303   return result;
304 }
305 
Transform(Special::Kind x)306 stg::Special::Kind Transformer::Transform(Special::Kind x) {
307   switch (x) {
308     case Special::VOID:
309       return stg::Special::Kind::VOID;
310     case Special::VARIADIC:
311       return stg::Special::Kind::VARIADIC;
312     case Special::NULLPTR:
313       return stg::Special::Kind::NULLPTR;
314     default:
315       Die() << "unknown Special::Kind " << x;
316   }
317 }
318 
Transform(PointerReference::Kind x)319 stg::PointerReference::Kind Transformer::Transform(PointerReference::Kind x) {
320   switch (x) {
321     case PointerReference::POINTER:
322       return stg::PointerReference::Kind::POINTER;
323     case PointerReference::LVALUE_REFERENCE:
324       return stg::PointerReference::Kind::LVALUE_REFERENCE;
325     case PointerReference::RVALUE_REFERENCE:
326       return stg::PointerReference::Kind::RVALUE_REFERENCE;
327     default:
328       Die() << "unknown PointerReference::Kind " << x;
329   }
330 }
331 
Transform(Qualified::Qualifier x)332 stg::Qualifier Transformer::Transform(Qualified::Qualifier x) {
333   switch (x) {
334     case Qualified::CONST:
335       return stg::Qualifier::CONST;
336     case Qualified::VOLATILE:
337       return stg::Qualifier::VOLATILE;
338     case Qualified::RESTRICT:
339       return stg::Qualifier::RESTRICT;
340     case Qualified::ATOMIC:
341       return stg::Qualifier::ATOMIC;
342     default:
343       Die() << "unknown Qualified::Qualifier " << x;
344   }
345 }
346 
Transform(Primitive::Encoding x)347 stg::Primitive::Encoding Transformer::Transform(Primitive::Encoding x) {
348   switch (x) {
349     case Primitive::BOOLEAN:
350       return stg::Primitive::Encoding::BOOLEAN;
351     case Primitive::SIGNED_INTEGER:
352       return stg::Primitive::Encoding::SIGNED_INTEGER;
353     case Primitive::UNSIGNED_INTEGER:
354       return stg::Primitive::Encoding::UNSIGNED_INTEGER;
355     case Primitive::SIGNED_CHARACTER:
356       return stg::Primitive::Encoding::SIGNED_CHARACTER;
357     case Primitive::UNSIGNED_CHARACTER:
358       return stg::Primitive::Encoding::UNSIGNED_CHARACTER;
359     case Primitive::REAL_NUMBER:
360       return stg::Primitive::Encoding::REAL_NUMBER;
361     case Primitive::COMPLEX_NUMBER:
362       return stg::Primitive::Encoding::COMPLEX_NUMBER;
363     case Primitive::UTF:
364       return stg::Primitive::Encoding::UTF;
365     default:
366       Die() << "unknown Primitive::Encoding " << x;
367   }
368 }
369 
Transform(BaseClass::Inheritance x)370 stg::BaseClass::Inheritance Transformer::Transform(BaseClass::Inheritance x) {
371   switch (x) {
372     case BaseClass::NON_VIRTUAL:
373       return stg::BaseClass::Inheritance::NON_VIRTUAL;
374     case BaseClass::VIRTUAL:
375       return stg::BaseClass::Inheritance::VIRTUAL;
376     default:
377       Die() << "unknown BaseClass::Inheritance " << x;
378   }
379 }
380 
Transform(StructUnion::Kind x)381 stg::StructUnion::Kind Transformer::Transform(StructUnion::Kind x) {
382   switch (x) {
383     case StructUnion::STRUCT:
384       return stg::StructUnion::Kind::STRUCT;
385     case StructUnion::UNION:
386       return stg::StructUnion::Kind::UNION;
387     default:
388       Die() << "unknown StructUnion::Kind " << x;
389   }
390 }
391 
Transform(ElfSymbol::SymbolType x)392 stg::ElfSymbol::SymbolType Transformer::Transform(ElfSymbol::SymbolType x) {
393   switch (x) {
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,std::optional<std::string> path)463 void CheckFormatVersion(uint32_t version, std::optional<std::string> path) {
464   Check(std::count(kSupportedFormatVersions.begin(),
465                    kSupportedFormatVersions.end(), version) > 0)
466       << "STG format version " << version
467       << " is not supported, minimum supported version: "
468       << kSupportedFormatVersions.front();
469   if (version != kSupportedFormatVersions.back()) {
470     auto warn = Warn();
471     warn << "STG format version " << version
472          << " is deprecated, consider upgrading stg format to latest version ("
473          << kSupportedFormatVersions.back() << ")";
474     if (path) {
475       warn << " with: stg --stg " << *path << " --output " << *path;
476     }
477   }
478 }
479 
480 }  // namespace
481 
Read(Graph & graph,const std::string & path)482 Id Read(Graph& graph, const std::string& path) {
483   std::ifstream ifs(path);
484   Check(ifs.good()) << "error opening file '" << path
485                     << "' for reading: " << Error(errno);
486   google::protobuf::io::IstreamInputStream is(&ifs);
487   proto::STG stg;
488   google::protobuf::TextFormat::Parse(&is, &stg);
489   CheckFormatVersion(stg.version(), path);
490   return Transformer(graph).Transform(stg);
491 }
492 
ReadFromString(Graph & graph,const std::string_view input)493 Id ReadFromString(Graph& graph, const std::string_view input) {
494   proto::STG stg;
495   google::protobuf::TextFormat::ParseFromString(std::string(input), &stg);
496   CheckFormatVersion(stg.version(), std::nullopt);
497   return Transformer(graph).Transform(stg);
498 }
499 
500 }  // namespace proto
501 }  // namespace stg
502