[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