[llvm] [llvm-symbolizer] Make symbolizer parse section relative syntax (PR #168524)

via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 25 02:18:17 PDT 2026


https://github.com/midhuncodes7 updated https://github.com/llvm/llvm-project/pull/168524

>From 6280d2382724b449c1a3fd63d19c4e934caa4d34 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Thu, 13 Nov 2025 12:04:34 +0530
Subject: [PATCH 01/30] section relative syntax implementation

---
 .../llvm-symbolizer/xcoff-section-relative.ll |  51 ++++++
 .../llvm-symbolizer/xcoff-section-syntax.test |  31 ++++
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 158 +++++++++++++++++-
 3 files changed, 232 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
 create mode 100644 llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test

diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
new file mode 100644
index 0000000000000..cfc6b31812a98
--- /dev/null
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
@@ -0,0 +1,51 @@
+;; Test section-relative address syntax for XCOFF
+;; The syntax (SECTION_TYPE)(+offset) represents: offset from section base
+
+; REQUIRES: system-aix
+; RUN: llc -filetype=obj -o %t -mtriple=powerpc-aix-ibm-xcoff -function-sections < %s
+
+;; Test 1: Symbolize .foo using section-relative offset
+; RUN: llvm-nm --numeric-sort %t | grep " T \.foo$" | awk '{printf "CODE (TEXT)(+0x%%s)", $1}' > %t.foo_query
+; RUN: llvm-symbolizer --obj=%t @%t.foo_query | FileCheck %s --check-prefix=TEST-FOO
+
+;; Test 2: Symbolize .bar using section-relative offset
+; RUN: llvm-nm --numeric-sort %t | grep " T \.bar$" | awk '{printf "CODE (TEXT)(+0x%%s)", $1}' > %t.bar_query
+; RUN: llvm-symbolizer --obj=%t @%t.bar_query | FileCheck %s --check-prefix=TEST-BAR
+
+;; Test 3: Symbolize global_var using section-relative offset in DATA section
+; RUN: llvm-readobj --sections %t | awk '/Name: \.data/{found=1} found && /VirtualAddress:/{print $2; exit}' > %t.data_base
+; RUN: llvm-nm --numeric-sort %t | grep " D global_var$" | awk '{print $1}' > %t.global_var_vma
+; RUN: sh -c 'printf "%%d\n" $(cat %t.data_base)' > %t.data_base_dec
+; RUN: sh -c 'printf "%%d\n" 0x$(cat %t.global_var_vma)' > %t.global_var_dec
+; RUN: awk 'NR==FNR{base=$1; next} {vma=$1; printf "DATA (DATA)(+0x%%x)", vma-base}' %t.data_base_dec %t.global_var_dec > %t.data_query
+; RUN: llvm-symbolizer --obj=%t @%t.data_query | FileCheck %s --check-prefix=TEST-DATA
+
+;; Test 4: Verify section structure with llvm-readobj
+; RUN: llvm-readobj --sections %t | FileCheck %s --check-prefix=SECTIONS
+
+define void @foo() {
+entry:
+  ret void
+}
+
+define void @bar() {
+entry:
+  ret void
+}
+
+ at global_var = global i32 42, align 4
+
+;; Verify correct symbolization with section-relative syntax
+; TEST-FOO: .foo
+; TEST-FOO-NEXT: ??:0:0
+
+; TEST-BAR: .bar
+; TEST-BAR-NEXT: ??:0:0
+
+; TEST-DATA: global_var
+
+;; Verify XCOFF sections exist with correct types
+; SECTIONS: Name: .text
+; SECTIONS: Type: STYP_TEXT
+; SECTIONS: Name: .data
+; SECTIONS: Type: STYP_DATA
\ No newline at end of file
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
new file mode 100644
index 0000000000000..01bda672387f4
--- /dev/null
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -0,0 +1,31 @@
+## Test section-relative address syntax parsing for XCOFF
+## This tests that the (SECTION_TYPE)(+offset) syntax produces appropriate
+## error messages for invalid syntax
+
+# REQUIRES: system-aix
+
+## Create a simple XCOFF object for testing
+# RUN: echo "define void @test() { ret void }" | \
+# RUN:   llc -filetype=obj -mtriple=powerpc-aix-ibm-xcoff -o %t.o
+
+## Test invalid section type
+# RUN: llvm-symbolizer --obj=%t.o '(INVALID)(+0x10)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=INVALID-TYPE
+
+## Test missing '+' sign
+# RUN: llvm-symbolizer --obj=%t.o '(TEXT)(0x10)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=NO-PLUS
+
+## Test invalid offset value (not a hex number)
+# RUN: llvm-symbolizer --obj=%t.o '(TEXT)(+abc)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=INVALID-OFFSET
+
+## Test empty section type
+# RUN: llvm-symbolizer --obj=%t.o '()(+0x10)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=EMPTY-SECTION
+
+## Verify error messages are helpful
+# INVALID-TYPE: unknown section type
+# NO-PLUS: section-relative offset must start with '+'
+# INVALID-OFFSET: invalid offset in section-relative address
+# EMPTY-SECTION: unknown section type
\ No newline at end of file
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 4784dafeb2948..d239d1aad73d7 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -17,12 +17,15 @@
 #include "Opts.inc"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/Config/config.h"
 #include "llvm/DebugInfo/Symbolize/DIPrinter.h"
 #include "llvm/DebugInfo/Symbolize/Markup.h"
 #include "llvm/DebugInfo/Symbolize/MarkupFilter.h"
 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
+#include "llvm/Object/XCOFFObjectFile.h"
 #include "llvm/Debuginfod/BuildIDFetcher.h"
 #include "llvm/Debuginfod/Debuginfod.h"
 #include "llvm/Debuginfod/HTTPClient.h"
@@ -157,11 +160,97 @@ static Error makeStringError(StringRef Msg) {
   return make_error<StringError>(Msg, inconvertibleErrorCode());
 }
 
+// Helper function to get XCOFF section type flag from string
+ static std::optional<XCOFF::SectionTypeFlags> parseXCOFFSectionType(StringRef TypeStr) {
+   return StringSwitch<std::optional<XCOFF::SectionTypeFlags>>(TypeStr)
+       .Case("PAD", XCOFF::STYP_PAD)
+       .Case("DWARF", XCOFF::STYP_DWARF)
+       .Case("TEXT", XCOFF::STYP_TEXT)
+       .Case("DATA", XCOFF::STYP_DATA)
+       .Case("BSS", XCOFF::STYP_BSS)
+       .Case("EXCEPT", XCOFF::STYP_EXCEPT)
+       .Case("INFO", XCOFF::STYP_INFO)
+       .Case("TDATA", XCOFF::STYP_TDATA)
+       .Case("TBSS", XCOFF::STYP_TBSS)
+       .Case("LOADER", XCOFF::STYP_LOADER)
+       .Case("DEBUG", XCOFF::STYP_DEBUG)
+       .Case("TYPCHK", XCOFF::STYP_TYPCHK)
+       .Case("OVRFLO", XCOFF::STYP_OVRFLO)
+       .Default(std::nullopt);
+ }
+
+ // Find the base VMA of the first section matching the given type for XCOFF.
+ // The syntax (SECTION_TYPE)(+offset) represents an offset from the section base,
+ // so we return the section's base address to compute: VMA = base + offset.
+ static Expected<uint64_t> getXCOFFSectionBaseAddress(
+     const object::XCOFFObjectFile *XCOFFObj,
+     XCOFF::SectionTypeFlags TypeFlag) {
+
+   for (const auto &Section : XCOFFObj->sections()) {
+     DataRefImpl SecRef = Section.getRawDataRefImpl();
+     int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
+
+     if ((Flags & 0xFFFF) == TypeFlag) {
+       return Section.getAddress();
+     }
+   }
+
+   return createStringError(inconvertibleErrorCode(),
+                            "section type not found in XCOFF object");
+ }
+
+ static Expected<uint64_t> validateSectionType(StringRef ModulePath,
+                                                 StringRef SectionType,
+                                                 uint64_t &Offset,
+                                                 LLVMSymbolizer &Symbolizer) {
+   // Parse the section type string
+   auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
+   if (!SectionTypeFlag) {
+     return createStringError(inconvertibleErrorCode(),
+                             "unknown section type: " + SectionType.str());
+   }
+
+   // Get the module info to access the object file
+   auto ModuleOrErr = Symbolizer.getOrCreateModuleInfo(ModulePath);
+   if (!ModuleOrErr) {
+     return ModuleOrErr.takeError();
+   }
+
+   auto BinaryOrErr = object::createBinary(ModulePath);
+   if (!BinaryOrErr) {
+     return BinaryOrErr.takeError();
+   }
+
+   object::Binary *Binary = BinaryOrErr->getBinary();
+   if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Binary)) {
+     // Get the base VMA of the section matching the type
+     auto SectionBaseOrErr = getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
+     if (!SectionBaseOrErr)
+       return SectionBaseOrErr.takeError();
+
+     uint64_t SectionBase = *SectionBaseOrErr;
+     uint64_t SectionRelativeOffset = Offset;
+
+     // Convert section-relative offset to absolute VMA
+     // VMA = section_base + offset
+     Offset = SectionBase + SectionRelativeOffset;
+
+     // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
+     // so we use absolute VMA addressing instead.
+     return object::SectionedAddress::UndefSection;
+   }
+
+   return createStringError(inconvertibleErrorCode(),
+                           "section type syntax is only supported for XCOFF objects");
+ }
+
 static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
                           StringRef InputString, Command &Cmd,
                           std::string &ModuleName, object::BuildID &BuildID,
-                          StringRef &Symbol, uint64_t &Offset) {
+                          StringRef &Symbol, uint64_t &Offset,
+                          StringRef &SectionType) {
   ModuleName = BinaryName;
+  SectionType = StringRef();
   if (InputString.consume_front("CODE ")) {
     Cmd = Command::Code;
   } else if (InputString.consume_front("DATA ")) {
@@ -245,10 +334,43 @@ static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
         AddrSpec.consume_front_insensitive("+0x");
   }
 
+  // Check for section-relative address syntax: (SECTION_TYPE)(+0x0)
+   if (AddrSpec.starts_with("(")) {
+     size_t FirstClose = AddrSpec.find(')');
+     if (FirstClose != StringRef::npos && FirstClose + 1 < AddrSpec.size() &&
+         AddrSpec[FirstClose + 1] == '(') {
+       size_t SecondOpen = FirstClose + 1;
+       size_t SecondClose = AddrSpec.find(')', SecondOpen);
+       if (SecondClose != StringRef::npos) {
+         // Extract section type from first parentheses
+         SectionType = AddrSpec.substr(1, FirstClose - 1);
+
+         // Validate that section type is not empty
+         if (SectionType.empty())
+           return makeStringError("unknown section type: empty section type");
+
+         // Extract offset from second parentheses
+         StringRef OffsetPart = AddrSpec.substr(SecondOpen + 1, SecondClose - SecondOpen - 1);
+
+         // The offset should start with '+'
+         if (!OffsetPart.consume_front("+"))
+           return makeStringError("section-relative offset must start with '+'");
+
+         // Parse the offset - auto-detect base (0x prefix = hex, otherwise decimal)
+         if (OffsetPart.getAsInteger(0, Offset))
+           return makeStringError("invalid offset in section-relative address");
+
+         Symbol = StringRef();
+         return Error::success();
+       }
+     }
+   }
+
   // If address specification is a number, treat it as a module offset.
   if (!AddrSpec.getAsInteger(IsAddr2Line ? 16 : 0, Offset)) {
     // Module offset is an address.
     Symbol = StringRef();
+    SectionType = StringRef();
     return Error::success();
   }
 
@@ -260,6 +382,7 @@ static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
   // Otherwise it is a symbol name, potentially with an offset.
   Symbol = AddrSpec;
   Offset = 0;
+  SectionType = StringRef();
 
   // If the address specification contains '+', try treating it as
   // "symbol + offset".
@@ -282,10 +405,11 @@ template <typename T>
 void executeCommand(StringRef ModuleName, const T &ModuleSpec, Command Cmd,
                     StringRef Symbol, uint64_t Offset, uint64_t AdjustVMA,
                     bool ShouldInline, OutputStyle Style,
-                    LLVMSymbolizer &Symbolizer, DIPrinter &Printer) {
-  uint64_t AdjustedOffset = Offset - AdjustVMA;
-  object::SectionedAddress Address = {AdjustedOffset,
-                                      object::SectionedAddress::UndefSection};
+                    LLVMSymbolizer &Symbolizer, DIPrinter &Printer,
+                    uint64_t SectionIndex) {
+   uint64_t AdjustedOffset = Offset - AdjustVMA;
+   object::SectionedAddress Address = {AdjustedOffset, SectionIndex};
+
   Request SymRequest = {
       ModuleName, Symbol.empty() ? std::make_optional(Offset) : std::nullopt,
       Symbol};
@@ -342,6 +466,7 @@ static void symbolizeInput(const opt::InputArgList &Args,
   object::BuildID BuildID(IncomingBuildID.begin(), IncomingBuildID.end());
   uint64_t Offset = 0;
   StringRef Symbol;
+  StringRef SectionType;
 
   // An empty input string may be used to check if the process is alive and
   // responding to input. Do not emit a message on stderr in this case but
@@ -352,24 +477,41 @@ static void symbolizeInput(const opt::InputArgList &Args,
   }
   if (Error E = parseCommand(Args.getLastArgValue(OPT_obj_EQ), IsAddr2Line,
                              StringRef(InputString), Cmd, ModuleName, BuildID,
-                             Symbol, Offset)) {
+                             Symbol, Offset, SectionType)) {
     handleAllErrors(std::move(E), [&](const StringError &EI) {
       printError(EI, InputString);
       printUnknownLineInfo(ModuleName, Printer);
     });
     return;
   }
+
+  // Validate section index from section type if specified
+  uint64_t SectionIndex = object::SectionedAddress::UndefSection;
+  if (!SectionType.empty() && !ModuleName.empty()) {
+    auto SectionIndexOrErr = validateSectionType(ModuleName, SectionType, Offset, Symbolizer);
+    if (!SectionIndexOrErr) {
+      handleAllErrors(SectionIndexOrErr.takeError(), [&](const ErrorInfoBase &EI) {
+        printError(EI, InputString);
+      });
+      printUnknownLineInfo(ModuleName, Printer);
+      return;
+    }
+    SectionIndex = *SectionIndexOrErr;
+  }
+
   bool ShouldInline = Args.hasFlag(OPT_inlines, OPT_no_inlines, !IsAddr2Line);
   if (!BuildID.empty()) {
     assert(ModuleName.empty());
     if (!Args.hasArg(OPT_no_debuginfod))
       enableDebuginfod(Symbolizer, Args);
     std::string BuildIDStr = toHex(BuildID);
+    // Note: Section type resolution is not supported for BuildID-based lookup
     executeCommand(BuildIDStr, BuildID, Cmd, Symbol, Offset, AdjustVMA,
-                   ShouldInline, Style, Symbolizer, Printer);
+                   ShouldInline, Style, Symbolizer, Printer,
+                    object::SectionedAddress::UndefSection);
   } else {
     executeCommand(ModuleName, ModuleName, Cmd, Symbol, Offset, AdjustVMA,
-                   ShouldInline, Style, Symbolizer, Printer);
+ShouldInline, Style, Symbolizer, Printer, SectionIndex);
   }
 }
 

>From 07ab95bdabbf2c69f0fe18d7acb7103e262c19d5 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Sun, 9 Nov 2025 12:33:22 -0500
Subject: [PATCH 02/30] symbolizer to accept section relative syntax

---
 llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll | 2 +-
 llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test | 2 +-
 llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp            | 1 +
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
index cfc6b31812a98..d1e21fe135e9e 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
@@ -48,4 +48,4 @@ entry:
 ; SECTIONS: Name: .text
 ; SECTIONS: Type: STYP_TEXT
 ; SECTIONS: Name: .data
-; SECTIONS: Type: STYP_DATA
\ No newline at end of file
+; SECTIONS: Type: STYP_DATA
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index 01bda672387f4..ca5ef9d3cb2cc 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -28,4 +28,4 @@
 # INVALID-TYPE: unknown section type
 # NO-PLUS: section-relative offset must start with '+'
 # INVALID-OFFSET: invalid offset in section-relative address
-# EMPTY-SECTION: unknown section type
\ No newline at end of file
+# EMPTY-SECTION: unknown section type
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index d239d1aad73d7..3bdbce55c4f68 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -29,6 +29,7 @@
 #include "llvm/Debuginfod/BuildIDFetcher.h"
 #include "llvm/Debuginfod/Debuginfod.h"
 #include "llvm/Debuginfod/HTTPClient.h"
+#include "llvm/Object/XCOFFObjectFile.h"
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/Option.h"

>From a0b4db7d32a4a3ca40141e555ee6a2c428c47593 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Tue, 18 Nov 2025 07:24:11 -0500
Subject: [PATCH 03/30] code format fix

---
 llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 3bdbce55c4f68..1ad5d43409b4a 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -1,4 +1,5 @@
-//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===//
+//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer
+//------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

>From c6d3711b619d5e11eabbec834d83484b21efae4e Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Wed, 21 Jan 2026 10:59:18 +0530
Subject: [PATCH 04/30] Review comments addressed

---
 .../llvm-symbolizer/xcoff-section-syntax.test |  4 +-
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 78 ++++++++++---------
 2 files changed, 44 insertions(+), 38 deletions(-)

diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index ca5ef9d3cb2cc..2465d1ec738fc 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -25,7 +25,7 @@
 # RUN:   FileCheck %s --check-prefix=EMPTY-SECTION
 
 ## Verify error messages are helpful
-# INVALID-TYPE: unknown section type
+# INVALID-TYPE: unknown or unsupported section type
 # NO-PLUS: section-relative offset must start with '+'
 # INVALID-OFFSET: invalid offset in section-relative address
-# EMPTY-SECTION: unknown section type
+# EMPTY-SECTION: unknown section type: empty section type
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 1ad5d43409b4a..4400a8ead2abb 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -162,44 +162,49 @@ static Error makeStringError(StringRef Msg) {
   return make_error<StringError>(Msg, inconvertibleErrorCode());
 }
 
