Add an option that allows one to "decode" the LSDA.

The LSDA is a bit difficult for the non-initiated to read. Even with comments,
it's not always clear what's going on. This wraps the ASM streamer in a class
that retains the LSDA and then emits a human-readable description of what's
going on in it.

So instead of having to make sense of:

Lexception1:
        .byte   255
        .byte   155
        .byte   168
        .space  1
        .byte   3
        .byte   26
Lset0 = Ltmp7-Leh_func_begin1
      .long     Lset0
Lset1 = Ltmp812-Ltmp7
      .long     Lset1
Lset2 = Ltmp913-Leh_func_begin1
      .long     Lset2
      .byte     3
Lset3 = Ltmp812-Leh_func_begin1
      .long     Lset3
Lset4 = Leh_func_end1-Ltmp812
      .long     Lset4
      .long     0
      .byte     0
      .byte     1
      .byte     0
      .byte     2
      .byte     125
      .long     __ZTIi@GOTPCREL+4
      .long     __ZTIPKc@GOTPCREL+4

you can read this instead:

## Exception Handling Table: Lexception1
##  @LPStart Encoding: omit
##    @TType Encoding: indirect pcrel sdata4
##        @TType Base: 40 bytes
## @CallSite Encoding: udata4
## @Action Table Size: 26 bytes

## Action 1:
##   A throw between Ltmp7 and Ltmp812 jumps to Ltmp913 on an exception.
##     For type(s):  __ZTIi@GOTPCREL+4 __ZTIPKc@GOTPCREL+4
## Action 2:
##   A throw between Ltmp812 and Leh_func_end1 does not have a landing pad.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@133286 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Bill Wendling 2011-06-17 20:35:21 +00:00
parent 3761c34e03
commit 916a94b870
7 changed files with 395 additions and 17 deletions

View File

@ -547,6 +547,9 @@ namespace llvm {
///
/// \param ShowInst - Whether to show the MCInst representation inline with
/// the assembly.
///
/// \param DecodeLSDA - If true, emit comments that translates the LSDA into a
/// human readable format. Only usable with CFI.
MCStreamer *createAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS,
bool isVerboseAsm,
bool useLoc,
@ -554,7 +557,8 @@ namespace llvm {
MCInstPrinter *InstPrint = 0,
MCCodeEmitter *CE = 0,
TargetAsmBackend *TAB = 0,
bool ShowInst = false);
bool ShowInst = false,
bool DecodeLSDA = false);
/// createMachOStreamer - Create a machine code streamer which will generate
/// Mach-O format object files.

View File

@ -47,7 +47,8 @@ namespace llvm {
MCInstPrinter *InstPrint,
MCCodeEmitter *CE,
TargetAsmBackend *TAB,
bool ShowInst);
bool ShowInst,
bool DecodeLSDA);
/// Target - Wrapper for Target specific information.
///
@ -100,7 +101,8 @@ namespace llvm {
MCInstPrinter *InstPrint,
MCCodeEmitter *CE,
TargetAsmBackend *TAB,
bool ShowInst);
bool ShowInst,
bool DecodeLSDA);
private:
/// Next - The next registered target in the linked list, maintained by the
@ -334,10 +336,11 @@ namespace llvm {
MCInstPrinter *InstPrint,
MCCodeEmitter *CE,
TargetAsmBackend *TAB,
bool ShowInst) const {
bool ShowInst,
bool DecodeLSDA) const {
// AsmStreamerCtorFn is default to llvm::createAsmStreamer
return AsmStreamerCtorFn(Ctx, OS, isVerboseAsm, useLoc, useCFI,
InstPrint, CE, TAB, ShowInst);
InstPrint, CE, TAB, ShowInst, DecodeLSDA);
}
/// @}

View File

