mirror of
https://github.com/intel/llvm.git
synced 2026-01-19 09:31:59 +08:00
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:
committed by
Maksim Panchenko
parent
99dce7d05e
commit
bc8cb088c0
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user