-// Helper function to get XCOFF section type flag from string
- static std::optional<XCOFF::SectionTypeFlags> parseXCOFFSectionType(StringRef TypeStr) {
-   return StringSwitch<std::optional<XCOFF::SectionTypeFlags>>(TypeStr)
-       .Case("PAD", XCOFF::STYP_PAD)
-       .Case("DWARF", XCOFF::STYP_DWARF)
-       .Case("TEXT", XCOFF::STYP_TEXT)
-       .Case("DATA", XCOFF::STYP_DATA)
-       .Case("BSS", XCOFF::STYP_BSS)
-       .Case("EXCEPT", XCOFF::STYP_EXCEPT)
-       .Case("INFO", XCOFF::STYP_INFO)
-       .Case("TDATA", XCOFF::STYP_TDATA)
-       .Case("TBSS", XCOFF::STYP_TBSS)
-       .Case("LOADER", XCOFF::STYP_LOADER)
-       .Case("DEBUG", XCOFF::STYP_DEBUG)
-       .Case("TYPCHK", XCOFF::STYP_TYPCHK)
-       .Case("OVRFLO", XCOFF::STYP_OVRFLO)
-       .Default(std::nullopt);
- }
-
- // Find the base VMA of the first section matching the given type for XCOFF.
- // The syntax (SECTION_TYPE)(+offset) represents an offset from the section base,
- // so we return the section's base address to compute: VMA = base + offset.
- static Expected<uint64_t> getXCOFFSectionBaseAddress(
-     const object::XCOFFObjectFile *XCOFFObj,
-     XCOFF::SectionTypeFlags TypeFlag) {
+// Helper function to get XCOFF section type flag from string.
+// Only TEXT and DATA are supported since:
+// - These are the only sections mapped by the AIX process map (procmap).
+// - BSS addresses are relative to DATA section base.
+// - Thread-local sections (TDATA, TBSS) cannot be symbolized from runtime
+//   addresses.
+static std::optional<XCOFF::SectionTypeFlags>
+parseXCOFFSectionType(StringRef TypeStr) {
+  return StringSwitch<std::optional<XCOFF::SectionTypeFlags>>(TypeStr)
+      .Case("TEXT", XCOFF::STYP_TEXT)
+      .Case("DATA", XCOFF::STYP_DATA)
+      .Default(std::nullopt);
+}
 
-   for (const auto &Section : XCOFFObj->sections()) {
-     DataRefImpl SecRef = Section.getRawDataRefImpl();
-     int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
+// Find the base VMA of the unique section matching the given type for XCOFF.
+// The syntax (SECTION_TYPE)(+offset) represents an offset from the section base,
+// so we return the section's base address to compute: VMA = base + offset.
+// This function verifies there is exactly one section of the given type, as
+// multiple sections of the same type would make the address ambiguous.
+static Expected<uint64_t>
+getXCOFFSectionBaseAddress(const object::XCOFFObjectFile *XCOFFObj,
+                           XCOFF::SectionTypeFlags TypeFlag) {
+  std::optional<uint64_t> SectionBase;
+
+  for (const auto &Section : XCOFFObj->sections()) {
+    DataRefImpl SecRef = Section.getRawDataRefImpl();
+    int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
+
+    if ((Flags & 0xFFFF) == TypeFlag) {
+      if (SectionBase)
+        return createStringError(
+            inconvertibleErrorCode(),
+            "multiple sections of the same type found in XCOFF object");
+      SectionBase = Section.getAddress();
+    }
+  }
 
-     if ((Flags & 0xFFFF) == TypeFlag) {
-       return Section.getAddress();
-     }
-   }
+  if (!SectionBase)
+    return createStringError(inconvertibleErrorCode(),
+                             "section type not found in XCOFF object");
 
-   return createStringError(inconvertibleErrorCode(),
-                            "section type not found in XCOFF object");
- }
+  return *SectionBase;
+}
 
  static Expected<uint64_t> validateSectionType(StringRef ModulePath,
                                                  StringRef SectionType,
@@ -209,7 +214,8 @@ static Error makeStringError(StringRef Msg) {
    auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
    if (!SectionTypeFlag) {
      return createStringError(inconvertibleErrorCode(),
-                             "unknown section type: " + SectionType.str());
+                              "unknown or unsupported section type: " +
+                                  SectionType.str());
    }
 
    // Get the module info to access the object file

>From a6ff5f39a9b525f11fbcc328aac4014fa85b7db9 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Wed, 21 Jan 2026 02:22:19 -0500
Subject: [PATCH 05/30] Fix formatting

---
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 94 +++++++++----------
 1 file changed, 47 insertions(+), 47 deletions(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 13e298e86d78e..4b639626be255 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -205,53 +205,53 @@ getXCOFFSectionBaseAddress(const object::XCOFFObjectFile *XCOFFObj,
   return *SectionBase;
 }
 
- static Expected<uint64_t> validateSectionType(StringRef ModulePath,
-                                                 StringRef SectionType,
-                                                 uint64_t &Offset,
-                                                 LLVMSymbolizer &Symbolizer) {
-   // Parse the section type string
-   auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
-   if (!SectionTypeFlag) {
-     return createStringError(inconvertibleErrorCode(),
-                              "unknown or unsupported section type: " +
-                                  SectionType.str());
-   }
-
-   // Get the module info to access the object file
-   auto ModuleOrErr = Symbolizer.getOrCreateModuleInfo(ModulePath);
-   if (!ModuleOrErr) {
-     return ModuleOrErr.takeError();
-   }
-
-   auto BinaryOrErr = object::createBinary(ModulePath);
-   if (!BinaryOrErr) {
-     return BinaryOrErr.takeError();
-   }
-
-   object::Binary *Binary = BinaryOrErr->getBinary();
-   if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Binary)) {
-     // Get the base VMA of the section matching the type
-     auto SectionBaseOrErr =
-         getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
-     if (!SectionBaseOrErr)
-       return SectionBaseOrErr.takeError();
-
-     uint64_t SectionBase = *SectionBaseOrErr;
-     uint64_t SectionRelativeOffset = Offset;
-
-     // Convert section-relative offset to absolute VMA
-     // VMA = section_base + offset
-     Offset = SectionBase + SectionRelativeOffset;
-
-     // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
-     // so we use absolute VMA addressing instead.
-     return object::SectionedAddress::UndefSection;
-   }
-
-   return createStringError(
-       inconvertibleErrorCode(),
-       "section type syntax is only supported for XCOFF objects");
- }
+static Expected<uint64_t> validateSectionType(StringRef ModulePath,
+                                              StringRef SectionType,
+                                              uint64_t &Offset,
+                                              LLVMSymbolizer &Symbolizer) {
+  // Parse the section type string
+  auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
+  if (!SectionTypeFlag) {
+    return createStringError(inconvertibleErrorCode(),
+                             "unknown or unsupported section type: " +
+                                 SectionType.str());
+  }
+
+  // Get the module info to access the object file
+  auto ModuleOrErr = Symbolizer.getOrCreateModuleInfo(ModulePath);
+  if (!ModuleOrErr) {
+    return ModuleOrErr.takeError();
+  }
+
+  auto BinaryOrErr = object::createBinary(ModulePath);
+  if (!BinaryOrErr) {
+    return BinaryOrErr.takeError();
+  }
+
+  object::Binary *Binary = BinaryOrErr->getBinary();
+  if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Binary)) {
+    // Get the base VMA of the section matching the type
+    auto SectionBaseOrErr =
+        getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
+    if (!SectionBaseOrErr)
+      return SectionBaseOrErr.takeError();
+
+    uint64_t SectionBase = *SectionBaseOrErr;
+    uint64_t SectionRelativeOffset = Offset;
+
+    // Convert section-relative offset to absolute VMA
+    // VMA = section_base + offset
+    Offset = SectionBase + SectionRelativeOffset;
+
+    // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
+    // so we use absolute VMA addressing instead.
+    return object::SectionedAddress::UndefSection;
+  }
+
+  return createStringError(
+      inconvertibleErrorCode(),
+      "section type syntax is only supported for XCOFF objects");
+}
 
 static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
                           StringRef InputString, Command &Cmd,

>From 81e701bbdf1faaec8fa9346fe97f60d7a0be00c2 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Wed, 21 Jan 2026 02:22:19 -0500
Subject: [PATCH 06/30] Fix formatting

---
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 102 +++++++++---------
 1 file changed, 51 insertions(+), 51 deletions(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 13e298e86d78e..c235dfe8f81ca 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -176,10 +176,10 @@ parseXCOFFSectionType(StringRef TypeStr) {
 }
 
 // Find the base VMA of the unique section matching the given type for XCOFF.
-// The syntax (SECTION_TYPE)(+offset) represents an offset from the section base,
-// so we return the section's base address to compute: VMA = base + offset.
-// This function verifies there is exactly one section of the given type, as
-// multiple sections of the same type would make the address ambiguous.
+// The syntax (SECTION_TYPE)(+offset) represents an offset from the section
+// base, so we return the section's base address to compute: VMA = base +
+// offset. This function verifies there is exactly one section of the given
+// type, as multiple sections of the same type would make the address ambiguous.
 static Expected<uint64_t>
 getXCOFFSectionBaseAddress(const object::XCOFFObjectFile *XCOFFObj,
                            XCOFF::SectionTypeFlags TypeFlag) {
@@ -205,53 +205,53 @@ getXCOFFSectionBaseAddress(const object::XCOFFObjectFile *XCOFFObj,
   return *SectionBase;
 }
 
- static Expected<uint64_t> validateSectionType(StringRef ModulePath,
-                                                 StringRef SectionType,
-                                                 uint64_t &Offset,
-                                                 LLVMSymbolizer &Symbolizer) {
-   // Parse the section type string
-   auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
-   if (!SectionTypeFlag) {
-     return createStringError(inconvertibleErrorCode(),
-                              "unknown or unsupported section type: " +
-                                  SectionType.str());
-   }
-
-   // Get the module info to access the object file
-   auto ModuleOrErr = Symbolizer.getOrCreateModuleInfo(ModulePath);
-   if (!ModuleOrErr) {
-     return ModuleOrErr.takeError();
-   }
-
-   auto BinaryOrErr = object::createBinary(ModulePath);
-   if (!BinaryOrErr) {
-     return BinaryOrErr.takeError();
-   }
-
-   object::Binary *Binary = BinaryOrErr->getBinary();
-   if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Binary)) {
-     // Get the base VMA of the section matching the type
-     auto SectionBaseOrErr =
-         getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
-     if (!SectionBaseOrErr)
-       return SectionBaseOrErr.takeError();
-
-     uint64_t SectionBase = *SectionBaseOrErr;
-     uint64_t SectionRelativeOffset = Offset;
-
-     // Convert section-relative offset to absolute VMA
-     // VMA = section_base + offset
-     Offset = SectionBase + SectionRelativeOffset;
-
-     // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
-     // so we use absolute VMA addressing instead.
-     return object::SectionedAddress::UndefSection;
-   }
-
-   return createStringError(
-       inconvertibleErrorCode(),
-       "section type syntax is only supported for XCOFF objects");
- }
+static Expected<uint64_t> validateSectionType(StringRef ModulePath,
+                                              StringRef SectionType,
+                                              uint64_t &Offset,
+                                              LLVMSymbolizer &Symbolizer) {
+  // Parse the section type string
+  auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
+  if (!SectionTypeFlag) {
+    return createStringError(inconvertibleErrorCode(),
+                             "unknown or unsupported section type: " +
+                                 SectionType.str());
+  }
+
+  // Get the module info to access the object file
+  auto ModuleOrErr = Symbolizer.getOrCreateModuleInfo(ModulePath);
+  if (!ModuleOrErr) {
+    return ModuleOrErr.takeError();
+  }
+
+  auto BinaryOrErr = object::createBinary(ModulePath);
+  if (!BinaryOrErr) {
+    return BinaryOrErr.takeError();
+  }
+
+  object::Binary *Binary = BinaryOrErr->getBinary();
+  if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Binary)) {
+    // Get the base VMA of the section matching the type
+    auto SectionBaseOrErr =
+        getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
+    if (!SectionBaseOrErr)
+      return SectionBaseOrErr.takeError();
+
+    uint64_t SectionBase = *SectionBaseOrErr;
+    uint64_t SectionRelativeOffset = Offset;
+
+    // Convert section-relative offset to absolute VMA
+    // VMA = section_base + offset
+    Offset = SectionBase + SectionRelativeOffset;
+
+    // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
+    // so we use absolute VMA addressing instead.
+    return object::SectionedAddress::UndefSection;
+  }
+
+  return createStringError(
+      inconvertibleErrorCode(),
+      "section type syntax is only supported for XCOFF objects");
+}
 
 static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
                           StringRef InputString, Command &Cmd,

>From c209dd20c02c2d5a820ca8396865bdfe8b06ca83 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Mon, 23 Feb 2026 13:09:52 +0530
Subject: [PATCH 07/30] Address review comments

---
 .../llvm-symbolizer/xcoff-section-relative.ll |  51 --------
 .../xcoff-section-relative.test               |  91 +++++++++++++
 .../llvm-symbolizer/xcoff-section-syntax.test | 122 ++++++++++++++++--
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp |  78 ++++++-----
 4 files changed, 237 insertions(+), 105 deletions(-)
 delete mode 100644 llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
 create mode 100644 llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test

diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
deleted file mode 100644
index d1e21fe135e9e..0000000000000
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
+++ /dev/null
@@ -1,51 +0,0 @@
-;; Test section-relative address syntax for XCOFF
-;; The syntax (SECTION_TYPE)(+offset) represents: offset from section base
-
-; REQUIRES: system-aix
-; RUN: llc -filetype=obj -o %t -mtriple=powerpc-aix-ibm-xcoff -function-sections < %s
-
-;; Test 1: Symbolize .foo using section-relative offset
-; RUN: llvm-nm --numeric-sort %t | grep " T \.foo$" | awk '{printf "CODE (TEXT)(+0x%%s)", $1}' > %t.foo_query
-; RUN: llvm-symbolizer --obj=%t @%t.foo_query | FileCheck %s --check-prefix=TEST-FOO
-
-;; Test 2: Symbolize .bar using section-relative offset
-; RUN: llvm-nm --numeric-sort %t | grep " T \.bar$" | awk '{printf "CODE (TEXT)(+0x%%s)", $1}' > %t.bar_query
-; RUN: llvm-symbolizer --obj=%t @%t.bar_query | FileCheck %s --check-prefix=TEST-BAR
-
-;; Test 3: Symbolize global_var using section-relative offset in DATA section
-; RUN: llvm-readobj --sections %t | awk '/Name: \.data/{found=1} found && /VirtualAddress:/{print $2; exit}' > %t.data_base
-; RUN: llvm-nm --numeric-sort %t | grep " D global_var$" | awk '{print $1}' > %t.global_var_vma
-; RUN: sh -c 'printf "%%d\n" $(cat %t.data_base)' > %t.data_base_dec
-; RUN: sh -c 'printf "%%d\n" 0x$(cat %t.global_var_vma)' > %t.global_var_dec
-; RUN: awk 'NR==FNR{base=$1; next} {vma=$1; printf "DATA (DATA)(+0x%%x)", vma-base}' %t.data_base_dec %t.global_var_dec > %t.data_query
-; RUN: llvm-symbolizer --obj=%t @%t.data_query | FileCheck %s --check-prefix=TEST-DATA
-
-;; Test 4: Verify section structure with llvm-readobj
-; RUN: llvm-readobj --sections %t | FileCheck %s --check-prefix=SECTIONS
-
-define void @foo() {
-entry:
-  ret void
-}
-
-define void @bar() {
-entry:
-  ret void
-}
-
- at global_var = global i32 42, align 4
-
-;; Verify correct symbolization with section-relative syntax
-; TEST-FOO: .foo
-; TEST-FOO-NEXT: ??:0:0
-
-; TEST-BAR: .bar
-; TEST-BAR-NEXT: ??:0:0
-
-; TEST-DATA: global_var
-
-;; Verify XCOFF sections exist with correct types
-; SECTIONS: Name: .text
-; SECTIONS: Type: STYP_TEXT
-; SECTIONS: Name: .data
-; SECTIONS: Type: STYP_DATA
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
new file mode 100644
index 0000000000000..6075589f62947
--- /dev/null
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
@@ -0,0 +1,91 @@
+## Test section-relative address syntax for XCOFF.
+## The syntax (SECTION_TYPE)(+offset) represents: offset from section base.
+## Only TEXT and DATA section types are supported.
+
+# REQUIRES: system-aix
+
+## Create XCOFF object with TEXT section at address 0x100 and DATA at 0x200.
+# RUN: yaml2obj %s --docnum=1 -o %t.xcoff
+
+## Test 1: Symbolize function using TEXT section-relative offset.
+## foo is at 0x100 (TEXT base) + 0x0 offset.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+0x0)' | FileCheck %s --check-prefix=TEXT-FOO
+
+# TEXT-FOO: foo
+# TEXT-FOO-NEXT: ??:0:0
+
+## Test 2: Symbolize function at offset within TEXT section.
+## bar is at 0x100 (TEXT base) + 0x4 offset = 0x104.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+0x4)' | FileCheck %s --check-prefix=TEXT-BAR
+
+# TEXT-BAR: bar
+# TEXT-BAR-NEXT: ??:0:0
+
+## Test 3: Symbolize global variable using DATA section-relative offset.
+## global_var is at 0x200 (DATA base) + 0x0 offset.
+# RUN: llvm-symbolizer --obj=%t.xcoff 'DATA (DATA)(+0x0)' | FileCheck %s --check-prefix=DATA-VAR
+
+# DATA-VAR: global_var
+
+## Test 4: Verify decimal offset works.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+4)' | FileCheck %s --check-prefix=TEXT-BAR
+
+## XCOFF object with TEXT section at 0x100 and DATA section at 0x200.
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x1DF
+Sections:
+  - Name:            .text
+    Address:         0x100
+    Flags:           [ STYP_TEXT ]
+    SectionData:     "4E8000204E800020"  # Two blr instructions (4 bytes each)
+  - Name:            .data
+    Address:         0x200
+    Flags:           [ STYP_DATA ]
+    SectionData:     "0000002A"  # 32-bit value 42
+Symbols:
+  - Name:            .foo
+    Value:           0x100
+    Section:         .text
+    StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_LD
+        StorageMappingClass:  XMC_PR
+  - Name:            foo
+    Value:           0x100
+    Section:         .text
+    StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_PR
+  - Name:            .bar
+    Value:           0x104
+    Section:         .text
+    StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_LD
+        StorageMappingClass:  XMC_PR
+  - Name:            bar
+    Value:           0x104
+    Section:         .text
+    StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_PR
+  - Name:            global_var
+    Value:           0x200
+    Section:         .data
+    StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_RW
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index 2465d1ec738fc..83917a82b961d 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -1,31 +1,125 @@
-## Test section-relative address syntax parsing for XCOFF
+## Test section-relative address syntax parsing and error handling for XCOFF.
 ## This tests that the (SECTION_TYPE)(+offset) syntax produces appropriate
-## error messages for invalid syntax
+## error messages for invalid inputs.
 
 # REQUIRES: system-aix
 
-## Create a simple XCOFF object for testing
-# RUN: echo "define void @test() { ret void }" | \
-# RUN:   llc -filetype=obj -mtriple=powerpc-aix-ibm-xcoff -o %t.o
+## Create a simple XCOFF object for testing.
+# RUN: yaml2obj %s --docnum=1 -o %t.xcoff
 
-## Test invalid section type
-# RUN: llvm-symbolizer --obj=%t.o '(INVALID)(+0x10)' 2>&1 | \
+## Test invalid/unsupported section type.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(INVALID)(+0x10)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=INVALID-TYPE
 
-## Test missing '+' sign
-# RUN: llvm-symbolizer --obj=%t.o '(TEXT)(0x10)' 2>&1 | \
+## Test unsupported section type (BSS is not supported).
+# RUN: llvm-symbolizer --obj=%t.xcoff '(BSS)(+0x10)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=INVALID-TYPE
+
+## Test missing '+' sign.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(0x10)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=NO-PLUS
 
-## Test invalid offset value (not a hex number)
-# RUN: llvm-symbolizer --obj=%t.o '(TEXT)(+abc)' 2>&1 | \
+## Test invalid offset value.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+xyz)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=INVALID-OFFSET
 
-## Test empty section type
-# RUN: llvm-symbolizer --obj=%t.o '()(+0x10)' 2>&1 | \
+## Test empty section type.
+# RUN: llvm-symbolizer --obj=%t.xcoff '()(+0x10)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=EMPTY-SECTION
 
-## Verify error messages are helpful
 # INVALID-TYPE: unknown or unsupported section type
 # NO-PLUS: section-relative offset must start with '+'
 # INVALID-OFFSET: invalid offset in section-relative address
 # EMPTY-SECTION: unknown section type: empty section type
