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