xref: /aosp_15_r20/external/stg/dwarf_wrappers.h (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright 2022 Google LLC
5 //
6 // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7 // "License"); you may not use this file except in compliance with the
8 // License.  You may obtain a copy of the License at
9 //
10 //     https://llvm.org/LICENSE.txt
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
18 // Author: Aleksei Vetrov
19 
20 #ifndef STG_DWARF_WRAPPERS_H_
21 #define STG_DWARF_WRAPPERS_H_
22 
23 #include <elfutils/libdw.h>
24 
25 #include <cstddef>
26 #include <cstdint>
27 #include <optional>
28 #include <ostream>
29 #include <string>
30 #include <vector>
31 
32 namespace stg {
33 namespace dwarf {
34 
35 struct Address {
36   // ADDRESS - relocated, section-relative offset
37   // TLS - broken (elfutils bug), TLS-relative offset
38   //       TODO: match TLS variables by address
39   enum class Kind { ADDRESS, TLS };
40 
AddressAddress41   Address(Kind kind, uint64_t value) : kind(kind), value(value) {}
42   auto operator<=>(const Address&) const = default;
43 
44   Kind kind;
45   uint64_t value;
46 };
47 
48 std::ostream& operator<<(std::ostream& os, const Address& address);
49 
50 // C++ wrapper over Dwarf_Die, providing interface for its various properties.
51 struct Entry {
52   // All methods in libdw take Dwarf_Die by non-const pointer as libdw caches
53   // in it a link to the associated abbreviation table. Updating this link is
54   // not thread-safe and so we cannot, for example, hold a std::shared_ptr to a
55   // heap-allocated Dwarf_Die.
56   //
57   // The only options left are holding a std::unique_ptr or storing a value.
58   // Unique pointers will add one more level of indirection to a hot path.
59   // So we choose to store Dwarf_Die values.
60   //
61   // Each Entry only contains references to DWARF file memory and is fairly
62   // small (32 bytes), so copies can be easily made if necessary. However,
63   // within one thread it is preferable to pass it by reference.
64   Dwarf_Die die{};
65 
66   // Get list of direct descendants of an entry in the DWARF tree.
67   std::vector<Entry> GetChildren();
68 
69   // All getters are non-const as libdw may need to modify Dwarf_Die.
70   int GetTag();
71   Dwarf_Off GetOffset();
72   std::optional<std::string> MaybeGetString(uint32_t attribute);
73   std::optional<std::string> MaybeGetDirectString(uint32_t attribute);
74   std::optional<uint64_t> MaybeGetUnsignedConstant(uint32_t attribute);
75   uint64_t MustGetUnsignedConstant(uint32_t attribute);
76   bool GetFlag(uint32_t attribute);
77   std::optional<Entry> MaybeGetReference(uint32_t attribute);
78   std::optional<Address> MaybeGetAddress(uint32_t attribute);
79   std::optional<uint64_t> MaybeGetMemberByteOffset();
80   std::optional<uint64_t> MaybeGetVtableOffset();
81   // Returns value of subrange element count if it is constant or nullopt if it
82   // is not defined or cannot be represented as constant.
83   std::optional<uint64_t> MaybeGetCount();
84 };
85 
86 // Metadata and top-level entry of a compilation unit.
87 struct CompilationUnit {
88   int version;
89   Entry entry;
90 };
91 
92 std::vector<CompilationUnit> GetCompilationUnits(Dwarf& dwarf);
93 
94 class Files {
95  public:
96   Files() = default;
97   explicit Files(Entry& compilation_unit);
98   std::optional<std::string> MaybeGetFile(Entry& entry,
99                                           uint32_t attribute) const;
100 
101  private:
102   Dwarf_Files* files_ = nullptr;
103   size_t files_count_ = 0;
104 };
105 
106 }  // namespace dwarf
107 }  // namespace stg
108 
109 #endif  // STG_DWARF_WRAPPERS_H_
110