109467b48Spatrick //===- FileAnalysis.cpp -----------------------------------------*- C++ -*-===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick
909467b48Spatrick #include "FileAnalysis.h"
1009467b48Spatrick #include "GraphBuilder.h"
1109467b48Spatrick
1209467b48Spatrick #include "llvm/BinaryFormat/ELF.h"
1309467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFContext.h"
14*d415bd75Srobert #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
1509467b48Spatrick #include "llvm/MC/MCAsmInfo.h"
1609467b48Spatrick #include "llvm/MC/MCContext.h"
1709467b48Spatrick #include "llvm/MC/MCDisassembler/MCDisassembler.h"
1809467b48Spatrick #include "llvm/MC/MCInst.h"
1909467b48Spatrick #include "llvm/MC/MCInstPrinter.h"
2009467b48Spatrick #include "llvm/MC/MCInstrAnalysis.h"
2109467b48Spatrick #include "llvm/MC/MCInstrDesc.h"
2209467b48Spatrick #include "llvm/MC/MCInstrInfo.h"
2309467b48Spatrick #include "llvm/MC/MCObjectFileInfo.h"
2409467b48Spatrick #include "llvm/MC/MCRegisterInfo.h"
2509467b48Spatrick #include "llvm/MC/MCSubtargetInfo.h"
2609467b48Spatrick #include "llvm/MC/MCTargetOptions.h"
27*d415bd75Srobert #include "llvm/MC/TargetRegistry.h"
2809467b48Spatrick #include "llvm/Object/Binary.h"
2909467b48Spatrick #include "llvm/Object/COFF.h"
3009467b48Spatrick #include "llvm/Object/ELFObjectFile.h"
3109467b48Spatrick #include "llvm/Object/ObjectFile.h"
3209467b48Spatrick #include "llvm/Support/Casting.h"
3309467b48Spatrick #include "llvm/Support/CommandLine.h"
3409467b48Spatrick #include "llvm/Support/Error.h"
3509467b48Spatrick #include "llvm/Support/MemoryBuffer.h"
3609467b48Spatrick #include "llvm/Support/TargetSelect.h"
3709467b48Spatrick #include "llvm/Support/raw_ostream.h"
3809467b48Spatrick
3909467b48Spatrick using Instr = llvm::cfi_verify::FileAnalysis::Instr;
4009467b48Spatrick using LLVMSymbolizer = llvm::symbolize::LLVMSymbolizer;
4109467b48Spatrick
4209467b48Spatrick namespace llvm {
4309467b48Spatrick namespace cfi_verify {
4409467b48Spatrick
4509467b48Spatrick bool IgnoreDWARFFlag;
4609467b48Spatrick
4709467b48Spatrick static cl::opt<bool, true> IgnoreDWARFArg(
4809467b48Spatrick "ignore-dwarf",
4909467b48Spatrick cl::desc(
5009467b48Spatrick "Ignore all DWARF data. This relaxes the requirements for all "
5109467b48Spatrick "statically linked libraries to have been compiled with '-g', but "
5209467b48Spatrick "will result in false positives for 'CFI unprotected' instructions."),
5309467b48Spatrick cl::location(IgnoreDWARFFlag), cl::init(false));
5409467b48Spatrick
stringCFIProtectionStatus(CFIProtectionStatus Status)5509467b48Spatrick StringRef stringCFIProtectionStatus(CFIProtectionStatus Status) {
5609467b48Spatrick switch (Status) {
5709467b48Spatrick case CFIProtectionStatus::PROTECTED:
5809467b48Spatrick return "PROTECTED";
5909467b48Spatrick case CFIProtectionStatus::FAIL_NOT_INDIRECT_CF:
6009467b48Spatrick return "FAIL_NOT_INDIRECT_CF";
6109467b48Spatrick case CFIProtectionStatus::FAIL_ORPHANS:
6209467b48Spatrick return "FAIL_ORPHANS";
6309467b48Spatrick case CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH:
6409467b48Spatrick return "FAIL_BAD_CONDITIONAL_BRANCH";
6509467b48Spatrick case CFIProtectionStatus::FAIL_REGISTER_CLOBBERED:
6609467b48Spatrick return "FAIL_REGISTER_CLOBBERED";
6709467b48Spatrick case CFIProtectionStatus::FAIL_INVALID_INSTRUCTION:
6809467b48Spatrick return "FAIL_INVALID_INSTRUCTION";
6909467b48Spatrick }
7009467b48Spatrick llvm_unreachable("Attempted to stringify an unknown enum value.");
7109467b48Spatrick }
7209467b48Spatrick
Create(StringRef Filename)7309467b48Spatrick Expected<FileAnalysis> FileAnalysis::Create(StringRef Filename) {
7409467b48Spatrick // Open the filename provided.
7509467b48Spatrick Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
7609467b48Spatrick object::createBinary(Filename);
7709467b48Spatrick if (!BinaryOrErr)
7809467b48Spatrick return BinaryOrErr.takeError();
7909467b48Spatrick
8009467b48Spatrick // Construct the object and allow it to take ownership of the binary.
8109467b48Spatrick object::OwningBinary<object::Binary> Binary = std::move(BinaryOrErr.get());
8209467b48Spatrick FileAnalysis Analysis(std::move(Binary));
8309467b48Spatrick
8409467b48Spatrick Analysis.Object = dyn_cast<object::ObjectFile>(Analysis.Binary.getBinary());
8509467b48Spatrick if (!Analysis.Object)
8609467b48Spatrick return make_error<UnsupportedDisassembly>("Failed to cast object");
8709467b48Spatrick
8809467b48Spatrick switch (Analysis.Object->getArch()) {
8909467b48Spatrick case Triple::x86:
9009467b48Spatrick case Triple::x86_64:
9109467b48Spatrick case Triple::aarch64:
9209467b48Spatrick case Triple::aarch64_be:
9309467b48Spatrick break;
9409467b48Spatrick default:
9509467b48Spatrick return make_error<UnsupportedDisassembly>("Unsupported architecture.");
9609467b48Spatrick }
9709467b48Spatrick
9809467b48Spatrick Analysis.ObjectTriple = Analysis.Object->makeTriple();
99*d415bd75Srobert Expected<SubtargetFeatures> Features = Analysis.Object->getFeatures();
100*d415bd75Srobert if (!Features)
101*d415bd75Srobert return Features.takeError();
102*d415bd75Srobert
103*d415bd75Srobert Analysis.Features = *Features;
10409467b48Spatrick
10509467b48Spatrick // Init the rest of the object.
10609467b48Spatrick if (auto InitResponse = Analysis.initialiseDisassemblyMembers())
10709467b48Spatrick return std::move(InitResponse);
10809467b48Spatrick
10909467b48Spatrick if (auto SectionParseResponse = Analysis.parseCodeSections())
11009467b48Spatrick return std::move(SectionParseResponse);
11109467b48Spatrick
11209467b48Spatrick if (auto SymbolTableParseResponse = Analysis.parseSymbolTable())
11309467b48Spatrick return std::move(SymbolTableParseResponse);
11409467b48Spatrick
11509467b48Spatrick return std::move(Analysis);
11609467b48Spatrick }
11709467b48Spatrick
FileAnalysis(object::OwningBinary<object::Binary> Binary)11809467b48Spatrick FileAnalysis::FileAnalysis(object::OwningBinary<object::Binary> Binary)
11909467b48Spatrick : Binary(std::move(Binary)) {}
12009467b48Spatrick
FileAnalysis(const Triple & ObjectTriple,const SubtargetFeatures & Features)12109467b48Spatrick FileAnalysis::FileAnalysis(const Triple &ObjectTriple,
12209467b48Spatrick const SubtargetFeatures &Features)
12309467b48Spatrick : ObjectTriple(ObjectTriple), Features(Features) {}
12409467b48Spatrick
12509467b48Spatrick const Instr *
getPrevInstructionSequential(const Instr & InstrMeta) const12609467b48Spatrick FileAnalysis::getPrevInstructionSequential(const Instr &InstrMeta) const {
12709467b48Spatrick std::map<uint64_t, Instr>::const_iterator KV =
12809467b48Spatrick Instructions.find(InstrMeta.VMAddress);
12909467b48Spatrick if (KV == Instructions.end() || KV == Instructions.begin())
13009467b48Spatrick return nullptr;
13109467b48Spatrick
13209467b48Spatrick if (!(--KV)->second.Valid)
13309467b48Spatrick return nullptr;
13409467b48Spatrick
13509467b48Spatrick return &KV->second;
13609467b48Spatrick }
13709467b48Spatrick
13809467b48Spatrick const Instr *
getNextInstructionSequential(const Instr & InstrMeta) const13909467b48Spatrick FileAnalysis::getNextInstructionSequential(const Instr &InstrMeta) const {
14009467b48Spatrick std::map<uint64_t, Instr>::const_iterator KV =
14109467b48Spatrick Instructions.find(InstrMeta.VMAddress);
14209467b48Spatrick if (KV == Instructions.end() || ++KV == Instructions.end())
14309467b48Spatrick return nullptr;
14409467b48Spatrick
14509467b48Spatrick if (!KV->second.Valid)
14609467b48Spatrick return nullptr;
14709467b48Spatrick
14809467b48Spatrick return &KV->second;
14909467b48Spatrick }
15009467b48Spatrick
usesRegisterOperand(const Instr & InstrMeta) const15109467b48Spatrick bool FileAnalysis::usesRegisterOperand(const Instr &InstrMeta) const {
15209467b48Spatrick for (const auto &Operand : InstrMeta.Instruction) {
15309467b48Spatrick if (Operand.isReg())
15409467b48Spatrick return true;
15509467b48Spatrick }
15609467b48Spatrick return false;
15709467b48Spatrick }
15809467b48Spatrick
getInstruction(uint64_t Address) const15909467b48Spatrick const Instr *FileAnalysis::getInstruction(uint64_t Address) const {
16009467b48Spatrick const auto &InstrKV = Instructions.find(Address);
16109467b48Spatrick if (InstrKV == Instructions.end())
16209467b48Spatrick return nullptr;
16309467b48Spatrick
16409467b48Spatrick return &InstrKV->second;
16509467b48Spatrick }
16609467b48Spatrick
getInstructionOrDie(uint64_t Address) const16709467b48Spatrick const Instr &FileAnalysis::getInstructionOrDie(uint64_t Address) const {
16809467b48Spatrick const auto &InstrKV = Instructions.find(Address);
16909467b48Spatrick assert(InstrKV != Instructions.end() && "Address doesn't exist.");
17009467b48Spatrick return InstrKV->second;
17109467b48Spatrick }
17209467b48Spatrick
isCFITrap(const Instr & InstrMeta) const17309467b48Spatrick bool FileAnalysis::isCFITrap(const Instr &InstrMeta) const {
17409467b48Spatrick const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
17509467b48Spatrick return InstrDesc.isTrap() || willTrapOnCFIViolation(InstrMeta);
17609467b48Spatrick }
17709467b48Spatrick
willTrapOnCFIViolation(const Instr & InstrMeta) const17809467b48Spatrick bool FileAnalysis::willTrapOnCFIViolation(const Instr &InstrMeta) const {
17909467b48Spatrick const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
18009467b48Spatrick if (!InstrDesc.isCall())
18109467b48Spatrick return false;
18209467b48Spatrick uint64_t Target;
18309467b48Spatrick if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
18409467b48Spatrick InstrMeta.InstructionSize, Target))
18509467b48Spatrick return false;
18673471bf0Spatrick return TrapOnFailFunctionAddresses.contains(Target);
18709467b48Spatrick }
18809467b48Spatrick
canFallThrough(const Instr & InstrMeta) const18909467b48Spatrick bool FileAnalysis::canFallThrough(const Instr &InstrMeta) const {
19009467b48Spatrick if (!InstrMeta.Valid)
19109467b48Spatrick return false;
19209467b48Spatrick
19309467b48Spatrick if (isCFITrap(InstrMeta))
19409467b48Spatrick return false;
19509467b48Spatrick
19609467b48Spatrick const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
19709467b48Spatrick if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo))
19809467b48Spatrick return InstrDesc.isConditionalBranch();
19909467b48Spatrick
20009467b48Spatrick return true;
20109467b48Spatrick }
20209467b48Spatrick
20309467b48Spatrick const Instr *
getDefiniteNextInstruction(const Instr & InstrMeta) const20409467b48Spatrick FileAnalysis::getDefiniteNextInstruction(const Instr &InstrMeta) const {
20509467b48Spatrick if (!InstrMeta.Valid)
20609467b48Spatrick return nullptr;
20709467b48Spatrick
20809467b48Spatrick if (isCFITrap(InstrMeta))
20909467b48Spatrick return nullptr;
21009467b48Spatrick
21109467b48Spatrick const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
21209467b48Spatrick const Instr *NextMetaPtr;
21309467b48Spatrick if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo)) {
21409467b48Spatrick if (InstrDesc.isConditionalBranch())
21509467b48Spatrick return nullptr;
21609467b48Spatrick
21709467b48Spatrick uint64_t Target;
21809467b48Spatrick if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
21909467b48Spatrick InstrMeta.InstructionSize, Target))
22009467b48Spatrick return nullptr;
22109467b48Spatrick
22209467b48Spatrick NextMetaPtr = getInstruction(Target);
22309467b48Spatrick } else {
22409467b48Spatrick NextMetaPtr =
22509467b48Spatrick getInstruction(InstrMeta.VMAddress + InstrMeta.InstructionSize);
22609467b48Spatrick }
22709467b48Spatrick
22809467b48Spatrick if (!NextMetaPtr || !NextMetaPtr->Valid)
22909467b48Spatrick return nullptr;
23009467b48Spatrick
23109467b48Spatrick return NextMetaPtr;
23209467b48Spatrick }
23309467b48Spatrick
23409467b48Spatrick std::set<const Instr *>
getDirectControlFlowXRefs(const Instr & InstrMeta) const23509467b48Spatrick FileAnalysis::getDirectControlFlowXRefs(const Instr &InstrMeta) const {
23609467b48Spatrick std::set<const Instr *> CFCrossReferences;
23709467b48Spatrick const Instr *PrevInstruction = getPrevInstructionSequential(InstrMeta);
23809467b48Spatrick
23909467b48Spatrick if (PrevInstruction && canFallThrough(*PrevInstruction))
24009467b48Spatrick CFCrossReferences.insert(PrevInstruction);
24109467b48Spatrick
24209467b48Spatrick const auto &TargetRefsKV = StaticBranchTargetings.find(InstrMeta.VMAddress);
24309467b48Spatrick if (TargetRefsKV == StaticBranchTargetings.end())
24409467b48Spatrick return CFCrossReferences;
24509467b48Spatrick
24609467b48Spatrick for (uint64_t SourceInstrAddress : TargetRefsKV->second) {
24709467b48Spatrick const auto &SourceInstrKV = Instructions.find(SourceInstrAddress);
24809467b48Spatrick if (SourceInstrKV == Instructions.end()) {
24909467b48Spatrick errs() << "Failed to find source instruction at address "
25009467b48Spatrick << format_hex(SourceInstrAddress, 2)
25109467b48Spatrick << " for the cross-reference to instruction at address "
25209467b48Spatrick << format_hex(InstrMeta.VMAddress, 2) << ".\n";
25309467b48Spatrick continue;
25409467b48Spatrick }
25509467b48Spatrick
25609467b48Spatrick CFCrossReferences.insert(&SourceInstrKV->second);
25709467b48Spatrick }
25809467b48Spatrick
25909467b48Spatrick return CFCrossReferences;
26009467b48Spatrick }
26109467b48Spatrick
26209467b48Spatrick const std::set<object::SectionedAddress> &
getIndirectInstructions() const26309467b48Spatrick FileAnalysis::getIndirectInstructions() const {
26409467b48Spatrick return IndirectInstructions;
26509467b48Spatrick }
26609467b48Spatrick
getRegisterInfo() const26709467b48Spatrick const MCRegisterInfo *FileAnalysis::getRegisterInfo() const {
26809467b48Spatrick return RegisterInfo.get();
26909467b48Spatrick }
27009467b48Spatrick
getMCInstrInfo() const27109467b48Spatrick const MCInstrInfo *FileAnalysis::getMCInstrInfo() const { return MII.get(); }
27209467b48Spatrick
getMCInstrAnalysis() const27309467b48Spatrick const MCInstrAnalysis *FileAnalysis::getMCInstrAnalysis() const {
27409467b48Spatrick return MIA.get();
27509467b48Spatrick }
27609467b48Spatrick
27709467b48Spatrick Expected<DIInliningInfo>
symbolizeInlinedCode(object::SectionedAddress Address)27809467b48Spatrick FileAnalysis::symbolizeInlinedCode(object::SectionedAddress Address) {
27909467b48Spatrick assert(Symbolizer != nullptr && "Symbolizer is invalid.");
28009467b48Spatrick
281097a140dSpatrick return Symbolizer->symbolizeInlinedCode(std::string(Object->getFileName()),
282097a140dSpatrick Address);
28309467b48Spatrick }
28409467b48Spatrick
28509467b48Spatrick CFIProtectionStatus
validateCFIProtection(const GraphResult & Graph) const28609467b48Spatrick FileAnalysis::validateCFIProtection(const GraphResult &Graph) const {
28709467b48Spatrick const Instr *InstrMetaPtr = getInstruction(Graph.BaseAddress);
28809467b48Spatrick if (!InstrMetaPtr)
28909467b48Spatrick return CFIProtectionStatus::FAIL_INVALID_INSTRUCTION;
29009467b48Spatrick
29109467b48Spatrick const auto &InstrDesc = MII->get(InstrMetaPtr->Instruction.getOpcode());
29209467b48Spatrick if (!InstrDesc.mayAffectControlFlow(InstrMetaPtr->Instruction, *RegisterInfo))
29309467b48Spatrick return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
29409467b48Spatrick
29509467b48Spatrick if (!usesRegisterOperand(*InstrMetaPtr))
29609467b48Spatrick return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
29709467b48Spatrick
29809467b48Spatrick if (!Graph.OrphanedNodes.empty())
29909467b48Spatrick return CFIProtectionStatus::FAIL_ORPHANS;
30009467b48Spatrick
30109467b48Spatrick for (const auto &BranchNode : Graph.ConditionalBranchNodes) {
30209467b48Spatrick if (!BranchNode.CFIProtection)
30309467b48Spatrick return CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH;
30409467b48Spatrick }
30509467b48Spatrick
30609467b48Spatrick if (indirectCFOperandClobber(Graph) != Graph.BaseAddress)
30709467b48Spatrick return CFIProtectionStatus::FAIL_REGISTER_CLOBBERED;
30809467b48Spatrick
30909467b48Spatrick return CFIProtectionStatus::PROTECTED;
31009467b48Spatrick }
31109467b48Spatrick
indirectCFOperandClobber(const GraphResult & Graph) const31209467b48Spatrick uint64_t FileAnalysis::indirectCFOperandClobber(const GraphResult &Graph) const {
31309467b48Spatrick assert(Graph.OrphanedNodes.empty() && "Orphaned nodes should be empty.");
31409467b48Spatrick
31509467b48Spatrick // Get the set of registers we must check to ensure they're not clobbered.
31609467b48Spatrick const Instr &IndirectCF = getInstructionOrDie(Graph.BaseAddress);
31709467b48Spatrick DenseSet<unsigned> RegisterNumbers;
31809467b48Spatrick for (const auto &Operand : IndirectCF.Instruction) {
31909467b48Spatrick if (Operand.isReg())
32009467b48Spatrick RegisterNumbers.insert(Operand.getReg());
32109467b48Spatrick }
32209467b48Spatrick assert(RegisterNumbers.size() && "Zero register operands on indirect CF.");
32309467b48Spatrick
32409467b48Spatrick // Now check all branches to indirect CFs and ensure no clobbering happens.
32509467b48Spatrick for (const auto &Branch : Graph.ConditionalBranchNodes) {
32609467b48Spatrick uint64_t Node;
32709467b48Spatrick if (Branch.IndirectCFIsOnTargetPath)
32809467b48Spatrick Node = Branch.Target;
32909467b48Spatrick else
33009467b48Spatrick Node = Branch.Fallthrough;
33109467b48Spatrick
33209467b48Spatrick // Some architectures (e.g., AArch64) cannot load in an indirect branch, so
33309467b48Spatrick // we allow them one load.
33409467b48Spatrick bool canLoad = !MII->get(IndirectCF.Instruction.getOpcode()).mayLoad();
33509467b48Spatrick
33609467b48Spatrick // We walk backwards from the indirect CF. It is the last node returned by
33709467b48Spatrick // Graph.flattenAddress, so we skip it since we already handled it.
33809467b48Spatrick DenseSet<unsigned> CurRegisterNumbers = RegisterNumbers;
33909467b48Spatrick std::vector<uint64_t> Nodes = Graph.flattenAddress(Node);
34009467b48Spatrick for (auto I = Nodes.rbegin() + 1, E = Nodes.rend(); I != E; ++I) {
34109467b48Spatrick Node = *I;
34209467b48Spatrick const Instr &NodeInstr = getInstructionOrDie(Node);
34309467b48Spatrick const auto &InstrDesc = MII->get(NodeInstr.Instruction.getOpcode());
34409467b48Spatrick
34509467b48Spatrick for (auto RI = CurRegisterNumbers.begin(), RE = CurRegisterNumbers.end();
34609467b48Spatrick RI != RE; ++RI) {
34709467b48Spatrick unsigned RegNum = *RI;
34809467b48Spatrick if (InstrDesc.hasDefOfPhysReg(NodeInstr.Instruction, RegNum,
34909467b48Spatrick *RegisterInfo)) {
35009467b48Spatrick if (!canLoad || !InstrDesc.mayLoad())
35109467b48Spatrick return Node;
35209467b48Spatrick canLoad = false;
35309467b48Spatrick CurRegisterNumbers.erase(RI);
35409467b48Spatrick // Add the registers this load reads to those we check for clobbers.
35509467b48Spatrick for (unsigned i = InstrDesc.getNumDefs(),
35609467b48Spatrick e = InstrDesc.getNumOperands(); i != e; i++) {
357*d415bd75Srobert const auto &Operand = NodeInstr.Instruction.getOperand(i);
35809467b48Spatrick if (Operand.isReg())
35909467b48Spatrick CurRegisterNumbers.insert(Operand.getReg());
36009467b48Spatrick }
36109467b48Spatrick break;
36209467b48Spatrick }
36309467b48Spatrick }
36409467b48Spatrick }
36509467b48Spatrick }
36609467b48Spatrick
36709467b48Spatrick return Graph.BaseAddress;
36809467b48Spatrick }
36909467b48Spatrick
printInstruction(const Instr & InstrMeta,raw_ostream & OS) const37009467b48Spatrick void FileAnalysis::printInstruction(const Instr &InstrMeta,
37109467b48Spatrick raw_ostream &OS) const {
372*d415bd75Srobert Printer->printInst(&InstrMeta.Instruction, 0, "", *SubtargetInfo, OS);
37309467b48Spatrick }
37409467b48Spatrick
initialiseDisassemblyMembers()37509467b48Spatrick Error FileAnalysis::initialiseDisassemblyMembers() {
37609467b48Spatrick std::string TripleName = ObjectTriple.getTriple();
37709467b48Spatrick ArchName = "";
37809467b48Spatrick MCPU = "";
37909467b48Spatrick std::string ErrorString;
38009467b48Spatrick
38173471bf0Spatrick LLVMSymbolizer::Options Opt;
38273471bf0Spatrick Opt.UseSymbolTable = false;
38373471bf0Spatrick Symbolizer.reset(new LLVMSymbolizer(Opt));
38409467b48Spatrick
38509467b48Spatrick ObjectTarget =
38609467b48Spatrick TargetRegistry::lookupTarget(ArchName, ObjectTriple, ErrorString);
38709467b48Spatrick if (!ObjectTarget)
38809467b48Spatrick return make_error<UnsupportedDisassembly>(
38909467b48Spatrick (Twine("Couldn't find target \"") + ObjectTriple.getTriple() +
39009467b48Spatrick "\", failed with error: " + ErrorString)
39109467b48Spatrick .str());
39209467b48Spatrick
39309467b48Spatrick RegisterInfo.reset(ObjectTarget->createMCRegInfo(TripleName));
39409467b48Spatrick if (!RegisterInfo)
39509467b48Spatrick return make_error<UnsupportedDisassembly>(
39609467b48Spatrick "Failed to initialise RegisterInfo.");
39709467b48Spatrick
39809467b48Spatrick MCTargetOptions MCOptions;
39909467b48Spatrick AsmInfo.reset(
40009467b48Spatrick ObjectTarget->createMCAsmInfo(*RegisterInfo, TripleName, MCOptions));
40109467b48Spatrick if (!AsmInfo)
40209467b48Spatrick return make_error<UnsupportedDisassembly>("Failed to initialise AsmInfo.");
40309467b48Spatrick
40409467b48Spatrick SubtargetInfo.reset(ObjectTarget->createMCSubtargetInfo(
40509467b48Spatrick TripleName, MCPU, Features.getString()));
40609467b48Spatrick if (!SubtargetInfo)
40709467b48Spatrick return make_error<UnsupportedDisassembly>(
40809467b48Spatrick "Failed to initialise SubtargetInfo.");
40909467b48Spatrick
41009467b48Spatrick MII.reset(ObjectTarget->createMCInstrInfo());
41109467b48Spatrick if (!MII)
41209467b48Spatrick return make_error<UnsupportedDisassembly>("Failed to initialise MII.");
41309467b48Spatrick
41473471bf0Spatrick Context.reset(new MCContext(Triple(TripleName), AsmInfo.get(),
41573471bf0Spatrick RegisterInfo.get(), SubtargetInfo.get()));
41609467b48Spatrick
41709467b48Spatrick Disassembler.reset(
41809467b48Spatrick ObjectTarget->createMCDisassembler(*SubtargetInfo, *Context));
41909467b48Spatrick
42009467b48Spatrick if (!Disassembler)
42109467b48Spatrick return make_error<UnsupportedDisassembly>(
42209467b48Spatrick "No disassembler available for target");
42309467b48Spatrick
42409467b48Spatrick MIA.reset(ObjectTarget->createMCInstrAnalysis(MII.get()));
42509467b48Spatrick
42609467b48Spatrick Printer.reset(ObjectTarget->createMCInstPrinter(
42709467b48Spatrick ObjectTriple, AsmInfo->getAssemblerDialect(), *AsmInfo, *MII,
42809467b48Spatrick *RegisterInfo));
42909467b48Spatrick
43009467b48Spatrick return Error::success();
43109467b48Spatrick }
43209467b48Spatrick
parseCodeSections()43309467b48Spatrick Error FileAnalysis::parseCodeSections() {
43409467b48Spatrick if (!IgnoreDWARFFlag) {
43509467b48Spatrick std::unique_ptr<DWARFContext> DWARF = DWARFContext::create(*Object);
43609467b48Spatrick if (!DWARF)
43709467b48Spatrick return make_error<StringError>("Could not create DWARF information.",
43809467b48Spatrick inconvertibleErrorCode());
43909467b48Spatrick
44009467b48Spatrick bool LineInfoValid = false;
44109467b48Spatrick
44209467b48Spatrick for (auto &Unit : DWARF->compile_units()) {
44309467b48Spatrick const auto &LineTable = DWARF->getLineTableForUnit(Unit.get());
44409467b48Spatrick if (LineTable && !LineTable->Rows.empty()) {
44509467b48Spatrick LineInfoValid = true;
44609467b48Spatrick break;
44709467b48Spatrick }
44809467b48Spatrick }
44909467b48Spatrick
45009467b48Spatrick if (!LineInfoValid)
45109467b48Spatrick return make_error<StringError>(
45209467b48Spatrick "DWARF line information missing. Did you compile with '-g'?",
45309467b48Spatrick inconvertibleErrorCode());
45409467b48Spatrick }
45509467b48Spatrick
45609467b48Spatrick for (const object::SectionRef &Section : Object->sections()) {
45709467b48Spatrick // Ensure only executable sections get analysed.
45809467b48Spatrick if (!(object::ELFSectionRef(Section).getFlags() & ELF::SHF_EXECINSTR))
45909467b48Spatrick continue;
46009467b48Spatrick
46109467b48Spatrick // Avoid checking the PLT since it produces spurious failures on AArch64
46209467b48Spatrick // when ignoring DWARF data.
46309467b48Spatrick Expected<StringRef> NameOrErr = Section.getName();
46409467b48Spatrick if (NameOrErr && *NameOrErr == ".plt")
46509467b48Spatrick continue;
46609467b48Spatrick consumeError(NameOrErr.takeError());
46709467b48Spatrick
46809467b48Spatrick Expected<StringRef> Contents = Section.getContents();
46909467b48Spatrick if (!Contents)
47009467b48Spatrick return Contents.takeError();
47109467b48Spatrick ArrayRef<uint8_t> SectionBytes = arrayRefFromStringRef(*Contents);
47209467b48Spatrick
47309467b48Spatrick parseSectionContents(SectionBytes,
47409467b48Spatrick {Section.getAddress(), Section.getIndex()});
47509467b48Spatrick }
47609467b48Spatrick return Error::success();
47709467b48Spatrick }
47809467b48Spatrick
parseSectionContents(ArrayRef<uint8_t> SectionBytes,object::SectionedAddress Address)47909467b48Spatrick void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
48009467b48Spatrick object::SectionedAddress Address) {
48109467b48Spatrick assert(Symbolizer && "Symbolizer is uninitialised.");
48209467b48Spatrick MCInst Instruction;
48309467b48Spatrick Instr InstrMeta;
48409467b48Spatrick uint64_t InstructionSize;
48509467b48Spatrick
48609467b48Spatrick for (uint64_t Byte = 0; Byte < SectionBytes.size();) {
48709467b48Spatrick bool ValidInstruction =
48809467b48Spatrick Disassembler->getInstruction(Instruction, InstructionSize,
48909467b48Spatrick SectionBytes.drop_front(Byte), 0,
49009467b48Spatrick outs()) == MCDisassembler::Success;
49109467b48Spatrick
49209467b48Spatrick Byte += InstructionSize;
49309467b48Spatrick
49409467b48Spatrick uint64_t VMAddress = Address.Address + Byte - InstructionSize;
49509467b48Spatrick InstrMeta.Instruction = Instruction;
49609467b48Spatrick InstrMeta.VMAddress = VMAddress;
49709467b48Spatrick InstrMeta.InstructionSize = InstructionSize;
49809467b48Spatrick InstrMeta.Valid = ValidInstruction;
49909467b48Spatrick
50009467b48Spatrick addInstruction(InstrMeta);
50109467b48Spatrick
50209467b48Spatrick if (!ValidInstruction)
50309467b48Spatrick continue;
50409467b48Spatrick
50509467b48Spatrick // Skip additional parsing for instructions that do not affect the control
50609467b48Spatrick // flow.
50709467b48Spatrick const auto &InstrDesc = MII->get(Instruction.getOpcode());
50809467b48Spatrick if (!InstrDesc.mayAffectControlFlow(Instruction, *RegisterInfo))
50909467b48Spatrick continue;
51009467b48Spatrick
51109467b48Spatrick uint64_t Target;
51209467b48Spatrick if (MIA->evaluateBranch(Instruction, VMAddress, InstructionSize, Target)) {
51309467b48Spatrick // If the target can be evaluated, it's not indirect.
51409467b48Spatrick StaticBranchTargetings[Target].push_back(VMAddress);
51509467b48Spatrick continue;
51609467b48Spatrick }
51709467b48Spatrick
51809467b48Spatrick if (!usesRegisterOperand(InstrMeta))
51909467b48Spatrick continue;
52009467b48Spatrick
52109467b48Spatrick if (InstrDesc.isReturn())
52209467b48Spatrick continue;
52309467b48Spatrick
52409467b48Spatrick // Check if this instruction exists in the range of the DWARF metadata.
52509467b48Spatrick if (!IgnoreDWARFFlag) {
526097a140dSpatrick auto LineInfo =
527097a140dSpatrick Symbolizer->symbolizeCode(std::string(Object->getFileName()),
528097a140dSpatrick {VMAddress, Address.SectionIndex});
52909467b48Spatrick if (!LineInfo) {
53009467b48Spatrick handleAllErrors(LineInfo.takeError(), [](const ErrorInfoBase &E) {
53109467b48Spatrick errs() << "Symbolizer failed to get line: " << E.message() << "\n";
53209467b48Spatrick });
53309467b48Spatrick continue;
53409467b48Spatrick }
53509467b48Spatrick
53609467b48Spatrick if (LineInfo->FileName == DILineInfo::BadString)
53709467b48Spatrick continue;
53809467b48Spatrick }
53909467b48Spatrick
54009467b48Spatrick IndirectInstructions.insert({VMAddress, Address.SectionIndex});
54109467b48Spatrick }
54209467b48Spatrick }
54309467b48Spatrick
addInstruction(const Instr & Instruction)54409467b48Spatrick void FileAnalysis::addInstruction(const Instr &Instruction) {
54509467b48Spatrick const auto &KV =
54609467b48Spatrick Instructions.insert(std::make_pair(Instruction.VMAddress, Instruction));
54709467b48Spatrick if (!KV.second) {
54809467b48Spatrick errs() << "Failed to add instruction at address "
54909467b48Spatrick << format_hex(Instruction.VMAddress, 2)
55009467b48Spatrick << ": Instruction at this address already exists.\n";
55109467b48Spatrick exit(EXIT_FAILURE);
55209467b48Spatrick }
55309467b48Spatrick }
55409467b48Spatrick
parseSymbolTable()55509467b48Spatrick Error FileAnalysis::parseSymbolTable() {
55609467b48Spatrick // Functions that will trap on CFI violations.
55709467b48Spatrick SmallSet<StringRef, 4> TrapOnFailFunctions;
55809467b48Spatrick TrapOnFailFunctions.insert("__cfi_slowpath");
55909467b48Spatrick TrapOnFailFunctions.insert("__cfi_slowpath_diag");
56009467b48Spatrick TrapOnFailFunctions.insert("abort");
56109467b48Spatrick
56209467b48Spatrick // Look through the list of symbols for functions that will trap on CFI
56309467b48Spatrick // violations.
56409467b48Spatrick for (auto &Sym : Object->symbols()) {
56509467b48Spatrick auto SymNameOrErr = Sym.getName();
56609467b48Spatrick if (!SymNameOrErr)
56709467b48Spatrick consumeError(SymNameOrErr.takeError());
56873471bf0Spatrick else if (TrapOnFailFunctions.contains(*SymNameOrErr)) {
56909467b48Spatrick auto AddrOrErr = Sym.getAddress();
57009467b48Spatrick if (!AddrOrErr)
57109467b48Spatrick consumeError(AddrOrErr.takeError());
57209467b48Spatrick else
57309467b48Spatrick TrapOnFailFunctionAddresses.insert(*AddrOrErr);
57409467b48Spatrick }
57509467b48Spatrick }
57609467b48Spatrick if (auto *ElfObject = dyn_cast<object::ELFObjectFileBase>(Object)) {
57709467b48Spatrick for (const auto &Addr : ElfObject->getPltAddresses()) {
57873471bf0Spatrick if (!Addr.first)
57973471bf0Spatrick continue;
58073471bf0Spatrick object::SymbolRef Sym(*Addr.first, Object);
58109467b48Spatrick auto SymNameOrErr = Sym.getName();
58209467b48Spatrick if (!SymNameOrErr)
58309467b48Spatrick consumeError(SymNameOrErr.takeError());
58473471bf0Spatrick else if (TrapOnFailFunctions.contains(*SymNameOrErr))
58509467b48Spatrick TrapOnFailFunctionAddresses.insert(Addr.second);
58609467b48Spatrick }
58709467b48Spatrick }
58809467b48Spatrick return Error::success();
58909467b48Spatrick }
59009467b48Spatrick
UnsupportedDisassembly(StringRef Text)591097a140dSpatrick UnsupportedDisassembly::UnsupportedDisassembly(StringRef Text)
592097a140dSpatrick : Text(std::string(Text)) {}
59309467b48Spatrick
59409467b48Spatrick char UnsupportedDisassembly::ID;
log(raw_ostream & OS) const59509467b48Spatrick void UnsupportedDisassembly::log(raw_ostream &OS) const {
59609467b48Spatrick OS << "Could not initialise disassembler: " << Text;
59709467b48Spatrick }
59809467b48Spatrick
convertToErrorCode() const59909467b48Spatrick std::error_code UnsupportedDisassembly::convertToErrorCode() const {
60009467b48Spatrick return std::error_code();
60109467b48Spatrick }
60209467b48Spatrick
60309467b48Spatrick } // namespace cfi_verify
60409467b48Spatrick } // namespace llvm
605