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