aboutsummaryrefslogtreecommitdiff
path: root/dwarf_wrappers.h
blob: 172489a30e584086842c23c629222c073fd2780e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright 2022 Google LLC
//
// Licensed under the Apache License v2.0 with LLVM Exceptions (the
// "License"); you may not use this file except in compliance with the
// License.  You may obtain a copy of the License at
//
//     https://llvm.org/LICENSE.txt
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Aleksei Vetrov

#ifndef STG_DWARF_WRAPPERS_H_
#define STG_DWARF_WRAPPERS_H_

#include <elf.h>
#include <elfutils/libdw.h>
#include <elfutils/libdwfl.h>

#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <ostream>
#include <string>
#include <tuple>
#include <vector>

namespace stg {
namespace dwarf {

struct Address {
  // TODO: use auto operator<=>
  bool operator<(const Address& other) const {
    return std::tie(value, is_tls) < std::tie(other.value, other.is_tls);
  }

  bool operator==(const Address& other) const {
    return value == other.value && is_tls == other.is_tls;
  }

  uint64_t value;
  bool is_tls;
};

std::ostream& operator<<(std::ostream& os, const Address& address);

// C++ wrapper over Dwarf_Die, providing interface for its various properties.
struct Entry {
  // All methods in libdw take Dwarf_Die by non-const pointer as libdw caches
  // in it a link to the associated abbreviation table. Updating this link is
  // not thread-safe and so we cannot, for example, hold a std::shared_ptr to a
  // heap-allocated Dwarf_Die.
  //
  // The only options left are holding a std::unique_ptr or storing a value.
  // Unique pointers will add one more level of indirection to a hot path.
  // So we choose to store Dwarf_Die values.
  //
  // Each Entry only contains references to DWARF file memory and is fairly
  // small (32 bytes), so copies can be easily made if necessary. However,
  // within one thread it is preferable to pass it by reference.
  Dwarf_Die die{};

  // Get list of direct descendants of an entry in the DWARF tree.
  std::vector<Entry> GetChildren();

  // All getters are non-const as libdw may need to modify Dwarf_Die.
  int GetTag();
  Dwarf_Off GetOffset();
  std::optional<std::string> MaybeGetString(uint32_t attribute);
  std::optional<std::string> MaybeGetDirectString(uint32_t attribute);
  std::optional<uint64_t> MaybeGetUnsignedConstant(uint32_t attribute);
  uint64_t MustGetUnsignedConstant(uint32_t attribute);
  bool GetFlag(uint32_t attribute);
  std::optional<Entry> MaybeGetReference(uint32_t attribute);
  std::optional<Address> MaybeGetAddress(uint32_t attribute);
  std::optional<uint64_t> MaybeGetMemberByteOffset();
  std::optional<uint64_t> MaybeGetVtableOffset();
  // Returns value of subrange element count if it is constant or nullopt if it
  // is not defined or cannot be represented as constant.
  std::optional<uint64_t> MaybeGetCount();
};

// Metadata and top-level entry of a compilation unit.
struct CompilationUnit {
  int version;
  Entry entry;
};

// C++ wrapper over libdw (DWARF library).
//
// Creates a "Dwarf" object from an ELF file or a memory and controls the life
// cycle of the created objects.
class Handler {
 public:
  explicit Handler(const std::string& path);
  Handler(char* data, size_t size);

  Elf* GetElf();
  std::vector<CompilationUnit> GetCompilationUnits();

 private:
  struct DwflDeleter {
    void operator()(Dwfl* dwfl) {
      dwfl_end(dwfl);
    }
  };

  void InitialiseDwarf();

  std::unique_ptr<Dwfl, DwflDeleter> dwfl_;
  // Lifetime of Dwfl_Module and Dwarf is controlled by Dwfl.
  Dwfl_Module* dwfl_module_ = nullptr;
  Dwarf* dwarf_ = nullptr;
};

class Files {
 public:
  Files() = default;
  explicit Files(Entry& compilation_unit);
  std::optional<std::string> MaybeGetFile(Entry& entry,
                                          uint32_t attribute) const;

 private:
  Dwarf_Files* files_ = nullptr;
  size_t files_count_ = 0;
};

}  // namespace dwarf
}  // namespace stg

#endif  // STG_DWARF_WRAPPERS_H_