diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-12-18 20:30:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2024-04-06 20:11:55 +0000 |
commit | 5f757f3ff9144b609b3c433dfd370cc6bdc191ad (patch) | |
tree | 1b4e980b866cd26a00af34c0a653eb640bd09caf /contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | |
parent | 3e1c8a35f741a5d114d0ba670b15191355711fe9 (diff) | |
parent | 312c0ed19cc5276a17bacf2120097bec4515b0f1 (diff) |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 203 |
1 files changed, 193 insertions, 10 deletions
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 8161de57b58e..dddc08b3bc01 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -13,6 +13,7 @@ #include "CodeViewDebug.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/TinyPtrVector.h" @@ -26,6 +27,7 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Config/llvm-config.h" @@ -54,7 +56,6 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" @@ -141,7 +142,7 @@ StringRef CodeViewDebug::getFullFilepath(const DIFile *File) { // 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.startswith("/") || Filename.startswith("/")) { + if (Dir.starts_with("/") || Filename.starts_with("/")) { if (llvm::sys::path::is_absolute(Filename, llvm::sys::path::Style::posix)) return Filename; Filepath = std::string(Dir); @@ -248,7 +249,10 @@ CodeViewDebug::getInlineSite(const DILocation *InlinedAt, InlinedAt->getLine(), InlinedAt->getColumn(), SMLoc()); Site->Inlinee = Inlinee; InlinedSubprograms.insert(Inlinee); - getFuncIdForSubprogram(Inlinee); + auto InlineeIdx = getFuncIdForSubprogram(Inlinee); + + if (InlinedAt->getInlinedAt() == nullptr) + CurFn->Inlinees.insert(InlineeIdx); } return *Site; } @@ -906,10 +910,10 @@ static std::string flattenCommandLine(ArrayRef<std::string> Args, i++; // Skip this argument and next one. continue; } - if (Arg.startswith("-object-file-name") || Arg == MainFilename) + if (Arg.starts_with("-object-file-name") || Arg == MainFilename) continue; // Skip fmessage-length for reproduciability. - if (Arg.startswith("-fmessage-length")) + if (Arg.starts_with("-fmessage-length")) continue; if (PrintedOneArg) OS << " "; @@ -1192,6 +1196,7 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, OS.emitInt32(uint32_t(FI.FrameProcOpts)); endSymbolRecord(FrameProcEnd); + emitInlinees(FI.Inlinees); emitLocalVariableList(FI, FI.Locals); emitGlobalVariableList(FI.Globals); emitLexicalBlockList(FI.ChildBlocks, FI); @@ -1243,6 +1248,8 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, if (SP != nullptr) emitDebugInfoForUDTs(LocalUDTs); + emitDebugInfoForJumpTables(FI); + // We're done with this function. emitEndSymbolRecord(SymbolKind::S_PROC_ID_END); } @@ -1390,6 +1397,12 @@ void CodeViewDebug::calculateRanges( if (Location->Register == 0 || Location->LoadChain.size() > 1) continue; + // Codeview can only express byte-aligned offsets, ensure that we have a + // byte-boundaried location. + if (Location->FragmentInfo) + if (Location->FragmentInfo->OffsetInBits % 8) + continue; + LocalVarDef DR; DR.CVRegister = TRI->getCodeViewRegNum(Location->Register); DR.InMemory = !Location->LoadChain.empty(); @@ -1533,8 +1546,8 @@ void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { } FPO |= FrameProcedureOptions(uint32_t(CurFn->EncodedLocalFramePtrReg) << 14U); FPO |= FrameProcedureOptions(uint32_t(CurFn->EncodedParamFramePtrReg) << 16U); - if (Asm->TM.getOptLevel() != CodeGenOpt::None && - !GV.hasOptSize() && !GV.hasOptNone()) + if (Asm->TM.getOptLevel() != CodeGenOptLevel::None && !GV.hasOptSize() && + !GV.hasOptNone()) FPO |= FrameProcedureOptions::OptimizedForSpeed; if (GV.hasProfileData()) { FPO |= FrameProcedureOptions::ValidProfileCounts; @@ -1578,6 +1591,11 @@ void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { } } } + + // Mark branches that may potentially be using jump tables with labels. + bool isThumb = Triple(MMI->getModule()->getTargetTriple()).getArch() == + llvm::Triple::ArchType::thumb; + discoverJumpTableBranches(MF, isThumb); } static bool shouldEmitUdt(const DIType *T) { @@ -2571,7 +2589,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { // Virtual function pointer member. if ((Member->getFlags() & DINode::FlagArtificial) && - Member->getName().startswith("_vptr$")) { + Member->getName().starts_with("_vptr$")) { VFPtrRecord VFPR(getTypeIndex(Member->getBaseType())); ContinuationBuilder.writeMemberType(VFPR); MemberCount++; @@ -3024,7 +3042,7 @@ void CodeViewDebug::collectLexicalBlockInfo( if (!BlockInsertion.second) return; - // Create a lexical block containing the variables and collect the the + // Create a lexical block containing the variables and collect the // lexical block information for the children. const InsnRange &Range = Ranges.front(); assert(Range.first && Range.second); @@ -3083,6 +3101,10 @@ void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) { } } + bool isThumb = Triple(MMI->getModule()->getTargetTriple()).getArch() == + llvm::Triple::ArchType::thumb; + collectDebugInfoForJumpTables(MF, isThumb); + CurFn->Annotations = MF->getCodeViewAnnotations(); CurFn->End = Asm->getFunctionEnd(); @@ -3336,7 +3358,7 @@ void CodeViewDebug::emitConstantSymbolRecord(const DIType *DTy, APSInt &Value, // Encoded integers shouldn't need more than 10 bytes. uint8_t Data[10]; - BinaryStreamWriter Writer(Data, llvm::support::endianness::little); + BinaryStreamWriter Writer(Data, llvm::endianness::little); CodeViewRecordIO IO(Writer); cantFail(IO.mapEncodedInteger(Value)); StringRef SRef((char *)Data, Writer.getOffset()); @@ -3442,3 +3464,164 @@ void CodeViewDebug::emitDebugInfoForGlobal(const CVGlobalVariable &CVGV) { emitConstantSymbolRecord(DIGV->getType(), Value, QualifiedName); } } + +void forEachJumpTableBranch( + const MachineFunction *MF, bool isThumb, + const std::function<void(const MachineJumpTableInfo &, const MachineInstr &, + int64_t)> &Callback) { + auto JTI = MF->getJumpTableInfo(); + if (JTI && !JTI->isEmpty()) { +#ifndef NDEBUG + auto UsedJTs = llvm::SmallBitVector(JTI->getJumpTables().size()); +#endif + for (const auto &MBB : *MF) { + // Search for indirect branches... + const auto LastMI = MBB.getFirstTerminator(); + if (LastMI != MBB.end() && LastMI->isIndirectBranch()) { + if (isThumb) { + // ... that directly use jump table operands. + // NOTE: ARM uses pattern matching to lower its BR_JT SDNode to + // machine instructions, hence inserting a JUMP_TABLE_DEBUG_INFO node + // interferes with this process *but* the resulting pseudo-instruction + // uses a Jump Table operand, so extract the jump table index directly + // from that. + for (const auto &MO : LastMI->operands()) { + if (MO.isJTI()) { + unsigned Index = MO.getIndex(); +#ifndef NDEBUG + UsedJTs.set(Index); +#endif + Callback(*JTI, *LastMI, Index); + break; + } + } + } else { + // ... that have jump table debug info. + // NOTE: The debug info is inserted as a JUMP_TABLE_DEBUG_INFO node + // when lowering the BR_JT SDNode to an indirect branch. + for (auto I = MBB.instr_rbegin(), E = MBB.instr_rend(); I != E; ++I) { + if (I->isJumpTableDebugInfo()) { + unsigned Index = I->getOperand(0).getImm(); +#ifndef NDEBUG + UsedJTs.set(Index); +#endif + Callback(*JTI, *LastMI, Index); + break; + } + } + } + } + } +#ifndef NDEBUG + assert(UsedJTs.all() && + "Some of jump tables were not used in a debug info instruction"); +#endif + } +} + +void CodeViewDebug::discoverJumpTableBranches(const MachineFunction *MF, + bool isThumb) { + forEachJumpTableBranch( + MF, isThumb, + [this](const MachineJumpTableInfo &, const MachineInstr &BranchMI, + int64_t) { requestLabelBeforeInsn(&BranchMI); }); +} + +void CodeViewDebug::collectDebugInfoForJumpTables(const MachineFunction *MF, + bool isThumb) { + forEachJumpTableBranch( + MF, isThumb, + [this, MF](const MachineJumpTableInfo &JTI, const MachineInstr &BranchMI, + int64_t JumpTableIndex) { + // For label-difference jump tables, find the base expression. + // Otherwise the jump table uses an absolute address (so no base + // is required). + const MCSymbol *Base; + uint64_t BaseOffset = 0; + const MCSymbol *Branch = getLabelBeforeInsn(&BranchMI); + JumpTableEntrySize EntrySize; + switch (JTI.getEntryKind()) { + case MachineJumpTableInfo::EK_Custom32: + case MachineJumpTableInfo::EK_GPRel32BlockAddress: + case MachineJumpTableInfo::EK_GPRel64BlockAddress: + llvm_unreachable( + "EK_Custom32, EK_GPRel32BlockAddress, and " + "EK_GPRel64BlockAddress should never be emitted for COFF"); + case MachineJumpTableInfo::EK_BlockAddress: + // Each entry is an absolute address. + EntrySize = JumpTableEntrySize::Pointer; + Base = nullptr; + break; + case MachineJumpTableInfo::EK_Inline: + case MachineJumpTableInfo::EK_LabelDifference32: + case MachineJumpTableInfo::EK_LabelDifference64: + // Ask the AsmPrinter. + std::tie(Base, BaseOffset, Branch, EntrySize) = + Asm->getCodeViewJumpTableInfo(JumpTableIndex, &BranchMI, Branch); + break; + } + + CurFn->JumpTables.push_back( + {EntrySize, Base, BaseOffset, Branch, + MF->getJTISymbol(JumpTableIndex, MMI->getContext()), + JTI.getJumpTables()[JumpTableIndex].MBBs.size()}); + }); +} + +void CodeViewDebug::emitDebugInfoForJumpTables(const FunctionInfo &FI) { + for (auto JumpTable : FI.JumpTables) { + MCSymbol *JumpTableEnd = beginSymbolRecord(SymbolKind::S_ARMSWITCHTABLE); + if (JumpTable.Base) { + OS.AddComment("Base offset"); + OS.emitCOFFSecRel32(JumpTable.Base, JumpTable.BaseOffset); + OS.AddComment("Base section index"); + OS.emitCOFFSectionIndex(JumpTable.Base); + } else { + OS.AddComment("Base offset"); + OS.emitInt32(0); + OS.AddComment("Base section index"); + OS.emitInt16(0); + } + OS.AddComment("Switch type"); + OS.emitInt16(static_cast<uint16_t>(JumpTable.EntrySize)); + OS.AddComment("Branch offset"); + OS.emitCOFFSecRel32(JumpTable.Branch, /*Offset=*/0); + OS.AddComment("Table offset"); + OS.emitCOFFSecRel32(JumpTable.Table, /*Offset=*/0); + OS.AddComment("Branch section index"); + OS.emitCOFFSectionIndex(JumpTable.Branch); + OS.AddComment("Table section index"); + OS.emitCOFFSectionIndex(JumpTable.Table); + OS.AddComment("Entries count"); + OS.emitInt32(JumpTable.TableSize); + endSymbolRecord(JumpTableEnd); + } +} + +void CodeViewDebug::emitInlinees( + const SmallSet<codeview::TypeIndex, 1> &Inlinees) { + // Divide the list of inlinees into chunks such that each chunk fits within + // one record. + constexpr size_t ChunkSize = + (MaxRecordLength - sizeof(SymbolKind) - sizeof(uint32_t)) / + sizeof(uint32_t); + + SmallVector<TypeIndex> SortedInlinees{Inlinees.begin(), Inlinees.end()}; + llvm::sort(SortedInlinees); + + size_t CurrentIndex = 0; + while (CurrentIndex < SortedInlinees.size()) { + auto Symbol = beginSymbolRecord(SymbolKind::S_INLINEES); + auto CurrentChunkSize = + std::min(ChunkSize, SortedInlinees.size() - CurrentIndex); + OS.AddComment("Count"); + OS.emitInt32(CurrentChunkSize); + + const size_t CurrentChunkEnd = CurrentIndex + CurrentChunkSize; + for (; CurrentIndex < CurrentChunkEnd; ++CurrentIndex) { + OS.AddComment("Inlinee"); + OS.emitInt32(SortedInlinees[CurrentIndex].getIndex()); + } + endSymbolRecord(Symbol); + } +} |