Files
UnrealEngineUWP/Engine/Source/Programs/CrashReport/AutoReporter/Form1.cs
Ben Marsh 149375b14b Update copyright notices to 2015.
[CL 2379638 by Ben Marsh in Main branch]
2014-12-07 19:09:38 -05:00

467 lines
20 KiB
C#

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace AutoReporter
{
public partial class Form1 : Form
{
static public string unknown = "Unknown";
static public string newLine = "\r\n";
static public string seperator = " | ";
public struct CSData
{
public string function;
public string address;
public string filename;
public string filenameSml;
public string line;
public string module;
public string moduleSml;
public string GetCallStack(bool bFunctions, bool bAddresses, bool bFiles, bool bModules, bool bShortnames, bool bUnknowns)
{
string callStack = "";
string callStackLine = "";
if (bFunctions && (bUnknowns || function != unknown))
{
callStackLine += function + seperator;
}
if (bAddresses && (bUnknowns || address != unknown))
{
callStackLine += address + seperator;
}
if (bFiles)
{
int iPreLen = callStackLine.Length;
if (!bShortnames && (bUnknowns || filename != unknown))
{
callStackLine += filename;
}
else if (bUnknowns || filenameSml != unknown)
{
callStackLine += filenameSml;
}
if (bUnknowns || line != unknown)
{
callStackLine += ":L" + line;
}
if (iPreLen != callStackLine.Length)
{
callStackLine += seperator;
}
}
if (bModules)
{
int iPreLen = callStackLine.Length;
if (!bShortnames && (bUnknowns || module != unknown))
{
callStackLine += module;
}
else if (bUnknowns || moduleSml != unknown)
{
callStackLine += moduleSml;
}
if (iPreLen != callStackLine.Length)
{
callStackLine += seperator;
}
}
if (callStackLine.Length > 0)
{
// Remove the end seperator
callStackLine = callStackLine.Substring(0, callStackLine.Length - seperator.Length);
callStack += callStackLine + newLine;
}
return callStack;
}
}
public string summary;
public string crashDesc;
public string assertOri; // The original crash
public CSData assertData; // The extracted crash components
public string callStackOri; // The original callstack
public List<CSData> callStackData; // The extracted callstack components
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
crashDesc = textBox1.Text;
summary = textBox2.Text;
Close();
}
private void checkbox_Click(object sender, EventArgs e)
{
textBox3.Text = GetCallStack(); // Update the text box based on the users setting
}
private void form1_Resize(object sender, System.EventArgs e)
{
textBox1.Width = Width - ((textBox1.Location.X * 2) + (8 * 2)); // 8 is windows border
textBox2.Width = Width - ((textBox2.Location.X * 2) + (8 * 2)); // 8 is windows border
textBox3.Width = Width - ((textBox3.Location.X * 2) + (8 * 2)); // 8 is windows border
textBox3.Height = MainPanel.Height - textBox3.Location.Y - ButtonPanel.Height;
}
public string GetCallStack()
{
string callStack = "";
// Now append out callstack data depending on the users button choice
bool bOriginal = checkbox7.Checked;
if (bOriginal)
{
callStack += callStackOri; // Just show the original layout
}
else
{
// If invalid callstack type, just display as normal
if (callStackData == null)
{
callStack += callStackOri;
}
else
{
// Try to show a simplified crash, if we have it
string assert = "";
if (assertData.address != null)
{
if (assertData.module != null)
{
assert += assertData.module + newLine;
}
if (assertData.function != null)
{
assert += assertData.function + seperator;
}
assert += assertData.address + newLine + newLine;
}
else if (assertOri != null)
{
assert = assertOri + newLine;
}
callStack += assert;
// How add each line depending on the users settings
bool bFunctions = checkbox1.Checked;
bool bAddresses = checkbox2.Checked;
bool bFiles = checkbox3.Checked;
bool bModules = checkbox4.Checked;
bool bShortnames = checkbox5.Checked;
bool bUnknowns = checkbox6.Checked;
foreach (CSData csdata in callStackData)
{
callStack += csdata.GetCallStack(bFunctions, bAddresses, bFiles, bModules, bShortnames, bUnknowns);
}
}
}
return callStack;
}
public void SetCallStack(string CallStack)
{
callStackOri = CallStack; // Cache the original callstack
GenerateMinCallStack(); // Generate a minimalist callstack display
textBox3.Text = GetCallStack(); // Update the text box based on the users setting
// Resize based on the new text length (only do this once tho, now we can resize correctly)
int NewLabelHeight = textBox3.Lines.Length * 15;// (CallStack.Length / 80) * 15;
NewLabelHeight = System.Math.Max(textBox3.Height, NewLabelHeight);
NewLabelHeight = System.Math.Min(textBox3.Height + 300, NewLabelHeight);
int LabelHeightIncrease = NewLabelHeight - textBox3.Height;
Height += LabelHeightIncrease;
}
public bool GenerateMinCallStack()
{
// Take a copy of the callstack, we don't want to overwrite it
string callStackCpy = callStackOri;
// If this string is not empty
if (callStackCpy.Length > 0)
{
const string file = "[File:";
const string line = "[Line: ";
const string rightBracket = "]";
const string slash = "\\";
const string space = " ";
// There are two different types of header information the callstack file could have, attempt to resolve both...
const string fatalError = "Fatal error!\r\n\r\n";
int iFatalError = callStackCpy.IndexOf( fatalError );
if (iFatalError != -1)
{
// Trim the excess header
int iHeaderLength = iFatalError + fatalError.Length;
callStackCpy = callStackCpy.Remove(0, iHeaderLength);
}
else
{
// If the first should fail, try to find the second...
const string stack = "Stack: ";
int iStack = callStackCpy.IndexOf( stack );
if (iStack != -1)
{
// Remove everything before (but keep the ensure error if it has one)
const string assertFailed = "Assertion failed: ";
int iassertFailed = callStackCpy.IndexOf( assertFailed );
if ((iassertFailed != -1) && (iassertFailed < iStack))
{
// Extract the crash
int iassertOffset = iassertFailed + assertFailed.Length;
int iassertLength = iStack - iassertOffset;
assertOri = callStackCpy.Substring(iassertOffset, iassertLength);
// Try the tidy the crash somewhat too
int iNewLine = assertOri.IndexOf(newLine);
if (iNewLine != -1)
{
int iNewLineOffset = iNewLine + newLine.Length;
int iNewLineLength = assertOri.Length - iNewLineOffset - newLine.Length;
if (iNewLineLength > 0)
{
assertData.module = assertOri.Substring(iNewLineOffset, iNewLineLength);
}
}
int iLine = assertOri.IndexOf(line);
if (iLine != -1)
{
int iLineOffset = iLine + line.Length;
string assertLineTmp = assertOri.Substring(iLineOffset);
int iRightBracket = assertLineTmp.IndexOf(rightBracket);
if (iRightBracket != -1)
{
assertData.line = assertLineTmp.Substring(0, iRightBracket);
}
}
int iFile = assertOri.IndexOf(file);
if (iFile != -1)
{
int iFileOffset = iFile + file.Length;
string assertFileTmp = assertOri.Substring(iFileOffset);
int iRightBracket2 = assertFileTmp.IndexOf(rightBracket);
if (iRightBracket2 != -1)
{
assertData.filename = assertFileTmp.Substring(0, iRightBracket2);
// Do a minimal version of the filename too
assertData.filenameSml = assertData.filename;
int iSlash = assertData.filenameSml.LastIndexOf(slash);
if (iSlash != -1)
{
int iSlashOffset = iSlash + slash.Length;
assertData.filenameSml = assertData.filenameSml.Substring(iSlashOffset);
}
}
assertData.address = assertOri.Substring(0, iFile - space.Length); // Remove trailing space too
}
}
// Trim the excess header
int iHeaderLength = iStack + stack.Length;
callStackCpy = callStackCpy.Remove(0, iHeaderLength);
}
else
{
// Unhandled header type
return false;
}
}
// Now the header has been removed, separate the component data
const string parentheses = "() ";
const string hex = "0x";
const string bytes = " bytes ";
const string filenameNotFound = " (filename not found) ";
const string colon = ":";
const string in_ = "[in ";
// Allocate our array to hold the data
if (callStackData == null)
{
callStackData = new List<CSData>();
}
callStackData.Clear();
// Now loop through all the callstack lines
int iNewLine2 = -1;
bool bAddToCS = false;
string lastcsdatafunction = "";
while (( ( iNewLine2 = callStackCpy.IndexOf(newLine) ) != -1 ))
{
// Grab the top line of the callstack
CSData csdata;
string csline = callStackCpy.Substring(0, iNewLine2);
int iNewLineOffset = iNewLine2 + newLine.Length;
callStackCpy = callStackCpy.Remove(0, iNewLineOffset);
// Try to extract the function name (if any)
csdata.function = unknown;
int iParentheses = csline.IndexOf(parentheses);
if (iParentheses != -1)
{
csdata.function = csline.Substring(0, iParentheses);
int iParenthesesOffset = iParentheses + parentheses.Length;
csline = csline.Remove(0, iParenthesesOffset);
}
// Try to extract the address (could be one of two formats)
csdata.address = unknown;
int iHex = csline.IndexOf(hex);
if (iHex != -1)
{
int iBytes = csline.IndexOf(bytes);
if (iBytes != -1)
{
// Chop to bytes
int iBytesOffset = iBytes + bytes.Length;
csdata.address = csline.Substring(iHex, iBytesOffset - space.Length); // Remove trailing space too
csline = csline.Remove(0, iHex + iBytesOffset);
}
else
{
int iSpace = csline.IndexOf(space);
if (iSpace != -1)
{
// Chop to space
int iSpaceOffset = iSpace + space.Length + 1;
csdata.address = csline.Substring(iHex, iSpaceOffset);
csline = csline.Remove(0, iHex + iSpaceOffset + space.Length); // Remove trailing space too
}
}
}
// Try to extract the filename (if any)
csdata.filename = unknown;
csdata.filenameSml = unknown;
csdata.line = unknown;
int iFilenameNotFound = csline.IndexOf(filenameNotFound);
if (iFilenameNotFound != -1)
{
int iFilenameNotFoundOffset = iFilenameNotFound + filenameNotFound.Length;
csline = csline.Remove(0, iFilenameNotFoundOffset);
}
else
{
int iRightBracket = csline.IndexOf(rightBracket);
if (iRightBracket != -1)
{
csdata.filename = csline.Substring(file.Length, iRightBracket - file.Length); // Remove "[File:" too
int iRightBracketOffset = iRightBracket + rightBracket.Length;
csline = csline.Remove(0, iRightBracketOffset + space.Length); // Remove trailing space too
// Try to extract the line number
int iColon = csdata.filename.LastIndexOf(colon);
if (iColon != -1)
{
int iColonOffset = iColon + colon.Length;
csdata.line = csdata.filename.Substring(iColonOffset);
csdata.filename = csdata.filename.Remove(iColon);
}
// Do a minimal version of the filename too
csdata.filenameSml = csdata.filename;
int iSlash = csdata.filenameSml.LastIndexOf(slash);
if (iSlash != -1)
{
int iSlashOffset = iSlash + slash.Length;
csdata.filenameSml = csdata.filenameSml.Substring(iSlashOffset);
}
}
}
// Try to get the module
csdata.module = unknown;
csdata.moduleSml = unknown;
int iRightBracket2 = csline.IndexOf(rightBracket);
if (iRightBracket2 != -1)
{
csdata.module = csline.Substring(in_.Length, iRightBracket2 - in_.Length); // Remove "[in " too
int iRightBracketOffset = iRightBracket2 + rightBracket.Length;
csline = csline.Remove(0, iRightBracketOffset);
// Do a minimal version of the module too
csdata.moduleSml = csdata.module;
int iSlash = csdata.moduleSml.LastIndexOf(slash);
if (iSlash != -1)
{
int iSlashOffset = iSlash + slash.Length;
csdata.moduleSml = csdata.moduleSml.Substring(iSlashOffset);
}
}
// Add this info to our array (skip any lines we don't need that may have occurred after the crash)
if (!bAddToCS && assertData.line != null && assertData.filename != null)
{
if ( ( string.Compare( csdata.line, assertData.line, true ) == 0 )
&& ( string.Compare( csdata.filename, assertData.filename, true ) == 0 ) )
{
if (lastcsdatafunction.Length > 0)
{
assertData.function = lastcsdatafunction; // The previous callstack's function is the crash function type
}
bAddToCS = true;
}
}
else
{
bAddToCS = true; // Incase we don't have crash information
}
if ( bAddToCS )
{
callStackData.Add(csdata);
}
lastcsdatafunction = csdata.function;
}
}
return true;
}
public void SetServiceError(string ErrorMsg)
{
textBox1.Visible = false;
label4.Visible = false;
textBox2.Visible = false;
label1.Text = "An error occurred connecting to the Report Service: \n" + ErrorMsg;
label1.Height += 20;
}
public void ShowBalloon( string Msg, int BalloonTimeInMs )
{
AppErrorNotifyInfo.BalloonTipText = Msg;
AppErrorNotifyInfo.Visible = true;
AppErrorNotifyInfo.ShowBalloonTip( BalloonTimeInMs );
}
public void HideBalloon()
{
AppErrorNotifyInfo.Visible = false;
}
}
}