/// <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 IList <SnapshotRegion> sortedRegions = this.SnapshotRegions.OrderBy(x => x.BaseAddress.ToUInt64()).ToList(); // Create and initialize the stack with the first region Stack <SnapshotRegion> combinedRegions = new Stack <SnapshotRegion>(); combinedRegions.Push(sortedRegions[0]); // Build the remaining regions for (Int32 index = combinedRegions.Count; index < sortedRegions.Count; index++) { SnapshotRegion top = combinedRegions.Peek(); if (top.EndAddress.ToUInt64() < sortedRegions[index].BaseAddress.ToUInt64()) { // If the interval does not overlap, put it on the top of the stack combinedRegions.Push(sortedRegions[index]); } else if (top.EndAddress.ToUInt64() == sortedRegions[index].BaseAddress.ToUInt64()) { // The regions are adjacent; merge them top.RegionSize = sortedRegions[index].EndAddress.Subtract(top.BaseAddress).ToInt32(); // Combine values and labels top.SetElementLabels(top.GetElementLabels()?.Concat(sortedRegions[index].GetElementLabels())); top.SetCurrentValues(top.GetCurrentValues()?.Concat(sortedRegions[index].GetCurrentValues())); top.SetPreviousValues(top.GetPreviousValues()?.Concat(sortedRegions[index].GetPreviousValues())); } else if (top.EndAddress.ToUInt64() <= sortedRegions[index].EndAddress.ToUInt64()) { // The regions overlap top.RegionSize = sortedRegions[index].EndAddress.Subtract(top.BaseAddress).ToInt32(); Int32 overlapSize = unchecked ((Int32)(sortedRegions[index].EndAddress.ToUInt64() - top.EndAddress.ToUInt64())); // Overlap has conflicting values, so we prioritize the top region and trim the current region sortedRegions[index].SetElementLabels(sortedRegions[index].GetElementLabels()?.SubArray(overlapSize, sortedRegions[index].RegionSize - overlapSize)); sortedRegions[index].SetCurrentValues(sortedRegions[index].GetCurrentValues()?.SubArray(overlapSize, sortedRegions[index].RegionSize - overlapSize)); sortedRegions[index].SetPreviousValues(sortedRegions[index].GetPreviousValues()?.SubArray(overlapSize, sortedRegions[index].RegionSize - overlapSize)); // Combine values and labels top.SetElementLabels(top.GetElementLabels()?.Concat(sortedRegions[index].GetElementLabels())); top.SetCurrentValues(top.GetCurrentValues()?.Concat(sortedRegions[index].GetCurrentValues())); top.SetPreviousValues(top.GetPreviousValues()?.Concat(sortedRegions[index].GetPreviousValues())); } } 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>(); 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 += this.Alignment; }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); // Ensure region size is worth keeping. This can happen if we grab a misaligned segment if (subRegion.RegionSize < Conversions.GetTypeSize(this.ElementType)) { continue; } // Copy the current values and labels. subRegion.SetCurrentValues(this.CurrentValues.LargestSubArray(startIndex, subRegion.RegionSize)); subRegion.SetPreviousValues(this.PreviousValues.LargestSubArray(startIndex, subRegion.RegionSize)); subRegion.SetElementLabels(this.ElementLabels.LargestSubArray(startIndex, subRegion.RegionSize)); validRegions.Add(subRegion); startIndex += validRegionSize; } this.ValidBits = null; return(validRegions); }
/// <summary> /// Masks the given memory regions against the given memory regions, keeping the common elements of the two in O(n). /// </summary> /// <param name="groundTruth">The snapshot regions to mask the target regions against.</param> public void MaskRegions(IEnumerable <NormalizedRegion> groundTruth) { List <SnapshotRegion> resultRegions = new List <SnapshotRegion>(); groundTruth = this.MergeAndSortRegions(groundTruth); // if (this.SnapshotRegions == null || groundTruth == null || this.SnapshotRegions.Count <= 0 || groundTruth.Count() <= 0) { // this.SnapshotRegions = resultRegions; // return; } this.MergeAndSortRegions(); // TODO: Resolve the masking issues below: return; // Initialize stacks with regions and masking regions Queue <SnapshotRegion> candidateRegions = new Queue <SnapshotRegion>(); Queue <NormalizedRegion> maskingRegions = new Queue <NormalizedRegion>(); // Build candidate region queue from target region array foreach (SnapshotRegion region in this.SnapshotRegions.OrderBy(x => x.BaseAddress.ToUInt64())) { candidateRegions.Enqueue(region); } // Build masking region queue from snapshot foreach (NormalizedRegion maskRegion in groundTruth.OrderBy(x => x.BaseAddress.ToUInt64())) { maskingRegions.Enqueue(maskRegion); } if (candidateRegions.Count <= 0 || maskingRegions.Count <= 0) { this.SnapshotRegions = resultRegions; return; } SnapshotRegion currentRegion; NormalizedRegion currentMask = maskingRegions.Dequeue(); while (candidateRegions.Count > 0) { // Grab next region currentRegion = candidateRegions.Dequeue(); // Grab the next mask following the current region while (currentMask.EndAddress.ToUInt64() < currentRegion.BaseAddress.ToUInt64() && maskingRegions.Count > 0) { currentMask = maskingRegions.Dequeue(); } // Check for mask completely removing this region if (currentMask.EndAddress.ToUInt64() < currentRegion.BaseAddress.ToUInt64() || currentMask.BaseAddress.ToUInt64() > currentRegion.EndAddress.ToUInt64()) { continue; } // Mask completely overlaps, just use the original region if (currentMask.BaseAddress == currentRegion.BaseAddress && currentMask.EndAddress == currentRegion.EndAddress) { resultRegions.Add(currentRegion); continue; } // Mask is within bounds; Grab the masked portion of this region Int32 baseOffset = currentMask.BaseAddress.ToUInt64() <= currentRegion.BaseAddress.ToUInt64() ? 0 : currentMask.BaseAddress.Subtract(currentRegion.BaseAddress).ToInt32(); SnapshotRegion newRegion = new SnapshotRegion(currentRegion as NormalizedRegion); newRegion.BaseAddress = currentRegion.BaseAddress + baseOffset; newRegion.BaseAddress = Math.Min(currentMask.EndAddress.ToUInt64(), currentRegion.EndAddress.ToUInt64()).ToIntPtr(); newRegion.SetCurrentValues(currentRegion.GetCurrentValues().LargestSubArray(baseOffset, newRegion.RegionSize)); newRegion.SetPreviousValues(currentRegion.GetPreviousValues().LargestSubArray(baseOffset, newRegion.RegionSize)); newRegion.SetElementLabels(currentRegion.GetElementLabels().LargestSubArray(baseOffset, newRegion.RegionSize)); newRegion.ElementType = currentRegion.ElementType; newRegion.Alignment = currentRegion.Alignment; resultRegions.Add(newRegion); } this.SnapshotRegions = resultRegions; }