summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBill Wendling <isanbard@gmail.com>2011-06-17 20:35:21 +0000
committerBill Wendling <isanbard@gmail.com>2011-06-17 20:35:21 +0000
commit916a94b870042772568fca7995cf45aef7a6e333 (patch)
tree48eae701400bdf4228cb0a0de1c63da71246a37b /lib
parent3761c34e03a1220f0cc2ee7df31feeec5ee7e15c (diff)
downloadllvm-916a94b870042772568fca7995cf45aef7a6e333.tar.gz
llvm-916a94b870042772568fca7995cf45aef7a6e333.tar.bz2
llvm-916a94b870042772568fca7995cf45aef7a6e333.tar.xz
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
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/LLVMTargetMachine.cpp5
-rw-r--r--lib/MC/MCAsmStreamer.cpp368
-rw-r--r--lib/Target/PTX/PTXMCAsmStreamer.cpp3
-rw-r--r--lib/Target/PTX/PTXTargetMachine.cpp3
4 files changed, 373 insertions, 6 deletions
diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp
index b98fbed695..4ed959e120 100644
--- a/lib/CodeGen/LLVMTargetMachine.cpp
+++ b/lib/CodeGen/LLVMTargetMachine.cpp
@@ -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;
}
diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp
index e8b09fcace..01de450d97 100644
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/lib/MC/MCAsmStreamer.cpp
@@ -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);
}
diff --git a/lib/Target/PTX/PTXMCAsmStreamer.cpp b/lib/Target/PTX/PTXMCAsmStreamer.cpp
index 1574670b6e..bc37b6a1fb 100644
--- a/lib/Target/PTX/PTXMCAsmStreamer.cpp
+++ b/lib/Target/PTX/PTXMCAsmStreamer.cpp
@@ -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);
}
diff --git a/lib/Target/PTX/PTXTargetMachine.cpp b/lib/Target/PTX/PTXTargetMachine.cpp
index 1b737c9d86..31ed09c3e9 100644
--- a/lib/Target/PTX/PTXTargetMachine.cpp
+++ b/lib/Target/PTX/PTXTargetMachine.cpp
@@ -27,7 +27,8 @@ namespace llvm {
MCInstPrinter *InstPrint,
MCCodeEmitter *CE,
TargetAsmBackend *TAB,
- bool ShowInst);
+ bool ShowInst,
+ bool DecodeLSDA);
}
extern "C" void LLVMInitializePTXTarget() {