From d88953cc229dcbf5d93aa04711ee599b3d073094 Mon Sep 17 00:00:00 2001 From: Jonghyun Park Date: Tue, 8 Aug 2017 01:27:16 +0900 Subject: [PATCH 18/29] Support FEATURE_GDBJIT_FRAME (including NI & IL_Stub) --- src/vm/CMakeLists.txt | 3 + src/vm/gdbjit.cpp | 1108 ++++++++++++++++++++++++++++++++++--------------- src/vm/gdbjit.h | 13 +- src/vm/prestub.cpp | 29 +- src/vm/util.cpp | 10 +- 5 files changed, 813 insertions(+), 350 deletions(-) diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index c610d3c..835e31c 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -31,6 +31,9 @@ if(FEATURE_GDBJIT) ) add_definitions(-DFEATURE_GDBJIT) endif(FEATURE_GDBJIT) +if(FEATURE_GDBJIT_FRAME) + add_definitions(-DFEATURE_GDBJIT_FRAME) +endif(FEATURE_GDBJIT_FRAME) set(VM_SOURCES_DAC_AND_WKS_COMMON appdomain.cpp diff --git a/src/vm/gdbjit.cpp b/src/vm/gdbjit.cpp index ace6b76..5a3f074 100644 --- a/src/vm/gdbjit.cpp +++ b/src/vm/gdbjit.cpp @@ -648,46 +648,6 @@ struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; // END of GDB JIT interface -/* Predefined section names */ -const char* SectionNames[] = { - "", - ".text", - ".shstrtab", - ".debug_str", - ".debug_abbrev", - ".debug_info", - ".debug_pubnames", - ".debug_pubtypes", - ".debug_line", - ".symtab", - ".strtab" - /* After the last (.strtab) section zero or more .thunk_* sections are generated. - - Each .thunk_* section contains a single .thunk_#. - These symbols are mapped to methods (or trampolines) called by currently compiled method. */ -}; - -const int SectionNamesCount = sizeof(SectionNames) / sizeof(SectionNames[0]); // Does not include .thunk_* sections - -/* Static data for section headers */ -struct SectionHeader { - uint32_t m_type; - uint64_t m_flags; -} Sections[] = { - {SHT_NULL, 0}, - {SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR}, - {SHT_STRTAB, 0}, - {SHT_PROGBITS, SHF_MERGE | SHF_STRINGS }, - {SHT_PROGBITS, 0}, - {SHT_PROGBITS, 0}, - {SHT_PROGBITS, 0}, - {SHT_PROGBITS, 0}, - {SHT_PROGBITS, 0}, - {SHT_SYMTAB, 0}, - {SHT_STRTAB, 0}, - {SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR} -}; - /* Static data for .debug_str section */ const char* DebugStrings[] = { "CoreCLR", "" /* module name */, "" /* module path */ @@ -1748,8 +1708,661 @@ static int getNextPrologueIndex(int from, const SymbolsInfo *lines, int nlines) return -1; } +static inline bool isListedModule(const WCHAR *wszModuleFile) +{ + static NewArrayHolder wszModuleNames = nullptr; + static DWORD cBytesNeeded = 0; + + // Get names of interesting modules from environment + if (wszModuleNames == nullptr && cBytesNeeded == 0) + { + DWORD cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), NULL, 0); + + if (cCharsNeeded == 0) + { + cBytesNeeded = 0xffffffff; + return false; + } + + WCHAR *wszModuleNamesBuf = new WCHAR[cCharsNeeded+1]; + + cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), wszModuleNamesBuf, cCharsNeeded); + + if (cCharsNeeded == 0) + { + delete[] wszModuleNamesBuf; + cBytesNeeded = 0xffffffff; + return false; + } + + wszModuleNames = wszModuleNamesBuf; + cBytesNeeded = cCharsNeeded + 1; + } + else if (wszModuleNames == nullptr) + { + return false; + } + + _ASSERTE(wszModuleNames != nullptr && cBytesNeeded > 0); + + BOOL isUserDebug = FALSE; + + NewArrayHolder wszModuleName = new WCHAR[cBytesNeeded]; + LPWSTR pComma = wcsstr(wszModuleNames, W(",")); + LPWSTR tmp = wszModuleNames; + + while (pComma != NULL) + { + wcsncpy(wszModuleName, tmp, pComma - tmp); + wszModuleName[pComma - tmp] = W('\0'); + + if (wcscmp(wszModuleName, wszModuleFile) == 0) + { + isUserDebug = TRUE; + break; + } + tmp = pComma + 1; + pComma = wcsstr(tmp, W(",")); + } + if (isUserDebug == FALSE) + { + wcsncpy(wszModuleName, tmp, wcslen(tmp)); + wszModuleName[wcslen(tmp)] = W('\0'); + if (wcscmp(wszModuleName, wszModuleFile) == 0) + { + isUserDebug = TRUE; + } + } + + return isUserDebug; +} + static NotifyGdb::AddrSet codeAddrs; +class Elf_SectionTracker +{ + private: + unsigned int m_Flag; + + private: + NewArrayHolder m_NamePtr; + unsigned int m_NameLen; + + private: + unsigned int m_Ind; + unsigned int m_Off; + unsigned int m_Len; + + private: + Elf_Shdr m_Hdr; + + private: + Elf_SectionTracker *m_Next; + + public: + Elf_SectionTracker(const char *name, unsigned ind, unsigned off, uint32_t type, uint64_t flags); + ~Elf_SectionTracker(); + + public: + bool NeedHeaderUpdate() const; + void DisableHeaderUpdate(); + + public: + unsigned int GetIndex() const { return m_Ind; } + unsigned int GetOffset() const { return m_Off; } + unsigned int GetSize() const { return m_Len; } + + public: + const char *GetName() const { return m_NamePtr; } + unsigned int GetNameLen() const { return m_NameLen; } + + public: + Elf_SectionTracker *GetNext(void); + void SetNext(Elf_SectionTracker *next); + + public: + void Forward(unsigned int len); + + public: + Elf_Shdr *Header(void); + const Elf_Shdr *Header(void) const; + +}; + +Elf_SectionTracker::Elf_SectionTracker(const char *name, + unsigned ind, unsigned off, + uint32_t type, uint64_t flags) + : m_Flag(0), + m_NamePtr(nullptr), + m_NameLen(0), + m_Ind(ind), + m_Off(off), + m_Len(0), + m_Next(nullptr) +{ + if (name) + { + unsigned int len = strlen(name); + char *ptr = new char[len + 1]; + + strncpy(ptr, name, len + 1); + + m_NamePtr = ptr; + m_NameLen = len; + } + + m_Hdr.sh_type = type; + m_Hdr.sh_flags = flags; + m_Hdr.sh_name = 0; + m_Hdr.sh_addr = 0; + m_Hdr.sh_offset = 0; + m_Hdr.sh_size = 0; + m_Hdr.sh_link = SHN_UNDEF; + m_Hdr.sh_info = 0; + m_Hdr.sh_addralign = 1; + m_Hdr.sh_entsize = 0; +} + +Elf_SectionTracker::~Elf_SectionTracker() +{ +} + +#define ESTF_NO_HEADER_UPDATE 0x00000001 + +bool Elf_SectionTracker::NeedHeaderUpdate() const +{ + return !(m_Flag & ESTF_NO_HEADER_UPDATE); +} + +void Elf_SectionTracker::DisableHeaderUpdate() +{ + m_Flag |= ESTF_NO_HEADER_UPDATE; +} + +void Elf_SectionTracker::Forward(unsigned int len) +{ + m_Len += len; +} + +void Elf_SectionTracker::SetNext(Elf_SectionTracker *next) +{ + m_Next = next; +} + +Elf_SectionTracker *Elf_SectionTracker::GetNext(void) +{ + return m_Next; +} + +Elf_Shdr *Elf_SectionTracker::Header(void) +{ + return &m_Hdr; +} + +const Elf_Shdr *Elf_SectionTracker::Header(void) const +{ + return &m_Hdr; +} + +class Elf_Buffer +{ + private: + NewArrayHolder m_Ptr; + unsigned int m_Len; + unsigned int m_Pos; + + public: + Elf_Buffer(unsigned int len); + + private: + char *Ensure(unsigned int len); + void Forward(unsigned int len); + + public: + unsigned int GetPos() const + { + return m_Pos; + } + + char *GetPtr(unsigned int off = 0) + { + return m_Ptr.GetValue() + off; + } + + public: + char *Reserve(unsigned int len); + template T *ReserveT(unsigned int len = sizeof(T)) + { + _ASSERTE(len >= sizeof(T)); + return reinterpret_cast(Reserve(len)); + } + + public: + void Append(const char *src, unsigned int len); + template void AppendT(T *src) + { + Append(reinterpret_cast(src), sizeof(T)); + } +}; + +Elf_Buffer::Elf_Buffer(unsigned int len) + : m_Ptr(new char[len]) + , m_Len(len) + , m_Pos(0) +{ +} + +char *Elf_Buffer::Ensure(unsigned int len) +{ + bool bAdjusted = false; + + while (m_Pos + len > m_Len) + { + m_Len *= 2; + bAdjusted = true; + } + + if (bAdjusted) + { + char *ptr = new char [m_Len * 2]; + memcpy(ptr, m_Ptr.GetValue(), m_Pos); + m_Ptr = ptr; + } + + return GetPtr(m_Pos); +} + +void Elf_Buffer::Forward(unsigned int len) +{ + m_Pos += len; +} + +char *Elf_Buffer::Reserve(unsigned int len) +{ + char *ptr = Ensure(len); + Forward(len); + return ptr; +} + +void Elf_Buffer::Append(const char *src, unsigned int len) +{ + char *dst = Reserve(len); + memcpy(dst, src, len); +} + +#define ELF_BUILDER_TEXT_SECTION_INDEX 1 + +class Elf_Builder +{ + private: + Elf_Buffer m_Buffer; + + private: + unsigned int m_SectionCount; + Elf_SectionTracker *m_First; + Elf_SectionTracker *m_Last; + Elf_SectionTracker *m_Curr; + + public: + Elf_Builder(); + ~Elf_Builder(); + + public: + unsigned int GetSectionCount(void) { return m_SectionCount; } + + public: + void Initialize(PCODE codePtr, TADDR codeLen); + + public: + Elf_SectionTracker *OpenSection(const char *name, uint32_t type, uint64_t flags); + void CloseSection(); + + public: + char *Reserve(unsigned int len); + template T *ReserveT(unsigned int len = sizeof(T)) + { + _ASSERTE(len >= sizeof(T)); + return reinterpret_cast(Reserve(len)); + } + + public: + void Append(const char *src, unsigned int len); + template void AppendT(T *src) + { + Append(reinterpret_cast(src), sizeof(T)); + } + + public: + void Finalize(void); + + public: + char *Export(UINT64 *len); +}; + +Elf_Builder::Elf_Builder() + : m_Buffer(128), + m_SectionCount(0), + m_First(nullptr), + m_Last(nullptr), + m_Curr(nullptr) +{ +} + +Elf_Builder::~Elf_Builder() +{ + Elf_SectionTracker *curr = m_First; + + while (curr) + { + Elf_SectionTracker *next = curr->GetNext(); + delete curr; + curr = next; + } +} + +void Elf_Builder::Initialize(PCODE codePtr, TADDR codeLen) +{ + // + // Reserve ELF Header + // + m_Buffer.Reserve(sizeof(Elf_Ehdr)); + + // + // Create NULL section + // + Elf_SectionTracker *null = OpenSection("", SHT_NULL, 0); + { + null->DisableHeaderUpdate(); + null->Header()->sh_addralign = 0; + } + CloseSection(); + + // + // Create '.text' section + // + Elf_SectionTracker *text = OpenSection(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); + { + text->DisableHeaderUpdate(); + text->Header()->sh_addr = codePtr; + text->Header()->sh_size = codeLen; + + _ASSERTE(text->GetIndex() == ELF_BUILDER_TEXT_SECTION_INDEX); + } + CloseSection(); +} + +char *Elf_Builder::Reserve(unsigned int len) +{ + _ASSERTE(m_Curr != nullptr && "Section should be opened before"); + char *ptr = m_Buffer.Reserve(len); + m_Curr->Forward(len); + return ptr; +} + +void Elf_Builder::Append(const char *src, unsigned int len) +{ + _ASSERTE(m_Curr != nullptr && "Section should be opened before"); + char *dst = Reserve(len); + memcpy(dst, src, len); +} + +Elf_SectionTracker *Elf_Builder::OpenSection(const char *name, uint32_t type, uint64_t flags) +{ + _ASSERTE(m_Curr == nullptr && "Section should be closed before"); + + Elf_SectionTracker *next = new Elf_SectionTracker(name, m_SectionCount, m_Buffer.GetPos(), type, flags); + + if (m_First == NULL) + { + m_First = next; + } + + if (m_Last != NULL) + { + m_Last->SetNext(next); + } + + m_SectionCount++; + + m_Last = next; + m_Curr = next; + + return next; +} + +void Elf_Builder::CloseSection() +{ + _ASSERTE(m_Curr != nullptr && "Section should be opened before"); + m_Curr = nullptr; +} + +char *Elf_Builder::Export(UINT64 *pLen) +{ + unsigned int len = m_Buffer.GetPos(); + const char *src = m_Buffer.GetPtr(); + char *dst = new char[len]; + + memcpy(dst, src, len); + + if (pLen) + { + *pLen = len; + } + + return dst; +} + +void Elf_Builder::Finalize() +{ + // + // Create '.shstrtab' + // + Elf_SectionTracker *shstrtab = OpenSection(".shstrtab", SHT_STRTAB, 0); + { + Elf_SectionTracker *curr = m_First; + + while (curr) + { + unsigned int off = shstrtab->GetSize(); + unsigned int len = curr->GetNameLen(); + + char *dst = Reserve(len + 1); + memcpy(dst, curr->GetName(), len); + dst[len] = '\0'; + + curr->Header()->sh_name = off; + + curr = curr->GetNext(); + } + } + CloseSection(); + + // + // Create Section Header(s) Table + // + unsigned int shtOffset = m_Buffer.GetPos(); + { + Elf_SectionTracker *curr = m_First; + + while (curr) + { + if (curr->NeedHeaderUpdate()) + { + curr->Header()->sh_offset = curr->GetOffset(); + curr->Header()->sh_size = curr->GetSize(); + } + m_Buffer.AppendT(curr->Header()); + curr = curr->GetNext(); + } + } + + // + // Update ELF Header + // + Elf_Ehdr *elfHeader = new (m_Buffer.GetPtr()) Elf_Ehdr; + +#ifdef _TARGET_ARM_ + elfHeader->e_flags = EF_ARM_EABI_VER5; +#ifdef ARM_SOFTFP + elfHeader->e_flags |= EF_ARM_SOFT_FLOAT; +#else + elfHeader->e_flags |= EF_ARM_VFP_FLOAT; +#endif +#endif + elfHeader->e_shoff = shtOffset; + elfHeader->e_shentsize = sizeof(Elf_Shdr); + elfHeader->e_shnum = m_SectionCount; + elfHeader->e_shstrndx = shstrtab->GetIndex(); +} + +#ifdef FEATURE_GDBJIT_FRAME +struct __attribute__((packed)) Length +{ + UINT32 value; + + Length &operator=(UINT32 n) + { + value = n; + return *this; + } + + Length() + { + value = 0; + } +}; + +struct __attribute__((packed)) CIE +{ + Length length; + UINT32 id; + UINT8 version; + UINT8 augmentation; + UINT8 code_alignment_factor; + INT8 data_alignment_factor; + UINT8 return_address_register; + UINT8 instructions[0]; +}; + +struct __attribute__((packed)) FDE +{ + Length length; + UINT32 cie; + PCODE initial_location; + TADDR address_range; + UINT8 instructions[0]; +}; + +static void BuildDebugFrame(Elf_Builder &elfBuilder, PCODE pCode, TADDR codeSize) +{ +#if defined(_TARGET_ARM_) + const unsigned int code_alignment_factor = 2; + const int data_alignment_factor = -4; + + UINT8 cieCode[] = { + // DW_CFA_def_cfa 13[sp], 0 + 0x0c, 0x0d, 0x00, + }; + + UINT8 fdeCode[] = { + // DW_CFA_advance_loc 1 + 0x02, 0x01, + // DW_CFA_def_cfa_offset 8 + 0x0e, 0x08, + // DW_CFA_offset 11(r11), -8(= -4 * 2) + (0x02 << 6) | 0x0b, 0x02, + // DW_CFA_offset 14(lr), -4(= -4 * 1) + (0x02 << 6) | 0x0e, 0x01, + // DW_CFA_def_cfa_register 11(r11) + 0x0d, 0x0b, + }; +#elif defined(_TARGET_X86_) + const unsigned int code_alignment_factor = 1; + const int data_alignment_factor = -4; + + UINT8 cieCode[] = { + // DW_CFA_def_cfa 4(esp), 4 + 0x0c, 0x04, 0x04, + // DW_CFA_offset 8(eip), -4(= -4 * 1) + (0x02 << 6) | 0x08, 0x01, + }; + + UINT8 fdeCode[] = { + // DW_CFA_advance_loc 1 + 0x02, 0x01, + // DW_CFA_def_cfa_offset 8 + 0x0e, 0x08, + // DW_CFA_offset 5(ebp), -8(= -4 * 2) + (0x02 << 6) | 0x05, 0x02, + // DW_CFA_def_cfa_register 5(ebp) + 0x0d, 0x05, + }; +#elif defined(_TARGET_AMD64_) + const unsigned int code_alignment_factor = 1; + const int data_alignment_factor = -8; + + UINT8 cieCode[] = { + // DW_CFA_def_cfa 7(rsp), 8 + 0x0c, 0x07, 0x08, + // DW_CFA_offset 16, -16 (= -8 * 2) + (0x02 << 6) | 0x10, 0x01, + }; + + UINT8 fdeCode[] = { + // DW_CFA_advance_loc(1) + 0x02, 0x01, + // DW_CFA_def_cfa_offset(16) + 0x0e, 0x10, + // DW_CFA_offset 6, -16 (= -8 * 2) + (0x02 << 6) | 0x06, 0x02, + // DW_CFA_def_cfa_register(6) + 0x0d, 0x06, + }; +#else +#error "Unsupported architecture" +#endif + + elfBuilder.OpenSection(".debug_frame", SHT_PROGBITS, 0); + + // + // Common Information Entry + // + int cieLen = ALIGN_UP(sizeof(CIE) + sizeof(cieCode), ADDRESS_SIZE) + sizeof(Length); + + CIE *pCIE = elfBuilder.ReserveT(cieLen); + + memset(pCIE, 0, cieLen); + + pCIE->length = cieLen - sizeof(Length); + pCIE->id = 0xffffffff; + pCIE->version = 3; + pCIE->augmentation = 0; + Leb128Encode(code_alignment_factor, reinterpret_cast(&pCIE->code_alignment_factor), 1); + Leb128Encode(data_alignment_factor, reinterpret_cast(&pCIE->data_alignment_factor), 1); + + pCIE->return_address_register = 0; + + memcpy(&pCIE->instructions, cieCode, sizeof(cieCode)); + + // + // Frame Description Entry + // + int fdeLen = ALIGN_UP((sizeof(FDE) + sizeof(fdeCode)), ADDRESS_SIZE) + sizeof(Length); + + FDE *pFDE = elfBuilder.ReserveT(fdeLen); + + memset(pFDE, 0, fdeLen); + + pFDE->length = fdeLen - sizeof(Length); + pFDE->cie = 0; + pFDE->initial_location = pCode; + pFDE->address_range = codeSize; + memcpy(&pFDE->instructions, fdeCode, sizeof(fdeCode)); + + elfBuilder.CloseSection(); +} +#endif // FEATURE_GDBJIT_FRAME + /* Create ELF/DWARF debug info for jitted method */ void NotifyGdb::MethodCompiled(MethodDesc* methodDescPtr) { @@ -1765,19 +2378,21 @@ void NotifyGdb::MethodCompiled(MethodDesc* methodDescPtr) void NotifyGdb::OnMethodCompiled(MethodDesc* methodDescPtr) { - int symbolCount = 0; - NewArrayHolder symbolNames; - PCODE pCode = methodDescPtr->GetNativeCode(); + if (pCode == NULL) + { return; - unsigned int symInfoLen = 0; - NewArrayHolder symInfo = nullptr; - LocalsInfo locals; + } /* Get method name & size of jitted code */ - LPCUTF8 methodName = methodDescPtr->GetName(); EECodeInfo codeInfo(pCode); + + if (!codeInfo.IsValid()) + { + return; + } + TADDR codeSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfoToken()); pCode = PCODEToPINSTR(pCode); @@ -1800,59 +2415,76 @@ void NotifyGdb::OnMethodCompiled(MethodDesc* methodDescPtr) if (length == 0) return; - static NewArrayHolder wszModuleNames = nullptr; - DWORD cCharsNeeded = 0; + bool bNotify = false; - // Get names of interesting modules from environment - if (wszModuleNames == nullptr) + Elf_Builder elfBuilder; + + elfBuilder.Initialize(pCode, codeSize); + +#ifdef FEATURE_GDBJIT_FRAME { - cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), NULL, 0); + bool bEmitted = EmitFrameInfo(elfBuilder, pCode, codeSize); + bNotify = bNotify || bEmitted; + } +#endif - if(cCharsNeeded == 0) - return; - wszModuleNames = new WCHAR[cCharsNeeded+1]; - cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), wszModuleNames, cCharsNeeded); - if(cCharsNeeded == 0) - return; + if (isListedModule(wszModuleFile)) + { + bool bEmitted = EmitDebugInfo(elfBuilder, methodDescPtr, pCode, codeSize, szModuleFile); + bNotify = bNotify || bEmitted; } - else + + if (!bNotify) { - cCharsNeeded = wcslen(wszModuleNames); + return; } - BOOL isUserDebug = FALSE; + elfBuilder.Finalize(); - NewArrayHolder wszModuleName = new WCHAR[cCharsNeeded+1]; - LPWSTR pComma = wcsstr(wszModuleNames, W(",")); - LPWSTR tmp = wszModuleNames; + /* Create GDB JIT structures */ + NewHolder jit_symbols = new jit_code_entry; - while (pComma != NULL) - { - wcsncpy(wszModuleName, tmp, pComma - tmp); - wszModuleName[pComma - tmp] = W('\0'); + /* Fill the new entry */ + jit_symbols->next_entry = jit_symbols->prev_entry = 0; + jit_symbols->symfile_addr = elfBuilder.Export(&jit_symbols->symfile_size); - if (wcscmp(wszModuleName, wszModuleFile) == 0) - { - isUserDebug = TRUE; - break; - } - tmp = pComma + 1; - pComma = wcsstr(tmp, W(",")); - } - if (isUserDebug == FALSE) + /* Link into list */ + jit_code_entry *head = __jit_debug_descriptor.first_entry; + __jit_debug_descriptor.first_entry = jit_symbols; + if (head != 0) { - wcsncpy(wszModuleName, tmp, wcslen(tmp)); - wszModuleName[wcslen(tmp)] = W('\0'); - if (wcscmp(wszModuleName, wszModuleFile) == 0) - { - isUserDebug = TRUE; - } + jit_symbols->next_entry = head; + head->prev_entry = jit_symbols; } - if (isUserDebug == FALSE) - { - return; - } + jit_symbols.SuppressRelease(); + + /* Notify the debugger */ + __jit_debug_descriptor.relevant_entry = jit_symbols; + __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; + __jit_debug_register_code(); +} + +#ifdef FEATURE_GDBJIT_FRAME +bool NotifyGdb::EmitFrameInfo(Elf_Builder &elfBuilder, PCODE pCode, TADDR codeSize) +{ + BuildDebugFrame(elfBuilder, pCode, codeSize); + return true; +} +#endif // FEATURE_GDBJIT_FRAME + +bool NotifyGdb::EmitDebugInfo(Elf_Builder &elfBuilder, MethodDesc* methodDescPtr, PCODE pCode, TADDR codeSize, const char *szModuleFile) +{ + unsigned int thunkIndexBase = elfBuilder.GetSectionCount(); + + LPCUTF8 methodName = methodDescPtr->GetName(); + + int symbolCount = 0; + NewArrayHolder symbolNames; + + unsigned int symInfoLen = 0; + NewArrayHolder symInfo = nullptr; + LocalsInfo locals; NewHolder pTypeMap = new TK_TypeInfoMap(); @@ -1860,7 +2492,7 @@ void NotifyGdb::OnMethodCompiled(MethodDesc* methodDescPtr) HRESULT hr = GetDebugInfoFromPDB(methodDescPtr, symInfo, symInfoLen, locals); if (FAILED(hr) || symInfoLen == 0) { - return; + return false; } int method_count = countFuncs(symInfo, symInfoLen); @@ -1871,7 +2503,7 @@ void NotifyGdb::OnMethodCompiled(MethodDesc* methodDescPtr) /* Collect addresses of thunks called by method */ if (!CollectCalledMethods(pCalledMethods, (TADDR)methodDescPtr->GetNativeCode(), method, symbolNames, symbolCount)) { - return; + return false; } pCH->SetCalledMethods(NULL); @@ -1887,7 +2519,7 @@ void NotifyGdb::OnMethodCompiled(MethodDesc* methodDescPtr) if (firstLineIndex >= symInfoLen) { - return; + return false; } int start_index = getNextPrologueIndex(0, symInfo, symInfoLen); @@ -1921,19 +2553,19 @@ void NotifyGdb::OnMethodCompiled(MethodDesc* methodDescPtr) start_index = end_index; } - MemBuf elfHeader, sectHeaders, sectStr, sectSymTab, sectStrTab, dbgInfo, dbgAbbrev, dbgPubname, dbgPubType, dbgLine, - dbgStr, elfFile; + MemBuf sectSymTab, sectStrTab, dbgInfo, dbgAbbrev, dbgPubname, dbgPubType, dbgLine, + dbgStr; /* Build .debug_abbrev section */ if (!BuildDebugAbbrev(dbgAbbrev)) { - return; + return false; } /* Build .debug_line section */ if (!BuildLineTable(dbgLine, pCode, codeSize, symInfo, symInfoLen)) { - return; + return false; } DebugStrings[1] = szModuleFile; @@ -1941,13 +2573,13 @@ void NotifyGdb::OnMethodCompiled(MethodDesc* methodDescPtr) /* Build .debug_str section */ if (!BuildDebugStrings(dbgStr, pTypeMap, method)) { - return; + return false; } /* Build .debug_info section */ if (!BuildDebugInfo(dbgInfo, pTypeMap, method)) { - return; + return false; } for (int i = 0; i < method.GetCount(); ++i) @@ -1959,13 +2591,13 @@ void NotifyGdb::OnMethodCompiled(MethodDesc* methodDescPtr) /* Build .debug_pubname section */ if (!BuildDebugPub(dbgPubname, methodName, dbgInfo.MemSize, 0x28)) { - return; + return false; } /* Build debug_pubtype section */ if (!BuildDebugPub(dbgPubType, "int", dbgInfo.MemSize, 0x1a)) { - return; + return false; } /* Build .strtab section */ @@ -1979,158 +2611,64 @@ void NotifyGdb::OnMethodCompiled(MethodDesc* methodDescPtr) } if (!BuildStringTableSection(sectStrTab, symbolNames, symbolCount)) { - return; + return false; } /* Build .symtab section */ - if (!BuildSymbolTableSection(sectSymTab, pCode, codeSize, method, symbolNames, symbolCount)) + if (!BuildSymbolTableSection(sectSymTab, pCode, codeSize, method, symbolNames, symbolCount, thunkIndexBase)) { - return; + return false; } - /* Build section headers table and section names table */ - BuildSectionTables(sectHeaders, sectStr, method, symbolCount); - - /* Patch section offsets & sizes */ - long offset = sizeof(Elf_Ehdr); - Elf_Shdr* pShdr = reinterpret_cast(sectHeaders.MemPtr.GetValue()); - ++pShdr; // .text - pShdr->sh_addr = pCode; - pShdr->sh_size = codeSize; - ++pShdr; // .shstrtab - pShdr->sh_offset = offset; - pShdr->sh_size = sectStr.MemSize; - offset += sectStr.MemSize; - ++pShdr; // .debug_str - pShdr->sh_offset = offset; - pShdr->sh_size = dbgStr.MemSize; - offset += dbgStr.MemSize; - ++pShdr; // .debug_abbrev - pShdr->sh_offset = offset; - pShdr->sh_size = dbgAbbrev.MemSize; - offset += dbgAbbrev.MemSize; - ++pShdr; // .debug_info - pShdr->sh_offset = offset; - pShdr->sh_size = dbgInfo.MemSize; - offset += dbgInfo.MemSize; - ++pShdr; // .debug_pubnames - pShdr->sh_offset = offset; - pShdr->sh_size = dbgPubname.MemSize; - offset += dbgPubname.MemSize; - ++pShdr; // .debug_pubtypes - pShdr->sh_offset = offset; - pShdr->sh_size = dbgPubType.MemSize; - offset += dbgPubType.MemSize; - ++pShdr; // .debug_line - pShdr->sh_offset = offset; - pShdr->sh_size = dbgLine.MemSize; - offset += dbgLine.MemSize; - ++pShdr; // .symtab - pShdr->sh_offset = offset; - pShdr->sh_size = sectSymTab.MemSize; - pShdr->sh_link = GetSectionIndex(".strtab"); - offset += sectSymTab.MemSize; - ++pShdr; // .strtab - pShdr->sh_offset = offset; - pShdr->sh_size = sectStrTab.MemSize; - offset += sectStrTab.MemSize; - - // .thunks for (int i = 1 + method.GetCount(); i < symbolCount; i++) { - ++pShdr; - pShdr->sh_addr = PCODEToPINSTR(symbolNames[i].m_value); - pShdr->sh_size = 8; - } + char name[256]; - /* Build ELF header */ - if (!BuildELFHeader(elfHeader)) - { - return; + sprintf_s(name, _countof(name), ".thunk_%i", i); + + Elf_SectionTracker *thunk = elfBuilder.OpenSection(name, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); + thunk->DisableHeaderUpdate(); + elfBuilder.CloseSection(); } - Elf_Ehdr* header = reinterpret_cast(elfHeader.MemPtr.GetValue()); -#ifdef _TARGET_ARM_ - header->e_flags = EF_ARM_EABI_VER5; -#ifdef ARM_SOFTFP - header->e_flags |= EF_ARM_SOFT_FLOAT; -#else - header->e_flags |= EF_ARM_VFP_FLOAT; -#endif -#endif - header->e_shoff = offset; - header->e_shentsize = sizeof(Elf_Shdr); - int thunks_count = symbolCount - method.GetCount() - 1; - header->e_shnum = SectionNamesCount + thunks_count; - header->e_shstrndx = GetSectionIndex(".shstrtab"); - - /* Build ELF image in memory */ - elfFile.MemSize = elfHeader.MemSize + sectStr.MemSize + dbgStr.MemSize + dbgAbbrev.MemSize + dbgInfo.MemSize + - dbgPubname.MemSize + dbgPubType.MemSize + dbgLine.MemSize + sectSymTab.MemSize + - sectStrTab.MemSize + sectHeaders.MemSize; - elfFile.MemPtr = new char[elfFile.MemSize]; - - /* Copy section data */ - offset = 0; - memcpy(elfFile.MemPtr, elfHeader.MemPtr, elfHeader.MemSize); - offset += elfHeader.MemSize; - memcpy(elfFile.MemPtr + offset, sectStr.MemPtr, sectStr.MemSize); - offset += sectStr.MemSize; - memcpy(elfFile.MemPtr + offset, dbgStr.MemPtr, dbgStr.MemSize); - offset += dbgStr.MemSize; - memcpy(elfFile.MemPtr + offset, dbgAbbrev.MemPtr, dbgAbbrev.MemSize); - offset += dbgAbbrev.MemSize; - memcpy(elfFile.MemPtr + offset, dbgInfo.MemPtr, dbgInfo.MemSize); - offset += dbgInfo.MemSize; - memcpy(elfFile.MemPtr + offset, dbgPubname.MemPtr, dbgPubname.MemSize); - offset += dbgPubname.MemSize; - memcpy(elfFile.MemPtr + offset, dbgPubType.MemPtr, dbgPubType.MemSize); - offset += dbgPubType.MemSize; - memcpy(elfFile.MemPtr + offset, dbgLine.MemPtr, dbgLine.MemSize); - offset += dbgLine.MemSize; - memcpy(elfFile.MemPtr + offset, sectSymTab.MemPtr, sectSymTab.MemSize); - offset += sectSymTab.MemSize; - memcpy(elfFile.MemPtr + offset, sectStrTab.MemPtr, sectStrTab.MemSize); - offset += sectStrTab.MemSize; - - memcpy(elfFile.MemPtr + offset, sectHeaders.MemPtr, sectHeaders.MemSize); - - elfFile.MemPtr.SuppressRelease(); - -#ifdef GDBJIT_DUMPELF - DumpElf(methodName, elfFile); -#endif - /* Create GDB JIT structures */ - NewHolder jit_symbols = new jit_code_entry; + elfBuilder.OpenSection(".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS); + elfBuilder.Append(dbgStr.MemPtr, dbgStr.MemSize); + elfBuilder.CloseSection(); - /* Fill the new entry */ - jit_symbols->next_entry = jit_symbols->prev_entry = 0; - jit_symbols->symfile_addr = elfFile.MemPtr; - jit_symbols->symfile_size = elfFile.MemSize; - - /* Link into list */ - jit_code_entry *head = __jit_debug_descriptor.first_entry; - __jit_debug_descriptor.first_entry = jit_symbols; - if (head != 0) - { - jit_symbols->next_entry = head; - head->prev_entry = jit_symbols; - } - - jit_symbols.SuppressRelease(); + elfBuilder.OpenSection(".debug_abbrev", SHT_PROGBITS, 0); + elfBuilder.Append(dbgAbbrev.MemPtr, dbgAbbrev.MemSize); + elfBuilder.CloseSection(); - /* Notify the debugger */ - __jit_debug_descriptor.relevant_entry = jit_symbols; - __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; - __jit_debug_register_code(); + elfBuilder.OpenSection(".debug_info", SHT_PROGBITS, 0); + elfBuilder.Append(dbgInfo.MemPtr, dbgInfo.MemSize); + elfBuilder.CloseSection(); + + elfBuilder.OpenSection(".debug_pubnames", SHT_PROGBITS, 0); + elfBuilder.Append(dbgPubname.MemPtr, dbgPubname.MemSize); + elfBuilder.CloseSection(); + + elfBuilder.OpenSection(".debug_pubtypes", SHT_PROGBITS, 0); + elfBuilder.Append(dbgPubType.MemPtr, dbgPubType.MemSize); + elfBuilder.CloseSection(); + + elfBuilder.OpenSection(".debug_line", SHT_PROGBITS, 0); + elfBuilder.Append(dbgLine.MemPtr, dbgLine.MemSize); + elfBuilder.CloseSection(); + + Elf_SectionTracker *strtab = elfBuilder.OpenSection(".strtab", SHT_STRTAB, 0); + elfBuilder.Append(sectStrTab.MemPtr, sectStrTab.MemSize); + elfBuilder.CloseSection(); + + Elf_SectionTracker *symtab = elfBuilder.OpenSection(".symtab", SHT_SYMTAB, 0); + elfBuilder.Append(sectSymTab.MemPtr, sectSymTab.MemSize); + symtab->Header()->sh_link = strtab->GetIndex(); + symtab->Header()->sh_entsize = sizeof(Elf_Sym); + elfBuilder.CloseSection(); + + return true; } void NotifyGdb::MethodDropped(MethodDesc* methodDescPtr) { - static const int textSectionIndex = GetSectionIndex(".text"); - - if (textSectionIndex < 0) - return; - PCODE pCode = methodDescPtr->GetNativeCode(); if (pCode == NULL) @@ -2144,7 +2682,7 @@ void NotifyGdb::MethodDropped(MethodDesc* methodDescPtr) const Elf_Ehdr* pEhdr = reinterpret_cast(ptr); const Elf_Shdr* pShdr = reinterpret_cast(ptr + pEhdr->e_shoff); - pShdr += textSectionIndex; // bump to .text section + pShdr += ELF_BUILDER_TEXT_SECTION_INDEX; // bump to .text section if (pShdr->sh_addr == pCode) { /* Notify the debugger */ @@ -2637,10 +3175,9 @@ bool NotifyGdb::BuildStringTableSection(MemBuf& buf, NewArrayHolder /* Build ELF .symtab section */ bool NotifyGdb::BuildSymbolTableSection(MemBuf& buf, PCODE addr, TADDR codeSize, FunctionMemberPtrArrayHolder &method, - NewArrayHolder &symbolNames, int symbolCount) + NewArrayHolder &symbolNames, int symbolCount, + unsigned int thunkIndexBase) { - static const int textSectionIndex = GetSectionIndex(".text"); - buf.MemSize = symbolCount * sizeof(Elf_Sym); buf.MemPtr = new char[buf.MemSize]; @@ -2659,7 +3196,7 @@ bool NotifyGdb::BuildSymbolTableSection(MemBuf& buf, PCODE addr, TADDR codeSize, sym[i].setBindingAndType(STB_GLOBAL, STT_FUNC); sym[i].st_other = 0; sym[i].st_value = PINSTRToPCODE(symbolNames[i].m_value - addr); - sym[i].st_shndx = textSectionIndex; + sym[i].st_shndx = ELF_BUILDER_TEXT_SECTION_INDEX; sym[i].st_size = symbolNames[i].m_size; } @@ -2668,7 +3205,7 @@ bool NotifyGdb::BuildSymbolTableSection(MemBuf& buf, PCODE addr, TADDR codeSize, sym[i].st_name = symbolNames[i].m_off; sym[i].setBindingAndType(STB_GLOBAL, STT_FUNC); sym[i].st_other = 0; - sym[i].st_shndx = SectionNamesCount + (i - (1 + method.GetCount())); // .thunks section index + sym[i].st_shndx = thunkIndexBase + (i - (1 + method.GetCount())); // .thunks section index sym[i].st_size = 8; #ifdef _TARGET_ARM_ sym[i].st_value = 1; // for THUMB code @@ -2679,97 +3216,6 @@ bool NotifyGdb::BuildSymbolTableSection(MemBuf& buf, PCODE addr, TADDR codeSize, return true; } -int NotifyGdb::GetSectionIndex(const char *sectName) -{ - for (int i = 0; i < SectionNamesCount; ++i) - if (strcmp(SectionNames[i], sectName) == 0) - return i; - return -1; -} - -/* Build the ELF section headers table and section names table */ -void NotifyGdb::BuildSectionTables(MemBuf& sectBuf, MemBuf& strBuf, FunctionMemberPtrArrayHolder &method, - int symbolCount) -{ - static const int symtabSectionIndex = GetSectionIndex(".symtab"); - static const int nullSectionIndex = GetSectionIndex(""); - - const int thunks_count = symbolCount - 1 - method.GetCount(); - - // Approximate length of single section name. - // Used only to reduce memory reallocations. - static const int SECT_NAME_LENGTH = 11; - - strBuf.Resize(SECT_NAME_LENGTH * (SectionNamesCount + thunks_count)); - - Elf_Shdr* sectionHeaders = new Elf_Shdr[SectionNamesCount + thunks_count]; - sectBuf.MemPtr = reinterpret_cast(sectionHeaders); - sectBuf.MemSize = sizeof(Elf_Shdr) * (SectionNamesCount + thunks_count); - - Elf_Shdr* pSh = sectionHeaders; - uint32_t sectNameOffset = 0; - - // Additional memory for remaining section names, - // grows twice on each reallocation. - int addSize = SECT_NAME_LENGTH; - - // Fill section headers and names - for (int i = 0; i < SectionNamesCount + thunks_count; ++i, ++pSh) - { - char thunkSectNameBuf[256]; // temporary buffer for .thunk_# section name - const char *sectName; - - bool isThunkSection = i >= SectionNamesCount; - if (isThunkSection) - { - sprintf_s(thunkSectNameBuf, _countof(thunkSectNameBuf), ".thunk_%i", i); - sectName = thunkSectNameBuf; - } - else - { - sectName = SectionNames[i]; - } - - // Ensure that there is enough memory for section name, - // reallocate if necessary. - pSh->sh_name = sectNameOffset; - sectNameOffset += strlen(sectName) + 1; - if (sectNameOffset > strBuf.MemSize) - { - // Allocate more memory for remaining section names - strBuf.Resize(sectNameOffset + addSize); - addSize *= 2; - } - - strcpy(strBuf.MemPtr + pSh->sh_name, sectName); - - // All .thunk_* sections have the same type and flags - int index = isThunkSection ? SectionNamesCount : i; - pSh->sh_type = Sections[index].m_type; - pSh->sh_flags = Sections[index].m_flags; - - pSh->sh_addr = 0; - pSh->sh_offset = 0; - pSh->sh_size = 0; - pSh->sh_link = SHN_UNDEF; - pSh->sh_info = 0; - pSh->sh_addralign = i == nullSectionIndex ? 0 : 1; - pSh->sh_entsize = i == symtabSectionIndex ? sizeof(Elf_Sym) : 0; - } - - // Set actual used size to avoid garbage in ELF section - strBuf.MemSize = sectNameOffset; -} - -/* Build the ELF header */ -bool NotifyGdb::BuildELFHeader(MemBuf& buf) -{ - Elf_Ehdr* header = new Elf_Ehdr; - buf.MemPtr = reinterpret_cast(header); - buf.MemSize = sizeof(Elf_Ehdr); - return true; -} - /* Split full path name into directory & file names */ void NotifyGdb::SplitPathname(const char* path, const char*& pathName, const char*& fileName) { diff --git a/src/vm/gdbjit.h b/src/vm/gdbjit.h index 84b9109..ebd5a7a 100644 --- a/src/vm/gdbjit.h +++ b/src/vm/gdbjit.h @@ -324,6 +324,7 @@ public: }; struct Elf_Symbol; +class Elf_Builder; class NotifyGdb { @@ -404,12 +405,14 @@ private: static void OnMethodCompiled(MethodDesc* methodDescPtr); - static int GetSectionIndex(const char *sectName); - static bool BuildELFHeader(MemBuf& buf); - static void BuildSectionTables(MemBuf& sectBuf, MemBuf& strBuf, FunctionMemberPtrArrayHolder &method, - int symbolCount); +#ifdef FEATURE_GDBJIT_FRAME + static bool EmitFrameInfo(Elf_Builder &, PCODE pCode, TADDR codeSzie); +#endif // FEATURE_GDBJIT_FRAME + static bool EmitDebugInfo(Elf_Builder &, MethodDesc* methodDescPtr, PCODE pCode, TADDR codeSize, const char *szModuleFile); + static bool BuildSymbolTableSection(MemBuf& buf, PCODE addr, TADDR codeSize, FunctionMemberPtrArrayHolder &method, - NewArrayHolder &symbolNames, int symbolCount); + NewArrayHolder &symbolNames, int symbolCount, + unsigned int thunkIndexBase); static bool BuildStringTableSection(MemBuf& strTab, NewArrayHolder &symbolNames, int symbolCount); static bool BuildDebugStrings(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMemberPtrArrayHolder &method); static bool BuildDebugAbbrev(MemBuf& buf); diff --git a/src/vm/prestub.cpp b/src/vm/prestub.cpp index fccec51..88bd9de 100644 --- a/src/vm/prestub.cpp +++ b/src/vm/prestub.cpp @@ -52,7 +52,12 @@ #include "callcounter.h" #endif -#ifndef DACCESS_COMPILE +#if defined(FEATURE_GDBJIT) +#include "gdbjit.h" +__declspec(thread) bool tls_isSymReaderInProgress = false; +#endif + +#ifndef DACCESS_COMPILE EXTERN_C void STDCALL ThePreStub(); @@ -231,17 +236,13 @@ void DACNotifyCompilationFinished(MethodDesc *methodDesc) _ASSERTE(modulePtr); -#ifndef FEATURE_GDBJIT // Are we listed? USHORT jnt = jn.Requested((TADDR) modulePtr, t); if (jnt & CLRDATA_METHNOTIFY_GENERATED) { // If so, throw an exception! -#endif DACNotify::DoJITNotification(methodDesc); -#ifndef FEATURE_GDBJIT } -#endif } } @@ -678,6 +679,15 @@ Done: LOG((LF_CORDB, LL_EVERYTHING, "MethodDesc::MakeJitWorker finished. Stub is" FMT_ADDR "\n", DBG_ADDR(pCode))); +#if defined(FEATURE_GDBJIT) && defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE) + if (!tls_isSymReaderInProgress) + { + tls_isSymReaderInProgress = true; + NotifyGdb::MethodCompiled(this); + tls_isSymReaderInProgress = false; + } +#endif + return pCode; } @@ -1568,6 +1578,15 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT) } #endif // FEATURE_INTERPRETER } // end if (pCode == NULL) +#if defined(FEATURE_GDBJIT) && defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE) + else if (!tls_isSymReaderInProgress) + { + tls_isSymReaderInProgress = true; + NotifyGdb::MethodCompiled(this); + tls_isSymReaderInProgress = false; + } +#endif + } // end else if (IsIL() || IsNoMetadata()) else if (IsNDirect()) { diff --git a/src/vm/util.cpp b/src/vm/util.cpp index da7d18c..9d9800b 100644 --- a/src/vm/util.cpp +++ b/src/vm/util.cpp @@ -3315,7 +3315,6 @@ void InitializeClrNotifications() #if defined(FEATURE_GDBJIT) #include "gdbjit.h" -__declspec(thread) bool tls_isSymReaderInProgress = false; #endif // FEATURE_GDBJIT // called from the runtime @@ -3329,14 +3328,7 @@ void DACNotify::DoJITNotification(MethodDesc *MethodDescPtr) MODE_PREEMPTIVE; } CONTRACTL_END; -#if defined(FEATURE_GDBJIT) && defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE) - if(!tls_isSymReaderInProgress) - { - tls_isSymReaderInProgress = true; - NotifyGdb::MethodCompiled(MethodDescPtr); - tls_isSymReaderInProgress = false; - } -#endif + TADDR Args[2] = { JIT_NOTIFICATION, (TADDR) MethodDescPtr }; DACNotifyExceptionHelper(Args, 2); } -- 2.7.4