From 5099964c673cd45e16d443a3b02f51bade303eee Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 10 May 2014 14:16:27 -0500 Subject: Implement backtraces on Windows. Much !!FUN!! was had --- WinBacktrace.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 WinBacktrace.cpp (limited to 'WinBacktrace.cpp') diff --git a/WinBacktrace.cpp b/WinBacktrace.cpp new file mode 100644 index 00000000..f111cd6f --- /dev/null +++ b/WinBacktrace.cpp @@ -0,0 +1,80 @@ +/* Copyright 2014 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// CAUTION: +// This file contains all manner of hackery and insanity. +// I will not be responsible for any loss of sanity due to reading this code. +// Here be dragons! + +#include "WinBacktrace.h" + +#include + +#ifndef __i386__ +#error WinBacktrace is only supported on x86 architectures. +#endif + + +void dumpInfo(StackFrame* frame, const BYTE* caller, HINSTANCE hInst); + +// We need to do some crazy shit to walk through the stack. +// Windows unwinds the stack when an exception is thrown, so we +// need to examine the EXCEPTION_POINTERS's CONTEXT. +size_t getBacktrace(StackFrame *stack, size_t size, CONTEXT ctx) +{ + // Written using information and a bit of pseudocode from + // http://www.eptacom.net/pubblicazioni/pub_eng/except.html + // This is probably one of the most horrifying things I've ever written. + + // This tracks whether the current EBP is valid. + // When an invalid EBP is encountered, we stop walking the stack. + bool validEBP = true; + DWORD ebp = ctx.Ebp; // The current EBP (Extended Base Pointer) + DWORD eip = ctx.Eip; + int i; + for (i = 0; i < size; i++) + { + if (ebp & 3) + validEBP = false; + // FIXME: This function is obsolete, according to MSDN. + else if (IsBadReadPtr((void*) ebp, 8)) + validEBP = false; + + if (!validEBP) break; + + // Find the caller. + // On the first iteration, the caller is whatever EIP points to. + // On successive iterations, the caller is the byte after EBP. + BYTE* caller = !i ? (BYTE*)eip : *((BYTE**) ebp + 1); + // The first ebp is the EBP from the CONTEXT. + // On successive iterations, the EBP is the DWORD that the previous EBP points to. + ebp = !i ? ebp : *(DWORD*)ebp; + + // Find the caller's module. + // We'll use VirtualQuery to get information about the caller's address. + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery(caller, &mbi, sizeof(mbi)); + + // We can get the instance handle from the allocation base. + HINSTANCE hInst = (HINSTANCE)mbi.AllocationBase; + + // If the handle is 0, then the EBP is invalid. + if (hInst == 0) validEBP = false; + // Otherwise, dump info about the caller. + else stack[i].address = (void*)caller; + } + + return i; +} -- cgit From 4f6cd65c13261bd3562a3adf5891ed4ee4c1cb59 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 10 May 2014 14:19:13 -0500 Subject: Remove unused function --- WinBacktrace.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'WinBacktrace.cpp') diff --git a/WinBacktrace.cpp b/WinBacktrace.cpp index f111cd6f..2c9a3960 100644 --- a/WinBacktrace.cpp +++ b/WinBacktrace.cpp @@ -26,9 +26,6 @@ #error WinBacktrace is only supported on x86 architectures. #endif - -void dumpInfo(StackFrame* frame, const BYTE* caller, HINSTANCE hInst); - // We need to do some crazy shit to walk through the stack. // Windows unwinds the stack when an exception is thrown, so we // need to examine the EXCEPTION_POINTERS's CONTEXT. -- cgit From aefa73ad111578d5c118bd05ee68bff1f2f2119b Mon Sep 17 00:00:00 2001 From: Forkk Date: Sat, 10 May 2014 14:56:44 -0500 Subject: Fix stupid tabs. Thanks, QtCreator... ._. --- WinBacktrace.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'WinBacktrace.cpp') diff --git a/WinBacktrace.cpp b/WinBacktrace.cpp index 2c9a3960..1ea079bf 100644 --- a/WinBacktrace.cpp +++ b/WinBacktrace.cpp @@ -38,7 +38,7 @@ size_t getBacktrace(StackFrame *stack, size_t size, CONTEXT ctx) // This tracks whether the current EBP is valid. // When an invalid EBP is encountered, we stop walking the stack. bool validEBP = true; - DWORD ebp = ctx.Ebp; // The current EBP (Extended Base Pointer) + DWORD ebp = ctx.Ebp; // The current EBP (Extended Base Pointer) DWORD eip = ctx.Eip; int i; for (i = 0; i < size; i++) @@ -57,7 +57,7 @@ size_t getBacktrace(StackFrame *stack, size_t size, CONTEXT ctx) BYTE* caller = !i ? (BYTE*)eip : *((BYTE**) ebp + 1); // The first ebp is the EBP from the CONTEXT. // On successive iterations, the EBP is the DWORD that the previous EBP points to. - ebp = !i ? ebp : *(DWORD*)ebp; + ebp = !i ? ebp : *(DWORD*)ebp; // Find the caller's module. // We'll use VirtualQuery to get information about the caller's address. -- cgit