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

ahueck / llvm-dimeta / 13933486559

18 Mar 2025 09:06PM UTC coverage: 83.197% (-0.4%) from 83.637%
13933486559

push

github

web-flow
Refactoring (#35)

1027 of 1482 branches covered (69.3%)

Branch coverage included in aggregate %.

86 of 87 new or added lines in 10 files covered. (98.85%)

17 existing lines in 7 files now uncovered.

1924 of 2065 relevant lines covered (93.17%)

3950.95 hits per line

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

81.17
/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 <optional>
17

18
namespace dimeta::di::util {
19

20
namespace printer {
21

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

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

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

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

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

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

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

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

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

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

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

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

83
}  // namespace printer
84

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

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

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

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

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

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

119
    if (byte_index_ >= lower_bound && byte_index_ < upper_bound) {
774✔
120
      auto* const member_base_type = derived_ty->getBaseType();
268✔
121

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

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

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

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

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

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

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

162
bool is_pointer_like(const llvm::DIType& di_type) {
628✔
163
  if (const auto* type = llvm::dyn_cast<llvm::DIDerivedType>(&di_type)) {
1,132!
164
    return type->getTag() == llvm::dwarf::DW_TAG_array_type || type->getTag() == llvm::dwarf::DW_TAG_reference_type ||
1,008!
165
           type->getTag() == llvm::dwarf::DW_TAG_pointer_type ||
504✔
166
           type->getTag() == llvm::dwarf::DW_TAG_ptr_to_member_type;
44✔
167
  }
168
  return false;
124✔
169
}
628✔
170

171
bool is_non_static_member(const llvm::DINode& elem) {
2,772✔
172
  return elem.getTag() == llvm::dwarf::DW_TAG_member &&
4,858✔
173
         llvm::cast<llvm::DIType>(elem).getFlags() != llvm::DINode::DIFlags::FlagStaticMember;
2,086✔
174
}
175

176
size_t get_num_composite_members(const llvm::DICompositeType& composite) {
92✔
177
  const auto num_members =
184✔
178
      llvm::count_if(composite.getElements(), [&](const auto* node) { return is_non_static_member(*node); });
326✔
179
  return num_members;
184✔
180
}
92✔
181

182
llvm::SmallVector<llvm::DIDerivedType*, 4> get_composite_members(const llvm::DICompositeType& composite) {
36✔
183
  llvm::SmallVector<llvm::DIDerivedType*, 4> members;
36✔
184
  for (auto* member : composite.getElements()) {
78✔
185
    if (is_non_static_member(*member)) {
42!
186
      members.push_back(llvm::dyn_cast<llvm::DIDerivedType>(member));
42✔
187
    }
42✔
188
  }
42✔
189
  return members;
36✔
190
}
36!
191

192
}  // 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