+
+## Test error: section type not found (DATA section doesn't exist).
+# RUN: yaml2obj %s --docnum=2 -o %t.nodata.xcoff
+# RUN: llvm-symbolizer --obj=%t.nodata.xcoff '(DATA)(+0x0)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=NO-SECTION
+
+# NO-SECTION: section type not found in XCOFF object
+
+## Test error: multiple sections of same type.
+# RUN: yaml2obj %s --docnum=3 -o %t.multi.xcoff
+# RUN: llvm-symbolizer --obj=%t.multi.xcoff '(TEXT)(+0x0)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=MULTI-SECTION
+
+# MULTI-SECTION: multiple sections of the same type found in XCOFF object
+
+## Test error: section type syntax on non-XCOFF object.
+# RUN: yaml2obj %s --docnum=4 -o %t.elf
+# RUN: llvm-symbolizer --obj=%t.elf '(TEXT)(+0x0)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=NON-XCOFF
+
+# NON-XCOFF: section type syntax is only supported for XCOFF objects
+
+## Document 1: Basic XCOFF object with TEXT and DATA sections.
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x1DF
+Sections:
+  - Name:    .text
+    Address: 0x100
+    Flags:   [ STYP_TEXT ]
+    SectionData: "4E800020"
+  - Name:    .data
+    Address: 0x200
+    Flags:   [ STYP_DATA ]
+    SectionData: "00000000"
+Symbols:
+  - Name:            foo
+    Value:           0x100
+    Section:         .text
+    StorageClass:    C_EXT
+
+## Document 2: XCOFF object with only TEXT section (no DATA).
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x1DF
+Sections:
+  - Name:    .text
+    Address: 0x100
+    Flags:   [ STYP_TEXT ]
+    SectionData: "4E800020"
+Symbols:
+  - Name:            foo
+    Value:           0x100
+    Section:         .text
+    StorageClass:    C_EXT
+
+## Document 3: XCOFF object with multiple TEXT sections.
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x1DF
+Sections:
+  - Name:    .text
+    Address: 0x100
+    Flags:   [ STYP_TEXT ]
+    SectionData: "4E800020"
+  - Name:    .text2
+    Address: 0x200
+    Flags:   [ STYP_TEXT ]
+    SectionData: "4E800020"
+Symbols:
+  - Name:            foo
+    Value:           0x100
+    Section:         .text
+    StorageClass:    C_EXT
+
+## Document 4: ELF object (non-XCOFF) for testing error case.
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address: 0x1000
+    Content: "C3"
+Symbols:
+  - Name:    foo
+    Section: .text
+    Value:   0x1000
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index c235dfe8f81ca..91361b44956d4 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -185,22 +185,20 @@ getXCOFFSectionBaseAddress(const object::XCOFFObjectFile *XCOFFObj,
                            XCOFF::SectionTypeFlags TypeFlag) {
   std::optional<uint64_t> SectionBase;
 
-  for (const auto &Section : XCOFFObj->sections()) {
+  for (const object::SectionRef &Section : XCOFFObj->sections()) {
     DataRefImpl SecRef = Section.getRawDataRefImpl();
     int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
 
     if ((Flags & 0xFFFF) == TypeFlag) {
       if (SectionBase)
         return createStringError(
-            inconvertibleErrorCode(),
             "multiple sections of the same type found in XCOFF object");
       SectionBase = Section.getAddress();
     }
   }
 
   if (!SectionBase)
-    return createStringError(inconvertibleErrorCode(),
-                             "section type not found in XCOFF object");
+    return createStringError("section type not found in XCOFF object");
 
   return *SectionBase;
 }
@@ -210,47 +208,47 @@ static Expected<uint64_t> validateSectionType(StringRef ModulePath,
                                               uint64_t &Offset,
                                               LLVMSymbolizer &Symbolizer) {
   // Parse the section type string
-  auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
-  if (!SectionTypeFlag) {
-    return createStringError(inconvertibleErrorCode(),
-                             "unknown or unsupported section type: " +
-                                 SectionType.str());
-  }
-
-  // Get the module info to access the object file
-  auto ModuleOrErr = Symbolizer.getOrCreateModuleInfo(ModulePath);
-  if (!ModuleOrErr) {
+  std::optional<XCOFF::SectionTypeFlags> SectionTypeFlag =
+      parseXCOFFSectionType(SectionType);
+  if (!SectionTypeFlag)
+    return createStringError("unknown or unsupported section type: " +
+                             SectionType.str());
+
+  // Get the module info to verify the module exists and is valid.
+  Expected<SymbolizableModule *> ModuleOrErr =
+      Symbolizer.getOrCreateModuleInfo(ModulePath);
+  if (!ModuleOrErr)
     return ModuleOrErr.takeError();
-  }
 
-  auto BinaryOrErr = object::createBinary(ModulePath);
-  if (!BinaryOrErr) {
+  // TODO: Consider caching the binary to avoid re-opening for each address.
+  Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
+      object::createBinary(ModulePath);
+  if (!BinaryOrErr)
     return BinaryOrErr.takeError();
-  }
 
   object::Binary *Binary = BinaryOrErr->getBinary();
-  if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Binary)) {
-    // Get the base VMA of the section matching the type
-    auto SectionBaseOrErr =
-        getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
-    if (!SectionBaseOrErr)
-      return SectionBaseOrErr.takeError();
-
-    uint64_t SectionBase = *SectionBaseOrErr;
-    uint64_t SectionRelativeOffset = Offset;
-
-    // Convert section-relative offset to absolute VMA
-    // VMA = section_base + offset
-    Offset = SectionBase + SectionRelativeOffset;
-
-    // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
-    // so we use absolute VMA addressing instead.
-    return object::SectionedAddress::UndefSection;
-  }
-
-  return createStringError(
-      inconvertibleErrorCode(),
-      "section type syntax is only supported for XCOFF objects");
+  const object::XCOFFObjectFile *XCOFFObj =
+      dyn_cast<object::XCOFFObjectFile>(Binary);
+  if (!XCOFFObj)
+    return createStringError(
+        "section type syntax is only supported for XCOFF objects");
+
+  // Get the base VMA of the section matching the type
+  Expected<uint64_t> SectionBaseOrErr =
+      getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
+  if (!SectionBaseOrErr)
+    return SectionBaseOrErr.takeError();
+
+  uint64_t SectionBase = *SectionBaseOrErr;
+  uint64_t SectionRelativeOffset = Offset;
+
+  // Convert section-relative offset to absolute VMA
+  // VMA = section_base + offset
+  Offset = SectionBase + SectionRelativeOffset;
+
+  // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
+  // so we use absolute VMA addressing instead.
+  return object::SectionedAddress::UndefSection;
 }
 
 static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,

>From c94a13c95fe05762ab609c4d2e5a6e7367f7e70a Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Mon, 23 Feb 2026 15:07:23 +0530
Subject: [PATCH 08/30] Address review comments

---
 .../llvm-symbolizer/xcoff-section-syntax.test     | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index 83917a82b961d..05010f21d8f89 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -71,6 +71,11 @@ Symbols:
     Value:           0x100
     Section:         .text
     StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_PR
 
 ## Document 2: XCOFF object with only TEXT section (no DATA).
 --- !XCOFF
@@ -86,6 +91,11 @@ Symbols:
     Value:           0x100
     Section:         .text
     StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_PR
 
 ## Document 3: XCOFF object with multiple TEXT sections.
 --- !XCOFF
@@ -105,6 +115,11 @@ Symbols:
     Value:           0x100
     Section:         .text
     StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_PR
 
 ## Document 4: ELF object (non-XCOFF) for testing error case.
 --- !ELF

>From 38593298c1c8f865d54823f53ccb920769a7fa3e Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Mon, 23 Feb 2026 05:24:20 -0500
Subject: [PATCH 09/30] Address review comments

---
 llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 91361b44956d4..7a6652a079ad1 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -1,5 +1,4 @@
-//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer
-//------------===//
+//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

>From 8ffc71ee624ca5b66f48b39d76ae321578efbc6b Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Mon, 23 Feb 2026 19:39:24 +0530
Subject: [PATCH 10/30] Address review comments

---
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 24 ++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 91361b44956d4..8dacfc5587282 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -47,11 +47,17 @@
 #include <cstdio>
 #include <cstring>
 #include <iostream>
+#include <map>
 #include <string>
 
 using namespace llvm;
 using namespace symbolize;
 
