Skip to content

[NFC][DebugInfo] Wrap DILineInfo return type with std::optional to handle missing debug info. #129792

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 17, 2025

Conversation

ZequanWu
Copy link
Contributor

@ZequanWu ZequanWu commented Mar 4, 2025

Currently, DIContext::getLineInfoForAddress and DIContext::getLineInfoForDataAddress returns empty DILineInfo when the debug info is missing for the given address. This is not differentiable with the case when debug info is found for the given address but the debug info is default value (filename:linenum is :0).

This change wraps the return types of DIContext::getLineInfoForAddress and DIContext::getLineInfoForDataAddress with std::optional.

@llvmbot
Copy link
Member

llvmbot commented Mar 4, 2025

@llvm/pr-subscribers-platform-windows

@llvm/pr-subscribers-debuginfo

Author: Zequan Wu (ZequanWu)

Changes

Currently, DIContext::getLineInfoForAddress and DIContext::getLineInfoForDataAddress returns empty DILineInfo when the debug info is missing for the given address. This is not differentiable with the case when debug info is found for the given address but the debug info is default value (filename:linenum is <invalid>:0). This change makes it clear that std::nullopt is returned from these APIs when debug info is missing for the given address.


Full diff: https://github.com/llvm/llvm-project/pull/129792.diff

13 Files Affected:

  • (modified) llvm/include/llvm/DebugInfo/BTF/BTFContext.h (+2-2)
  • (modified) llvm/include/llvm/DebugInfo/DIContext.h (+4-2)
  • (modified) llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h (+2-2)
  • (modified) llvm/include/llvm/DebugInfo/PDB/PDBContext.h (+2-2)
  • (modified) llvm/lib/DebugInfo/BTF/BTFContext.cpp (+7-5)
  • (modified) llvm/lib/DebugInfo/DWARF/DWARFContext.cpp (+14-10)
  • (modified) llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp (+5-2)
  • (modified) llvm/lib/DebugInfo/PDB/PDBContext.cpp (+17-10)
  • (modified) llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp (+10-6)
  • (modified) llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp (+4-1)
  • (modified) llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp (+4-2)
  • (modified) llvm/tools/llvm-objdump/MachODump.cpp (+6-5)
  • (modified) llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp (+9-11)
diff --git a/llvm/include/llvm/DebugInfo/BTF/BTFContext.h b/llvm/include/llvm/DebugInfo/BTF/BTFContext.h
index c16bee6133220..e3f7f57749ff1 100644
--- a/llvm/include/llvm/DebugInfo/BTF/BTFContext.h
+++ b/llvm/include/llvm/DebugInfo/BTF/BTFContext.h
@@ -30,11 +30,11 @@ class BTFContext final : public DIContext {
     // BTF is no DWARF, so ignore this operation for now.
   }
 
