llvm.org GIT mirror llvm / cd0e538
[llvm-objdump] Switch between ARM/Thumb based on mapping symbols. The ARMDisassembler changes allow changing between ARM and Thumb mode based on the MCSubtargetInfo, rather than the Target, which simplifies the other changes a bit. I'm not really happy with adding more target-specific logic to tools/llvm-objdump/, but there isn't any easy way around it: the logic in question specifically applies to disassembling an object file, and that code simply isn't located in lib/Target, at least at the moment. Differential Revision: https://reviews.llvm.org/D60927 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@363903 91177308-0d34-0410-b5e6-96231b3b80d8 Eli Friedman 29 days ago
5 changed file(s) with 120 addition(s) and 78 deletion(s). Raw diff Collapse all Expand all
5353 protected:
5454 ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source);
5555
56 virtual uint16_t getEMachine() const = 0;
5756 virtual uint64_t getSymbolSize(DataRefImpl Symb) const = 0;
5857 virtual uint8_t getSymbolBinding(DataRefImpl Symb) const = 0;
5958 virtual uint8_t getSymbolOther(DataRefImpl Symb) const = 0;
8988 void setARMSubArch(Triple &TheTriple) const override;
9089
9190 virtual uint16_t getEType() const = 0;
91
92 virtual uint16_t getEMachine() const = 0;
9293
9394 std::vector> getPltAddresses() const;
9495 };
138138 ArrayRef Bytes, uint64_t Address,
139139 raw_ostream &VStream,
140140 raw_ostream &CStream) const override;
141 };
142
143 /// Thumb disassembler for all Thumb platforms.
144 class ThumbDisassembler : public MCDisassembler {
145 public:
146 ThumbDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) :
147 MCDisassembler(STI, Ctx) {
148 }
149
150 ~ThumbDisassembler() override = default;
151
152 DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
153 ArrayRef Bytes, uint64_t Address,
154 raw_ostream &VStream,
155 raw_ostream &CStream) const override;
156141
157142 private:
143 DecodeStatus getARMInstruction(MCInst &Instr, uint64_t &Size,
144 ArrayRef Bytes, uint64_t Address,
145 raw_ostream &VStream,
146 raw_ostream &CStream) const;
147
148 DecodeStatus getThumbInstruction(MCInst &Instr, uint64_t &Size,
149 ArrayRef Bytes, uint64_t Address,
150 raw_ostream &VStream,
151 raw_ostream &CStream) const;
152
158153 mutable ITStatus ITBlock;
159154 mutable VPTStatus VPTBlock;
160155
518513 return new ARMDisassembler(STI, Ctx);
519514 }
520515
521 static MCDisassembler *createThumbDisassembler(const Target &T,
522 const MCSubtargetInfo &STI,
523 MCContext &Ctx) {
524 return new ThumbDisassembler(STI, Ctx);
525 }
526
527516 // Post-decoding checks
528517 static DecodeStatus checkDecodedInstruction(MCInst &MI, uint64_t &Size,
529518 uint64_t Address, raw_ostream &OS,
561550 ArrayRef Bytes,
562551 uint64_t Address, raw_ostream &OS,
563552 raw_ostream &CS) const {
553 if (STI.getFeatureBits()[ARM::ModeThumb])
554 return getThumbInstruction(MI, Size, Bytes, Address, OS, CS);
555 return getARMInstruction(MI, Size, Bytes, Address, OS, CS);
556 }
557
558 DecodeStatus ARMDisassembler::getARMInstruction(MCInst &MI, uint64_t &Size,
559 ArrayRef Bytes,
560 uint64_t Address,
561 raw_ostream &OS,
562 raw_ostream &CS) const {
564563 CommentStream = &CS;
565564
566565 assert(!STI.getFeatureBits()[ARM::ModeThumb] &&
697696 // to fix up the predicate operands using this context information as a
698697 // post-pass.
699698 MCDisassembler::DecodeStatus
700 ThumbDisassembler::AddThumbPredicate(MCInst &MI) const {
699 ARMDisassembler::AddThumbPredicate(MCInst &MI) const {
701700 MCDisassembler::DecodeStatus S = Success;
702701
703702 const FeatureBitset &FeatureBits = getSubtargetInfo().getFeatureBits();
812811 // mode, the auto-generated decoder will give them an (incorrect)
813812 // predicate operand. We need to rewrite these operands based on the IT
814813 // context as a post-pass.
815 void ThumbDisassembler::UpdateThumbVFPPredicate(
814 void ARMDisassembler::UpdateThumbVFPPredicate(
816815 DecodeStatus &S, MCInst &MI) const {
817816 unsigned CC;
818817 CC = ITBlock.getITCC();
843842 }
844843 }
845844
846 DecodeStatus ThumbDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
847 ArrayRef Bytes,
848 uint64_t Address,
849 raw_ostream &OS,
850 raw_ostream &CS) const {
845 DecodeStatus ARMDisassembler::getThumbInstruction(MCInst &MI, uint64_t &Size,
846 ArrayRef Bytes,
847 uint64_t Address,
848 raw_ostream &OS,
849 raw_ostream &CS) const {
851850 CommentStream = &CS;
852851
853852 assert(STI.getFeatureBits()[ARM::ModeThumb] &&
10451044 TargetRegistry::RegisterMCDisassembler(getTheARMBETarget(),
10461045 createARMDisassembler);
10471046 TargetRegistry::RegisterMCDisassembler(getTheThumbLETarget(),
1048 createThumbDisassembler);
1047 createARMDisassembler);
10491048 TargetRegistry::RegisterMCDisassembler(getTheThumbBETarget(),
1050 createThumbDisassembler);
1049 createARMDisassembler);
10511050 }
10521051
10531052 static const uint16_t GPRDecoderTable[] = {
None ;RUN: llc -mtriple=thumbv7-linux-gnueabi < %s | llvm-mc -triple=thumbv7-linux-gnueabi -filetype=obj > %t
1 ; Two pass decoding needed because llvm-objdump does not respect mapping symbols
2 ;RUN: llvm-objdump -triple=armv7 -d %t | FileCheck %s --check-prefix=ARM
3 ;RUN: llvm-objdump -triple=thumbv7 -d %t | FileCheck %s --check-prefix=THUMB
0 ;RUN: llc -mtriple=thumbv7-linux-gnueabi < %s | llvm-mc -triple=thumbv7-linux-gnueabi -filetype=obj | llvm-objdump -d - | FileCheck %s
41
52 define hidden i32 @bah(i8* %start) #0 align 2 {
63 %1 = ptrtoint i8* %start to i32
96 ret i32 %3
107 }
118
12 ; ARM: $a
13 ; ARM-NEXT: 04 70 2d e5 str r7, [sp, #-4]!
14 ; ARM: $t
15 ; ARM-NEXT: 48 1c
16
17 ; THUMB: $a{{.*}}:
18 ; THUMB-NEXT: 04 70
19 ; THUMB-NEXT: 2d e5
20 ; THUMB: $t{{.*}}:
21 ; THUMB-NEXT: 48 1c adds r0, r1, #1
9 ; CHECK: $a{{.*}}:
10 ; CHECK-NEXT: 04 70 2d e5 str r7, [sp, #-4]!
11 ; CHECK: $t{{.*}}:
12 ; CHECK-NEXT: 48 1c adds r0, r1, #1
None @ RUN: llvm-mc < %s -triple armv7r -mattr=+hwdiv-arm -filetype=obj | llvm-objdump -triple=thumb -d - | FileCheck %s
1 @ RUN: llvm-mc < %s -triple armv7r -mattr=+hwdiv-arm -filetype=obj | llvm-objdump -triple=arm -d - | FileCheck %s --check-prefix=CHECK-ARM
0 @ RUN: llvm-mc < %s -triple armv7r -mattr=+hwdiv-arm -filetype=obj | llvm-objdump -d - | FileCheck %s
1 @ v7r implies Thumb hwdiv, but ARM hwdiv is optional
2 @ FIXME: Does that imply we should actually refuse to disassemble it?
23
34 .eabi_attribute Tag_CPU_arch, 10 // v7
45 .eabi_attribute Tag_CPU_arch_profile, 0x52 // 'R' profile
89 udiv r0, r1, r2
910
1011 @CHECK-LABEL: div_arm
11 @CHECK-NOT: udiv r0, r1, r2
12 @CHECK-ARM-NOT: udiv r0, r1, r2
12 @CHECK: 11 f2 30 e7
1313
1414 .thumb
1515 div_thumb:
602602 OldLineInfo = LineInfo;
603603 }
604604
605 static bool isAArch64Elf(const ObjectFile *Obj) {
606 const auto *Elf = dyn_cast(Obj);
607 return Elf && Elf->getEMachine() == ELF::EM_AARCH64;
608 }
609
605610 static bool isArmElf(const ObjectFile *Obj) {
606 return (Obj->isELF() &&
607 (Obj->getArch() == Triple::aarch64 ||
608 Obj->getArch() == Triple::aarch64_be ||
609 Obj->getArch() == Triple::arm || Obj->getArch() == Triple::armeb ||
610 Obj->getArch() == Triple::thumb ||
611 Obj->getArch() == Triple::thumbeb));
611 const auto *Elf = dyn_cast(Obj);
612 return Elf && Elf->getEMachine() == ELF::EM_ARM;
613 }
614
615 static bool hasMappingSymbols(const ObjectFile *Obj) {
616 return isArmElf(Obj) || isAArch64Elf(Obj);
612617 }
613618
614619 static void printRelocation(const RelocationRef &Rel, uint64_t Address,
953958 return false;
954959 }
955960
961
962 typedef std::pair MappingSymbolPair;
963 static char getMappingSymbolKind(ArrayRef MappingSymbols,
964 uint64_t Address) {
965 auto Sym = bsearch(MappingSymbols, [Address](const MappingSymbolPair &Val) {
966 return Val.first > Address;
967 });
968 // Return zero for any address before the first mapping symbol; this means
969 // we should use the default disassembly mode, depending on the target.
970 if (Sym == MappingSymbols.begin())
971 return '\x00';
972 return (Sym - 1)->second;
973 }
974
956975 static uint64_t
957976 dumpARMELFData(uint64_t SectionAddr, uint64_t Index, uint64_t End,
958977 const ObjectFile *Obj, ArrayRef Bytes,
959 const std::vector &TextMappingSymsAddr) {
978 ArrayRef MappingSymbols) {
960979 support::endianness Endian =
961980 Obj->isLittleEndian() ? support::little : support::big;
962981 while (Index < End) {
980999 ++Index;
9811000 }
9821001 outs() << "\n";
983 if (std::binary_search(TextMappingSymsAddr.begin(),
984 TextMappingSymsAddr.end(), Index))
1002 if (getMappingSymbolKind(MappingSymbols, Index) != 'd')
9851003 break;
9861004 }
9871005 return Index;
10221040 }
10231041
10241042 static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
1025 MCContext &Ctx, MCDisassembler *DisAsm,
1043 MCContext &Ctx, MCDisassembler *PrimaryDisAsm,
1044 MCDisassembler *SecondaryDisAsm,
10261045 const MCInstrAnalysis *MIA, MCInstPrinter *IP,
1027 const MCSubtargetInfo *STI, PrettyPrinter &PIP,
1046 const MCSubtargetInfo *PrimarySTI,
1047 const MCSubtargetInfo *SecondarySTI,
1048 PrettyPrinter &PIP,
10281049 SourcePrinter &SP, bool InlineRelocs) {
1050 const MCSubtargetInfo *STI = PrimarySTI;
1051 MCDisassembler *DisAsm = PrimaryDisAsm;
1052 bool PrimaryIsThumb = false;
1053 if (isArmElf(Obj))
1054 PrimaryIsThumb = STI->checkFeatures("+thumb-mode");
1055
10291056 std::map> RelocMap;
10301057 if (InlineRelocs)
10311058 RelocMap = getRelocsMap(*Obj);
11121139
11131140 // Get the list of all the symbols in this section.
11141141 SectionSymbolsTy &Symbols = AllSymbols[Section];
1115 std::vector DataMappingSymsAddr;
1116 std::vector TextMappingSymsAddr;
1117 if (isArmElf(Obj)) {
1142 std::vector MappingSymbols;
1143 if (hasMappingSymbols(Obj)) {
11181144 for (const auto &Symb : Symbols) {
11191145 uint64_t Address = std::get<0>(Symb);
11201146 StringRef Name = std::get<1>(Symb);
11211147 if (Name.startswith("$d"))
1122 DataMappingSymsAddr.push_back(Address - SectionAddr);
1148 MappingSymbols.emplace_back(Address - SectionAddr, 'd');
11231149 if (Name.startswith("$x"))
1124 TextMappingSymsAddr.push_back(Address - SectionAddr);
1150 MappingSymbols.emplace_back(Address - SectionAddr, 'x');
11251151 if (Name.startswith("$a"))
1126 TextMappingSymsAddr.push_back(Address - SectionAddr);
1152 MappingSymbols.emplace_back(Address - SectionAddr, 'a');
11271153 if (Name.startswith("$t"))
1128 TextMappingSymsAddr.push_back(Address - SectionAddr);
1154 MappingSymbols.emplace_back(Address - SectionAddr, 't');
11291155 }
11301156 }
11311157
1132 llvm::sort(DataMappingSymsAddr);
1133 llvm::sort(TextMappingSymsAddr);
1158 llvm::sort(MappingSymbols);
11341159
11351160 if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) {
11361161 // AMDGPU disassembler uses symbolizer for printing labels
12681293 Index = End;
12691294 }
12701295
1271 bool CheckARMELFData = isArmElf(Obj) &&
1296 bool CheckARMELFData = hasMappingSymbols(Obj) &&
12721297 std::get<2>(Symbols[SI]) != ELF::STT_OBJECT &&
12731298 !DisassembleAll;
12741299 while (Index < End) {
1275 // AArch64 ELF binaries can interleave data and text in the same
1276 // section. We rely on the markers introduced to understand what we
1277 // need to dump. If the data marker is within a function, it is
1300 // ARM and AArch64 ELF binaries can interleave data and text in the
1301 // same section. We rely on the markers introduced to understand what
1302 // we need to dump. If the data marker is within a function, it is
12781303 // denoted as a word/short etc.
12791304 if (CheckARMELFData &&
1280 std::binary_search(DataMappingSymsAddr.begin(),
1281 DataMappingSymsAddr.end(), Index)) {
1305 getMappingSymbolKind(MappingSymbols, Index) == 'd') {
12821306 Index = dumpARMELFData(SectionAddr, Index, End, Obj, Bytes,
1283 TextMappingSymsAddr);
1307 MappingSymbols);
12841308 continue;
12851309 }
12861310
12981322 outs() << "\t\t..." << '\n';
12991323 Index += N;
13001324 continue;
1325 }
1326 }
1327
1328 if (SecondarySTI) {
1329 if (getMappingSymbolKind(MappingSymbols, Index) == 'a') {
1330 STI = PrimaryIsThumb ? SecondarySTI : PrimarySTI;
1331 DisAsm = PrimaryIsThumb ? SecondaryDisAsm : PrimaryDisAsm;
1332 } else if (getMappingSymbolKind(MappingSymbols, Index) == 't') {
1333 STI = PrimaryIsThumb ? PrimarySTI : SecondarySTI;
1334 DisAsm = PrimaryIsThumb ? PrimaryDisAsm : SecondaryDisAsm;
13011335 }
13021336 }
13031337
14581492 report_error(Obj->getFileName(),
14591493 "no disassembler for target " + TripleName);
14601494
1495 // If we have an ARM object file, we need a second disassembler, because
1496 // ARM CPUs have two different instruction sets: ARM mode, and Thumb mode.
1497 // We use mapping symbols to switch between the two assemblers, where
1498 // appropriate.
1499 std::unique_ptr SecondaryDisAsm;
1500 std::unique_ptr SecondarySTI;
1501 if (isArmElf(Obj) && !STI->checkFeatures("+mclass")) {
1502 if (STI->checkFeatures("+thumb-mode"))
1503 Features.AddFeature("-thumb-mode");
1504 else
1505 Features.AddFeature("+thumb-mode");
1506 SecondarySTI.reset(TheTarget->createMCSubtargetInfo(TripleName, MCPU,
1507 Features.getString()));
1508 SecondaryDisAsm.reset(TheTarget->createMCDisassembler(*SecondarySTI, Ctx));
1509 }
1510
14611511 std::unique_ptr MIA(
14621512 TheTarget->createMCInstrAnalysis(MII.get()));
14631513
14761526 if (!IP->applyTargetSpecificCLOption(Opt))
14771527 error("Unrecognized disassembler option: " + Opt);
14781528
1479 disassembleObject(TheTarget, Obj, Ctx, DisAsm.get(), MIA.get(), IP.get(),
1480 STI.get(), PIP, SP, InlineRelocs);
1529 disassembleObject(TheTarget, Obj, Ctx, DisAsm.get(), SecondaryDisAsm.get(),
1530 MIA.get(), IP.get(), STI.get(), SecondarySTI.get(), PIP,
1531 SP, InlineRelocs);
14811532 }
14821533
14831534 void printRelocations(const ObjectFile *Obj) {