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

ahueck / llvm-dimeta / 19336900257

13 Nov 2025 03:35PM UTC coverage: 72.7% (-10.7%) from 83.355%
19336900257

Pull #45

github

web-flow
Merge 6e107a749 into c60847ea6
Pull Request #45: Disable TBAA for all cases

1701 of 2973 branches covered (57.21%)

Branch coverage included in aggregate %.

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

56 existing lines in 6 files now uncovered.

2219 of 2419 relevant lines covered (91.73%)

7456.57 hits per line

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

76.62
/lib/type/DimetaParse.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 "DimetaParse.h"
9

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

15
#include "llvm/ADT/STLExtras.h"
16

17
#include <iterator>
18
#include <llvm/BinaryFormat/Dwarf.h>
19
#include <llvm/IR/DebugInfoMetadata.h>
20
#include <numeric>  // for std::accumulate
21
#include <tuple>
22
#include <type_traits>
23

24
namespace dimeta::parser {
25
namespace helper {
26

27
template <typename T, typename... Args>
28
inline std::shared_ptr<Member> make_member(std::string_view name, Args&&... args) {
8,601✔
29
  static_assert(std::is_same_v<T, QualifiedCompound> || std::is_same_v<T, QualifiedFundamental>, "Wrong qualtype.");
30
  return std::make_shared<Member>(Member{name.data(), T{std::forward<Args>(args)...}});
8,601!
UNCOV
31
}
×
32

33
template <typename T>
34
inline std::shared_ptr<BaseClass> make_base(T&& compound) {  //, BaseClass::VTable&& vtable = {}) {
1,218✔
35
  static_assert(std::is_same_v<typename std::remove_cv<T>::type, QualifiedCompound>, "Need a qualified compound.");
36
  return std::make_shared<BaseClass>(
1,218!
37
      BaseClass{std::forward<T>(compound)});  //, std::forward<BaseClass::VTable>(vtable)});
1,218✔
38
}
39

40
inline CompoundType::Tag dwarf2compound(const llvm::dwarf::Tag tag) {
5,260✔
41
  using namespace llvm::dwarf;
42
  switch (tag) {
5,260!
43
    case DW_TAG_enumeration_type:
44
      return dimeta::CompoundType::Tag::kEnum;
27✔
45
    case DW_TAG_class_type:
46
      return dimeta::CompoundType::Tag::kClass;
1,627✔
47
    case DW_TAG_structure_type:
48
      return dimeta::CompoundType::Tag::kStruct;
3,597✔
49
    case DW_TAG_union_type:
50
      return dimeta::CompoundType::Tag::kUnion;
9✔
51
    default:
52
      return dimeta::CompoundType::Tag::kUnknown;
×
53
  }
54
}
5,260✔
55

56
inline FundamentalType::Encoding dwarf2encoding(const unsigned di_encoding) {
10,634✔
57
  using namespace llvm::dwarf;
58
  switch (di_encoding) {
10,634!
59
    case DW_ATE_float:
60
      return FundamentalType::Encoding::kFloat;
3,009✔
61
    case DW_ATE_signed:
62
      return FundamentalType::Encoding::kSignedInt;
5,873✔
63
    case DW_ATE_unsigned:
64
      return FundamentalType::Encoding::kUnsignedInt;
521✔
65
    case DW_ATE_unsigned_char:
66
      return FundamentalType::Encoding::kUnsignedChar;
129✔
67
    case DW_ATE_signed_char:
68
      return FundamentalType::Encoding::kSignedChar;
976✔
69
    case DW_ATE_boolean:
70
      return FundamentalType::Encoding::kBool;
72✔
71
    case DW_ATE_UTF:
72
      return FundamentalType::Encoding::kUTFChar;
27✔
73
    case DW_ATE_complex_float:
74
      return FundamentalType::Encoding::kComplex;
27✔
75
    default:
76
      return FundamentalType::Encoding::kUnknown;
×
77
  }
78
}
10,634✔
79

80
inline Qualifier dwarf2qual(unsigned tag) {
20,634✔
81
  using namespace llvm::dwarf;
82
  switch (tag) {
20,634!
83
    case DW_TAG_pointer_type:
84
      return Qualifier::kPtr;
16,916✔
85
    case DW_TAG_reference_type:
86
      return Qualifier::kRef;
584✔
87
    case DW_TAG_const_type:
88
      return Qualifier::kConst;
676✔
89
    case DW_TAG_ptr_to_member_type:
90
      return Qualifier::kPtrToMember;
72✔
91
    case DW_TAG_array_type:
92
      return Qualifier::kArray;
2,206✔
93
    case diparser::state::CustomDwarfTag::kVector:
94
      return Qualifier::kVector;
180✔
95
    default:
96
      return Qualifier::kNone;
×
97
  }
98
}
20,634✔
99

100
inline Qualifiers make_qualifiers(const llvm::SmallVector<unsigned, 8>& tag_collector) {
17,062✔
101
  llvm::SmallVector<unsigned, 8> dwarf_quals;
17,062✔
102
  llvm::copy_if(tag_collector, std::back_inserter(dwarf_quals), [&](const auto& tag) {
27,379!
103
    const auto tag_qual = helper::dwarf2qual(tag);
10,317✔
104
    return tag_qual != Qualifier::kNone;
20,634✔
105
  });
10,317✔
106

107
  Qualifiers quals;
17,062✔
108
  quals.reserve(tag_collector.size());
17,062!
109
  llvm::transform(dwarf_quals, std::back_inserter(quals), [&](const auto& tag) -> Qualifier {
27,379!
110
    const auto tag_qual = helper::dwarf2qual(tag);
10,317✔
111
    return Qualifier{tag_qual};
20,634✔
112
  });
10,317✔
113

114
  return quals;
17,062✔
115
}
17,062!
116

117
template <typename Type>
118
inline ArraySizeList make_array_sizes(const Type&,
17,062✔
119
                                      const std::vector<diparser::state::MetaData::ArrayData>& meta_array_data) {
120
  ArraySizeList list;
17,062✔
121
  if (meta_array_data.empty()) {
17,062✔
122
    return list;
15,905✔
123
  }
124
  // const auto array_size_calc = [&type](const diparser::state::MetaData::ArrayData& array, bool is_last) {
125
  //   const auto array_byte_size = (array.array_size_bits / 8);
126
  //   // is an array of pointers:
127
  //   if (array.array_of_pointer > 0) {
128
  //     return array_byte_size / (array.array_of_pointer / 8);
129
  //   }
130
  //   // is an array of the "type":
131
  //   if (is_last && type.extent > 0) {
132
  //     return array_byte_size / type.extent;
133
  //   }
134
  //   return array_byte_size;
135
  // };
136
  const auto array_size_calc_sub = [](const diparser::state::MetaData::ArrayData& array, bool) {
2,350✔
137
    // LOG_FATAL(array.subranges.size());
138
    ArraySize sum =
2,386✔
139
        std::accumulate(array.subranges.begin(), array.subranges.end(), ArraySize{1}, std::multiplies<ArraySize>());
1,193✔
140
    return sum;
2,386✔
141
  };
1,193✔
142

143
  for (auto it = meta_array_data.begin(); it != meta_array_data.end(); ++it) {
2,350✔
144
    const auto& array          = *it;
1,193✔
145
    const bool is_last_element = (it == std::prev(std::end(meta_array_data)));
1,193!
146
    const auto size            = array_size_calc_sub(array, is_last_element);
1,193!
147
    list.emplace_back(size);
1,193!
148
    // LOG_FATAL("Array: " << size);
149
  }
1,193✔
150

151
  return list;
1,157✔
152
}
17,062!
153

154
template <typename T>
155
inline QualType<T> make_qual_type(const T& type, const diparser::state::MetaData& meta_) {
17,062✔
156
  static_assert(std::is_same_v<T, CompoundType> || std::is_same_v<T, FundamentalType>, "Wrong type.");
157

158
  Qualifiers quals = helper::make_qualifiers(meta_.dwarf_tags);
17,062✔
159
  if (meta_.is_member_static) {
17,062✔
160
    // TODO should this be the last, or should it be position dependent w.r.t. dwarf_tags?
161
    quals.emplace_back(Qualifier::kStatic);
204!
162
  }
204✔
163
  const auto array_size   = helper::make_array_sizes(type, meta_.arrays);
17,062!
164
  const auto typedef_name = meta_.typedef_names.empty() ? std::string{} : *meta_.typedef_names.begin();
17,062!
165

166
  Extent vec_size{0};
17,062✔
167
  for (const auto& array_data : meta_.arrays) {
18,255✔
168
    if (array_data.is_vector) {
1,193!
169
      assert(vec_size == 0 && "Multiple vectors detected in arrays.");
180!
170
      vec_size = array_data.array_size_bits / 8;
90✔
171
    }
90✔
172
  }
1,193✔
173

174
  return QualType<T>{
17,062✔
175
      type, array_size, quals, typedef_name, vec_size, meta_.is_vector, meta_.is_forward_decl, meta_.is_recurring};
17,062!
176
}
17,062✔
177

178
inline CompoundType make_compound(const llvm::DICompositeType* composite_type) {
5,260✔
179
  auto compound =
5,260✔
180
      [](llvm::StringRef compound_name, llvm::StringRef compound_identifier, llvm::dwarf::Tag tag,
15,780✔
181
         Extent size_in_bits) {
182
        return CompoundType{std::string{compound_name}, std::string{compound_identifier}, dwarf2compound(tag),
5,260!
183
                            size_in_bits / 8};
31,560✔
184
      }(composite_type->getName(), composite_type->getIdentifier(),
5,260✔
185
        static_cast<llvm::dwarf::Tag>(composite_type->getTag()), composite_type->getSizeInBits());
5,260✔
186
  return compound;
5,260✔
187
}
5,260!
188

189
inline QualifiedCompound make_qualified_compound(const diparser::state::MetaData& meta_) {
5,260✔
190
  return make_qual_type<CompoundType>(make_compound(llvm::dyn_cast<llvm::DICompositeType>(meta_.type)), meta_);
5,260!
UNCOV
191
}
×
192

193
QualifiedFundamental make_qualified_fundamental(const diparser::state::MetaData& meta_, std::string_view name,
11,802✔
194
                                                FundamentalType::Encoding encoding) {
195
  const auto size = [&]() {
23,604✔
196
    auto size = (meta_.type->getSizeInBits() / 8);
11,802✔
197
    if (size == 0) {
11,802✔
198
      if (encoding == FundamentalType::Encoding::kNullptr || encoding == FundamentalType::Encoding::kFunctionPtr) {
330!
199
        // sizeof std::nullptr == sizeof void*
200
        size =
330✔
201
            meta_.member_size > 0 ? meta_.member_size : (meta_.derived_size > 0 ? meta_.derived_size : sizeof(void*));
330✔
202
      }
330✔
203
    }
330✔
204
    return size;
23,604✔
205
  }();
11,802✔
206
  auto fundamental = FundamentalType{std::string{name}, size, encoding};
11,802!
207
  return make_qual_type<FundamentalType>(fundamental, meta_);
11,802!
208
}
11,802✔
209

210
}  // namespace helper
211

212
class DITypeParser final : public diparser::DIParseEvents {
6,985✔
213
  using CompoundStack = llvm::SmallVector<QualifiedCompound, 4>;
214
  DimetaParseResult result_;
215
  CompoundStack composite_stack_;
216

217
 public:
218
  [[nodiscard]] const DimetaParseResult& getParsedType() const {
6,985✔
219
    return result_;
6,985✔
220
  }
221

222
  template <typename QualType>
223
  void emplace_result(QualType&& type) {
7,243✔
224
    result_.type_.emplace<QualType>(std::forward<QualType>(type));
7,243✔
225
  }
7,243✔
226

227
  template <typename QualType>
228
  void emplace_member(QualType&& type, const diparser::state::MetaData& meta_) {
8,601✔
229
    static_assert(std::is_same_v<QualType, QualifiedCompound> || std::is_same_v<QualType, QualifiedFundamental>,
230
                  "Wrong QualType for member.");
231
    assert(!composite_stack_.empty() && "Member requires composite on stack");
17,202!
232
    auto& containing_composite = composite_stack_.back().type;
8,601✔
233
    if (meta_.is_member_static) {
8,601✔
234
      containing_composite.static_members.emplace_back(
408!
235
          helper::make_member<QualType>(meta_.member_name, std::forward<QualType>(type)));
204✔
236
    } else {
204✔
237
      containing_composite.offsets.emplace_back(meta_.member_offset);
8,397✔
238
      containing_composite.sizes.emplace_back(meta_.member_size);
8,397✔
239
      containing_composite.members.emplace_back(
16,794!
240
          helper::make_member<QualType>(meta_.member_name, std::forward<QualType>(type)));
8,397✔
241
    }
242
  }
8,601✔
243

244
  void emplace_fundamental(const diparser::state::MetaData& meta_, std::string_view name,
11,802✔
245
                           FundamentalType::Encoding encoding = FundamentalType::kUnknown) {
246
    auto qual_type_fundamental = helper::make_qualified_fundamental(meta_, name, encoding);
11,802✔
247

248
    if (meta_.is_member) {
11,802✔
249
      emplace_member(std::move(qual_type_fundamental), meta_);
7,077!
250
      return;
7,077✔
251
    }
252

253
    emplace_result<QualifiedFundamental>(std::move(qual_type_fundamental));
4,725!
254
  }
11,802!
255

256
  void make_fundamental(const diparser::state::MetaData& meta_) override {
10,598✔
257
    const auto* basic_type = llvm::dyn_cast<llvm::DIBasicType>(meta_.type);
10,598✔
258
    assert(basic_type != nullptr && "DIBasicType should not be null at this point");
21,196!
259
    const auto name = basic_type->getName();
10,598✔
260

261
    const auto encoding = (!name.empty() && name.contains("nullptr"))
10,598!
262
                              ? FundamentalType::Encoding::kNullptr
263
                              : helper::dwarf2encoding(basic_type->getEncoding());
10,580✔
264

265
    emplace_fundamental(meta_, basic_type->getName(), encoding);
10,598✔
266
  }
10,598✔
267

268
  void make_function_ptr(const diparser::state::MetaData& meta_) override {
312✔
269
    emplace_fundamental(meta_, "", FundamentalType::kFunctionPtr);
312✔
270
  }
312✔
271

272
  void make_void_ptr(const diparser::state::MetaData& meta_) override {
562✔
273
    const auto* derived_type = llvm::dyn_cast<llvm::DIDerivedType>(meta_.type);
562✔
274
    assert(derived_type != nullptr && "Type void* should be a derived type");
1,124!
275
    emplace_fundamental(meta_, "void", FundamentalType::Encoding::kVoid);
562✔
276
  }
562✔
277

278
  void make_vtable(const diparser::state::MetaData& meta_) override {
276✔
279
    const auto* derived_type = llvm::dyn_cast<llvm::DIDerivedType>(meta_.type);
276✔
280
    assert(derived_type != nullptr && "Vtable should be a derived type");
552!
281
    assert(meta_.is_member && "Vtable should be a member of composite");
552!
282
    emplace_fundamental(meta_, derived_type->getName(), FundamentalType::Encoding::kVtablePtr);
276✔
283
  }
276✔
284

285
  void make_enum_member(const diparser::state::MetaData& meta_) override {
54✔
286
    const auto* basic_type = llvm::dyn_cast<llvm::DIBasicType>(meta_.type);
54✔
287
    assert(basic_type != nullptr && "DIBasicType should not be null for enum value");
108!
288
    assert(!composite_stack_.empty() && "Requires a composite type on stack");
108!
289
    assert((composite_stack_.back().type.type == CompoundType::Tag::kEnumClass ||
108!
290
            composite_stack_.back().type.type == CompoundType::Tag::kEnum) &&
291
           "Requires a enum type on stack");
292

293
    emplace_fundamental(meta_, basic_type->getName(), helper::dwarf2encoding(basic_type->getEncoding()));
54✔
294

295
    auto& enum_type = composite_stack_.back().type;
54✔
296
    if (enum_type.sizes.size() > 1) {
54✔
297
      // emplace_fundamental adds enum value as "member" with offset in enum compound, but we want it to be "1" member
298
      // only:
299
      enum_type.sizes.erase(std::next(std::begin(enum_type.sizes)), std::end(enum_type.sizes));
36✔
300
    }
36✔
301
    if (enum_type.offsets.size() > 1) {
54✔
302
      // emplace_fundamental adds enum value as "member" with offset in enum compound, but we want it to be "1" member
303
      // only:
304
      enum_type.offsets.erase(std::next(std::begin(enum_type.offsets)), std::end(enum_type.offsets));
36✔
305
    }
36✔
306
  }
54✔
307

308
  void make_composite(const diparser::state::MetaData& meta_) override {
5,260✔
309
    assert(llvm::dyn_cast<llvm::DICompositeType>(meta_.type) != nullptr);
5,260!
310

311
    const QualifiedCompound q_compound = helper::make_qualified_compound(meta_);
5,260✔
312
    composite_stack_.emplace_back(std::move(q_compound));
5,260!
313
  }
5,260✔
314

315
  void finalize_composite(const diparser::state::MetaData& current_meta) override {
5,260✔
316
    assert(!composite_stack_.empty() && "Requires a composite type on stack");
10,520!
317
    auto finalized_composite = composite_stack_.pop_back_val();
5,260✔
318

319
    if (current_meta.is_member) {
5,260✔
320
      emplace_member(std::move(finalized_composite), current_meta);
1,524!
321
      return;
1,524✔
322
    }
323

324
    if (current_meta.is_base_class) {
3,736✔
325
      const auto base          = helper::make_base(std::move(finalized_composite));
1,218!
326
      const bool size_one      = base->base.type.extent == 1;
1,218✔
327
      const bool empty_members = base->base.type.members.empty();
1,218✔
328
      // const bool ebo_base        = base->base.type.bases.size() > 1 &&
329
      // base->base.type.bases.front()->empty_base_class;
330
      base->is_empty_base_class  = size_one && empty_members;
1,218✔
331
      base->offset               = current_meta.member_offset;
1,218✔
332
      auto& containing_composite = composite_stack_.back().type;
1,218!
333
      // if (!base->is_empty_base_class) {
334
      //   containing_composite.offsets.emplace_back(current_meta.member_offset);
335
      //   containing_composite.sizes.emplace_back(finalized_composite.type.extent);
336
      // }
337
      containing_composite.bases.emplace_back(std::move(base));
1,218!
338
      return;
339
    }
1,218✔
340

341
    assert(composite_stack_.empty() && "Assumes top level compound here");
5,036!
342
    emplace_result<QualifiedCompound>(std::move(finalized_composite));
2,518!
343
  }
5,260!
344
};
345

346
std::optional<DimetaParseResult> make_dimetadata(const llvm::DINode* node) {
6,985✔
347
  if (!(llvm::isa<llvm::DIVariable>(node) || llvm::isa<llvm::DIType>(node))) {
6,985!
348
    return {};
×
349
  }
350
  DITypeParser parser;
6,985✔
351
  diparser::visit_node(node, parser);
6,985!
352
  return parser.getParsedType();
6,985!
353
}
6,985✔
354

355
}  // namespace dimeta::parser
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