/// <summary> /// Read the EH clause from a given file offset in the PE image. /// </summary> /// <param name="reader">R2R image reader<param> /// <param name="offset">Offset of the EH clause in the image</param> public EHClause(ReadyToRunReader reader, int offset) { Flags = (CorExceptionFlag)BitConverter.ToUInt32(reader.Image, offset + 0 * sizeof(uint)); TryOffset = BitConverter.ToUInt32(reader.Image, offset + 1 * sizeof(uint)); TryEnd = BitConverter.ToUInt32(reader.Image, offset + 2 * sizeof(uint)); HandlerOffset = BitConverter.ToUInt32(reader.Image, offset + 3 * sizeof(uint)); HandlerEnd = BitConverter.ToUInt32(reader.Image, offset + 4 * sizeof(uint)); ClassTokenOrFilterOffset = BitConverter.ToUInt32(reader.Image, offset + 5 * sizeof(uint)); if ((Flags & CorExceptionFlag.COR_ILEXCEPTION_CLAUSE_KIND_MASK) == CorExceptionFlag.COR_ILEXCEPTION_CLAUSE_NONE) { ClassName = MetadataNameFormatter.FormatHandle(reader.MetadataReader, MetadataTokens.Handle((int)ClassTokenOrFilterOffset)); } }
public RuntimeFunction( ReadyToRunReader readyToRunReader, int id, int startRva, int endRva, int unwindRva, int codeOffset, ReadyToRunMethod method, BaseUnwindInfo unwindInfo, BaseGcInfo gcInfo, EHInfo ehInfo) { _readyToRunReader = readyToRunReader; Id = id; StartAddress = startRva; UnwindRVA = unwindRva; Method = method; UnwindInfo = unwindInfo; if (endRva != -1) { Size = endRva - startRva; } else if (unwindInfo is x86.UnwindInfo) { Size = (int)((x86.UnwindInfo)unwindInfo).FunctionLength; } else if (unwindInfo is Arm.UnwindInfo) { Size = (int)((Arm.UnwindInfo)unwindInfo).FunctionLength; } else if (unwindInfo is Arm64.UnwindInfo) { Size = (int)((Arm64.UnwindInfo)unwindInfo).FunctionLength; } else if (gcInfo != null) { Size = gcInfo.CodeLength; } else { Size = -1; } CodeOffset = codeOffset; method.GcInfo = gcInfo; EHInfo = ehInfo; }
private void EnsureInitialized() { if (_boundsList != null) { return; } ReadyToRunReader _readyToRunReader = _runtimeFunction.ReadyToRunReader; int offset = _offset; _boundsList = new List <DebugInfoBoundsEntry>(); _variablesList = new List <NativeVarInfo>(); Machine machine = _readyToRunReader.Machine; byte[] image = _readyToRunReader.Image; _machine = machine; // Get the id of the runtime function from the NativeArray uint lookback = 0; uint debugInfoOffset = NativeReader.DecodeUnsigned(image, (uint)offset, ref lookback); if (lookback != 0) { System.Diagnostics.Debug.Assert(0 < lookback && lookback < offset); debugInfoOffset = (uint)offset - lookback; } NibbleReader reader = new NibbleReader(image, (int)debugInfoOffset); uint boundsByteCount = reader.ReadUInt(); uint variablesByteCount = reader.ReadUInt(); int boundsOffset = reader.GetNextByteOffset(); int variablesOffset = (int)(boundsOffset + boundsByteCount); if (boundsByteCount > 0) { ParseBounds(image, boundsOffset); } if (variablesByteCount > 0) { ParseNativeVarInfo(image, variablesOffset); } }
public RuntimeFunction( ReadyToRunReader readyToRunReader, int id, int startRva, int endRva, int unwindRva, int codeOffset, ReadyToRunMethod method, BaseUnwindInfo unwindInfo) { _readyToRunReader = readyToRunReader; Id = id; StartAddress = startRva; EndAddress = endRva; UnwindRVA = unwindRva; Method = method; UnwindInfo = unwindInfo; CodeOffset = codeOffset; }
public static TransitionBlock FromReader(ReadyToRunReader reader) { switch (reader.Architecture) { case Architecture.X86: return(X86TransitionBlock.Instance); case Architecture.X64: return(reader.OperatingSystem == OperatingSystem.Windows ? X64WindowsTransitionBlock.Instance : X64UnixTransitionBlock.Instance); case Architecture.Arm: return(ArmTransitionBlock.Instance); case Architecture.Arm64: return(Arm64TransitionBlock.Instance); default: throw new NotImplementedException(); } }
/// <summary> /// Read the EH clause from a given file offset in the PE image. /// </summary> /// <param name="reader">R2R image reader<param> /// <param name="offset">Offset of the EH clause in the image</param> public EHClause(ReadyToRunReader reader, int offset) { Flags = (CorExceptionFlag)BitConverter.ToUInt32(reader.Image, offset + 0 * sizeof(uint)); TryOffset = BitConverter.ToUInt32(reader.Image, offset + 1 * sizeof(uint)); TryEnd = BitConverter.ToUInt32(reader.Image, offset + 2 * sizeof(uint)); HandlerOffset = BitConverter.ToUInt32(reader.Image, offset + 3 * sizeof(uint)); HandlerEnd = BitConverter.ToUInt32(reader.Image, offset + 4 * sizeof(uint)); ClassTokenOrFilterOffset = BitConverter.ToUInt32(reader.Image, offset + 5 * sizeof(uint)); if ((Flags & CorExceptionFlag.COR_ILEXCEPTION_CLAUSE_KIND_MASK) == CorExceptionFlag.COR_ILEXCEPTION_CLAUSE_NONE) { if (reader.Composite) { // TODO: EH clauses in composite mode ClassName = "TODO-composite module in EH clause"; } else { ClassName = MetadataNameFormatter.FormatHandle(reader.GetGlobalMetadata()?.MetadataReader, MetadataTokens.Handle((int)ClassTokenOrFilterOffset)); } } }
public PgoDataLoader(ReadyToRunReader r2rReader, SignatureFormattingOptions formatOptions) { _formatOptions = formatOptions; _r2rReader = r2rReader; }
public InliningInfoSection2(ReadyToRunReader reader, int offset, int endOffset) { _r2r = reader; _startOffset = offset; _endOffset = endOffset; }
/// <summary> /// Extracts the method signature from the metadata by rid /// </summary> public ReadyToRunMethod( ReadyToRunReader readyToRunReader, IAssemblyMetadata componentReader, EntityHandle methodHandle, int entryPointId, string owningType, string constrainedType, string[] instanceArgs, int?fixupOffset) { _readyToRunReader = readyToRunReader; _fixupOffset = fixupOffset; MethodHandle = methodHandle; EntryPointRuntimeFunctionId = entryPointId; ComponentReader = componentReader; EntityHandle owningTypeHandle; GenericParameterHandleCollection genericParams = default(GenericParameterHandleCollection); DisassemblingGenericContext genericContext = new DisassemblingGenericContext(typeParameters: Array.Empty <string>(), methodParameters: instanceArgs); DisassemblingTypeProvider typeProvider = new DisassemblingTypeProvider(); // get the method signature from the method handle switch (MethodHandle.Kind) { case HandleKind.MethodDefinition: { MethodDefinition methodDef = ComponentReader.MetadataReader.GetMethodDefinition((MethodDefinitionHandle)MethodHandle); if (methodDef.RelativeVirtualAddress != 0) { MethodBodyBlock mbb = ComponentReader.ImageReader.GetMethodBody(methodDef.RelativeVirtualAddress); if (!mbb.LocalSignature.IsNil) { StandaloneSignature ss = ComponentReader.MetadataReader.GetStandaloneSignature(mbb.LocalSignature); LocalSignature = ss.DecodeLocalSignature(typeProvider, genericContext); } } Name = ComponentReader.MetadataReader.GetString(methodDef.Name); Signature = methodDef.DecodeSignature <string, DisassemblingGenericContext>(typeProvider, genericContext); owningTypeHandle = methodDef.GetDeclaringType(); genericParams = methodDef.GetGenericParameters(); } break; case HandleKind.MemberReference: { MemberReference memberRef = ComponentReader.MetadataReader.GetMemberReference((MemberReferenceHandle)MethodHandle); Name = ComponentReader.MetadataReader.GetString(memberRef.Name); Signature = memberRef.DecodeMethodSignature <string, DisassemblingGenericContext>(typeProvider, genericContext); owningTypeHandle = memberRef.Parent; } break; default: throw new NotImplementedException(); } if (owningType != null) { DeclaringType = owningType; } else { DeclaringType = MetadataNameFormatter.FormatHandle(ComponentReader.MetadataReader, owningTypeHandle); } StringBuilder sb = new StringBuilder(); sb.Append(Signature.ReturnType); sb.Append(" "); sb.Append(DeclaringType); sb.Append("."); sb.Append(Name); if (Signature.GenericParameterCount != 0) { sb.Append("<"); for (int i = 0; i < Signature.GenericParameterCount; i++) { if (i > 0) { sb.Append(", "); } if (instanceArgs != null && instanceArgs.Length > i) { sb.Append(instanceArgs[i]); } else { sb.Append("!"); sb.Append(i); } } sb.Append(">"); } sb.Append("("); for (int i = 0; i < Signature.ParameterTypes.Length; i++) { if (i > 0) { sb.Append(", "); } sb.AppendFormat($"{Signature.ParameterTypes[i]}"); } sb.Append(")"); SignatureString = sb.ToString(); }
public DebugInfo(ReadyToRunReader readyToRunReader, int offset) { this._readyToRunReader = readyToRunReader; this._offset = offset; }
public MethodMemoryMap( TraceProcess p, TraceTypeSystemContext tsc, TraceRuntimeDescToTypeSystemDesc idParser, int clrInstanceID, FileInfo preciseDebugInfoFile, Logger logger) { // Capture the addresses of jitted code List <MemoryRegionInfo> infos = new List <MemoryRegionInfo>(); Dictionary <JittedID, MemoryRegionInfo> info = new Dictionary <JittedID, MemoryRegionInfo>(); foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadTraceData>()) { if (e.ClrInstanceID != clrInstanceID) { continue; } MethodDesc method = null; try { method = idParser.ResolveMethodID(e.MethodID); } catch { } if (method != null) { JittedID jittedID = new JittedID(e.MethodID, 0); if (!info.ContainsKey(jittedID)) { info.Add(jittedID, new MemoryRegionInfo { StartAddress = e.MethodStartAddress, EndAddress = e.MethodStartAddress + checked ((uint)e.MethodSize), Method = method, }); } } } foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadVerboseTraceData>()) { if (e.ClrInstanceID != clrInstanceID) { continue; } MethodDesc method = null; try { method = idParser.ResolveMethodID(e.MethodID, throwIfNotFound: false); } catch { } if (method != null) { JittedID jittedID = new JittedID(e.MethodID, e.ReJITID); if (!info.ContainsKey(jittedID)) { info.Add(jittedID, new MemoryRegionInfo { StartAddress = e.MethodStartAddress, EndAddress = e.MethodStartAddress + checked ((uint)e.MethodSize), Method = method, }); } } } var sigProvider = new R2RSignatureTypeProviderForGlobalTables(tsc); foreach (var module in p.LoadedModules) { if (module.FilePath == "") { continue; } if (!File.Exists(module.FilePath)) { continue; } try { byte[] image = File.ReadAllBytes(module.FilePath); using (FileStream fstream = new FileStream(module.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { var r2rCheckPEReader = new System.Reflection.PortableExecutable.PEReader(fstream, System.Reflection.PortableExecutable.PEStreamOptions.LeaveOpen); if (!ILCompiler.Reflection.ReadyToRun.ReadyToRunReader.IsReadyToRunImage(r2rCheckPEReader)) { continue; } } var reader = new ILCompiler.Reflection.ReadyToRun.ReadyToRunReader(tsc, module.FilePath); foreach (var methodEntry in reader.GetCustomMethodToRuntimeFunctionMapping <TypeDesc, MethodDesc, R2RSigProviderContext>(sigProvider)) { foreach (var runtimeFunction in methodEntry.Value.RuntimeFunctions) { infos.Add(new MemoryRegionInfo { StartAddress = module.ImageBase + (ulong)runtimeFunction.StartAddress, EndAddress = module.ImageBase + (ulong)runtimeFunction.StartAddress + (uint)runtimeFunction.Size, Method = methodEntry.Key, NativeToILMap = runtimeFunction.DebugInfo != null ? CreateNativeToILMap(methodEntry.Key, runtimeFunction.DebugInfo.BoundsList) : null, }); } } } catch { logger.PrintWarning($"Failed to load method entry points from R2R module {module.FilePath}"); } } List <PreciseDebugInfo> preciseInfos = null; if (preciseDebugInfoFile != null) { preciseInfos = File.ReadAllLines(preciseDebugInfoFile.FullName) .Select(l => JsonSerializer.Deserialize <PreciseDebugInfo>(l)) .ToList(); } if (preciseInfos != null && preciseInfos.Count > 0) { foreach (PreciseDebugInfo preciseDebugInf in preciseInfos) { if (info.TryGetValue(new JittedID((long)preciseDebugInf.MethodID, 0), out MemoryRegionInfo inf)) { inf.NativeToILMap = CreateNativeToILMap(idParser, preciseDebugInf); } } } else { // Associate NativeToILMap with MethodLoad event found Memory Regions foreach (MethodILToNativeMapTraceData e in p.EventsInProcess.ByEventType <MethodILToNativeMapTraceData>()) { if (info.TryGetValue(new JittedID(e.MethodID, e.ReJITID), out MemoryRegionInfo inf)) { inf.NativeToILMap = CreateNativeToILMap(inf.Method, e); } } } // Sort the R2R data by StartAddress MemoryRegionInfoStartAddressComparer startAddressComparer = new MemoryRegionInfoStartAddressComparer(); infos.Sort(startAddressComparer); // For each method found via MethodLoad events, check to see if it exists in the infos array, and if it does not, build a list to add List <MemoryRegionInfo> memoryRegionsToAdd = new List <MemoryRegionInfo>(); foreach (var methodLoadInfo in info.Values) { int searchResult = infos.BinarySearch(methodLoadInfo, startAddressComparer); if (searchResult < 0) { memoryRegionsToAdd.Add(methodLoadInfo); } } // Add the regions from the MethodLoad events, and keep the overall array sorted infos.AddRange(memoryRegionsToAdd); infos.Sort(startAddressComparer); _infos = infos.ToArray(); _infoKeys = _infos.Select(i => i.StartAddress).ToArray(); #if DEBUG for (int i = 0; i < _infos.Length - 1; i++) { var cur = _infos[i]; var next = _infos[i + 1]; if (cur.EndAddress <= next.StartAddress) { continue; } Debug.Fail("Overlap in memory ranges"); } #endif }
internal ReadyToRunAssembly(ReadyToRunReader reader) { _reader = reader; }
static int InnerProcessTraceFileMain(CommandLineOptions commandLineOptions) { if (commandLineOptions.TraceFile == null) { PrintUsage(commandLineOptions, "--trace must be specified"); return(-8); } if (commandLineOptions.OutputFileName == null) { PrintUsage(commandLineOptions, "--output must be specified"); return(-8); } if (commandLineOptions.OutputFileName != null) { if (!commandLineOptions.FileType.HasValue) { PrintUsage(commandLineOptions, $"--pgo-file-type must be specified"); return(-9); } if ((commandLineOptions.FileType.Value != PgoFileType.jittrace) && (commandLineOptions.FileType != PgoFileType.mibc)) { PrintUsage(commandLineOptions, $"Invalid output pgo type {commandLineOptions.FileType} specified."); return(-9); } if (commandLineOptions.FileType == PgoFileType.jittrace) { if (!commandLineOptions.OutputFileName.Name.EndsWith(".jittrace")) { PrintUsage(commandLineOptions, $"jittrace output file name must end with .jittrace"); return(-9); } } if (commandLineOptions.FileType == PgoFileType.mibc) { if (!commandLineOptions.OutputFileName.Name.EndsWith(".mibc")) { PrintUsage(commandLineOptions, $"mibc output file name must end with .mibc"); return(-9); } } } string etlFileName = commandLineOptions.TraceFile.FullName; foreach (string nettraceExtension in new string[] { ".netperf", ".netperf.zip", ".nettrace" }) { if (commandLineOptions.TraceFile.FullName.EndsWith(nettraceExtension)) { etlFileName = commandLineOptions.TraceFile.FullName.Substring(0, commandLineOptions.TraceFile.FullName.Length - nettraceExtension.Length) + ".etlx"; PrintMessage($"Creating ETLX file {etlFileName} from {commandLineOptions.TraceFile.FullName}"); TraceLog.CreateFromEventPipeDataFile(commandLineOptions.TraceFile.FullName, etlFileName); } } string lttngExtension = ".trace.zip"; if (commandLineOptions.TraceFile.FullName.EndsWith(lttngExtension)) { etlFileName = commandLineOptions.TraceFile.FullName.Substring(0, commandLineOptions.TraceFile.FullName.Length - lttngExtension.Length) + ".etlx"; PrintMessage($"Creating ETLX file {etlFileName} from {commandLineOptions.TraceFile.FullName}"); TraceLog.CreateFromLttngTextDataFile(commandLineOptions.TraceFile.FullName, etlFileName); } UnZipIfNecessary(ref etlFileName, commandLineOptions.BasicProgressMessages ? Console.Out : new StringWriter()); using (var traceLog = TraceLog.OpenOrConvert(etlFileName)) { if ((!commandLineOptions.Pid.HasValue && commandLineOptions.ProcessName == null) && traceLog.Processes.Count != 1) { PrintError("Trace file contains multiple processes to distinguish between"); PrintOutput("Either a pid or process name from the following list must be specified"); foreach (TraceProcess proc in traceLog.Processes) { PrintOutput($"Procname = {proc.Name} Pid = {proc.ProcessID}"); } return(1); } if (commandLineOptions.Pid.HasValue && (commandLineOptions.ProcessName != null)) { PrintError("--pid and --process-name cannot be specified together"); return(-1); } // For a particular process TraceProcess p; if (commandLineOptions.Pid.HasValue) { p = traceLog.Processes.LastProcessWithID(commandLineOptions.Pid.Value); } else if (commandLineOptions.ProcessName != null) { List <TraceProcess> matchingProcesses = new List <TraceProcess>(); foreach (TraceProcess proc in traceLog.Processes) { if (String.Compare(proc.Name, commandLineOptions.ProcessName, StringComparison.OrdinalIgnoreCase) == 0) { matchingProcesses.Add(proc); } } if (matchingProcesses.Count == 0) { PrintError("Unable to find matching process in trace"); return(-1); } if (matchingProcesses.Count > 1) { StringBuilder errorMessage = new StringBuilder(); errorMessage.AppendLine("Found multiple matching processes in trace"); foreach (TraceProcess proc in matchingProcesses) { errorMessage.AppendLine($"{proc.Name}\tpid={proc.ProcessID}\tCPUMSec={proc.CPUMSec}"); } PrintError(errorMessage.ToString()); return(-2); } p = matchingProcesses[0]; } else { p = traceLog.Processes.First(); } if (!p.EventsInProcess.ByEventType <MethodDetailsTraceData>().Any()) { PrintError($"No MethodDetails\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?"); return(-3); } if (!p.EventsInProcess.ByEventType <GCBulkTypeTraceData>().Any()) { PrintError($"No BulkType data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?"); return(-4); } if (!p.EventsInProcess.ByEventType <ModuleLoadUnloadTraceData>().Any()) { PrintError($"No managed module load data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?"); return(-5); } if (!p.EventsInProcess.ByEventType <MethodJittingStartedTraceData>().Any()) { PrintError($"No managed jit starting data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?"); return(-5); } PgoTraceProcess pgoProcess = new PgoTraceProcess(p); int? clrInstanceId = commandLineOptions.ClrInstanceId; if (!clrInstanceId.HasValue) { HashSet <int> clrInstanceIds = new HashSet <int>(); HashSet <int> examinedClrInstanceIds = new HashSet <int>(); foreach (var assemblyLoadTrace in p.EventsInProcess.ByEventType <AssemblyLoadUnloadTraceData>()) { if (examinedClrInstanceIds.Add(assemblyLoadTrace.ClrInstanceID)) { if (pgoProcess.ClrInstanceIsCoreCLRInstance(assemblyLoadTrace.ClrInstanceID)) { clrInstanceIds.Add(assemblyLoadTrace.ClrInstanceID); } } } if (clrInstanceIds.Count != 1) { if (clrInstanceIds.Count == 0) { PrintError($"No managed CLR in target process, or per module information could not be loaded from the trace."); } else { // There are multiple clr processes... search for the one that implements int[] clrInstanceIdsArray = clrInstanceIds.ToArray(); Array.Sort(clrInstanceIdsArray); StringBuilder errorMessage = new StringBuilder(); errorMessage.AppendLine("Multiple CLR instances used in process. Choose one to examine with -clrInstanceID:<id> Valid ids:"); foreach (int instanceID in clrInstanceIds) { errorMessage.AppendLine(instanceID.ToString()); } PrintError(errorMessage.ToString()); } return(-10); } else { clrInstanceId = clrInstanceIds.First(); } } var tsc = new TraceTypeSystemContext(pgoProcess, clrInstanceId.Value, s_logger); if (commandLineOptions.VerboseWarnings) { PrintWarning($"{traceLog.EventsLost} Lost events"); } bool filePathError = false; if (commandLineOptions.Reference != null) { foreach (FileInfo fileReference in commandLineOptions.Reference) { if (!File.Exists(fileReference.FullName)) { PrintError($"Unable to find reference '{fileReference.FullName}'"); filePathError = true; } else { tsc.GetModuleFromPath(fileReference.FullName); } } } if (filePathError) { return(-6); } if (!tsc.Initialize()) { return(-12); } TraceRuntimeDescToTypeSystemDesc idParser = new TraceRuntimeDescToTypeSystemDesc(p, tsc, clrInstanceId.Value); SortedDictionary <int, ProcessedMethodData> methodsToAttemptToPrepare = new SortedDictionary <int, ProcessedMethodData>(); if (commandLineOptions.ProcessR2REvents) { foreach (var e in p.EventsInProcess.ByEventType <R2RGetEntryPointTraceData>()) { int parenIndex = e.MethodSignature.IndexOf('('); string retArg = e.MethodSignature.Substring(0, parenIndex); string paramsArgs = e.MethodSignature.Substring(parenIndex); string methodNameFromEventDirectly = retArg + e.MethodNamespace + "." + e.MethodName + paramsArgs; if (e.ClrInstanceID != clrInstanceId.Value) { if (!commandLineOptions.Warnings) { continue; } PrintWarning($"Skipped R2REntryPoint {methodNameFromEventDirectly} due to ClrInstanceID of {e.ClrInstanceID}"); continue; } MethodDesc method = null; string extraWarningText = null; try { method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings); } catch (Exception exception) { extraWarningText = exception.ToString(); } if (method == null) { if ((e.MethodNamespace == "dynamicClass") || !commandLineOptions.Warnings) { continue; } PrintWarning($"Unable to parse {methodNameFromEventDirectly} when looking up R2R methods"); if (extraWarningText != null) { PrintWarning(extraWarningText); } continue; } if ((e.TimeStampRelativeMSec >= commandLineOptions.ExcludeEventsBefore) && (e.TimeStampRelativeMSec <= commandLineOptions.ExcludeEventsAfter)) { methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "R2RLoad")); } } } // Find all the jitStart events. if (commandLineOptions.ProcessJitEvents) { foreach (var e in p.EventsInProcess.ByEventType <MethodJittingStartedTraceData>()) { int parenIndex = e.MethodSignature.IndexOf('('); string retArg = e.MethodSignature.Substring(0, parenIndex); string paramsArgs = e.MethodSignature.Substring(parenIndex); string methodNameFromEventDirectly = retArg + e.MethodNamespace + "." + e.MethodName + paramsArgs; if (e.ClrInstanceID != clrInstanceId.Value) { if (!commandLineOptions.Warnings) { continue; } PrintWarning($"Skipped {methodNameFromEventDirectly} due to ClrInstanceID of {e.ClrInstanceID}"); continue; } MethodDesc method = null; string extraWarningText = null; try { method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings); } catch (Exception exception) { extraWarningText = exception.ToString(); } if (method == null) { if ((e.MethodNamespace == "dynamicClass") || !commandLineOptions.Warnings) { continue; } PrintWarning($"Unable to parse {methodNameFromEventDirectly}"); if (extraWarningText != null) { PrintWarning(extraWarningText); } continue; } if ((e.TimeStampRelativeMSec >= commandLineOptions.ExcludeEventsBefore) && (e.TimeStampRelativeMSec <= commandLineOptions.ExcludeEventsAfter)) { methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "JitStart")); } } } Dictionary <MethodDesc, Dictionary <MethodDesc, int> > callGraph = null; Dictionary <MethodDesc, int> exclusiveSamples = null; if (commandLineOptions.GenerateCallGraph) { HashSet <MethodDesc> methodsListedToPrepare = new HashSet <MethodDesc>(); foreach (var entry in methodsToAttemptToPrepare) { methodsListedToPrepare.Add(entry.Value.Method); } callGraph = new Dictionary <MethodDesc, Dictionary <MethodDesc, int> >(); exclusiveSamples = new Dictionary <MethodDesc, int>(); // Capture the addresses of jitted code List <ValueTuple <InstructionPointerRange, MethodDesc> > codeLocations = new List <(InstructionPointerRange, MethodDesc)>(); foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadTraceData>()) { if (e.ClrInstanceID != clrInstanceId.Value) { continue; } MethodDesc method = null; try { method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings); } catch (Exception) { } if (method != null) { codeLocations.Add((new InstructionPointerRange(e.MethodStartAddress, e.MethodSize), method)); } } foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadVerboseTraceData>()) { if (e.ClrInstanceID != clrInstanceId.Value) { continue; } MethodDesc method = null; try { method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings); } catch (Exception) { } if (method != null) { codeLocations.Add((new InstructionPointerRange(e.MethodStartAddress, e.MethodSize), method)); } } var sigProvider = new R2RSignatureTypeProvider(tsc); foreach (var module in p.LoadedModules) { if (module.FilePath == "") { continue; } if (!File.Exists(module.FilePath)) { continue; } try { byte[] image = File.ReadAllBytes(module.FilePath); using (FileStream fstream = new FileStream(module.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { var r2rCheckPEReader = new System.Reflection.PortableExecutable.PEReader(fstream, System.Reflection.PortableExecutable.PEStreamOptions.LeaveOpen); if (!ILCompiler.Reflection.ReadyToRun.ReadyToRunReader.IsReadyToRunImage(r2rCheckPEReader)) { continue; } } var reader = new ILCompiler.Reflection.ReadyToRun.ReadyToRunReader(tsc, module.FilePath); foreach (var methodEntry in reader.GetCustomMethodToRuntimeFunctionMapping <TypeDesc, MethodDesc, R2RSigProviderContext>(sigProvider)) { foreach (var runtimeFunction in methodEntry.Value.RuntimeFunctions) { codeLocations.Add((new InstructionPointerRange(module.ImageBase + (ulong)runtimeFunction.StartAddress, runtimeFunction.Size), methodEntry.Key)); } } } catch { } } InstructionPointerRange[] instructionPointerRanges = new InstructionPointerRange[codeLocations.Count]; MethodDesc[] methods = new MethodDesc[codeLocations.Count]; for (int i = 0; i < codeLocations.Count; i++) { instructionPointerRanges[i] = codeLocations[i].Item1; methods[i] = codeLocations[i].Item2; } Array.Sort(instructionPointerRanges, methods); foreach (var e in p.EventsInProcess.ByEventType <SampledProfileTraceData>()) { var callstack = e.CallStack(); if (callstack == null) { continue; } ulong address1 = callstack.CodeAddress.Address; MethodDesc topOfStackMethod = LookupMethodByAddress(address1); MethodDesc nextMethod = null; if (callstack.Caller != null) { ulong address2 = callstack.Caller.CodeAddress.Address; nextMethod = LookupMethodByAddress(address2); } if (topOfStackMethod != null) { if (!methodsListedToPrepare.Contains(topOfStackMethod)) { methodsListedToPrepare.Add(topOfStackMethod); methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, topOfStackMethod, "SampleMethod")); } if (exclusiveSamples.TryGetValue(topOfStackMethod, out int count)) { exclusiveSamples[topOfStackMethod] = count + 1; } else { exclusiveSamples[topOfStackMethod] = 1; } } if (topOfStackMethod != null && nextMethod != null) { if (!methodsListedToPrepare.Contains(nextMethod)) { methodsListedToPrepare.Add(nextMethod); methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, nextMethod, "SampleMethodCaller")); } if (!callGraph.TryGetValue(nextMethod, out var innerDictionary)) { innerDictionary = new Dictionary <MethodDesc, int>(); callGraph[nextMethod] = innerDictionary; } if (innerDictionary.TryGetValue(topOfStackMethod, out int count)) { innerDictionary[topOfStackMethod] = count + 1; } else { innerDictionary[topOfStackMethod] = 1; } } } MethodDesc LookupMethodByAddress(ulong address) { int index = Array.BinarySearch(instructionPointerRanges, new InstructionPointerRange(address, 1)); if (index >= 0) { return(methods[index]); } else { index = ~index; if (index >= instructionPointerRanges.Length) { return(null); } if (instructionPointerRanges[index].StartAddress < address) { if (instructionPointerRanges[index].EndAddress > address) { return(methods[index]); } } if (index == 0) { return(null); } index--; if (instructionPointerRanges[index].StartAddress < address) { if (instructionPointerRanges[index].EndAddress > address) { return(methods[index]); } } return(null); } } } Dictionary <MethodDesc, MethodChunks> instrumentationDataByMethod = new Dictionary <MethodDesc, MethodChunks>(); foreach (var e in p.EventsInProcess.ByEventType <JitInstrumentationDataVerboseTraceData>()) { AddToInstrumentationData(e.ClrInstanceID, e.MethodID, e.MethodFlags, e.Data); } foreach (var e in p.EventsInProcess.ByEventType <JitInstrumentationDataTraceData>()) { AddToInstrumentationData(e.ClrInstanceID, e.MethodID, e.MethodFlags, e.Data); } // Local function used with the above two loops as the behavior is supposed to be identical void AddToInstrumentationData(int eventClrInstanceId, long methodID, int methodFlags, byte[] data) { if (eventClrInstanceId != clrInstanceId.Value) { return; } MethodDesc method = null; try { method = idParser.ResolveMethodID(methodID, commandLineOptions.VerboseWarnings); } catch (Exception) { } if (method != null) { if (!instrumentationDataByMethod.TryGetValue(method, out MethodChunks perMethodChunks)) { perMethodChunks = new MethodChunks(); instrumentationDataByMethod.Add(method, perMethodChunks); } const int FinalChunkFlag = unchecked ((int)0x80000000); int chunkIndex = methodFlags & ~FinalChunkFlag; if ((chunkIndex != (perMethodChunks.LastChunk + 1)) || perMethodChunks.Done) { instrumentationDataByMethod.Remove(method); return; } perMethodChunks.LastChunk = perMethodChunks.InstrumentationData.Count; perMethodChunks.InstrumentationData.Add(data); if ((methodFlags & FinalChunkFlag) == FinalChunkFlag) { perMethodChunks.Done = true; } } } if (commandLineOptions.DisplayProcessedEvents) { foreach (var entry in methodsToAttemptToPrepare) { MethodDesc method = entry.Value.Method; string reason = entry.Value.Reason; PrintOutput($"{entry.Value.Millisecond.ToString("F4")} {reason} {method}"); } } PrintMessage($"Done processing input file"); if (commandLineOptions.OutputFileName == null) { return(0); } // Deduplicate entries HashSet <MethodDesc> methodsInListAlready = new HashSet <MethodDesc>(); List <ProcessedMethodData> methodsUsedInProcess = new List <ProcessedMethodData>(); PgoDataLoader pgoDataLoader = new PgoDataLoader(idParser); foreach (var entry in methodsToAttemptToPrepare) { if (methodsInListAlready.Add(entry.Value.Method)) { var methodData = entry.Value; if (commandLineOptions.GenerateCallGraph) { exclusiveSamples.TryGetValue(methodData.Method, out methodData.ExclusiveWeight); callGraph.TryGetValue(methodData.Method, out methodData.WeightedCallData); } if (instrumentationDataByMethod.TryGetValue(methodData.Method, out MethodChunks chunks)) { int size = 0; foreach (byte[] arr in chunks.InstrumentationData) { size += arr.Length; } byte[] instrumentationData = new byte[size]; int offset = 0; foreach (byte[] arr in chunks.InstrumentationData) { arr.CopyTo(instrumentationData, offset); offset += arr.Length; } var intDecompressor = new PgoProcessor.PgoEncodedCompressedIntParser(instrumentationData, 0); methodData.InstrumentationData = PgoProcessor.ParsePgoData <TypeSystemEntityOrUnknown>(pgoDataLoader, intDecompressor, true).ToArray(); } methodsUsedInProcess.Add(methodData); } } if (commandLineOptions.FileType.Value == PgoFileType.jittrace) { GenerateJittraceFile(commandLineOptions.OutputFileName, methodsUsedInProcess, commandLineOptions.JitTraceOptions); } else if (commandLineOptions.FileType.Value == PgoFileType.mibc) { ILCompiler.MethodProfileData[] methodProfileData = new ILCompiler.MethodProfileData[methodsUsedInProcess.Count]; for (int i = 0; i < methodProfileData.Length; i++) { ProcessedMethodData processedData = methodsUsedInProcess[i]; methodProfileData[i] = new ILCompiler.MethodProfileData(processedData.Method, ILCompiler.MethodProfilingDataFlags.ReadMethodCode, processedData.ExclusiveWeight, processedData.WeightedCallData, 0xFFFFFFFF, processedData.InstrumentationData); } return(MibcEmitter.GenerateMibcFile(tsc, commandLineOptions.OutputFileName, methodProfileData, commandLineOptions.ValidateOutputFile, commandLineOptions.Uncompressed)); } } return(0); }