Teach llvm-flo how to read .eh_frame information from binaries

Summary: In order to reorder binaries with C++ exceptions, we first need to
read DWARF CFI (call frame info) from binaries in a table in the .eh_frame
ELF section. This table contains unwinding information we need to be aware of
when reordering basic blocks, so as to avoid corrupting it. This patch also
cleans up some code from Exceptions.cpp due to a refactoring where we moved
some functions to the LLVM's libSupport.

(cherry picked from FBD2614464)
This commit is contained in:
Rafael Auler 2015-11-05 13:37:30 -08:00 committed by Maksim Panchenko
parent 7d592d0975
commit 2088875656
3 changed files with 13 additions and 113 deletions

View file

@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
CodeGen
Core
DebugInfoDWARF
MC
MCDisassembler
MCParser

View file

@ -45,119 +45,6 @@ PrintExceptions("print-exceptions",
} // namespace opts
namespace {
/// Read an unsigned LEB128 value from data, advancing it past the value.
uintptr_t readULEB128(const uint8_t *&Data) {
uintptr_t Result = 0;
uintptr_t Shift = 0;
unsigned char Byte;
do {
Byte = *Data++;
Result |= (Byte & 0x7f) << Shift;
Shift += 7;
} while (Byte & 0x80);
return Result;
}
/// Read a signed LEB128 value from data, advancing it past the value.
uintptr_t readSLEB128(const uint8_t *&Data) {
uintptr_t Result = 0;
uintptr_t Shift = 0;
unsigned char Byte;
do {
Byte = *Data++;
Result |= (Byte & 0x7f) << Shift;
Shift += 7;
} while (Byte & 0x80);
if ((Byte & 0x40) && (Shift < (sizeof(Result) << 3))) {
Result |= (~0 << Shift);
}
return Result;
}
/// Read and return a T from data, advancing it past the read item.
template<typename T>
T readValue(const uint8_t *&Data) {
T Val;
memcpy(&Val, Data, sizeof(T));
Data += sizeof(T);
return Val;
}
/// Read an encoded DWARF value from data, advancing it past any data read. This
/// function was adapted from the ExceptionDemo.cpp example in llvm.
uintptr_t readEncodedPointer(const uint8_t *&Data, uint8_t Encoding) {
uintptr_t Result = 0;
auto const Start = Data;
if (Encoding == DW_EH_PE_omit)
return Result;
// first get value
switch (Encoding & 0x0F) {
case DW_EH_PE_absptr:
Result = readValue<uintptr_t>(Data);
break;
case DW_EH_PE_uleb128:
Result = readULEB128(Data);
break;
case DW_EH_PE_sleb128:
Result = readSLEB128(Data);
break;
case DW_EH_PE_udata2:
Result = readValue<uint16_t>(Data);
break;
case DW_EH_PE_udata4:
Result = readValue<uint32_t>(Data);
break;
case DW_EH_PE_udata8:
Result = readValue<uint64_t>(Data);
break;
case DW_EH_PE_sdata2:
Result = readValue<int16_t>(Data);
break;
case DW_EH_PE_sdata4:
Result = readValue<int32_t>(Data);
break;
case DW_EH_PE_sdata8:
Result = readValue<int64_t>(Data);
break;
default:
llvm_unreachable("not implemented");
}
// then add relative offset
switch (Encoding & 0x70) {
case DW_EH_PE_absptr:
// do nothing
break;
case DW_EH_PE_pcrel:
Result += reinterpret_cast<uintptr_t>(Start);
break;
case DW_EH_PE_textrel:
case DW_EH_PE_datarel:
case DW_EH_PE_funcrel:
case DW_EH_PE_aligned:
default:
llvm_unreachable("not implemented");
}
// then apply indirection
if (Encoding & 0x80 /*DW_EH_PE_indirect*/) {
Result = *((uintptr_t*)Result);
}
return Result;
}
} // namespace
// readLSDA is reading and dumping the whole .gcc_exception_table section
// at once.
//

View file

@ -19,6 +19,7 @@
#include "DataReader.h"
#include "Exceptions.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
@ -105,6 +106,10 @@ static cl::opt<bool>
DumpData("dump-data", cl::desc("dump parsed flo data and exit (debugging)"),
cl::Hidden);
static cl::opt<bool>
DumpEHFrame("dump-eh-frame", cl::desc("dump parsed .eh_frame (debugging)"),
cl::Hidden);
static cl::opt<bool>
PrintAll("print-all", cl::desc("print functions after each stage"),
cl::Hidden);
@ -464,6 +469,13 @@ static void OptimizeFile(ELFObjectFileBase *File, const DataReader &DR) {
}
}
// Process debug sections.
std::unique_ptr<DWARFContext> DwCtx(new DWARFContextInMemory(*File));
if (opts::DumpEHFrame) {
const auto *Frames = DwCtx->getEHFrame();
Frames->dump(outs());
}
// Disassemble every function and build it's control flow graph.
for (auto &BFI : BinaryFunctions) {
BinaryFunction &Function = BFI.second;