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

via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 16 00:58:25 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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



More information about the llvm-commits mailing list