Browse Source

Fixed stack trace so it works on other machines
Minidump is now created on a separate thread in order to preserve the call stack of the crashed thread

BearishSun 10 years ago
parent
commit
97382096d8

+ 0 - 1
BansheeCore/Include/BsSceneObject.h

@@ -5,7 +5,6 @@
 #include "BsVector3.h"
 #include "BsQuaternion.h"
 #include "BsRTTIType.h"
-#include "BsCoreSceneManager.h"
 #include "BsGameObjectManager.h"
 #include "BsGameObject.h"
 #include "BsComponent.h"

+ 1 - 0
BansheeCore/Include/BsSceneObjectRTTI.h

@@ -6,6 +6,7 @@
 #include "BsGameObjectHandle.h"
 #include "BsGameObjectManager.h"
 #include "BsComponent.h"
+#include "BsPrefabDiff.h"
 
 namespace BansheeEngine
 {

+ 0 - 2
BansheeCore/Source/BsSceneObject.cpp

@@ -6,9 +6,7 @@
 #include "BsSceneObjectRTTI.h"
 #include "BsMemorySerializer.h"
 #include "BsGameObjectManager.h"
-#include "BsPrefab.h"
 #include "BsPrefabUtility.h"
-#include "BsPrefabDiff.h"
 #include "BsMatrix3.h"
 
 namespace BansheeEngine

+ 11 - 5
BansheeEditor/Source/BsEditorApplication.cpp

@@ -22,12 +22,14 @@
 #include "BsProjectSettings.h"
 #include "BsEditorSettings.h"
 #include "BsScriptManager.h"
-#include "BsFileSystem.h"
+#include "BsImporter.h"
+#include "BsVirtualInput.h"
+#include "BsResources.h"
+#include "BsCoreSceneManager.h"
 
 // DEBUG ONLY
-#include "BsResources.h"
+#include "BsFileSystem.h"
 #include "BsSceneObject.h"
-#include "BsImporter.h"
 #include "BsGpuProgram.h"
 #include "BsShader.h"
 #include "BsTexture.h"
@@ -35,7 +37,6 @@
 #include "BsTechnique.h"
 #include "BsPass.h"
 #include "BsCRenderable.h"
-#include "BsVirtualInput.h"
 #include "BsFolderMonitor.h"
 #include "BsCCamera.h"
 #include "BsCGUIWidget.h"
@@ -76,6 +77,7 @@ namespace BansheeEngine
 
 	EditorApplication::~EditorApplication()
 	{
+#if BS_DEBUG
 		/************************************************************************/
 		/* 								DEBUG CODE                      		*/
 		/************************************************************************/
@@ -93,6 +95,7 @@ namespace BansheeEngine
 		/************************************************************************/
 		/* 							END DEBUG CODE                      		*/
 		/************************************************************************/
+#endif
 
 		ProjectLibrary::shutDown();
 		BuiltinEditorResources::shutDown();
@@ -145,10 +148,12 @@ namespace BansheeEngine
 		MainEditorWindow* mainWindow = MainEditorWindow::create(getPrimaryWindow());
 		ScriptManager::instance().initialize();
 
+		BS_EXCEPT(InternalErrorException, "Forced crash");
+		
+#if BS_DEBUG
 		/************************************************************************/
 		/* 								DEBUG CODE                      		*/
 		/************************************************************************/
-
 		HShader dummyParsedShader = Importer::instance().import<Shader>(RUNTIME_DATA_PATH + "Raw\\Engine\\Shaders\\TestFX.bsl");
 		assert(dummyParsedShader != nullptr); // Ad hoc unit test
 
@@ -203,6 +208,7 @@ namespace BansheeEngine
 		/************************************************************************/
 		/* 							END DEBUG CODE                      		*/
 		/************************************************************************/
+#endif
 	}
 
 	void EditorApplication::onShutDown()

+ 61 - 8
BansheeUtility/Source/Win32/BsWin32CrashHandler.cpp

@@ -199,10 +199,13 @@ namespace BansheeEngine
 		options |= SYMOPT_UNDNAME;
 		options |= SYMOPT_FAIL_CRITICAL_ERRORS;
 		options |= SYMOPT_NO_PROMPTS;
-		options |= SYMOPT_DEFERRED_LOADS;
 
 		SymSetOptions(options);
-		SymInitialize(hProcess, nullptr, true);
+		if(!SymInitialize(hProcess, nullptr, false))
+		{
+			LOGERR("SymInitialize failed. Error code: " + toString((UINT32)GetLastError()));
+			return;
+		}
 
 		DWORD bufferSize;
 		gEnumProcessModules(hProcess, nullptr, 0, &bufferSize);
@@ -223,11 +226,39 @@ namespace BansheeEngine
 			gGetModuleBaseName(hProcess, modules[i], moduleName, BS_MAX_STACKTRACE_NAME_BYTES);
 
 			char pdbSearchPath[BS_MAX_STACKTRACE_NAME_BYTES];
-			GetFullPathNameA(imageName, BS_MAX_STACKTRACE_NAME_BYTES, pdbSearchPath, nullptr);
+			char* fileName = nullptr;
+			GetFullPathNameA(moduleName, BS_MAX_STACKTRACE_NAME_BYTES, pdbSearchPath, &fileName);
+			*fileName = '\0';
+
 			SymSetSearchPath(GetCurrentProcess(), pdbSearchPath);
 
-			SymLoadModule64(hProcess, modules[i], imageName, moduleName, (DWORD64)moduleInfo.lpBaseOfDll,
+			DWORD64 moduleAddress = SymLoadModule64(hProcess, modules[i], imageName, moduleName, (DWORD64)moduleInfo.lpBaseOfDll,
 				(DWORD)moduleInfo.SizeOfImage);
+
+			if (moduleAddress != 0)
+			{
+				IMAGEHLP_MODULE64 imageInfo;
+				memset(&imageInfo, 0, sizeof(imageInfo));
+				imageInfo.SizeOfStruct = sizeof(imageInfo);
+
+				if(!SymGetModuleInfo64(GetCurrentProcess(), moduleAddress, &imageInfo))
+				{
+					LOGWRN("Failed retrieving module info for module: " + String(moduleName) + ". Error code: " + toString((UINT32)GetLastError()));
+				}
+				else
+				{
+					// Disabled because too much spam in the log, enable as needed
+#if 0
+					if (imageInfo.SymType == SymNone)
+						LOGWRN("Failed loading symbols for module: " + String(moduleName));
+#endif
+				}
+			}
+			else
+			{
+				LOGWRN("Failed loading module " + String(moduleName) + ".Error code: " + toString((UINT32)GetLastError()) +
+					". Search path: " + String(pdbSearchPath) + ". Image name: " + String(imageName));
+			}
 		}
 
 		bs_free(modules);
@@ -362,9 +393,17 @@ namespace BansheeEngine
 		}
 	}
 
