diff --git a/llvm/test/tools/llvm-objdump/MachO/function-starts.test b/llvm/test/tools/llvm-objdump/MachO/function-starts.test --- a/llvm/test/tools/llvm-objdump/MachO/function-starts.test +++ b/llvm/test/tools/llvm-objdump/MachO/function-starts.test @@ -1,7 +1,21 @@ ## 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 diff --git a/llvm/tools/llvm-objdump/MachODump.h b/llvm/tools/llvm-objdump/MachODump.h --- a/llvm/tools/llvm-objdump/MachODump.h +++ b/llvm/tools/llvm-objdump/MachODump.h @@ -32,6 +32,8 @@ void parseMachOOptions(const llvm::opt::InputArgList &InputArgs); +enum FunctionStartsMode { FSAddrs, FSNames, FSBoth, FSNone }; + // MachO specific options extern bool Bind; extern bool DataInCode; @@ -41,7 +43,7 @@ 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/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -78,7 +78,7 @@ static bool ArchiveMemberOffsets; bool objdump::IndirectSymbols; bool objdump::DataInCode; -bool objdump::FunctionStarts; +FunctionStartsMode objdump::FunctionStartsType = FSNone; bool objdump::LinkOptHints; bool objdump::InfoPlist; bool objdump::DylibsUsed; @@ -108,7 +108,15 @@ 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(A->getValue()) + .Case("addrs", FSAddrs) + .Case("names", FSNames) + .Case("both", FSBoth) + .Default(FSNone); + if (FunctionStartsType == FSNone) + invalidArgValue(A); + } LinkOptHints = InputArgs.hasArg(OBJDUMP_link_opt_hints); InfoPlist = InputArgs.hasArg(OBJDUMP_info_plist); DylibsUsed = InputArgs.hasArg(OBJDUMP_dylibs_used); @@ -1074,12 +1082,34 @@ } } + DenseMap SymbolNames; + if (FunctionStartsType == FSNames || FunctionStartsType == FSBoth) { + for (SymbolRef Sym : O->symbols()) { + if (Expected Addr = Sym.getAddress()) { + if (Expected 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(Addr)) << "\n"; + if (FunctionStartsType == FSNames) { + 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(Addr)); + + if (FunctionStartsType == FSBoth) { + outs() << " " << SymbolNames.lookup(Addr); + } + outs() << "\n"; + } } } @@ -1900,8 +1930,9 @@ // UniversalHeaders or ArchiveHeaders. if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase || Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols || - DataInCode || FunctionStarts || LinkOptHints || DylibsUsed || DylibId || - Rpaths || ObjcMetaData || (!FilterSections.empty())) { + DataInCode || FunctionStartsType != FSNone || LinkOptHints || + DylibsUsed || DylibId || Rpaths || ObjcMetaData || + (!FilterSections.empty())) { if (LeadingHeaders) { outs() << Name; if (!ArchiveMemberName.empty()) @@ -1956,7 +1987,7 @@ PrintIndirectSymbols(MachOOF, Verbose); if (DataInCode) PrintDataInCodeTable(MachOOF, Verbose); - if (FunctionStarts) + if (FunctionStartsType != FSNone) PrintFunctionStarts(MachOOF); if (LinkOptHints) PrintLinkOptHints(MachOOF); diff --git a/llvm/tools/llvm-objdump/ObjdumpOpts.td b/llvm/tools/llvm-objdump/ObjdumpOpts.td --- a/llvm/tools/llvm-objdump/ObjdumpOpts.td +++ b/llvm/tools/llvm-objdump/ObjdumpOpts.td @@ -281,11 +281,15 @@ HelpText<"Print the data in code table for Mach-O objects (requires --macho)">, Group; -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; +def : Flag<["--"], "function-starts">, Alias, + AliasArgs<["addrs"]>, Group; + 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.h b/llvm/tools/llvm-objdump/llvm-objdump.h --- a/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/llvm/tools/llvm-objdump/llvm-objdump.h @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/DIContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" #include "llvm/Object/Archive.h" +#include "llvm/Option/Arg.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" @@ -146,6 +147,8 @@ reportError(EO.takeError(), std::forward(Args)...); } +void invalidArgValue(const llvm::opt::Arg *A); + std::string getFileNameForError(const object::Archive::Child &C, unsigned Index); SymbolInfoTy createSymbolInfo(const object::ObjectFile *Obj, diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -2503,7 +2503,7 @@ } } -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() + "'"); } @@ -2759,9 +2759,10 @@ !DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !(MachOOpt && (Bind || DataInCode || DylibId || DylibsUsed || ExportsTrie || - FirstPrivateHeader || FunctionStarts || IndirectSymbols || InfoPlist || - LazyBind || LinkOptHints || ObjcMetaData || Rebase || Rpaths || - UniversalHeaders || WeakBind || !FilterSections.empty()))) { + FirstPrivateHeader || FunctionStartsType != FSNone || + IndirectSymbols || InfoPlist || LazyBind || LinkOptHints || + ObjcMetaData || Rebase || Rpaths || UniversalHeaders || WeakBind || + !FilterSections.empty()))) { T->printHelp(ToolName); return 2; }