Depends on https://github.com/llvm/llvm-project/pull/100674 Currently, we treat VLAs declared as `int[]` and `int[0]` identically. I.e., we create them as `IncompleteArrayType`s. However, the `DW_AT_count` for `int[0]` *does* exist, and is retrievable without an execution context. This patch decouples the notion of "has 0 elements" from "has no known `DW_AT_count`". This aligns with how Clang represents `int[0]` in the AST (it treats it as a `ConstantArrayType` of 0 size). This issue was surfaced when adapting LLDB to https://github.com/llvm/llvm-project/issues/93069. There, the `__compressed_pair_padding` type has a `char[0]` member. If we previously got the `__compressed_pair_padding` out of a module (where clang represents `char[0]` as a `ConstantArrayType`), and try to merge the AST with one we got from DWARF (where LLDB used to represent `char[0]` as an `IncompleteArrayType`), the AST structural equivalence check fails, resulting in silent ASTImporter failures. This manifested in a failure in `TestNonModuleTypeSeparation.py`. **Implementation** 1. Adjust `ParseChildArrayInfo` to store the element counts of each VLA dimension as an `optional<uint64_t>`, instead of a regular `uint64_t`. So when we pass this down to `CreateArrayType`, we have a better heuristic for what is an `IncompleteArrayType`. 2. In `TypeSystemClang::GetBitSize`, if we encounter a `ConstantArrayType` simply return the size that it was created with. If we couldn't determine the authoritative bound from DWARF during parsing, we would've created an `IncompleteArrayType`. This ensures that `GetBitSize` on arrays with `DW_AT_count 0x0` returns `0` (whereas previously it would've returned a `std::nullopt`, causing that `FieldDecl` to just get dropped during printing)
142 lines
4.0 KiB
C++
142 lines
4.0 KiB
C++
//===-- DWARFASTParser.cpp ------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "DWARFASTParser.h"
|
|
#include "DWARFAttribute.h"
|
|
#include "DWARFDIE.h"
|
|
#include "SymbolFileDWARF.h"
|
|
|
|
#include "lldb/Core/ValueObject.h"
|
|
#include "lldb/Symbol/SymbolFile.h"
|
|
#include "lldb/Target/StackFrame.h"
|
|
#include <optional>
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::dwarf;
|
|
using namespace lldb_private::plugin::dwarf;
|
|
|
|
std::optional<SymbolFile::ArrayInfo>
|
|
DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die,
|
|
const ExecutionContext *exe_ctx) {
|
|
SymbolFile::ArrayInfo array_info;
|
|
if (!parent_die)
|
|
return std::nullopt;
|
|
|
|
for (DWARFDIE die : parent_die.children()) {
|
|
const dw_tag_t tag = die.Tag();
|
|
if (tag != DW_TAG_subrange_type)
|
|
continue;
|
|
|
|
DWARFAttributes attributes = die.GetAttributes();
|
|
if (attributes.Size() == 0)
|
|
continue;
|
|
|
|
std::optional<uint64_t> num_elements;
|
|
uint64_t lower_bound = 0;
|
|
uint64_t upper_bound = 0;
|
|
bool upper_bound_valid = false;
|
|
for (size_t i = 0; i < attributes.Size(); ++i) {
|
|
const dw_attr_t attr = attributes.AttributeAtIndex(i);
|
|
DWARFFormValue form_value;
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
|
|
switch (attr) {
|
|
case DW_AT_name:
|
|
break;
|
|
|
|
case DW_AT_count:
|
|
if (DWARFDIE var_die = die.GetReferencedDIE(DW_AT_count)) {
|
|
if (var_die.Tag() == DW_TAG_variable)
|
|
if (exe_ctx) {
|
|
if (auto frame = exe_ctx->GetFrameSP()) {
|
|
Status error;
|
|
lldb::VariableSP var_sp;
|
|
auto valobj_sp = frame->GetValueForVariableExpressionPath(
|
|
var_die.GetName(), eNoDynamicValues, 0, var_sp, error);
|
|
if (valobj_sp) {
|
|
num_elements = valobj_sp->GetValueAsUnsigned(0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
num_elements = form_value.Unsigned();
|
|
break;
|
|
|
|
case DW_AT_bit_stride:
|
|
array_info.bit_stride = form_value.Unsigned();
|
|
break;
|
|
|
|
case DW_AT_byte_stride:
|
|
array_info.byte_stride = form_value.Unsigned();
|
|
break;
|
|
|
|
case DW_AT_lower_bound:
|
|
lower_bound = form_value.Unsigned();
|
|
break;
|
|
|
|
case DW_AT_upper_bound:
|
|
upper_bound_valid = true;
|
|
upper_bound = form_value.Unsigned();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!num_elements || *num_elements == 0) {
|
|
if (upper_bound_valid && upper_bound >= lower_bound)
|
|
num_elements = upper_bound - lower_bound + 1;
|
|
}
|
|
|
|
array_info.element_orders.push_back(num_elements);
|
|
}
|
|
return array_info;
|
|
}
|
|
|
|
Type *DWARFASTParser::GetTypeForDIE(const DWARFDIE &die) {
|
|
if (!die)
|
|
return nullptr;
|
|
|
|
SymbolFileDWARF *dwarf = die.GetDWARF();
|
|
if (!dwarf)
|
|
return nullptr;
|
|
|
|
DWARFAttributes attributes = die.GetAttributes();
|
|
if (attributes.Size() == 0)
|
|
return nullptr;
|
|
|
|
DWARFFormValue type_die_form;
|
|
for (size_t i = 0; i < attributes.Size(); ++i) {
|
|
dw_attr_t attr = attributes.AttributeAtIndex(i);
|
|
DWARFFormValue form_value;
|
|
|
|
if (attr == DW_AT_type && attributes.ExtractFormValueAtIndex(i, form_value))
|
|
return dwarf->ResolveTypeUID(form_value.Reference(), true);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
AccessType
|
|
DWARFASTParser::GetAccessTypeFromDWARF(uint32_t dwarf_accessibility) {
|
|
switch (dwarf_accessibility) {
|
|
case DW_ACCESS_public:
|
|
return eAccessPublic;
|
|
case DW_ACCESS_private:
|
|
return eAccessPrivate;
|
|
case DW_ACCESS_protected:
|
|
return eAccessProtected;
|
|
default:
|
|
break;
|
|
}
|
|
return eAccessNone;
|
|
}
|