Add GDB JIT support for source line debug information.
authorDmitri Botcharnikov <dmitry.b@samsung.com>
Thu, 14 Jul 2016 16:23:23 +0000 (19:23 +0300)
committerEvgeny Pavlov <e.pavlov@samsung.com>
Fri, 22 Jul 2016 07:57:30 +0000 (10:57 +0300)
src/coreclr/hosts/inc/coreclrhost.h
src/coreclr/hosts/unixcoreruncommon/CMakeLists.txt
src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp
src/vm/CMakeLists.txt
src/vm/gdbjit.cpp [new file with mode: 0644]
src/vm/gdbjit.h [new file with mode: 0644]
src/vm/util.cpp

index f0d7952..733174b 100644 (file)
@@ -46,5 +46,22 @@ CORECLR_HOSTING_API(coreclr_execute_assembly,
             unsigned int* exitCode);
 
 #undef CORECLR_HOSTING_API
-                      
+
+struct SequencePointInfo
+{
+    int lineNumber, ilOffset;
+    char16_t* fileName;
+};
+
+struct MethodDebugInfo
+{
+    SequencePointInfo* points;
+    int size;
+};
+
+typedef int (*GetInfoForMethodDelegate)(const char*, unsigned int, MethodDebugInfo& methodDebugInfo);
+extern GetInfoForMethodDelegate getInfoForMethodDelegate;
+
 #endif // __CORECLR_HOST_H__
+
+
index a17e0a0..1bf8f4d 100644 (file)
@@ -2,6 +2,10 @@ project(unixcoreruncommon)
 
 add_compile_options(-fPIC)
 
