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 <string>
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::__anonab65cec60111::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::__anonab65cec60111::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<void>(*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::OBJECT:
418 return ElfSymbol::OBJECT;
419 case stg::ElfSymbol::SymbolType::FUNCTION:
420 return ElfSymbol::FUNCTION;
421 case stg::ElfSymbol::SymbolType::COMMON:
422 return ElfSymbol::COMMON;
423 case stg::ElfSymbol::SymbolType::TLS:
424 return ElfSymbol::TLS;
425 case stg::ElfSymbol::SymbolType::GNU_IFUNC:
426 return ElfSymbol::GNU_IFUNC;
427 }
428 }
429
430 template <typename MapId>
operator ()(stg::ElfSymbol::Binding x)431 ElfSymbol::Binding Transform<MapId>::operator()(stg::ElfSymbol::Binding x) {
432 switch (x) {
433 case stg::ElfSymbol::Binding::GLOBAL:
434 return ElfSymbol::GLOBAL;
435 case stg::ElfSymbol::Binding::LOCAL:
436 return ElfSymbol::LOCAL;
437 case stg::ElfSymbol::Binding::WEAK:
438 return ElfSymbol::WEAK;
439 case stg::ElfSymbol::Binding::GNU_UNIQUE:
440 return ElfSymbol::GNU_UNIQUE;
441 }
442 }
443
444 template <typename MapId>
operator ()(stg::ElfSymbol::Visibility x)445 ElfSymbol::Visibility Transform<MapId>::operator()(
446 stg::ElfSymbol::Visibility x) {
447 switch (x) {
448 case stg::ElfSymbol::Visibility::DEFAULT:
449 return ElfSymbol::DEFAULT;
450 case stg::ElfSymbol::Visibility::PROTECTED:
451 return ElfSymbol::PROTECTED;
452 case stg::ElfSymbol::Visibility::HIDDEN:
453 return ElfSymbol::HIDDEN;
454 case stg::ElfSymbol::Visibility::INTERNAL:
455 return ElfSymbol::INTERNAL;
456 }
457 }
458
459 template <typename ProtoNode>
SortNodesById(google::protobuf::RepeatedPtrField<ProtoNode> & nodes)460 void SortNodesById(google::protobuf::RepeatedPtrField<ProtoNode>& nodes) {
461 std::sort(
462 nodes.pointer_begin(), nodes.pointer_end(),
463 [](const auto* lhs, const auto* rhs) { return lhs->id() < rhs->id(); });
464 }
465
466 template <typename ProtoNode>
SortNodesByName(google::protobuf::RepeatedPtrField<ProtoNode> & nodes)467 void SortNodesByName(google::protobuf::RepeatedPtrField<ProtoNode>& nodes) {
468 const auto compare = [](const auto* lhs, const auto* rhs) {
469 const int comparison = lhs->name().compare(rhs->name());
470 return comparison < 0 || (comparison == 0 && lhs->id() < rhs->id());
471 };
472 std::sort(nodes.pointer_begin(), nodes.pointer_end(), compare);
473 }
474
SortMethodsByMangledName(google::protobuf::RepeatedPtrField<Method> & methods)475 void SortMethodsByMangledName(google::protobuf::RepeatedPtrField<Method>& methods) {
476 const auto compare = [](const Method* lhs, const Method* rhs) {
477 const int comparison = lhs->mangled_name().compare(rhs->mangled_name());
478 return comparison < 0 || (comparison == 0 && lhs->id() < rhs->id());
479 };
480 std::sort(methods.pointer_begin(), methods.pointer_end(), compare);
481 }
482
SortElfSymbolsByVersionedName(google::protobuf::RepeatedPtrField<ElfSymbol> & elf_symbols)483 void SortElfSymbolsByVersionedName(
484 google::protobuf::RepeatedPtrField<ElfSymbol>& elf_symbols) {
485 // TODO: use spaceship operator <=>
486 const auto compare = [](const ElfSymbol* lhs, const ElfSymbol* rhs) {
487 if (const int c = lhs->name().compare(rhs->name()); c != 0) {
488 return c < 0;
489 }
490
491 // Put symbols with version info after those without version info.
492 if (lhs->has_version_info() != rhs->has_version_info()) {
493 return rhs->has_version_info();
494 }
495
496 if (lhs->has_version_info()) {
497 const auto& l_version = lhs->version_info();
498 const auto& r_version = rhs->version_info();
499 if (const int c = l_version.name().compare(r_version.name()); c != 0) {
500 return c < 0;
501 }
502
503 // Put symbols with default version before those with non-default version.
504 if (l_version.is_default() != r_version.is_default()) {
505 return r_version.is_default();
506 }
507 }
508
509 return lhs->id() < rhs->id();
510 };
511 std::sort(elf_symbols.pointer_begin(), elf_symbols.pointer_end(), compare);
512 }
513
SortNodes(STG & stg)514 void SortNodes(STG& stg) {
515 SortNodesById(*stg.mutable_void_());
516 SortNodesById(*stg.mutable_variadic());
517 SortNodesById(*stg.mutable_pointer_reference());
518 SortNodesById(*stg.mutable_pointer_to_member());
519 SortNodesByName(*stg.mutable_typedef_());
520 SortNodesById(*stg.mutable_qualified());
521 SortNodesById(*stg.mutable_primitive());
522 SortNodesById(*stg.mutable_array());
523 SortNodesById(*stg.mutable_base_class());
524 SortMethodsByMangledName(*stg.mutable_method());
525 SortNodesByName(*stg.mutable_member());
526 SortNodesByName(*stg.mutable_struct_union());
527 SortNodesByName(*stg.mutable_enumeration());
528 SortNodesById(*stg.mutable_function());
529 SortElfSymbolsByVersionedName(*stg.mutable_elf_symbol());
530 }
531
532 class HexPrinter : public google::protobuf::TextFormat::FastFieldValuePrinter {
PrintUInt32(uint32_t value,google::protobuf::TextFormat::BaseTextGenerator * generator) const533 void PrintUInt32(
534 uint32_t value,
535 google::protobuf::TextFormat::BaseTextGenerator* generator) const final {
536 std::ostringstream os;
537 // 0x01234567
538 os << "0x" << std::hex << std::setfill('0') << std::setw(8) << value;
539 generator->PrintString(os.str());
540 }
541 };
542
543 class AnnotationHexPrinter : public google::protobuf::TextFormat::FastFieldValuePrinter {
544 public:
AnnotationHexPrinter(Describe & describe,const std::unordered_map<uint32_t,Id> & internal_id_by_external_id)545 AnnotationHexPrinter(
546 Describe& describe,
547 const std::unordered_map<uint32_t, Id>& internal_id_by_external_id)
548 : describe_(describe),
549 internal_id_by_external_id_(internal_id_by_external_id) {}
550
551 private:
PrintUInt32(uint32_t value,google::protobuf::TextFormat::BaseTextGenerator * generator) const552 void PrintUInt32(
553 uint32_t value,
554 google::protobuf::TextFormat::BaseTextGenerator* generator) const final {
555 std::ostringstream os;
556 // 0x01234567 # Describe(0x01234567)
557 os << "0x" << std::hex << std::setfill('0') << std::setw(8) << value
558 << " # " << describe_(internal_id_by_external_id_.at(value));
559 generator->PrintString(os.str());
560 }
561
562 Describe& describe_;
563 const std::unordered_map<uint32_t, Id>& internal_id_by_external_id_;
564 };
565
566 const uint32_t kWrittenFormatVersion = 2;
567
568 // Collection of fields which represent edges in the STG proto.
569 //
570 // This collection is used to register the AnnotationHexPrinter for each of the
571 // fields, which will print a description of the node in STG to which the edge
572 // points.
573 const std::array<const google::protobuf::FieldDescriptor*, 18> edge_descriptors = {
574 PointerReference::descriptor()->FindFieldByNumber(3),
575 PointerToMember::descriptor()->FindFieldByNumber(3),
576 Typedef::descriptor()->FindFieldByNumber(3),
577 Qualified::descriptor()->FindFieldByNumber(3),
578 Array::descriptor()->FindFieldByNumber(3),
579 BaseClass::descriptor()->FindFieldByNumber(2),
580 Method::descriptor()->FindFieldByNumber(5),
581 Member::descriptor()->FindFieldByNumber(3),
582 StructUnion::Definition::descriptor()->FindFieldByNumber(2),
583 StructUnion::Definition::descriptor()->FindFieldByNumber(3),
584 StructUnion::Definition::descriptor()->FindFieldByNumber(4),
585 Enumeration::Definition::descriptor()->FindFieldByNumber(1),
586 Function::descriptor()->FindFieldByNumber(2),
587 Function::descriptor()->FindFieldByNumber(3),
588 ElfSymbol::descriptor()->FindFieldByNumber(10),
589 Interface::descriptor()->FindFieldByNumber(2),
590 Interface::descriptor()->FindFieldByNumber(3),
591 STG::descriptor()->FindFieldByNumber(2),
592 };
593
594 } // namespace
595
Write(const Id & root,google::protobuf::io::ZeroCopyOutputStream & os,bool annotate)596 void Writer::Write(const Id& root, google::protobuf::io::ZeroCopyOutputStream& os,
597 bool annotate) {
598 proto::STG stg;
599 StableId stable_id(graph_);
600 Transform<StableId> transform(graph_, stg, stable_id);
601 stg.set_root_id(transform(root));
602 SortNodes(stg);
603 stg.set_version(kWrittenFormatVersion);
604
605 // Print
606 google::protobuf::TextFormat::Printer printer;
607 printer.SetDefaultFieldValuePrinter(new HexPrinter());
608 if (annotate) {
609 NameCache names;
610 Describe describe(graph_, names);
611 auto internal_id_by_external_id = transform.GetInternalIdByExternalIdMap();
612 for (const auto* descriptor : edge_descriptors) {
613 Check(printer.RegisterFieldValuePrinter(
614 descriptor,
615 new AnnotationHexPrinter(describe, internal_id_by_external_id)))
616 << "Failed to register annotation printer for descriptor: "
617 << descriptor->name();
618 }
619 Check(printer.Print(stg, &os)) << "Failed to write STG";
620 } else {
621 Check(printer.Print(stg, &os)) << "Failed to write STG";
622 }
623 }
624
625 } // namespace proto
626 } // namespace stg
627