-	void win32_writeMiniDump(const Path& filePath, EXCEPTION_POINTERS* exceptionData)
+	struct MiniDumpParams
 	{
-		HANDLE hFile = CreateFileW(filePath.toWString().c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 
+		Path filePath;
+		EXCEPTION_POINTERS* exceptionData;
+	};
+
+	DWORD CALLBACK win32_writeMiniDumpWorker(void* data)
+	{
+		MiniDumpParams* params = (MiniDumpParams*)data;
+
+		HANDLE hFile = CreateFileW(params->filePath.toWString().c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
 			FILE_ATTRIBUTE_NORMAL, nullptr);
 
 		if (hFile != INVALID_HANDLE_VALUE)
@@ -372,13 +411,27 @@ namespace BansheeEngine
 			MINIDUMP_EXCEPTION_INFORMATION DumpExceptionInfo;
 
 			DumpExceptionInfo.ThreadId = GetCurrentThreadId();
-			DumpExceptionInfo.ExceptionPointers = exceptionData;
+			DumpExceptionInfo.ExceptionPointers = params->exceptionData;
 			DumpExceptionInfo.ClientPointers = false;
 
-			MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, 
+			MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal,
 				&DumpExceptionInfo, nullptr, nullptr);
 			CloseHandle(hFile);
 		}
