1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <elf.h>
18
19 #include <fstream>
20 #include <iostream>
21 #include <map>
22 #include <optional>
23 #include <queue>
24 #include <string>
25
26 #include <sys/param.h>
27
28 #include "dwarf_constants.h"
29 #include "dwarf_info.h"
30 #include "elf_reader.h"
31
32 #include <berberis/base/algorithm.h>
33 #include <berberis/base/stringprintf.h>
34 #include <json/json.h>
35
36 namespace {
37
38 using berberis::StringPrintf;
39
40 constexpr const char* kKindArray = "array";
41 constexpr const char* kKindAtomic = "atomic";
42 constexpr const char* kKindConst = "const";
43 constexpr const char* kKindClass = "class";
44 constexpr const char* kKindFunction = "function";
45 constexpr const char* kKindIncomplete = "incomplete";
46 constexpr const char* kKindRestrict = "restrict";
47 constexpr const char* kKindStruct = "struct";
48 constexpr const char* kKindUnion = "union";
49 constexpr const char* kKindVolatile = "volatile";
50
51 class JsonNameValue {
52 public:
JsonNameValue(const std::string name,const Json::Value & value)53 JsonNameValue(const std::string name, const Json::Value& value) : name_(name), value_(value) {}
name() const54 const std::string& name() const { return name_; }
55
value() const56 const Json::Value& value() const { return value_; }
57
58 private:
59 std::string name_;
60 Json::Value value_;
61 };
62
63 class TypeInfo {
64 public:
TypeInfo(uint64_t id,const char * kind,const std::string & name,uint64_t size_bits)65 TypeInfo(uint64_t id, const char* kind, const std::string& name, uint64_t size_bits)
66 : id_(id), kind_(kind), name_(name), size_bits_(size_bits) {}
~TypeInfo()67 virtual ~TypeInfo() {}
68
id() const69 uint64_t id() const { return id_; }
70
kind() const71 const char* kind() const { return kind_; }
name() const72 const std::string& name() const { return name_; }
size() const73 uint64_t size() const { return size_bits_; }
74
75 virtual JsonNameValue GetJson() const = 0;
76
EqualsTo(const TypeInfo * other) const77 virtual bool EqualsTo(const TypeInfo* other) const {
78 // This is default implementation - should work for most TypeInfos
79 return kind_ == other->kind_ && size_bits_ == other->size_bits_ && name_ == other->name_;
80 }
81
82 // It usually is just a name but for classes and function it represents just
83 // the class or function name without 'class'/'func' prefix. Used to correctly
84 // resolve names for nested classes/unions/...
base_name() const85 virtual const std::string& base_name() const { return name(); }
86
87 private:
88 uint64_t id_;
89
90 protected:
91 const char* kind_;
92 std::string name_;
93 uint64_t size_bits_;
94
95 private:
96 DISALLOW_IMPLICIT_CONSTRUCTORS(TypeInfo);
97 };
98
usage(const char * argv0)99 void usage(const char* argv0) {
100 printf("usage: %s [--filter=<path_to_filter_file>] <path_to_elf_file>\n", argv0);
101 }
102
error(const char * fmt,...)103 __attribute__((__noreturn__)) void error(const char* fmt, ...) {
104 va_list ap;
105 va_start(ap, fmt);
106 vfprintf(stderr, fmt, ap);
107 va_end(ap);
108 fprintf(stderr, "\n");
109 exit(1);
110 }
111
warning(const char * fmt,...)112 void warning(const char* fmt, ...) {
113 va_list ap;
114 va_start(ap, fmt);
115 vfprintf(stderr, fmt, ap);
116 va_end(ap);
117 fprintf(stderr, "\n");
118 }
119
120 // TODO: This method does not provide necessary guarantees for being able to
121 // compare anonymous types by name.
122 //
123 // * There are number of situation where a type does not have a name
124 // * 1. There are anonymous function pointers
125 // * 2. Unnamed unions and structs inside other unions or structs
126 // The current approach is to use global counter.
127 //
128 // Note that there is no guarantee that these names are going to be same for
129 // a library compiled on different architectures.
GenerateGlobalAnonName()130 std::string GenerateGlobalAnonName() {
131 static size_t counter = 0;
132 return StringPrintf("#%zd", ++counter);
133 }
134
135 class TypeInfoFunction : public TypeInfo {
136 public:
TypeInfoFunction(uint64_t id,const std::string & name,const std::string & base_name)137 TypeInfoFunction(uint64_t id, const std::string& name, const std::string& base_name)
138 : TypeInfo(id, kKindFunction, name, 0),
139 base_name_(base_name),
140 has_variadic_args_(false),
141 is_virtual_method_(false) {}
142
~TypeInfoFunction()143 virtual ~TypeInfoFunction() {}
144
SetReturnType(const std::string & return_type)145 void SetReturnType(const std::string& return_type) { return_type_ = return_type; }
146
SetHasVariadicArgs(bool has_variadic_args)147 void SetHasVariadicArgs(bool has_variadic_args) { has_variadic_args_ = has_variadic_args; }
148
SetCallingConvention(const std::string & calling_convention)149 void SetCallingConvention(const std::string& calling_convention) {
150 calling_convention_ = calling_convention;
151 }
152
AddParam(const std::string & param_name)153 void AddParam(const std::string& param_name) { params_.push_back(param_name); }
154
EqualsTo(const TypeInfo *) const155 virtual bool EqualsTo(const TypeInfo*) const override {
156 // This method is not applicable for function types.
157 return false;
158 }
159
GetJson() const160 virtual JsonNameValue GetJson() const override {
161 Json::Value obj(Json::objectValue);
162
163 obj["has_variadic_args"] = has_variadic_args_;
164 obj["is_virtual_method"] = is_virtual_method_;
165 obj["kind"] = kind_;
166 Json::Value params_array(Json::arrayValue);
167 for (const auto& param : params_) {
168 params_array.append(param);
169 }
170 obj["params"] = params_array;
171 obj["return_type"] = return_type_;
172 obj["size"] = Json::UInt64(size_bits_);
173
174 if (!calling_convention_.empty()) {
175 obj["calling_convention"] = calling_convention_;
176 }
177
178 return JsonNameValue(name_, obj);
179 }
180
base_name() const181 virtual const std::string& base_name() const override { return base_name_; }
182
183 private:
184 std::string base_name_;
185 bool has_variadic_args_;
186 bool is_virtual_method_;
187 std::string return_type_;
188 std::string calling_convention_;
189 std::vector<std::string> params_;
190 };
191
192 enum class ReferenceType { pointer, reference, rvalue_reference };
193
194 class TypeInfoReference : public TypeInfo {
195 public:
TypeInfoReference(uint64_t id,const char * kind,const std::string & name,uint64_t size_bits,const std::string & pointee_type)196 TypeInfoReference(uint64_t id,
197 const char* kind,
198 const std::string& name,
199 uint64_t size_bits,
200 const std::string& pointee_type)
201 : TypeInfo(id, kind, name, size_bits), pointee_type_(pointee_type) {}
202
~TypeInfoReference()203 virtual ~TypeInfoReference() {}
204
GetJson() const205 virtual JsonNameValue GetJson() const override {
206 Json::Value obj(Json::objectValue);
207
208 obj["kind"] = kind_;
209 obj["pointee_type"] = pointee_type_;
210 obj["size"] = Json::UInt64(size_bits_);
211
212 return JsonNameValue(name_, obj);
213 }
214
215 private:
216 std::string pointee_type_;
217 };
218
219 class TypeInfoModifier : public TypeInfo {
220 public:
TypeInfoModifier(uint64_t id,const char * kind,const std::string & name,uint64_t size_bits,const std::string & base_type)221 TypeInfoModifier(uint64_t id,
222 const char* kind,
223 const std::string& name,
224 uint64_t size_bits,
225 const std::string& base_type)
226 : TypeInfo(id, kind, name, size_bits), base_type_(base_type) {}
227
~TypeInfoModifier()228 virtual ~TypeInfoModifier() {}
229
GetJson() const230 virtual JsonNameValue GetJson() const override {
231 Json::Value obj(Json::objectValue);
232
233 obj["kind"] = kind_;
234 obj["base_type"] = base_type_;
235 obj["size"] = Json::UInt64(size_bits_);
236
237 return JsonNameValue(name_, obj);
238 }
239
240 private:
241 std::string base_type_;
242 };
243
244 class TypeInfoIncomplete : public TypeInfo {
245 public:
TypeInfoIncomplete(uint64_t id,const std::string & name,const std::string & base_name)246 TypeInfoIncomplete(uint64_t id, const std::string& name, const std::string& base_name)
247 : TypeInfo(id, kKindIncomplete, name, 0), base_name_(base_name) {}
~TypeInfoIncomplete()248 virtual ~TypeInfoIncomplete() {}
249
GetJson() const250 virtual JsonNameValue GetJson() const override {
251 Json::Value obj(Json::objectValue);
252
253 obj["kind"] = kind_;
254
255 return JsonNameValue(name_, obj);
256 }
257
base_name() const258 virtual const std::string& base_name() const override { return base_name_; }
259
260 private:
261 std::string base_name_;
262 };
263
264 class TypeInfoVoid : public TypeInfoIncomplete {
265 public:
TypeInfoVoid()266 TypeInfoVoid() : TypeInfoIncomplete(0, "void", "void") {}
~TypeInfoVoid()267 virtual ~TypeInfoVoid() {}
268 };
269
270 class TypeInfoBase : public TypeInfo {
271 public:
TypeInfoBase(uint64_t id,const std::string & name,uint64_t size_bits,const char * kind,bool is_signed)272 TypeInfoBase(uint64_t id,
273 const std::string& name,
274 uint64_t size_bits,
275 const char* kind,
276 bool is_signed)
277 : TypeInfo(id, kind, name, size_bits), is_signed_(is_signed) {}
~TypeInfoBase()278 virtual ~TypeInfoBase() {}
279
GetJson() const280 virtual JsonNameValue GetJson() const override {
281 Json::Value obj(Json::objectValue);
282
283 obj["kind"] = kind_;
284 obj["signed"] = is_signed_;
285 obj["size"] = Json::UInt64(size_bits_);
286
287 return JsonNameValue(name_, obj);
288 }
289
290 private:
291 bool is_signed_;
292 };
293
294 class TypeInfoArray : public TypeInfo {
295 public:
TypeInfoArray(uint64_t id,const std::string & name,uint64_t size_bits,const std::string & element_type)296 TypeInfoArray(uint64_t id,
297 const std::string& name,
298 uint64_t size_bits,
299 const std::string& element_type)
300 : TypeInfo(id, kKindArray, name, size_bits), element_type_(element_type) {}
~TypeInfoArray()301 virtual ~TypeInfoArray() {}
302
GetJson() const303 virtual JsonNameValue GetJson() const override {
304 Json::Value obj(Json::objectValue);
305
306 obj["kind"] = kind_;
307 obj["element_type"] = element_type_;
308 obj["size"] = Json::UInt64(size_bits_);
309
310 return JsonNameValue(name_, obj);
311 }
312
313 private:
314 std::string element_type_;
315 };
316
317 class TypeInfoClassField {
318 public:
TypeInfoClassField()319 TypeInfoClassField() : offset_bits_(0) {}
TypeInfoClassField(const std::string & name,const std::string & type_name,uint32_t offset_bits)320 TypeInfoClassField(const std::string& name, const std::string& type_name, uint32_t offset_bits)
321 : name_(name), type_name_(type_name), offset_bits_(offset_bits) {}
322
323 TypeInfoClassField(TypeInfoClassField&& that) = default;
324 TypeInfoClassField& operator=(TypeInfoClassField&& that) = default;
325
name() const326 const std::string& name() const { return name_; }
type_name() const327 const std::string& type_name() const { return type_name_; }
offset_bits() const328 uint64_t offset_bits() const { return offset_bits_; }
329
330 private:
331 std::string name_;
332 std::string type_name_;
333 uint64_t offset_bits_;
334
335 friend bool operator!=(const TypeInfoClassField& one, const TypeInfoClassField& two);
336
337 DISALLOW_COPY_AND_ASSIGN(TypeInfoClassField);
338 };
339
operator !=(const TypeInfoClassField & one,const TypeInfoClassField & two)340 bool operator!=(const TypeInfoClassField& one, const TypeInfoClassField& two) {
341 return one.offset_bits_ != two.offset_bits_ || one.name_ != two.name_ /* ||
342 one.type_name_ != two.type_name_*/
343 ;
344 }
345
346 class TypeInfoClass : public TypeInfo {
347 public:
TypeInfoClass(uint64_t id,const char * kind,const std::string & name,uint64_t size_bits,const std::string & base_name)348 TypeInfoClass(uint64_t id,
349 const char* kind,
350 const std::string& name,
351 uint64_t size_bits,
352 const std::string& base_name)
353 : TypeInfo(id, kind, name, size_bits), base_name_(base_name) {}
~TypeInfoClass()354 virtual ~TypeInfoClass() {}
355
AddField(const std::string & name,const std::string & type_name,uint32_t offset_bits)356 void AddField(const std::string& name, const std::string& type_name, uint32_t offset_bits) {
357 fields_.push_back(TypeInfoClassField(name, type_name, offset_bits));
358 }
359
AddInheritance(const std::string & name)360 void AddInheritance(const std::string& name) { inheritance_types_.push_back(name); }
361
EqualsTo(const TypeInfo * other) const362 virtual bool EqualsTo(const TypeInfo* other) const override {
363 if (!TypeInfo::EqualsTo(other)) {
364 return false;
365 }
366
367 auto other_class = static_cast<const TypeInfoClass*>(other);
368
369 if (fields_.size() != other_class->fields_.size()) {
370 return false;
371 }
372
373 for (size_t i = 0; i < fields_.size(); ++i) {
374 if (fields_[i] != other_class->fields_[i]) {
375 return false;
376 }
377 }
378
379 return true;
380 }
381
GetJson() const382 virtual JsonNameValue GetJson() const override {
383 Json::Value fields(Json::arrayValue);
384
385 for (auto& field : fields_) {
386 Json::Value field_obj(Json::objectValue);
387 field_obj["name"] = field.name();
388 field_obj["offset"] = Json::UInt64(field.offset_bits());
389 field_obj["type"] = field.type_name();
390 fields.append(field_obj);
391 }
392
393 Json::Value inheritance_types_array(Json::arrayValue);
394 for (const auto& inheritance_type : inheritance_types_) {
395 inheritance_types_array.append(inheritance_type);
396 }
397
398 Json::Value obj(Json::objectValue);
399
400 obj["inheritance"] = inheritance_types_array;
401 obj["fields"] = fields;
402 obj["kind"] = kind_;
403 obj["size"] = Json::UInt64(size_bits_);
404
405 return JsonNameValue(name_, obj);
406 }
407
base_name() const408 virtual const std::string& base_name() const override { return base_name_; }
409
410 private:
411 std::string base_name_;
412 std::vector<TypeInfoClassField> fields_;
413 std::vector<std::string> inheritance_types_;
414 };
415
416 // Returns nullptr for 'void'
GetAtTypeDie(const nogrod::DwarfDie * die,const nogrod::DwarfInfo * info)417 const nogrod::DwarfDie* GetAtTypeDie(const nogrod::DwarfDie* die, const nogrod::DwarfInfo* info) {
418 auto offset = die->GetUint64Attribute(DW_AT_type);
419 if (offset) {
420 auto target_die = info->GetDieByOffset(offset.value());
421 if (target_die == nullptr) {
422 error("Couldn't find die for type of die at offset 0x%" PRIx64 " (DW_AT_type=0x%" PRIx64 ")",
423 die->offset(),
424 offset.value());
425 }
426
427 return target_die;
428 }
429
430 // If there is no DW_AT_type check DW_AT_specification
431 auto specification_offset = die->GetUint64Attribute(DW_AT_specification);
432 if (!specification_offset) { // this is 'void'
433 return nullptr;
434 }
435
436 auto specification_die = info->GetDieByOffset(specification_offset.value());
437 if (specification_die == nullptr) {
438 error("Couldn't find die for specification of die at offset 0x%" PRIx64
439 " (DW_AT_type=0x%" PRIx64 ")",
440 die->offset(),
441 specification_offset.value());
442 }
443
444 return GetAtTypeDie(specification_die, info);
445 }
446
ParseBaseType(const nogrod::DwarfDie * die)447 std::unique_ptr<TypeInfo> ParseBaseType(const nogrod::DwarfDie* die) {
448 auto encoding_attr = die->GetUint64Attribute(DW_AT_encoding);
449 if (!encoding_attr) {
450 error("Couldn't find DW_AT_encoding for DW_TAG_base_type at offset 0x%" PRIx64, die->offset());
451 }
452 uint64_t encoding = encoding_attr.value();
453
454 auto size_attr = die->GetUint64Attribute(DW_AT_byte_size);
455 uint64_t size = 0;
456
457 if ((encoding == DW_ATE_signed_char || encoding == DW_ATE_unsigned_char) && !size_attr) {
458 size = 1;
459 } else {
460 if (!size_attr) {
461 error("Couldn't find DW_AT_byte_size for DW_TAG_base_type at offset 0x%" PRIx64,
462 die->offset());
463 }
464 size = size_attr.value();
465 }
466
467 if (size > 128 || !powerof2(size)) {
468 error("Unsupported size %" PRId64 " for DW_TAG_base_type at offset 0x%" PRIx64
469 " - must be no greater than 128 and a power of 2",
470 size,
471 die->offset());
472 }
473
474 bool is_signed = false;
475 const char* kind;
476 const char* prefix;
477
478 switch (encoding) {
479 case DW_ATE_signed:
480 kind = "int";
481 prefix = "int";
482 is_signed = true;
483 break;
484 case DW_ATE_unsigned:
485 kind = "int";
486 prefix = "unsigned int";
487 is_signed = false;
488 break;
489 case DW_ATE_boolean:
490 kind = "int";
491 prefix = "bool";
492 is_signed = false;
493 break;
494 case DW_ATE_float:
495 kind = "float";
496 prefix = "float";
497 is_signed = true;
498 break;
499 case DW_ATE_signed_char:
500 kind = "char";
501 prefix = "char";
502 is_signed = true;
503 break;
504 case DW_ATE_unsigned_char:
505 case DW_ATE_UTF:
506 kind = "char";
507 prefix = "unsigned char";
508 is_signed = false;
509 break;
510 default:
511 error("Unsupported DW_AT_encoding=0x%" PRIx64 " for DW_TAG_base_type at offset 0x%" PRIx64,
512 encoding,
513 die->offset());
514 }
515
516 std::string name = prefix;
517 if (strcmp(prefix, "bool") != 0) {
518 name = StringPrintf("%s%" PRId64, prefix, size * CHAR_BIT);
519 }
520
521 return std::unique_ptr<TypeInfoBase>(
522 new TypeInfoBase(die->offset(), name, size * CHAR_BIT, kind, is_signed));
523 }
524
ParseEnumType(const nogrod::DwarfDie * die)525 std::unique_ptr<TypeInfo> ParseEnumType(const nogrod::DwarfDie* die) {
526 auto size_attr = die->GetUint64Attribute(DW_AT_byte_size);
527 if (!size_attr) {
528 error("Couldn't find DW_AT_byte_size for DW_TAG_base_type at offset 0x%" PRIx64, die->offset());
529 }
530
531 uint64_t size = size_attr.value() * CHAR_BIT;
532
533 std::string name = StringPrintf("%s%" PRId64, "unsigned int", size);
534
535 return std::unique_ptr<TypeInfoBase>(new TypeInfoBase(die->offset(), name, size, "int", false));
536 }
537
GetDieName(const nogrod::DwarfDie * die)538 std::optional<std::string> GetDieName(const nogrod::DwarfDie* die) {
539 auto die_name = die->GetStringAttribute(DW_AT_linkage_name);
540
541 if (!die_name) {
542 die_name = die->GetStringAttribute(DW_AT_name);
543 }
544
545 return die_name;
546 }
547
UpdateName(std::string original,bool is_first,std::string base_name)548 std::string UpdateName(std::string original, bool is_first, std::string base_name) {
549 if (!is_first) {
550 original += ", ";
551 }
552 std::vector<std::string> kind_strs{kKindStruct,
553 kKindClass,
554 kKindUnion,
555 kKindArray,
556 kKindAtomic,
557 kKindFunction,
558 kKindIncomplete,
559 kKindRestrict,
560 kKindVolatile};
561 for (const auto& kind_str : kind_strs) {
562 auto index = base_name.find(kind_str);
563 if (index != std::string::npos) {
564 // remove "kind" prefix and a following space
565 base_name.erase(index, kind_str.length() + 1);
566 }
567 }
568 original += base_name;
569 return original;
570 }
571
GenerateClassName(const auto & children,auto class_name,const nogrod::DwarfDie * die,const nogrod::DwarfInfo * dwarf_info,std::unordered_map<uint64_t,std::unique_ptr<TypeInfo>> * types)572 std::string GenerateClassName(const auto& children,
573 auto class_name,
574 const nogrod::DwarfDie* die,
575 const nogrod::DwarfInfo* dwarf_info,
576 std::unordered_map<uint64_t, std::unique_ptr<TypeInfo>>* types) {
577 std::string template_params = "";
578 for (size_t i = 0; i < children.size(); ++i) {
579 auto child = children[i];
580
581 if (child->tag() == DW_TAG_GNU_template_parameter_pack) {
582 const auto& parameter_pack_children = child->children();
583 for (auto child_child : parameter_pack_children) {
584 if (child_child->tag() == DW_TAG_template_type_parameter ||
585 child_child->tag() == DW_TAG_template_value_parameter) {
586 auto temp_type_die = GetAtTypeDie(child_child, dwarf_info);
587 if (temp_type_die == nullptr) {
588 continue;
589 }
590 auto template_type_info = ParseDie(temp_type_die, child, dwarf_info, types);
591 template_params =
592 UpdateName(template_params, i == 0, (template_type_info->base_name()).c_str());
593 continue;
594 }
595 }
596 continue;
597 }
598
599 if (child->tag() == DW_TAG_template_type_parameter ||
600 child->tag() == DW_TAG_template_value_parameter) {
601 auto child_type_die = GetAtTypeDie(child, dwarf_info);
602 if (child_type_die == nullptr) {
603 continue;
604 }
605 auto child_type_info = ParseDie(child_type_die, die, dwarf_info, types);
606
607 if (std::string_view{child_type_info->base_name()}.find("bool") != std::string_view::npos) {
608 auto num = child->GetUint64Attribute(DW_AT_const_value);
609 if (num) {
610 // Using the value of bool to avoid dedup failure
611 std::string bool_val = num.value() == 0 ? "false" : "true";
612 template_params = UpdateName(template_params, i == 0, bool_val);
613 }
614 } else {
615 template_params =
616 UpdateName(template_params, i == 0, (child_type_info->base_name()).c_str());
617 }
618 continue;
619 }
620 }
621
622 if (!template_params.empty()) {
623 return class_name + "<" + template_params + ">";
624 }
625
626 return class_name;
627 }
628
629 const TypeInfo* ParseDie(const nogrod::DwarfDie* start,
630 const nogrod::DwarfDie* referenced_by,
631 const nogrod::DwarfInfo* dwarf_info,
632 std::unordered_map<uint64_t, std::unique_ptr<TypeInfo>>* types);
633
ParseClass(const char * kind,const nogrod::DwarfDie * die,const nogrod::DwarfDie * referenced_by,const nogrod::DwarfInfo * dwarf_info,std::unordered_map<uint64_t,std::unique_ptr<TypeInfo>> * types)634 const TypeInfo* ParseClass(const char* kind,
635 const nogrod::DwarfDie* die,
636 const nogrod::DwarfDie* referenced_by,
637 const nogrod::DwarfInfo* dwarf_info,
638 std::unordered_map<uint64_t, std::unique_ptr<TypeInfo>>* types) {
639 auto die_name = GetDieName(die);
640 auto die_tag = die->tag();
641 // Use typedef name in case if this class is part of
642 // "typedef struct { .. } blah;" declaration
643 if (!die_name && referenced_by != nullptr && referenced_by->tag() == DW_TAG_typedef) {
644 die_name = GetDieName(referenced_by);
645 die_tag = referenced_by->tag();
646 }
647
648 std::string class_name;
649 if (die_name) {
650 class_name = die_name.value();
651 } else {
652 class_name = GenerateGlobalAnonName();
653 }
654
655 auto parent_die = die->parent();
656
657 if (parent_die->tag() == DW_TAG_structure_type || parent_die->tag() == DW_TAG_class_type ||
658 parent_die->tag() == DW_TAG_union_type) {
659 const TypeInfo* parent_type_info = ParseDie(parent_die, nullptr, dwarf_info, types);
660 CHECK(parent_type_info != nullptr);
661 class_name = StringPrintf("%s::%s", parent_type_info->base_name().c_str(), class_name.c_str());
662 }
663
664 while (parent_die->tag() == DW_TAG_namespace) {
665 // Note: if type placed in anonymous namespace is used with template, e.g.,
666 // "icu_65::MaybeStackArray<icu_65::(anonymous namespace)::LocaleAndWeight, 20>"
667 // then string "(anonymous namespace)" is used by clang. But the namespace object
668 // itself doesn't have a name. Assign name "(anonymous namespace)" for consistency.
669 static constexpr const char* kAnonymousNamespaceName = "(anonymous namespace)";
670 auto parent_die_optional_name = GetDieName(parent_die);
671 const char* parent_die_name = parent_die_optional_name
672 ? parent_die_optional_name.value().c_str()
673 : kAnonymousNamespaceName;
674 class_name = StringPrintf("%s::%s", parent_die_name, class_name.c_str());
675 parent_die = parent_die->parent();
676 }
677
678 std::string name = StringPrintf("%s %s", kind, class_name.c_str());
679
680 // TODO: align????
681 bool incomplete = die->GetBoolAttributeOr(DW_AT_declaration, false);
682
683 if (incomplete) {
684 if (!die_name) {
685 warning("The incomplete type at offset 0x%" PRIx64 " referenced by \"%s\"@0x%" PRIx64
686 " is anonymous (ignoring)",
687 die->offset(),
688 referenced_by != nullptr ? GetDieName(referenced_by).value_or("<no name>").c_str()
689 : "<null>",
690 referenced_by != nullptr ? referenced_by->offset() : 0);
691 }
692
693 std::unique_ptr<TypeInfoIncomplete> incomplete_type_holder(
694 new TypeInfoIncomplete(die->offset(), name, class_name));
695 TypeInfoIncomplete* result = incomplete_type_holder.get();
696 (*types)[die->offset()] = std::move(incomplete_type_holder);
697 // An incomplete struct - find other dies by name and parse them too.
698 // This should solve the case where actual type is declared in another
699 // compilation unit. We could get some false positives - this is ok.
700 std::vector<const nogrod::DwarfDie*> dies = dwarf_info->FindDiesByName(class_name);
701 if (dies.empty()) {
702 warning(
703 "Couldn't find dies by name \"%s\" for incomplete type at the offset 0x%x (likely "
704 "because it had no name) - ignoring",
705 class_name.c_str(),
706 result->id());
707 }
708
709 for (auto namefellow_die : dies) {
710 // Limit to the tag of the original incomplete type
711 if (namefellow_die->tag() != die_tag) {
712 continue;
713 }
714 ParseDie(namefellow_die, nullptr, dwarf_info, types);
715 }
716 return result;
717 }
718
719 auto size = die->GetUint64Attribute(DW_AT_byte_size);
720
721 if (!size) {
722 error("No DW_AT_byte_size specified for type at offset 0x%" PRIx64, die->offset());
723 }
724
725 const auto& children = die->children();
726 class_name = GenerateClassName(children, class_name, die, dwarf_info, types);
727 name = StringPrintf("%s %s", kind, class_name.c_str());
728 std::unique_ptr<TypeInfoClass> type_info_holder(
729 new TypeInfoClass(die->offset(), kind, name, size.value() * CHAR_BIT, class_name));
730 TypeInfoClass* type_info = type_info_holder.get();
731 (*types)[die->offset()] = std::move(type_info_holder);
732
733 for (auto child : children) {
734 if (child->tag() == DW_TAG_subprogram) {
735 continue;
736 }
737
738 // Skip nested types - they are parsed only if referenced by a DW_AT_member (see below).
739 if (child->tag() == DW_TAG_structure_type || child->tag() == DW_TAG_union_type ||
740 child->tag() == DW_TAG_class_type || child->tag() == DW_TAG_enumeration_type ||
741 child->tag() == DW_TAG_typedef) {
742 continue;
743 }
744
745 if (child->tag() == DW_TAG_inheritance) {
746 auto inheritance_die = GetAtTypeDie(child, dwarf_info);
747 CHECK(inheritance_die != nullptr); // voids are not allowed here.
748 auto inheritance_type_info = ParseDie(inheritance_die, die, dwarf_info, types);
749 type_info->AddInheritance(inheritance_type_info->name());
750 continue;
751 }
752
753 if (child->tag() == DW_TAG_template_type_parameter ||
754 child->tag() == DW_TAG_template_value_parameter ||
755 child->tag() == DW_TAG_GNU_template_parameter_pack ||
756 child->tag() == DW_TAG_GNU_template_template_param) {
757 // These types do not affect struct layout unless they are used
758 // for members. This is why we should probably ignore them here.
759 // auto type_die = GetAtTypeDie(child, dwarf_info);
760 // ParseDie(type_die, dwarf_info, types);
761 continue;
762 }
763
764 if (child->tag() != DW_TAG_member) { // see if this is the case...
765 error("Unexpected tag 0x%x for the die at offset 0x%" PRIx64 ", expected DW_TAG_member",
766 child->tag(),
767 child->offset());
768 }
769
770 if (child->GetBoolAttributeOr(DW_AT_external, false)) {
771 // DW_AT_external is dwarvish for static member
772 continue;
773 }
774
775 auto member_die = GetAtTypeDie(child, dwarf_info);
776 CHECK(member_die != nullptr);
777 auto member_type_info = ParseDie(member_die, die, dwarf_info, types);
778
779 auto name = child->GetStringAttribute(DW_AT_name);
780
781 // Nested unions and structs may not have a name.
782 if (!name && member_die->tag() != DW_TAG_union_type &&
783 member_die->tag() != DW_TAG_structure_type) {
784 error("DW_AT_name is not set for the die at offset 0x%" PRIx64, child->offset());
785 }
786
787 std::string type_name = member_type_info->name();
788
789 // TODO: handle bit offset
790 auto offset = child->GetUint64AttributeOr(DW_AT_data_member_location, 0);
791 type_info->AddField(name.value_or(""), type_name, offset * CHAR_BIT);
792 }
793
794 // is_polymorphic??
795
796 return type_info;
797 }
798
ParseFunction(const nogrod::DwarfDie * die,const nogrod::DwarfInfo * dwarf_info,std::unordered_map<uint64_t,std::unique_ptr<TypeInfo>> * types)799 const TypeInfo* ParseFunction(const nogrod::DwarfDie* die,
800 const nogrod::DwarfInfo* dwarf_info,
801 std::unordered_map<uint64_t, std::unique_ptr<TypeInfo>>* types) {
802 auto die_name = GetDieName(die);
803 if (!die_name && die->tag() != DW_TAG_subroutine_type) {
804 error("Couldn't resolve name for die at offset=0x%" PRIx64, die->offset());
805 }
806
807 std::string function_name = die_name ? die_name.value() : GenerateGlobalAnonName();
808
809 std::string name = StringPrintf("func %s", function_name.c_str());
810
811 std::unique_ptr<TypeInfoFunction> type_info_holder(
812 new TypeInfoFunction(die->offset(), name, function_name));
813 TypeInfoFunction* type_info = type_info_holder.get();
814 (*types)[die->offset()] = std::move(type_info_holder);
815
816 auto return_die = GetAtTypeDie(die, dwarf_info);
817 type_info->SetReturnType(ParseDie(return_die, die, dwarf_info, types)->name());
818
819 // This is special case of hard-fp (AAPCS_VFP)
820 if (die->GetUint64AttributeOr(DW_AT_calling_convention, 0) == DW_CC_LLVM_AAPCS_VFP) {
821 type_info->SetCallingConvention("aapcs-vfp");
822 }
823
824 // parse parameters
825 const auto& children = die->children();
826 for (auto child : children) {
827 if (child->tag() == DW_TAG_formal_parameter) {
828 auto param_die = GetAtTypeDie(child, dwarf_info);
829 // presumably we cannot have void formal parameter... DW_AT_type is
830 // required here
831 CHECK(param_die != nullptr); // FAIL_IF?
832 type_info->AddParam(ParseDie(param_die, die, dwarf_info, types)->name());
833 } else if (child->tag() == DW_TAG_unspecified_parameters) {
834 type_info->SetHasVariadicArgs(true);
835 break; // No more formal_parameters after this. TODO: replace with stricter check maybe?
836 }
837 }
838
839 return type_info;
840 }
841
ParseReference(const ReferenceType reference_type,const nogrod::DwarfDie * die,const nogrod::DwarfInfo * dwarf_info,std::unordered_map<uint64_t,std::unique_ptr<TypeInfo>> * types)842 std::unique_ptr<TypeInfo> ParseReference(
843 const ReferenceType reference_type,
844 const nogrod::DwarfDie* die,
845 const nogrod::DwarfInfo* dwarf_info,
846 std::unordered_map<uint64_t, std::unique_ptr<TypeInfo>>* types) {
847 auto referenced_die = GetAtTypeDie(die, dwarf_info);
848 std::string referenced_type_name = ParseDie(referenced_die, die, dwarf_info, types)->name();
849 std::string name = referenced_type_name;
850 const char* kind = nullptr;
851
852 switch (reference_type) {
853 case ReferenceType::pointer:
854 name += "*";
855 kind = "pointer";
856 break;
857 case ReferenceType::reference:
858 name += "&";
859 kind = "reference";
860 break;
861 case ReferenceType::rvalue_reference:
862 name += "&&";
863 kind = "rvalue_reference";
864 break;
865 }
866
867 return std::make_unique<TypeInfoReference>(
868 die->offset(),
869 kind,
870 name,
871 die->compilation_unit_header()->address_size() * CHAR_BIT,
872 referenced_type_name);
873 }
874
ParseModifier(const char * kind,const nogrod::DwarfDie * die,const nogrod::DwarfInfo * dwarf_info,std::unordered_map<uint64_t,std::unique_ptr<TypeInfo>> * types)875 std::unique_ptr<TypeInfo> ParseModifier(
876 const char* kind,
877 const nogrod::DwarfDie* die,
878 const nogrod::DwarfInfo* dwarf_info,
879 std::unordered_map<uint64_t, std::unique_ptr<TypeInfo>>* types) {
880 // The only field we need is base_type
881 auto base_die = GetAtTypeDie(die, dwarf_info);
882 auto base_type = ParseDie(base_die, die, dwarf_info, types);
883 std::string base_type_name = base_type->name();
884 uint64_t base_type_size = base_type->size();
885
886 std::string name = StringPrintf("%s %s", base_type_name.c_str(), kind);
887
888 return std::make_unique<TypeInfoModifier>(
889 die->offset(), kind, name, base_type_size, base_type_name);
890 }
891
ParseArray(const nogrod::DwarfDie * die,const nogrod::DwarfInfo * dwarf_info,std::unordered_map<uint64_t,std::unique_ptr<TypeInfo>> * types)892 std::unique_ptr<TypeInfo> ParseArray(
893 const nogrod::DwarfDie* die,
894 const nogrod::DwarfInfo* dwarf_info,
895 std::unordered_map<uint64_t, std::unique_ptr<TypeInfo>>* types) {
896 uint64_t count = 0;
897
898 auto element_die = GetAtTypeDie(die, dwarf_info);
899 if (element_die == nullptr) {
900 error("'void' cannot be element type of an array (die at offset 0x%" PRIx64 ")", die->offset());
901 }
902
903 auto element_type = ParseDie(element_die, die, dwarf_info, types);
904
905 auto children = die->children();
906
907 std::string name = element_type->name();
908
909 for (auto child : die->children()) {
910 if (child->tag() != DW_TAG_subrange_type) {
911 error("Unexpected tag 0x%x for the die at offset 0x%" PRIx64
912 ", expected DW_TAG_subrange_type",
913 child->tag(),
914 child->offset());
915 }
916
917 auto count_attr = child->GetUint64Attribute(DW_AT_count);
918 if (count_attr) {
919 count = count_attr.value();
920 } else { // use DW_AT_upper_bound/lower_bound
921 count = child->GetUint64AttributeOr(DW_AT_upper_bound, 0) -
922 child->GetUint64AttributeOr(DW_AT_lower_bound, 0) + 1;
923 }
924
925 name += StringPrintf("[%" PRId64 "]", count);
926 }
927
928 return std::make_unique<TypeInfoArray>(
929 die->offset(), name, count * element_type->size(), element_type->name());
930 }
931
ParseUnspecifiedType(const nogrod::DwarfDie * die)932 std::unique_ptr<TypeInfo> ParseUnspecifiedType(const nogrod::DwarfDie* die) {
933 // The only unspecified_type we support is nullptr_t
934 auto die_name = GetDieName(die);
935 if (!die_name) {
936 error("Couldn't resolve name for die at offset=0x%" PRIx64, die->offset());
937 }
938
939 if (die_name.value() != "decltype(nullptr)") {
940 error("Unspecified type \"%s\" at offset 0x%" PRIx64
941 " is not supported "
942 "(the only supported unspecified type is nullptr_t)",
943 die_name.value().c_str(),
944 die->offset());
945 }
946
947 return std::make_unique<TypeInfoBase>(die->offset(), die_name.value(), 32, "nullptr_t", false);
948 }
949
ParseDie(const nogrod::DwarfDie * die,const nogrod::DwarfDie * referenced_by,const nogrod::DwarfInfo * dwarf_info,std::unordered_map<uint64_t,std::unique_ptr<TypeInfo>> * types)950 const TypeInfo* ParseDie(const nogrod::DwarfDie* die,
951 const nogrod::DwarfDie* referenced_by,
952 const nogrod::DwarfInfo* dwarf_info,
953 std::unordered_map<uint64_t, std::unique_ptr<TypeInfo>>* types) {
954 if (die == nullptr) {
955 auto it = types->find(0);
956 if (it != types->end()) {
957 return it->second.get();
958 } else {
959 std::unique_ptr<TypeInfo> void_type(new TypeInfoVoid());
960 TypeInfo* result = void_type.get();
961 (*types)[0] = std::move(void_type);
962 return result;
963 }
964 }
965
966 auto it = types->find(die->offset());
967 if (it != types->end()) {
968 return it->second.get();
969 }
970
971 std::unique_ptr<TypeInfo> type_info;
972
973 switch (die->tag()) {
974 case DW_TAG_subprogram:
975 case DW_TAG_subroutine_type:
976 case DW_TAG_label:
977 return ParseFunction(die, dwarf_info, types);
978 case DW_TAG_pointer_type:
979 case DW_TAG_ptr_to_member_type:
980 type_info = ParseReference(ReferenceType::pointer, die, dwarf_info, types);
981 break;
982 case DW_TAG_reference_type:
983 type_info = ParseReference(ReferenceType::reference, die, dwarf_info, types);
984 break;
985 case DW_TAG_rvalue_reference_type:
986 type_info = ParseReference(ReferenceType::rvalue_reference, die, dwarf_info, types);
987 break;
988 case DW_TAG_atomic_type:
989 type_info = ParseModifier(kKindAtomic, die, dwarf_info, types);
990 break;
991 case DW_TAG_const_type:
992 type_info = ParseModifier(kKindConst, die, dwarf_info, types);
993 break;
994 case DW_TAG_restrict_type:
995 type_info = ParseModifier(kKindRestrict, die, dwarf_info, types);
996 break;
997 case DW_TAG_volatile_type:
998 type_info = ParseModifier(kKindVolatile, die, dwarf_info, types);
999 break;
1000 case DW_TAG_typedef: {
1001 auto typedef_type = GetAtTypeDie(die, dwarf_info);
1002 return ParseDie(typedef_type, die, dwarf_info, types);
1003 }
1004 case DW_TAG_structure_type:
1005 return ParseClass(kKindStruct, die, referenced_by, dwarf_info, types);
1006 case DW_TAG_class_type:
1007 return ParseClass(kKindClass, die, referenced_by, dwarf_info, types);
1008 case DW_TAG_union_type:
1009 return ParseClass(kKindUnion, die, referenced_by, dwarf_info, types);
1010 case DW_TAG_base_type:
1011 type_info = ParseBaseType(die);
1012 break;
1013 case DW_TAG_enumeration_type:
1014 type_info = ParseEnumType(die);
1015 break;
1016 case DW_TAG_unspecified_type:
1017 type_info = ParseUnspecifiedType(die);
1018 break;
1019 case DW_TAG_array_type:
1020 type_info = ParseArray(die, dwarf_info, types);
1021 break;
1022 default:
1023 error("Unsupported die tag: 0x%x at the offset 0x%x", die->tag(), die->offset());
1024 }
1025
1026 CHECK(type_info);
1027
1028 const TypeInfo* result = type_info.get();
1029 (*types)[die->offset()] = std::move(type_info);
1030 return result;
1031 }
1032
IsModifierType(const TypeInfo * type)1033 bool IsModifierType(const TypeInfo* type) {
1034 std::string kind = type->kind();
1035 return kind == kKindConst || kind == kKindVolatile || kind == kKindRestrict;
1036 }
1037
IsArrayType(const TypeInfo * type)1038 bool IsArrayType(const TypeInfo* type) {
1039 return type->kind() == kKindArray;
1040 }
1041
warning_too_many_dies(const std::string & symbol_name,const std::vector<const nogrod::DwarfDie * > & dies)1042 void warning_too_many_dies(const std::string& symbol_name,
1043 const std::vector<const nogrod::DwarfDie*>& dies) {
1044 std::string offsets;
1045 for (auto die : dies) {
1046 offsets += StringPrintf("0x%" PRIx64 " ", die->offset());
1047 }
1048
1049 warning("Too many DIEs for %s - offsets=[ %s] - will consider only the first one",
1050 symbol_name.c_str(),
1051 offsets.c_str());
1052 }
1053
error_unsuccessful_dedup(const std::string & type_name,const std::vector<const TypeInfo * > & types)1054 __attribute__((__noreturn__)) void error_unsuccessful_dedup(
1055 const std::string& type_name,
1056 const std::vector<const TypeInfo*>& types) {
1057 std::string type_infos;
1058 for (auto type : types) {
1059 type_infos += StringPrintf("(id=0x%" PRIx64 ", kind=\'%s\', name='%s', size=%" PRId64 ") ",
1060 type->id(),
1061 type->kind(),
1062 type->name().c_str(),
1063 type->size());
1064 }
1065
1066 error("Unsuccessful dedup for %s, number of types left=%d, type_infos=[%s]",
1067 type_name.c_str(),
1068 types.size(),
1069 type_infos.c_str());
1070 }
1071
FindBestDie(const nogrod::DwarfInfo * dwarf_info,const std::string & name)1072 const nogrod::DwarfDie* FindBestDie(const nogrod::DwarfInfo* dwarf_info, const std::string& name) {
1073 std::vector<const nogrod::DwarfDie*> dies = dwarf_info->FindDiesByName(name);
1074 if (dies.empty()) {
1075 return nullptr;
1076 }
1077
1078 const nogrod::DwarfDie* variable_die = nullptr;
1079 const nogrod::DwarfDie* subprogram_die = nullptr;
1080 const nogrod::DwarfDie* label_die = nullptr;
1081
1082 for (const auto die : dies) {
1083 if (die->tag() == DW_TAG_variable) {
1084 if (variable_die != nullptr) {
1085 warning("Multiple variable DIEs for %s - will consider only the first one", name.c_str());
1086 } else {
1087 variable_die = die;
1088 }
1089 } else if (die->tag() == DW_TAG_subprogram) {
1090 if (subprogram_die != nullptr) {
1091 warning("Multiple subprogram DIEs for %s - will consider only the first one", name.c_str());
1092 } else {
1093 subprogram_die = die;
1094 }
1095 } else if (die->tag() == DW_TAG_label) {
1096 if (label_die != nullptr) {
1097 warning("Multiple label DIEs for %s - will consider only the first one", name.c_str());
1098 } else {
1099 label_die = die;
1100 }
1101 }
1102 }
1103
1104 if (variable_die != nullptr) {
1105 return variable_die;
1106 }
1107 if (subprogram_die != nullptr) {
1108 return subprogram_die;
1109 }
1110 if (label_die != nullptr) {
1111 return label_die;
1112 }
1113
1114 if (dies.size() > 1) {
1115 warning_too_many_dies(name, dies);
1116 }
1117 return dies[0];
1118 }
1119
ReadFileToStringVector(const char * name,std::vector<std::string> * lines)1120 bool ReadFileToStringVector(const char* name, std::vector<std::string>* lines) {
1121 std::ifstream fs(name);
1122 if (!fs.is_open()) {
1123 return false;
1124 }
1125 std::string line;
1126 while (std::getline(fs, line)) {
1127 lines->push_back(line);
1128 }
1129 return true;
1130 }
1131
1132 } // namespace
1133
main(int argc,const char ** argv)1134 int main(int argc, const char** argv) {
1135 const char* elf_file_name = nullptr;
1136 const char* filter_file_name = nullptr;
1137
1138 if (argc == 2) {
1139 elf_file_name = argv[1];
1140 } else if (argc == 3 && strncmp(argv[1], "--filter=", 9) == 0) {
1141 filter_file_name = argv[1] + 9;
1142 elf_file_name = argv[2];
1143 } else {
1144 usage(argv[0]);
1145 return 0;
1146 }
1147
1148 std::string error_msg;
1149
1150 std::unique_ptr<nogrod::ElfFile> elf_file = nogrod::ElfFile::Load(elf_file_name, &error_msg);
1151
1152 if (!elf_file) {
1153 error("Error loading elf-file \"%s\": %s", elf_file_name, error_msg.c_str());
1154 }
1155
1156 std::vector<std::string> names;
1157
1158 if (filter_file_name) {
1159 if (!ReadFileToStringVector(filter_file_name, &names)) {
1160 error("Error reading symbols from \"%s\"", filter_file_name);
1161 }
1162 } else {
1163 if (!elf_file->ReadExportedSymbols(&names, &error_msg)) {
1164 error("Error reading exported symbols from \"%s\": %s", elf_file_name, error_msg.c_str());
1165 }
1166 }
1167
1168 std::unique_ptr<nogrod::DwarfInfo> dwarf_info = elf_file->ReadDwarfInfo(&error_msg);
1169 if (!dwarf_info) {
1170 error("Error loading dwarf_info from \"%s\": %s", elf_file_name, error_msg.c_str());
1171 }
1172
1173 // map: type id (offset) -> type
1174 std::unordered_map<uint64_t, std::unique_ptr<TypeInfo>> types;
1175
1176 // map: symbol name -> type id (offset)
1177 std::map<std::string, uint64_t> symbols;
1178
1179 for (const auto& name : names) {
1180 const nogrod::DwarfDie* die = FindBestDie(dwarf_info.get(), name);
1181 if (die == nullptr) {
1182 warning("Couldn't find compatible DIE for %s - skipping...", name.c_str());
1183 continue;
1184 }
1185
1186 if (die->tag() == DW_TAG_subprogram || die->tag() == DW_TAG_label) {
1187 const TypeInfo* subprogram_type = ParseDie(die, nullptr, dwarf_info.get(), &types);
1188 symbols[name] = subprogram_type->id();
1189 } else if (die->tag() == DW_TAG_variable) {
1190 auto variable_type_die = GetAtTypeDie(die, dwarf_info.get());
1191 const TypeInfo* variable_type = ParseDie(variable_type_die, die, dwarf_info.get(), &types);
1192 symbols[name] = variable_type->id();
1193 } else { // Something else
1194 // TODO(random-googler): parse something else meaningfully...
1195 ParseDie(die, nullptr, dwarf_info.get(), &types);
1196 }
1197 }
1198
1199 Json::Value root(Json::objectValue);
1200 Json::Value symbols_json(Json::objectValue);
1201 for (const auto& symbol : symbols) {
1202 auto& type_name = types[symbol.second]->name();
1203 symbols_json[symbol.first]["type"] = type_name;
1204 }
1205
1206 root["symbols"] = symbols_json;
1207
1208 // Sort types by name.
1209 std::map<std::string, std::vector<const TypeInfo*>> types_by_name;
1210 for (auto& elem : types) {
1211 const TypeInfo* type_info = elem.second.get();
1212 const std::string& name = type_info->name();
1213 std::vector<const TypeInfo*>& types_list = types_by_name[name];
1214 // Remove duplicate types.
1215 bool type_info_exists = berberis::ContainsIf(
1216 types_list, [type_info](const TypeInfo* element) { return element->EqualsTo(type_info); });
1217 if (!type_info_exists) {
1218 types_list.push_back(type_info);
1219 }
1220 }
1221
1222 // Second pass
1223 for (auto& entry : types_by_name) {
1224 auto& types = entry.second;
1225 if (types.size() == 1) {
1226 continue;
1227 }
1228
1229 // Remove incomplete types
1230 // TODO: Improve this by removing all types referencing the incomplete type.
1231 // Once it is done the next step (removing modifiers and arrays with size=0)
1232 // can be removed as well.
1233 types.erase(
1234 std::remove_if(types.begin(),
1235 types.end(),
1236 [](const TypeInfo* element) { return element->kind() == kKindIncomplete; }),
1237 types.end());
1238
1239 // Remove modifier and array types with size = 0
1240 // TODO: This is mostly correct, see TODO above for details.
1241 types.erase(std::remove_if(types.begin(),
1242 types.end(),
1243 [](const TypeInfo* element) {
1244 return (IsModifierType(element) || IsArrayType(element)) &&
1245 element->size() == 0;
1246 }),
1247 types.end());
1248
1249 if (types.size() != 1) {
1250 error_unsuccessful_dedup(entry.first, types);
1251 }
1252 }
1253
1254 Json::Value types_json(Json::objectValue);
1255 for (const auto& type : types_by_name) {
1256 auto json_with_name = type.second[0]->GetJson();
1257 types_json[json_with_name.name()] = json_with_name.value();
1258 }
1259
1260 root["types"] = types_json;
1261
1262 Json::StreamWriterBuilder factory;
1263 std::unique_ptr<Json::StreamWriter> const json_writer(factory.newStreamWriter());
1264 json_writer->write(root, &std::cout);
1265
1266 return 0;
1267 }
1268