Support DWARF expressions in CFI instructions

Summary:
Modify the MC layer (MCDwarf.h|cpp) to understand CFI
instructions dealing with DWARF expressions. Add code to emit DWARF
expressions in MCDwarf. Change llvm-bolt to pass these CFI instructions
to streamer instead of bailing on them. Change -dump-eh-frame option in
llvm-bolt to dump the EH frame of the rewritten binary in addition to
the one in the original binary, allowing us to proper test this patch.

(cherry picked from FBD4194452)
This commit is contained in:
Rafael Auler
2016-11-15 10:40:00 -08:00
committed by Maksim Panchenko
parent 99dce7d05e
commit bc8cb088c0
2 changed files with 58 additions and 61 deletions

View File

@@ -585,13 +585,13 @@ bool CFIReaderWriter::fillCFIInfoFor(BinaryFunction &Function) const {
case DW_CFA_def_cfa:
Function.addCFIInstruction(
Offset, MCCFIInstruction::createDefCfa(nullptr, Instr.Ops[1],
-Instr.Ops[0]));
Instr.Ops[0]));
break;
case DW_CFA_def_cfa_sf:
Function.addCFIInstruction(
Offset, MCCFIInstruction::createDefCfa(
nullptr, Instr.Ops[1],
-(DataAlignment * int64_t(Instr.Ops[0]))));
DataAlignment * int64_t(Instr.Ops[0])));
break;
case DW_CFA_def_cfa_register:
Function.addCFIInstruction(
@@ -601,12 +601,12 @@ bool CFIReaderWriter::fillCFIInfoFor(BinaryFunction &Function) const {
case DW_CFA_def_cfa_offset:
Function.addCFIInstruction(
Offset,
MCCFIInstruction::createDefCfaOffset(nullptr, -Instr.Ops[0]));
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]))));
nullptr, DataAlignment * int64_t(Instr.Ops[0])));
break;
case DW_CFA_GNU_args_size:
Function.addCFIInstruction(
@@ -622,11 +622,40 @@ bool CFIReaderWriter::fillCFIInfoFor(BinaryFunction &Function) const {
return false;
case DW_CFA_expression:
case DW_CFA_def_cfa_expression:
case DW_CFA_val_expression:
if (opts::Verbosity >= 1) {
errs() << "BOLT-WARNING: DWARF CFA expressions unimplemented\n";
case DW_CFA_val_expression: {
MCDwarfExprBuilder Builder;
for (const auto &Operation : Instr.ExprOps) {
switch (Operation.Ops.size()) {
case 0:
Builder.appendOperation(Operation.Opcode);
break;
case 1:
Builder.appendOperation(Operation.Opcode, Operation.Ops[0]);
break;
case 2:
Builder.appendOperation(Operation.Opcode, Operation.Ops[0],
Operation.Ops[1]);
break;
default:
llvm_unreachable("Unrecognized DWARF expression");
}
}
return false;
if (Opcode == DW_CFA_expression) {
Function.addCFIInstruction(
Offset, MCCFIInstruction::createExpression(
nullptr, Instr.Ops[0], Builder.take()));
} else if (Opcode == DW_CFA_def_cfa_expression) {
Function.addCFIInstruction(Offset,
MCCFIInstruction::createDefCfaExpression(
nullptr, Builder.take()));
} else {
assert(Opcode == DW_CFA_val_expression && "Unexpected opcode");
Function.addCFIInstruction(
Offset, MCCFIInstruction::createValExpression(
nullptr, Instr.Ops[0], Builder.take()));
}
break;
}
case DW_CFA_MIPS_advance_loc8:
if (opts::Verbosity >= 1) {
errs() << "BOLT-WARNING: DW_CFA_MIPS_advance_loc unimplemented\n";
@@ -636,8 +665,8 @@ bool CFIReaderWriter::fillCFIInfoFor(BinaryFunction &Function) const {
case DW_CFA_lo_user:
case DW_CFA_hi_user:
if (opts::Verbosity >= 1) {
errs() <<
"BOLT-WARNING: DW_CFA_GNU_* and DW_CFA_*_user unimplemented\n";
errs() << "BOLT-WARNING: DW_CFA_GNU_* and DW_CFA_*_user "
"unimplemented\n";
}
return false;
default:

View File

@@ -1042,6 +1042,7 @@ void RewriteInstance::readSpecialSections() {
// Process debug sections.
EHFrame = BC->DwCtx->getEHFrame();
if (opts::DumpEHFrame) {
outs() << "BOLT-INFO: Dumping original binary .eh_frame\n";
EHFrame->dump(outs());
}
CFIRdWrt.reset(new CFIReaderWriter(*EHFrame, FrameHdrAddress, FrameHdrCopy));
@@ -1240,55 +1241,6 @@ namespace {
// Helper function to emit the contents of a function via a MCStreamer object.
void emitFunction(MCStreamer &Streamer, BinaryFunction &Function,
BinaryContext &BC, bool EmitColdPart) {
// Define a helper to decode and emit CFI instructions at a given point in a
// BB
auto emitCFIInstr = [&Streamer](const MCCFIInstruction &CFIInstr) {
switch (CFIInstr.getOperation()) {
default:
llvm_unreachable("Unexpected instruction");
case MCCFIInstruction::OpDefCfaOffset:
Streamer.EmitCFIDefCfaOffset(CFIInstr.getOffset());
break;
case MCCFIInstruction::OpAdjustCfaOffset:
Streamer.EmitCFIAdjustCfaOffset(CFIInstr.getOffset());
break;
case MCCFIInstruction::OpDefCfa:
Streamer.EmitCFIDefCfa(CFIInstr.getRegister(), CFIInstr.getOffset());
break;
case MCCFIInstruction::OpDefCfaRegister:
Streamer.EmitCFIDefCfaRegister(CFIInstr.getRegister());
break;
case MCCFIInstruction::OpOffset:
Streamer.EmitCFIOffset(CFIInstr.getRegister(), CFIInstr.getOffset());
break;
case MCCFIInstruction::OpRegister:
Streamer.EmitCFIRegister(CFIInstr.getRegister(),
CFIInstr.getRegister2());
break;
case MCCFIInstruction::OpRelOffset:
Streamer.EmitCFIRelOffset(CFIInstr.getRegister(), CFIInstr.getOffset());
break;
case MCCFIInstruction::OpUndefined:
Streamer.EmitCFIUndefined(CFIInstr.getRegister());
break;
case MCCFIInstruction::OpRememberState:
Streamer.EmitCFIRememberState();
break;
case MCCFIInstruction::OpRestoreState:
Streamer.EmitCFIRestoreState();
break;
case MCCFIInstruction::OpRestore:
Streamer.EmitCFIRestore(CFIInstr.getRegister());
break;
case MCCFIInstruction::OpSameValue:
Streamer.EmitCFISameValue(CFIInstr.getRegister());
break;
case MCCFIInstruction::OpGnuArgsSize:
Streamer.EmitCFIGnuArgsSize(CFIInstr.getOffset());
break;
}
};
// No need for human readability?
// FIXME: what difference does it make in reality?
// Ctx.setUseNamesOnTempLabels(false);
@@ -1350,7 +1302,7 @@ void emitFunction(MCStreamer &Streamer, BinaryFunction &Function,
continue;
break;
}
emitCFIInstr(CFIInstr);
Streamer.EmitCFIInstruction(CFIInstr);
}
}
@@ -1391,7 +1343,7 @@ void emitFunction(MCStreamer &Streamer, BinaryFunction &Function,
continue;
}
if (BC.MIA->isCFI(Instr)) {
emitCFIInstr(*Function.getCFIFor(Instr));
Streamer.EmitCFIInstruction(*Function.getCFIFor(Instr));
continue;
}
if (opts::UpdateDebugSections) {
@@ -2212,6 +2164,22 @@ void RewriteInstance::rewriteFile() {
// TODO: we should find a way to mark the binary as optimized by us.
Out->keep();
// If requested, open again the binary we just wrote to dump its EH Frame
if (opts::DumpEHFrame) {
ErrorOr<OwningBinary<Binary>> BinaryOrErr =
createBinary(opts::OutputFilename);
if (std::error_code EC = BinaryOrErr.getError())
report_error(opts::OutputFilename, EC);
Binary &Binary = *BinaryOrErr.get().getBinary();
if (auto *E = dyn_cast<ELFObjectFileBase>(&Binary)) {
DWARFContextInMemory DwCtx(*E);
const auto &EHFrame = DwCtx.getEHFrame();
outs() << "BOLT-INFO: Dumping rewritten .eh_frame\n";
EHFrame->dump(outs());
}
}
}
bool RewriteInstance::shouldOverwriteSection(StringRef SectionName) {