|
| 1 | +#include "propeller/mini_disassembler.h" |
| 2 | + |
| 3 | +#include <cstdint> |
| 4 | +#include <memory> |
| 5 | +#include <string> |
| 6 | + |
| 7 | +#include "absl/base/nullability.h" |
| 8 | +#include "absl/log/check.h" |
| 9 | +#include "absl/log/log.h" |
| 10 | +#include "absl/memory/memory.h" |
| 11 | +#include "absl/status/status.h" |
| 12 | +#include "absl/status/statusor.h" |
| 13 | +#include "absl/strings/str_format.h" |
| 14 | +#include "absl/strings/string_view.h" |
| 15 | +#include "llvm/ADT/ArrayRef.h" |
| 16 | +#include "llvm/ADT/StringRef.h" |
| 17 | +#include "llvm/MC/MCInst.h" |
| 18 | +#include "llvm/MC/MCInstrDesc.h" |
| 19 | +#include "llvm/MC/MCInstrInfo.h" |
| 20 | +#include "llvm/MC/TargetRegistry.h" |
| 21 | +#include "llvm/Object/ObjectFile.h" |
| 22 | +#include "llvm/Support/Error.h" |
| 23 | +#include "llvm/Support/TargetSelect.h" |
| 24 | +#include "llvm/Support/raw_ostream.h" |
| 25 | +#include "llvm/TargetParser/Triple.h" |
| 26 | + |
| 27 | +namespace propeller { |
| 28 | +absl::StatusOr<absl::Nonnull<std::unique_ptr<MiniDisassembler>>> |
| 29 | +MiniDisassembler::Create(const llvm::object::ObjectFile *object_file) { |
| 30 | + auto disassembler = |
| 31 | + absl::WrapUnique<MiniDisassembler>(new MiniDisassembler(object_file)); |
| 32 | + |
| 33 | + std::string err; |
| 34 | + llvm::InitializeAllTargetInfos(); |
| 35 | + llvm::InitializeAllTargetMCs(); |
| 36 | + llvm::InitializeAllAsmParsers(); |
| 37 | + llvm::InitializeAllDisassemblers(); |
| 38 | + |
| 39 | + llvm::Triple triple; |
| 40 | + triple.setArch( |
| 41 | + llvm::Triple::ArchType(object_file->getArch())); |
| 42 | + const llvm::Target *target = |
| 43 | + llvm::TargetRegistry::lookupTarget(triple.normalize(), err); |
| 44 | + if (target == nullptr) { |
| 45 | + return absl::FailedPreconditionError(absl::StrFormat( |
| 46 | + "no target for triple '%s': %s", triple.getArchName(), err)); |
| 47 | + } |
| 48 | + disassembler->mri_ = |
| 49 | + absl::WrapUnique(target->createMCRegInfo(triple.getTriple())); |
| 50 | + if (disassembler->mri_ == nullptr) { |
| 51 | + return absl::FailedPreconditionError(absl::StrFormat( |
| 52 | + "createMCRegInfo failed for triple '%s'", triple.getArchName())); |
| 53 | + } |
| 54 | + disassembler->asm_info_ = absl::WrapUnique(target->createMCAsmInfo( |
| 55 | + *disassembler->mri_, triple.getTriple(), llvm::MCTargetOptions())); |
| 56 | + if (disassembler->asm_info_ == nullptr) { |
| 57 | + return absl::FailedPreconditionError(absl::StrFormat( |
| 58 | + "createMCAsmInfo failed for triple '%s'", triple.getArchName())); |
| 59 | + } |
| 60 | + |
| 61 | + disassembler->sti_ = absl::WrapUnique(target->createMCSubtargetInfo( |
| 62 | + triple.getTriple(), /*CPU=*/"", /*Features=*/"")); |
| 63 | + if (disassembler->sti_ == nullptr) { |
| 64 | + return absl::FailedPreconditionError(absl::StrFormat( |
| 65 | + "createMCSubtargetInfo failed for triple '%s'", triple.getArchName())); |
| 66 | + } |
| 67 | + |
| 68 | + disassembler->mii_ = absl::WrapUnique(target->createMCInstrInfo()); |
| 69 | + if (disassembler->mii_ == nullptr) { |
| 70 | + return absl::FailedPreconditionError(absl::StrFormat( |
| 71 | + "createMCInstrInfo failed for triple '%s'", triple.getArchName())); |
| 72 | + } |
| 73 | + |
| 74 | + disassembler->mia_ = |
| 75 | + absl::WrapUnique(target->createMCInstrAnalysis(disassembler->mii_.get())); |
| 76 | + if (disassembler->mia_ == nullptr) { |
| 77 | + return absl::FailedPreconditionError(absl::StrFormat( |
| 78 | + "createMCInstrAnalysis failed for triple '%s'", triple.getArchName())); |
| 79 | + } |
| 80 | + |
| 81 | + disassembler->ctx_ = std::make_unique<llvm::MCContext>( |
| 82 | + triple, disassembler->asm_info_.get(), disassembler->mri_.get(), |
| 83 | + disassembler->sti_.get()); |
| 84 | + disassembler->disasm_ = absl::WrapUnique( |
| 85 | + target->createMCDisassembler(*disassembler->sti_, *disassembler->ctx_)); |
| 86 | + if (disassembler->disasm_ == nullptr) |
| 87 | + return absl::FailedPreconditionError( |
| 88 | + absl::StrFormat("createMCDisassembler failed")); |
| 89 | + |
| 90 | + return disassembler; |
| 91 | +} |
| 92 | + |
| 93 | +absl::StatusOr<llvm::MCInst> MiniDisassembler::DisassembleOne( |
| 94 | + uint64_t binary_address) { |
| 95 | + for (const auto §ion : object_file_->sections()) { |
| 96 | + if (!section.isText() || section.isVirtual()) { |
| 97 | + continue; |
| 98 | + } |
| 99 | + if (binary_address < section.getAddress() || |
| 100 | + binary_address >= section.getAddress() + section.getSize()) { |
| 101 | + continue; |
| 102 | + } |
| 103 | + llvm::Expected<llvm::StringRef> content = section.getContents(); |
| 104 | + if (!content) { |
| 105 | + return absl::FailedPreconditionError("section has no content"); |
| 106 | + } |
| 107 | + llvm::ArrayRef<uint8_t> content_bytes( |
| 108 | + reinterpret_cast<const uint8_t *>(content->data()), content->size()); |
| 109 | + uint64_t section_offset = binary_address - section.getAddress(); |
| 110 | + llvm::MCInst inst; |
| 111 | + uint64_t size; |
| 112 | + if (!disasm_->getInstruction(inst, size, |
| 113 | + content_bytes.slice(section_offset), |
| 114 | + binary_address, llvm::nulls())) { |
| 115 | + return absl::FailedPreconditionError(absl::StrFormat( |
| 116 | + "getInstruction failed at binary address 0x%lx", binary_address)); |
| 117 | + } |
| 118 | + return inst; |
| 119 | + } |
| 120 | + return absl::FailedPreconditionError(absl::StrFormat( |
| 121 | + "no section containing address 0x%lx found", binary_address)); |
| 122 | +} |
| 123 | + |
| 124 | +bool MiniDisassembler::MayAffectControlFlow(const llvm::MCInst &inst) { |
| 125 | + return mii_->get(inst.getOpcode()).mayAffectControlFlow(inst, *mri_); |
| 126 | +} |
| 127 | + |
| 128 | +llvm::StringRef MiniDisassembler::GetInstructionName( |
| 129 | + const llvm::MCInst &inst) const { |
| 130 | + return mii_->getName(inst.getOpcode()); |
| 131 | +} |
| 132 | + |
| 133 | +absl::StatusOr<bool> MiniDisassembler::MayAffectControlFlow( |
| 134 | + uint64_t binary_address) { |
| 135 | + auto inst = DisassembleOne(binary_address); |
| 136 | + if (!inst.ok()) return inst.status(); |
| 137 | + return MayAffectControlFlow(inst.value()); |
| 138 | +} |
| 139 | +} // namespace propeller |
0 commit comments