Make llvm-objdump handle both arm and thumb disassembly from the same Mach-O

file with -macho, the Mach-O specific object file parser option.

After some discussion I chose to do this implementation contained in the logic
of llvm-objdump’s MachODump.cpp using a second disassembler for thumb when
needed and with updates mostly contained in the MachOObjectFile class.

llvm-svn: 215931
This commit is contained in:
Kevin Enderby 2014-08-18 20:21:02 +00:00
parent a2d4b09a55
commit ec5ca03674
5 changed files with 185 additions and 13 deletions

View File

@ -137,6 +137,7 @@ public:
StringRef getFileFormatName() const override;
unsigned getArch() const override;
Triple getArch(const char **McpuDefault, Triple *ThumbTriple) const;
relocation_iterator section_rel_begin(unsigned Index) const;
relocation_iterator section_rel_end(unsigned Index) const;
@ -215,7 +216,12 @@ public:
StringRef &Suffix);
static Triple::ArchType getArch(uint32_t CPUType);
static Triple getArch(uint32_t CPUType, uint32_t CPUSubType);
static Triple getArch(uint32_t CPUType, uint32_t CPUSubType,
const char **McpuDefault = nullptr);
static Triple getThumbArch(uint32_t CPUType, uint32_t CPUSubType,
const char **McpuDefault = nullptr);
static Triple getArch(uint32_t CPUType, uint32_t CPUSubType,
const char **McpuDefault, Triple *ThumbTriple);
static bool isValidArch(StringRef ArchFlag);
static Triple getHostArch();

View File

@ -87,8 +87,9 @@ public:
SF_Absolute = 1U << 3, // Absolute symbol
SF_Common = 1U << 4, // Symbol has common linkage
SF_Indirect = 1U << 5, // Symbol is an alias to another symbol
SF_FormatSpecific = 1U << 6 // Specific to the object file format
SF_FormatSpecific = 1U << 6, // Specific to the object file format
// (e.g. section symbols)
SF_Thumb = 1U << 7 // Thumb symbol in a 32-bit ARM binary
};
BasicSymbolRef() : OwningObject(nullptr) { }

View File

