Add the -section option to llvm-objdump used with -macho that takes the argument

segname,sectname to specify a Mach-O section to print.  The printing is based on
the section type or section attributes.

The printing of the module initialization and termination section types is printed
with this change.  Printing of other section types will be added next.

llvm-svn: 227649
This commit is contained in:
Kevin Enderby 2015-01-31 00:37:11 +00:00
parent 295596a0a7
commit f6d258537d
5 changed files with 207 additions and 25 deletions

View File

@ -0,0 +1,4 @@
// RUN: llvm-objdump -m -section __DATA,__mod_init_func %p/Inputs/dylibModInit.macho-x86_64 | FileCheck %s -check-prefix=MODINIT
MODINIT: Contents of (__DATA,__mod_init_func) section
MODINIT: 0x0000000000001000 0x0000000000000f30 _libinit

View File

@ -91,6 +91,11 @@ cl::opt<bool>
cl::desc("Print the linker optimization hints for "
"Mach-O objects (requires -macho)"));
cl::list<std::string>
llvm::DumpSections("section",
cl::desc("Prints the specified segment,section for "
"Mach-O objects (requires -macho)"));
static cl::list<std::string>
ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
cl::ZeroOrMore);
@ -499,6 +504,190 @@ static void PrintLinkOptHints(MachOObjectFile *O) {
}
}
typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
static void CreateSymbolAddressMap(MachOObjectFile *O,
SymbolAddressMap *AddrMap) {
// Create a map of symbol addresses to symbol names.
for (const SymbolRef &Symbol : O->symbols()) {
SymbolRef::Type ST;
Symbol.getType(ST);
if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
ST == SymbolRef::ST_Other) {
uint64_t Address;
Symbol.getAddress(Address);
StringRef SymName;
Symbol.getName(SymName);
(*AddrMap)[Address] = SymName;
}
}
}
// GuessSymbolName is passed the address of what might be a symbol and a
// pointer to the SymbolAddressMap. It returns the name of a symbol
// with that address or nullptr if no symbol is found with that address.
static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {
const char *SymbolName = nullptr;
// A DenseMap can't lookup up some values.
if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
StringRef name = AddrMap->lookup(value);
if (!name.empty())
SymbolName = name.data();
}
return SymbolName;
}
static void DumpInitTermPointerSection(MachOObjectFile *O, const char *sect,
uint32_t sect_size, uint64_t sect_addr,
SymbolAddressMap *AddrMap,
bool verbose) {
uint32_t stride;
if (O->is64Bit())
stride = sizeof(uint64_t);
else
stride = sizeof(uint32_t);
for (uint32_t i = 0; i < sect_size; i += stride) {
const char *SymbolName = nullptr;
if (O->is64Bit()) {
outs() << format("0x%016" PRIx64, sect_addr + i * stride) << " ";
uint64_t pointer_value;
memcpy(&pointer_value, sect + i, stride);
if (O->isLittleEndian() != sys::IsLittleEndianHost)
sys::swapByteOrder(pointer_value);
outs() << format("0x%016" PRIx64, pointer_value);
if (verbose)
SymbolName = GuessSymbolName(pointer_value, AddrMap);
} else {
outs() << format("0x%08" PRIx64, sect_addr + i * stride) << " ";
uint32_t pointer_value;
memcpy(&pointer_value, sect + i, stride);
if (O->isLittleEndian() != sys::IsLittleEndianHost)
sys::swapByteOrder(pointer_value);
outs() << format("0x%08" PRIx32, pointer_value);
if (verbose)
SymbolName = GuessSymbolName(pointer_value, AddrMap);
}
if (SymbolName)
outs() << " " << SymbolName;
outs() << "\n";
}
}
static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,
uint32_t size, uint64_t addr) {
uint32_t cputype = O->getHeader().cputype;
if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {
uint32_t j;
for (uint32_t i = 0; i < size; i += j, addr += j) {
if (O->is64Bit())
outs() << format("%016" PRIx64, addr) << "\t";
else
outs() << format("%08" PRIx64, sect) << "\t";
for (j = 0; j < 16 && i + j < size; j++) {
uint8_t byte_word = *(sect + i + j);
outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
}
outs() << "\n";
}
} else {
uint32_t j;
for (uint32_t i = 0; i < size; i += j, addr += j) {
if (O->is64Bit())
outs() << format("%016" PRIx64, addr) << "\t";
else
outs() << format("%08" PRIx64, sect) << "\t";
for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;
j += sizeof(int32_t)) {
if (i + j + sizeof(int32_t) < size) {
uint32_t long_word;
memcpy(&long_word, sect + i + j, sizeof(int32_t));
if (O->isLittleEndian() != sys::IsLittleEndianHost)
sys::swapByteOrder(long_word);
outs() << format("%08" PRIx32, long_word) << " ";
} else {
for (uint32_t k = 0; i + j + k < size; k++) {
uint8_t byte_word = *(sect + i + j);
outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
}
}
}
outs() << "\n";
}
}
}
static void DumpSectionContents(MachOObjectFile *O, bool verbose) {
SymbolAddressMap AddrMap;
if (verbose)
CreateSymbolAddressMap(O, &AddrMap);
for (unsigned i = 0; i < DumpSections.size(); ++i) {
StringRef DumpSection = DumpSections[i];
std::pair<StringRef, StringRef> DumpSegSectName;
DumpSegSectName = DumpSection.split(',');
StringRef DumpSegName, DumpSectName;
if (DumpSegSectName.second.size()) {
DumpSegName = DumpSegSectName.first;
DumpSectName = DumpSegSectName.second;
} else {
DumpSegName = "";
DumpSectName = DumpSegSectName.first;
}
for (const SectionRef &Section : O->sections()) {
StringRef SectName;
Section.getName(SectName);
DataRefImpl Ref = Section.getRawDataRefImpl();
StringRef SegName = O->getSectionFinalSegmentName(Ref);
if ((DumpSegName.empty() || SegName == DumpSegName) &&
(SectName == DumpSectName)) {
outs() << "Contents of (" << SegName << "," << SectName
<< ") section\n";
uint32_t section_type;
if (O->is64Bit()) {
const MachO::section_64 Sec = O->getSection64(Ref);
section_type = Sec.flags & MachO::SECTION_TYPE;
} else {
const MachO::section Sec = O->getSection(Ref);
section_type = Sec.flags & MachO::SECTION_TYPE;
}
StringRef BytesStr;
Section.getContents(BytesStr);
const char *sect = reinterpret_cast<const char *>(BytesStr.data());
uint32_t sect_size = BytesStr.size();
uint64_t sect_addr = Section.getAddress();
if (verbose) {
switch (section_type) {
case MachO::S_REGULAR:
DumpRawSectionContents(O, sect, sect_size, sect_addr);
break;
case MachO::S_ZEROFILL:
outs() << "zerofill section and has no contents in the file\n";
break;
case MachO::S_MOD_INIT_FUNC_POINTERS:
case MachO::S_MOD_TERM_FUNC_POINTERS:
DumpInitTermPointerSection(O, sect, sect_size, sect_addr, &AddrMap,
verbose);
break;
default:
outs() << "Unknown section type ("
<< format("0x%08" PRIx32, section_type) << ")\n";
DumpRawSectionContents(O, sect, sect_size, sect_addr);
break;
}
} else {
if (section_type == MachO::S_ZEROFILL)
outs() << "zerofill section and has no contents in the file\n";
else
DumpRawSectionContents(O, sect, sect_size, sect_addr);
}
}
}
}
}
// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file
// and if it is and there is a list of architecture flags is specified then
// check to make sure this Mach-O file is one of those architectures or all
@ -546,7 +735,8 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF,
// info. And don't print it otherwise like in the case of printing the
// UniversalHeaders or ArchiveHeaders.
if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind ||
LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints) {
LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints ||
DumpSections.size() != 0) {
outs() << Filename;
if (!ArchiveMemberName.empty())
outs() << '(' << ArchiveMemberName << ')';
@ -569,6 +759,8 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF,
PrintSectionHeaders(MachOOF);
if (SectionContents)
PrintSectionContents(MachOOF);
if (DumpSections.size() != 0)
DumpSectionContents(MachOOF, true);
if (SymbolTable)
PrintSymbolTable(MachOOF);
if (UnwindInfo)
@ -1045,7 +1237,6 @@ void llvm::ParseInputMachO(StringRef Filename) {
<< "Unrecognized file type.\n";
}
typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
typedef std::pair<uint64_t, const char *> BindInfoEntry;
typedef std::vector<BindInfoEntry> BindTable;
typedef BindTable::iterator bind_table_iterator;
@ -1066,21 +1257,6 @@ struct DisassembleInfo {
BindTable *bindtable;
};
// GuessSymbolName is passed the address of what might be a symbol and a
// pointer to the DisassembleInfo struct. It returns the name of a symbol
// with that address or nullptr if no symbol is found with that address.
static const char *GuessSymbolName(uint64_t value,
struct DisassembleInfo *info) {
const char *SymbolName = nullptr;
// A DenseMap can't lookup up some values.
if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
StringRef name = info->AddrMap->lookup(value);
if (!name.empty())
SymbolName = name.data();
}
return SymbolName;
}
// SymbolizerGetOpInfo() is the operand information call back function.
// This is called to get the symbolic information for operand(s) of an
// instruction when it is being done. This routine does this from
@ -1171,8 +1347,8 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
}
if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {
const char *add = GuessSymbolName(r_value, info);
const char *sub = GuessSymbolName(pair_r_value, info);
const char *add = GuessSymbolName(r_value, info->AddrMap);
const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
uint32_t offset = value - (r_value - pair_r_value);
op_info->AddSymbol.Present = 1;
if (add != nullptr)
@ -1373,8 +1549,8 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
else
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
const char *add = GuessSymbolName(r_value, info);
const char *sub = GuessSymbolName(pair_r_value, info);
const char *add = GuessSymbolName(r_value, info->AddrMap);
const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
int32_t offset = value - (r_value - pair_r_value);
op_info->AddSymbol.Present = 1;
if (add != nullptr)
@ -1403,7 +1579,7 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
}
}
const char *add = GuessSymbolName(value, info);
const char *add = GuessSymbolName(value, info->AddrMap);
if (add != nullptr) {
op_info->AddSymbol.Name = add;
return 1;
@ -1864,7 +2040,7 @@ const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
//
// NOTE: need add passing the ReferenceValue to this routine. Then that code
// would simply be this:
// SymbolName = GuessSymbolName(ReferenceValue, info);
// SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
return SymbolName;
}
@ -2207,7 +2383,7 @@ const char *SymbolizerSymbolLookUp(void *DisInfo, uint64_t ReferenceValue,
return nullptr;
}
const char *SymbolName = GuessSymbolName(ReferenceValue, info);
const char *SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {
*ReferenceName = GuessIndirectSymbol(ReferenceValue, info);

View File

@ -906,7 +906,8 @@ int main(int argc, char **argv) {
&& !(ArchiveHeaders && MachOOpt)
&& !(IndirectSymbols && MachOOpt)
&& !(DataInCode && MachOOpt)
&& !(LinkOptHints && MachOOpt)) {
&& !(LinkOptHints && MachOOpt)
&& !(DumpSections.size() != 0 && MachOOpt)) {
cl::PrintHelpMessage();
return 2;
}

View File

@ -26,6 +26,7 @@ extern cl::opt<std::string> TripleName;
extern cl::opt<std::string> ArchName;
extern cl::opt<std::string> MCPU;
extern cl::list<std::string> MAttrs;
extern cl::list<std::string> DumpSections;
extern cl::opt<bool> Disassemble;
extern cl::opt<bool> NoShowRawInsn;
extern cl::opt<bool> PrivateHeaders;