xref: /aosp_15_r20/external/stg/dwarf_wrappers.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 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_wrappers.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 <cstddef>
26*9e3b08aeSAndroid Build Coastguard Worker #include <cstdint>
27*9e3b08aeSAndroid Build Coastguard Worker #include <optional>
28*9e3b08aeSAndroid Build Coastguard Worker #include <ostream>
29*9e3b08aeSAndroid Build Coastguard Worker #include <string>
30*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
31*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
32*9e3b08aeSAndroid Build Coastguard Worker 
33*9e3b08aeSAndroid Build Coastguard Worker #include "error.h"
34*9e3b08aeSAndroid Build Coastguard Worker #include "hex.h"
35*9e3b08aeSAndroid Build Coastguard Worker 
36*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
37*9e3b08aeSAndroid Build Coastguard Worker namespace dwarf {
38*9e3b08aeSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const Address & address)39*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const Address& address) {
40*9e3b08aeSAndroid Build Coastguard Worker   switch (address.kind) {
41*9e3b08aeSAndroid Build Coastguard Worker     case Address::Kind::ADDRESS:
42*9e3b08aeSAndroid Build Coastguard Worker       return os << Hex(address.value);
43*9e3b08aeSAndroid Build Coastguard Worker     case Address::Kind::TLS:
44*9e3b08aeSAndroid Build Coastguard Worker       return os << "TLS:" << Hex(address.value);
45*9e3b08aeSAndroid Build Coastguard Worker   }
46*9e3b08aeSAndroid Build Coastguard Worker }
47*9e3b08aeSAndroid Build Coastguard Worker 
48*9e3b08aeSAndroid Build Coastguard Worker namespace {
49*9e3b08aeSAndroid Build Coastguard Worker 
50*9e3b08aeSAndroid Build Coastguard Worker constexpr int kReturnOk = 0;
51*9e3b08aeSAndroid Build Coastguard Worker constexpr int kReturnNoEntry = 1;
52*9e3b08aeSAndroid Build Coastguard Worker 
GetAttribute(Dwarf_Die * die,uint32_t attribute)53*9e3b08aeSAndroid Build Coastguard Worker std::optional<Dwarf_Attribute> GetAttribute(Dwarf_Die* die,
54*9e3b08aeSAndroid Build Coastguard Worker                                             uint32_t attribute) {
55*9e3b08aeSAndroid Build Coastguard Worker   // Create an optional with default-initialized value already inside
56*9e3b08aeSAndroid Build Coastguard Worker   std::optional<Dwarf_Attribute> result(std::in_place);
57*9e3b08aeSAndroid Build Coastguard Worker   // "integrate" automatically resolves DW_AT_abstract_origin and
58*9e3b08aeSAndroid Build Coastguard Worker   // DW_AT_specification references, fetching the attribute from the linked DIE.
59*9e3b08aeSAndroid Build Coastguard Worker   //
60*9e3b08aeSAndroid Build Coastguard Worker   // libdw has infinite loop protection, as it stops after 16 dereferences.
61*9e3b08aeSAndroid Build Coastguard Worker   // TODO: don't use dwarf_attr_integrate by default
62*9e3b08aeSAndroid Build Coastguard Worker   if (!dwarf_attr_integrate(die, attribute, &result.value())) {
63*9e3b08aeSAndroid Build Coastguard Worker     result.reset();
64*9e3b08aeSAndroid Build Coastguard Worker   }
65*9e3b08aeSAndroid Build Coastguard Worker   return result;
66*9e3b08aeSAndroid Build Coastguard Worker }
67*9e3b08aeSAndroid Build Coastguard Worker 
68*9e3b08aeSAndroid Build Coastguard Worker // Get the attribute directly from DIE without following DW_AT_specification and
69*9e3b08aeSAndroid Build Coastguard Worker // DW_AT_abstract_origin references.
GetDirectAttribute(Dwarf_Die * die,uint32_t attribute)70*9e3b08aeSAndroid Build Coastguard Worker std::optional<Dwarf_Attribute> GetDirectAttribute(Dwarf_Die* die,
71*9e3b08aeSAndroid Build Coastguard Worker                                                   uint32_t attribute) {
72*9e3b08aeSAndroid Build Coastguard Worker   // Create an optional with default-initialized value already inside
73*9e3b08aeSAndroid Build Coastguard Worker   std::optional<Dwarf_Attribute> result(std::in_place);
74*9e3b08aeSAndroid Build Coastguard Worker   if (!dwarf_attr(die, attribute, &result.value())) {
75*9e3b08aeSAndroid Build Coastguard Worker     result.reset();
76*9e3b08aeSAndroid Build Coastguard Worker   }
77*9e3b08aeSAndroid Build Coastguard Worker   return result;
78*9e3b08aeSAndroid Build Coastguard Worker }
79*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetUnsignedOperand(const Dwarf_Op & operand)80*9e3b08aeSAndroid Build Coastguard Worker std::optional<uint64_t> MaybeGetUnsignedOperand(const Dwarf_Op& operand) {
81*9e3b08aeSAndroid Build Coastguard Worker   switch (operand.atom) {
82*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_addr:
83*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_const1u:
84*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_const2u:
85*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_const4u:
86*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_const8u:
87*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_constu:
88*9e3b08aeSAndroid Build Coastguard Worker       return operand.number;
89*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_const1s:
90*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_const2s:
91*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_const4s:
92*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_const8s:
93*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_consts:
94*9e3b08aeSAndroid Build Coastguard Worker       if (static_cast<int64_t>(operand.number) < 0) {
95*9e3b08aeSAndroid Build Coastguard Worker         // Atom is not an unsigned constant
96*9e3b08aeSAndroid Build Coastguard Worker         return std::nullopt;
97*9e3b08aeSAndroid Build Coastguard Worker       }
98*9e3b08aeSAndroid Build Coastguard Worker       return operand.number;
99*9e3b08aeSAndroid Build Coastguard Worker     case DW_OP_lit0...DW_OP_lit31:
100*9e3b08aeSAndroid Build Coastguard Worker       return operand.atom - DW_OP_lit0;
101*9e3b08aeSAndroid Build Coastguard Worker     default:
102*9e3b08aeSAndroid Build Coastguard Worker       return std::nullopt;
103*9e3b08aeSAndroid Build Coastguard Worker   }
104*9e3b08aeSAndroid Build Coastguard Worker }
105*9e3b08aeSAndroid Build Coastguard Worker 
106*9e3b08aeSAndroid Build Coastguard Worker struct Expression {
operator []stg::dwarf::__anon4d8866ff0111::Expression107*9e3b08aeSAndroid Build Coastguard Worker   const Dwarf_Op& operator[](size_t i) const {
108*9e3b08aeSAndroid Build Coastguard Worker     return atoms[i];
109*9e3b08aeSAndroid Build Coastguard Worker   }
110*9e3b08aeSAndroid Build Coastguard Worker 
111*9e3b08aeSAndroid Build Coastguard Worker   Dwarf_Op* atoms = nullptr;
112*9e3b08aeSAndroid Build Coastguard Worker   size_t length = 0;
113*9e3b08aeSAndroid Build Coastguard Worker };
114*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetExpression(Dwarf_Attribute & attribute)115*9e3b08aeSAndroid Build Coastguard Worker std::optional<Expression> MaybeGetExpression(Dwarf_Attribute& attribute) {
116*9e3b08aeSAndroid Build Coastguard Worker   Expression result;
117*9e3b08aeSAndroid Build Coastguard Worker 
118*9e3b08aeSAndroid Build Coastguard Worker   Check(dwarf_getlocation(&attribute, &result.atoms, &result.length) ==
119*9e3b08aeSAndroid Build Coastguard Worker         kReturnOk) << "dwarf_getlocation returned error";
120*9e3b08aeSAndroid Build Coastguard Worker   // If no location attribute is present or has an empty location description,
121*9e3b08aeSAndroid Build Coastguard Worker   // the variable is present in the source but not in the object code.
122*9e3b08aeSAndroid Build Coastguard Worker   // So zero length expression is equivalent of no location attribute.
123*9e3b08aeSAndroid Build Coastguard Worker   if (result.length == 0) {
124*9e3b08aeSAndroid Build Coastguard Worker     return std::nullopt;
125*9e3b08aeSAndroid Build Coastguard Worker   }
126*9e3b08aeSAndroid Build Coastguard Worker   Check(result.atoms != nullptr)
127*9e3b08aeSAndroid Build Coastguard Worker       << "dwarf_getlocation returned non-empty expression with NULL atoms";
128*9e3b08aeSAndroid Build Coastguard Worker   return result;
129*9e3b08aeSAndroid Build Coastguard Worker }
130*9e3b08aeSAndroid Build Coastguard Worker 
131*9e3b08aeSAndroid Build Coastguard Worker }  // namespace
132*9e3b08aeSAndroid Build Coastguard Worker 
GetCompilationUnits(Dwarf & dwarf)133*9e3b08aeSAndroid Build Coastguard Worker std::vector<CompilationUnit> GetCompilationUnits(Dwarf& dwarf) {
134*9e3b08aeSAndroid Build Coastguard Worker   std::vector<CompilationUnit> result;
135*9e3b08aeSAndroid Build Coastguard Worker   Dwarf_Off offset = 0;
136*9e3b08aeSAndroid Build Coastguard Worker   while (true) {
137*9e3b08aeSAndroid Build Coastguard Worker     Dwarf_Off next_offset;
138*9e3b08aeSAndroid Build Coastguard Worker     size_t header_size = 0;
139*9e3b08aeSAndroid Build Coastguard Worker     Dwarf_Half version = 0;
140*9e3b08aeSAndroid Build Coastguard Worker     const int return_code =
141*9e3b08aeSAndroid Build Coastguard Worker         dwarf_next_unit(&dwarf, offset, &next_offset, &header_size, &version,
142*9e3b08aeSAndroid Build Coastguard Worker                         nullptr, nullptr, nullptr, nullptr, nullptr);
143*9e3b08aeSAndroid Build Coastguard Worker     Check(return_code == kReturnOk || return_code == kReturnNoEntry)
144*9e3b08aeSAndroid Build Coastguard Worker         << "dwarf_next_unit returned error";
145*9e3b08aeSAndroid Build Coastguard Worker     if (return_code == kReturnNoEntry) {
146*9e3b08aeSAndroid Build Coastguard Worker       break;
147*9e3b08aeSAndroid Build Coastguard Worker     }
148*9e3b08aeSAndroid Build Coastguard Worker     result.push_back({version, {}});
149*9e3b08aeSAndroid Build Coastguard Worker     Check(dwarf_offdie(&dwarf, offset + header_size,
150*9e3b08aeSAndroid Build Coastguard Worker                        &result.back().entry.die) != nullptr)
151*9e3b08aeSAndroid Build Coastguard Worker         << "dwarf_offdie returned error";
152*9e3b08aeSAndroid Build Coastguard Worker 
153*9e3b08aeSAndroid Build Coastguard Worker     offset = next_offset;
154*9e3b08aeSAndroid Build Coastguard Worker   }
155*9e3b08aeSAndroid Build Coastguard Worker   return result;
156*9e3b08aeSAndroid Build Coastguard Worker }
157*9e3b08aeSAndroid Build Coastguard Worker 
GetChildren()158*9e3b08aeSAndroid Build Coastguard Worker std::vector<Entry> Entry::GetChildren() {
159*9e3b08aeSAndroid Build Coastguard Worker   Entry child;
160*9e3b08aeSAndroid Build Coastguard Worker   int return_code = dwarf_child(&die, &child.die);
161*9e3b08aeSAndroid Build Coastguard Worker   Check(return_code == kReturnOk || return_code == kReturnNoEntry)
162*9e3b08aeSAndroid Build Coastguard Worker       << "dwarf_child returned error";
163*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Entry> result;
164*9e3b08aeSAndroid Build Coastguard Worker   while (return_code == kReturnOk) {
165*9e3b08aeSAndroid Build Coastguard Worker     result.push_back(child);
166*9e3b08aeSAndroid Build Coastguard Worker     return_code = dwarf_siblingof(&child.die, &child.die);
167*9e3b08aeSAndroid Build Coastguard Worker     Check(return_code == kReturnOk || return_code == kReturnNoEntry)
168*9e3b08aeSAndroid Build Coastguard Worker         << "dwarf_siblingof returned error";
169*9e3b08aeSAndroid Build Coastguard Worker   }
170*9e3b08aeSAndroid Build Coastguard Worker   return result;
171*9e3b08aeSAndroid Build Coastguard Worker }
172*9e3b08aeSAndroid Build Coastguard Worker 
GetTag()173*9e3b08aeSAndroid Build Coastguard Worker int Entry::GetTag() {
174*9e3b08aeSAndroid Build Coastguard Worker   return dwarf_tag(&die);
175*9e3b08aeSAndroid Build Coastguard Worker }
176*9e3b08aeSAndroid Build Coastguard Worker 
GetOffset()177*9e3b08aeSAndroid Build Coastguard Worker Dwarf_Off Entry::GetOffset() {
178*9e3b08aeSAndroid Build Coastguard Worker   return dwarf_dieoffset(&die);
179*9e3b08aeSAndroid Build Coastguard Worker }
180*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetString(uint32_t attribute)181*9e3b08aeSAndroid Build Coastguard Worker std::optional<std::string> Entry::MaybeGetString(uint32_t attribute) {
182*9e3b08aeSAndroid Build Coastguard Worker   std::optional<std::string> result;
183*9e3b08aeSAndroid Build Coastguard Worker   auto dwarf_attribute = GetAttribute(&die, attribute);
184*9e3b08aeSAndroid Build Coastguard Worker   if (!dwarf_attribute) {
185*9e3b08aeSAndroid Build Coastguard Worker     return result;
186*9e3b08aeSAndroid Build Coastguard Worker   }
187*9e3b08aeSAndroid Build Coastguard Worker 
188*9e3b08aeSAndroid Build Coastguard Worker   const char* value = dwarf_formstring(&dwarf_attribute.value());
189*9e3b08aeSAndroid Build Coastguard Worker   Check(value != nullptr) << "dwarf_formstring returned error";
190*9e3b08aeSAndroid Build Coastguard Worker   result.emplace(value);
191*9e3b08aeSAndroid Build Coastguard Worker   return result;
192*9e3b08aeSAndroid Build Coastguard Worker }
193*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetDirectString(uint32_t attribute)194*9e3b08aeSAndroid Build Coastguard Worker std::optional<std::string> Entry::MaybeGetDirectString(uint32_t attribute) {
195*9e3b08aeSAndroid Build Coastguard Worker   std::optional<std::string> result;
196*9e3b08aeSAndroid Build Coastguard Worker   auto dwarf_attribute = GetDirectAttribute(&die, attribute);
197*9e3b08aeSAndroid Build Coastguard Worker   if (!dwarf_attribute) {
198*9e3b08aeSAndroid Build Coastguard Worker     return result;
199*9e3b08aeSAndroid Build Coastguard Worker   }
200*9e3b08aeSAndroid Build Coastguard Worker 
201*9e3b08aeSAndroid Build Coastguard Worker   const char* value = dwarf_formstring(&dwarf_attribute.value());
202*9e3b08aeSAndroid Build Coastguard Worker   Check(value != nullptr) << "dwarf_formstring returned error";
203*9e3b08aeSAndroid Build Coastguard Worker   result.emplace(value);
204*9e3b08aeSAndroid Build Coastguard Worker   return result;
205*9e3b08aeSAndroid Build Coastguard Worker }
206*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetUnsignedConstant(uint32_t attribute)207*9e3b08aeSAndroid Build Coastguard Worker std::optional<uint64_t> Entry::MaybeGetUnsignedConstant(uint32_t attribute) {
208*9e3b08aeSAndroid Build Coastguard Worker   auto dwarf_attribute = GetAttribute(&die, attribute);
209*9e3b08aeSAndroid Build Coastguard Worker   if (!dwarf_attribute) {
210*9e3b08aeSAndroid Build Coastguard Worker     return {};
211*9e3b08aeSAndroid Build Coastguard Worker   }
212*9e3b08aeSAndroid Build Coastguard Worker 
213*9e3b08aeSAndroid Build Coastguard Worker   uint64_t value;
214*9e3b08aeSAndroid Build Coastguard Worker   if (dwarf_formudata(&dwarf_attribute.value(), &value) != kReturnOk) {
215*9e3b08aeSAndroid Build Coastguard Worker     Die() << "dwarf_formudata returned error";
216*9e3b08aeSAndroid Build Coastguard Worker   }
217*9e3b08aeSAndroid Build Coastguard Worker   return value;
218*9e3b08aeSAndroid Build Coastguard Worker }
219*9e3b08aeSAndroid Build Coastguard Worker 
MustGetUnsignedConstant(uint32_t attribute)220*9e3b08aeSAndroid Build Coastguard Worker uint64_t Entry::MustGetUnsignedConstant(uint32_t attribute) {
221*9e3b08aeSAndroid Build Coastguard Worker   auto maybe_constant = MaybeGetUnsignedConstant(attribute);
222*9e3b08aeSAndroid Build Coastguard Worker   if (!maybe_constant) {
223*9e3b08aeSAndroid Build Coastguard Worker     Die() << "DWARF entry <" << Hex(GetOffset()) << "> with tag " << GetTag()
224*9e3b08aeSAndroid Build Coastguard Worker           << " is missing attribute " << Hex(attribute);
225*9e3b08aeSAndroid Build Coastguard Worker   }
226*9e3b08aeSAndroid Build Coastguard Worker   return maybe_constant.value();
227*9e3b08aeSAndroid Build Coastguard Worker }
228*9e3b08aeSAndroid Build Coastguard Worker 
GetFlag(uint32_t attribute)229*9e3b08aeSAndroid Build Coastguard Worker bool Entry::GetFlag(uint32_t attribute) {
230*9e3b08aeSAndroid Build Coastguard Worker   bool result = false;
231*9e3b08aeSAndroid Build Coastguard Worker   auto dwarf_attribute = (attribute == DW_AT_declaration)
232*9e3b08aeSAndroid Build Coastguard Worker                              ? GetDirectAttribute(&die, attribute)
233*9e3b08aeSAndroid Build Coastguard Worker                              : GetAttribute(&die, attribute);
234*9e3b08aeSAndroid Build Coastguard Worker   if (!dwarf_attribute) {
235*9e3b08aeSAndroid Build Coastguard Worker     return result;
236*9e3b08aeSAndroid Build Coastguard Worker   }
237*9e3b08aeSAndroid Build Coastguard Worker 
238*9e3b08aeSAndroid Build Coastguard Worker   Check(dwarf_formflag(&dwarf_attribute.value(), &result) == kReturnOk)
239*9e3b08aeSAndroid Build Coastguard Worker       << "dwarf_formflag returned error";
240*9e3b08aeSAndroid Build Coastguard Worker   return result;
241*9e3b08aeSAndroid Build Coastguard Worker }
242*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetReference(uint32_t attribute)243*9e3b08aeSAndroid Build Coastguard Worker std::optional<Entry> Entry::MaybeGetReference(uint32_t attribute) {
244*9e3b08aeSAndroid Build Coastguard Worker   std::optional<Entry> result;
245*9e3b08aeSAndroid Build Coastguard Worker   auto dwarf_attribute = GetAttribute(&die, attribute);
246*9e3b08aeSAndroid Build Coastguard Worker   if (!dwarf_attribute) {
247*9e3b08aeSAndroid Build Coastguard Worker     return result;
248*9e3b08aeSAndroid Build Coastguard Worker   }
249*9e3b08aeSAndroid Build Coastguard Worker 
250*9e3b08aeSAndroid Build Coastguard Worker   result.emplace();
251*9e3b08aeSAndroid Build Coastguard Worker   Check(dwarf_formref_die(&dwarf_attribute.value(), &result->die))
252*9e3b08aeSAndroid Build Coastguard Worker       << "dwarf_formref_die returned error";
253*9e3b08aeSAndroid Build Coastguard Worker   return result;
254*9e3b08aeSAndroid Build Coastguard Worker }
255*9e3b08aeSAndroid Build Coastguard Worker 
256*9e3b08aeSAndroid Build Coastguard Worker namespace {
257*9e3b08aeSAndroid Build Coastguard Worker 
GetAddressFromLocation(Dwarf_Attribute & attribute)258*9e3b08aeSAndroid Build Coastguard Worker std::optional<Address> GetAddressFromLocation(Dwarf_Attribute& attribute) {
259*9e3b08aeSAndroid Build Coastguard Worker   const auto expression_opt = MaybeGetExpression(attribute);
260*9e3b08aeSAndroid Build Coastguard Worker   if (!expression_opt) {
261*9e3b08aeSAndroid Build Coastguard Worker     return {};
262*9e3b08aeSAndroid Build Coastguard Worker   }
263*9e3b08aeSAndroid Build Coastguard Worker   const Expression& expression = *expression_opt;
264*9e3b08aeSAndroid Build Coastguard Worker 
265*9e3b08aeSAndroid Build Coastguard Worker   Dwarf_Attribute result_attribute;
266*9e3b08aeSAndroid Build Coastguard Worker   if (dwarf_getlocation_attr(&attribute, expression.atoms, &result_attribute) ==
267*9e3b08aeSAndroid Build Coastguard Worker       kReturnOk) {
268*9e3b08aeSAndroid Build Coastguard Worker     uint64_t address;
269*9e3b08aeSAndroid Build Coastguard Worker     Check(dwarf_formaddr(&result_attribute, &address) == kReturnOk)
270*9e3b08aeSAndroid Build Coastguard Worker         << "dwarf_formaddr returned error";
271*9e3b08aeSAndroid Build Coastguard Worker     return Address{Address::Kind::ADDRESS, address};
272*9e3b08aeSAndroid Build Coastguard Worker   }
273*9e3b08aeSAndroid Build Coastguard Worker 
274*9e3b08aeSAndroid Build Coastguard Worker   if (expression.length == 1 && expression[0].atom == DW_OP_addr) {
275*9e3b08aeSAndroid Build Coastguard Worker     // DW_OP_addr is unsupported by dwarf_getlocation_attr, so we need to
276*9e3b08aeSAndroid Build Coastguard Worker     // manually extract the address from expression.
277*9e3b08aeSAndroid Build Coastguard Worker     return Address{Address::Kind::ADDRESS, expression[0].number};
278*9e3b08aeSAndroid Build Coastguard Worker   }
279*9e3b08aeSAndroid Build Coastguard Worker   if (expression.length == 2 && expression[0].atom == DW_OP_addr &&
280*9e3b08aeSAndroid Build Coastguard Worker       expression[1].atom == DW_OP_plus_uconst) {
281*9e3b08aeSAndroid Build Coastguard Worker     // A rather odd case seen from Clang.
282*9e3b08aeSAndroid Build Coastguard Worker     return Address{Address::Kind::ADDRESS,
283*9e3b08aeSAndroid Build Coastguard Worker                    expression[0].number + expression[1].number};
284*9e3b08aeSAndroid Build Coastguard Worker   }
285*9e3b08aeSAndroid Build Coastguard Worker 
286*9e3b08aeSAndroid Build Coastguard Worker   // TLS operation has different encodings in Clang and GCC:
287*9e3b08aeSAndroid Build Coastguard Worker   // * Clang 14 uses DW_OP_GNU_push_tls_address
288*9e3b08aeSAndroid Build Coastguard Worker   // * GCC 12 uses DW_OP_form_tls_address
289*9e3b08aeSAndroid Build Coastguard Worker   if (expression.length == 2 &&
290*9e3b08aeSAndroid Build Coastguard Worker       (expression[1].atom == DW_OP_GNU_push_tls_address ||
291*9e3b08aeSAndroid Build Coastguard Worker        expression[1].atom == DW_OP_form_tls_address)) {
292*9e3b08aeSAndroid Build Coastguard Worker     // TLS symbols address may be incorrect because of unsupported
293*9e3b08aeSAndroid Build Coastguard Worker     // relocations. Resetting it to zero the same way as it is done in
294*9e3b08aeSAndroid Build Coastguard Worker     // elf::Reader::MaybeAddTypeInfo.
295*9e3b08aeSAndroid Build Coastguard Worker     // TODO: match TLS variables by address
296*9e3b08aeSAndroid Build Coastguard Worker     return Address{Address::Kind::TLS, 0};
297*9e3b08aeSAndroid Build Coastguard Worker   }
298*9e3b08aeSAndroid Build Coastguard Worker 
299*9e3b08aeSAndroid Build Coastguard Worker   Die() << "Unsupported data location expression";
300*9e3b08aeSAndroid Build Coastguard Worker }
301*9e3b08aeSAndroid Build Coastguard Worker 
302*9e3b08aeSAndroid Build Coastguard Worker }  // namespace
303*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetAddress(uint32_t attribute)304*9e3b08aeSAndroid Build Coastguard Worker std::optional<Address> Entry::MaybeGetAddress(uint32_t attribute) {
305*9e3b08aeSAndroid Build Coastguard Worker   auto dwarf_attribute = GetAttribute(&die, attribute);
306*9e3b08aeSAndroid Build Coastguard Worker   if (!dwarf_attribute) {
307*9e3b08aeSAndroid Build Coastguard Worker     return {};
308*9e3b08aeSAndroid Build Coastguard Worker   }
309*9e3b08aeSAndroid Build Coastguard Worker   if (attribute == DW_AT_location) {
310*9e3b08aeSAndroid Build Coastguard Worker     return GetAddressFromLocation(*dwarf_attribute);
311*9e3b08aeSAndroid Build Coastguard Worker   }
312*9e3b08aeSAndroid Build Coastguard Worker 
313*9e3b08aeSAndroid Build Coastguard Worker   uint64_t address;
314*9e3b08aeSAndroid Build Coastguard Worker   Check(dwarf_formaddr(&dwarf_attribute.value(), &address) == kReturnOk)
315*9e3b08aeSAndroid Build Coastguard Worker       << "dwarf_formaddr returned error";
316*9e3b08aeSAndroid Build Coastguard Worker   return Address{Address::Kind::ADDRESS, address};
317*9e3b08aeSAndroid Build Coastguard Worker }
318*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetMemberByteOffset()319*9e3b08aeSAndroid Build Coastguard Worker std::optional<uint64_t> Entry::MaybeGetMemberByteOffset() {
320*9e3b08aeSAndroid Build Coastguard Worker   auto attribute = GetAttribute(&die, DW_AT_data_member_location);
321*9e3b08aeSAndroid Build Coastguard Worker   if (!attribute) {
322*9e3b08aeSAndroid Build Coastguard Worker     return {};
323*9e3b08aeSAndroid Build Coastguard Worker   }
324*9e3b08aeSAndroid Build Coastguard Worker 
325*9e3b08aeSAndroid Build Coastguard Worker   uint64_t offset;
326*9e3b08aeSAndroid Build Coastguard Worker   // Try to interpret attribute as an unsigned integer constant
327*9e3b08aeSAndroid Build Coastguard Worker   if (dwarf_formudata(&attribute.value(), &offset) == kReturnOk) {
328*9e3b08aeSAndroid Build Coastguard Worker     return offset;
329*9e3b08aeSAndroid Build Coastguard Worker   }
330*9e3b08aeSAndroid Build Coastguard Worker 
331*9e3b08aeSAndroid Build Coastguard Worker   // Parse location expression
332*9e3b08aeSAndroid Build Coastguard Worker   const auto expression_opt = MaybeGetExpression(attribute.value());
333*9e3b08aeSAndroid Build Coastguard Worker   if (!expression_opt) {
334*9e3b08aeSAndroid Build Coastguard Worker     return {};
335*9e3b08aeSAndroid Build Coastguard Worker   }
336*9e3b08aeSAndroid Build Coastguard Worker   const Expression& expression = *expression_opt;
337*9e3b08aeSAndroid Build Coastguard Worker 
338*9e3b08aeSAndroid Build Coastguard Worker   // Parse virtual base classes offset, which looks like this:
339*9e3b08aeSAndroid Build Coastguard Worker   //   [0] = DW_OP_dup
340*9e3b08aeSAndroid Build Coastguard Worker   //   [1] = DW_OP_deref
341*9e3b08aeSAndroid Build Coastguard Worker   //   [2] = constant operand
342*9e3b08aeSAndroid Build Coastguard Worker   //   [3] = DW_OP_minus
343*9e3b08aeSAndroid Build Coastguard Worker   //   [4] = DW_OP_deref
344*9e3b08aeSAndroid Build Coastguard Worker   //   [5] = DW_OP_plus
345*9e3b08aeSAndroid Build Coastguard Worker   // This form is not in the standard, but hardcoded in compilers:
346*9e3b08aeSAndroid Build Coastguard Worker   //   * https://github.com/llvm/llvm-project/blob/release/17.x/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp#L1611
347*9e3b08aeSAndroid Build Coastguard Worker   //   * https://github.com/gcc-mirror/gcc/blob/releases/gcc-13/gcc/dwarf2out.cc#L20029
348*9e3b08aeSAndroid Build Coastguard Worker   if (expression.length == 6 &&
349*9e3b08aeSAndroid Build Coastguard Worker       expression[0].atom == DW_OP_dup &&
350*9e3b08aeSAndroid Build Coastguard Worker       expression[1].atom == DW_OP_deref &&
351*9e3b08aeSAndroid Build Coastguard Worker       expression[3].atom == DW_OP_minus &&
352*9e3b08aeSAndroid Build Coastguard Worker       expression[4].atom == DW_OP_deref &&
353*9e3b08aeSAndroid Build Coastguard Worker       expression[5].atom == DW_OP_plus) {
354*9e3b08aeSAndroid Build Coastguard Worker     const auto byte_offset = MaybeGetUnsignedOperand(expression[2]);
355*9e3b08aeSAndroid Build Coastguard Worker     if (byte_offset) {
356*9e3b08aeSAndroid Build Coastguard Worker       return byte_offset;
357*9e3b08aeSAndroid Build Coastguard Worker     }
358*9e3b08aeSAndroid Build Coastguard Worker   }
359*9e3b08aeSAndroid Build Coastguard Worker 
360*9e3b08aeSAndroid Build Coastguard Worker   Die() << "Unsupported member offset expression, " << Hex(GetOffset());
361*9e3b08aeSAndroid Build Coastguard Worker }
362*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetVtableOffset()363*9e3b08aeSAndroid Build Coastguard Worker std::optional<uint64_t> Entry::MaybeGetVtableOffset() {
364*9e3b08aeSAndroid Build Coastguard Worker   auto attribute = GetAttribute(&die, DW_AT_vtable_elem_location);
365*9e3b08aeSAndroid Build Coastguard Worker   if (!attribute) {
366*9e3b08aeSAndroid Build Coastguard Worker     return {};
367*9e3b08aeSAndroid Build Coastguard Worker   }
368*9e3b08aeSAndroid Build Coastguard Worker 
369*9e3b08aeSAndroid Build Coastguard Worker   // Parse location expression
370*9e3b08aeSAndroid Build Coastguard Worker   const auto expression_opt = MaybeGetExpression(attribute.value());
371*9e3b08aeSAndroid Build Coastguard Worker   if (!expression_opt) {
372*9e3b08aeSAndroid Build Coastguard Worker     return {};
373*9e3b08aeSAndroid Build Coastguard Worker   }
374*9e3b08aeSAndroid Build Coastguard Worker   const Expression& expression = *expression_opt;
375*9e3b08aeSAndroid Build Coastguard Worker 
376*9e3b08aeSAndroid Build Coastguard Worker   // We expect compilers to produce expression with one constant operand
377*9e3b08aeSAndroid Build Coastguard Worker   if (expression.length == 1) {
378*9e3b08aeSAndroid Build Coastguard Worker     const auto offset = MaybeGetUnsignedOperand(expression[0]);
379*9e3b08aeSAndroid Build Coastguard Worker     if (offset) {
380*9e3b08aeSAndroid Build Coastguard Worker       return offset;
381*9e3b08aeSAndroid Build Coastguard Worker     }
382*9e3b08aeSAndroid Build Coastguard Worker   }
383*9e3b08aeSAndroid Build Coastguard Worker 
384*9e3b08aeSAndroid Build Coastguard Worker   Die() << "Unsupported vtable offset expression, " << Hex(GetOffset());
385*9e3b08aeSAndroid Build Coastguard Worker }
386*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetCount()387*9e3b08aeSAndroid Build Coastguard Worker std::optional<uint64_t> Entry::MaybeGetCount() {
388*9e3b08aeSAndroid Build Coastguard Worker   auto lower_bound_attribute = MaybeGetUnsignedConstant(DW_AT_lower_bound);
389*9e3b08aeSAndroid Build Coastguard Worker   if (lower_bound_attribute && *lower_bound_attribute != 0) {
390*9e3b08aeSAndroid Build Coastguard Worker     Die() << "Non-zero DW_AT_lower_bound is not supported";
391*9e3b08aeSAndroid Build Coastguard Worker   }
392*9e3b08aeSAndroid Build Coastguard Worker   auto upper_bound_attribute = GetAttribute(&die, DW_AT_upper_bound);
393*9e3b08aeSAndroid Build Coastguard Worker   auto count_attribute = GetAttribute(&die, DW_AT_count);
394*9e3b08aeSAndroid Build Coastguard Worker   if (!upper_bound_attribute && !count_attribute) {
395*9e3b08aeSAndroid Build Coastguard Worker     return {};
396*9e3b08aeSAndroid Build Coastguard Worker   }
397*9e3b08aeSAndroid Build Coastguard Worker   if (upper_bound_attribute && count_attribute) {
398*9e3b08aeSAndroid Build Coastguard Worker     Die() << "Both DW_AT_upper_bound and DW_AT_count given";
399*9e3b08aeSAndroid Build Coastguard Worker   }
400*9e3b08aeSAndroid Build Coastguard Worker   Dwarf_Attribute dwarf_attribute;
401*9e3b08aeSAndroid Build Coastguard Worker   uint64_t addend;
402*9e3b08aeSAndroid Build Coastguard Worker   if (upper_bound_attribute) {
403*9e3b08aeSAndroid Build Coastguard Worker     dwarf_attribute = *upper_bound_attribute;
404*9e3b08aeSAndroid Build Coastguard Worker     addend = 1;
405*9e3b08aeSAndroid Build Coastguard Worker   } else {
406*9e3b08aeSAndroid Build Coastguard Worker     dwarf_attribute = *count_attribute;
407*9e3b08aeSAndroid Build Coastguard Worker     addend = 0;
408*9e3b08aeSAndroid Build Coastguard Worker   }
409*9e3b08aeSAndroid Build Coastguard Worker 
410*9e3b08aeSAndroid Build Coastguard Worker   uint64_t value;
411*9e3b08aeSAndroid Build Coastguard Worker   if (dwarf_formudata(&dwarf_attribute, &value) == kReturnOk) {
412*9e3b08aeSAndroid Build Coastguard Worker     return value + addend;
413*9e3b08aeSAndroid Build Coastguard Worker   }
414*9e3b08aeSAndroid Build Coastguard Worker 
415*9e3b08aeSAndroid Build Coastguard Worker   // Don't fail if attribute is not a constant and treat this as no count
416*9e3b08aeSAndroid Build Coastguard Worker   // provided. This can happen if array has variable length.
417*9e3b08aeSAndroid Build Coastguard Worker   // TODO: implement clean solution for separating "not a
418*9e3b08aeSAndroid Build Coastguard Worker   // constant" errors from other errors.
419*9e3b08aeSAndroid Build Coastguard Worker   return {};
420*9e3b08aeSAndroid Build Coastguard Worker }
421*9e3b08aeSAndroid Build Coastguard Worker 
Files(Entry & compilation_unit)422*9e3b08aeSAndroid Build Coastguard Worker Files::Files(Entry& compilation_unit) {
423*9e3b08aeSAndroid Build Coastguard Worker   if (dwarf_getsrcfiles(&compilation_unit.die, &files_, &files_count_) !=
424*9e3b08aeSAndroid Build Coastguard Worker       kReturnOk) {
425*9e3b08aeSAndroid Build Coastguard Worker     Die() << "No source file information in DWARF";
426*9e3b08aeSAndroid Build Coastguard Worker   }
427*9e3b08aeSAndroid Build Coastguard Worker }
428*9e3b08aeSAndroid Build Coastguard Worker 
MaybeGetFile(Entry & entry,uint32_t attribute) const429*9e3b08aeSAndroid Build Coastguard Worker std::optional<std::string> Files::MaybeGetFile(Entry& entry,
430*9e3b08aeSAndroid Build Coastguard Worker                                                uint32_t attribute) const {
431*9e3b08aeSAndroid Build Coastguard Worker   auto file_index = entry.MaybeGetUnsignedConstant(attribute);
432*9e3b08aeSAndroid Build Coastguard Worker   if (!file_index) {
433*9e3b08aeSAndroid Build Coastguard Worker     return std::nullopt;
434*9e3b08aeSAndroid Build Coastguard Worker   }
435*9e3b08aeSAndroid Build Coastguard Worker   Check(files_ != nullptr) << "dwarf::Files was not initialised";
436*9e3b08aeSAndroid Build Coastguard Worker   if (*file_index >= files_count_) {
437*9e3b08aeSAndroid Build Coastguard Worker     Die() << "File index is greater than or equal files count (" << *file_index
438*9e3b08aeSAndroid Build Coastguard Worker           << " >= " << files_count_ << ")";
439*9e3b08aeSAndroid Build Coastguard Worker   }
440*9e3b08aeSAndroid Build Coastguard Worker   const char* result = dwarf_filesrc(files_, *file_index, nullptr, nullptr);
441*9e3b08aeSAndroid Build Coastguard Worker   Check(result != nullptr) << "dwarf_filesrc returned error";
442*9e3b08aeSAndroid Build Coastguard Worker   return result;
443*9e3b08aeSAndroid Build Coastguard Worker }
444*9e3b08aeSAndroid Build Coastguard Worker 
445*9e3b08aeSAndroid Build Coastguard Worker }  // namespace dwarf
446*9e3b08aeSAndroid Build Coastguard Worker }  // namespace stg
447