@ -439,6 +439,9 @@ uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const {
if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF))
Result |= SymbolRef::SF_Weak;
if (MachOFlags & (MachO::N_ARM_THUMB_DEF))
Result |= SymbolRef::SF_Thumb;
if ((MachOType & MachO::N_TYPE) == MachO::N_ABS)
Result |= SymbolRef::SF_Absolute;
@ -1293,7 +1296,11 @@ Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) {
}
}
Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) {
Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType,
const char **McpuDefault) {
if (McpuDefault)
*McpuDefault = nullptr;
switch (CPUType) {
case MachO::CPU_TYPE_I386:
switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
@ -1322,14 +1329,20 @@ Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) {
case MachO::CPU_SUBTYPE_ARM_V6:
return Triple("armv6-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V6M:
if (McpuDefault)
*McpuDefault = "cortex-m0";
return Triple("armv6m-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7:
return Triple("armv7-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7EM:
if (McpuDefault)
*McpuDefault = "cortex-m4";
return Triple("armv7em-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7K:
return Triple("armv7k-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7M:
if (McpuDefault)
*McpuDefault = "cortex-m3";
return Triple("armv7m-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7S:
return Triple("armv7s-apple-darwin");
@ -1362,6 +1375,57 @@ Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) {
}
}
Triple MachOObjectFile::getThumbArch(uint32_t CPUType, uint32_t CPUSubType,
const char **McpuDefault) {
if (McpuDefault)
*McpuDefault = nullptr;
switch (CPUType) {
case MachO::CPU_TYPE_ARM:
switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
case MachO::CPU_SUBTYPE_ARM_V4T:
return Triple("thumbv4t-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V5TEJ:
return Triple("thumbv5e-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_XSCALE:
return Triple("xscale-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V6:
return Triple("thumbv6-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V6M:
if (McpuDefault)
*McpuDefault = "cortex-m0";
return Triple("thumbv6m-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7:
return Triple("thumbv7-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7EM:
if (McpuDefault)
*McpuDefault = "cortex-m4";
return Triple("thumbv7em-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7K:
return Triple("thumbv7k-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7M:
if (McpuDefault)
*McpuDefault = "cortex-m3";
return Triple("thumbv7m-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7S:
return Triple("thumbv7s-apple-darwin");
default:
return Triple();
}
default:
return Triple();
}
}
Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType,
const char **McpuDefault,
Triple *ThumbTriple) {
Triple T = MachOObjectFile::getArch(CPUType, CPUSubType, McpuDefault);
*ThumbTriple = MachOObjectFile::getThumbArch(CPUType, CPUSubType,
McpuDefault);
return T;
}
Triple MachOObjectFile::getHostArch() {
return Triple(sys::getDefaultTargetTriple());
}
@ -1390,6 +1454,25 @@ unsigned MachOObjectFile::getArch() const {
return getArch(getCPUType(this));
}
Triple MachOObjectFile::getArch(const char **McpuDefault,
Triple *ThumbTriple) const {
Triple T;
if (is64Bit()) {
MachO::mach_header_64 H_64;
H_64 = getHeader64();
T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype, McpuDefault);
*ThumbTriple = MachOObjectFile::getThumbArch(H_64.cputype, H_64.cpusubtype,
McpuDefault);
} else {
MachO::mach_header H;
H = getHeader();
T = MachOObjectFile::getArch(H.cputype, H.cpusubtype, McpuDefault);
*ThumbTriple = MachOObjectFile::getThumbArch(H.cputype, H.cpusubtype,
McpuDefault);
}
return T;
}
relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const {
DataRefImpl DRI;
DRI.d.a = Index;

View File

@ -0,0 +1,15 @@
@ RUN: llvm-mc < %s -triple armv7-apple-darwin -filetype=obj | llvm-objdump -m -d - | FileCheck %s
.thumb
.thumb_func _t
_t:
nop
nop
.align 2
.arm
_a:
nop
@ CHECK: 00 bf nop
@ CHECK-NEXT: 00 bf nop
@ CHECK: 00 f0 20 e3 nop

View File

@ -50,22 +50,36 @@ static cl::opt<bool>
static cl::opt<std::string>
DSYMFile("dsym", cl::desc("Use .dSYM file for debug info"));
static const Target *GetTarget(const MachOObjectFile *MachOObj) {
static std::string ThumbTripleName;
static const Target *GetTarget(const MachOObjectFile *MachOObj,
const char **McpuDefault,
const Target **ThumbTarget) {
// Figure out the target triple.
if (TripleName.empty()) {
llvm::Triple TT("unknown-unknown-unknown");
TT.setArch(Triple::ArchType(MachOObj->getArch()));
llvm::Triple ThumbTriple = Triple();
TT = MachOObj->getArch(McpuDefault, &ThumbTriple);
TripleName = TT.str();
ThumbTripleName = ThumbTriple.str();
}
// Get the target specific parser.
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
if (TheTarget)
if (TheTarget && ThumbTripleName.empty())
return TheTarget;
errs() << "llvm-objdump: error: unable to get target for '" << TripleName
<< "', see --version and --triple.\n";
*ThumbTarget = TargetRegistry::lookupTarget(ThumbTripleName, Error);
if (*ThumbTarget)
return TheTarget;
errs() << "llvm-objdump: error: unable to get target for '";
if (!TheTarget)
errs() << TripleName;
else
errs() << ThumbTripleName;
errs() << "', see --version and --triple.\n";
return nullptr;
}
@ -211,14 +225,26 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
static void DisassembleInputMachO2(StringRef Filename,
MachOObjectFile *MachOOF) {
const Target *TheTarget = GetTarget(MachOOF);
const char *McpuDefault = nullptr;
const Target *ThumbTarget = nullptr;
const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget);
if (!TheTarget) {
// GetTarget prints out stuff.
return;
}
if (MCPU.empty() && McpuDefault)
MCPU = McpuDefault;
std::unique_ptr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
std::unique_ptr<MCInstrAnalysis> InstrAnalysis(
TheTarget->createMCInstrAnalysis(InstrInfo.get()));
std::unique_ptr<const MCInstrInfo> ThumbInstrInfo;
std::unique_ptr<MCInstrAnalysis> ThumbInstrAnalysis;
if (ThumbTarget) {
ThumbInstrInfo.reset(ThumbTarget->createMCInstrInfo());
ThumbInstrAnalysis.reset(
ThumbTarget->createMCInstrAnalysis(ThumbInstrInfo.get()));
}
// Package up features to be passed to target/subtarget
std::string FeaturesStr;
@ -249,6 +275,34 @@ static void DisassembleInputMachO2(StringRef Filename,
return;
}
// Set up thumb disassembler.
std::unique_ptr<const MCRegisterInfo> ThumbMRI;
std::unique_ptr<const MCAsmInfo> ThumbAsmInfo;
std::unique_ptr<const MCSubtargetInfo> ThumbSTI;
std::unique_ptr<const MCDisassembler> ThumbDisAsm;
std::unique_ptr<MCInstPrinter> ThumbIP;
std::unique_ptr<MCContext> ThumbCtx;
if (ThumbTarget) {
ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTripleName));
ThumbAsmInfo.reset(
ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName));
ThumbSTI.reset(
ThumbTarget->createMCSubtargetInfo(ThumbTripleName, MCPU, FeaturesStr));
ThumbCtx.reset(new MCContext(ThumbAsmInfo.get(), ThumbMRI.get(), nullptr));
ThumbDisAsm.reset(ThumbTarget->createMCDisassembler(*ThumbSTI, *ThumbCtx));
int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();
ThumbIP.reset(ThumbTarget->createMCInstPrinter(
ThumbAsmPrinterVariant, *ThumbAsmInfo, *ThumbInstrInfo, *ThumbMRI,
*ThumbSTI));
}
if (ThumbTarget && (!ThumbInstrAnalysis || !ThumbAsmInfo || !ThumbSTI ||
!ThumbDisAsm || !ThumbIP)) {
errs() << "error: couldn't initialize disassembler for target "
<< ThumbTripleName << '\n';
return;
}
outs() << '\n' << Filename << ":\n\n";
MachO::mach_header Header = MachOOF->getHeader();
@ -396,6 +450,10 @@ static void DisassembleInputMachO2(StringRef Filename,
symbolTableWorked = true;
DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl();
bool isThumb =
(MachOOF->getSymbolFlags(Symb) & SymbolRef::SF_Thumb) && ThumbTarget;
outs() << SymName << ":\n";
DILineInfo lastLine;
for (uint64_t Index = Start; Index < End; Index += Size) {
@ -422,9 +480,18 @@ static void DisassembleInputMachO2(StringRef Filename,
continue;
}
if (DisAsm->getInstruction(Inst, Size, memoryObject, Index,
DebugOut, nulls())) {
bool gotInst;
if (isThumb)
gotInst = ThumbDisAsm->getInstruction(Inst, Size, memoryObject, Index,
DebugOut, nulls());
else
gotInst = DisAsm->getInstruction(Inst, Size, memoryObject, Index,
DebugOut, nulls());
if (gotInst) {
DumpBytes(StringRef(Bytes.data() + Index, Size));
if (isThumb)
ThumbIP->printInst(&Inst, outs(), "");
else
IP->printInst(&Inst, outs(), "");
// Print debug info.