/*
* Copyright (c) 2020 Trail of Bits, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "Legacy.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wold-style-cast"
#pragma clang diagnostic ignored "-Wdocumentation"
#pragma clang diagnostic ignored "-Wswitch-enum"
#include
#include
#include
#include
#include
#include
#include
#include
#pragma clang diagnostic pop
#include
#include
#include
#include
#include
#include "mcsema/Arch/Arch.h"
#include "mcsema/BC/Callback.h"
#include "mcsema/BC/Legacy.h"
#include "mcsema/BC/Util.h"
DEFINE_string(pc_annotation, "",
"Name of the metadata to apply to every LLVM instruction. The "
"metadata includes the approximate program counter of the "
"original instruction that produced the lifted bitcode.");
namespace mcsema {
namespace legacy {
namespace {
// Create the node for a `mcsema_real_eip` annotation.
static llvm::MDNode *CreateInstAnnotation(llvm::Function *F, uint64_t addr) {
auto addr_val = llvm::ConstantInt::get(gWordType, addr);
#if LLVM_VERSION_NUMBER >= LLVM_VERSION(3, 6)
auto addr_md = llvm::ValueAsMetadata::get(addr_val);
return llvm::MDNode::get(*gContext, addr_md);
#else
return llvm::MDNode::get(*gContext, addr_val);
#endif
}
static unsigned AnnotationID(void) {
static bool has_id = false;
static unsigned id = 0;
if (!has_id) {
has_id = true;
id = gContext->getMDKindID(FLAGS_pc_annotation);
}
return id;
}
// Annotate and instruction with the `mcsema_real_eip` annotation if that
// instruction is unannotated.
static void AnnotateInst(llvm::Instruction *inst, llvm::MDNode *annot) {
auto id = AnnotationID();
if (!inst->getMetadata(id)) {
inst->setMetadata(id, annot);
}
}
} // namespace
// Create a `mcsema_real_eip` annotation, and annotate every unannotated
// instruction with this new annotation.
void AnnotateInsts(llvm::Function *func, uint64_t pc) {
auto annot = CreateInstAnnotation(func, pc);
for (llvm::BasicBlock &block : *func) {
for (llvm::Instruction &inst : block) {
AnnotateInst(&inst, annot);
}
}
}
// Propagate any instruction annotations.
void PropagateInstAnnotations(void) {
auto id = AnnotationID();
std::vector pending;
for (auto &func : *gModule) {
if (func.isDeclaration()) {
continue;
}
for (auto &block : func) {
llvm::MDNode *prev = nullptr;
for (auto &inst : block) {
auto curr = inst.getMetadata(id);
if (curr) {
prev = curr;
} else if (prev) {
inst.setMetadata(id, prev);
} else {
pending.push_back(&inst);
}
if (prev && pending.size()) {
for (auto pending_inst : pending) {
pending_inst->setMetadata(id, prev);
}
pending.clear();
}
}
if (prev && pending.size()) {
for (auto pending_inst : pending) {
pending_inst->setMetadata(id, prev);
}
pending.clear();
}
}
}
}
} // namespace legacy
} // namespace mcsema