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