1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
9 // NotifyGdb implementation.
11 //*****************************************************************************
14 #include "formattype.h"
16 #include "gdbjithelpers.h"
18 __declspec(thread) bool tls_isSymReaderInProgress = false;
21 static void DumpElf(const char* methodName, const char *addr, size_t size)
23 char dump[1024] = { 0, };
25 strcat(dump, methodName);
28 FILE *f = fopen(dump, "wb");
29 fwrite(addr, sizeof(char), size, f);
35 GetTypeInfoFromTypeHandle(TypeHandle typeHandle,
36 NotifyGdb::PTK_TypeInfoMap pTypeMap,
37 FunctionMemberPtrArrayHolder &method)
39 TypeInfoBase *foundTypeInfo = nullptr;
40 TypeKey key = typeHandle.GetTypeKey();
41 PTR_MethodTable pMT = typeHandle.GetMethodTable();
43 if (pTypeMap->Lookup(&key, &foundTypeInfo))
48 CorElementType corType = typeHandle.GetSignatureCorElementType();
53 case ELEMENT_TYPE_CHAR:
54 case ELEMENT_TYPE_VOID:
55 case ELEMENT_TYPE_BOOLEAN:
67 NewHolder<PrimitiveTypeInfo> typeInfo = new PrimitiveTypeInfo(typeHandle);
68 pTypeMap->Add(typeInfo->GetTypeKey(), typeInfo);
69 typeInfo.SuppressRelease();
72 case ELEMENT_TYPE_VALUETYPE:
73 case ELEMENT_TYPE_CLASS:
75 ApproxFieldDescIterator fieldDescIterator(pMT,
76 pMT->IsString() ? ApproxFieldDescIterator::INSTANCE_FIELDS : ApproxFieldDescIterator::ALL_FIELDS);
77 ULONG cFields = fieldDescIterator.Count();
79 NewHolder<ClassTypeInfo> typeInfo = new ClassTypeInfo(typeHandle, cFields, method);
81 NewHolder<RefTypeInfo> refTypeInfo = nullptr;
82 if (!typeHandle.IsValueType())
84 refTypeInfo = new NamedRefTypeInfo(typeHandle, typeInfo);
85 typeInfo.SuppressRelease();
87 pTypeMap->Add(refTypeInfo->GetTypeKey(), refTypeInfo);
88 refTypeInfo.SuppressRelease();
92 pTypeMap->Add(typeInfo->GetTypeKey(), typeInfo);
93 typeInfo.SuppressRelease();
97 // Now fill in the array
101 for (ULONG i = 0; i < cFields; i++)
103 pField = fieldDescIterator.Next();
105 LPCUTF8 szName = pField->GetName();
106 typeInfo->members[i].m_member_name = new char[strlen(szName) + 1];
107 strcpy(typeInfo->members[i].m_member_name, szName);
108 if (!pField->IsStatic())
110 typeInfo->members[i].m_member_offset = (ULONG)pField->GetOffset();
111 if (!typeHandle.IsValueType())
112 typeInfo->members[i].m_member_offset += Object::GetOffsetOfFirstField();
117 MethodTable* pMT = pField->GetEnclosingMethodTable();
118 base = pField->GetBase();
120 // TODO: add support of generics with static fields
121 if (pField->IsRVA() || !pMT->IsDynamicStatics())
123 PTR_VOID pAddress = pField->GetStaticAddressHandle((PTR_VOID)dac_cast<TADDR>(base));
124 typeInfo->members[i].m_static_member_address = dac_cast<TADDR>(pAddress);
128 typeInfo->members[i].m_member_type =
129 GetTypeInfoFromTypeHandle(pField->GetExactFieldType(typeHandle), pTypeMap, method);
131 // handle the System.String case:
132 // coerce type of the second field into array type
133 if (pMT->IsString() && i == 1)
135 TypeInfoBase* elemTypeInfo = typeInfo->members[1].m_member_type;
136 typeInfo->m_array_type = new ArrayTypeInfo(typeHandle.MakeSZArray(), 1, elemTypeInfo);
137 typeInfo->members[1].m_member_type = typeInfo->m_array_type;
140 // Ignore inheritance from System.Object and System.ValueType classes.
141 if (!typeHandle.IsValueType() &&
142 pMT->GetParentMethodTable() && pMT->GetParentMethodTable()->GetParentMethodTable())
144 typeInfo->m_parent = GetTypeInfoFromTypeHandle(typeHandle.GetParent(), pTypeMap, method);
152 case ELEMENT_TYPE_PTR:
153 case ELEMENT_TYPE_BYREF:
155 TypeInfoBase* valTypeInfo = GetTypeInfoFromTypeHandle(typeHandle.GetTypeParam(), pTypeMap, method);
156 NewHolder<RefTypeInfo> typeInfo = new RefTypeInfo(typeHandle, valTypeInfo);
158 typeInfo->m_type_offset = valTypeInfo->m_type_offset;
160 pTypeMap->Add(typeInfo->GetTypeKey(), typeInfo);
161 typeInfo.SuppressRelease();
164 case ELEMENT_TYPE_ARRAY:
165 case ELEMENT_TYPE_SZARRAY:
167 NewHolder<ClassTypeInfo> info = new ClassTypeInfo(typeHandle, pMT->GetRank() == 1 ? 2 : 3, method);
168 NewHolder<RefTypeInfo> refTypeInfo = new NamedRefTypeInfo(typeHandle, info);
169 info.SuppressRelease();
171 pTypeMap->Add(refTypeInfo->GetTypeKey(), refTypeInfo);
172 refTypeInfo.SuppressRelease();
174 TypeInfoBase* lengthTypeInfo = GetTypeInfoFromTypeHandle(
175 TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_I4)), pTypeMap, method);
177 TypeInfoBase* valTypeInfo = GetTypeInfoFromTypeHandle(typeHandle.GetTypeParam(), pTypeMap, method);
178 info->m_array_type = new ArrayTypeInfo(typeHandle, 1, valTypeInfo);
180 info->members[0].m_member_name = new char[16];
181 strcpy(info->members[0].m_member_name, "m_NumComponents");
182 info->members[0].m_member_offset = ArrayBase::GetOffsetOfNumComponents();
183 info->members[0].m_member_type = lengthTypeInfo;
185 info->members[1].m_member_name = new char[7];
186 strcpy(info->members[1].m_member_name, "m_Data");
187 info->members[1].m_member_offset = ArrayBase::GetDataPtrOffset(pMT);
188 info->members[1].m_member_type = info->m_array_type;
190 if (pMT->GetRank() != 1)
192 TypeHandle dwordArray(MscorlibBinder::GetElementType(ELEMENT_TYPE_I4));
193 info->m_array_bounds_type = new ArrayTypeInfo(dwordArray.MakeSZArray(), pMT->GetRank(), lengthTypeInfo);
194 info->members[2].m_member_name = new char[9];
195 strcpy(info->members[2].m_member_name, "m_Bounds");
196 info->members[2].m_member_offset = ArrayBase::GetBoundsOffset(pMT);
197 info->members[2].m_member_type = info->m_array_bounds_type;
203 COMPlusThrowHR(COR_E_NOTSUPPORTED);
207 TypeInfoBase* GetArgTypeInfo(MethodDesc* methodDescPtr,
208 NotifyGdb::PTK_TypeInfoMap pTypeMap,
210 FunctionMemberPtrArrayHolder &method)
212 MetaSig sig(methodDescPtr);
216 th = sig.GetRetTypeHandleNT();
224 th = sig.GetLastTypeHandleNT();
226 return GetTypeInfoFromTypeHandle(th, pTypeMap, method);
229 TypeInfoBase* GetLocalTypeInfo(MethodDesc *methodDescPtr,
230 NotifyGdb::PTK_TypeInfoMap pTypeMap,
232 FunctionMemberPtrArrayHolder &funcs)
234 COR_ILMETHOD_DECODER method(methodDescPtr->GetILHeader());
235 if (method.GetLocalVarSigTok())
238 PCCOR_SIGNATURE pComSig;
240 if (FAILED(methodDescPtr->GetMDImport()->GetSigFromToken(method.GetLocalVarSigTok(), &cbSigLen, &pComSig)))
242 printf("\nInvalid record");
246 _ASSERTE(*pComSig == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG);
248 SigTypeContext typeContext(methodDescPtr, TypeHandle());
249 MetaSig sig(pComSig, cbSigLen, methodDescPtr->GetModule(), &typeContext, MetaSig::sigLocalVars);
256 TypeHandle th = sig.GetLastTypeHandleNT();
257 return GetTypeInfoFromTypeHandle(th, pTypeMap, funcs);
262 HRESULT GetArgNameByILIndex(MethodDesc* methodDescPtr, unsigned index, NewArrayHolder<char> ¶mName)
264 IMDInternalImport* mdImport = methodDescPtr->GetMDImport();
265 mdParamDef paramToken;
270 // Param indexing is 1-based.
271 ULONG32 mdIndex = index + 1;
273 MetaSig sig(methodDescPtr);
278 status = mdImport->FindParamOfMethod(methodDescPtr->GetMemberDef(), mdIndex, ¶mToken);
282 status = mdImport->GetParamDefProps(paramToken, &seq, &attr, &name);
283 paramName = new char[strlen(name) + 1];
284 strcpy(paramName, name);
289 // Copy-pasted from src/debug/di/module.cpp
290 HRESULT FindNativeInfoInILVariable(DWORD dwIndex,
292 ICorDebugInfo::NativeVarInfo* nativeInfoList,
293 unsigned int nativeInfoCount,
294 ICorDebugInfo::NativeVarInfo** ppNativeInfo)
296 _ASSERTE(ppNativeInfo != NULL);
297 *ppNativeInfo = NULL;
298 int lastGoodOne = -1;
299 for (unsigned int i = 0; i < (unsigned)nativeInfoCount; i++)
301 if (nativeInfoList[i].varNumber == dwIndex)
303 if ((lastGoodOne == -1) || (nativeInfoList[lastGoodOne].startOffset < nativeInfoList[i].startOffset))
308 if ((nativeInfoList[i].startOffset <= ip) &&
309 (nativeInfoList[i].endOffset > ip))
311 *ppNativeInfo = &(nativeInfoList[i]);
318 if ((lastGoodOne > -1) && (nativeInfoList[lastGoodOne].endOffset == ip))
320 *ppNativeInfo = &(nativeInfoList[lastGoodOne]);
324 return CORDBG_E_IL_VAR_NOT_AVAILABLE;
327 BYTE* DebugInfoStoreNew(void * pData, size_t cBytes)
329 return new BYTE[cBytes];
332 /* Get IL to native offsets map */
334 GetMethodNativeMap(MethodDesc* methodDesc,
336 NewArrayHolder<DebuggerILToNativeMap> &map,
338 ICorDebugInfo::NativeVarInfo** ppVars)
340 // Use the DebugInfoStore to get IL->Native maps.
341 // It doesn't matter whether we're jitted, ngenned etc.
343 DebugInfoRequest request;
344 TADDR nativeCodeStartAddr = PCODEToPINSTR(methodDesc->GetNativeCode());
345 request.InitFromStartingAddr(methodDesc, nativeCodeStartAddr);
348 ULONG32 countMapCopy;
349 NewHolder<ICorDebugInfo::OffsetMapping> mapCopy(NULL);
351 BOOL success = DebugInfoManager::GetBoundariesAndVars(request,
364 // Need to convert map formats.
365 *numMap = countMapCopy;
367 map = new DebuggerILToNativeMap[countMapCopy];
370 for (i = 0; i < *numMap; i++)
372 map[i].ilOffset = mapCopy[i].ilOffset;
373 map[i].nativeStartOffset = mapCopy[i].nativeOffset;
376 map[i - 1].nativeEndOffset = map[i].nativeStartOffset;
378 map[i].source = mapCopy[i].source;
382 map[i - 1].nativeEndOffset = 0;
387 HRESULT FunctionMember::GetLocalsDebugInfo(NotifyGdb::PTK_TypeInfoMap pTypeMap,
389 int startNativeOffset,
390 FunctionMemberPtrArrayHolder &method)
393 ICorDebugInfo::NativeVarInfo* nativeVar = NULL;
401 for (i = 0; i < m_num_args - thisOffs; i++)
403 if (FindNativeInfoInILVariable(i + thisOffs, startNativeOffset, locals.vars, locals.countVars, &nativeVar) == S_OK)
405 vars[i + thisOffs].m_var_type = GetArgTypeInfo(md, pTypeMap, i + 1, method);
406 GetArgNameByILIndex(md, i + thisOffs, vars[i + thisOffs].m_var_name);
407 vars[i + thisOffs].m_il_index = i;
408 vars[i + thisOffs].m_native_offset = nativeVar->loc.vlStk.vlsOffset;
409 vars[i + thisOffs].m_var_abbrev = 6;
412 //Add info about 'this' as first argument
415 if (FindNativeInfoInILVariable(0, startNativeOffset, locals.vars, locals.countVars, &nativeVar) == S_OK)
417 TypeHandle th = TypeHandle(md->GetMethodTable());
418 if (th.IsValueType())
419 th = th.MakePointer();
420 vars[0].m_var_type = GetTypeInfoFromTypeHandle(th, pTypeMap, method);
421 vars[0].m_var_name = new char[strlen("this") + 1];
422 strcpy(vars[0].m_var_name, "this");
423 vars[0].m_il_index = 0;
424 vars[0].m_native_offset = nativeVar->loc.vlStk.vlsOffset;
425 vars[0].m_var_abbrev = 13;
429 for (; i < m_num_vars; i++)
431 if (FindNativeInfoInILVariable(
432 i, startNativeOffset, locals.vars, locals.countVars, &nativeVar) == S_OK)
434 int ilIndex = i - m_num_args;
435 vars[i].m_var_type = GetLocalTypeInfo(md, pTypeMap, ilIndex, method);
436 vars[i].m_var_name = new char[strlen(locals.localsName[ilIndex]) + 1];
437 strcpy(vars[i].m_var_name, locals.localsName[ilIndex]);
438 vars[i].m_il_index = ilIndex;
439 vars[i].m_native_offset = nativeVar->loc.vlStk.vlsOffset;
440 vars[i].m_var_abbrev = 5;
443 int ilLen = locals.localsScope[ilIndex].ilEndOffset - locals.localsScope[ilIndex].ilStartOffset;
444 if (GetBlockInNativeCode(locals.localsScope[ilIndex].ilStartOffset, ilLen, &nativeStart, &nativeEnd))
446 vars[i].m_low_pc = md->GetNativeCode() + nativeStart;
447 vars[i].m_high_pc = nativeEnd - nativeStart;
454 MethodDebugInfo::MethodDebugInfo(int numPoints, int numLocals)
456 points = (SequencePointInfo*) CoTaskMemAlloc(sizeof(SequencePointInfo) * numPoints);
457 if (points == nullptr)
461 memset(points, 0, sizeof(SequencePointInfo) * numPoints);
471 locals = (LocalVarInfo*) CoTaskMemAlloc(sizeof(LocalVarInfo) * numLocals);
472 if (locals == nullptr)
474 CoTaskMemFree(points);
477 memset(locals, 0, sizeof(LocalVarInfo) * numLocals);
478 localsSize = numLocals;
481 MethodDebugInfo::~MethodDebugInfo()
485 for (int i = 0; i < localsSize; i++)
486 CoTaskMemFree(locals[i].name);
487 CoTaskMemFree(locals);
490 for (int i = 0; i < size; i++)
491 CoTaskMemFree(points[i].fileName);
492 CoTaskMemFree(points);
495 /* Get mapping of IL offsets to source line numbers */
497 GetDebugInfoFromPDB(MethodDesc* methodDescPtr,
498 NewArrayHolder<SymbolsInfo> &symInfo,
499 unsigned int &symInfoLen,
502 NewArrayHolder<DebuggerILToNativeMap> map;
505 if (!getInfoForMethodDelegate)
508 if (GetMethodNativeMap(methodDescPtr, &numMap, map, &locals.countVars, &locals.vars) != S_OK)
511 const Module* mod = methodDescPtr->GetMethodTable()->GetModule();
512 SString modName = mod->GetFile()->GetPath();
513 if (modName.IsEmpty())
516 StackScratchBuffer scratch;
517 const char* szModName = modName.GetUTF8(scratch);
519 MethodDebugInfo methodDebugInfo(numMap, locals.countVars);
521 if (getInfoForMethodDelegate(szModName, methodDescPtr->GetMemberDef(), methodDebugInfo) == FALSE)
525 symInfo = new SymbolsInfo[numMap];
527 locals.size = methodDebugInfo.localsSize;
528 locals.localsName = new NewArrayHolder<char>[locals.size];
529 locals.localsScope = new LocalsInfo::Scope [locals.size];
531 for (ULONG32 i = 0; i < locals.size; i++)
533 size_t sizeRequired = WideCharToMultiByte(CP_UTF8, 0, methodDebugInfo.locals[i].name, -1, NULL, 0, NULL, NULL);
534 locals.localsName[i] = new char[sizeRequired];
536 int len = WideCharToMultiByte(
537 CP_UTF8, 0, methodDebugInfo.locals[i].name, -1, locals.localsName[i], sizeRequired, NULL, NULL);
538 locals.localsScope[i].ilStartOffset = methodDebugInfo.locals[i].startOffset;
539 locals.localsScope[i].ilEndOffset = methodDebugInfo.locals[i].endOffset;
542 for (ULONG32 j = 0; j < numMap; j++)
544 SymbolsInfo& s = symInfo[j];
553 s.nativeOffset = map[j].nativeStartOffset;
554 s.ilOffset = map[j].ilOffset;
555 s.source = map[j].source;
558 for (ULONG32 i = 0; i < methodDebugInfo.size; i++)
560 const SequencePointInfo& sp = methodDebugInfo.points[i];
562 if (methodDebugInfo.points[i].ilOffset == map[j].ilOffset)
565 int len = WideCharToMultiByte(CP_UTF8, 0, sp.fileName, -1, s.fileName, sizeof(s.fileName), NULL, NULL);
567 s.lineNumber = sp.lineNumber;
576 /* LEB128 for 32-bit unsigned integer */
577 int Leb128Encode(uint32_t num, char* buf, int size)
583 uint8_t byte = num & 0x7F;
596 /* LEB128 for 32-bit signed integer */
597 int Leb128Encode(int32_t num, char* buf, int size)
600 bool hasMore = true, isNegative = num < 0;
602 while (hasMore && i < size)
604 uint8_t byte = num & 0x7F;
607 if ((num == 0 && (byte & 0x40) == 0) || (num == -1 && (byte & 0x40) == 0x40))
617 int GetFrameLocation(int nativeOffset, char* bufVarLoc)
619 char cnvBuf[16] = {0};
620 int len = Leb128Encode(static_cast<int32_t>(nativeOffset), cnvBuf, sizeof(cnvBuf));
621 bufVarLoc[0] = len + 1;
622 bufVarLoc[1] = DW_OP_fbreg;
623 for (int j = 0; j < len; j++)
625 bufVarLoc[j + 2] = cnvBuf[j];
628 return len + 2; // We add '2' because first 2 bytes contain length of expression and DW_OP_fbreg operation.
639 struct jit_code_entry
641 struct jit_code_entry *next_entry;
642 struct jit_code_entry *prev_entry;
643 const char *symfile_addr;
647 struct jit_descriptor
650 /* This type should be jit_actions_t, but we use uint32_t
651 to be explicit about the bitwidth. */
653 struct jit_code_entry *relevant_entry;
654 struct jit_code_entry *first_entry;
656 // GDB puts a breakpoint in this function.
657 // To prevent from inlining we add noinline attribute and inline assembler statement.
659 void __attribute__((noinline)) __jit_debug_register_code() { __asm__(""); };
661 /* Make sure to specify the version statically, because the
662 debugger may check the version before we can set it. */
663 struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
664 static CrstStatic g_jitDescriptorCrst;
666 // END of GDB JIT interface
671 DebugStringsCU(const char *module, const char *path)
672 : m_producerName("CoreCLR"),
673 m_moduleName(module),
676 m_moduleNameOffset(0),
681 int GetProducerOffset() const { return m_producerOffset; }
682 int GetModuleNameOffset() const { return m_moduleNameOffset; }
683 int GetModuleDirOffset() const { return m_moduleDirOffset; }
685 void DumpStrings(char *ptr, int &offset)
687 m_producerOffset = offset;
688 DumpString(m_producerName, ptr, offset);
690 m_moduleNameOffset = offset;
691 DumpString(m_moduleName, ptr, offset);
693 m_moduleDirOffset = offset;
694 DumpString(m_moduleDir, ptr, offset);
698 const char* m_producerName;
699 const char* m_moduleName;
700 const char* m_moduleDir;
702 int m_producerOffset;
703 int m_moduleNameOffset;
704 int m_moduleDirOffset;
706 static void DumpString(const char *str, char *ptr, int &offset)
710 strcpy(ptr + offset, str);
712 offset += strlen(str) + 1;
716 /* Static data for .debug_abbrev */
717 const unsigned char AbbrevTable[] = {
718 1, DW_TAG_compile_unit, DW_CHILDREN_yes,
719 DW_AT_producer, DW_FORM_strp, DW_AT_language, DW_FORM_data2, DW_AT_name, DW_FORM_strp, DW_AT_comp_dir, DW_FORM_strp,
720 DW_AT_stmt_list, DW_FORM_sec_offset, 0, 0,
722 2, DW_TAG_base_type, DW_CHILDREN_no,
723 DW_AT_name, DW_FORM_strp, DW_AT_encoding, DW_FORM_data1, DW_AT_byte_size, DW_FORM_data1, 0, 0,
725 3, DW_TAG_typedef, DW_CHILDREN_no, DW_AT_name, DW_FORM_strp,
726 DW_AT_type, DW_FORM_ref4, 0, 0,
728 4, DW_TAG_subprogram, DW_CHILDREN_yes,
729 DW_AT_name, DW_FORM_strp, DW_AT_linkage_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1,
730 DW_AT_type, DW_FORM_ref4, DW_AT_external, DW_FORM_flag_present,
731 DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc, DW_FORM_size,
732 DW_AT_frame_base, DW_FORM_exprloc, 0, 0,
734 5, DW_TAG_variable, DW_CHILDREN_no,
735 DW_AT_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1, DW_AT_type,
736 DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc, 0, 0,
738 6, DW_TAG_formal_parameter, DW_CHILDREN_no,
739 DW_AT_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1, DW_AT_type,
740 DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc, 0, 0,
742 7, DW_TAG_class_type, DW_CHILDREN_yes,
743 DW_AT_name, DW_FORM_strp, DW_AT_byte_size, DW_FORM_data4, 0, 0,
745 8, DW_TAG_member, DW_CHILDREN_no,
746 DW_AT_name, DW_FORM_strp, DW_AT_type, DW_FORM_ref4, DW_AT_data_member_location, DW_FORM_data4, 0, 0,
748 9, DW_TAG_pointer_type, DW_CHILDREN_no,
749 DW_AT_type, DW_FORM_ref4, DW_AT_byte_size, DW_FORM_data1, 0, 0,
751 10, DW_TAG_array_type, DW_CHILDREN_yes,
752 DW_AT_type, DW_FORM_ref4, 0, 0,
754 11, DW_TAG_subrange_type, DW_CHILDREN_no,
755 DW_AT_upper_bound, DW_FORM_exprloc, 0, 0,
757 12, DW_TAG_subprogram, DW_CHILDREN_yes,
758 DW_AT_name, DW_FORM_strp, DW_AT_linkage_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1,
759 DW_AT_type, DW_FORM_ref4, DW_AT_external, DW_FORM_flag_present,
760 DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc, DW_FORM_size,
761 DW_AT_frame_base, DW_FORM_exprloc, DW_AT_object_pointer, DW_FORM_ref4, 0, 0,
763 13, DW_TAG_formal_parameter, DW_CHILDREN_no,
764 DW_AT_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1, DW_AT_type,
765 DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc, DW_AT_artificial, DW_FORM_flag_present, 0, 0,
767 14, DW_TAG_member, DW_CHILDREN_no,
768 DW_AT_name, DW_FORM_strp, DW_AT_type, DW_FORM_ref4, DW_AT_external, DW_FORM_flag_present, 0, 0,
770 15, DW_TAG_variable, DW_CHILDREN_no, DW_AT_specification, DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc,
773 16, DW_TAG_try_block, DW_CHILDREN_no,
774 DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc, DW_FORM_size,
777 17, DW_TAG_catch_block, DW_CHILDREN_no,
778 DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc, DW_FORM_size,
781 18, DW_TAG_inheritance, DW_CHILDREN_no, DW_AT_type, DW_FORM_ref4, DW_AT_data_member_location, DW_FORM_data1,
784 19, DW_TAG_subrange_type, DW_CHILDREN_no,
785 DW_AT_upper_bound, DW_FORM_udata, 0, 0,
787 20, DW_TAG_lexical_block, DW_CHILDREN_yes,
788 DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc, DW_FORM_size,
794 const int AbbrevTableSize = sizeof(AbbrevTable);
796 /* Static data for .debug_line, including header */
797 #define DWARF_LINE_BASE (-5)
798 #define DWARF_LINE_RANGE 14
799 #define DWARF_OPCODE_BASE 13
801 #ifdef FEATURE_GDBJIT_LANGID_CS
802 /* TODO: use corresponding constant when it will be added to llvm */
803 #define DW_LANG_MICROSOFT_CSHARP 0x9e57
806 DwarfLineNumHeader LineNumHeader = {
807 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}
810 /* Static data for .debug_info */
811 struct __attribute__((packed)) DebugInfoCU
820 #ifdef FEATURE_GDBJIT_LANGID_CS
821 1, 0, DW_LANG_MICROSOFT_CSHARP, 0, 0
823 1, 0, DW_LANG_C89, 0, 0
827 struct __attribute__((packed)) DebugInfoTryCatchSub
829 uint8_t m_sub_abbrev;
830 uintptr_t m_sub_low_pc, m_sub_high_pc;
833 struct __attribute__((packed)) DebugInfoSub
835 uint8_t m_sub_abbrev;
837 uint32_t m_linkage_name;
838 uint8_t m_file, m_line;
840 uintptr_t m_sub_low_pc, m_sub_high_pc;
841 uint8_t m_sub_loc[2];
844 struct __attribute__((packed)) DebugInfoSubMember
850 struct __attribute__((packed)) DebugInfoLexicalBlock
853 uintptr_t m_low_pc, m_high_pc;
856 // Holder for array of pointers to FunctionMember objects
857 class FunctionMemberPtrArrayHolder : public NewArrayHolder<NewHolder<FunctionMember>>
863 explicit FunctionMemberPtrArrayHolder(int cElements) :
864 NewArrayHolder<NewHolder<FunctionMember>>(new NewHolder<FunctionMember>[cElements]),
865 m_cElements(cElements)
875 struct __attribute__((packed)) DebugInfoType
877 uint8_t m_type_abbrev;
878 uint32_t m_type_name;
883 struct __attribute__((packed)) DebugInfoVar
885 uint8_t m_var_abbrev;
887 uint8_t m_var_file, m_var_line;
891 struct __attribute__((packed)) DebugInfoTypeDef
893 uint8_t m_typedef_abbrev;
894 uint32_t m_typedef_name;
895 uint32_t m_typedef_type;
898 struct __attribute__((packed)) DebugInfoClassType
900 uint8_t m_type_abbrev;
901 uint32_t m_type_name;
902 uint32_t m_byte_size;
905 struct __attribute__((packed)) DebugInfoInheritance
909 uint8_t m_data_member_location;
912 struct __attribute__((packed)) DebugInfoClassMember
914 uint8_t m_member_abbrev;
915 uint32_t m_member_name;
916 uint32_t m_member_type;
919 struct __attribute__((packed)) DebugInfoStaticMember
921 uint8_t m_member_abbrev;
922 uint32_t m_member_specification;
926 struct __attribute__((packed)) DebugInfoRefType
928 uint8_t m_type_abbrev;
933 struct __attribute__((packed)) DebugInfoArrayType
939 void TypeInfoBase::DumpStrings(char* ptr, int& offset)
943 strcpy(ptr + offset, m_type_name);
944 m_type_name_offset = offset;
946 offset += strlen(m_type_name) + 1;
949 void TypeInfoBase::CalculateName()
954 const TypeString::FormatFlags formatFlags = static_cast<TypeString::FormatFlags>(
955 TypeString::FormatNamespace |
956 TypeString::FormatAngleBrackets);
958 TypeString::AppendType(sName, typeHandle, formatFlags);
960 StackScratchBuffer buffer;
961 const UTF8 *utf8 = sName.GetUTF8(buffer);
962 if (typeHandle.IsValueType())
964 m_type_name = new char[strlen(utf8) + 1];
965 strcpy(m_type_name, utf8);
969 m_type_name = new char[strlen(utf8) + 1 + 2];
970 strcpy(m_type_name, "__");
971 strcpy(m_type_name + 2, utf8);
975 for (char *p = m_type_name; *p; ++p)
982 void TypeInfoBase::SetTypeHandle(TypeHandle handle)
985 typeKey = handle.GetTypeKey();
988 TypeHandle TypeInfoBase::GetTypeHandle()
993 TypeKey* TypeInfoBase::GetTypeKey()
998 void TypeDefInfo::DumpStrings(char *ptr, int &offset)
1002 strcpy(ptr + offset, m_typedef_name);
1003 m_typedef_name_offset = offset;
1005 offset += strlen(m_typedef_name) + 1;
1008 void TypeDefInfo::DumpDebugInfo(char *ptr, int &offset)
1010 if (m_is_visited && m_base_ptr == ptr)
1016 m_is_visited = true;
1020 DebugInfoTypeDef buf;
1021 buf.m_typedef_abbrev = 3;
1022 buf.m_typedef_name = m_typedef_name_offset;
1023 buf.m_typedef_type = offset + sizeof(DebugInfoTypeDef);
1024 m_typedef_type_offset = offset;
1026 memcpy(ptr + offset,
1028 sizeof(DebugInfoTypeDef));
1031 offset += sizeof(DebugInfoTypeDef);
1034 static const char *GetCSharpTypeName(TypeInfoBase *typeInfo)
1036 switch(typeInfo->GetTypeHandle().GetSignatureCorElementType())
1038 case ELEMENT_TYPE_I1: return "sbyte";
1039 case ELEMENT_TYPE_U1: return "byte";
1040 case ELEMENT_TYPE_CHAR: return "char";
1041 case ELEMENT_TYPE_VOID: return "void";
1042 case ELEMENT_TYPE_BOOLEAN: return "bool";
1043 case ELEMENT_TYPE_I2: return "short";
1044 case ELEMENT_TYPE_U2: return "ushort";
1045 case ELEMENT_TYPE_I4: return "int";
1046 case ELEMENT_TYPE_U4: return "uint";
1047 case ELEMENT_TYPE_I8: return "long";
1048 case ELEMENT_TYPE_U8: return "ulong";
1049 case ELEMENT_TYPE_R4: return "float";
1050 case ELEMENT_TYPE_R8: return "double";
1051 default: return typeInfo->m_type_name;
1055 PrimitiveTypeInfo::PrimitiveTypeInfo(TypeHandle typeHandle)
1056 : TypeInfoBase(typeHandle),
1057 m_typedef_info(new TypeDefInfo(nullptr, 0))
1059 CorElementType corType = typeHandle.GetSignatureCorElementType();
1060 m_type_encoding = CorElementTypeToDWEncoding[corType];
1061 m_type_size = CorTypeInfo::Size(corType);
1063 if (corType == ELEMENT_TYPE_CHAR)
1065 m_type_name = new char[9];
1066 strcpy(m_type_name, "char16_t");
1074 void PrimitiveTypeInfo::DumpStrings(char* ptr, int& offset)
1076 TypeInfoBase::DumpStrings(ptr, offset);
1077 if (!m_typedef_info->m_typedef_name)
1079 const char *typeName = GetCSharpTypeName(this);
1080 m_typedef_info->m_typedef_name = new char[strlen(typeName) + 1];
1081 strcpy(m_typedef_info->m_typedef_name, typeName);
1083 m_typedef_info->DumpStrings(ptr, offset);
1086 void PrimitiveTypeInfo::DumpDebugInfo(char *ptr, int &offset)
1088 if (m_is_visited && m_base_ptr == ptr)
1094 m_is_visited = true;
1096 m_typedef_info->DumpDebugInfo(ptr, offset);
1100 DebugInfoType bufType;
1101 bufType.m_type_abbrev = 2;
1102 bufType.m_type_name = m_type_name_offset;
1103 bufType.m_encoding = m_type_encoding;
1104 bufType.m_byte_size = m_type_size;
1106 memcpy(ptr + offset,
1108 sizeof(DebugInfoType));
1110 // Replace offset from real type to typedef
1111 m_type_offset = m_typedef_info->m_typedef_type_offset;
1114 offset += sizeof(DebugInfoType);
1117 ClassTypeInfo::ClassTypeInfo(TypeHandle typeHandle, int num_members, FunctionMemberPtrArrayHolder &method)
1118 : TypeInfoBase(typeHandle),
1119 m_num_members(num_members),
1120 members(new TypeMember[num_members]),
1123 m_array_type(nullptr)
1125 CorElementType corType = typeHandle.GetSignatureCorElementType();
1126 PTR_MethodTable pMT = typeHandle.GetMethodTable();
1130 case ELEMENT_TYPE_VALUETYPE:
1131 case ELEMENT_TYPE_CLASS:
1132 m_type_size = pMT->IsValueType() ? typeHandle.GetSize() : typeHandle.AsMethodTable()->GetBaseSize();
1134 case ELEMENT_TYPE_ARRAY:
1135 case ELEMENT_TYPE_SZARRAY:
1136 m_type_size = pMT->GetClass()->GetSize();
1145 void TypeMember::DumpStrings(char* ptr, int& offset)
1149 strcpy(ptr + offset, m_member_name);
1150 m_member_name_offset = offset;
1152 offset += strlen(m_member_name) + 1;
1155 void TypeMember::DumpDebugInfo(char* ptr, int& offset)
1159 DebugInfoClassMember memberEntry;
1161 if (m_static_member_address == 0)
1162 memberEntry.m_member_abbrev = 8;
1165 memberEntry.m_member_abbrev = 14;
1166 m_member_offset = offset;
1168 memberEntry.m_member_name = m_member_name_offset;
1169 memberEntry.m_member_type = m_member_type->m_type_offset;
1171 memcpy(ptr + offset, &memberEntry, sizeof(DebugInfoClassMember));
1172 if (m_static_member_address == 0)
1173 memcpy(ptr + offset + sizeof(DebugInfoClassMember), &m_member_offset, sizeof(m_member_offset));
1175 offset += sizeof(DebugInfoClassMember);
1176 if (m_static_member_address == 0)
1177 offset += sizeof(m_member_offset);
1180 void TypeMember::DumpStaticDebugInfo(char* ptr, int& offset)
1182 const int ptrSize = sizeof(TADDR);
1183 const int valueTypeBufSize = ptrSize + 6;
1184 const int refTypeBufSize = ptrSize + 2;
1186 bool isValueType = m_member_type->GetTypeHandle().GetSignatureCorElementType() ==
1187 ELEMENT_TYPE_VALUETYPE;
1191 bufSize = valueTypeBufSize;
1195 bufSize = refTypeBufSize;
1200 DebugInfoStaticMember memberEntry;
1202 memberEntry.m_member_abbrev = 15;
1203 memberEntry.m_member_specification = m_member_offset;
1204 memcpy(ptr + offset, &memberEntry, sizeof(DebugInfoStaticMember));
1206 // for value type static fields compute address as:
1207 // addr = (*addr+sizeof(OBJECTREF))
1210 char buf[valueTypeBufSize] = {0};
1211 buf[0] = ptrSize + 5;
1212 buf[1] = DW_OP_addr;
1214 for (int i = 0; i < ptrSize; i++)
1216 buf[i + 2] = m_static_member_address >> (i * 8);
1219 buf[ptrSize + 2] = DW_OP_deref;
1220 buf[ptrSize + 3] = DW_OP_const1u;
1221 buf[ptrSize + 4] = sizeof(OBJECTREF);
1222 buf[ptrSize + 5] = DW_OP_plus;
1224 memcpy(ptr + offset + sizeof(DebugInfoStaticMember), &buf, bufSize);
1228 char buf[refTypeBufSize] = {0};
1229 buf[0] = ptrSize + 1;
1230 buf[1] = DW_OP_addr;
1232 for (int i = 0; i < ptrSize; i++)
1234 buf[i + 2] = m_static_member_address >> (i * 8);
1237 memcpy(ptr + offset + sizeof(DebugInfoStaticMember), &buf, bufSize);
1240 offset += sizeof(DebugInfoStaticMember);
1244 void FunctionMember::MangleName(char *buf, int &buf_offset, const char *name)
1246 int name_length = strlen(name);
1249 int tmp_len = sprintf_s(tmp, _countof(tmp), "%i", name_length);
1254 strncpy(buf + buf_offset, tmp, tmp_len);
1255 buf_offset += tmp_len;
1259 for (int i = 0; i < name_length; i++)
1262 bool valid = (c >= 'a' && c <= 'z') ||
1263 (c >= 'A' && c <= 'Z') ||
1264 (c >= '0' && c <= '9');
1265 *(buf + buf_offset + i) = valid ? c : '_';
1268 buf_offset += name_length;
1271 void FunctionMember::DumpMangledNamespaceAndMethod(char *buf, int &offset, const char *nspace, const char *mname)
1273 static const char *begin_mangled = "_ZN";
1274 static const char *end_mangled = "Ev";
1275 static const int begin_mangled_len = strlen(begin_mangled);
1276 static const int end_mangled_len = strlen(end_mangled);
1279 strncpy(buf + offset, begin_mangled, begin_mangled_len);
1280 offset += begin_mangled_len;
1282 MangleName(buf, offset, nspace);
1283 MangleName(buf, offset, mname);
1286 strncpy(buf + offset, end_mangled, end_mangled_len);
1287 offset += end_mangled_len;
1294 void FunctionMember::DumpLinkageName(char* ptr, int& offset)
1296 SString namespaceOrClassName;
1299 md->GetMethodInfoNoSig(namespaceOrClassName, methodName);
1300 SString utf8namespaceOrClassName;
1301 SString utf8methodName;
1302 namespaceOrClassName.ConvertToUTF8(utf8namespaceOrClassName);
1303 methodName.ConvertToUTF8(utf8methodName);
1305 const char *nspace = utf8namespaceOrClassName.GetUTF8NoConvert();
1306 const char *mname = utf8methodName.GetUTF8NoConvert();
1308 if (!nspace || !mname)
1310 m_linkage_name_offset = 0;
1314 m_linkage_name_offset = offset;
1315 DumpMangledNamespaceAndMethod(ptr, offset, nspace, mname);
1318 void FunctionMember::DumpStrings(char* ptr, int& offset)
1320 TypeMember::DumpStrings(ptr, offset);
1322 for (int i = 0; i < m_num_vars; ++i)
1324 vars[i].DumpStrings(ptr, offset);
1327 DumpLinkageName(ptr, offset);
1330 bool FunctionMember::GetBlockInNativeCode(int blockILOffset, int blockILLen, TADDR *startOffset, TADDR *endOffset)
1332 PCODE pCode = md->GetNativeCode();
1334 const int blockILEnd = blockILOffset + blockILLen;
1339 bool inBlock = false;
1341 for (int i = 0; i < nlines; ++i)
1343 TADDR nativeOffset = lines[i].nativeOffset + pCode;
1345 // Limit block search to current function addresses
1346 if (nativeOffset < m_sub_low_pc)
1348 if (nativeOffset >= m_sub_low_pc + m_sub_high_pc)
1351 // Skip invalid IL offsets
1352 switch(lines[i].ilOffset)
1354 case ICorDebugInfo::PROLOG:
1355 case ICorDebugInfo::EPILOG:
1356 case ICorDebugInfo::NO_MAPPING:
1362 // Check if current IL is within block
1363 if (blockILOffset <= lines[i].ilOffset && lines[i].ilOffset < blockILEnd)
1367 *startOffset = lines[i].nativeOffset;
1375 *endOffset = lines[i].nativeOffset;
1384 *endOffset = m_sub_low_pc + m_sub_high_pc - pCode;
1387 return *endOffset != *startOffset;
1390 void FunctionMember::DumpTryCatchBlock(char* ptr, int& offset, int ilOffset, int ilLen, int abbrev)
1395 if (!GetBlockInNativeCode(ilOffset, ilLen, &startOffset, &endOffset))
1400 DebugInfoTryCatchSub subEntry;
1402 subEntry.m_sub_abbrev = abbrev;
1403 subEntry.m_sub_low_pc = md->GetNativeCode() + startOffset;
1404 subEntry.m_sub_high_pc = endOffset - startOffset;
1406 memcpy(ptr + offset, &subEntry, sizeof(DebugInfoTryCatchSub));
1408 offset += sizeof(DebugInfoTryCatchSub);
1411 void FunctionMember::DumpTryCatchDebugInfo(char* ptr, int& offset)
1416 COR_ILMETHOD *pHeader = md->GetILHeader();
1417 COR_ILMETHOD_DECODER header(pHeader);
1419 unsigned ehCount = header.EHCount();
1421 for (unsigned e = 0; e < ehCount; e++)
1423 IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehBuff;
1424 const IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;
1426 ehInfo = header.EH->EHClause(e, &ehBuff);
1428 DumpTryCatchBlock(ptr, offset, ehInfo->TryOffset, ehInfo->TryLength, 16);
1429 DumpTryCatchBlock(ptr, offset, ehInfo->HandlerOffset, ehInfo->HandlerLength, 17);
1433 void FunctionMember::DumpVarsWithScopes(char *ptr, int &offset)
1435 NewArrayHolder<DebugInfoLexicalBlock> scopeStack = new DebugInfoLexicalBlock[m_num_vars];
1437 int scopeStackSize = 0;
1438 for (int i = 0; i < m_num_vars; ++i)
1440 if (vars[i].m_high_pc == 0) // no scope info
1442 vars[i].DumpDebugInfo(ptr, offset);
1446 // Try to step out to enclosing scope, finilizing scopes on the way
1447 while (scopeStackSize > 0 &&
1448 vars[i].m_low_pc >= (scopeStack[scopeStackSize - 1].m_low_pc +
1449 scopeStack[scopeStackSize - 1].m_high_pc))
1454 memset(ptr + offset, 0, 1);
1460 // Continue adding to prev scope?
1461 if (scopeStackSize > 0 &&
1462 scopeStack[scopeStackSize - 1].m_low_pc == vars[i].m_low_pc &&
1463 scopeStack[scopeStackSize - 1].m_high_pc == vars[i].m_high_pc)
1465 vars[i].DumpDebugInfo(ptr, offset);
1470 scopeStack[scopeStackSize - 1].m_abbrev = 20;
1471 scopeStack[scopeStackSize - 1].m_low_pc = vars[i].m_low_pc;
1472 scopeStack[scopeStackSize - 1].m_high_pc = vars[i].m_high_pc;
1476 memcpy(ptr + offset, scopeStack + (scopeStackSize - 1), sizeof(DebugInfoLexicalBlock));
1478 offset += sizeof(DebugInfoLexicalBlock);
1480 vars[i].DumpDebugInfo(ptr, offset);
1482 // Finalize any remaining scopes
1483 while (scopeStackSize > 0)
1487 memset(ptr + offset, 0, 1);
1495 void FunctionMember::DumpDebugInfo(char* ptr, int& offset)
1499 DebugInfoSub subEntry;
1501 subEntry.m_sub_abbrev = 4;
1502 subEntry.m_sub_name = m_member_name_offset;
1503 subEntry.m_linkage_name = m_linkage_name_offset;
1504 subEntry.m_file = m_file;
1505 subEntry.m_line = m_line;
1506 subEntry.m_sub_type = m_member_type->m_type_offset;
1507 subEntry.m_sub_low_pc = m_sub_low_pc;
1508 subEntry.m_sub_high_pc = m_sub_high_pc;
1509 subEntry.m_sub_loc[0] = m_sub_loc[0];
1510 subEntry.m_sub_loc[1] = m_sub_loc[1];
1512 if (!md->IsStatic())
1514 DebugInfoSubMember subMemberEntry;
1515 subEntry.m_sub_abbrev = 12;
1516 subMemberEntry.sub = subEntry;
1517 subMemberEntry.m_obj_ptr = offset+sizeof(DebugInfoSubMember);
1518 memcpy(ptr + offset, &subMemberEntry, sizeof(DebugInfoSubMember));
1522 memcpy(ptr + offset, &subEntry, sizeof(DebugInfoSub));
1524 m_entry_offset = offset;
1528 if (!md->IsStatic())
1530 offset += sizeof(DebugInfoSubMember);
1534 offset += sizeof(DebugInfoSub);
1537 DumpVarsWithScopes(ptr, offset);
1539 DumpTryCatchDebugInfo(ptr, offset);
1541 // terminate children
1549 int FunctionMember::GetArgsAndLocalsLen()
1554 // Format for DWARF location expression: [expression length][operation][offset in SLEB128 encoding]
1555 for (int i = 0; i < m_num_vars; i++)
1557 locSize += 2; // First byte contains expression length, second byte contains operation (DW_OP_fbreg).
1558 locSize += Leb128Encode(static_cast<int32_t>(vars[i].m_native_offset), tmpBuf, sizeof(tmpBuf));
1563 void ClassTypeInfo::DumpStrings(char* ptr, int& offset)
1565 TypeInfoBase::DumpStrings(ptr, offset);
1567 for (int i = 0; i < m_num_members; ++i)
1569 members[i].DumpStrings(ptr, offset);
1572 if (m_parent != nullptr)
1574 m_parent->DumpStrings(ptr, offset);
1578 void RefTypeInfo::DumpStrings(char* ptr, int& offset)
1580 TypeInfoBase::DumpStrings(ptr, offset);
1581 m_value_type->DumpStrings(ptr, offset);
1584 void RefTypeInfo::DumpDebugInfo(char* ptr, int& offset)
1586 if (m_is_visited && m_base_ptr == ptr)
1592 m_is_visited = true;
1594 m_type_offset = offset;
1595 offset += sizeof(DebugInfoRefType);
1596 m_value_type->DumpDebugInfo(ptr, offset);
1599 DebugInfoRefType refType;
1600 refType.m_type_abbrev = 9;
1601 refType.m_ref_type = m_value_type->m_type_offset;
1602 refType.m_byte_size = m_type_size;
1603 memcpy(ptr + m_type_offset, &refType, sizeof(DebugInfoRefType));
1611 void NamedRefTypeInfo::DumpDebugInfo(char* ptr, int& offset)
1613 if (m_is_visited && m_base_ptr == ptr)
1619 m_is_visited = true;
1621 m_type_offset = offset;
1622 offset += sizeof(DebugInfoRefType) + sizeof(DebugInfoTypeDef);
1623 m_value_type->DumpDebugInfo(ptr, offset);
1626 DebugInfoRefType refType;
1627 refType.m_type_abbrev = 9;
1628 refType.m_ref_type = m_value_type->m_type_offset;
1629 refType.m_byte_size = m_type_size;
1630 memcpy(ptr + m_type_offset, &refType, sizeof(DebugInfoRefType));
1632 DebugInfoTypeDef bugTypeDef;
1633 bugTypeDef.m_typedef_abbrev = 3;
1634 bugTypeDef.m_typedef_name = m_value_type->m_type_name_offset + 2;
1635 bugTypeDef.m_typedef_type = m_type_offset;
1636 memcpy(ptr + m_type_offset + sizeof(DebugInfoRefType), &bugTypeDef, sizeof(DebugInfoTypeDef));
1637 m_type_offset += sizeof(DebugInfoRefType);
1645 void ClassTypeInfo::DumpDebugInfo(char* ptr, int& offset)
1647 if (m_is_visited && m_base_ptr == ptr)
1653 m_is_visited = true;
1655 if (m_parent != nullptr)
1657 m_parent->DumpDebugInfo(ptr, offset);
1660 // make sure that types of all members are dumped
1661 for (int i = 0; i < m_num_members; ++i)
1663 if (members[i].m_member_type != this)
1665 members[i].m_member_type->DumpDebugInfo(ptr, offset);
1671 DebugInfoClassType bufType;
1672 bufType.m_type_abbrev = 7;
1673 bufType.m_type_name = m_type_name_offset;
1674 bufType.m_byte_size = m_type_size;
1676 memcpy(ptr + offset, &bufType, sizeof(DebugInfoClassType));
1677 m_type_offset = offset;
1679 offset += sizeof(DebugInfoClassType);
1681 for (int i = 0; i < m_num_members; ++i)
1683 members[i].DumpDebugInfo(ptr, offset);
1686 for (int i = 0; i < m_method.GetCount(); ++i)
1688 if (m_method[i]->md->GetMethodTable() == GetTypeHandle().GetMethodTable())
1690 // our method is part of this class, we should dump it now before terminating members
1691 m_method[i]->DumpDebugInfo(ptr, offset);
1695 if (m_parent != nullptr)
1699 DebugInfoInheritance buf;
1701 if (RefTypeInfo *m_p = dynamic_cast<RefTypeInfo*>(m_parent))
1702 buf.m_type = m_p->m_value_type->m_type_offset;
1704 buf.m_type = m_parent->m_type_offset;
1705 buf.m_data_member_location = 0;
1706 memcpy(ptr + offset, &buf, sizeof(DebugInfoInheritance));
1708 offset += sizeof(DebugInfoInheritance);
1711 // members terminator
1718 for (int i = 0; i < m_num_members; ++i)
1720 if (members[i].m_static_member_address != 0)
1721 members[i].DumpStaticDebugInfo(ptr, offset);
1725 void ArrayTypeInfo::DumpDebugInfo(char* ptr, int& offset)
1727 if (m_is_visited && m_base_ptr == ptr)
1733 m_is_visited = true;
1735 m_elem_type->DumpDebugInfo(ptr, offset);
1739 DebugInfoArrayType arrType;
1741 arrType.m_abbrev = 10; // DW_TAG_array_type abbrev
1742 arrType.m_type = m_elem_type->m_type_offset;
1744 memcpy(ptr + offset, &arrType, sizeof(DebugInfoArrayType));
1745 m_type_offset = offset;
1747 offset += sizeof(DebugInfoArrayType);
1749 char tmp[16] = { 0 };
1750 int len = Leb128Encode(static_cast<uint32_t>(m_count - 1), tmp + 1, sizeof(tmp) - 1);
1753 tmp[0] = 19; // DW_TAG_subrange_type abbrev with const upper bound
1754 memcpy(ptr + offset, tmp, len + 1);
1760 memset(ptr + offset, 0, 1);
1765 void VarDebugInfo::DumpStrings(char *ptr, int& offset)
1769 strcpy(ptr + offset, m_var_name);
1770 m_var_name_offset = offset;
1772 offset += strlen(m_var_name) + 1;
1775 void VarDebugInfo::DumpDebugInfo(char* ptr, int& offset)
1778 int len = GetFrameLocation(m_native_offset, bufVarLoc);
1781 DebugInfoVar bufVar;
1783 bufVar.m_var_abbrev = m_var_abbrev;
1784 bufVar.m_var_name = m_var_name_offset;
1785 bufVar.m_var_file = 1;
1786 bufVar.m_var_line = 1;
1787 bufVar.m_var_type = m_var_type->m_type_offset;
1788 memcpy(ptr + offset, &bufVar, sizeof(DebugInfoVar));
1789 memcpy(ptr + offset + sizeof(DebugInfoVar), bufVarLoc, len);
1791 offset += sizeof(DebugInfoVar);
1795 /* static data for symbol strings */
1800 int m_section, m_size;
1801 NewArrayHolder<char> m_symbol_name;
1802 Elf_Symbol() : m_name(nullptr), m_off(0), m_value(0), m_section(0), m_size(0) {}
1806 static int countFuncs(T &arr, int n)
1809 for (int i = 0; i < n; i++) {
1810 if (arr[i].ilOffset == ICorDebugInfo::PROLOG)
1819 static int getNextPrologueIndex(int from, T &arr, int n)
1821 for (int i = from; i < n; ++i) {
1822 if (arr[i].ilOffset == ICorDebugInfo::PROLOG)
1830 static NewArrayHolder<WCHAR> g_wszModuleNames;
1831 static DWORD g_cBytesNeeded;
1833 static inline bool isListedModule(const WCHAR *wszModuleFile)
1835 if (g_wszModuleNames == nullptr)
1840 _ASSERTE(g_cBytesNeeded > 0);
1842 BOOL isUserDebug = FALSE;
1844 NewArrayHolder<WCHAR> wszModuleName = new WCHAR[g_cBytesNeeded];
1845 LPWSTR pComma = wcsstr(g_wszModuleNames, W(","));
1846 LPWSTR tmp = g_wszModuleNames;
1848 while (pComma != NULL)
1850 wcsncpy(wszModuleName, tmp, pComma - tmp);
1851 wszModuleName[pComma - tmp] = W('\0');
1853 if (wcscmp(wszModuleName, wszModuleFile) == 0)
1859 pComma = wcsstr(tmp, W(","));
1861 if (isUserDebug == FALSE)
1863 wcsncpy(wszModuleName, tmp, wcslen(tmp));
1864 wszModuleName[wcslen(tmp)] = W('\0');
1865 if (wcscmp(wszModuleName, wszModuleFile) == 0)
1874 static NotifyGdb::AddrSet g_codeAddrs;
1875 static CrstStatic g_codeAddrsCrst;
1877 class Elf_SectionTracker
1880 unsigned int m_Flag;
1883 NewArrayHolder<char> m_NamePtr;
1884 unsigned int m_NameLen;
1895 Elf_SectionTracker *m_Next;
1898 Elf_SectionTracker(const char *name, unsigned ind, unsigned off, uint32_t type, uint64_t flags);
1899 ~Elf_SectionTracker();
1902 bool NeedHeaderUpdate() const;
1903 void DisableHeaderUpdate();
1906 unsigned int GetIndex() const { return m_Ind; }
1907 unsigned int GetOffset() const { return m_Off; }
1908 unsigned int GetSize() const { return m_Len; }
1911 const char *GetName() const { return m_NamePtr; }
1912 unsigned int GetNameLen() const { return m_NameLen; }
1915 Elf_SectionTracker *GetNext(void);
1916 void SetNext(Elf_SectionTracker *next);
1919 void Forward(unsigned int len);
1922 Elf_Shdr *Header(void);
1923 const Elf_Shdr *Header(void) const;
1927 Elf_SectionTracker::Elf_SectionTracker(const char *name,
1928 unsigned ind, unsigned off,
1929 uint32_t type, uint64_t flags)
1940 unsigned int len = strlen(name);
1941 char *ptr = new char[len + 1];
1943 strncpy(ptr, name, len + 1);
1949 m_Hdr.sh_type = type;
1950 m_Hdr.sh_flags = flags;
1953 m_Hdr.sh_offset = 0;
1955 m_Hdr.sh_link = SHN_UNDEF;
1957 m_Hdr.sh_addralign = 1;
1958 m_Hdr.sh_entsize = 0;
1961 Elf_SectionTracker::~Elf_SectionTracker()
1965 #define ESTF_NO_HEADER_UPDATE 0x00000001
1967 bool Elf_SectionTracker::NeedHeaderUpdate() const
1969 return !(m_Flag & ESTF_NO_HEADER_UPDATE);
1972 void Elf_SectionTracker::DisableHeaderUpdate()
1974 m_Flag |= ESTF_NO_HEADER_UPDATE;
1977 void Elf_SectionTracker::Forward(unsigned int len)
1982 void Elf_SectionTracker::SetNext(Elf_SectionTracker *next)
1987 Elf_SectionTracker *Elf_SectionTracker::GetNext(void)
1992 Elf_Shdr *Elf_SectionTracker::Header(void)
1997 const Elf_Shdr *Elf_SectionTracker::Header(void) const
2005 NewArrayHolder<char> m_Ptr;
2010 Elf_Buffer(unsigned int len);
2013 char *Ensure(unsigned int len);
2014 void Forward(unsigned int len);
2017 unsigned int GetPos() const
2022 char *GetPtr(unsigned int off = 0)
2024 return m_Ptr.GetValue() + off;
2028 char *Reserve(unsigned int len);
2029 template <typename T> T *ReserveT(unsigned int len = sizeof(T))
2031 _ASSERTE(len >= sizeof(T));
2032 return reinterpret_cast<T *>(Reserve(len));
2036 void Append(const char *src, unsigned int len);
2037 template <typename T> void AppendT(T *src)
2039 Append(reinterpret_cast<const char *>(src), sizeof(T));
2043 Elf_Buffer::Elf_Buffer(unsigned int len)
2044 : m_Ptr(new char[len])
2050 char *Elf_Buffer::Ensure(unsigned int len)
2052 bool bAdjusted = false;
2054 while (m_Pos + len > m_Len)
2062 char *ptr = new char [m_Len * 2];
2063 memcpy(ptr, m_Ptr.GetValue(), m_Pos);
2067 return GetPtr(m_Pos);
2070 void Elf_Buffer::Forward(unsigned int len)
2075 char *Elf_Buffer::Reserve(unsigned int len)
2077 char *ptr = Ensure(len);
2082 void Elf_Buffer::Append(const char *src, unsigned int len)
2084 char *dst = Reserve(len);
2085 memcpy(dst, src, len);
2088 #define ELF_BUILDER_TEXT_SECTION_INDEX 1
2093 Elf_Buffer m_Buffer;
2096 unsigned int m_SectionCount;
2097 Elf_SectionTracker *m_First;
2098 Elf_SectionTracker *m_Last;
2099 Elf_SectionTracker *m_Curr;
2106 unsigned int GetSectionCount(void) { return m_SectionCount; }
2109 void Initialize(PCODE codePtr, TADDR codeLen);
2112 Elf_SectionTracker *OpenSection(const char *name, uint32_t type, uint64_t flags);
2113 void CloseSection();
2116 char *Reserve(unsigned int len);
2117 template <typename T> T *ReserveT(unsigned int len = sizeof(T))
2119 _ASSERTE(len >= sizeof(T));
2120 return reinterpret_cast<T *>(Reserve(len));
2124 void Append(const char *src, unsigned int len);
2125 template <typename T> void AppendT(T *src)
2127 Append(reinterpret_cast<const char *>(src), sizeof(T));
2131 void Finalize(void);
2134 char *Export(size_t *len);
2137 Elf_Builder::Elf_Builder()
2146 Elf_Builder::~Elf_Builder()
2148 Elf_SectionTracker *curr = m_First;
2152 Elf_SectionTracker *next = curr->GetNext();
2158 void Elf_Builder::Initialize(PCODE codePtr, TADDR codeLen)
2161 // Reserve ELF Header
2163 m_Buffer.Reserve(sizeof(Elf_Ehdr));
2166 // Create NULL section
2168 Elf_SectionTracker *null = OpenSection("", SHT_NULL, 0);
2170 null->DisableHeaderUpdate();
2171 null->Header()->sh_addralign = 0;
2176 // Create '.text' section
2178 Elf_SectionTracker *text = OpenSection(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
2180 text->DisableHeaderUpdate();
2181 text->Header()->sh_addr = codePtr;
2182 text->Header()->sh_size = codeLen;
2184 _ASSERTE(text->GetIndex() == ELF_BUILDER_TEXT_SECTION_INDEX);
2189 char *Elf_Builder::Reserve(unsigned int len)
2191 _ASSERTE(m_Curr != nullptr && "Section should be opened before");
2192 char *ptr = m_Buffer.Reserve(len);
2193 m_Curr->Forward(len);
2197 void Elf_Builder::Append(const char *src, unsigned int len)
2199 _ASSERTE(m_Curr != nullptr && "Section should be opened before");
2200 char *dst = Reserve(len);
2201 memcpy(dst, src, len);
2204 Elf_SectionTracker *Elf_Builder::OpenSection(const char *name, uint32_t type, uint64_t flags)
2206 _ASSERTE(m_Curr == nullptr && "Section should be closed before");
2208 Elf_SectionTracker *next = new Elf_SectionTracker(name, m_SectionCount, m_Buffer.GetPos(), type, flags);
2210 if (m_First == NULL)
2217 m_Last->SetNext(next);
2228 void Elf_Builder::CloseSection()
2230 _ASSERTE(m_Curr != nullptr && "Section should be opened before");
2234 char *Elf_Builder::Export(size_t *pLen)
2236 unsigned int len = m_Buffer.GetPos();
2237 const char *src = m_Buffer.GetPtr();
2238 char *dst = new char[len];
2240 memcpy(dst, src, len);
2250 void Elf_Builder::Finalize()
2253 // Create '.shstrtab'
2255 Elf_SectionTracker *shstrtab = OpenSection(".shstrtab", SHT_STRTAB, 0);
2257 Elf_SectionTracker *curr = m_First;
2261 unsigned int off = shstrtab->GetSize();
2262 unsigned int len = curr->GetNameLen();
2264 char *dst = Reserve(len + 1);
2265 memcpy(dst, curr->GetName(), len);
2268 curr->Header()->sh_name = off;
2270 curr = curr->GetNext();
2276 // Create Section Header(s) Table
2278 unsigned int shtOffset = m_Buffer.GetPos();
2280 Elf_SectionTracker *curr = m_First;
2284 if (curr->NeedHeaderUpdate())
2286 curr->Header()->sh_offset = curr->GetOffset();
2287 curr->Header()->sh_size = curr->GetSize();
2289 m_Buffer.AppendT(curr->Header());
2290 curr = curr->GetNext();
2295 // Update ELF Header
2297 Elf_Ehdr *elfHeader = new (m_Buffer.GetPtr()) Elf_Ehdr;
2300 elfHeader->e_flags = EF_ARM_EABI_VER5;
2302 elfHeader->e_flags |= EF_ARM_SOFT_FLOAT;
2304 elfHeader->e_flags |= EF_ARM_VFP_FLOAT;
2307 elfHeader->e_shoff = shtOffset;
2308 elfHeader->e_shentsize = sizeof(Elf_Shdr);
2309 elfHeader->e_shnum = m_SectionCount;
2310 elfHeader->e_shstrndx = shstrtab->GetIndex();
2313 #ifdef FEATURE_GDBJIT_FRAME
2314 struct __attribute__((packed)) Length
2318 Length &operator=(UINT32 n)
2330 struct __attribute__((packed)) CIE
2336 UINT8 code_alignment_factor;
2337 INT8 data_alignment_factor;
2338 UINT8 return_address_register;
2339 UINT8 instructions[0];
2342 struct __attribute__((packed)) FDE
2346 PCODE initial_location;
2347 TADDR address_range;
2348 UINT8 instructions[0];
2351 static void BuildDebugFrame(Elf_Builder &elfBuilder, PCODE pCode, TADDR codeSize)
2353 #if defined(_TARGET_ARM_)
2354 const unsigned int code_alignment_factor = 2;
2355 const int data_alignment_factor = -4;
2358 // DW_CFA_def_cfa 13[sp], 0
2363 // DW_CFA_advance_loc 1
2365 // DW_CFA_def_cfa_offset 8
2367 // DW_CFA_offset 11(r11), -8(= -4 * 2)
2368 (0x02 << 6) | 0x0b, 0x02,
2369 // DW_CFA_offset 14(lr), -4(= -4 * 1)
2370 (0x02 << 6) | 0x0e, 0x01,
2371 // DW_CFA_def_cfa_register 11(r11)
2374 #elif defined(_TARGET_X86_)
2375 const unsigned int code_alignment_factor = 1;
2376 const int data_alignment_factor = -4;
2379 // DW_CFA_def_cfa 4(esp), 4
2381 // DW_CFA_offset 8(eip), -4(= -4 * 1)
2382 (0x02 << 6) | 0x08, 0x01,
2386 // DW_CFA_advance_loc 1
2388 // DW_CFA_def_cfa_offset 8
2390 // DW_CFA_offset 5(ebp), -8(= -4 * 2)
2391 (0x02 << 6) | 0x05, 0x02,
2392 // DW_CFA_def_cfa_register 5(ebp)
2395 #elif defined(_TARGET_AMD64_)
2396 const unsigned int code_alignment_factor = 1;
2397 const int data_alignment_factor = -8;
2400 // DW_CFA_def_cfa 7(rsp), 8
2402 // DW_CFA_offset 16, -16 (= -8 * 2)
2403 (0x02 << 6) | 0x10, 0x01,
2407 // DW_CFA_advance_loc(1)
2409 // DW_CFA_def_cfa_offset(16)
2411 // DW_CFA_offset 6, -16 (= -8 * 2)
2412 (0x02 << 6) | 0x06, 0x02,
2413 // DW_CFA_def_cfa_register(6)
2417 #error "Unsupported architecture"
2420 elfBuilder.OpenSection(".debug_frame", SHT_PROGBITS, 0);
2423 // Common Information Entry
2425 int cieLen = ALIGN_UP(sizeof(CIE) + sizeof(cieCode), ADDRESS_SIZE) + sizeof(Length);
2427 CIE *pCIE = elfBuilder.ReserveT<CIE>(cieLen);
2429 memset(pCIE, 0, cieLen);
2431 pCIE->length = cieLen - sizeof(Length);
2432 pCIE->id = 0xffffffff;
2434 pCIE->augmentation = 0;
2435 Leb128Encode(code_alignment_factor, reinterpret_cast<char *>(&pCIE->code_alignment_factor), 1);
2436 Leb128Encode(data_alignment_factor, reinterpret_cast<char *>(&pCIE->data_alignment_factor), 1);
2438 pCIE->return_address_register = 0;
2440 memcpy(&pCIE->instructions, cieCode, sizeof(cieCode));
2443 // Frame Description Entry
2445 int fdeLen = ALIGN_UP((sizeof(FDE) + sizeof(fdeCode)), ADDRESS_SIZE) + sizeof(Length);
2447 FDE *pFDE = elfBuilder.ReserveT<FDE>(fdeLen);
2449 memset(pFDE, 0, fdeLen);
2451 pFDE->length = fdeLen - sizeof(Length);
2453 pFDE->initial_location = pCode;
2454 pFDE->address_range = codeSize;
2455 memcpy(&pFDE->instructions, fdeCode, sizeof(fdeCode));
2457 elfBuilder.CloseSection();
2459 #endif // FEATURE_GDBJIT_FRAME
2461 void NotifyGdb::Initialize()
2463 g_jitDescriptorCrst.Init(CrstNotifyGdb);
2464 g_codeAddrsCrst.Init(CrstNotifyGdb);
2466 // Get names of interesting modules from environment
2467 if (g_wszModuleNames == nullptr && g_cBytesNeeded == 0)
2469 DWORD cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), NULL, 0);
2471 if (cCharsNeeded == 0)
2473 g_cBytesNeeded = 0xffffffff;
2477 WCHAR *wszModuleNamesBuf = new WCHAR[cCharsNeeded+1];
2479 cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), wszModuleNamesBuf, cCharsNeeded);
2481 if (cCharsNeeded == 0)
2483 delete[] wszModuleNamesBuf;
2484 g_cBytesNeeded = 0xffffffff;
2488 g_wszModuleNames = wszModuleNamesBuf;
2489 g_cBytesNeeded = cCharsNeeded + 1;
2493 /* Create ELF/DWARF debug info for jitted method */
2494 void NotifyGdb::MethodPrepared(MethodDesc* methodDescPtr)
2498 if (!tls_isSymReaderInProgress)
2500 tls_isSymReaderInProgress = true;
2501 NotifyGdb::OnMethodPrepared(methodDescPtr);
2502 tls_isSymReaderInProgress = false;
2508 EX_END_CATCH(SwallowAllExceptions);
2511 void NotifyGdb::OnMethodPrepared(MethodDesc* methodDescPtr)
2513 PCODE pCode = methodDescPtr->GetNativeCode();
2517 /* Get method name & size of jitted code */
2518 EECodeInfo codeInfo(pCode);
2519 if (!codeInfo.IsValid())
2524 TADDR codeSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfoToken());
2526 pCode = PCODEToPINSTR(pCode);
2528 /* Get module name */
2529 const Module* mod = methodDescPtr->GetMethodTable()->GetModule();
2530 SString modName = mod->GetFile()->GetPath();
2531 StackScratchBuffer scratch;
2532 const char* szModName = modName.GetUTF8(scratch);
2533 const char* szModuleFile = SplitFilename(szModName);
2535 int length = MultiByteToWideChar(CP_UTF8, 0, szModuleFile, -1, NULL, 0);
2538 NewArrayHolder<WCHAR> wszModuleFile = new WCHAR[length+1];
2539 length = MultiByteToWideChar(CP_UTF8, 0, szModuleFile, -1, wszModuleFile, length);
2544 bool bNotify = false;
2546 Elf_Builder elfBuilder;
2548 elfBuilder.Initialize(pCode, codeSize);
2550 #ifdef FEATURE_GDBJIT_FRAME
2551 if (g_pConfig->ShouldEmitDebugFrame())
2553 bool bEmitted = EmitFrameInfo(elfBuilder, pCode, codeSize);
2554 bNotify = bNotify || bEmitted;
2558 if (isListedModule(wszModuleFile))
2560 bool bEmitted = EmitDebugInfo(elfBuilder, methodDescPtr, pCode, codeSize);
2561 bNotify = bNotify || bEmitted;
2563 #ifdef FEATURE_GDBJIT_SYMTAB
2566 bool bEmitted = EmitSymtab(elfBuilder, methodDescPtr, pCode, codeSize);
2567 bNotify = bNotify || bEmitted;
2576 elfBuilder.Finalize();
2578 char *symfile_addr = NULL;
2579 size_t symfile_size = 0;
2581 symfile_addr = elfBuilder.Export(&symfile_size);
2584 LPCUTF8 methodName = methodDescPtr->GetName();
2586 if (g_pConfig->ShouldDumpElfOnMethod(methodName))
2588 DumpElf(methodName, symfile_addr, symfile_size);
2592 /* Create GDB JIT structures */
2593 NewHolder<jit_code_entry> jit_symbols = new jit_code_entry;
2595 /* Fill the new entry */
2596 jit_symbols->next_entry = jit_symbols->prev_entry = 0;
2597 jit_symbols->symfile_addr = symfile_addr;
2598 jit_symbols->symfile_size = symfile_size;
2601 CrstHolder crst(&g_jitDescriptorCrst);
2603 /* Link into list */
2604 jit_code_entry *head = __jit_debug_descriptor.first_entry;
2605 __jit_debug_descriptor.first_entry = jit_symbols;
2608 jit_symbols->next_entry = head;
2609 head->prev_entry = jit_symbols;
2612 jit_symbols.SuppressRelease();
2614 /* Notify the debugger */
2615 __jit_debug_descriptor.relevant_entry = jit_symbols;
2616 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
2617 __jit_debug_register_code();
2621 #ifdef FEATURE_GDBJIT_FRAME
2622 bool NotifyGdb::EmitFrameInfo(Elf_Builder &elfBuilder, PCODE pCode, TADDR codeSize)
2624 BuildDebugFrame(elfBuilder, pCode, codeSize);
2627 #endif // FEATURE_GDBJIT_FRAME
2629 #ifdef FEATURE_GDBJIT_SYMTAB
2630 bool NotifyGdb::EmitSymtab(Elf_Builder &elfBuilder, MethodDesc* methodDescPtr, PCODE pCode, TADDR codeSize)
2632 NewArrayHolder<DebuggerILToNativeMap> map = nullptr;
2633 NewArrayHolder<Elf_Symbol> symbols = nullptr;
2634 NewArrayHolder<NewArrayHolder<char>> symbolNames = nullptr;
2639 LPCUTF8 methodName = methodDescPtr->GetName();
2641 if (GetMethodNativeMap(methodDescPtr, &numMap, map, NULL, NULL) == S_OK)
2643 int methodCount = countFuncs(map, numMap);
2644 symbolCount = methodCount + 1;
2645 symbols = new Elf_Symbol[symbolCount];
2647 if (methodCount > 1)
2648 symbolNames = new NewArrayHolder<char>[methodCount - 1];
2650 int startIndex = getNextPrologueIndex(0, map, numMap);
2652 int methodNameSize = strlen(methodName) + 10;
2654 for (int i = 1; i < symbolCount; ++i)
2656 int endIndex = getNextPrologueIndex(startIndex + 1, map, numMap);
2658 PCODE methodStart = map[startIndex].nativeStartOffset;
2659 TADDR methodSize = endIndex == -1 ? codeSize - methodStart : map[endIndex].nativeStartOffset - methodStart;
2663 symbols[i].m_name = methodName;
2667 int symbolNameIndex = i - 2;
2668 symbolNames[symbolNameIndex] = new char[methodNameSize];
2669 sprintf_s(symbolNames[symbolNameIndex], methodNameSize, "%s_%d", methodName, symbolNameIndex + 1);
2670 symbols[i].m_name = symbolNames[symbolNameIndex];
2673 symbols[i].m_value = pCode + methodStart;
2674 symbols[i].m_size = methodSize;
2676 startIndex = endIndex;
2682 symbols = new Elf_Symbol[symbolCount];
2684 symbols[1].m_name = methodName;
2685 symbols[1].m_value = pCode;
2686 symbols[1].m_size = codeSize;
2689 symbols[0].m_name = "";
2691 MemBuf sectSymTab, sectStrTab;
2693 if (!BuildStringTableSection(sectStrTab, symbols, symbolCount))
2698 if (!BuildSymbolTableSection(sectSymTab, pCode, codeSize, symbolCount - 1, symbols, symbolCount, 0))
2703 Elf_SectionTracker *strtab = elfBuilder.OpenSection(".strtab", SHT_STRTAB, 0);
2704 elfBuilder.Append(sectStrTab.MemPtr, sectStrTab.MemSize);
2705 elfBuilder.CloseSection();
2707 Elf_SectionTracker *symtab = elfBuilder.OpenSection(".symtab", SHT_SYMTAB, 0);
2708 elfBuilder.Append(sectSymTab.MemPtr, sectSymTab.MemSize);
2709 symtab->Header()->sh_link = strtab->GetIndex();
2710 symtab->Header()->sh_entsize = sizeof(Elf_Sym);
2711 elfBuilder.CloseSection();
2715 #endif // FEATURE_GDBJIT_SYMTAB
2717 bool NotifyGdb::EmitDebugInfo(Elf_Builder &elfBuilder, MethodDesc* methodDescPtr, PCODE pCode, TADDR codeSize)
2719 unsigned int thunkIndexBase = elfBuilder.GetSectionCount();
2721 LPCUTF8 methodName = methodDescPtr->GetName();
2723 int symbolCount = 0;
2724 NewArrayHolder<Elf_Symbol> symbolNames;
2726 unsigned int symInfoLen = 0;
2727 NewArrayHolder<SymbolsInfo> symInfo = nullptr;
2730 NewHolder<TK_TypeInfoMap> pTypeMap = new TK_TypeInfoMap();
2732 /* Get debug info for method from portable PDB */
2733 HRESULT hr = GetDebugInfoFromPDB(methodDescPtr, symInfo, symInfoLen, locals);
2734 if (FAILED(hr) || symInfoLen == 0)
2739 int method_count = countFuncs(symInfo, symInfoLen);
2740 FunctionMemberPtrArrayHolder method(method_count);
2742 CodeHeader* pCH = (CodeHeader*)pCode - 1;
2743 CalledMethod* pCalledMethods = reinterpret_cast<CalledMethod*>(pCH->GetCalledMethods());
2744 /* Collect addresses of thunks called by method */
2745 if (!CollectCalledMethods(pCalledMethods, (TADDR)methodDescPtr->GetNativeCode(), method, symbolNames, symbolCount))
2749 pCH->SetCalledMethods(NULL);
2751 MetaSig sig(methodDescPtr);
2752 int nArgsCount = sig.NumFixedArgs();
2756 unsigned int firstLineIndex = 0;
2757 for (;firstLineIndex < symInfoLen; firstLineIndex++) {
2758 if (symInfo[firstLineIndex].lineNumber != 0 && symInfo[firstLineIndex].lineNumber != HiddenLine) break;
2761 if (firstLineIndex >= symInfoLen)
2766 int start_index = getNextPrologueIndex(0, symInfo, symInfoLen);
2768 for (int method_index = 0; method_index < method.GetCount(); ++method_index)
2770 method[method_index] = new FunctionMember(methodDescPtr, locals.size, nArgsCount);
2772 int end_index = getNextPrologueIndex(start_index + 1, symInfo, symInfoLen);
2774 PCODE method_start = symInfo[start_index].nativeOffset;
2775 TADDR method_size = end_index == -1 ? codeSize - method_start : symInfo[end_index].nativeOffset - method_start;
2777 // method return type
2778 method[method_index]->m_member_type = GetArgTypeInfo(methodDescPtr, pTypeMap, 0, method);
2779 method[method_index]->m_sub_low_pc = pCode + method_start;
2780 method[method_index]->m_sub_high_pc = method_size;
2781 method[method_index]->lines = symInfo;
2782 method[method_index]->nlines = symInfoLen;
2783 method[method_index]->GetLocalsDebugInfo(pTypeMap, locals, symInfo[firstLineIndex].nativeOffset, method);
2784 size_t methodNameSize = strlen(methodName) + 10;
2785 method[method_index]->m_member_name = new char[methodNameSize];
2786 if (method_index == 0)
2787 sprintf_s(method[method_index]->m_member_name, methodNameSize, "%s", methodName);
2789 sprintf_s(method[method_index]->m_member_name, methodNameSize, "%s_%i", methodName, method_index);
2792 GetTypeInfoFromTypeHandle(TypeHandle(method[method_index]->md->GetMethodTable()), pTypeMap, method);
2794 start_index = end_index;
2797 MemBuf sectSymTab, sectStrTab, dbgInfo, dbgAbbrev, dbgPubname, dbgPubType, dbgLine,
2800 /* Build .debug_abbrev section */
2801 if (!BuildDebugAbbrev(dbgAbbrev))
2806 const char *cuPath = "";
2808 /* Build .debug_line section */
2809 if (!BuildLineTable(dbgLine, pCode, codeSize, symInfo, symInfoLen, cuPath))
2814 // Split full path to compile unit into file name and directory path
2815 const char *fileName = SplitFilename(cuPath);
2816 int dirLen = fileName - cuPath;
2817 NewArrayHolder<char> dirPath;
2820 dirPath = new char[dirLen];
2821 memcpy(dirPath, cuPath, dirLen - 1);
2822 dirPath[dirLen - 1] = '\0';
2825 DebugStringsCU debugStringsCU(fileName, dirPath ? (const char *)dirPath : "");
2827 /* Build .debug_str section */
2828 if (!BuildDebugStrings(dbgStr, pTypeMap, method, debugStringsCU))
2833 /* Build .debug_info section */
2834 if (!BuildDebugInfo(dbgInfo, pTypeMap, method, debugStringsCU))
2839 for (int i = 0; i < method.GetCount(); ++i)
2841 method[i]->lines = nullptr;
2842 method[i]->nlines = 0;
2845 /* Build .debug_pubname section */
2846 if (!BuildDebugPub(dbgPubname, methodName, dbgInfo.MemSize, 0x28))
2851 /* Build debug_pubtype section */
2852 if (!BuildDebugPub(dbgPubType, "int", dbgInfo.MemSize, 0x1a))
2857 /* Build .strtab section */
2858 symbolNames[0].m_name = "";
2859 for (int i = 0; i < method.GetCount(); ++i)
2861 symbolNames[1 + i].m_name = method[i]->m_member_name;
2862 symbolNames[1 + i].m_value = method[i]->m_sub_low_pc;
2863 symbolNames[1 + i].m_section = 1;
2864 symbolNames[1 + i].m_size = method[i]->m_sub_high_pc;
2866 if (!BuildStringTableSection(sectStrTab, symbolNames, symbolCount))
2870 /* Build .symtab section */
2871 if (!BuildSymbolTableSection(sectSymTab, pCode, codeSize, method.GetCount(), symbolNames, symbolCount, thunkIndexBase))
2876 for (int i = 1 + method.GetCount(); i < symbolCount; i++)
2880 sprintf_s(name, _countof(name), ".thunk_%i", i);
2882 Elf_SectionTracker *thunk = elfBuilder.OpenSection(name, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
2883 thunk->DisableHeaderUpdate();
2884 elfBuilder.CloseSection();
2887 elfBuilder.OpenSection(".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS);
2888 elfBuilder.Append(dbgStr.MemPtr, dbgStr.MemSize);
2889 elfBuilder.CloseSection();
2891 elfBuilder.OpenSection(".debug_abbrev", SHT_PROGBITS, 0);
2892 elfBuilder.Append(dbgAbbrev.MemPtr, dbgAbbrev.MemSize);
2893 elfBuilder.CloseSection();
2895 elfBuilder.OpenSection(".debug_info", SHT_PROGBITS, 0);
2896 elfBuilder.Append(dbgInfo.MemPtr, dbgInfo.MemSize);
2897 elfBuilder.CloseSection();
2899 elfBuilder.OpenSection(".debug_pubnames", SHT_PROGBITS, 0);
2900 elfBuilder.Append(dbgPubname.MemPtr, dbgPubname.MemSize);
2901 elfBuilder.CloseSection();
2903 elfBuilder.OpenSection(".debug_pubtypes", SHT_PROGBITS, 0);
2904 elfBuilder.Append(dbgPubType.MemPtr, dbgPubType.MemSize);
2905 elfBuilder.CloseSection();
2907 elfBuilder.OpenSection(".debug_line", SHT_PROGBITS, 0);
2908 elfBuilder.Append(dbgLine.MemPtr, dbgLine.MemSize);
2909 elfBuilder.CloseSection();
2911 Elf_SectionTracker *strtab = elfBuilder.OpenSection(".strtab", SHT_STRTAB, 0);
2912 elfBuilder.Append(sectStrTab.MemPtr, sectStrTab.MemSize);
2913 elfBuilder.CloseSection();
2915 Elf_SectionTracker *symtab = elfBuilder.OpenSection(".symtab", SHT_SYMTAB, 0);
2916 elfBuilder.Append(sectSymTab.MemPtr, sectSymTab.MemSize);
2917 symtab->Header()->sh_link = strtab->GetIndex();
2918 symtab->Header()->sh_entsize = sizeof(Elf_Sym);
2919 elfBuilder.CloseSection();
2924 void NotifyGdb::MethodPitched(MethodDesc* methodDescPtr)
2926 PCODE pCode = methodDescPtr->GetNativeCode();
2931 CrstHolder crst(&g_jitDescriptorCrst);
2933 /* Find relevant entry */
2934 for (jit_code_entry* jit_symbols = __jit_debug_descriptor.first_entry; jit_symbols != 0; jit_symbols = jit_symbols->next_entry)
2936 const char* ptr = jit_symbols->symfile_addr;
2937 uint64_t size = jit_symbols->symfile_size;
2939 const Elf_Ehdr* pEhdr = reinterpret_cast<const Elf_Ehdr*>(ptr);
2940 const Elf_Shdr* pShdr = reinterpret_cast<const Elf_Shdr*>(ptr + pEhdr->e_shoff);
2941 pShdr += ELF_BUILDER_TEXT_SECTION_INDEX; // bump to .text section
2942 if (pShdr->sh_addr == pCode)
2944 /* Notify the debugger */
2945 __jit_debug_descriptor.relevant_entry = jit_symbols;
2946 __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
2947 __jit_debug_register_code();
2952 /* Unlink from list */
2953 if (jit_symbols->prev_entry == 0)
2954 __jit_debug_descriptor.first_entry = jit_symbols->next_entry;
2956 jit_symbols->prev_entry->next_entry = jit_symbols->next_entry;
2963 /* Build the DWARF .debug_line section */
2964 bool NotifyGdb::BuildLineTable(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines,
2965 const char * &cuPath)
2967 MemBuf fileTable, lineProg;
2969 /* Build file table */
2970 if (!BuildFileTable(fileTable, lines, nlines, cuPath))
2972 /* Build line info program */
2973 if (!BuildLineProg(lineProg, startAddr, codeSize, lines, nlines))
2978 buf.MemSize = sizeof(DwarfLineNumHeader) + fileTable.MemSize + lineProg.MemSize;
2979 buf.MemPtr = new char[buf.MemSize];
2981 /* Fill the line info header */
2982 DwarfLineNumHeader* header = reinterpret_cast<DwarfLineNumHeader*>(buf.MemPtr.GetValue());
2983 memcpy(buf.MemPtr, &LineNumHeader, sizeof(DwarfLineNumHeader));
2984 header->m_length = buf.MemSize - sizeof(header->m_length);
2986 // Set m_hdr_field to the number of bytes following the m_hdr_field field to the beginning of the first byte of
2987 // the line number program itself.
2988 header->m_hdr_length = sizeof(DwarfLineNumHeader)
2989 - sizeof(header->m_length)
2990 - sizeof(header->m_version)
2991 - sizeof(header->m_hdr_length)
2992 + fileTable.MemSize;
2994 /* copy file table */
2995 memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader), fileTable.MemPtr, fileTable.MemSize);
2996 /* copy line program */
2997 memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader) + fileTable.MemSize, lineProg.MemPtr, lineProg.MemSize);
3002 // A class for building Directory Table and File Table (in .debug_line section) from a list of files
3003 class NotifyGdb::FileTableBuilder
3007 NewArrayHolder< NewArrayHolder<char> > m_dirs;
3016 NewArrayHolder<FileEntry> m_files;
3019 int FindDir(const char *name) const
3021 for (int i = 0; i < m_dirs_count; ++i)
3023 if (strcmp(m_dirs[i], name) == 0)
3029 int FindFile(const char *path) const
3031 for (int i = 0; i < m_files_count; ++i)
3033 if (strcmp(m_files[i].path, path) == 0)
3041 FileTableBuilder(int capacity) :
3042 m_capacity(capacity),
3043 m_dirs(new NewArrayHolder<char>[capacity]),
3045 m_files(new FileEntry[capacity]),
3050 int Add(const char *path)
3053 int i = FindFile(path);
3057 if (m_files_count >= m_capacity)
3060 // Add new file entry
3061 m_files[m_files_count].path = path;
3062 const char *filename = SplitFilename(path);
3063 m_files[m_files_count].name = filename;
3064 int dirLen = filename - path;
3067 m_files[m_files_count].dir = 0;
3068 return m_files_count++;
3071 // Construct directory path
3072 NewArrayHolder<char> dirName = new char[dirLen + 1];
3073 int delimiterDelta = dirLen == 1 ? 0 : 1; // Avoid empty dir entry when file is at Unix root /
3074 memcpy(dirName, path, dirLen - delimiterDelta);
3075 dirName[dirLen - delimiterDelta] = '\0';
3077 // Try to find existing directory entry
3078 i = FindDir(dirName);
3081 m_files[m_files_count].dir = i + 1;
3082 return m_files_count++;
3085 // Create new directory entry
3086 if (m_dirs_count >= m_capacity)
3089 m_dirs[m_dirs_count++] = dirName.Extract();
3091 m_files[m_files_count].dir = m_dirs_count;
3092 return m_files_count++;
3095 void Build(MemBuf& buf)
3097 unsigned totalSize = 0;
3099 // Compute buffer size
3100 for (unsigned i = 0; i < m_dirs_count; ++i)
3101 totalSize += strlen(m_dirs[i]) + 1;
3105 for (unsigned i = 0; i < m_files_count; ++i)
3107 int len = Leb128Encode(static_cast<uint32_t>(m_files[i].dir), cnv_buf, sizeof(cnv_buf));
3108 totalSize += strlen(m_files[i].name) + 1 + len + 2;
3113 buf.MemSize = totalSize;
3114 buf.MemPtr = new char[buf.MemSize];
3116 char *ptr = buf.MemPtr;
3118 for (unsigned i = 0; i < m_dirs_count; ++i)
3120 strcpy(ptr, m_dirs[i]);
3121 ptr += strlen(m_dirs[i]) + 1;
3123 // final zero byte for directory table
3126 for (unsigned i = 0; i < m_files_count; ++i)
3128 strcpy(ptr, m_files[i].name);
3129 ptr += strlen(m_files[i].name) + 1;
3131 // Index in directory table
3132 int len = Leb128Encode(static_cast<uint32_t>(m_files[i].dir), cnv_buf, sizeof(cnv_buf));
3133 memcpy(ptr, cnv_buf, len);
3136 // Two LEB128 entries which we don't care
3145 /* Buid the source files table for DWARF source line info */
3146 bool NotifyGdb::BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines, const char * &cuPath)
3148 FileTableBuilder fileTable(nlines);
3151 for (unsigned i = 0; i < nlines; ++i)
3153 const char* fileName = lines[i].fileName;
3155 if (fileName[0] == '\0')
3158 if (*cuPath == '\0') // Use first non-empty filename as compile unit
3161 lines[i].fileIndex = fileTable.Add(fileName);
3164 fileTable.Build(buf);
3169 /* Command to set absolute address */
3170 void NotifyGdb::IssueSetAddress(char*& ptr, PCODE addr)
3173 *ptr++ = ADDRESS_SIZE + 1;
3174 *ptr++ = DW_LNE_set_address;
3175 *reinterpret_cast<PCODE*>(ptr) = addr;
3176 ptr += ADDRESS_SIZE;
3179 /* End of line program */
3180 void NotifyGdb::IssueEndOfSequence(char*& ptr)
3184 *ptr++ = DW_LNE_end_sequence;
3187 /* Command w/o parameters */
3188 void NotifyGdb::IssueSimpleCommand(char*& ptr, uint8_t command)
3193 /* Command with one LEB128 parameter */
3194 void NotifyGdb::IssueParamCommand(char*& ptr, uint8_t command, char* param, int param_size)
3197 while (param_size-- > 0)
3203 static void fixLineMapping(SymbolsInfo* lines, unsigned nlines)
3205 // Fix EPILOGUE line mapping
3207 for (int i = 0; i < nlines; ++i)
3209 if (lines[i].lineNumber == HiddenLine)
3211 if (lines[i].ilOffset == ICorDebugInfo::PROLOG) // will be fixed in next step
3217 if (lines[i].lineNumber == 0)
3219 lines[i].lineNumber = prevLine;
3223 prevLine = lines[i].lineNumber;
3227 // Fix PROLOGUE line mapping
3228 prevLine = lines[nlines - 1].lineNumber;
3229 for (int i = nlines - 1; i >= 0; --i)
3231 if (lines[i].lineNumber == HiddenLine)
3233 if (lines[i].lineNumber == 0)
3234 lines[i].lineNumber = prevLine;
3236 prevLine = lines[i].lineNumber;
3239 for (int i = 0; i < nlines; ++i)
3241 if (lines[i].lineNumber == HiddenLine)
3243 lines[i].lineNumber = 0;
3244 if (i + 1 < nlines && lines[i + 1].ilOffset == ICorDebugInfo::NO_MAPPING)
3245 lines[i + 1].lineNumber = 0;
3250 /* Build program for DWARF source line section */
3251 bool NotifyGdb::BuildLineProg(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines)
3255 /* reserve memory assuming worst case: set address, advance line command, set proglogue/epilogue and copy for each line */
3257 + 6 /* set file command */
3258 + nlines * 6 /* advance line commands */
3259 + nlines * (3 + ADDRESS_SIZE) /* set address commands */
3260 + nlines * 1 /* set prologue end or epilogue begin commands */
3261 + nlines * 1 /* copy commands */
3262 + 6 /* advance PC command */
3263 + 3; /* end of sequence command */
3264 buf.MemPtr = new char[buf.MemSize];
3265 char* ptr = buf.MemPtr;
3267 if (buf.MemPtr == nullptr)
3270 fixLineMapping(lines, nlines);
3272 int prevLine = 1, prevFile = 0;
3274 for (int i = 0; i < nlines; ++i)
3276 /* different source file */
3277 if (lines[i].fileIndex != prevFile)
3279 int len = Leb128Encode(static_cast<uint32_t>(lines[i].fileIndex+1), cnv_buf, sizeof(cnv_buf));
3280 IssueParamCommand(ptr, DW_LNS_set_file, cnv_buf, len);
3281 prevFile = lines[i].fileIndex;
3284 // GCC don't use the is_prologue_end flag to mark the first instruction after the prologue.
3285 // Instead of it it is issueing a line table entry for the first instruction of the prologue
3286 // and one for the first instruction after the prologue.
3287 // We do not want to confuse the debugger so we have to avoid adding a line in such case.
3288 if (i > 0 && lines[i - 1].nativeOffset == lines[i].nativeOffset)
3291 IssueSetAddress(ptr, startAddr + lines[i].nativeOffset);
3293 if (lines[i].lineNumber != prevLine) {
3294 int len = Leb128Encode(static_cast<int32_t>(lines[i].lineNumber - prevLine), cnv_buf, sizeof(cnv_buf));
3295 IssueParamCommand(ptr, DW_LNS_advance_line, cnv_buf, len);
3296 prevLine = lines[i].lineNumber;
3299 if (lines[i].ilOffset == ICorDebugInfo::EPILOG)
3300 IssueSimpleCommand(ptr, DW_LNS_set_epilogue_begin);
3301 else if (i > 0 && lines[i - 1].ilOffset == ICorDebugInfo::PROLOG)
3302 IssueSimpleCommand(ptr, DW_LNS_set_prologue_end);
3304 IssueParamCommand(ptr, DW_LNS_copy, NULL, 0);
3307 int lastAddr = nlines > 0 ? lines[nlines - 1].nativeOffset : 0;
3309 // Advance PC to the end of function
3310 if (lastAddr < codeSize) {
3311 int len = Leb128Encode(static_cast<uint32_t>(codeSize - lastAddr), cnv_buf, sizeof(cnv_buf));
3312 IssueParamCommand(ptr, DW_LNS_advance_pc, cnv_buf, len);
3315 IssueEndOfSequence(ptr);
3317 buf.MemSize = ptr - buf.MemPtr;
3321 /* Build the DWARF .debug_str section */
3322 bool NotifyGdb::BuildDebugStrings(MemBuf& buf,
3323 PTK_TypeInfoMap pTypeMap,
3324 FunctionMemberPtrArrayHolder &method,
3325 DebugStringsCU &debugStringsCU)
3327 int totalLength = 0;
3329 /* calculate total section size */
3330 debugStringsCU.DumpStrings(nullptr, totalLength);
3332 for (int i = 0; i < method.GetCount(); ++i)
3334 method[i]->DumpStrings(nullptr, totalLength);
3338 auto iter = pTypeMap->Begin();
3339 while (iter != pTypeMap->End())
3341 TypeInfoBase *typeInfo = iter->Value();
3342 typeInfo->DumpStrings(nullptr, totalLength);
3347 buf.MemSize = totalLength;
3348 buf.MemPtr = new char[totalLength];
3351 char* bufPtr = buf.MemPtr;
3354 debugStringsCU.DumpStrings(bufPtr, offset);
3356 for (int i = 0; i < method.GetCount(); ++i)
3358 method[i]->DumpStrings(bufPtr, offset);
3362 auto iter = pTypeMap->Begin();
3363 while (iter != pTypeMap->End())
3365 TypeInfoBase *typeInfo = iter->Value();
3366 typeInfo->DumpStrings(bufPtr, offset);
3374 /* Build the DWARF .debug_abbrev section */
3375 bool NotifyGdb::BuildDebugAbbrev(MemBuf& buf)
3377 buf.MemPtr = new char[AbbrevTableSize];
3378 buf.MemSize = AbbrevTableSize;
3380 memcpy(buf.MemPtr, AbbrevTable, AbbrevTableSize);
3384 /* Build tge DWARF .debug_info section */
3385 bool NotifyGdb::BuildDebugInfo(MemBuf& buf,
3386 PTK_TypeInfoMap pTypeMap,
3387 FunctionMemberPtrArrayHolder &method,
3388 DebugStringsCU &debugStringsCU)
3390 int totalTypeVarSubSize = 0;
3392 auto iter = pTypeMap->Begin();
3393 while (iter != pTypeMap->End())
3395 TypeInfoBase *typeInfo = iter->Value();
3396 typeInfo->DumpDebugInfo(nullptr, totalTypeVarSubSize);
3401 for (int i = 0; i < method.GetCount(); ++i)
3403 method[i]->DumpDebugInfo(nullptr, totalTypeVarSubSize);
3406 //int locSize = GetArgsAndLocalsLen(argsDebug, argsDebugSize, localsDebug, localsDebugSize);
3407 buf.MemSize = sizeof(DwarfCompUnit) + sizeof(DebugInfoCU) + totalTypeVarSubSize + 2;
3408 buf.MemPtr = new char[buf.MemSize];
3411 /* Compile uint header */
3412 DwarfCompUnit* cu = reinterpret_cast<DwarfCompUnit*>(buf.MemPtr.GetValue());
3413 cu->m_length = buf.MemSize - sizeof(uint32_t);
3415 cu->m_abbrev_offset = 0;
3416 cu->m_addr_size = ADDRESS_SIZE;
3417 offset += sizeof(DwarfCompUnit);
3419 reinterpret_cast<DebugInfoCU*>(buf.MemPtr + offset);
3420 memcpy(buf.MemPtr + offset, &debugInfoCU, sizeof(DebugInfoCU));
3421 offset += sizeof(DebugInfoCU);
3422 diCU->m_prod_off = debugStringsCU.GetProducerOffset();
3423 diCU->m_cu_name = debugStringsCU.GetModuleNameOffset();
3424 diCU->m_cu_dir = debugStringsCU.GetModuleDirOffset();
3426 auto iter = pTypeMap->Begin();
3427 while (iter != pTypeMap->End())
3429 TypeInfoBase *typeInfo = iter->Value();
3430 typeInfo->DumpDebugInfo(buf.MemPtr, offset);
3434 for (int i = 0; i < method.GetCount(); ++i)
3436 if (!method[i]->IsDumped())
3438 method[i]->DumpDebugInfo(buf.MemPtr, offset);
3442 method[i]->DumpDebugInfo(buf.MemPtr, method[i]->m_entry_offset);
3445 memset(buf.MemPtr + offset, 0, buf.MemSize - offset);
3449 /* Build the DWARF lookup section */
3450 bool NotifyGdb::BuildDebugPub(MemBuf& buf, const char* name, uint32_t size, uint32_t die_offset)
3452 uint32_t length = sizeof(DwarfPubHeader) + sizeof(uint32_t) + strlen(name) + 1 + sizeof(uint32_t);
3454 buf.MemSize = length;
3455 buf.MemPtr = new char[buf.MemSize];
3457 DwarfPubHeader* header = reinterpret_cast<DwarfPubHeader*>(buf.MemPtr.GetValue());
3458 header->m_length = length - sizeof(uint32_t);
3459 header->m_version = 2;
3460 header->m_debug_info_off = 0;
3461 header->m_debug_info_len = size;
3462 *reinterpret_cast<uint32_t*>(buf.MemPtr + sizeof(DwarfPubHeader)) = die_offset;
3463 strcpy(buf.MemPtr + sizeof(DwarfPubHeader) + sizeof(uint32_t), name);
3464 *reinterpret_cast<uint32_t*>(buf.MemPtr + length - sizeof(uint32_t)) = 0;
3469 /* Store addresses and names of the called methods into symbol table */
3470 bool NotifyGdb::CollectCalledMethods(CalledMethod* pCalledMethods,
3472 FunctionMemberPtrArrayHolder &method,
3473 NewArrayHolder<Elf_Symbol> &symbolNames,
3476 AddrSet tmpCodeAddrs;
3478 CrstHolder crst(&g_codeAddrsCrst);
3480 if (!g_codeAddrs.Contains(nativeCode))
3481 g_codeAddrs.Add(nativeCode);
3483 CalledMethod* pList = pCalledMethods;
3485 /* count called methods */
3486 while (pList != NULL)
3488 TADDR callAddr = (TADDR)pList->GetCallAddr();
3489 if (!tmpCodeAddrs.Contains(callAddr) && !g_codeAddrs.Contains(callAddr)) {
3490 tmpCodeAddrs.Add(callAddr);
3492 pList = pList->GetNext();
3495 symbolCount = 1 + method.GetCount() + tmpCodeAddrs.GetCount();
3496 symbolNames = new Elf_Symbol[symbolCount];
3498 pList = pCalledMethods;
3499 int i = 1 + method.GetCount();
3500 while (i < symbolCount && pList != NULL)
3502 TADDR callAddr = (TADDR)pList->GetCallAddr();
3503 if (!g_codeAddrs.Contains(callAddr))
3505 MethodDesc* pMD = pList->GetMethodDesc();
3506 LPCUTF8 methodName = pMD->GetName();
3507 int symbolNameLength = strlen(methodName) + sizeof("__thunk_");
3508 symbolNames[i].m_symbol_name = new char[symbolNameLength];
3509 symbolNames[i].m_name = symbolNames[i].m_symbol_name;
3510 sprintf_s((char*)symbolNames[i].m_name, symbolNameLength, "__thunk_%s", methodName);
3511 symbolNames[i].m_value = callAddr;
3513 g_codeAddrs.Add(callAddr);
3515 pList = pList->GetNext();
3521 /* Build ELF .strtab section */
3522 bool NotifyGdb::BuildStringTableSection(MemBuf& buf, NewArrayHolder<Elf_Symbol> &symbolNames, int symbolCount)
3525 for (int i = 0; i < symbolCount; ++i)
3526 len += strlen(symbolNames[i].m_name) + 1;
3527 len++; // end table with zero-length string
3530 buf.MemPtr = new char[buf.MemSize];
3532 char* ptr = buf.MemPtr;
3533 for (int i = 0; i < symbolCount; ++i)
3535 symbolNames[i].m_off = ptr - buf.MemPtr;
3536 strcpy(ptr, symbolNames[i].m_name);
3537 ptr += strlen(symbolNames[i].m_name) + 1;
3539 buf.MemPtr[buf.MemSize-1] = 0;
3544 /* Build ELF .symtab section */
3545 bool NotifyGdb::BuildSymbolTableSection(MemBuf& buf, PCODE addr, TADDR codeSize, int methodCount,
3546 NewArrayHolder<Elf_Symbol> &symbolNames, int symbolCount,
3547 unsigned int thunkIndexBase)
3549 buf.MemSize = symbolCount * sizeof(Elf_Sym);
3550 buf.MemPtr = new char[buf.MemSize];
3552 Elf_Sym *sym = reinterpret_cast<Elf_Sym*>(buf.MemPtr.GetValue());
3556 sym[0].st_other = 0;
3557 sym[0].st_value = 0;
3559 sym[0].st_shndx = SHN_UNDEF;
3561 for (int i = 1; i < 1 + methodCount; ++i)
3563 sym[i].st_name = symbolNames[i].m_off;
3564 sym[i].setBindingAndType(STB_GLOBAL, STT_FUNC);
3565 sym[i].st_other = 0;
3566 sym[i].st_value = PINSTRToPCODE(symbolNames[i].m_value - addr);
3567 sym[i].st_shndx = ELF_BUILDER_TEXT_SECTION_INDEX;
3568 sym[i].st_size = symbolNames[i].m_size;
3571 for (int i = 1 + methodCount; i < symbolCount; ++i)
3573 sym[i].st_name = symbolNames[i].m_off;
3574 sym[i].setBindingAndType(STB_GLOBAL, STT_FUNC);
3575 sym[i].st_other = 0;
3576 sym[i].st_shndx = thunkIndexBase + (i - (1 + methodCount)); // .thunks section index
3579 sym[i].st_value = 1; // for THUMB code
3581 sym[i].st_value = 0;
3587 /* Split file name part from the full path */
3588 const char * NotifyGdb::SplitFilename(const char* path)
3590 // Search for the last directory delimiter (Windows or Unix)
3591 const char *pSlash = nullptr;
3592 for (const char *p = path; *p != '\0'; p++)
3594 if (*p == '/' || *p == '\\')
3598 return pSlash ? pSlash + 1 : path;
3601 /* ELF 32bit header */
3602 Elf32_Ehdr::Elf32_Ehdr()
3604 e_ident[EI_MAG0] = ElfMagic[0];
3605 e_ident[EI_MAG1] = ElfMagic[1];
3606 e_ident[EI_MAG2] = ElfMagic[2];
3607 e_ident[EI_MAG3] = ElfMagic[3];
3608 e_ident[EI_CLASS] = ELFCLASS32;
3609 e_ident[EI_DATA] = ELFDATA2LSB;
3610 e_ident[EI_VERSION] = EV_CURRENT;
3611 e_ident[EI_OSABI] = ELFOSABI_NONE;
3612 e_ident[EI_ABIVERSION] = 0;
3613 for (int i = EI_PAD; i < EI_NIDENT; ++i)
3617 #if defined(_TARGET_X86_)
3619 #elif defined(_TARGET_ARM_)
3626 e_ehsize = sizeof(Elf32_Ehdr);
3631 /* ELF 64bit header */
3632 Elf64_Ehdr::Elf64_Ehdr()
3634 e_ident[EI_MAG0] = ElfMagic[0];
3635 e_ident[EI_MAG1] = ElfMagic[1];
3636 e_ident[EI_MAG2] = ElfMagic[2];
3637 e_ident[EI_MAG3] = ElfMagic[3];
3638 e_ident[EI_CLASS] = ELFCLASS64;
3639 e_ident[EI_DATA] = ELFDATA2LSB;
3640 e_ident[EI_VERSION] = EV_CURRENT;
3641 e_ident[EI_OSABI] = ELFOSABI_NONE;
3642 e_ident[EI_ABIVERSION] = 0;
3643 for (int i = EI_PAD; i < EI_NIDENT; ++i)
3647 #if defined(_TARGET_AMD64_)
3648 e_machine = EM_X86_64;
3649 #elif defined(_TARGET_ARM64_)
3650 e_machine = EM_AARCH64;
3656 e_ehsize = sizeof(Elf64_Ehdr);