Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
wdbg.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2010 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * Win32 debug support code.
25  */
26 
27 #include "precompiled.h"
28 #include "lib/debug.h"
29 
30 #include "lib/bits.h"
31 #include "lib/sysdep/os/win/win.h"
33 
34 
35 // return 1 if the pointer appears to be totally bogus, otherwise 0.
36 // this check is not authoritative (the pointer may be "valid" but incorrect)
37 // but can be used to filter out obviously wrong values in a portable manner.
38 int debug_IsPointerBogus(const void* p)
39 {
40  if(p < (void*)0x10000)
41  return true;
42 #if ARCH_AMD64
43  if(p == (const void*)(uintptr_t)0xCCCCCCCCCCCCCCCCull)
44  return true;
45 #elif ARCH_IA32
46  if(p == (const void*)(uintptr_t)0xCCCCCCCCul)
47  return true;
48 #endif
49 
50  // notes:
51  // - we don't check alignment because nothing can be assumed about a
52  // string pointer and we mustn't reject any actually valid pointers.
53  // - nor do we bother checking the address against known stack/heap areas
54  // because that doesn't cover everything (e.g. DLLs, VirtualAlloc).
55  // - cannot use IsBadReadPtr because it accesses the mem
56  // (false alarm for reserved address space).
57 
58  return false;
59 }
60 
61 
62 bool debug_IsCodePointer(void* p)
63 {
64  uintptr_t addr = (uintptr_t)p;
65  // totally invalid pointer
67  return false;
68  // comes before load address
69  static const HMODULE base = GetModuleHandle(0);
70  if(addr < (uintptr_t)base)
71  return false;
72 
73  return true;
74 }
75 
76 
77 bool debug_IsStackPointer(void* p)
78 {
79  uintptr_t addr = (uintptr_t)p;
80  // totally invalid pointer
82  return false;
83  // not aligned
84  if(addr % sizeof(void*))
85  return false;
86  // out of bounds (note: IA-32 stack grows downwards)
87  NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
88  if(!(tib->StackLimit < p && p < tib->StackBase))
89  return false;
90 
91  return true;
92 }
93 
94 
95 void debug_puts(const wchar_t* text)
96 {
97  OutputDebugStringW(text);
98 }
99 
100 
101 void wdbg_printf(const wchar_t* fmt, ...)
102 {
103  wchar_t buf[1024+1]; // wvsprintfW will truncate to this size
104  va_list ap;
105  va_start(ap, fmt);
106  wvsprintfW(buf, fmt, ap); // (return value doesn't indicate whether truncation occurred)
107  va_end(ap);
108 
109  debug_puts(buf);
110 }
111 
112 
113 // inform the debugger of the current thread's description, which it then
114 // displays instead of just the thread handle.
115 //
116 // see "Setting a Thread Name (Unmanaged)": http://msdn2.microsoft.com/en-us/library/xcb2z8hs(vs.71).aspx
117 void debug_SetThreadName(const char* name)
118 {
119  // we pass information to the debugger via a special exception it
120  // swallows. if not running under one, bail now to avoid
121  // "first chance exception" warnings.
122  if(!IsDebuggerPresent())
123  return;
124 
125  // presented by Jay Bazuzi (from the VC debugger team) at TechEd 1999.
126  const struct ThreadNameInfo
127  {
128  DWORD type;
129  const char* name;
130  DWORD thread_id; // any valid ID or -1 for current thread
131  DWORD flags;
132  }
133  info = { 0x1000, name, (DWORD)-1, 0 };
134  __try
135  {
136  RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info);
137  }
138  __except(EXCEPTION_EXECUTE_HANDLER)
139  {
140  // if we get here, the debugger didn't handle the exception.
141  // this happens if profiling with Dependency Walker; ENSURE
142  // must not be called because we may be in critical init.
143  }
144 }
LIB_API void debug_puts(const wchar_t *text)
[system-dependent] write a string to the debug channel.
Definition: udbg.cpp:106
LIB_API bool debug_IsCodePointer(void *p)
does the given pointer appear to point to code?
Definition: wdbg.cpp:62
LIB_API void debug_SetThreadName(const char *name)
inform the debugger of the current thread&#39;s name.
Definition: bdbg.cpp:126
LIB_API int debug_IsPointerBogus(const void *p)
check if a pointer appears to be totally invalid.
Definition: udbg.cpp:114
LIB_API bool debug_IsStackPointer(void *p)
does the given pointer appear to point to the stack?
Definition: wdbg.cpp:77
unsigned long DWORD
Definition: wgl.h:56
void wdbg_printf(const wchar_t *fmt,...)
same as debug_printf except that some type conversions aren&#39;t supported (in particular, no floating point) and output is limited to 1024+1 characters.
Definition: wdbg.cpp:101