xref: /aosp_15_r20/external/stg/proto_writer.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_writer.h"
21 
22 #include <algorithm>
23 #include <array>
24 #include <cstdint>
25 #include <iomanip>
26 #include <ios>
27 #include <ostream>
28 #include <sstream>
29 #include <tuple>
30 #include <unordered_map>
31 #include <unordered_set>
32 
33 #include <google/protobuf/descriptor.h>
34 #include <google/protobuf/io/zero_copy_stream.h>
35 #include <google/protobuf/repeated_ptr_field.h>
36 #include <google/protobuf/text_format.h>
37 #include "error.h"
38 #include "graph.h"
39 #include "naming.h"
40 #include "stable_hash.h"
41 #include "stg.pb.h"
42 
43 namespace stg {
44 namespace proto {
45 
46 namespace {
47 
48 class StableId {
49  public:
StableId(const Graph & graph)50   explicit StableId(const Graph& graph) : stable_hash_(graph) {}
51 
operator ()(Id id)52   uint32_t operator()(Id id) {
53     return stable_hash_(id).value;
54   }
55 
56  private:
57   StableHash stable_hash_;
58 };
59 
60 template <typename MapId>
61 struct Transform {
Transformstg::proto::__anon9c9f2c680111::Transform62   Transform(const Graph& graph, proto::STG& stg, MapId& map_id)
63       : graph(graph), stg(stg), map_id(map_id) {}
64 
65   uint32_t operator()(Id);
66 
67   void operator()(const stg::Special&, uint32_t);
68   void operator()(const stg::PointerReference&, uint32_t);
69   void operator()(const stg::PointerToMember&, uint32_t);
70   void operator()(const stg::Typedef&, uint32_t);
71   void operator()(const stg::Qualified&, uint32_t);
72   void operator()(const stg::Primitive&, uint32_t);
73   void operator()(const stg::Array&, uint32_t);
74   void operator()(const stg::BaseClass&, uint32_t);
75   void operator()(const stg::Method&, uint32_t);
76   void operator()(const stg::Member&, uint32_t);
77   void operator()(const stg::VariantMember&, uint32_t);
78   void operator()(const stg::StructUnion&, uint32_t);
79   void operator()(const stg::Enumeration&, uint32_t);
80   void operator()(const stg::Variant&, uint32_t);
81   void operator()(const stg::Function&, uint32_t);
82   void operator()(const stg::ElfSymbol&, uint32_t);
83   void operator()(const stg::Interface&, uint32_t);
84 
85   Special::Kind operator()(stg::Special::Kind);
86   PointerReference::Kind operator()(stg::PointerReference::Kind);
87   Qualified::Qualifier operator()(stg::Qualifier);
88   Primitive::Encoding operator()(stg::Primitive::Encoding);
89   BaseClass::Inheritance operator()(stg::BaseClass::Inheritance);
90   StructUnion::Kind operator()(stg::StructUnion::Kind);
91   ElfSymbol::SymbolType operator()(stg::ElfSymbol::SymbolType);
92   ElfSymbol::Binding operator()(stg::ElfSymbol::Binding);
93   ElfSymbol::Visibility operator()(stg::ElfSymbol::Visibility);
94 
GetInternalIdByExternalIdMapstg::proto::__anon9c9f2c680111::Transform95   std::unordered_map<uint32_t, Id> GetInternalIdByExternalIdMap() {
96     std::unordered_map<uint32_t, Id> internal_id_map;
97     for (const auto& [id, ext_id] : external_id_by_internal_id) {
98       internal_id_map.emplace(ext_id, id);
99     }
100     return internal_id_map;
101   }
102 
103   const Graph& graph;
104   proto::STG& stg;
105   std::unordered_map<Id, uint32_t> external_id_by_internal_id;
106   std::unordered_set<uint32_t> used_ids;
107 
108   // Function object: Id -> uint32_t
109   MapId& map_id;
110 };
111 
112 template <typename MapId>
operator ()(Id id)113 uint32_t Transform<MapId>::operator()(Id id) {
114   auto [it, inserted] = external_id_by_internal_id.emplace(id, 0);
115   if (inserted) {
116     uint32_t mapped_id = map_id(id);
117 
118     // Ensure uniqueness of external ids. It is best to probe here since id
119     // generators will not in general guarantee that the mapping from internal
120     // ids to external ids will be injective.
121     while (!used_ids.insert(mapped_id).second) {
122       ++mapped_id;
123     }
124     it->second = mapped_id;
125     graph.Apply(*this, id, mapped_id);
126   }
127   return it->second;
128 }
129 
130 template <typename MapId>
operator ()(const stg::Special & x,uint32_t id)131 void Transform<MapId>::operator()(const stg::Special& x, uint32_t id) {
132   auto& special = *stg.add_special();
133   special.set_id(id);
134   special.set_kind((*this)(x.kind));
135 }
136 
137 template <typename MapId>
operator ()(const stg::PointerReference & x,uint32_t id)138 void Transform<MapId>::operator()(const stg::PointerReference& x, uint32_t id) {
139   auto& pointer_reference = *stg.add_pointer_reference();
140   pointer_reference.set_id(id);
141   pointer_reference.set_kind((*this)(x.kind));
142   pointer_reference.set_pointee_type_id((*this)(x.pointee_type_id));
143 }
144 
145 template <typename MapId>
operator ()(const stg::PointerToMember & x,uint32_t id)146 void Transform<MapId>::operator()(const stg::PointerToMember& x, uint32_t id) {
147   auto& pointer_to_member = *stg.add_pointer_to_member();
148   pointer_to_member.set_id(id);
149   pointer_to_member.set_containing_type_id((*this)(x.containing_type_id));
150   pointer_to_member.set_pointee_type_id((*this)(x.pointee_type_id));
151 }
152 
153 template <typename MapId>
operator ()(const stg::Typedef & x,uint32_t id)154 void Transform<MapId>::operator()(const stg::Typedef& x, uint32_t id) {
155   auto& typedef_ = *stg.add_typedef_();
156   typedef_.set_id(id);
157   typedef_.set_name(x.name);
158   typedef_.set_referred_type_id((*this)(x.referred_type_id));
159 }
160 
161 template <typename MapId>
operator ()(const stg::Qualified & x,uint32_t id)162 void Transform<MapId>::operator()(const stg::Qualified& x, uint32_t id) {
163   auto& qualified = *stg.add_qualified();
164   qualified.set_id(id);
165   qualified.set_qualifier((*this)(x.qualifier));
166   qualified.set_qualified_type_id((*this)(x.qualified_type_id));
167 }
168 
169 template <typename MapId>
operator ()(const stg::Primitive & x,uint32_t id)170 void Transform<MapId>::operator()(const stg::Primitive& x, uint32_t id) {
171   auto& primitive = *stg.add_primitive();
172   primitive.set_id(id);
173   primitive.set_name(x.name);
174   if (x.encoding) {
175     primitive.set_encoding((*this)(*x.encoding));
176   }
177   primitive.set_bytesize(x.bytesize);
178 }
179 
180 template <typename MapId>
operator ()(const stg::Array & x,uint32_t id)181 void Transform<MapId>::operator()(const stg::Array& x, uint32_t id) {
182   auto& array = *stg.add_array();
183   array.set_id(id);
184   array.set_number_of_elements(x.number_of_elements);
185   array.set_element_type_id((*this)(x.element_type_id));
186 }
187 
188 template <typename MapId>
operator ()(const stg::BaseClass & x,uint32_t id)189 void Transform<MapId>::operator()(const stg::BaseClass& x, uint32_t id) {
190   auto& base_class = *stg.add_base_class();
191   base_class.set_id(id);
192   base_class.set_type_id((*this)(x.type_id));
193   base_class.set_offset(x.offset);
194   base_class.set_inheritance((*this)(x.inheritance));
195 }
196 
197 template <typename MapId>
operator ()(const stg::Method & x,uint32_t id)198 void Transform<MapId>::operator()(const stg::Method& x, uint32_t id) {
199   auto& method = *stg.add_method();
200   method.set_id(id);
201   method.set_mangled_name(x.mangled_name);
202   method.set_name(x.name);
203   method.set_vtable_offset(x.vtable_offset);
204   method.set_type_id((*this)(x.type_id));
205 }
206 
207 template <typename MapId>
operator ()(const stg::Member & x,uint32_t id)208 void Transform<MapId>::operator()(const stg::Member& x, uint32_t id) {
209   auto& member = *stg.add_member();
210   member.set_id(id);
211   member.set_name(x.name);
212   member.set_type_id((*this)(x.type_id));
213   member.set_offset(x.offset);
214   member.set_bitsize(x.bitsize);
215 }
216 
217 template <typename MapId>
operator ()(const stg::VariantMember & x,uint32_t id)218 void Transform<MapId>::operator()(const stg::VariantMember& x, uint32_t id) {
219   auto& variant_member = *stg.add_variant_member();
220   variant_member.set_id(id);
221   variant_member.set_name(x.name);
222   if (x.discriminant_value) {
223     variant_member.set_discriminant_value(*x.discriminant_value);
224   }
225   variant_member.set_type_id((*this)(x.type_id));
226 }
227 
228 template <typename MapId>
operator ()(const stg::StructUnion & x,uint32_t id)229 void Transform<MapId>::operator()(const stg::StructUnion& x, uint32_t id) {
230   auto& struct_union = *stg.add_struct_union();
231   struct_union.set_id(id);
232   struct_union.set_kind((*this)(x.kind));
233   struct_union.set_name(x.name);
234   if (x.definition) {
235     auto& definition = *struct_union.mutable_definition();
236     definition.set_bytesize(x.definition->bytesize);
237     for (const auto id : x.definition->base_classes) {
238       definition.add_base_class_id((*this)(id));
239     }
240     for (const auto id : x.definition->methods) {
241       definition.add_method_id((*this)(id));
242     }
243     for (const auto id : x.definition->members) {
244       definition.add_member_id((*this)(id));
245     }
246   }
247 }
248 
249 template <typename MapId>
operator ()(const stg::Enumeration & x,uint32_t id)250 void Transform<MapId>::operator()(const stg::Enumeration& x, uint32_t id) {
251   auto& enumeration = *stg.add_enumeration();
252   enumeration.set_id(id);
253   enumeration.set_name(x.name);
254   if (x.definition) {
255     auto& definition = *enumeration.mutable_definition();
256     definition.set_underlying_type_id(
257         (*this)(x.definition->underlying_type_id));
258     for (const auto& [name, value] : x.definition->enumerators) {
259       auto& enumerator = *definition.add_enumerator();
260       enumerator.set_name(name);
261       enumerator.set_value(value);
262     }
263   }
264 }
265 
266 template <typename MapId>
operator ()(const stg::Variant & x,uint32_t id)267 void Transform<MapId>::operator()(const stg::Variant& x, uint32_t id) {
268   auto& variant = *stg.add_variant();
269   variant.set_id(id);
270   variant.set_name(x.name);
271   variant.set_bytesize(x.bytesize);
272   if (x.discriminant.has_value()) {
273     variant.set_discriminant((*this)(x.discriminant.value()));
274   }
275   for (const auto id : x.members) {
276     variant.add_member_id((*this)(id));
277   }
278 }
279 
280 template <typename MapId>
operator ()(const stg::Function & x,uint32_t id)281 void Transform<MapId>::operator()(const stg::Function& x, uint32_t id) {
282   auto& function = *stg.add_function();
283   function.set_id(id);
284   function.set_return_type_id((*this)(x.return_type_id));
285   for (const auto id : x.parameters) {
286     function.add_parameter_id((*this)(id));
287   }
288 }
289 
290 template <typename MapId>
operator ()(const stg::ElfSymbol & x,uint32_t id)291 void Transform<MapId>::operator()(const stg::ElfSymbol& x, uint32_t id) {
292   auto& elf_symbol = *stg.add_elf_symbol();
293   elf_symbol.set_id(id);
294   elf_symbol.set_name(x.symbol_name);
295   if (x.version_info) {
296     auto& version_info = *elf_symbol.mutable_version_info();
297     version_info.set_is_default(x.version_info->is_default);
298     version_info.set_name(x.version_info->name);
299   }
300   elf_symbol.set_is_defined(x.is_defined);
301   elf_symbol.set_symbol_type((*this)(x.symbol_type));
302   elf_symbol.set_binding((*this)(x.binding));
303   elf_symbol.set_visibility((*this)(x.visibility));
304   if (x.crc) {
305     elf_symbol.set_crc(x.crc->number);
306   }
307   if (x.ns) {
308     elf_symbol.set_namespace_(*x.ns);
309   }
310   if (x.type_id) {
311     elf_symbol.set_type_id((*this)(*x.type_id));
312   }
313   if (x.full_name) {
314     elf_symbol.set_full_name(*x.full_name);
315   }
316 }
317 
318 template <typename MapId>
operator ()(const stg::Interface & x,uint32_t id)319 void Transform<MapId>::operator()(const stg::Interface& x, uint32_t id) {
320   auto& interface = *stg.add_interface();
321   interface.set_id(id);
322   for (const auto& [_, id] : x.symbols) {
323     interface.add_symbol_id((*this)(id));
324   }
325   for (const auto& [_, id] : x.types) {
326     interface.add_type_id((*this)(id));
327   }
328 }
329 
330 template <typename MapId>
operator ()(stg::PointerReference::Kind x)331 PointerReference::Kind Transform<MapId>::operator()(
332     stg::PointerReference::Kind x) {
333   switch (x) {
334     case stg::PointerReference::Kind::POINTER:
335       return PointerReference::POINTER;
336     case stg::PointerReference::Kind::LVALUE_REFERENCE:
337       return PointerReference::LVALUE_REFERENCE;
338     case stg::PointerReference::Kind::RVALUE_REFERENCE:
339       return PointerReference::RVALUE_REFERENCE;
340   }
341 }
342 
343 template <typename MapId>
operator ()(stg::Special::Kind x)344 Special::Kind Transform<MapId>::operator()(
345     stg::Special::Kind x) {
346   switch (x) {
347     case stg::Special::Kind::VOID:
348       return Special::VOID;
349     case stg::Special::Kind::VARIADIC:
350       return Special::VARIADIC;
351     case stg::Special::Kind::NULLPTR:
352       return Special::NULLPTR;
353   }
354 }
355 
356 template <typename MapId>
operator ()(stg::Qualifier x)357 Qualified::Qualifier Transform<MapId>::operator()(stg::Qualifier x) {
358   switch (x) {
359     case stg::Qualifier::CONST:
360       return Qualified::CONST;
361     case stg::Qualifier::VOLATILE:
362       return Qualified::VOLATILE;
363     case stg::Qualifier::RESTRICT:
364       return Qualified::RESTRICT;
365     case stg::Qualifier::ATOMIC:
366       return Qualified::ATOMIC;
367   }
368 }
369 
370 template <typename MapId>
operator ()(stg::Primitive::Encoding x)371 Primitive::Encoding Transform<MapId>::operator()(stg::Primitive::Encoding x) {
372   switch (x) {
373     case stg::Primitive::Encoding::BOOLEAN:
374       return Primitive::BOOLEAN;
375     case stg::Primitive::Encoding::SIGNED_INTEGER:
376       return Primitive::SIGNED_INTEGER;
377     case stg::Primitive::Encoding::UNSIGNED_INTEGER:
378       return Primitive::UNSIGNED_INTEGER;
379     case stg::Primitive::Encoding::SIGNED_CHARACTER:
380       return Primitive::SIGNED_CHARACTER;
381     case stg::Primitive::Encoding::UNSIGNED_CHARACTER:
382       return Primitive::UNSIGNED_CHARACTER;
383     case stg::Primitive::Encoding::REAL_NUMBER:
384       return Primitive::REAL_NUMBER;
385     case stg::Primitive::Encoding::COMPLEX_NUMBER:
386       return Primitive::COMPLEX_NUMBER;
387     case stg::Primitive::Encoding::UTF:
388       return Primitive::UTF;
389   }
390 }
391 
392 template <typename MapId>
operator ()(stg::BaseClass::Inheritance x)393 BaseClass::Inheritance Transform<MapId>::operator()(
394     stg::BaseClass::Inheritance x) {
395   switch (x) {
396     case stg::BaseClass::Inheritance::NON_VIRTUAL:
397       return BaseClass::NON_VIRTUAL;
398     case stg::BaseClass::Inheritance::VIRTUAL:
399       return BaseClass::VIRTUAL;
400   }
401 }
402 
403 template <typename MapId>
operator ()(stg::StructUnion::Kind x)404 StructUnion::Kind Transform<MapId>::operator()(stg::StructUnion::Kind x) {
405   switch (x) {
406     case stg::StructUnion::Kind::STRUCT:
407       return StructUnion::STRUCT;
408     case stg::StructUnion::Kind::UNION:
409       return StructUnion::UNION;
410   }
411 }
412 
413 template <typename MapId>
operator ()(stg::ElfSymbol::SymbolType x)414 ElfSymbol::SymbolType Transform<MapId>::operator()(
415     stg::ElfSymbol::SymbolType x) {
416   switch (x) {
417     case stg::ElfSymbol::SymbolType::NOTYPE:
418       return ElfSymbol::NOTYPE;
419     case stg::ElfSymbol::SymbolType::OBJECT:
420       return ElfSymbol::OBJECT;
421     case stg::ElfSymbol::SymbolType::FUNCTION:
422       return ElfSymbol::FUNCTION;
423     case stg::ElfSymbol::SymbolType::COMMON:
424       return ElfSymbol::COMMON;
425     case stg::ElfSymbol::SymbolType::TLS:
426       return ElfSymbol::TLS;
427     case stg::ElfSymbol::SymbolType::GNU_IFUNC:
428       return ElfSymbol::GNU_IFUNC;
429   }
430 }
431 
432 template <typename MapId>
operator ()(stg::ElfSymbol::Binding x)433 ElfSymbol::Binding Transform<MapId>::operator()(stg::ElfSymbol::Binding x) {
434   switch (x) {
435     case stg::ElfSymbol::Binding::GLOBAL:
436       return ElfSymbol::GLOBAL;
437     case stg::ElfSymbol::Binding::LOCAL:
438       return ElfSymbol::LOCAL;
439     case stg::ElfSymbol::Binding::WEAK:
440       return ElfSymbol::WEAK;
441     case stg::ElfSymbol::Binding::GNU_UNIQUE:
442       return ElfSymbol::GNU_UNIQUE;
443   }
444 }
445 
446 template <typename MapId>
operator ()(stg::ElfSymbol::Visibility x)447 ElfSymbol::Visibility Transform<MapId>::operator()(
448     stg::ElfSymbol::Visibility x) {
449   switch (x) {
450     case stg::ElfSymbol::Visibility::DEFAULT:
451       return ElfSymbol::DEFAULT;
452     case stg::ElfSymbol::Visibility::PROTECTED:
453       return ElfSymbol::PROTECTED;
454     case stg::ElfSymbol::Visibility::HIDDEN:
455       return ElfSymbol::HIDDEN;
456     case stg::ElfSymbol::Visibility::INTERNAL:
457       return ElfSymbol::INTERNAL;
458   }
459 }
460 
461 template <typename ProtoNode>
SortNodesById(google::protobuf::RepeatedPtrField<ProtoNode> & nodes)462 void SortNodesById(google::protobuf::RepeatedPtrField<ProtoNode>& nodes) {
463   const auto compare = [](const auto* lhs, const auto* rhs) {
464     return lhs->id() < rhs->id();
465   };
466   std::sort(nodes.pointer_begin(), nodes.pointer_end(), compare);
467 }
468 
469 template <typename ProtoNode>
SortNodesByName(google::protobuf::RepeatedPtrField<ProtoNode> & nodes)470 void SortNodesByName(google::protobuf::RepeatedPtrField<ProtoNode>& nodes) {
471   const auto compare = [](const auto* lhs, const auto* rhs) {
472     return std::forward_as_tuple(lhs->name(), lhs->id())
473         < std::forward_as_tuple(rhs->name(), rhs->id());
474   };
475   std::sort(nodes.pointer_begin(), nodes.pointer_end(), compare);
476 }
477 
SortMethodsByMangledName(google::protobuf::RepeatedPtrField<Method> & methods)478 void SortMethodsByMangledName(google::protobuf::RepeatedPtrField<Method>& methods) {
479   const auto compare = [](const Method* lhs, const Method* rhs) {
480     return std::forward_as_tuple(lhs->mangled_name(), lhs->id())
481         < std::forward_as_tuple(rhs->mangled_name(), rhs->id());
482   };
483   std::sort(methods.pointer_begin(), methods.pointer_end(), compare);
484 }
485 
SortElfSymbolsByVersionedName(google::protobuf::RepeatedPtrField<ElfSymbol> & elf_symbols)486 void SortElfSymbolsByVersionedName(
487     google::protobuf::RepeatedPtrField<ElfSymbol>& elf_symbols) {
488   const auto compare = [](const ElfSymbol* lhs, const ElfSymbol* rhs) {
489     // Sorting by:
490     //
491     // name
492     // version name
493     // ID as tie-breaker
494     //
495     // Note: symbols without version information will be ordered before
496     // versioned symbols of the same name.
497     return std::forward_as_tuple(lhs->name(), lhs->version_info().name(),
498                                  lhs->id())
499         < std::forward_as_tuple(rhs->name(), rhs->version_info().name(),
500                                 rhs->id());
501   };
502   std::sort(elf_symbols.pointer_begin(), elf_symbols.pointer_end(), compare);
503 }
504 
SortNodes(STG & stg)505 void SortNodes(STG& stg) {
506   SortNodesById(*stg.mutable_void_());
507   SortNodesById(*stg.mutable_variadic());
508   SortNodesById(*stg.mutable_pointer_reference());
509   SortNodesById(*stg.mutable_pointer_to_member());
510   SortNodesByName(*stg.mutable_typedef_());
511   SortNodesById(*stg.mutable_qualified());
512   SortNodesById(*stg.mutable_primitive());
513   SortNodesById(*stg.mutable_array());
514   SortNodesById(*stg.mutable_base_class());
515   SortMethodsByMangledName(*stg.mutable_method());
516   SortNodesByName(*stg.mutable_member());
517   SortNodesByName(*stg.mutable_struct_union());
518   SortNodesByName(*stg.mutable_enumeration());
519   SortNodesById(*stg.mutable_function());
520   SortElfSymbolsByVersionedName(*stg.mutable_elf_symbol());
521 }
522 
523 class HexPrinter : public google::protobuf::TextFormat::FastFieldValuePrinter {
PrintUInt32(uint32_t value,google::protobuf::TextFormat::BaseTextGenerator * generator) const524   void PrintUInt32(
525       uint32_t value,
526       google::protobuf::TextFormat::BaseTextGenerator* generator) const final {
527     std::ostringstream os;
528     // 0x01234567
529     os << "0x" << std::hex << std::setfill('0') << std::setw(8) << value;
530     generator->PrintString(os.str());
531   }
532 };
533 
534 class AnnotationHexPrinter : public google::protobuf::TextFormat::FastFieldValuePrinter {
535  public:
AnnotationHexPrinter(Describe & describe,const std::unordered_map<uint32_t,Id> & internal_id_by_external_id)536   AnnotationHexPrinter(
537       Describe& describe,
538       const std::unordered_map<uint32_t, Id>& internal_id_by_external_id)
539       : describe_(describe),
540         internal_id_by_external_id_(internal_id_by_external_id) {}
541 
542  private:
PrintUInt32(uint32_t value,google::protobuf::TextFormat::BaseTextGenerator * generator) const543   void PrintUInt32(
544       uint32_t value,
545       google::protobuf::TextFormat::BaseTextGenerator* generator) const final {
546     std::ostringstream os;
547     // 0x01234567  # Describe(0x01234567)
548     os << "0x" << std::hex << std::setfill('0') << std::setw(8) << value
549        << "  # " << describe_(internal_id_by_external_id_.at(value));
550     generator->PrintString(os.str());
551   }
552 
553   Describe& describe_;
554   const std::unordered_map<uint32_t, Id>& internal_id_by_external_id_;
555 };
556 
557 const uint32_t kWrittenFormatVersion = 2;
558 
559 // Collection of fields which represent edges in the STG proto.
560 //
561 // This collection is used to register the AnnotationHexPrinter for each of the
562 // fields, which will print a description of the node in STG to which the edge
563 // points.
564 const std::array<const google::protobuf::FieldDescriptor*, 19> edge_descriptors = {
565     PointerReference::descriptor()->FindFieldByNumber(3),
566     PointerToMember::descriptor()->FindFieldByNumber(3),
567     Typedef::descriptor()->FindFieldByNumber(3),
568     Qualified::descriptor()->FindFieldByNumber(3),
569     Array::descriptor()->FindFieldByNumber(3),
570     BaseClass::descriptor()->FindFieldByNumber(2),
571     Method::descriptor()->FindFieldByNumber(5),
572     Member::descriptor()->FindFieldByNumber(3),
573     VariantMember::descriptor()->FindFieldByNumber(4),
574     StructUnion::Definition::descriptor()->FindFieldByNumber(2),
575     StructUnion::Definition::descriptor()->FindFieldByNumber(3),
576     StructUnion::Definition::descriptor()->FindFieldByNumber(4),
577     Enumeration::Definition::descriptor()->FindFieldByNumber(1),
578     Function::descriptor()->FindFieldByNumber(2),
579     Function::descriptor()->FindFieldByNumber(3),
580     ElfSymbol::descriptor()->FindFieldByNumber(10),
581     Interface::descriptor()->FindFieldByNumber(2),
582     Interface::descriptor()->FindFieldByNumber(3),
583     STG::descriptor()->FindFieldByNumber(2),
584 };
585 
586 }  // namespace
587 
Write(const Id & root,google::protobuf::io::ZeroCopyOutputStream & os,bool annotate)588 void Writer::Write(const Id& root, google::protobuf::io::ZeroCopyOutputStream& os,
589                    bool annotate) {
590   proto::STG stg;
591   StableId stable_id(graph_);
592   Transform<StableId> transform(graph_, stg, stable_id);
593   stg.set_root_id(transform(root));
594   SortNodes(stg);
595   stg.set_version(kWrittenFormatVersion);
596 
597   // Print
598   google::protobuf::TextFormat::Printer printer;
599   printer.SetDefaultFieldValuePrinter(new HexPrinter());
600   if (annotate) {
601     NameCache names;
602     Describe describe(graph_, names);
603     auto internal_id_by_external_id = transform.GetInternalIdByExternalIdMap();
604     for (const auto* descriptor : edge_descriptors) {
605       Check(printer.RegisterFieldValuePrinter(
606           descriptor,
607           new AnnotationHexPrinter(describe, internal_id_by_external_id)))
608           << "Failed to register annotation printer for descriptor: "
609           << descriptor->name();
610     }
611     Check(printer.Print(stg, &os)) << "Failed to write STG";
612   } else {
613     Check(printer.Print(stg, &os)) << "Failed to write STG";
614   }
615 }
616 
617 }  // namespace proto
618 }  // namespace stg
619