public Allocation(AllocationData data) { MessageDescriptor d = AllocationData.Descriptor; foreach (FieldDescriptor f in d.Fields) { fields.Add(f.Name, data[f]); } this.id = this[ALLOCATION_ID]; }
/// <summary> /// Returns the allocation block with the given addresses. /// </summary> /// <param name="address1">The trace 1 address to be searched for.</param> /// <param name="address2">The trace 2 address to be searched for.</param> private AllocationData FindAllocationBlock(ulong address1, ulong address2) { // Find by start address // The blocks are sorted by start address, so the first hit should be the right one - else the correct block does not exist // TODO In all tests this list stayed quite small, implement it in O(log n) anyway? // AllocationData candidate = _allocs.Last(a => a.Key <= address1).Value; AllocationData candidate = null; for (int i = _allocs.Count - 1; i >= 0; --i) { if (_allocs.Keys[i] <= address1) { candidate = _allocs.Values[i]; if (address1 <= candidate.EndAddress1 && candidate.StartAddress2 <= address2 && address2 <= candidate.EndAddress2) { return(candidate); } break; } } return(null); }
/// <summary> /// Encodes all entries of the given trace file as 64-bit integers. This implies a loss of information. /// The least significant 4 bits of each entry will contain the entry type (directly casted from <see cref="TraceEntryTypes"/>). /// </summary> /// <param name="traceFile">The trace file to be encoded.</param> /// <returns>A list of encoded trace entries.</returns> public static IEnumerable <long> EncodeTraceEntries(TraceFile traceFile) { // Initialize stack memory allocation block AllocationData stackMemory = new AllocationData { AllocationLineNumber = 0, FreeLineNumber = traceFile.EntryCount, // Never freed StartAddress = traceFile.StackPointerMin, EndAddress = traceFile.StackPointerMax }; // Run through entries int line = 0; SortedList <int, AllocationData> allocs = new SortedList <int, AllocationData>(); foreach (TraceEntry entry in traceFile.Entries) { // Encode type right away ulong enc = (ulong)entry.EntryType; switch (entry.EntryType) { case TraceEntryTypes.Allocation: { // Save allocation data AllocationEntry allocationEntry = (AllocationEntry)entry; allocs[line] = new AllocationData() { AllocationLineNumber = line, FreeLineNumber = traceFile.EntryCount, // First assume as never freed, is overwritten as soon as a matching free is encountered StartAddress = allocationEntry.Address, EndAddress = allocationEntry.Address + allocationEntry.Size }; // Encode allocation size enc |= (ulong)allocationEntry.Size << 4; break; } case TraceEntryTypes.Free: { // Find corresponding allocation block to mark as freed FreeEntry freeEntry = (FreeEntry)entry; var allocCandidates = allocs.Where(a => a.Key <= line && a.Value.FreeLineNumber >= line && a.Value.StartAddress == freeEntry.Address); if (!allocCandidates.Any()) { // TODO Error handling (same problem as in TraceFileComparer) //Debug.WriteLine($"Warning! Processing line {line}: Skipped free() without any matching allocation block."); } else { // Mark block as freed AllocationData allocData = allocCandidates.First().Value; allocData.FreeLineNumber = line; } // Not encoded break; } case TraceEntryTypes.ImageMemoryRead: { // Encode instruction and address offset ImageMemoryReadEntry imageMemoryReadEntry = (ImageMemoryReadEntry)entry; enc |= imageMemoryReadEntry.InstructionAddress << 4; enc |= (ulong)imageMemoryReadEntry.MemoryAddress << 32; break; } case TraceEntryTypes.ImageMemoryWrite: { // Encode instruction and address offset ImageMemoryWriteEntry imageMemoryWriteEntry = (ImageMemoryWriteEntry)entry; enc |= imageMemoryWriteEntry.InstructionAddress << 4; enc |= (ulong)imageMemoryWriteEntry.MemoryAddress << 32; break; } case TraceEntryTypes.AllocMemoryRead: { // Find related allocation block // Stack or heap? AllocMemoryReadEntry allocMemoryReadEntry = (AllocMemoryReadEntry)entry; AllocationData allocData = stackMemory; if (allocMemoryReadEntry.MemoryAddress < stackMemory.StartAddress || stackMemory.EndAddress < allocMemoryReadEntry.MemoryAddress) { // Heap? var allocCandidates = allocs.Where(a => a.Key <= line && a.Value.FreeLineNumber >= line && a.Value.StartAddress <= allocMemoryReadEntry.MemoryAddress && allocMemoryReadEntry.MemoryAddress <= a.Value.EndAddress); if (!allocCandidates.Any()) { // TODO error handling - caused by missed malloc() //Program.Log($"Error: Could not find allocation block for [{line}] {allocMemoryReadEntry.ToString()}\n", Program.LogLevel.Error); Debug.WriteLine($"Error: Could not find allocation block for [{line}] {allocMemoryReadEntry.ToString()}"); break; } else { allocData = allocCandidates.Last().Value; } } // Encode instruction address, the size of the allocation block, and the offset enc |= allocMemoryReadEntry.InstructionAddress << 4; enc |= (allocMemoryReadEntry.MemoryAddress - allocData.StartAddress) << 32; //enc |= (allocData.EndAddress - allocData.StartAddress) << 48; // Only catches sizes less than 64 KB (16 bit address space) break; } case TraceEntryTypes.AllocMemoryWrite: { // Find related allocation block // Stack or heap? AllocMemoryWriteEntry allocMemoryWriteEntry = (AllocMemoryWriteEntry)entry; AllocationData allocData = stackMemory; if (allocMemoryWriteEntry.MemoryAddress < stackMemory.StartAddress || stackMemory.EndAddress < allocMemoryWriteEntry.MemoryAddress) { // Heap? var allocCandidates = allocs.Where(a => a.Key <= line && a.Value.FreeLineNumber >= line && a.Value.StartAddress <= allocMemoryWriteEntry.MemoryAddress && allocMemoryWriteEntry.MemoryAddress <= a.Value.EndAddress); if (!allocCandidates.Any()) { // TODO error handling - caused by missed malloc() //Program.Log($"Error: Could not find allocation block for [{line}] {allocMemoryWriteEntry.ToString()}\n", Program.LogLevel.Error); Debug.WriteLine($"Error: Could not find allocation block for [{line}] {allocMemoryWriteEntry.ToString()}"); break; } else { allocData = allocCandidates.Last().Value; } } // Encode instruction address, the size of the allocation block, and the offset enc |= allocMemoryWriteEntry.InstructionAddress << 4; enc |= (allocMemoryWriteEntry.MemoryAddress - allocData.StartAddress) << 32; //enc |= (allocData.EndAddress - allocData.StartAddress) << 48; // Only catches sizes less than 64 KB (16 bit address space) break; } case TraceEntryTypes.Branch: { // Encode branch source and destination image offsets, and the "taken" flag BranchEntry branchEntry = (BranchEntry)entry; enc |= branchEntry.SourceInstructionAddress << 4; enc |= (ulong)branchEntry.DestinationInstructionAddress << 32; enc |= (ulong)(branchEntry.Taken ? 1 : 0) << 63; break; } } yield return(unchecked ((long)enc)); ++line; } }
private async Task SearchDataAsync() { try { if (string.IsNullOrWhiteSpace(SubNo)) { return; } if (string.IsNullOrWhiteSpace(SelectedMasterAwb)) { await Application.Current.MainPage.DisplayAlert("提示", "选择主单号", "确定"); return; } var rst = App.Allocations.Where(p => p.MasterAwb == SelectedMasterAwb && p.SubAwb == SubNo.TrimEnd()); var enumerable = rst as AllocationData[] ?? rst.ToArray(); if (enumerable.Any()) { var firstItem = enumerable.First(); // 如果已经盘点过就不要再进行盘点 if (firstItem.IsChecked != StateKind.Checked) { //清理 Allots.Clear(); firstItem.IsChecked = StateKind.Checked; App.Allocations.First(p => p.MasterAwb == SelectedMasterAwb && p.SubAwb == SubNo).IsChecked = StateKind.Checked; //更新缓存中的数据,因为需要同步到服务器上 //App.CheckedAllocations.First(p => p.MasterAwb == SelectedMasterAwb && p.SubAwb == SubNo).IsChecked = // StateKind.Checked; if (App.CheckedAllocations.Contains(firstItem)) { foreach (var data in App.CheckedAllocations) { if (data.MasterAwb == SelectedMasterAwb && data.SubAwb == SubNo) { data.IsChecked = StateKind.Checked; } } } else { App.CheckedAllocations.Push(firstItem); } //这个是持久化保存,就是防止手持设备突然退出时候,数据能够备份 _realm.Write(() => { var first = _realm.All <AllocationData2>().FirstOrDefault(p => p.MasterAwb == SelectedMasterAwb && p.SubAwb == SubNo); if (first != null) { first.IsChecked = 2; } else { _realm.Add(new AllocationData2 { Amount = firstItem.Amount, IsChecked = (int)firstItem.IsChecked, MasterAwb = firstItem.MasterAwb, SubAwb = firstItem.SubAwb, }); } }); //判断是否需要查验 if (!string.IsNullOrWhiteSpace(firstItem.Status) && firstItem.Status.Contains("查验")) { chayanPlayer.Play(); } else { okPlayer.Play(); } Allots.Add(firstItem); ScanedCount = ScanedCount + 1; Count = Allots.Count; } } else { //新增 yizhuangPlayer.Play(); //http://101.201.28.235:91/version/nodata.wav //await CrossMediaManager.Current.Play("http://101.201.28.235:91/version/nodata.wav"); if (await Application.Current.MainPage.DisplayAlert("提示", "是否标记为溢装到货", "确定", "取消")) { Allots.Clear(); var newItem = new AllocationData { IsChecked = StateKind.OverChecked, MasterAwb = SelectedMasterAwb, SubAwb = SubNo, Amount = 1 }; Allots.Add(newItem); Count = allots.Count; App.Allocations.Add(newItem); App.CheckedAllocations.Push(newItem); ScanedCount = ScanedCount + 1; //添加到本地数据库 _realm.Write(() => { _realm.Add(new AllocationData2 { Amount = 1, IsChecked = 3, MasterAwb = SelectedMasterAwb, SubAwb = SubNo, }); }); } } //TODO: 需要找到扫码完成之后选中文本 SubNo = string.Empty; OnPropertyChanged(nameof(Summary)); } catch (Exception ex) { await Application.Current.MainPage.DisplayAlert("提示", $"盘点出错:{ex.Message}", "确定"); } }
/// <summary> /// Executes the comparison and returns whether the two traces have identical memory access patterns. /// </summary> /// <returns></returns> public bool Compare() { // Run linearily through trace entries and compare them // If the traces have different length, use the shorter one as reference // This should not lead to wrong results: The shorter trace won't just randomly end, instead there has to be some kind of branch mismatch before // Keep track of currently allocated datablocks AllocationData stackMemory = new AllocationData() // StartAddress = Top of stack, EndAddress = Bottom of stack { StartAddress1 = TraceFile1.StackPointerMin, StartAddress2 = TraceFile2.StackPointerMin, EndAddress1 = TraceFile1.StackPointerMax, EndAddress2 = TraceFile2.StackPointerMax }; int totalEntries = Math.Min(TraceFile1.EntryCount, TraceFile2.EntryCount); var traceFile1Enumerator = TraceFile1.Entries.GetEnumerator(); var traceFile2Enumerator = TraceFile2.Entries.GetEnumerator(); for (int i = 0; i < totalEntries; ++i) { // Retrieve entries traceFile1Enumerator.MoveNext(); traceFile2Enumerator.MoveNext(); TraceEntry e1 = traceFile1Enumerator.Current; TraceEntry e2 = traceFile2Enumerator.Current; // The entries should have the same type // If not, something must have gone very wrong: Differing branches are detected, so we should not run into differing instructions if (e1.EntryType != e2.EntryType) { Result = ComparisonResults.ExecutionFlow_DifferentType; ComparisonErrorLine = i; ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2); if (PrintResults) { PrintComparisonResult($"Entries #{i} have different type (probably some bigger error occured?).", false, $"Trace 1: {e1.ToString()}", $"Trace 2: {e2.ToString()}"); } return(false); } // Act depending on entry types switch (e1.EntryType) { // Possible leakages: // - Different branch targets // - In one execution the branch is taken, in the other one not case TraceEntryTypes.Branch: { // Cast entries BranchEntry branch1 = (BranchEntry)e1; BranchEntry branch2 = (BranchEntry)e2; // Compare targets if (branch1.DestinationImageId != branch2.DestinationImageId || branch1.DestinationInstructionAddress != branch2.DestinationInstructionAddress) { Result = ComparisonResults.ExecutionFlow_DifferentBranchTarget; ComparisonErrorLine = i; ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2); if (PrintResults) { PrintComparisonResult($"Entries #{i}: Different branch target: <{branch1.DestinationImageName}+{branch1.DestinationInstructionAddress.ToString("X8")}> vs. <{branch2.DestinationImageName}+{branch2.DestinationInstructionAddress.ToString("X8")}>", false, $"Trace 1: {e1.ToString()}", $"Trace 2: {e2.ToString()}"); } return(false); } // Compare "taken" if (branch1.Taken != branch2.Taken) { if (branch1.Taken) { Result = ComparisonResults.ExecutionFlow_BranchTakenIn1; ComparisonErrorLine = i; ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2); if (PrintResults) { PrintComparisonResult($"Entries #{i}: Branch to <{branch1.DestinationImageName}+{branch1.DestinationInstructionAddress.ToString("X8")}> taken in trace 1, but not in trace 2.", false, $"Trace 1: {e1.ToString()}", $"Trace 2: {e2.ToString()}"); } } else { Result = ComparisonResults.ExecutionFlow_BranchTakenIn2; ComparisonErrorLine = i; ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2); if (PrintResults) { PrintComparisonResult($"Entries #{i}: Branch to <{branch1.DestinationImageName}+{branch1.DestinationInstructionAddress.ToString("X8")}> not taken in trace 1, but in trace 2.", false, $"Trace 1: {e1.ToString()}", $"Trace 2: {e2.ToString()}"); } } return(false); } // OK break; } // Store allocation metadata // Possible leakages: // - The allocation size might differ case TraceEntryTypes.Allocation: { // Cast entries AllocationEntry alloc1 = (AllocationEntry)e1; AllocationEntry alloc2 = (AllocationEntry)e2; // Compare sizes if (alloc1.Size != alloc2.Size) { Result = ComparisonResults.MemoryAccess_DifferentAllocationSize; ComparisonErrorLine = i; ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2); if (PrintResults) { PrintComparisonResult($"Entries #{i}: Allocation size differs: {alloc1.Size} vs. {alloc2.Size}", false, $"Trace 1: {e1.ToString()}", $"Trace 2: {e2.ToString()}"); } return(false); } // Save allocation data _allocs[alloc1.Address] = new AllocationData() { StartAddress1 = alloc1.Address, EndAddress1 = alloc1.Address + alloc1.Size, StartAddress2 = alloc2.Address, EndAddress2 = alloc2.Address + alloc2.Size }; // OK break; } // Remove allocation metadata from list case TraceEntryTypes.Free: { // Cast entries FreeEntry free1 = (FreeEntry)e1; FreeEntry free2 = (FreeEntry)e2; // Make sure the frees apply to the same datablock if (!_allocs.TryGetValue(free1.Address, out AllocationData freeCandidate)) { /*Result = ComparisonResults.MemoryAccess_FreedBlockNotFound; * ComparisonErrorLine = i; * PrintComparisonResult($"Entries #{i}: Cannot find freed allocation block for execution trace 1.", false, * $"Trace 1: {e1.ToString()}", * $"Trace 2: {e2.ToString()}"); * // TODO This line is triggered in the Alloc/Free prefix, when one malloc() call was missed * return false;*/ } else if (freeCandidate.StartAddress2 != free2.Address) { Result = ComparisonResults.MemoryAccess_FreedBlockNotMatching; ComparisonErrorLine = i; ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2); if (PrintResults) { PrintComparisonResult($"Entries #{i}: Freed allocation block of execution trace 1 does not match freed block of execution trace 2.", false, $"Trace 1: {e1.ToString()}", $"Trace 2: {e2.ToString()}"); } return(false); } else { // OK, remove allocation block _allocs.Remove(free1.Address); } break; } // Possible leakages: // -> Different access offset in image case TraceEntryTypes.ImageMemoryRead: { // Cast entries ImageMemoryReadEntry read1 = (ImageMemoryReadEntry)e1; ImageMemoryReadEntry read2 = (ImageMemoryReadEntry)e2; // Compare relative access offsets if (read1.MemoryAddress != read2.MemoryAddress) { Result = ComparisonResults.MemoryAccess_DifferentImageMemoryReadOffset; ComparisonErrorLine = i; ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2); if (PrintResults) { PrintComparisonResult($"Entries #{i}: Memory read offsets in image differ: {read1.MemoryImageName}+{read1.MemoryAddress.ToString("X")} vs. {read2.MemoryImageName}+{read2.MemoryAddress.ToString("X")}", false, $"Trace 1: {e1.ToString()}", $"Trace 2: {e2.ToString()}"); } return(false); } // OK break; } // Possible leakages: // -> Different access offset in image case TraceEntryTypes.ImageMemoryWrite: { // Cast entries ImageMemoryWriteEntry write1 = (ImageMemoryWriteEntry)e1; ImageMemoryWriteEntry write2 = (ImageMemoryWriteEntry)e2; // Compare relative access offsets if (write1.MemoryAddress != write2.MemoryAddress) { Result = ComparisonResults.MemoryAccess_DifferentImageMemoryWriteOffset; ComparisonErrorLine = i; ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2); if (PrintResults) { PrintComparisonResult($"Entries #{i}: Memory write offsets in image differ: {write1.MemoryImageName}+{write1.MemoryAddress.ToString("X")} vs. {write2.MemoryImageName}+{write2.MemoryAddress.ToString("X")}", false, $"Trace 1: {e1.ToString()}", $"Trace 2: {e2.ToString()}"); } return(false); } // OK break; } // Possible leakages: // -> Different access offset (after subtracting allocation base addresses) case TraceEntryTypes.AllocMemoryRead: { // Cast entries AllocMemoryReadEntry read1 = (AllocMemoryReadEntry)e1; AllocMemoryReadEntry read2 = (AllocMemoryReadEntry)e2; // Find related allocation block AllocationData allocCandidate = FindAllocationBlock(read1.MemoryAddress, read2.MemoryAddress); if (allocCandidate == null) { // Stack access? if (stackMemory.StartAddress1 <= read1.MemoryAddress && read1.MemoryAddress <= stackMemory.EndAddress1 && stackMemory.StartAddress2 <= read2.MemoryAddress && read2.MemoryAddress <= stackMemory.EndAddress2) { allocCandidate = stackMemory; } else { // TODO remove warning, better include the fs/gs segment bounds in the trace if (PrintResults) { PrintComparisonResult($"Entries #{i}: Cannot find common accessed allocation block. Maybe there are segment registers involved?", true, $"Trace 1: {read1.ToString()}", $"Trace 2: {read2.ToString()}", $"Stack: {stackMemory.ToString()}"); } break; } } // Calculate and compare relative access offsets ulong offset1 = read1.MemoryAddress - allocCandidate.StartAddress1; ulong offset2 = read2.MemoryAddress - allocCandidate.StartAddress2; if (offset1 != offset2) { Result = ComparisonResults.MemoryAccess_DifferentAllocMemoryReadOffset; ComparisonErrorLine = i; ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2); if (PrintResults) { PrintComparisonResult($"Entries #{i}: Memory read offsets in common allocation block differ: +{offset1.ToString("X8")} vs. +{offset2.ToString("X8")}", false, $"Trace 1: {e1.ToString()}", $"Trace 2: {e2.ToString()}"); } return(false); } // OK break; } // Possible leakages: // -> Different access offset (after subtracting allocation/stack pointer base addresses) case TraceEntryTypes.AllocMemoryWrite: { // Cast entries AllocMemoryWriteEntry write1 = (AllocMemoryWriteEntry)e1; AllocMemoryWriteEntry write2 = (AllocMemoryWriteEntry)e2; // Find related allocation block AllocationData allocCandidate = FindAllocationBlock(write1.MemoryAddress, write2.MemoryAddress); if (allocCandidate == null) { // Stack access? if (stackMemory.StartAddress1 <= write1.MemoryAddress && write1.MemoryAddress <= stackMemory.EndAddress1 && stackMemory.StartAddress2 <= write2.MemoryAddress && write2.MemoryAddress <= stackMemory.EndAddress2) { allocCandidate = stackMemory; } else { // TODO remove warning, better include the fs/gs segment bounds in the trace if (PrintResults) { PrintComparisonResult($"Entries #{i}: Cannot find common accessed allocation block. Maybe there are segment registers involved?", true, $"Trace 1: {write1.ToString()}", $"Trace 2: {write2.ToString()}", $"Stack: {stackMemory.ToString()}"); } break; } } // Calculate and compare relative access offsets ulong offset1 = write1.MemoryAddress - allocCandidate.StartAddress1; ulong offset2 = write2.MemoryAddress - allocCandidate.StartAddress2; if (offset1 != offset2) { Result = ComparisonResults.MemoryAccess_DifferentAllocMemoryWriteOffset; ComparisonErrorLine = i; ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2); if (PrintResults) { PrintComparisonResult($"Entries #{i}: Memory write offsets in common allocation block differ: +{offset1.ToString("X8")} vs. +{offset2.ToString("X8")}", false, $"Trace 1: {e1.ToString()}", $"Trace 2: {e2.ToString()}"); } return(false); } // OK break; } } } // No differences found Result = ComparisonResults.Match; return(true); }