From: kvochko Date: Fri, 21 Oct 2016 09:17:38 +0000 (+0300) Subject: [GDBJIT] Generate more complete debug information (#7617) X-Git-Tag: accepted/tizen/base/20180629.140029~3283 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3a9ee939d1043f8347ce94a49bb38d517e3bb52d;p=platform%2Fupstream%2Fcoreclr.git [GDBJIT] Generate more complete debug information (#7617) * Implement support for classes * Add support for 'this' argument type * System.String debug info * Functions are generated as class members in DWARF, use TypeKey as type key. * Initial support of references * Support 'this' artificial argument in gdbjit * Resolve issue with recursive types in gdbjit * DWARF classes are terminated even if they don't have children * Fix System.Char encoding. * Add support static fields for classes * Add support for single dimension arrays. * Simplify signature parsing. * Preliminary support for multidimensional arrays. * Add support of value types --- diff --git a/src/vm/gdbjit.cpp b/src/vm/gdbjit.cpp index 0aa2fcc..04c6985 100644 --- a/src/vm/gdbjit.cpp +++ b/src/vm/gdbjit.cpp @@ -15,151 +15,251 @@ #include "gdbjit.h" #include "gdbjithelpers.h" -void GetTypeInfoFromSignature(PCCOR_SIGNATURE typePtr, - unsigned typeLen, - unsigned ilIndex, - const char** typeStr, - ULONG& typeSize, - int& typeEncoding) -{ - unsigned numArgs; - PCCOR_SIGNATURE typeEnd = typePtr + typeLen; - - // get the calling convention out - CorSigUncompressData(typePtr); - - numArgs = CorSigUncompressData(typePtr); - int typ; - mdToken tk; - int i = 0; - while (typePtr < typeEnd) - { - if (i > ilIndex) +TypeInfoBase* +GetTypeInfoFromTypeHandle(TypeHandle typeHandle, NotifyGdb::PTK_TypeInfoMap pTypeMap) +{ + TypeInfoBase *typeInfo = nullptr; + TypeKey key = typeHandle.GetTypeKey(); + PTR_MethodTable pMT = typeHandle.GetMethodTable(); + + if (pTypeMap->Lookup(&key, &typeInfo)) + { + return typeInfo; + } + + CorElementType corType = typeHandle.GetSignatureCorElementType(); + switch (corType) + { + case ELEMENT_TYPE_VOID: + case ELEMENT_TYPE_BOOLEAN: + case ELEMENT_TYPE_CHAR: + case ELEMENT_TYPE_I1: + case ELEMENT_TYPE_U1: + case ELEMENT_TYPE_I2: + case ELEMENT_TYPE_U2: + case ELEMENT_TYPE_I4: + case ELEMENT_TYPE_U4: + case ELEMENT_TYPE_I8: + case ELEMENT_TYPE_U8: + case ELEMENT_TYPE_R4: + case ELEMENT_TYPE_R8: + case ELEMENT_TYPE_U: + case ELEMENT_TYPE_I: + typeInfo = new (nothrow) PrimitiveTypeInfo(typeHandle, CorElementTypeToDWEncoding[corType]); + if (typeInfo == nullptr) + return nullptr; + + typeInfo->m_type_size = CorTypeInfo::Size(corType); + break; + case ELEMENT_TYPE_VALUETYPE: + case ELEMENT_TYPE_CLASS: + { + ApproxFieldDescIterator fieldDescIterator(pMT, + pMT->IsString() ? ApproxFieldDescIterator::INSTANCE_FIELDS : ApproxFieldDescIterator::ALL_FIELDS); + ULONG cFields = fieldDescIterator.Count(); + + typeInfo = new (nothrow) ClassTypeInfo(typeHandle, cFields); + + if (typeInfo == nullptr) + return nullptr; + + typeInfo->m_type_size = typeHandle.AsMethodTable()->GetClass()->GetSize(); - SigParser sigTemp(typePtr); - sigTemp.PeekElemTypeSize(&typeSize); + pTypeMap->Add(typeInfo->GetTypeKey(), typeInfo); + typeInfo->CalculateName(); - switch (typ = *typePtr) + RefTypeInfo* refTypeInfo = nullptr; + if (!typeHandle.IsValueType()) + { + // name the type + refTypeInfo = new (nothrow) RefTypeInfo(typeHandle, typeInfo); + if (refTypeInfo == nullptr) + { + return nullptr; + } + refTypeInfo->m_type_size = sizeof(TADDR); + refTypeInfo->m_value_type = typeInfo; + refTypeInfo->CalculateName(); + + pTypeMap->Add(refTypeInfo->GetTypeKey(), refTypeInfo); + } + // + // Now fill in the array + // + FieldDesc *pField; + + for (ULONG i = 0; i < cFields; i++) + { + pField = fieldDescIterator.Next(); + ClassTypeInfo *info = static_cast(typeInfo); + + LPCUTF8 szName = pField->GetName(); + info->members[i].m_member_name = new char[strlen(szName) + 1]; + strcpy(info->members[i].m_member_name, szName); + if (!pField->IsStatic()) + { + info->members[i].m_member_offset = (ULONG)pField->GetOffset(); + if (!typeHandle.IsValueType()) + info->members[i].m_member_offset += Object::GetOffsetOfFirstField(); + } + else + { + PTR_BYTE base = 0; + if (!pField->IsRVA()) + { + MethodTable* pMT = pField->GetEnclosingMethodTable(); + base = pField->GetBaseInDomainLocalModule(pMT->GetDomainLocalModule(NULL)); + } + PTR_VOID pAddress = pField->GetStaticAddressHandle((PTR_VOID)dac_cast(base)); + info->members[i].m_static_member_address = dac_cast(pAddress); + } + + info->members[i].m_member_type = + GetTypeInfoFromTypeHandle(pField->GetExactFieldType(typeHandle), pTypeMap); + + // handle the System.String case: + // coerce type of the second field into array type + if (pMT->IsString() && i == 1) + { + TypeInfoBase* elemTypeInfo = info->members[1].m_member_type; + TypeInfoBase* arrayTypeInfo = new (nothrow) ArrayTypeInfo(typeHandle.MakeSZArray(), 0, elemTypeInfo); + if (arrayTypeInfo == nullptr) + return nullptr; + info->members[1].m_member_type = arrayTypeInfo; + } + } + if (refTypeInfo) + return refTypeInfo; + else + return typeInfo; + } + case ELEMENT_TYPE_BYREF: { - case ELEMENT_TYPE_VOID: - *typeStr = "void"; - typeEncoding = DW_ATE_address; - break; - case ELEMENT_TYPE_BOOLEAN: - *typeStr = "bool"; - typeEncoding = DW_ATE_boolean; - break; - case ELEMENT_TYPE_CHAR: - *typeStr = "char"; - typeEncoding = DW_ATE_signed; - break; - case ELEMENT_TYPE_I1: - *typeStr = "int8"; - typeEncoding = DW_ATE_signed; - break; - case ELEMENT_TYPE_U1: - *typeStr = "uint8"; - typeEncoding = DW_ATE_unsigned; - break; - case ELEMENT_TYPE_I2: - *typeStr = "int16"; - typeEncoding = DW_ATE_signed; - break; - case ELEMENT_TYPE_U2: - *typeStr = "uint16"; - typeEncoding = DW_ATE_unsigned; - break; - case ELEMENT_TYPE_I4: - *typeStr = "int32"; - typeEncoding = DW_ATE_signed; - break; - case ELEMENT_TYPE_U4: - *typeStr = "uint32"; - typeEncoding = DW_ATE_unsigned; - break; - case ELEMENT_TYPE_I8: - *typeStr = "int64"; - typeEncoding = DW_ATE_signed; - break; - case ELEMENT_TYPE_U8: - *typeStr = "uint64"; - typeEncoding = DW_ATE_unsigned; - break; - case ELEMENT_TYPE_R4: - *typeStr = "float32"; - typeEncoding = DW_ATE_float; - break; - case ELEMENT_TYPE_R8: - *typeStr = "float64"; - typeEncoding = DW_ATE_float; - break; - case ELEMENT_TYPE_U: - *typeStr = "native uint"; - typeEncoding = DW_ATE_unsigned; - break; - case ELEMENT_TYPE_I: - *typeStr = "native int"; - typeEncoding = DW_ATE_signed; - break; - case ELEMENT_TYPE_CLASS: - *typeStr = "class"; - typeEncoding = DW_ATE_address; // FIXME: Add DW_TAG_class_type - typePtr += CorSigUncompressToken(typePtr, &tk); - break; - case ELEMENT_TYPE_ARRAY: - case ELEMENT_TYPE_SZARRAY: - *typeStr = "array"; - typeEncoding = DW_ATE_address; // FIXME: Add arr type - typePtr++; - break; - default: - *typeStr = "unknown"; - typeEncoding = DW_ATE_address; + TypeInfoBase* valTypeInfo = GetTypeInfoFromTypeHandle(typeHandle.GetTypeParam(), pTypeMap); + typeInfo = new (nothrow) RefTypeInfo(typeHandle, valTypeInfo); + if (typeInfo == nullptr) + return nullptr; + typeInfo->m_type_size = sizeof(TADDR); + typeInfo->m_type_offset = valTypeInfo->m_type_offset; + break; } - i++; - typePtr++; + case ELEMENT_TYPE_ARRAY: + case ELEMENT_TYPE_SZARRAY: + { + typeInfo = new (nothrow) ClassTypeInfo(typeHandle, 2); + if (typeInfo == nullptr) + return nullptr; + typeInfo->m_type_size = pMT->GetClass()->GetSize(); + + typeInfo->CalculateName(); + RefTypeInfo *refTypeInfo = new (nothrow) RefTypeInfo(typeHandle, typeInfo); + if (refTypeInfo == nullptr) + { + return nullptr; + } + refTypeInfo->m_type_size = sizeof(TADDR); + refTypeInfo->m_value_type = typeInfo; + refTypeInfo->CalculateName(); + + pTypeMap->Add(refTypeInfo->GetTypeKey(), refTypeInfo); + + TypeInfoBase* lengthTypeInfo = GetTypeInfoFromTypeHandle( + TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_I4)), pTypeMap); + + TypeInfoBase* valTypeInfo = GetTypeInfoFromTypeHandle(typeHandle.GetTypeParam(), pTypeMap); + TypeInfoBase* arrayTypeInfo = new (nothrow) ArrayTypeInfo(typeHandle, 0, valTypeInfo); + if (arrayTypeInfo == nullptr) + return nullptr; + + ClassTypeInfo *info = static_cast(typeInfo); + + info->members[0].m_member_name = new (nothrow) char[16]; + strcpy(info->members[0].m_member_name, "m_NumComponents"); + info->members[0].m_member_offset = ArrayBase::GetOffsetOfNumComponents(); + info->members[0].m_member_type = lengthTypeInfo; + info->members[0].m_member_type->m_type_size = sizeof(DWORD); + + info->members[1].m_member_name = new (nothrow) char[7]; + strcpy(info->members[1].m_member_name, "m_Data"); + info->members[1].m_member_offset = ArrayBase::GetDataPtrOffset(pMT); + info->members[1].m_member_type = arrayTypeInfo; + info->members[1].m_member_type->m_type_size = sizeof(TADDR); + + return refTypeInfo; + } + default: + ASSERT(0 && "not implemented"); + break; } + // name the type + if (corType == ELEMENT_TYPE_CHAR) + { + typeInfo->m_type_name = new char[9]; + strcpy(typeInfo->m_type_name, "char16_t"); + } + else + { + typeInfo->CalculateName(); + } + pTypeMap->Add(typeInfo->GetTypeKey(), typeInfo); + return typeInfo; } -void GetArgTypeInfo(MethodDesc* MethodDescPtr, - unsigned ilIndex, - const char** typeStr, - ULONG& typeSize, - int& typeEncoding) +TypeInfoBase* GetArgTypeInfo(MethodDesc* MethodDescPtr, + NotifyGdb::PTK_TypeInfoMap pTypeMap, + unsigned ilIndex) { - DWORD cbSigLen; - PCCOR_SIGNATURE pComSig; - MethodDescPtr->GetSig(&pComSig, &cbSigLen); - GetTypeInfoFromSignature(pComSig, cbSigLen, ilIndex, typeStr, typeSize, typeEncoding); + MetaSig sig(MethodDescPtr); + TypeHandle th; + if (ilIndex == 0) + { + th = sig.GetRetTypeHandleNT(); + } + else + { + while (--ilIndex) + sig.SkipArg(); + + sig.NextArg(); + th = sig.GetLastTypeHandleNT(); + } + return GetTypeInfoFromTypeHandle(th, pTypeMap); } -void GetLocalTypeInfo(MethodDesc *MethodDescPtr, - unsigned ilIndex, - const char** typeStr, - ULONG& typeSize, - int& typeEncoding) +TypeInfoBase* GetLocalTypeInfo(MethodDesc *MethodDescPtr, + NotifyGdb::PTK_TypeInfoMap pTypeMap, + unsigned ilIndex) { COR_ILMETHOD_DECODER method(MethodDescPtr->GetILHeader()); if (method.GetLocalVarSigTok()) { DWORD cbSigLen; PCCOR_SIGNATURE pComSig; - CQuickBytes qbMemberSig; - size_t dwL; if (FAILED(MethodDescPtr->GetMDImport()->GetSigFromToken(method.GetLocalVarSigTok(), &cbSigLen, &pComSig))) { printf("\nInvalid record"); - return; + return nullptr; } _ASSERTE(*pComSig == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG); - GetTypeInfoFromSignature(pComSig, cbSigLen, ilIndex, typeStr, typeSize, typeEncoding); + + SigTypeContext typeContext(MethodDescPtr, TypeHandle()); + MetaSig sig(pComSig, cbSigLen, MethodDescPtr->GetModule(), &typeContext, MetaSig::sigLocalVars); + if (ilIndex > 0) + { + while (ilIndex--) + sig.SkipArg(); + } + sig.NextArg(); + TypeHandle th = sig.GetLastTypeHandleNT(); + return GetTypeInfoFromTypeHandle(th, pTypeMap); } + return nullptr; } -HRESULT GetArgNameByILIndex(MethodDesc* MethodDescPtr, unsigned index, LPCSTR ¶mName) +HRESULT GetArgNameByILIndex(MethodDesc* MethodDescPtr, unsigned index, LPSTR ¶mName) { IMDInternalImport* mdImport = MethodDescPtr->GetMDImport(); mdParamDef paramToken; @@ -170,16 +270,18 @@ HRESULT GetArgNameByILIndex(MethodDesc* MethodDescPtr, unsigned index, LPCSTR &p // Param indexing is 1-based. ULONG32 mdIndex = index + 1; - MetaSig* sig = new MetaSig(MethodDescPtr); - if (sig->HasThis()) + MetaSig sig(MethodDescPtr); + if (sig.HasThis()) { mdIndex--; } - delete sig; status = mdImport->FindParamOfMethod(MethodDescPtr->GetMemberDef(), mdIndex, ¶mToken); if (status == S_OK) { - status = mdImport->GetParamDefProps(paramToken, &seq, &attr, ¶mName); + LPCSTR name; + status = mdImport->GetParamDefProps(paramToken, &seq, &attr, &name); + paramName = new char[strlen(name) + 1]; + strcpy(paramName, name); } return status; } @@ -286,36 +388,28 @@ GetMethodNativeMap(MethodDesc* methodDesc, return S_OK; } -HRESULT GetLocalsDebugInfo(MethodDesc* MethodDescPtr, +HRESULT FunctionMember::GetLocalsDebugInfo(NotifyGdb::PTK_TypeInfoMap pTypeMap, LocalsInfo& locals, - NewArrayHolder& localsDebug, - int localsDebugSize, - NewArrayHolder& argsDebug, - int nArgsCount, int startNativeOffset) { ICorDebugInfo::NativeVarInfo* nativeVar = NULL; - int thisOffs = 0; - ULONG typeSize = 0; - int typeEncoding = 0; - const char* typeStr; - if (!MethodDescPtr->IsStatic()) + if (!md->IsStatic()) + { thisOffs = 1; + } - for (int i = 0; i < nArgsCount - thisOffs; i++) + int i; + for (i = 0; i < m_num_args - thisOffs; i++) { - if (FindNativeInfoInILVariable(i + thisOffs, startNativeOffset, &locals.pVars, locals.countVars, &nativeVar) == - S_OK) + if (FindNativeInfoInILVariable(i + thisOffs, startNativeOffset, &locals.pVars, locals.countVars, &nativeVar) == S_OK) { - GetArgTypeInfo(MethodDescPtr, i + 1, &typeStr, typeSize, typeEncoding); - argsDebug[i + thisOffs].m_type_encoding = typeEncoding; - argsDebug[i + thisOffs].m_type_name = typeStr; - GetArgNameByILIndex(MethodDescPtr, i + thisOffs, argsDebug[i + thisOffs].m_arg_name); - argsDebug[i + thisOffs].m_type_size = typeSize; - argsDebug[i + thisOffs].m_il_index = i; - argsDebug[i + thisOffs].m_native_offset = nativeVar->loc.vlStk.vlsOffset; + vars[i + thisOffs].m_var_type = GetArgTypeInfo(md, pTypeMap, i + 1); + GetArgNameByILIndex(md, i + thisOffs, vars[i + thisOffs].m_var_name); + vars[i + thisOffs].m_il_index = i; + vars[i + thisOffs].m_native_offset = nativeVar->loc.vlStk.vlsOffset; + vars[i + thisOffs].m_var_abbrev = 6; } } //Add info about 'this' as first argument @@ -323,28 +417,26 @@ HRESULT GetLocalsDebugInfo(MethodDesc* MethodDescPtr, { if (FindNativeInfoInILVariable(0, startNativeOffset, &locals.pVars, locals.countVars, &nativeVar) == S_OK) { - argsDebug[0].m_type_encoding = DW_ATE_address; - argsDebug[0].m_type_name = "this"; - argsDebug[0].m_arg_name = "this"; - argsDebug[0].m_type_size = sizeof(TADDR); - argsDebug[0].m_il_index = 0; - argsDebug[0].m_native_offset = nativeVar->loc.vlStk.vlsOffset; - } + vars[0].m_var_type = GetTypeInfoFromTypeHandle(TypeHandle(md->GetMethodTable()), pTypeMap); + vars[0].m_var_name = new char[strlen("this") + 1]; + strcpy(vars[0].m_var_name, "this"); + vars[0].m_il_index = 0; + vars[0].m_native_offset = nativeVar->loc.vlStk.vlsOffset; + vars[0].m_var_abbrev = 13; + } + i++; } - - - for (int i = 0; i < localsDebugSize; i++) + for (; i < m_num_vars; i++) { if (FindNativeInfoInILVariable( - i + nArgsCount, startNativeOffset, &locals.pVars, locals.countVars, &nativeVar) == S_OK) + i, startNativeOffset, &locals.pVars, locals.countVars, &nativeVar) == S_OK) { - GetLocalTypeInfo(MethodDescPtr, i, &typeStr, typeSize, typeEncoding); - localsDebug[i].m_type_encoding = typeEncoding; - localsDebug[i].m_type_name = typeStr; - localsDebug[i].m_var_name = locals.localsName[i]; - localsDebug[i].m_type_size = typeSize; - localsDebug[i].m_il_index = i; - localsDebug[i].m_native_offset = nativeVar->loc.vlStk.vlsOffset; + vars[i].m_var_type = GetLocalTypeInfo(md, pTypeMap, i - m_num_args); + vars[i].m_var_name = new char[strlen(locals.localsName[i - m_num_args]) + 1]; + strcpy(vars[i].m_var_name, locals.localsName[i - m_num_args]); + vars[i].m_il_index = i - m_num_args; + vars[i].m_native_offset = nativeVar->loc.vlStk.vlsOffset; + vars[i].m_var_abbrev = 5; } } return S_OK; @@ -371,45 +463,43 @@ GetDebugInfoFromPDB(MethodDesc* MethodDescPtr, SymbolsInfo** symInfo, unsigned i StackScratchBuffer scratch; const char* szModName = modName.GetUTF8(scratch); - MethodDebugInfo* methodDebugInfo = new (nothrow) MethodDebugInfo(); - if (methodDebugInfo == nullptr) - return E_OUTOFMEMORY; + MethodDebugInfo methodDebugInfo; - methodDebugInfo->points = (SequencePointInfo*) CoTaskMemAlloc(sizeof(SequencePointInfo) * numMap); - if (methodDebugInfo->points == nullptr) + methodDebugInfo.points = (SequencePointInfo*) CoTaskMemAlloc(sizeof(SequencePointInfo) * numMap); + if (methodDebugInfo.points == nullptr) return E_OUTOFMEMORY; - methodDebugInfo->size = numMap; + methodDebugInfo.size = numMap; - if (getInfoForMethodDelegate(szModName, MethodDescPtr->GetMemberDef(), *methodDebugInfo) == FALSE) + if (getInfoForMethodDelegate(szModName, MethodDescPtr->GetMemberDef(), methodDebugInfo) == FALSE) return E_FAIL; - symInfoLen = methodDebugInfo->size; + symInfoLen = methodDebugInfo.size; *symInfo = new (nothrow) SymbolsInfo[symInfoLen]; if (*symInfo == nullptr) return E_FAIL; - locals.size = methodDebugInfo->localsSize; + locals.size = methodDebugInfo.localsSize; locals.localsName = new (nothrow) char *[locals.size]; if (locals.localsName == nullptr) return E_FAIL; for (ULONG32 i = 0; i < locals.size; i++) { - size_t sizeRequired = WideCharToMultiByte(CP_UTF8, 0, methodDebugInfo->locals[i], -1, NULL, 0, NULL, NULL); + size_t sizeRequired = WideCharToMultiByte(CP_UTF8, 0, methodDebugInfo.locals[i], -1, NULL, 0, NULL, NULL); locals.localsName[i] = new (nothrow) char[sizeRequired]; int len = WideCharToMultiByte( - CP_UTF8, 0, methodDebugInfo->locals[i], -1, locals.localsName[i], sizeRequired, NULL, NULL); + CP_UTF8, 0, methodDebugInfo.locals[i], -1, locals.localsName[i], sizeRequired, NULL, NULL); } for (ULONG32 i = 0; i < symInfoLen; i++) { for (ULONG32 j = 0; j < numMap; j++) { - if (methodDebugInfo->points[i].ilOffset == map[j].ilOffset) + if (methodDebugInfo.points[i].ilOffset == map[j].ilOffset) { SymbolsInfo& s = (*symInfo)[i]; - const SequencePointInfo& sp = methodDebugInfo->points[i]; + const SequencePointInfo& sp = methodDebugInfo.points[i]; s.nativeOffset = map[j].nativeStartOffset; s.ilOffset = map[j].ilOffset; @@ -421,10 +511,65 @@ GetDebugInfoFromPDB(MethodDesc* MethodDescPtr, SymbolsInfo** symInfo, unsigned i } } - CoTaskMemFree(methodDebugInfo->points); + CoTaskMemFree(methodDebugInfo.points); return S_OK; } +/* LEB128 for 32-bit unsigned integer */ +int Leb128Encode(uint32_t num, char* buf, int size) +{ + int i = 0; + + do + { + uint8_t byte = num & 0x7F; + if (i >= size) + break; + num >>= 7; + if (num != 0) + byte |= 0x80; + buf[i++] = byte; + } + while (num != 0); + + return i; +} + +/* LEB128 for 32-bit signed integer */ +int Leb128Encode(int32_t num, char* buf, int size) +{ + int i = 0; + bool hasMore = true, isNegative = num < 0; + + while (hasMore && i < size) + { + uint8_t byte = num & 0x7F; + num >>= 7; + + if ((num == 0 && (byte & 0x40) == 0) || (num == -1 && (byte & 0x40) == 0x40)) + hasMore = false; + else + byte |= 0x80; + buf[i++] = byte; + } + + return i; +} + +int GetFrameLocation(int nativeOffset, char* bufVarLoc) +{ + char cnvBuf[16] = {0}; + int len = Leb128Encode(static_cast(nativeOffset), cnvBuf, sizeof(cnvBuf)); + bufVarLoc[0] = len + 1; + bufVarLoc[1] = DW_OP_fbreg; + for (int j = 0; j < len; j++) + { + bufVarLoc[j + 2] = cnvBuf[j]; + } + + return len + 2; // We add '2' because first 2 bytes contain length of expression and DW_OP_fbreg operation. +} + // GDB JIT interface typedef enum { @@ -490,7 +635,7 @@ struct SectionHeader { /* Static data for .debug_str section */ const char* DebugStrings[] = { - "CoreCLR", "" /* module name */, "" /* module path */, "" /* method name */ + "CoreCLR", "" /* module name */, "" /* module path */ }; const int DebugStringCount = sizeof(DebugStrings) / sizeof(DebugStrings[0]); @@ -528,6 +673,45 @@ const unsigned char AbbrevTable[] = { 6, DW_TAG_formal_parameter, DW_CHILDREN_no, DW_AT_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1, DW_AT_type, DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc, 0, 0, + + 7, DW_TAG_class_type, DW_CHILDREN_yes, + DW_AT_name, DW_FORM_strp, DW_AT_byte_size, DW_FORM_data1, 0, 0, + + 8, DW_TAG_member, DW_CHILDREN_no, + DW_AT_name, DW_FORM_strp, DW_AT_type, DW_FORM_ref4, DW_AT_data_member_location, DW_FORM_data4, 0, 0, + + 9, DW_TAG_pointer_type, DW_CHILDREN_no, + DW_AT_type, DW_FORM_ref4, DW_AT_byte_size, DW_FORM_data1, 0, 0, + + 10, DW_TAG_array_type, DW_CHILDREN_yes, + DW_AT_type, DW_FORM_ref4, 0, 0, + + 11, DW_TAG_subrange_type, DW_CHILDREN_no, + DW_AT_upper_bound, DW_FORM_exprloc, 0, 0, + + 12, DW_TAG_subprogram, DW_CHILDREN_yes, + DW_AT_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1, + DW_AT_type, DW_FORM_ref4, DW_AT_external, DW_FORM_flag_present, + DW_AT_low_pc, DW_FORM_addr, DW_AT_high_pc, +#if defined(_TARGET_AMD64_) + DW_FORM_data8, +#elif defined(_TARGET_ARM_) + DW_FORM_data4, +#else +#error Unsupported platform! +#endif + DW_AT_frame_base, DW_FORM_exprloc, DW_AT_object_pointer, DW_FORM_ref4, 0, 0, + + 13, DW_TAG_formal_parameter, DW_CHILDREN_no, + DW_AT_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1, DW_AT_type, + DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc, DW_AT_artificial, DW_FORM_flag_present, 0, 0, + + 14, DW_TAG_member, DW_CHILDREN_no, + DW_AT_name, DW_FORM_strp, DW_AT_type, DW_FORM_ref4, DW_AT_external, DW_FORM_flag_present, 0, 0, + + 15, DW_TAG_variable, DW_CHILDREN_no, DW_AT_specification, DW_FORM_ref4, DW_AT_location, DW_FORM_exprloc, + 0, 0, + 0 }; @@ -568,19 +752,15 @@ struct __attribute__((packed)) DebugInfoSub #error Unsupported platform! #endif uint8_t m_sub_loc[2]; -} debugInfoSub = { - 4, 0, 1, 1, 0x1a, 0, 0, {1, -#if defined(_TARGET_AMD64_) - DW_OP_reg6 -#elif defined(_TARGET_ARM_) - DW_OP_reg11 -#else -#error Unsupported platform! -#endif - }, }; +struct __attribute__((packed)) DebugInfoSubMember +{ + DebugInfoSub sub; + uint32_t m_obj_ptr; +}; +static FunctionMember* method = nullptr; struct __attribute__((packed)) DebugInfoType { @@ -590,8 +770,6 @@ struct __attribute__((packed)) DebugInfoType uint8_t m_byte_size; }; -DebugInfoType retType; - struct __attribute__((packed)) DebugInfoVar { uint8_t m_var_abbrev; @@ -600,6 +778,424 @@ struct __attribute__((packed)) DebugInfoVar uint32_t m_var_type; }; +struct __attribute__((packed)) DebugInfoClassType +{ + uint8_t m_type_abbrev; + uint32_t m_type_name; + uint8_t m_byte_size; +}; + +struct __attribute__((packed)) DebugInfoClassMember +{ + uint8_t m_member_abbrev; + uint32_t m_member_name; + uint32_t m_member_type; +}; + +struct __attribute__((packed)) DebugInfoStaticMember +{ + uint8_t m_member_abbrev; + uint32_t m_member_specification; +}; + + +struct __attribute__((packed)) DebugInfoRefType +{ + uint8_t m_type_abbrev; + uint32_t m_ref_type; + uint8_t m_byte_size; +}; + +struct __attribute__((packed)) DebugInfoArrayType +{ + uint8_t m_abbrev; + uint32_t m_type; +}; + +void TypeInfoBase::DumpStrings(char* ptr, int& offset) +{ + if (ptr != nullptr) + { + strcpy(ptr + offset, m_type_name); + m_type_name_offset = offset; + } + offset += strlen(m_type_name) + 1; +} + +void TypeInfoBase::CalculateName() +{ + // name the type + SString sName; + typeHandle.GetName(sName); + StackScratchBuffer buffer; + const UTF8 *utf8 = sName.GetUTF8(buffer); + m_type_name = new char[strlen(utf8) + 1]; + strcpy(m_type_name, utf8); +} + +void TypeInfoBase::SetTypeHandle(TypeHandle handle) +{ + typeHandle = handle; + typeKey = handle.GetTypeKey(); +} + +TypeHandle TypeInfoBase::GetTypeHandle() +{ + return typeHandle; +} + +TypeKey* TypeInfoBase::GetTypeKey() +{ + return &typeKey; +} + +void PrimitiveTypeInfo::DumpDebugInfo(char* ptr, int& offset) +{ + if (m_type_offset != 0) + { + return; + } + + if (ptr != nullptr) + { + DebugInfoType bufType; + bufType.m_type_abbrev = 2; + bufType.m_type_name = m_type_name_offset; + bufType.m_encoding = m_type_encoding; + bufType.m_byte_size = m_type_size; + + memcpy(ptr + offset, + &bufType, + sizeof(DebugInfoType)); + m_type_offset = offset; + } + + offset += sizeof(DebugInfoType); +} + +ClassTypeInfo::ClassTypeInfo(TypeHandle typeHandle, int num_members) + : TypeInfoBase(typeHandle), + m_num_members(num_members), + members(new TypeMember[num_members]) +{ +} + +ClassTypeInfo::~ClassTypeInfo() +{ + if (members != nullptr && m_num_members > 0) + { + delete[] members; + } +} + +void TypeMember::DumpStrings(char* ptr, int& offset) +{ + if (ptr != nullptr) + { + strcpy(ptr + offset, m_member_name); + m_member_name_offset = offset; + } + offset += strlen(m_member_name) + 1; +} + +void TypeMember::DumpDebugInfo(char* ptr, int& offset) +{ + if (ptr != nullptr) + { + DebugInfoClassMember memberEntry; + + if (m_static_member_address == 0) + memberEntry.m_member_abbrev = 8; + else + { + memberEntry.m_member_abbrev = 14; + m_member_offset = offset; + } + memberEntry.m_member_name = m_member_name_offset; + memberEntry.m_member_type = m_member_type->m_type_offset; + + memcpy(ptr + offset, &memberEntry, sizeof(DebugInfoClassMember)); + if (m_static_member_address == 0) + memcpy(ptr + offset + sizeof(DebugInfoClassMember), &m_member_offset, sizeof(m_member_offset)); + } + offset += sizeof(DebugInfoClassMember); + if (m_static_member_address == 0) + offset += sizeof(m_member_offset); +} + +void TypeMember::DumpStaticDebugInfo(char* ptr, int& offset) +{ + const int ptrSize = sizeof(TADDR); + if (ptr != nullptr) + { + DebugInfoStaticMember memberEntry; + + memberEntry.m_member_abbrev = 15; + memberEntry.m_member_specification = m_member_offset; + memcpy(ptr + offset, &memberEntry, sizeof(DebugInfoStaticMember)); + + char buf[ptrSize + 2] = {0}; + buf[0] = ptrSize + 1; + buf[1] = DW_OP_addr; + + for (int i = 0; i < ptrSize; i++) + { + buf[i + 2] = m_static_member_address >> (i * 8); + } + + memcpy(ptr + offset + sizeof(DebugInfoStaticMember), &buf, ptrSize + 2); + } + offset += sizeof(DebugInfoStaticMember); + offset += ptrSize + 2; +} + + +void FunctionMember::DumpStrings(char* ptr, int& offset) +{ + TypeMember::DumpStrings(ptr, offset); + + for (int i = 0; i < m_num_vars; ++i) + { + vars[i].DumpStrings(ptr, offset); + } +} + +void FunctionMember::DumpDebugInfo(char* ptr, int& offset) +{ + if (ptr != nullptr) + { + DebugInfoSub subEntry; + + subEntry.m_sub_abbrev = 4; + subEntry.m_sub_name = m_member_name_offset; + subEntry.m_file = m_file; + subEntry.m_line = m_line; + subEntry.m_sub_type = m_member_type->m_type_offset; + subEntry.m_sub_low_pc = m_sub_low_pc; + subEntry.m_sub_high_pc = m_sub_high_pc; + subEntry.m_sub_loc[0] = m_sub_loc[0]; + subEntry.m_sub_loc[1] = m_sub_loc[1]; + + if (!md->IsStatic()) + { + DebugInfoSubMember subMemberEntry; + subEntry.m_sub_abbrev = 12; + subMemberEntry.sub = subEntry; + subMemberEntry.m_obj_ptr = offset+sizeof(DebugInfoSubMember); + memcpy(ptr + offset, &subMemberEntry, sizeof(DebugInfoSubMember)); + } + else + { + memcpy(ptr + offset, &subEntry, sizeof(DebugInfoSub)); + } + m_entry_offset = offset; + dumped = true; + } + + if (!md->IsStatic()) + { + offset += sizeof(DebugInfoSubMember); + } + else + { + offset += sizeof(DebugInfoSub); + } + for (int i = 0; i < m_num_vars; ++i) + { + vars[i].DumpDebugInfo(ptr, offset); + } + + // terminate children + if (ptr != nullptr) + { + ptr[offset] = 0; + } + offset++; +} + +int FunctionMember::GetArgsAndLocalsLen() +{ + int locSize = 0; + char tmpBuf[16]; + + // Format for DWARF location expression: [expression length][operation][offset in SLEB128 encoding] + for (int i = 0; i < m_num_vars; i++) + { + locSize += 2; // First byte contains expression length, second byte contains operation (DW_OP_fbreg). + locSize += Leb128Encode(static_cast(vars[i].m_native_offset), tmpBuf, sizeof(tmpBuf)); + } + return locSize; +} + +void ClassTypeInfo::DumpStrings(char* ptr, int& offset) +{ + TypeInfoBase::DumpStrings(ptr, offset); + + for (int i = 0; i < m_num_members; ++i) + { + members[i].DumpStrings(ptr, offset); + } +} + +void RefTypeInfo::DumpStrings(char* ptr, int& offset) +{ + TypeInfoBase::DumpStrings(ptr, offset); + m_value_type->DumpStrings(ptr, offset); +} + +void RefTypeInfo::DumpDebugInfo(char* ptr, int& offset) +{ + if (m_type_offset != 0) + { + return; + } + m_type_offset = offset; + offset += sizeof(DebugInfoRefType); + m_value_type->DumpDebugInfo(ptr, offset); + if (ptr != nullptr) + { + DebugInfoRefType refType; + refType.m_type_abbrev = 9; + refType.m_ref_type = m_value_type->m_type_offset; + refType.m_byte_size = m_type_size; + memcpy(ptr + m_type_offset, &refType, sizeof(DebugInfoRefType)); + } + else + { + m_type_offset = 0; + } +} +void ClassTypeInfo::DumpDebugInfo(char* ptr, int& offset) +{ + if (m_type_offset != 0) + { + return; + } + // make sure that types of all members are dumped + for (int i = 0; i < m_num_members; ++i) + { + if (members[i].m_member_type->m_type_offset == 0 && members[i].m_member_type != this) + { + members[i].m_member_type->DumpDebugInfo(ptr, offset); + } + } + + if (ptr != nullptr) + { + DebugInfoClassType bufType; + bufType.m_type_abbrev = 7; + bufType.m_type_name = m_type_name_offset; + bufType.m_byte_size = m_type_size; + + memcpy(ptr + offset, &bufType, sizeof(DebugInfoClassType)); + m_type_offset = offset; + } + offset += sizeof(DebugInfoClassType); + + for (int i = 0; i < m_num_members; ++i) + { + members[i].DumpDebugInfo(ptr, offset); + } + + if (method->md->GetMethodTable() == GetTypeHandle().GetMethodTable()) + { + // our method is part of this class, we should dump it now before terminating members + method->DumpDebugInfo(ptr, offset); + } + + // members terminator + if (ptr != nullptr) + { + ptr[offset] = 0; + } + offset++; + + for (int i = 0; i < m_num_members; ++i) + { + if (members[i].m_static_member_address != 0) + members[i].DumpStaticDebugInfo(ptr, offset); + } + +} + +void ArrayTypeInfo::DumpDebugInfo(char* ptr, int& offset) +{ + if (m_type_offset != 0) + { + return; + } + if (m_elem_type->m_type_offset == 0) + { + m_elem_type->DumpDebugInfo(ptr, offset); + } + if (ptr != nullptr) + { + DebugInfoArrayType arrType; + + arrType.m_abbrev = 10; // DW_TAG_array_type abbrev + arrType.m_type = m_elem_type->m_type_offset; + + memcpy(ptr + offset, &arrType, sizeof(DebugInfoArrayType)); + m_type_offset = offset; + } + offset += sizeof(DebugInfoArrayType); + + char tmp[16] = { 0 }; + int len = Leb128Encode(static_cast(m_count_offset), tmp, sizeof(tmp)); + if (ptr != nullptr) + { + char buf[64]; + buf[0] = 11; // DW_TAG_subrange_type abbrev + buf[1] = len + 3; + buf[2] = DW_OP_push_object_address; + buf[3] = DW_OP_plus_uconst; + for (int j = 0; j < len; j++) + { + buf[j + 4] = tmp[j]; + } + buf[len + 4] = DW_OP_deref; + + memcpy(ptr + offset, buf, len + 5); + } + offset += (len + 5); + + if (ptr != nullptr) + { + memset(ptr + offset, 0, 1); + } + offset += 1; +} + +void VarDebugInfo::DumpStrings(char *ptr, int& offset) +{ + if (ptr != nullptr) + { + strcpy(ptr + offset, m_var_name); + m_var_name_offset = offset; + } + offset += strlen(m_var_name) + 1; +} + +void VarDebugInfo::DumpDebugInfo(char* ptr, int& offset) +{ + char bufVarLoc[16]; + int len = GetFrameLocation(m_native_offset, bufVarLoc); + if (ptr != nullptr) + { + DebugInfoVar bufVar; + + bufVar.m_var_abbrev = m_var_abbrev; + bufVar.m_var_name = m_var_name_offset; + bufVar.m_var_file = 1; + bufVar.m_var_line = 1; + bufVar.m_var_type = m_var_type->m_type_offset; + memcpy(ptr + offset, &bufVar, sizeof(DebugInfoVar)); + memcpy(ptr + offset + sizeof(DebugInfoVar), bufVarLoc, len); + } + offset += sizeof(DebugInfoVar); + offset += len; +} + /* static data for symbol strings */ struct Elf_Symbol { const char* m_name; @@ -702,8 +1298,17 @@ void NotifyGdb::MethodCompiled(MethodDesc* MethodDescPtr) } if (isUserDebug == FALSE) + { return; - + } + + NewHolder pTypeMap = new TK_TypeInfoMap(); + + if (pTypeMap == nullptr) + { + return; + } + CodeHeader* pCH = ((CodeHeader*)(pCode & ~1)) - 1; CalledMethod* pCalledMethods = reinterpret_cast(pCH->GetCalledMethods()); /* Collect addresses of thunks called by method */ @@ -720,25 +1325,18 @@ void NotifyGdb::MethodCompiled(MethodDesc* MethodDescPtr) return; } - NewArrayHolder localsDebug = new(nothrow) LocalsDebugInfo[locals.size]; - - MetaSig* sig = new MetaSig(MethodDescPtr); - int nArgsCount = sig->NumFixedArgs(); - if (sig->HasThis()) + MetaSig sig(MethodDescPtr); + int nArgsCount = sig.NumFixedArgs(); + if (sig.HasThis()) nArgsCount++; - delete sig; - ULONG typeSize = 0; - int typeEncoding = 0; - const char* typeStr; - GetArgTypeInfo(MethodDescPtr, 0, &typeStr, typeSize, typeEncoding); - retType.m_type_abbrev = 2; - retType.m_encoding = typeEncoding; - retType.m_byte_size = typeSize; + method = new FunctionMember(MethodDescPtr, locals.size, nArgsCount); + // method return type + method->m_member_type = GetArgTypeInfo(MethodDescPtr, pTypeMap, 0); + method->GetLocalsDebugInfo(pTypeMap, locals, symInfo[0].nativeOffset); - NewArrayHolder argsDebug = new(nothrow) ArgsDebugInfo[nArgsCount]; - - GetLocalsDebugInfo(MethodDescPtr, locals, localsDebug, locals.size, argsDebug, nArgsCount, symInfo[0].nativeOffset); + // method's class + GetTypeInfoFromTypeHandle(TypeHandle(method->md->GetMethodTable()), pTypeMap); MemBuf elfHeader, sectHeaders, sectStr, sectSymTab, sectStrTab, dbgInfo, dbgAbbrev, dbgPubname, dbgPubType, dbgLine, dbgStr, elfFile; @@ -748,8 +1346,11 @@ void NotifyGdb::MethodCompiled(MethodDesc* MethodDescPtr) { return; } - debugInfoSub.m_sub_low_pc = pCode; - debugInfoSub.m_sub_high_pc = codeSize; + method->m_sub_low_pc = pCode; + method->m_sub_high_pc = codeSize; + method->m_member_name = new char[strlen(methodName) + 1]; + strcpy(method->m_member_name, methodName); + /* Build .debug_line section */ if (!BuildLineTable(dbgLine, pCode, codeSize, symInfo, symInfoLen)) { @@ -757,16 +1358,15 @@ void NotifyGdb::MethodCompiled(MethodDesc* MethodDescPtr) } DebugStrings[1] = szModuleFile; - DebugStrings[3] = methodName; /* Build .debug_str section */ - if (!BuildDebugStrings(dbgStr, argsDebug, nArgsCount, localsDebug, locals.size, typeStr)) + if (!BuildDebugStrings(dbgStr, pTypeMap)) { return; } /* Build .debug_info section */ - if (!BuildDebugInfo(dbgInfo, argsDebug, nArgsCount, localsDebug, locals.size)) + if (!BuildDebugInfo(dbgInfo, pTypeMap)) { return; } @@ -787,6 +1387,8 @@ void NotifyGdb::MethodCompiled(MethodDesc* MethodDescPtr) return; } + delete method; + /* Build .strtab section */ SymbolNames[0].m_name = ""; SymbolNames[1].m_name = methodName; @@ -925,7 +1527,7 @@ void NotifyGdb::MethodCompiled(MethodDesc* MethodDescPtr) #endif /* Create GDB JIT structures */ - jit_code_entry* jit_symbols = new (nothrow) jit_code_entry; + NewHolder jit_symbols = new (nothrow) jit_code_entry; if (jit_symbols == nullptr) { @@ -946,11 +1548,12 @@ void NotifyGdb::MethodCompiled(MethodDesc* MethodDescPtr) head->prev_entry = jit_symbols; } + jit_symbols.SuppressRelease(); + /* Notify the debugger */ __jit_debug_descriptor.relevant_entry = jit_symbols; __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; __jit_debug_register_code(); - } void NotifyGdb::MethodDropped(MethodDesc* MethodDescPtr) @@ -1029,7 +1632,7 @@ bool NotifyGdb::BuildLineTable(MemBuf& buf, PCODE startAddr, TADDR codeSize, Sym /* Buid the source files table for DWARF source line info */ bool NotifyGdb::BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines) { - const char** files = nullptr; + NewArrayHolder files = nullptr; unsigned nfiles = 0; /* GetValue file names and replace them with indices in file table */ @@ -1075,7 +1678,6 @@ bool NotifyGdb::BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines) if (buf.MemPtr == nullptr) { - delete[] files; return false; } @@ -1093,7 +1695,6 @@ bool NotifyGdb::BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines) // final zero byte *ptr = 0; - delete[] files; return true; } @@ -1212,39 +1813,26 @@ bool NotifyGdb::BuildLineProg(MemBuf& buf, PCODE startAddr, TADDR codeSize, Symb } /* Build the DWARF .debug_str section */ -bool NotifyGdb::BuildDebugStrings(MemBuf& buf, - NewArrayHolder& argsDebug, - unsigned int argsDebugSize, - NewArrayHolder& localsDebug, - unsigned int localsDebugSize, const char *retTypeStr) +bool NotifyGdb::BuildDebugStrings(MemBuf& buf, PTK_TypeInfoMap pTypeMap) { - uint32_t totalLength = 0; - + int totalLength = 0; + /* calculate total section size */ for (int i = 0; i < DebugStringCount; ++i) { totalLength += strlen(DebugStrings[i]) + 1; } - retType.m_type_name = totalLength; - totalLength += strlen(retTypeStr) + 1; - - for (int i = 0; i < argsDebugSize; ++i) - { - argsDebug[i].m_type_name_offset = totalLength; - totalLength += strlen(argsDebug[i].m_type_name) + 1; - - argsDebug[i].m_arg_name_offset = totalLength; - totalLength += strlen(argsDebug[i].m_arg_name) + 1; - } + method->DumpStrings(nullptr, totalLength); - for (int i = 0; i < localsDebugSize; ++i) { - localsDebug[i].m_type_name_offset = totalLength; - totalLength += strlen(localsDebug[i].m_type_name) + 1; - - localsDebug[i].m_var_name_offset = totalLength; - totalLength += strlen(localsDebug[i].m_var_name) + 1; + auto iter = pTypeMap->Begin(); + while (iter != pTypeMap->End()) + { + TypeInfoBase *typeInfo = iter->Value(); + typeInfo->DumpStrings(nullptr, totalLength); + iter++; + } } buf.MemSize = totalLength; @@ -1255,30 +1843,23 @@ bool NotifyGdb::BuildDebugStrings(MemBuf& buf, /* copy strings */ char* bufPtr = buf.MemPtr; + int offset = 0; for (int i = 0; i < DebugStringCount; ++i) { - strcpy(bufPtr, DebugStrings[i]); - bufPtr += strlen(DebugStrings[i]) + 1; + strcpy(bufPtr + offset, DebugStrings[i]); + offset += strlen(DebugStrings[i]) + 1; } - strcpy(bufPtr, retTypeStr); - bufPtr += strlen(retTypeStr) + 1; - for (int i = 0; i < argsDebugSize; ++i) - { - strcpy(bufPtr, argsDebug[i].m_type_name); - bufPtr += strlen(argsDebug[i].m_type_name) + 1; - - strcpy(bufPtr, argsDebug[i].m_arg_name); - bufPtr += strlen(argsDebug[i].m_arg_name) + 1; - } + method->DumpStrings(bufPtr, offset); - for (int i = 0; i < localsDebugSize; ++i) { - strcpy(bufPtr, localsDebug[i].m_type_name); - bufPtr += strlen(localsDebug[i].m_type_name) + 1; - - strcpy(bufPtr, localsDebug[i].m_var_name); - bufPtr += strlen(localsDebug[i].m_var_name) + 1; + auto iter = pTypeMap->Begin(); + while (iter != pTypeMap->End()) + { + TypeInfoBase *typeInfo = iter->Value(); + typeInfo->DumpStrings(bufPtr, offset); + iter++; + } } return true; @@ -1297,51 +1878,24 @@ bool NotifyGdb::BuildDebugAbbrev(MemBuf& buf) return true; } -int NotifyGdb::GetArgsAndLocalsLen(NewArrayHolder& argsDebug, - unsigned int argsDebugSize, - NewArrayHolder& localsDebug, - unsigned int localsDebugSize) -{ - int locSize = 0; - char tmpBuf[16]; - - // Format for DWARF location expression: [expression length][operation][offset in SLEB128 encoding] - for (int i = 0; i < argsDebugSize; i++) - { - locSize += 2; // First byte contains expression length, second byte contains operation (DW_OP_fbreg). - locSize += Leb128Encode(static_cast(argsDebug[i].m_native_offset), tmpBuf, sizeof(tmpBuf)); - } - for (int i = 0; i < localsDebugSize; i++) - { - locSize += 2; // First byte contains expression length, second byte contains operation (DW_OP_fbreg). - locSize += Leb128Encode(static_cast(localsDebug[i].m_native_offset), tmpBuf, sizeof(tmpBuf)); - } - return locSize; -} - -int NotifyGdb::GetFrameLocation(int nativeOffset, char* bufVarLoc) +/* Build tge DWARF .debug_info section */ +bool NotifyGdb::BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap) { - char cnvBuf[16] = {0}; - int len = Leb128Encode(static_cast(nativeOffset), cnvBuf, sizeof(cnvBuf)); - bufVarLoc[0] = len + 1; - bufVarLoc[1] = DW_OP_fbreg; - for (int j = 0; j < len; j++) + int totalTypeVarSubSize = 0; { - bufVarLoc[j + 2] = cnvBuf[j]; + auto iter = pTypeMap->Begin(); + while (iter != pTypeMap->End()) + { + TypeInfoBase *typeInfo = iter->Value(); + typeInfo->DumpDebugInfo(nullptr, totalTypeVarSubSize); + iter++; + } } - return len + 2; // We add '2' because first 2 bytes contain length of expression and DW_OP_fbreg operation. -} -/* Build tge DWARF .debug_info section */ -bool NotifyGdb::BuildDebugInfo(MemBuf& buf, NewArrayHolder &argsDebug, unsigned int argsDebugSize, - NewArrayHolder &localsDebug, unsigned int localsDebugSize) -{ - - int locSize = GetArgsAndLocalsLen(argsDebug, argsDebugSize, localsDebug, localsDebugSize); - buf.MemSize = sizeof(DwarfCompUnit) + sizeof(DebugInfoCU) + sizeof(DebugInfoSub) + - sizeof(DebugInfoType) + (sizeof(DebugInfoVar) + - sizeof(DebugInfoType)) * (localsDebugSize + argsDebugSize) + locSize + 2; // Last 2 bytes contain zero end marker. + method->DumpDebugInfo(nullptr, totalTypeVarSubSize); + //int locSize = GetArgsAndLocalsLen(argsDebug, argsDebugSize, localsDebug, localsDebugSize); + buf.MemSize = sizeof(DwarfCompUnit) + sizeof(DebugInfoCU) + totalTypeVarSubSize + 2; buf.MemPtr = new (nothrow) char[buf.MemSize]; if (buf.MemPtr == nullptr) @@ -1360,78 +1914,25 @@ bool NotifyGdb::BuildDebugInfo(MemBuf& buf, NewArrayHolder &argsD offset += sizeof(DebugInfoCU); diCU->m_prod_off = 0; diCU->m_cu_name = strlen(DebugStrings[0]) + 1; - debugInfoSub.m_sub_type = offset; - - - memcpy(buf.MemPtr + offset, &retType, sizeof(DebugInfoType)); - offset += sizeof(DebugInfoType); - - DebugInfoType* bufType = new (nothrow) DebugInfoType[localsDebugSize + argsDebugSize]; - if (bufType == nullptr) - return false; - // TODO: args - for (int i = 0; i < argsDebugSize; i++) { - bufType[i].m_type_abbrev = 2; - bufType[i].m_type_name = argsDebug[i].m_type_name_offset; - bufType[i].m_encoding = argsDebug[i].m_type_encoding; - bufType[i].m_byte_size = argsDebug[i].m_type_size; - argsDebug[i].m_type_offset = offset + i * sizeof(DebugInfoType); + auto iter = pTypeMap->Begin(); + while (iter != pTypeMap->End()) + { + TypeInfoBase *typeInfo = iter->Value(); + typeInfo->DumpDebugInfo(buf.MemPtr, offset); + iter++; + } + } + if (!method->IsDumped()) + { + method->DumpDebugInfo(buf.MemPtr, offset); + } + else + { + method->DumpDebugInfo(buf.MemPtr, method->m_entry_offset); } - - for (int i = argsDebugSize; i < (localsDebugSize + argsDebugSize); i++) - { - bufType[i].m_type_abbrev = 2; - bufType[i].m_type_name = localsDebug[i-argsDebugSize].m_type_name_offset; - bufType[i].m_encoding = localsDebug[i-argsDebugSize].m_type_encoding; - bufType[i].m_byte_size = localsDebug[i-argsDebugSize].m_type_size; - localsDebug[i - argsDebugSize].m_type_offset = offset + i * sizeof(DebugInfoType); - } - memcpy(buf.MemPtr + offset, bufType, sizeof(DebugInfoType) * (localsDebugSize + argsDebugSize)); - offset += sizeof(DebugInfoType) * (localsDebugSize + argsDebugSize); - - /* copy debug information */ - DebugInfoSub* diSub = reinterpret_cast(buf.MemPtr + offset); - memcpy(buf.MemPtr + offset, &debugInfoSub, sizeof(DebugInfoSub)); - diSub->m_sub_name = strlen(DebugStrings[0]) + 1 + strlen(DebugStrings[1]) + 1 + strlen(DebugStrings[2]) + 1; - offset += sizeof(DebugInfoSub); - DebugInfoVar* bufVar = new (nothrow) DebugInfoVar[localsDebugSize + argsDebugSize]; - if (bufVar == nullptr) - return false; - char bufVarLoc[16]; - for (int i = 0; i < argsDebugSize; i++) - { - bufVar[i].m_var_abbrev = 6; - bufVar[i].m_var_name = argsDebug[i].m_arg_name_offset; - bufVar[i].m_var_file = 1; - bufVar[i].m_var_line = 1; - bufVar[i].m_var_type = argsDebug[i].m_type_offset; - memcpy(buf.MemPtr + offset, &bufVar[i], sizeof(DebugInfoVar)); - offset += sizeof(DebugInfoVar); - int len = GetFrameLocation(argsDebug[i].m_native_offset, bufVarLoc); - memcpy(buf.MemPtr + offset, bufVarLoc, len); - offset += len; - } - - for (int i = argsDebugSize; i < (localsDebugSize + argsDebugSize); i++) - { - bufVar[i].m_var_abbrev = 5; - bufVar[i].m_var_name = localsDebug[i-argsDebugSize].m_var_name_offset; - bufVar[i].m_var_file = 1; - bufVar[i].m_var_line = 1; - bufVar[i].m_var_type = localsDebug[i-argsDebugSize].m_type_offset; - memcpy(buf.MemPtr + offset, &bufVar[i], sizeof(DebugInfoVar)); - offset += sizeof(DebugInfoVar); - int len = GetFrameLocation(localsDebug[i-argsDebugSize].m_native_offset, bufVarLoc); - memcpy(buf.MemPtr + offset, bufVarLoc, len); - offset += len; - } - delete []bufVar; - - /* zero end marker */ - buf.MemPtr[buf.MemSize-2] = 0; - buf.MemPtr[buf.MemSize-1] = 0; + memset(buf.MemPtr + offset, 0, buf.MemSize - offset); return true; } @@ -1646,17 +2147,18 @@ bool NotifyGdb::BuildSectionTable(MemBuf& buf) bool NotifyGdb::BuildELFHeader(MemBuf& buf) { Elf_Ehdr* header = new (nothrow) Elf_Ehdr; - buf.MemPtr = reinterpret_cast(header); - buf.MemSize = sizeof(Elf_Ehdr); - + if (header == nullptr) + { return false; - + } + + buf.MemPtr = reinterpret_cast(header); + buf.MemSize = sizeof(Elf_Ehdr); return true; - } -/* Split full path name into directory & file anmes */ +/* Split full path name into directory & file names */ void NotifyGdb::SplitPathname(const char* path, const char*& pathName, const char*& fileName) { char* pSlash = strrchr(path, '/'); @@ -1674,47 +2176,6 @@ void NotifyGdb::SplitPathname(const char* path, const char*& pathName, const cha } } -/* LEB128 for 32-bit unsigned integer */ -int NotifyGdb::Leb128Encode(uint32_t num, char* buf, int size) -{ - int i = 0; - - do - { - uint8_t byte = num & 0x7F; - if (i >= size) - break; - num >>= 7; - if (num != 0) - byte |= 0x80; - buf[i++] = byte; - } - while (num != 0); - - return i; -} - -/* LEB128 for 32-bit signed integer */ -int NotifyGdb::Leb128Encode(int32_t num, char* buf, int size) -{ - int i = 0; - bool hasMore = true, isNegative = num < 0; - - while (hasMore && i < size) - { - uint8_t byte = num & 0x7F; - num >>= 7; - - if ((num == 0 && (byte & 0x40) == 0) || (num == -1 && (byte & 0x40) == 0x40)) - hasMore = false; - else - byte |= 0x80; - buf[i++] = byte; - } - - return i; -} - #ifdef _DEBUG void NotifyGdb::DumpElf(const char* methodName, const MemBuf& elfFile) { diff --git a/src/vm/gdbjit.h b/src/vm/gdbjit.h index bfc2178..133cc79 100644 --- a/src/vm/gdbjit.h +++ b/src/vm/gdbjit.h @@ -34,6 +34,46 @@ #error "Target is not supported" #endif + +static constexpr const int CorElementTypeToDWEncoding[] = +{ +/* ELEMENT_TYPE_END */ 0, +/* ELEMENT_TYPE_VOID */ DW_ATE_address, +/* ELEMENT_TYPE_BOOLEAN */ DW_ATE_boolean, +/* ELEMENT_TYPE_CHAR */ DW_ATE_UTF, +/* ELEMENT_TYPE_I1 */ DW_ATE_signed, +/* ELEMENT_TYPE_U1 */ DW_ATE_unsigned, +/* ELEMENT_TYPE_I2 */ DW_ATE_signed, +/* ELEMENT_TYPE_U2 */ DW_ATE_unsigned, +/* ELEMENT_TYPE_I4 */ DW_ATE_signed, +/* ELEMENT_TYPE_U4 */ DW_ATE_unsigned, +/* ELEMENT_TYPE_I8 */ DW_ATE_signed, +/* ELEMENT_TYPE_U8 */ DW_ATE_unsigned, +/* ELEMENT_TYPE_R4 */ DW_ATE_float, +/* ELEMENT_TYPE_R8 */ DW_ATE_float, +/* ELEMENT_TYPE_STRING */ DW_ATE_address, +/* ELEMENT_TYPE_PTR */ DW_ATE_address, +/* ELEMENT_TYPE_BYREF */ DW_ATE_address, +/* ELEMENT_TYPE_VALUETYPE */ DW_ATE_address, +/* ELEMENT_TYPE_CLASS */ DW_ATE_address, +/* ELEMENT_TYPE_VAR */ DW_ATE_address, +/* ELEMENT_TYPE_ARRAY */ DW_ATE_address, +/* ELEMENT_TYPE_GENERICINST */ DW_ATE_address, +/* ELEMENT_TYPE_TYPEDBYREF */ DW_ATE_address, +/* SKIP 17 */ DW_ATE_address, +/* ELEMENT_TYPE_I */ DW_ATE_signed, +/* ELEMENT_TYPE_U */ DW_ATE_unsigned, +/* SKIP 1a */ DW_ATE_address, +/* ELEMENT_TYPE_FNPTR */ DW_ATE_address, +/* ELEMENT_TYPE_OBJECT */ DW_ATE_address, +/* ELEMENT_TYPE_SZARRAY */ DW_ATE_address, +/* ELEMENT_TYPE_MVAR */ DW_ATE_address, +/* ELEMENT_TYPE_CMOD_REQD */ DW_ATE_address, +/* ELEMENT_TYPE_CMOD_OPT */ DW_ATE_address, +/* ELEMENT_TYPE_INTERNAL */ DW_ATE_address, +/* ELEMENT_TYPE_MAX */ DW_ATE_address, +}; + struct __attribute__((packed)) DwarfCompUnit { uint32_t m_length; @@ -70,44 +110,195 @@ struct SymbolsInfo int lineNumber, ilOffset, nativeOffset, fileIndex; char fileName[2*MAX_PATH_FNAME]; }; -struct LocalsInfo + +class DwarfDumpable +{ +public: + // writes all string literals this type needs to ptr + virtual void DumpStrings(char* ptr, int& offset) = 0; + + virtual void DumpDebugInfo(char* ptr, int& offset) = 0; +}; + +class LocalsInfo { +public: int size; char** localsName; ULONG32 countVars; ICorDebugInfo::NativeVarInfo *pVars; }; -struct ArgsDebugInfo +class TypeMember; + +class TypeInfoBase : public DwarfDumpable { - int m_type_index; - const char* m_type_name; - int m_type_name_offset; - int m_type_encoding; - int m_type_size; - int m_type_abbrev; +public: + TypeInfoBase(TypeHandle typeHandle) + : m_type_name(nullptr), + m_type_name_offset(0), + m_type_size(0), + m_type_offset(0), + typeHandle(typeHandle), + typeKey(typeHandle.GetTypeKey()) + { + } + + virtual ~TypeInfoBase() + { + if (m_type_name != nullptr) + { + delete[] m_type_name; + } + } + + virtual void DumpStrings(char* ptr, int& offset) override; + void CalculateName(); + void SetTypeHandle(TypeHandle handle); + TypeHandle GetTypeHandle(); + TypeKey* GetTypeKey(); + + char* m_type_name; + int m_type_name_offset; + ULONG m_type_size; int m_type_offset; - int m_il_index; - const char* m_arg_name; - int m_arg_name_offset; - int m_arg_abbrev; - int m_native_offset; +private: + TypeHandle typeHandle; + TypeKey typeKey; }; -struct LocalsDebugInfo +class PrimitiveTypeInfo: public TypeInfoBase { - int m_type_index; - const char* m_type_name; - int m_type_name_offset; +public: + PrimitiveTypeInfo(TypeHandle typeHandle, int encoding) + : TypeInfoBase(typeHandle), + m_type_encoding(encoding) + { + } + + void DumpDebugInfo(char* ptr, int& offset) override; + int m_type_encoding; - int m_type_size; - int m_type_abbrev; - int m_type_offset; - int m_il_index; +}; + +class RefTypeInfo: public TypeInfoBase +{ +public: + RefTypeInfo(TypeHandle typeHandle, TypeInfoBase *value_type) + : TypeInfoBase(typeHandle), + m_value_type(value_type) + { + } + void DumpStrings(char* ptr, int& offset) override; + void DumpDebugInfo(char* ptr, int& offset) override; + TypeInfoBase *m_value_type; +}; + +class ClassTypeInfo: public TypeInfoBase +{ +public: + ClassTypeInfo(TypeHandle typeHandle, int num_members); + ~ClassTypeInfo(); + + void DumpStrings(char* ptr, int& offset) override; + void DumpDebugInfo(char* ptr, int& offset) override; + + int m_num_members; + TypeMember* members; +}; + +class TypeMember: public DwarfDumpable +{ +public: + TypeMember() + : m_member_name(nullptr), + m_member_name_offset(0), + m_member_offset(0), + m_static_member_address(0), + m_member_type(nullptr) + { + } + + ~TypeMember() + { + if (m_member_name != nullptr) + { + delete[] m_member_name; + } + } + + void DumpStrings(char* ptr, int& offset) override; + void DumpDebugInfo(char* ptr, int& offset) override; + void DumpStaticDebugInfo(char* ptr, int& offset); + + char* m_member_name; + int m_member_name_offset; + int m_member_offset; + TADDR m_static_member_address; + TypeInfoBase *m_member_type; +}; + +class ArrayTypeInfo: public TypeInfoBase +{ +public: + ArrayTypeInfo(TypeHandle typeHandle, int countOffset, TypeInfoBase* elemType) + : TypeInfoBase(typeHandle), + m_count_offset(countOffset), + m_elem_type(elemType) + { + } + + ~ArrayTypeInfo() + { + if (m_elem_type != nullptr) + { + delete m_elem_type; + } + } + + void DumpDebugInfo(char* ptr, int& offset) override; + + int m_count_offset; + TypeInfoBase *m_elem_type; +}; + +class VarDebugInfo: public DwarfDumpable +{ +public: + VarDebugInfo(int abbrev) + : m_var_name(nullptr), + m_var_abbrev(abbrev), + m_var_name_offset(0), + m_il_index(0), + m_native_offset(0), + m_var_type(nullptr) + { + } + + VarDebugInfo() + : m_var_name(nullptr), + m_var_abbrev(6), + m_var_name_offset(0), + m_il_index(0), + m_native_offset(0), + m_var_type(nullptr) + { + } + + virtual ~VarDebugInfo() + { + delete[] m_var_name; + } + + void DumpStrings(char* ptr, int& offset) override; + void DumpDebugInfo(char* ptr, int& offset) override; + char* m_var_name; - int m_var_name_offset; int m_var_abbrev; + int m_var_name_offset; + int m_il_index; int m_native_offset; + TypeInfoBase *m_var_type; }; class NotifyGdb @@ -115,7 +306,54 @@ class NotifyGdb public: static void MethodCompiled(MethodDesc* MethodDescPtr); static void MethodDropped(MethodDesc* MethodDescPtr); + template + class DeleteValuesOnDestructSHashTraits : public PARENT_TRAITS + { + public: + static inline void OnDestructPerEntryCleanupAction(typename PARENT_TRAITS::element_t e) + { + delete e.Value(); + } + static const bool s_DestructPerEntryCleanupAction = true; + }; + + template + class TypeKeyHashTraits : public DefaultSHashTraits< KeyValuePair > + { + public: + // explicitly declare local typedefs for these traits types, otherwise + // the compiler may get confused + typedef typename DefaultSHashTraits< KeyValuePair >::element_t element_t; + typedef typename DefaultSHashTraits< KeyValuePair >::count_t count_t; + typedef TypeKey* key_t; + + static key_t GetKey(element_t e) + { + LIMITED_METHOD_CONTRACT; + return e.Key(); + } + static BOOL Equals(key_t k1, key_t k2) + { + LIMITED_METHOD_CONTRACT; + return k1->Equals(k2); + } + static count_t Hash(key_t k) + { + LIMITED_METHOD_CONTRACT; + return k->ComputeHash(); + } + + static const element_t Null() { LIMITED_METHOD_CONTRACT; return element_t(key_t(),VALUE()); } + static const element_t Deleted() { LIMITED_METHOD_CONTRACT; return element_t(key_t(-1), VALUE()); } + static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e.Key() == key_t(); } + static bool IsDeleted(const element_t &e) { return e.Key() == key_t(-1); } + }; + + typedef MapSHash>> TK_TypeInfoMap; + typedef TK_TypeInfoMap* PTK_TypeInfoMap; + private: + struct MemBuf { NewArrayHolder MemPtr; @@ -129,17 +367,9 @@ private: static bool BuildSectionTable(MemBuf& buf); static bool BuildSymbolTableSection(MemBuf& buf, PCODE addr, TADDR codeSize); static bool BuildStringTableSection(MemBuf& strTab); - static bool BuildDebugStrings(MemBuf& buf, - NewArrayHolder& argsDebug, - unsigned int argsDebugSize, - NewArrayHolder& localsDebug, - unsigned int localsDebugSize, const char *retTypeStr); + static bool BuildDebugStrings(MemBuf& buf, PTK_TypeInfoMap pTypeMap); static bool BuildDebugAbbrev(MemBuf& buf); - static bool BuildDebugInfo(MemBuf& buf, - NewArrayHolder& argsDebug, - unsigned int argsDebugSize, - NewArrayHolder& localsDebug, - unsigned int localsDebugSize); + static bool BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap); static bool BuildDebugPub(MemBuf& buf, const char* name, uint32_t size, uint32_t dieOffset); static bool BuildLineTable(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines); static bool BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines); @@ -152,16 +382,65 @@ private: static void IssueSpecialCommand(char*& ptr, int8_t line_shift, uint8_t addr_shift); static void SplitPathname(const char* path, const char*& pathName, const char*& fileName); static bool CollectCalledMethods(CalledMethod* pCM); - static int Leb128Encode(uint32_t num, char* buf, int size); - static int Leb128Encode(int32_t num, char* buf, int size); - static int GetFrameLocation(int nativeOffset, char* varLoc); - static int GetArgsAndLocalsLen(NewArrayHolder& argsDebug, - unsigned int argsDebugSize, - NewArrayHolder& localsDebug, - unsigned int localsDebugSize); #ifdef _DEBUG static void DumpElf(const char* methodName, const MemBuf& buf); #endif }; +class FunctionMember: public TypeMember +{ +public: + FunctionMember(MethodDesc *md, int num_locals, int num_args) + : TypeMember(), + md(md), + m_file(1), + m_line(1), + m_sub_low_pc(0), + m_sub_high_pc(0), + m_sub_loc(), + m_num_args(num_args), + m_num_locals(num_locals), + m_num_vars(num_args + num_locals), + m_entry_offset(0), + vars(new VarDebugInfo[m_num_vars]), + dumped(false) + { + m_sub_loc[0] = 1; +#if defined(_TARGET_AMD64_) + m_sub_loc[1] = DW_OP_reg6; +#elif defined(_TARGET_ARM_) + m_sub_loc[1] = DW_OP_reg11; +#else +#error Unsupported platform! +#endif + } + + virtual ~FunctionMember() + { + delete[] vars; + } + + void DumpStrings(char* ptr, int& offset) override; + void DumpDebugInfo(char* ptr, int& offset) override; + HRESULT GetLocalsDebugInfo(NotifyGdb::PTK_TypeInfoMap pTypeMap, + LocalsInfo& locals, + int startNativeOffset); + BOOL IsDumped() + { + return dumped; + } + + MethodDesc *md; + uint8_t m_file, m_line; + uintptr_t m_sub_low_pc, m_sub_high_pc; + uint8_t m_sub_loc[2]; + uint8_t m_num_args; + uint8_t m_num_locals; + uint16_t m_num_vars; + int m_entry_offset; + VarDebugInfo* vars; +private: + int GetArgsAndLocalsLen(); + BOOL dumped; +}; #endif // #ifndef __GDBJIT_H__