[llvm-branch-commits] [llvm] [llvm-readobj][ELF] Print the address of each --stack-sizes entry (PR #232331)
Prabhu Rajasekaran via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Oct 19 04:47:38 PDT 2026
https://github.com/Prabhuk updated https://github.com/llvm/llvm-project/pull/232331
>From eefa27be50eaa21da33bd9939aff8f7069c01b5a Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Thu, 15 Oct 2026 06:55:36 -0700
Subject: [PATCH 1/4] [llvm-readobj][ELF] Print the address of each
--stack-sizes entry
In a linked file, print the function address that each .stack_sizes
entry holds as Address in the LLVM and JSON output. The entries can then
be matched with --call-graph-info output by address, without looking up
function names.
Assisted-by: Gemini
---
.../tools/llvm-readobj/ELF/stack-sizes.test | 27 ++++++++++++++++--
llvm/tools/llvm-readobj/ELFDumper.cpp | 28 +++++++++++++------
2 files changed, 44 insertions(+), 11 deletions(-)
diff --git a/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test b/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
index 8ce1a6f1b6b27e..c9c5fd52142eae 100644
--- a/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
+++ b/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
@@ -176,8 +176,8 @@ Symbols:
# SYM-LLVM-NEXT: ]
## Check that we correctly report the stack sizes in an executable (non-relocatable)
-## object file. This also shows that the sh_link field is ignored in this situation
-## without warning.
+## object file, with the address of each function in the LLVM and JSON output. This
+## also shows that the sh_link field is ignored in this situation without warning.
# RUN: yaml2obj --docnum=2 %s -o %t02
# RUN: llvm-readelf --stack-sizes %t02 2>&1 \
@@ -185,6 +185,8 @@ Symbols:
# RUN: --match-full-lines --implicit-check-not=warning:
# RUN: llvm-readobj --stack-sizes %t02 2>&1 \
# RUN: | FileCheck %s --check-prefix=EXEC-LLVM --implicit-check-not=warning:
+# RUN: llvm-readobj --elf-output-style=JSON --pretty-print --stack-sizes %t02 2>&1 \
+# RUN: | FileCheck %s --check-prefix=EXEC-JSON --implicit-check-not=warning:
# EXEC-GNU: Size Functions
# EXEC-GNU-NEXT: 16 other
@@ -195,18 +197,32 @@ Symbols:
# EXEC-LLVM: StackSizes [
# EXEC-LLVM-NEXT: Entry {
# EXEC-LLVM-NEXT: Functions: [other]
+# EXEC-LLVM-NEXT: Address: 0x0{{$}}
# EXEC-LLVM-NEXT: Size: 0x10
# EXEC-LLVM-NEXT: }
# EXEC-LLVM-NEXT: Entry {
# EXEC-LLVM-NEXT: Functions: [other_end]
+# EXEC-LLVM-NEXT: Address: 0x10{{$}}
# EXEC-LLVM-NEXT: Size: 0x20
# EXEC-LLVM-NEXT: }
# EXEC-LLVM-NEXT: Entry {
# EXEC-LLVM-NEXT: Functions: [bar]
+# EXEC-LLVM-NEXT: Address: 0x20{{$}}
# EXEC-LLVM-NEXT: Size: 0x30
# EXEC-LLVM-NEXT: }
# EXEC-LLVM-NEXT: ]
+# EXEC-JSON: "StackSizes": [
+# EXEC-JSON-NEXT: {
+# EXEC-JSON-NEXT: "Entry": {
+# EXEC-JSON-NEXT: "Functions": [
+# EXEC-JSON-NEXT: "other"
+# EXEC-JSON-NEXT: ],
+# EXEC-JSON-NEXT: "Address": 0,
+# EXEC-JSON-NEXT: "Size": 16
+# EXEC-JSON-NEXT: }
+# EXEC-JSON-NEXT: },
+
--- !ELF
FileHeader:
Class: ELFCLASS64
@@ -392,11 +408,13 @@ Symbols:
# SUDDENEND-LLVM: StackSizes [
# SUDDENEND-LLVM-NEXT: Entry {
# SUDDENEND-LLVM-NEXT: Functions: [foo]
+# SUDDENEND-LLVM-NEXT: Address: 0x0{{$}}
# SUDDENEND-LLVM-NEXT: Size: 0x8
# SUDDENEND-LLVM-NEXT: }
# SUDDENEND-LLVM-NEXT: warning: '[[FILE]]': SHT_PROGBITS section with index 2 ended while trying to extract a stack size entry
# SUDDENEND-LLVM-NEXT: Entry {
# SUDDENEND-LLVM-NEXT: Functions: [foo]
+# SUDDENEND-LLVM-NEXT: Address: 0x0{{$}}
# SUDDENEND-LLVM-NEXT: Size: 0x8
# SUDDENEND-LLVM-NEXT: }
# SUDDENEND-LLVM-NEXT: warning: '[[FILE]]': SHT_PROGBITS section with index 3 ended while trying to extract a stack size entry
@@ -638,14 +656,17 @@ Sections:
# MULTIPLE-LLVM: StackSizes [
# MULTIPLE-LLVM-NEXT: Entry {
# MULTIPLE-LLVM-NEXT: Functions: [other]
+# MULTIPLE-LLVM-NEXT: Address: 0x0{{$}}
# MULTIPLE-LLVM-NEXT: Size: 0x10
# MULTIPLE-LLVM-NEXT: }
# MULTIPLE-LLVM-NEXT: Entry {
# MULTIPLE-LLVM-NEXT: Functions: [other_end]
+# MULTIPLE-LLVM-NEXT: Address: 0x10{{$}}
# MULTIPLE-LLVM-NEXT: Size: 0x20
# MULTIPLE-LLVM-NEXT: }
# MULTIPLE-LLVM-NEXT: Entry {
# MULTIPLE-LLVM-NEXT: Functions: [bar]
+# MULTIPLE-LLVM-NEXT: Address: 0x20{{$}}
# MULTIPLE-LLVM-NEXT: Size: 0x30
# MULTIPLE-LLVM-NEXT: }
# MULTIPLE-LLVM-NEXT: ]
@@ -907,6 +928,7 @@ Sections:
# MULTIPLE-SYMBOLS-LLVM: StackSizes [
# MULTIPLE-SYMBOLS-LLVM-NEXT: Entry {
# MULTIPLE-SYMBOLS-LLVM-NEXT: Functions: [foo, bar]
+# MULTIPLE-SYMBOLS-LLVM-NEXT: Address: 0x0{{$}}
# MULTIPLE-SYMBOLS-LLVM-NEXT: Size: 0x10
# MULTIPLE-SYMBOLS-LLVM-NEXT: }
# MULTIPLE-SYMBOLS-LLVM-NEXT: ]
@@ -955,6 +977,7 @@ Symbols:
# THUMB-LLVM: StackSizes [
# THUMB-LLVM-NEXT: Entry {
# THUMB-LLVM-NEXT: Functions: [foo]
+# THUMB-LLVM-NEXT: Address: 0x1000{{$}}
# THUMB-LLVM-NEXT: Size: 0x10
# THUMB-LLVM-NEXT: }
# THUMB-LLVM-NEXT: ]
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 623ae0a98eb76c..77f2eaa28b3fa6 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -368,8 +368,12 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
unsigned Ndx, const Elf_Shdr *SymTab,
const Elf_Shdr *FunctionSec, const Elf_Shdr &StackSizeSec,
const RelocationResolver &Resolver, DataExtractor Data);
+ // Prints a stack size entry. Address is the function's address: the value
+ // stored in the entry in a linked file, or the value that its relocation
+ // resolves to in a relocatable file.
virtual void printStackSizeEntry(uint64_t Size,
- ArrayRef<std::string> FuncNames) = 0;
+ ArrayRef<std::string> FuncNames,
+ uint64_t Address) = 0;
void printRelocatableStackSizes(std::function<void()> PrintHeader);
void printNonRelocatableStackSizes(std::function<void()> PrintHeader);
@@ -749,8 +753,8 @@ template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> {
void printGNUVersionSectionProlog(const typename ELFT::Shdr &Sec,
const Twine &Label, unsigned EntriesNum);
- void printStackSizeEntry(uint64_t Size,
- ArrayRef<std::string> FuncNames) override;
+ void printStackSizeEntry(uint64_t Size, ArrayRef<std::string> FuncNames,
+ uint64_t Address) override;
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
@@ -806,8 +810,8 @@ template <typename ELFT> class LLVMELFDumper : public ELFDumper<ELFT> {
bool /*ExtraSymInfo*/) const override;
void printProgramHeaders() override;
void printSectionMapping() override {}
- void printStackSizeEntry(uint64_t Size,
- ArrayRef<std::string> FuncNames) override;
+ void printStackSizeEntry(uint64_t Size, ArrayRef<std::string> FuncNames,
+ uint64_t Address) override;
void printCallGraphRelocation(const CallGraphFunc<ELFT> &Func,
const Elf_Shdr &RelSec, const Elf_Shdr &SymTab);
// Returns the names of the functions at the address that the relocation for
@@ -7258,12 +7262,12 @@ bool ELFDumper<ELFT>::printFunctionStackSize(
}
if (FuncSymIndexes.empty()) {
- printStackSizeEntry(StackSize, {"?"});
+ printStackSizeEntry(StackSize, {"?"}, SymValue);
} else {
SmallVector<std::string> FuncSymNames;
for (uint32_t Index : FuncSymIndexes)
FuncSymNames.push_back(this->getStaticSymbolName(Index));
- printStackSizeEntry(StackSize, FuncSymNames);
+ printStackSizeEntry(StackSize, FuncSymNames, SymValue);
}
return true;
@@ -7271,7 +7275,8 @@ bool ELFDumper<ELFT>::printFunctionStackSize(
template <class ELFT>
void GNUELFDumper<ELFT>::printStackSizeEntry(uint64_t Size,
- ArrayRef<std::string> FuncNames) {
+ ArrayRef<std::string> FuncNames,
+ uint64_t /*Address*/) {
OS.PadToColumn(2);
OS << format_decimal(Size, 11);
OS.PadToColumn(18);
@@ -9001,9 +9006,14 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printStackSizes() {
template <class ELFT>
void LLVMELFDumper<ELFT>::printStackSizeEntry(uint64_t Size,
- ArrayRef<std::string> FuncNames) {
+ ArrayRef<std::string> FuncNames,
+ uint64_t Address) {
DictScope D(W, "Entry");
W.printList("Functions", FuncNames);
+ // In a linked file, the function is identified by its address, as in
+ // --call-graph-info.
+ if (this->Obj.getHeader().e_type != ELF::ET_REL)
+ W.printHex("Address", Address);
W.printHex("Size", Size);
}
>From bfa7a558d45d3cf34aa78e288e584a3288c4d4e4 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Thu, 15 Oct 2026 14:32:07 -0700
Subject: [PATCH 2/4] Document printStackSizeEntry and say when Address is
printed
---
llvm/tools/llvm-readobj/ELFDumper.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 889ea7b2cc5380..80e7190f19fdb4 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -368,9 +368,9 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
unsigned Ndx, const Elf_Shdr *SymTab,
const Elf_Shdr *FunctionSec, const Elf_Shdr &StackSizeSec,
const RelocationResolver &Resolver, DataExtractor Data);
- // Prints a stack size entry. Address is the function's address: the value
- // stored in the entry in a linked file, or the value that its relocation
- // resolves to in a relocatable file.
+ /// Prints a stack size entry for the functions in \p FuncNames. \p Address
+ /// is the function's address: the value stored in the entry in a linked
+ /// file, or the value that its relocation resolves to in a relocatable file.
virtual void printStackSizeEntry(uint64_t Size,
ArrayRef<std::string> FuncNames,
uint64_t Address) = 0;
@@ -9009,8 +9009,8 @@ void LLVMELFDumper<ELFT>::printStackSizeEntry(uint64_t Size,
uint64_t Address) {
DictScope D(W, "Entry");
W.printList("Functions", FuncNames);
- // In a linked file, the function is identified by its address, as in
- // --call-graph-info.
+ // Print the address only for a linked file. In a relocatable file the field
+ // holds a placeholder for the relocation that applies to it.
if (this->Obj.getHeader().e_type != ELF::ET_REL)
W.printHex("Address", Address);
W.printHex("Size", Size);
>From cbb430151cc43f37582b0d818a7bd0d85379c0ca Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Fri, 16 Oct 2026 15:36:45 -0700
Subject: [PATCH 3/4] Say why Address is not printed for a relocatable file
---
llvm/tools/llvm-readobj/ELFDumper.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 2798524413c219..07967217a98185 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -9007,8 +9007,8 @@ void LLVMELFDumper<ELFT>::printStackSizeEntry(uint64_t Size,
uint64_t Address) {
DictScope D(W, "Entry");
W.printList("Functions", FuncNames);
- // Print the address only for a linked file. In a relocatable file the field
- // holds a placeholder for the relocation that applies to it.
+ // Print the address only for a linked file. In a relocatable file the value
+ // stored in the entry is just the implicit addend of its relocation.
if (this->Obj.getHeader().e_type != ELF::ET_REL)
W.printHex("Address", Address);
W.printHex("Size", Size);
>From 15958e0a4758d3435b4742ba9c4c3b07751c420f Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Mon, 19 Oct 2026 04:43:03 -0700
Subject: [PATCH 4/4] Pass the address to printStackSizeEntry only for a linked
file
The printer no longer decides based on the file type, and the comments
no longer describe the value in a relocatable file.
---
llvm/tools/llvm-readobj/ELFDumper.cpp | 33 +++++++++++++++------------
1 file changed, 18 insertions(+), 15 deletions(-)
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 07967217a98185..751c6af06c1506 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -377,11 +377,11 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
const Elf_Shdr *FunctionSec, const Elf_Shdr &StackSizeSec,
const RelocationResolver &Resolver, DataExtractor Data);
/// Prints a stack size entry for the functions in \p FuncNames. \p Address
- /// is the function's address: the value stored in the entry in a linked
- /// file, or the value that its relocation resolves to in a relocatable file.
+ /// is the function's address as stored in the entry, and is only set for a
+ /// linked file.
virtual void printStackSizeEntry(uint64_t Size,
ArrayRef<std::string> FuncNames,
- uint64_t Address) = 0;
+ std::optional<uint64_t> Address) = 0;
void printRelocatableStackSizes(std::function<void()> PrintHeader);
void printNonRelocatableStackSizes(std::function<void()> PrintHeader);
@@ -762,7 +762,7 @@ template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> {
const Twine &Label, unsigned EntriesNum);
void printStackSizeEntry(uint64_t Size, ArrayRef<std::string> FuncNames,
- uint64_t Address) override;
+ std::optional<uint64_t> Address) override;
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
@@ -819,7 +819,7 @@ template <typename ELFT> class LLVMELFDumper : public ELFDumper<ELFT> {
void printProgramHeaders() override;
void printSectionMapping() override {}
void printStackSizeEntry(uint64_t Size, ArrayRef<std::string> FuncNames,
- uint64_t Address) override;
+ std::optional<uint64_t> Address) override;
void printCallGraphRelocation(const CallGraphFunc<ELFT> &Func,
const Elf_Shdr &RelSec, const Elf_Shdr &SymTab);
// Returns the names of the functions at the address that the relocation for
@@ -7266,22 +7266,27 @@ bool ELFDumper<ELFT>::printFunctionStackSize(
return false;
}
+ // The address is only printed for a linked file. In a relocatable file the
+ // entry holds a placeholder for its relocation rather than an address.
+ std::optional<uint64_t> Address;
+ if (Obj.getHeader().e_type != ELF::ET_REL)
+ Address = SymValue;
if (FuncSymIndexes.empty()) {
- printStackSizeEntry(StackSize, {"?"}, SymValue);
+ printStackSizeEntry(StackSize, {"?"}, Address);
} else {
SmallVector<std::string> FuncSymNames;
for (uint32_t Index : FuncSymIndexes)
FuncSymNames.push_back(this->getStaticSymbolName(Index));
- printStackSizeEntry(StackSize, FuncSymNames, SymValue);
+ printStackSizeEntry(StackSize, FuncSymNames, Address);
}
return true;
}
template <class ELFT>
-void GNUELFDumper<ELFT>::printStackSizeEntry(uint64_t Size,
- ArrayRef<std::string> FuncNames,
- uint64_t /*Address*/) {
+void GNUELFDumper<ELFT>::printStackSizeEntry(
+ uint64_t Size, ArrayRef<std::string> FuncNames,
+ std::optional<uint64_t> /*Address*/) {
OS.PadToColumn(2);
OS << format_decimal(Size, 11);
OS.PadToColumn(18);
@@ -9004,13 +9009,11 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printStackSizes() {
template <class ELFT>
void LLVMELFDumper<ELFT>::printStackSizeEntry(uint64_t Size,
ArrayRef<std::string> FuncNames,
- uint64_t Address) {
+ std::optional<uint64_t> Address) {
DictScope D(W, "Entry");
W.printList("Functions", FuncNames);
- // Print the address only for a linked file. In a relocatable file the value
- // stored in the entry is just the implicit addend of its relocation.
- if (this->Obj.getHeader().e_type != ELF::ET_REL)
- W.printHex("Address", Address);
+ if (Address)
+ W.printHex("Address", *Address);
W.printHex("Size", Size);
}
More information about the llvm-branch-commits
mailing list