[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