0ad/source/lib/sysdep/os/win/wdbg.cpp
janwas 4663ac0fe7 split debug_assert into ENSURE and ASSERT as discussed in a previous meeting.
the old debug_assert always ran and tested the expression, which slows
down release builds. wrapping them in #ifndef NDEBUG is clumsy. the new
ASSERT behaves like assert and ENSURE like the old debug_assert. Let's
change any time-critical but not-super-important ENSURE to ASSERT to
speed up release builds. (already done in bits.h and unique_range.h)

This was SVN commit r9362.
2011-04-30 13:01:45 +00:00

144 lines
4.2 KiB
C++

/* Copyright (c) 2010 Wildfire Games
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* Win32 debug support code.
*/
#include "precompiled.h"
#include "lib/debug.h"
#include "lib/bits.h"
#include "lib/sysdep/os/win/win.h"
#include "lib/sysdep/os/win/wutil.h"
// return 1 if the pointer appears to be totally bogus, otherwise 0.
// this check is not authoritative (the pointer may be "valid" but incorrect)
// but can be used to filter out obviously wrong values in a portable manner.
int debug_IsPointerBogus(const void* p)
{
if(p < (void*)0x10000)
return true;
#if ARCH_AMD64
if(p == (const void*)(uintptr_t)0xCCCCCCCCCCCCCCCCull)
return true;
#elif ARCH_IA32
if(p == (const void*)(uintptr_t)0xCCCCCCCCul)
return true;
#endif
// notes:
// - we don't check alignment because nothing can be assumed about a
// string pointer and we mustn't reject any actually valid pointers.
// - nor do we bother checking the address against known stack/heap areas
// because that doesn't cover everything (e.g. DLLs, VirtualAlloc).
// - cannot use IsBadReadPtr because it accesses the mem
// (false alarm for reserved address space).
return false;
}
bool debug_IsCodePointer(void* p)
{
uintptr_t addr = (uintptr_t)p;
// totally invalid pointer
if(debug_IsPointerBogus(p))
return false;
// comes before load address
static const HMODULE base = GetModuleHandle(0);
if(addr < (uintptr_t)base)
return false;
return true;
}
bool debug_IsStackPointer(void* p)
{
uintptr_t addr = (uintptr_t)p;
// totally invalid pointer
if(debug_IsPointerBogus(p))
return false;
// not aligned
if(addr % sizeof(void*))
return false;
// out of bounds (note: IA-32 stack grows downwards)
NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
if(!(tib->StackLimit < p && p < tib->StackBase))
return false;
return true;
}
void debug_puts(const wchar_t* text)
{
OutputDebugStringW(text);
}
void wdbg_printf(const wchar_t* fmt, ...)
{
wchar_t buf[1024+1]; // wvsprintfW will truncate to this size
va_list ap;
va_start(ap, fmt);
wvsprintfW(buf, fmt, ap); // (return value doesn't indicate whether truncation occurred)
va_end(ap);
debug_puts(buf);
}
// inform the debugger of the current thread's description, which it then
// displays instead of just the thread handle.
//
// see "Setting a Thread Name (Unmanaged)": http://msdn2.microsoft.com/en-us/library/xcb2z8hs(vs.71).aspx
void debug_SetThreadName(const char* name)
{
// we pass information to the debugger via a special exception it
// swallows. if not running under one, bail now to avoid
// "first chance exception" warnings.
if(!IsDebuggerPresent())
return;
// presented by Jay Bazuzi (from the VC debugger team) at TechEd 1999.
const struct ThreadNameInfo
{
DWORD type;
const char* name;
DWORD thread_id; // any valid ID or -1 for current thread
DWORD flags;
}
info = { 0x1000, name, (DWORD)-1, 0 };
__try
{
RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
// if we get here, the debugger didn't handle the exception.
// this happens if profiling with Dependency Walker; ENSURE
// must not be called because we may be in critical init.
}
}