[llvm] bc99fd9 - [llvm-objdump/mac] Add new function starts print mode
Keith Smiley via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 14 15:45:26 PDT 2022
Author: Keith Smiley
Date: 2022-10-14T15:42:18-07:00
New Revision: bc99fd95e090a406a16fe431047d8b7d59af7dc0
URL: https://github.com/llvm/llvm-project/commit/bc99fd95e090a406a16fe431047d8b7d59af7dc0
DIFF: https://github.com/llvm/llvm-project/commit/bc99fd95e090a406a16fe431047d8b7d59af7dc0.diff
LOG: [llvm-objdump/mac] Add new function starts print mode
This updates the `--function-starts` argument to now accept 3 different
modes, `addrs` for just printing the addresses of the function starts
(previous behavior), `names` for just printing the names of the function
starts, and `both` to print them both side by side.
In general if you're debugging function starts issues it's useful to see
the symbol name alongside the address. This also mirrors Apple's
`dyldinfo -function_starts` command which prints both.
Differential Revision: https://reviews.llvm.org/D119050
Added:
Modified:
llvm/docs/CommandGuide/llvm-objdump.rst
llvm/test/tools/llvm-objdump/MachO/function-starts.test
llvm/tools/llvm-objdump/MachODump.cpp
llvm/tools/llvm-objdump/MachODump.h
llvm/tools/llvm-objdump/ObjdumpOpts.td
llvm/tools/llvm-objdump/llvm-objdump.cpp
llvm/tools/llvm-objdump/llvm-objdump.h
Removed:
################################################################################
diff --git a/llvm/docs/CommandGuide/llvm-objdump.rst b/llvm/docs/CommandGuide/llvm-objdump.rst
index 7879ac163b10..65a26bb3da84 100644
--- a/llvm/docs/CommandGuide/llvm-objdump.rst
+++ b/llvm/docs/CommandGuide/llvm-objdump.rst
@@ -356,9 +356,12 @@ MACH-O ONLY OPTIONS AND COMMANDS
Display exported symbols.
-.. option:: --function-starts
+.. option:: --function-starts [=<addrs|names|both>]
- Print the function starts table for Mach-O objects.
+ Print the function starts table for Mach-O objects. Either ``addrs``
+ (default) to print only the addresses of functions, ``names`` to print only
+ the names of the functions (when available), or ``both`` to print the
+ names beside the addresses.
.. option:: -g
diff --git a/llvm/test/tools/llvm-objdump/MachO/function-starts.test b/llvm/test/tools/llvm-objdump/MachO/function-starts.test
index a9cab10d3497..8c013174c4ec 100644
--- a/llvm/test/tools/llvm-objdump/MachO/function-starts.test
+++ b/llvm/test/tools/llvm-objdump/MachO/function-starts.test
@@ -1,7 +1,30 @@
## This test verifies that llvm-objdump correctly prints function starts data.
-RUN: llvm-objdump --macho --function-starts %p/Inputs/hello.exe.macho-i386 | FileCheck %s --check-prefix=32-BIT
+RUN: llvm-objdump --macho --function-starts %p/Inputs/hello.exe.macho-i386 | FileCheck %s --check-prefix=32-BIT --implicit-check-not=_main
+RUN: llvm-objdump --macho --function-starts=addrs %p/Inputs/hello.exe.macho-i386 | FileCheck %s --check-prefix=32-BIT --implicit-check-not=_main
32-BIT: 00001f40
-RUN: llvm-objdump --macho --function-starts %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s --check-prefix=64-BIT
+RUN: llvm-objdump --macho --function-starts=names %p/Inputs/hello.exe.macho-i386 | FileCheck %s --check-prefix=32-BIT-NAMES
+32-BIT-NAMES: {{^}}_main
+
+RUN: llvm-objdump --macho --function-starts=both %p/Inputs/hello.exe.macho-i386 | FileCheck %s --check-prefix=32-BIT-BOTH
+32-BIT-BOTH: 00001f40 _main
+
+RUN: llvm-objdump --macho --function-starts %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s --check-prefix=64-BIT --implicit-check-not=_main
+RUN: llvm-objdump --macho --function-starts=addrs %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s --check-prefix=64-BIT --implicit-check-not=_main
64-BIT: 0000000100000f30
+
+RUN: llvm-objdump --macho --function-starts=names %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s --check-prefix=64-BIT-NAMES
+64-BIT-NAMES: {{^}}_main
+
+RUN: llvm-objdump --macho --function-starts=both %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s --check-prefix=64-BIT-BOTH
+64-BIT-BOTH: 0000000100000f30 _main
+
+RUN: llvm-strip %p/Inputs/hello.exe.macho-x86_64 -o %t.stripped
+RUN: llvm-objdump --macho --function-starts=both %t.stripped | FileCheck %s --check-prefix=BOTH-STRIPPED
+BOTH-STRIPPED: 0000000100000f30 ?
+
+RUN: llvm-strip %p/Inputs/hello.exe.macho-x86_64 -o %t.stripped
+RUN: llvm-objdump --macho --function-starts=names %t.stripped | FileCheck %s --check-prefix=NAMES-STRIPPED
+NAMES-STRIPPED: function-starts.test.tmp.stripped:
+NAMES-STRIPPED-EMPTY:
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index 4637b09787b7..3164159da062 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -78,7 +78,8 @@ bool objdump::UniversalHeaders;
static bool ArchiveMemberOffsets;
bool objdump::IndirectSymbols;
bool objdump::DataInCode;
-bool objdump::FunctionStarts;
+FunctionStartsMode objdump::FunctionStartsType =
+ objdump::FunctionStartsMode::None;
bool objdump::LinkOptHints;
bool objdump::InfoPlist;
bool objdump::ChainedFixups;
@@ -112,7 +113,15 @@ void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) {
ArchiveMemberOffsets = InputArgs.hasArg(OBJDUMP_archive_member_offsets);
IndirectSymbols = InputArgs.hasArg(OBJDUMP_indirect_symbols);
DataInCode = InputArgs.hasArg(OBJDUMP_data_in_code);
- FunctionStarts = InputArgs.hasArg(OBJDUMP_function_starts);
+ if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_function_starts_EQ)) {
+ FunctionStartsType = StringSwitch<FunctionStartsMode>(A->getValue())
+ .Case("addrs", FunctionStartsMode::Addrs)
+ .Case("names", FunctionStartsMode::Names)
+ .Case("both", FunctionStartsMode::Both)
+ .Default(FunctionStartsMode::None);
+ if (FunctionStartsType == FunctionStartsMode::None)
+ invalidArgValue(A);
+ }
LinkOptHints = InputArgs.hasArg(OBJDUMP_link_opt_hints);
InfoPlist = InputArgs.hasArg(OBJDUMP_info_plist);
ChainedFixups = InputArgs.hasArg(OBJDUMP_chained_fixups);
@@ -1080,12 +1089,39 @@ static void PrintFunctionStarts(MachOObjectFile *O) {
}
}
+ DenseMap<uint64_t, StringRef> SymbolNames;
+ if (FunctionStartsType == FunctionStartsMode::Names ||
+ FunctionStartsType == FunctionStartsMode::Both) {
+ for (SymbolRef Sym : O->symbols()) {
+ if (Expected<uint64_t> Addr = Sym.getAddress()) {
+ if (Expected<StringRef> Name = Sym.getName()) {
+ SymbolNames[*Addr] = *Name;
+ }
+ }
+ }
+ }
+
for (uint64_t S : FunctionStarts) {
uint64_t Addr = BaseSegmentAddress + S;
- if (O->is64Bit())
- outs() << format("%016" PRIx64, Addr) << "\n";
- else
- outs() << format("%08" PRIx32, static_cast<uint32_t>(Addr)) << "\n";
+ if (FunctionStartsType == FunctionStartsMode::Names) {
+ auto It = SymbolNames.find(Addr);
+ if (It != SymbolNames.end())
+ outs() << It->second << "\n";
+ } else {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, Addr);
+ else
+ outs() << format("%08" PRIx32, static_cast<uint32_t>(Addr));
+
+ if (FunctionStartsType == FunctionStartsMode::Both) {
+ auto It = SymbolNames.find(Addr);
+ if (It != SymbolNames.end())
+ outs() << " " << It->second;
+ else
+ outs() << " ?";
+ }
+ outs() << "\n";
+ }
}
}
@@ -2111,9 +2147,9 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
// UniversalHeaders or ArchiveHeaders.
if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||
Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||
- DataInCode || FunctionStarts || LinkOptHints || ChainedFixups ||
- DyldInfo || DylibsUsed || DylibId || Rpaths || ObjcMetaData ||
- (!FilterSections.empty())) {
+ DataInCode || FunctionStartsType != FunctionStartsMode::None ||
+ LinkOptHints || ChainedFixups || DyldInfo || DylibsUsed || DylibId ||
+ Rpaths || ObjcMetaData || (!FilterSections.empty())) {
if (LeadingHeaders) {
outs() << Name;
if (!ArchiveMemberName.empty())
@@ -2168,7 +2204,7 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
PrintIndirectSymbols(MachOOF, Verbose);
if (DataInCode)
PrintDataInCodeTable(MachOOF, Verbose);
- if (FunctionStarts)
+ if (FunctionStartsType != FunctionStartsMode::None)
PrintFunctionStarts(MachOOF);
if (LinkOptHints)
PrintLinkOptHints(MachOOF);
diff --git a/llvm/tools/llvm-objdump/MachODump.h b/llvm/tools/llvm-objdump/MachODump.h
index 2e2c2b8b7cc5..d9d3a70663f6 100644
--- a/llvm/tools/llvm-objdump/MachODump.h
+++ b/llvm/tools/llvm-objdump/MachODump.h
@@ -34,6 +34,8 @@ namespace objdump {
void parseMachOOptions(const llvm::opt::InputArgList &InputArgs);
+enum class FunctionStartsMode { Addrs, Names, Both, None };
+
// MachO specific options
extern bool Bind;
extern bool DataInCode;
@@ -45,7 +47,7 @@ extern bool DylibsUsed;
extern bool ExportsTrie;
extern bool FirstPrivateHeader;
extern bool FullLeadingAddr;
-extern bool FunctionStarts;
+extern FunctionStartsMode FunctionStartsType;
extern bool IndirectSymbols;
extern bool InfoPlist;
extern bool LazyBind;
diff --git a/llvm/tools/llvm-objdump/ObjdumpOpts.td b/llvm/tools/llvm-objdump/ObjdumpOpts.td
index 46eefa1edbb1..205bb94981e4 100644
--- a/llvm/tools/llvm-objdump/ObjdumpOpts.td
+++ b/llvm/tools/llvm-objdump/ObjdumpOpts.td
@@ -305,11 +305,15 @@ def data_in_code : Flag<["--"], "data-in-code">,
HelpText<"Print the data in code table for Mach-O objects (requires --macho)">,
Group<grp_mach_o>;
-def function_starts : Flag<["--"], "function-starts">,
- HelpText<"Print the function starts table for "
- "Mach-O objects (requires --macho)">,
+def function_starts_EQ : Joined<["--"], "function-starts=">,
+ HelpText<"Print the function starts table for Mach-O objects. "
+ "Options: addrs (default), names, both (requires --macho)">,
+ Values<"addrs,names,both">,
Group<grp_mach_o>;
+def : Flag<["--"], "function-starts">, Alias<function_starts_EQ>,
+ AliasArgs<["addrs"]>, Group<grp_mach_o>;
+
def link_opt_hints : Flag<["--"], "link-opt-hints">,
HelpText<"Print the linker optimization hints for "
"Mach-O objects (requires --macho)">,
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index aa3c053cf4aa..efa64ede5071 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -2928,7 +2928,7 @@ static object::BuildID parseBuildIDArg(const opt::Arg *A) {
return object::BuildID(BuildID.begin(), BuildID.end());
}
-static void invalidArgValue(const opt::Arg *A) {
+void objdump::invalidArgValue(const opt::Arg *A) {
reportCmdLineError("'" + StringRef(A->getValue()) +
"' is not a valid value for '" + A->getSpelling() + "'");
}
@@ -3217,10 +3217,10 @@ int main(int argc, char **argv) {
!DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !Offloading &&
!(MachOOpt &&
(Bind || DataInCode || ChainedFixups || DyldInfo || DylibId ||
- DylibsUsed || ExportsTrie || FirstPrivateHeader || FunctionStarts ||
- IndirectSymbols || InfoPlist || LazyBind || LinkOptHints ||
- ObjcMetaData || Rebase || Rpaths || UniversalHeaders || WeakBind ||
- !FilterSections.empty()))) {
+ DylibsUsed || ExportsTrie || FirstPrivateHeader ||
+ FunctionStartsType != FunctionStartsMode::None || IndirectSymbols ||
+ InfoPlist || LazyBind || LinkOptHints || ObjcMetaData || Rebase ||
+ Rpaths || UniversalHeaders || WeakBind || !FilterSections.empty()))) {
T->printHelp(ToolName);
return 2;
}
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h
index c64c042d513e..efb445195259 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.h
+++ b/llvm/tools/llvm-objdump/llvm-objdump.h
@@ -20,6 +20,10 @@ namespace llvm {
class StringRef;
class Twine;
+namespace opt {
+class Arg;
+} // namespace opt
+
namespace object {
class RelocationRef;
struct VersionEntry;
@@ -146,6 +150,8 @@ T unwrapOrError(Expected<T> EO, Ts &&... Args) {
reportError(EO.takeError(), std::forward<Ts>(Args)...);
}
+void invalidArgValue(const opt::Arg *A);
+
std::string getFileNameForError(const object::Archive::Child &C,
unsigned Index);
SymbolInfoTy createSymbolInfo(const object::ObjectFile &Obj,
More information about the llvm-commits
mailing list