+if(FEATURE_GDBJIT)    
+   add_definitions(-DFEATURE_GDBJIT)
+endif(FEATURE_GDBJIT)
+
 _add_library(unixcoreruncommon
     STATIC
     coreruncommon.cpp
index b4c54ca..ae2d49c 100644 (file)
@@ -34,7 +34,7 @@
 // If set to 1, server GC is enabled on startup. If 0, server GC is
 // disabled. Server GC is off by default.
 static const char* serverGcVar = "CORECLR_SERVER_GC";
-
+GetInfoForMethodDelegate getInfoForMethodDelegate = NULL;
 #if defined(__linux__)
 #define symlinkEntrypointExecutable "/proc/self/exe"
 #elif !defined(__APPLE__)
@@ -402,6 +402,24 @@ int ExecuteManagedAssembly(
             }
             else 
             {
+#ifdef FEATURE_GDBJIT                
+                coreclr_create_delegate_ptr CreateDelegate =
+                (coreclr_create_delegate_ptr)dlsym(coreclrLib,
+                                           "coreclr_create_delegate");
+
+                // st = CreateDelegate(hostHandle, domainId, "System.Diagnostics.Debug.SymbolReader",
+                //           "System.Diagnostics.Debug.SymbolReader.SymbolReader", "GetLineByILOffset",
+                //           (void **)&getLineByILOffsetDelegate);
+                st = CreateDelegate(hostHandle, domainId, "System.Diagnostics.Debug.SymbolReader",
+                          "System.Diagnostics.Debug.SymbolReader.SymbolReader", "GetInfoForMethod",
+                          (void **)&getInfoForMethodDelegate);
+
+                if (!SUCCEEDED(st))
+                {
+                    fprintf(stderr, "coreclr_create_delegate failed - status: 0x%08x\n", st);
+                    exitCode = -1;
+                }
+#endif // FEATURE_GDBJIT                
                 st = executeAssembly(
                         hostHandle,
                         domainId,
index 89a6437..d82530d 100644 (file)
@@ -27,6 +27,17 @@ if(CLR_CMAKE_PLATFORM_UNIX)
     add_compile_options(-fPIC)
 endif(CLR_CMAKE_PLATFORM_UNIX)
 
+if(FEATURE_GDBJIT)
+    set(VM_SOURCES_GDBJIT
+    ../gc/gccommon.cpp
+    ../gc/gcscan.cpp
+    ../gc/gcsvr.cpp
+    ../gc/gcwks.cpp
+    gdbjit.cpp
+    )
+   add_definitions(-DFEATURE_GDBJIT)
+endif(FEATURE_GDBJIT)    
+
 set(VM_SOURCES_DAC_AND_WKS_COMMON
     appdomain.cpp
     array.cpp
@@ -109,6 +120,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON
     virtualcallstub.cpp
     win32threadpool.cpp
     zapsig.cpp
+    ${VM_SOURCES_GDBJIT}
 )
 
 if(FEATURE_READYTORUN)
diff --git a/src/vm/gdbjit.cpp b/src/vm/gdbjit.cpp
new file mode 100644 (file)
index 0000000..c60f349
--- /dev/null
@@ -0,0 +1,1075 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//*****************************************************************************
+// File: gdbjit.cpp
+//
+
+//
+// NotifyGdb implementation.
+//
+//*****************************************************************************
+
+#include "common.h"
+#include "../coreclr/hosts/inc/coreclrhost.h"
+#include "gdbjit.h"
+
+struct DebuggerILToNativeMap
+{
+    ULONG ilOffset;
+    ULONG nativeStartOffset;
+    ULONG nativeEndOffset;
+    ICorDebugInfo::SourceTypes source;
+};
+BYTE* DebugInfoStoreNew(void * pData, size_t cBytes)
+{
+    return new (nothrow) BYTE[cBytes];
+}
+
+/* Get IL to native offsets map */
+HRESULT
+GetMethodNativeMap(MethodDesc* methodDesc,
+                   ULONG32* numMap,
+                   DebuggerILToNativeMap** map)
+{
+    // Use the DebugInfoStore to get IL->Native maps.
+    // It doesn't matter whether we're jitted, ngenned etc.
+
+    DebugInfoRequest request;
+    TADDR nativeCodeStartAddr = PCODEToPINSTR(methodDesc->GetNativeCode());
+    request.InitFromStartingAddr(methodDesc, nativeCodeStartAddr);
+
+    // Bounds info.
+    ULONG32 countMapCopy;
+    NewHolder<ICorDebugInfo::OffsetMapping> mapCopy(NULL);
+
+    BOOL success = DebugInfoManager::GetBoundariesAndVars(request,
+                                                          DebugInfoStoreNew,
+                                                          NULL, // allocator
+                                                          &countMapCopy,
+                                                          &mapCopy,
+                                                          NULL,
+                                                          NULL);
+
+    if (!success)
+    {
+        return E_FAIL;
+    }
+
+    // Need to convert map formats.
+    *numMap = countMapCopy;
+
+    *map = new (nothrow) DebuggerILToNativeMap[countMapCopy];
+    if (!*map)
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    ULONG32 i;
+    for (i = 0; i < *numMap; i++)
+    {
+        (*map)[i].ilOffset = mapCopy[i].ilOffset;
+        (*map)[i].nativeStartOffset = mapCopy[i].nativeOffset;
+        if (i > 0)
+        {
+            (*map)[i - 1].nativeEndOffset = (*map)[i].nativeStartOffset;
+        }
+        (*map)[i].source = mapCopy[i].source;
+    }
+    if (*numMap >= 1)
+    {
+        (*map)[i - 1].nativeEndOffset = 0;
+    }
+    return S_OK;
+}
+
+/* Get mapping of IL offsets to source line numbers */
+HRESULT
+GetDebugInfoFromPDB(MethodDesc* MethodDescPtr, SymbolsInfo** symInfo, unsigned int &symInfoLen)
+{
+    DebuggerILToNativeMap* map = NULL;
+
+    ULONG32 numMap;
+
+    if (!getInfoForMethodDelegate)
+        return E_FAIL;
+    
+    if (GetMethodNativeMap(MethodDescPtr, &numMap, &map) != S_OK)
+        return E_FAIL;
+
+    const Module* mod = MethodDescPtr->GetMethodTable()->GetModule();
+    SString modName = mod->GetFile()->GetPath();
+    StackScratchBuffer scratch;
+    const char* szModName = modName.GetUTF8(scratch);
+
+    MethodDebugInfo *methodDebugInfo = new (nothrow )MethodDebugInfo();
+    if (methodDebugInfo == nullptr)
+        return E_OUTOFMEMORY;
+    methodDebugInfo->points = (SequencePointInfo*) CoTaskMemAlloc(sizeof(SequencePointInfo) * numMap);
+    if (methodDebugInfo->points == nullptr)
+        return E_OUTOFMEMORY;
+    methodDebugInfo->size = numMap;
+
+    if (!getInfoForMethodDelegate(szModName, MethodDescPtr->GetMemberDef(), *methodDebugInfo))
+        return E_FAIL;
+
+    symInfoLen = methodDebugInfo->size;
+    *symInfo = new (nothrow) SymbolsInfo[symInfoLen];
+    if (*symInfo == nullptr)
+        return E_FAIL;
+
+    for (ULONG32 i = 0; i < symInfoLen; i++)
+    {
+        for (ULONG32 j = 0; j < numMap; j++)
+        {
+            if (methodDebugInfo->points[i].ilOffset == map[j].ilOffset)
+            {
+                SymbolsInfo& s = (*symInfo)[i];
+                const SequencePointInfo& sp = methodDebugInfo->points[i];
+
+                s.nativeOffset = map[j].nativeStartOffset;
+                s.ilOffset = map[j].ilOffset;
+                s.fileIndex = 0;
+                //wcscpy(s.fileName, sp.fileName);
+                int len = WideCharToMultiByte(CP_UTF8, 0, sp.fileName, -1, s.fileName, sizeof(s.fileName), NULL, NULL);
+                s.fileName[len] = 0;
+                s.lineNumber = sp.lineNumber;
+            }
+        }
+    }
+
+    CoTaskMemFree(methodDebugInfo->points);
+    return S_OK;
+}
+
+// GDB JIT interface
+typedef enum
+{
+  JIT_NOACTION = 0,
+  JIT_REGISTER_FN,
+  JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry
+{
+  struct jit_code_entry *next_entry;
+  struct jit_code_entry *prev_entry;
+  const char *symfile_addr;
+  UINT64 symfile_size;
+};
+
+struct jit_descriptor
+{
+  UINT32 version;
+  /* This type should be jit_actions_t, but we use uint32_t
+     to be explicit about the bitwidth.  */
+  UINT32 action_flag;
+  struct jit_code_entry *relevant_entry;
+  struct jit_code_entry *first_entry;
+};
+/* GDB puts a breakpoint in this function.  */
+extern "C"
+void __attribute__((noinline)) __jit_debug_register_code() { };
+
+/* Make sure to specify the version statically, because the
+   debugger may check the version before we can set it.  */
+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", ""
+};
+
+const int SectionNamesCount = sizeof(SectionNames) / sizeof(SectionNames[0]);
+
+/* 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}
+};
+
+/* Static data for .debug_str section */
+const char* DebugStrings[] = {
+    "CoreCLR", "" /* module name */, "" /* module path */, "" /* method name */, "int"
+};
+
+const int DebugStringCount = sizeof(DebugStrings) / sizeof(DebugStrings[0]);
+
+/* Static data for .debug_abbrev */
+const unsigned char AbbrevTable[] = {
+    1, DW_TAG_compile_unit, DW_children_yes,
+        DW_AT_producer, DW_FORM_strp, DW_AT_language, DW_FORM_data2, DW_AT_name, DW_FORM_strp,
+        DW_AT_stmt_list, DW_FORM_sec_offset, 0, 0,
+    2, DW_TAG_subprogram, DW_children_no,
+        DW_AT_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1,
+        DW_AT_type, DW_FORM_ref4, DW_AT_external, DW_FORM_flag_present, 0, 0,
+    3, DW_TAG_base_type, DW_children_no,
+        DW_AT_name, DW_FORM_strp, DW_AT_encoding, DW_FORM_data1, DW_AT_byte_size, DW_FORM_data1,0, 0,
+    0
+};
+
+const int AbbrevTableSize = sizeof(AbbrevTable);
+
+/* Static data for .debug_line, including header */
+#define DWARF_LINE_BASE (-5)
+#define DWARF_LINE_RANGE 14
+#define DWARF_OPCODE_BASE 13
+
+DwarfLineNumHeader LineNumHeader = {
+    0, 2, 0, 1, 1, DWARF_LINE_BASE, DWARF_LINE_RANGE, DWARF_OPCODE_BASE, {0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1}
+};
+
+/* Static data for .debug_info */
+struct __attribute__((packed)) DebugInfo
+{
+    uint8_t m_cu_abbrev;
+    uint32_t m_prod_off;
+    uint16_t m_lang;
+    uint32_t m_cu_name;
+    uint32_t m_line_num;
+    
+    uint8_t m_sub_abbrev;
+    uint32_t m_sub_name;
+    uint8_t m_file, m_line;
+    uint32_t m_sub_type;
+    
+    uint8_t m_type_abbrev;
+    uint32_t m_type_name;
+    uint8_t m_encoding;
+    uint8_t m_byte_size;
+} debugInfo = {
+    1, 0, DW_LANG_C89, 0, 0,
+    2, 0, 1, 1, 37,
+    3, 0, DW_ATE_signed, 4
+};
+
+/* Create ELF/DWARF debug info for jitted method */
+void NotifyGdb::MethodCompiled(MethodDesc* MethodDescPtr)
+{
+    PCODE pCode = MethodDescPtr->GetNativeCode();
+
+    if (pCode == NULL)
+        return;
+    unsigned int symInfoLen = 0;
+    SymbolsInfo* symInfo = nullptr;
+
+    /* Get method name & size of jitted code */
+    LPCUTF8 methodName = MethodDescPtr->GetName();
+    EECodeInfo codeInfo(pCode);
+    TADDR codeSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfo());
+    
+#ifdef _TARGET_ARM_    
+    pCode &= ~1; // clear thumb flag for debug info
+#endif    
+
+    /* Get module name */
+    const Module* mod = MethodDescPtr->GetMethodTable()->GetModule();
+    SString modName = mod->GetFile()->GetPath();
+    StackScratchBuffer scratch;
+    const char* szModName = modName.GetUTF8(scratch);
+    const char *szModulePath, *szModuleFile;
+    
+    SplitPathname(szModName, szModulePath, szModuleFile);
+    
+    /* Get debug info for method from portable PDB */
+    HRESULT hr = GetDebugInfoFromPDB(MethodDescPtr, &symInfo, symInfoLen);
+    if (FAILED(hr) || symInfoLen == 0)
+    {
+        return;
+    }
+
+    MemBuf elfHeader, sectHeaders, sectStr, dbgInfo, dbgAbbrev, dbgPubname, dbgPubType, dbgLine, dbgStr, elfFile;
+
+    /* Build .debug_abbrev section */
+    if (!BuildDebugAbbrev(dbgAbbrev))
+    {
+        delete[] symInfo;
+        return;
+    }
+    
+    /* Build .debug_line section */
+    if (!BuildLineTable(dbgLine, pCode, symInfo, symInfoLen))
+    {
+        delete[] symInfo;
+        delete[] dbgAbbrev.MemPtr;
+        return;
+    }
+    
+    DebugStrings[1] = szModuleFile;
+    DebugStrings[3] = methodName;
+    
+    /* Build .debug_str section */
+    if (!BuildDebugStrings(dbgStr))
+    {
+        delete[] symInfo;
+        delete[] dbgAbbrev.MemPtr;
+        delete[] dbgLine.MemPtr;
+        return;
+    }
+    
+    /* Build .debug_info section */
+    if (!BuildDebugInfo(dbgInfo))
+    {
+        delete[] symInfo;
+        delete[] dbgAbbrev.MemPtr;
+        delete[] dbgLine.MemPtr;
+        delete[] dbgStr.MemPtr;
+        return;
+    }
+    
+    /* Build .debug_pubname section */
+    if (!BuildDebugPub(dbgPubname, methodName, dbgInfo.MemSize, 26))
+    {
+        delete[] symInfo;
+        delete[] dbgAbbrev.MemPtr;
+        delete[] dbgLine.MemPtr;
+        delete[] dbgStr.MemPtr;
+        delete[] dbgInfo.MemPtr;
+        return;
+    }
+    
+    /* Build debug_pubtype section */
+    if (!BuildDebugPub(dbgPubType, "int", dbgInfo.MemSize, 37))
+    {
+        delete[] symInfo;
+        delete[] dbgAbbrev.MemPtr;
+        delete[] dbgLine.MemPtr;
+        delete[] dbgStr.MemPtr;
+        delete[] dbgInfo.MemPtr;
+        delete[] dbgPubname.MemPtr;
+        return;
+    }
+    
+    /* Build section names section */
+    if (!BuildSectionNameTable(sectStr))
+    {
+        delete[] symInfo;
+        delete[] dbgAbbrev.MemPtr;
+        delete[] dbgLine.MemPtr;
+        delete[] dbgStr.MemPtr;
+        delete[] dbgInfo.MemPtr;
+        delete[] dbgPubname.MemPtr;
+        delete[] dbgPubType.MemPtr;
+        return;
+    }
+
+    /* Build section headers table */
+    if (!BuildSectionTable(sectHeaders))
+    {
+        delete[] symInfo;
+        delete[] dbgAbbrev.MemPtr;
+        delete[] dbgLine.MemPtr;
+        delete[] dbgStr.MemPtr;
+        delete[] dbgInfo.MemPtr;
+        delete[] dbgPubname.MemPtr;
+        delete[] dbgPubType.MemPtr;
+        delete[] sectStr.MemPtr;
+        return;
+    }
+
+    /* Patch section offsets & sizes */
+    long offset = sizeof(Elf_Ehdr);
+    Elf_Shdr* pShdr = reinterpret_cast<Elf_Shdr*>(sectHeaders.MemPtr);
+    ++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;
+    
+    /* Build ELF header */
+    if (!BuildELFHeader(elfHeader))
+    {
+        delete[] symInfo;
+        delete[] dbgAbbrev.MemPtr;
+        delete[] dbgLine.MemPtr;
+        delete[] dbgStr.MemPtr;
+        delete[] dbgInfo.MemPtr;
+        delete[] dbgPubname.MemPtr;
+        delete[] dbgPubType.MemPtr;
+        delete[] sectStr.MemPtr;
+        delete[] sectHeaders.MemPtr;
+        return;
+    }
+    Elf_Ehdr* header = reinterpret_cast<Elf_Ehdr*>(elfHeader.MemPtr);
+#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);
+    header->e_shnum = SectionNamesCount - 1;
+    header->e_shstrndx = 2;
+
+    /* Build ELF image in memory */
+    elfFile.MemSize = elfHeader.MemSize + sectStr.MemSize + dbgStr.MemSize + dbgAbbrev.MemSize
+                        + dbgInfo.MemSize + dbgPubname.MemSize + dbgPubType.MemSize + dbgLine.MemSize + sectHeaders.MemSize;
+    elfFile.MemPtr =  new (nothrow) char[elfFile.MemSize];
+    if (elfFile.MemPtr == nullptr)
+    {
+        delete[] symInfo;
+        delete[] dbgAbbrev.MemPtr;
+        delete[] dbgLine.MemPtr;
+        delete[] dbgStr.MemPtr;
+        delete[] dbgInfo.MemPtr;
+        delete[] dbgPubname.MemPtr;
+        delete[] dbgPubType.MemPtr;
+        delete[] sectStr.MemPtr;
+        delete[] sectHeaders.MemPtr;
+        delete[] elfHeader.MemPtr;
+        return;
+    }
+    
+    /* 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, sectHeaders.MemPtr, sectHeaders.MemSize);
+    
+    delete[] symInfo;
+    delete[] elfHeader.MemPtr;
+    delete[] sectStr.MemPtr;
+    delete[] dbgStr.MemPtr;
+    delete[] dbgAbbrev.MemPtr;
+    delete[] dbgInfo.MemPtr;
+    delete[] dbgPubname.MemPtr;
+    delete[] dbgPubType.MemPtr;
+    delete[] dbgLine.MemPtr;
+    delete[] sectHeaders.MemPtr;
+    
+    /* Create GDB JIT structures */
+    jit_code_entry* jit_symbols = new (nothrow) jit_code_entry;
+    
+    if (jit_symbols == nullptr)
+    {
+        delete elfFile.MemPtr;
+        return;
+    }
+    
+    /* 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;
+    }
+    
+    /* Notify the debugger */
+    __jit_debug_descriptor.relevant_entry = jit_symbols;
+    __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+    __jit_debug_register_code();
+
+}
+
+void NotifyGdb::MethodDropped(MethodDesc* MethodDescPtr)
+{
+    PCODE pCode = MethodDescPtr->GetNativeCode();
+
+    if (pCode == NULL)
+        return;
+    
+    /* Find relevant entry */
+    for (jit_code_entry* jit_symbols = __jit_debug_descriptor.first_entry; jit_symbols != 0; jit_symbols = jit_symbols->next_entry)
+    {
+        const char* ptr = jit_symbols->symfile_addr;
+        uint64_t size = jit_symbols->symfile_size;
+        
+        const Elf_Ehdr* pEhdr = reinterpret_cast<const Elf_Ehdr*>(ptr);
+        const Elf_Shdr* pShdr = reinterpret_cast<const Elf_Shdr*>(ptr + pEhdr->e_shoff);
+        ++pShdr; // bump to .text section
+        if (pShdr->sh_addr == pCode)
+        {
+            /* Notify the debugger */
+            __jit_debug_descriptor.relevant_entry = jit_symbols;
+            __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
+            __jit_debug_register_code();
+            
+            /* Free memory */
+            delete[] ptr;
+            
+            /* Unlink from list */
+            if (jit_symbols->prev_entry == 0)
+                __jit_debug_descriptor.first_entry = jit_symbols->next_entry;
+            else
+                jit_symbols->prev_entry->next_entry = jit_symbols->next_entry;
+            delete jit_symbols;
+            break;
+        }
+    }
+}
+
+/* Build the DWARF .debug_line section */
+bool NotifyGdb::BuildLineTable(MemBuf& buf, PCODE startAddr, SymbolsInfo* lines, unsigned nlines)
+{
+    MemBuf fileTable, lineProg;
+    
+    /* Build file table */
+    if (!BuildFileTable(fileTable, lines, nlines))
+        return false;
+    /* Build line info program */ 
+    if (!BuildLineProg(lineProg, startAddr, lines, nlines))
+    {
+        delete[] fileTable.MemPtr;
+        return false;
+    }
+    
+    buf.MemSize = sizeof(DwarfLineNumHeader) + 1 + fileTable.MemSize + lineProg.MemSize;
+    buf.MemPtr = new (nothrow) char[buf.MemSize];
+    
+    if (buf.MemPtr == nullptr)
+    {
+        delete[] fileTable.MemPtr;
+        delete[] lineProg.MemPtr;
+        return false;
+    }
+    
+    /* Fill the line info header */
+    DwarfLineNumHeader* header = reinterpret_cast<DwarfLineNumHeader*>(buf.MemPtr);
+    memcpy(buf.MemPtr, &LineNumHeader, sizeof(DwarfLineNumHeader));
+    header->m_length = buf.MemSize - sizeof(uint32_t);
+    header->m_hdr_length = sizeof(DwarfLineNumHeader) + 1 + fileTable.MemSize - 2 * sizeof(uint32_t) - sizeof(uint16_t);
+    buf.MemPtr[sizeof(DwarfLineNumHeader)] = 0; // this is for missing directory table
+    /* copy file table */
+    memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader) + 1, fileTable.MemPtr, fileTable.MemSize);
+    /* copy line program */
+    memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader) + 1 + fileTable.MemSize, lineProg.MemPtr, lineProg.MemSize);
+    
+    delete[] fileTable.MemPtr;
+    delete[] lineProg.MemPtr;
+    
+    return true;
+}
+
+/* Buid the source files table for DWARF source line info */
+bool NotifyGdb::BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines)
+{
+    const char** files = nullptr;
+    unsigned nfiles = 0;
+    
+    /* Extract file names and replace them with indices in file table */
+    files = new (nothrow) const char*[nlines];
+    if (files == nullptr)
+        return false;
+    for (unsigned i = 0; i < nlines; ++i)
+    {
+        const char *filePath, *fileName;
+        SplitPathname(lines[i].fileName, filePath, fileName);
+
+        /* if this isn't first then we already added file, so adjust index */
+        lines[i].fileIndex = (nfiles) ? (nfiles - 1) : (nfiles);
+
+        bool found = false;
+        for (int j = 0; j < nfiles; ++j)
+        {
+            if (strcmp(fileName, files[j]) == 0)
+            {
+                found = true;
+                break;
+            }
+        }
+        
+        /* add new source file */
+        if (!found)
+        {
+            files[nfiles++] = fileName;
+        }
+    }
+    
+    /* build file table */
+    unsigned totalSize = 0;
+    
+    for (unsigned i = 0; i < nfiles; ++i)
+    {
+        totalSize += strlen(files[i]) + 1 + 3;
+    }
+    totalSize += 1;
+    
+    buf.MemSize = totalSize;
+    buf.MemPtr = new (nothrow) char[buf.MemSize];
+    
+    if (buf.MemPtr == nullptr)
+    {
+        delete[] files;
+        return false;
+    }
+    
+    /* copy collected file names */
+    char *ptr = buf.MemPtr;
+    for (unsigned i = 0; i < nfiles; ++i)
+    {
+        strcpy(ptr, files[i]);
+        ptr += strlen(files[i]) + 1;
+        // three LEB128 entries which we don't care
+        *ptr++ = 0;
+        *ptr++ = 0;
+        *ptr++ = 0;
+    }
+    // final zero byte
+    *ptr = 0;
+
+    delete[] files;
+    return true;
+}
+
+/* Command to set absolute address */
+void NotifyGdb::IssueSetAddress(char*& ptr, PCODE addr)
+{
+    *ptr++ = 0;
+    *ptr++ = ADDRESS_SIZE + 1;
+    *ptr++ = DW_LNE_set_address;
+    *reinterpret_cast<PCODE*>(ptr) = addr;
+    ptr += ADDRESS_SIZE;
+}
+
+/* End of line program */
+void NotifyGdb::IssueEndOfSequence(char*& ptr)
+{
+    *ptr++ = 0;
+    *ptr++ = 1;
+    *ptr++ = DW_LNE_end_sequence;
+}
+
+/* Command w/o parameters */
+void NotifyGdb::IssueSimpleCommand(char*& ptr, uint8_t command)
+{
+    *ptr++ = command;
+}
+
+/* Command with one LEB128 parameter */
+void NotifyGdb::IssueParamCommand(char*& ptr, uint8_t command, char* param, int param_size)
+{
+    *ptr++ = command;
+    while (param_size-- > 0)
+    {
+        *ptr++ = *param++;
+    }
+}
+
+/* Special command moves address, line number and issue one row to source line matrix */
+void NotifyGdb::IssueSpecialCommand(char*& ptr, int8_t line_shift, uint8_t addr_shift)
+{
+    *ptr++ = (line_shift - DWARF_LINE_BASE) + addr_shift * DWARF_LINE_RANGE + DWARF_OPCODE_BASE;
+}
+
+/* Check to see if given shifts are fit into one byte command */
+bool NotifyGdb::FitIntoSpecialOpcode(int8_t line_shift, uint8_t addr_shift)
+{
+    unsigned opcode = (line_shift - DWARF_LINE_BASE) + addr_shift * DWARF_LINE_RANGE + DWARF_OPCODE_BASE;
+    
+    return opcode < 255;
+}
+
+/* Build program for DWARF source line section */
+bool NotifyGdb::BuildLineProg(MemBuf& buf, PCODE startAddr, SymbolsInfo* lines, unsigned nlines)
+{
+    static char cnv_buf[16];
+    
+    /* reserve memory assuming worst case: one extended and one special command for each line */
+    buf.MemSize = nlines * ( 4 + ADDRESS_SIZE) + 4;
+    buf.MemPtr = new (nothrow) char[buf.MemSize];
+    char* ptr = buf.MemPtr;
+  
+    if (buf.MemPtr == nullptr)
+        return false;
+    
+    /* set absolute start address */
+    IssueSetAddress(ptr, startAddr);
+    IssueSimpleCommand(ptr, DW_LNS_set_prologue_end);
+    
+    int prevLine = 1, prevAddr = 0, prevFile = 0;
+    
+    for (int i = 0; i < nlines; ++i)
+    {
+        /* different source file */
+        if (lines[i].fileIndex != prevFile)
+        {
+            int len = Leb128Encode(static_cast<uint32_t>(lines[i].fileIndex+1), cnv_buf, sizeof(cnv_buf));
+            IssueParamCommand(ptr, DW_LNS_set_file, cnv_buf, len);
+            prevFile = lines[i].fileIndex;
+        }
+        /* too big line number shift */
+        if (lines[i].lineNumber - prevLine > (DWARF_LINE_BASE + DWARF_LINE_RANGE - 1))
+        {
+            int len = Leb128Encode(static_cast<int32_t>(lines[i].lineNumber - prevLine), cnv_buf, sizeof(cnv_buf));
+            IssueParamCommand(ptr, DW_LNS_advance_line, cnv_buf, len);
+            prevLine = lines[i].lineNumber;
+        }
+        /* first try special opcode */
+        if (FitIntoSpecialOpcode(lines[i].lineNumber - prevLine, lines[i].nativeOffset - prevAddr))
+            IssueSpecialCommand(ptr, lines[i].lineNumber - prevLine, lines[i].nativeOffset - prevAddr);
+        else
+        {
+            IssueSetAddress(ptr, startAddr + lines[i].nativeOffset);
+            IssueSpecialCommand(ptr, lines[i].lineNumber - prevLine, 0);
+        }
+           
+        prevLine = lines[i].lineNumber;
+        prevAddr = lines[i].nativeOffset;
+    }
+    
+    IssueEndOfSequence(ptr); 
+    
+    buf.MemSize = ptr - buf.MemPtr;
+    return true;
+}
+
+/* Build the DWARF .debug_str section */
+bool NotifyGdb::BuildDebugStrings(MemBuf& buf)
+{
+    uint32_t totalLength = 0;
+    
+    /* calculate total section size */
+    for (int i = 0; i < DebugStringCount; ++i)
+    {
+        totalLength += strlen(DebugStrings[i]) + 1;
+    }
+    
+    buf.MemSize = totalLength;
+    buf.MemPtr = new (nothrow) char[totalLength];
+    
+    if (buf.MemPtr == nullptr)
+        return false;
+
+    /* copy strings */
+    char* bufPtr = buf.MemPtr;
+    for (int i = 0; i < DebugStringCount; ++i)
+    {
+        strcpy(bufPtr, DebugStrings[i]);
+        bufPtr += strlen(DebugStrings[i]) + 1;
+    }
+    
+    return true;
+}
+
+/* Build the DWARF .debug_abbrev section */
+bool NotifyGdb::BuildDebugAbbrev(MemBuf& buf)
+{
+    buf.MemPtr = new (nothrow) char[AbbrevTableSize];
+    buf.MemSize = AbbrevTableSize;
+    
+    if (buf.MemPtr == nullptr)
+        return false;
+    
+    memcpy(buf.MemPtr, AbbrevTable, AbbrevTableSize);
+    return true;
+}
+
+/* Build tge DWARF .debug_info section */
+bool NotifyGdb::BuildDebugInfo(MemBuf& buf)
+{
+    buf.MemSize = sizeof(DwarfCompUnit) + sizeof(DebugInfo) + 1;
+    buf.MemPtr = new (nothrow) char[buf.MemSize];
+
+    if (buf.MemPtr == nullptr)
+        return false;
+    
+    /* Compile uint header */
+    DwarfCompUnit* cu = reinterpret_cast<DwarfCompUnit*>(buf.MemPtr);
+    cu->m_length = buf.MemSize - sizeof(uint32_t);
+    cu->m_version = 4;
+    cu->m_abbrev_offset = 0;
+    cu->m_addr_size = ADDRESS_SIZE;
+    
+    /* copy debug information */
+    DebugInfo* di = reinterpret_cast<DebugInfo*>(buf.MemPtr + sizeof(DwarfCompUnit));
+    memcpy(buf.MemPtr + sizeof(DwarfCompUnit), &debugInfo, sizeof(DebugInfo));
+    di->m_prod_off = 0;
+    di->m_cu_name = strlen(DebugStrings[0]) + 1;
+    di->m_sub_name = strlen(DebugStrings[0]) + 1 + strlen(DebugStrings[1]) + 1 + strlen(DebugStrings[2]) + 1;
+    di->m_type_name = strlen(DebugStrings[0]) + 1 + strlen(DebugStrings[1]) + 1 + strlen(DebugStrings[2]) + 1 + strlen(DebugStrings[3]) + 1;
+    
+    /* zero end marker */
+    buf.MemPtr[buf.MemSize-1] = 0;
+    return true;
+}
+
+/* Build the DWARF lookup section */
+bool NotifyGdb::BuildDebugPub(MemBuf& buf, const char* name, uint32_t size, uint32_t die_offset)
+{
+    uint32_t length = sizeof(DwarfPubHeader) + sizeof(uint32_t) + strlen(name) + 1 + sizeof(uint32_t);
+    
+    buf.MemSize = length;
+    buf.MemPtr = new (nothrow) char[buf.MemSize];
+    
+    if (buf.MemPtr == nullptr)
+        return false;
+
+    DwarfPubHeader* header = reinterpret_cast<DwarfPubHeader*>(buf.MemPtr);
+    header->m_length = length - sizeof(uint32_t);
+    header->m_version = 2;
+    header->m_debug_info_off = 0;
+    header->m_debug_info_len = size;
+    *reinterpret_cast<uint32_t*>(buf.MemPtr + sizeof(DwarfPubHeader)) = die_offset;
+    strcpy(buf.MemPtr + sizeof(DwarfPubHeader) + sizeof(uint32_t), name);
+    *reinterpret_cast<uint32_t*>(buf.MemPtr + length - sizeof(uint32_t)) = 0;
+    
+    return true;
+}
+
+/* Build ELF string section */
+bool NotifyGdb::BuildSectionNameTable(MemBuf& buf)
+{
+    uint32_t totalLength = 0;
+    
+    /* calculate total size */
+    for (int i = 0; i < SectionNamesCount; ++i)
+    {
+        totalLength += strlen(SectionNames[i]) + 1;
+    }
+    
+    buf.MemSize = totalLength;
+    buf.MemPtr = new (nothrow) char[totalLength];
+    if (buf.MemPtr == nullptr)
+        return false;
+
+    /* copy strings */
+    char* bufPtr = buf.MemPtr;
+    for (int i = 0; i < SectionNamesCount; ++i)
+    {
+        strcpy(bufPtr, SectionNames[i]);
+        bufPtr += strlen(SectionNames[i]) + 1;
+    }
+    
+    return true;
+}
+
+/* Build the ELF section headers table */
+bool NotifyGdb::BuildSectionTable(MemBuf& buf)
+{
+    Elf_Shdr* sectionHeaders = new (nothrow) Elf_Shdr[SectionNamesCount - 1];    
+    Elf_Shdr* pSh = sectionHeaders;
+
+    if (sectionHeaders == nullptr)
+    {
+        return false;
+    }
+    
+    /* NULL entry */
+    pSh->sh_name = 0;
+    pSh->sh_type = SHT_NULL;
+    pSh->sh_flags = 0;
+    pSh->sh_addr = 0;
+    pSh->sh_offset = 0;
+    pSh->sh_size = 0;
+    pSh->sh_link = SHN_UNDEF;
+    pSh->sh_info = 0;
+    pSh->sh_addralign = 0;
+    pSh->sh_entsize = 0;
+    
+    ++pSh;
+    /* fill section header data */
+    uint32_t sectNameOffset = 1;
+    for (int i = 1; i < SectionNamesCount - 1; ++i, ++pSh)
+    {
+        pSh->sh_name = sectNameOffset;
+        sectNameOffset += strlen(SectionNames[i]) + 1;
+        pSh->sh_type = Sections[i].m_type;
+        pSh->sh_flags = Sections[i].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 = 1;
+        pSh->sh_entsize = 0;
+    }
+
+    buf.MemPtr = reinterpret_cast<char*>(sectionHeaders);
+    buf.MemSize = sizeof(Elf_Shdr) * (SectionNamesCount - 1);
+    return true;
+}
+
+/* Build the ELF header */
+bool NotifyGdb::BuildELFHeader(MemBuf& buf)
+{
+    Elf_Ehdr* header = new (nothrow) Elf_Ehdr;
+    buf.MemPtr = reinterpret_cast<char*>(header);
+    buf.MemSize = sizeof(Elf_Ehdr);
+    
+    if (header == nullptr)
+        return false;
+    
+    return true;
+        
+}
+
+/* Split full path name into directory & file anmes */
+void NotifyGdb::SplitPathname(const char* path, const char*& pathName, const char*& fileName)
+{
+    char* pSlash = strrchr(path, '/');
+    
+    if (pSlash != nullptr)
+    {
+        *pSlash = 0;
+        fileName = ++pSlash;
+        pathName = path;
+    }
+    else 
+    {
+        fileName = path;
+        pathName = nullptr;
+    }
+}
+
+/* LEB128 for 32-bit unsigned integer */
+int NotifyGdb::Leb128Encode(uint32_t num, char* buf, int size)
+{
+    int i = 0;
+    
+    do
+    {
+        uint8_t byte = num & 0x7F;
+        if (i >= size)
+            break;
+        num >>= 7;
+        if (num != 0)
+            byte |= 0x80;
+        buf[i++] = byte;
+    }
+    while (num != 0);
+    
+    return i;
+}
+
+/* LEB128 for 32-bit signed integer */
+int NotifyGdb::Leb128Encode(int32_t num, char* buf, int size)
+{
+    int i = 0;
+    bool hasMore = true, isNegative = num < 0;
+    
+    while (hasMore && i < size)
+    {
+        uint8_t byte = num & 0x7F;
+        num >>= 7;
+        
+        if ((num == 0 && (byte & 0x40) == 0) || (num  == -1 && (byte & 0x40) == 0x40))
+            hasMore = false;
+        else
+            byte |= 0x80;
+        buf[i++] = byte;
+    }
+    
+    return i;
+}
+
+/* ELF 32bit header */
+Elf32_Ehdr::Elf32_Ehdr()
+{
+    e_ident[EI_MAG0] = ELFMAG0;
+    e_ident[EI_MAG1] = ELFMAG1;
+    e_ident[EI_MAG2] = ELFMAG2;
+    e_ident[EI_MAG3] = ELFMAG3;
+    e_ident[EI_CLASS] = ELFCLASS32;
+    e_ident[EI_DATA] = ELFDATA2LSB;
+    e_ident[EI_VERSION] = EV_CURRENT;
+    e_ident[EI_OSABI] = ELFOSABI_SYSV;
+    e_ident[EI_ABIVERSION] = 0;
+    for (int i = EI_PAD; i < EI_NIDENT; ++i)
+        e_ident[i] = 0;
+
+    e_type = ET_REL;
+#if defined(_TARGET_X86_)
+    e_machine = EM_386;
+#elif defined(_TARGET_ARM_)
+    e_machine = EM_ARM;
+#endif    
+    e_flags = 0;
+    e_version = 1;
+    e_entry = 0;
+    e_phoff = 0;
+    e_ehsize = sizeof(Elf32_Ehdr);
+    e_phentsize = 0;
+    e_phnum = 0;
+}
+
+/* ELF 64bit header */
+Elf64_Ehdr::Elf64_Ehdr()
+{
+    e_ident[EI_MAG0] = ELFMAG0;
+    e_ident[EI_MAG1] = ELFMAG1;
+    e_ident[EI_MAG2] = ELFMAG2;
+    e_ident[EI_MAG3] = ELFMAG3;
+    e_ident[EI_CLASS] = ELFCLASS64;
+    e_ident[EI_DATA] = ELFDATA2LSB;
+    e_ident[EI_VERSION] = EV_CURRENT;
+    e_ident[EI_OSABI] = ELFOSABI_SYSV;
+    e_ident[EI_ABIVERSION] = 0;
+    for (int i = EI_PAD; i < EI_NIDENT; ++i)
+        e_ident[i] = 0;
+
+    e_type = ET_REL;
+#if defined(_TARGET_AMD64_)
+    e_machine = EM_X86_64;
+#elif defined(_TARGET_ARM64_)
+    e_machine = EM_AARCH64;
+#endif
+    e_flags = 0;
+    e_version = 1;
+    e_entry = 0;
+    e_phoff = 0;
+    e_ehsize = sizeof(Elf64_Ehdr);
+    e_phentsize = 0;
+    e_phnum = 0;
+}
diff --git a/src/vm/gdbjit.h b/src/vm/gdbjit.h
new file mode 100644 (file)
index 0000000..16850cd
--- /dev/null
@@ -0,0 +1,523 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//*****************************************************************************
+// File: gdbjit.h
+// 
+
+//
+// Header file for GDB JIT interface implemenation.
+//
+//*****************************************************************************
+
+
+#ifndef __GDBJIT_H__
+#define __GDBJIT_H__
+
+#include <stdint.h>
+#include "method.hpp"
+
+/* Type for a 16-bit quantity.  */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities.  */
+typedef uint32_t Elf32_Word;
+typedef        int32_t  Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef        int32_t  Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities.  */
+typedef uint64_t Elf32_Xword;
+typedef        int64_t  Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef        int64_t  Elf64_Sxword;
+
+/* Type of addresses.  */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets.  */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities.  */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* The ELF file header.  This appears at the start of every ELF file.  */
+
+#define EI_NIDENT (16)
+
+struct  Elf32_Ehdr
+{
+  unsigned char        e_ident[EI_NIDENT];     /* Magic number and other info */
+  Elf32_Half   e_type;                 /* Object file type */
+  Elf32_Half   e_machine;              /* Architecture */
+  Elf32_Word   e_version;              /* Object file version */
+  Elf32_Addr   e_entry;                /* Entry point virtual address */
+  Elf32_Off    e_phoff;                /* Program header table file offset */
+  Elf32_Off    e_shoff;                /* Section header table file offset */
+  Elf32_Word   e_flags;                /* Processor-specific flags */
+  Elf32_Half   e_ehsize;               /* ELF header size in bytes */
+  Elf32_Half   e_phentsize;            /* Program header table entry size */
+  Elf32_Half   e_phnum;                /* Program header table entry count */
+  Elf32_Half   e_shentsize;            /* Section header table entry size */
+  Elf32_Half   e_shnum;                /* Section header table entry count */
+  Elf32_Half   e_shstrndx;             /* Section header string table index */
+  Elf32_Ehdr();
+};
+
+struct  Elf64_Ehdr
+{
+  unsigned char        e_ident[EI_NIDENT];     /* Magic number and other info */
+  Elf64_Half   e_type;                 /* Object file type */
+  Elf64_Half   e_machine;              /* Architecture */
+  Elf64_Word   e_version;              /* Object file version */
+  Elf64_Addr   e_entry;                /* Entry point virtual address */
+  Elf64_Off    e_phoff;                /* Program header table file offset */
+  Elf64_Off    e_shoff;                /* Section header table file offset */
+  Elf64_Word   e_flags;                /* Processor-specific flags */
+  Elf64_Half   e_ehsize;               /* ELF header size in bytes */
+  Elf64_Half   e_phentsize;            /* Program header table entry size */
+  Elf64_Half   e_phnum;                /* Program header table entry count */
+  Elf64_Half   e_shentsize;            /* Section header table entry size */
+  Elf64_Half   e_shnum;                /* Section header table entry count */
+  Elf64_Half   e_shstrndx;             /* Section header string table index */
+  Elf64_Ehdr();
+};
+
+#define EI_MAG0                0               /* File identification byte 0 index */
+#define ELFMAG0                0x7f            /* Magic number byte 0 */
+
+#define EI_MAG1                1               /* File identification byte 1 index */
+#define ELFMAG1                'E'             /* Magic number byte 1 */
+
+#define EI_MAG2                2               /* File identification byte 2 index */
+#define ELFMAG2                'L'             /* Magic number byte 2 */
+
+#define EI_MAG3                3               /* File identification byte 3 index */
+#define ELFMAG3                'F'             /* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word.  */
+#define        ELFMAG          "\177ELF"
+#define        SELFMAG         4
+
+#define EI_CLASS       4               /* File class byte index */
+#define ELFCLASSNONE   0               /* Invalid class */
+#define ELFCLASS32     1               /* 32-bit objects */
+#define ELFCLASS64     2               /* 64-bit objects */
+#define ELFCLASSNUM    3
+
+#define EI_DATA                5               /* Data encoding byte index */
+#define ELFDATANONE    0               /* Invalid data encoding */
+#define ELFDATA2LSB    1               /* 2's complement, little endian */
+#define ELFDATA2MSB    2               /* 2's complement, big endian */
+#define ELFDATANUM     3
+
+#define EI_VERSION     6               /* File version byte index */
+                                       /* Value must be EV_CURRENT */
+
+#define EI_OSABI       7               /* OS ABI identification */
+#define ELFOSABI_NONE          0       /* UNIX System V ABI */
+#define ELFOSABI_SYSV          0       /* Alias.  */
+#define ELFOSABI_HPUX          1       /* HP-UX */
+#define ELFOSABI_NETBSD                2       /* NetBSD.  */
+#define ELFOSABI_GNU           3       /* Object uses GNU ELF extensions.  */
+#define ELFOSABI_LINUX         ELFOSABI_GNU /* Compatibility alias.  */
+#define ELFOSABI_SOLARIS       6       /* Sun Solaris.  */
+#define ELFOSABI_AIX           7       /* IBM AIX.  */
+#define ELFOSABI_IRIX          8       /* SGI Irix.  */
+#define ELFOSABI_FREEBSD       9       /* FreeBSD.  */
+#define ELFOSABI_TRU64         10      /* Compaq TRU64 UNIX.  */
+#define ELFOSABI_MODESTO       11      /* Novell Modesto.  */
+#define ELFOSABI_OPENBSD       12      /* OpenBSD.  */
+#define ELFOSABI_ARM_AEABI     64      /* ARM EABI */
+#define ELFOSABI_ARM           97      /* ARM */
+#define ELFOSABI_STANDALONE    255     /* Standalone (embedded) application */
+
+#define EI_ABIVERSION  8               /* ABI version */
+
+#define EI_PAD         9               /* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type).  */
+
+#define ET_NONE                0               /* No file type */
+#define ET_REL         1               /* Relocatable file */
+#define ET_EXEC                2               /* Executable file */
+#define ET_DYN         3               /* Shared object file */
+#define ET_CORE                4               /* Core file */
+#define        ET_NUM          5               /* Number of defined types */
+#define ET_LOOS                0xfe00          /* OS-specific range start */
+#define ET_HIOS                0xfeff          /* OS-specific range end */
+#define ET_LOPROC      0xff00          /* Processor-specific range start */
+#define ET_HIPROC      0xffff          /* Processor-specific range end */
+
+/* Legal values for e_machine (architecture).  */
+
+#define EM_NONE                 0              /* No machine */
+#define EM_M32          1              /* AT&T WE 32100 */
+#define EM_SPARC        2              /* SUN SPARC */
+#define EM_386          3              /* Intel 80386 */
+#define EM_68K          4              /* Motorola m68k family */
+#define EM_88K          5              /* Motorola m88k family */
+#define EM_860          7              /* Intel 80860 */
+#define EM_MIPS                 8              /* MIPS R3000 big-endian */
+#define EM_S370                 9              /* IBM System/370 */
+#define EM_MIPS_RS3_LE 10              /* MIPS R3000 little-endian */
+
+#define EM_PARISC      15              /* HPPA */
+#define EM_VPP500      17              /* Fujitsu VPP500 */
+#define EM_SPARC32PLUS 18              /* Sun's "v8plus" */
+#define EM_960         19              /* Intel 80960 */
+#define EM_PPC         20              /* PowerPC */
+#define EM_PPC64       21              /* PowerPC 64-bit */
+#define EM_S390                22              /* IBM S390 */
+
+#define EM_V800                36              /* NEC V800 series */
+#define EM_FR20                37              /* Fujitsu FR20 */
+#define EM_RH32                38              /* TRW RH-32 */
+#define EM_RCE         39              /* Motorola RCE */
+#define EM_ARM         40              /* ARM */
+#define EM_FAKE_ALPHA  41              /* Digital Alpha */
+#define EM_SH          42              /* Hitachi SH */
+#define EM_SPARCV9     43              /* SPARC v9 64-bit */
+#define EM_TRICORE     44              /* Siemens Tricore */
+#define EM_ARC         45              /* Argonaut RISC Core */
+#define EM_H8_300      46              /* Hitachi H8/300 */
+#define EM_H8_300H     47              /* Hitachi H8/300H */
+#define EM_H8S         48              /* Hitachi H8S */
+#define EM_H8_500      49              /* Hitachi H8/500 */
+#define EM_IA_64       50              /* Intel Merced */
+#define EM_MIPS_X      51              /* Stanford MIPS-X */
+#define EM_COLDFIRE    52              /* Motorola Coldfire */
+#define EM_68HC12      53              /* Motorola M68HC12 */
+#define EM_MMA         54              /* Fujitsu MMA Multimedia Accelerator*/
+#define EM_PCP         55              /* Siemens PCP */
+#define EM_NCPU                56              /* Sony nCPU embeeded RISC */
+#define EM_NDR1                57              /* Denso NDR1 microprocessor */
+#define EM_STARCORE    58              /* Motorola Start*Core processor */
+#define EM_ME16                59              /* Toyota ME16 processor */
+#define EM_ST100       60              /* STMicroelectronic ST100 processor */
+#define EM_TINYJ       61              /* Advanced Logic Corp. Tinyj emb.fam*/
+#define EM_X86_64      62              /* AMD x86-64 architecture */
+#define EM_PDSP                63              /* Sony DSP Processor */
+
+#define EM_FX66                66              /* Siemens FX66 microcontroller */
+#define EM_ST9PLUS     67              /* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7         68              /* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16      69              /* Motorola MC68HC16 microcontroller */
+#define EM_68HC11      70              /* Motorola MC68HC11 microcontroller */
+#define EM_68HC08      71              /* Motorola MC68HC08 microcontroller */
+#define EM_68HC05      72              /* Motorola MC68HC05 microcontroller */
+#define EM_SVX         73              /* Silicon Graphics SVx */
+#define EM_ST19                74              /* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX         75              /* Digital VAX */
+#define EM_CRIS                76              /* Axis Communications 32-bit embedded processor */
+#define EM_JAVELIN     77              /* Infineon Technologies 32-bit embedded processor */
+#define EM_FIREPATH    78              /* Element 14 64-bit DSP Processor */
+#define EM_ZSP         79              /* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX                80              /* Donald Knuth's educational 64-bit processor */
+#define EM_HUANY       81              /* Harvard University machine-independent object files */
+#define EM_PRISM       82              /* SiTera Prism */
+#define EM_AVR         83              /* Atmel AVR 8-bit microcontroller */
+#define EM_FR30                84              /* Fujitsu FR30 */
+#define EM_D10V                85              /* Mitsubishi D10V */
+#define EM_D30V                86              /* Mitsubishi D30V */
+#define EM_V850                87              /* NEC v850 */
+#define EM_M32R                88              /* Mitsubishi M32R */
+#define EM_MN10300     89              /* Matsushita MN10300 */
+#define EM_MN10200     90              /* Matsushita MN10200 */
+#define EM_PJ          91              /* picoJava */
+#define EM_OPENRISC    92              /* OpenRISC 32-bit embedded processor */
+#define EM_ARC_A5      93              /* ARC Cores Tangent-A5 */
+#define EM_XTENSA      94              /* Tensilica Xtensa Architecture */
+#define EM_AARCH64     183             /* ARM AARCH64 */
+#define EM_TILEPRO     188             /* Tilera TILEPro */
+#define EM_MICROBLAZE  189             /* Xilinx MicroBlaze */
+#define EM_TILEGX      191             /* Tilera TILE-Gx */
+#define EM_NUM         192
+
+#define EV_NONE                0               /* Invalid ELF version */
+#define EV_CURRENT     1               /* Current version */
+#define EV_NUM         2
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_ARM_RELEXEC         0x01
+#define EF_ARM_HASENTRY                0x02
+#define EF_ARM_INTERWORK       0x04
+#define EF_ARM_APCS_26         0x08
+#define EF_ARM_APCS_FLOAT      0x10
+#define EF_ARM_PIC             0x20
+#define EF_ARM_ALIGN8          0x40 /* 8-bit structure alignment is in use */
+#define EF_ARM_NEW_ABI         0x80
+#define EF_ARM_OLD_ABI         0x100
+#define EF_ARM_SOFT_FLOAT      0x200
+#define EF_ARM_VFP_FLOAT       0x400
+#define EF_ARM_MAVERICK_FLOAT  0x800
+
+#define EF_ARM_EABI_VERSION(flags)     ((flags) & EF_ARM_EABIMASK)
+#define EF_ARM_EABI_UNKNOWN    0x00000000
+#define EF_ARM_EABI_VER1       0x01000000
+#define EF_ARM_EABI_VER2       0x02000000
+#define EF_ARM_EABI_VER3       0x03000000
+#define EF_ARM_EABI_VER4       0x04000000
+#define EF_ARM_EABI_VER5       0x05000000
+
+
+/* Section header.  */
+
+typedef struct
+{
+  Elf32_Word   sh_name;                /* Section name (string tbl index) */
+  Elf32_Word   sh_type;                /* Section type */
+  Elf32_Word   sh_flags;               /* Section flags */
+  Elf32_Addr   sh_addr;                /* Section virtual addr at execution */
+  Elf32_Off    sh_offset;              /* Section file offset */
+  Elf32_Word   sh_size;                /* Section size in bytes */
+  Elf32_Word   sh_link;                /* Link to another section */
+  Elf32_Word   sh_info;                /* Additional section information */
+  Elf32_Word   sh_addralign;           /* Section alignment */
+  Elf32_Word   sh_entsize;             /* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+  Elf64_Word   sh_name;                /* Section name (string tbl index) */
+  Elf64_Word   sh_type;                /* Section type */
+  Elf64_Xword  sh_flags;               /* Section flags */
+  Elf64_Addr   sh_addr;                /* Section virtual addr at execution */
+  Elf64_Off    sh_offset;              /* Section file offset */
+  Elf64_Xword  sh_size;                /* Section size in bytes */
+  Elf64_Word   sh_link;                /* Link to another section */
+  Elf64_Word   sh_info;                /* Additional section information */
+  Elf64_Xword  sh_addralign;           /* Section alignment */
+  Elf64_Xword  sh_entsize;             /* Entry size if section holds table */
+} Elf64_Shdr;
+
+/* Special section indices.  */
+
+#define SHN_UNDEF      0               /* Undefined section */
+#define SHN_LORESERVE  0xff00          /* Start of reserved indices */
+#define SHN_LOPROC     0xff00          /* Start of processor-specific */
+#define SHN_BEFORE     0xff00          /* Order section before all others
+                                          (Solaris).  */
+#define SHN_AFTER      0xff01          /* Order section after all others
+                                          (Solaris).  */
+#define SHN_HIPROC     0xff1f          /* End of processor-specific */
+#define SHN_LOOS       0xff20          /* Start of OS-specific */
+#define SHN_HIOS       0xff3f          /* End of OS-specific */
+#define SHN_ABS                0xfff1          /* Associated symbol is absolute */
+#define SHN_COMMON     0xfff2          /* Associated symbol is common */
+#define SHN_XINDEX     0xffff          /* Index is in extra table.  */
+#define SHN_HIRESERVE  0xffff          /* End of reserved indices */
+
+/* Legal values for sh_type (section type).  */
+
+#define SHT_NULL         0             /* Section header table entry unused */
+#define SHT_PROGBITS     1             /* Program data */
+#define SHT_SYMTAB       2             /* Symbol table */
+#define SHT_STRTAB       3             /* String table */
+#define SHT_RELA         4             /* Relocation entries with addends */
+#define SHT_HASH         5             /* Symbol hash table */
+#define SHT_DYNAMIC      6             /* Dynamic linking information */
+#define SHT_NOTE         7             /* Notes */
+#define SHT_NOBITS       8             /* Program space with no data (bss) */
+#define SHT_REL                  9             /* Relocation entries, no addends */
+#define SHT_SHLIB        10            /* Reserved */
+#define SHT_DYNSYM       11            /* Dynamic linker symbol table */
+#define SHT_INIT_ARRAY   14            /* Array of constructors */
+#define SHT_FINI_ARRAY   15            /* Array of destructors */
+#define SHT_PREINIT_ARRAY 16           /* Array of pre-constructors */
+#define SHT_GROUP        17            /* Section group */
+#define SHT_SYMTAB_SHNDX  18           /* Extended section indeces */
+#define        SHT_NUM           19            /* Number of defined types.  */
+#define SHT_LOOS         0x60000000    /* Start OS-specific.  */
+#define SHT_GNU_ATTRIBUTES 0x6ffffff5  /* Object attributes.  */
+#define SHT_GNU_HASH     0x6ffffff6    /* GNU-style hash table.  */
+#define SHT_GNU_LIBLIST          0x6ffffff7    /* Prelink library list */
+#define SHT_CHECKSUM     0x6ffffff8    /* Checksum for DSO content.  */
+#define SHT_LOSUNW       0x6ffffffa    /* Sun-specific low bound.  */
+#define SHT_SUNW_move    0x6ffffffa
+#define SHT_SUNW_COMDAT   0x6ffffffb
+#define SHT_SUNW_syminfo  0x6ffffffc
+#define SHT_GNU_verdef   0x6ffffffd    /* Version definition section.  */
+#define SHT_GNU_verneed          0x6ffffffe    /* Version needs section.  */
+#define SHT_GNU_versym   0x6fffffff    /* Version symbol table.  */
+#define SHT_HISUNW       0x6fffffff    /* Sun-specific high bound.  */
+#define SHT_HIOS         0x6fffffff    /* End OS-specific type */
+#define SHT_LOPROC       0x70000000    /* Start of processor-specific */
+#define SHT_HIPROC       0x7fffffff    /* End of processor-specific */
+#define SHT_LOUSER       0x80000000    /* Start of application-specific */
+#define SHT_HIUSER       0x8fffffff    /* End of application-specific */
+
+/* Legal values for sh_flags (section flags).  */
+
+#define SHF_WRITE           (1 << 0)   /* Writable */
+#define SHF_ALLOC           (1 << 1)   /* Occupies memory during execution */
+#define SHF_EXECINSTR       (1 << 2)   /* Executable */
+#define SHF_MERGE           (1 << 4)   /* Might be merged */
+#define SHF_STRINGS         (1 << 5)   /* Contains nul-terminated strings */
+#define SHF_INFO_LINK       (1 << 6)   /* `sh_info' contains SHT index */
+#define SHF_LINK_ORDER      (1 << 7)   /* Preserve order after combining */
+#define SHF_OS_NONCONFORMING (1 << 8)  /* Non-standard OS specific handling
+                                          required */
+#define SHF_GROUP           (1 << 9)   /* Section is member of a group.  */
+#define SHF_TLS                     (1 << 10)  /* Section hold thread-local data.  */
+#define SHF_MASKOS          0x0ff00000 /* OS-specific.  */
+#define SHF_MASKPROC        0xf0000000 /* Processor-specific */
+#define SHF_ORDERED         (1 << 30)  /* Special ordering requirement
+                                          (Solaris).  */
+#define SHF_EXCLUDE         (1 << 31)  /* Section is excluded unless
+                                          referenced or allocated (Solaris).*/
+
+#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
+    typedef Elf32_Ehdr  Elf_Ehdr;
+    typedef Elf32_Shdr  Elf_Shdr;
+#define ADDRESS_SIZE 4    
+#elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
+    typedef Elf64_Ehdr  Elf_Ehdr;
+    typedef Elf64_Shdr  Elf_Shdr;
+#define ADDRESS_SIZE 8    
+#else
+#error "Target is not supported"
+#endif
+
+
+#define DW_TAG_compile_unit             0x11
+#define DW_TAG_subprogram               0x2e
+#define DW_TAG_base_type                0x24
+
+#define DW_children_no                  0
+#define DW_children_yes                 1
+
+#define DW_AT_name                              0x03
+#define DW_AT_byte_size                         0x0b
+#define DW_AT_stmt_list                         0x10
+#define DW_AT_language                          0x13
+#define DW_AT_producer                          0x25
+#define DW_AT_decl_file                         0x3a
+#define DW_AT_decl_line                         0x3b
+#define DW_AT_encoding                          0x3e
+#define DW_AT_external                          0x3f
+#define DW_AT_type                              0x49
+
+#define DW_FORM_data2                   0x05
+#define DW_FORM_data1                   0x0b
+#define DW_FORM_strp                    0x0e
+#define DW_FORM_ref4                    0x13
+#define DW_FORM_sec_offset              0x17
+#define DW_FORM_flag_present            0x19
+
+/* Line number standard opcode name. */
+#define DW_LNS_copy                     0x01
+#define DW_LNS_advance_pc               0x02
+#define DW_LNS_advance_line             0x03
+#define DW_LNS_set_file                 0x04
+#define DW_LNS_set_column               0x05
+#define DW_LNS_negate_stmt              0x06
+#define DW_LNS_set_basic_block          0x07
+#define DW_LNS_const_add_pc             0x08
+#define DW_LNS_fixed_advance_pc         0x09
+#define DW_LNS_set_prologue_end         0x0a /* DWARF3 */
+#define DW_LNS_set_epilogue_begin       0x0b /* DWARF3 */
+#define DW_LNS_set_isa                  0x0c /* DWARF3 */
+
+/* Line number extended opcode name. */
+#define DW_LNE_end_sequence             0x01
+#define DW_LNE_set_address              0x02
+#define DW_LNE_define_file              0x03
+#define DW_LNE_set_discriminator        0x04  /* DWARF4 */
+
+#define DW_LANG_C89                     0x0001
+
+#define DW_ATE_address                  0x1
+#define DW_ATE_boolean                  0x2
+#define DW_ATE_complex_float            0x3
+#define DW_ATE_float                    0x4
+#define DW_ATE_signed                   0x5
+#define DW_ATE_signed_char              0x6
+#define DW_ATE_unsigned                 0x7
+#define DW_ATE_unsigned_char            0x8
+#define DW_ATE_imaginary_float          0x9  /* DWARF3 */
+#define DW_ATE_packed_decimal           0xa  /* DWARF3f */
+#define DW_ATE_numeric_string           0xb  /* DWARF3f */
+#define DW_ATE_edited                   0xc  /* DWARF3f */
+#define DW_ATE_signed_fixed             0xd  /* DWARF3f */
+#define DW_ATE_unsigned_fixed           0xe  /* DWARF3f */
+#define DW_ATE_decimal_float            0xf  /* DWARF3f */
+
+struct __attribute__((packed)) DwarfCompUnit
+{
+    uint32_t m_length;
+    uint16_t m_version;
+    uint32_t m_abbrev_offset;
+    uint8_t m_addr_size;
+};
+
+struct __attribute__((packed)) DwarfPubHeader
+{
+    uint32_t m_length;
+    uint16_t m_version;
+    uint32_t m_debug_info_off;
+    uint32_t m_debug_info_len;
+};
+
+#define DW_LNS_MAX DW_LNS_set_isa
+
+struct __attribute__((packed)) DwarfLineNumHeader
+{
+    uint32_t m_length;
+    uint16_t m_version;
+    uint32_t m_hdr_length;
+    uint8_t m_min_instr_len;
+    uint8_t m_def_is_stmt;
+    int8_t m_line_base;
+    uint8_t m_line_range;
+    uint8_t m_opcode_base;
+    uint8_t m_std_num_arg[DW_LNS_MAX];
+};
+
+struct SymbolsInfo
+{
+    int lineNumber, ilOffset, nativeOffset, fileIndex;
+    char fileName[2*MAX_PATH_FNAME];
+};
+
+
+class NotifyGdb
+{
+public:
+    static void MethodCompiled(MethodDesc* MethodDescPtr);
+    static void MethodDropped(MethodDesc* MethodDescPtr);
+private:
+    struct MemBuf
+    {
+        char* MemPtr;
+        unsigned MemSize;
+        MemBuf() : MemPtr(0), MemSize(0)
+        {}
+    };
+
+    static bool BuildELFHeader(MemBuf& buf);
+    static bool BuildSectionNameTable(MemBuf& buf);
+    static bool BuildSectionTable(MemBuf& buf);
+    static bool BuildDebugStrings(MemBuf& buf);
+    static bool BuildDebugAbbrev(MemBuf& buf);    
+    static bool BuildDebugInfo(MemBuf& buf);
+    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 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 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);
+};
+
+#endif // #ifndef __GDBJIT_H__
index 7a05624..703564e 100644 (file)
@@ -3359,6 +3359,10 @@ void InitializeClrNotifications()
 #pragma optimize("", off)
 #endif  // _MSC_VER
 
+#if defined(FEATURE_GDBJIT)
+#include "gdbjit.h"
+#endif // FEATURE_GDBJIT
+
 // called from the runtime
 void DACNotify::DoJITNotification(MethodDesc *MethodDescPtr)
 {
@@ -3370,7 +3374,9 @@ void DACNotify::DoJITNotification(MethodDesc *MethodDescPtr)
         MODE_PREEMPTIVE;
     }
     CONTRACTL_END;
-
+#if defined(FEATURE_GDBJIT) && defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
+    NotifyGdb::MethodCompiled(MethodDescPtr);
+#endif    
     TADDR Args[2] = { JIT_NOTIFICATION, (TADDR) MethodDescPtr };
     DACNotifyExceptionHelper(Args, 2);
 }
@@ -3386,6 +3392,9 @@ void DACNotify::DoJITDiscardNotification(MethodDesc *MethodDescPtr)
     }
     CONTRACTL_END;
 
+#if defined(FEATURE_GDBJIT) && defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
+    NotifyGdb::MethodDropped(MethodDescPtr);
+#endif    
     TADDR Args[2] = { JIT_DISCARD_NOTIFICATION, (TADDR) MethodDescPtr };
     DACNotifyExceptionHelper(Args, 2);
 }