-  DILineInfo getLineInfoForAddress(
+  std::optional<DILineInfo> getLineInfoForAddress(
       object::SectionedAddress Address,
       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
 
-  DILineInfo
+  std::optional<DILineInfo>
   getLineInfoForDataAddress(object::SectionedAddress Address) override;
 
   DILineInfoTable getLineInfoForAddressRange(
diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h
index 71685ba09d8db..c90b99987f1db 100644
--- a/llvm/include/llvm/DebugInfo/DIContext.h
+++ b/llvm/include/llvm/DebugInfo/DIContext.h
@@ -252,10 +252,12 @@ class DIContext {
     return true;
   }
 
-  virtual DILineInfo getLineInfoForAddress(
+  // For getLineInfoForAddress and getLineInfoForDataAddress, std::nullopt is
+  // returned when debug info is missing for the given address.
+  virtual std::optional<DILineInfo> getLineInfoForAddress(
       object::SectionedAddress Address,
       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
-  virtual DILineInfo
+  virtual std::optional<DILineInfo>
   getLineInfoForDataAddress(object::SectionedAddress Address) = 0;
   virtual DILineInfoTable getLineInfoForAddressRange(
       object::SectionedAddress Address, uint64_t Size,
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
index 0d6e2b076cc34..6df3f5066e327 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
@@ -386,10 +386,10 @@ class DWARFContext : public DIContext {
   ///            executable's debug info.
   DIEsForAddress getDIEsForAddress(uint64_t Address, bool CheckDWO = false);
 
-  DILineInfo getLineInfoForAddress(
+  std::optional<DILineInfo> getLineInfoForAddress(
       object::SectionedAddress Address,
       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
-  DILineInfo
+  std::optional<DILineInfo>
   getLineInfoForDataAddress(object::SectionedAddress Address) override;
   DILineInfoTable getLineInfoForAddressRange(
       object::SectionedAddress Address, uint64_t Size,
diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBContext.h b/llvm/include/llvm/DebugInfo/PDB/PDBContext.h
index 3163c0a1dae03..fedfcd483dcc3 100644
--- a/llvm/include/llvm/DebugInfo/PDB/PDBContext.h
+++ b/llvm/include/llvm/DebugInfo/PDB/PDBContext.h
@@ -42,10 +42,10 @@ namespace pdb {
 
     void dump(raw_ostream &OS, DIDumpOptions DIDumpOpts) override;
 
-    DILineInfo getLineInfoForAddress(
+    std::optional<DILineInfo> getLineInfoForAddress(
         object::SectionedAddress Address,
         DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
-    DILineInfo
+    std::optional<DILineInfo>
     getLineInfoForDataAddress(object::SectionedAddress Address) override;
     DILineInfoTable getLineInfoForAddressRange(
         object::SectionedAddress Address, uint64_t Size,
diff --git a/llvm/lib/DebugInfo/BTF/BTFContext.cpp b/llvm/lib/DebugInfo/BTF/BTFContext.cpp
index 2e651cb378dbf..412bd42ee0b67 100644
--- a/llvm/lib/DebugInfo/BTF/BTFContext.cpp
+++ b/llvm/lib/DebugInfo/BTF/BTFContext.cpp
@@ -20,12 +20,13 @@ using namespace llvm;
 using object::ObjectFile;
 using object::SectionedAddress;
 
-DILineInfo BTFContext::getLineInfoForAddress(SectionedAddress Address,
-                                             DILineInfoSpecifier Specifier) {
+std::optional<DILineInfo>
+BTFContext::getLineInfoForAddress(SectionedAddress Address,
+                                  DILineInfoSpecifier Specifier) {
   const BTF::BPFLineInfo *LineInfo = BTF.findLineInfo(Address);
   DILineInfo Result;
   if (!LineInfo)
-    return Result;
+    return std::nullopt;
 
   Result.LineSource = BTF.findString(LineInfo->LineOff);
   Result.FileName = BTF.findString(LineInfo->FileNameOff);
@@ -34,9 +35,10 @@ DILineInfo BTFContext::getLineInfoForAddress(SectionedAddress Address,
   return Result;
 }
 
-DILineInfo BTFContext::getLineInfoForDataAddress(SectionedAddress Address) {
+std::optional<DILineInfo>
+BTFContext::getLineInfoForDataAddress(SectionedAddress Address) {
   // BTF does not convey such information.
-  return {};
+  return std::nullopt;
 }
 
 DILineInfoTable
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 99e1642ff23ad..afa91b098efe5 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -1730,40 +1730,44 @@ DWARFContext::getLocalsForAddress(object::SectionedAddress Address) {
   return Result;
 }
 
-DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
-                                               DILineInfoSpecifier Spec) {
-  DILineInfo Result;
+std::optional<DILineInfo>
+DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
+                                    DILineInfoSpecifier Spec) {
   DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address.Address);
   if (!CU)
-    return Result;
+    return std::nullopt;
 
-  getFunctionNameAndStartLineForAddress(
+  DILineInfo Result;
+  bool HasDebugInfoForAddress = getFunctionNameAndStartLineForAddress(
       CU, Address.Address, Spec.FNKind, Spec.FLIKind, Result.FunctionName,
       Result.StartFileName, Result.StartLine, Result.StartAddress);
   if (Spec.FLIKind != FileLineInfoKind::None) {
     if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) {
-      LineTable->getFileLineInfoForAddress(
+      HasDebugInfoForAddress |= LineTable->getFileLineInfoForAddress(
           {Address.Address, Address.SectionIndex}, Spec.ApproximateLine,
           CU->getCompilationDir(), Spec.FLIKind, Result);
     }
   }
+  if (!HasDebugInfoForAddress)
+    return std::nullopt;
 
   return Result;
 }
 
-DILineInfo
+std::optional<DILineInfo>
 DWARFContext::getLineInfoForDataAddress(object::SectionedAddress Address) {
-  DILineInfo Result;
   DWARFCompileUnit *CU = getCompileUnitForDataAddress(Address.Address);
   if (!CU)
-    return Result;
+    return std::nullopt;
 
   if (DWARFDie Die = CU->getVariableForAddress(Address.Address)) {
+    DILineInfo Result;
     Result.FileName = Die.getDeclFile(FileLineInfoKind::AbsoluteFilePath);
     Result.Line = Die.getDeclLine();
+    return Result;
   }
 
-  return Result;
+  return std::nullopt;
 }
 
 DILineInfoTable DWARFContext::getLineInfoForAddressRange(
diff --git a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
index 568af5ee8e3ae..23d9c1f5ddf2c 100644
--- a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
+++ b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
@@ -728,8 +728,11 @@ llvm::Error DwarfTransformer::verify(StringRef GsymPath,
           DICtx.getInliningInfoForAddress(SectAddr, DLIS);
       uint32_t NumDwarfInlineInfos = DwarfInlineInfos.getNumberOfFrames();
       if (NumDwarfInlineInfos == 0) {
-        DwarfInlineInfos.addFrame(
-            DICtx.getLineInfoForAddress(SectAddr, DLIS));
+        if (std::optional<DILineInfo> DwarfLineInfo =
+                DICtx.getLineInfoForAddress(SectAddr, DLIS))
+          DwarfInlineInfos.addFrame(*DwarfLineInfo);
+        else
+          DwarfInlineInfos.addFrame(DILineInfo());
       }
 
       // Check for 1 entry that has no file and line info
diff --git a/llvm/lib/DebugInfo/PDB/PDBContext.cpp b/llvm/lib/DebugInfo/PDB/PDBContext.cpp
index e600fb7385f13..dd38295ac62b5 100644
--- a/llvm/lib/DebugInfo/PDB/PDBContext.cpp
+++ b/llvm/lib/DebugInfo/PDB/PDBContext.cpp
@@ -32,8 +32,9 @@ PDBContext::PDBContext(const COFFObjectFile &Object,
 
 void PDBContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts){}
 
-DILineInfo PDBContext::getLineInfoForAddress(object::SectionedAddress Address,
-                                             DILineInfoSpecifier Specifier) {
+std::optional<DILineInfo>
+PDBContext::getLineInfoForAddress(object::SectionedAddress Address,
+                                  DILineInfoSpecifier Specifier) {
   DILineInfo Result;
   Result.FunctionName = getFunctionName(Address.Address, Specifier.FNKind);
 
@@ -64,11 +65,11 @@ DILineInfo PDBContext::getLineInfoForAddress(object::SectionedAddress Address,
   return Result;
 }
 
-DILineInfo
+std::optional<DILineInfo>
 PDBContext::getLineInfoForDataAddress(object::SectionedAddress Address) {
   // Unimplemented. S_GDATA and S_LDATA in CodeView (used to describe global
   // variables) aren't capable of carrying line information.
-  return DILineInfo();
+  return std::nullopt;
 }
 
 DILineInfoTable
@@ -84,9 +85,11 @@ PDBContext::getLineInfoForAddressRange(object::SectionedAddress Address,
     return Table;
 
   while (auto LineInfo = LineNumbers->getNext()) {
-    DILineInfo LineEntry = getLineInfoForAddress(
+    std::optional<DILineInfo> LineEntry = getLineInfoForAddress(
         {LineInfo->getVirtualAddress(), Address.SectionIndex}, Specifier);
-    Table.push_back(std::make_pair(LineInfo->getVirtualAddress(), LineEntry));
+    if (LineEntry)
+      Table.push_back(
+          std::make_pair(LineInfo->getVirtualAddress(), *LineEntry));
   }
   return Table;
 }
@@ -95,19 +98,22 @@ DIInliningInfo
 PDBContext::getInliningInfoForAddress(object::SectionedAddress Address,
                                       DILineInfoSpecifier Specifier) {
   DIInliningInfo InlineInfo;
-  DILineInfo CurrentLine = getLineInfoForAddress(Address, Specifier);
+  std::optional<DILineInfo> CurrentLine =
+      getLineInfoForAddress(Address, Specifier);
 
   // Find the function at this address.
   std::unique_ptr<PDBSymbol> ParentFunc =
       Session->findSymbolByAddress(Address.Address, PDB_SymType::Function);
   if (!ParentFunc) {
-    InlineInfo.addFrame(CurrentLine);
+    if (CurrentLine)
+      InlineInfo.addFrame(*CurrentLine);
     return InlineInfo;
   }
 
   auto Frames = ParentFunc->findInlineFramesByVA(Address.Address);
   if (!Frames || Frames->getChildCount() == 0) {
-    InlineInfo.addFrame(CurrentLine);
+    if (CurrentLine)
+      InlineInfo.addFrame(*CurrentLine);
     return InlineInfo;
   }
 
@@ -131,7 +137,8 @@ PDBContext::getInliningInfoForAddress(object::SectionedAddress Address,
     InlineInfo.addFrame(LineInfo);
   }
 
-  InlineInfo.addFrame(CurrentLine);
+  if (CurrentLine)
+    InlineInfo.addFrame(*CurrentLine);
   return InlineInfo;
 }
 
diff --git a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
index d5e1dc759df5c..dcd6188daf580 100644
--- a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
@@ -276,8 +276,11 @@ SymbolizableObjectFile::symbolizeCode(object::SectionedAddress ModuleOffset,
   if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)
     ModuleOffset.SectionIndex =
         getModuleSectionIndexForAddress(ModuleOffset.Address);
-  DILineInfo LineInfo =
-      DebugInfoContext->getLineInfoForAddress(ModuleOffset, LineInfoSpecifier);
+  DILineInfo LineInfo;
+  if (std::optional<DILineInfo> DBGLineInfo =
+          DebugInfoContext->getLineInfoForAddress(ModuleOffset,
+                                                  LineInfoSpecifier))
+    LineInfo = *DBGLineInfo;
 
   // Override function name from symbol table if necessary.
   if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) {
@@ -334,10 +337,11 @@ DIGlobal SymbolizableObjectFile::symbolizeData(
   Res.DeclFile = FileName;
 
   // Try and get a better filename:lineno pair from the debuginfo, if present.
-  DILineInfo DL = DebugInfoContext->getLineInfoForDataAddress(ModuleOffset);
-  if (DL.Line != 0) {
-    Res.DeclFile = DL.FileName;
-    Res.DeclLine = DL.Line;
+  std::optional<DILineInfo> DL =
+      DebugInfoContext->getLineInfoForDataAddress(ModuleOffset);
+  if (DL && DL->Line != 0) {
+    Res.DeclFile = DL->FileName;
+    Res.DeclLine = DL->Line;
   }
   return Res;
 }
diff --git a/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp
index 1f4557217cf24..086a09b08db19 100644
--- a/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp
@@ -71,7 +71,10 @@ static VTuneMethodBatch getMethodBatch(LinkGraph &G, bool EmitDebugInfo) {
         SAddr, Sym->getSize(),
         DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
     Method.SourceFileSI = Batch.Strings.size();
-    Batch.Strings.push_back(DC->getLineInfoForAddress(SAddr).FileName);
+    if (std::optional<DILineInfo> LineInfo = DC->getLineInfoForAddress(SAddr))
+      Batch.Strings.push_back(LineInfo->FileName);
+    else
+      Batch.Strings.push_back(DILineInfo::BadString);
     for (auto &LInfo : LinesInfo) {
       Method.LineTable.push_back(
           std::pair<unsigned, unsigned>{/*unsigned*/ Sym->getOffset(),
diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index d63c51566e80c..d35cae29c9aa2 100644
--- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -565,9 +565,11 @@ static bool lookup(ObjectFile &Obj, DWARFContext &DICtx, uint64_t Address,
 
   // TODO: it is neccessary to set proper SectionIndex here.
   // object::SectionedAddress::UndefSection works for only absolute addresses.
-  if (DILineInfo LineInfo = DICtx.getLineInfoForAddress(
+  DILineInfo LineInfo;
+  if (std::optional<DILineInfo> DBGLineInfo = DICtx.getLineInfoForAddress(
           {Lookup, object::SectionedAddress::UndefSection}))
-    LineInfo.dump(OS);
+    LineInfo = *DBGLineInfo;
+  LineInfo.dump(OS);
 
   return true;
 }
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index ab6f65cd41a36..09b684f11839f 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -7594,7 +7594,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
       else
         outs() << SymName << ":\n";
 
-      DILineInfo lastLine;
+      std::optional<DILineInfo> lastLine;
       for (uint64_t Index = Start; Index < End; Index += Size) {
         MCInst Inst;
 
@@ -7646,11 +7646,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
 
           // Print debug info.
           if (diContext) {
-            DILineInfo dli = diContext->getLineInfoForAddress({PC, SectIdx});
+            std::optional<DILineInfo> dli =
+                diContext->getLineInfoForAddress({PC, SectIdx});
             // Print valid line info if it changed.
-            if (dli != lastLine && dli.Line != 0)
-              outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'
-                     << dli.Column;
+            if (dli && dli != lastLine && dli->Line != 0)
+              outs() << "\t## " << dli->FileName << ':' << dli->Line << ':'
+                     << dli->Column;
             lastLine = dli;
           }
           outs() << "\n";
diff --git a/llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp b/llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp
index 5b203adfeb284..7bcc709bffbf0 100644
--- a/llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp
+++ b/llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp
@@ -343,17 +343,15 @@ TEST(BTFParserTest, btfContext) {
   BTFParser BTF;
   std::unique_ptr<BTFContext> Ctx = BTFContext::create(Mock.makeObj());
 
-  DILineInfo I1 = Ctx->getLineInfoForAddress({16, 1});
-  EXPECT_EQ(I1.Line, 7u);
-  EXPECT_EQ(I1.Column, 1u);
-  EXPECT_EQ(I1.FileName, "a.c");
-  EXPECT_EQ(I1.LineSource, "first line");
-
-  DILineInfo I2 = Ctx->getLineInfoForAddress({24, 1});
-  EXPECT_EQ(I2.Line, 0u);
-  EXPECT_EQ(I2.Column, 0u);
-  EXPECT_EQ(I2.FileName, DILineInfo::BadString);
-  EXPECT_EQ(I2.LineSource, std::nullopt);
+  std::optional<DILineInfo> I1 = Ctx->getLineInfoForAddress({16, 1});
+  EXPECT_TRUE(I1.has_value());
+  EXPECT_EQ(I1->Line, 7u);
+  EXPECT_EQ(I1->Column, 1u);
+  EXPECT_EQ(I1->FileName, "a.c");
+  EXPECT_EQ(I1->LineSource, "first line");
+
+  std::optional<DILineInfo> I2 = Ctx->getLineInfoForAddress({24, 1});
+  EXPECT_FALSE(I2.has_value());
 }
 
 static uint32_t mkInfo(uint32_t Kind) { return Kind << 24; }

@llvmbot
Copy link
Member

llvmbot commented Mar 4, 2025

@llvm/pr-subscribers-llvm-binary-utilities

Author: Zequan Wu (ZequanWu)

Changes

Currently, DIContext::getLineInfoForAddress and DIContext::getLineInfoForDataAddress returns empty DILineInfo when the debug info is missing for the given address. This is not differentiable with the case when debug info is found for the given address but the debug info is default value (filename:linenum is <invalid>:0). This change makes it clear that std::nullopt is returned from these APIs when debug info is missing for the given address.


Full diff: https://github.com/llvm/llvm-project/pull/129792.diff

13 Files Affected:

  • (modified) llvm/include/llvm/DebugInfo/BTF/BTFContext.h (+2-2)
  • (modified) llvm/include/llvm/DebugInfo/DIContext.h (+4-2)
  • (modified) llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h (+2-2)
  • (modified) llvm/include/llvm/DebugInfo/PDB/PDBContext.h (+2-2)
  • (modified) llvm/lib/DebugInfo/BTF/BTFContext.cpp (+7-5)
  • (modified) llvm/lib/DebugInfo/DWARF/DWARFContext.cpp (+14-10)
  • (modified) llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp (+5-2)
  • (modified) llvm/lib/DebugInfo/PDB/PDBContext.cpp (+17-10)
  • (modified) llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp (+10-6)
  • (modified) llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp (+4-1)
  • (modified) llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp (+4-2)
  • (modified) llvm/tools/llvm-objdump/MachODump.cpp (+6-5)
  • (modified) llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp (+9-11)
diff --git a/llvm/include/llvm/DebugInfo/BTF/BTFContext.h b/llvm/include/llvm/DebugInfo/BTF/BTFContext.h
index c16bee6133220..e3f7f57749ff1 100644
--- a/llvm/include/llvm/DebugInfo/BTF/BTFContext.h
+++ b/llvm/include/llvm/DebugInfo/BTF/BTFContext.h
@@ -30,11 +30,11 @@ class BTFContext final : public DIContext {
     // BTF is no DWARF, so ignore this operation for now.
   }
 
-  DILineInfo getLineInfoForAddress(
+  std::optional<DILineInfo> getLineInfoForAddress(
       object::SectionedAddress Address,
       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
 
-  DILineInfo
+  std::optional<DILineInfo>
   getLineInfoForDataAddress(object::SectionedAddress Address) override;
 
   DILineInfoTable getLineInfoForAddressRange(
diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h
index 71685ba09d8db..c90b99987f1db 100644
--- a/llvm/include/llvm/DebugInfo/DIContext.h
+++ b/llvm/include/llvm/DebugInfo/DIContext.h
@@ -252,10 +252,12 @@ class DIContext {
     return true;
   }
 
-  virtual DILineInfo getLineInfoForAddress(
+  // For getLineInfoForAddress and getLineInfoForDataAddress, std::nullopt is
+  // returned when debug info is missing for the given address.
+  virtual std::optional<DILineInfo> getLineInfoForAddress(
       object::SectionedAddress Address,
       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
-  virtual DILineInfo
+  virtual std::optional<DILineInfo>
   getLineInfoForDataAddress(object::SectionedAddress Address) = 0;
   virtual DILineInfoTable getLineInfoForAddressRange(
       object::SectionedAddress Address, uint64_t Size,
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
index 0d6e2b076cc34..6df3f5066e327 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
@@ -386,10 +386,10 @@ class DWARFContext : public DIContext {
   ///            executable's debug info.
   DIEsForAddress getDIEsForAddress(uint64_t Address, bool CheckDWO = false);
 
-  DILineInfo getLineInfoForAddress(
+  std::optional<DILineInfo> getLineInfoForAddress(
       object::SectionedAddress Address,
       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
-  DILineInfo
+  std::optional<DILineInfo>
   getLineInfoForDataAddress(object::SectionedAddress Address) override;
   DILineInfoTable getLineInfoForAddressRange(
       object::SectionedAddress Address, uint64_t Size,
diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBContext.h b/llvm/include/llvm/DebugInfo/PDB/PDBContext.h
index 3163c0a1dae03..fedfcd483dcc3 100644
--- a/llvm/include/llvm/DebugInfo/PDB/PDBContext.h
+++ b/llvm/include/llvm/DebugInfo/PDB/PDBContext.h
@@ -42,10 +42,10 @@ namespace pdb {
 
     void dump(raw_ostream &OS, DIDumpOptions DIDumpOpts) override;
 
-    DILineInfo getLineInfoForAddress(
+    std::optional<DILineInfo> getLineInfoForAddress(
         object::SectionedAddress Address,
         DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
-    DILineInfo
+    std::optional<DILineInfo>
     getLineInfoForDataAddress(object::SectionedAddress Address) override;
     DILineInfoTable getLineInfoForAddressRange(
         object::SectionedAddress Address, uint64_t Size,
diff --git a/llvm/lib/DebugInfo/BTF/BTFContext.cpp b/llvm/lib/DebugInfo/BTF/BTFContext.cpp
index 2e651cb378dbf..412bd42ee0b67 100644
--- a/llvm/lib/DebugInfo/BTF/BTFContext.cpp
+++ b/llvm/lib/DebugInfo/BTF/BTFContext.cpp
@@ -20,12 +20,13 @@ using namespace llvm;
 using object::ObjectFile;
 using object::SectionedAddress;
 
-DILineInfo BTFContext::getLineInfoForAddress(SectionedAddress Address,
-                                             DILineInfoSpecifier Specifier) {
+std::optional<DILineInfo>
+BTFContext::getLineInfoForAddress(SectionedAddress Address,
+                                  DILineInfoSpecifier Specifier) {
   const BTF::BPFLineInfo *LineInfo = BTF.findLineInfo(Address);
   DILineInfo Result;
   if (!LineInfo)
-    return Result;
+    return std::nullopt;
 
   Result.LineSource = BTF.findString(LineInfo->LineOff);
   Result.FileName = BTF.findString(LineInfo->FileNameOff);
@@ -34,9 +35,10 @@ DILineInfo BTFContext::getLineInfoForAddress(SectionedAddress Address,
   return Result;
 }
 
-DILineInfo BTFContext::getLineInfoForDataAddress(SectionedAddress Address) {
+std::optional<DILineInfo>
+BTFContext::getLineInfoForDataAddress(SectionedAddress Address) {
   // BTF does not convey such information.
-  return {};
+  return std::nullopt;
 }
 
 DILineInfoTable
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 99e1642ff23ad..afa91b098efe5 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -1730,40 +1730,44 @@ DWARFContext::getLocalsForAddress(object::SectionedAddress Address) {
   return Result;
 }
 
-DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
-                                               DILineInfoSpecifier Spec) {
-  DILineInfo Result;
+std::optional<DILineInfo>
+DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
+                                    DILineInfoSpecifier Spec) {
   DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address.Address);
   if (!CU)
-    return Result;
+    return std::nullopt;
 
-  getFunctionNameAndStartLineForAddress(
+  DILineInfo Result;
+  bool HasDebugInfoForAddress = getFunctionNameAndStartLineForAddress(
       CU, Address.Address, Spec.FNKind, Spec.FLIKind, Result.FunctionName,
       Result.StartFileName, Result.StartLine, Result.StartAddress);
   if (Spec.FLIKind != FileLineInfoKind::None) {
     if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) {
-      LineTable->getFileLineInfoForAddress(
+      HasDebugInfoForAddress |= LineTable->getFileLineInfoForAddress(
           {Address.Address, Address.SectionIndex}, Spec.ApproximateLine,
           CU->getCompilationDir(), Spec.FLIKind, Result);
     }
   }
+  if (!HasDebugInfoForAddress)
+    return std::nullopt;
 
   return Result;
 }
 
-DILineInfo
+std::optional<DILineInfo>
 DWARFContext::getLineInfoForDataAddress(object::SectionedAddress Address) {
-  DILineInfo Result;
   DWARFCompileUnit *CU = getCompileUnitForDataAddress(Address.Address);
   if (!CU)
-    return Result;
+    return std::nullopt;
 
   if (DWARFDie Die = CU->getVariableForAddress(Address.Address)) {
+    DILineInfo Result;
     Result.FileName = Die.getDeclFile(FileLineInfoKind::AbsoluteFilePath);
     Result.Line = Die.getDeclLine();
+    return Result;
   }
 
-  return Result;
+  return std::nullopt;
 }
 
 DILineInfoTable DWARFContext::getLineInfoForAddressRange(
diff --git a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
index 568af5ee8e3ae..23d9c1f5ddf2c 100644
--- a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
+++ b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
@@ -728,8 +728,11 @@ llvm::Error DwarfTransformer::verify(StringRef GsymPath,
           DICtx.getInliningInfoForAddress(SectAddr, DLIS);
       uint32_t NumDwarfInlineInfos = DwarfInlineInfos.getNumberOfFrames();
       if (NumDwarfInlineInfos == 0) {
-        DwarfInlineInfos.addFrame(
-            DICtx.getLineInfoForAddress(SectAddr, DLIS));
+        if (std::optional<DILineInfo> DwarfLineInfo =
+                DICtx.getLineInfoForAddress(SectAddr, DLIS))
+          DwarfInlineInfos.addFrame(*DwarfLineInfo);
+        else
+          DwarfInlineInfos.addFrame(DILineInfo());
       }
 
       // Check for 1 entry that has no file and line info
diff --git a/llvm/lib/DebugInfo/PDB/PDBContext.cpp b/llvm/lib/DebugInfo/PDB/PDBContext.cpp
index e600fb7385f13..dd38295ac62b5 100644
--- a/llvm/lib/DebugInfo/PDB/PDBContext.cpp
+++ b/llvm/lib/DebugInfo/PDB/PDBContext.cpp
@@ -32,8 +32,9 @@ PDBContext::PDBContext(const COFFObjectFile &Object,
 
 void PDBContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts){}
 
-DILineInfo PDBContext::getLineInfoForAddress(object::SectionedAddress Address,
-                                             DILineInfoSpecifier Specifier) {
+std::optional<DILineInfo>
+PDBContext::getLineInfoForAddress(object::SectionedAddress Address,
+                                  DILineInfoSpecifier Specifier) {
   DILineInfo Result;
   Result.FunctionName = getFunctionName(Address.Address, Specifier.FNKind);
 
@@ -64,11 +65,11 @@ DILineInfo PDBContext::getLineInfoForAddress(object::SectionedAddress Address,
   return Result;
 }
 
-DILineInfo
+std::optional<DILineInfo>
 PDBContext::getLineInfoForDataAddress(object::SectionedAddress Address) {
   // Unimplemented. S_GDATA and S_LDATA in CodeView (used to describe global
   // variables) aren't capable of carrying line information.
-  return DILineInfo();
+  return std::nullopt;
 }
 
 DILineInfoTable
@@ -84,9 +85,11 @@ PDBContext::getLineInfoForAddressRange(object::SectionedAddress Address,
     return Table;
 
   while (auto LineInfo = LineNumbers->getNext()) {
-    DILineInfo LineEntry = getLineInfoForAddress(
+    std::optional<DILineInfo> LineEntry = getLineInfoForAddress(
         {LineInfo->getVirtualAddress(), Address.SectionIndex}, Specifier);
-    Table.push_back(std::make_pair(LineInfo->getVirtualAddress(), LineEntry));
+    if (LineEntry)
+      Table.push_back(
+          std::make_pair(LineInfo->getVirtualAddress(), *LineEntry));
   }
   return Table;
 }
@@ -95,19 +98,22 @@ DIInliningInfo
 PDBContext::getInliningInfoForAddress(object::SectionedAddress Address,
                                       DILineInfoSpecifier Specifier) {
   DIInliningInfo InlineInfo;
-  DILineInfo CurrentLine = getLineInfoForAddress(Address, Specifier);
+  std::optional<DILineInfo> CurrentLine =
+      getLineInfoForAddress(Address, Specifier);
 
   // Find the function at this address.
   std::unique_ptr<PDBSymbol> ParentFunc =
       Session->findSymbolByAddress(Address.Address, PDB_SymType::Function);
   if (!ParentFunc) {
-    InlineInfo.addFrame(CurrentLine);
+    if (CurrentLine)
+      InlineInfo.addFrame(*CurrentLine);
     return InlineInfo;
   }
 
   auto Frames = ParentFunc->findInlineFramesByVA(Address.Address);
   if (!Frames || Frames->getChildCount() == 0) {
-    InlineInfo.addFrame(CurrentLine);
+    if (CurrentLine)
+      InlineInfo.addFrame(*CurrentLine);
     return InlineInfo;
   }
 
@@ -131,7 +137,8 @@ PDBContext::getInliningInfoForAddress(object::SectionedAddress Address,
     InlineInfo.addFrame(LineInfo);
   }
 
-  InlineInfo.addFrame(CurrentLine);
+  if (CurrentLine)
+    InlineInfo.addFrame(*CurrentLine);
   return InlineInfo;
 }
 
diff --git a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
index d5e1dc759df5c..dcd6188daf580 100644
--- a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
@@ -276,8 +276,11 @@ SymbolizableObjectFile::symbolizeCode(object::SectionedAddress ModuleOffset,
   if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)
     ModuleOffset.SectionIndex =
         getModuleSectionIndexForAddress(ModuleOffset.Address);
-  DILineInfo LineInfo =
-      DebugInfoContext->getLineInfoForAddress(ModuleOffset, LineInfoSpecifier);
+  DILineInfo LineInfo;
+  if (std::optional<DILineInfo> DBGLineInfo =
+          DebugInfoContext->getLineInfoForAddress(ModuleOffset,
+                                                  LineInfoSpecifier))
+    LineInfo = *DBGLineInfo;
 
   // Override function name from symbol table if necessary.
   if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) {
@@ -334,10 +337,11 @@ DIGlobal SymbolizableObjectFile::symbolizeData(
   Res.DeclFile = FileName;
 
   // Try and get a better filename:lineno pair from the debuginfo, if present.
-  DILineInfo DL = DebugInfoContext->getLineInfoForDataAddress(ModuleOffset);
-  if (DL.Line != 0) {
-    Res.DeclFile = DL.FileName;
-    Res.DeclLine = DL.Line;
+  std::optional<DILineInfo> DL =
+      DebugInfoContext->getLineInfoForDataAddress(ModuleOffset);
+  if (DL && DL->Line != 0) {
+    Res.DeclFile = DL->FileName;
+    Res.DeclLine = DL->Line;
   }
   return Res;
 }
diff --git a/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp
index 1f4557217cf24..086a09b08db19 100644
--- a/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp
@@ -71,7 +71,10 @@ static VTuneMethodBatch getMethodBatch(LinkGraph &G, bool EmitDebugInfo) {
         SAddr, Sym->getSize(),
         DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
     Method.SourceFileSI = Batch.Strings.size();
-    Batch.Strings.push_back(DC->getLineInfoForAddress(SAddr).FileName);
+    if (std::optional<DILineInfo> LineInfo = DC->getLineInfoForAddress(SAddr))
+      Batch.Strings.push_back(LineInfo->FileName);
+    else
+      Batch.Strings.push_back(DILineInfo::BadString);
     for (auto &LInfo : LinesInfo) {
       Method.LineTable.push_back(
           std::pair<unsigned, unsigned>{/*unsigned*/ Sym->getOffset(),
diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index d63c51566e80c..d35cae29c9aa2 100644
--- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -565,9 +565,11 @@ static bool lookup(ObjectFile &Obj, DWARFContext &DICtx, uint64_t Address,
 
   // TODO: it is neccessary to set proper SectionIndex here.
   // object::SectionedAddress::UndefSection works for only absolute addresses.
-  if (DILineInfo LineInfo = DICtx.getLineInfoForAddress(
+  DILineInfo LineInfo;
+  if (std::optional<DILineInfo> DBGLineInfo = DICtx.getLineInfoForAddress(
           {Lookup, object::SectionedAddress::UndefSection}))
-    LineInfo.dump(OS);
+    LineInfo = *DBGLineInfo;
+  LineInfo.dump(OS);
 
   return true;
 }
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index ab6f65cd41a36..09b684f11839f 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -7594,7 +7594,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
       else
         outs() << SymName << ":\n";
 
-      DILineInfo lastLine;
+      std::optional<DILineInfo> lastLine;
       for (uint64_t Index = Start; Index < End; Index += Size) {
         MCInst Inst;
 
@@ -7646,11 +7646,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
 
           // Print debug info.
           if (diContext) {
-            DILineInfo dli = diContext->getLineInfoForAddress({PC, SectIdx});
+            std::optional<DILineInfo> dli =
+                diContext->getLineInfoForAddress({PC, SectIdx});
             // Print valid line info if it changed.
-            if (dli != lastLine && dli.Line != 0)
-              outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'
-                     << dli.Column;
+            if (dli && dli != lastLine && dli->Line != 0)
+              outs() << "\t## " << dli->FileName << ':' << dli->Line << ':'
+                     << dli->Column;
             lastLine = dli;
           }
           outs() << "\n";
diff --git a/llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp b/llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp
index 5b203adfeb284..7bcc709bffbf0 100644
--- a/llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp
+++ b/llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp
@@ -343,17 +343,15 @@ TEST(BTFParserTest, btfContext) {
   BTFParser BTF;
   std::unique_ptr<BTFContext> Ctx = BTFContext::create(Mock.makeObj());
 
-  DILineInfo I1 = Ctx->getLineInfoForAddress({16, 1});
-  EXPECT_EQ(I1.Line, 7u);
-  EXPECT_EQ(I1.Column, 1u);
-  EXPECT_EQ(I1.FileName, "a.c");
-  EXPECT_EQ(I1.LineSource, "first line");
-
-  DILineInfo I2 = Ctx->getLineInfoForAddress({24, 1});
-  EXPECT_EQ(I2.Line, 0u);
-  EXPECT_EQ(I2.Column, 0u);
-  EXPECT_EQ(I2.FileName, DILineInfo::BadString);
-  EXPECT_EQ(I2.LineSource, std::nullopt);
+  std::optional<DILineInfo> I1 = Ctx->getLineInfoForAddress({16, 1});
+  EXPECT_TRUE(I1.has_value());
+  EXPECT_EQ(I1->Line, 7u);
+  EXPECT_EQ(I1->Column, 1u);
+  EXPECT_EQ(I1->FileName, "a.c");
+  EXPECT_EQ(I1->LineSource, "first line");
+
+  std::optional<DILineInfo> I2 = Ctx->getLineInfoForAddress({24, 1});
+  EXPECT_FALSE(I2.has_value());
 }
 
 static uint32_t mkInfo(uint32_t Kind) { return Kind << 24; }

Copy link
Member

@jryans jryans left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a useful improvement to me, thanks! 😄

Copy link
Collaborator

@dwblaikie dwblaikie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still seems like this might benefit from being split up a bit more (looks like there are some more places in this patch that have changes in behavior that aren't tested, like MachODump.cpp, maybe), but I guess it'll do.

@ZequanWu ZequanWu merged commit 6dbe82f into llvm:main Mar 17, 2025
6 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants