--- /dev/null
+// 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;
+}
--- /dev/null
+// 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__