forked from OSchip/llvm-project
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:
parent
de46e6fc07
commit
a30d04c3e2
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
Loading…
Reference in New Issue