+// Cache for XCOFF section base addresses to avoid re-opening binaries.
+// Key: (ModulePath, SectionTypeFlag), Value: SectionBaseAddress
+static std::map<std::pair<std::string, XCOFF::SectionTypeFlags>, uint64_t>
+    XCOFFSectionBaseCache;
+
 namespace {
 enum ID {
   OPT_INVALID = 0, // This is not an option ID.
@@ -220,7 +226,17 @@ static Expected<uint64_t> validateSectionType(StringRef ModulePath,
   if (!ModuleOrErr)
     return ModuleOrErr.takeError();
 
-  // TODO: Consider caching the binary to avoid re-opening for each address.
+  // Check cache for section base address.
+  std::pair<std::string, XCOFF::SectionTypeFlags> CacheKey =
+      std::make_pair(ModulePath.str(), *SectionTypeFlag);
+  std::map<std::pair<std::string, XCOFF::SectionTypeFlags>,
+           uint64_t>::iterator CacheIt = XCOFFSectionBaseCache.find(CacheKey);
+  if (CacheIt != XCOFFSectionBaseCache.end()) {
+    Offset = CacheIt->second + Offset;
+    return object::SectionedAddress::UndefSection;
+  }
+
+  // Not in cache - open binary and compute section base.
   Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
       object::createBinary(ModulePath);
   if (!BinaryOrErr)
@@ -240,11 +256,13 @@ static Expected<uint64_t> validateSectionType(StringRef ModulePath,
     return SectionBaseOrErr.takeError();
 
   uint64_t SectionBase = *SectionBaseOrErr;
-  uint64_t SectionRelativeOffset = Offset;
+
+  // Cache the section base for future lookups.
+  XCOFFSectionBaseCache[CacheKey] = SectionBase;
 
   // Convert section-relative offset to absolute VMA
   // VMA = section_base + offset
-  Offset = SectionBase + SectionRelativeOffset;
+  Offset = SectionBase + Offset;
 
   // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
   // so we use absolute VMA addressing instead.

>From e9f1fded383ba1d858890934d1a2df85b09ead0c Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Mon, 23 Feb 2026 09:19:42 -0500
Subject: [PATCH 11/30] Fix formatting

---
 llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 2007a23dd6824..4456067b5719b 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -228,8 +228,8 @@ static Expected<uint64_t> validateSectionType(StringRef ModulePath,
   // Check cache for section base address.
   std::pair<std::string, XCOFF::SectionTypeFlags> CacheKey =
       std::make_pair(ModulePath.str(), *SectionTypeFlag);
-  std::map<std::pair<std::string, XCOFF::SectionTypeFlags>,
-           uint64_t>::iterator CacheIt = XCOFFSectionBaseCache.find(CacheKey);
+  std::map<std::pair<std::string, XCOFF::SectionTypeFlags>, uint64_t>::iterator
+      CacheIt = XCOFFSectionBaseCache.find(CacheKey);
   if (CacheIt != XCOFFSectionBaseCache.end()) {
     Offset = CacheIt->second + Offset;
     return object::SectionedAddress::UndefSection;

>From 550be4d5fce3c1a37e6e370d21833a13171f3ab9 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Thu, 13 Nov 2025 12:04:34 +0530
Subject: [PATCH 12/30] section relative syntax implementation

---
 .../llvm-symbolizer/xcoff-section-relative.ll |  51 ++++++
 .../llvm-symbolizer/xcoff-section-syntax.test |  31 ++++
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 158 +++++++++++++++++-
 3 files changed, 232 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
 create mode 100644 llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test

diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
new file mode 100644
index 0000000000000..cfc6b31812a98
--- /dev/null
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
@@ -0,0 +1,51 @@
+;; Test section-relative address syntax for XCOFF
+;; The syntax (SECTION_TYPE)(+offset) represents: offset from section base
+
+; REQUIRES: system-aix
+; RUN: llc -filetype=obj -o %t -mtriple=powerpc-aix-ibm-xcoff -function-sections < %s
+
+;; Test 1: Symbolize .foo using section-relative offset
+; RUN: llvm-nm --numeric-sort %t | grep " T \.foo$" | awk '{printf "CODE (TEXT)(+0x%%s)", $1}' > %t.foo_query
+; RUN: llvm-symbolizer --obj=%t @%t.foo_query | FileCheck %s --check-prefix=TEST-FOO
+
+;; Test 2: Symbolize .bar using section-relative offset
+; RUN: llvm-nm --numeric-sort %t | grep " T \.bar$" | awk '{printf "CODE (TEXT)(+0x%%s)", $1}' > %t.bar_query
+; RUN: llvm-symbolizer --obj=%t @%t.bar_query | FileCheck %s --check-prefix=TEST-BAR
+
+;; Test 3: Symbolize global_var using section-relative offset in DATA section
+; RUN: llvm-readobj --sections %t | awk '/Name: \.data/{found=1} found && /VirtualAddress:/{print $2; exit}' > %t.data_base
+; RUN: llvm-nm --numeric-sort %t | grep " D global_var$" | awk '{print $1}' > %t.global_var_vma
+; RUN: sh -c 'printf "%%d\n" $(cat %t.data_base)' > %t.data_base_dec
+; RUN: sh -c 'printf "%%d\n" 0x$(cat %t.global_var_vma)' > %t.global_var_dec
+; RUN: awk 'NR==FNR{base=$1; next} {vma=$1; printf "DATA (DATA)(+0x%%x)", vma-base}' %t.data_base_dec %t.global_var_dec > %t.data_query
+; RUN: llvm-symbolizer --obj=%t @%t.data_query | FileCheck %s --check-prefix=TEST-DATA
+
+;; Test 4: Verify section structure with llvm-readobj
+; RUN: llvm-readobj --sections %t | FileCheck %s --check-prefix=SECTIONS
+
+define void @foo() {
+entry:
+  ret void
+}
+
+define void @bar() {
+entry:
+  ret void
+}
+
+ at global_var = global i32 42, align 4
+
+;; Verify correct symbolization with section-relative syntax
+; TEST-FOO: .foo
+; TEST-FOO-NEXT: ??:0:0
+
+; TEST-BAR: .bar
+; TEST-BAR-NEXT: ??:0:0
+
+; TEST-DATA: global_var
+
+;; Verify XCOFF sections exist with correct types
+; SECTIONS: Name: .text
+; SECTIONS: Type: STYP_TEXT
+; SECTIONS: Name: .data
+; SECTIONS: Type: STYP_DATA
\ No newline at end of file
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
new file mode 100644
index 0000000000000..01bda672387f4
--- /dev/null
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -0,0 +1,31 @@
+## Test section-relative address syntax parsing for XCOFF
+## This tests that the (SECTION_TYPE)(+offset) syntax produces appropriate
+## error messages for invalid syntax
+
+# REQUIRES: system-aix
+
+## Create a simple XCOFF object for testing
+# RUN: echo "define void @test() { ret void }" | \
+# RUN:   llc -filetype=obj -mtriple=powerpc-aix-ibm-xcoff -o %t.o
+
+## Test invalid section type
+# RUN: llvm-symbolizer --obj=%t.o '(INVALID)(+0x10)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=INVALID-TYPE
+
+## Test missing '+' sign
+# RUN: llvm-symbolizer --obj=%t.o '(TEXT)(0x10)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=NO-PLUS
+
+## Test invalid offset value (not a hex number)
+# RUN: llvm-symbolizer --obj=%t.o '(TEXT)(+abc)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=INVALID-OFFSET
+
+## Test empty section type
+# RUN: llvm-symbolizer --obj=%t.o '()(+0x10)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=EMPTY-SECTION
+
+## Verify error messages are helpful
+# INVALID-TYPE: unknown section type
+# NO-PLUS: section-relative offset must start with '+'
+# INVALID-OFFSET: invalid offset in section-relative address
+# EMPTY-SECTION: unknown section type
\ No newline at end of file
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 4784dafeb2948..d239d1aad73d7 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -17,12 +17,15 @@
 #include "Opts.inc"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/Config/config.h"
 #include "llvm/DebugInfo/Symbolize/DIPrinter.h"
 #include "llvm/DebugInfo/Symbolize/Markup.h"
 #include "llvm/DebugInfo/Symbolize/MarkupFilter.h"
 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
+#include "llvm/Object/XCOFFObjectFile.h"
 #include "llvm/Debuginfod/BuildIDFetcher.h"
 #include "llvm/Debuginfod/Debuginfod.h"
 #include "llvm/Debuginfod/HTTPClient.h"
@@ -157,11 +160,97 @@ static Error makeStringError(StringRef Msg) {
   return make_error<StringError>(Msg, inconvertibleErrorCode());
 }
 
+// Helper function to get XCOFF section type flag from string
+ static std::optional<XCOFF::SectionTypeFlags> parseXCOFFSectionType(StringRef TypeStr) {
+   return StringSwitch<std::optional<XCOFF::SectionTypeFlags>>(TypeStr)
+       .Case("PAD", XCOFF::STYP_PAD)
+       .Case("DWARF", XCOFF::STYP_DWARF)
+       .Case("TEXT", XCOFF::STYP_TEXT)
+       .Case("DATA", XCOFF::STYP_DATA)
+       .Case("BSS", XCOFF::STYP_BSS)
+       .Case("EXCEPT", XCOFF::STYP_EXCEPT)
+       .Case("INFO", XCOFF::STYP_INFO)
+       .Case("TDATA", XCOFF::STYP_TDATA)
+       .Case("TBSS", XCOFF::STYP_TBSS)
+       .Case("LOADER", XCOFF::STYP_LOADER)
+       .Case("DEBUG", XCOFF::STYP_DEBUG)
+       .Case("TYPCHK", XCOFF::STYP_TYPCHK)
+       .Case("OVRFLO", XCOFF::STYP_OVRFLO)
+       .Default(std::nullopt);
+ }
+
+ // Find the base VMA of the first section matching the given type for XCOFF.
+ // The syntax (SECTION_TYPE)(+offset) represents an offset from the section base,
+ // so we return the section's base address to compute: VMA = base + offset.
+ static Expected<uint64_t> getXCOFFSectionBaseAddress(
+     const object::XCOFFObjectFile *XCOFFObj,
+     XCOFF::SectionTypeFlags TypeFlag) {
+
+   for (const auto &Section : XCOFFObj->sections()) {
+     DataRefImpl SecRef = Section.getRawDataRefImpl();
+     int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
+
+     if ((Flags & 0xFFFF) == TypeFlag) {
+       return Section.getAddress();
+     }
+   }
+
+   return createStringError(inconvertibleErrorCode(),
+                            "section type not found in XCOFF object");
+ }
+
+ static Expected<uint64_t> validateSectionType(StringRef ModulePath,
+                                                 StringRef SectionType,
+                                                 uint64_t &Offset,
+                                                 LLVMSymbolizer &Symbolizer) {
+   // Parse the section type string
+   auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
+   if (!SectionTypeFlag) {
+     return createStringError(inconvertibleErrorCode(),
+                             "unknown section type: " + SectionType.str());
+   }
+
+   // Get the module info to access the object file
+   auto ModuleOrErr = Symbolizer.getOrCreateModuleInfo(ModulePath);
+   if (!ModuleOrErr) {
+     return ModuleOrErr.takeError();
+   }
+
+   auto BinaryOrErr = object::createBinary(ModulePath);
+   if (!BinaryOrErr) {
+     return BinaryOrErr.takeError();
+   }
+
+   object::Binary *Binary = BinaryOrErr->getBinary();
+   if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Binary)) {
+     // Get the base VMA of the section matching the type
+     auto SectionBaseOrErr = getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
+     if (!SectionBaseOrErr)
+       return SectionBaseOrErr.takeError();
+
+     uint64_t SectionBase = *SectionBaseOrErr;
+     uint64_t SectionRelativeOffset = Offset;
+
+     // Convert section-relative offset to absolute VMA
+     // VMA = section_base + offset
+     Offset = SectionBase + SectionRelativeOffset;
+
+     // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
+     // so we use absolute VMA addressing instead.
+     return object::SectionedAddress::UndefSection;
+   }
+
+   return createStringError(inconvertibleErrorCode(),
+                           "section type syntax is only supported for XCOFF objects");
+ }
+
 static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
                           StringRef InputString, Command &Cmd,
                           std::string &ModuleName, object::BuildID &BuildID,
-                          StringRef &Symbol, uint64_t &Offset) {
+                          StringRef &Symbol, uint64_t &Offset,
+                          StringRef &SectionType) {
   ModuleName = BinaryName;
+  SectionType = StringRef();
   if (InputString.consume_front("CODE ")) {
     Cmd = Command::Code;
   } else if (InputString.consume_front("DATA ")) {
@@ -245,10 +334,43 @@ static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
         AddrSpec.consume_front_insensitive("+0x");
   }
 
+  // Check for section-relative address syntax: (SECTION_TYPE)(+0x0)
+   if (AddrSpec.starts_with("(")) {
+     size_t FirstClose = AddrSpec.find(')');
+     if (FirstClose != StringRef::npos && FirstClose + 1 < AddrSpec.size() &&
+         AddrSpec[FirstClose + 1] == '(') {
+       size_t SecondOpen = FirstClose + 1;
+       size_t SecondClose = AddrSpec.find(')', SecondOpen);
+       if (SecondClose != StringRef::npos) {
+         // Extract section type from first parentheses
+         SectionType = AddrSpec.substr(1, FirstClose - 1);
+
+         // Validate that section type is not empty
+         if (SectionType.empty())
+           return makeStringError("unknown section type: empty section type");
+
+         // Extract offset from second parentheses
+         StringRef OffsetPart = AddrSpec.substr(SecondOpen + 1, SecondClose - SecondOpen - 1);
+
+         // The offset should start with '+'
+         if (!OffsetPart.consume_front("+"))
+           return makeStringError("section-relative offset must start with '+'");
+
+         // Parse the offset - auto-detect base (0x prefix = hex, otherwise decimal)
+         if (OffsetPart.getAsInteger(0, Offset))
+           return makeStringError("invalid offset in section-relative address");
+
+         Symbol = StringRef();
+         return Error::success();
+       }
+     }
+   }
+
   // If address specification is a number, treat it as a module offset.
   if (!AddrSpec.getAsInteger(IsAddr2Line ? 16 : 0, Offset)) {
     // Module offset is an address.
     Symbol = StringRef();
+    SectionType = StringRef();
     return Error::success();
   }
 
@@ -260,6 +382,7 @@ static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
   // Otherwise it is a symbol name, potentially with an offset.
   Symbol = AddrSpec;
   Offset = 0;
+  SectionType = StringRef();
 
   // If the address specification contains '+', try treating it as
   // "symbol + offset".
@@ -282,10 +405,11 @@ template <typename T>
 void executeCommand(StringRef ModuleName, const T &ModuleSpec, Command Cmd,
                     StringRef Symbol, uint64_t Offset, uint64_t AdjustVMA,
                     bool ShouldInline, OutputStyle Style,
-                    LLVMSymbolizer &Symbolizer, DIPrinter &Printer) {
-  uint64_t AdjustedOffset = Offset - AdjustVMA;
-  object::SectionedAddress Address = {AdjustedOffset,
-                                      object::SectionedAddress::UndefSection};
+                    LLVMSymbolizer &Symbolizer, DIPrinter &Printer,
+                    uint64_t SectionIndex) {
+   uint64_t AdjustedOffset = Offset - AdjustVMA;
+   object::SectionedAddress Address = {AdjustedOffset, SectionIndex};
+
   Request SymRequest = {
       ModuleName, Symbol.empty() ? std::make_optional(Offset) : std::nullopt,
       Symbol};
@@ -342,6 +466,7 @@ static void symbolizeInput(const opt::InputArgList &Args,
   object::BuildID BuildID(IncomingBuildID.begin(), IncomingBuildID.end());
   uint64_t Offset = 0;
   StringRef Symbol;
+  StringRef SectionType;
 
   // An empty input string may be used to check if the process is alive and
   // responding to input. Do not emit a message on stderr in this case but
@@ -352,24 +477,41 @@ static void symbolizeInput(const opt::InputArgList &Args,
   }
   if (Error E = parseCommand(Args.getLastArgValue(OPT_obj_EQ), IsAddr2Line,
                              StringRef(InputString), Cmd, ModuleName, BuildID,
-                             Symbol, Offset)) {
+                             Symbol, Offset, SectionType)) {
     handleAllErrors(std::move(E), [&](const StringError &EI) {
       printError(EI, InputString);
       printUnknownLineInfo(ModuleName, Printer);
     });
     return;
   }
+
+  // Validate section index from section type if specified
+  uint64_t SectionIndex = object::SectionedAddress::UndefSection;
+  if (!SectionType.empty() && !ModuleName.empty()) {
+    auto SectionIndexOrErr = validateSectionType(ModuleName, SectionType, Offset, Symbolizer);
+    if (!SectionIndexOrErr) {
+      handleAllErrors(SectionIndexOrErr.takeError(), [&](const ErrorInfoBase &EI) {
+        printError(EI, InputString);
+      });
+      printUnknownLineInfo(ModuleName, Printer);
+      return;
+    }
+    SectionIndex = *SectionIndexOrErr;
+  }
+
   bool ShouldInline = Args.hasFlag(OPT_inlines, OPT_no_inlines, !IsAddr2Line);
   if (!BuildID.empty()) {
     assert(ModuleName.empty());
     if (!Args.hasArg(OPT_no_debuginfod))
       enableDebuginfod(Symbolizer, Args);
     std::string BuildIDStr = toHex(BuildID);
+    // Note: Section type resolution is not supported for BuildID-based lookup
     executeCommand(BuildIDStr, BuildID, Cmd, Symbol, Offset, AdjustVMA,
-                   ShouldInline, Style, Symbolizer, Printer);
+                   ShouldInline, Style, Symbolizer, Printer,
+                    object::SectionedAddress::UndefSection);
   } else {
     executeCommand(ModuleName, ModuleName, Cmd, Symbol, Offset, AdjustVMA,
-                   ShouldInline, Style, Symbolizer, Printer);
+ShouldInline, Style, Symbolizer, Printer, SectionIndex);
   }
 }
 

>From 6626eb83882435cd0c4f0748cbcf783e0f72d81f Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Sun, 9 Nov 2025 12:33:22 -0500
Subject: [PATCH 13/30] symbolizer to accept section relative syntax

---
 llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll | 2 +-
 llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test | 2 +-
 llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp            | 1 +
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
index cfc6b31812a98..d1e21fe135e9e 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
@@ -48,4 +48,4 @@ entry:
 ; SECTIONS: Name: .text
 ; SECTIONS: Type: STYP_TEXT
 ; SECTIONS: Name: .data
-; SECTIONS: Type: STYP_DATA
\ No newline at end of file
+; SECTIONS: Type: STYP_DATA
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index 01bda672387f4..ca5ef9d3cb2cc 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -28,4 +28,4 @@
 # INVALID-TYPE: unknown section type
 # NO-PLUS: section-relative offset must start with '+'
 # INVALID-OFFSET: invalid offset in section-relative address
-# EMPTY-SECTION: unknown section type
\ No newline at end of file
+# EMPTY-SECTION: unknown section type
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index d239d1aad73d7..3bdbce55c4f68 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -29,6 +29,7 @@
 #include "llvm/Debuginfod/BuildIDFetcher.h"
 #include "llvm/Debuginfod/Debuginfod.h"
 #include "llvm/Debuginfod/HTTPClient.h"
+#include "llvm/Object/XCOFFObjectFile.h"
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/Option.h"

>From 2f67976d9088e0937ff27c78b312e0efab1b76a6 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Tue, 18 Nov 2025 07:24:11 -0500
Subject: [PATCH 14/30] code format fix

---
 llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 3bdbce55c4f68..1ad5d43409b4a 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -1,4 +1,5 @@
-//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===//
+//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer
+//------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

>From b77eeb3a44232c3d431a1b1b910a9d14f5aaadc7 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Wed, 21 Jan 2026 10:59:18 +0530
Subject: [PATCH 15/30] Review comments addressed

---
 .../llvm-symbolizer/xcoff-section-syntax.test |  4 +-
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 78 ++++++++++---------
 2 files changed, 44 insertions(+), 38 deletions(-)

diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index ca5ef9d3cb2cc..2465d1ec738fc 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -25,7 +25,7 @@
 # RUN:   FileCheck %s --check-prefix=EMPTY-SECTION
 
 ## Verify error messages are helpful
-# INVALID-TYPE: unknown section type
+# INVALID-TYPE: unknown or unsupported section type
 # NO-PLUS: section-relative offset must start with '+'
 # INVALID-OFFSET: invalid offset in section-relative address
-# EMPTY-SECTION: unknown section type
+# EMPTY-SECTION: unknown section type: empty section type
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 1ad5d43409b4a..4400a8ead2abb 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -162,44 +162,49 @@ static Error makeStringError(StringRef Msg) {
   return make_error<StringError>(Msg, inconvertibleErrorCode());
 }
 
-// Helper function to get XCOFF section type flag from string
- static std::optional<XCOFF::SectionTypeFlags> parseXCOFFSectionType(StringRef TypeStr) {
-   return StringSwitch<std::optional<XCOFF::SectionTypeFlags>>(TypeStr)
-       .Case("PAD", XCOFF::STYP_PAD)
-       .Case("DWARF", XCOFF::STYP_DWARF)
-       .Case("TEXT", XCOFF::STYP_TEXT)
-       .Case("DATA", XCOFF::STYP_DATA)
-       .Case("BSS", XCOFF::STYP_BSS)
-       .Case("EXCEPT", XCOFF::STYP_EXCEPT)
-       .Case("INFO", XCOFF::STYP_INFO)
-       .Case("TDATA", XCOFF::STYP_TDATA)
-       .Case("TBSS", XCOFF::STYP_TBSS)
-       .Case("LOADER", XCOFF::STYP_LOADER)
-       .Case("DEBUG", XCOFF::STYP_DEBUG)
-       .Case("TYPCHK", XCOFF::STYP_TYPCHK)
-       .Case("OVRFLO", XCOFF::STYP_OVRFLO)
-       .Default(std::nullopt);
- }
-
- // Find the base VMA of the first section matching the given type for XCOFF.
- // The syntax (SECTION_TYPE)(+offset) represents an offset from the section base,
- // so we return the section's base address to compute: VMA = base + offset.
- static Expected<uint64_t> getXCOFFSectionBaseAddress(
-     const object::XCOFFObjectFile *XCOFFObj,
-     XCOFF::SectionTypeFlags TypeFlag) {
+// Helper function to get XCOFF section type flag from string.
+// Only TEXT and DATA are supported since:
+// - These are the only sections mapped by the AIX process map (procmap).
+// - BSS addresses are relative to DATA section base.
+// - Thread-local sections (TDATA, TBSS) cannot be symbolized from runtime
+//   addresses.
+static std::optional<XCOFF::SectionTypeFlags>
+parseXCOFFSectionType(StringRef TypeStr) {
+  return StringSwitch<std::optional<XCOFF::SectionTypeFlags>>(TypeStr)
+      .Case("TEXT", XCOFF::STYP_TEXT)
+      .Case("DATA", XCOFF::STYP_DATA)
+      .Default(std::nullopt);
+}
 
-   for (const auto &Section : XCOFFObj->sections()) {
-     DataRefImpl SecRef = Section.getRawDataRefImpl();
-     int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
+// Find the base VMA of the unique section matching the given type for XCOFF.
+// The syntax (SECTION_TYPE)(+offset) represents an offset from the section base,
+// so we return the section's base address to compute: VMA = base + offset.
+// This function verifies there is exactly one section of the given type, as
+// multiple sections of the same type would make the address ambiguous.
+static Expected<uint64_t>
+getXCOFFSectionBaseAddress(const object::XCOFFObjectFile *XCOFFObj,
+                           XCOFF::SectionTypeFlags TypeFlag) {
+  std::optional<uint64_t> SectionBase;
+
+  for (const auto &Section : XCOFFObj->sections()) {
+    DataRefImpl SecRef = Section.getRawDataRefImpl();
+    int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
+
+    if ((Flags & 0xFFFF) == TypeFlag) {
+      if (SectionBase)
+        return createStringError(
+            inconvertibleErrorCode(),
+            "multiple sections of the same type found in XCOFF object");
+      SectionBase = Section.getAddress();
+    }
+  }
 
-     if ((Flags & 0xFFFF) == TypeFlag) {
-       return Section.getAddress();
-     }
-   }
+  if (!SectionBase)
+    return createStringError(inconvertibleErrorCode(),
+                             "section type not found in XCOFF object");
 
-   return createStringError(inconvertibleErrorCode(),
-                            "section type not found in XCOFF object");
- }
+  return *SectionBase;
+}
 
  static Expected<uint64_t> validateSectionType(StringRef ModulePath,
                                                  StringRef SectionType,
@@ -209,7 +214,8 @@ static Error makeStringError(StringRef Msg) {
    auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
    if (!SectionTypeFlag) {
      return createStringError(inconvertibleErrorCode(),
-                             "unknown section type: " + SectionType.str());
+                              "unknown or unsupported section type: " +
+                                  SectionType.str());
    }
 
    // Get the module info to access the object file

>From 0a9bcc4cf038b627a9126b181fd1cb34132ec3df Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Wed, 21 Jan 2026 02:22:19 -0500
Subject: [PATCH 16/30] Fix formatting

---
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 78 ++++++++++---------
 1 file changed, 40 insertions(+), 38 deletions(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 4400a8ead2abb..bc4b4a1a807a0 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -206,51 +206,53 @@ getXCOFFSectionBaseAddress(const object::XCOFFObjectFile *XCOFFObj,
   return *SectionBase;
 }
 
- static Expected<uint64_t> validateSectionType(StringRef ModulePath,
-                                                 StringRef SectionType,
-                                                 uint64_t &Offset,
-                                                 LLVMSymbolizer &Symbolizer) {
-   // Parse the section type string
-   auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
-   if (!SectionTypeFlag) {
-     return createStringError(inconvertibleErrorCode(),
-                              "unknown or unsupported section type: " +
-                                  SectionType.str());
-   }
+static Expected<uint64_t> validateSectionType(StringRef ModulePath,
+                                              StringRef SectionType,
+                                              uint64_t &Offset,
+                                              LLVMSymbolizer &Symbolizer) {
+  // Parse the section type string
+  auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
+  if (!SectionTypeFlag) {
+    return createStringError(inconvertibleErrorCode(),
+                             "unknown or unsupported section type: " +
+                                 SectionType.str());
+  }
 
-   // Get the module info to access the object file
-   auto ModuleOrErr = Symbolizer.getOrCreateModuleInfo(ModulePath);
-   if (!ModuleOrErr) {
-     return ModuleOrErr.takeError();
-   }
+  // Get the module info to access the object file
+  auto ModuleOrErr = Symbolizer.getOrCreateModuleInfo(ModulePath);
+  if (!ModuleOrErr) {
+    return ModuleOrErr.takeError();
+  }
 
-   auto BinaryOrErr = object::createBinary(ModulePath);
-   if (!BinaryOrErr) {
-     return BinaryOrErr.takeError();
-   }
+  auto BinaryOrErr = object::createBinary(ModulePath);
+  if (!BinaryOrErr) {
+    return BinaryOrErr.takeError();
+  }
 
-   object::Binary *Binary = BinaryOrErr->getBinary();
-   if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Binary)) {
-     // Get the base VMA of the section matching the type
-     auto SectionBaseOrErr = getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
-     if (!SectionBaseOrErr)
-       return SectionBaseOrErr.takeError();
+  object::Binary *Binary = BinaryOrErr->getBinary();
+  if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Binary)) {
+    // Get the base VMA of the section matching the type
+    auto SectionBaseOrErr =
+        getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
+    if (!SectionBaseOrErr)
+      return SectionBaseOrErr.takeError();
 
-     uint64_t SectionBase = *SectionBaseOrErr;
-     uint64_t SectionRelativeOffset = Offset;
+    uint64_t SectionBase = *SectionBaseOrErr;
+    uint64_t SectionRelativeOffset = Offset;
 
-     // Convert section-relative offset to absolute VMA
-     // VMA = section_base + offset
-     Offset = SectionBase + SectionRelativeOffset;
+    // Convert section-relative offset to absolute VMA
+    // VMA = section_base + offset
+    Offset = SectionBase + SectionRelativeOffset;
 
-     // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
-     // so we use absolute VMA addressing instead.
-     return object::SectionedAddress::UndefSection;
-   }
+    // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
+    // so we use absolute VMA addressing instead.
+    return object::SectionedAddress::UndefSection;
+  }
 
-   return createStringError(inconvertibleErrorCode(),
-                           "section type syntax is only supported for XCOFF objects");
- }
+  return createStringError(
+      inconvertibleErrorCode(),
+      "section type syntax is only supported for XCOFF objects");
+}
 
 static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
                           StringRef InputString, Command &Cmd,

>From aacd13abb5fc08acbcde9886d631a2225acf6fc4 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Wed, 21 Jan 2026 02:22:19 -0500
Subject: [PATCH 17/30] Fix formatting

---
 llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index bc4b4a1a807a0..e93adf09cc89c 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -177,10 +177,10 @@ parseXCOFFSectionType(StringRef TypeStr) {
 }
 
 // Find the base VMA of the unique section matching the given type for XCOFF.
