public void dumpSymbolInfo(System.IO.TextWriter tw, CruncherSymbol info) { tw.WriteLine("Symbol: " + info.Name); tw.WriteLine("Size: " + info.Size.ToString()); tw.WriteLine("Total padding: " + info.CalcTotalPadding().ToString()); tw.WriteLine("Members"); tw.WriteLine("-------"); foreach (CruncherSymbol child in info.m_children) { if (child.Padding > 0) { long paddingOffset = child.Offset - child.Padding; tw.WriteLine(String.Format("{0,-40} {1,5} {2,5}", "****Padding", paddingOffset, child.Padding)); } tw.WriteLine(String.Format("{0,-40} {1,5} {2,5}", child.Name, child.Offset, child.Size)); } // Final structure padding. if (info.Padding > 0) { long paddingOffset = (long)info.Size - info.Padding; tw.WriteLine(String.Format("{0,-40} {1,5} {2,5}", "****Padding", paddingOffset, info.Padding)); } }
private bool ProcessChild(IDiaSymbol symbol, out CruncherSymbol info) { info = new CruncherSymbol(); if (symbol.isStatic != 0 || (symbol.symTag != (uint)SymTagEnum.SymTagData && symbol.symTag != (uint)SymTagEnum.SymTagBaseClass)) { return(false); } if (symbol.locationType != LocationType.IsThisRel && symbol.locationType != LocationType.IsNull && symbol.locationType != LocationType.IsBitField) { return(false); } ulong len = symbol.length; IDiaSymbol typeSymbol = symbol.type; if (typeSymbol != null) { len = typeSymbol.length; } string symbolName = symbol.name; if (symbol.symTag == (uint)SymTagEnum.SymTagBaseClass) { symbolName = "Base: " + symbolName; } info.Set(symbolName, (typeSymbol != null ? typeSymbol.name : ""), len, symbol.offset); return(true); }
public void ProcessChildren(IDiaSymbol symbol) { IDiaEnumSymbols children; symbol.findChildren(SymTagEnum.SymTagNull, null, 0, out children); foreach (IDiaSymbol child in children) { CruncherSymbol childInfo; if (ProcessChild(child, out childInfo)) { AddChild(childInfo); } } // Sort children by offset, recalc padding. // Sorting is not needed normally (for data fields), but sometimes base class order is wrong. if (HasChildren) { m_children.Sort(CompareOffsets); for (int i = 0; i < m_children.Count; ++i) { CruncherSymbol child = m_children[i]; child.Padding = CalcPadding(child.Offset, i); } Padding = CalcPadding((long)Size, m_children.Count); } }
private void AddChild(CruncherSymbol child) { if (m_children == null) { m_children = new List <CruncherSymbol>(); } m_children.Add(child); }
void ShowSelectedSymbolInfo() { dataGridViewSymbolInfo.Rows.Clear(); CruncherSymbol info = FindSelectedSymbolInfo(); if (info != null) { ShowSymbolInfo(info); } }
private void copyTypeLayoutToClipboardToolStripMenuItem_Click(object sender, EventArgs e) { CruncherSymbol info = FindSelectedSymbolInfo(); if (info != null) { System.IO.StringWriter tw = new System.IO.StringWriter(); m_CruncherData.dumpSymbolInfo(tw, info); Clipboard.SetText(tw.ToString()); } }
private long CalcPadding(long offset, int index) { long padding = 0; if (HasChildren && index > 0) { CruncherSymbol lastInfo = m_children[index - 1]; padding = offset - (lastInfo.Offset + (long)lastInfo.Size); } return(padding > 0 ? padding : 0); }
private void dataGridViewSymbolInfo_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) { if (dataGridViewSymbolInfo.SelectedRows.Count != 0) { DataGridViewRow selectedRow = dataGridViewSymbolInfo.SelectedRows[0]; CruncherSymbol info = selectedRow.Tag as CruncherSymbol; if (info != null && info.TypeName != null) { textBoxFilter.Text = info.TypeName.Replace("*", "[*]"); } } }
void PopulateDataTable(DataTable table, IDiaEnumSymbols symbols, BackgroundWorker LoadingWorker) { int TotalSymbolCount = symbols.count; int CurSymIndex = 0; string msg = String.Format("Loading {0} symbols...", TotalSymbolCount); Console.WriteLine(msg); LoadingWorker?.ReportProgress(0, msg); System.Diagnostics.Stopwatch watch = new Stopwatch(); watch.Start(); table.BeginLoadData(); foreach (IDiaSymbol sym in symbols) { if (sym.length > 0 && !HasSymbol(sym.name)) { CruncherSymbol info = new CruncherSymbol(sym.name, "", sym.length, 0); info.ProcessChildren(sym); long totalPadding = info.CalcTotalPadding(); DataRow row = table.NewRow(); string symbolName = sym.name; row["Symbol"] = symbolName; row["Size"] = info.Size; row["Padding"] = totalPadding; row["Padding/Size"] = (double)totalPadding / info.Size; table.Rows.Add(row); m_SymbolMap.Add(info.Name, info); // Report progress to loading bar int percentProgress = (int)Math.Round((double)(100 * CurSymIndex++) / TotalSymbolCount); percentProgress = Math.Max(Math.Min(percentProgress, 99), 1); LoadingWorker?.ReportProgress(percentProgress, String.Format("Adding symbol {0} of {1}", CurSymIndex, TotalSymbolCount)); } } table.EndLoadData(); watch.Stop(); // Format and display the TimeSpan value. TimeSpan ts = watch.Elapsed; string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10); string CompleteMessage = String.Format("Finished processing {0} symbols in {1}", TotalSymbolCount, elapsedTime); Console.WriteLine(CompleteMessage); LoadingWorker?.ReportProgress(100, CompleteMessage); }
CruncherSymbol FindSelectedSymbolInfo() { if (dataGridSymbols.SelectedRows.Count == 0) { return(null); } DataGridViewRow selectedRow = dataGridSymbols.SelectedRows[0]; string symbolName = selectedRow.Cells[0].Value.ToString(); CruncherSymbol info = m_CruncherData.FindSymbolInfo(symbolName); return(info); }
private static int CompareOffsets(CruncherSymbol x, CruncherSymbol y) { // Base classes have to go first. if (x.IsBase && !y.IsBase) { return(-1); } if (!x.IsBase && y.IsBase) { return(1); } if (x.Offset == y.Offset) { return(x.Size == y.Size ? 0 : (x.Size < y.Size) ? -1 : 1); } else { return((x.Offset < y.Offset) ? -1 : 1); } }
public CruncherReport(string PDBFile, string CSVFile) { m_CruncherData = new CruncherData(null); string result = m_CruncherData.LoadDataFromPdb(PDBFile, null); if (result == null) { System.Console.WriteLine("Something went wrong loading PDB file, see log. Exiting..."); return; } List <Tuple <string, ulong, ulong> > SymbolsToValidate = new List <Tuple <string, ulong, ulong> >(); TextFieldParser parser = new TextFieldParser(CSVFile); parser.Delimiters = new String[] { "," }; while (true) { string[] elements = parser.ReadFields(); if (elements == null) { break; } SymbolsToValidate.Add(new Tuple <string, ulong, ulong>(elements[0], Convert.ToUInt64(elements[1]), Convert.ToUInt64(elements[2]))); } foreach (Tuple <string, ulong, ulong> SymbolToValidate in SymbolsToValidate) { CruncherSymbol Info = m_CruncherData.FindSymbolInfo(SymbolToValidate.Item1); if (Info == null) { System.Console.WriteLine("ERROR: Unable to find symbol '" + SymbolToValidate.Item1 + "' in PDB"); } else { if (Info.Size > SymbolToValidate.Item2) { string Larger = "WARNING: Symbol '" + SymbolToValidate.Item1 + "'was expected to be " + SymbolToValidate.Item2 + " bytes with " + SymbolToValidate.Item3 + " bytes of padding, however it is " + Info.Size + " bytes with " + Info.Padding + " bytes of padding. Inspect symbol to ensure no unneeded size regressions have occurred and update expected symbol size csv as needed."; System.Console.WriteLine(Larger); } else if (Info.Size < SymbolToValidate.Item2) { string Smaller = "Symbol '" + SymbolToValidate.Item1 + "'was expected to be " + SymbolToValidate.Item2 + " bytes with " + SymbolToValidate.Item3 + " bytes of padding, however it is " + Info.Size + " bytes with " + Info.Padding + " bytes of padding. Consider updating symbol size csv as to maintain size savings."; System.Console.WriteLine(Smaller); } } } }
/** Shows the given symbol info on the tables on the right hand side */ void ShowSymbolInfo(CruncherSymbol info) { dataGridViewSymbolInfo.Rows.Clear(); if (!info.HasChildren) { return; } if (bUpdateStack && (UndoStack.Count == 0 || info.Name != UndoStack.Peek())) { RedoStack.Clear(); UndoStack.Push(info.Name); } long cacheLineSize = (long)GetCacheLineSize(); long prevCacheBoundaryOffset = m_prefetchStartOffset; if (prevCacheBoundaryOffset > (long)info.Size) { prevCacheBoundaryOffset = (long)info.Size; } long numCacheLines = 0; InsertCachelineBoundaryRowsDelegate InsertCachelineBoundaryRows = (nextOffset) => { while (nextOffset - prevCacheBoundaryOffset >= cacheLineSize) { numCacheLines = numCacheLines + 1; long cacheLineOffset = numCacheLines * cacheLineSize + m_prefetchStartOffset; string[] boundaryRow = { "Cacheline boundary", cacheLineOffset.ToString(), "" }; dataGridViewSymbolInfo.Rows.Add(boundaryRow); prevCacheBoundaryOffset = cacheLineOffset; } }; foreach (CruncherSymbol child in info.m_children) { if (child.Padding > 0) { long paddingOffset = child.Offset - child.Padding; InsertCachelineBoundaryRows(paddingOffset); string[] paddingRow = { "*Padding*", paddingOffset.ToString(), child.Padding.ToString() }; dataGridViewSymbolInfo.Rows.Add(paddingRow); } InsertCachelineBoundaryRows(child.Offset); string[] row = { child.Name, child.Offset.ToString(), child.Size.ToString() }; dataGridViewSymbolInfo.Rows.Add(row); dataGridViewSymbolInfo.Rows[dataGridViewSymbolInfo.Rows.Count - 1].Tag = child; if (child.TypeName != null && child.TypeName.Length != 0) { dataGridViewSymbolInfo.Rows[dataGridViewSymbolInfo.Rows.Count - 1].Cells[0].ToolTipText = child.TypeName; } } // Final structure padding. if (info.Padding > 0) { long paddingOffset = (long)info.Size - info.Padding; string[] paddingRow = { "*Padding*", paddingOffset.ToString(), info.Padding.ToString() }; dataGridViewSymbolInfo.Rows.Add(paddingRow); } }