• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <elf.h>
24 #include <elfutils/libdw.h>
25 #include <elfutils/libdwfl.h>
26 
27 #include <cstddef>
28 #include <cstdint>
29 #include <memory>
30 #include <optional>
31 #include <ostream>
32 #include <string>
33 #include <tuple>
34 #include <vector>
35 
36 namespace stg {
37 namespace dwarf {
38 
39 struct Address {
40   // TODO: use auto operator<=>
41   bool operator<(const Address& other) const {
42     return std::tie(value, is_tls) < std::tie(other.value, other.is_tls);
43   }
44 
45   bool operator==(const Address& other) const {
46     return value == other.value && is_tls == other.is_tls;
47   }
48 
49   uint64_t value;
50   bool is_tls;
51 };
52 
53 std::ostream& operator<<(std::ostream& os, const Address& address);
54 
55 // C++ wrapper over Dwarf_Die, providing interface for its various properties.
56 struct Entry {
57   // All methods in libdw take Dwarf_Die by non-const pointer as libdw caches
58   // in it a link to the associated abbreviation table. Updating this link is
59   // not thread-safe and so we cannot, for example, hold a std::shared_ptr to a
60   // heap-allocated Dwarf_Die.
61   //
62   // The only options left are holding a std::unique_ptr or storing a value.
63   // Unique pointers will add one more level of indirection to a hot path.
64   // So we choose to store Dwarf_Die values.
65   //
66   // Each Entry only contains references to DWARF file memory and is fairly
67   // small (32 bytes), so copies can be easily made if necessary. However,
68   // within one thread it is preferable to pass it by reference.
69   Dwarf_Die die{};
70 
71   // Get list of direct descendants of an entry in the DWARF tree.
72   std::vector<Entry> GetChildren();
73 
74   // All getters are non-const as libdw may need to modify Dwarf_Die.
75   int GetTag();
76   Dwarf_Off GetOffset();
77   std::optional<std::string> MaybeGetString(uint32_t attribute);
78   std::optional<std::string> MaybeGetDirectString(uint32_t attribute);
79   std::optional<uint64_t> MaybeGetUnsignedConstant(uint32_t attribute);
80   uint64_t MustGetUnsignedConstant(uint32_t attribute);
81   bool GetFlag(uint32_t attribute);
82   std::optional<Entry> MaybeGetReference(uint32_t attribute);
83   std::optional<Address> MaybeGetAddress(uint32_t attribute);
84   std::optional<uint64_t> MaybeGetMemberByteOffset();
85   std::optional<uint64_t> MaybeGetVtableOffset();
86   // Returns value of subrange element count if it is constant or nullopt if it
87   // is not defined or cannot be represented as constant.
88   std::optional<uint64_t> MaybeGetCount();
89 };
90 
91 // Metadata and top-level entry of a compilation unit.
92 struct CompilationUnit {
93   int version;
94   Entry entry;
95 };
96 
97 // C++ wrapper over libdw (DWARF library).
98 //
99 // Creates a "Dwarf" object from an ELF file or a memory and controls the life
100 // cycle of the created objects.
101 class Handler {
102  public:
103   explicit Handler(const std::string& path);
104   Handler(char* data, size_t size);
105 
106   Elf* GetElf();
107   std::vector<CompilationUnit> GetCompilationUnits();
108 
109  private:
110   struct DwflDeleter {
operatorDwflDeleter111     void operator()(Dwfl* dwfl) {
112       dwfl_end(dwfl);
113     }
114   };
115 
116   void InitialiseDwarf();
117 
118   std::unique_ptr<Dwfl, DwflDeleter> dwfl_;
119   // Lifetime of Dwfl_Module and Dwarf is controlled by Dwfl.
120   Dwfl_Module* dwfl_module_ = nullptr;
121   Dwarf* dwarf_ = nullptr;
122 };
123 
124 class Files {
125  public:
126   Files() = default;
127   explicit Files(Entry& compilation_unit);
128   std::optional<std::string> MaybeGetFile(Entry& entry,
129                                           uint32_t attribute) const;
130 
131  private:
132   Dwarf_Files* files_ = nullptr;
133   size_t files_count_ = 0;
134 };
135 
136 }  // namespace dwarf
137 }  // namespace stg
138 
139 #endif  // STG_DWARF_WRAPPERS_H_
140