Files
revng-revng/lib/Model/Importer/Binary/PECOFFImporter.cpp
Alessandro Di Federico ee0b8f44c1 Introduce BinaryImporter
This is a big step to split revng-lift in two parts: one that only
writes the model and one that actually lifts to LLVM IR.

* Introduce `revng import binary`
* Split off `BinaryFile.h`
* Drop `revng.h`
* `GeneratedCodeBasicInfo`: use model
* Reduce role of `GeneratedCodeBasicInfo` in favor of
  `model::Architecture` and `model::Register` methods
* `CodeGenerator`: adopt `RawBinaryView` and model
* `JumpTargetManager`: adopt `RawBinaryView` and model
* `ExternalJumpsHandler`: adopt model
* `InstructionTranslator`: discard `Architecture` in favor of
  `EndianessMismatch`
* Many other changes
2022-03-08 15:15:24 +01:00

109 lines
3.5 KiB
C++

/// \file PECOFF.cpp
/// \brief
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
#include "revng/Model/Binary.h"
#include "revng/Support/Debug.h"
#include "BinaryImporterHelper.h"
#include "Importers.h"
using namespace llvm;
static Logger<> Log("pecoff-importer");
class PECOFFImporter : public BinaryImporterHelper {
private:
TupleTree<model::Binary> &Model;
const object::COFFObjectFile &TheBinary;
public:
PECOFFImporter(TupleTree<model::Binary> &Model,
const object::COFFObjectFile &TheBinary) :
Model(Model), TheBinary(TheBinary) {}
Error import();
};
Error PECOFFImporter::import() {
using namespace model;
revng_assert(Model->Architecture != Architecture::Invalid);
Architecture = Model->Architecture;
auto PointerSize = Architecture::getPointerSize(Architecture);
bool IsLittleEndian = Architecture::isLittleEndian(Architecture);
if ((PointerSize != 4 and PointerSize != 8) or not IsLittleEndian)
return createError("Only 32/64-bit little endian COFF files are supported");
const object::pe32_header *PE32Header = TheBinary.getPE32Header();
MetaAddress ImageBase = MetaAddress::invalid();
if (PE32Header) {
// TODO: ImageBase should aligned to 4kb pages, should we check that?
ImageBase = fromPC(PE32Header->ImageBase);
Model->EntryPoint = ImageBase + u64(PE32Header->AddressOfEntryPoint);
} else {
const object::pe32plus_header *PE32PlusHeader = TheBinary
.getPE32PlusHeader();
if (not PE32PlusHeader)
return createError("Invalid PE Header");
// PE32+ Header
ImageBase = fromPC(PE32PlusHeader->ImageBase);
Model->EntryPoint = ImageBase + u64(PE32PlusHeader->AddressOfEntryPoint);
}
// Read sections
for (const llvm::object::SectionRef &SecRef : TheBinary.sections()) {
unsigned Id = TheBinary.getSectionID(SecRef);
Expected<const object::coff_section *> SecOrErr = TheBinary.getSection(Id);
if (not SecOrErr) {
revng_log(Log,
"Error in section with ID " << Id << ": "
<< SecOrErr.takeError());
continue;
}
const object::coff_section *CoffRef = *SecOrErr;
// VirtualSize might be larger than SizeOfRawData (extra data at the end of
// the section) or viceversa (data mapped in memory but not present in
// memory, e.g., .bss)
uint64_t SegmentSize = std::min(CoffRef->VirtualSize,
CoffRef->SizeOfRawData);
MetaAddress Start = ImageBase + u64(CoffRef->VirtualAddress);
Segment Segment({ Start, u64(CoffRef->VirtualSize) });
Segment.StartOffset = CoffRef->PointerToRawData;
Segment.FileSize = Segment.StartOffset + SegmentSize;
Segment.IsReadable = CoffRef->Characteristics & COFF::IMAGE_SCN_MEM_READ;
Segment.IsWriteable = CoffRef->Characteristics & COFF::IMAGE_SCN_MEM_WRITE;
Segment.IsExecutable = CoffRef->Characteristics
& COFF::IMAGE_SCN_MEM_EXECUTE;
Segment.verify(true);
Model->Segments.insert(std::move(Segment));
}
return Error::success();
}
Error importPECOFF(TupleTree<model::Binary> &Model,
const object::COFFObjectFile &TheBinary,
uint64_t PreferredBaseAddress) {
// TODO: use PreferredBaseAddress if PIC
(void) PreferredBaseAddress;
PECOFFImporter Importer(Model, TheBinary);
return Importer.import();
}