【发布时间】:2020-08-18 08:00:37
【问题描述】:
我尝试使用 TraceProcessing 库从具有关联 Clr Stackwalk 事件的托管异常中获取堆栈跟踪。原则上,解析事件并获取方法地址应该很容易。
using Microsoft.Windows.EventTracing;
using Microsoft.Windows.EventTracing.Events;
using System;
using System.Collections.Generic;
using System.Linq;
namespace TraceProcessingStackDecoding
{
class Program
{
static void Main(string[] args)
{
string etlFile = args[0];
using ITraceProcessor processor = TraceProcessor.Create(etlFile, new TraceProcessorSettings
{
AllowLostEvents = true,
});
IPendingResult<IGenericEventDataSource> genericEvents = processor.UseGenericEvents();
processor.Process();
const int ClrStackWalkEventId = 82;
const string DotNetRuntimeProviderName = "Microsoft-Windows-DotNETRuntime";
foreach (IGenericEvent clrStackWalk in genericEvents.Result.Events.Where( x=> x.ProviderName == DotNetRuntimeProviderName && x.Id == ClrStackWalkEventId))
{
IReadOnlyList<Address> stackAddresses = clrStackWalk.Fields["Stack"].AsAddressList;
uint frameCount = clrStackWalk.Fields["FrameCount"].AsUInt32;
if( stackAddresses.Count != frameCount)
{
Console.WriteLine($"Error: Address List has only {stackAddresses.Count} entries but expected were {frameCount} entries!");
}
}
}
}
}
但是当我这样做时,我发现几乎所有堆栈帧都丢失了。我总是得到 2。如果我没记错的话,它应该返回所有数据,直到事件结束。
Error: Address List has only 2 entries but expected were 34 entries!
Error: Address List has only 2 entries but expected were 35 entries!
Error: Address List has only 2 entries but expected were 35 entries!
Error: Address List has only 2 entries but expected were 35 entries!
Error: Address List has only 2 entries but expected were 36 entries!
Error: Address List has only 2 entries but expected were 37 entries!
Error: Address List has only 2 entries but expected were 64 entries!
Error: Address List has only 2 entries but expected were 30 entries!
Error: Address List has only 2 entries but expected were 77 entries!
Error: Address List has only 2 entries but expected were 77 entries!
Error: Address List has only 2 entries but expected were 31 entries!
Error: Address List has only 2 entries but expected were 77 entries!
Clr Stackwalk 事件清单将其定义为:
<template tid="ClrStackWalk">
<data name="ClrInstanceID" inType="win:UInt16"/>
<data name="Reserved1" inType="win:UInt8"/>
<data name="Reserved2" inType="win:UInt8"/>
<data name="FrameCount" inType="win:UInt32"/>
<data name="Stack" count="2" inType="win:Pointer"/>
</template>
问题可能是您认真对待的计数属性。但这不是事件实际记录的方式,地址列表几乎是 100% 的动态堆栈列表,没有固定计数。如果它是显示事件中的最后一项,则最好将直到事件结束的所有数据作为地址列表返回。
由于我无法访问原始事件,我只有一个不错的类型安全尽管无用的包装器,这使得无法获取 .NET Stackwalk 事件的堆栈帧。 除此之外,当我尝试查找符号时,TraceProcessing 是否还支持 JITed 代码?在 API 级别,我只能在图像级别找到一种方法,这将无法解码 JITed 代码?但是由于 TraceProcessing 可以解码 JITed 调用堆栈,我认为 API 级别可能缺少一些东西。
foreach (Address stackAdr in stackAddresses)
{
foreach (var image in ev.Process.Images)
{
var range = image.AddressRange;
if ( ( (range.BaseAddress < range.LimitAddress) && (stackAdr > range.BaseAddress && stackAdr < range.LimitAddress)) ||
( (range.BaseAddress > range.LimitAddress) && (stackAdr < range.BaseAddress && stackAdr > range.LimitAddress)) )
{
IStackSymbol stackSymbol = image.GetSymbol(stackAdr);
Console.WriteLine(stackSymbol?.FunctionName);
}
}
}
这种方法是否适用于开箱即用的 JIT 代码,还是我需要手动解码所有 JIT 事件?
【问题讨论】:
标签: c# etw .net-traceprocessing