1 // Copyright (c) 2017 Samsung Electronics Co., LTD
2 // Distributed under the MIT License.
3 // See the LICENSE file in the project root for more information.
10 #include <unordered_set>
12 #include "typeprinter.h"
14 #include "symbolreader.h"
18 static const char *g_nonUserCode = "System.Diagnostics.DebuggerNonUserCodeAttribute..ctor";
19 static const char *g_stepThrough = "System.Diagnostics.DebuggerStepThroughAttribute..ctor";
20 // TODO: DebuggerStepThroughAttribute also affects breakpoints when JMC is enabled
23 static const std::unordered_set<std::string> g_operatorMethodNames
28 "op_UnaryNegation", // - (unary)
29 "op_UnaryPlus", // + (unary)
31 "op_True", // Not defined
32 "op_False", // Not defined
33 "op_AddressOf", // & (unary)
34 "op_OnesComplement", // ~
35 "op_PointerDereference", // * (unary)
37 "op_Addition", // + (binary)
38 "op_Subtraction", // - (binary)
39 "op_Multiply", // * (binary)
42 "op_ExclusiveOr", // ^
43 "op_BitwiseAnd", // & (binary)
45 "op_LogicalAnd", // &&
47 "op_Assign", // Not defined (= is not the same)
49 "op_RightShift", // >>
50 "op_SignedRightShift", // Not defined
51 "op_UnsignedRightShift", // Not defined
53 "op_GreaterThan", // >
55 "op_Inequality", // !=
56 "op_GreaterThanOrEqual", // >=
57 "op_LessThanOrEqual", // <=
58 "op_UnsignedRightShiftAssignment", // Not defined
59 "op_MemberSelection", // ->
60 "op_RightShiftAssignment", // >>=
61 "op_MultiplicationAssignment", // *=
62 "op_PointerToMemberSelection", // ->*
63 "op_SubtractionAssignment", // -=
64 "op_ExclusiveOrAssignment", // ^=
65 "op_LeftShiftAssignment", // <<=
66 "op_ModulusAssignment", // %=
67 "op_AdditionAssignment", // +=
68 "op_BitwiseAndAssignment", // &=
69 "op_BitwiseOrAssignment", // |=
71 "op_DivisionAssignment" // /=
74 bool Modules::ShouldLoadSymbolsForModule(const std::string &moduleName)
76 std::string name = GetFileName(moduleName);
77 if (name.find("System.") == 0 || name.find("SOS.") == 0)
82 static bool HasAttribute(IMetaDataImport *pMD, mdToken tok, const std::string &attrName)
86 ULONG numAttributes = 0;
87 HCORENUM fEnum = NULL;
88 mdCustomAttribute attr;
89 while(SUCCEEDED(pMD->EnumCustomAttributes(&fEnum, tok, 0, &attr, 1, &numAttributes)) && numAttributes != 0)
91 mdToken ptkObj = mdTokenNil;
92 mdToken ptkType = mdTokenNil;
93 pMD->GetCustomAttributeProps(attr, &ptkObj, &ptkType, nullptr, nullptr);
96 std::list<std::string> emptyArgs;
97 TypePrinter::NameForToken(ptkType, pMD, mdName, true, emptyArgs);
99 if (mdName == attrName)
105 pMD->CloseEnum(fEnum);
110 static bool HasSourceLocation(SymbolReader *symbolReader, mdMethodDef methodDef)
113 std::vector<SymbolReader::SequencePoint> points;
114 if (FAILED(symbolReader->GetSequencePoints(methodDef, points)))
117 for (auto &p : points)
119 if (p.startLine != 0 && p.startLine != SymbolReader::HiddenLine)
125 static HRESULT GetNonJMCMethodsForTypeDef(
126 IMetaDataImport *pMD,
129 std::vector<mdToken> &excludeMethods)
133 ULONG numMethods = 0;
134 HCORENUM fEnum = NULL;
135 mdMethodDef methodDef;
136 while(SUCCEEDED(pMD->EnumMethods(&fEnum, typeDef, &methodDef, 1, &numMethods)) && numMethods != 0)
139 mdTypeDef memTypeDef;
141 WCHAR szFunctionName[mdNameLen] = {0};
143 Status = pMD->GetMethodProps(methodDef, &memTypeDef,
144 szFunctionName, _countof(szFunctionName), &nameLen,
145 nullptr, nullptr, nullptr, nullptr, nullptr);
150 if ((g_operatorMethodNames.find(to_utf8(szFunctionName)) != g_operatorMethodNames.end())
151 || HasAttribute(pMD, methodDef, g_nonUserCode)
152 || HasAttribute(pMD, methodDef, g_stepThrough)
153 || !HasSourceLocation(sr, methodDef))
155 excludeMethods.push_back(methodDef);
158 pMD->CloseEnum(fEnum);
160 mdProperty propertyDef;
161 ULONG numProperties = 0;
162 HCORENUM propEnum = NULL;
163 while(SUCCEEDED(pMD->EnumProperties(&propEnum, typeDef, &propertyDef, 1, &numProperties)) && numProperties != 0)
165 mdMethodDef mdSetter;
166 mdMethodDef mdGetter;
167 if (SUCCEEDED(pMD->GetPropertyProps(propertyDef,
184 if (mdSetter != mdMethodDefNil)
185 excludeMethods.push_back(mdSetter);
186 if (mdGetter != mdMethodDefNil)
187 excludeMethods.push_back(mdGetter);
190 pMD->CloseEnum(propEnum);
195 static HRESULT GetNonJMCClassesAndMethods(ICorDebugModule *pModule, SymbolReader *sr, std::vector<mdToken> &excludeTokens)
199 ToRelease<IUnknown> pMDUnknown;
200 ToRelease<IMetaDataImport> pMD;
201 IfFailRet(pModule->GetMetaDataInterface(IID_IMetaDataImport, &pMDUnknown));
202 IfFailRet(pMDUnknown->QueryInterface(IID_IMetaDataImport, (LPVOID*) &pMD));
204 ULONG numTypedefs = 0;
205 HCORENUM fEnum = NULL;
207 while(SUCCEEDED(pMD->EnumTypeDefs(&fEnum, &typeDef, 1, &numTypedefs)) && numTypedefs != 0)
209 if (HasAttribute(pMD, typeDef, g_nonUserCode))
210 excludeTokens.push_back(typeDef);
212 GetNonJMCMethodsForTypeDef(pMD, sr, typeDef, excludeTokens);
214 pMD->CloseEnum(fEnum);
219 HRESULT Modules::SetJMCFromAttributes(ICorDebugModule *pModule, SymbolReader *symbolReader)
221 std::vector<mdToken> excludeTokens;
223 GetNonJMCClassesAndMethods(pModule, symbolReader, excludeTokens);
225 for (mdToken token : excludeTokens)
227 if (TypeFromToken(token) == mdtMethodDef)
229 ToRelease<ICorDebugFunction> pFunction;
230 ToRelease<ICorDebugFunction2> pFunction2;
231 if (FAILED(pModule->GetFunctionFromToken(token, &pFunction)))
233 if (FAILED(pFunction->QueryInterface(IID_ICorDebugFunction2, (LPVOID *)&pFunction2)))
236 pFunction2->SetJMCStatus(FALSE);
238 else if (TypeFromToken(token) == mdtTypeDef)
240 ToRelease<ICorDebugClass> pClass;
241 ToRelease<ICorDebugClass2> pClass2;
242 if (FAILED(pModule->GetClassFromToken(token, &pClass)))
244 if (FAILED(pClass->QueryInterface(IID_ICorDebugClass2, (LPVOID *)&pClass2)))
247 pClass2->SetJMCStatus(FALSE);