+
+		return 0;
+	}
+
+	void win32_writeMiniDump(const Path& filePath, EXCEPTION_POINTERS* exceptionData)
+	{
+		MiniDumpParams param = { filePath, exceptionData };
+
+		// Write minidump on a second thread in order to preserve the current thread's call stack
+		DWORD threadId = 0;
+		HANDLE hThread = CreateThread(nullptr, 0, &win32_writeMiniDumpWorker, &param, 0, &threadId);
+
+		WaitForSingleObject(hThread, INFINITE);
+		CloseHandle(hThread);
 	}
 
 	static const wchar_t* gMiniDumpName = L"minidump.dmp";

+ 2 - 2
BansheeUtility/Source/Win32/BsWin32FileSystem.cpp

@@ -49,7 +49,7 @@ namespace BansheeEngine
 		case ERROR_NEGATIVE_SEEK:
 			BS_EXCEPT(IOException, "Negative seek.");
 		default:
-			BS_EXCEPT(IOException, "Undefined file system exception.");
+			BS_EXCEPT(IOException, "Undefined file system exception: " + toString((UINT32)error));
 		}
 	}
 
@@ -469,7 +469,7 @@ namespace BansheeEngine
 	void FileSystem::createDir(const Path& fullPath)
 	{
 		Path parentPath = fullPath;
-		while (!exists(parentPath))
+		while (!exists(parentPath) && parentPath.getNumDirectories() > 0)
 		{
 			parentPath = parentPath.getParent();
 		}

+ 0 - 16
TODO.txt

@@ -16,19 +16,6 @@ return them in checkForModifications?
 ---------------------------------------------------------------------
 Prefab diff
 
-Add "dirty object" system to C#. Each ScriptResource and ScriptGameObject should have a dirty flag.
- - It should be toggle-able via EditorUtility.SetDirty or similar. (Possibly make this part of ProjectLibrary)
- - There should also be a method to check if something is dirty via EditorUtility.IsDirty or similar. (Possibly make this part of ProjectLibrary)
-  - Hook this up to Scene.IsModified because it is currently not implemented (Might need to keep a link to active Prefab in scene to do this)
- - Add a "Save Project" button that automatically saves all dirty assets. Do this automatically when user quits the editor.
- - Call SetDirty manually whenever:
-  - A new object or component is added to the scene
-  - An object or component is removed from the scene
-  - An object is reparented
-  - When component or resource is modified from inspector
- - Record all portions where objects & components get modified so I can mark them dirty, will likely need
-    to use those some points for undo/redo
-
  Test (likely later once I have more editor functionality working):
   - Game object handle compare
   - ID restore systems 
@@ -38,7 +25,6 @@ Add "dirty object" system to C#. Each ScriptResource and ScriptGameObject should
 Polish
 
 Ribek use:
- - When I'm directly editing a resource like material, I need to save it after editing is done. Use the "dirty" system for that?
  - Hook up color picker to guicolor field
 
 Other polish:
@@ -54,8 +40,6 @@ Other polish:
     - Will need a way to retrieve the full property name, up to the parent Component/Resource
 	- Will need to extend inspectable fields so they know their parent inspector so they have access to the dictionar
    - Custom inspectors can get rid of manual "isExpanded" bools and use the dictionary instead
- - Need a proper way to detect when the scene was modified
-  - Display modifications in the status bar (scene modified, and also project modified).
 
 Stage 2 polish:
  - Prefabs