[llvm] [llvm-otool] Add -function_offsets option (PR #196727)
Ryan Mansfield via llvm-commits
llvm-commits at lists.llvm.org
Sat May 9 07:18:36 PDT 2026
https://github.com/rjmansfield created https://github.com/llvm/llvm-project/pull/196727
Print the decimal offset from the last label before each disassembled instruction, matching classic otool behaviour.
>From d50b0880ca4d11ce592f765ca803b5863e3fefbe Mon Sep 17 00:00:00 2001
From: Ryan Mansfield <ryan_mansfield at apple.com>
Date: Sat, 9 May 2026 10:15:31 -0400
Subject: [PATCH] [llvm-otool] Add -function_offsets option
Print the decimal offset from the last label before each
disassembled instruction, matching classic otool behaviour.
---
llvm/docs/CommandGuide/llvm-otool.rst | 4 ++++
.../llvm-objdump/MachO/otool-function-offsets.test | 10 ++++++++++
llvm/tools/llvm-objdump/MachODump.cpp | 11 ++++++++++-
llvm/tools/llvm-objdump/MachODump.h | 1 +
llvm/tools/llvm-objdump/OtoolOpts.td | 3 ++-
llvm/tools/llvm-objdump/llvm-objdump.cpp | 2 ++
6 files changed, 29 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/tools/llvm-objdump/MachO/otool-function-offsets.test
diff --git a/llvm/docs/CommandGuide/llvm-otool.rst b/llvm/docs/CommandGuide/llvm-otool.rst
index 17aa9089b3875..842f3be47a4b9 100644
--- a/llvm/docs/CommandGuide/llvm-otool.rst
+++ b/llvm/docs/CommandGuide/llvm-otool.rst
@@ -51,6 +51,10 @@ OPTIONS
Print universal headers.
+.. option:: -function_offsets
+
+ Print the decimal offset from the last label when disassembling.
+
.. option:: -G
Print data-in-code table.
diff --git a/llvm/test/tools/llvm-objdump/MachO/otool-function-offsets.test b/llvm/test/tools/llvm-objdump/MachO/otool-function-offsets.test
new file mode 100644
index 0000000000000..aa21678a77da1
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/MachO/otool-function-offsets.test
@@ -0,0 +1,10 @@
+# Test that -function_offsets prints decimal offsets from last label.
+
+RUN: llvm-otool -function_offsets -v -t %p/Inputs/bind.macho-x86_64 \
+RUN: | FileCheck %s
+
+CHECK: _myfunc:
+CHECK-NEXT: +0 {{[0-9a-f]+}} pushq %rbp
+CHECK-NEXT: +1 {{[0-9a-f]+}} movq %rsp, %rbp
+CHECK-NEXT: +4 {{[0-9a-f]+}} popq %rbp
+CHECK-NEXT: +5 {{[0-9a-f]+}} retq
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index 8b5a56b0db095..2eafffab24acd 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -83,6 +83,7 @@ std::string objdump::DisSymName;
bool objdump::IsOtool;
bool objdump::UseMemberSyntax;
bool objdump::SymbolicOperands;
+bool objdump::FunctionOffsets;
std::vector<std::string> objdump::ArchFlags;
static bool ArchAll = false;
@@ -7709,14 +7710,17 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
outs() << SymName << ":\n";
DILineInfo lastLine;
+ uint64_t LabelOffset = Start;
for (uint64_t Index = Start; Index < End; Index += Size) {
MCInst Inst;
// If this is the first symbol in the section and it was not at the
// start of the section, see if we are at its Index now and if so print
// the symbol name.
- if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart)
+ if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart) {
outs() << SymName << ":\n";
+ LabelOffset = SymbolStart;
+ }
uint64_t PC = SectAddress + Index;
@@ -7725,6 +7729,9 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
SP->printSourceLine(FOS, {PC, SectIdx}, Filename, *LEP);
}
+ if (FunctionOffsets)
+ outs() << format("%+6" PRId64 " ", (int64_t)(Index - LabelOffset));
+
if (LeadingAddr) {
if (FullLeadingAddr) {
if (MachOOF->is64Bit())
@@ -7828,6 +7835,8 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
raw_svector_ostream Annotations(AnnotationsBytes);
if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,
Annotations)) {
+ if (FunctionOffsets)
+ outs() << format("%+6" PRId64 " ", (int64_t)Index);
if (LeadingAddr) {
if (FullLeadingAddr) {
if (MachOOF->is64Bit())
diff --git a/llvm/tools/llvm-objdump/MachODump.h b/llvm/tools/llvm-objdump/MachODump.h
index b9a316a4deb16..34eee36aa4742 100644
--- a/llvm/tools/llvm-objdump/MachODump.h
+++ b/llvm/tools/llvm-objdump/MachODump.h
@@ -48,6 +48,7 @@ extern bool DylibsUsed;
extern bool ExportsTrie;
extern bool FirstPrivateHeader;
extern bool FullLeadingAddr;
+extern bool FunctionOffsets;
extern FunctionStartsMode FunctionStartsType;
extern bool IndirectSymbols;
extern bool InfoPlist;
diff --git a/llvm/tools/llvm-objdump/OtoolOpts.td b/llvm/tools/llvm-objdump/OtoolOpts.td
index e14c09aee42f4..9b82b311340d2 100644
--- a/llvm/tools/llvm-objdump/OtoolOpts.td
+++ b/llvm/tools/llvm-objdump/OtoolOpts.td
@@ -45,12 +45,13 @@ def dyld_info : Flag<["-"], "dyld_info">,
def m : Flag<["-"], "m">,
HelpText<"don't use archive(member) syntax">;
+def function_offsets : Flag<["-"], "function_offsets">,
+ HelpText<"print decimal offset from last label when disassembling">;
// Not (yet?) implemented:
// -c print argument strings of a core file
// -dyld_opcodes
// -addr_slide=arg
-// -function_offsets
// Obsolete and unsupported:
def grp_obsolete : OptionGroup<"kind">,
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 8c090ba1e29e7..3e1bf281758a8 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -3694,6 +3694,8 @@ static void parseOtoolOptions(const llvm::opt::InputArgList &InputArgs) {
UseMemberSyntax = !InputArgs.hasArg(OTOOL_m);
+ FunctionOffsets = InputArgs.hasArg(OTOOL_function_offsets);
+
InputFilenames = InputArgs.getAllArgValues(OTOOL_INPUT);
if (InputFilenames.empty())
reportCmdLineError("no input file");
More information about the llvm-commits
mailing list