-// The syntax (SECTION_TYPE)(+offset) represents an offset from the section base,
-// so we return the section's base address to compute: VMA = base + offset.
-// This function verifies there is exactly one section of the given type, as
-// multiple sections of the same type would make the address ambiguous.
+// The syntax (SECTION_TYPE)(+offset) represents an offset from the section
+// base, so we return the section's base address to compute: VMA = base +
+// offset. This function verifies there is exactly one section of the given
+// type, as multiple sections of the same type would make the address ambiguous.
 static Expected<uint64_t>
 getXCOFFSectionBaseAddress(const object::XCOFFObjectFile *XCOFFObj,
                            XCOFF::SectionTypeFlags TypeFlag) {

>From 109cd0d5d544c13f098a52f72849155f53df750b Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Mon, 23 Feb 2026 13:09:52 +0530
Subject: [PATCH 18/30] Address review comments

---
 .../llvm-symbolizer/xcoff-section-relative.ll |  51 --------
 .../xcoff-section-relative.test               |  91 +++++++++++++
 .../llvm-symbolizer/xcoff-section-syntax.test | 122 ++++++++++++++++--
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp |  78 ++++++-----
 4 files changed, 237 insertions(+), 105 deletions(-)
 delete mode 100644 llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
 create mode 100644 llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test

diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
deleted file mode 100644
index d1e21fe135e9e..0000000000000
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.ll
+++ /dev/null
@@ -1,51 +0,0 @@
-;; Test section-relative address syntax for XCOFF
-;; The syntax (SECTION_TYPE)(+offset) represents: offset from section base
-
-; REQUIRES: system-aix
-; RUN: llc -filetype=obj -o %t -mtriple=powerpc-aix-ibm-xcoff -function-sections < %s
-
-;; Test 1: Symbolize .foo using section-relative offset
-; RUN: llvm-nm --numeric-sort %t | grep " T \.foo$" | awk '{printf "CODE (TEXT)(+0x%%s)", $1}' > %t.foo_query
-; RUN: llvm-symbolizer --obj=%t @%t.foo_query | FileCheck %s --check-prefix=TEST-FOO
-
-;; Test 2: Symbolize .bar using section-relative offset
-; RUN: llvm-nm --numeric-sort %t | grep " T \.bar$" | awk '{printf "CODE (TEXT)(+0x%%s)", $1}' > %t.bar_query
-; RUN: llvm-symbolizer --obj=%t @%t.bar_query | FileCheck %s --check-prefix=TEST-BAR
-
-;; Test 3: Symbolize global_var using section-relative offset in DATA section
-; RUN: llvm-readobj --sections %t | awk '/Name: \.data/{found=1} found && /VirtualAddress:/{print $2; exit}' > %t.data_base
-; RUN: llvm-nm --numeric-sort %t | grep " D global_var$" | awk '{print $1}' > %t.global_var_vma
-; RUN: sh -c 'printf "%%d\n" $(cat %t.data_base)' > %t.data_base_dec
-; RUN: sh -c 'printf "%%d\n" 0x$(cat %t.global_var_vma)' > %t.global_var_dec
-; RUN: awk 'NR==FNR{base=$1; next} {vma=$1; printf "DATA (DATA)(+0x%%x)", vma-base}' %t.data_base_dec %t.global_var_dec > %t.data_query
-; RUN: llvm-symbolizer --obj=%t @%t.data_query | FileCheck %s --check-prefix=TEST-DATA
-
-;; Test 4: Verify section structure with llvm-readobj
-; RUN: llvm-readobj --sections %t | FileCheck %s --check-prefix=SECTIONS
-
-define void @foo() {
-entry:
-  ret void
-}
-
-define void @bar() {
-entry:
-  ret void
-}
-
- at global_var = global i32 42, align 4
-
-;; Verify correct symbolization with section-relative syntax
-; TEST-FOO: .foo
-; TEST-FOO-NEXT: ??:0:0
-
-; TEST-BAR: .bar
-; TEST-BAR-NEXT: ??:0:0
-
-; TEST-DATA: global_var
-
-;; Verify XCOFF sections exist with correct types
-; SECTIONS: Name: .text
-; SECTIONS: Type: STYP_TEXT
-; SECTIONS: Name: .data
-; SECTIONS: Type: STYP_DATA
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
new file mode 100644
index 0000000000000..6075589f62947
--- /dev/null
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
@@ -0,0 +1,91 @@
+## Test section-relative address syntax for XCOFF.
+## The syntax (SECTION_TYPE)(+offset) represents: offset from section base.
+## Only TEXT and DATA section types are supported.
+
+# REQUIRES: system-aix
+
+## Create XCOFF object with TEXT section at address 0x100 and DATA at 0x200.
+# RUN: yaml2obj %s --docnum=1 -o %t.xcoff
+
+## Test 1: Symbolize function using TEXT section-relative offset.
+## foo is at 0x100 (TEXT base) + 0x0 offset.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+0x0)' | FileCheck %s --check-prefix=TEXT-FOO
+
+# TEXT-FOO: foo
+# TEXT-FOO-NEXT: ??:0:0
+
+## Test 2: Symbolize function at offset within TEXT section.
+## bar is at 0x100 (TEXT base) + 0x4 offset = 0x104.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+0x4)' | FileCheck %s --check-prefix=TEXT-BAR
+
+# TEXT-BAR: bar
+# TEXT-BAR-NEXT: ??:0:0
+
+## Test 3: Symbolize global variable using DATA section-relative offset.
+## global_var is at 0x200 (DATA base) + 0x0 offset.
+# RUN: llvm-symbolizer --obj=%t.xcoff 'DATA (DATA)(+0x0)' | FileCheck %s --check-prefix=DATA-VAR
+
+# DATA-VAR: global_var
+
+## Test 4: Verify decimal offset works.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+4)' | FileCheck %s --check-prefix=TEXT-BAR
+
+## XCOFF object with TEXT section at 0x100 and DATA section at 0x200.
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x1DF
+Sections:
+  - Name:            .text
+    Address:         0x100
+    Flags:           [ STYP_TEXT ]
+    SectionData:     "4E8000204E800020"  # Two blr instructions (4 bytes each)
+  - Name:            .data
+    Address:         0x200
+    Flags:           [ STYP_DATA ]
+    SectionData:     "0000002A"  # 32-bit value 42
+Symbols:
+  - Name:            .foo
+    Value:           0x100
+    Section:         .text
+    StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_LD
+        StorageMappingClass:  XMC_PR
+  - Name:            foo
+    Value:           0x100
+    Section:         .text
+    StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_PR
+  - Name:            .bar
+    Value:           0x104
+    Section:         .text
+    StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_LD
+        StorageMappingClass:  XMC_PR
+  - Name:            bar
+    Value:           0x104
+    Section:         .text
+    StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_PR
+  - Name:            global_var
+    Value:           0x200
+    Section:         .data
+    StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_RW
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index 2465d1ec738fc..83917a82b961d 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -1,31 +1,125 @@
-## Test section-relative address syntax parsing for XCOFF
+## Test section-relative address syntax parsing and error handling for XCOFF.
 ## This tests that the (SECTION_TYPE)(+offset) syntax produces appropriate
-## error messages for invalid syntax
+## error messages for invalid inputs.
 
 # REQUIRES: system-aix
 
-## Create a simple XCOFF object for testing
-# RUN: echo "define void @test() { ret void }" | \
-# RUN:   llc -filetype=obj -mtriple=powerpc-aix-ibm-xcoff -o %t.o
+## Create a simple XCOFF object for testing.
+# RUN: yaml2obj %s --docnum=1 -o %t.xcoff
 
-## Test invalid section type
-# RUN: llvm-symbolizer --obj=%t.o '(INVALID)(+0x10)' 2>&1 | \
+## Test invalid/unsupported section type.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(INVALID)(+0x10)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=INVALID-TYPE
 
-## Test missing '+' sign
-# RUN: llvm-symbolizer --obj=%t.o '(TEXT)(0x10)' 2>&1 | \
+## Test unsupported section type (BSS is not supported).
+# RUN: llvm-symbolizer --obj=%t.xcoff '(BSS)(+0x10)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=INVALID-TYPE
+
+## Test missing '+' sign.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(0x10)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=NO-PLUS
 
-## Test invalid offset value (not a hex number)
-# RUN: llvm-symbolizer --obj=%t.o '(TEXT)(+abc)' 2>&1 | \
+## Test invalid offset value.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+xyz)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=INVALID-OFFSET
 
-## Test empty section type
-# RUN: llvm-symbolizer --obj=%t.o '()(+0x10)' 2>&1 | \
+## Test empty section type.
+# RUN: llvm-symbolizer --obj=%t.xcoff '()(+0x10)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=EMPTY-SECTION
 
-## Verify error messages are helpful
 # INVALID-TYPE: unknown or unsupported section type
 # NO-PLUS: section-relative offset must start with '+'
 # INVALID-OFFSET: invalid offset in section-relative address
 # EMPTY-SECTION: unknown section type: empty section type
+
+## Test error: section type not found (DATA section doesn't exist).
+# RUN: yaml2obj %s --docnum=2 -o %t.nodata.xcoff
+# RUN: llvm-symbolizer --obj=%t.nodata.xcoff '(DATA)(+0x0)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=NO-SECTION
+
+# NO-SECTION: section type not found in XCOFF object
+
+## Test error: multiple sections of same type.
+# RUN: yaml2obj %s --docnum=3 -o %t.multi.xcoff
+# RUN: llvm-symbolizer --obj=%t.multi.xcoff '(TEXT)(+0x0)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=MULTI-SECTION
+
+# MULTI-SECTION: multiple sections of the same type found in XCOFF object
+
+## Test error: section type syntax on non-XCOFF object.
+# RUN: yaml2obj %s --docnum=4 -o %t.elf
+# RUN: llvm-symbolizer --obj=%t.elf '(TEXT)(+0x0)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=NON-XCOFF
+
+# NON-XCOFF: section type syntax is only supported for XCOFF objects
+
+## Document 1: Basic XCOFF object with TEXT and DATA sections.
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x1DF
+Sections:
+  - Name:    .text
+    Address: 0x100
+    Flags:   [ STYP_TEXT ]
+    SectionData: "4E800020"
+  - Name:    .data
+    Address: 0x200
+    Flags:   [ STYP_DATA ]
+    SectionData: "00000000"
+Symbols:
+  - Name:            foo
+    Value:           0x100
+    Section:         .text
+    StorageClass:    C_EXT
+
+## Document 2: XCOFF object with only TEXT section (no DATA).
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x1DF
+Sections:
+  - Name:    .text
+    Address: 0x100
+    Flags:   [ STYP_TEXT ]
+    SectionData: "4E800020"
+Symbols:
+  - Name:            foo
+    Value:           0x100
+    Section:         .text
+    StorageClass:    C_EXT
+
+## Document 3: XCOFF object with multiple TEXT sections.
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x1DF
+Sections:
+  - Name:    .text
+    Address: 0x100
+    Flags:   [ STYP_TEXT ]
+    SectionData: "4E800020"
+  - Name:    .text2
+    Address: 0x200
+    Flags:   [ STYP_TEXT ]
+    SectionData: "4E800020"
+Symbols:
+  - Name:            foo
+    Value:           0x100
+    Section:         .text
+    StorageClass:    C_EXT
+
+## Document 4: ELF object (non-XCOFF) for testing error case.
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address: 0x1000
+    Content: "C3"
+Symbols:
+  - Name:    foo
+    Section: .text
+    Value:   0x1000
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index e93adf09cc89c..3abd1562bcbb3 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -186,22 +186,20 @@ getXCOFFSectionBaseAddress(const object::XCOFFObjectFile *XCOFFObj,
                            XCOFF::SectionTypeFlags TypeFlag) {
   std::optional<uint64_t> SectionBase;
 
-  for (const auto &Section : XCOFFObj->sections()) {
+  for (const object::SectionRef &Section : XCOFFObj->sections()) {
     DataRefImpl SecRef = Section.getRawDataRefImpl();
     int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
 
     if ((Flags & 0xFFFF) == TypeFlag) {
       if (SectionBase)
         return createStringError(
-            inconvertibleErrorCode(),
             "multiple sections of the same type found in XCOFF object");
       SectionBase = Section.getAddress();
     }
   }
 
   if (!SectionBase)
-    return createStringError(inconvertibleErrorCode(),
-                             "section type not found in XCOFF object");
+    return createStringError("section type not found in XCOFF object");
 
   return *SectionBase;
 }
@@ -211,47 +209,47 @@ static Expected<uint64_t> validateSectionType(StringRef ModulePath,
                                               uint64_t &Offset,
                                               LLVMSymbolizer &Symbolizer) {
   // Parse the section type string
-  auto SectionTypeFlag = parseXCOFFSectionType(SectionType);
-  if (!SectionTypeFlag) {
-    return createStringError(inconvertibleErrorCode(),
-                             "unknown or unsupported section type: " +
-                                 SectionType.str());
-  }
-
-  // Get the module info to access the object file
-  auto ModuleOrErr = Symbolizer.getOrCreateModuleInfo(ModulePath);
-  if (!ModuleOrErr) {
+  std::optional<XCOFF::SectionTypeFlags> SectionTypeFlag =
+      parseXCOFFSectionType(SectionType);
+  if (!SectionTypeFlag)
+    return createStringError("unknown or unsupported section type: " +
+                             SectionType.str());
+
+  // Get the module info to verify the module exists and is valid.
+  Expected<SymbolizableModule *> ModuleOrErr =
+      Symbolizer.getOrCreateModuleInfo(ModulePath);
+  if (!ModuleOrErr)
     return ModuleOrErr.takeError();
-  }
 
-  auto BinaryOrErr = object::createBinary(ModulePath);
-  if (!BinaryOrErr) {
+  // TODO: Consider caching the binary to avoid re-opening for each address.
+  Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
+      object::createBinary(ModulePath);
+  if (!BinaryOrErr)
     return BinaryOrErr.takeError();
-  }
 
   object::Binary *Binary = BinaryOrErr->getBinary();
-  if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Binary)) {
-    // Get the base VMA of the section matching the type
-    auto SectionBaseOrErr =
-        getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
-    if (!SectionBaseOrErr)
-      return SectionBaseOrErr.takeError();
-
-    uint64_t SectionBase = *SectionBaseOrErr;
-    uint64_t SectionRelativeOffset = Offset;
-
-    // Convert section-relative offset to absolute VMA
-    // VMA = section_base + offset
-    Offset = SectionBase + SectionRelativeOffset;
-
-    // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
-    // so we use absolute VMA addressing instead.
-    return object::SectionedAddress::UndefSection;
-  }
-
-  return createStringError(
-      inconvertibleErrorCode(),
-      "section type syntax is only supported for XCOFF objects");
+  const object::XCOFFObjectFile *XCOFFObj =
+      dyn_cast<object::XCOFFObjectFile>(Binary);
+  if (!XCOFFObj)
+    return createStringError(
+        "section type syntax is only supported for XCOFF objects");
+
+  // Get the base VMA of the section matching the type
+  Expected<uint64_t> SectionBaseOrErr =
+      getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
+  if (!SectionBaseOrErr)
+    return SectionBaseOrErr.takeError();
+
+  uint64_t SectionBase = *SectionBaseOrErr;
+  uint64_t SectionRelativeOffset = Offset;
+
+  // Convert section-relative offset to absolute VMA
+  // VMA = section_base + offset
+  Offset = SectionBase + SectionRelativeOffset;
+
+  // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
+  // so we use absolute VMA addressing instead.
+  return object::SectionedAddress::UndefSection;
 }
 
 static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,

>From f1a12d382471e5ad54f7b6a5852b707322c9a57e Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Mon, 23 Feb 2026 15:07:23 +0530
Subject: [PATCH 19/30] Address review comments

---
 .../llvm-symbolizer/xcoff-section-syntax.test     | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index 83917a82b961d..05010f21d8f89 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -71,6 +71,11 @@ Symbols:
     Value:           0x100
     Section:         .text
     StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_PR
 
 ## Document 2: XCOFF object with only TEXT section (no DATA).
 --- !XCOFF
@@ -86,6 +91,11 @@ Symbols:
     Value:           0x100
     Section:         .text
     StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_PR
 
 ## Document 3: XCOFF object with multiple TEXT sections.
 --- !XCOFF
@@ -105,6 +115,11 @@ Symbols:
     Value:           0x100
     Section:         .text
     StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_PR
 
 ## Document 4: ELF object (non-XCOFF) for testing error case.
 --- !ELF

>From 510f588a9c1f547171068dc3cb4f99d548615280 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Mon, 23 Feb 2026 19:39:24 +0530
Subject: [PATCH 20/30] Address review comments

---
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 24 ++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 3abd1562bcbb3..6e9029df6fbd3 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -48,11 +48,17 @@
 #include <cstdio>
 #include <cstring>
 #include <iostream>
+#include <map>
 #include <string>
 
 using namespace llvm;
 using namespace symbolize;
 
