[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
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)">,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user