@ -72,6 +72,8 @@ static cl::opt<bool> ShowMCEncoding("show-mc-encoding", cl::Hidden,
cl::desc("Show encoding in .s output"));
static cl::opt<bool> ShowMCInst("show-mc-inst", cl::Hidden,
cl::desc("Show instruction structure in .s output"));
static cl::opt<bool> DecodeMCLSDA("decode-mc-lsda", cl::Hidden,
cl::desc("Print LSDA in human readable format in .s output"));
static cl::opt<bool> EnableMCLogging("enable-mc-api-logging", cl::Hidden,
cl::desc("Enable MC API logging"));
static cl::opt<bool> VerifyMachineCode("verify-machineinstrs", cl::Hidden,
@ -152,7 +154,8 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM,
hasMCUseCFI(),
InstPrinter,
MCE, TAB,
ShowMCInst);
ShowMCInst,
DecodeMCLSDA);
AsmStreamer.reset(S);
break;
}

View File

@ -19,6 +19,7 @@
#include "llvm/MC/MCSymbol.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
@ -33,8 +34,10 @@ using namespace llvm;
namespace {
class MCAsmStreamer : public MCStreamer {
protected:
formatted_raw_ostream &OS;
const MCAsmInfo &MAI;
private:
OwningPtr<MCInstPrinter> InstPrinter;
OwningPtr<MCCodeEmitter> Emitter;
OwningPtr<TargetAsmBackend> AsmBackend;
@ -1242,12 +1245,371 @@ void MCAsmStreamer::Finish() {
EmitFrames(false);
}
//===----------------------------------------------------------------------===//
/// MCLSDADecoderAsmStreamer - This is identical to the MCAsmStreamer, but
/// outputs a description of the LSDA in a human readable format.
///
namespace {
class MCLSDADecoderAsmStreamer : public MCAsmStreamer {
const MCSymbol *PersonalitySymbol;
const MCSymbol *LSDASymbol;
bool InLSDA;
bool ReadingULEB128;
uint64_t BytesRead;
uint64_t ActionTableBytes;
uint64_t LSDASize;
SmallVector<char, 2> ULEB128Value;
std::vector<int64_t> LSDAEncoding;
std::vector<const MCExpr*> Assignments;
/// GetULEB128Value - A helper function to convert the value in the
/// ULEB128Value vector into a uint64_t.
uint64_t GetULEB128Value(SmallVectorImpl<char> &ULEB128Value) {
uint64_t Val = 0;
for (unsigned i = 0, e = ULEB128Value.size(); i != e; ++i)
Val |= (ULEB128Value[i] & 0x7F) << (7 * i);
return Val;
}
/// ResetState - Reset the state variables.
void ResetState() {
PersonalitySymbol = 0;
LSDASymbol = 0;
LSDASize = 0;
BytesRead = 0;
ActionTableBytes = 0;
InLSDA = false;
ReadingULEB128 = false;
ULEB128Value.clear();
LSDAEncoding.clear();
Assignments.clear();
}
void EmitEHTableDescription();
const char *DecodeDWARFEncoding(unsigned Encoding) {
switch (Encoding) {
case dwarf::DW_EH_PE_absptr: return "absptr";
case dwarf::DW_EH_PE_omit: return "omit";
case dwarf::DW_EH_PE_pcrel: return "pcrel";
case dwarf::DW_EH_PE_udata4: return "udata4";
case dwarf::DW_EH_PE_udata8: return "udata8";
case dwarf::DW_EH_PE_sdata4: return "sdata4";
case dwarf::DW_EH_PE_sdata8: return "sdata8";
case dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_udata4: return "pcrel udata4";
case dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_sdata4: return "pcrel sdata4";
case dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_udata8: return "pcrel udata8";
case dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_sdata8: return "pcrel sdata8";
case dwarf::DW_EH_PE_indirect|dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_udata4:
return "indirect pcrel udata4";
case dwarf::DW_EH_PE_indirect|dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_sdata4:
return "indirect pcrel sdata4";
case dwarf::DW_EH_PE_indirect|dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_udata8:
return "indirect pcrel udata8";
case dwarf::DW_EH_PE_indirect|dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_sdata8:
return "indirect pcrel sdata8";
}
return "<unknown encoding>";
}
public:
MCLSDADecoderAsmStreamer(MCContext &Context, formatted_raw_ostream &os,
bool isVerboseAsm, bool useLoc, bool useCFI,
MCInstPrinter *printer, MCCodeEmitter *emitter,
TargetAsmBackend *asmbackend,
bool showInst)
: MCAsmStreamer(Context, os, isVerboseAsm, useLoc, useCFI,
printer, emitter, asmbackend, showInst) {
ResetState();
}
~MCLSDADecoderAsmStreamer() {}
virtual void Finish() {
ResetState();
MCAsmStreamer::Finish();
}
virtual void EmitLabel(MCSymbol *Symbol) {
if (Symbol == LSDASymbol)
InLSDA = true;
MCAsmStreamer::EmitLabel(Symbol);
}
virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
if (InLSDA)
Assignments.push_back(Value);
MCAsmStreamer::EmitAssignment(Symbol, Value);
}
virtual void EmitIntValue(uint64_t Value, unsigned Size,
unsigned AddrSpace = 0);
virtual void EmitValueImpl(const MCExpr *Value, unsigned Size,
unsigned AddrSpace);
virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue,
unsigned AddrSpace);
virtual void EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) {
PersonalitySymbol = Sym;
MCAsmStreamer::EmitCFIPersonality(Sym, Encoding);
}
virtual void EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) {
LSDASymbol = Sym;
MCAsmStreamer::EmitCFILsda(Sym, Encoding);
}
};
} // end anonymous namespace
void MCLSDADecoderAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size,
unsigned AddrSpace) {
if (!InLSDA)
return MCAsmStreamer::EmitIntValue(Value, Size, AddrSpace);
BytesRead += Size;
// We place the LSDA into the LSDAEncoding vector for later analysis. If we
// have a ULEB128, we read that in separate iterations through here and then
// get its value.
if (!ReadingULEB128) {
LSDAEncoding.push_back(Value);
int EncodingSize = LSDAEncoding.size();
if (EncodingSize == 1 || EncodingSize == 3) {
// The LPStart and TType encodings.
if (Value != dwarf::DW_EH_PE_omit) {
// The encoding is next and is a ULEB128 value.
ReadingULEB128 = true;
ULEB128Value.clear();
} else {
// The encoding was omitted. Put a 0 here as a placeholder.
LSDAEncoding.push_back(0);
}
} else if (EncodingSize == 5) {
// The next value is a ULEB128 value that tells us how long the call site
// table is -- where the start of the action tab
ReadingULEB128 = true;
ULEB128Value.clear();
}
InLSDA = (LSDASize == 0 || BytesRead < LSDASize);
} else {
// We're reading a ULEB128. Make it so!
assert(Size == 1 && "Non-byte representation of a ULEB128?");
ULEB128Value.push_back(Value);
if ((Value & 0x80) == 0) {
uint64_t Val = GetULEB128Value(ULEB128Value);
LSDAEncoding.push_back(Val);
ULEB128Value.clear();
ReadingULEB128 = false;
if (LSDAEncoding.size() == 4)
// The fourth value tells us where the bottom of the type table is.
LSDASize = BytesRead + LSDAEncoding[3];
else if (LSDAEncoding.size() == 6)
// The sixth value tells us where the start of the action table is.
ActionTableBytes = BytesRead;
}
}
MCAsmStreamer::EmitValueImpl(MCConstantExpr::Create(Value, getContext()),
Size, AddrSpace);
if (LSDASize != 0 && !InLSDA)
EmitEHTableDescription();
}
void MCLSDADecoderAsmStreamer::EmitValueImpl(const MCExpr *Value,
unsigned Size,
unsigned AddrSpace) {
if (InLSDA && LSDASize != 0) {
assert(BytesRead + Size <= LSDASize && "EH table too small!");
if (BytesRead > uint64_t(LSDAEncoding[5]) + ActionTableBytes)
// Insert the type values.
Assignments.push_back(Value);
LSDAEncoding.push_back(Assignments.size());
BytesRead += Size;
InLSDA = (LSDASize == 0 || BytesRead < LSDASize);
}
MCAsmStreamer::EmitValueImpl(Value, Size, AddrSpace);
if (LSDASize != 0 && !InLSDA)
EmitEHTableDescription();
}
void MCLSDADecoderAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue,
unsigned AddrSpace) {
if (InLSDA && ReadingULEB128) {
for (uint64_t I = NumBytes; I != 0; --I)
ULEB128Value.push_back(FillValue);
BytesRead += NumBytes;
if ((FillValue & 0x80) == 0) {
uint64_t Val = GetULEB128Value(ULEB128Value);
LSDAEncoding.push_back(Val);
ULEB128Value.clear();
ReadingULEB128 = false;
if (LSDAEncoding.size() == 4)
// The fourth value tells us where the bottom of the type table is.
LSDASize = BytesRead + LSDAEncoding[3];
else if (LSDAEncoding.size() == 6)
// The sixth value tells us where the start of the action table is.
ActionTableBytes = BytesRead;
}
}
MCAsmStreamer::EmitFill(NumBytes, FillValue, AddrSpace);
}
/// EmitEHTableDescription - Emit a human readable version of the LSDA.
void MCLSDADecoderAsmStreamer::EmitEHTableDescription() {
assert(LSDAEncoding.size() > 6 && "Invalid LSDA!");
// Emit header information.
StringRef C = MAI.getCommentString();
#define CMT OS << C << ' '
CMT << "Exception Handling Table: " << LSDASymbol->getName() << "\n";
CMT << " @LPStart Encoding: " << DecodeDWARFEncoding(LSDAEncoding[0]) << "\n";
if (LSDAEncoding[1])
CMT << "@LPStart: 0x" << LSDAEncoding[1] << "\n";
CMT << " @TType Encoding: " << DecodeDWARFEncoding(LSDAEncoding[2]) << "\n";
CMT << " @TType Base: " << LSDAEncoding[3] << " bytes\n";
CMT << "@CallSite Encoding: " << DecodeDWARFEncoding(LSDAEncoding[4]) << "\n";
CMT << "@Action Table Size: " << LSDAEncoding[5] << " bytes\n\n";
bool isSjLjEH = (MAI.getExceptionHandlingType() == ExceptionHandling::ARM);
int64_t CallSiteTableSize = LSDAEncoding[5];
unsigned CallSiteEntrySize;
if (!isSjLjEH)
CallSiteEntrySize = 4 + // Region start.
4 + // Region end.
4 + // Landing pad.
1; // TType index.
else
CallSiteEntrySize = 1 + // Call index.
1 + // Landing pad.
1; // TType index.
unsigned NumEntries = CallSiteTableSize / CallSiteEntrySize;
assert(CallSiteTableSize % CallSiteEntrySize == 0 &&
"The action table size is not a multiple of what it should be!");
unsigned TTypeIdx = 5 + // Action table size index.
(isSjLjEH ? 3 : 4) * NumEntries + // Action table entries.
1; // Just because.
// Emit the action table.
unsigned Action = 1;
for (unsigned I = 6; I < TTypeIdx; ) {
CMT << "Action " << Action++ << ":\n";
// The beginning of the throwing region.
uint64_t Idx = LSDAEncoding[I++];
if (!isSjLjEH) {
CMT << " A throw between "
<< *cast<MCBinaryExpr>(Assignments[Idx - 1])->getLHS() << " and ";
// The end of the throwing region.
Idx = LSDAEncoding[I++];
OS << *cast<MCBinaryExpr>(Assignments[Idx - 1])->getLHS();
} else {
CMT << " A throw from call " << *Assignments[Idx - 1];
}
// The landing pad.
Idx = LSDAEncoding[I++];
if (Idx) {
OS << " jumps to "
<< *cast<MCBinaryExpr>(Assignments[Idx - 1])->getLHS()
<< " on an exception.\n";
} else {
OS << " does not have a landing pad.\n";
++I;
continue;
}
// The index into the action table.
Idx = LSDAEncoding[I++];
if (!Idx) {
CMT << " :cleanup:\n";
continue;
}
// A semi-graphical representation of what the different indexes are in the
// loop below.
//
// Idx - Index into the action table.
// Action - Index into the type table from the type table base.
// Next - Offset from Idx to the next action type.
//
// Idx---.
// |
// v
// [call site table] _1 _2 _3
// TTypeIdx--> .........................
// [action 1] _1 _2
// [action 2] _1 _2
// ...
// [action n] _1 _2
// [type m] ^
// ... |
// [type 1] `---Next
//
int Action = LSDAEncoding[TTypeIdx + Idx - 1];
if ((Action & 0x40) != 0)
// Ignore exception specifications.
continue;
// Emit the types that are caught by this exception.
CMT << " For type(s): ";
for (;;) {
if ((Action & 0x40) != 0)
// Ignore exception specifications.
break;
if (uint64_t Ty = LSDAEncoding[LSDAEncoding.size() - Action]) {
OS << " " << *Assignments[Ty - 1];
// Types can be chained together. Typically, it's a negative offset from
// the current type to a different one in the type table.
int Next = LSDAEncoding[TTypeIdx + Idx];
if (Next == 0)
break;
if ((Next & 0x40) != 0)
Next = (int)(signed char)(Next | 0x80);
Idx += Next + 1;
Action = LSDAEncoding[TTypeIdx + Idx - 1];
continue;
} else {
OS << " :catchall:";
}
break;
}
OS << "\n";
}
OS << "\n";
ResetState();
}
MCStreamer *llvm::createAsmStreamer(MCContext &Context,
formatted_raw_ostream &OS,
bool isVerboseAsm, bool useLoc,
bool useCFI,
MCInstPrinter *IP, MCCodeEmitter *CE,
TargetAsmBackend *TAB, bool ShowInst) {
bool useCFI, MCInstPrinter *IP,
MCCodeEmitter *CE, TargetAsmBackend *TAB,
bool ShowInst, bool DecodeLSDA) {
if (DecodeLSDA)
return new MCLSDADecoderAsmStreamer(Context, OS, isVerboseAsm, useLoc,
useCFI, IP, CE, TAB, ShowInst);
return new MCAsmStreamer(Context, OS, isVerboseAsm, useLoc, useCFI,
IP, CE, TAB, ShowInst);
}

