Skip to content

Commit

Permalink
[Linux][GDB-JIT] Add try/catch blocks to methods in DWARF (dotnet/cor…
Browse files Browse the repository at this point in the history
…eclr#8650)

* Add try/catch blocks to DWARF info

Use info about exception handling from IL and map it to
native code as try/catch blocks in DWARF.

* Improve locals naming convention consistency in gdbjit

* Drop pointer to line info from FunctionMember after it is dumped


Commit migrated from dotnet/coreclr@93187ae
  • Loading branch information
ayuckhulk authored and janvorli committed Dec 16, 2016
1 parent 8e9a60a commit 1ab7972
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 3 deletions.
157 changes: 155 additions & 2 deletions src/coreclr/src/vm/gdbjit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,28 @@ const unsigned char AbbrevTable[] = {
15, DW_TAG_variable, DW_CHILDREN_no, DW_AT_specification, DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc,
0, 0,

16, DW_TAG_try_block, DW_CHILDREN_no,
DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc,
#if defined(_TARGET_AMD64_)
DW_FORM_data8,
#elif defined(_TARGET_ARM_)
DW_FORM_data4,
#else
#error Unsupported platform!
#endif
0, 0,

17, DW_TAG_catch_block, DW_CHILDREN_no,
DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc,
#if defined(_TARGET_AMD64_)
DW_FORM_data8,
#elif defined(_TARGET_ARM_)
DW_FORM_data4,
#else
#error Unsupported platform!
#endif
0, 0,

0
};

Expand All @@ -767,6 +789,18 @@ struct __attribute__((packed)) DebugInfoCU
1, 0, DW_LANG_C89, 0, 0
};

struct __attribute__((packed)) DebugInfoTryCatchSub
{
uint8_t m_sub_abbrev;
#if defined(_TARGET_AMD64_)
uint64_t m_sub_low_pc, m_sub_high_pc;
#elif defined(_TARGET_ARM_)
uint32_t m_sub_low_pc, m_sub_high_pc;
#else
#error Unsupported platform!
#endif
};

struct __attribute__((packed)) DebugInfoSub
{
uint8_t m_sub_abbrev;
Expand Down Expand Up @@ -1116,6 +1150,109 @@ void FunctionMember::DumpStrings(char* ptr, int& offset)
DumpLinkageName(ptr, offset);
}

bool FunctionMember::GetBlockInNativeCode(int blockILOffset, int blockILLen, TADDR *startOffset, TADDR *endOffset)
{
PCODE pCode = md->GetNativeCode();

const int blockILEnd = blockILOffset + blockILLen;

*startOffset = 0;
*endOffset = 0;

bool inBlock = false;

for (int i = 0; i < nlines; ++i)
{
TADDR nativeOffset = lines[i].nativeOffset + pCode;

// Limit block search to current function addresses
if (nativeOffset < m_sub_low_pc)
continue;
if (nativeOffset >= m_sub_low_pc + m_sub_high_pc)
break;

// Skip invalid IL offsets
switch(lines[i].ilOffset)
{
case ICorDebugInfo::PROLOG:
case ICorDebugInfo::EPILOG:
case ICorDebugInfo::NO_MAPPING:
continue;
default:
break;
}

// Check if current IL is within block
if (blockILOffset <= lines[i].ilOffset && lines[i].ilOffset < blockILEnd)
{
if (!inBlock)
{
*startOffset = lines[i].nativeOffset;
inBlock = true;
}
}
else
{
if (inBlock)
{
*endOffset = lines[i].nativeOffset;
inBlock = false;
break;
}
}
}

if (inBlock)
{
*endOffset = m_sub_low_pc + m_sub_high_pc - pCode;
}

return *endOffset != *startOffset;
}

