blob: a9b4478e33c40fb482f2a15668ba8b8cce6f9b6d [file] [log] [blame]
//===- SyntheticTypeNameBuilder.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 "SyntheticTypeNameBuilder.h"
#include "DWARFLinkerCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
#include "llvm/Support/ScopedPrinter.h"
namespace llvm {
namespace dwarflinker_parallel {
Error SyntheticTypeNameBuilder::assignName(
UnitEntryPairTy InputUnitEntryPair,
std::optional<std::pair<size_t, size_t>> ChildIndex) {
[[maybe_unused]] const CompileUnit::DIEInfo &Info =
InputUnitEntryPair.CU->getDIEInfo(InputUnitEntryPair.DieEntry);
assert(Info.needToPlaceInTypeTable() &&
"Cann't assign name for non-type DIE");
if (InputUnitEntryPair.CU->getDieTypeEntry(InputUnitEntryPair.DieEntry) !=
nullptr)
return Error::success();
SyntheticName.resize(0);
RecursionDepth = 0;
return addDIETypeName(InputUnitEntryPair, ChildIndex, true);
}
void SyntheticTypeNameBuilder::addArrayDimension(
UnitEntryPairTy InputUnitEntryPair) {
for (const DWARFDebugInfoEntry *CurChild =
InputUnitEntryPair.CU->getFirstChildEntry(
InputUnitEntryPair.DieEntry);
CurChild && CurChild->getAbbreviationDeclarationPtr();
CurChild = InputUnitEntryPair.CU->getSiblingEntry(CurChild)) {
if (CurChild->getTag() == dwarf::DW_TAG_subrange_type ||
CurChild->getTag() == dwarf::DW_TAG_generic_subrange) {
SyntheticName += "[";
if (std::optional<DWARFFormValue> Val =
InputUnitEntryPair.CU->find(CurChild, dwarf::DW_AT_count)) {
if (std::optional<uint64_t> ConstVal = Val->getAsUnsignedConstant()) {
SyntheticName += std::to_string(*ConstVal);
} else if (std::optional<int64_t> ConstVal =
Val->getAsSignedConstant()) {
SyntheticName += std::to_string(*ConstVal);
}
}
SyntheticName += "]";
}
}
}
static dwarf::Attribute TypeAttr[] = {dwarf::DW_AT_type};
Error SyntheticTypeNameBuilder::addSignature(UnitEntryPairTy InputUnitEntryPair,
bool addTemplateParameters) {
// Add entry type.
if (Error Err = addReferencedODRDies(InputUnitEntryPair, false, TypeAttr))
return Err;
SyntheticName += ':';
SmallVector<const DWARFDebugInfoEntry *, 10> TemplateParameters;
SmallVector<const DWARFDebugInfoEntry *, 20> FunctionParameters;
for (const DWARFDebugInfoEntry *CurChild =
InputUnitEntryPair.CU->getFirstChildEntry(
InputUnitEntryPair.DieEntry);
CurChild && CurChild->getAbbreviationDeclarationPtr();
CurChild = InputUnitEntryPair.CU->getSiblingEntry(CurChild)) {
dwarf::Tag ChildTag = CurChild->getTag();
if (addTemplateParameters &&
(ChildTag == dwarf::DW_TAG_template_type_parameter ||
ChildTag == dwarf::DW_TAG_template_value_parameter))
TemplateParameters.push_back(CurChild);
else if (ChildTag == dwarf::DW_TAG_formal_parameter ||
ChildTag == dwarf::DW_TAG_unspecified_parameters)
FunctionParameters.push_back(CurChild);
else if (addTemplateParameters &&
ChildTag == dwarf::DW_TAG_GNU_template_parameter_pack) {
for (const DWARFDebugInfoEntry *CurGNUChild =
InputUnitEntryPair.CU->getFirstChildEntry(CurChild);
CurGNUChild && CurGNUChild->getAbbreviationDeclarationPtr();
CurGNUChild = InputUnitEntryPair.CU->getSiblingEntry(CurGNUChild))
TemplateParameters.push_back(CurGNUChild);
} else if (ChildTag == dwarf::DW_TAG_GNU_formal_parameter_pack) {
for (const DWARFDebugInfoEntry *CurGNUChild =
InputUnitEntryPair.CU->getFirstChildEntry(CurChild);
CurGNUChild && CurGNUChild->getAbbreviationDeclarationPtr();
CurGNUChild = InputUnitEntryPair.CU->getSiblingEntry(CurGNUChild))
FunctionParameters.push_back(CurGNUChild);
}
}
// Add parameters.
if (Error Err = addParamNames(*InputUnitEntryPair.CU, FunctionParameters))
return Err;
// Add template parameters.
if (Error Err =
addTemplateParamNames(*InputUnitEntryPair.CU, TemplateParameters))
return Err;
return Error::success();
}
Error SyntheticTypeNameBuilder::addParamNames(
CompileUnit &CU,
SmallVector<const DWARFDebugInfoEntry *, 20> &FunctionParameters) {
SyntheticName += '(';
for (const DWARFDebugInfoEntry *FunctionParameter : FunctionParameters) {
if (SyntheticName.back() != '(')
SyntheticName += ", ";
if (dwarf::toUnsigned(CU.find(FunctionParameter, dwarf::DW_AT_artificial),
0))
SyntheticName += "^";
if (Error Err = addReferencedODRDies(
UnitEntryPairTy{&CU, FunctionParameter}, false, TypeAttr))
return Err;
}
SyntheticName += ')';
return Error::success();
}
Error SyntheticTypeNameBuilder::addTemplateParamNames(
CompileUnit &CU,
SmallVector<const DWARFDebugInfoEntry *, 10> &TemplateParameters) {
if (!TemplateParameters.empty()) {
SyntheticName += '<';
for (const DWARFDebugInfoEntry *Parameter : TemplateParameters) {
if (SyntheticName.back() != '<')
SyntheticName += ", ";
if (Parameter->getTag() == dwarf::DW_TAG_template_value_parameter) {
if (std::optional<DWARFFormValue> Val =
CU.find(Parameter, dwarf::DW_AT_const_value)) {
if (std::optional<uint64_t> ConstVal = Val->getAsUnsignedConstant())
SyntheticName += std::to_string(*ConstVal);
else if (std::optional<int64_t> ConstVal = Val->getAsSignedConstant())
SyntheticName += std::to_string(*ConstVal);
}
}
if (Error Err = addReferencedODRDies(UnitEntryPairTy{&CU, Parameter},
false, TypeAttr))
return Err;
}
SyntheticName += '>';
}
return Error::success();
}
void SyntheticTypeNameBuilder::addOrderedName(
std::pair<size_t, size_t> ChildIdx) {
std::string Name;
llvm::raw_string_ostream stream(Name);
stream << format_hex_no_prefix(ChildIdx.first, ChildIdx.second);
SyntheticName += Name;
}
// Examine DIE and return type deduplication candidate: some DIEs could not be
// deduplicated, namespace may refer to another namespace.
static std::optional<UnitEntryPairTy>
getTypeDeduplicationCandidate(UnitEntryPairTy UnitEntryPair) {
switch (UnitEntryPair.DieEntry->getTag()) {
case dwarf::DW_TAG_null:
case dwarf::DW_TAG_compile_unit:
case dwarf::DW_TAG_partial_unit:
case dwarf::DW_TAG_type_unit:
case dwarf::DW_TAG_skeleton_unit: {
return std::nullopt;
}
case dwarf::DW_TAG_namespace: {
// Check if current namespace refers another.
if (UnitEntryPair.CU->find(UnitEntryPair.DieEntry, dwarf::DW_AT_extension))
UnitEntryPair = UnitEntryPair.getNamespaceOrigin();
// Content of anonimous namespaces should not be deduplicated.
if (!UnitEntryPair.CU->find(UnitEntryPair.DieEntry, dwarf::DW_AT_name))
llvm_unreachable("Cann't deduplicate anonimous namespace");
return UnitEntryPair;
}
default:
return UnitEntryPair;
}
}
Error SyntheticTypeNameBuilder::addParentName(
UnitEntryPairTy &InputUnitEntryPair) {
std::optional<UnitEntryPairTy> UnitEntryPair = InputUnitEntryPair.getParent();
if (!UnitEntryPair)
return Error::success();
UnitEntryPair = getTypeDeduplicationCandidate(*UnitEntryPair);
if (!UnitEntryPair)
return Error::success();
if (TypeEntry *ImmediateParentName =
UnitEntryPair->CU->getDieTypeEntry(UnitEntryPair->DieEntry)) {
SyntheticName += ImmediateParentName->getKey();
SyntheticName += ".";
return Error::success();
}
// Collect parent entries.
SmallVector<UnitEntryPairTy, 10> Parents;
do {
Parents.push_back(*UnitEntryPair);
UnitEntryPair = UnitEntryPair->getParent();
if (!UnitEntryPair)
break;
UnitEntryPair = getTypeDeduplicationCandidate(*UnitEntryPair);
if (!UnitEntryPair)
break;
} while (!UnitEntryPair->CU->getDieTypeEntry(UnitEntryPair->DieEntry));
// Assign name for each parent entry.
size_t NameStart = SyntheticName.size();
for (UnitEntryPairTy Parent : reverse(Parents)) {
SyntheticName.resize(NameStart);
if (Error Err = addDIETypeName(Parent, std::nullopt, true))
return Err;
}
// Add parents delimiter.
SyntheticName += ".";
return Error::success();
}
void SyntheticTypeNameBuilder::addDieNameFromDeclFileAndDeclLine(
UnitEntryPairTy &InputUnitEntryPair, bool &HasDeclFileName) {
if (std::optional<DWARFFormValue> DeclFileVal = InputUnitEntryPair.CU->find(
InputUnitEntryPair.DieEntry, dwarf::DW_AT_decl_file)) {
if (std::optional<DWARFFormValue> DeclLineVal = InputUnitEntryPair.CU->find(
InputUnitEntryPair.DieEntry, dwarf::DW_AT_decl_line)) {
if (std::optional<std::pair<StringRef, StringRef>> DirAndFilename =
InputUnitEntryPair.CU->getDirAndFilenameFromLineTable(
*DeclFileVal)) {
SyntheticName += DirAndFilename->first;
SyntheticName += DirAndFilename->second;
if (std::optional<uint64_t> DeclLineIntVal =
dwarf::toUnsigned(*DeclLineVal)) {
SyntheticName += " ";
SyntheticName += utohexstr(*DeclLineIntVal);
}
HasDeclFileName = true;
}
}
}
}
void SyntheticTypeNameBuilder::addValueName(UnitEntryPairTy InputUnitEntryPair,
dwarf::Attribute Attr) {
if (std::optional<DWARFFormValue> Val =
InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry, Attr)) {
if (std::optional<uint64_t> ConstVal = Val->getAsUnsignedConstant()) {
SyntheticName += " ";
SyntheticName += std::to_string(*ConstVal);
} else if (std::optional<int64_t> ConstVal = Val->getAsSignedConstant()) {
SyntheticName += " ";
SyntheticName += std::to_string(*ConstVal);
}
}
}
Error SyntheticTypeNameBuilder::addReferencedODRDies(
UnitEntryPairTy InputUnitEntryPair, bool AssignNameToTypeDescriptor,
ArrayRef<dwarf::Attribute> ODRAttrs) {
bool FirstIteration = true;
for (dwarf::Attribute Attr : ODRAttrs) {
if (std::optional<DWARFFormValue> AttrValue =
InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry, Attr)) {
std::optional<UnitEntryPairTy> RefDie =
InputUnitEntryPair.CU->resolveDIEReference(
*AttrValue, ResolveInterCUReferencesMode::Resolve);
if (!RefDie)
continue;
if (!RefDie->DieEntry)
return createStringError(std::errc::invalid_argument,
"Cann't resolve DIE reference");
if (!FirstIteration)
SyntheticName += ",";
RecursionDepth++;
if (RecursionDepth > 1000)
return createStringError(
std::errc::invalid_argument,
"Cann't parse input DWARF. Recursive dependence.");
if (Error Err =
addDIETypeName(*RefDie, std::nullopt, AssignNameToTypeDescriptor))
return Err;
RecursionDepth--;
FirstIteration = false;
}
}
return Error::success();
}
Error SyntheticTypeNameBuilder::addTypeName(UnitEntryPairTy InputUnitEntryPair,
bool AddParentNames) {
bool HasLinkageName = false;
bool HasShortName = false;
bool HasTemplatesInShortName = false;
bool HasDeclFileName = false;
// Try to get name from the DIE.
if (std::optional<DWARFFormValue> Val = InputUnitEntryPair.CU->find(
InputUnitEntryPair.DieEntry,
{dwarf::DW_AT_MIPS_linkage_name, dwarf::DW_AT_linkage_name})) {
// Firstly check for linkage name.
SyntheticName += dwarf::toStringRef(Val);
HasLinkageName = true;
} else if (std::optional<DWARFFormValue> Val = InputUnitEntryPair.CU->find(
InputUnitEntryPair.DieEntry, dwarf::DW_AT_name)) {
// Then check for short name.
StringRef Name = dwarf::toStringRef(Val);
SyntheticName += Name;
HasShortName = true;
HasTemplatesInShortName =
Name.ends_with(">") && Name.count("<") != 0 && !Name.ends_with("<=>");
} else {
// Finally check for declaration attributes.
addDieNameFromDeclFileAndDeclLine(InputUnitEntryPair, HasDeclFileName);
}
// Add additional name parts for some DIEs.
switch (InputUnitEntryPair.DieEntry->getTag()) {
case dwarf::DW_TAG_union_type:
case dwarf::DW_TAG_interface_type:
case dwarf::DW_TAG_class_type:
case dwarf::DW_TAG_structure_type:
case dwarf::DW_TAG_subroutine_type:
case dwarf::DW_TAG_subprogram: {
if (InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry,
dwarf::DW_AT_artificial))
SyntheticName += "^";
// No need to add signature information for linkage name,
// also no need to add template parameters name if short name already
// includes them.
if (!HasLinkageName)
if (Error Err =
addSignature(InputUnitEntryPair, !HasTemplatesInShortName))
return Err;
} break;
case dwarf::DW_TAG_coarray_type:
case dwarf::DW_TAG_array_type: {
addArrayDimension(InputUnitEntryPair);
} break;
case dwarf::DW_TAG_subrange_type: {
addValueName(InputUnitEntryPair, dwarf::DW_AT_count);
} break;
case dwarf::DW_TAG_template_value_parameter: {
if (!HasTemplatesInShortName) {
// TODO add support for DW_AT_location
addValueName(InputUnitEntryPair, dwarf::DW_AT_const_value);
}
} break;
default: {
// Nothing to do.
} break;
}
// If name for the DIE is not determined yet add referenced types to the name.
if (!HasLinkageName && !HasShortName && !HasDeclFileName) {
if (InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry,
getODRAttributes()))
if (Error Err = addReferencedODRDies(InputUnitEntryPair, AddParentNames,
getODRAttributes()))
return Err;
}
return Error::success();
}
Error SyntheticTypeNameBuilder::addDIETypeName(
UnitEntryPairTy InputUnitEntryPair,
std::optional<std::pair<size_t, size_t>> ChildIndex,
bool AssignNameToTypeDescriptor) {
std::optional<UnitEntryPairTy> UnitEntryPair =
getTypeDeduplicationCandidate(InputUnitEntryPair);
if (!UnitEntryPair)
return Error::success();
TypeEntry *TypeEntryPtr =
InputUnitEntryPair.CU->getDieTypeEntry(InputUnitEntryPair.DieEntry);
// Check if DIE already has a name.
if (!TypeEntryPtr) {
size_t NameStart = SyntheticName.size();
if (AssignNameToTypeDescriptor) {
if (Error Err = addParentName(*UnitEntryPair))
return Err;
}
addTypePrefix(UnitEntryPair->DieEntry);
if (ChildIndex) {
addOrderedName(*ChildIndex);
} else {
if (Error Err = addTypeName(*UnitEntryPair, AssignNameToTypeDescriptor))
return Err;
}
if (AssignNameToTypeDescriptor) {
// Add built name to the DIE.
TypeEntryPtr = TypePoolRef.insert(SyntheticName.substr(NameStart));
InputUnitEntryPair.CU->setDieTypeEntry(InputUnitEntryPair.DieEntry,
TypeEntryPtr);
}
} else
SyntheticName += TypeEntryPtr->getKey();
return Error::success();
}
void SyntheticTypeNameBuilder::addTypePrefix(
const DWARFDebugInfoEntry *DieEntry) {
switch (DieEntry->getTag()) {
case dwarf::DW_TAG_base_type: {
SyntheticName += "{0}";
} break;
case dwarf::DW_TAG_namespace: {
SyntheticName += "{1}";
} break;
case dwarf::DW_TAG_formal_parameter: {
SyntheticName += "{2}";
} break;
// dwarf::DW_TAG_unspecified_parameters have the same prefix as before.
case dwarf::DW_TAG_unspecified_parameters: {
SyntheticName += "{2}";
} break;
case dwarf::DW_TAG_template_type_parameter: {
SyntheticName += "{3}";
} break;
// dwarf::DW_TAG_template_value_parameter have the same prefix as before.
case dwarf::DW_TAG_template_value_parameter: {
SyntheticName += "{3}";
} break;
case dwarf::DW_TAG_GNU_formal_parameter_pack: {
SyntheticName += "{4}";
} break;
case dwarf::DW_TAG_GNU_template_parameter_pack: {
SyntheticName += "{5}";
} break;
case dwarf::DW_TAG_inheritance: {
SyntheticName += "{6}";
} break;
case dwarf::DW_TAG_array_type: {
SyntheticName += "{7}";
} break;
case dwarf::DW_TAG_class_type: {
SyntheticName += "{8}";
} break;
case dwarf::DW_TAG_enumeration_type: {
SyntheticName += "{9}";
} break;
case dwarf::DW_TAG_imported_declaration: {
SyntheticName += "{A}";
} break;
case dwarf::DW_TAG_member: {
SyntheticName += "{B}";
} break;
case dwarf::DW_TAG_pointer_type: {
SyntheticName += "{C}";
} break;
case dwarf::DW_TAG_reference_type: {
SyntheticName += "{D}";
} break;
case dwarf::DW_TAG_string_type: {
SyntheticName += "{E}";
} break;
case dwarf::DW_TAG_structure_type: {
SyntheticName += "{F}";
} break;
case dwarf::DW_TAG_subroutine_type: {
SyntheticName += "{G}";
} break;
case dwarf::DW_TAG_typedef: {
SyntheticName += "{H}";
} break;
case dwarf::DW_TAG_union_type: {
SyntheticName += "{I}";
} break;
case dwarf::DW_TAG_variant: {
SyntheticName += "{J}";
} break;
case dwarf::DW_TAG_inlined_subroutine: {
SyntheticName += "{K}";
} break;
case dwarf::DW_TAG_module: {
SyntheticName += "{L}";
} break;
case dwarf::DW_TAG_ptr_to_member_type: {
SyntheticName += "{M}";
} break;
case dwarf::DW_TAG_set_type: {
SyntheticName += "{N}";
} break;
case dwarf::DW_TAG_subrange_type: {
SyntheticName += "{O}";
} break;
case dwarf::DW_TAG_with_stmt: {
SyntheticName += "{P}";
} break;
case dwarf::DW_TAG_access_declaration: {
SyntheticName += "{Q}";
} break;
case dwarf::DW_TAG_catch_block: {
SyntheticName += "{R}";
} break;
case dwarf::DW_TAG_const_type: {
SyntheticName += "{S}";
} break;
case dwarf::DW_TAG_constant: {
SyntheticName += "{T}";
} break;
case dwarf::DW_TAG_enumerator: {
SyntheticName += "{U}";
} break;
case dwarf::DW_TAG_file_type: {
SyntheticName += "{V}";
} break;
case dwarf::DW_TAG_friend: {
SyntheticName += "{W}";
} break;
case dwarf::DW_TAG_namelist: {
SyntheticName += "{X}";
} break;
case dwarf::DW_TAG_namelist_item: {
SyntheticName += "{Y}";
} break;
case dwarf::DW_TAG_packed_type: {
SyntheticName += "{Z}";
} break;
case dwarf::DW_TAG_subprogram: {
SyntheticName += "{a}";
} break;
case dwarf::DW_TAG_thrown_type: {
SyntheticName += "{b}";
} break;
case dwarf::DW_TAG_variant_part: {
SyntheticName += "{c}";
} break;
case dwarf::DW_TAG_variable: {
SyntheticName += "{d}";
} break;
case dwarf::DW_TAG_volatile_type: {
SyntheticName += "{e}";
} break;
case dwarf::DW_TAG_dwarf_procedure: {
SyntheticName += "{f}";
} break;
case dwarf::DW_TAG_restrict_type: {
SyntheticName += "{g}";
} break;
case dwarf::DW_TAG_interface_type: {
SyntheticName += "{h}";
} break;
case dwarf::DW_TAG_imported_module: {
SyntheticName += "{i}";
} break;
case dwarf::DW_TAG_unspecified_type: {
SyntheticName += "{j}";
} break;
case dwarf::DW_TAG_imported_unit: {
SyntheticName += "{k}";
} break;
case dwarf::DW_TAG_condition: {
SyntheticName += "{l}";
} break;
case dwarf::DW_TAG_shared_type: {
SyntheticName += "{m}";
} break;
case dwarf::DW_TAG_rvalue_reference_type: {
SyntheticName += "{n}";
} break;
case dwarf::DW_TAG_template_alias: {
SyntheticName += "{o}";
} break;
case dwarf::DW_TAG_coarray_type: {
SyntheticName += "{p}";
} break;
case dwarf::DW_TAG_generic_subrange: {
SyntheticName += "{q}";
} break;
case dwarf::DW_TAG_dynamic_type: {
SyntheticName += "{r}";
} break;
case dwarf::DW_TAG_atomic_type: {
SyntheticName += "{s}";
} break;
case dwarf::DW_TAG_call_site: {
SyntheticName += "{t}";
} break;
case dwarf::DW_TAG_call_site_parameter: {
SyntheticName += "{u}";
} break;
case dwarf::DW_TAG_immutable_type: {
SyntheticName += "{v}";
} break;
case dwarf::DW_TAG_entry_point: {
SyntheticName += "{w}";
} break;
case dwarf::DW_TAG_label: {
SyntheticName += "{x}";
} break;
case dwarf::DW_TAG_lexical_block: {
SyntheticName += "{y}";
} break;
case dwarf::DW_TAG_common_block: {
SyntheticName += "{z}";
} break;
case dwarf::DW_TAG_common_inclusion: {
SyntheticName += "{|}";
} break;
case dwarf::DW_TAG_try_block: {
SyntheticName += "{~}";
} break;
case dwarf::DW_TAG_null: {
llvm_unreachable("No type prefix for DW_TAG_null");
} break;
case dwarf::DW_TAG_compile_unit: {
llvm_unreachable("No type prefix for DW_TAG_compile_unit");
} break;
case dwarf::DW_TAG_partial_unit: {
llvm_unreachable("No type prefix for DW_TAG_partial_unit");
} break;
case dwarf::DW_TAG_type_unit: {
llvm_unreachable("No type prefix for DW_TAG_type_unit");
} break;
case dwarf::DW_TAG_skeleton_unit: {
llvm_unreachable("No type prefix for DW_TAG_skeleton_unit");
} break;
default: {
SyntheticName += "{~~";
SyntheticName += utohexstr(DieEntry->getTag());
SyntheticName += "}";
} break;
}
}
OrderedChildrenIndexAssigner::OrderedChildrenIndexAssigner(
CompileUnit &CU, const DWARFDebugInfoEntry *DieEntry) {
switch (DieEntry->getTag()) {
case dwarf::DW_TAG_array_type:
case dwarf::DW_TAG_coarray_type:
case dwarf::DW_TAG_class_type:
case dwarf::DW_TAG_common_block:
case dwarf::DW_TAG_lexical_block:
case dwarf::DW_TAG_structure_type:
case dwarf::DW_TAG_subprogram:
case dwarf::DW_TAG_subroutine_type:
case dwarf::DW_TAG_union_type:
case dwarf::DW_TAG_GNU_template_template_param:
case dwarf::DW_TAG_GNU_formal_parameter_pack: {
NeedCountChildren = true;
} break;
case dwarf::DW_TAG_enumeration_type: {
// TODO : do we need to add condition
NeedCountChildren = true;
} break;
default: {
// Nothing to do.
}
}
// Calculate maximal index value
if (NeedCountChildren) {
for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(DieEntry);
CurChild && CurChild->getAbbreviationDeclarationPtr();
CurChild = CU.getSiblingEntry(CurChild)) {
std::optional<size_t> ArrayIndex = tagToArrayIndex(CU, CurChild);
if (!ArrayIndex)
continue;
assert((*ArrayIndex < ChildIndexesWidth.size()) &&
"Wrong index for ChildIndexesWidth");
ChildIndexesWidth[*ArrayIndex]++;
}
// Calculate index field width(number of digits in hexadecimal
// representation).
for (size_t &Width : ChildIndexesWidth) {
size_t digitsCounter = 1;
size_t NumToCompare = 15;
while (NumToCompare < Width) {
NumToCompare <<= 4;
digitsCounter++;
}
Width = digitsCounter;
}
}
}
std::optional<size_t> OrderedChildrenIndexAssigner::tagToArrayIndex(
CompileUnit &CU, const DWARFDebugInfoEntry *DieEntry) {
if (!NeedCountChildren)
return std::nullopt;
switch (DieEntry->getTag()) {
case dwarf::DW_TAG_unspecified_parameters:
case dwarf::DW_TAG_formal_parameter:
return 0;
case dwarf::DW_TAG_template_value_parameter:
case dwarf::DW_TAG_template_type_parameter:
return 1;
case dwarf::DW_TAG_enumeration_type:
if (std::optional<uint32_t> ParentIdx = DieEntry->getParentIdx()) {
if (*ParentIdx && CU.getDebugInfoEntry(*ParentIdx)->getTag() ==
dwarf::DW_TAG_array_type)
return 2;
}
return std::nullopt;
case dwarf::DW_TAG_subrange_type:
return 3;
case dwarf::DW_TAG_generic_subrange:
return 4;
case dwarf::DW_TAG_enumerator:
return 5;
case dwarf::DW_TAG_namelist_item:
return 6;
case dwarf::DW_TAG_member:
return 7;
default:
return std::nullopt;
};
}
std::optional<std::pair<size_t, size_t>>
OrderedChildrenIndexAssigner::getChildIndex(
CompileUnit &CU, const DWARFDebugInfoEntry *ChildDieEntry) {
std::optional<size_t> ArrayIndex = tagToArrayIndex(CU, ChildDieEntry);
if (!ArrayIndex)
return std::nullopt;
assert((*ArrayIndex < OrderedChildIdxs.size()) &&
"Wrong index for ChildIndexesWidth");
assert(ChildIndexesWidth[*ArrayIndex] < 16 &&
"Index width exceeds 16 digits.");
std::pair<size_t, size_t> Result = std::make_pair(
OrderedChildIdxs[*ArrayIndex], ChildIndexesWidth[*ArrayIndex]);
OrderedChildIdxs[*ArrayIndex]++;
return Result;
}
} // end of namespace dwarflinker_parallel
} // namespace llvm