Annotate BinaryFunctions with MCCFIInstructions encoding CFI

Summary:
In order to represent CFI information in our BinaryFunction class, this
patch adds a map of Offsets to CFI instructions. In this way, we make it easy to
check exactly where DWARF CFI information is annotated in the disassembled
function.

(cherry picked from FBD2619216)
This commit is contained in:
Rafael Auler 2015-11-04 16:48:47 -08:00 committed by Maksim Panchenko
parent de46e6fc07
commit a30d04c3e2
5 changed files with 208 additions and 3 deletions

View File

@ -76,7 +76,8 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
<< "\n Section : " << SectionName
<< "\n Orc Section : " << getCodeSectionName()
<< "\n IsSimple : " << IsSimple
<< "\n BB Count : " << BasicBlocksLayout.size();
<< "\n BB Count : " << BasicBlocksLayout.size()
<< "\n CFI Instrs : " << FrameInstructions.size();
if (BasicBlocksLayout.size()) {
OS << "\n BB Layout : ";
auto Sep = "";
@ -177,6 +178,33 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
OS << '\n';
}
if (FrameInstructions.empty()) {
OS << "End of Function \"" << getName() << "\"\n";
return;
}
OS << "DWARF CFI Instructions:\n";
for (auto &CFIInstr : FrameInstructions) {
OS << format(" %08x: ", CFIInstr.first);
switch(CFIInstr.second.getOperation()) {
case MCCFIInstruction::OpSameValue: OS << "OpSameValue"; break;
case MCCFIInstruction::OpRememberState: OS << "OpRememberState"; break;
case MCCFIInstruction::OpRestoreState: OS << "OpRestoreState"; break;
case MCCFIInstruction::OpOffset: OS << "OpOffset"; break;
case MCCFIInstruction::OpDefCfaRegister: OS << "OpDefCfaRegister"; break;
case MCCFIInstruction::OpDefCfaOffset: OS << "OpDefCfaOffset"; break;
case MCCFIInstruction::OpDefCfa: OS << "OpDefCfa"; break;
case MCCFIInstruction::OpRelOffset: OS << "OpRelOffset"; break;
case MCCFIInstruction::OpAdjustCfaOffset: OS << "OfAdjustCfaOffset"; break;
case MCCFIInstruction::OpEscape: OS << "OpEscape"; break;
case MCCFIInstruction::OpRestore: OS << "OpRestore"; break;
case MCCFIInstruction::OpUndefined: OS << "OpUndefined"; break;
case MCCFIInstruction::OpRegister: OS << "OpRegister"; break;
case MCCFIInstruction::OpWindowSave: OS << "OpWindowSave"; break;
}
OS << "\n";
}
OS << "End of Function \"" << getName() << "\"\n";
}

View File