void FunctionMember::DumpTryCatchBlock(char* ptr, int& offset, int ilOffset, int ilLen, int abbrev)
{
TADDR startOffset;
TADDR endOffset;

if (!GetBlockInNativeCode(ilOffset, ilLen, &startOffset, &endOffset))
return;

if (ptr != nullptr)
{
DebugInfoTryCatchSub subEntry;

subEntry.m_sub_abbrev = abbrev;
subEntry.m_sub_low_pc = md->GetNativeCode() + startOffset;
subEntry.m_sub_high_pc = endOffset - startOffset;

memcpy(ptr + offset, &subEntry, sizeof(DebugInfoTryCatchSub));
}
offset += sizeof(DebugInfoTryCatchSub);
}

void FunctionMember::DumpTryCatchDebugInfo(char* ptr, int& offset)
{
if (!md)
return;

COR_ILMETHOD *pHeader = md->GetILHeader();
COR_ILMETHOD_DECODER header(pHeader);

unsigned ehCount = header.EHCount();

for (unsigned e = 0; e < ehCount; e++)
{
IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehBuff;
const IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;

ehInfo = header.EH->EHClause(e, &ehBuff);

DumpTryCatchBlock(ptr, offset, ehInfo->TryOffset, ehInfo->TryLength, 16);
DumpTryCatchBlock(ptr, offset, ehInfo->HandlerOffset, ehInfo->HandlerLength, 17);
}
}

void FunctionMember::DumpDebugInfo(char* ptr, int& offset)
{
if (ptr != nullptr)
Expand Down Expand Up @@ -1162,6 +1299,8 @@ void FunctionMember::DumpDebugInfo(char* ptr, int& offset)
vars[i].DumpDebugInfo(ptr, offset);
}

DumpTryCatchDebugInfo(ptr, offset);

// terminate children
if (ptr != nullptr)
{
Expand Down Expand Up @@ -1585,7 +1724,7 @@ void NotifyGdb::MethodCompiled(MethodDesc* MethodDescPtr)
}

/* Build .debug_info section */
if (!BuildDebugInfo(dbgInfo, pTypeMap))
if (!BuildDebugInfo(dbgInfo, pTypeMap, symInfo, symInfoLen))
{
return;
}
Expand Down Expand Up @@ -2130,7 +2269,7 @@ bool NotifyGdb::BuildDebugAbbrev(MemBuf& buf)
}

/* Build tge DWARF .debug_info section */
bool NotifyGdb::BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap)
bool NotifyGdb::BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap, SymbolsInfo* lines, unsigned nlines)
{
int totalTypeVarSubSize = 0;
{
Expand All @@ -2145,8 +2284,22 @@ bool NotifyGdb::BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap)

for (int i = 0; i < method.GetCount(); ++i)
{
method[i]->lines = lines;
method[i]->nlines = nlines;
method[i]->DumpDebugInfo(nullptr, totalTypeVarSubSize);
}
// Drop pointers to lines when exiting current scope
struct DropMethodLines
{
~DropMethodLines()
{
for (int i = 0; i < method.GetCount(); ++i)
{
method[i]->lines = nullptr;
method[i]->nlines = 0;
}
}
} dropMethodLines;

//int locSize = GetArgsAndLocalsLen(argsDebug, argsDebugSize, localsDebug, localsDebugSize);
buf.MemSize = sizeof(DwarfCompUnit) + sizeof(DebugInfoCU) + totalTypeVarSubSize + 2;
Expand Down
9 changes: 8 additions & 1 deletion src/coreclr/src/vm/gdbjit.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ class NotifyGdb
static bool BuildStringTableSection(MemBuf& strTab);
static bool BuildDebugStrings(MemBuf& buf, PTK_TypeInfoMap pTypeMap);
static bool BuildDebugAbbrev(MemBuf& buf);
static bool BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap);
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, TADDR codeSize, SymbolsInfo* lines, unsigned nlines);
static bool BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines);
Expand Down Expand Up @@ -423,6 +423,8 @@ class FunctionMember: public TypeMember
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)
{
Expand All @@ -443,6 +445,7 @@ class FunctionMember: public TypeMember

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);
Expand All @@ -460,12 +463,16 @@ class FunctionMember: public TypeMember
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__

0 comments on commit 1ab7972

Please sign in to comment.