summaryrefslogtreecommitdiff
path: root/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
commiteb11fae6d08f479c0799db45860a98af528fa6e7 (patch)
tree44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
parentb8a2042aa938069e862750553db0e4d82d25822c (diff)
Notes
Diffstat (limited to 'lib/CodeGen/AsmPrinter/CodeViewDebug.cpp')
-rw-r--r--lib/CodeGen/AsmPrinter/CodeViewDebug.cpp477
1 files changed, 400 insertions, 77 deletions
diff --git a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 1d0a003dc50a..8c5c5478d01a 100644
--- a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -36,7 +36,6 @@
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
-#include "llvm/CodeGen/TargetLoweringObjectFile.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Config/llvm-config.h"
@@ -75,6 +74,7 @@
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include <algorithm>
#include <cassert>
@@ -114,6 +114,16 @@ StringRef CodeViewDebug::getFullFilepath(const DIFile *File) {
StringRef Dir = File->getDirectory(), Filename = File->getFilename();
+ // If this is a Unix-style path, just use it as is. Don't try to canonicalize
+ // it textually because one of the path components could be a symlink.
+ if (!Dir.empty() && Dir[0] == '/') {
+ Filepath = Dir;
+ if (Dir.back() != '/')
+ Filepath += '/';
+ Filepath += Filename;
+ return Filepath;
+ }
+
// Clang emits directory and relative filename info into the IR, but CodeView
// operates on full paths. We could change Clang to emit full paths too, but
// that would increase the IR size and probably not needed for other users.
@@ -165,14 +175,21 @@ unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) {
auto Insertion = FileIdMap.insert(std::make_pair(FullPath, NextId));
if (Insertion.second) {
// We have to compute the full filepath and emit a .cv_file directive.
- std::string Checksum = fromHex(F->getChecksum());
- void *CKMem = OS.getContext().allocate(Checksum.size(), 1);
- memcpy(CKMem, Checksum.data(), Checksum.size());
- ArrayRef<uint8_t> ChecksumAsBytes(reinterpret_cast<const uint8_t *>(CKMem),
- Checksum.size());
- DIFile::ChecksumKind ChecksumKind = F->getChecksumKind();
+ ArrayRef<uint8_t> ChecksumAsBytes;
+ FileChecksumKind CSKind = FileChecksumKind::None;
+ if (F->getChecksum()) {
+ std::string Checksum = fromHex(F->getChecksum()->Value);
+ void *CKMem = OS.getContext().allocate(Checksum.size(), 1);
+ memcpy(CKMem, Checksum.data(), Checksum.size());
+ ChecksumAsBytes = ArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(CKMem), Checksum.size());
+ switch (F->getChecksum()->Kind) {
+ case DIFile::CSK_MD5: CSKind = FileChecksumKind::MD5; break;
+ case DIFile::CSK_SHA1: CSKind = FileChecksumKind::SHA1; break;
+ }
+ }
bool Success = OS.EmitCVFileDirective(NextId, FullPath, ChecksumAsBytes,
- static_cast<unsigned>(ChecksumKind));
+ static_cast<unsigned>(CSKind));
(void)Success;
assert(Success && ".cv_file directive failed");
}
@@ -358,15 +375,15 @@ unsigned CodeViewDebug::getPointerSizeInBytes() {
}
void CodeViewDebug::recordLocalVariable(LocalVariable &&Var,
- const DILocation *InlinedAt) {
- if (InlinedAt) {
+ const LexicalScope *LS) {
+ if (const DILocation *InlinedAt = LS->getInlinedAt()) {
// This variable was inlined. Associate it with the InlineSite.
const DISubprogram *Inlinee = Var.DIVar->getScope()->getSubprogram();
InlineSite &Site = getInlineSite(InlinedAt, Inlinee);
Site.InlinedLocals.emplace_back(Var);
} else {
- // This variable goes in the main ProcSym.
- CurFn->Locals.emplace_back(Var);
+ // This variable goes into the corresponding lexical scope.
+ ScopeVariables[LS].emplace_back(Var);
}
}
@@ -463,7 +480,7 @@ void CodeViewDebug::endModule() {
// Emit per-function debug information.
for (auto &P : FnDebugInfo)
if (!P.first->isDeclarationForLinker())
- emitDebugInfoForFunction(P.first, P.second);
+ emitDebugInfoForFunction(P.first, *P.second);
// Emit global variable debug information.
setCurrentSubprogram(nullptr);
@@ -501,12 +518,12 @@ void CodeViewDebug::endModule() {
clear();
}
-static void emitNullTerminatedSymbolName(MCStreamer &OS, StringRef S) {
+static void emitNullTerminatedSymbolName(MCStreamer &OS, StringRef S,
+ unsigned MaxFixedRecordLength = 0xF00) {
// The maximum CV record length is 0xFF00. Most of the strings we emit appear
// after a fixed length portion of the record. The fixed length portion should
// always be less than 0xF00 (3840) bytes, so truncate the string so that the
// overall record size is less than the maximum allowed.
- unsigned MaxFixedRecordLength = 0xF00;
SmallString<32> NullTerminatedString(
S.take_front(MaxRecordLength - MaxFixedRecordLength - 1));
NullTerminatedString.push_back('\0');
@@ -517,7 +534,7 @@ void CodeViewDebug::emitTypeInformation() {
if (TypeTable.empty())
return;
- // Start the .debug$T section with 0x4.
+ // Start the .debug$T or .debug$P section with 0x4.
OS.SwitchSection(Asm->getObjFileLowering().getCOFFDebugTypesSection());
emitCodeViewMagicVersion();
@@ -572,7 +589,7 @@ void CodeViewDebug::emitTypeGlobalHashes() {
OS.AddComment("Section Version");
OS.EmitIntValue(0, 2);
OS.AddComment("Hash Algorithm");
- OS.EmitIntValue(uint16_t(GlobalTypeHashAlg::SHA1), 2);
+ OS.EmitIntValue(uint16_t(GlobalTypeHashAlg::SHA1_8), 2);
TypeIndex TI(TypeIndex::FirstNonSimpleIndex);
for (const auto &GHR : TypeTable.hashes()) {
@@ -585,7 +602,7 @@ void CodeViewDebug::emitTypeGlobalHashes() {
OS.AddComment(Comment);
++TI;
}
- assert(GHR.Hash.size() % 20 == 0);
+ assert(GHR.Hash.size() == 8);
StringRef S(reinterpret_cast<const char *>(GHR.Hash.data()),
GHR.Hash.size());
OS.EmitBinaryData(S);
@@ -821,10 +838,61 @@ void CodeViewDebug::switchToDebugSectionForSymbol(const MCSymbol *GVSym) {
emitCodeViewMagicVersion();
}
+// Emit an S_THUNK32/S_END symbol pair for a thunk routine.
+// The only supported thunk ordinal is currently the standard type.
+void CodeViewDebug::emitDebugInfoForThunk(const Function *GV,
+ FunctionInfo &FI,
+ const MCSymbol *Fn) {
+ std::string FuncName = GlobalValue::dropLLVMManglingEscape(GV->getName());
+ const ThunkOrdinal ordinal = ThunkOrdinal::Standard; // Only supported kind.
+
+ OS.AddComment("Symbol subsection for " + Twine(FuncName));
+ MCSymbol *SymbolsEnd = beginCVSubsection(DebugSubsectionKind::Symbols);
+
+ // Emit S_THUNK32
+ MCSymbol *ThunkRecordBegin = MMI->getContext().createTempSymbol(),
+ *ThunkRecordEnd = MMI->getContext().createTempSymbol();
+ OS.AddComment("Record length");
+ OS.emitAbsoluteSymbolDiff(ThunkRecordEnd, ThunkRecordBegin, 2);
+ OS.EmitLabel(ThunkRecordBegin);
+ OS.AddComment("Record kind: S_THUNK32");
+ OS.EmitIntValue(unsigned(SymbolKind::S_THUNK32), 2);
+ OS.AddComment("PtrParent");
+ OS.EmitIntValue(0, 4);
+ OS.AddComment("PtrEnd");
+ OS.EmitIntValue(0, 4);
+ OS.AddComment("PtrNext");
+ OS.EmitIntValue(0, 4);
+ OS.AddComment("Thunk section relative address");
+ OS.EmitCOFFSecRel32(Fn, /*Offset=*/0);
+ OS.AddComment("Thunk section index");
+ OS.EmitCOFFSectionIndex(Fn);
+ OS.AddComment("Code size");
+ OS.emitAbsoluteSymbolDiff(FI.End, Fn, 2);
+ OS.AddComment("Ordinal");
+ OS.EmitIntValue(unsigned(ordinal), 1);
+ OS.AddComment("Function name");
+ emitNullTerminatedSymbolName(OS, FuncName);
+ // Additional fields specific to the thunk ordinal would go here.
+ OS.EmitLabel(ThunkRecordEnd);
+
+ // Local variables/inlined routines are purposely omitted here. The point of
+ // marking this as a thunk is so Visual Studio will NOT stop in this routine.
+
+ // Emit S_PROC_ID_END
+ const unsigned RecordLengthForSymbolEnd = 2;
+ OS.AddComment("Record length");
+ OS.EmitIntValue(RecordLengthForSymbolEnd, 2);
+ OS.AddComment("Record kind: S_PROC_ID_END");
+ OS.EmitIntValue(unsigned(SymbolKind::S_PROC_ID_END), 2);
+
+ endCVSubsection(SymbolsEnd);
+}
+
void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
FunctionInfo &FI) {
- // For each function there is a separate subsection
- // which holds the PC to file:line table.
+ // For each function there is a separate subsection which holds the PC to
+ // file:line table.
const MCSymbol *Fn = Asm->getSymbol(GV);
assert(Fn);
@@ -836,6 +904,11 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
assert(SP);
setCurrentSubprogram(SP);
+ if (SP->isThunk()) {
+ emitDebugInfoForThunk(GV, FI, Fn);
+ return;
+ }
+
// If we have a display name, build the fully qualified name by walking the
// chain of scopes.
if (!SP->getName().empty())
@@ -898,6 +971,7 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
OS.EmitLabel(ProcRecordEnd);
emitLocalVariableList(FI.Locals);
+ emitLexicalBlockList(FI.ChildBlocks, FI);
// Emit inlined call site information. Only emit functions inlined directly
// into the parent function. We'll emit the other sites recursively as part
@@ -1018,7 +1092,7 @@ void CodeViewDebug::collectVariableInfoFromMFTable(
LocalVariable Var;
Var.DIVar = VI.Var;
Var.DefRanges.emplace_back(std::move(DefRange));
- recordLocalVariable(std::move(Var), VI.Loc->getInlinedAt());
+ recordLocalVariable(std::move(Var), Scope);
}
}
@@ -1100,7 +1174,7 @@ void CodeViewDebug::calculateRanges(
auto J = std::next(I);
const DIExpression *DIExpr = DVInst->getDebugExpression();
while (J != E &&
- !fragmentsOverlap(DIExpr, J->first->getDebugExpression()))
+ !DIExpr->fragmentsOverlap(J->first->getDebugExpression()))
++J;
if (J != E)
End = getLabelBeforeInsn(J->first);
@@ -1149,14 +1223,15 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
Var.DIVar = DIVar;
calculateRanges(Var, Ranges);
- recordLocalVariable(std::move(Var), InlinedAt);
+ recordLocalVariable(std::move(Var), Scope);
}
}
void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) {
const Function &GV = MF->getFunction();
- assert(FnDebugInfo.count(&GV) == false);
- CurFn = &FnDebugInfo[&GV];
+ auto Insertion = FnDebugInfo.insert({&GV, llvm::make_unique<FunctionInfo>()});
+ assert(Insertion.second && "function already has info");
+ CurFn = Insertion.first->second.get();
CurFn->FuncId = NextFuncId++;
CurFn->Begin = Asm->getFunctionBegin();
@@ -1261,6 +1336,7 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) {
return lowerTypePointer(cast<DIDerivedType>(Ty));
case dwarf::DW_TAG_ptr_to_member_type:
return lowerTypeMemberPointer(cast<DIDerivedType>(Ty));
+ case dwarf::DW_TAG_restrict_type:
case dwarf::DW_TAG_const_type:
case dwarf::DW_TAG_volatile_type:
// TODO: add support for DW_TAG_atomic_type here
@@ -1281,6 +1357,8 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) {
return lowerTypeClass(cast<DICompositeType>(Ty));
case dwarf::DW_TAG_union_type:
return lowerTypeUnion(cast<DICompositeType>(Ty));
+ case dwarf::DW_TAG_unspecified_type:
+ return TypeIndex::None();
default:
// Use the null type index.
return TypeIndex();
@@ -1308,7 +1386,7 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
DITypeRef ElementTypeRef = Ty->getBaseType();
TypeIndex ElementTypeIndex = getTypeIndex(ElementTypeRef);
// IndexType is size_t, which depends on the bitness of the target.
- TypeIndex IndexType = Asm->TM.getPointerSize() == 8
+ TypeIndex IndexType = getPointerSizeInBytes() == 8
? TypeIndex(SimpleTypeKind::UInt64Quad)
: TypeIndex(SimpleTypeKind::UInt32Long);
@@ -1323,7 +1401,9 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
const DISubrange *Subrange = cast<DISubrange>(Element);
assert(Subrange->getLowerBound() == 0 &&
"codeview doesn't support subranges with lower bounds");
- int64_t Count = Subrange->getCount();
+ int64_t Count = -1;
+ if (auto *CI = Subrange->getCount().dyn_cast<ConstantInt*>())
+ Count = CI->getSExtValue();
// Forward declarations of arrays without a size and VLAs use a count of -1.
// Emit a count of zero in these cases to match what MSVC does for arrays
@@ -1441,12 +1521,13 @@ TypeIndex CodeViewDebug::lowerTypeBasic(const DIBasicType *Ty) {
return TypeIndex(STK);
}
-TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) {
+TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty,
+ PointerOptions PO) {
TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType());
- // Pointers to simple types can use SimpleTypeMode, rather than having a
- // dedicated pointer type record.
- if (PointeeTI.isSimple() &&
+ // Pointers to simple types without any options can use SimpleTypeMode, rather
+ // than having a dedicated pointer type record.
+ if (PointeeTI.isSimple() && PO == PointerOptions::None &&
PointeeTI.getSimpleMode() == SimpleTypeMode::Direct &&
Ty->getTag() == dwarf::DW_TAG_pointer_type) {
SimpleTypeMode Mode = Ty->getSizeInBits() == 64
@@ -1470,10 +1551,7 @@ TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) {
PM = PointerMode::RValueReference;
break;
}
- // FIXME: MSVC folds qualifiers into PointerOptions in the context of a method
- // 'this' pointer, but not normal contexts. Figure out what we're supposed to
- // do.
- PointerOptions PO = PointerOptions::None;
+
PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8);
return TypeTable.writeLeafType(PR);
}
@@ -1511,16 +1589,17 @@ translatePtrToMemberRep(unsigned SizeInBytes, bool IsPMF, unsigned Flags) {
llvm_unreachable("invalid ptr to member representation");
}
-TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty) {
+TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty,
+ PointerOptions PO) {
assert(Ty->getTag() == dwarf::DW_TAG_ptr_to_member_type);
TypeIndex ClassTI = getTypeIndex(Ty->getClassType());
TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType(), Ty->getClassType());
- PointerKind PK = Asm->TM.getPointerSize() == 8 ? PointerKind::Near64
- : PointerKind::Near32;
+ PointerKind PK = getPointerSizeInBytes() == 8 ? PointerKind::Near64
+ : PointerKind::Near32;
bool IsPMF = isa<DISubroutineType>(Ty->getBaseType());
PointerMode PM = IsPMF ? PointerMode::PointerToMemberFunction
: PointerMode::PointerToDataMember;
- PointerOptions PO = PointerOptions::None; // FIXME
+
assert(Ty->getSizeInBits() / 8 <= 0xff && "pointer size too big");
uint8_t SizeInBytes = Ty->getSizeInBits() / 8;
MemberPointerInfo MPI(
@@ -1545,6 +1624,7 @@ static CallingConvention dwarfCCToCodeView(unsigned DwarfCC) {
TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) {
ModifierOptions Mods = ModifierOptions::None;
+ PointerOptions PO = PointerOptions::None;
bool IsModifier = true;
const DIType *BaseTy = Ty;
while (IsModifier && BaseTy) {
@@ -1552,9 +1632,16 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) {
switch (BaseTy->getTag()) {
case dwarf::DW_TAG_const_type:
Mods |= ModifierOptions::Const;
+ PO |= PointerOptions::Const;
break;
case dwarf::DW_TAG_volatile_type:
Mods |= ModifierOptions::Volatile;
+ PO |= PointerOptions::Volatile;
+ break;
+ case dwarf::DW_TAG_restrict_type:
+ // Only pointer types be marked with __restrict. There is no known flag
+ // for __restrict in LF_MODIFIER records.
+ PO |= PointerOptions::Restrict;
break;
default:
IsModifier = false;
@@ -1563,7 +1650,31 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) {
if (IsModifier)
BaseTy = cast<DIDerivedType>(BaseTy)->getBaseType().resolve();
}
+
+ // Check if the inner type will use an LF_POINTER record. If so, the
+ // qualifiers will go in the LF_POINTER record. This comes up for types like
+ // 'int *const' and 'int *__restrict', not the more common cases like 'const
+ // char *'.
+ if (BaseTy) {
+ switch (BaseTy->getTag()) {
+ case dwarf::DW_TAG_pointer_type:
+ case dwarf::DW_TAG_reference_type:
+ case dwarf::DW_TAG_rvalue_reference_type:
+ return lowerTypePointer(cast<DIDerivedType>(BaseTy), PO);
+ case dwarf::DW_TAG_ptr_to_member_type:
+ return lowerTypeMemberPointer(cast<DIDerivedType>(BaseTy), PO);
+ default:
+ break;
+ }
+ }
+
TypeIndex ModifiedTI = getTypeIndex(BaseTy);
+
+ // Return the base type index if there aren't any modifiers. For example, the
+ // metadata could contain restrict wrappers around non-pointer types.
+ if (Mods == ModifierOptions::None)
+ return ModifiedTI;
+
ModifierRecord MR(ModifiedTI, Mods);
return TypeTable.writeLeafType(MR);
}
@@ -1573,6 +1684,11 @@ TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
for (DITypeRef ArgTypeRef : Ty->getTypeArray())
ReturnAndArgTypeIndices.push_back(getTypeIndex(ArgTypeRef));
+ // MSVC uses type none for variadic argument.
+ if (ReturnAndArgTypeIndices.size() > 1 &&
+ ReturnAndArgTypeIndices.back() == TypeIndex::Void()) {
+ ReturnAndArgTypeIndices.back() = TypeIndex::None();
+ }
TypeIndex ReturnTypeIndex = TypeIndex::Void();
ArrayRef<TypeIndex> ArgTypeIndices = None;
if (!ReturnAndArgTypeIndices.empty()) {
@@ -1602,6 +1718,11 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
for (DITypeRef ArgTypeRef : Ty->getTypeArray())
ReturnAndArgTypeIndices.push_back(getTypeIndex(ArgTypeRef));
+ // MSVC uses type none for variadic argument.
+ if (ReturnAndArgTypeIndices.size() > 1 &&
+ ReturnAndArgTypeIndices.back() == TypeIndex::Void()) {
+ ReturnAndArgTypeIndices.back() = TypeIndex::None();
+ }
TypeIndex ReturnTypeIndex = TypeIndex::Void();
ArrayRef<TypeIndex> ArgTypeIndices = None;
if (!ReturnAndArgTypeIndices.empty()) {
@@ -1716,6 +1837,26 @@ static ClassOptions getCommonClassOptions(const DICompositeType *Ty) {
return CO;
}
+void CodeViewDebug::addUDTSrcLine(const DIType *Ty, TypeIndex TI) {
+ switch (Ty->getTag()) {
+ case dwarf::DW_TAG_class_type:
+ case dwarf::DW_TAG_structure_type:
+ case dwarf::DW_TAG_union_type:
+ case dwarf::DW_TAG_enumeration_type:
+ break;
+ default:
+ return;
+ }
+
+ if (const auto *File = Ty->getFile()) {
+ StringIdRecord SIDR(TypeIndex(0x0), getFullFilepath(File));
+ TypeIndex SIDI = TypeTable.writeLeafType(SIDR);
+
+ UdtSourceLineRecord USLR(TI, SIDI, Ty->getLine());
+ TypeTable.writeLeafType(USLR);
+ }
+}
+
TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) {
ClassOptions CO = getCommonClassOptions(Ty);
TypeIndex FTI;
@@ -1744,7 +1885,11 @@ TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) {
EnumRecord ER(EnumeratorCount, CO, FTI, FullName, Ty->getIdentifier(),
getTypeIndex(Ty->getBaseType()));
- return TypeTable.writeLeafType(ER);
+ TypeIndex EnumTI = TypeTable.writeLeafType(ER);
+
+ addUDTSrcLine(Ty, EnumTI);
+
+ return EnumTI;
}
//===----------------------------------------------------------------------===//
@@ -1793,12 +1938,33 @@ void CodeViewDebug::collectMemberInfo(ClassInfo &Info,
Info.Members.push_back({DDTy, 0});
return;
}
- // An unnamed member must represent a nested struct or union. Add all the
- // indirect fields to the current record.
+
+ // An unnamed member may represent a nested struct or union. Attempt to
+ // interpret the unnamed member as a DICompositeType possibly wrapped in
+ // qualifier types. Add all the indirect fields to the current record if that
+ // succeeds, and drop the member if that fails.
assert((DDTy->getOffsetInBits() % 8) == 0 && "Unnamed bitfield member!");
uint64_t Offset = DDTy->getOffsetInBits();
const DIType *Ty = DDTy->getBaseType().resolve();
- const DICompositeType *DCTy = cast<DICompositeType>(Ty);
+ bool FullyResolved = false;
+ while (!FullyResolved) {
+ switch (Ty->getTag()) {
+ case dwarf::DW_TAG_const_type:
+ case dwarf::DW_TAG_volatile_type:
+ // FIXME: we should apply the qualifier types to the indirect fields
+ // rather than dropping them.
+ Ty = cast<DIDerivedType>(Ty)->getBaseType().resolve();
+ break;
+ default:
+ FullyResolved = true;
+ break;
+ }
+ }
+
+ const DICompositeType *DCTy = dyn_cast<DICompositeType>(Ty);
+ if (!DCTy)
+ return;
+
ClassInfo NestedInfo = collectClassInfo(DCTy);
for (const ClassInfo::MemberInfo &IndirectField : NestedInfo.Members)
Info.Members.push_back(
@@ -1838,7 +2004,28 @@ ClassInfo CodeViewDebug::collectClassInfo(const DICompositeType *Ty) {
return Info;
}
+static bool shouldAlwaysEmitCompleteClassType(const DICompositeType *Ty) {
+ // This routine is used by lowerTypeClass and lowerTypeUnion to determine
+ // if a complete type should be emitted instead of a forward reference.
+ return Ty->getName().empty() && Ty->getIdentifier().empty() &&
+ !Ty->isForwardDecl();
+}
+
TypeIndex CodeViewDebug::lowerTypeClass(const DICompositeType *Ty) {
+ // Emit the complete type for unnamed structs. C++ classes with methods
+ // which have a circular reference back to the class type are expected to
+ // be named by the front-end and should not be "unnamed". C unnamed
+ // structs should not have circular references.
+ if (shouldAlwaysEmitCompleteClassType(Ty)) {
+ // If this unnamed complete type is already in the process of being defined
+ // then the description of the type is malformed and cannot be emitted
+ // into CodeView correctly so report a fatal error.
+ auto I = CompleteTypeIndices.find(Ty);
+ if (I != CompleteTypeIndices.end() && I->second == TypeIndex())
+ report_fatal_error("cannot debug circular reference to unnamed type");
+ return getCompleteTypeIndex(Ty);
+ }
+
// First, construct the forward decl. Don't look into Ty to compute the
// forward decl options, since it might not be available in all TUs.
TypeRecordKind Kind = getRecordKind(Ty);
@@ -1875,13 +2062,7 @@ TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) {
SizeInBytes, FullName, Ty->getIdentifier());
TypeIndex ClassTI = TypeTable.writeLeafType(CR);
- if (const auto *File = Ty->getFile()) {
- StringIdRecord SIDR(TypeIndex(0x0), getFullFilepath(File));
- TypeIndex SIDI = TypeTable.writeLeafType(SIDR);
-
- UdtSourceLineRecord USLR(ClassTI, SIDI, Ty->getLine());
- TypeTable.writeLeafType(USLR);
- }
+ addUDTSrcLine(Ty, ClassTI);
addToUDTs(Ty);
@@ -1889,6 +2070,10 @@ TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) {
}
TypeIndex CodeViewDebug::lowerTypeUnion(const DICompositeType *Ty) {
+ // Emit the complete type for unnamed unions.
+ if (shouldAlwaysEmitCompleteClassType(Ty))
+ return getCompleteTypeIndex(Ty);
+
ClassOptions CO =
ClassOptions::ForwardReference | getCommonClassOptions(Ty);
std::string FullName = getFullyQualifiedName(Ty);
@@ -1917,11 +2102,7 @@ TypeIndex CodeViewDebug::lowerCompleteTypeUnion(const DICompositeType *Ty) {
Ty->getIdentifier());
TypeIndex UnionTI = TypeTable.writeLeafType(UR);
- StringIdRecord SIR(TypeIndex(0x0), getFullFilepath(Ty->getFile()));
- TypeIndex SIRI = TypeTable.writeLeafType(SIR);
-
- UdtSourceLineRecord USLR(UnionTI, SIRI, Ty->getLine());
- TypeTable.writeLeafType(USLR);
+ addUDTSrcLine(Ty, UnionTI);
addToUDTs(Ty);
@@ -1943,8 +2124,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
for (const DIDerivedType *I : Info.Inheritance) {
if (I->getFlags() & DINode::FlagVirtual) {
// Virtual base.
- // FIXME: Emit VBPtrOffset when the frontend provides it.
- unsigned VBPtrOffset = 0;
+ unsigned VBPtrOffset = I->getVBPtrOffset();
// FIXME: Despite the accessor name, the offset is really in bytes.
unsigned VBTableIndex = I->getOffsetInBits() / 4;
auto RecordKind = (I->getFlags() & DINode::FlagIndirectVirtualBase) == DINode::FlagIndirectVirtualBase
@@ -1956,6 +2136,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
VBTableIndex);
ContinuationBuilder.writeMemberType(VBCR);
+ MemberCount++;
} else {
assert(I->getOffsetInBits() % 8 == 0 &&
"bases must be on byte boundaries");
@@ -1963,6 +2144,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
getTypeIndex(I->getBaseType()),
I->getOffsetInBits() / 8);
ContinuationBuilder.writeMemberType(BCR);
+ MemberCount++;
}
}
@@ -2121,9 +2303,7 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) {
return getTypeIndex(Ty);
}
- // Check if we've already translated the complete record type. Lowering a
- // complete type should never trigger lowering another complete type, so we
- // can reuse the hash table lookup result.
+ // Check if we've already translated the complete record type.
const auto *CTy = cast<DICompositeType>(Ty);
auto InsertResult = CompleteTypeIndices.insert({CTy, TypeIndex()});
if (!InsertResult.second)
@@ -2134,13 +2314,16 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) {
// Make sure the forward declaration is emitted first. It's unclear if this
// is necessary, but MSVC does it, and we should follow suit until we can show
// otherwise.
- TypeIndex FwdDeclTI = getTypeIndex(CTy);
+ // We only emit a forward declaration for named types.
+ if (!CTy->getName().empty() || !CTy->getIdentifier().empty()) {
+ TypeIndex FwdDeclTI = getTypeIndex(CTy);
- // Just use the forward decl if we don't have complete type info. This might
- // happen if the frontend is using modules and expects the complete definition
- // to be emitted elsewhere.
- if (CTy->isForwardDecl())
- return FwdDeclTI;
+ // Just use the forward decl if we don't have complete type info. This
+ // might happen if the frontend is using modules and expects the complete
+ // definition to be emitted elsewhere.
+ if (CTy->isForwardDecl())
+ return FwdDeclTI;
+ }
TypeIndex TI;
switch (CTy->getTag()) {
@@ -2155,7 +2338,11 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) {
llvm_unreachable("not a record");
}
- InsertResult.first->second = TI;
+ // Update the type index associated with this CompositeType. This cannot
+ // use the 'InsertResult' iterator above because it is potentially
+ // invalidated by map insertions which can occur while lowering the class
+ // type above.
+ CompleteTypeIndices[CTy] = TI;
return TI;
}
@@ -2179,10 +2366,10 @@ void CodeViewDebug::emitLocalVariableList(ArrayRef<LocalVariable> Locals) {
for (const LocalVariable &L : Locals)
if (L.DIVar->isParameter())
Params.push_back(&L);
- std::sort(Params.begin(), Params.end(),
- [](const LocalVariable *L, const LocalVariable *R) {
- return L->DIVar->getArg() < R->DIVar->getArg();
- });
+ llvm::sort(Params.begin(), Params.end(),
+ [](const LocalVariable *L, const LocalVariable *R) {
+ return L->DIVar->getArg() < R->DIVar->getArg();
+ });
for (const LocalVariable *L : Params)
emitLocalVariable(*L);
@@ -2272,15 +2459,150 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
}
}
+void CodeViewDebug::emitLexicalBlockList(ArrayRef<LexicalBlock *> Blocks,
+ const FunctionInfo& FI) {
+ for (LexicalBlock *Block : Blocks)
+ emitLexicalBlock(*Block, FI);
+}
+
+/// Emit an S_BLOCK32 and S_END record pair delimiting the contents of a
+/// lexical block scope.
+void CodeViewDebug::emitLexicalBlock(const LexicalBlock &Block,
+ const FunctionInfo& FI) {
+ MCSymbol *RecordBegin = MMI->getContext().createTempSymbol(),
+ *RecordEnd = MMI->getContext().createTempSymbol();
+
+ // Lexical block symbol record.
+ OS.AddComment("Record length");
+ OS.emitAbsoluteSymbolDiff(RecordEnd, RecordBegin, 2); // Record Length
+ OS.EmitLabel(RecordBegin);
+ OS.AddComment("Record kind: S_BLOCK32");
+ OS.EmitIntValue(SymbolKind::S_BLOCK32, 2); // Record Kind
+ OS.AddComment("PtrParent");
+ OS.EmitIntValue(0, 4); // PtrParent
+ OS.AddComment("PtrEnd");
+ OS.EmitIntValue(0, 4); // PtrEnd
+ OS.AddComment("Code size");
+ OS.emitAbsoluteSymbolDiff(Block.End, Block.Begin, 4); // Code Size
+ OS.AddComment("Function section relative address");
+ OS.EmitCOFFSecRel32(Block.Begin, /*Offset=*/0); // Func Offset
+ OS.AddComment("Function section index");
+ OS.EmitCOFFSectionIndex(FI.Begin); // Func Symbol
+ OS.AddComment("Lexical block name");
+ emitNullTerminatedSymbolName(OS, Block.Name); // Name
+ OS.EmitLabel(RecordEnd);
+
+ // Emit variables local to this lexical block.
+ emitLocalVariableList(Block.Locals);
+
+ // Emit lexical blocks contained within this block.
+ emitLexicalBlockList(Block.Children, FI);
+
+ // Close the lexical block scope.
+ OS.AddComment("Record length");
+ OS.EmitIntValue(2, 2); // Record Length
+ OS.AddComment("Record kind: S_END");
+ OS.EmitIntValue(SymbolKind::S_END, 2); // Record Kind
+}
+
+/// Convenience routine for collecting lexical block information for a list
+/// of lexical scopes.
+void CodeViewDebug::collectLexicalBlockInfo(
+ SmallVectorImpl<LexicalScope *> &Scopes,
+ SmallVectorImpl<LexicalBlock *> &Blocks,
+ SmallVectorImpl<LocalVariable> &Locals) {
+ for (LexicalScope *Scope : Scopes)
+ collectLexicalBlockInfo(*Scope, Blocks, Locals);
+}
+
+/// Populate the lexical blocks and local variable lists of the parent with
+/// information about the specified lexical scope.
+void CodeViewDebug::collectLexicalBlockInfo(
+ LexicalScope &Scope,
+ SmallVectorImpl<LexicalBlock *> &ParentBlocks,
+ SmallVectorImpl<LocalVariable> &ParentLocals) {
+ if (Scope.isAbstractScope())
+ return;
+
+ auto LocalsIter = ScopeVariables.find(&Scope);
+ if (LocalsIter == ScopeVariables.end()) {
+ // This scope does not contain variables and can be eliminated.
+ collectLexicalBlockInfo(Scope.getChildren(), ParentBlocks, ParentLocals);
+ return;
+ }
+ SmallVectorImpl<LocalVariable> &Locals = LocalsIter->second;
+
+ const DILexicalBlock *DILB = dyn_cast<DILexicalBlock>(Scope.getScopeNode());
+ if (!DILB) {
+ // This scope is not a lexical block and can be eliminated, but keep any
+ // local variables it contains.
+ ParentLocals.append(Locals.begin(), Locals.end());
+ collectLexicalBlockInfo(Scope.getChildren(), ParentBlocks, ParentLocals);
+ return;
+ }
+
+ const SmallVectorImpl<InsnRange> &Ranges = Scope.getRanges();
+ if (Ranges.size() != 1 || !getLabelAfterInsn(Ranges.front().second)) {
+ // This lexical block scope has too many address ranges to represent in the
+ // current CodeView format or does not have a valid address range.
+ // Eliminate this lexical scope and promote any locals it contains to the
+ // parent scope.
+ //
+ // For lexical scopes with multiple address ranges you may be tempted to
+ // construct a single range covering every instruction where the block is
+ // live and everything in between. Unfortunately, Visual Studio only
+ // displays variables from the first matching lexical block scope. If the
+ // first lexical block contains exception handling code or cold code which
+ // is moved to the bottom of the routine creating a single range covering
+ // nearly the entire routine, then it will hide all other lexical blocks
+ // and the variables they contain.
+ //
+ ParentLocals.append(Locals.begin(), Locals.end());
+ collectLexicalBlockInfo(Scope.getChildren(), ParentBlocks, ParentLocals);
+ return;
+ }
+
+ // Create a new CodeView lexical block for this lexical scope. If we've
+ // seen this DILexicalBlock before then the scope tree is malformed and
+ // we can handle this gracefully by not processing it a second time.
+ auto BlockInsertion = CurFn->LexicalBlocks.insert({DILB, LexicalBlock()});
+ if (!BlockInsertion.second)
+ return;
+
+ // Create a lexical block containing the local variables and collect the
+ // the lexical block information for the children.
+ const InsnRange &Range = Ranges.front();
+ assert(Range.first && Range.second);
+ LexicalBlock &Block = BlockInsertion.first->second;
+ Block.Begin = getLabelBeforeInsn(Range.first);
+ Block.End = getLabelAfterInsn(Range.second);
+ assert(Block.Begin && "missing label for scope begin");
+ assert(Block.End && "missing label for scope end");
+ Block.Name = DILB->getName();
+ Block.Locals = std::move(Locals);
+ ParentBlocks.push_back(&Block);
+ collectLexicalBlockInfo(Scope.getChildren(), Block.Children, Block.Locals);
+}
+
void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) {
const Function &GV = MF->getFunction();
assert(FnDebugInfo.count(&GV));
- assert(CurFn == &FnDebugInfo[&GV]);
+ assert(CurFn == FnDebugInfo[&GV].get());
collectVariableInfo(GV.getSubprogram());
+ // Build the lexical block structure to emit for this routine.
+ if (LexicalScope *CFS = LScopes.getCurrentFunctionScope())
+ collectLexicalBlockInfo(*CFS, CurFn->ChildBlocks, CurFn->Locals);
+
+ // Clear the scope and variable information from the map which will not be
+ // valid after we have finished processing this routine. This also prepares
+ // the map for the subsequent routine.
+ ScopeVariables.clear();
+
// Don't emit anything if we don't have any line tables.
- if (!CurFn->HaveLineInfo) {
+ // Thunks are compiler-generated and probably won't have source correlation.
+ if (!CurFn->HaveLineInfo && !GV.getSubprogram()->isThunk()) {
FnDebugInfo.erase(&GV);
CurFn = nullptr;
return;
@@ -2296,8 +2618,8 @@ void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) {
void CodeViewDebug::beginInstruction(const MachineInstr *MI) {
DebugHandlerBase::beginInstruction(MI);
- // Ignore DBG_VALUE locations and function prologue.
- if (!Asm || !CurFn || MI->isDebugValue() ||
+ // Ignore DBG_VALUE and DBG_LABEL locations and function prologue.
+ if (!Asm || !CurFn || MI->isDebugInstr() ||
MI->getFlag(MachineInstr::FrameSetup))
return;
@@ -2306,7 +2628,7 @@ void CodeViewDebug::beginInstruction(const MachineInstr *MI) {
DebugLoc DL = MI->getDebugLoc();
if (!DL && MI->getParent() != PrevInstBB) {
for (const auto &NextMI : *MI->getParent()) {
- if (NextMI.isDebugValue())
+ if (NextMI.isDebugInstr())
continue;
DL = NextMI.getDebugLoc();
if (DL)
@@ -2432,6 +2754,7 @@ void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV,
// FIXME: Thread local data, etc
MCSymbol *DataBegin = MMI->getContext().createTempSymbol(),
*DataEnd = MMI->getContext().createTempSymbol();
+ const unsigned FixedLengthOfThisRecord = 12;
OS.AddComment("Record length");
OS.emitAbsoluteSymbolDiff(DataEnd, DataBegin, 2);
OS.EmitLabel(DataBegin);
@@ -2459,6 +2782,6 @@ void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV,
OS.AddComment("Segment");
OS.EmitCOFFSectionIndex(GVSym);
OS.AddComment("Name");
- emitNullTerminatedSymbolName(OS, DIGV->getName());
+ emitNullTerminatedSymbolName(OS, DIGV->getName(), FixedLengthOfThisRecord);
OS.EmitLabel(DataEnd);
}