[lld] [llvm] [Symbolizer] Support for Missing Line Numbers. (PR #82240)

via llvm-commits llvm-commits at lists.llvm.org
Tue May 7 06:06:56 PDT 2024


https://github.com/ampandey-1995 updated https://github.com/llvm/llvm-project/pull/82240

>From 8a6e8aa155dfef7bc62625662b898ddaaea1ef67 Mon Sep 17 00:00:00 2001
From: Amit Pandey <amit.pandey at amd.com>
Date: Wed, 14 Feb 2024 16:31:48 +0530
Subject: [PATCH 01/12] [Symbolizer] Support for Missing Line Numbers.

LLVM Symbolizer attempt to symbolize addresses of optimized binaries
reports missing line numbers for some cases. It maybe due to compiler
which sometimes cannot map an instruction to line number due to
optimizations. Symbolizer should handle those cases gracefully.

Adding an option '--skip-line-zero' to symbolizer so as to report the
nearest non-zero line number.
---
 bolt/lib/Core/BinaryFunction.cpp              |   3 +-
 lld/Common/DWARF.cpp                          |   3 +-
 llvm/docs/CommandGuide/llvm-symbolizer.rst    |   4 +
 llvm/include/llvm/DebugInfo/DIContext.h       |   8 +-
 .../llvm/DebugInfo/DWARF/DWARFDebugLine.h     |  16 +-
 .../llvm/DebugInfo/Symbolize/Symbolize.h      |   2 +
 llvm/lib/DebugInfo/DWARF/DWARFContext.cpp     |  10 +-
 llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp   |  35 ++++-
 llvm/lib/DebugInfo/Symbolize/Symbolize.cpp    |   8 +-
 .../llvm-symbolizer/approximate-line-info.s   | 142 ++++++++++++++++++
 llvm/tools/llvm-symbolizer/Opts.td            |   1 +
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp |   8 +
 12 files changed, 215 insertions(+), 25 deletions(-)
 create mode 100644 llvm/test/tools/llvm-symbolizer/approximate-line-info.s

diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index 1fa96dfaabde8..a9f704e447cc6 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -193,7 +193,8 @@ static SMLoc findDebugLineInformationForInstructionAt(
 
   SMLoc NullResult = DebugLineTableRowRef::NULL_ROW.toSMLoc();
   uint32_t RowIndex = LineTable->lookupAddress(
-      {Address, object::SectionedAddress::UndefSection});
+      {Address, object::SectionedAddress::UndefSection},
+      DILineInfoSpecifier::ApproximateLineKind::None);
   if (RowIndex == LineTable->UnknownRowIndex)
     return NullResult;
 
diff --git a/lld/Common/DWARF.cpp b/lld/Common/DWARF.cpp
index 2cd8ca4575dee..8e1e9c6e53015 100644
--- a/lld/Common/DWARF.cpp
+++ b/lld/Common/DWARF.cpp
@@ -93,7 +93,8 @@ std::optional<DILineInfo> DWARFCache::getDILineInfo(uint64_t offset,
   DILineInfo info;
   for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) {
     if (lt->getFileLineInfoForAddress(
-            {offset, sectionIndex}, nullptr,
+            {offset, sectionIndex},
+            DILineInfoSpecifier::ApproximateLineKind::None, nullptr,
             DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info))
       return info;
   }
diff --git a/llvm/docs/CommandGuide/llvm-symbolizer.rst b/llvm/docs/CommandGuide/llvm-symbolizer.rst
index 59c0ab6d196ac..ee60d97babcbc 100644
--- a/llvm/docs/CommandGuide/llvm-symbolizer.rst
+++ b/llvm/docs/CommandGuide/llvm-symbolizer.rst
@@ -216,6 +216,10 @@ OPTIONS
   This can be used to perform lookups as if the object were relocated by the
   offset.
 
+.. option:: --approximate-line-info=<before/after>
+
+  Search the object to find the approximate non-zero line numbers nearest to for a given address.
+
 .. option:: --basenames, -s
 
   Print just the file's name without any directories, instead of the
diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h
index b75dc8db54336..eb4ff761119db 100644
--- a/llvm/include/llvm/DebugInfo/DIContext.h
+++ b/llvm/include/llvm/DebugInfo/DIContext.h
@@ -152,14 +152,16 @@ struct DILineInfoSpecifier {
     RelativeFilePath,
     AbsoluteFilePath
   };
+  enum ApproximateLineKind { None, Before, After };
   using FunctionNameKind = DINameKind;
-
   FileLineInfoKind FLIKind;
   FunctionNameKind FNKind;
+  ApproximateLineKind ALKind;
 
   DILineInfoSpecifier(FileLineInfoKind FLIKind = FileLineInfoKind::RawValue,
-                      FunctionNameKind FNKind = FunctionNameKind::None)
-      : FLIKind(FLIKind), FNKind(FNKind) {}
+                      FunctionNameKind FNKind = FunctionNameKind::None,
+                      ApproximateLineKind ALKind = ApproximateLineKind::None)
+      : FLIKind(FLIKind), FNKind(FNKind), ALKind(ALKind) {}
 
   inline bool operator==(const DILineInfoSpecifier &RHS) const {
     return FLIKind == RHS.FLIKind && FNKind == RHS.FNKind;
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
index ce3bae6a1760c..cb3531b75730f 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
@@ -240,7 +240,9 @@ class DWARFDebugLine {
 
     /// Returns the index of the row with file/line info for a given address,
     /// or UnknownRowIndex if there is no such row.
-    uint32_t lookupAddress(object::SectionedAddress Address) const;
+    uint32_t
+    lookupAddress(object::SectionedAddress Address,
+                  DILineInfoSpecifier::ApproximateLineKind LineKind) const;
 
     bool lookupAddressRange(object::SectionedAddress Address, uint64_t Size,
                             std::vector<uint32_t> &Result) const;
@@ -266,10 +268,10 @@ class DWARFDebugLine {
 
     /// Fills the Result argument with the file and line information
     /// corresponding to Address. Returns true on success.
-    bool getFileLineInfoForAddress(object::SectionedAddress Address,
-                                   const char *CompDir,
-                                   DILineInfoSpecifier::FileLineInfoKind Kind,
-                                   DILineInfo &Result) const;
+    bool getFileLineInfoForAddress(
+        object::SectionedAddress Address,
+        DILineInfoSpecifier::ApproximateLineKind LineKind, const char *CompDir,
+        DILineInfoSpecifier::FileLineInfoKind Kind, DILineInfo &Result) const;
 
     /// Extracts directory name by its Entry in include directories table
     /// in prologue. Returns true on success.
@@ -301,7 +303,9 @@ class DWARFDebugLine {
     getSourceByIndex(uint64_t FileIndex,
                      DILineInfoSpecifier::FileLineInfoKind Kind) const;
 
-    uint32_t lookupAddressImpl(object::SectionedAddress Address) const;
+    uint32_t
+    lookupAddressImpl(object::SectionedAddress Address,
+                      DILineInfoSpecifier::ApproximateLineKind LineKind) const;
 
     bool lookupAddressRangeImpl(object::SectionedAddress Address, uint64_t Size,
                                 std::vector<uint32_t> &Result) const;
diff --git a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
index 11a169cfc20a6..7b560f4b7dbb2 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
@@ -44,6 +44,7 @@ using namespace object;
 
 using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind;
 using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
+using ApproximateLineKind = DILineInfoSpecifier::ApproximateLineKind;
 
 class CachedBinary;
 
@@ -52,6 +53,7 @@ class LLVMSymbolizer {
   struct Options {
     FunctionNameKind PrintFunctions = FunctionNameKind::LinkageName;
     FileLineInfoKind PathStyle = FileLineInfoKind::AbsoluteFilePath;
+    ApproximateLineKind ApproximateLineNumbers = ApproximateLineKind::None;
     bool UseSymbolTable = true;
     bool Demangle = true;
     bool RelativeAddresses = false;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index b7297c18da7c9..9bf7dbd0acc10 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -1742,8 +1742,8 @@ DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
   if (Spec.FLIKind != FileLineInfoKind::None) {
     if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) {
       LineTable->getFileLineInfoForAddress(
-          {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
-          Spec.FLIKind, Result);
+          {Address.Address, Address.SectionIndex}, Spec.ALKind,
+          CU->getCompilationDir(), Spec.FLIKind, Result);
     }
   }
 
@@ -1838,7 +1838,7 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
       DILineInfo Frame;
       LineTable = getLineTableForUnit(CU);
       if (LineTable && LineTable->getFileLineInfoForAddress(
-                           {Address.Address, Address.SectionIndex},
+                           {Address.Address, Address.SectionIndex}, Spec.ALKind,
                            CU->getCompilationDir(), Spec.FLIKind, Frame))
         InliningInfo.addFrame(Frame);
     }
@@ -1865,8 +1865,8 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
         // For the topmost routine, get file/line info from line table.
         if (LineTable)
           LineTable->getFileLineInfoForAddress(
-              {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
-              Spec.FLIKind, Frame);
+              {Address.Address, Address.SectionIndex}, Spec.ALKind,
+              CU->getCompilationDir(), Spec.FLIKind, Frame);
       } else {
         // Otherwise, use call file, call line and call column from
         // previous DIE in inlined chain.
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 572628f45fc23..f32c69abe5a0d 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -1313,10 +1313,11 @@ uint32_t DWARFDebugLine::LineTable::findRowInSeq(
 }
 
 uint32_t DWARFDebugLine::LineTable::lookupAddress(
-    object::SectionedAddress Address) const {
+    object::SectionedAddress Address,
+    DILineInfoSpecifier::ApproximateLineKind LineKind) const {
 
   // Search for relocatable addresses
-  uint32_t Result = lookupAddressImpl(Address);
+  uint32_t Result = lookupAddressImpl(Address, LineKind);
 
   if (Result != UnknownRowIndex ||
       Address.SectionIndex == object::SectionedAddress::UndefSection)
@@ -1324,11 +1325,12 @@ uint32_t DWARFDebugLine::LineTable::lookupAddress(
 
   // Search for absolute addresses
   Address.SectionIndex = object::SectionedAddress::UndefSection;
-  return lookupAddressImpl(Address);
+  return lookupAddressImpl(Address, LineKind);
 }
 
 uint32_t DWARFDebugLine::LineTable::lookupAddressImpl(
-    object::SectionedAddress Address) const {
+    object::SectionedAddress Address,
+    DILineInfoSpecifier::ApproximateLineKind LineKind) const {
   // First, find an instruction sequence containing the given address.
   DWARFDebugLine::Sequence Sequence;
   Sequence.SectionIndex = Address.SectionIndex;
@@ -1337,7 +1339,24 @@ uint32_t DWARFDebugLine::LineTable::lookupAddressImpl(
                                       DWARFDebugLine::Sequence::orderByHighPC);
   if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex)
     return UnknownRowIndex;
-  return findRowInSeq(*It, Address);
+
+  uint32_t RowIndex = findRowInSeq(*It, Address);
+  if (LineKind == DILineInfoSpecifier::ApproximateLineKind::Before) {
+    for (auto SeqInst = Sequence.HighPC; SeqInst >= It->LowPC; --SeqInst) {
+      if (Rows[RowIndex].Line)
+        break;
+      Address.Address--;
+      RowIndex = findRowInSeq(*It, Address);
+    }
+  } else if (LineKind == DILineInfoSpecifier::ApproximateLineKind::After) {
+    for (auto SeqInst = Sequence.HighPC; SeqInst < It->HighPC; ++SeqInst) {
+      if (Rows[RowIndex].Line)
+        break;
+      Address.Address++;
+      RowIndex = findRowInSeq(*It, Address);
+    }
+  }
+  return RowIndex;
 }
 
 bool DWARFDebugLine::LineTable::lookupAddressRange(
@@ -1477,10 +1496,12 @@ bool DWARFDebugLine::Prologue::getFileNameByIndex(
 }
 
 bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
-    object::SectionedAddress Address, const char *CompDir,
+    object::SectionedAddress Address,
+    DILineInfoSpecifier::ApproximateLineKind LineKind, const char *CompDir,
     FileLineInfoKind Kind, DILineInfo &Result) const {
   // Get the index of row we're looking for in the line table.
-  uint32_t RowIndex = lookupAddress(Address);
+  uint32_t RowIndex = lookupAddress(Address, LineKind);
+
   if (RowIndex == -1U)
     return false;
   // Take file number and line/column from the row.
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index 32c5e3251df62..6c8303bcee6ca 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -71,7 +71,9 @@ LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier,
     ModuleOffset.Address += Info->getModulePreferredBase();
 
   DILineInfo LineInfo = Info->symbolizeCode(
-      ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
+      ModuleOffset,
+      DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions,
+                          Opts.ApproximateLineNumbers),
       Opts.UseSymbolTable);
   if (Opts.Demangle)
     LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
@@ -116,7 +118,9 @@ Expected<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCodeCommon(
     ModuleOffset.Address += Info->getModulePreferredBase();
 
   DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
-      ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
+      ModuleOffset,
+      DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions,
+                          Opts.ApproximateLineNumbers),
       Opts.UseSymbolTable);
   if (Opts.Demangle) {
     for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
diff --git a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
new file mode 100644
index 0000000000000..b7d56b0e64534
--- /dev/null
+++ b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
@@ -0,0 +1,142 @@
+# REQUIRES: x86-registered-target
+
+# RUN: llvm-mc -g -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-symbolizer --obj=%t.o 0xa | FileCheck --check-prefix=APPROX-NONE %s
+# RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before 0xa | FileCheck --check-prefix=APPROX-BEFORE %s
+# RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=after 0xa | FileCheck --check-prefix=APPROX-AFTER %s
+
+# APPROX-NONE: main
+# APPROX-NONE-NEXT: /home/ampandey/test-hip/main.c:0:6
+# APPROX-BEFORE: main
+# APPROX-BEFORE-NEXT: /home/ampandey/test-hip/main.c:4:6
+# APPROX-AFTER: main
+# APPROX-AFTER-NEXT: /home/ampandey/test-hip/main.c:8:2
+
+## Generated from C Code
+##
+## int foo = 0;
+## int x=89;
+## int main() {
+## if(x)
+##  return foo;
+## else
+##  return x;
+## }
+##
+## clang -S -O3 -gline-tables-only --target=x86_64-pc-linux
+
+	.text
+	.file	"main.c"
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.file	0 "/home/ampandey/test-hip" "main.c" md5 0x26c3fbaea8e6febaf09ef44d37ec5ecc
+	.cfi_startproc
+# %bb.0:                                # %entry
+	.loc	0 4 6 prologue_end              # main.c:4:6
+	movl	x(%rip), %eax
+	testl	%eax, %eax
+	je	.LBB0_2
+# %bb.1:                                # %entry
+	.loc	0 0 6 is_stmt 0                 # main.c:0:6
+	movl	foo(%rip), %eax
+.LBB0_2:                                # %entry
+	.loc	0 8 2 is_stmt 1                 # main.c:8:2
+	retq
+.Ltmp0:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.type	foo, at object                     # @foo
+	.bss
+	.globl	foo
+	.p2align	2, 0x0
+foo:
+	.long	0                               # 0x0
+	.size	foo, 4
+
+	.type	x, at object                       # @x
+	.data
+	.globl	x
+	.p2align	2, 0x0
+x:
+	.long	89                              # 0x59
+	.size	x, 4
+
+	.section	.debug_abbrev,"", at progbits
+	.byte	1                               # Abbreviation Code
+	.byte	17                              # DW_TAG_compile_unit
+	.byte	0                               # DW_CHILDREN_no
+	.byte	37                              # DW_AT_producer
+	.byte	37                              # DW_FORM_strx1
+	.byte	19                              # DW_AT_language
+	.byte	5                               # DW_FORM_data2
+	.byte	3                               # DW_AT_name
+	.byte	37                              # DW_FORM_strx1
+	.byte	114                             # DW_AT_str_offsets_base
+	.byte	23                              # DW_FORM_sec_offset
+	.byte	16                              # DW_AT_stmt_list
+	.byte	23                              # DW_FORM_sec_offset
+	.byte	27                              # DW_AT_comp_dir
+	.byte	37                              # DW_FORM_strx1
+	.byte	17                              # DW_AT_low_pc
+	.byte	27                              # DW_FORM_addrx
+	.byte	18                              # DW_AT_high_pc
+	.byte	6                               # DW_FORM_data4
+	.byte	115                             # DW_AT_addr_base
+	.byte	23                              # DW_FORM_sec_offset
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+	.byte	1                               # Abbrev [1] 0xc:0x17 DW_TAG_compile_unit
+	.byte	0                               # DW_AT_producer
+	.short	29                              # DW_AT_language
+	.byte	1                               # DW_AT_name
+	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
+	.long	.Lline_table_start0             # DW_AT_stmt_list
+	.byte	2                               # DW_AT_comp_dir
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
+	.long	.Laddr_table_base0              # DW_AT_addr_base
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	16                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:ampandey-1995/llvm-project.git 6751baed8d1ee8c5fd12fe5a06aa67275fc1ebf6)" # string offset=0
+.Linfo_string1:
+	.asciz	"main.c"                        # string offset=113
+.Linfo_string2:
+	.asciz	"/home/ampandey/test-hip"       # string offset=120
+	.section	.debug_str_offsets,"", at progbits
+	.long	.Linfo_string0
+	.long	.Linfo_string1
+	.long	.Linfo_string2
+	.section	.debug_addr,"", at progbits
+	.long	.Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+	.short	5                               # DWARF version number
+	.byte	8                               # Address size
+	.byte	0                               # Segment selector size
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.ident	"clang version 19.0.0git (git at github.com:ampandey-1995/llvm-project.git 6751baed8d1ee8c5fd12fe5a06aa67275fc1ebf6)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/llvm/tools/llvm-symbolizer/Opts.td b/llvm/tools/llvm-symbolizer/Opts.td
index edc80bfe59673..80ec4721c45e0 100644
--- a/llvm/tools/llvm-symbolizer/Opts.td
+++ b/llvm/tools/llvm-symbolizer/Opts.td
@@ -17,6 +17,7 @@ def grp_mach_o : OptionGroup<"kind">,
                  HelpText<"llvm-symbolizer Mach-O Specific Options">;
 
 def addresses : F<"addresses", "Show address before line information">;
+defm approximate_line_info : Eq<"approximate-line-info","Find approximate non-zero line number information nearest to given address.">,Values<"<before/after>">;
 defm adjust_vma
     : Eq<"adjust-vma", "Add specified offset to object file addresses">,
       MetaVarName<"<offset>">;
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index b98bdbc388faf..530dbdfd5c8b5 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -482,6 +482,14 @@ int llvm_symbolizer_main(int argc, char **argv, const llvm::ToolContext &) {
   } else {
     Opts.PathStyle = DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath;
   }
+  StringRef ApproximateLineKindVal =
+      Args.getLastArgValue(OPT_approximate_line_info_EQ);
+  Opts.ApproximateLineNumbers =
+      ApproximateLineKindVal == "before"
+          ? DILineInfoSpecifier::ApproximateLineKind::Before
+      : ApproximateLineKindVal == "after"
+          ? DILineInfoSpecifier::ApproximateLineKind::After
+          : DILineInfoSpecifier::ApproximateLineKind::None;
   Opts.DebugFileDirectory = Args.getAllArgValues(OPT_debug_file_directory_EQ);
   Opts.DefaultArch = Args.getLastArgValue(OPT_default_arch_EQ).str();
   Opts.Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, !IsAddr2Line);

>From 2b9bd48761c58f70f31ddde06027a35436de45a0 Mon Sep 17 00:00:00 2001
From: Amit Pandey <pandey.kumaramit2023 at gmail.com>
Date: Mon, 19 Feb 2024 17:40:53 +0530
Subject: [PATCH 02/12] Clean up some unused variables.

---
 llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index f32c69abe5a0d..5b7d9ebeef715 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -1340,21 +1340,23 @@ uint32_t DWARFDebugLine::LineTable::lookupAddressImpl(
   if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex)
     return UnknownRowIndex;
 
-  uint32_t RowIndex = findRowInSeq(*It, Address);
+  uint32_t RowIndex;
   if (LineKind == DILineInfoSpecifier::ApproximateLineKind::Before) {
-    for (auto SeqInst = Sequence.HighPC; SeqInst >= It->LowPC; --SeqInst) {
+    for (auto SeqInst = Sequence.HighPC; SeqInst >= It->LowPC;) {
+      RowIndex = findRowInSeq(*It, Address);
       if (Rows[RowIndex].Line)
         break;
-      Address.Address--;
-      RowIndex = findRowInSeq(*It, Address);
+      Address.Address = --SeqInst;
     }
   } else if (LineKind == DILineInfoSpecifier::ApproximateLineKind::After) {
-    for (auto SeqInst = Sequence.HighPC; SeqInst < It->HighPC; ++SeqInst) {
+    for (auto SeqInst = Sequence.HighPC; SeqInst <= It->HighPC;) {
+      RowIndex = findRowInSeq(*It, Address);
       if (Rows[RowIndex].Line)
         break;
-      Address.Address++;
-      RowIndex = findRowInSeq(*It, Address);
+      Address.Address = ++SeqInst;
     }
+  } else {
+    RowIndex = findRowInSeq(*It, Address);
   }
   return RowIndex;
 }

>From 8fa8f104cdcb3ea28fc1446c7de3aee13abb220e Mon Sep 17 00:00:00 2001
From: Amit Pandey <pandey.kumaramit2023 at gmail.com>
Date: Thu, 22 Feb 2024 21:44:04 +0530
Subject: [PATCH 03/12] Addressing Comments

Update the command guide,help output.  Adding (approximate) tag to for
approximated line information output.
---
 llvm/docs/CommandGuide/llvm-symbolizer.rst    | 20 ++++++++++++++--
 llvm/include/llvm/DebugInfo/DIContext.h       |  2 ++
 .../llvm/DebugInfo/DWARF/DWARFDebugLine.h     |  4 ++--
 llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp   | 24 ++++++++++++-------
 llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp    | 12 +++++++---
 .../llvm-symbolizer/approximate-line-info.s   | 20 +++++++++++++---
 .../output-style-json-code.test               | 14 +++++------
 llvm/test/tools/llvm-symbolizer/source.ll     |  2 +-
 8 files changed, 71 insertions(+), 27 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-symbolizer.rst b/llvm/docs/CommandGuide/llvm-symbolizer.rst
index ee60d97babcbc..64e14a63861c6 100644
--- a/llvm/docs/CommandGuide/llvm-symbolizer.rst
+++ b/llvm/docs/CommandGuide/llvm-symbolizer.rst
@@ -207,6 +207,17 @@ Example 7 - Addresses as symbol names:
   foz
   /tmp/test.h:1:0
 
+Example 8 - Addresses having approximate line info:
+
+.. code-block:: console
+
+  $ llvm-symbolizer --obj=test.elf --approximate-line-info=before 0xa
+  main
+  /home/ampandey/test-hip/main.c:4:6 (approximate)
+  $ llvm-symbolizer --obj=test.elf --approximate-line-info=after 0xa
+  main
+  /home/ampandey/test-hip/main.c:8:2 (approximate)
+
 OPTIONS
 -------
 
@@ -216,9 +227,11 @@ OPTIONS
   This can be used to perform lookups as if the object were relocated by the
   offset.
 
-.. option:: --approximate-line-info=<before/after>
+.. option:: --approximate-line-info=<before|after>
 
-  Search the object to find the approximate non-zero line numbers nearest to for a given address.
+  Print the approximate non-zero line number nearest to an input address.
+  Nearest lookup is performed by querying the line-table structure for an
+  address having non-zero line information with close proxmity.
 
 .. option:: --basenames, -s
 
@@ -374,6 +387,7 @@ OPTIONS
         "ModuleName": "inlined.elf",
         "Symbol": [
           {
+            "Approximate": false,
             "Column": 18,
             "Discriminator": 0,
             "FileName": "/tmp/test.cpp",
@@ -384,6 +398,7 @@ OPTIONS
             "StartLine": 9
           },
           {
+            "Approximate": false,
             "Column": 0,
             "Discriminator": 0,
             "FileName": "/tmp/test.cpp",
@@ -400,6 +415,7 @@ OPTIONS
         "ModuleName": "inlined.elf",
         "Symbol": [
           {
+            "Approximate": false,
             "Column": 3,
             "Discriminator": 0,
             "FileName": "/tmp/test.cpp",
diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h
index eb4ff761119db..fb18f6d124a49 100644
--- a/llvm/include/llvm/DebugInfo/DIContext.h
+++ b/llvm/include/llvm/DebugInfo/DIContext.h
@@ -30,6 +30,7 @@ namespace llvm {
 
 /// A format-neutral container for source line information.
 struct DILineInfo {
+  static constexpr const char *const ApproxString = "(approximate)";
   // DILineInfo contains "<invalid>" for function/filename it cannot fetch.
   static constexpr const char *const BadString = "<invalid>";
   // Use "??" instead of "<invalid>" to make our output closer to addr2line.
@@ -50,6 +51,7 @@ struct DILineInfo {
   // DWARF-specific.
   uint32_t Discriminator = 0;
 
+  bool IsApproximatedLine = 0;
   DILineInfo()
       : FileName(BadString), FunctionName(BadString), StartFileName(BadString) {
   }
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
index cb3531b75730f..5a60dadf9269e 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
@@ -240,7 +240,7 @@ class DWARFDebugLine {
 
     /// Returns the index of the row with file/line info for a given address,
     /// or UnknownRowIndex if there is no such row.
-    uint32_t
+    std::pair<uint32_t, bool>
     lookupAddress(object::SectionedAddress Address,
                   DILineInfoSpecifier::ApproximateLineKind LineKind) const;
 
@@ -303,7 +303,7 @@ class DWARFDebugLine {
     getSourceByIndex(uint64_t FileIndex,
                      DILineInfoSpecifier::FileLineInfoKind Kind) const;
 
-    uint32_t
+    std::pair<uint32_t, bool>
     lookupAddressImpl(object::SectionedAddress Address,
                       DILineInfoSpecifier::ApproximateLineKind LineKind) const;
 
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 5b7d9ebeef715..71d4552259ded 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -1312,14 +1312,14 @@ uint32_t DWARFDebugLine::LineTable::findRowInSeq(
   return RowPos - Rows.begin();
 }
 
-uint32_t DWARFDebugLine::LineTable::lookupAddress(
+std::pair<uint32_t, bool> DWARFDebugLine::LineTable::lookupAddress(
     object::SectionedAddress Address,
     DILineInfoSpecifier::ApproximateLineKind LineKind) const {
 
   // Search for relocatable addresses
-  uint32_t Result = lookupAddressImpl(Address, LineKind);
+  std::pair<uint32_t, bool> Result = lookupAddressImpl(Address, LineKind);
 
-  if (Result != UnknownRowIndex ||
+  if (Result.first != UnknownRowIndex ||
       Address.SectionIndex == object::SectionedAddress::UndefSection)
     return Result;
 
@@ -1328,7 +1328,7 @@ uint32_t DWARFDebugLine::LineTable::lookupAddress(
   return lookupAddressImpl(Address, LineKind);
 }
 
-uint32_t DWARFDebugLine::LineTable::lookupAddressImpl(
+std::pair<uint32_t, bool> DWARFDebugLine::LineTable::lookupAddressImpl(
     object::SectionedAddress Address,
     DILineInfoSpecifier::ApproximateLineKind LineKind) const {
   // First, find an instruction sequence containing the given address.
@@ -1338,14 +1338,17 @@ uint32_t DWARFDebugLine::LineTable::lookupAddressImpl(
   SequenceIter It = llvm::upper_bound(Sequences, Sequence,
                                       DWARFDebugLine::Sequence::orderByHighPC);
   if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex)
-    return UnknownRowIndex;
+    return {UnknownRowIndex, false};
 
-  uint32_t RowIndex;
+  uint32_t RowIndex = UnknownRowIndex;
+  bool SecondAttempt = false;
   if (LineKind == DILineInfoSpecifier::ApproximateLineKind::Before) {
     for (auto SeqInst = Sequence.HighPC; SeqInst >= It->LowPC;) {
       RowIndex = findRowInSeq(*It, Address);
       if (Rows[RowIndex].Line)
         break;
+      if (!SecondAttempt)
+        SecondAttempt = true;
       Address.Address = --SeqInst;
     }
   } else if (LineKind == DILineInfoSpecifier::ApproximateLineKind::After) {
@@ -1353,12 +1356,14 @@ uint32_t DWARFDebugLine::LineTable::lookupAddressImpl(
       RowIndex = findRowInSeq(*It, Address);
       if (Rows[RowIndex].Line)
         break;
+      if (!SecondAttempt)
+        SecondAttempt = true;
       Address.Address = ++SeqInst;
     }
   } else {
     RowIndex = findRowInSeq(*It, Address);
   }
-  return RowIndex;
+  return {RowIndex, SecondAttempt};
 }
 
 bool DWARFDebugLine::LineTable::lookupAddressRange(
@@ -1502,8 +1507,8 @@ bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
     DILineInfoSpecifier::ApproximateLineKind LineKind, const char *CompDir,
     FileLineInfoKind Kind, DILineInfo &Result) const {
   // Get the index of row we're looking for in the line table.
-  uint32_t RowIndex = lookupAddress(Address, LineKind);
-
+  auto &&RowIndexValue = lookupAddress(Address, LineKind);
+  uint32_t RowIndex = RowIndexValue.first;
   if (RowIndex == -1U)
     return false;
   // Take file number and line/column from the row.
@@ -1514,6 +1519,7 @@ bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
   Result.Column = Row.Column;
   Result.Discriminator = Row.Discriminator;
   Result.Source = getSourceByIndex(Row.File, Kind);
+  Result.IsApproximatedLine = RowIndexValue.second;
   return true;
 }
 
diff --git a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
index 716312f26e0ba..bce29d1e18a7d 100644
--- a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
@@ -131,14 +131,17 @@ void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) {
 
 void LLVMPrinter::printSimpleLocation(StringRef Filename,
                                       const DILineInfo &Info) {
-  OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n';
+  OS << Filename << ':' << Info.Line << ':' << Info.Column
+     << (Info.IsApproximatedLine ? (" " + Twine(Info.ApproxString)) : "")
+     << '\n';
   printContext(
       SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));
 }
 
 void GNUPrinter::printSimpleLocation(StringRef Filename,
                                      const DILineInfo &Info) {
-  OS << Filename << ':' << Info.Line;
+  OS << Filename << ':' << Info.Line
+     << (Info.IsApproximatedLine ? (" " + Twine(Info.ApproxString)) : "");
   if (Info.Discriminator)
     OS << " (discriminator " << Info.Discriminator << ')';
   OS << '\n';
@@ -158,6 +161,8 @@ void PlainPrinterBase::printVerbose(StringRef Filename,
   OS << "  Column: " << Info.Column << '\n';
   if (Info.Discriminator)
     OS << "  Discriminator: " << Info.Discriminator << '\n';
+  if (Info.IsApproximatedLine)
+    OS << "  Approximate: " << Info.IsApproximatedLine << '\n';
 }
 
 void LLVMPrinter::printStartAddress(const DILineInfo &Info) {
@@ -308,7 +313,8 @@ static json::Object toJSON(const DILineInfo &LineInfo) {
         LineInfo.FileName != DILineInfo::BadString ? LineInfo.FileName : ""},
        {"Line", LineInfo.Line},
        {"Column", LineInfo.Column},
-       {"Discriminator", LineInfo.Discriminator}});
+       {"Discriminator", LineInfo.Discriminator},
+       {"Approximate", LineInfo.IsApproximatedLine}});
 }
 
 void JSONPrinter::print(const Request &Request, const DILineInfo &Info) {
diff --git a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
index b7d56b0e64534..26e595c83cdf8 100644
--- a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
+++ b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
@@ -1,16 +1,30 @@
 # REQUIRES: x86-registered-target
 
 # RUN: llvm-mc -g -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: llvm-symbolizer --obj=%t.o 0xa | FileCheck --check-prefix=APPROX-NONE %s
+# RUN: llvm-symbolizer --obj=%t.o 0xa | FileCheck --check-prefixes=APPROX-NONE %s
 # RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before 0xa | FileCheck --check-prefix=APPROX-BEFORE %s
 # RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=after 0xa | FileCheck --check-prefix=APPROX-AFTER %s
+# RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before 0xa 0x10 | FileCheck --check-prefixes=APPROX-BEFORE,NO-APPROX %s
+# RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before --verbose 0xa | FileCheck --check-prefix=APPROX-VERBOSE %s
+# RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before --output-style=JSON 0xa | FileCheck --check-prefix=APPROX-JSON %s
 
 # APPROX-NONE: main
 # APPROX-NONE-NEXT: /home/ampandey/test-hip/main.c:0:6
 # APPROX-BEFORE: main
-# APPROX-BEFORE-NEXT: /home/ampandey/test-hip/main.c:4:6
+# APPROX-BEFORE-NEXT: /home/ampandey/test-hip/main.c:4:6 (approximate)
 # APPROX-AFTER: main
-# APPROX-AFTER-NEXT: /home/ampandey/test-hip/main.c:8:2
+# APPROX-AFTER-NEXT: /home/ampandey/test-hip/main.c:8:2 (approximate)
+# NO-APPROX: main
+# NO-APPROX-NEXT: /home/ampandey/test-hip/main.c:8:2
+
+#APPROX-VERBOSE: main
+#APPROX-VERBOSE-NEXT: Filename: /home/ampandey/test-hip/main.c
+#APPROX-VERBOSE-NEXT: Function start address: 0x0
+#APPROX-VERBOSE-NEXT: Line: 4
+#APPROX-VERBOSE-NEXT: Column: 6
+#APPROX-VERBOSE-NEXT: Approximate: 1
+
+#APPROX-JSON: [{"Address":"0xa","ModuleName":"{{.*}}/test/tools/llvm-symbolizer/Output/approximate-line-info.s.tmp.o","Symbol":[{"Approximate":true,"Column":6,"Discriminator":0,"FileName":"/home/ampandey/test-hip/main.c","FunctionName":"main","Line":4,"StartAddress":"0x0","StartFileName":"","StartLine":0}]}]
 
 ## Generated from C Code
 ##
diff --git a/llvm/test/tools/llvm-symbolizer/output-style-json-code.test b/llvm/test/tools/llvm-symbolizer/output-style-json-code.test
index 0e0e61c0bf119..d6410eeae2201 100644
--- a/llvm/test/tools/llvm-symbolizer/output-style-json-code.test
+++ b/llvm/test/tools/llvm-symbolizer/output-style-json-code.test
@@ -12,12 +12,12 @@
 ## Expected a list with one empty object with default values.
 # RUN: llvm-symbolizer --output-style=JSON -e %p/Inputs/addr.exe 0x10000000 | \
 # RUN:   FileCheck %s --check-prefix=NOT-FOUND --strict-whitespace --match-full-lines --implicit-check-not={{.}}
-# NOT-FOUND:[{"Address":"0x10000000","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}]
+# NOT-FOUND:[{"Address":"0x10000000","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}]
 
 ## Check a non-zero discriminator.
 # RUN: llvm-symbolizer --output-style=JSON --obj=%p/Inputs/discrim 0x400575 | \
 # RUN:   FileCheck %s --check-prefix=DISCRIM --strict-whitespace --match-full-lines --implicit-check-not={{.}}
-# DISCRIM:[{"Address":"0x400575","ModuleName":"{{.*}}/Inputs/discrim","Symbol":[{"Column":17,"Discriminator":2,"FileName":"/tmp{{/|\\\\}}discrim.c","FunctionName":"foo","Line":5,"StartAddress":"0x400560","StartFileName":"/tmp{{/|\\\\}}discrim.c","StartLine":4}]}]
+# DISCRIM:[{"Address":"0x400575","ModuleName":"{{.*}}/Inputs/discrim","Symbol":[{"Approximate":false,"Column":17,"Discriminator":2,"FileName":"/tmp{{/|\\\\}}discrim.c","FunctionName":"foo","Line":5,"StartAddress":"0x400560","StartFileName":"/tmp{{/|\\\\}}discrim.c","StartLine":4}]}]
 
 ## In case of stdin input the output will contain a single JSON object for each input string.
 
@@ -27,7 +27,7 @@
 ## Invalid first argument before any valid one.
 # NO-INLINES:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"something"}
 ## Resolve valid address.
-# NO-INLINES-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2}]}
+# NO-INLINES-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Approximate":false,"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2}]}
 ## Invalid argument after a valid one.
 # NO-INLINES-NEXT:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"some"}
 
@@ -37,7 +37,7 @@
 ## Invalid first argument before any valid one.
 # INLINE:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"something"}
 ## Resolve valid address.
-# INLINE-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inctwo","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inc","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
+# INLINE-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Approximate":false,"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inctwo","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inc","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
 ## Invalid argument after a valid one.
 # INLINE-NEXT:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"some"}
 
@@ -48,7 +48,7 @@
 ## Invalid first argument before any valid one.
 # INLINE-A2L:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"something"}
 ## Resolve valid address.
-# INLINE-A2L-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inctwo","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inc","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
+# INLINE-A2L-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Approximate":false,"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inctwo","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inc","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
 ## Invalid argument after a valid one.
 # INLINE-A2L:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"some"}
 
@@ -58,11 +58,11 @@
 ## Invalid first argument before any valid one.
 # NO-FUNC-A2L:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"something"}
 ## Resolve valid address.
-# NO-FUNC-A2L-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
+# NO-FUNC-A2L-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Approximate":false,"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
 ## Invalid argument after a valid one.
 # NO-FUNC-A2L-NEXT:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"some"}
 
 ## When a module offset is specified by a symbol, more than one source location can be found.
 # RUN: llvm-symbolizer --output-style=JSON --no-inlines -e %p/Inputs/symbols.so "static_func" | \
 # RUN:   FileCheck %s --check-prefix=MULTIPLE --strict-whitespace --match-full-lines --implicit-check-not={{.}}
-# MULTIPLE:[{"Loc":[{"Column":24,"Discriminator":0,"FileName":"/tmp/dbginfo{{/|\\\\}}symbols.part3.c","FunctionName":"static_func","Line":4,"StartAddress":"0x121d","StartFileName":"/tmp/dbginfo{{/|\\\\}}symbols.part3.c","StartLine":4},{"Column":24,"Discriminator":0,"FileName":"/tmp/dbginfo{{/|\\\\}}symbols.part4.c","FunctionName":"static_func","Line":4,"StartAddress":"0x125f","StartFileName":"/tmp/dbginfo{{/|\\\\}}symbols.part4.c","StartLine":4}],"ModuleName":"{{.*}}Inputs/symbols.so","SymName":"static_func"}]
+# MULTIPLE:[{"Loc":[{"Approximate":false,"Column":24,"Discriminator":0,"FileName":"/tmp/dbginfo{{/|\\\\}}symbols.part3.c","FunctionName":"static_func","Line":4,"StartAddress":"0x121d","StartFileName":"/tmp/dbginfo{{/|\\\\}}symbols.part3.c","StartLine":4},{"Approximate":false,"Column":24,"Discriminator":0,"FileName":"/tmp/dbginfo{{/|\\\\}}symbols.part4.c","FunctionName":"static_func","Line":4,"StartAddress":"0x125f","StartFileName":"/tmp/dbginfo{{/|\\\\}}symbols.part4.c","StartLine":4}],"ModuleName":"{{.*}}Inputs/symbols.so","SymName":"static_func"}]
diff --git a/llvm/test/tools/llvm-symbolizer/source.ll b/llvm/test/tools/llvm-symbolizer/source.ll
index 8a12c85812689..7f7072ee90b51 100644
--- a/llvm/test/tools/llvm-symbolizer/source.ll
+++ b/llvm/test/tools/llvm-symbolizer/source.ll
@@ -22,7 +22,7 @@
 ;; Check JSON style output.
 ; RUN: llvm-symbolizer --print-source-context-lines=3 --obj=%t.o 0 --output-style=JSON | \
 ; RUN:   FileCheck %s --check-prefix=JSON --strict-whitespace --match-full-lines --implicit-check-not={{.}}
-; JSON:[{"Address":"0x0","ModuleName":"{{.*}}.o","Symbol":[{"Column":13,"Discriminator":0,"FileName":"/source.c","FunctionName":"foo","Line":3,"Source":"2  : // Line 2\n3 >: void foo() {}\n4  : // Line 4\n","StartAddress":"0x0","StartFileName":"/source.c","StartLine":3}]}]
+; JSON:[{"Address":"0x0","ModuleName":"{{.*}}.o","Symbol":[{"Approximate":false,"Column":13,"Discriminator":0,"FileName":"/source.c","FunctionName":"foo","Line":3,"Source":"2  : // Line 2\n3 >: void foo() {}\n4  : // Line 4\n","StartAddress":"0x0","StartFileName":"/source.c","StartLine":3}]}]
 
 ;; Generated from the following source:
 ;; // Line 1

>From 21f8a3b569136eac95c32b35fa19203df24a5059 Mon Sep 17 00:00:00 2001
From: Amit Pandey <pandey.kumaramit2023 at gmail.com>
Date: Thu, 22 Feb 2024 22:08:20 +0530
Subject: [PATCH 04/12] Fix Typos.

---
 bolt/lib/Core/BinaryFunction.cpp                        | 3 ++-
 llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp             | 2 +-
 llvm/test/tools/llvm-symbolizer/approximate-line-info.s | 2 +-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index a9f704e447cc6..7891cbd6ce66a 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -192,9 +192,10 @@ static SMLoc findDebugLineInformationForInstructionAt(
       "Cannot fit instruction debug line information into SMLoc's pointer");
 
   SMLoc NullResult = DebugLineTableRowRef::NULL_ROW.toSMLoc();
-  uint32_t RowIndex = LineTable->lookupAddress(
+  auto RowIndexValue = LineTable->lookupAddress(
       {Address, object::SectionedAddress::UndefSection},
       DILineInfoSpecifier::ApproximateLineKind::None);
+  uint32_t RowIndex = RowIndexValue.first;
   if (RowIndex == LineTable->UnknownRowIndex)
     return NullResult;
 
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 71d4552259ded..9d44812909c79 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -1507,7 +1507,7 @@ bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
     DILineInfoSpecifier::ApproximateLineKind LineKind, const char *CompDir,
     FileLineInfoKind Kind, DILineInfo &Result) const {
   // Get the index of row we're looking for in the line table.
-  auto &&RowIndexValue = lookupAddress(Address, LineKind);
+  auto RowIndexValue = lookupAddress(Address, LineKind);
   uint32_t RowIndex = RowIndexValue.first;
   if (RowIndex == -1U)
     return false;
diff --git a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
index 26e595c83cdf8..9d3db5ef1b1e0 100644
--- a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
+++ b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
@@ -1,7 +1,7 @@
 # REQUIRES: x86-registered-target
 
 # RUN: llvm-mc -g -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: llvm-symbolizer --obj=%t.o 0xa | FileCheck --check-prefixes=APPROX-NONE %s
+# RUN: llvm-symbolizer --obj=%t.o 0xa | FileCheck --check-prefix=APPROX-NONE %s
 # RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before 0xa | FileCheck --check-prefix=APPROX-BEFORE %s
 # RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=after 0xa | FileCheck --check-prefix=APPROX-AFTER %s
 # RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before 0xa 0x10 | FileCheck --check-prefixes=APPROX-BEFORE,NO-APPROX %s

>From 5d9271fe0f4904418f14c3d8373676ee5f0e1879 Mon Sep 17 00:00:00 2001
From: Amit Pandey <pandey.kumaramit2023 at gmail.com>
Date: Wed, 13 Mar 2024 10:43:28 +0530
Subject: [PATCH 05/12] Addressing Comments of @dwblaike

1. Simplifying loop logic.
2. Adding logic to search non-zero line information only upto function
   boundaries.
---
 llvm/docs/CommandGuide/llvm-symbolizer.rst  |  2 +-
 llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp | 29 ++++++++++-----------
 2 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-symbolizer.rst b/llvm/docs/CommandGuide/llvm-symbolizer.rst
index 64e14a63861c6..76d155b49d00a 100644
--- a/llvm/docs/CommandGuide/llvm-symbolizer.rst
+++ b/llvm/docs/CommandGuide/llvm-symbolizer.rst
@@ -231,7 +231,7 @@ OPTIONS
 
   Print the approximate non-zero line number nearest to an input address.
   Nearest lookup is performed by querying the line-table structure for an
-  address having non-zero line information with close proxmity.
+  address having non-zero line information with close proximity.
 
 .. option:: --basenames, -s
 
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 9d44812909c79..23ed45b1d81c2 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -1340,30 +1340,29 @@ std::pair<uint32_t, bool> DWARFDebugLine::LineTable::lookupAddressImpl(
   if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex)
     return {UnknownRowIndex, false};
 
-  uint32_t RowIndex = UnknownRowIndex;
-  bool SecondAttempt = false;
+  uint32_t RowIndex = UnknownRowIndex;bool IsApproximate = false;
   if (LineKind == DILineInfoSpecifier::ApproximateLineKind::Before) {
-    for (auto SeqInst = Sequence.HighPC; SeqInst >= It->LowPC;) {
+    while (Address.Address >= It->LowPC) {
       RowIndex = findRowInSeq(*It, Address);
-      if (Rows[RowIndex].Line)
+      if(RowIndex!=UnknownRowIndex && Rows[RowIndex].Line)
         break;
-      if (!SecondAttempt)
-        SecondAttempt = true;
-      Address.Address = --SeqInst;
-    }
+      IsApproximate = true;
+      if(RowIndex!=UnknownRowIndex && Rows[RowIndex].PrologueEnd)break;
+      --Address.Address;
+      }
   } else if (LineKind == DILineInfoSpecifier::ApproximateLineKind::After) {
-    for (auto SeqInst = Sequence.HighPC; SeqInst <= It->HighPC;) {
+    while (Address.Address <= It->HighPC) {
       RowIndex = findRowInSeq(*It, Address);
-      if (Rows[RowIndex].Line)
+      if (RowIndex!=UnknownRowIndex && Rows[RowIndex].Line)
         break;
-      if (!SecondAttempt)
-        SecondAttempt = true;
-      Address.Address = ++SeqInst;
-    }
+      IsApproximate = true;
+      if(RowIndex!=UnknownRowIndex && Rows[RowIndex].EpilogueBegin)break;
+      ++Address.Address;
+      }
   } else {
     RowIndex = findRowInSeq(*It, Address);
   }
-  return {RowIndex, SecondAttempt};
+  return {RowIndex, IsApproximate};
 }
 
 bool DWARFDebugLine::LineTable::lookupAddressRange(

>From 6131f46e46a50efbdff163d966e732883ee2182b Mon Sep 17 00:00:00 2001
From: Amit Pandey <pandey.kumaramit2023 at gmail.com>
Date: Wed, 13 Mar 2024 13:42:52 +0530
Subject: [PATCH 06/12] Fix Clang Format warning.

---
 llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp     | 17 ++++++++++-------
 .../llvm-symbolizer/approximate-line-info.s     | 16 ++++++++--------
 2 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 23ed45b1d81c2..dae29ae4ef7e1 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -1340,25 +1340,28 @@ std::pair<uint32_t, bool> DWARFDebugLine::LineTable::lookupAddressImpl(
   if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex)
     return {UnknownRowIndex, false};
 
-  uint32_t RowIndex = UnknownRowIndex;bool IsApproximate = false;
+  uint32_t RowIndex = UnknownRowIndex;
+  bool IsApproximate = false;
   if (LineKind == DILineInfoSpecifier::ApproximateLineKind::Before) {
     while (Address.Address >= It->LowPC) {
       RowIndex = findRowInSeq(*It, Address);
-      if(RowIndex!=UnknownRowIndex && Rows[RowIndex].Line)
+      if (RowIndex != UnknownRowIndex && Rows[RowIndex].Line)
         break;
       IsApproximate = true;
-      if(RowIndex!=UnknownRowIndex && Rows[RowIndex].PrologueEnd)break;
+      if (RowIndex != UnknownRowIndex && Rows[RowIndex].PrologueEnd)
+        break;
       --Address.Address;
-      }
+    }
   } else if (LineKind == DILineInfoSpecifier::ApproximateLineKind::After) {
     while (Address.Address <= It->HighPC) {
       RowIndex = findRowInSeq(*It, Address);
-      if (RowIndex!=UnknownRowIndex && Rows[RowIndex].Line)
+      if (RowIndex != UnknownRowIndex && Rows[RowIndex].Line)
         break;
       IsApproximate = true;
-      if(RowIndex!=UnknownRowIndex && Rows[RowIndex].EpilogueBegin)break;
+      if (RowIndex != UnknownRowIndex && Rows[RowIndex].EpilogueBegin)
+        break;
       ++Address.Address;
-      }
+    }
   } else {
     RowIndex = findRowInSeq(*It, Address);
   }
diff --git a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
index 9d3db5ef1b1e0..ad046f4c4d944 100644
--- a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
+++ b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
@@ -9,22 +9,22 @@
 # RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before --output-style=JSON 0xa | FileCheck --check-prefix=APPROX-JSON %s
 
 # APPROX-NONE: main
-# APPROX-NONE-NEXT: /home/ampandey/test-hip/main.c:0:6
+# APPROX-NONE-NEXT: /tmp/test/main.c:0:6
 # APPROX-BEFORE: main
-# APPROX-BEFORE-NEXT: /home/ampandey/test-hip/main.c:4:6 (approximate)
+# APPROX-BEFORE-NEXT: /tmp/test/main.c:4:6 (approximate)
 # APPROX-AFTER: main
-# APPROX-AFTER-NEXT: /home/ampandey/test-hip/main.c:8:2 (approximate)
+# APPROX-AFTER-NEXT: /tmp/test/main.c:8:2 (approximate)
 # NO-APPROX: main
-# NO-APPROX-NEXT: /home/ampandey/test-hip/main.c:8:2
+# NO-APPROX-NEXT: /tmp/test/main.c:8:2
 
 #APPROX-VERBOSE: main
-#APPROX-VERBOSE-NEXT: Filename: /home/ampandey/test-hip/main.c
+#APPROX-VERBOSE-NEXT: Filename: /tmp/test/main.c
 #APPROX-VERBOSE-NEXT: Function start address: 0x0
 #APPROX-VERBOSE-NEXT: Line: 4
 #APPROX-VERBOSE-NEXT: Column: 6
 #APPROX-VERBOSE-NEXT: Approximate: 1
 
-#APPROX-JSON: [{"Address":"0xa","ModuleName":"{{.*}}/test/tools/llvm-symbolizer/Output/approximate-line-info.s.tmp.o","Symbol":[{"Approximate":true,"Column":6,"Discriminator":0,"FileName":"/home/ampandey/test-hip/main.c","FunctionName":"main","Line":4,"StartAddress":"0x0","StartFileName":"","StartLine":0}]}]
+#APPROX-JSON: [{"Address":"0xa","ModuleName":"{{.*}}/test/tools/llvm-symbolizer/Output/approximate-line-info.s.tmp.o","Symbol":[{"Approximate":true,"Column":6,"Discriminator":0,"FileName":"/tmp/test/main.c","FunctionName":"main","Line":4,"StartAddress":"0x0","StartFileName":"","StartLine":0}]}]
 
 ## Generated from C Code
 ##
@@ -46,7 +46,7 @@
 	.type	main, at function
 main:                                   # @main
 .Lfunc_begin0:
-	.file	0 "/home/ampandey/test-hip" "main.c" md5 0x26c3fbaea8e6febaf09ef44d37ec5ecc
+	.file	0 "/tmp/test" "main.c" md5 0x26c3fbaea8e6febaf09ef44d37ec5ecc
 	.cfi_startproc
 # %bb.0:                                # %entry
 	.loc	0 4 6 prologue_end              # main.c:4:6
@@ -135,7 +135,7 @@ x:
 .Linfo_string1:
 	.asciz	"main.c"                        # string offset=113
 .Linfo_string2:
-	.asciz	"/home/ampandey/test-hip"       # string offset=120
+	.asciz	"/tmp/test"       # string offset=120
 	.section	.debug_str_offsets,"", at progbits
 	.long	.Linfo_string0
 	.long	.Linfo_string1

>From d5773410c241a480b2a11724b92b8e24599aa7e8 Mon Sep 17 00:00:00 2001
From: Amit Pandey <pandey.kumaramit2023 at gmail.com>
Date: Thu, 14 Mar 2024 16:02:57 +0530
Subject: [PATCH 07/12] Fix Windows X64 CI failure.

---
 llvm/docs/CommandGuide/llvm-symbolizer.rst             |  2 +-
 .../test/tools/llvm-symbolizer/approximate-line-info.s | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-symbolizer.rst b/llvm/docs/CommandGuide/llvm-symbolizer.rst
index 76d155b49d00a..8ba41b302138e 100644
--- a/llvm/docs/CommandGuide/llvm-symbolizer.rst
+++ b/llvm/docs/CommandGuide/llvm-symbolizer.rst
@@ -231,7 +231,7 @@ OPTIONS
 
   Print the approximate non-zero line number nearest to an input address.
   Nearest lookup is performed by querying the line-table structure for an
-  address having non-zero line information with close proximity.
+  address having non-zero line information in close proximity.
 
 .. option:: --basenames, -s
 
diff --git a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
index ad046f4c4d944..b3874a9e33a92 100644
--- a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
+++ b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
@@ -9,16 +9,16 @@
 # RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before --output-style=JSON 0xa | FileCheck --check-prefix=APPROX-JSON %s
 
 # APPROX-NONE: main
-# APPROX-NONE-NEXT: /tmp/test/main.c:0:6
+# APPROX-NONE-NEXT: {{[/\]+}}tmp{{[/\]+}}test{{[/\]+}}main.c:0:6
 # APPROX-BEFORE: main
-# APPROX-BEFORE-NEXT: /tmp/test/main.c:4:6 (approximate)
+# APPROX-BEFORE-NEXT: {{[/\]+}}tmp{{[/\]+}}test{{[/\]+}}main.c:4:6 (approximate)
 # APPROX-AFTER: main
-# APPROX-AFTER-NEXT: /tmp/test/main.c:8:2 (approximate)
+# APPROX-AFTER-NEXT: {{[/\]+}}tmp{{[/\]+}}test{{[/\]+}}main.c:8:2 (approximate)
 # NO-APPROX: main
-# NO-APPROX-NEXT: /tmp/test/main.c:8:2
+# NO-APPROX-NEXT: {{[/\]+}}tmp{{[/\]+}}test{{[/\]+}}main.c:8:2
 
 #APPROX-VERBOSE: main
-#APPROX-VERBOSE-NEXT: Filename: /tmp/test/main.c
+#APPROX-VERBOSE-NEXT: Filename: {{[/\]+}}tmp{{[/\]+}}test{{[/\]+}}main.c
 #APPROX-VERBOSE-NEXT: Function start address: 0x0
 #APPROX-VERBOSE-NEXT: Line: 4
 #APPROX-VERBOSE-NEXT: Column: 6

>From ecd295608fece1a15475e7e92b2cd8797b6f2336 Mon Sep 17 00:00:00 2001
From: Amit Pandey <pandey.kumaramit2023 at gmail.com>
Date: Mon, 18 Mar 2024 15:04:30 +0530
Subject: [PATCH 08/12] Fix Windows CI Failure II

---
 .../tools/llvm-symbolizer/approximate-line-info.s    | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
index b3874a9e33a92..114426ad74f54 100644
--- a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
+++ b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
@@ -9,22 +9,22 @@
 # RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before --output-style=JSON 0xa | FileCheck --check-prefix=APPROX-JSON %s
 
 # APPROX-NONE: main
-# APPROX-NONE-NEXT: {{[/\]+}}tmp{{[/\]+}}test{{[/\]+}}main.c:0:6
+# APPROX-NONE-NEXT: /tmp/test{{[/|\]}}main.c:0:6
 # APPROX-BEFORE: main
-# APPROX-BEFORE-NEXT: {{[/\]+}}tmp{{[/\]+}}test{{[/\]+}}main.c:4:6 (approximate)
+# APPROX-BEFORE-NEXT: /tmp/test{{[/|\]}}main.c:4:6 (approximate)
 # APPROX-AFTER: main
-# APPROX-AFTER-NEXT: {{[/\]+}}tmp{{[/\]+}}test{{[/\]+}}main.c:8:2 (approximate)
+# APPROX-AFTER-NEXT: /tmp/test{{[/|\]}}main.c:8:2 (approximate)
 # NO-APPROX: main
-# NO-APPROX-NEXT: {{[/\]+}}tmp{{[/\]+}}test{{[/\]+}}main.c:8:2
+# NO-APPROX-NEXT: /tmp/test{{[/|\]}}main.c:8:2
 
 #APPROX-VERBOSE: main
-#APPROX-VERBOSE-NEXT: Filename: {{[/\]+}}tmp{{[/\]+}}test{{[/\]+}}main.c
+#APPROX-VERBOSE-NEXT: Filename: /tmp/test{{[/|\]}}main.c
 #APPROX-VERBOSE-NEXT: Function start address: 0x0
 #APPROX-VERBOSE-NEXT: Line: 4
 #APPROX-VERBOSE-NEXT: Column: 6
 #APPROX-VERBOSE-NEXT: Approximate: 1
 
-#APPROX-JSON: [{"Address":"0xa","ModuleName":"{{.*}}/test/tools/llvm-symbolizer/Output/approximate-line-info.s.tmp.o","Symbol":[{"Approximate":true,"Column":6,"Discriminator":0,"FileName":"/tmp/test/main.c","FunctionName":"main","Line":4,"StartAddress":"0x0","StartFileName":"","StartLine":0}]}]
+#APPROX-JSON: [{"Address":"0xa","ModuleName":"{{.*}}/test/tools/llvm-symbolizer/Output/approximate-line-info.s.tmp.o","Symbol":[{"Approximate":true,"Column":6,"Discriminator":0,"FileName":"/tmp/test{{[/|\]}}main.c","FunctionName":"main","Line":4,"StartAddress":"0x0","StartFileName":"","StartLine":0}]}]
 
 ## Generated from C Code
 ##

>From 2f5df14e7be6c4478f9f6ded903d5fc69d0fd464 Mon Sep 17 00:00:00 2001
From: Amit Pandey <pandey.kumaramit2023 at gmail.com>
Date: Tue, 26 Mar 2024 11:04:25 +0530
Subject: [PATCH 09/12] Fix Windows CI III

---
 .../test/tools/llvm-symbolizer/approximate-line-info.s | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
index 114426ad74f54..480d5cbed6133 100644
--- a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
+++ b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
@@ -9,13 +9,13 @@
 # RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before --output-style=JSON 0xa | FileCheck --check-prefix=APPROX-JSON %s
 
 # APPROX-NONE: main
-# APPROX-NONE-NEXT: /tmp/test{{[/|\]}}main.c:0:6
+# APPROX-NONE-NEXT: {{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:0:6
 # APPROX-BEFORE: main
-# APPROX-BEFORE-NEXT: /tmp/test{{[/|\]}}main.c:4:6 (approximate)
+# APPROX-BEFORE-NEXT: {{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:4:6 (approximate)
 # APPROX-AFTER: main
-# APPROX-AFTER-NEXT: /tmp/test{{[/|\]}}main.c:8:2 (approximate)
+# APPROX-AFTER-NEXT: {{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:8:2 (approximate)
 # NO-APPROX: main
-# NO-APPROX-NEXT: /tmp/test{{[/|\]}}main.c:8:2
+# NO-APPROX-NEXT: {{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:8:2
 
 #APPROX-VERBOSE: main
 #APPROX-VERBOSE-NEXT: Filename: /tmp/test{{[/|\]}}main.c
@@ -24,7 +24,7 @@
 #APPROX-VERBOSE-NEXT: Column: 6
 #APPROX-VERBOSE-NEXT: Approximate: 1
 
-#APPROX-JSON: [{"Address":"0xa","ModuleName":"{{.*}}/test/tools/llvm-symbolizer/Output/approximate-line-info.s.tmp.o","Symbol":[{"Approximate":true,"Column":6,"Discriminator":0,"FileName":"/tmp/test{{[/|\]}}main.c","FunctionName":"main","Line":4,"StartAddress":"0x0","StartFileName":"","StartLine":0}]}]
+#APPROX-JSON: [{"Address":"0xa","ModuleName":"{{.*}}{{[/|\]+}}test{{[/|\]+}}tools{{[/|\]+}}llvm-symbolizer{{[/|\]+}}Output{{[/|\]+}}approximate-line-info.s.tmp.o","Symbol":[{"Approximate":true,"Column":6,"Discriminator":0,"FileName":"{{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c","FunctionName":"main","Line":4,"StartAddress":"0x0","StartFileName":"","StartLine":0}]}]
 
 ## Generated from C Code
 ##

>From 0e78834e7f6b28afb0b256649f9c42f4e6f51bc1 Mon Sep 17 00:00:00 2001
From: Amit Pandey <pandey.kumaramit2023 at gmail.com>
Date: Wed, 3 Apr 2024 16:36:12 +0530
Subject: [PATCH 10/12] Address Comments of @dwblaike

---
 llvm/docs/CommandGuide/llvm-symbolizer.rst  | 4 ++--
 llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp | 6 ++++--
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-symbolizer.rst b/llvm/docs/CommandGuide/llvm-symbolizer.rst
index 8ba41b302138e..b75173781164d 100644
--- a/llvm/docs/CommandGuide/llvm-symbolizer.rst
+++ b/llvm/docs/CommandGuide/llvm-symbolizer.rst
@@ -213,10 +213,10 @@ Example 8 - Addresses having approximate line info:
 
   $ llvm-symbolizer --obj=test.elf --approximate-line-info=before 0xa
   main
-  /home/ampandey/test-hip/main.c:4:6 (approximate)
+  /tmp/test/main.c:4:6 (approximate)
   $ llvm-symbolizer --obj=test.elf --approximate-line-info=after 0xa
   main
-  /home/ampandey/test-hip/main.c:8:2 (approximate)
+  /tmp/test/main.c:8:2 (approximate)
 
 OPTIONS
 -------
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index dae29ae4ef7e1..87558d4ee578b 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -1348,7 +1348,8 @@ std::pair<uint32_t, bool> DWARFDebugLine::LineTable::lookupAddressImpl(
       if (RowIndex != UnknownRowIndex && Rows[RowIndex].Line)
         break;
       IsApproximate = true;
-      if (RowIndex != UnknownRowIndex && Rows[RowIndex].PrologueEnd)
+      if (RowIndex != UnknownRowIndex &&
+          (Rows[RowIndex].BasicBlock | Rows[RowIndex].PrologueEnd))
         break;
       --Address.Address;
     }
@@ -1358,7 +1359,8 @@ std::pair<uint32_t, bool> DWARFDebugLine::LineTable::lookupAddressImpl(
       if (RowIndex != UnknownRowIndex && Rows[RowIndex].Line)
         break;
       IsApproximate = true;
-      if (RowIndex != UnknownRowIndex && Rows[RowIndex].EpilogueBegin)
+      if (RowIndex != UnknownRowIndex &&
+          (Rows[RowIndex].BasicBlock | Rows[RowIndex].EpilogueBegin))
         break;
       ++Address.Address;
     }

>From 5139d84d2c2c65d78e8140a04e59d5d0d0373d4d Mon Sep 17 00:00:00 2001
From: Amit Pandey <pandey.kumaramit2023 at gmail.com>
Date: Mon, 29 Apr 2024 16:56:14 +0530
Subject: [PATCH 11/12] Address comments.

---
 bolt/lib/Core/BinaryFunction.cpp              |  3 +-
 lld/Common/DWARF.cpp                          |  3 +-
 llvm/docs/CommandGuide/llvm-symbolizer.rst    | 13 ++---
 llvm/include/llvm/DebugInfo/DIContext.h       |  7 ++-
 .../llvm/DebugInfo/DWARF/DWARFDebugLine.h     | 15 +++---
 .../llvm/DebugInfo/Symbolize/Symbolize.h      |  3 +-
 llvm/lib/DebugInfo/DWARF/DWARFContext.cpp     | 15 +++---
 llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp   | 53 ++++++++-----------
 llvm/lib/DebugInfo/Symbolize/Symbolize.cpp    |  4 +-
 .../llvm-symbolizer/approximate-line-info.s   | 39 +++++++-------
 llvm/tools/llvm-symbolizer/Opts.td            |  2 +-
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp |  9 +---
 12 files changed, 69 insertions(+), 97 deletions(-)

diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index 7891cbd6ce66a..dfca1182c139f 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -193,8 +193,7 @@ static SMLoc findDebugLineInformationForInstructionAt(
 
   SMLoc NullResult = DebugLineTableRowRef::NULL_ROW.toSMLoc();
   auto RowIndexValue = LineTable->lookupAddress(
-      {Address, object::SectionedAddress::UndefSection},
-      DILineInfoSpecifier::ApproximateLineKind::None);
+      {Address, object::SectionedAddress::UndefSection}, false);
   uint32_t RowIndex = RowIndexValue.first;
   if (RowIndex == LineTable->UnknownRowIndex)
     return NullResult;
diff --git a/lld/Common/DWARF.cpp b/lld/Common/DWARF.cpp
index 8e1e9c6e53015..fc1b6d22c1a10 100644
--- a/lld/Common/DWARF.cpp
+++ b/lld/Common/DWARF.cpp
@@ -93,8 +93,7 @@ std::optional<DILineInfo> DWARFCache::getDILineInfo(uint64_t offset,
   DILineInfo info;
   for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) {
     if (lt->getFileLineInfoForAddress(
-            {offset, sectionIndex},
-            DILineInfoSpecifier::ApproximateLineKind::None, nullptr,
+            {offset, sectionIndex}, nullptr, false,
             DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info))
       return info;
   }
diff --git a/llvm/docs/CommandGuide/llvm-symbolizer.rst b/llvm/docs/CommandGuide/llvm-symbolizer.rst
index b75173781164d..bdf206c31b855 100644
--- a/llvm/docs/CommandGuide/llvm-symbolizer.rst
+++ b/llvm/docs/CommandGuide/llvm-symbolizer.rst
@@ -211,12 +211,9 @@ Example 8 - Addresses having approximate line info:
 
 .. code-block:: console
 
-  $ llvm-symbolizer --obj=test.elf --approximate-line-info=before 0xa
+  $ llvm-symbolizer --obj=test.elf --approximate-line 0xa
   main
   /tmp/test/main.c:4:6 (approximate)
-  $ llvm-symbolizer --obj=test.elf --approximate-line-info=after 0xa
-  main
-  /tmp/test/main.c:8:2 (approximate)
 
 OPTIONS
 -------
@@ -227,11 +224,11 @@ OPTIONS
   This can be used to perform lookups as if the object were relocated by the
   offset.
 
-.. option:: --approximate-line-info=<before|after>
+.. option:: --approximate-line
 
-  Print the approximate non-zero line number nearest to an input address.
-  Nearest lookup is performed by querying the line-table structure for an
-  address having non-zero line information in close proximity.
+  Print the approximate non-zero line number that is nearest to before an
+  input address. Nearest lookup is performed by querying the line-table
+  structure for an address having non-zero line information in close proximity.
 
 .. option:: --basenames, -s
 
diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h
index fb18f6d124a49..d075cbd1dd147 100644
--- a/llvm/include/llvm/DebugInfo/DIContext.h
+++ b/llvm/include/llvm/DebugInfo/DIContext.h
@@ -154,16 +154,15 @@ struct DILineInfoSpecifier {
     RelativeFilePath,
     AbsoluteFilePath
   };
-  enum ApproximateLineKind { None, Before, After };
   using FunctionNameKind = DINameKind;
   FileLineInfoKind FLIKind;
   FunctionNameKind FNKind;
-  ApproximateLineKind ALKind;
+  bool ApproximateLine;
 
   DILineInfoSpecifier(FileLineInfoKind FLIKind = FileLineInfoKind::RawValue,
                       FunctionNameKind FNKind = FunctionNameKind::None,
-                      ApproximateLineKind ALKind = ApproximateLineKind::None)
-      : FLIKind(FLIKind), FNKind(FNKind), ALKind(ALKind) {}
+                      bool ApproximateLine = false)
+      : FLIKind(FLIKind), FNKind(FNKind), ApproximateLine(ApproximateLine) {}
 
   inline bool operator==(const DILineInfoSpecifier &RHS) const {
     return FLIKind == RHS.FLIKind && FNKind == RHS.FNKind;
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
index 5a60dadf9269e..b8b5f1d8688f8 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
@@ -240,9 +240,8 @@ class DWARFDebugLine {
 
     /// Returns the index of the row with file/line info for a given address,
     /// or UnknownRowIndex if there is no such row.
-    std::pair<uint32_t, bool>
-    lookupAddress(object::SectionedAddress Address,
-                  DILineInfoSpecifier::ApproximateLineKind LineKind) const;
+    std::pair<uint32_t, bool> lookupAddress(object::SectionedAddress Address,
+                                            bool ApproximateLine) const;
 
     bool lookupAddressRange(object::SectionedAddress Address, uint64_t Size,
                             std::vector<uint32_t> &Result) const;
@@ -268,10 +267,10 @@ class DWARFDebugLine {
 
     /// Fills the Result argument with the file and line information
     /// corresponding to Address. Returns true on success.
-    bool getFileLineInfoForAddress(
-        object::SectionedAddress Address,
-        DILineInfoSpecifier::ApproximateLineKind LineKind, const char *CompDir,
-        DILineInfoSpecifier::FileLineInfoKind Kind, DILineInfo &Result) const;
+    bool getFileLineInfoForAddress(object::SectionedAddress Address,
+                                   const char *CompDir, bool ApproximateLine,
+                                   DILineInfoSpecifier::FileLineInfoKind Kind,
+                                   DILineInfo &Result) const;
 
     /// Extracts directory name by its Entry in include directories table
     /// in prologue. Returns true on success.
@@ -305,7 +304,7 @@ class DWARFDebugLine {
 
     std::pair<uint32_t, bool>
     lookupAddressImpl(object::SectionedAddress Address,
-                      DILineInfoSpecifier::ApproximateLineKind LineKind) const;
+                      bool ApproximateLine) const;
 
     bool lookupAddressRangeImpl(object::SectionedAddress Address, uint64_t Size,
                                 std::vector<uint32_t> &Result) const;
diff --git a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
index 7b560f4b7dbb2..9dc9af7f0ddbb 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
@@ -44,7 +44,6 @@ using namespace object;
 
 using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind;
 using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
-using ApproximateLineKind = DILineInfoSpecifier::ApproximateLineKind;
 
 class CachedBinary;
 
@@ -53,7 +52,7 @@ class LLVMSymbolizer {
   struct Options {
     FunctionNameKind PrintFunctions = FunctionNameKind::LinkageName;
     FileLineInfoKind PathStyle = FileLineInfoKind::AbsoluteFilePath;
-    ApproximateLineKind ApproximateLineNumbers = ApproximateLineKind::None;
+    bool ApproximateLine = false;
     bool UseSymbolTable = true;
     bool Demangle = true;
     bool RelativeAddresses = false;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 9bf7dbd0acc10..49fc4dd00c4fe 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -1742,8 +1742,8 @@ DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
   if (Spec.FLIKind != FileLineInfoKind::None) {
     if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) {
       LineTable->getFileLineInfoForAddress(
-          {Address.Address, Address.SectionIndex}, Spec.ALKind,
-          CU->getCompilationDir(), Spec.FLIKind, Result);
+          {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
+          Spec.ApproximateLine, Spec.FLIKind, Result);
     }
   }
 
@@ -1837,9 +1837,10 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
     if (Spec.FLIKind != FileLineInfoKind::None) {
       DILineInfo Frame;
       LineTable = getLineTableForUnit(CU);
-      if (LineTable && LineTable->getFileLineInfoForAddress(
-                           {Address.Address, Address.SectionIndex}, Spec.ALKind,
-                           CU->getCompilationDir(), Spec.FLIKind, Frame))
+      if (LineTable &&
+          LineTable->getFileLineInfoForAddress(
+              {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
+              Spec.ApproximateLine, Spec.FLIKind, Frame))
         InliningInfo.addFrame(Frame);
     }
     return InliningInfo;
@@ -1865,8 +1866,8 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
         // For the topmost routine, get file/line info from line table.
         if (LineTable)
           LineTable->getFileLineInfoForAddress(
-              {Address.Address, Address.SectionIndex}, Spec.ALKind,
-              CU->getCompilationDir(), Spec.FLIKind, Frame);
+              {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
+              Spec.ApproximateLine, Spec.FLIKind, Frame);
       } else {
         // Otherwise, use call file, call line and call column from
         // previous DIE in inlined chain.
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 87558d4ee578b..0db77795700fa 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -1312,12 +1312,13 @@ uint32_t DWARFDebugLine::LineTable::findRowInSeq(
   return RowPos - Rows.begin();
 }
 
-std::pair<uint32_t, bool> DWARFDebugLine::LineTable::lookupAddress(
-    object::SectionedAddress Address,
-    DILineInfoSpecifier::ApproximateLineKind LineKind) const {
+std::pair<uint32_t, bool>
+DWARFDebugLine::LineTable::lookupAddress(object::SectionedAddress Address,
+                                         bool ApproximateLine) const {
 
   // Search for relocatable addresses
-  std::pair<uint32_t, bool> Result = lookupAddressImpl(Address, LineKind);
+  std::pair<uint32_t, bool> Result =
+      lookupAddressImpl(Address, ApproximateLine);
 
   if (Result.first != UnknownRowIndex ||
       Address.SectionIndex == object::SectionedAddress::UndefSection)
@@ -1325,12 +1326,12 @@ std::pair<uint32_t, bool> DWARFDebugLine::LineTable::lookupAddress(
 
   // Search for absolute addresses
   Address.SectionIndex = object::SectionedAddress::UndefSection;
-  return lookupAddressImpl(Address, LineKind);
+  return lookupAddressImpl(Address, ApproximateLine);
 }
 
-std::pair<uint32_t, bool> DWARFDebugLine::LineTable::lookupAddressImpl(
-    object::SectionedAddress Address,
-    DILineInfoSpecifier::ApproximateLineKind LineKind) const {
+std::pair<uint32_t, bool>
+DWARFDebugLine::LineTable::lookupAddressImpl(object::SectionedAddress Address,
+                                             bool ApproximateLine) const {
   // First, find an instruction sequence containing the given address.
   DWARFDebugLine::Sequence Sequence;
   Sequence.SectionIndex = Address.SectionIndex;
@@ -1340,32 +1341,21 @@ std::pair<uint32_t, bool> DWARFDebugLine::LineTable::lookupAddressImpl(
   if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex)
     return {UnknownRowIndex, false};
 
-  uint32_t RowIndex = UnknownRowIndex;
+  uint32_t RowIndex = findRowInSeq(*It, Address);
   bool IsApproximate = false;
-  if (LineKind == DILineInfoSpecifier::ApproximateLineKind::Before) {
-    while (Address.Address >= It->LowPC) {
-      RowIndex = findRowInSeq(*It, Address);
-      if (RowIndex != UnknownRowIndex && Rows[RowIndex].Line)
+  if (ApproximateLine) {
+    uint32_t ApproxRowIndex = RowIndex;
+    while (ApproxRowIndex >= It->FirstRowIndex) {
+      if (ApproxRowIndex != UnknownRowIndex && Rows[ApproxRowIndex].Line)
         break;
       IsApproximate = true;
-      if (RowIndex != UnknownRowIndex &&
-          (Rows[RowIndex].BasicBlock | Rows[RowIndex].PrologueEnd))
+      if (ApproxRowIndex != UnknownRowIndex &&
+          (Rows[ApproxRowIndex].BasicBlock | Rows[ApproxRowIndex].PrologueEnd))
         break;
-      --Address.Address;
+      --ApproxRowIndex;
     }
-  } else if (LineKind == DILineInfoSpecifier::ApproximateLineKind::After) {
-    while (Address.Address <= It->HighPC) {
-      RowIndex = findRowInSeq(*It, Address);
-      if (RowIndex != UnknownRowIndex && Rows[RowIndex].Line)
-        break;
-      IsApproximate = true;
-      if (RowIndex != UnknownRowIndex &&
-          (Rows[RowIndex].BasicBlock | Rows[RowIndex].EpilogueBegin))
-        break;
-      ++Address.Address;
-    }
-  } else {
-    RowIndex = findRowInSeq(*It, Address);
+    if (ApproxRowIndex >= It->FirstRowIndex)
+      RowIndex = ApproxRowIndex;
   }
   return {RowIndex, IsApproximate};
 }
@@ -1507,11 +1497,10 @@ bool DWARFDebugLine::Prologue::getFileNameByIndex(
 }
 
 bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
-    object::SectionedAddress Address,
-    DILineInfoSpecifier::ApproximateLineKind LineKind, const char *CompDir,
+    object::SectionedAddress Address, const char *CompDir, bool ApproximateLine,
     FileLineInfoKind Kind, DILineInfo &Result) const {
   // Get the index of row we're looking for in the line table.
-  auto RowIndexValue = lookupAddress(Address, LineKind);
+  auto RowIndexValue = lookupAddress(Address, ApproximateLine);
   uint32_t RowIndex = RowIndexValue.first;
   if (RowIndex == -1U)
     return false;
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index 6c8303bcee6ca..9d3bf6d38c0fa 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -73,7 +73,7 @@ LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier,
   DILineInfo LineInfo = Info->symbolizeCode(
       ModuleOffset,
       DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions,
-                          Opts.ApproximateLineNumbers),
+                          Opts.ApproximateLine),
       Opts.UseSymbolTable);
   if (Opts.Demangle)
     LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
@@ -120,7 +120,7 @@ Expected<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCodeCommon(
   DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
       ModuleOffset,
       DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions,
-                          Opts.ApproximateLineNumbers),
+                          Opts.ApproximateLine),
       Opts.UseSymbolTable);
   if (Opts.Demangle) {
     for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
diff --git a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
index 480d5cbed6133..54414cab816ec 100644
--- a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
+++ b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
@@ -1,30 +1,27 @@
 # REQUIRES: x86-registered-target
 
 # RUN: llvm-mc -g -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: llvm-symbolizer --obj=%t.o 0xa | FileCheck --check-prefix=APPROX-NONE %s
-# RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before 0xa | FileCheck --check-prefix=APPROX-BEFORE %s
-# RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=after 0xa | FileCheck --check-prefix=APPROX-AFTER %s
-# RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before 0xa 0x10 | FileCheck --check-prefixes=APPROX-BEFORE,NO-APPROX %s
-# RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before --verbose 0xa | FileCheck --check-prefix=APPROX-VERBOSE %s
-# RUN: llvm-symbolizer --obj=%t.o --approximate-line-info=before --output-style=JSON 0xa | FileCheck --check-prefix=APPROX-JSON %s
+# RUN: llvm-symbolizer --obj=%t.o 0xa | FileCheck --strict-whitespace --match-full-lines --check-prefix=APPROX-DISABLE %s
+# RUN: llvm-symbolizer --obj=%t.o --approximate-line 0xa | FileCheck --strict-whitespace --match-full-lines --check-prefix=APPROX-ENABLE %s
+# RUN: llvm-symbolizer --obj=%t.o --approximate-line 0xa 0x10 | FileCheck --strict-whitespace --match-full-lines --check-prefixes=APPROX-ENABLE,NO-APPROX %s
+# RUN: llvm-symbolizer --obj=%t.o --approximate-line --verbose 0xa | FileCheck --strict-whitespace --match-full-lines --check-prefix=APPROX-VERBOSE %s
+# RUN: llvm-symbolizer --obj=%t.o --approximate-line --output-style=JSON 0xa | FileCheck --strict-whitespace --match-full-lines --check-prefix=APPROX-JSON %s
 
-# APPROX-NONE: main
-# APPROX-NONE-NEXT: {{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:0:6
-# APPROX-BEFORE: main
-# APPROX-BEFORE-NEXT: {{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:4:6 (approximate)
-# APPROX-AFTER: main
-# APPROX-AFTER-NEXT: {{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:8:2 (approximate)
-# NO-APPROX: main
-# NO-APPROX-NEXT: {{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:8:2
+# APPROX-DISABLE:main
+# APPROX-DISABLE-NEXT:{{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:0:6
+# APPROX-ENABLE:main
+# APPROX-ENABLE-NEXT:{{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:4:6 (approximate)
+# NO-APPROX:main
+# NO-APPROX-NEXT:{{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:8:2
 
-#APPROX-VERBOSE: main
-#APPROX-VERBOSE-NEXT: Filename: /tmp/test{{[/|\]}}main.c
-#APPROX-VERBOSE-NEXT: Function start address: 0x0
-#APPROX-VERBOSE-NEXT: Line: 4
-#APPROX-VERBOSE-NEXT: Column: 6
-#APPROX-VERBOSE-NEXT: Approximate: 1
+#APPROX-VERBOSE:main
+#APPROX-VERBOSE-NEXT:  Filename: /tmp/test{{[/|\]}}main.c
+#APPROX-VERBOSE-NEXT:  Function start address: 0x0
+#APPROX-VERBOSE-NEXT:  Line: 4
+#APPROX-VERBOSE-NEXT:  Column: 6
+#APPROX-VERBOSE-NEXT:  Approximate: 1
 
-#APPROX-JSON: [{"Address":"0xa","ModuleName":"{{.*}}{{[/|\]+}}test{{[/|\]+}}tools{{[/|\]+}}llvm-symbolizer{{[/|\]+}}Output{{[/|\]+}}approximate-line-info.s.tmp.o","Symbol":[{"Approximate":true,"Column":6,"Discriminator":0,"FileName":"{{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c","FunctionName":"main","Line":4,"StartAddress":"0x0","StartFileName":"","StartLine":0}]}]
+#APPROX-JSON:[{"Address":"0xa","ModuleName":"{{.*}}{{[/|\]+}}test{{[/|\]+}}tools{{[/|\]+}}llvm-symbolizer{{[/|\]+}}Output{{[/|\]+}}approximate-line-info.s.tmp.o","Symbol":[{"Approximate":true,"Column":6,"Discriminator":0,"FileName":"{{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c","FunctionName":"main","Line":4,"StartAddress":"0x0","StartFileName":"","StartLine":0}]}]
 
 ## Generated from C Code
 ##
diff --git a/llvm/tools/llvm-symbolizer/Opts.td b/llvm/tools/llvm-symbolizer/Opts.td
index 80ec4721c45e0..097ea17b90e9e 100644
--- a/llvm/tools/llvm-symbolizer/Opts.td
+++ b/llvm/tools/llvm-symbolizer/Opts.td
@@ -17,7 +17,7 @@ def grp_mach_o : OptionGroup<"kind">,
                  HelpText<"llvm-symbolizer Mach-O Specific Options">;
 
 def addresses : F<"addresses", "Show address before line information">;
-defm approximate_line_info : Eq<"approximate-line-info","Find approximate non-zero line number information nearest to given address.">,Values<"<before/after>">;
+def approximate_line : F<"approximate-line","Show approximate non-zero line number information nearest to before the given address.">;
 defm adjust_vma
     : Eq<"adjust-vma", "Add specified offset to object file addresses">,
       MetaVarName<"<offset>">;
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 530dbdfd5c8b5..591bf70ea2e49 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -482,14 +482,7 @@ int llvm_symbolizer_main(int argc, char **argv, const llvm::ToolContext &) {
   } else {
     Opts.PathStyle = DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath;
   }
-  StringRef ApproximateLineKindVal =
-      Args.getLastArgValue(OPT_approximate_line_info_EQ);
-  Opts.ApproximateLineNumbers =
-      ApproximateLineKindVal == "before"
-          ? DILineInfoSpecifier::ApproximateLineKind::Before
-      : ApproximateLineKindVal == "after"
-          ? DILineInfoSpecifier::ApproximateLineKind::After
-          : DILineInfoSpecifier::ApproximateLineKind::None;
+  Opts.ApproximateLine = Args.hasArg(OPT_approximate_line);
   Opts.DebugFileDirectory = Args.getAllArgValues(OPT_debug_file_directory_EQ);
   Opts.DefaultArch = Args.getLastArgValue(OPT_default_arch_EQ).str();
   Opts.Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, !IsAddr2Line);

>From b650bfba0c12cc07fa671cbbee10012445e1d960 Mon Sep 17 00:00:00 2001
From: Amit Pandey <pandey.kumaramit2023 at gmail.com>
Date: Tue, 7 May 2024 12:34:19 +0530
Subject: [PATCH 12/12] Address review comments.

---
 bolt/lib/Core/BinaryFunction.cpp              |  5 +-
 lld/Common/DWARF.cpp                          |  2 +-
 llvm/docs/CommandGuide/llvm-symbolizer.rst    | 11 ++---
 .../llvm/DebugInfo/DWARF/DWARFDebugLine.h     | 14 +++---
 llvm/lib/DebugInfo/DWARF/DWARFContext.cpp     | 13 +++---
 llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp   | 46 ++++++++-----------
 llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp    |  8 ++--
 .../llvm-symbolizer/approximate-line-info.s   |  8 ++--
 .../output-style-json-code.test               | 14 +++---
 llvm/test/tools/llvm-symbolizer/source.ll     |  2 +-
 llvm/tools/llvm-symbolizer/Opts.td            |  2 +-
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp |  2 +-
 12 files changed, 60 insertions(+), 67 deletions(-)

diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index dfca1182c139f..1fa96dfaabde8 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -192,9 +192,8 @@ static SMLoc findDebugLineInformationForInstructionAt(
       "Cannot fit instruction debug line information into SMLoc's pointer");
 
   SMLoc NullResult = DebugLineTableRowRef::NULL_ROW.toSMLoc();
-  auto RowIndexValue = LineTable->lookupAddress(
-      {Address, object::SectionedAddress::UndefSection}, false);
-  uint32_t RowIndex = RowIndexValue.first;
+  uint32_t RowIndex = LineTable->lookupAddress(
+      {Address, object::SectionedAddress::UndefSection});
   if (RowIndex == LineTable->UnknownRowIndex)
     return NullResult;
 
diff --git a/lld/Common/DWARF.cpp b/lld/Common/DWARF.cpp
index fc1b6d22c1a10..2cd8ca4575dee 100644
--- a/lld/Common/DWARF.cpp
+++ b/lld/Common/DWARF.cpp
@@ -93,7 +93,7 @@ std::optional<DILineInfo> DWARFCache::getDILineInfo(uint64_t offset,
   DILineInfo info;
   for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) {
     if (lt->getFileLineInfoForAddress(
-            {offset, sectionIndex}, nullptr, false,
+            {offset, sectionIndex}, nullptr,
             DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info))
       return info;
   }
diff --git a/llvm/docs/CommandGuide/llvm-symbolizer.rst b/llvm/docs/CommandGuide/llvm-symbolizer.rst
index bdf206c31b855..664c8f5cb9b95 100644
--- a/llvm/docs/CommandGuide/llvm-symbolizer.rst
+++ b/llvm/docs/CommandGuide/llvm-symbolizer.rst
@@ -224,11 +224,11 @@ OPTIONS
   This can be used to perform lookups as if the object were relocated by the
   offset.
 
-.. option:: --approximate-line
+.. option:: --skip-line-zero
 
-  Print the approximate non-zero line number that is nearest to before an
-  input address. Nearest lookup is performed by querying the line-table
-  structure for an address having non-zero line information in close proximity.
+  If an address does not have an associated line number, use the last line
+  number from the current sequence in the line-table. Such lines are labeled
+  as "approximate" in the output as they may be misleading.
 
 .. option:: --basenames, -s
 
@@ -384,7 +384,6 @@ OPTIONS
         "ModuleName": "inlined.elf",
         "Symbol": [
           {
-            "Approximate": false,
             "Column": 18,
             "Discriminator": 0,
             "FileName": "/tmp/test.cpp",
@@ -395,7 +394,6 @@ OPTIONS
             "StartLine": 9
           },
           {
-            "Approximate": false,
             "Column": 0,
             "Discriminator": 0,
             "FileName": "/tmp/test.cpp",
@@ -412,7 +410,6 @@ OPTIONS
         "ModuleName": "inlined.elf",
         "Symbol": [
           {
-            "Approximate": false,
             "Column": 3,
             "Discriminator": 0,
             "FileName": "/tmp/test.cpp",
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
index b8b5f1d8688f8..ec1c312fb3970 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
@@ -240,8 +240,8 @@ class DWARFDebugLine {
 
     /// Returns the index of the row with file/line info for a given address,
     /// or UnknownRowIndex if there is no such row.
-    std::pair<uint32_t, bool> lookupAddress(object::SectionedAddress Address,
-                                            bool ApproximateLine) const;
+    uint32_t lookupAddress(object::SectionedAddress Address,
+                           bool &IsApproximateLine) const;
 
     bool lookupAddressRange(object::SectionedAddress Address, uint64_t Size,
                             std::vector<uint32_t> &Result) const;
@@ -268,7 +268,7 @@ class DWARFDebugLine {
     /// Fills the Result argument with the file and line information
     /// corresponding to Address. Returns true on success.
     bool getFileLineInfoForAddress(object::SectionedAddress Address,
-                                   const char *CompDir, bool ApproximateLine,
+                                   const char *CompDir,
                                    DILineInfoSpecifier::FileLineInfoKind Kind,
                                    DILineInfo &Result) const;
 
@@ -302,9 +302,8 @@ class DWARFDebugLine {
     getSourceByIndex(uint64_t FileIndex,
                      DILineInfoSpecifier::FileLineInfoKind Kind) const;
 
-    std::pair<uint32_t, bool>
-    lookupAddressImpl(object::SectionedAddress Address,
-                      bool ApproximateLine) const;
+    uint32_t lookupAddressImpl(object::SectionedAddress Address,
+                               bool &IsApproximateLine) const;
 
     bool lookupAddressRangeImpl(object::SectionedAddress Address, uint64_t Size,
                                 std::vector<uint32_t> &Result) const;
@@ -430,6 +429,9 @@ class DWARFDebugLine {
   using LineTableConstIter = LineTableMapTy::const_iterator;
 
   LineTableMapTy LineTableMap;
+
+public:
+  inline static bool ReportApproximateLine = false;
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 49fc4dd00c4fe..a672e4ab22c35 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -1736,6 +1736,7 @@ DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
   if (!CU)
     return Result;
 
+  DWARFDebugLine::ReportApproximateLine = Spec.ApproximateLine;
   getFunctionNameAndStartLineForAddress(
       CU, Address.Address, Spec.FNKind, Spec.FLIKind, Result.FunctionName,
       Result.StartFileName, Result.StartLine, Result.StartAddress);
@@ -1743,7 +1744,7 @@ DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
     if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) {
       LineTable->getFileLineInfoForAddress(
           {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
-          Spec.ApproximateLine, Spec.FLIKind, Result);
+          Spec.FLIKind, Result);
     }
   }
 
@@ -1830,6 +1831,7 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
 
   const DWARFLineTable *LineTable = nullptr;
   SmallVector<DWARFDie, 4> InlinedChain;
+  DWARFDebugLine::ReportApproximateLine = Spec.ApproximateLine;
   CU->getInlinedChainForAddress(Address.Address, InlinedChain);
   if (InlinedChain.size() == 0) {
     // If there is no DIE for address (e.g. it is in unavailable .dwo file),
@@ -1837,10 +1839,9 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
     if (Spec.FLIKind != FileLineInfoKind::None) {
       DILineInfo Frame;
       LineTable = getLineTableForUnit(CU);
-      if (LineTable &&
-          LineTable->getFileLineInfoForAddress(
-              {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
-              Spec.ApproximateLine, Spec.FLIKind, Frame))
+      if (LineTable && LineTable->getFileLineInfoForAddress(
+                           {Address.Address, Address.SectionIndex},
+                           CU->getCompilationDir(), Spec.FLIKind, Frame))
         InliningInfo.addFrame(Frame);
     }
     return InliningInfo;
@@ -1867,7 +1868,7 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
         if (LineTable)
           LineTable->getFileLineInfoForAddress(
               {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
-              Spec.ApproximateLine, Spec.FLIKind, Frame);
+              Spec.FLIKind, Frame);
       } else {
         // Otherwise, use call file, call line and call column from
         // previous DIE in inlined chain.
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 0db77795700fa..4802a8778987e 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -1312,26 +1312,25 @@ uint32_t DWARFDebugLine::LineTable::findRowInSeq(
   return RowPos - Rows.begin();
 }
 
-std::pair<uint32_t, bool>
+uint32_t
 DWARFDebugLine::LineTable::lookupAddress(object::SectionedAddress Address,
-                                         bool ApproximateLine) const {
+                                         bool &IsApproximateLine) const {
 
   // Search for relocatable addresses
-  std::pair<uint32_t, bool> Result =
-      lookupAddressImpl(Address, ApproximateLine);
+  uint32_t Result = lookupAddressImpl(Address, IsApproximateLine);
 
-  if (Result.first != UnknownRowIndex ||
+  if (Result != UnknownRowIndex ||
       Address.SectionIndex == object::SectionedAddress::UndefSection)
     return Result;
 
   // Search for absolute addresses
   Address.SectionIndex = object::SectionedAddress::UndefSection;
-  return lookupAddressImpl(Address, ApproximateLine);
+  return lookupAddressImpl(Address, IsApproximateLine);
 }
 
-std::pair<uint32_t, bool>
+uint32_t
 DWARFDebugLine::LineTable::lookupAddressImpl(object::SectionedAddress Address,
-                                             bool ApproximateLine) const {
+                                             bool &IsApproximateLine) const {
   // First, find an instruction sequence containing the given address.
   DWARFDebugLine::Sequence Sequence;
   Sequence.SectionIndex = Address.SectionIndex;
@@ -1339,25 +1338,18 @@ DWARFDebugLine::LineTable::lookupAddressImpl(object::SectionedAddress Address,
   SequenceIter It = llvm::upper_bound(Sequences, Sequence,
                                       DWARFDebugLine::Sequence::orderByHighPC);
   if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex)
-    return {UnknownRowIndex, false};
+    return UnknownRowIndex;
 
   uint32_t RowIndex = findRowInSeq(*It, Address);
-  bool IsApproximate = false;
-  if (ApproximateLine) {
-    uint32_t ApproxRowIndex = RowIndex;
-    while (ApproxRowIndex >= It->FirstRowIndex) {
-      if (ApproxRowIndex != UnknownRowIndex && Rows[ApproxRowIndex].Line)
-        break;
-      IsApproximate = true;
-      if (ApproxRowIndex != UnknownRowIndex &&
-          (Rows[ApproxRowIndex].BasicBlock | Rows[ApproxRowIndex].PrologueEnd))
-        break;
-      --ApproxRowIndex;
+  if (RowIndex != UnknownRowIndex && DWARFDebugLine::ReportApproximateLine) {
+    for (uint32_t ApproxRowIndex = RowIndex;
+         ApproxRowIndex >= It->FirstRowIndex; --ApproxRowIndex) {
+      if (Rows[ApproxRowIndex].Line)
+        return ApproxRowIndex;
+      IsApproximateLine = true;
     }
-    if (ApproxRowIndex >= It->FirstRowIndex)
-      RowIndex = ApproxRowIndex;
   }
-  return {RowIndex, IsApproximate};
+  return RowIndex;
 }
 
 bool DWARFDebugLine::LineTable::lookupAddressRange(
@@ -1497,11 +1489,11 @@ bool DWARFDebugLine::Prologue::getFileNameByIndex(
 }
 
 bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
-    object::SectionedAddress Address, const char *CompDir, bool ApproximateLine,
+    object::SectionedAddress Address, const char *CompDir,
     FileLineInfoKind Kind, DILineInfo &Result) const {
+  bool IsApproximateLine = false;
   // Get the index of row we're looking for in the line table.
-  auto RowIndexValue = lookupAddress(Address, ApproximateLine);
-  uint32_t RowIndex = RowIndexValue.first;
+  uint32_t RowIndex = lookupAddress(Address, IsApproximateLine);
   if (RowIndex == -1U)
     return false;
   // Take file number and line/column from the row.
@@ -1512,7 +1504,7 @@ bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
   Result.Column = Row.Column;
   Result.Discriminator = Row.Discriminator;
   Result.Source = getSourceByIndex(Row.File, Kind);
-  Result.IsApproximatedLine = RowIndexValue.second;
+  Result.IsApproximatedLine = IsApproximateLine;
   return true;
 }
 
diff --git a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
index bce29d1e18a7d..736bd29599523 100644
--- a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
@@ -299,7 +299,7 @@ static json::Object toJSON(const Request &Request, StringRef ErrorMsg = "") {
 }
 
 static json::Object toJSON(const DILineInfo &LineInfo) {
-  return json::Object(
+  json::Object obj = json::Object(
       {{"FunctionName", LineInfo.FunctionName != DILineInfo::BadString
                             ? LineInfo.FunctionName
                             : ""},
@@ -313,8 +313,10 @@ static json::Object toJSON(const DILineInfo &LineInfo) {
         LineInfo.FileName != DILineInfo::BadString ? LineInfo.FileName : ""},
        {"Line", LineInfo.Line},
        {"Column", LineInfo.Column},
-       {"Discriminator", LineInfo.Discriminator},
-       {"Approximate", LineInfo.IsApproximatedLine}});
+       {"Discriminator", LineInfo.Discriminator}});
+  if (LineInfo.IsApproximatedLine)
+    obj.insert({"Approximate", LineInfo.IsApproximatedLine});
+  return obj;
 }
 
 void JSONPrinter::print(const Request &Request, const DILineInfo &Info) {
diff --git a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
index 54414cab816ec..dacc04b6e9740 100644
--- a/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
+++ b/llvm/test/tools/llvm-symbolizer/approximate-line-info.s
@@ -2,10 +2,10 @@
 
 # RUN: llvm-mc -g -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
 # RUN: llvm-symbolizer --obj=%t.o 0xa | FileCheck --strict-whitespace --match-full-lines --check-prefix=APPROX-DISABLE %s
-# RUN: llvm-symbolizer --obj=%t.o --approximate-line 0xa | FileCheck --strict-whitespace --match-full-lines --check-prefix=APPROX-ENABLE %s
-# RUN: llvm-symbolizer --obj=%t.o --approximate-line 0xa 0x10 | FileCheck --strict-whitespace --match-full-lines --check-prefixes=APPROX-ENABLE,NO-APPROX %s
-# RUN: llvm-symbolizer --obj=%t.o --approximate-line --verbose 0xa | FileCheck --strict-whitespace --match-full-lines --check-prefix=APPROX-VERBOSE %s
-# RUN: llvm-symbolizer --obj=%t.o --approximate-line --output-style=JSON 0xa | FileCheck --strict-whitespace --match-full-lines --check-prefix=APPROX-JSON %s
+# RUN: llvm-symbolizer --obj=%t.o --skip-line-zero 0xa | FileCheck --strict-whitespace --match-full-lines --check-prefix=APPROX-ENABLE %s
+# RUN: llvm-symbolizer --obj=%t.o --skip-line-zero 0xa 0x10 | FileCheck --strict-whitespace --match-full-lines --check-prefixes=APPROX-ENABLE,NO-APPROX %s
+# RUN: llvm-symbolizer --obj=%t.o --skip-line-zero --verbose 0xa | FileCheck --strict-whitespace --match-full-lines --check-prefix=APPROX-VERBOSE %s
+# RUN: llvm-symbolizer --obj=%t.o --skip-line-zero --output-style=JSON 0xa | FileCheck --strict-whitespace --match-full-lines --check-prefix=APPROX-JSON %s
 
 # APPROX-DISABLE:main
 # APPROX-DISABLE-NEXT:{{[/|\]+}}tmp{{[/|\]+}}test{{[/|\]+}}main.c:0:6
diff --git a/llvm/test/tools/llvm-symbolizer/output-style-json-code.test b/llvm/test/tools/llvm-symbolizer/output-style-json-code.test
index d6410eeae2201..0e0e61c0bf119 100644
--- a/llvm/test/tools/llvm-symbolizer/output-style-json-code.test
+++ b/llvm/test/tools/llvm-symbolizer/output-style-json-code.test
@@ -12,12 +12,12 @@
 ## Expected a list with one empty object with default values.
 # RUN: llvm-symbolizer --output-style=JSON -e %p/Inputs/addr.exe 0x10000000 | \
 # RUN:   FileCheck %s --check-prefix=NOT-FOUND --strict-whitespace --match-full-lines --implicit-check-not={{.}}
-# NOT-FOUND:[{"Address":"0x10000000","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}]
+# NOT-FOUND:[{"Address":"0x10000000","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}]
 
 ## Check a non-zero discriminator.
 # RUN: llvm-symbolizer --output-style=JSON --obj=%p/Inputs/discrim 0x400575 | \
 # RUN:   FileCheck %s --check-prefix=DISCRIM --strict-whitespace --match-full-lines --implicit-check-not={{.}}
-# DISCRIM:[{"Address":"0x400575","ModuleName":"{{.*}}/Inputs/discrim","Symbol":[{"Approximate":false,"Column":17,"Discriminator":2,"FileName":"/tmp{{/|\\\\}}discrim.c","FunctionName":"foo","Line":5,"StartAddress":"0x400560","StartFileName":"/tmp{{/|\\\\}}discrim.c","StartLine":4}]}]
+# DISCRIM:[{"Address":"0x400575","ModuleName":"{{.*}}/Inputs/discrim","Symbol":[{"Column":17,"Discriminator":2,"FileName":"/tmp{{/|\\\\}}discrim.c","FunctionName":"foo","Line":5,"StartAddress":"0x400560","StartFileName":"/tmp{{/|\\\\}}discrim.c","StartLine":4}]}]
 
 ## In case of stdin input the output will contain a single JSON object for each input string.
 
@@ -27,7 +27,7 @@
 ## Invalid first argument before any valid one.
 # NO-INLINES:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"something"}
 ## Resolve valid address.
-# NO-INLINES-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Approximate":false,"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2}]}
+# NO-INLINES-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2}]}
 ## Invalid argument after a valid one.
 # NO-INLINES-NEXT:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"some"}
 
@@ -37,7 +37,7 @@
 ## Invalid first argument before any valid one.
 # INLINE:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"something"}
 ## Resolve valid address.
-# INLINE-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Approximate":false,"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inctwo","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inc","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
+# INLINE-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inctwo","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inc","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
 ## Invalid argument after a valid one.
 # INLINE-NEXT:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"some"}
 
@@ -48,7 +48,7 @@
 ## Invalid first argument before any valid one.
 # INLINE-A2L:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"something"}
 ## Resolve valid address.
-# INLINE-A2L-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Approximate":false,"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inctwo","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inc","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
+# INLINE-A2L-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inctwo","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inc","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
 ## Invalid argument after a valid one.
 # INLINE-A2L:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"some"}
 
@@ -58,11 +58,11 @@
 ## Invalid first argument before any valid one.
 # NO-FUNC-A2L:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"something"}
 ## Resolve valid address.
-# NO-FUNC-A2L-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Approximate":false,"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Approximate":false,"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
+# NO-FUNC-A2L-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
 ## Invalid argument after a valid one.
 # NO-FUNC-A2L-NEXT:{"Loc":[],"ModuleName":"{{.*}}/Inputs/addr.exe","SymName":"some"}
 
 ## When a module offset is specified by a symbol, more than one source location can be found.
 # RUN: llvm-symbolizer --output-style=JSON --no-inlines -e %p/Inputs/symbols.so "static_func" | \
 # RUN:   FileCheck %s --check-prefix=MULTIPLE --strict-whitespace --match-full-lines --implicit-check-not={{.}}
-# MULTIPLE:[{"Loc":[{"Approximate":false,"Column":24,"Discriminator":0,"FileName":"/tmp/dbginfo{{/|\\\\}}symbols.part3.c","FunctionName":"static_func","Line":4,"StartAddress":"0x121d","StartFileName":"/tmp/dbginfo{{/|\\\\}}symbols.part3.c","StartLine":4},{"Approximate":false,"Column":24,"Discriminator":0,"FileName":"/tmp/dbginfo{{/|\\\\}}symbols.part4.c","FunctionName":"static_func","Line":4,"StartAddress":"0x125f","StartFileName":"/tmp/dbginfo{{/|\\\\}}symbols.part4.c","StartLine":4}],"ModuleName":"{{.*}}Inputs/symbols.so","SymName":"static_func"}]
+# MULTIPLE:[{"Loc":[{"Column":24,"Discriminator":0,"FileName":"/tmp/dbginfo{{/|\\\\}}symbols.part3.c","FunctionName":"static_func","Line":4,"StartAddress":"0x121d","StartFileName":"/tmp/dbginfo{{/|\\\\}}symbols.part3.c","StartLine":4},{"Column":24,"Discriminator":0,"FileName":"/tmp/dbginfo{{/|\\\\}}symbols.part4.c","FunctionName":"static_func","Line":4,"StartAddress":"0x125f","StartFileName":"/tmp/dbginfo{{/|\\\\}}symbols.part4.c","StartLine":4}],"ModuleName":"{{.*}}Inputs/symbols.so","SymName":"static_func"}]
diff --git a/llvm/test/tools/llvm-symbolizer/source.ll b/llvm/test/tools/llvm-symbolizer/source.ll
index 7f7072ee90b51..8a12c85812689 100644
--- a/llvm/test/tools/llvm-symbolizer/source.ll
+++ b/llvm/test/tools/llvm-symbolizer/source.ll
@@ -22,7 +22,7 @@
 ;; Check JSON style output.
 ; RUN: llvm-symbolizer --print-source-context-lines=3 --obj=%t.o 0 --output-style=JSON | \
 ; RUN:   FileCheck %s --check-prefix=JSON --strict-whitespace --match-full-lines --implicit-check-not={{.}}
-; JSON:[{"Address":"0x0","ModuleName":"{{.*}}.o","Symbol":[{"Approximate":false,"Column":13,"Discriminator":0,"FileName":"/source.c","FunctionName":"foo","Line":3,"Source":"2  : // Line 2\n3 >: void foo() {}\n4  : // Line 4\n","StartAddress":"0x0","StartFileName":"/source.c","StartLine":3}]}]
+; JSON:[{"Address":"0x0","ModuleName":"{{.*}}.o","Symbol":[{"Column":13,"Discriminator":0,"FileName":"/source.c","FunctionName":"foo","Line":3,"Source":"2  : // Line 2\n3 >: void foo() {}\n4  : // Line 4\n","StartAddress":"0x0","StartFileName":"/source.c","StartLine":3}]}]
 
 ;; Generated from the following source:
 ;; // Line 1
diff --git a/llvm/tools/llvm-symbolizer/Opts.td b/llvm/tools/llvm-symbolizer/Opts.td
index 097ea17b90e9e..16025e2c0e2c8 100644
--- a/llvm/tools/llvm-symbolizer/Opts.td
+++ b/llvm/tools/llvm-symbolizer/Opts.td
@@ -17,7 +17,6 @@ def grp_mach_o : OptionGroup<"kind">,
                  HelpText<"llvm-symbolizer Mach-O Specific Options">;
 
 def addresses : F<"addresses", "Show address before line information">;
-def approximate_line : F<"approximate-line","Show approximate non-zero line number information nearest to before the given address.">;
 defm adjust_vma
     : Eq<"adjust-vma", "Add specified offset to object file addresses">,
       MetaVarName<"<offset>">;
@@ -56,6 +55,7 @@ def pretty_print : F<"pretty-print", "Make the output more human friendly">;
 defm print_source_context_lines : Eq<"print-source-context-lines", "Print N lines of source file context">;
 def relative_address : F<"relative-address", "Interpret addresses as addresses relative to the image base">;
 def relativenames : F<"relativenames", "Strip the compilation directory from paths">;
+def skip_line_zero : F<"skip-line-zero","Show approximate non-zero line number information nearest to before the given address.">;
 defm untag_addresses : B<"untag-addresses", "", "Remove memory tags from addresses before symbolization">;
 def use_dia: F<"dia", "Use the DIA library to access symbols (Windows only)">;
 def verbose : F<"verbose", "Print verbose line info">;
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 591bf70ea2e49..23abda6842671 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -482,7 +482,7 @@ int llvm_symbolizer_main(int argc, char **argv, const llvm::ToolContext &) {
   } else {
     Opts.PathStyle = DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath;
   }
-  Opts.ApproximateLine = Args.hasArg(OPT_approximate_line);
+  Opts.ApproximateLine = Args.hasArg(OPT_skip_line_zero);
   Opts.DebugFileDirectory = Args.getAllArgValues(OPT_debug_file_directory_EQ);
   Opts.DefaultArch = Args.getLastArgValue(OPT_default_arch_EQ).str();
   Opts.Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, !IsAddr2Line);



More information about the llvm-commits mailing list