xref: /aosp_15_r20/external/stg/dwarf_processor.cc (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
1*9e3b08aeSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2*9e3b08aeSAndroid Build Coastguard Worker // -*- mode: C++ -*-
3*9e3b08aeSAndroid Build Coastguard Worker //
4*9e3b08aeSAndroid Build Coastguard Worker // Copyright 2022-2023 Google LLC
5*9e3b08aeSAndroid Build Coastguard Worker //
6*9e3b08aeSAndroid Build Coastguard Worker // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7*9e3b08aeSAndroid Build Coastguard Worker // "License"); you may not use this file except in compliance with the
8*9e3b08aeSAndroid Build Coastguard Worker // License.  You may obtain a copy of the License at
9*9e3b08aeSAndroid Build Coastguard Worker //
10*9e3b08aeSAndroid Build Coastguard Worker //     https://llvm.org/LICENSE.txt
11*9e3b08aeSAndroid Build Coastguard Worker //
12*9e3b08aeSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
13*9e3b08aeSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
14*9e3b08aeSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*9e3b08aeSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
16*9e3b08aeSAndroid Build Coastguard Worker // limitations under the License.
17*9e3b08aeSAndroid Build Coastguard Worker //
18*9e3b08aeSAndroid Build Coastguard Worker // Author: Aleksei Vetrov
19*9e3b08aeSAndroid Build Coastguard Worker 
20*9e3b08aeSAndroid Build Coastguard Worker #include "dwarf_processor.h"
21*9e3b08aeSAndroid Build Coastguard Worker 
22*9e3b08aeSAndroid Build Coastguard Worker #include <dwarf.h>
23*9e3b08aeSAndroid Build Coastguard Worker #include <elfutils/libdw.h>
24*9e3b08aeSAndroid Build Coastguard Worker 
25*9e3b08aeSAndroid Build Coastguard Worker #include <algorithm>
26*9e3b08aeSAndroid Build Coastguard Worker #include <cstddef>
27*9e3b08aeSAndroid Build Coastguard Worker #include <cstdint>
28*9e3b08aeSAndroid Build Coastguard Worker #include <memory>
29*9e3b08aeSAndroid Build Coastguard Worker #include <optional>
30*9e3b08aeSAndroid Build Coastguard Worker #include <sstream>
31*9e3b08aeSAndroid Build Coastguard Worker #include <string>
32*9e3b08aeSAndroid Build Coastguard Worker #include <string_view>
33*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
34*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
35*9e3b08aeSAndroid Build Coastguard Worker 
36*9e3b08aeSAndroid Build Coastguard Worker #include "dwarf_wrappers.h"
37*9e3b08aeSAndroid Build Coastguard Worker #include "error.h"
38*9e3b08aeSAndroid Build Coastguard Worker #include "filter.h"
39*9e3b08aeSAndroid Build Coastguard Worker #include "hex.h"
40*9e3b08aeSAndroid Build Coastguard Worker #include "graph.h"
41*9e3b08aeSAndroid Build Coastguard Worker #include "scope.h"
42*9e3b08aeSAndroid Build Coastguard Worker 
43*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
44*9e3b08aeSAndroid Build Coastguard Worker namespace dwarf {
45*9e3b08aeSAndroid Build Coastguard Worker 
46*9e3b08aeSAndroid Build Coastguard Worker namespace {
47*9e3b08aeSAndroid Build Coastguard Worker 
HasIncompleteTypes(uint64_t language)48*9e3b08aeSAndroid Build Coastguard Worker bool HasIncompleteTypes(uint64_t language) {
49*9e3b08aeSAndroid Build Coastguard Worker   return language != DW_LANG_Rust;
50*9e3b08aeSAndroid Build Coastguard Worker }
51*9e3b08aeSAndroid Build Coastguard Worker 
EntryToString(Entry & entry)52*9e3b08aeSAndroid Build Coastguard Worker std::string EntryToString(Entry& entry) {
53*9e3b08aeSAndroid Build Coastguard Worker   std::ostringstream os;
54*9e3b08aeSAndroid Build Coastguard Worker   os << "DWARF entry <" << Hex(entry.GetOffset()) << ">";
55*9e3b08aeSAndroid Build Coastguard Worker   return os.str();
56*9e3b08aeSAndroid Build Coastguard Worker }
57*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetName(Entry & entry)58*9e3b08aeSAndroid Build Coastguard Worker std::optional<std::string> MaybeGetName(Entry& entry) {
59*9e3b08aeSAndroid Build Coastguard Worker   return entry.MaybeGetString(DW_AT_name);
60*9e3b08aeSAndroid Build Coastguard Worker }
61*9e3b08aeSAndroid Build Coastguard Worker 
GetName(Entry & entry)62*9e3b08aeSAndroid Build Coastguard Worker std::string GetName(Entry& entry) {
63*9e3b08aeSAndroid Build Coastguard Worker   auto result = MaybeGetName(entry);
64*9e3b08aeSAndroid Build Coastguard Worker   if (!result.has_value()) {
65*9e3b08aeSAndroid Build Coastguard Worker     Die() << "Name was not found for " << EntryToString(entry);
66*9e3b08aeSAndroid Build Coastguard Worker   }
67*9e3b08aeSAndroid Build Coastguard Worker   return std::move(*result);
68*9e3b08aeSAndroid Build Coastguard Worker }
69*9e3b08aeSAndroid Build Coastguard Worker 
GetNameOrEmpty(Entry & entry)70*9e3b08aeSAndroid Build Coastguard Worker std::string GetNameOrEmpty(Entry& entry) {
71*9e3b08aeSAndroid Build Coastguard Worker   auto result = MaybeGetName(entry);
72*9e3b08aeSAndroid Build Coastguard Worker   if (!result.has_value()) {
73*9e3b08aeSAndroid Build Coastguard Worker     return {};
74*9e3b08aeSAndroid Build Coastguard Worker   }
75*9e3b08aeSAndroid Build Coastguard Worker   return std::move(*result);
76*9e3b08aeSAndroid Build Coastguard Worker }
77*9e3b08aeSAndroid Build Coastguard Worker 
GetLinkageName(int version,Entry & entry)78*9e3b08aeSAndroid Build Coastguard Worker std::string GetLinkageName(int version, Entry& entry) {
79*9e3b08aeSAndroid Build Coastguard Worker   auto linkage_name = entry.MaybeGetString(
80*9e3b08aeSAndroid Build Coastguard Worker       version < 4 ? DW_AT_MIPS_linkage_name : DW_AT_linkage_name);
81*9e3b08aeSAndroid Build Coastguard Worker   if (linkage_name.has_value()) {
82*9e3b08aeSAndroid Build Coastguard Worker     return std::move(*linkage_name);
83*9e3b08aeSAndroid Build Coastguard Worker   }
84*9e3b08aeSAndroid Build Coastguard Worker   return GetNameOrEmpty(entry);
85*9e3b08aeSAndroid Build Coastguard Worker }
86*9e3b08aeSAndroid Build Coastguard Worker 
GetBitSize(Entry & entry)87*9e3b08aeSAndroid Build Coastguard Worker size_t GetBitSize(Entry& entry) {
88*9e3b08aeSAndroid Build Coastguard Worker   if (auto byte_size = entry.MaybeGetUnsignedConstant(DW_AT_byte_size)) {
89*9e3b08aeSAndroid Build Coastguard Worker     return *byte_size * 8;
90*9e3b08aeSAndroid Build Coastguard Worker   } else if (auto bit_size = entry.MaybeGetUnsignedConstant(DW_AT_bit_size)) {
91*9e3b08aeSAndroid Build Coastguard Worker     return *bit_size;
92*9e3b08aeSAndroid Build Coastguard Worker   }
93*9e3b08aeSAndroid Build Coastguard Worker   Die() << "Bit size was not found for " << EntryToString(entry);
94*9e3b08aeSAndroid Build Coastguard Worker }
95*9e3b08aeSAndroid Build Coastguard Worker 
GetByteSize(Entry & entry)96*9e3b08aeSAndroid Build Coastguard Worker size_t GetByteSize(Entry& entry) {
97*9e3b08aeSAndroid Build Coastguard Worker   if (auto byte_size = entry.MaybeGetUnsignedConstant(DW_AT_byte_size)) {
98*9e3b08aeSAndroid Build Coastguard Worker     return *byte_size;
99*9e3b08aeSAndroid Build Coastguard Worker   } else if (auto bit_size = entry.MaybeGetUnsignedConstant(DW_AT_bit_size)) {
100*9e3b08aeSAndroid Build Coastguard Worker     // Round up bit_size / 8 to get minimal needed storage size in bytes.
101*9e3b08aeSAndroid Build Coastguard Worker     return (*bit_size + 7) / 8;
102*9e3b08aeSAndroid Build Coastguard Worker   }
103*9e3b08aeSAndroid Build Coastguard Worker   Die() << "Byte size was not found for " << EntryToString(entry);
104*9e3b08aeSAndroid Build Coastguard Worker }
105*9e3b08aeSAndroid Build Coastguard Worker 
GetEncoding(Entry & entry)106*9e3b08aeSAndroid Build Coastguard Worker Primitive::Encoding GetEncoding(Entry& entry) {
107*9e3b08aeSAndroid Build Coastguard Worker   const auto dwarf_encoding = entry.MaybeGetUnsignedConstant(DW_AT_encoding);
108*9e3b08aeSAndroid Build Coastguard Worker   if (!dwarf_encoding) {
109*9e3b08aeSAndroid Build Coastguard Worker     Die() << "Encoding was not found for " << EntryToString(entry);
110*9e3b08aeSAndroid Build Coastguard Worker   }
111*9e3b08aeSAndroid Build Coastguard Worker   switch (*dwarf_encoding) {
112*9e3b08aeSAndroid Build Coastguard Worker     case DW_ATE_boolean:
113*9e3b08aeSAndroid Build Coastguard Worker       return Primitive::Encoding::BOOLEAN;
114*9e3b08aeSAndroid Build Coastguard Worker     case DW_ATE_complex_float:
115*9e3b08aeSAndroid Build Coastguard Worker       return Primitive::Encoding::COMPLEX_NUMBER;
116*9e3b08aeSAndroid Build Coastguard Worker     case DW_ATE_float:
117*9e3b08aeSAndroid Build Coastguard Worker       return Primitive::Encoding::REAL_NUMBER;
118*9e3b08aeSAndroid Build Coastguard Worker     case DW_ATE_signed:
119*9e3b08aeSAndroid Build Coastguard Worker       return Primitive::Encoding::SIGNED_INTEGER;
120*9e3b08aeSAndroid Build Coastguard Worker     case DW_ATE_signed_char:
121*9e3b08aeSAndroid Build Coastguard Worker       return Primitive::Encoding::SIGNED_CHARACTER;
122*9e3b08aeSAndroid Build Coastguard Worker     case DW_ATE_unsigned:
123*9e3b08aeSAndroid Build Coastguard Worker       return Primitive::Encoding::UNSIGNED_INTEGER;
124*9e3b08aeSAndroid Build Coastguard Worker     case DW_ATE_unsigned_char:
125*9e3b08aeSAndroid Build Coastguard Worker       return Primitive::Encoding::UNSIGNED_CHARACTER;
126*9e3b08aeSAndroid Build Coastguard Worker     case DW_ATE_UTF:
127*9e3b08aeSAndroid Build Coastguard Worker       return Primitive::Encoding::UTF;
128*9e3b08aeSAndroid Build Coastguard Worker     default:
129*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Unknown encoding " << Hex(*dwarf_encoding) << " for "
130*9e3b08aeSAndroid Build Coastguard Worker             << EntryToString(entry);
131*9e3b08aeSAndroid Build Coastguard Worker   }
132*9e3b08aeSAndroid Build Coastguard Worker }
133*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetReferredType(Entry & entry)134*9e3b08aeSAndroid Build Coastguard Worker std::optional<Entry> MaybeGetReferredType(Entry& entry) {
135*9e3b08aeSAndroid Build Coastguard Worker   return entry.MaybeGetReference(DW_AT_type);
136*9e3b08aeSAndroid Build Coastguard Worker }
137*9e3b08aeSAndroid Build Coastguard Worker 
GetReferredType(Entry & entry)138*9e3b08aeSAndroid Build Coastguard Worker Entry GetReferredType(Entry& entry) {
139*9e3b08aeSAndroid Build Coastguard Worker   auto result = MaybeGetReferredType(entry);
140*9e3b08aeSAndroid Build Coastguard Worker   if (!result.has_value()) {
141*9e3b08aeSAndroid Build Coastguard Worker     Die() << "Type reference was not found in " << EntryToString(entry);
142*9e3b08aeSAndroid Build Coastguard Worker   }
143*9e3b08aeSAndroid Build Coastguard Worker   return *result;
144*9e3b08aeSAndroid Build Coastguard Worker }
145*9e3b08aeSAndroid Build Coastguard Worker 
GetNumberOfElements(Entry & entry)146*9e3b08aeSAndroid Build Coastguard Worker size_t GetNumberOfElements(Entry& entry) {
147*9e3b08aeSAndroid Build Coastguard Worker   // DWARF standard says, that array dimensions could be an entry with
148*9e3b08aeSAndroid Build Coastguard Worker   // either DW_TAG_subrange_type or DW_TAG_enumeration_type. However, this
149*9e3b08aeSAndroid Build Coastguard Worker   // code supports only the DW_TAG_subrange_type.
150*9e3b08aeSAndroid Build Coastguard Worker   Check(entry.GetTag() == DW_TAG_subrange_type)
151*9e3b08aeSAndroid Build Coastguard Worker       << "Array's dimensions should be an entry of DW_TAG_subrange_type";
152*9e3b08aeSAndroid Build Coastguard Worker   std::optional<size_t> number_of_elements = entry.MaybeGetCount();
153*9e3b08aeSAndroid Build Coastguard Worker   if (number_of_elements) {
154*9e3b08aeSAndroid Build Coastguard Worker     return *number_of_elements;
155*9e3b08aeSAndroid Build Coastguard Worker   }
156*9e3b08aeSAndroid Build Coastguard Worker   // If a subrange has no DW_AT_count and no DW_AT_upper_bound attribute, its
157*9e3b08aeSAndroid Build Coastguard Worker   // size is unknown.
158*9e3b08aeSAndroid Build Coastguard Worker   return 0;
159*9e3b08aeSAndroid Build Coastguard Worker }
160*9e3b08aeSAndroid Build Coastguard Worker 
161*9e3b08aeSAndroid Build Coastguard Worker // Calculate number of bits from the "beginning" of the containing entity to
162*9e3b08aeSAndroid Build Coastguard Worker // the "beginning" of the data member using DW_AT_bit_offset.
163*9e3b08aeSAndroid Build Coastguard Worker //
164*9e3b08aeSAndroid Build Coastguard Worker // "Number of bits from the beginning", depends on the definition of the
165*9e3b08aeSAndroid Build Coastguard Worker // "beginning", which is different for big- and little-endian architectures.
166*9e3b08aeSAndroid Build Coastguard Worker // However, DW_AT_bit_offset is defined from the high order bit of the storage
167*9e3b08aeSAndroid Build Coastguard Worker // unit to the high order bit of a field and is the same for both architectures.
168*9e3b08aeSAndroid Build Coastguard Worker 
169*9e3b08aeSAndroid Build Coastguard Worker // So this function converts DW_AT_bit_offset to the "number of bits from the
170*9e3b08aeSAndroid Build Coastguard Worker // beginning".
CalculateBitfieldAdjustment(Entry & entry,size_t bit_size,bool is_little_endian_binary)171*9e3b08aeSAndroid Build Coastguard Worker size_t CalculateBitfieldAdjustment(Entry& entry, size_t bit_size,
172*9e3b08aeSAndroid Build Coastguard Worker                              bool is_little_endian_binary) {
173*9e3b08aeSAndroid Build Coastguard Worker   if (bit_size == 0) {
174*9e3b08aeSAndroid Build Coastguard Worker     // bit_size == 0 marks that it is not a bit field. No adjustment needed.
175*9e3b08aeSAndroid Build Coastguard Worker     return 0;
176*9e3b08aeSAndroid Build Coastguard Worker   }
177*9e3b08aeSAndroid Build Coastguard Worker   auto container_byte_size = entry.MaybeGetUnsignedConstant(DW_AT_byte_size);
178*9e3b08aeSAndroid Build Coastguard Worker   auto bit_offset = entry.MaybeGetUnsignedConstant(DW_AT_bit_offset);
179*9e3b08aeSAndroid Build Coastguard Worker   Check(container_byte_size.has_value() && bit_offset.has_value())
180*9e3b08aeSAndroid Build Coastguard Worker       << "If member offset is defined as DW_AT_data_member_location, bit field "
181*9e3b08aeSAndroid Build Coastguard Worker          "should have DW_AT_byte_size and DW_AT_bit_offset";
182*9e3b08aeSAndroid Build Coastguard Worker   // The following structure will be used as an example in the explanations:
183*9e3b08aeSAndroid Build Coastguard Worker   // struct foo {
184*9e3b08aeSAndroid Build Coastguard Worker   //   uint16_t rest_of_the_struct;
185*9e3b08aeSAndroid Build Coastguard Worker   //   uint16_t x : 5;
186*9e3b08aeSAndroid Build Coastguard Worker   //   uint16_t y : 6;
187*9e3b08aeSAndroid Build Coastguard Worker   //   uint16_t z : 5;
188*9e3b08aeSAndroid Build Coastguard Worker   // };
189*9e3b08aeSAndroid Build Coastguard Worker   if (is_little_endian_binary) {
190*9e3b08aeSAndroid Build Coastguard Worker     // Compiler usualy packs bit fields starting with the least significant
191*9e3b08aeSAndroid Build Coastguard Worker     // bits, but DW_AT_bit_offset is counted from high to low bits:
192*9e3b08aeSAndroid Build Coastguard Worker     //
193*9e3b08aeSAndroid Build Coastguard Worker     // rest of the struct|<    container   >
194*9e3b08aeSAndroid Build Coastguard Worker     //    Container bits: 01234|56789A|BCDEF
195*9e3b08aeSAndroid Build Coastguard Worker     //  Bit-fields' bits: 01234|012345|01234
196*9e3b08aeSAndroid Build Coastguard Worker     //        bit_offset: <<<<B<<<<<<5<<<<<0
197*9e3b08aeSAndroid Build Coastguard Worker     //   bits from start: 0>>>>>5>>>>>>B>>>>
198*9e3b08aeSAndroid Build Coastguard Worker     //                    <x:5>|< y:6>|<z:5>
199*9e3b08aeSAndroid Build Coastguard Worker     //
200*9e3b08aeSAndroid Build Coastguard Worker     //   x.bit_offset: 11 (0xB) bits
201*9e3b08aeSAndroid Build Coastguard Worker     //   y.bit_offset: 5 bits
202*9e3b08aeSAndroid Build Coastguard Worker     //   z.bit_offset: 0 bits
203*9e3b08aeSAndroid Build Coastguard Worker     //
204*9e3b08aeSAndroid Build Coastguard Worker     // So we need to subtract bit_offset from the container bit size
205*9e3b08aeSAndroid Build Coastguard Worker     // (container_byte_size * 8) to inverse direction. Also we need to convert
206*9e3b08aeSAndroid Build Coastguard Worker     // from high- to low-order bit, because the field "begins" with low-order
207*9e3b08aeSAndroid Build Coastguard Worker     // bit. To do so we need to subtract field's bit size. Resulting formula is:
208*9e3b08aeSAndroid Build Coastguard Worker     //
209*9e3b08aeSAndroid Build Coastguard Worker     //   container_byte_size * 8 - bit_offset - bit_size
210*9e3b08aeSAndroid Build Coastguard Worker     //
211*9e3b08aeSAndroid Build Coastguard Worker     // If we try it on example, we get correct values:
212*9e3b08aeSAndroid Build Coastguard Worker     //   x: 2 * 8 - 11 - 5 = 0
213*9e3b08aeSAndroid Build Coastguard Worker     //   y: 2 * 8 - 5 - 6 = 5
214*9e3b08aeSAndroid Build Coastguard Worker     //   z: 2 * 8 - 0 - 5 = 11 (0xB)
215*9e3b08aeSAndroid Build Coastguard Worker     return *container_byte_size * 8 - *bit_offset - bit_size;
216*9e3b08aeSAndroid Build Coastguard Worker   }
217*9e3b08aeSAndroid Build Coastguard Worker   // Big-endian orders begins with high-order bit and the bit_offset is from the
218*9e3b08aeSAndroid Build Coastguard Worker   // high order bit:
219*9e3b08aeSAndroid Build Coastguard Worker   //
220*9e3b08aeSAndroid Build Coastguard Worker   // rest of the struct|<    container   >
221*9e3b08aeSAndroid Build Coastguard Worker   //    Container bits: FEDCB|A98765|43210
222*9e3b08aeSAndroid Build Coastguard Worker   //  Bit-fields' bits: 43210|543210|43210
223*9e3b08aeSAndroid Build Coastguard Worker   //        bit_offset: 0>>>>>5>>>>>>B>>>>
224*9e3b08aeSAndroid Build Coastguard Worker   //   bits from start: 0>>>>>5>>>>>>B>>>>
225*9e3b08aeSAndroid Build Coastguard Worker   //                    <x:5>|< y:6>|<z:5>
226*9e3b08aeSAndroid Build Coastguard Worker   //
227*9e3b08aeSAndroid Build Coastguard Worker   // So we just return bit_offset.
228*9e3b08aeSAndroid Build Coastguard Worker   return *bit_offset;
229*9e3b08aeSAndroid Build Coastguard Worker }
230*9e3b08aeSAndroid Build Coastguard Worker 
231*9e3b08aeSAndroid Build Coastguard Worker // Calculate the number of bits from the beginning of the structure to the
232*9e3b08aeSAndroid Build Coastguard Worker // beginning of the data member.
GetDataBitOffset(Entry & entry,size_t bit_size,bool is_little_endian_binary)233*9e3b08aeSAndroid Build Coastguard Worker size_t GetDataBitOffset(Entry& entry, size_t bit_size,
234*9e3b08aeSAndroid Build Coastguard Worker                         bool is_little_endian_binary) {
235*9e3b08aeSAndroid Build Coastguard Worker   // Offset may be represented either by DW_AT_data_bit_offset (in bits) or by
236*9e3b08aeSAndroid Build Coastguard Worker   // DW_AT_data_member_location (in bytes).
237*9e3b08aeSAndroid Build Coastguard Worker   if (auto data_bit_offset =
238*9e3b08aeSAndroid Build Coastguard Worker           entry.MaybeGetUnsignedConstant(DW_AT_data_bit_offset)) {
239*9e3b08aeSAndroid Build Coastguard Worker     // DW_AT_data_bit_offset contains what this function needs for any type
240*9e3b08aeSAndroid Build Coastguard Worker     // of member (bitfield or not) on architecture of any endianness.
241*9e3b08aeSAndroid Build Coastguard Worker     return *data_bit_offset;
242*9e3b08aeSAndroid Build Coastguard Worker   } else if (auto byte_offset = entry.MaybeGetMemberByteOffset()) {
243*9e3b08aeSAndroid Build Coastguard Worker     // DW_AT_data_member_location contains offset in bytes.
244*9e3b08aeSAndroid Build Coastguard Worker     const size_t bit_offset = *byte_offset * 8;
245*9e3b08aeSAndroid Build Coastguard Worker     // But there can be offset part, coming from DW_AT_bit_offset. DWARF 5
246*9e3b08aeSAndroid Build Coastguard Worker     // standard requires to use DW_AT_data_bit_offset in this case, but a lot
247*9e3b08aeSAndroid Build Coastguard Worker     // of binaries still use combination of DW_AT_data_member_location and
248*9e3b08aeSAndroid Build Coastguard Worker     // DW_AT_bit_offset.
249*9e3b08aeSAndroid Build Coastguard Worker     const size_t bitfield_adjusment =
250*9e3b08aeSAndroid Build Coastguard Worker         CalculateBitfieldAdjustment(entry, bit_size, is_little_endian_binary);
251*9e3b08aeSAndroid Build Coastguard Worker     return bit_offset + bitfield_adjusment;
252*9e3b08aeSAndroid Build Coastguard Worker   } else {
253*9e3b08aeSAndroid Build Coastguard Worker     // If the beginning of the data member is the same as the beginning of the
254*9e3b08aeSAndroid Build Coastguard Worker     // containing entity then neither attribute is required.
255*9e3b08aeSAndroid Build Coastguard Worker     return 0;
256*9e3b08aeSAndroid Build Coastguard Worker   }
257*9e3b08aeSAndroid Build Coastguard Worker }
258*9e3b08aeSAndroid Build Coastguard Worker 
259*9e3b08aeSAndroid Build Coastguard Worker }  // namespace
260*9e3b08aeSAndroid Build Coastguard Worker 
261*9e3b08aeSAndroid Build Coastguard Worker // Transforms DWARF entries to STG.
262*9e3b08aeSAndroid Build Coastguard Worker class Processor {
263*9e3b08aeSAndroid Build Coastguard Worker  public:
Processor(Graph & graph,Id void_id,Id variadic_id,bool is_little_endian_binary,const std::unique_ptr<Filter> & file_filter,Types & result)264*9e3b08aeSAndroid Build Coastguard Worker   Processor(Graph& graph, Id void_id, Id variadic_id,
265*9e3b08aeSAndroid Build Coastguard Worker             bool is_little_endian_binary,
266*9e3b08aeSAndroid Build Coastguard Worker             const std::unique_ptr<Filter>& file_filter, Types& result)
267*9e3b08aeSAndroid Build Coastguard Worker       : maker_(graph),
268*9e3b08aeSAndroid Build Coastguard Worker         void_id_(void_id),
269*9e3b08aeSAndroid Build Coastguard Worker         variadic_id_(variadic_id),
270*9e3b08aeSAndroid Build Coastguard Worker         is_little_endian_binary_(is_little_endian_binary),
271*9e3b08aeSAndroid Build Coastguard Worker         file_filter_(file_filter),
272*9e3b08aeSAndroid Build Coastguard Worker         result_(result) {}
273*9e3b08aeSAndroid Build Coastguard Worker 
ProcessCompilationUnit(CompilationUnit & compilation_unit)274*9e3b08aeSAndroid Build Coastguard Worker   void ProcessCompilationUnit(CompilationUnit& compilation_unit) {
275*9e3b08aeSAndroid Build Coastguard Worker     version_ = compilation_unit.version;
276*9e3b08aeSAndroid Build Coastguard Worker     if (file_filter_ != nullptr) {
277*9e3b08aeSAndroid Build Coastguard Worker       files_ = dwarf::Files(compilation_unit.entry);
278*9e3b08aeSAndroid Build Coastguard Worker     }
279*9e3b08aeSAndroid Build Coastguard Worker     Process(compilation_unit.entry);
280*9e3b08aeSAndroid Build Coastguard Worker   }
281*9e3b08aeSAndroid Build Coastguard Worker 
ResolveSymbolSpecifications()282*9e3b08aeSAndroid Build Coastguard Worker   void ResolveSymbolSpecifications() {
283*9e3b08aeSAndroid Build Coastguard Worker     std::sort(unresolved_symbol_specifications_.begin(),
284*9e3b08aeSAndroid Build Coastguard Worker               unresolved_symbol_specifications_.end());
285*9e3b08aeSAndroid Build Coastguard Worker     std::sort(scoped_names_.begin(), scoped_names_.end());
286*9e3b08aeSAndroid Build Coastguard Worker     auto symbols_it = unresolved_symbol_specifications_.begin();
287*9e3b08aeSAndroid Build Coastguard Worker     auto names_it = scoped_names_.begin();
288*9e3b08aeSAndroid Build Coastguard Worker     while (symbols_it != unresolved_symbol_specifications_.end()) {
289*9e3b08aeSAndroid Build Coastguard Worker       while (names_it != scoped_names_.end() &&
290*9e3b08aeSAndroid Build Coastguard Worker              names_it->first < symbols_it->first) {
291*9e3b08aeSAndroid Build Coastguard Worker         ++names_it;
292*9e3b08aeSAndroid Build Coastguard Worker       }
293*9e3b08aeSAndroid Build Coastguard Worker       if (names_it == scoped_names_.end() ||
294*9e3b08aeSAndroid Build Coastguard Worker           names_it->first != symbols_it->first) {
295*9e3b08aeSAndroid Build Coastguard Worker         Die() << "Scoped name not found for entry " << Hex(symbols_it->first);
296*9e3b08aeSAndroid Build Coastguard Worker       }
297*9e3b08aeSAndroid Build Coastguard Worker       result_.symbols[symbols_it->second].scoped_name = names_it->second;
298*9e3b08aeSAndroid Build Coastguard Worker       ++symbols_it;
299*9e3b08aeSAndroid Build Coastguard Worker     }
300*9e3b08aeSAndroid Build Coastguard Worker   }
301*9e3b08aeSAndroid Build Coastguard Worker 
302*9e3b08aeSAndroid Build Coastguard Worker  private:
Process(Entry & entry)303*9e3b08aeSAndroid Build Coastguard Worker   void Process(Entry& entry) {
304*9e3b08aeSAndroid Build Coastguard Worker     try {
305*9e3b08aeSAndroid Build Coastguard Worker       return ProcessInternal(entry);
306*9e3b08aeSAndroid Build Coastguard Worker     } catch (Exception& e) {
307*9e3b08aeSAndroid Build Coastguard Worker       std::ostringstream os;
308*9e3b08aeSAndroid Build Coastguard Worker       os << "processing DIE " << Hex(entry.GetOffset());
309*9e3b08aeSAndroid Build Coastguard Worker       e.Add(os.str());
310*9e3b08aeSAndroid Build Coastguard Worker       throw;
311*9e3b08aeSAndroid Build Coastguard Worker     }
312*9e3b08aeSAndroid Build Coastguard Worker   }
313*9e3b08aeSAndroid Build Coastguard Worker 
ProcessInternal(Entry & entry)314*9e3b08aeSAndroid Build Coastguard Worker   void ProcessInternal(Entry& entry) {
315*9e3b08aeSAndroid Build Coastguard Worker     ++result_.processed_entries;
316*9e3b08aeSAndroid Build Coastguard Worker     const auto tag = entry.GetTag();
317*9e3b08aeSAndroid Build Coastguard Worker     switch (tag) {
318*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_array_type:
319*9e3b08aeSAndroid Build Coastguard Worker         ProcessArray(entry);
320*9e3b08aeSAndroid Build Coastguard Worker         break;
321*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_enumeration_type:
322*9e3b08aeSAndroid Build Coastguard Worker         ProcessEnum(entry);
323*9e3b08aeSAndroid Build Coastguard Worker         break;
324*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_class_type:
325*9e3b08aeSAndroid Build Coastguard Worker         ProcessStructUnion(entry, StructUnion::Kind::STRUCT);
326*9e3b08aeSAndroid Build Coastguard Worker         break;
327*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_structure_type:
328*9e3b08aeSAndroid Build Coastguard Worker         ProcessStructUnion(entry, StructUnion::Kind::STRUCT);
329*9e3b08aeSAndroid Build Coastguard Worker         break;
330*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_union_type:
331*9e3b08aeSAndroid Build Coastguard Worker         ProcessStructUnion(entry, StructUnion::Kind::UNION);
332*9e3b08aeSAndroid Build Coastguard Worker         break;
333*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_member:
334*9e3b08aeSAndroid Build Coastguard Worker         Die() << "DW_TAG_member outside of struct/class/union";
335*9e3b08aeSAndroid Build Coastguard Worker         break;
336*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_pointer_type:
337*9e3b08aeSAndroid Build Coastguard Worker         ProcessReference<PointerReference>(
338*9e3b08aeSAndroid Build Coastguard Worker             entry, PointerReference::Kind::POINTER);
339*9e3b08aeSAndroid Build Coastguard Worker         break;
340*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_reference_type:
341*9e3b08aeSAndroid Build Coastguard Worker         ProcessReference<PointerReference>(
342*9e3b08aeSAndroid Build Coastguard Worker             entry, PointerReference::Kind::LVALUE_REFERENCE);
343*9e3b08aeSAndroid Build Coastguard Worker         break;
344*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_rvalue_reference_type:
345*9e3b08aeSAndroid Build Coastguard Worker         ProcessReference<PointerReference>(
346*9e3b08aeSAndroid Build Coastguard Worker             entry, PointerReference::Kind::RVALUE_REFERENCE);
347*9e3b08aeSAndroid Build Coastguard Worker         break;
348*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_ptr_to_member_type:
349*9e3b08aeSAndroid Build Coastguard Worker         ProcessPointerToMember(entry);
350*9e3b08aeSAndroid Build Coastguard Worker         break;
351*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_unspecified_type:
352*9e3b08aeSAndroid Build Coastguard Worker         ProcessUnspecifiedType(entry);
353*9e3b08aeSAndroid Build Coastguard Worker         break;
354*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_compile_unit:
355*9e3b08aeSAndroid Build Coastguard Worker         language_ = entry.MustGetUnsignedConstant(DW_AT_language);
356*9e3b08aeSAndroid Build Coastguard Worker         ProcessAllChildren(entry);
357*9e3b08aeSAndroid Build Coastguard Worker         break;
358*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_typedef:
359*9e3b08aeSAndroid Build Coastguard Worker         ProcessTypedef(entry);
360*9e3b08aeSAndroid Build Coastguard Worker         break;
361*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_base_type:
362*9e3b08aeSAndroid Build Coastguard Worker         ProcessBaseType(entry);
363*9e3b08aeSAndroid Build Coastguard Worker         break;
364*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_const_type:
365*9e3b08aeSAndroid Build Coastguard Worker         ProcessReference<Qualified>(entry, Qualifier::CONST);
366*9e3b08aeSAndroid Build Coastguard Worker         break;
367*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_volatile_type:
368*9e3b08aeSAndroid Build Coastguard Worker         ProcessReference<Qualified>(entry, Qualifier::VOLATILE);
369*9e3b08aeSAndroid Build Coastguard Worker         break;
370*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_restrict_type:
371*9e3b08aeSAndroid Build Coastguard Worker         ProcessReference<Qualified>(entry, Qualifier::RESTRICT);
372*9e3b08aeSAndroid Build Coastguard Worker         break;
373*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_atomic_type:
374*9e3b08aeSAndroid Build Coastguard Worker         // TODO: test pending BTF / test suite support
375*9e3b08aeSAndroid Build Coastguard Worker         ProcessReference<Qualified>(entry, Qualifier::ATOMIC);
376*9e3b08aeSAndroid Build Coastguard Worker         break;
377*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_variable:
378*9e3b08aeSAndroid Build Coastguard Worker         // Process only variables visible externally
379*9e3b08aeSAndroid Build Coastguard Worker         if (entry.GetFlag(DW_AT_external)) {
380*9e3b08aeSAndroid Build Coastguard Worker           ProcessVariable(entry);
381*9e3b08aeSAndroid Build Coastguard Worker         }
382*9e3b08aeSAndroid Build Coastguard Worker         break;
383*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_subroutine_type:
384*9e3b08aeSAndroid Build Coastguard Worker         // Standalone function type, for example, used in function pointers.
385*9e3b08aeSAndroid Build Coastguard Worker         ProcessFunction(entry);
386*9e3b08aeSAndroid Build Coastguard Worker         break;
387*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_subprogram:
388*9e3b08aeSAndroid Build Coastguard Worker         // DWARF equivalent of ELF function symbol.
389*9e3b08aeSAndroid Build Coastguard Worker         ProcessFunction(entry);
390*9e3b08aeSAndroid Build Coastguard Worker         break;
391*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_namespace:
392*9e3b08aeSAndroid Build Coastguard Worker         ProcessNamespace(entry);
393*9e3b08aeSAndroid Build Coastguard Worker         break;
394*9e3b08aeSAndroid Build Coastguard Worker       case DW_TAG_lexical_block:
395*9e3b08aeSAndroid Build Coastguard Worker         ProcessAllChildren(entry);
396*9e3b08aeSAndroid Build Coastguard Worker         break;
397*9e3b08aeSAndroid Build Coastguard Worker 
398*9e3b08aeSAndroid Build Coastguard Worker       default:
399*9e3b08aeSAndroid Build Coastguard Worker         // TODO: die on unexpected tag, when this switch contains
400*9e3b08aeSAndroid Build Coastguard Worker         // all expected tags
401*9e3b08aeSAndroid Build Coastguard Worker         break;
402*9e3b08aeSAndroid Build Coastguard Worker     }
403*9e3b08aeSAndroid Build Coastguard Worker   }
404*9e3b08aeSAndroid Build Coastguard Worker 
ProcessAllChildren(Entry & entry)405*9e3b08aeSAndroid Build Coastguard Worker   void ProcessAllChildren(Entry& entry) {
406*9e3b08aeSAndroid Build Coastguard Worker     for (auto& child : entry.GetChildren()) {
407*9e3b08aeSAndroid Build Coastguard Worker       Process(child);
408*9e3b08aeSAndroid Build Coastguard Worker     }
409*9e3b08aeSAndroid Build Coastguard Worker   }
410*9e3b08aeSAndroid Build Coastguard Worker 
CheckNoChildren(Entry & entry)411*9e3b08aeSAndroid Build Coastguard Worker   void CheckNoChildren(Entry& entry) {
412*9e3b08aeSAndroid Build Coastguard Worker     if (!entry.GetChildren().empty()) {
413*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Entry expected to have no children";
414*9e3b08aeSAndroid Build Coastguard Worker     }
415*9e3b08aeSAndroid Build Coastguard Worker   }
416*9e3b08aeSAndroid Build Coastguard Worker 
ProcessNamespace(Entry & entry)417*9e3b08aeSAndroid Build Coastguard Worker   void ProcessNamespace(Entry& entry) {
418*9e3b08aeSAndroid Build Coastguard Worker     const auto name = GetNameOrEmpty(entry);
419*9e3b08aeSAndroid Build Coastguard Worker     const PushScopeName push_scope_name(scope_, "namespace", name);
420*9e3b08aeSAndroid Build Coastguard Worker     ProcessAllChildren(entry);
421*9e3b08aeSAndroid Build Coastguard Worker   }
422*9e3b08aeSAndroid Build Coastguard Worker 
ProcessBaseType(Entry & entry)423*9e3b08aeSAndroid Build Coastguard Worker   void ProcessBaseType(Entry& entry) {
424*9e3b08aeSAndroid Build Coastguard Worker     CheckNoChildren(entry);
425*9e3b08aeSAndroid Build Coastguard Worker     const auto type_name = GetName(entry);
426*9e3b08aeSAndroid Build Coastguard Worker     const size_t bit_size = GetBitSize(entry);
427*9e3b08aeSAndroid Build Coastguard Worker     if (bit_size % 8) {
428*9e3b08aeSAndroid Build Coastguard Worker       Die() << "type '" << type_name << "' size is not a multiple of 8";
429*9e3b08aeSAndroid Build Coastguard Worker     }
430*9e3b08aeSAndroid Build Coastguard Worker     const size_t byte_size = bit_size / 8;
431*9e3b08aeSAndroid Build Coastguard Worker     AddProcessedNode<Primitive>(entry, type_name, GetEncoding(entry),
432*9e3b08aeSAndroid Build Coastguard Worker                                 byte_size);
433*9e3b08aeSAndroid Build Coastguard Worker   }
434*9e3b08aeSAndroid Build Coastguard Worker 
ProcessTypedef(Entry & entry)435*9e3b08aeSAndroid Build Coastguard Worker   void ProcessTypedef(Entry& entry) {
436*9e3b08aeSAndroid Build Coastguard Worker     const auto type_name = GetName(entry);
437*9e3b08aeSAndroid Build Coastguard Worker     const auto full_name = scope_.name + type_name;
438*9e3b08aeSAndroid Build Coastguard Worker     const Id referred_type_id = GetReferredTypeId(MaybeGetReferredType(entry));
439*9e3b08aeSAndroid Build Coastguard Worker     const Id id = AddProcessedNode<Typedef>(entry, full_name, referred_type_id);
440*9e3b08aeSAndroid Build Coastguard Worker     if (!ShouldKeepDefinition(entry, type_name)) {
441*9e3b08aeSAndroid Build Coastguard Worker       // We always model (and keep) typedef definitions. But we should exclude
442*9e3b08aeSAndroid Build Coastguard Worker       // filtered out types from being type roots.
443*9e3b08aeSAndroid Build Coastguard Worker       return;
444*9e3b08aeSAndroid Build Coastguard Worker     }
445*9e3b08aeSAndroid Build Coastguard Worker     AddNamedTypeNode(id);
446*9e3b08aeSAndroid Build Coastguard Worker   }
447*9e3b08aeSAndroid Build Coastguard Worker 
448*9e3b08aeSAndroid Build Coastguard Worker   template<typename Node, typename KindType>
ProcessReference(Entry & entry,KindType kind)449*9e3b08aeSAndroid Build Coastguard Worker   void ProcessReference(Entry& entry, KindType kind) {
450*9e3b08aeSAndroid Build Coastguard Worker     const Id referred_type_id = GetReferredTypeId(MaybeGetReferredType(entry));
451*9e3b08aeSAndroid Build Coastguard Worker     AddProcessedNode<Node>(entry, kind, referred_type_id);
452*9e3b08aeSAndroid Build Coastguard Worker   }
453*9e3b08aeSAndroid Build Coastguard Worker 
ProcessPointerToMember(Entry & entry)454*9e3b08aeSAndroid Build Coastguard Worker   void ProcessPointerToMember(Entry& entry) {
455*9e3b08aeSAndroid Build Coastguard Worker     const Id containing_type_id =
456*9e3b08aeSAndroid Build Coastguard Worker         GetReferredTypeId(entry.MaybeGetReference(DW_AT_containing_type));
457*9e3b08aeSAndroid Build Coastguard Worker     const Id pointee_type_id = GetReferredTypeId(MaybeGetReferredType(entry));
458*9e3b08aeSAndroid Build Coastguard Worker     AddProcessedNode<PointerToMember>(entry, containing_type_id,
459*9e3b08aeSAndroid Build Coastguard Worker                                       pointee_type_id);
460*9e3b08aeSAndroid Build Coastguard Worker   }
461*9e3b08aeSAndroid Build Coastguard Worker 
ProcessUnspecifiedType(Entry & entry)462*9e3b08aeSAndroid Build Coastguard Worker   void ProcessUnspecifiedType(Entry& entry) {
463*9e3b08aeSAndroid Build Coastguard Worker     const std::string type_name =  GetName(entry);
464*9e3b08aeSAndroid Build Coastguard Worker     Check(type_name == "decltype(nullptr)")
465*9e3b08aeSAndroid Build Coastguard Worker         << "Unsupported DW_TAG_unspecified_type: " << type_name;
466*9e3b08aeSAndroid Build Coastguard Worker     AddProcessedNode<Special>(entry, Special::Kind::NULLPTR);
467*9e3b08aeSAndroid Build Coastguard Worker   }
468*9e3b08aeSAndroid Build Coastguard Worker 
ShouldKeepDefinition(Entry & entry,const std::string & name) const469*9e3b08aeSAndroid Build Coastguard Worker   bool ShouldKeepDefinition(Entry& entry, const std::string& name) const {
470*9e3b08aeSAndroid Build Coastguard Worker     if (!HasIncompleteTypes(language_) || file_filter_ == nullptr) {
471*9e3b08aeSAndroid Build Coastguard Worker       return true;
472*9e3b08aeSAndroid Build Coastguard Worker     }
473*9e3b08aeSAndroid Build Coastguard Worker     const auto file = files_.MaybeGetFile(entry, DW_AT_decl_file);
474*9e3b08aeSAndroid Build Coastguard Worker     if (!file) {
475*9e3b08aeSAndroid Build Coastguard Worker       // Built in types that do not have DW_AT_decl_file should be preserved.
476*9e3b08aeSAndroid Build Coastguard Worker       static constexpr std::string_view kBuiltinPrefix = "__";
477*9e3b08aeSAndroid Build Coastguard Worker       if (name.starts_with(kBuiltinPrefix)) {
478*9e3b08aeSAndroid Build Coastguard Worker         return true;
479*9e3b08aeSAndroid Build Coastguard Worker       }
480*9e3b08aeSAndroid Build Coastguard Worker       Die() << "File filter is provided, but " << name << " ("
481*9e3b08aeSAndroid Build Coastguard Worker             << EntryToString(entry) << ") doesn't have DW_AT_decl_file";
482*9e3b08aeSAndroid Build Coastguard Worker     }
483*9e3b08aeSAndroid Build Coastguard Worker     return (*file_filter_)(*file);
484*9e3b08aeSAndroid Build Coastguard Worker   }
485*9e3b08aeSAndroid Build Coastguard Worker 
ProcessStructUnion(Entry & entry,StructUnion::Kind kind)486*9e3b08aeSAndroid Build Coastguard Worker   void ProcessStructUnion(Entry& entry, StructUnion::Kind kind) {
487*9e3b08aeSAndroid Build Coastguard Worker     const auto type_name = GetNameOrEmpty(entry);
488*9e3b08aeSAndroid Build Coastguard Worker     const auto full_name =
489*9e3b08aeSAndroid Build Coastguard Worker         type_name.empty() ? type_name : scope_.name + type_name;
490*9e3b08aeSAndroid Build Coastguard Worker     const PushScopeName push_scope_name(scope_, kind, type_name);
491*9e3b08aeSAndroid Build Coastguard Worker 
492*9e3b08aeSAndroid Build Coastguard Worker     std::vector<Id> base_classes;
493*9e3b08aeSAndroid Build Coastguard Worker     std::vector<Id> members;
494*9e3b08aeSAndroid Build Coastguard Worker     std::vector<Id> methods;
495*9e3b08aeSAndroid Build Coastguard Worker     std::optional<VariantAndMembers> variant_and_members = std::nullopt;
496*9e3b08aeSAndroid Build Coastguard Worker 
497*9e3b08aeSAndroid Build Coastguard Worker     for (auto& child : entry.GetChildren()) {
498*9e3b08aeSAndroid Build Coastguard Worker       auto child_tag = child.GetTag();
499*9e3b08aeSAndroid Build Coastguard Worker       // All possible children of struct/class/union
500*9e3b08aeSAndroid Build Coastguard Worker       switch (child_tag) {
501*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_member:
502*9e3b08aeSAndroid Build Coastguard Worker           if (child.GetFlag(DW_AT_external)) {
503*9e3b08aeSAndroid Build Coastguard Worker             // static members are interpreted as variables and not included in
504*9e3b08aeSAndroid Build Coastguard Worker             // members.
505*9e3b08aeSAndroid Build Coastguard Worker             ProcessVariable(child);
506*9e3b08aeSAndroid Build Coastguard Worker           } else {
507*9e3b08aeSAndroid Build Coastguard Worker             members.push_back(GetIdForEntry(child));
508*9e3b08aeSAndroid Build Coastguard Worker             ProcessMember(child);
509*9e3b08aeSAndroid Build Coastguard Worker           }
510*9e3b08aeSAndroid Build Coastguard Worker           break;
511*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_subprogram:
512*9e3b08aeSAndroid Build Coastguard Worker           ProcessMethod(methods, child);
513*9e3b08aeSAndroid Build Coastguard Worker           break;
514*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_inheritance:
515*9e3b08aeSAndroid Build Coastguard Worker           base_classes.push_back(GetIdForEntry(child));
516*9e3b08aeSAndroid Build Coastguard Worker           ProcessBaseClass(child);
517*9e3b08aeSAndroid Build Coastguard Worker           break;
518*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_structure_type:
519*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_class_type:
520*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_union_type:
521*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_enumeration_type:
522*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_typedef:
523*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_const_type:
524*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_volatile_type:
525*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_restrict_type:
526*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_atomic_type:
527*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_array_type:
528*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_pointer_type:
529*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_reference_type:
530*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_rvalue_reference_type:
531*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_ptr_to_member_type:
532*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_unspecified_type:
533*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_variable:
534*9e3b08aeSAndroid Build Coastguard Worker           Process(child);
535*9e3b08aeSAndroid Build Coastguard Worker           break;
536*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_imported_declaration:
537*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_imported_module:
538*9e3b08aeSAndroid Build Coastguard Worker           // For now information there is useless for ABI monitoring, but we
539*9e3b08aeSAndroid Build Coastguard Worker           // need to check that there is no missing information in descendants.
540*9e3b08aeSAndroid Build Coastguard Worker           CheckNoChildren(child);
541*9e3b08aeSAndroid Build Coastguard Worker           break;
542*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_template_type_parameter:
543*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_template_value_parameter:
544*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_GNU_template_template_param:
545*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_GNU_template_parameter_pack:
546*9e3b08aeSAndroid Build Coastguard Worker           // We just skip these as neither GCC nor Clang seem to use them
547*9e3b08aeSAndroid Build Coastguard Worker           // properly (resulting in no references to such DIEs).
548*9e3b08aeSAndroid Build Coastguard Worker           break;
549*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_variant_part:
550*9e3b08aeSAndroid Build Coastguard Worker           if (full_name.empty()) {
551*9e3b08aeSAndroid Build Coastguard Worker             Die() << "Variant name should not be empty: "
552*9e3b08aeSAndroid Build Coastguard Worker                   << EntryToString(entry);
553*9e3b08aeSAndroid Build Coastguard Worker           }
554*9e3b08aeSAndroid Build Coastguard Worker           variant_and_members = GetVariantAndMembers(child);
555*9e3b08aeSAndroid Build Coastguard Worker           break;
556*9e3b08aeSAndroid Build Coastguard Worker         default:
557*9e3b08aeSAndroid Build Coastguard Worker           Die() << "Unexpected tag for child of struct/class/union: "
558*9e3b08aeSAndroid Build Coastguard Worker                 << Hex(child_tag) << ", " << EntryToString(child);
559*9e3b08aeSAndroid Build Coastguard Worker       }
560*9e3b08aeSAndroid Build Coastguard Worker     }
561*9e3b08aeSAndroid Build Coastguard Worker 
562*9e3b08aeSAndroid Build Coastguard Worker     if (variant_and_members.has_value()) {
563*9e3b08aeSAndroid Build Coastguard Worker       // Add a Variant node since this entry represents a variant rather than a
564*9e3b08aeSAndroid Build Coastguard Worker       // struct or union.
565*9e3b08aeSAndroid Build Coastguard Worker       const Id id =
566*9e3b08aeSAndroid Build Coastguard Worker           AddProcessedNode<Variant>(entry, full_name, GetByteSize(entry),
567*9e3b08aeSAndroid Build Coastguard Worker                                     variant_and_members->discriminant,
568*9e3b08aeSAndroid Build Coastguard Worker                                     std::move(variant_and_members->members));
569*9e3b08aeSAndroid Build Coastguard Worker       AddNamedTypeNode(id);
570*9e3b08aeSAndroid Build Coastguard Worker       return;
571*9e3b08aeSAndroid Build Coastguard Worker     }
572*9e3b08aeSAndroid Build Coastguard Worker 
573*9e3b08aeSAndroid Build Coastguard Worker     if (entry.GetFlag(DW_AT_declaration) ||
574*9e3b08aeSAndroid Build Coastguard Worker         !ShouldKeepDefinition(entry, type_name)) {
575*9e3b08aeSAndroid Build Coastguard Worker       // Declaration may have partial information about members or method.
576*9e3b08aeSAndroid Build Coastguard Worker       // We only need to parse children for information that will be needed in
577*9e3b08aeSAndroid Build Coastguard Worker       // complete definition, but don't need to store them in incomplete node.
578*9e3b08aeSAndroid Build Coastguard Worker       AddProcessedNode<StructUnion>(entry, kind, full_name);
579*9e3b08aeSAndroid Build Coastguard Worker       return;
580*9e3b08aeSAndroid Build Coastguard Worker     }
581*9e3b08aeSAndroid Build Coastguard Worker 
582*9e3b08aeSAndroid Build Coastguard Worker     const auto byte_size = GetByteSize(entry);
583*9e3b08aeSAndroid Build Coastguard Worker 
584*9e3b08aeSAndroid Build Coastguard Worker     const Id id = AddProcessedNode<StructUnion>(
585*9e3b08aeSAndroid Build Coastguard Worker         entry, kind, full_name, byte_size, std::move(base_classes),
586*9e3b08aeSAndroid Build Coastguard Worker         std::move(methods), std::move(members));
587*9e3b08aeSAndroid Build Coastguard Worker     if (!full_name.empty()) {
588*9e3b08aeSAndroid Build Coastguard Worker       AddNamedTypeNode(id);
589*9e3b08aeSAndroid Build Coastguard Worker     }
590*9e3b08aeSAndroid Build Coastguard Worker   }
591*9e3b08aeSAndroid Build Coastguard Worker 
ProcessVariantMember(Entry & entry)592*9e3b08aeSAndroid Build Coastguard Worker   void ProcessVariantMember(Entry& entry) {
593*9e3b08aeSAndroid Build Coastguard Worker     // TODO: Process signed discriminant values.
594*9e3b08aeSAndroid Build Coastguard Worker     auto dw_discriminant_value =
595*9e3b08aeSAndroid Build Coastguard Worker         entry.MaybeGetUnsignedConstant(DW_AT_discr_value);
596*9e3b08aeSAndroid Build Coastguard Worker     auto discriminant_value =
597*9e3b08aeSAndroid Build Coastguard Worker         dw_discriminant_value
598*9e3b08aeSAndroid Build Coastguard Worker             ? std::optional(static_cast<int64_t>(*dw_discriminant_value))
599*9e3b08aeSAndroid Build Coastguard Worker             : std::nullopt;
600*9e3b08aeSAndroid Build Coastguard Worker 
601*9e3b08aeSAndroid Build Coastguard Worker     auto children = entry.GetChildren();
602*9e3b08aeSAndroid Build Coastguard Worker     if (children.size() != 1) {
603*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Unexpected number of children for variant member: "
604*9e3b08aeSAndroid Build Coastguard Worker             << EntryToString(entry);
605*9e3b08aeSAndroid Build Coastguard Worker     }
606*9e3b08aeSAndroid Build Coastguard Worker 
607*9e3b08aeSAndroid Build Coastguard Worker     auto child = children[0];
608*9e3b08aeSAndroid Build Coastguard Worker     if (child.GetTag() != DW_TAG_member) {
609*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Unexpected tag for variant member child: "
610*9e3b08aeSAndroid Build Coastguard Worker             << Hex(child.GetTag()) << ", " << EntryToString(child);
611*9e3b08aeSAndroid Build Coastguard Worker     }
612*9e3b08aeSAndroid Build Coastguard Worker     if (GetDataBitOffset(child, 0, is_little_endian_binary_) != 0) {
613*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Unexpected data member location for variant member: "
614*9e3b08aeSAndroid Build Coastguard Worker             << EntryToString(child);
615*9e3b08aeSAndroid Build Coastguard Worker     }
616*9e3b08aeSAndroid Build Coastguard Worker 
617*9e3b08aeSAndroid Build Coastguard Worker     const std::string name = GetNameOrEmpty(child);
618*9e3b08aeSAndroid Build Coastguard Worker     auto referred_type_id = GetReferredTypeId(GetReferredType(child));
619*9e3b08aeSAndroid Build Coastguard Worker     AddProcessedNode<VariantMember>(entry, name, discriminant_value,
620*9e3b08aeSAndroid Build Coastguard Worker                                     referred_type_id);
621*9e3b08aeSAndroid Build Coastguard Worker   }
622*9e3b08aeSAndroid Build Coastguard Worker 
ProcessMember(Entry & entry)623*9e3b08aeSAndroid Build Coastguard Worker   void ProcessMember(Entry& entry) {
624*9e3b08aeSAndroid Build Coastguard Worker     const auto name = GetNameOrEmpty(entry);
625*9e3b08aeSAndroid Build Coastguard Worker     auto referred_type = GetReferredType(entry);
626*9e3b08aeSAndroid Build Coastguard Worker     const Id referred_type_id = GetIdForEntry(referred_type);
627*9e3b08aeSAndroid Build Coastguard Worker     auto optional_bit_size = entry.MaybeGetUnsignedConstant(DW_AT_bit_size);
628*9e3b08aeSAndroid Build Coastguard Worker     // Member has DW_AT_bit_size if and only if it is bit field.
629*9e3b08aeSAndroid Build Coastguard Worker     // STG uses bit_size == 0 to mark that the member is not a bit field.
630*9e3b08aeSAndroid Build Coastguard Worker     Check(!optional_bit_size || *optional_bit_size > 0)
631*9e3b08aeSAndroid Build Coastguard Worker         << "DW_AT_bit_size should be a positive number";
632*9e3b08aeSAndroid Build Coastguard Worker     auto bit_size = optional_bit_size ? *optional_bit_size : 0;
633*9e3b08aeSAndroid Build Coastguard Worker     AddProcessedNode<Member>(
634*9e3b08aeSAndroid Build Coastguard Worker         entry, std::move(name), referred_type_id,
635*9e3b08aeSAndroid Build Coastguard Worker         GetDataBitOffset(entry, bit_size, is_little_endian_binary_), bit_size);
636*9e3b08aeSAndroid Build Coastguard Worker   }
637*9e3b08aeSAndroid Build Coastguard Worker 
ProcessMethod(std::vector<Id> & methods,Entry & entry)638*9e3b08aeSAndroid Build Coastguard Worker   void ProcessMethod(std::vector<Id>& methods, Entry& entry) {
639*9e3b08aeSAndroid Build Coastguard Worker     Subprogram subprogram = GetSubprogram(entry);
640*9e3b08aeSAndroid Build Coastguard Worker     auto id = maker_.Add<Function>(std::move(subprogram.node));
641*9e3b08aeSAndroid Build Coastguard Worker     if (subprogram.external && subprogram.address) {
642*9e3b08aeSAndroid Build Coastguard Worker       // Only external functions with address are useful for ABI monitoring
643*9e3b08aeSAndroid Build Coastguard Worker       // TODO: cover virtual methods
644*9e3b08aeSAndroid Build Coastguard Worker       const auto new_symbol_idx = result_.symbols.size();
645*9e3b08aeSAndroid Build Coastguard Worker       result_.symbols.push_back(Types::Symbol{
646*9e3b08aeSAndroid Build Coastguard Worker           .scoped_name = GetScopedNameForSymbol(
647*9e3b08aeSAndroid Build Coastguard Worker               new_symbol_idx, subprogram.name_with_context),
648*9e3b08aeSAndroid Build Coastguard Worker           .linkage_name = subprogram.linkage_name,
649*9e3b08aeSAndroid Build Coastguard Worker           .address = *subprogram.address,
650*9e3b08aeSAndroid Build Coastguard Worker           .type_id = id});
651*9e3b08aeSAndroid Build Coastguard Worker     }
652*9e3b08aeSAndroid Build Coastguard Worker     const auto virtuality = entry.MaybeGetUnsignedConstant(DW_AT_virtuality)
653*9e3b08aeSAndroid Build Coastguard Worker                                  .value_or(DW_VIRTUALITY_none);
654*9e3b08aeSAndroid Build Coastguard Worker     if (virtuality == DW_VIRTUALITY_virtual ||
655*9e3b08aeSAndroid Build Coastguard Worker         virtuality == DW_VIRTUALITY_pure_virtual) {
656*9e3b08aeSAndroid Build Coastguard Worker       if (!subprogram.name_with_context.unscoped_name) {
657*9e3b08aeSAndroid Build Coastguard Worker         Die() << "Method " << EntryToString(entry) << " should have name";
658*9e3b08aeSAndroid Build Coastguard Worker       }
659*9e3b08aeSAndroid Build Coastguard Worker       if (subprogram.name_with_context.specification) {
660*9e3b08aeSAndroid Build Coastguard Worker         Die() << "Method " << EntryToString(entry)
661*9e3b08aeSAndroid Build Coastguard Worker               << " shouldn't have specification";
662*9e3b08aeSAndroid Build Coastguard Worker       }
663*9e3b08aeSAndroid Build Coastguard Worker       const auto vtable_offset = entry.MaybeGetVtableOffset().value_or(0);
664*9e3b08aeSAndroid Build Coastguard Worker       methods.push_back(AddProcessedNode<Method>(
665*9e3b08aeSAndroid Build Coastguard Worker           entry, subprogram.linkage_name,
666*9e3b08aeSAndroid Build Coastguard Worker           *subprogram.name_with_context.unscoped_name, vtable_offset, id));
667*9e3b08aeSAndroid Build Coastguard Worker     }
668*9e3b08aeSAndroid Build Coastguard Worker   }
669*9e3b08aeSAndroid Build Coastguard Worker 
ProcessBaseClass(Entry & entry)670*9e3b08aeSAndroid Build Coastguard Worker   void ProcessBaseClass(Entry& entry) {
671*9e3b08aeSAndroid Build Coastguard Worker     const Id type_id = GetReferredTypeId(GetReferredType(entry));
672*9e3b08aeSAndroid Build Coastguard Worker     const auto byte_offset = entry.MaybeGetMemberByteOffset();
673*9e3b08aeSAndroid Build Coastguard Worker     if (!byte_offset) {
674*9e3b08aeSAndroid Build Coastguard Worker       Die() << "No offset found for base class " << EntryToString(entry);
675*9e3b08aeSAndroid Build Coastguard Worker     }
676*9e3b08aeSAndroid Build Coastguard Worker     const auto bit_offset = *byte_offset * 8;
677*9e3b08aeSAndroid Build Coastguard Worker     const auto virtuality = entry.MaybeGetUnsignedConstant(DW_AT_virtuality)
678*9e3b08aeSAndroid Build Coastguard Worker                                  .value_or(DW_VIRTUALITY_none);
679*9e3b08aeSAndroid Build Coastguard Worker     BaseClass::Inheritance inheritance;
680*9e3b08aeSAndroid Build Coastguard Worker     if (virtuality == DW_VIRTUALITY_none) {
681*9e3b08aeSAndroid Build Coastguard Worker       inheritance = BaseClass::Inheritance::NON_VIRTUAL;
682*9e3b08aeSAndroid Build Coastguard Worker     } else if (virtuality == DW_VIRTUALITY_virtual) {
683*9e3b08aeSAndroid Build Coastguard Worker       inheritance = BaseClass::Inheritance::VIRTUAL;
684*9e3b08aeSAndroid Build Coastguard Worker     } else {
685*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Unexpected base class virtuality: " << virtuality;
686*9e3b08aeSAndroid Build Coastguard Worker     }
687*9e3b08aeSAndroid Build Coastguard Worker     AddProcessedNode<BaseClass>(entry, type_id, bit_offset, inheritance);
688*9e3b08aeSAndroid Build Coastguard Worker   }
689*9e3b08aeSAndroid Build Coastguard Worker 
ProcessArray(Entry & entry)690*9e3b08aeSAndroid Build Coastguard Worker   void ProcessArray(Entry& entry) {
691*9e3b08aeSAndroid Build Coastguard Worker     auto referred_type = GetReferredType(entry);
692*9e3b08aeSAndroid Build Coastguard Worker     Id referred_type_id = GetIdForEntry(referred_type);
693*9e3b08aeSAndroid Build Coastguard Worker     auto children = entry.GetChildren();
694*9e3b08aeSAndroid Build Coastguard Worker     // Multiple children in array describe multiple dimensions of this array.
695*9e3b08aeSAndroid Build Coastguard Worker     // For example, int[M][N] contains two children, M located in the first
696*9e3b08aeSAndroid Build Coastguard Worker     // child, N located in the second child. But in STG multidimensional arrays
697*9e3b08aeSAndroid Build Coastguard Worker     // are represented as chain of arrays: int[M][N] is array[M] of array[N] of
698*9e3b08aeSAndroid Build Coastguard Worker     // int.
699*9e3b08aeSAndroid Build Coastguard Worker     //
700*9e3b08aeSAndroid Build Coastguard Worker     // We need to chain children as types together in reversed order.
701*9e3b08aeSAndroid Build Coastguard Worker     // "referred_type_id" is updated every time to contain the top element in
702*9e3b08aeSAndroid Build Coastguard Worker     // the chain. Rightmost chldren refers to the original "referred_type_id".
703*9e3b08aeSAndroid Build Coastguard Worker     for (auto it = children.rbegin(); it != children.rend(); ++it) {
704*9e3b08aeSAndroid Build Coastguard Worker       auto& child = *it;
705*9e3b08aeSAndroid Build Coastguard Worker       // All subarrays except the first (last in the reversed order) are
706*9e3b08aeSAndroid Build Coastguard Worker       // attached to the corresponding child. First subarray (last in the
707*9e3b08aeSAndroid Build Coastguard Worker       // reversed order) is attached to the original entry itself.
708*9e3b08aeSAndroid Build Coastguard Worker       auto& entry_to_attach = (it + 1 == children.rend()) ? entry : child;
709*9e3b08aeSAndroid Build Coastguard Worker       // Update referred_type_id so next array in chain points there.
710*9e3b08aeSAndroid Build Coastguard Worker       referred_type_id = AddProcessedNode<Array>(
711*9e3b08aeSAndroid Build Coastguard Worker           entry_to_attach, GetNumberOfElements(child), referred_type_id);
712*9e3b08aeSAndroid Build Coastguard Worker     }
713*9e3b08aeSAndroid Build Coastguard Worker   }
714*9e3b08aeSAndroid Build Coastguard Worker 
ProcessEnum(Entry & entry)715*9e3b08aeSAndroid Build Coastguard Worker   void ProcessEnum(Entry& entry) {
716*9e3b08aeSAndroid Build Coastguard Worker     const auto type_name = GetNameOrEmpty(entry);
717*9e3b08aeSAndroid Build Coastguard Worker     const auto full_name =
718*9e3b08aeSAndroid Build Coastguard Worker         type_name.empty() ? type_name : scope_.name + type_name;
719*9e3b08aeSAndroid Build Coastguard Worker 
720*9e3b08aeSAndroid Build Coastguard Worker     if (entry.GetFlag(DW_AT_declaration)) {
721*9e3b08aeSAndroid Build Coastguard Worker       // It is expected to have only name and no children in declaration.
722*9e3b08aeSAndroid Build Coastguard Worker       // However, it is not guaranteed and we should do something if we find an
723*9e3b08aeSAndroid Build Coastguard Worker       // example.
724*9e3b08aeSAndroid Build Coastguard Worker       CheckNoChildren(entry);
725*9e3b08aeSAndroid Build Coastguard Worker       AddProcessedNode<Enumeration>(entry, full_name);
726*9e3b08aeSAndroid Build Coastguard Worker       return;
727*9e3b08aeSAndroid Build Coastguard Worker     }
728*9e3b08aeSAndroid Build Coastguard Worker     const Id underlying_type_id =
729*9e3b08aeSAndroid Build Coastguard Worker         GetReferredTypeId(MaybeGetReferredType(entry));
730*9e3b08aeSAndroid Build Coastguard Worker     auto children = entry.GetChildren();
731*9e3b08aeSAndroid Build Coastguard Worker     Enumeration::Enumerators enumerators;
732*9e3b08aeSAndroid Build Coastguard Worker     enumerators.reserve(children.size());
733*9e3b08aeSAndroid Build Coastguard Worker     for (auto& child : children) {
734*9e3b08aeSAndroid Build Coastguard Worker       auto child_tag = child.GetTag();
735*9e3b08aeSAndroid Build Coastguard Worker       switch (child_tag) {
736*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_enumerator: {
737*9e3b08aeSAndroid Build Coastguard Worker           const std::string enumerator_name = GetName(child);
738*9e3b08aeSAndroid Build Coastguard Worker           // TODO: detect signedness of underlying type and call
739*9e3b08aeSAndroid Build Coastguard Worker           // an appropriate method.
740*9e3b08aeSAndroid Build Coastguard Worker           std::optional<size_t> value_optional =
741*9e3b08aeSAndroid Build Coastguard Worker               child.MaybeGetUnsignedConstant(DW_AT_const_value);
742*9e3b08aeSAndroid Build Coastguard Worker           Check(value_optional.has_value()) << "Enumerator should have value";
743*9e3b08aeSAndroid Build Coastguard Worker           // TODO: support both uint64_t and int64_t, depending on
744*9e3b08aeSAndroid Build Coastguard Worker           // signedness of underlying type.
745*9e3b08aeSAndroid Build Coastguard Worker           enumerators.emplace_back(enumerator_name,
746*9e3b08aeSAndroid Build Coastguard Worker                                    static_cast<int64_t>(*value_optional));
747*9e3b08aeSAndroid Build Coastguard Worker           break;
748*9e3b08aeSAndroid Build Coastguard Worker         }
749*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_subprogram:
750*9e3b08aeSAndroid Build Coastguard Worker           // STG does not support virtual methods for enums.
751*9e3b08aeSAndroid Build Coastguard Worker           Check(child.MaybeGetUnsignedConstant(DW_AT_virtuality)
752*9e3b08aeSAndroid Build Coastguard Worker                     .value_or(DW_VIRTUALITY_none) == DW_VIRTUALITY_none)
753*9e3b08aeSAndroid Build Coastguard Worker               << "Enums can not have virtual methods: " << EntryToString(child);
754*9e3b08aeSAndroid Build Coastguard Worker           ProcessFunction(child);
755*9e3b08aeSAndroid Build Coastguard Worker           break;
756*9e3b08aeSAndroid Build Coastguard Worker         default:
757*9e3b08aeSAndroid Build Coastguard Worker           Die() << "Unexpected tag for child of enum: " << Hex(child_tag)
758*9e3b08aeSAndroid Build Coastguard Worker                 << ", " << EntryToString(child);
759*9e3b08aeSAndroid Build Coastguard Worker       }
760*9e3b08aeSAndroid Build Coastguard Worker     }
761*9e3b08aeSAndroid Build Coastguard Worker     if (!ShouldKeepDefinition(entry, type_name)) {
762*9e3b08aeSAndroid Build Coastguard Worker       AddProcessedNode<Enumeration>(entry, full_name);
763*9e3b08aeSAndroid Build Coastguard Worker       return;
764*9e3b08aeSAndroid Build Coastguard Worker     }
765*9e3b08aeSAndroid Build Coastguard Worker     const Id id = AddProcessedNode<Enumeration>(
766*9e3b08aeSAndroid Build Coastguard Worker         entry, full_name, underlying_type_id, std::move(enumerators));
767*9e3b08aeSAndroid Build Coastguard Worker     if (!full_name.empty()) {
768*9e3b08aeSAndroid Build Coastguard Worker       AddNamedTypeNode(id);
769*9e3b08aeSAndroid Build Coastguard Worker     }
770*9e3b08aeSAndroid Build Coastguard Worker   }
771*9e3b08aeSAndroid Build Coastguard Worker 
772*9e3b08aeSAndroid Build Coastguard Worker   struct VariantAndMembers {
773*9e3b08aeSAndroid Build Coastguard Worker     std::optional<Id> discriminant;
774*9e3b08aeSAndroid Build Coastguard Worker     std::vector<Id> members;
775*9e3b08aeSAndroid Build Coastguard Worker   };
776*9e3b08aeSAndroid Build Coastguard Worker 
GetVariantAndMembers(Entry & entry)777*9e3b08aeSAndroid Build Coastguard Worker   VariantAndMembers GetVariantAndMembers(Entry& entry) {
778*9e3b08aeSAndroid Build Coastguard Worker     std::vector<Id> members;
779*9e3b08aeSAndroid Build Coastguard Worker     std::optional<Id> discriminant = std::nullopt;
780*9e3b08aeSAndroid Build Coastguard Worker     auto discriminant_entry = entry.MaybeGetReference(DW_AT_discr);
781*9e3b08aeSAndroid Build Coastguard Worker     if (discriminant_entry.has_value()) {
782*9e3b08aeSAndroid Build Coastguard Worker       discriminant = GetIdForEntry(*discriminant_entry);
783*9e3b08aeSAndroid Build Coastguard Worker       ProcessMember(*discriminant_entry);
784*9e3b08aeSAndroid Build Coastguard Worker     }
785*9e3b08aeSAndroid Build Coastguard Worker 
786*9e3b08aeSAndroid Build Coastguard Worker     for (auto& child : entry.GetChildren()) {
787*9e3b08aeSAndroid Build Coastguard Worker       auto child_tag = child.GetTag();
788*9e3b08aeSAndroid Build Coastguard Worker       switch (child_tag) {
789*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_member: {
790*9e3b08aeSAndroid Build Coastguard Worker           if (child.GetOffset() != discriminant_entry->GetOffset()) {
791*9e3b08aeSAndroid Build Coastguard Worker             Die() << "Encountered rogue member for variant: "
792*9e3b08aeSAndroid Build Coastguard Worker                   << EntryToString(entry);
793*9e3b08aeSAndroid Build Coastguard Worker           }
794*9e3b08aeSAndroid Build Coastguard Worker           if (!child.GetFlag(DW_AT_artificial)) {
795*9e3b08aeSAndroid Build Coastguard Worker             Die() << "Variant discriminant must be an artificial member: "
796*9e3b08aeSAndroid Build Coastguard Worker                   << EntryToString(child);
797*9e3b08aeSAndroid Build Coastguard Worker           }
798*9e3b08aeSAndroid Build Coastguard Worker           break;
799*9e3b08aeSAndroid Build Coastguard Worker         }
800*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_variant:
801*9e3b08aeSAndroid Build Coastguard Worker           members.push_back(GetIdForEntry(child));
802*9e3b08aeSAndroid Build Coastguard Worker           ProcessVariantMember(child);
803*9e3b08aeSAndroid Build Coastguard Worker           break;
804*9e3b08aeSAndroid Build Coastguard Worker         default:
805*9e3b08aeSAndroid Build Coastguard Worker           Die() << "Unexpected tag for child of variant: " << Hex(child_tag)
806*9e3b08aeSAndroid Build Coastguard Worker                 << ", " << EntryToString(child);
807*9e3b08aeSAndroid Build Coastguard Worker       }
808*9e3b08aeSAndroid Build Coastguard Worker     }
809*9e3b08aeSAndroid Build Coastguard Worker     return VariantAndMembers{.discriminant = discriminant,
810*9e3b08aeSAndroid Build Coastguard Worker                              .members = std::move(members)};
811*9e3b08aeSAndroid Build Coastguard Worker   }
812*9e3b08aeSAndroid Build Coastguard Worker 
813*9e3b08aeSAndroid Build Coastguard Worker   struct NameWithContext {
814*9e3b08aeSAndroid Build Coastguard Worker     std::optional<Dwarf_Off> specification;
815*9e3b08aeSAndroid Build Coastguard Worker     std::optional<std::string> unscoped_name;
816*9e3b08aeSAndroid Build Coastguard Worker     std::optional<std::string> scoped_name;
817*9e3b08aeSAndroid Build Coastguard Worker   };
818*9e3b08aeSAndroid Build Coastguard Worker 
GetNameWithContext(Entry & entry)819*9e3b08aeSAndroid Build Coastguard Worker   NameWithContext GetNameWithContext(Entry& entry) {
820*9e3b08aeSAndroid Build Coastguard Worker     NameWithContext result;
821*9e3b08aeSAndroid Build Coastguard Worker     // Leaf of specification tree is usually a declaration (of a function or a
822*9e3b08aeSAndroid Build Coastguard Worker     // method). Then goes definition, which references declaration by
823*9e3b08aeSAndroid Build Coastguard Worker     // DW_AT_specification. And on top we have instantiation, which references
824*9e3b08aeSAndroid Build Coastguard Worker     // definition by DW_AT_abstract_origin. In the worst case we have:
825*9e3b08aeSAndroid Build Coastguard Worker     // * instantiation
826*9e3b08aeSAndroid Build Coastguard Worker     //     >-DW_AT_abstract_origin-> definition
827*9e3b08aeSAndroid Build Coastguard Worker     //         >-DW_AT_specification-> declaration
828*9e3b08aeSAndroid Build Coastguard Worker     //
829*9e3b08aeSAndroid Build Coastguard Worker     // By using attribute integration we fold all information from definition to
830*9e3b08aeSAndroid Build Coastguard Worker     // instantiation, flattening hierarchy:
831*9e3b08aeSAndroid Build Coastguard Worker     // * instantiation + definition
832*9e3b08aeSAndroid Build Coastguard Worker     //     >-DW_AT_specification-> declaration
833*9e3b08aeSAndroid Build Coastguard Worker     // NB: DW_AT_abstract_origin attribute is also visible, but it should be
834*9e3b08aeSAndroid Build Coastguard Worker     // ignored, since we already used it during integration.
835*9e3b08aeSAndroid Build Coastguard Worker     //
836*9e3b08aeSAndroid Build Coastguard Worker     // We also need to support this case, when we don't have separate
837*9e3b08aeSAndroid Build Coastguard Worker     // declaration:
838*9e3b08aeSAndroid Build Coastguard Worker     // * instantiation +
839*9e3b08aeSAndroid Build Coastguard Worker     //     >-DW_AT_abstract_origin -> definition
840*9e3b08aeSAndroid Build Coastguard Worker     //
841*9e3b08aeSAndroid Build Coastguard Worker     // So the final algorithm is to get final DW_AT_specification through the
842*9e3b08aeSAndroid Build Coastguard Worker     // whole chain, or use DW_AT_abstract_origin if there is no
843*9e3b08aeSAndroid Build Coastguard Worker     // DW_AT_specification.
844*9e3b08aeSAndroid Build Coastguard Worker     if (auto specification = entry.MaybeGetReference(DW_AT_specification)) {
845*9e3b08aeSAndroid Build Coastguard Worker       result.specification = specification->GetOffset();
846*9e3b08aeSAndroid Build Coastguard Worker     } else if (auto abstract_origin =
847*9e3b08aeSAndroid Build Coastguard Worker                    entry.MaybeGetReference(DW_AT_abstract_origin)) {
848*9e3b08aeSAndroid Build Coastguard Worker       result.specification = abstract_origin->GetOffset();
849*9e3b08aeSAndroid Build Coastguard Worker     }
850*9e3b08aeSAndroid Build Coastguard Worker     result.unscoped_name = entry.MaybeGetDirectString(DW_AT_name);
851*9e3b08aeSAndroid Build Coastguard Worker     if (!result.unscoped_name && !result.specification) {
852*9e3b08aeSAndroid Build Coastguard Worker       // If there is no name and specification, then this entry is anonymous.
853*9e3b08aeSAndroid Build Coastguard Worker       // Anonymous entries are modelled as the empty string and not nullopt.
854*9e3b08aeSAndroid Build Coastguard Worker       // This allows us to fill and register scoped_name (also empty string) to
855*9e3b08aeSAndroid Build Coastguard Worker       // be used in references.
856*9e3b08aeSAndroid Build Coastguard Worker       result.unscoped_name = std::string();
857*9e3b08aeSAndroid Build Coastguard Worker     }
858*9e3b08aeSAndroid Build Coastguard Worker     if (result.unscoped_name) {
859*9e3b08aeSAndroid Build Coastguard Worker       result.scoped_name = scope_.name + *result.unscoped_name;
860*9e3b08aeSAndroid Build Coastguard Worker       scoped_names_.emplace_back(
861*9e3b08aeSAndroid Build Coastguard Worker           entry.GetOffset(), *result.scoped_name);
862*9e3b08aeSAndroid Build Coastguard Worker     }
863*9e3b08aeSAndroid Build Coastguard Worker     return result;
864*9e3b08aeSAndroid Build Coastguard Worker   }
865*9e3b08aeSAndroid Build Coastguard Worker 
GetScopedNameForSymbol(size_t symbol_idx,const NameWithContext & name)866*9e3b08aeSAndroid Build Coastguard Worker   std::string GetScopedNameForSymbol(size_t symbol_idx,
867*9e3b08aeSAndroid Build Coastguard Worker                                      const NameWithContext& name) {
868*9e3b08aeSAndroid Build Coastguard Worker     // This method is designed to resolve this topology:
869*9e3b08aeSAndroid Build Coastguard Worker     //   A: specification=B
870*9e3b08aeSAndroid Build Coastguard Worker     //   B: name="foo"
871*9e3b08aeSAndroid Build Coastguard Worker     // Any other topologies are rejected:
872*9e3b08aeSAndroid Build Coastguard Worker     //   * Name and specification in one DIE: checked right below.
873*9e3b08aeSAndroid Build Coastguard Worker     //   * Chain of specifications will result in symbol referencing another
874*9e3b08aeSAndroid Build Coastguard Worker     //     specification, which will not be in scoped_names_, because "name and
875*9e3b08aeSAndroid Build Coastguard Worker     //     specification in one DIE" is rejected.
876*9e3b08aeSAndroid Build Coastguard Worker     if (name.scoped_name) {
877*9e3b08aeSAndroid Build Coastguard Worker       if (name.specification) {
878*9e3b08aeSAndroid Build Coastguard Worker         Die() << "Entry has name " << *name.scoped_name
879*9e3b08aeSAndroid Build Coastguard Worker               << " and specification " << Hex(*name.specification);
880*9e3b08aeSAndroid Build Coastguard Worker       }
881*9e3b08aeSAndroid Build Coastguard Worker       return *name.scoped_name;
882*9e3b08aeSAndroid Build Coastguard Worker     }
883*9e3b08aeSAndroid Build Coastguard Worker     if (name.specification) {
884*9e3b08aeSAndroid Build Coastguard Worker       unresolved_symbol_specifications_.emplace_back(*name.specification,
885*9e3b08aeSAndroid Build Coastguard Worker                                                      symbol_idx);
886*9e3b08aeSAndroid Build Coastguard Worker       // Name will be filled in ResolveSymbolSpecifications
887*9e3b08aeSAndroid Build Coastguard Worker       return {};
888*9e3b08aeSAndroid Build Coastguard Worker     }
889*9e3b08aeSAndroid Build Coastguard Worker     Die() << "Entry should have either name or specification";
890*9e3b08aeSAndroid Build Coastguard Worker   }
891*9e3b08aeSAndroid Build Coastguard Worker 
ProcessVariable(Entry & entry)892*9e3b08aeSAndroid Build Coastguard Worker   void ProcessVariable(Entry& entry) {
893*9e3b08aeSAndroid Build Coastguard Worker     auto name_with_context = GetNameWithContext(entry);
894*9e3b08aeSAndroid Build Coastguard Worker 
895*9e3b08aeSAndroid Build Coastguard Worker     auto referred_type = GetReferredType(entry);
896*9e3b08aeSAndroid Build Coastguard Worker     const Id referred_type_id = GetIdForEntry(referred_type);
897*9e3b08aeSAndroid Build Coastguard Worker 
898*9e3b08aeSAndroid Build Coastguard Worker     if (auto address = entry.MaybeGetAddress(DW_AT_location)) {
899*9e3b08aeSAndroid Build Coastguard Worker       // Only external variables with address are useful for ABI monitoring
900*9e3b08aeSAndroid Build Coastguard Worker       const auto new_symbol_idx = result_.symbols.size();
901*9e3b08aeSAndroid Build Coastguard Worker       result_.symbols.push_back(Types::Symbol{
902*9e3b08aeSAndroid Build Coastguard Worker           .scoped_name = GetScopedNameForSymbol(
903*9e3b08aeSAndroid Build Coastguard Worker               new_symbol_idx, name_with_context),
904*9e3b08aeSAndroid Build Coastguard Worker           .linkage_name = GetLinkageName(version_, entry),
905*9e3b08aeSAndroid Build Coastguard Worker           .address = *address,
906*9e3b08aeSAndroid Build Coastguard Worker           .type_id = referred_type_id});
907*9e3b08aeSAndroid Build Coastguard Worker     }
908*9e3b08aeSAndroid Build Coastguard Worker   }
909*9e3b08aeSAndroid Build Coastguard Worker 
ProcessFunction(Entry & entry)910*9e3b08aeSAndroid Build Coastguard Worker   void ProcessFunction(Entry& entry) {
911*9e3b08aeSAndroid Build Coastguard Worker     Subprogram subprogram = GetSubprogram(entry);
912*9e3b08aeSAndroid Build Coastguard Worker     const Id id = AddProcessedNode<Function>(entry, std::move(subprogram.node));
913*9e3b08aeSAndroid Build Coastguard Worker     if (subprogram.external && subprogram.address) {
914*9e3b08aeSAndroid Build Coastguard Worker       // Only external functions with address are useful for ABI monitoring
915*9e3b08aeSAndroid Build Coastguard Worker       const auto new_symbol_idx = result_.symbols.size();
916*9e3b08aeSAndroid Build Coastguard Worker       result_.symbols.push_back(Types::Symbol{
917*9e3b08aeSAndroid Build Coastguard Worker           .scoped_name = GetScopedNameForSymbol(
918*9e3b08aeSAndroid Build Coastguard Worker               new_symbol_idx, subprogram.name_with_context),
919*9e3b08aeSAndroid Build Coastguard Worker           .linkage_name = std::move(subprogram.linkage_name),
920*9e3b08aeSAndroid Build Coastguard Worker           .address = *subprogram.address,
921*9e3b08aeSAndroid Build Coastguard Worker           .type_id = id});
922*9e3b08aeSAndroid Build Coastguard Worker     }
923*9e3b08aeSAndroid Build Coastguard Worker   }
924*9e3b08aeSAndroid Build Coastguard Worker 
925*9e3b08aeSAndroid Build Coastguard Worker   struct Subprogram {
926*9e3b08aeSAndroid Build Coastguard Worker     Function node;
927*9e3b08aeSAndroid Build Coastguard Worker     NameWithContext name_with_context;
928*9e3b08aeSAndroid Build Coastguard Worker     std::string linkage_name;
929*9e3b08aeSAndroid Build Coastguard Worker     std::optional<Address> address;
930*9e3b08aeSAndroid Build Coastguard Worker     bool external;
931*9e3b08aeSAndroid Build Coastguard Worker   };
932*9e3b08aeSAndroid Build Coastguard Worker 
GetSubprogram(Entry & entry)933*9e3b08aeSAndroid Build Coastguard Worker   Subprogram GetSubprogram(Entry& entry) {
934*9e3b08aeSAndroid Build Coastguard Worker     const Id return_type_id = GetReferredTypeId(MaybeGetReferredType(entry));
935*9e3b08aeSAndroid Build Coastguard Worker 
936*9e3b08aeSAndroid Build Coastguard Worker     std::vector<Id> parameters;
937*9e3b08aeSAndroid Build Coastguard Worker     for (auto& child : entry.GetChildren()) {
938*9e3b08aeSAndroid Build Coastguard Worker       auto child_tag = child.GetTag();
939*9e3b08aeSAndroid Build Coastguard Worker       switch (child_tag) {
940*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_formal_parameter:
941*9e3b08aeSAndroid Build Coastguard Worker           parameters.push_back(GetReferredTypeId(GetReferredType(child)));
942*9e3b08aeSAndroid Build Coastguard Worker           break;
943*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_unspecified_parameters:
944*9e3b08aeSAndroid Build Coastguard Worker           // Note: C++ allows a single ... argument specification but C does
945*9e3b08aeSAndroid Build Coastguard Worker           // not. However, "extern int foo();" (note lack of "void" in
946*9e3b08aeSAndroid Build Coastguard Worker           // parameters) in C will produce the same DWARF as "extern int
947*9e3b08aeSAndroid Build Coastguard Worker           // foo(...);" in C++.
948*9e3b08aeSAndroid Build Coastguard Worker           CheckNoChildren(child);
949*9e3b08aeSAndroid Build Coastguard Worker           parameters.push_back(variadic_id_);
950*9e3b08aeSAndroid Build Coastguard Worker           break;
951*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_enumeration_type:
952*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_label:
953*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_lexical_block:
954*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_structure_type:
955*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_class_type:
956*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_union_type:
957*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_typedef:
958*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_const_type:
959*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_volatile_type:
960*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_restrict_type:
961*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_atomic_type:
962*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_array_type:
963*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_pointer_type:
964*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_reference_type:
965*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_rvalue_reference_type:
966*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_ptr_to_member_type:
967*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_unspecified_type:
968*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_inlined_subroutine:
969*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_subprogram:
970*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_variable:
971*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_call_site:
972*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_GNU_call_site:
973*9e3b08aeSAndroid Build Coastguard Worker           // TODO: Do not leak local types outside this scope.
974*9e3b08aeSAndroid Build Coastguard Worker           // TODO: It would be better to not process any
975*9e3b08aeSAndroid Build Coastguard Worker           // information that is function local but there is a dangling
976*9e3b08aeSAndroid Build Coastguard Worker           // reference Clang bug.
977*9e3b08aeSAndroid Build Coastguard Worker           Process(child);
978*9e3b08aeSAndroid Build Coastguard Worker           break;
979*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_imported_declaration:
980*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_imported_module:
981*9e3b08aeSAndroid Build Coastguard Worker           // For now information there is useless for ABI monitoring, but we
982*9e3b08aeSAndroid Build Coastguard Worker           // need to check that there is no missing information in descendants.
983*9e3b08aeSAndroid Build Coastguard Worker           CheckNoChildren(child);
984*9e3b08aeSAndroid Build Coastguard Worker           break;
985*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_template_type_parameter:
986*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_template_value_parameter:
987*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_GNU_template_template_param:
988*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_GNU_template_parameter_pack:
989*9e3b08aeSAndroid Build Coastguard Worker           // We just skip these as neither GCC nor Clang seem to use them
990*9e3b08aeSAndroid Build Coastguard Worker           // properly (resulting in no references to such DIEs).
991*9e3b08aeSAndroid Build Coastguard Worker           break;
992*9e3b08aeSAndroid Build Coastguard Worker         case DW_TAG_GNU_formal_parameter_pack:
993*9e3b08aeSAndroid Build Coastguard Worker           // https://wiki.dwarfstd.org/C++0x_Variadic_templates.md
994*9e3b08aeSAndroid Build Coastguard Worker           //
995*9e3b08aeSAndroid Build Coastguard Worker           // As per this (rejected) proposal, GCC includes parameters as
996*9e3b08aeSAndroid Build Coastguard Worker           // children of this DIE.
997*9e3b08aeSAndroid Build Coastguard Worker           for (auto& child2 : child.GetChildren()) {
998*9e3b08aeSAndroid Build Coastguard Worker             if (child2.GetTag() == DW_TAG_formal_parameter) {
999*9e3b08aeSAndroid Build Coastguard Worker               parameters.push_back(GetReferredTypeId(GetReferredType(child2)));
1000*9e3b08aeSAndroid Build Coastguard Worker             }
1001*9e3b08aeSAndroid Build Coastguard Worker           }
1002*9e3b08aeSAndroid Build Coastguard Worker           break;
1003*9e3b08aeSAndroid Build Coastguard Worker         default:
1004*9e3b08aeSAndroid Build Coastguard Worker           Die() << "Unexpected tag for child of function: " << Hex(child_tag)
1005*9e3b08aeSAndroid Build Coastguard Worker                 << ", " << EntryToString(child);
1006*9e3b08aeSAndroid Build Coastguard Worker       }
1007*9e3b08aeSAndroid Build Coastguard Worker     }
1008*9e3b08aeSAndroid Build Coastguard Worker 
1009*9e3b08aeSAndroid Build Coastguard Worker     return Subprogram{.node = Function(return_type_id, parameters),
1010*9e3b08aeSAndroid Build Coastguard Worker                       .name_with_context = GetNameWithContext(entry),
1011*9e3b08aeSAndroid Build Coastguard Worker                       .linkage_name = GetLinkageName(version_, entry),
1012*9e3b08aeSAndroid Build Coastguard Worker                       .address = entry.MaybeGetAddress(DW_AT_low_pc),
1013*9e3b08aeSAndroid Build Coastguard Worker                       .external = entry.GetFlag(DW_AT_external)};
1014*9e3b08aeSAndroid Build Coastguard Worker   }
1015*9e3b08aeSAndroid Build Coastguard Worker 
1016*9e3b08aeSAndroid Build Coastguard Worker   // Allocate or get already allocated STG Id for Entry.
GetIdForEntry(Entry & entry)1017*9e3b08aeSAndroid Build Coastguard Worker   Id GetIdForEntry(Entry& entry) {
1018*9e3b08aeSAndroid Build Coastguard Worker     return maker_.Get(Hex(entry.GetOffset()));
1019*9e3b08aeSAndroid Build Coastguard Worker   }
1020*9e3b08aeSAndroid Build Coastguard Worker 
1021*9e3b08aeSAndroid Build Coastguard Worker   // Same as GetIdForEntry, but returns "void_id_" for "unspecified" references,
1022*9e3b08aeSAndroid Build Coastguard Worker   // because it is normal for DWARF (5.2 Unspecified Type Entries).
GetReferredTypeId(std::optional<Entry> referred_type)1023*9e3b08aeSAndroid Build Coastguard Worker   Id GetReferredTypeId(std::optional<Entry> referred_type) {
1024*9e3b08aeSAndroid Build Coastguard Worker     return referred_type ? GetIdForEntry(*referred_type) : void_id_;
1025*9e3b08aeSAndroid Build Coastguard Worker   }
1026*9e3b08aeSAndroid Build Coastguard Worker 
1027*9e3b08aeSAndroid Build Coastguard Worker   // Wrapper for GetIdForEntry to allow lvalues.
GetReferredTypeId(Entry referred_type)1028*9e3b08aeSAndroid Build Coastguard Worker   Id GetReferredTypeId(Entry referred_type) {
1029*9e3b08aeSAndroid Build Coastguard Worker     return GetIdForEntry(referred_type);
1030*9e3b08aeSAndroid Build Coastguard Worker   }
1031*9e3b08aeSAndroid Build Coastguard Worker 
1032*9e3b08aeSAndroid Build Coastguard Worker   // Populate Id from method above with processed Node.
1033*9e3b08aeSAndroid Build Coastguard Worker   template <typename Node, typename... Args>
AddProcessedNode(Entry & entry,Args &&...args)1034*9e3b08aeSAndroid Build Coastguard Worker   Id AddProcessedNode(Entry& entry, Args&&... args) {
1035*9e3b08aeSAndroid Build Coastguard Worker     return maker_.Set<Node>(Hex(entry.GetOffset()),
1036*9e3b08aeSAndroid Build Coastguard Worker                             std::forward<Args>(args)...);
1037*9e3b08aeSAndroid Build Coastguard Worker   }
1038*9e3b08aeSAndroid Build Coastguard Worker 
AddNamedTypeNode(Id id)1039*9e3b08aeSAndroid Build Coastguard Worker   void AddNamedTypeNode(Id id) {
1040*9e3b08aeSAndroid Build Coastguard Worker     if (scope_.named) {
1041*9e3b08aeSAndroid Build Coastguard Worker       result_.named_type_ids.push_back(id);
1042*9e3b08aeSAndroid Build Coastguard Worker     }
1043*9e3b08aeSAndroid Build Coastguard Worker   }
1044*9e3b08aeSAndroid Build Coastguard Worker 
1045*9e3b08aeSAndroid Build Coastguard Worker   Maker<Hex<Dwarf_Off>> maker_;
1046*9e3b08aeSAndroid Build Coastguard Worker   Id void_id_;
1047*9e3b08aeSAndroid Build Coastguard Worker   Id variadic_id_;
1048*9e3b08aeSAndroid Build Coastguard Worker   bool is_little_endian_binary_;
1049*9e3b08aeSAndroid Build Coastguard Worker   const std::unique_ptr<Filter>& file_filter_;
1050*9e3b08aeSAndroid Build Coastguard Worker   Types& result_;
1051*9e3b08aeSAndroid Build Coastguard Worker   std::vector<std::pair<Dwarf_Off, std::string>> scoped_names_;
1052*9e3b08aeSAndroid Build Coastguard Worker   std::vector<std::pair<Dwarf_Off, size_t>> unresolved_symbol_specifications_;
1053*9e3b08aeSAndroid Build Coastguard Worker 
1054*9e3b08aeSAndroid Build Coastguard Worker   // Current scope.
1055*9e3b08aeSAndroid Build Coastguard Worker   Scope scope_;
1056*9e3b08aeSAndroid Build Coastguard Worker   int version_;
1057*9e3b08aeSAndroid Build Coastguard Worker   dwarf::Files files_;
1058*9e3b08aeSAndroid Build Coastguard Worker   uint64_t language_;
1059*9e3b08aeSAndroid Build Coastguard Worker };
1060*9e3b08aeSAndroid Build Coastguard Worker 
Process(Dwarf * dwarf,bool is_little_endian_binary,const std::unique_ptr<Filter> & file_filter,Graph & graph)1061*9e3b08aeSAndroid Build Coastguard Worker Types Process(Dwarf* dwarf, bool is_little_endian_binary,
1062*9e3b08aeSAndroid Build Coastguard Worker               const std::unique_ptr<Filter>& file_filter, Graph& graph) {
1063*9e3b08aeSAndroid Build Coastguard Worker   Types result;
1064*9e3b08aeSAndroid Build Coastguard Worker 
1065*9e3b08aeSAndroid Build Coastguard Worker   if (dwarf == nullptr) {
1066*9e3b08aeSAndroid Build Coastguard Worker     return result;
1067*9e3b08aeSAndroid Build Coastguard Worker   }
1068*9e3b08aeSAndroid Build Coastguard Worker 
1069*9e3b08aeSAndroid Build Coastguard Worker   const Id void_id = graph.Add<Special>(Special::Kind::VOID);
1070*9e3b08aeSAndroid Build Coastguard Worker   const Id variadic_id = graph.Add<Special>(Special::Kind::VARIADIC);
1071*9e3b08aeSAndroid Build Coastguard Worker   // TODO: Scope Processor to compilation units?
1072*9e3b08aeSAndroid Build Coastguard Worker   Processor processor(graph, void_id, variadic_id, is_little_endian_binary,
1073*9e3b08aeSAndroid Build Coastguard Worker                       file_filter, result);
1074*9e3b08aeSAndroid Build Coastguard Worker   for (auto& compilation_unit : GetCompilationUnits(*dwarf)) {
1075*9e3b08aeSAndroid Build Coastguard Worker     // Could fetch top-level attributes like compiler here.
1076*9e3b08aeSAndroid Build Coastguard Worker     processor.ProcessCompilationUnit(compilation_unit);
1077*9e3b08aeSAndroid Build Coastguard Worker   }
1078*9e3b08aeSAndroid Build Coastguard Worker   processor.ResolveSymbolSpecifications();
1079*9e3b08aeSAndroid Build Coastguard Worker 
1080*9e3b08aeSAndroid Build Coastguard Worker   return result;
1081*9e3b08aeSAndroid Build Coastguard Worker }
1082*9e3b08aeSAndroid Build Coastguard Worker 
1083*9e3b08aeSAndroid Build Coastguard Worker }  // namespace dwarf
1084*9e3b08aeSAndroid Build Coastguard Worker }  // namespace stg
1085