/// <summary> /// Merges regions in the current list of memory regions using a fast stack based algorithm O(nlogn + n). /// </summary> private void MergeAndSortRegions() { if (this.SnapshotRegions.IsNullOrEmpty()) { return; } // First, sort by start address IEnumerable <SnapshotRegion> sortedRegions = this.SnapshotRegions.OrderBy(x => x.BaseAddress.ToUInt64()); // Create and initialize the stack with the first region Stack <SnapshotRegion> combinedRegions = new Stack <SnapshotRegion>(); combinedRegions.Push(sortedRegions.First()); // Build the remaining regions foreach (SnapshotRegion region in sortedRegions.Skip(1)) { SnapshotRegion top = combinedRegions.Peek(); // If the regions do not overlap, the new region is the top region if (top.EndAddress.ToUInt64() < region.BaseAddress.ToUInt64()) { combinedRegions.Push(region); } // The regions are exactly adjacent; merge them else if (top.EndAddress.ToUInt64() == region.BaseAddress.ToUInt64()) { top.RegionSize = region.EndAddress.Subtract(top.BaseAddress).ToUInt64(); // Combine values and labels top.SetElementLabels(top.ElementLabels?.Concat(region.ElementLabels)); top.SetCurrentValues(top.CurrentValues?.Concat(region.CurrentValues)); top.SetPreviousValues(top.PreviousValues?.Concat(region.PreviousValues)); } // The regions overlap else if (top.EndAddress.ToUInt64() <= region.EndAddress.ToUInt64()) { top.RegionSize = region.EndAddress.Subtract(top.BaseAddress).ToUInt64(); Int32 overlapSize = unchecked ((Int32)(region.EndAddress.ToUInt64() - top.EndAddress.ToUInt64())); // Overlap has conflicting values, so we prioritize the top region and trim the current region region.SetElementLabels(region.ElementLabels?.SubArray(overlapSize, region.RegionSize.ToInt32() - overlapSize)); region.SetCurrentValues(region.CurrentValues?.SubArray(overlapSize, region.RegionSize.ToInt32() - overlapSize)); region.SetPreviousValues(region.PreviousValues?.SubArray(overlapSize, region.RegionSize.ToInt32() - overlapSize)); // Combine values and labels top.SetElementLabels(top.ElementLabels?.Concat(region.ElementLabels)); top.SetCurrentValues(top.CurrentValues?.Concat(region.CurrentValues)); top.SetPreviousValues(top.PreviousValues?.Concat(region.PreviousValues)); } } this.SnapshotRegions = combinedRegions.ToList().OrderBy(x => x.BaseAddress.ToUInt64()).ToList(); }
/// <summary> /// Gets the regions in this snapshot with a valid bit set. /// </summary> /// <returns>The regions in this snapshot with a valid bit set.</returns> public IEnumerable <SnapshotRegion> GetValidRegions() { List <SnapshotRegion> validRegions = new List <SnapshotRegion>(); Int32 elementSize = this.GetElementSize(); if (this.ValidBits == null) { return(validRegions); } for (Int32 startIndex = 0; startIndex < this.ValidBits.Length; startIndex += this.Alignment) { if (!this.ValidBits[startIndex]) { continue; } // Get the length of this valid segment Int32 validRegionSize = 0; do { // We only care if the aligned elements are valid validRegionSize += elementSize; }while (startIndex + validRegionSize < this.ValidBits.Length && this.ValidBits[startIndex + validRegionSize]); // Create new subregion from this valid region SnapshotRegion subRegion = new SnapshotRegion(this.BaseAddress + startIndex, validRegionSize.ToUInt64()); // Ensure region size is worth keeping. This can happen if we grab a misaligned segment if (subRegion.RegionSize < Conversions.GetTypeSize(this.ElementType).ToUInt64()) { continue; } // Copy the current values and labels. subRegion.SetCurrentValues(this.CurrentValues.LargestSubArray(startIndex, subRegion.RegionSize.ToInt64())); subRegion.SetPreviousValues(this.PreviousValues.LargestSubArray(startIndex, subRegion.RegionSize.ToInt64())); subRegion.SetElementLabels(this.ElementLabels.LargestSubArray(startIndex, subRegion.RegionSize.ToInt64())); validRegions.Add(subRegion); startIndex += validRegionSize; } this.ValidBits = null; return(validRegions); }
/// <summary> /// Combines the given memory regions with the given memory regions, only keeping the common elements of the two in O(nlogn + n). /// </summary> /// <param name="otherSnapshot">The snapshot regions to mask the target regions against.</param> private void Intersect(Snapshot otherSnapshot) { List <SnapshotRegion> resultRegions = new List <SnapshotRegion>(); otherSnapshot.MergeAndSortRegions(); IEnumerable <NormalizedRegion> otherRegions = otherSnapshot.GetSnapshotRegions(); if (this.SnapshotRegions.IsNullOrEmpty() || otherRegions.IsNullOrEmpty()) { this.SnapshotRegions = resultRegions; return; } this.MergeAndSortRegions(); // Initialize stacks with regions and masking regions Queue <SnapshotRegion> snapshotRegionQueue = new Queue <SnapshotRegion>(); Queue <NormalizedRegion> groundTruthQueue = new Queue <NormalizedRegion>(); // Build candidate region queue from snapshot region array foreach (SnapshotRegion region in this.SnapshotRegions.OrderBy(x => x.BaseAddress.ToUInt64())) { snapshotRegionQueue.Enqueue(region); } // Build masking region queue from snapshot foreach (NormalizedRegion maskRegion in otherRegions.OrderBy(x => x.BaseAddress.ToUInt64())) { groundTruthQueue.Enqueue(maskRegion); } if (snapshotRegionQueue.Count <= 0 || groundTruthQueue.Count <= 0) { this.SnapshotRegions = resultRegions; return; } SnapshotRegion nextSnapshotRegion; NormalizedRegion groundTruthMask = groundTruthQueue.Dequeue(); while (snapshotRegionQueue.Count > 0) { // Grab next region nextSnapshotRegion = snapshotRegionQueue.Dequeue(); // Grab the next mask following the current region while (groundTruthMask.EndAddress.ToUInt64() < nextSnapshotRegion.BaseAddress.ToUInt64() && groundTruthQueue.Count > 0) { groundTruthMask = groundTruthQueue.Dequeue(); } // Check for mask completely removing this region if (groundTruthMask.EndAddress.ToUInt64() < nextSnapshotRegion.BaseAddress.ToUInt64() || groundTruthMask.BaseAddress.ToUInt64() > nextSnapshotRegion.EndAddress.ToUInt64()) { continue; } // Check for mask completely engulfing this region else if (groundTruthMask.BaseAddress.ToUInt64() <= nextSnapshotRegion.BaseAddress.ToUInt64() && groundTruthMask.EndAddress.ToUInt64() >= nextSnapshotRegion.EndAddress.ToUInt64()) { resultRegions.Add(nextSnapshotRegion); continue; } // There are no edge cases, we must mask and copy the valid portion of this region else { UInt64 baseAddress = Math.Max(groundTruthMask.BaseAddress.ToUInt64(), nextSnapshotRegion.BaseAddress.ToUInt64()); UInt64 endAddress = Math.Min(groundTruthMask.EndAddress.ToUInt64(), nextSnapshotRegion.EndAddress.ToUInt64()); Int64 baseOffset = unchecked ((Int64)(baseAddress - nextSnapshotRegion.BaseAddress.ToUInt64())); SnapshotRegion newRegion = new SnapshotRegion(nextSnapshotRegion as NormalizedRegion); newRegion.BaseAddress = baseAddress.ToIntPtr(); newRegion.EndAddress = endAddress.ToIntPtr(); newRegion.SetCurrentValues(nextSnapshotRegion.CurrentValues.LargestSubArray(baseOffset, newRegion.RegionSize.ToInt64())); newRegion.SetPreviousValues(nextSnapshotRegion.PreviousValues.LargestSubArray(baseOffset, newRegion.RegionSize.ToInt64())); newRegion.SetElementLabels(nextSnapshotRegion.ElementLabels.LargestSubArray(baseOffset, newRegion.RegionSize.ToInt64())); newRegion.ElementType = nextSnapshotRegion.ElementType; newRegion.Alignment = nextSnapshotRegion.Alignment; resultRegions.Add(newRegion); } } this.SnapshotRegions = resultRegions; }