diff --git a/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Eventing/ExceptionsEventSource.cs b/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Eventing/ExceptionsEventSource.cs index 95806453b32..00668ee1553 100644 --- a/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Eventing/ExceptionsEventSource.cs +++ b/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Eventing/ExceptionsEventSource.cs @@ -79,9 +79,10 @@ public void ClassDescription( ulong ModuleId, uint Token, uint Flags, + uint StackTraceHidden, ulong[] TypeArgs) { - Span data = stackalloc EventData[5]; + Span data = stackalloc EventData[6]; Span typeArgsSpan = stackalloc byte[GetArrayDataSize(TypeArgs)]; FillArrayData(typeArgsSpan, TypeArgs); @@ -89,6 +90,7 @@ public void ClassDescription( SetValue(ref data[NameIdentificationEvents.ClassDescPayloads.ModuleId], ModuleId); SetValue(ref data[NameIdentificationEvents.ClassDescPayloads.Token], Token); SetValue(ref data[NameIdentificationEvents.ClassDescPayloads.Flags], Flags); + SetValue(ref data[NameIdentificationEvents.ClassDescPayloads.StackTraceHidden], StackTraceHidden); SetValue(ref data[NameIdentificationEvents.ClassDescPayloads.TypeArgs], typeArgsSpan); WriteEventWithFlushing(ExceptionEvents.EventIds.ClassDescription, data); @@ -101,11 +103,12 @@ public void FunctionDescription( ulong ClassId, uint ClassToken, ulong ModuleId, + uint StackTraceHidden, string Name, ulong[] TypeArgs, ulong[] ParameterTypes) { - Span data = stackalloc EventData[8]; + Span data = stackalloc EventData[9]; using PinnedData namePinned = PinnedData.Create(Name); Span typeArgsSpan = stackalloc byte[GetArrayDataSize(TypeArgs)]; FillArrayData(typeArgsSpan, TypeArgs); @@ -117,6 +120,7 @@ public void FunctionDescription( SetValue(ref data[NameIdentificationEvents.FunctionDescPayloads.ClassId], ClassId); SetValue(ref data[NameIdentificationEvents.FunctionDescPayloads.ClassToken], ClassToken); SetValue(ref data[NameIdentificationEvents.FunctionDescPayloads.ModuleId], ModuleId); + SetValue(ref data[NameIdentificationEvents.FunctionDescPayloads.StackTraceHidden], StackTraceHidden); SetValue(ref data[NameIdentificationEvents.FunctionDescPayloads.Name], namePinned); SetValue(ref data[NameIdentificationEvents.FunctionDescPayloads.TypeArgs], typeArgsSpan); SetValue(ref data[NameIdentificationEvents.FunctionDescPayloads.ParameterTypes], parameterTypesSpan); @@ -160,16 +164,18 @@ public void TokenDescription( ulong ModuleId, uint Token, uint OuterToken, + uint StackTraceHidden, string Name, string Namespace) { - Span data = stackalloc EventData[5]; + Span data = stackalloc EventData[6]; using PinnedData namePinned = PinnedData.Create(Name); using PinnedData namespacePinned = PinnedData.Create(Namespace); SetValue(ref data[NameIdentificationEvents.TokenDescPayloads.ModuleId], ModuleId); SetValue(ref data[NameIdentificationEvents.TokenDescPayloads.Token], Token); SetValue(ref data[NameIdentificationEvents.TokenDescPayloads.OuterToken], OuterToken); + SetValue(ref data[NameIdentificationEvents.TokenDescPayloads.StackTraceHidden], StackTraceHidden); SetValue(ref data[NameIdentificationEvents.TokenDescPayloads.Name], namePinned); SetValue(ref data[NameIdentificationEvents.TokenDescPayloads.Namespace], namespacePinned); diff --git a/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Eventing/ExceptionsEventSourceIdentifierCacheCallback.cs b/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Eventing/ExceptionsEventSourceIdentifierCacheCallback.cs index 5a76d8ea968..97575217b2c 100644 --- a/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Eventing/ExceptionsEventSourceIdentifierCacheCallback.cs +++ b/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Eventing/ExceptionsEventSourceIdentifierCacheCallback.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Diagnostics.Monitoring.StartupHook.Exceptions.Identification; +using System; namespace Microsoft.Diagnostics.Monitoring.StartupHook.Exceptions.Eventing { @@ -22,6 +23,7 @@ public override void OnClassData(ulong classId, ClassData data) data.ModuleId, data.Token, (uint)data.Flags, + Convert.ToUInt32(data.StackTraceHidden), data.TypeArgs); } @@ -42,6 +44,7 @@ public override void OnFunctionData(ulong functionId, FunctionData data) data.ParentClass, data.ParentClassToken, data.ModuleId, + Convert.ToUInt32(data.StackTraceHidden), data.Name, data.TypeArgs, data.ParameterTypes); @@ -69,6 +72,7 @@ public override void OnTokenData(ulong moduleId, uint typeToken, TokenData data) moduleId, typeToken, data.OuterToken, + Convert.ToUInt32(data.StackTraceHidden), data.Name, data.Namespace); } diff --git a/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Identification/ExceptionGroupIdentifierCache.cs b/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Identification/ExceptionGroupIdentifierCache.cs index 99ef3d1f5e6..2ce0b9e545d 100644 --- a/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Identification/ExceptionGroupIdentifierCache.cs +++ b/src/Microsoft.Diagnostics.Monitoring.StartupHook/Exceptions/Identification/ExceptionGroupIdentifierCache.cs @@ -96,6 +96,13 @@ public ulong GetOrAdd(MethodBase method) parentClassToken = Convert.ToUInt32(method.DeclaringType.MetadataToken); } + bool stackTraceHidden = false; + try + { + stackTraceHidden = method.GetCustomAttribute(inherit: false) != null; + } + catch (Exception) { } + // RTDynamicMethod does not implement GetGenericArguments. Type[] genericArguments = Array.Empty(); try @@ -111,8 +118,8 @@ public ulong GetOrAdd(MethodBase method) parentClassToken, GetOrAdd(method.Module), GetOrAdd(genericArguments), - GetOrAdd(method.GetParameters()) - ); + GetOrAdd(method.GetParameters()), + stackTraceHidden); if (_nameCache.FunctionData.TryAdd(methodId, data)) { @@ -205,11 +212,20 @@ public ulong GetOrAdd(Type type) { ulong moduleId = GetOrAdd(type.Module); uint typeToken = Convert.ToUInt32(type.MetadataToken); + + bool stackTraceHidden = false; + try + { + stackTraceHidden = type.GetCustomAttribute(inherit: false) != null; + } + catch (Exception) { } + ClassData classData = new( typeToken, moduleId, ClassFlags.None, - GetOrAdd(type.GetGenericArguments())); + GetOrAdd(type.GetGenericArguments()), + stackTraceHidden); if (!_nameCache.ClassData.TryAdd(classId, classData)) break; @@ -228,7 +244,8 @@ public ulong GetOrAdd(Type type) TokenData tokenData = new( type.Name, null == type.DeclaringType ? type.Namespace ?? string.Empty : string.Empty, - parentClassToken); + parentClassToken, + stackTraceHidden); if (!_nameCache.TokenData.TryAdd(key, tokenData)) break; diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/EventStacksPipeline.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/EventStacksPipeline.cs index cc891648e96..c0448c8e330 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/EventStacksPipeline.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/EventStacksPipeline.cs @@ -114,7 +114,8 @@ private void Callback(TraceEvent action) action.GetPayload(NameIdentificationEvents.FunctionDescPayloads.ClassToken), action.GetPayload(NameIdentificationEvents.FunctionDescPayloads.ModuleId), action.GetPayload(NameIdentificationEvents.FunctionDescPayloads.TypeArgs) ?? Array.Empty(), - action.GetPayload(NameIdentificationEvents.FunctionDescPayloads.ParameterTypes) ?? Array.Empty() + action.GetPayload(NameIdentificationEvents.FunctionDescPayloads.ParameterTypes) ?? Array.Empty(), + action.GetBoolPayload(NameIdentificationEvents.FunctionDescPayloads.StackTraceHidden) ); _result.NameCache.FunctionData.TryAdd(id, functionData); @@ -126,7 +127,8 @@ private void Callback(TraceEvent action) action.GetPayload(NameIdentificationEvents.ClassDescPayloads.Token), action.GetPayload(NameIdentificationEvents.ClassDescPayloads.ModuleId), (ClassFlags)action.GetPayload(NameIdentificationEvents.ClassDescPayloads.Flags), - action.GetPayload(NameIdentificationEvents.ClassDescPayloads.TypeArgs) ?? Array.Empty() + action.GetPayload(NameIdentificationEvents.ClassDescPayloads.TypeArgs) ?? Array.Empty(), + action.GetBoolPayload(NameIdentificationEvents.ClassDescPayloads.StackTraceHidden) ); _result.NameCache.ClassData.TryAdd(id, classData); @@ -148,7 +150,8 @@ private void Callback(TraceEvent action) var tokenData = new TokenData( action.GetPayload(NameIdentificationEvents.TokenDescPayloads.Name), action.GetPayload(NameIdentificationEvents.TokenDescPayloads.Namespace), - action.GetPayload(NameIdentificationEvents.TokenDescPayloads.OuterToken) + action.GetPayload(NameIdentificationEvents.TokenDescPayloads.OuterToken), + action.GetBoolPayload(NameIdentificationEvents.TokenDescPayloads.StackTraceHidden) ); _result.NameCache.TokenData.TryAdd(new ModuleScopedToken(modId, token), tokenData); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/NameCache.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/NameCache.cs index 6207e0837a5..308d5208679 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/NameCache.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/NameCache.cs @@ -32,16 +32,18 @@ internal enum ClassFlags : uint /// The identifier of the module that contains the class. /// The flags for the class. /// The class identifiers of the generic type arguments of the class. + /// If the class has . /// /// The name of the class can be retrieved from the corresponding . /// - internal sealed record class ClassData(uint Token, ulong ModuleId, ClassFlags Flags, ulong[] TypeArgs); + internal sealed record class ClassData(uint Token, ulong ModuleId, ClassFlags Flags, ulong[] TypeArgs, bool StackTraceHidden); /// The name of the token. /// The namespace of the Name. /// The metadata token of the parent container. + /// If the token has . [DebuggerDisplay("{Name}")] - internal sealed record class TokenData(string Name, string Namespace, uint OuterToken); + internal sealed record class TokenData(string Name, string Namespace, uint OuterToken, bool StackTraceHidden); /// The name of the function. /// The method token of the function (methodDef token). @@ -50,11 +52,12 @@ internal sealed record class TokenData(string Name, string Namespace, uint Outer /// The identifier of the module that contains the function. /// The class identifiers of the generic type arguments of the function. /// The class identifiers of the parameter types of the function. + /// If the function has . /// /// If is 0, then use . /// [DebuggerDisplay("{Name}")] - internal sealed record class FunctionData(string Name, uint MethodToken, ulong ParentClass, uint ParentClassToken, ulong ModuleId, ulong[] TypeArgs, ulong[] ParameterTypes); + internal sealed record class FunctionData(string Name, uint MethodToken, ulong ParentClass, uint ParentClassToken, ulong ModuleId, ulong[] TypeArgs, ulong[] ParameterTypes, bool StackTraceHidden); /// The name of the module. /// The version identifier of the module. diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/NameIdentificationEvents.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/NameIdentificationEvents.cs index 91394002118..50ed1b5bf37 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/NameIdentificationEvents.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/NameIdentificationEvents.cs @@ -16,9 +16,10 @@ public static class FunctionDescPayloads public const int ClassId = 2; public const int ClassToken = 3; public const int ModuleId = 4; - public const int Name = 5; - public const int TypeArgs = 6; - public const int ParameterTypes = 7; + public const int StackTraceHidden = 5; + public const int Name = 6; + public const int TypeArgs = 7; + public const int ParameterTypes = 8; } public static class ClassDescPayloads @@ -27,7 +28,8 @@ public static class ClassDescPayloads public const int ModuleId = 1; public const int Token = 2; public const int Flags = 3; - public const int TypeArgs = 4; + public const int StackTraceHidden = 4; + public const int TypeArgs = 5; } public static class ModuleDescPayloads @@ -42,8 +44,9 @@ public static class TokenDescPayloads public const int ModuleId = 0; public const int Token = 1; public const int OuterToken = 2; - public const int Name = 3; - public const int Namespace = 4; + public const int StackTraceHidden = 3; + public const int Name = 4; + public const int Namespace = 5; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/TraceEventExtensions.cs index 5ddfea78713..c6d03a0f617 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/TraceEventExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/TraceEventExtensions.cs @@ -2,11 +2,17 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Diagnostics.Tracing; +using System; namespace Microsoft.Diagnostics.Monitoring.WebApi { internal static class TraceEventExtensions { + public static bool GetBoolPayload(this TraceEvent traceEvent, int index) + { + return Convert.ToBoolean(GetPayload(traceEvent, index)); + } + public static T GetPayload(this TraceEvent traceEvent, int index) { return (T)traceEvent.PayloadValue(index); diff --git a/src/Profilers/CommonMonitorProfiler/CommonUtilities/ClrData.h b/src/Profilers/CommonMonitorProfiler/CommonUtilities/ClrData.h index c243c31a63c..22965e39d83 100644 --- a/src/Profilers/CommonMonitorProfiler/CommonUtilities/ClrData.h +++ b/src/Profilers/CommonMonitorProfiler/CommonUtilities/ClrData.h @@ -36,14 +36,15 @@ enum class ClassFlags : UINT32 class ClassData { public: - ClassData(ModuleID moduleId, mdTypeDef token, ClassFlags flags) : - _moduleId(moduleId), _token(token), _flags(flags) + ClassData(ModuleID moduleId, mdTypeDef token, ClassFlags flags, bool stackTraceHidden) : + _moduleId(moduleId), _token(token), _flags(flags), _stackTraceHidden(stackTraceHidden) { } const ModuleID GetModuleId() const { return _moduleId; } const mdTypeDef GetToken() const { return _token; } const ClassFlags GetFlags() const { return _flags; } + const bool GetStackTraceHidden() const { return _stackTraceHidden; } const std::vector& GetTypeArgs() const { return _typeArgs; } void AddTypeArg(ClassID id) { _typeArgs.push_back(static_cast(id)); } @@ -51,30 +52,34 @@ class ClassData ModuleID _moduleId; mdTypeDef _token; ClassFlags _flags; + bool _stackTraceHidden; std::vector _typeArgs; }; class TokenData { public: - TokenData(tstring&& name, tstring&& Namespace, mdTypeDef outerClass) : _name(name), _namespace(Namespace), _outerClass(outerClass) + TokenData(tstring&& name, tstring&& Namespace, mdTypeDef outerClass, bool stackTraceHidden) : + _name(name), _namespace(Namespace), _outerClass(outerClass), _stackTraceHidden(stackTraceHidden) { } const tstring& GetName() const { return _name; } const tstring& GetNamespace() const { return _namespace; } const mdTypeDef& GetOuterToken() const { return _outerClass; } + const bool GetStackTraceHidden() const { return _stackTraceHidden; } private: tstring _name; tstring _namespace; mdTypeDef _outerClass; + bool _stackTraceHidden; }; class FunctionData { public: - FunctionData(ModuleID moduleId, ClassID containingClass, tstring&& name, mdToken methodToken, mdTypeDef classToken) : - _moduleId(moduleId), _class(containingClass), _functionName(name), _methodToken(methodToken), _classToken(classToken) + FunctionData(ModuleID moduleId, ClassID containingClass, tstring&& name, mdToken methodToken, mdTypeDef classToken, bool stackTraceHidden) : + _moduleId(moduleId), _class(containingClass), _functionName(name), _methodToken(methodToken), _classToken(classToken), _stackTraceHidden(stackTraceHidden) { } @@ -83,6 +88,7 @@ class FunctionData const ClassID GetClass() const { return _class; } const mdToken GetMethodToken() const { return _methodToken; } const mdTypeDef GetClassToken() const { return _classToken; } + const bool GetStackTraceHidden() const { return _stackTraceHidden; } const std::vector& GetTypeArgs() const { return _typeArgs; } const std::vector& GetParameterTypes() const { return _parameterTypes; } void AddTypeArg(ClassID classID) { _typeArgs.push_back(static_cast(classID)); } @@ -93,6 +99,7 @@ class FunctionData tstring _functionName; mdToken _methodToken; mdTypeDef _classToken; + bool _stackTraceHidden; std::vector _typeArgs; std::vector _parameterTypes; }; diff --git a/src/Profilers/CommonMonitorProfiler/CommonUtilities/NameCache.cpp b/src/Profilers/CommonMonitorProfiler/CommonUtilities/NameCache.cpp index dd0f99ab3e1..5d059eea630 100644 --- a/src/Profilers/CommonMonitorProfiler/CommonUtilities/NameCache.cpp +++ b/src/Profilers/CommonMonitorProfiler/CommonUtilities/NameCache.cpp @@ -193,9 +193,9 @@ const std::unordered_map, std::shared_ptr functionData = std::make_shared(moduleId, parent, std::move(name), methodToken, parentToken); + std::shared_ptr functionData = std::make_shared(moduleId, parent, std::move(name), methodToken, parentToken, stackTraceHidden); for (int i = 0; i < typeArgsCount; i++) { functionData->AddTypeArg(typeArgs[i]); @@ -203,9 +203,9 @@ void NameCache::AddFunctionData(ModuleID moduleId, FunctionID id, tstring&& name _functionNames.emplace(id, functionData); } -void NameCache::AddClassData(ModuleID moduleId, ClassID id, mdTypeDef typeDef, ClassFlags flags, ClassID* typeArgs, int typeArgsCount) +void NameCache::AddClassData(ModuleID moduleId, ClassID id, mdTypeDef typeDef, ClassFlags flags, ClassID* typeArgs, int typeArgsCount, bool stackTraceHidden) { - std::shared_ptr classData = std::make_shared(moduleId, typeDef, flags); + std::shared_ptr classData = std::make_shared(moduleId, typeDef, flags, stackTraceHidden); for (int i = 0; i < typeArgsCount; i++) { classData->AddTypeArg(typeArgs[i]); @@ -213,9 +213,9 @@ void NameCache::AddClassData(ModuleID moduleId, ClassID id, mdTypeDef typeDef, C _classNames.emplace(id, classData); } -void NameCache::AddTokenData(ModuleID moduleId, mdTypeDef typeDef, mdTypeDef outerToken, tstring&& name, tstring&& Namespace) +void NameCache::AddTokenData(ModuleID moduleId, mdTypeDef typeDef, mdTypeDef outerToken, tstring&& name, tstring&& Namespace, bool stackTraceHidden) { - std::shared_ptr tokenData = std::make_shared(std::move(name), std::move(Namespace), outerToken); + std::shared_ptr tokenData = std::make_shared(std::move(name), std::move(Namespace), outerToken, stackTraceHidden); _names.emplace(std::make_pair(moduleId, typeDef), tokenData); } diff --git a/src/Profilers/CommonMonitorProfiler/CommonUtilities/NameCache.h b/src/Profilers/CommonMonitorProfiler/CommonUtilities/NameCache.h index d1549d071bc..0c8ed5c5db7 100644 --- a/src/Profilers/CommonMonitorProfiler/CommonUtilities/NameCache.h +++ b/src/Profilers/CommonMonitorProfiler/CommonUtilities/NameCache.h @@ -25,9 +25,9 @@ class NameCache bool TryGetTokenData(ModuleID modId, mdTypeDef token, std::shared_ptr& data); void AddModuleData(ModuleID moduleId, tstring&& name, GUID mvid); - void AddFunctionData(ModuleID moduleId, FunctionID id, tstring&& name, ClassID parent, mdToken methodToken, mdTypeDef parentToken, ClassID* typeArgs, int typeArgsCount); - void AddClassData(ModuleID moduleId, ClassID id, mdTypeDef typeDef, ClassFlags flags, ClassID* typeArgs, int typeArgsCount); - void AddTokenData(ModuleID moduleId, mdTypeDef typeDef, mdTypeDef outerToken, tstring&& name, tstring&& Namespace); + void AddFunctionData(ModuleID moduleId, FunctionID id, tstring&& name, ClassID parent, mdToken methodToken, mdTypeDef parentToken, ClassID* typeArgs, int typeArgsCount, bool stackTraceHidden); + void AddClassData(ModuleID moduleId, ClassID id, mdTypeDef typeDef, ClassFlags flags, ClassID* typeArgs, int typeArgsCount, bool stackTraceHidden); + void AddTokenData(ModuleID moduleId, mdTypeDef typeDef, mdTypeDef outerToken, tstring&& name, tstring&& Namespace, bool stackTraceHidden); HRESULT GetFullyQualifiedName(FunctionID id, tstring& name); HRESULT GetFullyQualifiedTypeName(ClassID classId, tstring& name); diff --git a/src/Profilers/CommonMonitorProfiler/CommonUtilities/TypeNameUtilities.cpp b/src/Profilers/CommonMonitorProfiler/CommonUtilities/TypeNameUtilities.cpp index 647cdc10f99..01c047877ca 100644 --- a/src/Profilers/CommonMonitorProfiler/CommonUtilities/TypeNameUtilities.cpp +++ b/src/Profilers/CommonMonitorProfiler/CommonUtilities/TypeNameUtilities.cpp @@ -86,7 +86,9 @@ HRESULT TypeNameUtilities::GetFunctionInfo(NameCache& nameCache, FunctionID id, IfFailRet(GetModuleInfo(nameCache, moduleId)); - nameCache.AddFunctionData(moduleId, id, tstring(funcName), classId, token, classToken, typeArgs, typeArgsCount); + bool stackTraceHidden = ShouldHideFromStackTrace(moduleId, classToken); + + nameCache.AddFunctionData(moduleId, id, tstring(funcName), classId, token, classToken, typeArgs, typeArgsCount, stackTraceHidden); // If the ClassID returned from GetFunctionInfo is 0, then the function is a shared generic function. if (classId != 0) @@ -169,7 +171,9 @@ HRESULT TypeNameUtilities::GetClassInfo(NameCache& nameCache, ClassID classId) } } - nameCache.AddClassData(modId, classId, classToken, flags, typeArgs, typeArgsCount); + bool stackTraceHidden = ShouldHideFromStackTrace(modId, classToken); + + nameCache.AddClassData(modId, classId, classToken, flags, typeArgs, typeArgsCount, stackTraceHidden); return S_OK; } @@ -193,6 +197,8 @@ HRESULT TypeNameUtilities::GetTypeDefName(NameCache& nameCache, ModuleID moduleI break; } + bool stackTraceHidden = ShouldHideFromStackTrace(moduleId, tokenToProcess); + WCHAR wName[256]; DWORD dwTypeDefFlags = 0; @@ -222,7 +228,7 @@ HRESULT TypeNameUtilities::GetTypeDefName(NameCache& nameCache, ModuleID moduleI wNameString = wNameString.substr(found + 1); } } - nameCache.AddTokenData(moduleId, tokenToProcess, outerTokenType, tstring(wNameString), tstring(wNamespaceString)); + nameCache.AddTokenData(moduleId, tokenToProcess, outerTokenType, tstring(wNameString), tstring(wNamespaceString), stackTraceHidden); tokenToProcess = outerTokenType; } @@ -283,3 +289,37 @@ HRESULT TypeNameUtilities::GetModuleInfo(NameCache& nameCache, ModuleID moduleId return S_OK; } + +bool TypeNameUtilities::ShouldHideFromStackTrace(ModuleID moduleId, mdToken token) +{ + bool hasAttribute = false; + if (HasStackTraceHiddenAttribute(moduleId, token, hasAttribute) != S_OK) { + // When encountering an error while checking for the attribute show the frame. + return false; + } + + return hasAttribute; +} + +HRESULT TypeNameUtilities::HasStackTraceHiddenAttribute(ModuleID moduleId, mdToken token, bool& hasAttribute) +{ + HRESULT hr; + hasAttribute = false; + + ComPtr pIMDImport; + IfFailRet(_profilerInfo->GetModuleMetaData(moduleId, + ofRead, + IID_IMetaDataImport, + (IUnknown**)&pIMDImport)); + + // GetCustomAttributeByName will return S_FALSE if the attribute is not found. + IfFailRet(pIMDImport->GetCustomAttributeByName( + token, + _T("System.Diagnostics.StackTraceHiddenAttribute"), + nullptr, + nullptr)); + + hasAttribute = (hr == S_OK); + + return S_OK; +} diff --git a/src/Profilers/CommonMonitorProfiler/CommonUtilities/TypeNameUtilities.h b/src/Profilers/CommonMonitorProfiler/CommonUtilities/TypeNameUtilities.h index 4690da28add..dc3df626813 100644 --- a/src/Profilers/CommonMonitorProfiler/CommonUtilities/TypeNameUtilities.h +++ b/src/Profilers/CommonMonitorProfiler/CommonUtilities/TypeNameUtilities.h @@ -24,6 +24,10 @@ class TypeNameUtilities HRESULT GetClassInfo(NameCache& nameCache, ClassID classId); HRESULT GetModuleInfo(NameCache& nameCache, ModuleID moduleId); HRESULT GetTypeDefName(NameCache& nameCache, ModuleID moduleId, mdTypeDef classToken); + HRESULT HasStackTraceHiddenAttribute(ModuleID moduleId, mdToken token, bool& hasAttribute); + // A wrapper around HasStackTraceHiddenAttribute to ensure consistent behavior when checking for the attribute + // encounters errors. + bool ShouldHideFromStackTrace(ModuleID moduleId, mdToken token); private: ComPtr _profilerInfo; }; diff --git a/src/Profilers/MonitorProfiler/Stacks/StacksEventProvider.cpp b/src/Profilers/MonitorProfiler/Stacks/StacksEventProvider.cpp index 5f148ee4520..84e98a6739a 100644 --- a/src/Profilers/MonitorProfiler/Stacks/StacksEventProvider.cpp +++ b/src/Profilers/MonitorProfiler/Stacks/StacksEventProvider.cpp @@ -46,6 +46,7 @@ HRESULT StacksEventProvider::WriteClassData(ClassID classId, const ClassData& cl static_cast(classData.GetModuleId()), classData.GetToken(), static_cast(classData.GetFlags()), + classData.GetStackTraceHidden(), classData.GetTypeArgs()); } @@ -57,6 +58,7 @@ HRESULT StacksEventProvider::WriteFunctionData(FunctionID functionId, const Func static_cast(functionData.GetClass()), functionData.GetClassToken(), static_cast(functionData.GetModuleId()), + functionData.GetStackTraceHidden(), functionData.GetName(), functionData.GetTypeArgs(), functionData.GetParameterTypes()); @@ -72,7 +74,13 @@ HRESULT StacksEventProvider::WriteModuleData(ModuleID moduleId, const ModuleData HRESULT StacksEventProvider::WriteTokenData(ModuleID moduleId, mdTypeDef typeDef, const TokenData& tokenData) { - return _tokenEvent->WritePayload(moduleId, typeDef, tokenData.GetOuterToken(), tokenData.GetName(), tokenData.GetNamespace()); + return _tokenEvent->WritePayload( + moduleId, + typeDef, + tokenData.GetOuterToken(), + tokenData.GetStackTraceHidden(), + tokenData.GetName(), + tokenData.GetNamespace()); } HRESULT StacksEventProvider::WriteEndEvent() diff --git a/src/Profilers/MonitorProfiler/Stacks/StacksEventProvider.h b/src/Profilers/MonitorProfiler/Stacks/StacksEventProvider.h index e2d6af6ce45..8f0d527767f 100644 --- a/src/Profilers/MonitorProfiler/Stacks/StacksEventProvider.h +++ b/src/Profilers/MonitorProfiler/Stacks/StacksEventProvider.h @@ -37,20 +37,20 @@ class StacksEventProvider ComPtr _profilerInfo; std::unique_ptr _provider; - + const WCHAR* CallstackPayloads[4] = { _T("ThreadId"), _T("ThreadName"), _T("FunctionIds"), _T("IpOffsets")}; std::unique_ptr, std::vector>> _callstackEvent; //Note we will either send a ClassId or a ClassToken. For Shared generic functions, there is no ClassID. - const WCHAR* FunctionPayloads[8] = { _T("FunctionId"), _T("MethodToken"), _T("ClassId"), _T("ClassToken"), _T("ModuleId"), _T("Name"), _T("TypeArgs"), _T("ParameterTypes") }; - std::unique_ptr, std::vector>> _functionEvent; + const WCHAR* FunctionPayloads[9] = { _T("FunctionId"), _T("MethodToken"), _T("ClassId"), _T("ClassToken"), _T("ModuleId"), _T("StackTraceHidden"), _T("Name"), _T("TypeArgs"), _T("ParameterTypes") }; + std::unique_ptr, std::vector>> _functionEvent; //We cannot retrieve detailed information for some ClassIds. Flags is used to indicate these conditions. - const WCHAR* ClassPayloads[5] = { _T("ClassId"), _T("ModuleId"), _T("Token"), _T("Flags"), _T("TypeArgs") }; - std::unique_ptr>> _classEvent; + const WCHAR* ClassPayloads[6] = { _T("ClassId"), _T("ModuleId"), _T("Token"), _T("Flags"), _T("StackTraceHidden"), _T("TypeArgs") }; + std::unique_ptr>> _classEvent; - const WCHAR* TokenPayloads[5] = { _T("ModuleId"), _T("Token"), _T("OuterToken"), _T("Name"), _T("Namespace") }; - std::unique_ptr> _tokenEvent; + const WCHAR* TokenPayloads[6] = { _T("ModuleId"), _T("Token"), _T("OuterToken"), _T("StackTraceHidden"), _T("Name"), _T("Namespace") }; + std::unique_ptr> _tokenEvent; const WCHAR* ModulePayloads[3] = { _T("ModuleId"), _T("ModuleVersionId"), _T("Name") }; std::unique_ptr> _moduleEvent; diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests/Exceptions/Eventing/ExceptionsEventListener.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests/Exceptions/Eventing/ExceptionsEventListener.cs index c9444ab823d..66304b0e10b 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests/Exceptions/Eventing/ExceptionsEventListener.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests/Exceptions/Eventing/ExceptionsEventListener.cs @@ -61,7 +61,8 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) ToUInt32(eventData.Payload[NameIdentificationEvents.ClassDescPayloads.Token]), ToUInt64(eventData.Payload[NameIdentificationEvents.ClassDescPayloads.ModuleId]), (ClassFlags)ToUInt32(eventData.Payload[NameIdentificationEvents.ClassDescPayloads.Flags]), - ToArray(eventData.Payload[NameIdentificationEvents.ClassDescPayloads.TypeArgs]))); + ToArray(eventData.Payload[NameIdentificationEvents.ClassDescPayloads.TypeArgs]), + ToBool(eventData.Payload[NameIdentificationEvents.ClassDescPayloads.StackTraceHidden]))); break; case ExceptionEvents.EventIds.FunctionDescription: NameCache.FunctionData.TryAdd( @@ -73,7 +74,8 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) ToUInt32(eventData.Payload[NameIdentificationEvents.FunctionDescPayloads.ClassToken]), ToUInt64(eventData.Payload[NameIdentificationEvents.FunctionDescPayloads.ModuleId]), ToArray(eventData.Payload[NameIdentificationEvents.FunctionDescPayloads.TypeArgs]), - ToArray(eventData.Payload[NameIdentificationEvents.FunctionDescPayloads.ParameterTypes]))); + ToArray(eventData.Payload[NameIdentificationEvents.FunctionDescPayloads.ParameterTypes]), + ToBool(eventData.Payload[NameIdentificationEvents.FunctionDescPayloads.StackTraceHidden]))); break; case ExceptionEvents.EventIds.ModuleDescription: NameCache.ModuleData.TryAdd( @@ -99,7 +101,8 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) new TokenData( ToString(eventData.Payload[NameIdentificationEvents.TokenDescPayloads.Name]), ToString(eventData.Payload[NameIdentificationEvents.TokenDescPayloads.Namespace]), - ToUInt32(eventData.Payload[NameIdentificationEvents.TokenDescPayloads.OuterToken]))); + ToUInt32(eventData.Payload[NameIdentificationEvents.TokenDescPayloads.OuterToken]), + ToBool(eventData.Payload[NameIdentificationEvents.TokenDescPayloads.StackTraceHidden]))); break; default: throw new NotSupportedException(); @@ -107,6 +110,11 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) } } + private static bool ToBool(object? value) + { + return Convert.ToBoolean(ToType(value)); + } + private static Guid ToGuid(object? value) { return ToType(value); diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests/Exceptions/Eventing/ExceptionsEventSourceTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests/Exceptions/Eventing/ExceptionsEventSourceTests.cs index 2fbf7109167..bb487938066 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests/Exceptions/Eventing/ExceptionsEventSourceTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests/Exceptions/Eventing/ExceptionsEventSourceTests.cs @@ -143,14 +143,15 @@ public void ExceptionsEventSource_WriteStackFrame_Event(ulong id, ulong methodId } [Theory] - [InlineData(0, 0, 0, 0, 0, "", new ulong[0], new ulong[0])] - [InlineData(1, 100663639, 128, 256, 512, "ThrowObjectDisposedException", new ulong[1] { 1024 }, new ulong[2] { 2048, 4096 })] + [InlineData(0, 0, 0, 0, 0, true, "", new ulong[0], new ulong[0])] + [InlineData(1, 100663639, 128, 256, 512, false, "ThrowObjectDisposedException", new ulong[1] { 1024 }, new ulong[2] { 2048, 4096 })] public void ExceptionsEventSource_WriteFunction_Event( ulong functionId, uint methodToken, ulong classId, uint classToken, ulong moduleId, + bool stackTraceHidden, string name, ulong[] typeArgs, ulong[] parameterTypes) @@ -160,7 +161,7 @@ public void ExceptionsEventSource_WriteFunction_Event( using ExceptionsEventListener listener = new(); listener.EnableEvents(source, EventLevel.Informational); - source.FunctionDescription(functionId, methodToken, classId, classToken, moduleId, name, typeArgs, parameterTypes); + source.FunctionDescription(functionId, methodToken, classId, classToken, moduleId, Convert.ToUInt32(stackTraceHidden), name, typeArgs, parameterTypes); Assert.True(listener.NameCache.FunctionData.TryGetValue(functionId, out FunctionData? function)); Assert.Equal(methodToken, function.MethodToken); @@ -168,6 +169,7 @@ public void ExceptionsEventSource_WriteFunction_Event( Assert.Equal(classToken, function.ParentClassToken); Assert.Equal(moduleId, function.ModuleId); Assert.Equal(name, function.Name); + Assert.Equal(stackTraceHidden, function.StackTraceHidden); // We would normally expect the following to return an array of the stack frame IDs // but in-process listener doesn't decode non-byte arrays correctly. Assert.Equal(Array.Empty(), function.TypeArgs); diff --git a/src/Tools/dotnet-monitor/Exceptions/EventExceptionsPipeline.cs b/src/Tools/dotnet-monitor/Exceptions/EventExceptionsPipeline.cs index d302e5d6c02..cd3f76addcc 100644 --- a/src/Tools/dotnet-monitor/Exceptions/EventExceptionsPipeline.cs +++ b/src/Tools/dotnet-monitor/Exceptions/EventExceptionsPipeline.cs @@ -63,7 +63,8 @@ private void Callback(TraceEvent traceEvent) traceEvent.GetPayload(NameIdentificationEvents.ClassDescPayloads.Token), traceEvent.GetPayload(NameIdentificationEvents.ClassDescPayloads.ModuleId), traceEvent.GetPayload(NameIdentificationEvents.ClassDescPayloads.Flags), - traceEvent.GetPayload(NameIdentificationEvents.ClassDescPayloads.TypeArgs) + traceEvent.GetPayload(NameIdentificationEvents.ClassDescPayloads.TypeArgs), + traceEvent.GetBoolPayload(NameIdentificationEvents.ClassDescPayloads.StackTraceHidden) ); break; case "ExceptionGroup": @@ -100,7 +101,8 @@ private void Callback(TraceEvent traceEvent) traceEvent.GetPayload(NameIdentificationEvents.FunctionDescPayloads.ModuleId), traceEvent.GetPayload(NameIdentificationEvents.FunctionDescPayloads.Name), traceEvent.GetPayload(NameIdentificationEvents.FunctionDescPayloads.TypeArgs), - traceEvent.GetPayload(NameIdentificationEvents.FunctionDescPayloads.ParameterTypes) + traceEvent.GetPayload(NameIdentificationEvents.FunctionDescPayloads.ParameterTypes), + traceEvent.GetBoolPayload(NameIdentificationEvents.FunctionDescPayloads.StackTraceHidden) ); break; case "ModuleDescription": @@ -123,7 +125,8 @@ private void Callback(TraceEvent traceEvent) traceEvent.GetPayload(NameIdentificationEvents.TokenDescPayloads.Token), traceEvent.GetPayload(NameIdentificationEvents.TokenDescPayloads.OuterToken), traceEvent.GetPayload(NameIdentificationEvents.TokenDescPayloads.Name), - traceEvent.GetPayload(NameIdentificationEvents.TokenDescPayloads.Namespace) + traceEvent.GetPayload(NameIdentificationEvents.TokenDescPayloads.Namespace), + traceEvent.GetBoolPayload(NameIdentificationEvents.TokenDescPayloads.StackTraceHidden) ); break; case "Flush": diff --git a/src/Tools/dotnet-monitor/Exceptions/EventExceptionsPipelineNameCache.cs b/src/Tools/dotnet-monitor/Exceptions/EventExceptionsPipelineNameCache.cs index 5cb3169509a..667d1446064 100644 --- a/src/Tools/dotnet-monitor/Exceptions/EventExceptionsPipelineNameCache.cs +++ b/src/Tools/dotnet-monitor/Exceptions/EventExceptionsPipelineNameCache.cs @@ -16,9 +16,9 @@ internal sealed class EventExceptionsPipelineNameCache : IExceptionsNameCache public NameCache NameCache => _nameCache; - public void AddClass(ulong id, uint token, ulong moduleId, ClassFlags flags, ulong[] typeArgs) + public void AddClass(ulong id, uint token, ulong moduleId, ClassFlags flags, ulong[] typeArgs, bool stackTraceHidden) { - _nameCache.ClassData.TryAdd(id, new ClassData(token, moduleId, flags, typeArgs ?? Array.Empty())); + _nameCache.ClassData.TryAdd(id, new ClassData(token, moduleId, flags, typeArgs, stackTraceHidden)); } public void AddExceptionGroup(ulong id, ulong exceptionClassId, ulong throwingMethodId, int ilOffset) @@ -26,9 +26,9 @@ public void AddExceptionGroup(ulong id, ulong exceptionClassId, ulong throwingMe _exceptionGroupMap.Add(id, new ExceptionGroup(exceptionClassId, throwingMethodId, ilOffset)); } - public void AddFunction(ulong id, uint methodToken, ulong classId, uint classToken, ulong moduleId, string name, ulong[] typeArgs, ulong[] parameterTypes) + public void AddFunction(ulong id, uint methodToken, ulong classId, uint classToken, ulong moduleId, string name, ulong[] typeArgs, ulong[] parameterTypes, bool stackTraceHidden) { - _nameCache.FunctionData.TryAdd(id, new FunctionData(name, methodToken, classId, classToken, moduleId, typeArgs ?? Array.Empty(), parameterTypes ?? Array.Empty())); + _nameCache.FunctionData.TryAdd(id, new FunctionData(name, methodToken, classId, classToken, moduleId, typeArgs, parameterTypes, stackTraceHidden)); } public void AddStackFrame(ulong id, ulong functionId, int ilOffset) @@ -41,11 +41,11 @@ public void AddModule(ulong id, Guid moduleVersionId, string moduleName) _nameCache.ModuleData.TryAdd(id, new ModuleData(moduleName, moduleVersionId)); } - public void AddToken(ulong moduleId, uint token, uint outerToken, string name, string @namespace) + public void AddToken(ulong moduleId, uint token, uint outerToken, string name, string @namespace, bool stackTraceHidden) { _nameCache.TokenData.TryAdd( new ModuleScopedToken(moduleId, token), - new TokenData(name, @namespace, outerToken)); + new TokenData(name, @namespace, outerToken, stackTraceHidden)); } public bool TryGetExceptionGroup(ulong groupId, out ulong exceptionClassId, out ulong throwingMethodId, out int ilOffset)