+// Cache for XCOFF section base addresses to avoid re-opening binaries.
+// Key: (ModulePath, SectionTypeFlag), Value: SectionBaseAddress
+static std::map<std::pair<std::string, XCOFF::SectionTypeFlags>, uint64_t>
+    XCOFFSectionBaseCache;
+
 namespace {
 enum ID {
   OPT_INVALID = 0, // This is not an option ID.
@@ -221,7 +227,17 @@ static Expected<uint64_t> validateSectionType(StringRef ModulePath,
   if (!ModuleOrErr)
     return ModuleOrErr.takeError();
 
-  // TODO: Consider caching the binary to avoid re-opening for each address.
+  // Check cache for section base address.
+  std::pair<std::string, XCOFF::SectionTypeFlags> CacheKey =
+      std::make_pair(ModulePath.str(), *SectionTypeFlag);
+  std::map<std::pair<std::string, XCOFF::SectionTypeFlags>,
+           uint64_t>::iterator CacheIt = XCOFFSectionBaseCache.find(CacheKey);
+  if (CacheIt != XCOFFSectionBaseCache.end()) {
+    Offset = CacheIt->second + Offset;
+    return object::SectionedAddress::UndefSection;
+  }
+
+  // Not in cache - open binary and compute section base.
   Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
       object::createBinary(ModulePath);
   if (!BinaryOrErr)
@@ -241,11 +257,13 @@ static Expected<uint64_t> validateSectionType(StringRef ModulePath,
     return SectionBaseOrErr.takeError();
 
   uint64_t SectionBase = *SectionBaseOrErr;
-  uint64_t SectionRelativeOffset = Offset;
+
+  // Cache the section base for future lookups.
+  XCOFFSectionBaseCache[CacheKey] = SectionBase;
 
   // Convert section-relative offset to absolute VMA
   // VMA = section_base + offset
-  Offset = SectionBase + SectionRelativeOffset;
+  Offset = SectionBase + Offset;
 
   // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
   // so we use absolute VMA addressing instead.

>From 9763bb5fcbd894e7aa52469ae44eceea2e138bad Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Mon, 23 Feb 2026 05:24:20 -0500
Subject: [PATCH 21/30] Address review comments

---
 llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 6e9029df6fbd3..48520e7c9b18d 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -1,5 +1,4 @@
-//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer
-//------------===//
+//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

>From c540d9d5556d625a28e928620b182e7c3fb88646 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Mon, 23 Feb 2026 09:19:42 -0500
Subject: [PATCH 22/30] Fix formatting

---
 llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 48520e7c9b18d..b268858108d55 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -229,8 +229,7 @@ static Expected<uint64_t> validateSectionType(StringRef ModulePath,
   // Check cache for section base address.
   std::pair<std::string, XCOFF::SectionTypeFlags> CacheKey =
       std::make_pair(ModulePath.str(), *SectionTypeFlag);
-  std::map<std::pair<std::string, XCOFF::SectionTypeFlags>,
-           uint64_t>::iterator CacheIt = XCOFFSectionBaseCache.find(CacheKey);
+  std::map<std::pair<std::string, XCOFF::SectionTypeFlags>, uint64_t>::iterator CacheIt = XCOFFSectionBaseCache.find(CacheKey);
   if (CacheIt != XCOFFSectionBaseCache.end()) {
     Offset = CacheIt->second + Offset;
     return object::SectionedAddress::UndefSection;

>From 804e92a18a468364a98198bd34e9b35a4734ad06 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhuensh.p at ibm.com>
Date: Mon, 23 Feb 2026 09:19:42 -0500
Subject: [PATCH 23/30] Fix formatting

---
 llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index b268858108d55..2aa4b5e6d3af2 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -229,7 +229,8 @@ static Expected<uint64_t> validateSectionType(StringRef ModulePath,
   // Check cache for section base address.
   std::pair<std::string, XCOFF::SectionTypeFlags> CacheKey =
       std::make_pair(ModulePath.str(), *SectionTypeFlag);
-  std::map<std::pair<std::string, XCOFF::SectionTypeFlags>, uint64_t>::iterator CacheIt = XCOFFSectionBaseCache.find(CacheKey);
+  std::map<std::pair<std::string, XCOFF::SectionTypeFlags>, uint64_t>::iterator
+      CacheIt = XCOFFSectionBaseCache.find(CacheKey);
   if (CacheIt != XCOFFSectionBaseCache.end()) {
     Offset = CacheIt->second + Offset;
     return object::SectionedAddress::UndefSection;

>From 6a995ed670a0335b32a7227346247721a7d95981 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Wed, 11 Mar 2026 13:08:03 +0530
Subject: [PATCH 24/30] Address review comments

---
 .../llvm/DebugInfo/Symbolize/Symbolize.h      |  17 ++
 llvm/lib/DebugInfo/Symbolize/Symbolize.cpp    |  42 ++++
 .../xcoff-section-relative.test               |  56 ++---
 .../llvm-symbolizer/xcoff-section-syntax.test | 118 ++++++-----
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 196 ++++++------------
 5 files changed, 220 insertions(+), 209 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
index 4fd7462d52ceb..6dae683d987e3 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
@@ -17,6 +17,7 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/ilist_node.h"
 #include "llvm/ADT/simple_ilist.h"
+#include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/DebugInfo/DIContext.h"
 #include "llvm/Object/Binary.h"
 #include "llvm/Object/BuildID.h"
@@ -133,6 +134,17 @@ class LLVMSymbolizer {
     BIDFetcher = std::move(Fetcher);
   }
 
+  /// For an XCOFF object at ModuleName, find the base address of the unique
+  /// section matching SectionTypeFlag. Returns an error if the object cannot
+  /// be opened, is not XCOFF, has no matching section, or has multiple matching
+  /// sections (which would make a section-relative address ambiguous).
+  /// SectionTypeName is the name (e.g. "TEXT") used in error
+  /// messages to identify which section type was not found or was ambiguous.
+  LLVM_ABI Expected<uint64_t>
+  getXCOFFSectionAddress(StringRef ModuleName,
+                         XCOFF::SectionTypeFlags SectionTypeFlag,
+                         StringRef SectionTypeName);
+
   /// Returns a SymbolizableModule or an error if loading debug info failed.
   /// Only one attempt is made to load a module, and errors during loading are
   /// only reported once. Subsequent calls to get module info for a module that
@@ -262,6 +274,11 @@ class LLVMSymbolizer {
   Options Opts;
 
   std::unique_ptr<BuildIDFetcher> BIDFetcher;
+
+  /// Cache for XCOFF section base addresses: (ModulePath, SectionTypeFlag) ->
+  /// base VMA.
+  std::map<std::pair<std::string, XCOFF::SectionTypeFlags>, uint64_t>
+      XCOFFSectionBaseCache;
 };
 
 // A binary intrusively linked into a LRU cache list. If the binary is empty,
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index 3821f53d26b98..2f7c07e704da7 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -27,6 +27,7 @@
 #include "llvm/Object/ELFObjectFile.h"
 #include "llvm/Object/MachO.h"
 #include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/XCOFFObjectFile.h"
 #include "llvm/Support/CRC.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/DataExtractor.h"
@@ -51,6 +52,47 @@ LLVMSymbolizer::LLVMSymbolizer(const Options &Opts)
 
 LLVMSymbolizer::~LLVMSymbolizer() = default;
 
+Expected<uint64_t>
+LLVMSymbolizer::getXCOFFSectionAddress(StringRef ModuleName,
+                                        XCOFF::SectionTypeFlags SectionTypeFlag,
+                                        StringRef SectionTypeName) {
+  // Check the cache first.
+  auto CacheKey = std::make_pair(ModuleName.str(), SectionTypeFlag);
+  auto It = XCOFFSectionBaseCache.find(CacheKey);
+  if (It != XCOFFSectionBaseCache.end())
+    return It->second;
+
+  Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
+      object::createBinary(ModuleName);
+  if (!BinaryOrErr)
+    return BinaryOrErr.takeError();
+
+  const auto *XCOFFObj =
+      dyn_cast<object::XCOFFObjectFile>(BinaryOrErr->getBinary());
+  if (!XCOFFObj)
+    return createStringError(
+        "section type syntax is only supported for XCOFF objects");
+
+  std::optional<uint64_t> SectionBase;
+  for (const object::SectionRef &Section : XCOFFObj->sections()) {
+    DataRefImpl SecRef = Section.getRawDataRefImpl();
+    int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
+    if ((Flags & 0xFFFF) != SectionTypeFlag)
+      continue;
+    if (SectionBase)
+      return createStringError("multiple '" + SectionTypeName +
+                               "' sections found in XCOFF object");
+    SectionBase = Section.getAddress();
+  }
+
+  if (!SectionBase)
+    return createStringError("no '" + SectionTypeName +
+                             "' section found in XCOFF object");
+
+  XCOFFSectionBaseCache.emplace(CacheKey, *SectionBase);
+  return *SectionBase;
+}
+
 template <typename T>
 Expected<DILineInfo>
 LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier,
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
index 6075589f62947..aa7979152ae07 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
@@ -1,33 +1,37 @@
 ## Test section-relative address syntax for XCOFF.
-## The syntax (SECTION_TYPE)(+offset) represents: offset from section base.
+## The syntax (SECTION_TYPE)(+offset) represents the offset from section base.
 ## Only TEXT and DATA section types are supported.
 
-# REQUIRES: system-aix
-
 ## Create XCOFF object with TEXT section at address 0x100 and DATA at 0x200.
 # RUN: yaml2obj %s --docnum=1 -o %t.xcoff
 
 ## Test 1: Symbolize function using TEXT section-relative offset.
-## foo is at 0x100 (TEXT base) + 0x0 offset.
+## .foo is at 0x100 (TEXT base) + 0x0 offset.
 # RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+0x0)' | FileCheck %s --check-prefix=TEXT-FOO
 
-# TEXT-FOO: foo
+# TEXT-FOO: .foo
 # TEXT-FOO-NEXT: ??:0:0
 
 ## Test 2: Symbolize function at offset within TEXT section.
-## bar is at 0x100 (TEXT base) + 0x4 offset = 0x104.
+## .bar is at 0x100 (TEXT base) + 0x4 offset = 0x104.
 # RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+0x4)' | FileCheck %s --check-prefix=TEXT-BAR
 
-# TEXT-BAR: bar
+# TEXT-BAR: .bar
 # TEXT-BAR-NEXT: ??:0:0
 
-## Test 3: Symbolize global variable using DATA section-relative offset.
-## global_var is at 0x200 (DATA base) + 0x0 offset.
-# RUN: llvm-symbolizer --obj=%t.xcoff 'DATA (DATA)(+0x0)' | FileCheck %s --check-prefix=DATA-VAR
+## Test 3: Symbolize global constant using TEXT section-relative offset.
+## .my_const is at 0x100 (TEXT base) + 0x8 offset = 0x108 (XMC_RO data in text).
+# RUN: llvm-symbolizer --obj=%t.xcoff 'DATA (TEXT)(+0x8)' | FileCheck %s --check-prefix=TEXT-CONST
+
+# TEXT-CONST: .my_const
+
+## Test 4: Symbolize global variable using DATA section-relative offset.
+## global_var is at 0x200 (DATA base) + 0x4 offset = 0x204.
+# RUN: llvm-symbolizer --obj=%t.xcoff 'DATA (DATA)(+0x4)' | FileCheck %s --check-prefix=DATA-VAR
 
 # DATA-VAR: global_var
 
-## Test 4: Verify decimal offset works.
+## Test 5: Verify decimal offset works.
 # RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+4)' | FileCheck %s --check-prefix=TEXT-BAR
 
 ## XCOFF object with TEXT section at 0x100 and DATA section at 0x200.
@@ -38,22 +42,17 @@ Sections:
   - Name:            .text
     Address:         0x100
     Flags:           [ STYP_TEXT ]
-    SectionData:     "4E8000204E800020"  # Two blr instructions (4 bytes each)
+    # Two blr instructions (4 bytes each) at 0x100 and 0x104, then 4 bytes of
+    # read-only constant data (.my_const) at 0x108.
+    SectionData:     "4E8000204E8000200000002A"
   - Name:            .data
     Address:         0x200
     Flags:           [ STYP_DATA ]
-    SectionData:     "0000002A"  # 32-bit value 42
+    # 4 bytes of padding then global_var at 0x204.
+    SectionData:     "000000000000002A"
 Symbols:
+  # .foo csect (XTY_SD): the function itself, as produced by -ffunction-sections.
   - Name:            .foo
-    Value:           0x100
-    Section:         .text
-    StorageClass:    C_EXT
-    NumberOfAuxEntries: 1
-    AuxEntries:
-      - Type:                 AUX_CSECT
-        SymbolType:           XTY_LD
-        StorageMappingClass:  XMC_PR
-  - Name:            foo
     Value:           0x100
     Section:         .text
     StorageClass:    C_EXT
@@ -62,6 +61,7 @@ Symbols:
       - Type:                 AUX_CSECT
         SymbolType:           XTY_SD
         StorageMappingClass:  XMC_PR
+  # .bar csect (XTY_SD): second function in its own csect.
   - Name:            .bar
     Value:           0x104
     Section:         .text
@@ -69,19 +69,21 @@ Symbols:
     NumberOfAuxEntries: 1
     AuxEntries:
       - Type:                 AUX_CSECT
-        SymbolType:           XTY_LD
+        SymbolType:           XTY_SD
         StorageMappingClass:  XMC_PR
-  - Name:            bar
-    Value:           0x104
+  # .my_const csect (XTY_SD, XMC_RO): read-only constant in TEXT section.
+  - Name:            .my_const
+    Value:           0x108
     Section:         .text
     StorageClass:    C_EXT
     NumberOfAuxEntries: 1
     AuxEntries:
       - Type:                 AUX_CSECT
         SymbolType:           XTY_SD
-        StorageMappingClass:  XMC_PR
+        StorageMappingClass:  XMC_RO
+  # global_var csect at DATA+0x4 (non-zero offset to show DATA offsets work).
   - Name:            global_var
-    Value:           0x200
+    Value:           0x204
     Section:         .data
     StorageClass:    C_EXT
     NumberOfAuxEntries: 1
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index 05010f21d8f89..4d9aafc1395d2 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -2,58 +2,101 @@
 ## This tests that the (SECTION_TYPE)(+offset) syntax produces appropriate
 ## error messages for invalid inputs.
 
-# REQUIRES: system-aix
-
 ## Create a simple XCOFF object for testing.
 # RUN: yaml2obj %s --docnum=1 -o %t.xcoff
 
-## Test invalid/unsupported section type.
+## Test invalid section type.
 # RUN: llvm-symbolizer --obj=%t.xcoff '(INVALID)(+0x10)' 2>&1 | \
-# RUN:   FileCheck %s --check-prefix=INVALID-TYPE
+# RUN:   FileCheck %s -DTYPE=INVALID --check-prefix=INVALID-TYPE
 
 ## Test unsupported section type (BSS is not supported).
 # RUN: llvm-symbolizer --obj=%t.xcoff '(BSS)(+0x10)' 2>&1 | \
-# RUN:   FileCheck %s --check-prefix=INVALID-TYPE
+# RUN:   FileCheck %s -DTYPE=BSS --check-prefix=INVALID-TYPE
+
+## Test invalid section type containing a dash.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(-)(+0x10)' 2>&1 | \
+# RUN:   FileCheck %s -DTYPE=- --check-prefix=INVALID-TYPE
+
+# INVALID-TYPE: error: '([[TYPE]])(+0x10)': unknown or unsupported section type "[[TYPE]]" in section-relative address
 
 ## Test missing '+' sign.
 # RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(0x10)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=NO-PLUS
 
+# NO-PLUS: error: '(TEXT)(0x10)': section-relative offset "0x10" must start with '+'
+
+## Test empty offset value.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)()' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=EMPTY-OFFSET
+
+# EMPTY-OFFSET: error: '(TEXT)()': section-relative offset "" must start with '+'
+
+## Test invalid offset: decimal digits followed by non-decimal hex characters,
+## e.g. 123abc. getAsInteger with base 0 requires the whole string to be valid,
+## so this is rejected.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+123abc)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=INVALID-OFFSET-HEXSUFFIX
+
+# INVALID-OFFSET-HEXSUFFIX: error: '(TEXT)(+123abc)': invalid offset "+123abc" in section-relative address
+
+## Test invalid offset: hex prefix 'x' without leading '0', e.g. xabc.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+xabc)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=INVALID-OFFSET-MISSINGZERO
+
+# INVALID-OFFSET-MISSINGZERO: error: '(TEXT)(+xabc)': invalid offset "+xabc" in section-relative address
+
+## Test invalid offset: hex value with non-hex letter, e.g. 0xdefg.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+0xdefg)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=INVALID-OFFSET-NONHEX
+
+# INVALID-OFFSET-NONHEX: error: '(TEXT)(+0xdefg)': invalid offset "+0xdefg" in section-relative address
+
+## Test that a leading-zero value (0123) is treated as octal (decimal 83) by
+## getAsInteger(0,...), not as decimal 123. The resolved address TEXT_BASE +
+## 83 = 0x153 has no symbol, so the output shows "??".
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+0123)' | \
+# RUN:   FileCheck %s --check-prefix=OCTAL
+
+# OCTAL: ??
+
 ## Test invalid offset value.
 # RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+xyz)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=INVALID-OFFSET
 
+# INVALID-OFFSET: error: '(TEXT)(+xyz)': invalid offset "+xyz" in section-relative address
+
 ## Test empty section type.
 # RUN: llvm-symbolizer --obj=%t.xcoff '()(+0x10)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=EMPTY-SECTION
 
-# INVALID-TYPE: unknown or unsupported section type
-# NO-PLUS: section-relative offset must start with '+'
-# INVALID-OFFSET: invalid offset in section-relative address
-# EMPTY-SECTION: unknown section type: empty section type
+# EMPTY-SECTION: error: '()(+0x10)': empty section type in section-relative address
 
 ## Test error: section type not found (DATA section doesn't exist).
 # RUN: yaml2obj %s --docnum=2 -o %t.nodata.xcoff
 # RUN: llvm-symbolizer --obj=%t.nodata.xcoff '(DATA)(+0x0)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=NO-SECTION
 
-# NO-SECTION: section type not found in XCOFF object
+# NO-SECTION: error: '(DATA)(+0x0)': no 'DATA' section found in XCOFF object
 
-## Test error: multiple sections of same type.
-# RUN: yaml2obj %s --docnum=3 -o %t.multi.xcoff
+## Test error: multiple sections of the same type.
+## Reuse Document 1 with -D SECT2_FLAGS=STYP_TEXT to add a second TEXT section.
+# RUN: yaml2obj %s --docnum=1 -D SECT2_FLAGS=STYP_TEXT -o %t.multi.xcoff
 # RUN: llvm-symbolizer --obj=%t.multi.xcoff '(TEXT)(+0x0)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=MULTI-SECTION
 
-# MULTI-SECTION: multiple sections of the same type found in XCOFF object
+# MULTI-SECTION: error: '(TEXT)(+0x0)': multiple 'TEXT' sections found in XCOFF object
 
-## Test error: section type syntax on non-XCOFF object.
-# RUN: yaml2obj %s --docnum=4 -o %t.elf
+## Test error: section type syntax with non-XCOFF object.
+# RUN: yaml2obj %s --docnum=3 -o %t.elf
 # RUN: llvm-symbolizer --obj=%t.elf '(TEXT)(+0x0)' 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=NON-XCOFF
 
-# NON-XCOFF: section type syntax is only supported for XCOFF objects
+# NON-XCOFF: error: '(TEXT)(+0x0)': section type syntax is only supported for XCOFF objects
 
-## Document 1: Basic XCOFF object with TEXT and DATA sections.
+## Document 1: Basic XCOFF object with TEXT and DATA sections, plus an optional
+## extra section whose type is controlled by [[SECT2_FLAGS]] (default: STYP_INFO).
+## Pass -D SECT2_FLAGS=STYP_TEXT when building to create a second TEXT section,
+## which triggers the "multiple sections" error.
 --- !XCOFF
 FileHeader:
   MagicNumber: 0x1DF
@@ -66,8 +109,12 @@ Sections:
     Address: 0x200
     Flags:   [ STYP_DATA ]
     SectionData: "00000000"
+  - Name:    .extra
+    Address: 0x300
+    Flags:   [ [[SECT2_FLAGS=STYP_INFO]] ]
+    SectionData: "00000000"
 Symbols:
-  - Name:            foo
+  - Name:            .foo
     Value:           0x100
     Section:         .text
     StorageClass:    C_EXT
@@ -87,31 +134,7 @@ Sections:
     Flags:   [ STYP_TEXT ]
     SectionData: "4E800020"
 Symbols:
-  - Name:            foo
-    Value:           0x100
-    Section:         .text
-    StorageClass:    C_EXT
-    NumberOfAuxEntries: 1
-    AuxEntries:
-      - Type:                 AUX_CSECT
-        SymbolType:           XTY_SD
-        StorageMappingClass:  XMC_PR
-
-## Document 3: XCOFF object with multiple TEXT sections.
---- !XCOFF
-FileHeader:
-  MagicNumber: 0x1DF
-Sections:
-  - Name:    .text
-    Address: 0x100
-    Flags:   [ STYP_TEXT ]
-    SectionData: "4E800020"
-  - Name:    .text2
-    Address: 0x200
-    Flags:   [ STYP_TEXT ]
-    SectionData: "4E800020"
-Symbols:
-  - Name:            foo
+  - Name:            .foo
     Value:           0x100
     Section:         .text
     StorageClass:    C_EXT
@@ -121,20 +144,13 @@ Symbols:
         SymbolType:           XTY_SD
         StorageMappingClass:  XMC_PR
 
-## Document 4: ELF object (non-XCOFF) for testing error case.
+## Document 3: ELF object (non-XCOFF) for testing the format-check error.
 --- !ELF
 FileHeader:
   Class:   ELFCLASS64
   Data:    ELFDATA2LSB
   Type:    ET_EXEC
-  Machine: EM_X86_64
 Sections:
   - Name:    .text
     Type:    SHT_PROGBITS
-    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
-    Address: 0x1000
     Content: "C3"
-Symbols:
-  - Name:    foo
-    Section: .text
-    Value:   0x1000
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 2aa4b5e6d3af2..0ab5bd7fa2d7a 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -25,11 +25,9 @@
 #include "llvm/DebugInfo/Symbolize/MarkupFilter.h"
 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
-#include "llvm/Object/XCOFFObjectFile.h"
 #include "llvm/Debuginfod/BuildIDFetcher.h"
 #include "llvm/Debuginfod/Debuginfod.h"
 #include "llvm/Debuginfod/HTTPClient.h"
-#include "llvm/Object/XCOFFObjectFile.h"
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/Option.h"
@@ -46,18 +44,11 @@
 #include <algorithm>
 #include <cstdio>
 #include <cstring>
-#include <iostream>
-#include <map>
 #include <string>
 
 using namespace llvm;
 using namespace symbolize;
 
-// Cache for XCOFF section base addresses to avoid re-opening binaries.
-// Key: (ModulePath, SectionTypeFlag), Value: SectionBaseAddress
-static std::map<std::pair<std::string, XCOFF::SectionTypeFlags>, uint64_t>
-    XCOFFSectionBaseCache;
-
 namespace {
 enum ID {
   OPT_INVALID = 0, // This is not an option ID.
@@ -167,10 +158,10 @@ static Error makeStringError(StringRef Msg) {
   return make_error<StringError>(Msg, inconvertibleErrorCode());
 }
 
-// Helper function to get XCOFF section type flag from string.
-// Only TEXT and DATA are supported since:
+// Only TEXT and DATA section types are supported in XCOFF section-relative
+// syntax since:
 // - These are the only sections mapped by the AIX process map (procmap).
-// - BSS addresses are relative to DATA section base.
+// - BSS addresses are relative to the DATA section base.
 // - Thread-local sections (TDATA, TBSS) cannot be symbolized from runtime
 //   addresses.
 static std::optional<XCOFF::SectionTypeFlags>
@@ -181,92 +172,27 @@ parseXCOFFSectionType(StringRef TypeStr) {
       .Default(std::nullopt);
 }
 
-// Find the base VMA of the unique section matching the given type for XCOFF.
-// The syntax (SECTION_TYPE)(+offset) represents an offset from the section
-// base, so we return the section's base address to compute: VMA = base +
-// offset. This function verifies there is exactly one section of the given
-// type, as multiple sections of the same type would make the address ambiguous.
+// Resolve a section-relative address of the form (SECTION_TYPE)(+offset) to an
+// absolute VMA for symbolization. Looks up the base address of the unique
+// section of the given type in the XCOFF object at ModulePath, then returns
+// SectionBase + Offset as the absolute VMA.
 static Expected<uint64_t>
-getXCOFFSectionBaseAddress(const object::XCOFFObjectFile *XCOFFObj,
-                           XCOFF::SectionTypeFlags TypeFlag) {
-  std::optional<uint64_t> SectionBase;
-
-  for (const object::SectionRef &Section : XCOFFObj->sections()) {
-    DataRefImpl SecRef = Section.getRawDataRefImpl();
-    int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
-
-    if ((Flags & 0xFFFF) == TypeFlag) {
-      if (SectionBase)
-        return createStringError(
-            "multiple sections of the same type found in XCOFF object");
-      SectionBase = Section.getAddress();
-    }
-  }
-
-  if (!SectionBase)
-    return createStringError("section type not found in XCOFF object");
-
-  return *SectionBase;
-}
-
-static Expected<uint64_t> validateSectionType(StringRef ModulePath,
-                                              StringRef SectionType,
-                                              uint64_t &Offset,
-                                              LLVMSymbolizer &Symbolizer) {
-  // Parse the section type string
+resolveXCOFFSectionAddress(StringRef ModulePath, StringRef SectionType,
+                           uint64_t Offset, LLVMSymbolizer &Symbolizer) {
   std::optional<XCOFF::SectionTypeFlags> SectionTypeFlag =
       parseXCOFFSectionType(SectionType);
   if (!SectionTypeFlag)
-    return createStringError("unknown or unsupported section type: " +
-                             SectionType.str());
-
-  // Get the module info to verify the module exists and is valid.
-  Expected<SymbolizableModule *> ModuleOrErr =
-      Symbolizer.getOrCreateModuleInfo(ModulePath);
-  if (!ModuleOrErr)
-    return ModuleOrErr.takeError();
-
-  // Check cache for section base address.
-  std::pair<std::string, XCOFF::SectionTypeFlags> CacheKey =
-      std::make_pair(ModulePath.str(), *SectionTypeFlag);
-  std::map<std::pair<std::string, XCOFF::SectionTypeFlags>, uint64_t>::iterator
-      CacheIt = XCOFFSectionBaseCache.find(CacheKey);
-  if (CacheIt != XCOFFSectionBaseCache.end()) {
-    Offset = CacheIt->second + Offset;
-    return object::SectionedAddress::UndefSection;
-  }
-
-  // Not in cache - open binary and compute section base.
-  Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
-      object::createBinary(ModulePath);
-  if (!BinaryOrErr)
-    return BinaryOrErr.takeError();
+    return createStringError("unknown or unsupported section type \"" +
+                             SectionType.str() +
+                             "\" in section-relative address");
 
-  object::Binary *Binary = BinaryOrErr->getBinary();
-  const object::XCOFFObjectFile *XCOFFObj =
-      dyn_cast<object::XCOFFObjectFile>(Binary);
-  if (!XCOFFObj)
-    return createStringError(
-        "section type syntax is only supported for XCOFF objects");
-
-  // Get the base VMA of the section matching the type
   Expected<uint64_t> SectionBaseOrErr =
-      getXCOFFSectionBaseAddress(XCOFFObj, *SectionTypeFlag);
+      Symbolizer.getXCOFFSectionAddress(ModulePath, *SectionTypeFlag,
+                                        SectionType);
   if (!SectionBaseOrErr)
     return SectionBaseOrErr.takeError();
 
-  uint64_t SectionBase = *SectionBaseOrErr;
-
-  // Cache the section base for future lookups.
-  XCOFFSectionBaseCache[CacheKey] = SectionBase;
-
-  // Convert section-relative offset to absolute VMA
-  // VMA = section_base + offset
-  Offset = SectionBase + Offset;
-
-  // Return UndefSection - XCOFF symbolizer doesn't support SectionedAddress,
-  // so we use absolute VMA addressing instead.
-  return object::SectionedAddress::UndefSection;
+  return *SectionBaseOrErr + Offset;
 }
 
 static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
@@ -359,37 +285,43 @@ static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
         AddrSpec.consume_front_insensitive("+0x");
   }
 
-  // Check for section-relative address syntax: (SECTION_TYPE)(+0x0)
-   if (AddrSpec.starts_with("(")) {
-     size_t FirstClose = AddrSpec.find(')');
-     if (FirstClose != StringRef::npos && FirstClose + 1 < AddrSpec.size() &&
-         AddrSpec[FirstClose + 1] == '(') {
-       size_t SecondOpen = FirstClose + 1;
-       size_t SecondClose = AddrSpec.find(')', SecondOpen);
-       if (SecondClose != StringRef::npos) {
-         // Extract section type from first parentheses
-         SectionType = AddrSpec.substr(1, FirstClose - 1);
-
-         // Validate that section type is not empty
-         if (SectionType.empty())
-           return makeStringError("unknown section type: empty section type");
-
-         // Extract offset from second parentheses
-         StringRef OffsetPart = AddrSpec.substr(SecondOpen + 1, SecondClose - SecondOpen - 1);
-
-         // The offset should start with '+'
-         if (!OffsetPart.consume_front("+"))
-           return makeStringError("section-relative offset must start with '+'");
-
-         // Parse the offset - auto-detect base (0x prefix = hex, otherwise decimal)
-         if (OffsetPart.getAsInteger(0, Offset))
-           return makeStringError("invalid offset in section-relative address");
-
-         Symbol = StringRef();
-         return Error::success();
-       }
-     }
-   }
+  // Check for section-relative address syntax: (SECTION_TYPE)(+offset)
+  if (AddrSpec.starts_with("(")) {
+    size_t FirstClose = AddrSpec.find(')');
+    if (FirstClose != StringRef::npos && FirstClose + 1 < AddrSpec.size() &&
+        AddrSpec[FirstClose + 1] == '(') {
+      size_t SecondOpen = FirstClose + 1;
+      size_t SecondClose = AddrSpec.find(')', SecondOpen);
+      if (SecondClose != StringRef::npos) {
+        // Extract section type from first parentheses.
+        SectionType = AddrSpec.substr(1, FirstClose - 1);
+
+        if (SectionType.empty())
+          return makeStringError(
+              "empty section type in section-relative address");
+
+        // Extract offset string from second parentheses.
+        StringRef OffsetStr =
+            AddrSpec.substr(SecondOpen + 1, SecondClose - SecondOpen - 1);
+
+        // The offset must start with '+'.
+        if (!OffsetStr.starts_with("+"))
+          return makeStringError(
+              "section-relative offset \"" + OffsetStr +
+              "\" must start with '+'");
+
+        StringRef OffsetValue = OffsetStr.drop_front(1);
+        // Parse the offset value; auto-detect base (0x prefix = hex,
+        // otherwise decimal).
+        if (OffsetValue.getAsInteger(0, Offset))
+          return makeStringError("invalid offset \"" + OffsetStr +
+                                 "\" in section-relative address");
+
+        Symbol = StringRef();
+        return Error::success();
+      }
+    }
+  }
 
   // If address specification is a number, treat it as a module offset.
   if (!AddrSpec.getAsInteger(IsAddr2Line ? 16 : 0, Offset)) {
@@ -510,18 +442,19 @@ static void symbolizeInput(const opt::InputArgList &Args,
     return;
   }
 
-  // Validate section index from section type if specified
-  uint64_t SectionIndex = object::SectionedAddress::UndefSection;
+  // If a section-relative address was parsed, resolve it to an absolute VMA.
   if (!SectionType.empty() && !ModuleName.empty()) {
-    auto SectionIndexOrErr = validateSectionType(ModuleName, SectionType, Offset, Symbolizer);
-    if (!SectionIndexOrErr) {
-      handleAllErrors(SectionIndexOrErr.takeError(), [&](const ErrorInfoBase &EI) {
-        printError(EI, InputString);
-      });
+    auto AbsoluteVMAOrErr =
+        resolveXCOFFSectionAddress(ModuleName, SectionType, Offset, Symbolizer);
+    if (!AbsoluteVMAOrErr) {
+      handleAllErrors(AbsoluteVMAOrErr.takeError(),
+                      [&](const ErrorInfoBase &EI) {
+                        printError(EI, InputString);
+                      });
       printUnknownLineInfo(ModuleName, Printer);
       return;
     }
-    SectionIndex = *SectionIndexOrErr;
+    Offset = *AbsoluteVMAOrErr;
   }
 
   bool ShouldInline = Args.hasFlag(OPT_inlines, OPT_no_inlines, !IsAddr2Line);
@@ -530,13 +463,14 @@ static void symbolizeInput(const opt::InputArgList &Args,
     if (!Args.hasArg(OPT_no_debuginfod))
       enableDebuginfod(Symbolizer, Args);
     std::string BuildIDStr = toHex(BuildID);
-    // Note: Section type resolution is not supported for BuildID-based lookup
+    // Note: Section type resolution is not supported for BuildID-based lookup.
     executeCommand(BuildIDStr, BuildID, Cmd, Symbol, Offset, AdjustVMA,
                    ShouldInline, Style, Symbolizer, Printer,
-                    object::SectionedAddress::UndefSection);
+                   object::SectionedAddress::UndefSection);
   } else {
     executeCommand(ModuleName, ModuleName, Cmd, Symbol, Offset, AdjustVMA,
-ShouldInline, Style, Symbolizer, Printer, SectionIndex);
+                   ShouldInline, Style, Symbolizer, Printer,
+                   object::SectionedAddress::UndefSection);
   }
 }
 

>From 9c00c18a532a07419fd142772e76fa26f3a66bda Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Fri, 13 Mar 2026 10:27:47 +0530
Subject: [PATCH 25/30] fix error

---
 llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 0ab5bd7fa2d7a..75add1bb187fe 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -44,6 +44,7 @@
 #include <algorithm>
 #include <cstdio>
 #include <cstring>
+#include <iostream>
 #include <string>
 
 using namespace llvm;
@@ -154,7 +155,7 @@ static StringRef getSpaceDelimitedWord(StringRef &Source) {
   return Result;
 }
 
-static Error makeStringError(StringRef Msg) {
+static Error makeStringError(const Twine &Msg) {
   return make_error<StringError>(Msg, inconvertibleErrorCode());
 }
 

>From 4a0ff08304a82e883adf932b150043645c5cf89b Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Mon, 16 Mar 2026 00:31:13 +0530
Subject: [PATCH 26/30] Test fail fix

---
 .../tools/llvm-symbolizer/xcoff-section-relative.test     | 8 ++++++--
 llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test | 2 ++
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
index aa7979152ae07..9452aa4c6d0aa 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
@@ -61,6 +61,7 @@ Symbols:
       - Type:                 AUX_CSECT
         SymbolType:           XTY_SD
         StorageMappingClass:  XMC_PR
+        SectionOrLength:      4
   # .bar csect (XTY_SD): second function in its own csect.
   - Name:            .bar
     Value:           0x104
@@ -71,7 +72,8 @@ Symbols:
       - Type:                 AUX_CSECT
         SymbolType:           XTY_SD
         StorageMappingClass:  XMC_PR
-  # .my_const csect (XTY_SD, XMC_RO): read-only constant in TEXT section.
+        SectionOrLength:      4
+  # .my_const csect (XTY_SD, XMC_PR): read-only constant in TEXT section.
   - Name:            .my_const
     Value:           0x108
     Section:         .text
@@ -80,7 +82,8 @@ Symbols:
     AuxEntries:
       - Type:                 AUX_CSECT
         SymbolType:           XTY_SD
-        StorageMappingClass:  XMC_RO
+        StorageMappingClass:  XMC_PR
+        SectionOrLength:      4
   # global_var csect at DATA+0x4 (non-zero offset to show DATA offsets work).
   - Name:            global_var
     Value:           0x204
@@ -91,3 +94,4 @@ Symbols:
       - Type:                 AUX_CSECT
         SymbolType:           XTY_SD
         StorageMappingClass:  XMC_RW
+        SectionOrLength:      4
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index 4d9aafc1395d2..25fdfc741a257 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -123,6 +123,7 @@ Symbols:
       - Type:                 AUX_CSECT
         SymbolType:           XTY_SD
         StorageMappingClass:  XMC_PR
+        SectionOrLength:      4
 
 ## Document 2: XCOFF object with only TEXT section (no DATA).
 --- !XCOFF
@@ -143,6 +144,7 @@ Symbols:
       - Type:                 AUX_CSECT
         SymbolType:           XTY_SD
         StorageMappingClass:  XMC_PR
+        SectionOrLength:      4
 
 ## Document 3: ELF object (non-XCOFF) for testing the format-check error.
 --- !ELF

>From 2a7f52dc74ee8b94be3c7bc7264187de68d81ec3 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Mon, 16 Mar 2026 16:54:40 +0530
Subject: [PATCH 27/30] fix formatting

---
 llvm/lib/DebugInfo/Symbolize/Symbolize.cpp    |  4 ++--
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 21 ++++++++-----------
 2 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index 2f7c07e704da7..a86b2dd5734c1 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -54,8 +54,8 @@ LLVMSymbolizer::~LLVMSymbolizer() = default;
 
 Expected<uint64_t>
 LLVMSymbolizer::getXCOFFSectionAddress(StringRef ModuleName,
-                                        XCOFF::SectionTypeFlags SectionTypeFlag,
-                                        StringRef SectionTypeName) {
+                                       XCOFF::SectionTypeFlags SectionTypeFlag,
+                                       StringRef SectionTypeName) {
   // Check the cache first.
   auto CacheKey = std::make_pair(ModuleName.str(), SectionTypeFlag);
   auto It = XCOFFSectionBaseCache.find(CacheKey);
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 1cc2a59c764a4..681c01ad1a328 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -192,9 +192,8 @@ resolveXCOFFSectionAddress(StringRef ModulePath, StringRef SectionType,
                              SectionType.str() +
                              "\" in section-relative address");
 
-  Expected<uint64_t> SectionBaseOrErr =
-      Symbolizer.getXCOFFSectionAddress(ModulePath, *SectionTypeFlag,
-                                        SectionType);
+  Expected<uint64_t> SectionBaseOrErr = Symbolizer.getXCOFFSectionAddress(
+      ModulePath, *SectionTypeFlag, SectionType);
   if (!SectionBaseOrErr)
     return SectionBaseOrErr.takeError();
 
@@ -312,9 +311,8 @@ static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
 
         // The offset must start with '+'.
         if (!OffsetStr.starts_with("+"))
-          return makeStringError(
-              "section-relative offset \"" + OffsetStr +
-              "\" must start with '+'");
+          return makeStringError("section-relative offset \"" + OffsetStr +
+                                 "\" must start with '+'");
 
         StringRef OffsetValue = OffsetStr.drop_front(1);
         // Parse the offset value; auto-detect base (0x prefix = hex,
@@ -370,8 +368,8 @@ void executeCommand(StringRef ModuleName, const T &ModuleSpec, Command Cmd,
                     bool ShouldInline, OutputStyle Style,
                     LLVMSymbolizer &Symbolizer, DIPrinter &Printer,
                     uint64_t SectionIndex) {
-   uint64_t AdjustedOffset = Offset - AdjustVMA;
-   object::SectionedAddress Address = {AdjustedOffset, SectionIndex};
+  uint64_t AdjustedOffset = Offset - AdjustVMA;
+  object::SectionedAddress Address = {AdjustedOffset, SectionIndex};
 
   Request SymRequest = {
       ModuleName, Symbol.empty() ? std::make_optional(Offset) : std::nullopt,
@@ -453,10 +451,9 @@ static void symbolizeInput(const opt::InputArgList &Args,
     auto AbsoluteVMAOrErr =
         resolveXCOFFSectionAddress(ModuleName, SectionType, Offset, Symbolizer);
     if (!AbsoluteVMAOrErr) {
-      handleAllErrors(AbsoluteVMAOrErr.takeError(),
-                      [&](const ErrorInfoBase &EI) {
-                        printError(EI, InputString);
-                      });
+      handleAllErrors(
+          AbsoluteVMAOrErr.takeError(),
+          [&](const ErrorInfoBase &EI) { printError(EI, InputString); });
       printUnknownLineInfo(ModuleName, Printer);
       return;
     }

>From 8fa174c71dd9f1fefe440fb164e4a38bc56a7290 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Wed, 25 Mar 2026 11:07:53 +0530
Subject: [PATCH 28/30] Address review comments

---
 .../llvm/DebugInfo/Symbolize/Symbolize.h      | 18 +++++-------
 llvm/lib/DebugInfo/Symbolize/Symbolize.cpp    | 29 +++++++++----------
 .../xcoff-section-relative.test               | 16 +++++-----
 .../llvm-symbolizer/xcoff-section-syntax.test | 29 ++++++++++++++-----
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp |  8 ++---
 5 files changed, 54 insertions(+), 46 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
index 6dae683d987e3..a1983a4e3cfe9 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
@@ -134,14 +134,13 @@ class LLVMSymbolizer {
     BIDFetcher = std::move(Fetcher);
   }
 
-  /// For an XCOFF object at ModuleName, find the base address of the unique
-  /// section matching SectionTypeFlag. Returns an error if the object cannot
-  /// be opened, is not XCOFF, has no matching section, or has multiple matching
-  /// sections (which would make a section-relative address ambiguous).
-  /// SectionTypeName is the name (e.g. "TEXT") used in error
-  /// messages to identify which section type was not found or was ambiguous.
+  /// For the XCOFF object at ModulePath, find the base address of the
+  /// unique section matching SectionTypeFlag. Returns an error if the object
+  /// is not XCOFF, has no matching section, or has multiple matching sections
+  /// (which would make a section-relative address ambiguous). SectionTypeName
+  /// (e.g. "TEXT") is used in error messages to identify the section type.
   LLVM_ABI Expected<uint64_t>
-  getXCOFFSectionAddress(StringRef ModuleName,
+  getXCOFFSectionAddress(StringRef ModulePath,
                          XCOFF::SectionTypeFlags SectionTypeFlag,
                          StringRef SectionTypeName);
 
@@ -275,10 +274,9 @@ class LLVMSymbolizer {
 
   std::unique_ptr<BuildIDFetcher> BIDFetcher;
 
-  /// Cache for XCOFF section base addresses: (ModulePath, SectionTypeFlag) ->
+  /// Cache for XCOFF section base addresses: ModulePath -> SectionTypeFlag ->
   /// base VMA.
-  std::map<std::pair<std::string, XCOFF::SectionTypeFlags>, uint64_t>
-      XCOFFSectionBaseCache;
+  StringMap<DenseMap<XCOFF::SectionTypeFlags, uint64_t>> XCOFFSectionBaseCache;
 };
 
 // A binary intrusively linked into a LRU cache list. If the binary is empty,
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index a86b2dd5734c1..f72dd59d1ae8a 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -53,22 +53,21 @@ LLVMSymbolizer::LLVMSymbolizer(const Options &Opts)
 LLVMSymbolizer::~LLVMSymbolizer() = default;
 
 Expected<uint64_t>
-LLVMSymbolizer::getXCOFFSectionAddress(StringRef ModuleName,
+LLVMSymbolizer::getXCOFFSectionAddress(StringRef ModulePath,
                                        XCOFF::SectionTypeFlags SectionTypeFlag,
                                        StringRef SectionTypeName) {
   // Check the cache first.
-  auto CacheKey = std::make_pair(ModuleName.str(), SectionTypeFlag);
-  auto It = XCOFFSectionBaseCache.find(CacheKey);
-  if (It != XCOFFSectionBaseCache.end())
-    return It->second;
-
-  Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
-      object::createBinary(ModuleName);
-  if (!BinaryOrErr)
-    return BinaryOrErr.takeError();
-
-  const auto *XCOFFObj =
-      dyn_cast<object::XCOFFObjectFile>(BinaryOrErr->getBinary());
+  auto &FlagMap = XCOFFSectionBaseCache[ModulePath];
+  auto CachedIt = FlagMap.find(SectionTypeFlag);
+  if (CachedIt != FlagMap.end())
+    return CachedIt->second;
+
+  Expected<ObjectFile *> ObjOrErr =
+      getOrCreateObject(ModulePath.str(), Opts.DefaultArch);
+  if (!ObjOrErr)
+    return ObjOrErr.takeError();
+
+  const auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(*ObjOrErr);
   if (!XCOFFObj)
     return createStringError(
         "section type syntax is only supported for XCOFF objects");
@@ -77,7 +76,7 @@ LLVMSymbolizer::getXCOFFSectionAddress(StringRef ModuleName,
   for (const object::SectionRef &Section : XCOFFObj->sections()) {
     DataRefImpl SecRef = Section.getRawDataRefImpl();
     int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
-    if ((Flags & 0xFFFF) != SectionTypeFlag)
+    if ((Flags & XCOFFSectionHeader32::SectionFlagsTypeMask) != SectionTypeFlag)
       continue;
     if (SectionBase)
       return createStringError("multiple '" + SectionTypeName +
@@ -89,7 +88,7 @@ LLVMSymbolizer::getXCOFFSectionAddress(StringRef ModuleName,
     return createStringError("no '" + SectionTypeName +
                              "' section found in XCOFF object");
 
-  XCOFFSectionBaseCache.emplace(CacheKey, *SectionBase);
+  FlagMap[SectionTypeFlag] = *SectionBase;
   return *SectionBase;
 }
 
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
index 619ab9e00b4c7..d456d5d711dbb 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-relative.test
@@ -19,11 +19,11 @@
 # TEXT-BAR: .bar
 # TEXT-BAR-NEXT: ??:0:0
 
-## Test 3: Symbolize global constant using TEXT section-relative offset.
-## .my_const is at 0x100 (TEXT base) + 0x8 offset = 0x108.
-# RUN: llvm-symbolizer --obj=%t.xcoff 'DATA (TEXT)(+0x8)' | FileCheck %s --check-prefix=TEXT-CONST
+## Test 3: Symbolize third symbol using TEXT section-relative offset.
+## my_const is at 0x100 (TEXT base) + 0x8 offset = 0x108.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+0x8)' | FileCheck %s --check-prefix=TEXT-CONST
 
-# TEXT-CONST: .my_const
+# TEXT-CONST: my_const
 
 ## Test 4: Symbolize global variable using DATA section-relative offset.
 ## global_var is at 0x200 (DATA base) + 0x4 offset = 0x204.
@@ -58,7 +58,7 @@ Symbols:
         SymbolType:           XTY_SD
         StorageMappingClass:  XMC_PR
         SectionOrLength:      4
-  # .bar csect (XTY_SD): second function in its own csect.
+  ## .bar csect (XTY_SD): second function in its own csect.
   - Name:            .bar
     Value:           0x104
     Section:         .text
@@ -69,8 +69,8 @@ Symbols:
         SymbolType:           XTY_SD
         StorageMappingClass:  XMC_PR
         SectionOrLength:      4
-  # .my_const csect (XTY_SD, XMC_PR): read-only constant in TEXT section.
-  - Name:            .my_const
+  ## my_const csect (XTY_SD, XMC_PR): read-only constant in TEXT section.
+  - Name:            my_const
     Value:           0x108
     Section:         .text
     StorageClass:    C_EXT
@@ -80,7 +80,7 @@ Symbols:
         SymbolType:           XTY_SD
         StorageMappingClass:  XMC_PR
         SectionOrLength:      4
-  # global_var csect at DATA+0x4 (non-zero offset to show DATA offsets work).
+  ## global_var csect at DATA+0x4 (non-zero offset to show DATA offsets work).
   - Name:            global_var
     Value:           0x204
     Section:         .data
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index 51ba49b497353..91856e98b173b 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -17,6 +17,10 @@
 # RUN: llvm-symbolizer --obj=%t.xcoff '(-)(+0x10)' 2>&1 | \
 # RUN:   FileCheck %s -DTYPE=- --check-prefix=INVALID-TYPE
 
+## Test empty section type.
+# RUN: llvm-symbolizer --obj=%t.xcoff '()(+0x10)' 2>&1 | \
+# RUN:   FileCheck %s -DTYPE= --check-prefix=INVALID-TYPE
+
 # INVALID-TYPE: error: '([[TYPE]])(+0x10)': unknown or unsupported section type "[[TYPE]]" in section-relative address
 
 ## Test missing '+' sign.
@@ -31,6 +35,24 @@
 
 # EMPTY-OFFSET: error: '(TEXT)()': section-relative offset "" must start with '+'
 
+## Test negative offset.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(-0x10)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=NEG-OFFSET
+
+# NEG-OFFSET: error: '(TEXT)(-0x10)': section-relative offset "-0x10" must start with '+'
+
+## Test negative decimal offset.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(-10)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=NEG-OFFSET-DEC
+
+# NEG-OFFSET-DEC: error: '(TEXT)(-10)': section-relative offset "-10" must start with '+'
+
+## Test offset with '+' followed by '-'.
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+-0x10)' 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=PLUS-NEG
+
+# PLUS-NEG: error: '(TEXT)(+-0x10)': invalid offset "+-0x10" in section-relative address
+
 ## Test invalid offset: decimal digits followed by non-decimal hex characters,
 ## e.g. 123abc. getAsInteger with base 0 requires the whole string to be valid,
 ## so this is rejected.
@@ -65,12 +87,6 @@
 
 # INVALID-OFFSET: error: '(TEXT)(+xyz)': invalid offset "+xyz" in section-relative address
 
-## Test empty section type.
-# RUN: llvm-symbolizer --obj=%t.xcoff '()(+0x10)' 2>&1 | \
-# RUN:   FileCheck %s --check-prefix=EMPTY-SECTION
-
-# EMPTY-SECTION: error: '()(+0x10)': empty section type in section-relative address
-
 ## Test error: section type not found (DATA section doesn't exist).
 # RUN: yaml2obj %s --docnum=2 -o %t.nodata.xcoff
 # RUN: llvm-symbolizer --obj=%t.nodata.xcoff '(DATA)(+0x0)' 2>&1 | \
@@ -109,7 +125,6 @@ Sections:
     Flags:   [ STYP_DATA ]
     SectionData: "00000000"
   - Name:    .extra
-    Address: 0x300
     Flags:   [ [[SECT2_FLAGS=STYP_INFO]] ]
     SectionData: "00000000"
 Symbols:
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 681c01ad1a328..55ca7d80a1865 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -50,11 +50,6 @@
 using namespace llvm;
 using namespace symbolize;
 
-// Cache for XCOFF section base addresses to avoid re-opening binaries.
-// Key: (ModulePath, SectionTypeFlag), Value: SectionBaseAddress
-static std::map<std::pair<std::string, XCOFF::SectionTypeFlags>, uint64_t>
-    XCOFFSectionBaseCache;
-
 namespace {
 enum ID {
   OPT_INVALID = 0, // This is not an option ID.
@@ -303,7 +298,8 @@ static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
 
         if (SectionType.empty())
           return makeStringError(
-              "empty section type in section-relative address");
+              "unknown or unsupported section type \"\" in section-relative "
+              "address");
 
         // Extract offset string from second parentheses.
         StringRef OffsetStr =

>From ec824a0cdc23d287c8fb12ce59c4402319d17a1e Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Wed, 25 Mar 2026 12:53:35 +0530
Subject: [PATCH 29/30] Address review comments

---
 llvm/include/llvm/Object/XCOFFObjectFile.h    |   2 +-
 llvm/lib/DebugInfo/Symbolize/Symbolize.cpp    |  26 ++---
 llvm/lib/Object/XCOFFObjectFile.cpp           |  38 ++++---
 .../llvm-symbolizer/xcoff-section-syntax.test |  23 +++-
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp | 106 ++++++++++--------
 5 files changed, 115 insertions(+), 80 deletions(-)

diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h
index da3538ecb3024..f4876476ea307 100644
--- a/llvm/include/llvm/Object/XCOFFObjectFile.h
+++ b/llvm/include/llvm/Object/XCOFFObjectFile.h
@@ -556,7 +556,7 @@ class LLVM_ABI XCOFFObjectFile : public ObjectFile {
   uintptr_t getSectionHeaderTableAddress() const;
   uintptr_t getEndOfSymbolTableAddress() const;
 
-  DataRefImpl getSectionByType(XCOFF::SectionTypeFlags SectType) const;
+  Expected<DataRefImpl> getSectionByType(XCOFF::SectionTypeFlags SectType) const;
   uint64_t getSectionFileOffsetToRawData(DataRefImpl Sec) const;
 
   // This returns a pointer to the start of the storage for the name field of
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index f72dd59d1ae8a..c0e4b5d182dc4 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -72,24 +72,20 @@ LLVMSymbolizer::getXCOFFSectionAddress(StringRef ModulePath,
     return createStringError(
         "section type syntax is only supported for XCOFF objects");
 
-  std::optional<uint64_t> SectionBase;
-  for (const object::SectionRef &Section : XCOFFObj->sections()) {
-    DataRefImpl SecRef = Section.getRawDataRefImpl();
-    int32_t Flags = XCOFFObj->getSectionFlags(SecRef);
-    if ((Flags & XCOFFSectionHeader32::SectionFlagsTypeMask) != SectionTypeFlag)
-      continue;
-    if (SectionBase)
-      return createStringError("multiple '" + SectionTypeName +
-                               "' sections found in XCOFF object");
-    SectionBase = Section.getAddress();
-  }
-
-  if (!SectionBase)
+  Expected<DataRefImpl> DRIOrErr = XCOFFObj->getSectionByType(SectionTypeFlag);
+  if (!DRIOrErr) {
+    consumeError(DRIOrErr.takeError());
+    return createStringError("multiple '" + SectionTypeName +
+                             "' sections found in XCOFF object");
+  }
+  DataRefImpl DRI = *DRIOrErr;
+  if (DRI.p == 0)
     return createStringError("no '" + SectionTypeName +
                              "' section found in XCOFF object");
 
-  FlagMap[SectionTypeFlag] = *SectionBase;
-  return *SectionBase;
+  uint64_t SectionBase = SectionRef(DRI, XCOFFObj).getAddress();
+  FlagMap[SectionTypeFlag] = SectionBase;
+  return SectionBase;
 }
 
 template <typename T>
diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp
index ed1f7505cafb1..2914c47d80d75 100644
--- a/llvm/lib/Object/XCOFFObjectFile.cpp
+++ b/llvm/lib/Object/XCOFFObjectFile.cpp
@@ -447,7 +447,10 @@ uint64_t XCOFFObjectFile::getSectionFileOffsetToRawData(DataRefImpl Sec) const {
 
 Expected<uintptr_t> XCOFFObjectFile::getSectionFileOffsetToRawData(
     XCOFF::SectionTypeFlags SectType) const {
-  DataRefImpl DRI = getSectionByType(SectType);
+  Expected<DataRefImpl> DRIOrErr = getSectionByType(SectType);
+  if (!DRIOrErr)
+    return DRIOrErr.takeError();
+  DataRefImpl DRI = *DRIOrErr;
 
   if (DRI.p == 0) // No section is not an error.
     return 0;
@@ -808,19 +811,25 @@ Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const {
 }
 
 DataRefImpl
+Expected<DataRefImpl>
 XCOFFObjectFile::getSectionByType(XCOFF::SectionTypeFlags SectType) const {
-  DataRefImpl DRI;
-  auto GetSectionAddr = [&](const auto &Sections) -> uintptr_t {
-    for (const auto &Sec : Sections)
-      if (Sec.getSectionType() == SectType)
-        return reinterpret_cast<uintptr_t>(&Sec);
-    return uintptr_t(0);
+  DataRefImpl Result;
+  Result.p = 0;
+  auto FindSection = [&](const auto &Sections) -> Error {
+    for (const auto &Sec : Sections) {
+      if (Sec.getSectionType() == SectType) {
+        if (Result.p != 0)
+          return createStringError(
+              "multiple XCOFF sections have type flag 0x" +
+              Twine::utohexstr(SectType));
+        Result.p = reinterpret_cast<uintptr_t>(&Sec);
+      }
+    }
+    return Error::success();
   };
-  if (is64Bit())
-    DRI.p = GetSectionAddr(sections64());
-  else
-    DRI.p = GetSectionAddr(sections32());
-  return DRI;
+  if (Error E = is64Bit() ? FindSection(sections64()) : FindSection(sections32()))
+    return std::move(E);
+  return Result;
 }
 
 Expected<StringRef>
@@ -1055,7 +1064,10 @@ Expected<ArrayRef<ExceptEnt>> XCOFFObjectFile::getExceptionEntries() const {
   if (!ExceptionSectOrErr)
     return ExceptionSectOrErr.takeError();
 
-  DataRefImpl DRI = getSectionByType(XCOFF::STYP_EXCEPT);
+  Expected<DataRefImpl> DRIOrErr = getSectionByType(XCOFF::STYP_EXCEPT);
+  if (!DRIOrErr)
+    return DRIOrErr.takeError();
+  DataRefImpl DRI = *DRIOrErr;
   if (DRI.p == 0)
     return ArrayRef<ExceptEnt>();
 
diff --git a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
index 91856e98b173b..d25ad2a2ed64c 100644
--- a/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
+++ b/llvm/test/tools/llvm-symbolizer/xcoff-section-syntax.test
@@ -73,13 +73,14 @@
 
 # INVALID-OFFSET-NONHEX: error: '(TEXT)(+0xdefg)': invalid offset "+0xdefg" in section-relative address
 
-## Test that a leading-zero value (0123) is treated as octal (decimal 83) by
-## getAsInteger(0,...), not as decimal 123. The resolved address TEXT_BASE +
-## 83 = 0x153 has no symbol, so the output shows "??".
-# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+0123)' | \
+## Test that a leading-zero value is treated as octal by getAsInteger(0,...).
+## +010 is octal 8, so TEXT_BASE(0x100) + 8 = 0x108 = .bar.
+## If +010 were parsed as decimal 10 instead, the address would be 0x10a,
+## which has no symbol (output would be "??").
+# RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+010)' | \
 # RUN:   FileCheck %s --check-prefix=OCTAL
 
-# OCTAL: ??
+# OCTAL: .bar
 
 ## Test invalid offset value.
 # RUN: llvm-symbolizer --obj=%t.xcoff '(TEXT)(+xyz)' 2>&1 | \
@@ -119,7 +120,7 @@ Sections:
   - Name:    .text
     Address: 0x100
     Flags:   [ STYP_TEXT ]
-    SectionData: "4E800020"
+    SectionData: "4E8000204E8000200000002A"
   - Name:    .data
     Address: 0x200
     Flags:   [ STYP_DATA ]
@@ -138,6 +139,16 @@ Symbols:
         SymbolType:           XTY_SD
         StorageMappingClass:  XMC_PR
         SectionOrLength:      4
+  - Name:            .bar
+    Value:           0x108
+    Section:         .text
+    StorageClass:    C_EXT
+    NumberOfAuxEntries: 1
+    AuxEntries:
+      - Type:                 AUX_CSECT
+        SymbolType:           XTY_SD
+        StorageMappingClass:  XMC_PR
+        SectionOrLength:      4
 
 ## Document 2: XCOFF object with only TEXT section (no DATA).
 --- !XCOFF
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 55ca7d80a1865..c5ed656a99f4d 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -195,13 +195,55 @@ resolveXCOFFSectionAddress(StringRef ModulePath, StringRef SectionType,
   return *SectionBaseOrErr + Offset;
 }
 
+// Parses (SECTION_TYPE)(+offset) syntax from AddrSpec.
+// Returns true (with SectionType and Offset set) if the syntax matches and is
+// valid; returns false if AddrSpec does not start with this syntax;
+// returns an error if the syntax is recognized but invalid.
+static Expected<bool>
+tryParseSectionRelativeAddress(StringRef AddrSpec, StringRef &SectionType,
+                               uint64_t &Offset) {
+  if (!AddrSpec.starts_with("("))
+    return false;
+
+  size_t FirstOpen = 0;
+  size_t FirstClose = AddrSpec.find(')');
+  if (FirstClose == StringRef::npos || FirstClose + 1 >= AddrSpec.size() ||
+      AddrSpec[FirstClose + 1] != '(')
+    return false;
+
+  size_t SecondOpen = FirstClose + 1;
+  size_t SecondClose = AddrSpec.find(')', SecondOpen);
+  if (SecondClose == StringRef::npos)
+    return false;
+
+  // Matched (X)(Y) pattern — now validate the contents.
+  SectionType = AddrSpec.substr(FirstOpen + 1, FirstClose - FirstOpen - 1);
+  if (SectionType.empty())
+    return makeStringError(
+        "unknown or unsupported section type \"\" in section-relative address");
+
+  StringRef OffsetStr =
+      AddrSpec.substr(SecondOpen + 1, SecondClose - SecondOpen - 1);
+  if (!OffsetStr.starts_with("+"))
+    return makeStringError("section-relative offset \"" + OffsetStr +
+                           "\" must start with '+'");
+
+  StringRef OffsetValue = OffsetStr.drop_front(1);
+  // Parse the offset value; auto-detect base (0x prefix = hex, 0 prefix =
+  // octal, otherwise decimal).
+  if (OffsetValue.getAsInteger(0, Offset))
+    return makeStringError("invalid offset \"" + OffsetStr +
+                           "\" in section-relative address");
+
+  return true;
+}
+
 static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
                           StringRef InputString, Command &Cmd,
                           std::string &ModuleName, object::BuildID &BuildID,
                           StringRef &Symbol, uint64_t &Offset,
                           StringRef &SectionType) {
   ModuleName = BinaryName;
-  SectionType = StringRef();
   if (InputString.consume_front("CODE ")) {
     Cmd = Command::Code;
   } else if (InputString.consume_front("DATA ")) {
@@ -265,8 +307,9 @@ static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
       return makeStringError("no input filename has been specified");
   }
 
-  // Parse address specification, which can be an offset in module or a
-  // symbol with optional offset.
+  // Parse address specification, which may be a section-relative address of
+  // the form (SECTION_TYPE)(+offset), a numeric module offset, or a symbol
+  // name with an optional offset.
   InputString = InputString.trim();
   if (InputString.empty())
     return makeStringError("no module offset has been specified");
@@ -275,59 +318,33 @@ static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
   // is consistent with GNU addr2line.
   int AddrSpecLength = InputString.find_first_of(" \n\r");
   StringRef AddrSpec = InputString.substr(0, AddrSpecLength);
+
+  // Check for section-relative address syntax: (SECTION_TYPE)(+offset).
+  Expected<bool> IsSectionRelOrErr =
+      tryParseSectionRelativeAddress(AddrSpec, SectionType, Offset);
+  if (!IsSectionRelOrErr)
+    return IsSectionRelOrErr.takeError();
+  if (*IsSectionRelOrErr) {
+    Symbol = StringRef();
+    return Error::success();
+  }
+
   bool StartsWithDigit = std::isdigit(AddrSpec.front());
 
+  // FIXME: This assumes that what follows will exclusively be interpreted as a
+  // hexadecimal value, and therefore contributes to an existing bug where
+  // +0xfunc_01 is interpreted as symbol name func_01 by llvm-addr2line.
   // GNU addr2line assumes the address is hexadecimal and allows a redundant
-  // "0x", "0X" prefix or an optional `+` sign; do the same for
-  // compatibility.
+  // "0x", "0X" prefix or an optional `+` sign; do the same for compatibility.
   if (IsAddr2Line) {
     AddrSpec.consume_front_insensitive("0x") ||
         AddrSpec.consume_front_insensitive("+0x");
   }
 
-  // Check for section-relative address syntax: (SECTION_TYPE)(+offset)
-  if (AddrSpec.starts_with("(")) {
-    size_t FirstClose = AddrSpec.find(')');
-    if (FirstClose != StringRef::npos && FirstClose + 1 < AddrSpec.size() &&
-        AddrSpec[FirstClose + 1] == '(') {
-      size_t SecondOpen = FirstClose + 1;
-      size_t SecondClose = AddrSpec.find(')', SecondOpen);
-      if (SecondClose != StringRef::npos) {
-        // Extract section type from first parentheses.
-        SectionType = AddrSpec.substr(1, FirstClose - 1);
-
-        if (SectionType.empty())
-          return makeStringError(
-              "unknown or unsupported section type \"\" in section-relative "
-              "address");
-
-        // Extract offset string from second parentheses.
-        StringRef OffsetStr =
-            AddrSpec.substr(SecondOpen + 1, SecondClose - SecondOpen - 1);
-
-        // The offset must start with '+'.
-        if (!OffsetStr.starts_with("+"))
-          return makeStringError("section-relative offset \"" + OffsetStr +
-                                 "\" must start with '+'");
-
-        StringRef OffsetValue = OffsetStr.drop_front(1);
-        // Parse the offset value; auto-detect base (0x prefix = hex,
-        // otherwise decimal).
-        if (OffsetValue.getAsInteger(0, Offset))
-          return makeStringError("invalid offset \"" + OffsetStr +
-                                 "\" in section-relative address");
-
-        Symbol = StringRef();
-        return Error::success();
-      }
-    }
-  }
-
   // If address specification is a number, treat it as a module offset.
   if (!AddrSpec.getAsInteger(IsAddr2Line ? 16 : 0, Offset)) {
     // Module offset is an address.
     Symbol = StringRef();
-    SectionType = StringRef();
     return Error::success();
   }
 
@@ -339,7 +356,6 @@ static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
   // Otherwise it is a symbol name, potentially with an offset.
   Symbol = AddrSpec;
   Offset = 0;
-  SectionType = StringRef();
 
   // If the address specification contains '+', try treating it as
   // "symbol + offset".

>From 5dba13771b921aea9c4e15e8bf233dd7f10d5139 Mon Sep 17 00:00:00 2001
From: Midhunesh <midhunesh.p at ibm.com>
Date: Wed, 25 Mar 2026 14:47:33 +0530
Subject: [PATCH 30/30] Address review comments

---
 llvm/lib/Object/XCOFFObjectFile.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp
index 2914c47d80d75..d4014ac4c31da 100644
--- a/llvm/lib/Object/XCOFFObjectFile.cpp
+++ b/llvm/lib/Object/XCOFFObjectFile.cpp
@@ -810,7 +810,6 @@ Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const {
   return DRI;
 }
 
-DataRefImpl
 Expected<DataRefImpl>
 XCOFFObjectFile::getSectionByType(XCOFF::SectionTypeFlags SectType) const {
   DataRefImpl Result;



More information about the llvm-commits mailing list