@ -24,6 +24,7 @@
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCSubtargetInfo.h"
@ -167,6 +168,10 @@ private:
using InstrMapType = std::map<uint32_t, MCInst>;
InstrMapType Instructions;
/// List of DWARF CFI instructions
using CFIInstrMapType = std::multimap<uint32_t, MCCFIInstruction>;
CFIInstrMapType FrameInstructions;
// Blocks are kept sorted in the layout order. If we need to change the
// layout (if BasicBlocksLayout stores a different order than BasicBlocks),
// the terminating instructions need to be modified.
@ -342,6 +347,10 @@ public:
Instructions.emplace(Offset, std::forward<MCInst>(Instruction));
}
void addCFIInstruction(uint64_t Offset, MCCFIInstruction &&Inst) {
FrameInstructions.emplace(Offset, std::forward<MCCFIInstruction>(Inst));
}
BinaryFunction &setFileOffset(uint64_t Offset) {
FileOffset = Offset;
return *this;

View File

@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Exceptions.h"
#include "BinaryFunction.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
@ -251,5 +252,135 @@ void readLSDA(ArrayRef<uint8_t> LSDAData, BinaryContext &BC) {
}
}
const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
void CFIReader::fillCFIInfoFor(BinaryFunction &Function) const {
uint64_t Address = Function.getAddress();
auto I = FDEs.find(Address);
if (I == FDEs.end())
return;
const FDE &CurFDE = *I->second;
if (Function.getSize() != CurFDE.getAddressRange()) {
errs() << "FLO-WARNING: CFI information size mismatch for function \""
<< Function.getName() << "\""
<< format(": Function size is %dB, CFI covers "
"%dB\n",
Function.getSize(), CurFDE.getAddressRange());
}
uint64_t Offset = 0;
uint64_t CodeAlignment = CurFDE.getLinkedCIE()->getCodeAlignmentFactor();
uint64_t DataAlignment = CurFDE.getLinkedCIE()->getDataAlignmentFactor();
for (const FrameEntry::Instruction &Instr : CurFDE) {
uint8_t Opcode = Instr.Opcode;
if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
switch (Instr.Opcode) {
case DW_CFA_nop:
break;
case DW_CFA_advance_loc4:
case DW_CFA_advance_loc2:
case DW_CFA_advance_loc1:
case DW_CFA_advance_loc:
// Advance our current address
Offset += CodeAlignment * int64_t(Instr.Ops[0]);
break;
case DW_CFA_offset_extended_sf:
Function.addCFIInstruction(
Offset,
MCCFIInstruction::createOffset(
nullptr, Instr.Ops[0], DataAlignment * int64_t(Instr.Ops[1])));
break;
case DW_CFA_offset_extended:
case DW_CFA_offset:
Function.addCFIInstruction(
Offset, MCCFIInstruction::createOffset(nullptr, Instr.Ops[0],
DataAlignment * Instr.Ops[1]));
break;
case DW_CFA_restore_extended:
case DW_CFA_restore:
Function.addCFIInstruction(
Offset, MCCFIInstruction::createRestore(nullptr, Instr.Ops[0]));
break;
case DW_CFA_set_loc:
assert(Instr.Ops[0] < Address && "set_loc out of function bounds");
assert(Instr.Ops[0] > Address + Function.getSize() &&
"set_loc out of function bounds");
Offset = Instr.Ops[0] - Address;
break;
case DW_CFA_undefined:
Function.addCFIInstruction(
Offset, MCCFIInstruction::createUndefined(nullptr, Instr.Ops[0]));
break;
case DW_CFA_same_value:
Function.addCFIInstruction(
Offset, MCCFIInstruction::createSameValue(nullptr, Instr.Ops[0]));
break;
case DW_CFA_register:
Function.addCFIInstruction(
Offset, MCCFIInstruction::createRegister(nullptr, Instr.Ops[0],
Instr.Ops[1]));
break;
case DW_CFA_remember_state:
Function.addCFIInstruction(
Offset, MCCFIInstruction::createRememberState(nullptr));
break;
case DW_CFA_restore_state:
Function.addCFIInstruction(Offset,
MCCFIInstruction::createRestoreState(nullptr));
break;
case DW_CFA_def_cfa:
Function.addCFIInstruction(
Offset,
MCCFIInstruction::createDefCfa(nullptr, Instr.Ops[0], Instr.Ops[1]));
break;
case DW_CFA_def_cfa_sf:
Function.addCFIInstruction(
Offset,
MCCFIInstruction::createDefCfa(
nullptr, Instr.Ops[0], DataAlignment * int64_t(Instr.Ops[1])));
break;
case DW_CFA_def_cfa_register:
Function.addCFIInstruction(Offset, MCCFIInstruction::createDefCfaRegister(
nullptr, Instr.Ops[0]));
break;
case DW_CFA_def_cfa_offset:
Function.addCFIInstruction(
Offset, MCCFIInstruction::createDefCfaOffset(nullptr, Instr.Ops[0]));
break;
case DW_CFA_def_cfa_offset_sf:
Function.addCFIInstruction(
Offset, MCCFIInstruction::createDefCfaOffset(
nullptr, DataAlignment * int64_t(Instr.Ops[0])));
break;
case DW_CFA_val_offset_sf:
case DW_CFA_val_offset:
llvm_unreachable("DWARF val_offset() unimplemented");
break;
case DW_CFA_expression:
case DW_CFA_def_cfa_expression:
case DW_CFA_val_expression:
llvm_unreachable("DWARF CFA expressions unimplemented");
break;
dbgs() << "DW_CFA_val_expression";
break;
case DW_CFA_MIPS_advance_loc8:
llvm_unreachable("DW_CFA_MIPS_advance_loc unimplemented");
break;
case DW_CFA_GNU_args_size:
case DW_CFA_GNU_window_save:
case DW_CFA_lo_user:
case DW_CFA_hi_user:
llvm_unreachable("DW_CFA_GNU_* and DW_CFA_*_use unimplemented");
break;
default:
llvm_unreachable("Unrecognized CFI instruction");
}
}
}
} // namespace flo
} // namespace llvm

View File

@ -14,12 +14,40 @@
#include "BinaryContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/DebugInfo/DWARF/DWARFFrame.h"
#include "llvm/Support/Casting.h"
#include <map>
namespace llvm {
namespace flo {
class BinaryFunction;
void readLSDA(ArrayRef<uint8_t> LSDAData, BinaryContext &BC);
/// \brief Wraps up information to read all CFI instructions and feed them to a
/// BinaryFunction.
class CFIReader {
public:
explicit CFIReader(const DWARFFrame &EHFrame) : EHFrame(EHFrame) {
// Prepare FDEs for fast lookup
for (const auto &Entry : EHFrame.Entries) {
const dwarf::FrameEntry *FE = Entry.get();
if (const auto *CurFDE = dyn_cast<dwarf::FDE>(FE)) {
FDEs[CurFDE->getInitialLocation()] = CurFDE;
}
}
}
using FDEsMap = std::map<uint64_t, const dwarf::FDE *>;
void fillCFIInfoFor(BinaryFunction &Function) const;
private:
const DWARFFrame &EHFrame;
FDEsMap FDEs;
};
} // namespace flo
} // namespace llvm

View File

@ -471,9 +471,14 @@ static void OptimizeFile(ELFObjectFileBase *File, const DataReader &DR) {
// Process debug sections.
std::unique_ptr<DWARFContext> DwCtx(new DWARFContextInMemory(*File));
const DWARFFrame &EHFrame = *DwCtx->getEHFrame();
if (opts::DumpEHFrame) {
const auto *Frames = DwCtx->getEHFrame();
Frames->dump(outs());
EHFrame.dump(outs());
}
CFIReader DwCFIReader(EHFrame);
if (!EHFrame.ParseError.empty()) {
errs() << "FLO-WARNING: EHFrame reader failed with message \""
<< EHFrame.ParseError << "\"\n";
}
// Disassemble every function and build it's control flow graph.
@ -533,6 +538,10 @@ static void OptimizeFile(ELFObjectFileBase *File, const DataReader &DR) {
if (!Function.disassemble(FunctionData))
continue;
// Fill in CFI information for this function
if (EHFrame.ParseError.empty())
DwCFIReader.fillCFIInfoFor(Function);
if (opts::PrintAll || opts::PrintDisasm)
Function.print(errs(), "after disassembly");