summaryrefslogtreecommitdiff
path: root/src/vm/gdbjit.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/gdbjit.h')
-rw-r--r--src/vm/gdbjit.h386
1 files changed, 375 insertions, 11 deletions
diff --git a/src/vm/gdbjit.h b/src/vm/gdbjit.h
index 467a970c0b..3160eccf57 100644
--- a/src/vm/gdbjit.h
+++ b/src/vm/gdbjit.h
@@ -16,6 +16,7 @@
#include <stdint.h>
#include "method.hpp"
+#include "dbginterface.h"
#include "../inc/llvm/ELF.h"
#include "../inc/llvm/Dwarf.h"
@@ -33,6 +34,46 @@
#error "Target is not supported"
#endif
+
+static constexpr const int CorElementTypeToDWEncoding[] =
+{
+/* ELEMENT_TYPE_END */ 0,
+/* ELEMENT_TYPE_VOID */ DW_ATE_address,
+/* ELEMENT_TYPE_BOOLEAN */ DW_ATE_boolean,
+/* ELEMENT_TYPE_CHAR */ DW_ATE_UTF,
+/* ELEMENT_TYPE_I1 */ DW_ATE_signed,
+/* ELEMENT_TYPE_U1 */ DW_ATE_unsigned,
+/* ELEMENT_TYPE_I2 */ DW_ATE_signed,
+/* ELEMENT_TYPE_U2 */ DW_ATE_unsigned,
+/* ELEMENT_TYPE_I4 */ DW_ATE_signed,
+/* ELEMENT_TYPE_U4 */ DW_ATE_unsigned,
+/* ELEMENT_TYPE_I8 */ DW_ATE_signed,
+/* ELEMENT_TYPE_U8 */ DW_ATE_unsigned,
+/* ELEMENT_TYPE_R4 */ DW_ATE_float,
+/* ELEMENT_TYPE_R8 */ DW_ATE_float,
+/* ELEMENT_TYPE_STRING */ DW_ATE_address,
+/* ELEMENT_TYPE_PTR */ DW_ATE_address,
+/* ELEMENT_TYPE_BYREF */ DW_ATE_address,
+/* ELEMENT_TYPE_VALUETYPE */ DW_ATE_address,
+/* ELEMENT_TYPE_CLASS */ DW_ATE_address,
+/* ELEMENT_TYPE_VAR */ DW_ATE_address,
+/* ELEMENT_TYPE_ARRAY */ DW_ATE_address,
+/* ELEMENT_TYPE_GENERICINST */ DW_ATE_address,
+/* ELEMENT_TYPE_TYPEDBYREF */ DW_ATE_address,
+/* SKIP 17 */ DW_ATE_address,
+/* ELEMENT_TYPE_I */ DW_ATE_signed,
+/* ELEMENT_TYPE_U */ DW_ATE_unsigned,
+/* SKIP 1a */ DW_ATE_address,
+/* ELEMENT_TYPE_FNPTR */ DW_ATE_address,
+/* ELEMENT_TYPE_OBJECT */ DW_ATE_address,
+/* ELEMENT_TYPE_SZARRAY */ DW_ATE_address,
+/* ELEMENT_TYPE_MVAR */ DW_ATE_address,
+/* ELEMENT_TYPE_CMOD_REQD */ DW_ATE_address,
+/* ELEMENT_TYPE_CMOD_OPT */ DW_ATE_address,
+/* ELEMENT_TYPE_INTERNAL */ DW_ATE_address,
+/* ELEMENT_TYPE_MAX */ DW_ATE_address,
+};
+
struct __attribute__((packed)) DwarfCompUnit
{
uint32_t m_length;
@@ -64,51 +105,374 @@ struct __attribute__((packed)) DwarfLineNumHeader
uint8_t m_std_num_arg[DW_LNS_MAX];
};
+const ULONG32 HiddenLine = 0x00feefee;
+
struct SymbolsInfo
{
int lineNumber, ilOffset, nativeOffset, fileIndex;
char fileName[2*MAX_PATH_FNAME];
+ ICorDebugInfo::SourceTypes source;
+};
+
+class DwarfDumpable
+{
+public:
+ // writes all string literals this type needs to ptr
+ virtual void DumpStrings(char* ptr, int& offset) = 0;
+
+ virtual void DumpDebugInfo(char* ptr, int& offset) = 0;
+};
+
+class LocalsInfo
+{
+public:
+ int size;
+ char** localsName;
+ ULONG32 countVars;
+ ICorDebugInfo::NativeVarInfo *pVars;
+};
+
+class TypeMember;
+
+class TypeInfoBase : public DwarfDumpable
+{
+public:
+ TypeInfoBase(TypeHandle typeHandle)
+ : m_type_name(nullptr),
+ m_type_name_offset(0),
+ m_type_size(0),
+ m_type_offset(0),
+ typeHandle(typeHandle),
+ typeKey(typeHandle.GetTypeKey())
+ {
+ }
+
+ virtual ~TypeInfoBase()
+ {
+ if (m_type_name != nullptr)
+ {
+ delete[] m_type_name;
+ }
+ }
+
+ virtual void DumpStrings(char* ptr, int& offset) override;
+ void CalculateName();
+ void SetTypeHandle(TypeHandle handle);
+ TypeHandle GetTypeHandle();
+ TypeKey* GetTypeKey();
+
+ char* m_type_name;
+ int m_type_name_offset;
+ ULONG m_type_size;
+ int m_type_offset;
+private:
+ TypeHandle typeHandle;
+ TypeKey typeKey;
+};
+
+class PrimitiveTypeInfo: public TypeInfoBase
+{
+public:
+ PrimitiveTypeInfo(TypeHandle typeHandle, int encoding)
+ : TypeInfoBase(typeHandle),
+ m_type_encoding(encoding)
+ {
+ }
+
+ void DumpDebugInfo(char* ptr, int& offset) override;
+
+ int m_type_encoding;
+};
+
+class RefTypeInfo: public TypeInfoBase
+{
+public:
+ RefTypeInfo(TypeHandle typeHandle, TypeInfoBase *value_type)
+ : TypeInfoBase(typeHandle),
+ m_value_type(value_type)
+ {
+ }
+ void DumpStrings(char* ptr, int& offset) override;
+ void DumpDebugInfo(char* ptr, int& offset) override;
+ TypeInfoBase *m_value_type;
+};
+
+class ClassTypeInfo: public TypeInfoBase
+{
+public:
+ ClassTypeInfo(TypeHandle typeHandle, int num_members);
+ ~ClassTypeInfo();
+
+ void DumpStrings(char* ptr, int& offset) override;
+ void DumpDebugInfo(char* ptr, int& offset) override;
+
+ int m_num_members;
+ TypeMember* members;
+};
+
+class TypeMember: public DwarfDumpable
+{
+public:
+ TypeMember()
+ : m_member_name(nullptr),
+ m_member_name_offset(0),
+ m_member_offset(0),
+ m_static_member_address(0),
+ m_member_type(nullptr)
+ {
+ }
+
+ ~TypeMember()
+ {
+ if (m_member_name != nullptr)
+ {
+ delete[] m_member_name;
+ }
+ }
+
+ void DumpStrings(char* ptr, int& offset) override;
+ void DumpDebugInfo(char* ptr, int& offset) override;
+ void DumpStaticDebugInfo(char* ptr, int& offset);
+
+ char* m_member_name;
+ int m_member_name_offset;
+ int m_member_offset;
+ TADDR m_static_member_address;
+ TypeInfoBase *m_member_type;
};
+class ArrayTypeInfo: public TypeInfoBase
+{
+public:
+ ArrayTypeInfo(TypeHandle typeHandle, int countOffset, TypeInfoBase* elemType)
+ : TypeInfoBase(typeHandle),
+ m_count_offset(countOffset),
+ m_elem_type(elemType)
+ {
+ }
+
+ ~ArrayTypeInfo()
+ {
+ if (m_elem_type != nullptr)
+ {
+ delete m_elem_type;
+ }
+ }
+
+ void DumpDebugInfo(char* ptr, int& offset) override;
+
+ int m_count_offset;
+ TypeInfoBase *m_elem_type;
+};
+
+class VarDebugInfo: public DwarfDumpable
+{
+public:
+ VarDebugInfo(int abbrev)
+ : m_var_name(nullptr),
+ m_var_abbrev(abbrev),
+ m_var_name_offset(0),
+ m_il_index(0),
+ m_native_offset(0),
+ m_var_type(nullptr)
+ {
+ }
+
+ VarDebugInfo()
+ : m_var_name(nullptr),
+ m_var_abbrev(6),
+ m_var_name_offset(0),
+ m_il_index(0),
+ m_native_offset(0),
+ m_var_type(nullptr)
+ {
+ }
+
+ virtual ~VarDebugInfo()
+ {
+ delete[] m_var_name;
+ }
+
+ void DumpStrings(char* ptr, int& offset) override;
+ void DumpDebugInfo(char* ptr, int& offset) override;
+
+ char* m_var_name;
+ int m_var_abbrev;
+ int m_var_name_offset;
+ int m_il_index;
+ int m_native_offset;
+ TypeInfoBase *m_var_type;
+};
class NotifyGdb
{
public:
static void MethodCompiled(MethodDesc* MethodDescPtr);
static void MethodDropped(MethodDesc* MethodDescPtr);
+ template <typename PARENT_TRAITS>
+ class DeleteValuesOnDestructSHashTraits : public PARENT_TRAITS
+ {
+ public:
+ static inline void OnDestructPerEntryCleanupAction(typename PARENT_TRAITS::element_t e)
+ {
+ delete e.Value();
+ }
+ static const bool s_DestructPerEntryCleanupAction = true;
+ };
+
+ template <typename VALUE>
+ class TypeKeyHashTraits : public DefaultSHashTraits< KeyValuePair<TypeKey*,VALUE> >
+ {
+ public:
+ // explicitly declare local typedefs for these traits types, otherwise
+ // the compiler may get confused
+ typedef typename DefaultSHashTraits< KeyValuePair<TypeKey*,VALUE> >::element_t element_t;
+ typedef typename DefaultSHashTraits< KeyValuePair<TypeKey*,VALUE> >::count_t count_t;
+ typedef TypeKey* key_t;
+
+ static key_t GetKey(element_t e)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return e.Key();
+ }
+ static BOOL Equals(key_t k1, key_t k2)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return k1->Equals(k2);
+ }
+ static count_t Hash(key_t k)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return k->ComputeHash();
+ }
+
+ static const element_t Null() { LIMITED_METHOD_CONTRACT; return element_t(key_t(),VALUE()); }
+ static const element_t Deleted() { LIMITED_METHOD_CONTRACT; return element_t(key_t(-1), VALUE()); }
+ static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e.Key() == key_t(); }
+ static bool IsDeleted(const element_t &e) { return e.Key() == key_t(-1); }
+ };
+
+ typedef MapSHash<TypeKey*, TypeInfoBase*, DeleteValuesOnDestructSHashTraits<TypeKeyHashTraits<TypeInfoBase*>>> TK_TypeInfoMap;
+ typedef TK_TypeInfoMap* PTK_TypeInfoMap;
+ typedef SetSHash< TADDR,
+ NoRemoveSHashTraits <
+ NonDacAwareSHashTraits< SetSHashTraits <TADDR> >
+ > > AddrSet;
private:
+
struct MemBuf
{
NewArrayHolder<char> MemPtr;
unsigned MemSize;
MemBuf() : MemPtr(0), MemSize(0)
{}
+ bool Resize(unsigned newSize)
+ {
+ if (newSize == 0)
+ {
+ MemPtr = nullptr;
+ MemSize = 0;
+ return true;
+ }
+ char *tmp = new (nothrow) char [newSize];
+ if (tmp == nullptr)
+ return false;
+ memmove(tmp, MemPtr.GetValue(), newSize < MemSize ? newSize : MemSize);
+ MemPtr = tmp;
+ MemSize = newSize;
+ return true;
+ }
};
+ static int GetSectionIndex(const char *sectName);
static bool BuildELFHeader(MemBuf& buf);
- static bool BuildSectionNameTable(MemBuf& buf);
- static bool BuildSectionTable(MemBuf& buf);
+ static bool BuildSectionTables(MemBuf& sectBuf, MemBuf& strBuf);
static bool BuildSymbolTableSection(MemBuf& buf, PCODE addr, TADDR codeSize);
static bool BuildStringTableSection(MemBuf& strTab);
- static bool BuildDebugStrings(MemBuf& buf);
- static bool BuildDebugAbbrev(MemBuf& buf);
- static bool BuildDebugInfo(MemBuf& buf);
+ static bool BuildDebugStrings(MemBuf& buf, PTK_TypeInfoMap pTypeMap);
+ static bool BuildDebugAbbrev(MemBuf& buf);
+ static bool BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap, SymbolsInfo* lines, unsigned nlines);
static bool BuildDebugPub(MemBuf& buf, const char* name, uint32_t size, uint32_t dieOffset);
- static bool BuildLineTable(MemBuf& buf, PCODE startAddr, SymbolsInfo* lines, unsigned nlines);
+ static bool BuildLineTable(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines);
static bool BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines);
- static bool BuildLineProg(MemBuf& buf, PCODE startAddr, SymbolsInfo* lines, unsigned nlines);
- static bool FitIntoSpecialOpcode(int8_t line_shift, uint8_t addr_shift);
+ static bool BuildLineProg(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines);
static void IssueSetAddress(char*& ptr, PCODE addr);
static void IssueEndOfSequence(char*& ptr);
static void IssueSimpleCommand(char*& ptr, uint8_t command);
static void IssueParamCommand(char*& ptr, uint8_t command, char* param, int param_len);
- static void IssueSpecialCommand(char*& ptr, int8_t line_shift, uint8_t addr_shift);
static void SplitPathname(const char* path, const char*& pathName, const char*& fileName);
- static int Leb128Encode(uint32_t num, char* buf, int size);
- static int Leb128Encode(int32_t num, char* buf, int size);
+ static bool CollectCalledMethods(CalledMethod* pCM, TADDR nativeCode);
#ifdef _DEBUG
static void DumpElf(const char* methodName, const MemBuf& buf);
#endif
};
+class FunctionMember: public TypeMember
+{
+public:
+ FunctionMember(MethodDesc *md, int num_locals, int num_args)
+ : TypeMember(),
+ md(md),
+ m_file(1),
+ m_line(1),
+ m_sub_low_pc(0),
+ m_sub_high_pc(0),
+ m_sub_loc(),
+ m_num_args(num_args),
+ m_num_locals(num_locals),
+ m_num_vars(num_args + num_locals),
+ m_entry_offset(0),
+ vars(new VarDebugInfo[m_num_vars]),
+ lines(NULL),
+ nlines(0),
+ m_linkage_name_offset(0),
+ dumped(false)
+ {
+ m_sub_loc[0] = 1;
+#if defined(_TARGET_AMD64_)
+ m_sub_loc[1] = DW_OP_reg6;
+#elif defined(_TARGET_ARM_)
+ m_sub_loc[1] = DW_OP_reg11;
+#else
+#error Unsupported platform!
+#endif
+ }
+
+ virtual ~FunctionMember()
+ {
+ delete[] vars;
+ }
+
+ void DumpStrings(char* ptr, int& offset) override;
+ void DumpDebugInfo(char* ptr, int& offset) override;
+ void DumpTryCatchDebugInfo(char* ptr, int& offset);
+ HRESULT GetLocalsDebugInfo(NotifyGdb::PTK_TypeInfoMap pTypeMap,
+ LocalsInfo& locals,
+ int startNativeOffset);
+ BOOL IsDumped()
+ {
+ return dumped;
+ }
+
+ MethodDesc *md;
+ uint8_t m_file, m_line;
+ uintptr_t m_sub_low_pc, m_sub_high_pc;
+ uint8_t m_sub_loc[2];
+ uint8_t m_num_args;
+ uint8_t m_num_locals;
+ uint16_t m_num_vars;
+ int m_entry_offset;
+ VarDebugInfo* vars;
+ SymbolsInfo* lines;
+ unsigned nlines;
+ int m_linkage_name_offset;
+private:
+ int GetArgsAndLocalsLen();
+ void MangleName(char *buf, int &buf_offset, const char *name);
+ void DumpMangledNamespaceAndMethod(char *buf, int &offset, const char *nspace, const char *mname);
+ void DumpLinkageName(char* ptr, int& offset);
+ bool GetBlockInNativeCode(int blockILOffset, int blockILLen, TADDR *startOffset, TADDR *endOffset);
+ void DumpTryCatchBlock(char* ptr, int& offset, int ilOffset, int ilLen, int abbrev);
+ BOOL dumped;
+};
#endif // #ifndef __GDBJIT_H__