View File

@ -533,7 +533,8 @@ namespace llvm {
bool isVerboseAsm, bool useLoc, bool useCFI,
MCInstPrinter *IP,
MCCodeEmitter *CE, TargetAsmBackend *TAB,
bool ShowInst) {
bool ShowInst,
bool /*DecodeLSDA*/) {
return new PTXMCAsmStreamer(Context, OS, isVerboseAsm, useLoc,
IP, CE, ShowInst);
}

View File

@ -27,7 +27,8 @@ namespace llvm {
MCInstPrinter *InstPrint,
MCCodeEmitter *CE,
TargetAsmBackend *TAB,
bool ShowInst);
bool ShowInst,
bool DecodeLSDA);
}
extern "C" void LLVMInitializePTXTarget() {

View File

@ -61,6 +61,10 @@ static cl::opt<bool>
ShowInstOperands("show-inst-operands",
cl::desc("Show instructions operands as parsed"));
static cl::opt<bool>
DecodeLSDA("decode-lsda",
cl::desc("Print LSDA in human readable format"));
static cl::opt<unsigned>
OutputAsmVariant("output-asm-variant",
cl::desc("Syntax variant to use for output printing"));
@ -97,7 +101,7 @@ IncludeDirs("I", cl::desc("Directory of include files"),
static cl::opt<std::string>
ArchName("arch", cl::desc("Target arch to assemble for, "
"see -version for available targets"));
"see -version for available targets"));
static cl::opt<std::string>
TripleName("triple", cl::desc("Target triple to assemble for, "
@ -110,12 +114,11 @@ MCPU("mcpu",
cl::init(""));
static cl::opt<bool>
NoInitialTextSection("n", cl::desc(
"Don't assume assembly file starts in the text section"));
NoInitialTextSection("n", cl::desc("Don't assume assembly file starts "
"in the text section"));
static cl::opt<bool>
SaveTempLabels("L", cl::desc(
"Don't discard temporary labels"));
SaveTempLabels("L", cl::desc("Don't discard temporary labels"));
enum ActionType {
AC_AsLex,
@ -358,7 +361,8 @@ static int AssembleInput(const char *ProgName) {
Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true,
/*useLoc*/ true,
/*useCFI*/ true, IP, CE, TAB,
ShowInst));
ShowInst,
DecodeLSDA));
} else if (FileType == OFT_Null) {
Str.reset(createNullStreamer(Ctx));
} else {