using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Windows.Forms; using System.Configuration; using System.Collections.Specialized; using static System.Int32; using static System.Windows.Forms.AxHost; using static System.Windows.Forms.VisualStyles.VisualStyleElement.ProgressBar; namespace CruncherSharp { public partial class CruncherSharpForm : Form { public enum SearchType { None, UnusedVTables, MSVCExtraPadding, MSVCEmptyBaseClass, UnusedInterfaces, UnusedVirtual, MaskingFunction, RemovedInline, } private readonly List _FunctionsToIgnore; private readonly Stack _NavigationStack; private readonly Stack _RedoNavigationStack; private SymbolAnalyzer _SymbolAnalyzerDia; #if RAWPDB private SymbolAnalyzer _SymbolAnalyzerRawPDB; #endif private readonly DataTable _Table; public bool _CloseRequested = false; public bool _HasInstancesCount = false; public bool _HasSecondPDB = false; public bool _HasMemPools = false; public bool _IgnoreSelectionChange = false; public bool _RestrictToSymbolsImportedFromCSV = false; private ulong _PrefetchStartOffset = 0; private SearchType _SearchCategory = SearchType.None; private SymbolInfo _SelectedSymbol; private Timer _TypingTimer; private SymbolAnalyzer CurrentSymbolAnalyzer { get { #if RAWPDB return useRawPDBToolStripMenuItem.Checked ? _SymbolAnalyzerRawPDB : _SymbolAnalyzerDia; #else return _SymbolAnalyzerDia; #endif } } public CruncherSharpForm() { InitializeComponent(); _SymbolAnalyzerDia = new SymbolAnalyzerDIA(); #if RAWPDB _SymbolAnalyzerRawPDB = new SymbolAnalyzerRawPDB(); #endif _Table = CreateDataTable(); _Table.CaseSensitive = checkBoxMatchCase.Checked; _NavigationStack = new Stack(); _RedoNavigationStack = new Stack(); _FunctionsToIgnore = new List(); _SelectedSymbol = null; bindingSourceSymbols.DataSource = _Table; dataGridSymbols.DataSource = bindingSourceSymbols; dataGridSymbols.Columns[0].Width = 275; for (int i = 1; i < dataGridSymbols.Columns.Count; i++) { dataGridSymbols.Columns[i].Width = 75; } UpdateColumnVisibility(); WindowState = FormWindowState.Maximized; string SymbolAnalyzer = ConfigurationManager.AppSettings.Get("SymbolAnalyzer"); useRawPDBToolStripMenuItem.Checked = SymbolAnalyzer == "RawPDB"; if (ShowMemPool("MB2")) { mB2ToolStripMenuItem.Checked = true; } NameValueCollection alignmentSection = (NameValueCollection)ConfigurationManager.GetSection("Alignment"); if (alignmentSection != null) { foreach (string Key in alignmentSection.AllKeys) { uint align = uint.Parse(alignmentSection.Get(Key)); CurrentSymbolAnalyzer.ConfigAlignment.Add(Key, align); } } NameValueCollection enumSection = (NameValueCollection)ConfigurationManager.GetSection("Enums"); if (enumSection != null) { foreach (string Key in enumSection.AllKeys) { uint align = uint.Parse(enumSection.Get(Key)); CurrentSymbolAnalyzer.ConfigEnum.Add(Key, align); } } } protected override void OnCreateControl() => OpenPDB(); public SearchType SearchCategory { get => _SearchCategory; private set { _SearchCategory = value; UpdateCheckedOption(); } } private void Reset() { checkedListBoxNamespaces.Items.Clear(); _Table.Clear(); dataGridViewSymbolInfo.Rows.Clear(); dataGridViewFunctionsInfo.Rows.Clear(); _SelectedSymbol = null; _RestrictToSymbolsImportedFromCSV = false; labelCurrentSymbol.Text = ""; _SymbolAnalyzerDia.Reset(); #if RAWPDB _SymbolAnalyzerRawPDB.Reset(); #endif UpdateBtnLoadText(); } private void UpdateBtnLoadText() { if (textBoxFilter.Text.Length > 0) btnLoad.Text = "Load filtered symbols"; else btnLoad.Text = "Load all symbols"; } private void exitToolStripMenuItem_Click(object sender, EventArgs e) { Close(); } private void loadPDBToolStripMenuItem_Click(object sender, EventArgs e) { if (loadPDBBackgroundWorker.IsBusy || loadCSVBackgroundWorker.IsBusy) return; OpenPDB(); } private void OpenPDB() { if (openPdbDialog.ShowDialog() != DialogResult.OK) return; Reset(); _SymbolAnalyzerDia.FileName = openPdbDialog.FileName; #if RAWPDB _SymbolAnalyzerRawPDB.FileName = openPdbDialog.FileName; _SymbolAnalyzerRawPDB.OpenAsync(openPdbDialog.FileName); #endif Text = "Cruncher# - " + openPdbDialog.FileName; btnLoad.Enabled = true; btnReset.Enabled = true; loadInstanceCountToolStripMenuItem.Enabled = true; textBoxFilter.Focus(); } public void LoadPdb(string fileName, bool secondPDB) { _SelectedSymbol = null; toolStripProgressBar.Value = 0; toolStripStatusLabel.Text = "Loading PDB..."; if (!secondPDB) { Text = "Cruncher# - " + fileName; if (textBoxFilter.Text.Length > 0) Text += " Filter: " + textBoxFilter.Text; } var task = new LoadPDBTask { FileName = fileName, SecondPDB = secondPDB, Filter = textBoxFilter.Text, MatchCase = checkBoxMatchCase.Checked, WholeExpression = checkBoxMatchWholeExpression.Checked, UseRegularExpression = checkBoxRegularExpressions.Checked, UseProgressBar = String.IsNullOrEmpty(textBoxFilter.Text) || !checkBoxMatchWholeExpression.Checked }; loadPDBBackgroundWorker.RunWorkerAsync(task); } private static string SymbolRowName = "Symbol"; private static string SizeRowName = "Size"; private static string MinAlignmentRowName = "Min alignment"; private static string PaddingRowName = "Padding"; private static string PaddingZonesRowName = "Padding zones"; private static string TotalPaddingRowName = "Total padding"; private static string PotentialSavingRowName = "Potential saving"; private static string TotalDeltaRowName = "Total delta"; private static string InstancesRowName = "Instances"; private static string TotalCountRowName = "Total count"; private static string TotalSizeRowName = "Total size"; private static string TotalWasteRowName = "Total waste"; private static string MempoolUsageRowName = "Mempool usage"; private static string MempoolTotalUsageRowName = "Mempool total usage"; private static string MempoolRowName = "Current mempool"; private static string MempoolDeltaRowName = "Delta to lower mempool"; private static string PotentialWinRowName = "Potential total saving"; private static string NewSizeRowName = "New size"; private static string DeltaRowName = "Delta"; private DataTable CreateDataTable() { var table = new DataTable("Symbols"); table.Columns.Add(new DataColumn {ColumnName = SymbolRowName, ReadOnly = true}); table.Columns.Add(new DataColumn { ColumnName = SizeRowName, ReadOnly = true, DataType = Type.GetType("System.UInt32") }); table.Columns.Add(new DataColumn { ColumnName = MinAlignmentRowName, ReadOnly = true, DataType = Type.GetType("System.UInt32") }); table.Columns.Add(new DataColumn { ColumnName = PaddingRowName, ReadOnly = true, DataType = Type.GetType("System.UInt32") }); table.Columns.Add(new DataColumn { ColumnName = PaddingZonesRowName, ReadOnly = true, DataType = Type.GetType("System.UInt32") }); table.Columns.Add(new DataColumn { ColumnName = TotalPaddingRowName, ReadOnly = true, DataType = Type.GetType("System.UInt32") }); table.Columns.Add(new DataColumn { ColumnName = PotentialSavingRowName, ReadOnly = true, DataType = Type.GetType("System.UInt32") }); table.Columns.Add(new DataColumn { ColumnName = MempoolRowName, ReadOnly = true, DataType = Type.GetType("System.UInt32") }); table.Columns.Add(new DataColumn { ColumnName = MempoolDeltaRowName, ReadOnly = true, DataType = Type.GetType("System.UInt32") }); table.Columns.Add(new DataColumn { ColumnName = InstancesRowName, ReadOnly = true, DataType = Type.GetType("System.UInt64") }); table.Columns.Add(new DataColumn { ColumnName = TotalCountRowName, ReadOnly = true, DataType = Type.GetType("System.UInt64") }); table.Columns.Add(new DataColumn { ColumnName = TotalSizeRowName, ReadOnly = true, DataType = Type.GetType("System.UInt64") }); table.Columns.Add(new DataColumn { ColumnName = TotalWasteRowName, ReadOnly = true, DataType = Type.GetType("System.UInt64") }); table.Columns.Add(new DataColumn { ColumnName = MempoolUsageRowName, ReadOnly = true, DataType = Type.GetType("System.UInt32") }); table.Columns.Add(new DataColumn { ColumnName = MempoolTotalUsageRowName, ReadOnly = true, DataType = Type.GetType("System.UInt32") }); table.Columns.Add(new DataColumn { ColumnName = PotentialWinRowName, ReadOnly = true, DataType = Type.GetType("System.UInt64") }); table.Columns.Add(new DataColumn { ColumnName = NewSizeRowName, ReadOnly = true, DataType = Type.GetType("System.UInt32") }); table.Columns.Add(new DataColumn { ColumnName = DeltaRowName, ReadOnly = true, DataType = Type.GetType("System.Int32") }); table.Columns.Add(new DataColumn { ColumnName = TotalDeltaRowName, ReadOnly = true, DataType = Type.GetType("System.Int64") }); return table; } void UpdateColumnVisibility() { dataGridSymbols.Columns[NewSizeRowName].Visible = _HasSecondPDB; dataGridSymbols.Columns[DeltaRowName].Visible = _HasSecondPDB; dataGridSymbols.Columns[TotalDeltaRowName].Visible = _HasSecondPDB; dataGridSymbols.Columns[InstancesRowName].Visible = _HasInstancesCount; dataGridSymbols.Columns[TotalCountRowName].Visible = _HasInstancesCount; dataGridSymbols.Columns[TotalSizeRowName].Visible = _HasInstancesCount && !_HasMemPools; dataGridSymbols.Columns[TotalWasteRowName].Visible = _HasInstancesCount && !_HasMemPools; dataGridSymbols.Columns[MempoolUsageRowName].Visible = _HasInstancesCount && _HasMemPools; dataGridSymbols.Columns[MempoolTotalUsageRowName].Visible = _HasInstancesCount && _HasMemPools; dataGridSymbols.Columns[PotentialWinRowName].Visible = _HasInstancesCount && _HasMemPools; } private void AddInstancesCount() { _HasInstancesCount = true; UpdateColumnVisibility(); } private void AddSecondPDB() { _HasSecondPDB = true; UpdateColumnVisibility(); } private void AddSymbolToTable(SymbolInfo symbolInfo) { var row = _Table.NewRow(); row[SymbolRowName] = symbolInfo.Name; row[SizeRowName] = symbolInfo.Size; row[PaddingRowName] = symbolInfo.Padding; row[MinAlignmentRowName] = symbolInfo.MinAlignment.Value; row[PaddingZonesRowName] = symbolInfo.PaddingZonesCount; row[TotalPaddingRowName] = symbolInfo.TotalPadding.Value; row[PotentialSavingRowName] = symbolInfo.PotentialSaving.Value; row[InstancesRowName] = symbolInfo.NumInstances; row[TotalCountRowName] = symbolInfo.TotalCount; row[TotalSizeRowName] = symbolInfo.TotalCount * symbolInfo.Size; row[TotalWasteRowName] = symbolInfo.TotalCount * symbolInfo.PotentialSaving; if (_HasSecondPDB && symbolInfo.NewSize != null) { row[NewSizeRowName] = symbolInfo.NewSize; row[DeltaRowName] = (long)symbolInfo.NewSize - (long)symbolInfo.Size; } if (_HasInstancesCount && symbolInfo.NumInstances > 0) { if (_HasMemPools) { row[TotalDeltaRowName] = symbolInfo.ComputeTotalMempoolDelta(); } else { row[TotalDeltaRowName] = symbolInfo.ComputeTotalDelta(); } } else if (_HasInstancesCount) { row[TotalDeltaRowName] = 0; } if (_HasMemPools && symbolInfo.CurrentMemPool > 0) { row[MempoolRowName] = symbolInfo.CurrentMemPool; row[MempoolDeltaRowName] = symbolInfo.Size - symbolInfo.LowerMemPool; row[MempoolUsageRowName] = (long)(symbolInfo.CurrentMemPool) * (long)symbolInfo.NumInstances; row[MempoolTotalUsageRowName] = (long)(symbolInfo.ComputeTotalMempoolUsage()); row[PotentialWinRowName] = (long)(symbolInfo.ComputePotentialTotalSaving()); } _Table.Rows.Add(row); } private ulong GetCacheLineSize() { return Convert.ToUInt32(textBoxCache.Text); } private SymbolInfo FindSelectedSymbolInfo() { if (dataGridSymbols.SelectedRows.Count == 0) return null; var selectedRow = dataGridSymbols.SelectedRows[0]; var symbolName = selectedRow.Cells[0].Value.ToString(); return CurrentSymbolAnalyzer.FindSymbolInfo(symbolName); } private string GetFilterString() { if (checkBoxSubclasses.Checked || checkBoxMember.Checked) return null; var filters = new List(); if (textBoxFilter.Text.Length > 0) if (checkBoxMatchWholeExpression.Checked) filters.Add($"Symbol = '{textBoxFilter.Text.Replace("'", string.Empty)}'"); else if (checkBoxRegularExpressions.Checked) filters.Add($"Symbol LIKE '{textBoxFilter.Text.Replace("'", string.Empty)}'"); else filters.Add($"Symbol LIKE '*{textBoxFilter.Text.Replace("'", string.Empty)}*'"); if (!chkShowTemplates.Checked) filters.Add("Symbol NOT LIKE '*<*'"); if (checkedListBoxNamespaces.CheckedItems.Count > 0) { var namespaceFilters = checkedListBoxNamespaces.CheckedItems.Cast() .Select(item => $"Symbol LIKE '*{item.Replace("'", string.Empty)}::*'"); filters.Add($"({string.Join(" OR ", namespaceFilters)})"); } return string.Join(" AND ", filters); } private void UpdateFilter() { _Table.CaseSensitive = checkBoxMatchCase.Checked; try { bindingSourceSymbols.Filter = GetFilterString(); textBoxFilter.BackColor = Color.Empty; textBoxFilter.ForeColor = Color.Empty; } catch (EvaluateException) { textBoxFilter.BackColor = Color.Red; textBoxFilter.ForeColor = Color.White; } } private void dataGridSymbols_SelectionChanged(object sender, EventArgs e) { if (_IgnoreSelectionChange) return; _PrefetchStartOffset = 0; if (dataGridSymbols.SelectedRows.Count > 1) ShowSelectionSummary(); else ShowSelectedSymbolInfo(); } private void dataGridSymbols_DerivedClassSelected(object sender, EventArgs e) { dataGridSymbols.ClearSelection(); if (TrySelectSymbol(sender.ToString()) == false) { var symbolInfo = CurrentSymbolAnalyzer.FindSymbolInfo(sender.ToString()); if (symbolInfo != null) { ShowSymbolInfo(symbolInfo); } } } private void dataGridSymbols_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) { _PrefetchStartOffset = 0; ShowSelectedSymbolInfo(); } private void ShowSelectionSummary() { dataGridViewSymbolInfo.Rows.Clear(); ulong totalMemory = 0; ulong totalWaste = 0; long totalDiff = 0; foreach (DataGridViewRow selectedRow in dataGridSymbols.SelectedRows) { var symbolName = selectedRow.Cells[0].Value.ToString(); var symbolInfo = CurrentSymbolAnalyzer.FindSymbolInfo(symbolName); if (_HasInstancesCount) { totalMemory += symbolInfo.NumInstances * symbolInfo.Size; totalWaste += symbolInfo.NumInstances * symbolInfo.PotentialSaving.Value; if (_HasSecondPDB) totalDiff += ((long) symbolInfo.NewSize - (long) symbolInfo.Size) * (long) symbolInfo.NumInstances; } else { totalMemory += symbolInfo.Size; totalWaste += symbolInfo.PotentialSaving.Value; } } labelCurrentSymbol.Text = "Total memory: " + totalMemory + " total waste: " + totalWaste; if (_HasInstancesCount && _HasSecondPDB) labelCurrentSymbol.Text += " total diff: " + totalDiff; } private void ShowSelectedSymbolInfo() { dataGridViewSymbolInfo.Rows.Clear(); var info = FindSelectedSymbolInfo(); if (info != null) { ShowSymbolInfo(info); } } private bool TrySelectSymbol(string name, bool ShowSelection = true) { foreach (DataGridViewRow dr in dataGridSymbols.Rows) { var dc = dr.Cells[0]; // name if (!dc.Value.ToString().Equals(name)) continue; _IgnoreSelectionChange = !ShowSelection; dataGridSymbols.CurrentCell = dc; _IgnoreSelectionChange = false; return true; } return false; } private void ShowSymbolInfo(SymbolInfo info) { if (_SelectedSymbol != info) { labelCurrentSymbol.Text = info.Name; if (_SelectedSymbol != null) { _NavigationStack.Push(_SelectedSymbol); } _RedoNavigationStack.Clear(); _SelectedSymbol = info; } UpdateSymbolGrid(); } private void ShowPreviousSymbolInfo() { if (_NavigationStack.Count == 0) return; if (_SelectedSymbol != null) { _RedoNavigationStack.Push(_SelectedSymbol); } _SelectedSymbol = _NavigationStack.Pop(); labelCurrentSymbol.Text = _SelectedSymbol.Name; UpdateSymbolGrid(); TrySelectSymbol(labelCurrentSymbol.Text, false); } private void ShowNextSymbolInfo() { if (_RedoNavigationStack.Count == 0) return; if (_SelectedSymbol != null) { _NavigationStack.Push(_SelectedSymbol); } _SelectedSymbol = _RedoNavigationStack.Pop(); labelCurrentSymbol.Text = _SelectedSymbol.Name; UpdateSymbolGrid(); TrySelectSymbol(labelCurrentSymbol.Text, false); } private void UpdateSymbolGrid() { dataGridViewSymbolInfo.Rows.Clear(); dataGridViewFunctionsInfo.Rows.Clear(); var prevCacheBoundaryOffset = _PrefetchStartOffset; if (_SelectedSymbol != null) { if (prevCacheBoundaryOffset > _SelectedSymbol.Size) prevCacheBoundaryOffset = _SelectedSymbol.Size; ulong numCacheLines = 0; var increment = 0; AddSymbolToGrid(_SelectedSymbol, ref prevCacheBoundaryOffset, ref numCacheLines, 0, increment); } } private void RefreshSymbolGrid(int rowIndex) { var firstRow = dataGridViewSymbolInfo.FirstDisplayedScrollingRowIndex; UpdateSymbolGrid(); if (rowIndex < dataGridViewSymbolInfo.Rows.Count) { dataGridViewSymbolInfo.Rows[rowIndex].Selected = true; dataGridViewSymbolInfo.FirstDisplayedScrollingRowIndex = firstRow; } } private void AddSymbolToGrid(SymbolInfo symbol, ref ulong prevCacheBoundaryOffset, ref ulong numCacheLines, ulong previousOffset, int increment) { var cacheLineSize = GetCacheLineSize(); var incrementText = ""; var incrementTextEmpty = ""; var whitespaceIncrementText = ""; for (var i = 0; i < increment; i++) { whitespaceIncrementText += " "; if (i == increment - 1) incrementText += " |__ "; else incrementText += " | "; incrementTextEmpty += " | "; } foreach (var member in symbol.Members) { var currentOffset = previousOffset + member.Offset; if (member.PaddingBefore > 0 && checkBoxPadding.Checked) { var paddingOffset = member.Offset - member.PaddingBefore; string[] paddingRow = { string.Empty, incrementTextEmpty, PaddingRowName, paddingOffset.ToString(), string.Empty, member.PaddingBefore.ToString(), string.Empty, string.Empty, member.PaddingBefore.ToString() }; dataGridViewSymbolInfo.Rows.Add(paddingRow); } if (checkBoxCacheLines.Checked) { var cacheLines = new List(); while (currentOffset >= cacheLineSize + prevCacheBoundaryOffset) { numCacheLines++; var cacheLineOffset = numCacheLines * cacheLineSize + _PrefetchStartOffset; cacheLines.Add(cacheLineOffset); prevCacheBoundaryOffset = cacheLineOffset; } if (cacheLines.Count > 3 && checkBoxSmartCacheLines.Checked) { string[] firstBoundaryRow = { string.Empty, incrementTextEmpty, "Cacheline boundary", cacheLines[0].ToString(), string.Empty, string.Empty, string.Empty }; dataGridViewSymbolInfo.Rows.Add(firstBoundaryRow); string[] middleBoundariesRow = { string.Empty, incrementTextEmpty, "Cacheline boundaries (...)", string.Empty, string.Empty, string.Empty, string.Empty }; dataGridViewSymbolInfo.Rows.Add(middleBoundariesRow); string[] lastBoundaryRow = { string.Empty, incrementTextEmpty, "Cacheline boundary", cacheLines[cacheLines.Count - 1].ToString(), string.Empty, string.Empty, string.Empty }; dataGridViewSymbolInfo.Rows.Add(lastBoundaryRow); } else { cacheLines.ForEach(offset => { string[] boundaryRow = { string.Empty, incrementTextEmpty, "Cacheline boundary", offset.ToString() }; dataGridViewSymbolInfo.Rows.Add(boundaryRow); }); } } var expand = ""; if (member.Expanded) expand = whitespaceIncrementText + "- "; else if (member.IsExapandable) expand = whitespaceIncrementText + "+ "; string PotentialSaving = string.Empty; if (member.PotentialSaving.HasValue) { PotentialSaving = member.PotentialSaving.ToString(); } else if (member.Category == SymbolMemberInfo.MemberCategory.VTable && symbol.HasUnusedVTable()) { PotentialSaving = "8"; } else if (member.TypeInfo != null && member.TypeInfo.PotentialSaving != null && member.TypeInfo.PotentialSaving.Value > 0) { PotentialSaving = member.TypeInfo.PotentialSaving.Value.ToString(); } object[] row = { expand, incrementText + member.DisplayName, member.TypeName, currentOffset.ToString(), (member.BitField ? member.BitPosition.ToString() : string.Empty), member.BitField ? (member.BitSize.ToString() + (member.BitSize == 1 ? " bit" : " bits")) : (member.Size.ToString() + (member.Size == 1 ? " byte" : " bytes")), member.MinAlignment.ToString(), member.TypeInfo?.Padding.ToString() ?? "0", PotentialSaving }; dataGridViewSymbolInfo.Rows.Add(row); dataGridViewSymbolInfo.Rows[dataGridViewSymbolInfo.Rows.Count - 1].Tag = member; if (member.Expanded && member.TypeInfo != null) AddSymbolToGrid(member.TypeInfo, ref prevCacheBoundaryOffset, ref numCacheLines, currentOffset, increment + 1); if (member.BitField && member.BitPaddingAfter > 0 && checkBoxBitPadding.Checked) { var paddingOffset = member.BitPaddingAfter.ToString() + " bits"; string[] paddingRow = { string.Empty, incrementTextEmpty, "Bitfield padding", currentOffset.ToString(), (member.BitPosition + member.BitSize).ToString(), paddingOffset }; dataGridViewSymbolInfo.Rows.Add(paddingRow); } } // Final structure padding. if (symbol.EndPadding > 0 && checkBoxPadding.Checked) { var endPaddingOffset = symbol.Size - symbol.EndPadding; string[] paddingRow = { string.Empty, string.Empty, PaddingRowName, endPaddingOffset.ToString(), string.Empty, symbol.EndPadding.ToString(), string.Empty, string.Empty, symbol.EndPadding.ToString() }; dataGridViewSymbolInfo.Rows.Add(paddingRow); } if (symbol.Functions != null) { foreach (var function in symbol.Functions) { object[] row = { function.DisplayName, function.Virtual, function.IsPure, function.IsOverride, function.IsOverloaded, function.IsMasking }; dataGridViewFunctionsInfo.Rows.Add(row); dataGridViewFunctionsInfo.Rows[dataGridViewFunctionsInfo.Rows.Count - 1].Tag = function; } } } private void dataGridSymbols_SortCompare(object sender, DataGridViewSortCompareEventArgs e) { if (e.Column.Index > 0) { e.Handled = true; TryParse(e.CellValue1.ToString(), out var val1); TryParse(e.CellValue2.ToString(), out var val2); e.SortResult = val1 - val2; } } private void dataGridViewSymbolInfo_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { var row = dataGridViewSymbolInfo.Rows[e.RowIndex]; var nameCell = row.Cells[2]; if (row.Tag is SymbolMemberInfo info) { if (info.Category == SymbolMemberInfo.MemberCategory.VTable) e.CellStyle.BackColor = Color.LemonChiffon; else if (info.IsBase) e.CellStyle.BackColor = Color.LightGreen; else if (info.BitField) { if (e.ColumnIndex == 3 ) // Offset column { e.CellStyle.BackColor = Color.FromArgb((int)((info.Offset * 37) % 256), 192, 192); // random color not too dark row.Cells[e.ColumnIndex].ToolTipText = "Bitfield"; } } else if (info.AlignWithPrevious) { if (e.ColumnIndex == 3) // Offset column { e.CellStyle.BackColor = Color.Salmon; row.Cells[e.ColumnIndex].ToolTipText = "Aligned with previous"; } } else if (checkBoxCacheLines.Checked && checkBoxShowOverlap.Checked) { var cacheLineSize = GetCacheLineSize(); var cacheOffset = (info.Offset - _PrefetchStartOffset) % cacheLineSize; if (cacheOffset + info.Size > cacheLineSize) { e.CellStyle.BackColor = Color.LightYellow; } } if (info.Volatile) { if (e.ColumnIndex == 0) // Name (Field) column { e.CellStyle.BackColor = Color.LightBlue; row.Cells[e.ColumnIndex].ToolTipText = "Volatile"; } } } else if (nameCell.Value.ToString() == PaddingRowName) { e.CellStyle.BackColor = Color.LightPink; if (e.ColumnIndex == 2) e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; } else if (nameCell.Value.ToString() == "Bitfield padding") { e.CellStyle.BackColor = Color.PaleVioletRed; if (e.ColumnIndex == 2) e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; } else if (nameCell.Value.ToString().StartsWith("Cacheline")) { e.CellStyle.BackColor = Color.LightGray; if (e.ColumnIndex == 2) e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; } } private void textBoxFilter_TextChanged(object sender, EventArgs e) { if (_TypingTimer == null) { _TypingTimer = new Timer(); _TypingTimer.Interval = 500; _TypingTimer.Tick += new EventHandler(this.HandleTypingTimerTimeout); } _TypingTimer.Stop(); _TypingTimer.Start(); } private void HandleTypingTimerTimeout(object sender, EventArgs e) { var timer = sender as Timer; if (timer == null) { return; } timer.Stop(); if (checkBoxMember.Checked || checkBoxSubclasses.Checked) PopulateDataTable(); else UpdateFilter(); UpdateBtnLoadText(); } private void textBoxFilter_KeyUp(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Return && !loadPDBBackgroundWorker.IsBusy && !loadCSVBackgroundWorker.IsBusy) { LoadPdb(CurrentSymbolAnalyzer.FileName, false); btnLoad.Text = "Cancel"; } } private void copyTypeLayoutToClipboardToolStripMenuItem_Click(object sender, EventArgs e) { var info = FindSelectedSymbolInfo(); if (info != null) Clipboard.SetText(info.ToString()); } private void textBoxCache_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == (char) Keys.Enter || e.KeyChar == (char) Keys.Escape) ShowSelectedSymbolInfo(); OnKeyPress(e); } private void textBoxCache_Leave(object sender, EventArgs e) { ShowSelectedSymbolInfo(); } private void setPrefetchStartOffsetToolStripMenuItem_Click(object sender, EventArgs e) { if (dataGridViewSymbolInfo.SelectedRows.Count != 0) { var selectedRow = dataGridViewSymbolInfo.SelectedRows[0]; ulong symbolOffset = Convert.ToUInt32(selectedRow.Cells[3].Value); _PrefetchStartOffset = symbolOffset % GetCacheLineSize(); RefreshSymbolGrid(selectedRow.Index); } } private void checkBoxCacheLines_CheckedChanged(object sender, EventArgs e) { checkBoxSmartCacheLines.Enabled = checkBoxCacheLines.Checked; checkBoxShowOverlap.Enabled = checkBoxCacheLines.Checked; textBoxCache.Enabled = checkBoxCacheLines.Checked; labelCacheLine.Enabled = checkBoxCacheLines.Checked; if (dataGridViewSymbolInfo.SelectedRows.Count != 0) { var selectedRow = dataGridViewSymbolInfo.SelectedRows[0]; RefreshSymbolGrid(selectedRow.Index); } else { RefreshSymbolGrid(0); } } private void dataGridViewSymbolInfo_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { var currentMouseOverRow = dataGridViewSymbolInfo.HitTest(e.X, e.Y).RowIndex; if (currentMouseOverRow >= 0) { dataGridViewSymbolInfo.Rows[currentMouseOverRow].Selected = true; contextMenuStripMembers.Show(dataGridViewSymbolInfo, new Point(e.X, e.Y)); } } else if (e.Button == MouseButtons.XButton1) { ShowPreviousSymbolInfo(); } else if (e.Button == MouseButtons.XButton2) { ShowNextSymbolInfo(); } } private void dataGridViewSymbolInfo_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) { var selectedRow = dataGridViewSymbolInfo.Rows[e.RowIndex]; var currentSymbolInfo = selectedRow.Tag as SymbolMemberInfo; if (currentSymbolInfo != null && currentSymbolInfo.Category != SymbolMemberInfo.MemberCategory.Member) { var typeName = currentSymbolInfo.TypeName; if (typeName.Contains("[")) typeName = typeName.Substring(0, typeName.IndexOf("[")); if (currentSymbolInfo.Category == SymbolMemberInfo.MemberCategory.Pointer) { if (typeName.Contains("*")) typeName = typeName.Substring(0, typeName.IndexOf("*")); if (typeName.Contains("&")) typeName = typeName.Substring(0, typeName.IndexOf("&")); } Cursor.Current = Cursors.WaitCursor; var jumpToSymbolInfo = CurrentSymbolAnalyzer.FindSymbolInfo(typeName, true); if (jumpToSymbolInfo != null) { if (e.ColumnIndex == 0) { if (currentSymbolInfo.IsExapandable) { currentSymbolInfo.Expanded = !currentSymbolInfo.Expanded; RefreshSymbolGrid(e.RowIndex); } } else { ShowSymbolInfo(jumpToSymbolInfo); TrySelectSymbol(typeName, false); } } Cursor.Current = Cursors.Default; } } private void chkShowTemplates_CheckedChanged(object sender, EventArgs e) { UpdateFilter(); } private void checkBoxSmartCacheLines_CheckedChanged(object sender, EventArgs e) { ShowSelectedSymbolInfo(); } private void checkedListBoxNamespaces_ItemCheck(object sender, ItemCheckEventArgs e) { this.BeginInvoke(new Action(() => { UpdateFilter(); })); } private void dataGridViewSymbolInfo_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Back) { ShowPreviousSymbolInfo(); } if (e.KeyCode == Keys.Next) { ShowNextSymbolInfo(); } OnKeyDown(e); } private void loadPDBBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { toolStripProgressBar.Value = e.ProgressPercentage; toolStripStatusLabel.Text = e.UserState as String; } private void loadPDBBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { UpdateBtnLoadText(); if (e.Cancelled) { if (_CloseRequested) { Close(); } else { toolStripStatusLabel.Text = ""; toolStripProgressBar.Value = 0; } return; } var loadPdbSuccess = (bool) e.Result; if (!loadPdbSuccess) { MessageBox.Show(this, CurrentSymbolAnalyzer.LastError); toolStripStatusLabel.Text = "Failed to load PDB."; return; } OnPDBLoaded(); } private void loadPDBBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) { e.Result = CurrentSymbolAnalyzer.LoadPdb(sender, e); } private void loadCSVBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { toolStripProgressBar.Value = e.ProgressPercentage; toolStripStatusLabel.Text = e.UserState as String; } private void loadCSVBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { UpdateBtnLoadText(); if (e.Cancelled) { if (_CloseRequested) { Close(); } else { toolStripStatusLabel.Text = ""; toolStripProgressBar.Value = 0; } return; } var loadCSVSuccess = (bool)e.Result; if (!loadCSVSuccess) { MessageBox.Show(this, CurrentSymbolAnalyzer.LastError); toolStripStatusLabel.Text = "Failed to load CSV."; return; } foreach (var symbol in CurrentSymbolAnalyzer.Symbols.Values) if (symbol.NumInstances > 0) symbol.UpdateTotalCount(symbol.NumInstances); AddInstancesCount(); OnPDBLoaded(); } private void loadCSVBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) { e.Result = CurrentSymbolAnalyzer.LoadCSV(sender, e); } private void OnPDBLoaded() { compareWithPDBToolStripMenuItem.Enabled = true; exportCsvToolStripMenuItem.Enabled = true; findUnusedVtablesToolStripMenuItem.Enabled = true; findMSVCExtraPaddingToolStripMenuItem.Enabled = true; findMSVCEmptyBaseClassToolStripMenuItem.Enabled = true; findUnusedInterfacesToolStripMenuItem.Enabled = true; findUnusedVirtualToolStripMenuItem.Enabled = true; findMaskingFunctionsToolStripMenuItem.Enabled = true; findRemovedInlineToolStripMenuItem.Enabled = true; // Temporarily clear the filter so, if current filter is invalid, we don't generate a ton of exceptions while populating the table var preExistingFilter = textBoxFilter.Text; textBoxFilter.Text = string.Empty; PopulateDataTable(); checkedListBoxNamespaces.Items.Clear(); if (checkedListBoxNamespaces.Enabled) { foreach (var name in CurrentSymbolAnalyzer.RootNamespaces) checkedListBoxNamespaces.Items.Add(name); } // Sort by name by default (ascending) dataGridSymbols.Sort(dataGridSymbols.Columns[0], ListSortDirection.Ascending); bindingSourceSymbols.Filter = null; // "Symbol LIKE '*rde*'"; // Restore the filter now that the table is populated textBoxFilter.Text = preExistingFilter; UpdateFilter(); ShowSelectedSymbolInfo(); _NavigationStack.Clear(); } private void loadInstanceCountToolStripMenuItem_Click(object sender, EventArgs e) { if (loadPDBBackgroundWorker.IsBusy || loadCSVBackgroundWorker.IsBusy) return; if (openCsvDialog.ShowDialog() == DialogResult.OK) LoadCsv(openPdbDialog.FileName); } private void LoadCsv(string fileName) { Cursor.Current = Cursors.WaitCursor; if (_HasInstancesCount) foreach (var symbol in CurrentSymbolAnalyzer.Symbols.Values) { symbol.NumInstances = 0; symbol.TotalCount = 0; } using (var sourceStream = File.Open(openCsvDialog.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { List tasks = new List(); using (var reader = new StreamReader(sourceStream)) { ; while (!reader.EndOfStream) { var line = reader.ReadLine(); var values = line.Split(','); var count = ulong.Parse(values[1]); if (count > 0) { var task = new LoadCSVTask { ClassName = values[0], Count = count }; tasks.Add(task); } } loadCSVBackgroundWorker.RunWorkerAsync(tasks); btnLoad.Text = "Cancel"; } } } private void compareWithPDBToolStripMenuItem_Click(object sender, EventArgs e) { if (loadPDBBackgroundWorker.IsBusy || loadCSVBackgroundWorker.IsBusy) return; if (openPdbDialog.ShowDialog() == DialogResult.OK) { AddSecondPDB(); LoadPdb(openPdbDialog.FileName, true); if (_HasMemPools) { foreach (var symbolInfo in CurrentSymbolAnalyzer.Symbols.Values) { symbolInfo.SetNewMemPools(CurrentSymbolAnalyzer.MemPools); } } } } private void exportCsvToolStripMenuItem_Click(object sender, EventArgs e) { if (loadPDBBackgroundWorker.IsBusy || loadCSVBackgroundWorker.IsBusy) return; if (saveCsvDialog.ShowDialog() == DialogResult.OK) using (var writer = new StreamWriter(saveCsvDialog.FileName)) { writer.WriteLine( "Name,Size,Padding,Padding zones,Total padding,Num Instances,Total size,Total waste,"); foreach (var symbolInfo in CurrentSymbolAnalyzer.Symbols.Values) writer.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7},", symbolInfo.Name, symbolInfo.Size, symbolInfo.Padding, symbolInfo.PaddingZonesCount, symbolInfo.TotalPadding.Value, symbolInfo.NumInstances, symbolInfo.NumInstances * symbolInfo.Size, symbolInfo.NumInstances * symbolInfo.Padding); } } private void CruncherSharpForm_FormClosing(object sender, FormClosingEventArgs e) { if (loadCSVBackgroundWorker.IsBusy) { e.Cancel = true; // Can't close form while background worker is busy! loadCSVBackgroundWorker.CancelAsync(); _CloseRequested = true; } if (loadPDBBackgroundWorker.IsBusy) { e.Cancel = true; // Can't close form while background worker is busy! loadPDBBackgroundWorker.CancelAsync(); _CloseRequested = true; } } private void findUnusedVtablesToolStripMenuItem_Click(object sender, EventArgs e) { if (SearchCategory == SearchType.UnusedVTables) SearchCategory = SearchType.None; else SearchCategory = SearchType.UnusedVTables; PopulateDataTable(); } private void Reset_Click(object sender, EventArgs e) { chkShowTemplates.Checked = false; checkBoxSmartCacheLines.Checked = true; checkBoxSubclasses.Checked = false; checkBoxMember.Checked = false; restrictToSymbolsImportedFroCSVToolStripMenuItem.Checked = false; restrictToUObjectsToolStripMenuItem.Checked = false; for (var i = 0; i < checkedListBoxNamespaces.Items.Count; i++) checkedListBoxNamespaces.SetItemChecked(i, false); textBoxFilter.Clear(); SearchCategory = SearchType.None; PopulateDataTable(); } private void findMSVCExtraPaddingToolStripMenuItem_Click(object sender, EventArgs e) { if (SearchCategory == SearchType.MSVCExtraPadding) SearchCategory = SearchType.None; else SearchCategory = SearchType.MSVCExtraPadding; PopulateDataTable(); } private void findMSVCEmptyBaseClassToolStripMenuItem_Click(object sender, EventArgs e) { if (SearchCategory == SearchType.MSVCEmptyBaseClass) SearchCategory = SearchType.None; else SearchCategory = SearchType.MSVCEmptyBaseClass; PopulateDataTable(); } private void findUnusedInterfacesToolStripMenuItem_Click(object sender, EventArgs e) { if (SearchCategory == SearchType.UnusedInterfaces) SearchCategory = SearchType.None; else SearchCategory = SearchType.UnusedInterfaces; PopulateDataTable(); } private void findUnusedVirtualToolStripMenuItem_Click(object sender, EventArgs e) { if (SearchCategory == SearchType.UnusedVirtual) SearchCategory = SearchType.None; else SearchCategory = SearchType.UnusedVirtual; PopulateDataTable(); } private void dataGridViewFunctionsInfo_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { var row = dataGridViewFunctionsInfo.Rows[e.RowIndex]; var info = row.Tag as SymbolFunctionInfo; if (_FunctionsToIgnore.Contains(info.Name)) e.CellStyle.BackColor = Color.LightGray; else switch (info.Category) { case SymbolFunctionInfo.FunctionCategory.Constructor: e.CellStyle.BackColor = Color.LightBlue; break; case SymbolFunctionInfo.FunctionCategory.Destructor: e.CellStyle.BackColor = Color.LightGreen; break; case SymbolFunctionInfo.FunctionCategory.StaticFunction: e.CellStyle.BackColor = Color.LightPink; break; default: switch (SearchCategory) { case SearchType.UnusedVirtual: if (info.UnusedVirtual) e.CellStyle.BackColor = Color.IndianRed; break; case SearchType.MaskingFunction: if (info.IsMasking) e.CellStyle.BackColor = Color.IndianRed; break; case SearchType.RemovedInline: if (info.WasInlineRemoved) e.CellStyle.BackColor = Color.IndianRed; break; } break; } } private void findMaskingFunctionsToolStripMenuItem_Click(object sender, EventArgs e) { if (SearchCategory == SearchType.MaskingFunction) SearchCategory = SearchType.None; else SearchCategory = SearchType.MaskingFunction; PopulateDataTable(); } private void ignoreFunctionToolStripMenuItem_Click(object sender, EventArgs e) { if (dataGridViewFunctionsInfo.SelectedRows.Count != 0) { var selectedRow = dataGridViewFunctionsInfo.SelectedRows[0]; var info = selectedRow.Tag as SymbolFunctionInfo; if (!_FunctionsToIgnore.Contains(info.Name)) { _FunctionsToIgnore.Add(info.Name); PopulateDataTable(); } } } private void dataGridViewFunctionsInfo_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { var currentMouseOverRow = dataGridViewFunctionsInfo.HitTest(e.X, e.Y).RowIndex; if (currentMouseOverRow >= 0) { dataGridViewFunctionsInfo.Rows[currentMouseOverRow].Selected = true; contextMenuStripFunctions.Show(dataGridViewFunctionsInfo, new Point(e.X, e.Y)); } } else if (e.Button == MouseButtons.XButton1) { ShowPreviousSymbolInfo(); } else if (e.Button == MouseButtons.XButton2) { ShowNextSymbolInfo(); } } private void dataGridSymbols_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { var row = dataGridSymbols.Rows[e.RowIndex]; var column= dataGridSymbols.Columns[e.ColumnIndex]; var symbolName = row.Cells[0].Value.ToString(); SymbolInfo CurrentSymbol = CurrentSymbolAnalyzer.FindSymbolInfo(symbolName); if (column.Name == InstancesRowName) { row.Cells[e.ColumnIndex].ToolTipText = "Number of instances of this class"; } else if (column.Name == TotalCountRowName) { row.Cells[e.ColumnIndex].ToolTipText = "Number of instances of this class, including derived classes and aggregated objects"; } else if (column.Name == PaddingRowName) { row.Cells[e.ColumnIndex].ToolTipText = "Memory padding in this class"; } else if (column.Name == TotalSizeRowName) { row.Cells[e.ColumnIndex].ToolTipText = "Size of the object multiplied by total count"; } else if (column.Name == TotalPaddingRowName) { row.Cells[e.ColumnIndex].ToolTipText = "Memory padding in this class, including parent classes and aggregated objects"; } else if (column.Name == MempoolUsageRowName) { row.Cells[e.ColumnIndex].ToolTipText = String.Format("Number of instances multiplied by current memory pool ({0})", CurrentSymbol.CurrentMemPool); } else if (column.Name == MempoolTotalUsageRowName) { row.Cells[e.ColumnIndex].ToolTipText = "Number of instances multiplied by current memory pool for current class and subclasses"; } else if (column.Name == MempoolDeltaRowName) { row.Cells[e.ColumnIndex].ToolTipText = String.Format("Delta with the lower memory pool ({0})", CurrentSymbol.LowerMemPool); if (CurrentSymbol.Padding >= (CurrentSymbol.Size - CurrentSymbol.LowerMemPool)) { row.Cells[e.ColumnIndex].Style.BackColor = Color.Green; row.Cells[e.ColumnIndex].ToolTipText += "\nPadding is bigger than delta"; } else if (CurrentSymbol.PotentialSaving >= (CurrentSymbol.Size - CurrentSymbol.LowerMemPool)) { row.Cells[e.ColumnIndex].Style.BackColor = Color.LightGreen; row.Cells[e.ColumnIndex].ToolTipText += "\nTotal padding is bigger than delta"; } } else if (column.Name == PotentialWinRowName) { row.Cells[e.ColumnIndex].ToolTipText = String.Format("Memory saving with potential saving"); } else if (column.Name == NewSizeRowName) { row.Cells[e.ColumnIndex].ToolTipText = String.Format("New memory pool ({0})", CurrentSymbol.NewMemPool); } } private void dataGridSymbols_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { var currentMouseOverRow = dataGridSymbols.HitTest(e.X, e.Y).RowIndex; if (currentMouseOverRow >= 0) { foreach (DataGridViewRow selectedRow in dataGridSymbols.SelectedRows) selectedRow.Selected = false; dataGridSymbols.Rows[currentMouseOverRow].Selected = true; toolStripMenuItemDerivedClasses.DropDownItems.Clear(); var info = FindSelectedSymbolInfo(); if (info != null) { if (info.DerivedClasses != null) { toolStripMenuItemDerivedClasses.Enabled = true; foreach (var DerivedClass in info.DerivedClasses) { toolStripMenuItemDerivedClasses.DropDownItems.Add(DerivedClass.Name, null, dataGridSymbols_DerivedClassSelected); } } else { toolStripMenuItemDerivedClasses.Enabled = false; } ShowSymbolInfo(info); } contextMenuStripClassInfo.Show(dataGridSymbols, new Point(e.X, e.Y)); } } else if (e.Button == MouseButtons.XButton1) { ShowPreviousSymbolInfo(); } else if (e.Button == MouseButtons.XButton2) { ShowNextSymbolInfo(); } } private void findRemovedInlineToolStripMenuItem_Click(object sender, EventArgs e) { SearchCategory = SearchType.RemovedInline; PopulateDataTable(); } private void UpdateCheckedOption() { findUnusedVtablesToolStripMenuItem.Checked = SearchCategory == SearchType.UnusedVTables; findUnusedVirtualToolStripMenuItem.Checked = SearchCategory == SearchType.UnusedVirtual; findMSVCExtraPaddingToolStripMenuItem.Checked = SearchCategory == SearchType.MSVCExtraPadding; findMSVCEmptyBaseClassToolStripMenuItem.Checked = SearchCategory == SearchType.MSVCEmptyBaseClass; findUnusedInterfacesToolStripMenuItem.Checked = SearchCategory == SearchType.UnusedInterfaces; findMaskingFunctionsToolStripMenuItem.Checked = SearchCategory == SearchType.MaskingFunction; findRemovedInlineToolStripMenuItem.Checked = SearchCategory == SearchType.RemovedInline; } private void TryAddSymbolToTable(SymbolInfo symbolInfo) { if (restrictToSymbolsImportedFroCSVToolStripMenuItem.Checked && !symbolInfo.IsImportedFromCSV) { return; } if (restrictToUObjectsToolStripMenuItem.Checked && !symbolInfo.IsA("UObject", CurrentSymbolAnalyzer)) { return; } switch (SearchCategory) { case SearchType.None: AddSymbolToTable(symbolInfo); break; case SearchType.UnusedVTables: if (symbolInfo.HasUnusedVTable()) AddSymbolToTable(symbolInfo); break; case SearchType.MSVCExtraPadding: if (symbolInfo.HasMSVCExtraPadding()) AddSymbolToTable(symbolInfo); break; case SearchType.MSVCEmptyBaseClass: if (symbolInfo.HasMSVCEmptyBaseClass) AddSymbolToTable(symbolInfo); break; case SearchType.UnusedInterfaces: if (symbolInfo.IsAbstract && symbolInfo.DerivedClasses == null) AddSymbolToTable(symbolInfo); break; case SearchType.UnusedVirtual: if (symbolInfo.Functions == null) break; foreach (var function in symbolInfo.Functions) if (function.UnusedVirtual) if (!_FunctionsToIgnore.Contains(function.Name)) { AddSymbolToTable(symbolInfo); break; } break; case SearchType.MaskingFunction: if (symbolInfo.Functions == null) break; foreach (var function in symbolInfo.Functions) if (function.IsMasking) if (!_FunctionsToIgnore.Contains(function.Name)) { AddSymbolToTable(symbolInfo); break; } break; case SearchType.RemovedInline: if (symbolInfo.Functions == null) break; foreach (var function in symbolInfo.Functions) if (function.WasInlineRemoved) if (!_FunctionsToIgnore.Contains(function.Name)) { AddSymbolToTable(symbolInfo); break; } break; } } private void TryAddSubclassesToTable(SymbolInfo symbolInfo) { if (symbolInfo != null && symbolInfo.DerivedClasses != null) { foreach (SymbolInfo DerivedClassInfo in symbolInfo.DerivedClasses) { TryAddSymbolToTable(DerivedClassInfo); TryAddSubclassesToTable(DerivedClassInfo); } } } private void PopulateDataTable() { _Table.Rows.Clear(); _Table.BeginLoadData(); if (checkBoxSubclasses.Checked) { if (textBoxFilter.Text.Length > 0) { SymbolInfo ClassInfo = CurrentSymbolAnalyzer.FindSymbolInfo(textBoxFilter.Text); if (ClassInfo != null) { TryAddSymbolToTable(ClassInfo); TryAddSubclassesToTable(ClassInfo); } } } else if (checkBoxMember.Checked) { if (textBoxFilter.Text.Length > 0) { SymbolInfo ClassInfo = CurrentSymbolAnalyzer.FindSymbolInfo(textBoxFilter.Text); if (ClassInfo != null) { foreach (SymbolInfo symbolInfo in CurrentSymbolAnalyzer.Symbols.Values) { bool foundMember = false; foreach(SymbolMemberInfo member in symbolInfo.Members) { if (member.Category == SymbolMemberInfo.MemberCategory.Base) { continue; } if (member.TypeName != textBoxFilter.Text) { continue; } foundMember = true; break; } if (foundMember) TryAddSymbolToTable(symbolInfo); } } } } else { foreach (var symbolInfo in CurrentSymbolAnalyzer.Symbols.Values) { TryAddSymbolToTable(symbolInfo); } } UpdateFilter(); _Table.EndLoadData(); } private void btnLoad_Click(object sender, EventArgs e) { if (loadCSVBackgroundWorker.IsBusy) { loadCSVBackgroundWorker.CancelAsync(); toolStripStatusLabel.Text = "Canceling..."; } else if (loadPDBBackgroundWorker.IsBusy) { loadPDBBackgroundWorker.CancelAsync(); toolStripStatusLabel.Text = "Canceling..."; } else { LoadPdb(CurrentSymbolAnalyzer.FileName, false); btnLoad.Text = "Cancel"; } } private void checkBoxMatchCase_CheckedChanged(object sender, EventArgs e) { UpdateFilter(); } private void checkBoxMatchWholeExpression_CheckedChanged(object sender, EventArgs e) { UpdateFilter(); } private void checkBoxRegularExpressions_CheckedChanged(object sender, EventArgs e) { if (checkBoxRegularExpressions.Checked) { checkBoxMatchWholeExpression.Checked = false; checkBoxMatchWholeExpression.Enabled = false; } else { checkBoxMatchWholeExpression.Enabled = true; } UpdateFilter(); } private void checkBoxPadding_CheckedChanged(object sender, EventArgs e) { if (dataGridViewSymbolInfo.SelectedRows.Count != 0) { var selectedRow = dataGridViewSymbolInfo.SelectedRows[0]; RefreshSymbolGrid(selectedRow.Index); } else { RefreshSymbolGrid(0); } } private void checkBoxBitPadding_CheckedChanged(object sender, EventArgs e) { if (dataGridViewSymbolInfo.SelectedRows.Count != 0) { var selectedRow = dataGridViewSymbolInfo.SelectedRows[0]; RefreshSymbolGrid(selectedRow.Index); } else { RefreshSymbolGrid(0); } } private void checkBoxFunctionAnalysis_CheckedChanged(object sender, EventArgs e) { Cursor.Current = Cursors.WaitCursor; CurrentSymbolAnalyzer.FunctionAnalysis = checkBoxFunctionAnalysis.Checked; Cursor.Current = Cursors.Default; } private void restrictToSymbolsImportedFroCSVToolStripMenuItem_Click(object sender, EventArgs e) { restrictToSymbolsImportedFroCSVToolStripMenuItem.Checked = !restrictToSymbolsImportedFroCSVToolStripMenuItem.Checked; PopulateDataTable(); } private void useRawPDBToolStripMenuItem_Click(object sender, EventArgs e) { useRawPDBToolStripMenuItem.Checked = !useRawPDBToolStripMenuItem.Checked; PopulateDataTable(); } private void checkBoxNamespaces_CheckedChanged(object sender, EventArgs e) { checkedListBoxNamespaces.Enabled = checkBoxNamespaces.Checked; checkedListBoxNamespaces.Visible = checkBoxNamespaces.Checked; checkedListBoxNamespaces.Items.Clear(); if (checkedListBoxNamespaces.Enabled) { foreach (var name in CurrentSymbolAnalyzer.RootNamespaces) checkedListBoxNamespaces.Items.Add(name); } } private void restrictToUObjectsToolStripMenuItem_Click(object sender, EventArgs e) { restrictToUObjectsToolStripMenuItem.Checked = !restrictToUObjectsToolStripMenuItem.Checked; PopulateDataTable(); } private void checkBoxSubclasses_CheckedChanged(object sender, EventArgs e) { if (checkBoxSubclasses.Checked && _SelectedSymbol != null) { textBoxFilter.Text = _SelectedSymbol.Name; } checkBoxMember.Checked = false; PopulateDataTable(); } private void checkBoxMember_CheckedChanged(object sender, EventArgs e) { if (checkBoxMember.Checked && _SelectedSymbol != null) { textBoxFilter.Text = _SelectedSymbol.Name; } checkBoxSubclasses.Checked = false; PopulateDataTable(); } private void customMBToolStripMenuItem_Click(object sender, EventArgs e) { mB2ToolStripMenuItem.Checked = false; mB3ToolStripMenuItem.Checked = false; customMBToolStripMenuItem.Checked = true; var memPoolsForm = new AddMemPoolsForm(); memPoolsForm.SetMemPools(CurrentSymbolAnalyzer.MemPools); memPoolsForm.ShowDialog(); CurrentSymbolAnalyzer.MemPools = memPoolsForm.GetMemPool(); if (!_HasMemPools && CurrentSymbolAnalyzer.MemPools.Count > 0) { _HasMemPools = true; } PopulateDataTable(); } private void mB2ToolStripMenuItem_Click(object sender, EventArgs e) { if (ShowMemPool("MB2")) { mB2ToolStripMenuItem.Checked = true; mB3ToolStripMenuItem.Checked = false; customMBToolStripMenuItem.Checked = false; } } private void mB3ToolStripMenuItem_Click(object sender, EventArgs e) { if (ShowMemPool("MB3")) { mB2ToolStripMenuItem.Checked = false; mB3ToolStripMenuItem.Checked = true; customMBToolStripMenuItem.Checked = false; } } private bool ShowMemPool(string memPoolName) { string MemoryPoolsSettings = ConfigurationManager.AppSettings.Get(memPoolName); if (MemoryPoolsSettings == null) return false; string[] MemoryPools = MemoryPoolsSettings.Split(','); List MemoryPoolsSize = new List(); foreach (var memPool in MemoryPools) { MemoryPoolsSize.Add(UInt32.Parse(memPool)); } if (MemoryPoolsSize.Count > 0) { _SymbolAnalyzerDia.MemPools = MemoryPoolsSize; #if RAWPDB _SymbolAnalyzerRawPDB.MemPools = MemoryPoolsSize; #endif _HasMemPools = true; PopulateDataTable(); return true; } return false; } } }