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

ahueck / llvm-dimeta / 19598487515

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

Pull #48

github

web-flow
Merge cefb3414f into e3aac00b8
Pull Request #48: Release 0.4

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

75.85
/lib/type/DIParser.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 "DIParser.h"
9

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

14
#include <cassert>
15
#include <cstdlib>
16
#include <llvm/BinaryFormat/Dwarf.h>
17
#include <llvm/IR/Constants.h>
18
#include <llvm/IR/DebugInfoMetadata.h>
19
#include <llvm/Support/Casting.h>
20
#include <optional>
21

22
namespace dimeta::diparser {
23

24
class DIEventVisitor : public visitor::DINodeVisitor<DIEventVisitor> {
25
  // TODO visitVariable
26
 private:
27
  state::MetaData current_;
28
  state::MetaStack stack_;
29
  DIParseEvents& events_;
30
  struct EnumMeta {
31
    llvm::DIType* enum_base{nullptr};
32
    bool is_enum{false};
33
  };
34
  EnumMeta enum_data_{};
8,499✔
35

36
 public:
37
  explicit DIEventVisitor(DIParseEvents& events);
38
  ~DIEventVisitor();
39

40
  bool visitBasicType(const llvm::DIBasicType*);
41

42
  bool visitDerivedType(const llvm::DIDerivedType*);
43

44
  bool visitCompositeType(const llvm::DICompositeType*);
45

46
  bool visitNode(const llvm::DINode* node);
47
  void leaveNode(const llvm::DINode* node);
48

49
  bool visitRecurringCompositeType(const llvm::DICompositeType*);
50

51
  void leaveBasicType(const llvm::DIBasicType*);
52

53
  void leaveCompositeType(const llvm::DICompositeType*);
54

55
  void leaveRecurringCompositeType(const llvm::DICompositeType*);
56
};
57

58
DIEventVisitor::DIEventVisitor(DIParseEvents& events) : events_{events} {
8,499!
59
}
8,499✔
60

61
DIEventVisitor::~DIEventVisitor() = default;
8,499✔
62

63
bool DIEventVisitor::visitBasicType(const llvm::DIBasicType* basic_type) {
12,905✔
64
  //  state::Entity fundamental_e{state::Entity::freestanding};
65
  current_.type = const_cast<llvm::DIBasicType*>(basic_type);
12,905✔
66

67
  if (current_.is_member) {
12,905✔
68
    assert(!stack_.empty() && "Free standing fundamental requires empty stack");
15,360!
69
    //    fundamental_e = state::Entity::member;
70
  }
7,680✔
71
  // create (free-standing) fundamental (finished recursion)
72
  //  current_.state = fundamental_e;
73

74
  if (enum_data_.is_enum) {
12,905✔
75
    // pattern matches enum types
76
    //    events.make_enum_member()
77
    enum_data_.enum_base = current_.type;
33✔
78
    return true;
33✔
79
  }
80

81
  events_.make_fundamental(current_);
12,872✔
82

83
  return true;
12,872✔
84
}
12,905✔
85

86
bool DIEventVisitor::visitDerivedType(const llvm::DIDerivedType* derived_type) {
32,863✔
87
  using namespace llvm::dwarf;
88

89
  const auto make_member = [&](const auto* derived) {
43,231✔
90
    current_.member_name      = derived_type->getName();
10,368✔
91
    current_.is_member        = true;
10,368✔
92
    current_.member_offset    = derived_type->getOffsetInBits() / 8;
10,368✔
93
    current_.member_size      = derived_type->getSizeInBits() / 8;
10,368✔
94
    current_.is_member_static = derived->isStaticMember();
10,368✔
95
  };
10,368✔
96

97
  current_.derived_size = derived_type->getSizeInBits() / 8;
32,863✔
98

99
  const auto tag = derived_type->getTag();
32,863✔
100
  switch (tag) {
32,863✔
101
    case DW_TAG_member: {
102
      make_member(derived_type);
10,185✔
103
      break;
10,185✔
104
    }
105
    case DW_TAG_variable: {
106
      // see test ir/02_mpicxx.ll: Datatype has a static member,
107
      // which is encoded as a variable, and not as a member (variable)
108
      if (!derived_type->isStaticMember()) {
183!
109
        LOG_WARNING("Variable is not a static member. " << *derived_type)
×
110
      } else {
×
111
        make_member(derived_type);
183✔
112
      }
113
      break;
183✔
114
    }
115
    case DW_TAG_typedef:
116
      current_.typedef_names.emplace_back(derived_type->getName());
9,857✔
117
      break;
9,857✔
118
    case DW_TAG_inheritance:
119
      current_.is_base_class = true;
1,480✔
120
      current_.member_offset = derived_type->getOffsetInBits() / 8;
1,480✔
121
      break;
1,480✔
122
    case DW_TAG_pointer_type:
123
      current_.dwarf_tags.emplace_back(tag);
10,326✔
124
      // array of pointers:
125
      if (!current_.arrays.empty()) {
10,326✔
126
        current_.arrays.back().array_of_pointer = derived_type->getSizeInBits();
385✔
127
      }
385✔
128
      break;
10,326✔
129
    default:
130
      current_.dwarf_tags.emplace_back(tag);
832✔
131
  }
832✔
132

133
  if (tag == DW_TAG_pointer_type && derived_type->getBaseType() == nullptr) {
32,863✔
134
    // void* pointer has no basetype
135
    current_.type        = const_cast<llvm::DIDerivedType*>(derived_type);
706✔
136
    current_.is_void_ptr = true;
706✔
137
    events_.make_void_ptr(current_);
706✔
138
    current_ = state::MetaData{};
706!
139
    return true;
330✔
140
  }
141

142
  // FIXME: hacky (current_.clear()) so vtable pointer -> pointer is not applied to vtable type.
143
  if (derived_type->getName() == "__vtbl_ptr_type") {
32,157✔
144
    assert(!stack_.empty() && "Vtable requires composite on stack");
656!
145
    // Create vtbl_ptr_type member to containing compound (first on stack)
146
    current_.type = const_cast<llvm::DIDerivedType*>(derived_type);
328✔
147
    //    current_.state = state::Entity::member;
148
    events_.make_vtable(current_);
328✔
149
    current_ = state::MetaData{};
328!
150
  }
163✔
151

152
  return true;
32,157✔
153
}
32,863✔
154

155
bool DIEventVisitor::visitNode(const llvm::DINode* node) {
1,915✔
156
  if (const auto* enumerator = llvm::dyn_cast<llvm::DIEnumerator>(node)) {
3,830✔
157
    assert(enum_data_.enum_base != nullptr && "Enumerator needs a base type.");
132!
158
    current_.member_name   = enumerator->getName();
66✔
159
    current_.member_offset = 0;
66✔
160
    current_.member_size   = enum_data_.enum_base->getSizeInBits() / 8;
66✔
161
    current_.type          = enum_data_.enum_base;
66✔
162
    current_.is_member     = true;
66✔
163
    events_.make_enum_member(current_);
66✔
164
  } else if (const auto* sub_range = llvm::dyn_cast<llvm::DISubrange>(node)) {
3,764✔
165
    assert(!current_.arrays.empty() && "Subrange requires array composite on stack");
2,954!
166

167
    const auto subrange_constant = [&sub_range]() -> std::optional<const llvm::ConstantInt*> {
2,954✔
168
#if LLVM_VERSION_MAJOR > 19
169
      if (llvm::isa<llvm::ConstantInt*>(sub_range->getCount())) {
532!
170
        auto* count = llvm::cast<llvm::ConstantInt*>(sub_range->getCount());
532✔
171
        return count;
532✔
172
      }
532✔
173
#else
174
      if (sub_range->getCount().is<llvm::ConstantInt*>()) {
945!
175
        auto* count = sub_range->getCount().get<llvm::ConstantInt*>();
945✔
176
        return count;
945✔
177
      }
945✔
178
#endif
NEW
179
      return {};
×
180
    }();
1,477✔
181

182
    if (subrange_constant.has_value()) {
1,477!
183
      const auto* count = subrange_constant.value();
1,477✔
184
      auto& array       = current_.arrays.back();
1,477✔
185
      if (!count->getValue().isNegative()) {
1,477✔
186
        auto range_count = count->getValue().getLimitedValue();
1,466✔
187
        array.subranges.push_back(range_count);
1,466✔
188
      } else {
1,466✔
189
        // see test cpp/stack_static_members_array.cpp
190
        // static int[] equals subrange(count: -1), we set simply to 0 for neg. numbers
191
        array.subranges.push_back(0);
11✔
192
      }
193
      // LOG_FATAL(range_count);
194
    }
1,477✔
195
  } else if (const auto* sub_routine = llvm::dyn_cast<llvm::DISubroutineType>(node)) {
2,221!
196
    // LOG_FATAL(sub_routine);
197
    current_.type = const_cast<llvm::DISubroutineType*>(sub_routine);
372✔
198
    events_.make_function_ptr(current_);
372✔
199
  }
372✔
200
  return true;
1,915✔
201
}
202

203
bool DIEventVisitor::visitCompositeType(const llvm::DICompositeType* composite_type) {
7,775✔
204
  // See, e.g., pass/c/stack_struct_array.c:
205
  if (composite_type->getTag() == llvm::dwarf::DW_TAG_array_type) {
7,775✔
206
    current_.is_vector = composite_type->isVector();
1,411✔
207
    current_.dwarf_tags.emplace_back(current_.is_vector ? static_cast<unsigned>(state::CustomDwarfTag::kVector)
1,411✔
208
                                                        : static_cast<unsigned>(llvm::dwarf::DW_TAG_array_type));
209
    current_.arrays.emplace_back(
1,411!
210
        state::MetaData::ArrayData{composite_type->getSizeInBits(), Extent{0}, {}, composite_type->isVector()});
1,411!
211
    // current_.array_size_bits =composite_type->getSizeInBits();
212
    return true;
1,411✔
213
  }
214

215
  current_.type            = const_cast<llvm::DICompositeType*>(composite_type);
6,364✔
216
  current_.has_vtable      = composite_type->getVTableHolder() == composite_type;
6,364✔
217
  current_.is_forward_decl = composite_type->isForwardDecl();
6,364✔
218

219
  enum_data_.is_enum = composite_type->getTag() == llvm::dwarf::DW_TAG_enumeration_type;
6,364✔
220
  //  current_.state      = state::Entity::Undef;  // determined in "leave" function
221

222
  events_.make_composite(current_);
6,364✔
223

224
  // "open" a composite type parsing (everything in the follow-up depth search gets added to that
225
  // current composite, such as members).
226
  // The so-far collected current_ metadata is used when leaving the opened composite:
227
  // Clear current_, as that meta info applied to the "composite_type"
228
  stack_.emplace_back(current_);
6,364✔
229
  current_ = state::MetaData{};
6,364!
230

231
  return true;
2,805✔
232
}
3,346✔
233

234
void DIEventVisitor::leaveCompositeType(const llvm::DICompositeType* composite_type) {
7,775✔
235
  // See, e.g., pass/c/stack_struct_array.c:
236
  if (composite_type->getTag() == llvm::dwarf::DW_TAG_array_type) {
7,775✔
237
    return;
1,411✔
238
  }
239

240
  assert(!stack_.empty() && "Required metadata is missing!");
12,728!
241

242
  //  state::Entity composite_e{state::Entity::freestanding};
243
  auto meta_for_composite = stack_.pop_back_val();
6,364✔
244

245
  if (meta_for_composite.is_member) {
6,364✔
246
    // add as member with current_meta data, and add it to current back_val() composite type.
247
    assert(!stack_.empty() && "Member composite requires composite on stack");
3,664!
248
    //    composite_e = state::Entity::member;
249
  }
1,832✔
250

251
  if (meta_for_composite.is_base_class) {
6,364✔
252
    // add as base class to back_val() composite type
253
    //    assert(composite_e != state::Entity::member);
254
    assert(!stack_.empty() && "Base composite requires composite on stack");
2,960!
255
    //    composite_e = state::Entity::base;
256
  }
1,480✔
257

258
  if (!(meta_for_composite.is_member || meta_for_composite.is_base_class)) {
6,364✔
259
    // create (free-standing) compound (finished recursion)
260
    assert(stack_.empty() && "Free standing composite requires empty stack");
6,104!
261
    //    assert(composite_e == state::Entity::freestanding);
262
  }
3,052✔
263

264
  //  meta_for_composite.state = composite_e;
265
  events_.finalize_composite(meta_for_composite);
6,364!
266

267
  enum_data_ = EnumMeta{};
6,364✔
268
}
8,879✔
269

270
void DIEventVisitor::leaveBasicType(const llvm::DIBasicType*) {
12,905✔
271
  current_ = state::MetaData{};
12,905!
272
}
5,742✔
273

274
void DIEventVisitor::leaveNode(const llvm::DINode* node) {
1,915✔
275
  if (llvm::isa<llvm::DISubroutineType>(node)) {
1,915✔
276
    current_ = state::MetaData{};
372!
277
  }
183✔
278
}
1,915✔
279

280
bool DIEventVisitor::visitRecurringCompositeType(const llvm::DICompositeType* recurring_composite) {
363✔
281
  current_.is_recurring = true;
363✔
282
  return this->visitCompositeType(recurring_composite);
363✔
283
}
284

285
void DIEventVisitor::leaveRecurringCompositeType(const llvm::DICompositeType* recurring_composite) {
363✔
286
  this->leaveCompositeType(recurring_composite);
363✔
287
}
363✔
288

289
void visit_node(const llvm::DINode* node, DIParseEvents& event_handler) {
8,499✔
290
  DIEventVisitor event_visitor{event_handler};
8,499✔
291
  const bool result = event_visitor.traverseNode(node);
8,499!
292
  if (!result) {
8,499!
293
    LOG_DEBUG("Did not parse properly: " << log::ditype_str(node));
294
  }
×
295
}
8,499✔
296

297
}  // namespace dimeta::diparser
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