• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ahueck / llvm-dimeta / 19598509829

22 Nov 2025 04:57PM UTC coverage: 73.626% (-9.7%) from 83.355%
19598509829

push

github

web-flow
Merge PR #48 from ahueck/devel

1746 of 2973 branches covered (58.73%)

Branch coverage included in aggregate %.

207 of 213 new or added lines in 8 files covered. (97.18%)

54 existing lines in 5 files now uncovered.

2232 of 2430 relevant lines covered (91.85%)

8946.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.37
/lib/type/DIUtil.cpp
1
//  llvm-dimeta library
2
//  Copyright (c) 2022-2025 llvm-dimeta authors
3
//  Distributed under the BSD 3-Clause license.
4
//  (See accompanying file LICENSE)
5
//  SPDX-License-Identifier: BSD-3-Clause
6
//
7

8
#include "DIUtil.h"
9

10
#include "DIVisitor.h"
11
#include "support/Logger.h"
12

13
#include "llvm/IR/DebugInfoMetadata.h"
14
#include "llvm/IR/Metadata.h"
15

16
#include <llvm/BinaryFormat/Dwarf.h>
17
#include <optional>
18

19
namespace dimeta::di::util {
20

21
namespace printer {
22

23
class DIPrinter : public visitor::DINodeVisitor<DIPrinter> {
24
 private:
25
  llvm::raw_ostream& outp_;
26
  std::optional<const llvm::Module*> module_;
27

28
  std::string no_pointer_str(const llvm::Metadata& type) {
88✔
29
    std::string view;
88✔
30
    llvm::raw_string_ostream rso(view);
88!
31
    type.print(rso, module_.value_or(nullptr));
88!
32

33
    if (module_) {
88!
34
      return rso.str();
88!
35
    }
36
    const llvm::StringRef ref(rso.str());
×
37
    const auto a_pos = ref.find("=");
×
38
    if (a_pos == llvm::StringRef::npos || (a_pos + 2) > ref.size()) {
×
39
      return ref.str();
×
40
    }
41

42
    return std::string{ref.substr(a_pos + 2)};
×
43
  }
88✔
44

45
  [[nodiscard]] unsigned width() const {
88✔
46
    return depth() == 1 ? 0 : depth();
88✔
47
  }
48

49
 public:
50
  explicit DIPrinter(llvm::raw_ostream& outp, const llvm::Module* mod = nullptr) : outp_(outp), module_(mod) {
11✔
51
  }
11✔
52

53
  bool visitVariable(const llvm::DIVariable* var) {
11✔
54
    outp_ << llvm::left_justify("", width()) << no_pointer_str(*var) << "\n";
11!
55
    return true;
11✔
UNCOV
56
  }
×
57

58
  bool visitNode(const llvm::DINode* var) {
×
59
    outp_ << llvm::left_justify("", width() + 3) << no_pointer_str(*var) << "\n";
×
60
    return true;
×
UNCOV
61
  }
×
62

63
  bool visitBasicType(const llvm::DIBasicType* basic_type) {
×
64
    outp_ << llvm::left_justify("", width() + 3) << no_pointer_str(*basic_type) << "\n";
×
65
    return true;
×
UNCOV
66
  }
×
67

68
  bool visitDerivedType(const llvm::DIDerivedType* derived_type) {
44✔
69
    outp_ << llvm::left_justify("", width()) << no_pointer_str(*derived_type) << "\n";
44!
70
    return true;
44✔
UNCOV
71
  }
×
72

73
  bool visitCompositeType(const llvm::DICompositeType* composite_type) {
22✔
74
    outp_ << llvm::left_justify("", width()) << no_pointer_str(*composite_type) << "\n";
22!
75
    return true;
22✔
UNCOV
76
  }
×
77

78
  bool visitRecurringCompositeType(const llvm::DICompositeType* composite_type) {
11✔
79
    outp_ << llvm::left_justify("", width()) << "**" << no_pointer_str(*composite_type) << "\n";
11!
80
    return true;
11✔
UNCOV
81
  }
×
82
};
83

84
}  // namespace printer
85

86
void print_dinode(llvm::DINode* node, llvm::raw_ostream& outs, llvm::Module* module) {
11✔
87
  printer::DIPrinter printer{outs, module};
11✔
88
  assert((llvm::isa<llvm::DIVariable>(node) || llvm::isa<llvm::DIType>(node)) && "Can only print variable or type");
22!
89
  printer.traverseNode(node);
11!
90
}
11✔
91

92
struct DestructureComposite : visitor::DINodeVisitor<DestructureComposite> {
93
  explicit DestructureComposite(const size_t index) : byte_index_{index} {
660✔
94
  }
660✔
95

96
  [[nodiscard]] std::optional<StructMember> result() const {
660✔
97
    return this->outermost_candidate_;
660✔
98
  }
164✔
99

100
  bool visitCompositeType(const llvm::DICompositeType* composite) const {
1,594✔
101
    LOG_DEBUG("visitCompositeType: " << log::ditype_str(composite) << ": " << composite->getName()
102
                                     << " index: " << byte_index_ << " offset base: " << this->offset_base_);
103
    return true;
1,594✔
104
  }
105

106
  bool visitDerivedType(const llvm::DIDerivedType* derived_ty) {
4,698✔
107
    if (derived_ty->getTag() != llvm::dwarf::DW_TAG_member) {
4,698✔
108
      return true;
1,480✔
109
    }
110
    // assert(derived_ty->getTag() == llvm::dwarf::DW_TAG_member && "Expected member element in composite ty");
111
    LOG_DEBUG("looking @ member: " << derived_ty->getName() << " offset: " << derived_ty->getOffsetInBits() / 8
112
                                   << " size: " << derived_ty->getSizeInBits() / 8);
113

114
    const auto deriv_offset = (derived_ty->getOffsetInBits() / 8);
3,218✔
115
    const auto deriv_size   = (derived_ty->getSizeInBits() / 8);
3,218✔
116
    const auto offset       = this->offset_base_ + deriv_offset;
3,218✔
117
    const auto lower_bound  = offset;
3,218✔
118
    const auto upper_bound  = offset + deriv_size;
3,218✔
119

120
    if (byte_index_ >= lower_bound && byte_index_ < upper_bound) {
3,218✔
121
      auto* const member_base_type = derived_ty->getBaseType();
1,040✔
122

123
      LOG_DEBUG("saving candidate member type " << log::ditype_str(member_base_type));
124

125
      this->outermost_candidate_.emplace(StructMember{const_cast<llvm::DIDerivedType*>(derived_ty), member_base_type});
1,040✔
126

127
      if (is_pointer_like(*member_base_type) || member_base_type->getTag() == llvm::dwarf::DW_TAG_array_type) {
1,040✔
128
        LOG_DEBUG("Terminating recursion, found pointer-like "
129
                  << is_pointer_like(*member_base_type) << " or array-like "
130
                  << (member_base_type->getTag() == llvm::dwarf::DW_TAG_array_type))
131
        return false;  // if offset matches, and its a pointer-like, we do not need to recurse.
650✔
132
      }
133

134
      // We should only ever be able to recurse into one composite type where the offset condition holds, so
135
      // save the offset base for that member.
136
      if (llvm::isa<llvm::DICompositeType>(member_base_type)) {
390✔
137
        LOG_DEBUG("setting offset base to: " << offset);
138
        this->offset_base_ = offset;
342✔
139
      }
342✔
140
    }
1,040✔
141
    return true;
2,568✔
142
  }
4,698✔
143

144
 private:
145
  size_t byte_index_;
146
  size_t offset_base_{};
660✔
147
  std::optional<StructMember> outermost_candidate_{};
660✔
148
};
149

150
std::optional<StructMember> resolve_byte_offset_to_member_of(const llvm::DICompositeType* composite, size_t offset) {
660✔
151
  DestructureComposite visitor{offset};
660✔
152
  visitor.traverseCompositeType(composite);
660!
153
  return visitor.result();
660!
154
}
660✔
155

156
bool is_pointer(const llvm::DIType& di_type) {
5,528✔
157
  if (const auto* type = llvm::dyn_cast<llvm::DIDerivedType>(&di_type)) {
11,056!
158
    return type->getTag() == llvm::dwarf::DW_TAG_reference_type || type->getTag() == llvm::dwarf::DW_TAG_pointer_type;
5,528✔
159
  }
160
  return false;
×
161
}
5,528✔
162

163
bool is_pointer_like(const llvm::DIType& di_type) {
2,484✔
164
  if (const auto* type = llvm::dyn_cast<llvm::DIDerivedType>(&di_type)) {
4,402✔
165
    return type->getTag() == llvm::dwarf::DW_TAG_array_type || type->getTag() == llvm::dwarf::DW_TAG_reference_type ||
3,836!
166
           type->getTag() == llvm::dwarf::DW_TAG_pointer_type ||
1,918✔
167
           type->getTag() == llvm::dwarf::DW_TAG_ptr_to_member_type;
56✔
168
  }
169
  return false;
566✔
170
}
2,484✔
171

172
bool is_non_static_member(const llvm::DINode& elem) {
6,812✔
173
  return elem.getTag() == llvm::dwarf::DW_TAG_member &&
11,196✔
174
         llvm::cast<llvm::DIType>(elem).getFlags() != llvm::DINode::DIFlags::FlagStaticMember;
4,384✔
175
}
176

177
bool is_member(const llvm::DINode& elem) {
9,450✔
178
  const auto* type = llvm::dyn_cast<llvm::DIType>(&elem);
9,450✔
179
  return elem.getTag() == llvm::dwarf::DW_TAG_member ||
16,350✔
180
         ((type != nullptr) && (type->getFlags() == llvm::DINode::DIFlags::FlagStaticMember));
6,900!
181
}
9,450✔
182

183
size_t get_num_composite_members(const llvm::DICompositeType& composite) {
24✔
184
  const auto num_members =
48✔
185
      llvm::count_if(composite.getElements(), [&](const auto* node) { return is_non_static_member(*node); });
176✔
186
  return num_members;
48✔
187
}
24✔
188

UNCOV
189
llvm::SmallVector<llvm::DIDerivedType*, 4> get_composite_members(const llvm::DICompositeType& composite) {
×
UNCOV
190
  llvm::SmallVector<llvm::DIDerivedType*, 4> members;
×
UNCOV
191
  for (auto* member : composite.getElements()) {
×
UNCOV
192
    if (is_non_static_member(*member)) {
×
UNCOV
193
      members.push_back(llvm::dyn_cast<llvm::DIDerivedType>(member));
×
UNCOV
194
    }
×
UNCOV
195
  }
×
UNCOV
196
  return members;
×
UNCOV
197
}
×
198

199
std::optional<llvm::DICompositeType*> desugar(llvm::DIType& qualified_composite, int pointer_level) {
1,846✔
200
  llvm::DIType* type = &qualified_composite;
1,846✔
201
  int reached_level{0};
1,846✔
202
  while (type && llvm::isa<llvm::DIDerivedType>(type)) {
5,338✔
203
    if (reached_level > pointer_level) {
3,798✔
204
      break;
306✔
205
    }
206
    auto* ditype = llvm::dyn_cast<llvm::DIDerivedType>(type);
3,492✔
207
    if (is_pointer(*ditype)) {
3,492✔
208
      reached_level++;
2,542✔
209
    }
2,542✔
210
    type = ditype->getBaseType();
3,492✔
211
  }
3,492✔
212

213
  if (auto* comp = llvm::dyn_cast_or_null<llvm::DICompositeType>(type)) {
2,236✔
214
    return comp;
390✔
215
  }
216
  return {};
1,456✔
217
}
1,846✔
218

219
// bool has_tbaa(const llvm::Instruction& inst) {
220
//   auto* access = inst.getMetadata(llvm::StringRef{"tbaa"});
221
//   return access != nullptr;
222
// }
223

224
bool is_array_member(const llvm::DINode& elem) {
4,596✔
225
  return is_member(elem) &&
6,948✔
226
         llvm::dyn_cast<llvm::DIDerivedType>(&elem)->getBaseType()->getTag() == llvm::dwarf::DW_TAG_array_type;
2,352✔
227
}
228

229
bool is_array(const llvm::DINode& elem) {
2,198✔
230
  auto comp = llvm::dyn_cast<llvm::DICompositeType>(&elem);
2,198✔
231
  return (comp != nullptr) && comp->getTag() == llvm::dwarf::DW_TAG_array_type;
2,198✔
232
}
2,198✔
233

234
}  // namespace dimeta::di::util
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc