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 };
665 // END of GDB JIT interface
667 /* Static data for .debug_str section */
668 const char* DebugStrings[] = {
669 "CoreCLR", "" /* module name */, "" /* module path */
672 const int DebugStringCount = sizeof(DebugStrings) / sizeof(DebugStrings[0]);
674 /* Static data for .debug_abbrev */
675 const unsigned char AbbrevTable[] = {
676 1, DW_TAG_compile_unit, DW_CHILDREN_yes,
677 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,
678 DW_AT_stmt_list, DW_FORM_sec_offset, 0, 0,
680 2, DW_TAG_base_type, DW_CHILDREN_no,
681 DW_AT_name, DW_FORM_strp, DW_AT_encoding, DW_FORM_data1, DW_AT_byte_size, DW_FORM_data1, 0, 0,
683 3, DW_TAG_typedef, DW_CHILDREN_no, DW_AT_name, DW_FORM_strp,
684 DW_AT_type, DW_FORM_ref4, 0, 0,
686 4, DW_TAG_subprogram, DW_CHILDREN_yes,
687 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,
688 DW_AT_type, DW_FORM_ref4, DW_AT_external, DW_FORM_flag_present,
689 DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc, DW_FORM_size,
690 DW_AT_frame_base, DW_FORM_exprloc, 0, 0,
692 5, DW_TAG_variable, DW_CHILDREN_no,
693 DW_AT_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1, DW_AT_type,
694 DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc, 0, 0,
696 6, DW_TAG_formal_parameter, DW_CHILDREN_no,
697 DW_AT_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1, DW_AT_type,
698 DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc, 0, 0,
700 7, DW_TAG_class_type, DW_CHILDREN_yes,
701 DW_AT_name, DW_FORM_strp, DW_AT_byte_size, DW_FORM_data4, 0, 0,
703 8, DW_TAG_member, DW_CHILDREN_no,
704 DW_AT_name, DW_FORM_strp, DW_AT_type, DW_FORM_ref4, DW_AT_data_member_location, DW_FORM_data4, 0, 0,
706 9, DW_TAG_pointer_type, DW_CHILDREN_no,
707 DW_AT_type, DW_FORM_ref4, DW_AT_byte_size, DW_FORM_data1, 0, 0,
709 10, DW_TAG_array_type, DW_CHILDREN_yes,
710 DW_AT_type, DW_FORM_ref4, 0, 0,
712 11, DW_TAG_subrange_type, DW_CHILDREN_no,
713 DW_AT_upper_bound, DW_FORM_exprloc, 0, 0,
715 12, DW_TAG_subprogram, DW_CHILDREN_yes,
716 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,
717 DW_AT_type, DW_FORM_ref4, DW_AT_external, DW_FORM_flag_present,
718 DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc, DW_FORM_size,
719 DW_AT_frame_base, DW_FORM_exprloc, DW_AT_object_pointer, DW_FORM_ref4, 0, 0,
721 13, DW_TAG_formal_parameter, DW_CHILDREN_no,
722 DW_AT_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1, DW_AT_type,
723 DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc, DW_AT_artificial, DW_FORM_flag_present, 0, 0,
725 14, DW_TAG_member, DW_CHILDREN_no,
726 DW_AT_name, DW_FORM_strp, DW_AT_type, DW_FORM_ref4, DW_AT_external, DW_FORM_flag_present, 0, 0,
728 15, DW_TAG_variable, DW_CHILDREN_no, DW_AT_specification, DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc,
731 16, DW_TAG_try_block, DW_CHILDREN_no,
732 DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc, DW_FORM_size,
735 17, DW_TAG_catch_block, DW_CHILDREN_no,
736 DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc, DW_FORM_size,
739 18, DW_TAG_inheritance, DW_CHILDREN_no, DW_AT_type, DW_FORM_ref4, DW_AT_data_member_location, DW_FORM_data1,
742 19, DW_TAG_subrange_type, DW_CHILDREN_no,
743 DW_AT_upper_bound, DW_FORM_udata, 0, 0,
745 20, DW_TAG_lexical_block, DW_CHILDREN_yes,
746 DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc, DW_FORM_size,
752 const int AbbrevTableSize = sizeof(AbbrevTable);
754 /* Static data for .debug_line, including header */
755 #define DWARF_LINE_BASE (-5)
756 #define DWARF_LINE_RANGE 14
757 #define DWARF_OPCODE_BASE 13
759 #ifdef FEATURE_GDBJIT_LANGID_CS
760 /* TODO: use corresponding constant when it will be added to llvm */
761 #define DW_LANG_MICROSOFT_CSHARP 0x9e57
764 DwarfLineNumHeader LineNumHeader = {
765 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}
768 /* Static data for .debug_info */
769 struct __attribute__((packed)) DebugInfoCU
778 #ifdef FEATURE_GDBJIT_LANGID_CS
779 1, 0, DW_LANG_MICROSOFT_CSHARP, 0, 0
781 1, 0, DW_LANG_C89, 0, 0
785 struct __attribute__((packed)) DebugInfoTryCatchSub
787 uint8_t m_sub_abbrev;
788 uintptr_t m_sub_low_pc, m_sub_high_pc;
791 struct __attribute__((packed)) DebugInfoSub
793 uint8_t m_sub_abbrev;
795 uint32_t m_linkage_name;
796 uint8_t m_file, m_line;
798 uintptr_t m_sub_low_pc, m_sub_high_pc;
799 uint8_t m_sub_loc[2];
802 struct __attribute__((packed)) DebugInfoSubMember
808 struct __attribute__((packed)) DebugInfoLexicalBlock
811 uintptr_t m_low_pc, m_high_pc;
814 // Holder for array of pointers to FunctionMember objects
815 class FunctionMemberPtrArrayHolder : public NewArrayHolder<NewHolder<FunctionMember>>
821 explicit FunctionMemberPtrArrayHolder(int cElements) :
822 NewArrayHolder<NewHolder<FunctionMember>>(new NewHolder<FunctionMember>[cElements]),
823 m_cElements(cElements)
833 struct __attribute__((packed)) DebugInfoType
835 uint8_t m_type_abbrev;
836 uint32_t m_type_name;
841 struct __attribute__((packed)) DebugInfoVar
843 uint8_t m_var_abbrev;
845 uint8_t m_var_file, m_var_line;
849 struct __attribute__((packed)) DebugInfoTypeDef
851 uint8_t m_typedef_abbrev;
852 uint32_t m_typedef_name;
853 uint32_t m_typedef_type;
856 struct __attribute__((packed)) DebugInfoClassType
858 uint8_t m_type_abbrev;
859 uint32_t m_type_name;
860 uint32_t m_byte_size;
863 struct __attribute__((packed)) DebugInfoInheritance
867 uint8_t m_data_member_location;
870 struct __attribute__((packed)) DebugInfoClassMember
872 uint8_t m_member_abbrev;
873 uint32_t m_member_name;
874 uint32_t m_member_type;
877 struct __attribute__((packed)) DebugInfoStaticMember
879 uint8_t m_member_abbrev;
880 uint32_t m_member_specification;
884 struct __attribute__((packed)) DebugInfoRefType
886 uint8_t m_type_abbrev;
891 struct __attribute__((packed)) DebugInfoArrayType
897 void TypeInfoBase::DumpStrings(char* ptr, int& offset)
901 strcpy(ptr + offset, m_type_name);
902 m_type_name_offset = offset;
904 offset += strlen(m_type_name) + 1;
907 void TypeInfoBase::CalculateName()
912 const TypeString::FormatFlags formatFlags = static_cast<TypeString::FormatFlags>(
913 TypeString::FormatNamespace |
914 TypeString::FormatAngleBrackets);
916 TypeString::AppendType(sName, typeHandle, formatFlags);
918 StackScratchBuffer buffer;
919 const UTF8 *utf8 = sName.GetUTF8(buffer);
920 if (typeHandle.IsValueType())
922 m_type_name = new char[strlen(utf8) + 1];
923 strcpy(m_type_name, utf8);
927 m_type_name = new char[strlen(utf8) + 1 + 2];
928 strcpy(m_type_name, "__");
929 strcpy(m_type_name + 2, utf8);
933 for (char *p = m_type_name; *p; ++p)
940 void TypeInfoBase::SetTypeHandle(TypeHandle handle)
943 typeKey = handle.GetTypeKey();
946 TypeHandle TypeInfoBase::GetTypeHandle()
951 TypeKey* TypeInfoBase::GetTypeKey()
956 void TypeDefInfo::DumpStrings(char *ptr, int &offset)
960 strcpy(ptr + offset, m_typedef_name);
961 m_typedef_name_offset = offset;
963 offset += strlen(m_typedef_name) + 1;
966 void TypeDefInfo::DumpDebugInfo(char *ptr, int &offset)
968 if (m_is_visited && m_base_ptr == ptr)
978 DebugInfoTypeDef buf;
979 buf.m_typedef_abbrev = 3;
980 buf.m_typedef_name = m_typedef_name_offset;
981 buf.m_typedef_type = offset + sizeof(DebugInfoTypeDef);
982 m_typedef_type_offset = offset;
986 sizeof(DebugInfoTypeDef));
989 offset += sizeof(DebugInfoTypeDef);
992 static const char *GetCSharpTypeName(TypeInfoBase *typeInfo)
994 switch(typeInfo->GetTypeHandle().GetSignatureCorElementType())
996 case ELEMENT_TYPE_I1: return "sbyte";
997 case ELEMENT_TYPE_U1: return "byte";
998 case ELEMENT_TYPE_CHAR: return "char";
999 case ELEMENT_TYPE_VOID: return "void";
1000 case ELEMENT_TYPE_BOOLEAN: return "bool";
1001 case ELEMENT_TYPE_I2: return "short";
1002 case ELEMENT_TYPE_U2: return "ushort";
1003 case ELEMENT_TYPE_I4: return "int";
1004 case ELEMENT_TYPE_U4: return "uint";
1005 case ELEMENT_TYPE_I8: return "long";
1006 case ELEMENT_TYPE_U8: return "ulong";
1007 case ELEMENT_TYPE_R4: return "float";
1008 case ELEMENT_TYPE_R8: return "double";
1009 default: return typeInfo->m_type_name;
1013 PrimitiveTypeInfo::PrimitiveTypeInfo(TypeHandle typeHandle)
1014 : TypeInfoBase(typeHandle),
1015 m_typedef_info(new TypeDefInfo(nullptr, 0))
1017 CorElementType corType = typeHandle.GetSignatureCorElementType();
1018 m_type_encoding = CorElementTypeToDWEncoding[corType];
1019 m_type_size = CorTypeInfo::Size(corType);
1021 if (corType == ELEMENT_TYPE_CHAR)
1023 m_type_name = new char[9];
1024 strcpy(m_type_name, "char16_t");
1032 void PrimitiveTypeInfo::DumpStrings(char* ptr, int& offset)
1034 TypeInfoBase::DumpStrings(ptr, offset);
1035 if (!m_typedef_info->m_typedef_name)
1037 const char *typeName = GetCSharpTypeName(this);
1038 m_typedef_info->m_typedef_name = new char[strlen(typeName) + 1];
1039 strcpy(m_typedef_info->m_typedef_name, typeName);
1041 m_typedef_info->DumpStrings(ptr, offset);
1044 void PrimitiveTypeInfo::DumpDebugInfo(char *ptr, int &offset)
1046 if (m_is_visited && m_base_ptr == ptr)
1052 m_is_visited = true;
1054 m_typedef_info->DumpDebugInfo(ptr, offset);
1058 DebugInfoType bufType;
1059 bufType.m_type_abbrev = 2;
1060 bufType.m_type_name = m_type_name_offset;
1061 bufType.m_encoding = m_type_encoding;
1062 bufType.m_byte_size = m_type_size;
1064 memcpy(ptr + offset,
1066 sizeof(DebugInfoType));
1068 // Replace offset from real type to typedef
1069 m_type_offset = m_typedef_info->m_typedef_type_offset;
1072 offset += sizeof(DebugInfoType);
1075 ClassTypeInfo::ClassTypeInfo(TypeHandle typeHandle, int num_members, FunctionMemberPtrArrayHolder &method)
1076 : TypeInfoBase(typeHandle),
1077 m_num_members(num_members),
1078 members(new TypeMember[num_members]),
1081 m_array_type(nullptr)
1083 CorElementType corType = typeHandle.GetSignatureCorElementType();
1084 PTR_MethodTable pMT = typeHandle.GetMethodTable();
1088 case ELEMENT_TYPE_VALUETYPE:
1089 case ELEMENT_TYPE_CLASS:
1090 m_type_size = pMT->IsValueType() ? typeHandle.GetSize() : typeHandle.AsMethodTable()->GetBaseSize();
1092 case ELEMENT_TYPE_ARRAY:
1093 case ELEMENT_TYPE_SZARRAY:
1094 m_type_size = pMT->GetClass()->GetSize();
1103 void TypeMember::DumpStrings(char* ptr, int& offset)
1107 strcpy(ptr + offset, m_member_name);
1108 m_member_name_offset = offset;
1110 offset += strlen(m_member_name) + 1;
1113 void TypeMember::DumpDebugInfo(char* ptr, int& offset)
1117 DebugInfoClassMember memberEntry;
1119 if (m_static_member_address == 0)
1120 memberEntry.m_member_abbrev = 8;
1123 memberEntry.m_member_abbrev = 14;
1124 m_member_offset = offset;
1126 memberEntry.m_member_name = m_member_name_offset;
1127 memberEntry.m_member_type = m_member_type->m_type_offset;
1129 memcpy(ptr + offset, &memberEntry, sizeof(DebugInfoClassMember));
1130 if (m_static_member_address == 0)
1131 memcpy(ptr + offset + sizeof(DebugInfoClassMember), &m_member_offset, sizeof(m_member_offset));
1133 offset += sizeof(DebugInfoClassMember);
1134 if (m_static_member_address == 0)
1135 offset += sizeof(m_member_offset);
1138 void TypeMember::DumpStaticDebugInfo(char* ptr, int& offset)
1140 const int ptrSize = sizeof(TADDR);
1141 const int valueTypeBufSize = ptrSize + 6;
1142 const int refTypeBufSize = ptrSize + 2;
1144 bool isValueType = m_member_type->GetTypeHandle().GetSignatureCorElementType() ==
1145 ELEMENT_TYPE_VALUETYPE;
1149 bufSize = valueTypeBufSize;
1153 bufSize = refTypeBufSize;
1158 DebugInfoStaticMember memberEntry;
1160 memberEntry.m_member_abbrev = 15;
1161 memberEntry.m_member_specification = m_member_offset;
1162 memcpy(ptr + offset, &memberEntry, sizeof(DebugInfoStaticMember));
1164 // for value type static fields compute address as:
1165 // addr = (*addr+sizeof(OBJECTREF))
1168 char buf[valueTypeBufSize] = {0};
1169 buf[0] = ptrSize + 5;
1170 buf[1] = DW_OP_addr;
1172 for (int i = 0; i < ptrSize; i++)
1174 buf[i + 2] = m_static_member_address >> (i * 8);
1177 buf[ptrSize + 2] = DW_OP_deref;
1178 buf[ptrSize + 3] = DW_OP_const1u;
1179 buf[ptrSize + 4] = sizeof(OBJECTREF);
1180 buf[ptrSize + 5] = DW_OP_plus;
1182 memcpy(ptr + offset + sizeof(DebugInfoStaticMember), &buf, bufSize);
1186 char buf[refTypeBufSize] = {0};
1187 buf[0] = ptrSize + 1;
1188 buf[1] = DW_OP_addr;
1190 for (int i = 0; i < ptrSize; i++)
1192 buf[i + 2] = m_static_member_address >> (i * 8);
1195 memcpy(ptr + offset + sizeof(DebugInfoStaticMember), &buf, bufSize);
1198 offset += sizeof(DebugInfoStaticMember);
1202 void FunctionMember::MangleName(char *buf, int &buf_offset, const char *name)
1204 int name_length = strlen(name);
1207 int tmp_len = sprintf_s(tmp, _countof(tmp), "%i", name_length);
1212 strncpy(buf + buf_offset, tmp, tmp_len);
1213 buf_offset += tmp_len;
1217 for (int i = 0; i < name_length; i++)
1220 bool valid = (c >= 'a' && c <= 'z') ||
1221 (c >= 'A' && c <= 'Z') ||
1222 (c >= '0' && c <= '9');
1223 *(buf + buf_offset + i) = valid ? c : '_';
1226 buf_offset += name_length;
1229 void FunctionMember::DumpMangledNamespaceAndMethod(char *buf, int &offset, const char *nspace, const char *mname)
1231 static const char *begin_mangled = "_ZN";
1232 static const char *end_mangled = "Ev";
1233 static const int begin_mangled_len = strlen(begin_mangled);
1234 static const int end_mangled_len = strlen(end_mangled);
1237 strncpy(buf + offset, begin_mangled, begin_mangled_len);
1238 offset += begin_mangled_len;
1240 MangleName(buf, offset, nspace);
1241 MangleName(buf, offset, mname);
1244 strncpy(buf + offset, end_mangled, end_mangled_len);
1245 offset += end_mangled_len;
1252 void FunctionMember::DumpLinkageName(char* ptr, int& offset)
1254 SString namespaceOrClassName;
1257 md->GetMethodInfoNoSig(namespaceOrClassName, methodName);
1258 SString utf8namespaceOrClassName;
1259 SString utf8methodName;
1260 namespaceOrClassName.ConvertToUTF8(utf8namespaceOrClassName);
1261 methodName.ConvertToUTF8(utf8methodName);
1263 const char *nspace = utf8namespaceOrClassName.GetUTF8NoConvert();
1264 const char *mname = utf8methodName.GetUTF8NoConvert();
1266 if (!nspace || !mname)
1268 m_linkage_name_offset = 0;
1272 m_linkage_name_offset = offset;
1273 DumpMangledNamespaceAndMethod(ptr, offset, nspace, mname);
1276 void FunctionMember::DumpStrings(char* ptr, int& offset)
1278 TypeMember::DumpStrings(ptr, offset);
1280 for (int i = 0; i < m_num_vars; ++i)
1282 vars[i].DumpStrings(ptr, offset);
1285 DumpLinkageName(ptr, offset);
1288 bool FunctionMember::GetBlockInNativeCode(int blockILOffset, int blockILLen, TADDR *startOffset, TADDR *endOffset)
1290 PCODE pCode = md->GetNativeCode();
1292 const int blockILEnd = blockILOffset + blockILLen;
1297 bool inBlock = false;
1299 for (int i = 0; i < nlines; ++i)
1301 TADDR nativeOffset = lines[i].nativeOffset + pCode;
1303 // Limit block search to current function addresses
1304 if (nativeOffset < m_sub_low_pc)
1306 if (nativeOffset >= m_sub_low_pc + m_sub_high_pc)
1309 // Skip invalid IL offsets
1310 switch(lines[i].ilOffset)
1312 case ICorDebugInfo::PROLOG:
1313 case ICorDebugInfo::EPILOG:
1314 case ICorDebugInfo::NO_MAPPING:
1320 // Check if current IL is within block
1321 if (blockILOffset <= lines[i].ilOffset && lines[i].ilOffset < blockILEnd)
1325 *startOffset = lines[i].nativeOffset;
1333 *endOffset = lines[i].nativeOffset;
1342 *endOffset = m_sub_low_pc + m_sub_high_pc - pCode;
1345 return *endOffset != *startOffset;
1348 void FunctionMember::DumpTryCatchBlock(char* ptr, int& offset, int ilOffset, int ilLen, int abbrev)
1353 if (!GetBlockInNativeCode(ilOffset, ilLen, &startOffset, &endOffset))
1358 DebugInfoTryCatchSub subEntry;
1360 subEntry.m_sub_abbrev = abbrev;
1361 subEntry.m_sub_low_pc = md->GetNativeCode() + startOffset;
1362 subEntry.m_sub_high_pc = endOffset - startOffset;
1364 memcpy(ptr + offset, &subEntry, sizeof(DebugInfoTryCatchSub));
1366 offset += sizeof(DebugInfoTryCatchSub);
1369 void FunctionMember::DumpTryCatchDebugInfo(char* ptr, int& offset)
1374 COR_ILMETHOD *pHeader = md->GetILHeader();
1375 COR_ILMETHOD_DECODER header(pHeader);
1377 unsigned ehCount = header.EHCount();
1379 for (unsigned e = 0; e < ehCount; e++)
1381 IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehBuff;
1382 const IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;
1384 ehInfo = header.EH->EHClause(e, &ehBuff);
1386 DumpTryCatchBlock(ptr, offset, ehInfo->TryOffset, ehInfo->TryLength, 16);
1387 DumpTryCatchBlock(ptr, offset, ehInfo->HandlerOffset, ehInfo->HandlerLength, 17);
1391 void FunctionMember::DumpVarsWithScopes(char *ptr, int &offset)
1393 NewArrayHolder<DebugInfoLexicalBlock> scopeStack = new DebugInfoLexicalBlock[m_num_vars];
1395 int scopeStackSize = 0;
1396 for (int i = 0; i < m_num_vars; ++i)
1398 if (vars[i].m_high_pc == 0) // no scope info
1400 vars[i].DumpDebugInfo(ptr, offset);
1404 // Try to step out to enclosing scope, finilizing scopes on the way
1405 while (scopeStackSize > 0 &&
1406 vars[i].m_low_pc >= (scopeStack[scopeStackSize - 1].m_low_pc +
1407 scopeStack[scopeStackSize - 1].m_high_pc))
1412 memset(ptr + offset, 0, 1);
1418 // Continue adding to prev scope?
1419 if (scopeStackSize > 0 &&
1420 scopeStack[scopeStackSize - 1].m_low_pc == vars[i].m_low_pc &&
1421 scopeStack[scopeStackSize - 1].m_high_pc == vars[i].m_high_pc)
1423 vars[i].DumpDebugInfo(ptr, offset);
1428 scopeStack[scopeStackSize - 1].m_abbrev = 20;
1429 scopeStack[scopeStackSize - 1].m_low_pc = vars[i].m_low_pc;
1430 scopeStack[scopeStackSize - 1].m_high_pc = vars[i].m_high_pc;
1434 memcpy(ptr + offset, scopeStack + (scopeStackSize - 1), sizeof(DebugInfoLexicalBlock));
1436 offset += sizeof(DebugInfoLexicalBlock);
1438 vars[i].DumpDebugInfo(ptr, offset);
1440 // Finalize any remaining scopes
1441 while (scopeStackSize > 0)
1445 memset(ptr + offset, 0, 1);
1453 void FunctionMember::DumpDebugInfo(char* ptr, int& offset)
1457 DebugInfoSub subEntry;
1459 subEntry.m_sub_abbrev = 4;
1460 subEntry.m_sub_name = m_member_name_offset;
1461 subEntry.m_linkage_name = m_linkage_name_offset;
1462 subEntry.m_file = m_file;
1463 subEntry.m_line = m_line;
1464 subEntry.m_sub_type = m_member_type->m_type_offset;
1465 subEntry.m_sub_low_pc = m_sub_low_pc;
1466 subEntry.m_sub_high_pc = m_sub_high_pc;
1467 subEntry.m_sub_loc[0] = m_sub_loc[0];
1468 subEntry.m_sub_loc[1] = m_sub_loc[1];
1470 if (!md->IsStatic())
1472 DebugInfoSubMember subMemberEntry;
1473 subEntry.m_sub_abbrev = 12;
1474 subMemberEntry.sub = subEntry;
1475 subMemberEntry.m_obj_ptr = offset+sizeof(DebugInfoSubMember);
1476 memcpy(ptr + offset, &subMemberEntry, sizeof(DebugInfoSubMember));
1480 memcpy(ptr + offset, &subEntry, sizeof(DebugInfoSub));
1482 m_entry_offset = offset;
1486 if (!md->IsStatic())
1488 offset += sizeof(DebugInfoSubMember);
1492 offset += sizeof(DebugInfoSub);
1495 DumpVarsWithScopes(ptr, offset);
1497 DumpTryCatchDebugInfo(ptr, offset);
1499 // terminate children
1507 int FunctionMember::GetArgsAndLocalsLen()
1512 // Format for DWARF location expression: [expression length][operation][offset in SLEB128 encoding]
1513 for (int i = 0; i < m_num_vars; i++)
1515 locSize += 2; // First byte contains expression length, second byte contains operation (DW_OP_fbreg).
1516 locSize += Leb128Encode(static_cast<int32_t>(vars[i].m_native_offset), tmpBuf, sizeof(tmpBuf));
1521 void ClassTypeInfo::DumpStrings(char* ptr, int& offset)
1523 TypeInfoBase::DumpStrings(ptr, offset);
1525 for (int i = 0; i < m_num_members; ++i)
1527 members[i].DumpStrings(ptr, offset);
1530 if (m_parent != nullptr)
1532 m_parent->DumpStrings(ptr, offset);
1536 void RefTypeInfo::DumpStrings(char* ptr, int& offset)
1538 TypeInfoBase::DumpStrings(ptr, offset);
1539 m_value_type->DumpStrings(ptr, offset);
1542 void RefTypeInfo::DumpDebugInfo(char* ptr, int& offset)
1544 if (m_is_visited && m_base_ptr == ptr)
1550 m_is_visited = true;
1552 m_type_offset = offset;
1553 offset += sizeof(DebugInfoRefType);
1554 m_value_type->DumpDebugInfo(ptr, offset);
1557 DebugInfoRefType refType;
1558 refType.m_type_abbrev = 9;
1559 refType.m_ref_type = m_value_type->m_type_offset;
1560 refType.m_byte_size = m_type_size;
1561 memcpy(ptr + m_type_offset, &refType, sizeof(DebugInfoRefType));
1569 void NamedRefTypeInfo::DumpDebugInfo(char* ptr, int& offset)
1571 if (m_is_visited && m_base_ptr == ptr)
1577 m_is_visited = true;
1579 m_type_offset = offset;
1580 offset += sizeof(DebugInfoRefType) + sizeof(DebugInfoTypeDef);
1581 m_value_type->DumpDebugInfo(ptr, offset);
1584 DebugInfoRefType refType;
1585 refType.m_type_abbrev = 9;
1586 refType.m_ref_type = m_value_type->m_type_offset;
1587 refType.m_byte_size = m_type_size;
1588 memcpy(ptr + m_type_offset, &refType, sizeof(DebugInfoRefType));
1590 DebugInfoTypeDef bugTypeDef;
1591 bugTypeDef.m_typedef_abbrev = 3;
1592 bugTypeDef.m_typedef_name = m_value_type->m_type_name_offset + 2;
1593 bugTypeDef.m_typedef_type = m_type_offset;
1594 memcpy(ptr + m_type_offset + sizeof(DebugInfoRefType), &bugTypeDef, sizeof(DebugInfoTypeDef));
1595 m_type_offset += sizeof(DebugInfoRefType);
1603 void ClassTypeInfo::DumpDebugInfo(char* ptr, int& offset)
1605 if (m_is_visited && m_base_ptr == ptr)
1611 m_is_visited = true;
1613 if (m_parent != nullptr)
1615 m_parent->DumpDebugInfo(ptr, offset);
1618 // make sure that types of all members are dumped
1619 for (int i = 0; i < m_num_members; ++i)
1621 if (members[i].m_member_type != this)
1623 members[i].m_member_type->DumpDebugInfo(ptr, offset);
1629 DebugInfoClassType bufType;
1630 bufType.m_type_abbrev = 7;
1631 bufType.m_type_name = m_type_name_offset;
1632 bufType.m_byte_size = m_type_size;
1634 memcpy(ptr + offset, &bufType, sizeof(DebugInfoClassType));
1635 m_type_offset = offset;
1637 offset += sizeof(DebugInfoClassType);
1639 for (int i = 0; i < m_num_members; ++i)
1641 members[i].DumpDebugInfo(ptr, offset);
1644 for (int i = 0; i < m_method.GetCount(); ++i)
1646 if (m_method[i]->md->GetMethodTable() == GetTypeHandle().GetMethodTable())
1648 // our method is part of this class, we should dump it now before terminating members
1649 m_method[i]->DumpDebugInfo(ptr, offset);
1653 if (m_parent != nullptr)
1657 DebugInfoInheritance buf;
1659 if (RefTypeInfo *m_p = dynamic_cast<RefTypeInfo*>(m_parent))
1660 buf.m_type = m_p->m_value_type->m_type_offset;
1662 buf.m_type = m_parent->m_type_offset;
1663 buf.m_data_member_location = 0;
1664 memcpy(ptr + offset, &buf, sizeof(DebugInfoInheritance));
1666 offset += sizeof(DebugInfoInheritance);
1669 // members terminator
1676 for (int i = 0; i < m_num_members; ++i)
1678 if (members[i].m_static_member_address != 0)
1679 members[i].DumpStaticDebugInfo(ptr, offset);
1683 void ArrayTypeInfo::DumpDebugInfo(char* ptr, int& offset)
1685 if (m_is_visited && m_base_ptr == ptr)
1691 m_is_visited = true;
1693 m_elem_type->DumpDebugInfo(ptr, offset);
1697 DebugInfoArrayType arrType;
1699 arrType.m_abbrev = 10; // DW_TAG_array_type abbrev
1700 arrType.m_type = m_elem_type->m_type_offset;
1702 memcpy(ptr + offset, &arrType, sizeof(DebugInfoArrayType));
1703 m_type_offset = offset;
1705 offset += sizeof(DebugInfoArrayType);
1707 char tmp[16] = { 0 };
1708 int len = Leb128Encode(static_cast<uint32_t>(m_count - 1), tmp + 1, sizeof(tmp) - 1);
1711 tmp[0] = 19; // DW_TAG_subrange_type abbrev with const upper bound
1712 memcpy(ptr + offset, tmp, len + 1);
1718 memset(ptr + offset, 0, 1);
1723 void VarDebugInfo::DumpStrings(char *ptr, int& offset)
1727 strcpy(ptr + offset, m_var_name);
1728 m_var_name_offset = offset;
1730 offset += strlen(m_var_name) + 1;
1733 void VarDebugInfo::DumpDebugInfo(char* ptr, int& offset)
1736 int len = GetFrameLocation(m_native_offset, bufVarLoc);
1739 DebugInfoVar bufVar;
1741 bufVar.m_var_abbrev = m_var_abbrev;
1742 bufVar.m_var_name = m_var_name_offset;
1743 bufVar.m_var_file = 1;
1744 bufVar.m_var_line = 1;
1745 bufVar.m_var_type = m_var_type->m_type_offset;
1746 memcpy(ptr + offset, &bufVar, sizeof(DebugInfoVar));
1747 memcpy(ptr + offset + sizeof(DebugInfoVar), bufVarLoc, len);
1749 offset += sizeof(DebugInfoVar);
1753 /* static data for symbol strings */
1758 int m_section, m_size;
1759 NewArrayHolder<char> m_symbol_name;
1760 Elf_Symbol() : m_name(nullptr), m_off(0), m_value(0), m_section(0), m_size(0) {}
1764 static int countFuncs(T &arr, int n)
1767 for (int i = 0; i < n; i++) {
1768 if (arr[i].ilOffset == ICorDebugInfo::PROLOG)
1777 static int getNextPrologueIndex(int from, T &arr, int n)
1779 for (int i = from; i < n; ++i) {
1780 if (arr[i].ilOffset == ICorDebugInfo::PROLOG)
1788 static inline bool isListedModule(const WCHAR *wszModuleFile)
1790 static NewArrayHolder<WCHAR> wszModuleNames = nullptr;
1791 static DWORD cBytesNeeded = 0;
1793 // Get names of interesting modules from environment
1794 if (wszModuleNames == nullptr && cBytesNeeded == 0)
1796 DWORD cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), NULL, 0);
1798 if (cCharsNeeded == 0)
1800 cBytesNeeded = 0xffffffff;
1804 WCHAR *wszModuleNamesBuf = new WCHAR[cCharsNeeded+1];
1806 cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), wszModuleNamesBuf, cCharsNeeded);
1808 if (cCharsNeeded == 0)
1810 delete[] wszModuleNamesBuf;
1811 cBytesNeeded = 0xffffffff;
1815 wszModuleNames = wszModuleNamesBuf;
1816 cBytesNeeded = cCharsNeeded + 1;
1818 else if (wszModuleNames == nullptr)
1823 _ASSERTE(wszModuleNames != nullptr && cBytesNeeded > 0);
1825 BOOL isUserDebug = FALSE;
1827 NewArrayHolder<WCHAR> wszModuleName = new WCHAR[cBytesNeeded];
1828 LPWSTR pComma = wcsstr(wszModuleNames, W(","));
1829 LPWSTR tmp = wszModuleNames;
1831 while (pComma != NULL)
1833 wcsncpy(wszModuleName, tmp, pComma - tmp);
1834 wszModuleName[pComma - tmp] = W('\0');
1836 if (wcscmp(wszModuleName, wszModuleFile) == 0)
1842 pComma = wcsstr(tmp, W(","));
1844 if (isUserDebug == FALSE)
1846 wcsncpy(wszModuleName, tmp, wcslen(tmp));
1847 wszModuleName[wcslen(tmp)] = W('\0');
1848 if (wcscmp(wszModuleName, wszModuleFile) == 0)
1857 static NotifyGdb::AddrSet codeAddrs;
1859 class Elf_SectionTracker
1862 unsigned int m_Flag;
1865 NewArrayHolder<char> m_NamePtr;
1866 unsigned int m_NameLen;
1877 Elf_SectionTracker *m_Next;
1880 Elf_SectionTracker(const char *name, unsigned ind, unsigned off, uint32_t type, uint64_t flags);
1881 ~Elf_SectionTracker();
1884 bool NeedHeaderUpdate() const;
1885 void DisableHeaderUpdate();
1888 unsigned int GetIndex() const { return m_Ind; }
1889 unsigned int GetOffset() const { return m_Off; }
1890 unsigned int GetSize() const { return m_Len; }
1893 const char *GetName() const { return m_NamePtr; }
1894 unsigned int GetNameLen() const { return m_NameLen; }
1897 Elf_SectionTracker *GetNext(void);
1898 void SetNext(Elf_SectionTracker *next);
1901 void Forward(unsigned int len);
1904 Elf_Shdr *Header(void);
1905 const Elf_Shdr *Header(void) const;
1909 Elf_SectionTracker::Elf_SectionTracker(const char *name,
1910 unsigned ind, unsigned off,
1911 uint32_t type, uint64_t flags)
1922 unsigned int len = strlen(name);
1923 char *ptr = new char[len + 1];
1925 strncpy(ptr, name, len + 1);
1931 m_Hdr.sh_type = type;
1932 m_Hdr.sh_flags = flags;
1935 m_Hdr.sh_offset = 0;
1937 m_Hdr.sh_link = SHN_UNDEF;
1939 m_Hdr.sh_addralign = 1;
1940 m_Hdr.sh_entsize = 0;
1943 Elf_SectionTracker::~Elf_SectionTracker()
1947 #define ESTF_NO_HEADER_UPDATE 0x00000001
1949 bool Elf_SectionTracker::NeedHeaderUpdate() const
1951 return !(m_Flag & ESTF_NO_HEADER_UPDATE);
1954 void Elf_SectionTracker::DisableHeaderUpdate()
1956 m_Flag |= ESTF_NO_HEADER_UPDATE;
1959 void Elf_SectionTracker::Forward(unsigned int len)
1964 void Elf_SectionTracker::SetNext(Elf_SectionTracker *next)
1969 Elf_SectionTracker *Elf_SectionTracker::GetNext(void)
1974 Elf_Shdr *Elf_SectionTracker::Header(void)
1979 const Elf_Shdr *Elf_SectionTracker::Header(void) const
1987 NewArrayHolder<char> m_Ptr;
1992 Elf_Buffer(unsigned int len);
1995 char *Ensure(unsigned int len);
1996 void Forward(unsigned int len);
1999 unsigned int GetPos() const
2004 char *GetPtr(unsigned int off = 0)
2006 return m_Ptr.GetValue() + off;
2010 char *Reserve(unsigned int len);
2011 template <typename T> T *ReserveT(unsigned int len = sizeof(T))
2013 _ASSERTE(len >= sizeof(T));
2014 return reinterpret_cast<T *>(Reserve(len));
2018 void Append(const char *src, unsigned int len);
2019 template <typename T> void AppendT(T *src)
2021 Append(reinterpret_cast<const char *>(src), sizeof(T));
2025 Elf_Buffer::Elf_Buffer(unsigned int len)
2026 : m_Ptr(new char[len])
2032 char *Elf_Buffer::Ensure(unsigned int len)
2034 bool bAdjusted = false;
2036 while (m_Pos + len > m_Len)
2044 char *ptr = new char [m_Len * 2];
2045 memcpy(ptr, m_Ptr.GetValue(), m_Pos);
2049 return GetPtr(m_Pos);
2052 void Elf_Buffer::Forward(unsigned int len)
2057 char *Elf_Buffer::Reserve(unsigned int len)
2059 char *ptr = Ensure(len);
2064 void Elf_Buffer::Append(const char *src, unsigned int len)
2066 char *dst = Reserve(len);
2067 memcpy(dst, src, len);
2070 #define ELF_BUILDER_TEXT_SECTION_INDEX 1
2075 Elf_Buffer m_Buffer;
2078 unsigned int m_SectionCount;
2079 Elf_SectionTracker *m_First;
2080 Elf_SectionTracker *m_Last;
2081 Elf_SectionTracker *m_Curr;
2088 unsigned int GetSectionCount(void) { return m_SectionCount; }
2091 void Initialize(PCODE codePtr, TADDR codeLen);
2094 Elf_SectionTracker *OpenSection(const char *name, uint32_t type, uint64_t flags);
2095 void CloseSection();
2098 char *Reserve(unsigned int len);
2099 template <typename T> T *ReserveT(unsigned int len = sizeof(T))
2101 _ASSERTE(len >= sizeof(T));
2102 return reinterpret_cast<T *>(Reserve(len));
2106 void Append(const char *src, unsigned int len);
2107 template <typename T> void AppendT(T *src)
2109 Append(reinterpret_cast<const char *>(src), sizeof(T));
2113 void Finalize(void);
2116 char *Export(size_t *len);
2119 Elf_Builder::Elf_Builder()
2128 Elf_Builder::~Elf_Builder()
2130 Elf_SectionTracker *curr = m_First;
2134 Elf_SectionTracker *next = curr->GetNext();
2140 void Elf_Builder::Initialize(PCODE codePtr, TADDR codeLen)
2143 // Reserve ELF Header
2145 m_Buffer.Reserve(sizeof(Elf_Ehdr));
2148 // Create NULL section
2150 Elf_SectionTracker *null = OpenSection("", SHT_NULL, 0);
2152 null->DisableHeaderUpdate();
2153 null->Header()->sh_addralign = 0;
2158 // Create '.text' section
2160 Elf_SectionTracker *text = OpenSection(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
2162 text->DisableHeaderUpdate();
2163 text->Header()->sh_addr = codePtr;
2164 text->Header()->sh_size = codeLen;
2166 _ASSERTE(text->GetIndex() == ELF_BUILDER_TEXT_SECTION_INDEX);
2171 char *Elf_Builder::Reserve(unsigned int len)
2173 _ASSERTE(m_Curr != nullptr && "Section should be opened before");
2174 char *ptr = m_Buffer.Reserve(len);
2175 m_Curr->Forward(len);
2179 void Elf_Builder::Append(const char *src, unsigned int len)
2181 _ASSERTE(m_Curr != nullptr && "Section should be opened before");
2182 char *dst = Reserve(len);
2183 memcpy(dst, src, len);
2186 Elf_SectionTracker *Elf_Builder::OpenSection(const char *name, uint32_t type, uint64_t flags)
2188 _ASSERTE(m_Curr == nullptr && "Section should be closed before");
2190 Elf_SectionTracker *next = new Elf_SectionTracker(name, m_SectionCount, m_Buffer.GetPos(), type, flags);
2192 if (m_First == NULL)
2199 m_Last->SetNext(next);
2210 void Elf_Builder::CloseSection()
2212 _ASSERTE(m_Curr != nullptr && "Section should be opened before");
2216 char *Elf_Builder::Export(size_t *pLen)
2218 unsigned int len = m_Buffer.GetPos();
2219 const char *src = m_Buffer.GetPtr();
2220 char *dst = new char[len];
2222 memcpy(dst, src, len);
2232 void Elf_Builder::Finalize()
2235 // Create '.shstrtab'
2237 Elf_SectionTracker *shstrtab = OpenSection(".shstrtab", SHT_STRTAB, 0);
2239 Elf_SectionTracker *curr = m_First;
2243 unsigned int off = shstrtab->GetSize();
2244 unsigned int len = curr->GetNameLen();
2246 char *dst = Reserve(len + 1);
2247 memcpy(dst, curr->GetName(), len);
2250 curr->Header()->sh_name = off;
2252 curr = curr->GetNext();
2258 // Create Section Header(s) Table
2260 unsigned int shtOffset = m_Buffer.GetPos();
2262 Elf_SectionTracker *curr = m_First;
2266 if (curr->NeedHeaderUpdate())
2268 curr->Header()->sh_offset = curr->GetOffset();
2269 curr->Header()->sh_size = curr->GetSize();
2271 m_Buffer.AppendT(curr->Header());
2272 curr = curr->GetNext();
2277 // Update ELF Header
2279 Elf_Ehdr *elfHeader = new (m_Buffer.GetPtr()) Elf_Ehdr;
2282 elfHeader->e_flags = EF_ARM_EABI_VER5;
2284 elfHeader->e_flags |= EF_ARM_SOFT_FLOAT;
2286 elfHeader->e_flags |= EF_ARM_VFP_FLOAT;
2289 elfHeader->e_shoff = shtOffset;
2290 elfHeader->e_shentsize = sizeof(Elf_Shdr);
2291 elfHeader->e_shnum = m_SectionCount;
2292 elfHeader->e_shstrndx = shstrtab->GetIndex();
2295 #ifdef FEATURE_GDBJIT_FRAME
2296 struct __attribute__((packed)) Length
2300 Length &operator=(UINT32 n)
2312 struct __attribute__((packed)) CIE
2318 UINT8 code_alignment_factor;
2319 INT8 data_alignment_factor;
2320 UINT8 return_address_register;
2321 UINT8 instructions[0];
2324 struct __attribute__((packed)) FDE
2328 PCODE initial_location;
2329 TADDR address_range;
2330 UINT8 instructions[0];
2333 static void BuildDebugFrame(Elf_Builder &elfBuilder, PCODE pCode, TADDR codeSize)
2335 #if defined(_TARGET_ARM_)
2336 const unsigned int code_alignment_factor = 2;
2337 const int data_alignment_factor = -4;
2340 // DW_CFA_def_cfa 13[sp], 0
2345 // DW_CFA_advance_loc 1
2347 // DW_CFA_def_cfa_offset 8
2349 // DW_CFA_offset 11(r11), -8(= -4 * 2)
2350 (0x02 << 6) | 0x0b, 0x02,
2351 // DW_CFA_offset 14(lr), -4(= -4 * 1)
2352 (0x02 << 6) | 0x0e, 0x01,
2353 // DW_CFA_def_cfa_register 11(r11)
2356 #elif defined(_TARGET_X86_)
2357 const unsigned int code_alignment_factor = 1;
2358 const int data_alignment_factor = -4;
2361 // DW_CFA_def_cfa 4(esp), 4
2363 // DW_CFA_offset 8(eip), -4(= -4 * 1)
2364 (0x02 << 6) | 0x08, 0x01,
2368 // DW_CFA_advance_loc 1
2370 // DW_CFA_def_cfa_offset 8
2372 // DW_CFA_offset 5(ebp), -8(= -4 * 2)
2373 (0x02 << 6) | 0x05, 0x02,
2374 // DW_CFA_def_cfa_register 5(ebp)
2377 #elif defined(_TARGET_AMD64_)
2378 const unsigned int code_alignment_factor = 1;
2379 const int data_alignment_factor = -8;
2382 // DW_CFA_def_cfa 7(rsp), 8
2384 // DW_CFA_offset 16, -16 (= -8 * 2)
2385 (0x02 << 6) | 0x10, 0x01,
2389 // DW_CFA_advance_loc(1)
2391 // DW_CFA_def_cfa_offset(16)
2393 // DW_CFA_offset 6, -16 (= -8 * 2)
2394 (0x02 << 6) | 0x06, 0x02,
2395 // DW_CFA_def_cfa_register(6)
2399 #error "Unsupported architecture"
2402 elfBuilder.OpenSection(".debug_frame", SHT_PROGBITS, 0);
2405 // Common Information Entry
2407 int cieLen = ALIGN_UP(sizeof(CIE) + sizeof(cieCode), ADDRESS_SIZE) + sizeof(Length);
2409 CIE *pCIE = elfBuilder.ReserveT<CIE>(cieLen);
2411 memset(pCIE, 0, cieLen);
2413 pCIE->length = cieLen - sizeof(Length);
2414 pCIE->id = 0xffffffff;
2416 pCIE->augmentation = 0;
2417 Leb128Encode(code_alignment_factor, reinterpret_cast<char *>(&pCIE->code_alignment_factor), 1);
2418 Leb128Encode(data_alignment_factor, reinterpret_cast<char *>(&pCIE->data_alignment_factor), 1);
2420 pCIE->return_address_register = 0;
2422 memcpy(&pCIE->instructions, cieCode, sizeof(cieCode));
2425 // Frame Description Entry
2427 int fdeLen = ALIGN_UP((sizeof(FDE) + sizeof(fdeCode)), ADDRESS_SIZE) + sizeof(Length);
2429 FDE *pFDE = elfBuilder.ReserveT<FDE>(fdeLen);
2431 memset(pFDE, 0, fdeLen);
2433 pFDE->length = fdeLen - sizeof(Length);
2435 pFDE->initial_location = pCode;
2436 pFDE->address_range = codeSize;
2437 memcpy(&pFDE->instructions, fdeCode, sizeof(fdeCode));
2439 elfBuilder.CloseSection();
2441 #endif // FEATURE_GDBJIT_FRAME
2443 /* Create ELF/DWARF debug info for jitted method */
2444 void NotifyGdb::MethodPrepared(MethodDesc* methodDescPtr)
2448 if (!tls_isSymReaderInProgress)
2450 tls_isSymReaderInProgress = true;
2451 NotifyGdb::OnMethodPrepared(methodDescPtr);
2452 tls_isSymReaderInProgress = false;
2458 EX_END_CATCH(SwallowAllExceptions);
2461 void NotifyGdb::OnMethodPrepared(MethodDesc* methodDescPtr)
2463 PCODE pCode = methodDescPtr->GetNativeCode();
2467 /* Get method name & size of jitted code */
2468 EECodeInfo codeInfo(pCode);
2469 if (!codeInfo.IsValid())
2474 TADDR codeSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfoToken());
2476 pCode = PCODEToPINSTR(pCode);
2478 /* Get module name */
2479 const Module* mod = methodDescPtr->GetMethodTable()->GetModule();
2480 SString modName = mod->GetFile()->GetPath();
2481 StackScratchBuffer scratch;
2482 const char* szModName = modName.GetUTF8(scratch);
2483 const char* szModuleFile = SplitFilename(szModName);
2485 int length = MultiByteToWideChar(CP_UTF8, 0, szModuleFile, -1, NULL, 0);
2488 NewArrayHolder<WCHAR> wszModuleFile = new WCHAR[length+1];
2489 length = MultiByteToWideChar(CP_UTF8, 0, szModuleFile, -1, wszModuleFile, length);
2494 bool bNotify = false;
2496 Elf_Builder elfBuilder;
2498 elfBuilder.Initialize(pCode, codeSize);
2500 #ifdef FEATURE_GDBJIT_FRAME
2501 if (g_pConfig->ShouldEmitDebugFrame())
2503 bool bEmitted = EmitFrameInfo(elfBuilder, pCode, codeSize);
2504 bNotify = bNotify || bEmitted;
2508 if (isListedModule(wszModuleFile))
2510 bool bEmitted = EmitDebugInfo(elfBuilder, methodDescPtr, pCode, codeSize);
2511 bNotify = bNotify || bEmitted;
2513 #ifdef FEATURE_GDBJIT_SYMTAB
2516 bool bEmitted = EmitSymtab(elfBuilder, methodDescPtr, pCode, codeSize);
2517 bNotify = bNotify || bEmitted;
2526 elfBuilder.Finalize();
2528 char *symfile_addr = NULL;
2529 size_t symfile_size = 0;
2531 symfile_addr = elfBuilder.Export(&symfile_size);
2534 LPCUTF8 methodName = methodDescPtr->GetName();
2536 if (g_pConfig->ShouldDumpElfOnMethod(methodName))
2538 DumpElf(methodName, symfile_addr, symfile_size);
2542 /* Create GDB JIT structures */
2543 NewHolder<jit_code_entry> jit_symbols = new jit_code_entry;
2545 /* Fill the new entry */
2546 jit_symbols->next_entry = jit_symbols->prev_entry = 0;
2547 jit_symbols->symfile_addr = symfile_addr;
2548 jit_symbols->symfile_size = symfile_size;
2550 /* Link into list */
2551 jit_code_entry *head = __jit_debug_descriptor.first_entry;
2552 __jit_debug_descriptor.first_entry = jit_symbols;
2555 jit_symbols->next_entry = head;
2556 head->prev_entry = jit_symbols;
2559 jit_symbols.SuppressRelease();
2561 /* Notify the debugger */
2562 __jit_debug_descriptor.relevant_entry = jit_symbols;
2563 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
2564 __jit_debug_register_code();
2567 #ifdef FEATURE_GDBJIT_FRAME
2568 bool NotifyGdb::EmitFrameInfo(Elf_Builder &elfBuilder, PCODE pCode, TADDR codeSize)
2570 BuildDebugFrame(elfBuilder, pCode, codeSize);
2573 #endif // FEATURE_GDBJIT_FRAME
2575 #ifdef FEATURE_GDBJIT_SYMTAB
2576 bool NotifyGdb::EmitSymtab(Elf_Builder &elfBuilder, MethodDesc* methodDescPtr, PCODE pCode, TADDR codeSize)
2578 NewArrayHolder<DebuggerILToNativeMap> map = nullptr;
2579 NewArrayHolder<Elf_Symbol> symbols = nullptr;
2580 NewArrayHolder<NewArrayHolder<char>> symbolNames = nullptr;
2585 LPCUTF8 methodName = methodDescPtr->GetName();
2587 if (GetMethodNativeMap(methodDescPtr, &numMap, map, NULL, NULL) == S_OK)
2589 int methodCount = countFuncs(map, numMap);
2590 symbolCount = methodCount + 1;
2591 symbols = new Elf_Symbol[symbolCount];
2593 if (methodCount > 1)
2594 symbolNames = new NewArrayHolder<char>[methodCount - 1];
2596 int startIndex = getNextPrologueIndex(0, map, numMap);
2598 int methodNameSize = strlen(methodName) + 10;
2600 for (int i = 1; i < symbolCount; ++i)
2602 int endIndex = getNextPrologueIndex(startIndex + 1, map, numMap);
2604 PCODE methodStart = map[startIndex].nativeStartOffset;
2605 TADDR methodSize = endIndex == -1 ? codeSize - methodStart : map[endIndex].nativeStartOffset - methodStart;
2609 symbols[i].m_name = methodName;
2613 int symbolNameIndex = i - 2;
2614 symbolNames[symbolNameIndex] = new char[methodNameSize];
2615 sprintf_s(symbolNames[symbolNameIndex], methodNameSize, "%s_%d", methodName, symbolNameIndex + 1);
2616 symbols[i].m_name = symbolNames[symbolNameIndex];
2619 symbols[i].m_value = pCode + methodStart;
2620 symbols[i].m_size = methodSize;
2622 startIndex = endIndex;
2628 symbols = new Elf_Symbol[symbolCount];
2630 symbols[1].m_name = methodName;
2631 symbols[1].m_value = pCode;
2632 symbols[1].m_size = codeSize;
2635 symbols[0].m_name = "";
2637 MemBuf sectSymTab, sectStrTab;
2639 if (!BuildStringTableSection(sectStrTab, symbols, symbolCount))
2644 if (!BuildSymbolTableSection(sectSymTab, pCode, codeSize, symbolCount - 1, symbols, symbolCount, 0))
2649 Elf_SectionTracker *strtab = elfBuilder.OpenSection(".strtab", SHT_STRTAB, 0);
2650 elfBuilder.Append(sectStrTab.MemPtr, sectStrTab.MemSize);
2651 elfBuilder.CloseSection();
2653 Elf_SectionTracker *symtab = elfBuilder.OpenSection(".symtab", SHT_SYMTAB, 0);
2654 elfBuilder.Append(sectSymTab.MemPtr, sectSymTab.MemSize);
2655 symtab->Header()->sh_link = strtab->GetIndex();
2656 symtab->Header()->sh_entsize = sizeof(Elf_Sym);
2657 elfBuilder.CloseSection();
2661 #endif // FEATURE_GDBJIT_SYMTAB
2663 bool NotifyGdb::EmitDebugInfo(Elf_Builder &elfBuilder, MethodDesc* methodDescPtr, PCODE pCode, TADDR codeSize)
2665 unsigned int thunkIndexBase = elfBuilder.GetSectionCount();
2667 LPCUTF8 methodName = methodDescPtr->GetName();
2669 int symbolCount = 0;
2670 NewArrayHolder<Elf_Symbol> symbolNames;
2672 unsigned int symInfoLen = 0;
2673 NewArrayHolder<SymbolsInfo> symInfo = nullptr;
2676 NewHolder<TK_TypeInfoMap> pTypeMap = new TK_TypeInfoMap();
2678 /* Get debug info for method from portable PDB */
2679 HRESULT hr = GetDebugInfoFromPDB(methodDescPtr, symInfo, symInfoLen, locals);
2680 if (FAILED(hr) || symInfoLen == 0)
2685 int method_count = countFuncs(symInfo, symInfoLen);
2686 FunctionMemberPtrArrayHolder method(method_count);
2688 CodeHeader* pCH = (CodeHeader*)pCode - 1;
2689 CalledMethod* pCalledMethods = reinterpret_cast<CalledMethod*>(pCH->GetCalledMethods());
2690 /* Collect addresses of thunks called by method */
2691 if (!CollectCalledMethods(pCalledMethods, (TADDR)methodDescPtr->GetNativeCode(), method, symbolNames, symbolCount))
2695 pCH->SetCalledMethods(NULL);
2697 MetaSig sig(methodDescPtr);
2698 int nArgsCount = sig.NumFixedArgs();
2702 unsigned int firstLineIndex = 0;
2703 for (;firstLineIndex < symInfoLen; firstLineIndex++) {
2704 if (symInfo[firstLineIndex].lineNumber != 0 && symInfo[firstLineIndex].lineNumber != HiddenLine) break;
2707 if (firstLineIndex >= symInfoLen)
2712 int start_index = getNextPrologueIndex(0, symInfo, symInfoLen);
2714 for (int method_index = 0; method_index < method.GetCount(); ++method_index)
2716 method[method_index] = new FunctionMember(methodDescPtr, locals.size, nArgsCount);
2718 int end_index = getNextPrologueIndex(start_index + 1, symInfo, symInfoLen);
2720 PCODE method_start = symInfo[start_index].nativeOffset;
2721 TADDR method_size = end_index == -1 ? codeSize - method_start : symInfo[end_index].nativeOffset - method_start;
2723 // method return type
2724 method[method_index]->m_member_type = GetArgTypeInfo(methodDescPtr, pTypeMap, 0, method);
2725 method[method_index]->m_sub_low_pc = pCode + method_start;
2726 method[method_index]->m_sub_high_pc = method_size;
2727 method[method_index]->lines = symInfo;
2728 method[method_index]->nlines = symInfoLen;
2729 method[method_index]->GetLocalsDebugInfo(pTypeMap, locals, symInfo[firstLineIndex].nativeOffset, method);
2730 size_t methodNameSize = strlen(methodName) + 10;
2731 method[method_index]->m_member_name = new char[methodNameSize];
2732 if (method_index == 0)
2733 sprintf_s(method[method_index]->m_member_name, methodNameSize, "%s", methodName);
2735 sprintf_s(method[method_index]->m_member_name, methodNameSize, "%s_%i", methodName, method_index);
2738 GetTypeInfoFromTypeHandle(TypeHandle(method[method_index]->md->GetMethodTable()), pTypeMap, method);
2740 start_index = end_index;
2743 MemBuf sectSymTab, sectStrTab, dbgInfo, dbgAbbrev, dbgPubname, dbgPubType, dbgLine,
2746 /* Build .debug_abbrev section */
2747 if (!BuildDebugAbbrev(dbgAbbrev))
2752 const char *cuPath = "";
2754 /* Build .debug_line section */
2755 if (!BuildLineTable(dbgLine, pCode, codeSize, symInfo, symInfoLen, cuPath))
2760 // Split full path to compile unit into file name and directory path
2761 const char *fileName = SplitFilename(cuPath);
2762 int dirLen = fileName - cuPath;
2763 NewArrayHolder<char> dirPath;
2766 dirPath = new char[dirLen];
2767 memcpy(dirPath, DebugStrings[1], dirLen - 1);
2768 dirPath[dirLen - 1] = '\0';
2770 DebugStrings[1] = fileName;
2771 DebugStrings[2] = dirPath ? (const char *)dirPath : "";
2773 /* Build .debug_str section */
2774 if (!BuildDebugStrings(dbgStr, pTypeMap, method))
2779 /* Build .debug_info section */
2780 if (!BuildDebugInfo(dbgInfo, pTypeMap, method))
2785 DebugStrings[1] = "";
2786 DebugStrings[2] = "";
2788 for (int i = 0; i < method.GetCount(); ++i)
2790 method[i]->lines = nullptr;
2791 method[i]->nlines = 0;
2794 /* Build .debug_pubname section */
2795 if (!BuildDebugPub(dbgPubname, methodName, dbgInfo.MemSize, 0x28))
2800 /* Build debug_pubtype section */
2801 if (!BuildDebugPub(dbgPubType, "int", dbgInfo.MemSize, 0x1a))
2806 /* Build .strtab section */
2807 symbolNames[0].m_name = "";
2808 for (int i = 0; i < method.GetCount(); ++i)
2810 symbolNames[1 + i].m_name = method[i]->m_member_name;
2811 symbolNames[1 + i].m_value = method[i]->m_sub_low_pc;
2812 symbolNames[1 + i].m_section = 1;
2813 symbolNames[1 + i].m_size = method[i]->m_sub_high_pc;
2815 if (!BuildStringTableSection(sectStrTab, symbolNames, symbolCount))
2819 /* Build .symtab section */
2820 if (!BuildSymbolTableSection(sectSymTab, pCode, codeSize, method.GetCount(), symbolNames, symbolCount, thunkIndexBase))
2825 for (int i = 1 + method.GetCount(); i < symbolCount; i++)
2829 sprintf_s(name, _countof(name), ".thunk_%i", i);
2831 Elf_SectionTracker *thunk = elfBuilder.OpenSection(name, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
2832 thunk->DisableHeaderUpdate();
2833 elfBuilder.CloseSection();
2836 elfBuilder.OpenSection(".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS);
2837 elfBuilder.Append(dbgStr.MemPtr, dbgStr.MemSize);
2838 elfBuilder.CloseSection();
2840 elfBuilder.OpenSection(".debug_abbrev", SHT_PROGBITS, 0);
2841 elfBuilder.Append(dbgAbbrev.MemPtr, dbgAbbrev.MemSize);
2842 elfBuilder.CloseSection();
2844 elfBuilder.OpenSection(".debug_info", SHT_PROGBITS, 0);
2845 elfBuilder.Append(dbgInfo.MemPtr, dbgInfo.MemSize);
2846 elfBuilder.CloseSection();
2848 elfBuilder.OpenSection(".debug_pubnames", SHT_PROGBITS, 0);
2849 elfBuilder.Append(dbgPubname.MemPtr, dbgPubname.MemSize);
2850 elfBuilder.CloseSection();
2852 elfBuilder.OpenSection(".debug_pubtypes", SHT_PROGBITS, 0);
2853 elfBuilder.Append(dbgPubType.MemPtr, dbgPubType.MemSize);
2854 elfBuilder.CloseSection();
2856 elfBuilder.OpenSection(".debug_line", SHT_PROGBITS, 0);
2857 elfBuilder.Append(dbgLine.MemPtr, dbgLine.MemSize);
2858 elfBuilder.CloseSection();
2860 Elf_SectionTracker *strtab = elfBuilder.OpenSection(".strtab", SHT_STRTAB, 0);
2861 elfBuilder.Append(sectStrTab.MemPtr, sectStrTab.MemSize);
2862 elfBuilder.CloseSection();
2864 Elf_SectionTracker *symtab = elfBuilder.OpenSection(".symtab", SHT_SYMTAB, 0);
2865 elfBuilder.Append(sectSymTab.MemPtr, sectSymTab.MemSize);
2866 symtab->Header()->sh_link = strtab->GetIndex();
2867 symtab->Header()->sh_entsize = sizeof(Elf_Sym);
2868 elfBuilder.CloseSection();
2873 void NotifyGdb::MethodPitched(MethodDesc* methodDescPtr)
2875 PCODE pCode = methodDescPtr->GetNativeCode();
2880 /* Find relevant entry */
2881 for (jit_code_entry* jit_symbols = __jit_debug_descriptor.first_entry; jit_symbols != 0; jit_symbols = jit_symbols->next_entry)
2883 const char* ptr = jit_symbols->symfile_addr;
2884 uint64_t size = jit_symbols->symfile_size;
2886 const Elf_Ehdr* pEhdr = reinterpret_cast<const Elf_Ehdr*>(ptr);
2887 const Elf_Shdr* pShdr = reinterpret_cast<const Elf_Shdr*>(ptr + pEhdr->e_shoff);
2888 pShdr += ELF_BUILDER_TEXT_SECTION_INDEX; // bump to .text section
2889 if (pShdr->sh_addr == pCode)
2891 /* Notify the debugger */
2892 __jit_debug_descriptor.relevant_entry = jit_symbols;
2893 __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
2894 __jit_debug_register_code();
2899 /* Unlink from list */
2900 if (jit_symbols->prev_entry == 0)
2901 __jit_debug_descriptor.first_entry = jit_symbols->next_entry;
2903 jit_symbols->prev_entry->next_entry = jit_symbols->next_entry;
2910 /* Build the DWARF .debug_line section */
2911 bool NotifyGdb::BuildLineTable(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines,
2912 const char * &cuPath)
2914 MemBuf fileTable, lineProg;
2916 /* Build file table */
2917 if (!BuildFileTable(fileTable, lines, nlines, cuPath))
2919 /* Build line info program */
2920 if (!BuildLineProg(lineProg, startAddr, codeSize, lines, nlines))
2925 buf.MemSize = sizeof(DwarfLineNumHeader) + fileTable.MemSize + lineProg.MemSize;
2926 buf.MemPtr = new char[buf.MemSize];
2928 /* Fill the line info header */
2929 DwarfLineNumHeader* header = reinterpret_cast<DwarfLineNumHeader*>(buf.MemPtr.GetValue());
2930 memcpy(buf.MemPtr, &LineNumHeader, sizeof(DwarfLineNumHeader));
2931 header->m_length = buf.MemSize - sizeof(header->m_length);
2933 // Set m_hdr_field to the number of bytes following the m_hdr_field field to the beginning of the first byte of
2934 // the line number program itself.
2935 header->m_hdr_length = sizeof(DwarfLineNumHeader)
2936 - sizeof(header->m_length)
2937 - sizeof(header->m_version)
2938 - sizeof(header->m_hdr_length)
2939 + fileTable.MemSize;
2941 /* copy file table */
2942 memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader), fileTable.MemPtr, fileTable.MemSize);
2943 /* copy line program */
2944 memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader) + fileTable.MemSize, lineProg.MemPtr, lineProg.MemSize);
2949 // A class for building Directory Table and File Table (in .debug_line section) from a list of files
2950 class NotifyGdb::FileTableBuilder
2954 NewArrayHolder< NewArrayHolder<char> > m_dirs;
2963 NewArrayHolder<FileEntry> m_files;
2966 int FindDir(const char *name) const
2968 for (int i = 0; i < m_dirs_count; ++i)
2970 if (strcmp(m_dirs[i], name) == 0)
2976 int FindFile(const char *path) const
2978 for (int i = 0; i < m_files_count; ++i)
2980 if (strcmp(m_files[i].path, path) == 0)
2988 FileTableBuilder(int capacity) :
2989 m_capacity(capacity),
2990 m_dirs(new NewArrayHolder<char>[capacity]),
2992 m_files(new FileEntry[capacity]),
2997 int Add(const char *path)
3000 int i = FindFile(path);
3004 if (m_files_count >= m_capacity)
3007 // Add new file entry
3008 m_files[m_files_count].path = path;
3009 const char *filename = SplitFilename(path);
3010 m_files[m_files_count].name = filename;
3011 int dirLen = filename - path;
3014 m_files[m_files_count].dir = 0;
3015 return m_files_count++;
3018 // Construct directory path
3019 NewArrayHolder<char> dirName = new char[dirLen + 1];
3020 int delimiterDelta = dirLen == 1 ? 0 : 1; // Avoid empty dir entry when file is at Unix root /
3021 memcpy(dirName, path, dirLen - delimiterDelta);
3022 dirName[dirLen - delimiterDelta] = '\0';
3024 // Try to find existing directory entry
3025 i = FindDir(dirName);
3028 m_files[m_files_count].dir = i + 1;
3029 return m_files_count++;
3032 // Create new directory entry
3033 if (m_dirs_count >= m_capacity)
3036 m_dirs[m_dirs_count++] = dirName.Extract();
3038 m_files[m_files_count].dir = m_dirs_count;
3039 return m_files_count++;
3042 void Build(MemBuf& buf)
3044 unsigned totalSize = 0;
3046 // Compute buffer size
3047 for (unsigned i = 0; i < m_dirs_count; ++i)
3048 totalSize += strlen(m_dirs[i]) + 1;
3052 for (unsigned i = 0; i < m_files_count; ++i)
3054 int len = Leb128Encode(static_cast<uint32_t>(m_files[i].dir), cnv_buf, sizeof(cnv_buf));
3055 totalSize += strlen(m_files[i].name) + 1 + len + 2;
3060 buf.MemSize = totalSize;
3061 buf.MemPtr = new char[buf.MemSize];
3063 char *ptr = buf.MemPtr;
3065 for (unsigned i = 0; i < m_dirs_count; ++i)
3067 strcpy(ptr, m_dirs[i]);
3068 ptr += strlen(m_dirs[i]) + 1;
3070 // final zero byte for directory table
3073 for (unsigned i = 0; i < m_files_count; ++i)
3075 strcpy(ptr, m_files[i].name);
3076 ptr += strlen(m_files[i].name) + 1;
3078 // Index in directory table
3079 int len = Leb128Encode(static_cast<uint32_t>(m_files[i].dir), cnv_buf, sizeof(cnv_buf));
3080 memcpy(ptr, cnv_buf, len);
3083 // Two LEB128 entries which we don't care
3092 /* Buid the source files table for DWARF source line info */
3093 bool NotifyGdb::BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines, const char * &cuPath)
3095 FileTableBuilder fileTable(nlines);
3098 for (unsigned i = 0; i < nlines; ++i)
3100 const char* fileName = lines[i].fileName;
3102 if (fileName[0] == '\0')
3105 if (*cuPath == '\0') // Use first non-empty filename as compile unit
3108 lines[i].fileIndex = fileTable.Add(fileName);
3111 fileTable.Build(buf);
3116 /* Command to set absolute address */
3117 void NotifyGdb::IssueSetAddress(char*& ptr, PCODE addr)
3120 *ptr++ = ADDRESS_SIZE + 1;
3121 *ptr++ = DW_LNE_set_address;
3122 *reinterpret_cast<PCODE*>(ptr) = addr;
3123 ptr += ADDRESS_SIZE;
3126 /* End of line program */
3127 void NotifyGdb::IssueEndOfSequence(char*& ptr)
3131 *ptr++ = DW_LNE_end_sequence;
3134 /* Command w/o parameters */
3135 void NotifyGdb::IssueSimpleCommand(char*& ptr, uint8_t command)
3140 /* Command with one LEB128 parameter */
3141 void NotifyGdb::IssueParamCommand(char*& ptr, uint8_t command, char* param, int param_size)
3144 while (param_size-- > 0)
3150 static void fixLineMapping(SymbolsInfo* lines, unsigned nlines)
3152 // Fix EPILOGUE line mapping
3154 for (int i = 0; i < nlines; ++i)
3156 if (lines[i].lineNumber == HiddenLine)
3158 if (lines[i].ilOffset == ICorDebugInfo::PROLOG) // will be fixed in next step
3164 if (lines[i].lineNumber == 0)
3166 lines[i].lineNumber = prevLine;
3170 prevLine = lines[i].lineNumber;
3174 // Fix PROLOGUE line mapping
3175 prevLine = lines[nlines - 1].lineNumber;
3176 for (int i = nlines - 1; i >= 0; --i)
3178 if (lines[i].lineNumber == HiddenLine)
3180 if (lines[i].lineNumber == 0)
3181 lines[i].lineNumber = prevLine;
3183 prevLine = lines[i].lineNumber;
3186 for (int i = 0; i < nlines; ++i)
3188 if (lines[i].lineNumber == HiddenLine)
3190 lines[i].lineNumber = 0;
3191 if (i + 1 < nlines && lines[i + 1].ilOffset == ICorDebugInfo::NO_MAPPING)
3192 lines[i + 1].lineNumber = 0;
3197 /* Build program for DWARF source line section */
3198 bool NotifyGdb::BuildLineProg(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines)
3200 static char cnv_buf[16];
3202 /* reserve memory assuming worst case: set address, advance line command, set proglogue/epilogue and copy for each line */
3204 + 6 /* set file command */
3205 + nlines * 6 /* advance line commands */
3206 + nlines * (3 + ADDRESS_SIZE) /* set address commands */
3207 + nlines * 1 /* set prologue end or epilogue begin commands */
3208 + nlines * 1 /* copy commands */
3209 + 6 /* advance PC command */
3210 + 3; /* end of sequence command */
3211 buf.MemPtr = new char[buf.MemSize];
3212 char* ptr = buf.MemPtr;
3214 if (buf.MemPtr == nullptr)
3217 fixLineMapping(lines, nlines);
3219 int prevLine = 1, prevFile = 0;
3221 for (int i = 0; i < nlines; ++i)
3223 /* different source file */
3224 if (lines[i].fileIndex != prevFile)
3226 int len = Leb128Encode(static_cast<uint32_t>(lines[i].fileIndex+1), cnv_buf, sizeof(cnv_buf));
3227 IssueParamCommand(ptr, DW_LNS_set_file, cnv_buf, len);
3228 prevFile = lines[i].fileIndex;
3231 // GCC don't use the is_prologue_end flag to mark the first instruction after the prologue.
3232 // Instead of it it is issueing a line table entry for the first instruction of the prologue
3233 // and one for the first instruction after the prologue.
3234 // We do not want to confuse the debugger so we have to avoid adding a line in such case.
3235 if (i > 0 && lines[i - 1].nativeOffset == lines[i].nativeOffset)
3238 IssueSetAddress(ptr, startAddr + lines[i].nativeOffset);
3240 if (lines[i].lineNumber != prevLine) {
3241 int len = Leb128Encode(static_cast<int32_t>(lines[i].lineNumber - prevLine), cnv_buf, sizeof(cnv_buf));
3242 IssueParamCommand(ptr, DW_LNS_advance_line, cnv_buf, len);
3243 prevLine = lines[i].lineNumber;
3246 if (lines[i].ilOffset == ICorDebugInfo::EPILOG)
3247 IssueSimpleCommand(ptr, DW_LNS_set_epilogue_begin);
3248 else if (i > 0 && lines[i - 1].ilOffset == ICorDebugInfo::PROLOG)
3249 IssueSimpleCommand(ptr, DW_LNS_set_prologue_end);
3251 IssueParamCommand(ptr, DW_LNS_copy, NULL, 0);
3254 int lastAddr = nlines > 0 ? lines[nlines - 1].nativeOffset : 0;
3256 // Advance PC to the end of function
3257 if (lastAddr < codeSize) {
3258 int len = Leb128Encode(static_cast<uint32_t>(codeSize - lastAddr), cnv_buf, sizeof(cnv_buf));
3259 IssueParamCommand(ptr, DW_LNS_advance_pc, cnv_buf, len);
3262 IssueEndOfSequence(ptr);
3264 buf.MemSize = ptr - buf.MemPtr;
3268 /* Build the DWARF .debug_str section */
3269 bool NotifyGdb::BuildDebugStrings(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMemberPtrArrayHolder &method)
3271 int totalLength = 0;
3273 /* calculate total section size */
3274 for (int i = 0; i < DebugStringCount; ++i)
3276 totalLength += strlen(DebugStrings[i]) + 1;
3279 for (int i = 0; i < method.GetCount(); ++i)
3281 method[i]->DumpStrings(nullptr, totalLength);
3285 auto iter = pTypeMap->Begin();
3286 while (iter != pTypeMap->End())
3288 TypeInfoBase *typeInfo = iter->Value();
3289 typeInfo->DumpStrings(nullptr, totalLength);
3294 buf.MemSize = totalLength;
3295 buf.MemPtr = new char[totalLength];
3298 char* bufPtr = buf.MemPtr;
3300 for (int i = 0; i < DebugStringCount; ++i)
3302 strcpy(bufPtr + offset, DebugStrings[i]);
3303 offset += strlen(DebugStrings[i]) + 1;
3306 for (int i = 0; i < method.GetCount(); ++i)
3308 method[i]->DumpStrings(bufPtr, offset);
3312 auto iter = pTypeMap->Begin();
3313 while (iter != pTypeMap->End())
3315 TypeInfoBase *typeInfo = iter->Value();
3316 typeInfo->DumpStrings(bufPtr, offset);
3324 /* Build the DWARF .debug_abbrev section */
3325 bool NotifyGdb::BuildDebugAbbrev(MemBuf& buf)
3327 buf.MemPtr = new char[AbbrevTableSize];
3328 buf.MemSize = AbbrevTableSize;
3330 memcpy(buf.MemPtr, AbbrevTable, AbbrevTableSize);
3334 /* Build tge DWARF .debug_info section */
3335 bool NotifyGdb::BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMemberPtrArrayHolder &method)
3337 int totalTypeVarSubSize = 0;
3339 auto iter = pTypeMap->Begin();
3340 while (iter != pTypeMap->End())
3342 TypeInfoBase *typeInfo = iter->Value();
3343 typeInfo->DumpDebugInfo(nullptr, totalTypeVarSubSize);
3348 for (int i = 0; i < method.GetCount(); ++i)
3350 method[i]->DumpDebugInfo(nullptr, totalTypeVarSubSize);
3353 //int locSize = GetArgsAndLocalsLen(argsDebug, argsDebugSize, localsDebug, localsDebugSize);
3354 buf.MemSize = sizeof(DwarfCompUnit) + sizeof(DebugInfoCU) + totalTypeVarSubSize + 2;
3355 buf.MemPtr = new char[buf.MemSize];
3358 /* Compile uint header */
3359 DwarfCompUnit* cu = reinterpret_cast<DwarfCompUnit*>(buf.MemPtr.GetValue());
3360 cu->m_length = buf.MemSize - sizeof(uint32_t);
3362 cu->m_abbrev_offset = 0;
3363 cu->m_addr_size = ADDRESS_SIZE;
3364 offset += sizeof(DwarfCompUnit);
3366 reinterpret_cast<DebugInfoCU*>(buf.MemPtr + offset);
3367 memcpy(buf.MemPtr + offset, &debugInfoCU, sizeof(DebugInfoCU));
3368 offset += sizeof(DebugInfoCU);
3369 diCU->m_prod_off = 0;
3370 diCU->m_cu_name = strlen(DebugStrings[0]) + 1;
3371 diCU->m_cu_dir = diCU->m_cu_name + strlen(DebugStrings[1]) + 1;
3373 auto iter = pTypeMap->Begin();
3374 while (iter != pTypeMap->End())
3376 TypeInfoBase *typeInfo = iter->Value();
3377 typeInfo->DumpDebugInfo(buf.MemPtr, offset);
3381 for (int i = 0; i < method.GetCount(); ++i)
3383 if (!method[i]->IsDumped())
3385 method[i]->DumpDebugInfo(buf.MemPtr, offset);
3389 method[i]->DumpDebugInfo(buf.MemPtr, method[i]->m_entry_offset);
3392 memset(buf.MemPtr + offset, 0, buf.MemSize - offset);
3396 /* Build the DWARF lookup section */
3397 bool NotifyGdb::BuildDebugPub(MemBuf& buf, const char* name, uint32_t size, uint32_t die_offset)
3399 uint32_t length = sizeof(DwarfPubHeader) + sizeof(uint32_t) + strlen(name) + 1 + sizeof(uint32_t);
3401 buf.MemSize = length;
3402 buf.MemPtr = new char[buf.MemSize];
3404 DwarfPubHeader* header = reinterpret_cast<DwarfPubHeader*>(buf.MemPtr.GetValue());
3405 header->m_length = length - sizeof(uint32_t);
3406 header->m_version = 2;
3407 header->m_debug_info_off = 0;
3408 header->m_debug_info_len = size;
3409 *reinterpret_cast<uint32_t*>(buf.MemPtr + sizeof(DwarfPubHeader)) = die_offset;
3410 strcpy(buf.MemPtr + sizeof(DwarfPubHeader) + sizeof(uint32_t), name);
3411 *reinterpret_cast<uint32_t*>(buf.MemPtr + length - sizeof(uint32_t)) = 0;
3416 /* Store addresses and names of the called methods into symbol table */
3417 bool NotifyGdb::CollectCalledMethods(CalledMethod* pCalledMethods,
3419 FunctionMemberPtrArrayHolder &method,
3420 NewArrayHolder<Elf_Symbol> &symbolNames,
3423 AddrSet tmpCodeAddrs;
3425 if (!codeAddrs.Contains(nativeCode))
3426 codeAddrs.Add(nativeCode);
3428 CalledMethod* pList = pCalledMethods;
3430 /* count called methods */
3431 while (pList != NULL)
3433 TADDR callAddr = (TADDR)pList->GetCallAddr();
3434 if (!tmpCodeAddrs.Contains(callAddr) && !codeAddrs.Contains(callAddr)) {
3435 tmpCodeAddrs.Add(callAddr);
3437 pList = pList->GetNext();
3440 symbolCount = 1 + method.GetCount() + tmpCodeAddrs.GetCount();
3441 symbolNames = new Elf_Symbol[symbolCount];
3443 pList = pCalledMethods;
3444 int i = 1 + method.GetCount();
3445 while (i < symbolCount && pList != NULL)
3447 TADDR callAddr = (TADDR)pList->GetCallAddr();
3448 if (!codeAddrs.Contains(callAddr))
3450 MethodDesc* pMD = pList->GetMethodDesc();
3451 LPCUTF8 methodName = pMD->GetName();
3452 int symbolNameLength = strlen(methodName) + sizeof("__thunk_");
3453 symbolNames[i].m_symbol_name = new char[symbolNameLength];
3454 symbolNames[i].m_name = symbolNames[i].m_symbol_name;
3455 sprintf_s((char*)symbolNames[i].m_name, symbolNameLength, "__thunk_%s", methodName);
3456 symbolNames[i].m_value = callAddr;
3458 codeAddrs.Add(callAddr);
3460 pList = pList->GetNext();
3466 /* Build ELF .strtab section */
3467 bool NotifyGdb::BuildStringTableSection(MemBuf& buf, NewArrayHolder<Elf_Symbol> &symbolNames, int symbolCount)
3470 for (int i = 0; i < symbolCount; ++i)
3471 len += strlen(symbolNames[i].m_name) + 1;
3472 len++; // end table with zero-length string
3475 buf.MemPtr = new char[buf.MemSize];
3477 char* ptr = buf.MemPtr;
3478 for (int i = 0; i < symbolCount; ++i)
3480 symbolNames[i].m_off = ptr - buf.MemPtr;
3481 strcpy(ptr, symbolNames[i].m_name);
3482 ptr += strlen(symbolNames[i].m_name) + 1;
3484 buf.MemPtr[buf.MemSize-1] = 0;
3489 /* Build ELF .symtab section */
3490 bool NotifyGdb::BuildSymbolTableSection(MemBuf& buf, PCODE addr, TADDR codeSize, int methodCount,
3491 NewArrayHolder<Elf_Symbol> &symbolNames, int symbolCount,
3492 unsigned int thunkIndexBase)
3494 buf.MemSize = symbolCount * sizeof(Elf_Sym);
3495 buf.MemPtr = new char[buf.MemSize];
3497 Elf_Sym *sym = reinterpret_cast<Elf_Sym*>(buf.MemPtr.GetValue());
3501 sym[0].st_other = 0;
3502 sym[0].st_value = 0;
3504 sym[0].st_shndx = SHN_UNDEF;
3506 for (int i = 1; i < 1 + methodCount; ++i)
3508 sym[i].st_name = symbolNames[i].m_off;
3509 sym[i].setBindingAndType(STB_GLOBAL, STT_FUNC);
3510 sym[i].st_other = 0;
3511 sym[i].st_value = PINSTRToPCODE(symbolNames[i].m_value - addr);
3512 sym[i].st_shndx = ELF_BUILDER_TEXT_SECTION_INDEX;
3513 sym[i].st_size = symbolNames[i].m_size;
3516 for (int i = 1 + methodCount; i < symbolCount; ++i)
3518 sym[i].st_name = symbolNames[i].m_off;
3519 sym[i].setBindingAndType(STB_GLOBAL, STT_FUNC);
3520 sym[i].st_other = 0;
3521 sym[i].st_shndx = thunkIndexBase + (i - (1 + methodCount)); // .thunks section index
3524 sym[i].st_value = 1; // for THUMB code
3526 sym[i].st_value = 0;
3532 /* Split file name part from the full path */
3533 const char * NotifyGdb::SplitFilename(const char* path)
3535 // Search for the last directory delimiter (Windows or Unix)
3536 const char *pSlash = nullptr;
3537 for (const char *p = path; *p != '\0'; p++)
3539 if (*p == '/' || *p == '\\')
3543 return pSlash ? pSlash + 1 : path;
3546 /* ELF 32bit header */
3547 Elf32_Ehdr::Elf32_Ehdr()
3549 e_ident[EI_MAG0] = ElfMagic[0];
3550 e_ident[EI_MAG1] = ElfMagic[1];
3551 e_ident[EI_MAG2] = ElfMagic[2];
3552 e_ident[EI_MAG3] = ElfMagic[3];
3553 e_ident[EI_CLASS] = ELFCLASS32;
3554 e_ident[EI_DATA] = ELFDATA2LSB;
3555 e_ident[EI_VERSION] = EV_CURRENT;
3556 e_ident[EI_OSABI] = ELFOSABI_NONE;
3557 e_ident[EI_ABIVERSION] = 0;
3558 for (int i = EI_PAD; i < EI_NIDENT; ++i)
3562 #if defined(_TARGET_X86_)
3564 #elif defined(_TARGET_ARM_)
3571 e_ehsize = sizeof(Elf32_Ehdr);
3576 /* ELF 64bit header */
3577 Elf64_Ehdr::Elf64_Ehdr()
3579 e_ident[EI_MAG0] = ElfMagic[0];
3580 e_ident[EI_MAG1] = ElfMagic[1];
3581 e_ident[EI_MAG2] = ElfMagic[2];
3582 e_ident[EI_MAG3] = ElfMagic[3];
3583 e_ident[EI_CLASS] = ELFCLASS64;
3584 e_ident[EI_DATA] = ELFDATA2LSB;
3585 e_ident[EI_VERSION] = EV_CURRENT;
3586 e_ident[EI_OSABI] = ELFOSABI_NONE;
3587 e_ident[EI_ABIVERSION] = 0;
3588 for (int i = EI_PAD; i < EI_NIDENT; ++i)
3592 #if defined(_TARGET_AMD64_)
3593 e_machine = EM_X86_64;
3594 #elif defined(_TARGET_ARM64_)
3595 e_machine = EM_AARCH64;
3601 e_ehsize = sizeof(Elf64_Ehdr);