From 9269be9ee332b44a06d59bdff451632f97a95dde Mon Sep 17 00:00:00 2001 From: janwas Date: Sat, 19 Jan 2008 11:33:11 +0000 Subject: [PATCH] remove mmgr and macros that redefine malloc/new/free (see http://www.wildfiregames.com/forum/index.php?showtopic=11450&hl= ) clean up debug module . no longer include platform-dependent header (-> less rebuilds) . DISPLAY_ERROR -> DEBUG_DISPLAY_ERROR . parts of config.h that don't affect all files moved to config.2 (-> fewer full rebuilds) . remove creaky symbol cache (no longer needed for mmgr) . remove TLS thread naming stuff (can use debugger's thread window instead; no need for platform independence there) wdbg: remove thread suspension and breakpoint APIs (not needed) acpi: fix: u64 -> uintptr_t wutil: fix WinScopedLock, use that instead of direct lock() functions misc: . get rid of SAFE_STRCPY, replace with strcpy_s . remove _getcwd (shouldn't be used) This was SVN commit r5563. --- source/gui/GUIutil.cpp | 2 +- source/lib/allocators/allocators.h | 13 +- source/lib/allocators/headerless.cpp | 2 - source/lib/config.h | 101 ++---- source/lib/config2.h | 64 ++++ source/lib/debug.cpp | 286 +-------------- source/lib/debug.h | 188 ++-------- source/lib/debug_stl.cpp | 2 - source/lib/external_libraries/sdl.h | 3 +- source/lib/file/common/trace.cpp | 1 - source/lib/file/io/block_cache.cpp | 5 +- source/lib/file/io/block_cache.h | 2 +- source/lib/file/vfs/file_cache.h | 2 +- source/lib/mmgr.cpp | 3 + source/lib/mmgr.h | 4 + source/lib/precompiled.h | 27 +- source/lib/res/graphics/ogl_tex.cpp | 4 +- source/lib/res/h_mgr.cpp | 4 - source/lib/self_test.h | 2 +- source/lib/sysdep/acpi.cpp | 6 +- source/lib/sysdep/ia32/ia32.cpp | 23 +- source/lib/sysdep/ia32/ia32.h | 3 +- source/lib/sysdep/unix/udbg.cpp | 2 +- source/lib/sysdep/unix/udbg.h | 4 - source/lib/sysdep/win/tests/test_wdbg_sym.h | 2 +- source/lib/sysdep/win/wdbg.cpp | 330 ++---------------- source/lib/sysdep/win/wdbg.h | 23 -- source/lib/sysdep/win/wdbg_sym.cpp | 120 +++---- source/lib/sysdep/win/wdir_watch.cpp | 2 - source/lib/sysdep/win/wdll_delay_load.cpp | 6 - source/lib/sysdep/win/whrt/counter.cpp | 4 - source/lib/sysdep/win/wposix/crt_posix.h | 2 +- source/lib/sysdep/win/wposix/waio.cpp | 6 +- source/lib/sysdep/win/wposix/wposix.cpp | 15 - source/lib/sysdep/win/wposix/wposix.h | 2 - source/lib/sysdep/win/wposix/wpthread.cpp | 5 +- source/lib/sysdep/win/wsdl.cpp | 4 +- source/lib/sysdep/win/wseh.cpp | 6 +- source/lib/sysdep/win/wseh.h | 3 +- source/lib/sysdep/win/wutil.cpp | 54 ++- source/lib/sysdep/win/wutil.h | 40 +-- source/lib/timer.cpp | 7 +- source/main.cpp | 2 +- source/ps/GameSetup/Atlas.cpp | 6 +- source/ps/GameSetup/GameSetup.cpp | 11 +- source/ps/XML/XML.h | 5 - source/ps/XML/XMLUtils.cpp | 4 - source/ps/XML/XercesErrorHandler.cpp | 1 - source/renderer/Renderer.cpp | 2 +- source/scripting/ScriptableComplex.inl | 6 - source/tools/atlas/GameInterface/Shareable.h | 21 +- .../tools/atlas/GameInterface/SharedMemory.h | 33 +- 52 files changed, 301 insertions(+), 1174 deletions(-) create mode 100644 source/lib/config2.h delete mode 100644 source/lib/sysdep/win/wdbg.h diff --git a/source/gui/GUIutil.cpp b/source/gui/GUIutil.cpp index 1b3cb3d350..a3faf4c5f6 100644 --- a/source/gui/GUIutil.cpp +++ b/source/gui/GUIutil.cpp @@ -279,7 +279,7 @@ void CInternalCGUIAccessorBase::HandleMessage(IGUIObject *pObject, const SGUIMes { \ /* Abort now, to avoid corrupting everything by invalidly \ casting pointers */ \ - DISPLAY_ERROR(L"FATAL ERROR: Inconsistent types in GUI"); \ + DEBUG_DISPLAY_ERROR(L"FATAL ERROR: Inconsistent types in GUI"); \ } \ } #include "GUItypes.h" diff --git a/source/lib/allocators/allocators.h b/source/lib/allocators/allocators.h index 0bf8dcc732..a911ad16ad 100644 --- a/source/lib/allocators/allocators.h +++ b/source/lib/allocators/allocators.h @@ -13,6 +13,7 @@ #include +#include "lib/config2.h" // CONFIG2_ALLOCATORS_OVERRUN_PROTECTION #include "lib/posix/posix_mman.h" // PROT_* #include "lib/sysdep/cpu.h" // cpu_CAS @@ -215,7 +216,7 @@ notify us when done; memory access permission is temporarily granted. (similar in principle to Software Transaction Memory). since this is quite slow, the protection is disabled unless -CONFIG_OVERRUN_PROTECTION == 1; this avoids having to remove the +CONFIG2_ALLOCATORS_OVERRUN_PROTECTION == 1; this avoids having to remove the wrapper code in release builds and re-write when looking for overruns. example usage: @@ -228,9 +229,6 @@ doSomethingWith(yc); // read/write access your_class_wrapper.lock(); // disallow further access until next .get() .. **/ -#ifdef REDEFINED_NEW -# include "lib/nommgr.h" -#endif template class OverrunProtector { public: @@ -257,7 +255,7 @@ public: void lock() { -#if CONFIG_OVERRUN_PROTECTION +#if CONFIG2_ALLOCATORS_OVERRUN_PROTECTION mprotect(object, sizeof(T), PROT_NONE); #endif } @@ -265,16 +263,13 @@ public: private: void unlock() { -#if CONFIG_OVERRUN_PROTECTION +#if CONFIG2_ALLOCATORS_OVERRUN_PROTECTION mprotect(object, sizeof(T), PROT_READ|PROT_WRITE); #endif } T* object; }; -#ifdef REDEFINED_NEW -# include "lib/mmgr.h" -#endif //----------------------------------------------------------------------------- diff --git a/source/lib/allocators/headerless.cpp b/source/lib/allocators/headerless.cpp index d67a38a701..b2dcf1ad12 100644 --- a/source/lib/allocators/headerless.cpp +++ b/source/lib/allocators/headerless.cpp @@ -388,10 +388,8 @@ public: FreedBlock* WriteTags(u8* p, size_t size) { -#include "lib/nommgr.h" FreedBlock* freedBlock = new(p) FreedBlock(s_headerId, size); (void)new(Footer(freedBlock)) FreedBlock(s_footerId, size); -#include "lib/mmgr.h" m_freeBlocks++; m_freeBytes += size; diff --git a/source/lib/config.h b/source/lib/config.h index a27bed645c..53d7dd987f 100644 --- a/source/lib/config.h +++ b/source/lib/config.h @@ -2,7 +2,7 @@ * ========================================================================= * File : config.h * Project : 0 A.D. - * Description : user-specified compile-time configuration. + * Description : compile-time configuration for the entire project * ========================================================================= */ @@ -11,74 +11,33 @@ #ifndef INCLUDED_CONFIG #define INCLUDED_CONFIG -// the config macros are always defined; their values (1 or 0) are -// tested with #if instead of #ifdef. -// this protects user code from typos such as #ifdef _MSC_VEER, which -// would silently remove code. instead, we will at least get "test of -// undefined macro" warnings here. not including this header also triggers -// such warnings, but won't happen often because we're included from PCH. -// -// allow override via compiler settings by checking #ifndef. +// notes: +// - this file is included in the PCH and thus affects the entire project. +// to avoid unnecessary full rebuilds, place settings of more limited +// applicability in config2.h and explicitly include that header. +// - config macros are always defined; their values (1 or 0) are tested +// with #if instead of #ifdef. this protects against typos by at least +// causing a warning if the tested macro is undefined. +// - allow override via compiler settings by checking #ifndef. -// omit frame pointers - stack frames will not be generated, which -// improves performance but makes walking the stack harder. -// this is acted upon by #pragmas in sysdep.h. +// pre-compiled headers +#ifndef CONFIG_ENABLE_PCH +# define CONFIG_ENABLE_PCH 1 // improve build performance +#endif + +// frame pointers #ifndef CONFIG_OMIT_FP # ifdef NDEBUG -# define CONFIG_OMIT_FP 1 +# define CONFIG_OMIT_FP 1 // improve performance # else -# define CONFIG_OMIT_FP 0 +# define CONFIG_OMIT_FP 0 // enable use of ia32's fast stack walk # endif #endif -// (only applicable if ARCH_IA32) 64-bit values will be returned in EDX:EAX. -// this chiefly affects ia32_rdtsc. if not set, a safer but slower fallback -// will be used that doesn't assume anything about return convention. -#ifndef CONFIG_RETURN64_EDX_EAX -# define CONFIG_RETURN64_EDX_EAX 1 -#endif - -// allow use of RDTSC for raw tick counts (otherwise, the slower but -// more reliable on MP systems wall-clock will be used). -#ifndef CONFIG_TIMER_ALLOW_RDTSC -# define CONFIG_TIMER_ALLOW_RDTSC 1 -#endif - -// this enables/disables the actual checking done by OverrunProtector-s -// (quite slow, entailing mprotect() before/after each access). -// define to 1 here or in the relevant module if you suspect mem corruption. -// we provide this option because OverrunProtector requires some changes to -// the object being wrapped, and we want to leave those intact but not -// significantly slow things down except when needed. -#ifndef CONFIG_OVERRUN_PROTECTION -# define CONFIG_OVERRUN_PROTECTION 0 -#endif - -// zero-copy IO means all clients share the cached buffer; changing their -// contents is forbidden. this flag causes the buffers to be marked as -// read-only via MMU (writes would cause an exception), which takes a -// bit of extra time. -#ifndef CONFIG_READ_ONLY_CACHE -#define CONFIG_READ_ONLY_CACHE 1 -#endif - -// enable memory tracking (slow). see mmgr.cpp. -#ifndef CONFIG_USE_MMGR -# define CONFIG_USE_MMGR 0 -#endif - -// enable the wsdl emulator in Windows builds. -// -// NOTE: the official SDL distribution has two problems on Windows: -// - it specifies "/defaultlib:msvcrt.lib". this is troublesome because -// multiple heaps are active; errors result when allocated blocks are -// (for reasons unknown) passed to a different heap to be freed. -// one workaround is to add "/nodefaultlib:msvcrt.lib" to the linker -// command line in debug configurations. -// - it doesn't support color hardware mouse cursors and clashes with -// cursor.cpp's efforts by resetting the mouse cursor after movement. -#ifndef CONFIG_USE_WSDL -# define CONFIG_USE_WSDL 1 +// try to prevent any exceptions from being thrown - even by the C++ +// standard library. useful only for performance tests. +#ifndef CONFIG_DISABLE_EXCEPTIONS +# define CONFIG_DISABLE_EXCEPTIONS 0 #endif // enable additional debug checks (very slow). @@ -91,22 +50,4 @@ # define CONFIG_FINAL 0 #endif -// enable trace output for low-level code - various functions will -// debug_printf when they are entered/exited. note that the appropriate -// TRACEn tags must be debug_filter_add-ed for this to have any effect. -#ifndef CONFIG_TRACE -# define CONFIG_TRACE 0 -#endif - -// try to prevent any exceptions from being thrown - even by the C++ -// standard library. useful only for performance tests. -#ifndef CONFIG_DISABLE_EXCEPTIONS -# define CONFIG_DISABLE_EXCEPTIONS 0 -#endif - -// precompiled headers (affects what precompiled.h pulls in; see there) -#ifndef CONFIG_ENABLE_PCH -# define CONFIG_ENABLE_PCH 1 -#endif - #endif // #ifndef INCLUDED_CONFIG diff --git a/source/lib/config2.h b/source/lib/config2.h new file mode 100644 index 0000000000..cd3a46dafe --- /dev/null +++ b/source/lib/config2.h @@ -0,0 +1,64 @@ +/** + * ========================================================================= + * File : config2.h + * Project : 0 A.D. + * Description : compile-time configuration for isolated spots + * ========================================================================= + */ + +// license: GPL; see lib/license.txt + +#ifndef INCLUDED_CONFIG2 +#define INCLUDED_CONFIG2 + +// rationale: a centralized header makes it much easier to see what all +// can be changed. it is assumed that only a few modules will need +// configuration choices, so rebuilding them all is acceptable. +// use config.h when settings must apply to the entire project. + +// (only applicable if ARCH_IA32) 64-bit values will be returned in EDX:EAX. +// this chiefly affects ia32_rdtsc. if not set, a safer but slower fallback +// will be used that doesn't assume anything about return convention. +#ifndef CONFIG2_IA32_RETURN64_EDX_EAX +# define CONFIG2_IA32_RETURN64_EDX_EAX 1 +#endif + +// allow use of RDTSC for raw tick counts (otherwise, the slower but +// more reliable on MP systems wall-clock will be used). +#ifndef CONFIG2_TIMER_ALLOW_RDTSC +# define CONFIG2_TIMER_ALLOW_RDTSC 1 +#endif + +// this enables/disables the actual checking done by OverrunProtector +// (quite slow, entailing mprotect() before/after each access). +// define to 1 here or in the relevant module if you suspect mem corruption. +// we provide this option because OverrunProtector requires some changes to +// the object being wrapped, and we want to leave those intact but not +// significantly slow things down except when needed. +#ifndef CONFIG2_ALLOCATORS_OVERRUN_PROTECTION +# define CONFIG2_ALLOCATORS_OVERRUN_PROTECTION 0 +#endif + +// zero-copy IO means all clients share the cached buffer; changing their +// contents is forbidden. this flag causes the buffers to be marked as +// read-only via MMU (writes would cause an exception), which takes a +// bit of extra time. +#ifndef CONFIG2_CACHE_READ_ONLY +#define CONFIG2_CACHE_READ_ONLY 1 +#endif + +// enable the wsdl emulator in Windows builds. +// +// NOTE: the official SDL distribution has two problems on Windows: +// - it specifies "/defaultlib:msvcrt.lib". this is troublesome because +// multiple heaps are active; errors result when allocated blocks are +// (for reasons unknown) passed to a different heap to be freed. +// one workaround is to add "/nodefaultlib:msvcrt.lib" to the linker +// command line in debug configurations. +// - it doesn't support color hardware mouse cursors and clashes with +// cursor.cpp's efforts by resetting the mouse cursor after movement. +#ifndef CONFIG2_WSDL +# define CONFIG2_WSDL 1 +#endif + +#endif // #ifndef INCLUDED_CONFIG2 diff --git a/source/lib/debug.cpp b/source/lib/debug.cpp index c5367baea2..dda7518a93 100644 --- a/source/lib/debug.cpp +++ b/source/lib/debug.cpp @@ -17,17 +17,10 @@ #include "app_hooks.h" #include "os_path.h" #include "path_util.h" -#include "debug_stl.h" #include "lib/allocators/allocators.h" // page_aligned_alloc #include "fnv_hash.h" -#include "lib/posix/posix_pthread.h" #include "lib/sysdep/cpu.h" // cpu_CAS #include "lib/sysdep/sysdep.h" -// some functions here are called from within mmgr; disable its hooks -// so that our allocations don't cause infinite recursion. -#ifdef REDEFINED_NEW -# include "lib/nommgr.h" -#endif ERROR_ASSOCIATE(ERR::SYM_NO_STACK_FRAMES_FOUND, "No stack frames found", -1); @@ -139,8 +132,7 @@ void debug_filter_remove(const char* tag) void debug_filter_clear() { - for(uint i = 0; i < MAX_TAGS; i++) - tags[i] = 0; + std::fill(tags, tags+MAX_TAGS, 0); } bool debug_filter_allows(const char* text) @@ -248,200 +240,6 @@ LibError debug_write_crashlog(const wchar_t* text) } - -////////////////////////////////////////////////////////////////////////////// -// -// storage for and construction of strings describing a symbol -// -////////////////////////////////////////////////////////////////////////////// - -// tightly pack strings within one large buffer. we never need to free them, -// since the program structure / addresses can never change. -static const size_t STRING_BUF_SIZE = 64*KiB; -static char* string_buf; -static char* string_buf_pos; - -static const char* symbol_string_build(void* symbol, const char* name, const char* file, int line) -{ - // maximum bytes allowed per string (arbitrary). - // needed to prevent possible overflows. - const size_t STRING_MAX = 1000; - - if(!string_buf) - { - string_buf = new char[STRING_BUF_SIZE]; - string_buf_pos = string_buf; - } - - // make sure there's enough space for a new string - char* string = string_buf_pos; - if(string + STRING_MAX >= string_buf + STRING_BUF_SIZE) - { - WARN_ERR(ERR::LIMIT); - return 0; - } - - // user didn't know name/file/line. attempt to resolve from debug info. - char name_buf[DBG_SYMBOL_LEN]; - char file_buf[DBG_FILE_LEN]; - if(!name || !file || !line) - { - int line_buf; - (void)debug_resolve_symbol(symbol, name_buf, file_buf, &line_buf); - - // only override the original parameters if value is meaningful; - // otherwise, stick with what we got, even if 0. - // (obviates test of return value; correctly handles partial failure). - if(name_buf[0]) - name = name_buf; - if(file_buf[0]) - file = file_buf; - if(line_buf) - line = line_buf; - } - - // file and line are available: write them - int len; - if(file && line) - { - // strip path from filename (long and irrelevant) - const char* fn_only = path_name_only(file); - - len = snprintf(string, STRING_MAX-1, "%s:%05d ", fn_only, line); - } - // only address is known - else - len = snprintf(string, STRING_MAX-1, "%p ", symbol); - - // append symbol name - if(name) - { - snprintf(string+len, STRING_MAX-1-len, "%s", name); - debug_stl_simplify_name(string+len); - } - - return string; -} - - -////////////////////////////////////////////////////////////////////////////// -// -// cache, mapping symbol address to its description string. -// -////////////////////////////////////////////////////////////////////////////// - -// note: we don't want to allocate a new string for every symbol - -// that would waste lots of memory. instead, when a new address is first -// encountered, allocate a string describing it, and store for later use. - -// hash table entry; valid iff symbol != 0. the string pointer must remain -// valid until the cache is shut down. -struct Symbol -{ - void* symbol; - const char* string; -}; - -static const uint MAX_SYMBOLS = 2048; -static Symbol* symbols; -static uint total_symbols; - - -static uint hash_jumps; - -// strip off lower 2 bits, since it's unlikely that 2 symbols are -// within 4 bytes of one another. -static uint hash(void* symbol) -{ - const uintptr_t address = (uintptr_t)symbol; - return (uint)( (address >> 2) % MAX_SYMBOLS ); -} - - -// algorithm: hash lookup with linear probing. -static const char* symbol_string_from_cache(void* symbol) -{ - // hash table not initialized yet, nothing to find - if(!symbols) - return 0; - - uint idx = hash(symbol); - for(;;) - { - Symbol* c = &symbols[idx]; - - // not in table - if(!c->symbol) - return 0; - // found - if(c->symbol == symbol) - return c->string; - - idx = (idx+1) % MAX_SYMBOLS; - } -} - - -// associate (must remain valid) with , for -// later calls to symbol_string_from_cache. -static void symbol_string_add_to_cache(const char* string, void* symbol) -{ - if(!symbols) - { - // note: must be zeroed to set each Symbol to "invalid" - symbols = (Symbol*)calloc(MAX_SYMBOLS, sizeof(Symbol)); - debug_assert(symbols); - } - - // hash table is completely full (guard against infinite loop below). - // if this happens, the string won't be cached - nothing serious. - if(total_symbols >= MAX_SYMBOLS) - WARN_ERR_RETURN(ERR::LIMIT); - total_symbols++; - - // find Symbol slot in hash table - Symbol* c; - uint idx = hash(symbol); - for(;;) - { - c = &symbols[idx]; - - // found an empty slot - if(!c->symbol) - break; - - idx = (idx+1) % MAX_SYMBOLS; - hash_jumps++; - } - - // commit Symbol information - c->symbol = symbol; - c->string = string; - - string_buf_pos += strlen(string)+1; -} - - - - -const char* debug_get_symbol_string(void* symbol, const char* name, const char* file, int line) -{ - // return it if already in cache - const char* string = symbol_string_from_cache(symbol); - if(string) - return string; - - // try to build a new string - string = symbol_string_build(symbol, name, file, line); - if(!string) - return 0; - - symbol_string_add_to_cache(string, symbol); - - return string; -} - - //----------------------------------------------------------------------------- // output //----------------------------------------------------------------------------- @@ -598,14 +396,7 @@ static ErrorReaction carry_out_ErrorReaction(ErrorReaction er, uint flags, u8* s case ER_EXIT: exit_requested = true; // see declaration - // disable memory-leak reporting to avoid a flood of warnings - // (lots of stuff will leak since we exit abnormally). - debug_heap_enable(DEBUG_HEAP_NONE); -#if CONFIG_USE_MMGR - mmgr_set_options(0); -#endif - - exit(EXIT_FAILURE); + abort(); } return er; @@ -730,76 +521,3 @@ ErrorReaction debug_warn_err(LibError err, u8* suppress, swprintf(buf, ARRAY_SIZE(buf), L"Function call failed: return value was %d (%hs)", err, err_buf); return debug_display_error(buf, DE_MANUAL_BREAK, skip,context, file,line,func, suppress); } - - -//----------------------------------------------------------------------------- -// thread naming -//----------------------------------------------------------------------------- - -// when debugging multithreading problems, logging the currently running -// thread is helpful; a user-specified name is easier to remember than just -// the thread handle. to that end, we provide a robust TLS mechanism that is -// much safer than the previous method of hijacking TIB.pvArbitrary. -// -// note: on Win9x thread "IDs" are pointers to the TIB xor-ed with an -// obfuscation value calculated at boot-time. -// -// __declspec(thread) et al. are now available on VC and newer GCC but we -// implement TLS manually (via pthread_setspecific) to ensure compatibility. - -static pthread_key_t tls_key; -static pthread_once_t tls_once = PTHREAD_ONCE_INIT; - - -// provided for completeness and to avoid displaying bogus resource leaks. -static void tls_shutdown() -{ - WARN_ERR(pthread_key_delete(tls_key)); - tls_key = 0; -} - - -// (called via pthread_once from debug_set_thread_name) -static void tls_init() -{ - WARN_ERR(pthread_key_create(&tls_key, 0)); // no dtor - - // note: do not use atexit; this may be called before _cinit. -} - - -// set the current thread's name; it will be returned by subsequent calls to -// debug_get_thread_name. -// -// the string pointed to by MUST remain valid throughout the -// entire program; best to pass a string literal. allocating a copy -// would be quite a bit more work due to cleanup issues. -// -// if supported on this platform, the debugger is notified of the new name; -// it will be displayed there instead of just the handle. -void debug_set_thread_name(const char* name) -{ - WARN_ERR(pthread_once(&tls_once, tls_init)); - - WARN_ERR(pthread_setspecific(tls_key, name)); - -#if OS_WIN - wdbg_set_thread_name(name); -#endif -} - - -// return the pointer assigned by debug_set_thread_name or 0 if -// that hasn't been done yet for this thread. -const char* debug_get_thread_name() -{ - return (const char*)pthread_getspecific(tls_key); -} - - - - -void debug_shutdown() -{ - tls_shutdown(); -} diff --git a/source/lib/debug.h b/source/lib/debug.h index cbb97e51d6..7a7cb30acf 100644 --- a/source/lib/debug.h +++ b/source/lib/debug.h @@ -11,103 +11,45 @@ #ifndef INCLUDED_DEBUG #define INCLUDED_DEBUG -#if OS_WIN -# include "lib/sysdep/win/wdbg.h" -#else -# include "lib/sysdep/unix/udbg.h" -#endif +// this module provides platform-independent debug facilities, useful for +// diagnosing and reporting program errors. +// - a symbol engine provides access to compiler-generated debug information and +// can also give a stack trace including local variables; +// - hooks into the memory allocator improve its leak detection; +// - our more powerful assert() replacement gives a stack trace so +// that the underlying problem becomes apparent; +// - the output routines make for platform-independent logging and +// crashlogs with "last-known activity" reporting. + /** + * trigger a breakpoint when reached/"called". + * if defined as a macro, the debugger can break directly into the + * target function instead of one frame below it as with a conventional + * call-based implementation. + **/ +#if MSC_VERSION +# define debug_break() __asm { int 3 } +#else +extern void debug_break(); +#endif -overview --------- - -this module provides platform-independent debug facilities, useful for -diagnosing and reporting program errors. -- a symbol engine provides access to compiler-generated debug information and - can also give a stack trace including local variables; -- the breakpoint API enables stopping when a given address is - executed, read or written to (as specified); -- a hook into the system's memory allocator can optionally check for and - report heap corruption; -- our more powerful assert() replacement gives a stack trace so - that the underlying problem becomes apparent; -- the output routines make for platform-independent logging and - crashlogs with "last-known activity" reporting. - - -usage ------ - -please see the detailed comments below on how to use the individual features. -much of this is only helpful if you explicity ask for it! - - -rationale ---------- - -much of this functionality already exists within the VC7 IDE/debugger. -motivation for this code is as follows: -- we want a consistent interface for all platforms; -- limitations(*) in the VC variants should be fixed; -- make debugging as easy as possible. - -* mostly pertaining to Release mode - e.g. symbols cannot be resolved -even if debug information is present and assert dialogs are useless. - -**/ //----------------------------------------------------------------------------- // debug memory allocator //----------------------------------------------------------------------------- /** - * check heap integrity (independently of mmgr). + * check heap integrity. * errors are reported by the CRT or via debug_display_error. **/ LIB_API void debug_heap_check(void); -enum DebugHeapChecks -{ - /** - * no automatic checks. (default) - **/ - DEBUG_HEAP_NONE = 0, - - /** - * basic automatic checks when deallocating. - **/ - DEBUG_HEAP_NORMAL = 1, - - /** - * all automatic checks on every memory API call. this is really - * slow (x100), but reports errors closer to where they occurred. - **/ - DEBUG_HEAP_ALL = 2 -}; - -/** - * call at any time; from then on, the specified checks will be performed. - * if not called, the default is DEBUG_HEAP_NONE, i.e. do nothing. - **/ -LIB_API void debug_heap_enable(DebugHeapChecks what); - //----------------------------------------------------------------------------- // output //----------------------------------------------------------------------------- -enum DebugLevel -{ - DEBUG_LEVEL_NONE = 0, - DEBUG_LEVEL_BRIEF = 2, - DEBUG_LEVEL_DETAILED = 5, - DEBUG_LEVEL_FULL = 9 -}; -#define DEBUG_PRINTF_BRIEF if(debug_level >= DEBUG_LEVEL_BRIEF) debug_printf -#define DEBUG_PRINTF_DETAILED if(debug_level >= DEBUG_LEVEL_DETAILED) debug_printf -#define DEBUG_PRINTF_FULL if(debug_level >= DEBUG_LEVEL_FULL ) debug_printf - /** * write a formatted string to the debug channel, subject to filtering * (see below). implemented via debug_puts - see performance note there. @@ -228,7 +170,7 @@ LIB_API ErrorReaction debug_display_error(const wchar_t* description, * convenience version, in case the advanced parameters aren't needed. * macro instead of providing overload/default values for C compatibility. **/ -#define DISPLAY_ERROR(text) debug_display_error(text, 0, 0,0, __FILE__,__LINE__,__func__, 0) +#define DEBUG_DISPLAY_ERROR(text) debug_display_error(text, 0, 0,0, __FILE__,__LINE__,__func__, 0) // @@ -438,59 +380,6 @@ LIB_API void debug_skip_next_err(LibError err); LIB_API void debug_skip_assert(); -//----------------------------------------------------------------------------- -// breakpoints -//----------------------------------------------------------------------------- - -/** - * trigger a breakpoint when reached/"called". - * defined as a macro by the platform-specific header above; this allows - * breaking directly into the target function, instead of one frame - * below it as with a conventional call-based implementation. - **/ -//#define debug_break() // not defined here; see above - - -/** - * sometimes mmgr's 'fences' (making sure padding before and after the - * allocation remains intact) aren't enough to catch hard-to-find - * memory corruption bugs. another tool is to trigger a debug exception - * when the later to be corrupted variable is accessed; the problem should - * then become apparent. - * the VC++ IDE provides such 'breakpoints', but can only detect write access. - * additionally, it can't resolve symbols in Release mode (where this would - * be most useful), so we provide a breakpoint API. - - * (values chosen to match IA-32 bit defs, so compiler can optimize. - * this isn't required; it'll work regardless.) - **/ -enum DbgBreakType -{ - DBG_BREAK_CODE = 0, /// execute - DBG_BREAK_DATA_WRITE = 1, /// write - DBG_BREAK_DATA = 3 /// read or write -}; - -/** - * arrange for a debug exception to be raised when the - * indicated memory is accessed. - * - * @param addr memory address - * for simplicity, the length (range of bytes to be checked) is derived - * from addr's alignment, and is typically 1 machine word. - * @param type the type of access to watch for (see DbgBreakType) - * @return LibError; ERR::LIMIT if no more breakpoints are available - * (they are a limited resource - only 4 on IA-32). - **/ -LIB_API LibError debug_set_break(void* addr, DbgBreakType type); - -/** - * remove all breakpoints that were set by debug_set_break. - * important, since these are a limited resource. - **/ -LIB_API LibError debug_remove_all_breaks(); - - //----------------------------------------------------------------------------- // symbol access //----------------------------------------------------------------------------- @@ -564,8 +453,6 @@ LIB_API LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, cha **/ LIB_API LibError debug_dump_stack(wchar_t* buf, size_t max_chars, uint skip, void* context); -LIB_API const char* debug_get_symbol_string(void* symbol, const char* name, const char* file, int line); - //----------------------------------------------------------------------------- // helper functions (used by implementation) @@ -581,14 +468,13 @@ LIB_API void debug_puts(const char* text); /** * return address of the Nth function on the call stack. * - * used by mmgr to determine what function requested each allocation; - * this is fast enough to allow that. - * * @param skip number of stack frames (i.e. functions on call stack) to skip. * @param context platform-specific representation of execution state * (e.g. Win32 CONTEXT). if not NULL, tracing starts there; this is useful * for exceptions. otherwise, tracing starts from the current call stack. * @return address of Nth function + * + * note: this does not access debug symbols and is therefore quite fast. **/ LIB_API void* debug_get_nth_caller(uint skip, void* context); @@ -611,26 +497,13 @@ LIB_API bool debug_is_stack_ptr(void* p); /** - * set the current thread's name; it will be returned by subsequent calls to - * debug_get_thread_name. + * inform the debugger of the current thread's name. * - * if supported on this platform, the debugger is notified of the new name; - * it will be displayed there instead of just the handle. - * - * @param name identifier string for thread. MUST remain valid throughout - * the entire program; best to pass a string literal. allocating a copy - * would be quite a bit more work due to cleanup issues. + * (threads are easier to keep apart when they are identified by + * name rather than TID.) **/ LIB_API void debug_set_thread_name(const char* name); -/** - * return current thread's name. - * - * @return thread name, or NULL if one hasn't been assigned yet - * via debug_set_thread_name. - **/ -LIB_API const char* debug_get_thread_name(); - /** * holds memory for an error message. @@ -677,11 +550,4 @@ LIB_API const wchar_t* debug_error_message_build( uint skip, void* context, ErrorMessageMem* emm); - -/** - * call at exit to avoid some leaks. - * not strictly necessary. - **/ -LIB_API void debug_shutdown(); - #endif // #ifndef INCLUDED_DEBUG diff --git a/source/lib/debug_stl.cpp b/source/lib/debug_stl.cpp index b6fe144e09..fc69ac3f9e 100644 --- a/source/lib/debug_stl.cpp +++ b/source/lib/debug_stl.cpp @@ -572,9 +572,7 @@ template bool get_container_info(const T& t, size_t size, size_t el_siz // construct a copy of begin() at it_mem. placement new is necessary // because VC8's secure copy ctor apparently otherwise complains about // invalid values in the (uninitialized) destination memory. -#include "lib/nommgr.h" new(it_mem) const_iterator(t.begin()); -#include "lib/mmgr.h" return true; } diff --git a/source/lib/external_libraries/sdl.h b/source/lib/external_libraries/sdl.h index 34478b61d6..38491c3e34 100644 --- a/source/lib/external_libraries/sdl.h +++ b/source/lib/external_libraries/sdl.h @@ -12,8 +12,9 @@ #define INCLUDED_SDL #include "sdl_fwd.h" +#include "lib/config2.h" // CONFIG2_WSDL -#if OS_WIN && CONFIG_USE_WSDL +#if OS_WIN && CONFIG2_WSDL # include "lib/sysdep/win/wsdl.h" #else diff --git a/source/lib/file/common/trace.cpp b/source/lib/file/common/trace.cpp index e16a6876ff..103142ff4b 100644 --- a/source/lib/file/common/trace.cpp +++ b/source/lib/file/common/trace.cpp @@ -13,7 +13,6 @@ #include "lib/allocators/pool.h" #include "lib/timer.h" // timer_Time -#include "lib/nommgr.h" // placement new /*virtual*/ ITrace::~ITrace() { diff --git a/source/lib/file/io/block_cache.cpp b/source/lib/file/io/block_cache.cpp index 4f7cda759b..94de8bcf98 100644 --- a/source/lib/file/io/block_cache.cpp +++ b/source/lib/file/io/block_cache.cpp @@ -11,6 +11,7 @@ #include "precompiled.h" #include "block_cache.h" +#include "lib/config2.h" // CONFIG2_CACHE_READ_ONLY #include "lib/file/common/file_stats.h" #include "lib/lockfree.h" #include "lib/allocators/pool.h" @@ -79,13 +80,13 @@ public: { if(m_blocks.size() > m_maxBlocks) { -#if CONFIG_READ_ONLY_CACHE +#if CONFIG2_CACHE_READ_ONLY mprotect((void*)m_blocks.front().buf.get(), BLOCK_SIZE, PROT_READ); #endif m_blocks.pop_front(); // evict oldest block } -#if CONFIG_READ_ONLY_CACHE +#if CONFIG2_CACHE_READ_ONLY mprotect((void*)buf.get(), BLOCK_SIZE, PROT_WRITE|PROT_READ); #endif m_blocks.push_back(Block(id, buf)); diff --git a/source/lib/file/io/block_cache.h b/source/lib/file/io/block_cache.h index fb084d34fd..7e66163b82 100644 --- a/source/lib/file/io/block_cache.h +++ b/source/lib/file/io/block_cache.h @@ -54,7 +54,7 @@ public: * * call this when the block's IO has completed; its data will * satisfy subsequent Retrieve calls for the same id. - * if CONFIG_READ_ONLY_CACHE, the memory is made read-only. + * if CONFIG2_CACHE_READ_ONLY, the memory is made read-only. **/ void Add(BlockId id, shared_ptr buf); diff --git a/source/lib/file/vfs/file_cache.h b/source/lib/file/vfs/file_cache.h index 63ab384a87..7b514c1a5e 100644 --- a/source/lib/file/vfs/file_cache.h +++ b/source/lib/file/vfs/file_cache.h @@ -53,7 +53,7 @@ public: * Add a file's contents to the cache. * * the cache will be able to satisfy subsequent Retrieve() calls by - * returning this data; if CONFIG_READ_ONLY_CACHE, the buffer is made + * returning this data; if CONFIG2_CACHE_READ_ONLY, the buffer is made * read-only. if need be and no references are currently attached to it, * the memory can also be commandeered by Reserve(). * diff --git a/source/lib/mmgr.cpp b/source/lib/mmgr.cpp index d9ee363269..9ee1ab1d42 100644 --- a/source/lib/mmgr.cpp +++ b/source/lib/mmgr.cpp @@ -10,6 +10,7 @@ #include "precompiled.h" +#if 0 ERROR_ASSOCIATE(ERR::MEM_ALLOC_NOT_FOUND, "Not a valid allocated address", -1); ERROR_ASSOCIATE(ERR::MEM_OVERWRITTEN, "Wrote to memory outside valid allocation", -1); @@ -1418,3 +1419,5 @@ void operator delete[](void* p, const char* file, int line, const char* func) th } #endif // #if CONFIG_USE_MMGR + +#endif \ No newline at end of file diff --git a/source/lib/mmgr.h b/source/lib/mmgr.h index 32a45cd268..d299f7f57c 100644 --- a/source/lib/mmgr.h +++ b/source/lib/mmgr.h @@ -1,3 +1,5 @@ +#if 0 + /** * ========================================================================= * File : mmgr.h @@ -290,3 +292,5 @@ extern void operator delete[](void* p, const char* file, int line, const char* f #define new new(_NORMAL_BLOCK, __FILE__, __LINE__) #endif // #if CONFIG_USE_MMGR + +#endif \ No newline at end of file diff --git a/source/lib/precompiled.h b/source/lib/precompiled.h index 45c4c88548..f6553232c9 100644 --- a/source/lib/precompiled.h +++ b/source/lib/precompiled.h @@ -9,14 +9,7 @@ // license: GPL; see lib/license.txt -// if PCHs are supported and enabled, we make an effort to include all -// system headers. otherwise, only a few headers (e.g. memory tracker) -// are pulled in and source files must include all the system headers -// they use. this policy ensures good compile performance whether or not -// PCHs are being used. - -#include "lib/config.h" // CONFIG_ENABLE_PCH -#include "lib/sysdep/compiler.h" // HAVE_PCH +#include "lib/sysdep/compiler.h" // MSC_VERSION, HAVE_PCH // disable some common and annoying warnings // (done as soon as possible so that headers below are covered) @@ -43,9 +36,8 @@ // headers made available everywhere for convenience // -#include "lib/sysdep/compiler.h" -#include "lib/sysdep/stl.h" #include "lib/sysdep/os.h" +#include "lib/sysdep/stl.h" #include "lib/sysdep/arch.h" #include "lib/lib_api.h" @@ -80,6 +72,15 @@ namespace fs = boost::filesystem; // precompiled headers // +// if PCHs are supported and enabled, we make an effort to include all +// system headers. otherwise, only a few central headers (e.g. types) +// are pulled in and source files must include all the system headers +// they use. this policy ensures good compile performance whether or not +// PCHs are being used. + +#include "lib/config.h" // CONFIG_ENABLE_PCH +#include "lib/sysdep/compiler.h" // HAVE_PCH + #if CONFIG_ENABLE_PCH && HAVE_PCH // anything placed here won't need to be compiled in each translation unit, @@ -140,7 +141,7 @@ namespace fs = boost::filesystem; #include #include #include -#include +#include // STL extensions #if GCC_VERSION @@ -157,7 +158,3 @@ namespace fs = boost::filesystem; #if MSC_VERSION # pragma warning(default:4702) #endif - -// (this must be included from every file to make sure all allocations -// are tracked; placing it in the PCH is a convenient means of doing so) -#include "mmgr.h" diff --git a/source/lib/res/graphics/ogl_tex.cpp b/source/lib/res/graphics/ogl_tex.cpp index cb5bb296da..9c796c25e4 100644 --- a/source/lib/res/graphics/ogl_tex.cpp +++ b/source/lib/res/graphics/ogl_tex.cpp @@ -223,7 +223,7 @@ static GLint choose_int_fmt(GLenum fmt, uint q_flags) { wchar_t buf[100]; swprintf(buf, ARRAY_SIZE(buf), L"choose_int_fmt: fmt 0x%x isn't covered! please add it", fmt); - DISPLAY_ERROR(buf); + DEBUG_DISPLAY_ERROR(buf); debug_assert(0); // given fmt isn't covered! please add it. // fall back to a reasonable default return half_bpp? GL_RGB4 : GL_RGB8; @@ -683,7 +683,7 @@ static void detect_gl_upload_caps() // warn if more-or-less essential features are missing if(!have_s3tc) - DISPLAY_ERROR(L"Performance warning: your graphics card does not support compressed textures. The game will try to continue anyway, but may be slower than expected. Please try updating your graphics drivers; if that doesn't help, please try upgrading your hardware."); + DEBUG_DISPLAY_ERROR(L"Performance warning: your graphics card does not support compressed textures. The game will try to continue anyway, but may be slower than expected. Please try updating your graphics drivers; if that doesn't help, please try upgrading your hardware."); } diff --git a/source/lib/res/h_mgr.cpp b/source/lib/res/h_mgr.cpp index ca25f58632..b2cdeeeae6 100644 --- a/source/lib/res/h_mgr.cpp +++ b/source/lib/res/h_mgr.cpp @@ -191,11 +191,9 @@ static HDATA* h_data_from_idx(const i32 idx) if(!page) return 0; -#include "lib/nommgr.h" // placement new // Initialise all the VfsPath members for(uint i = 0; i < hdata_per_page; ++i) new (&page[i].pathname) VfsPath; -#include "lib/mmgr.h" } // note: VC7.1 optimizes the divides to shift and mask. @@ -620,9 +618,7 @@ static LibError h_free_idx(i32 idx, HDATA* hd) hd->pathname.~VfsPath(); // FIXME: ugly hack, but necessary to reclaim std::string memory memset(hd, 0, sizeof(*hd)); -#include "lib/nommgr.h" // placement new new (&hd->pathname) VfsPath; // FIXME too: necessary because otherwise it'll break if we reuse this page -#include "lib/mmgr.h" free_idx(idx); diff --git a/source/lib/self_test.h b/source/lib/self_test.h index 3637e465b3..46ced39c10 100644 --- a/source/lib/self_test.h +++ b/source/lib/self_test.h @@ -115,7 +115,7 @@ For further details, see below. // macro magic (stringize+prepend L) and we already display file+line. #define TEST(condition) STMT(\ if(!(condition))\ - DISPLAY_ERROR(L"Self-test failed");\ + debug_display_error(L"Self-test failed");\ ) diff --git a/source/lib/sysdep/acpi.cpp b/source/lib/sysdep/acpi.cpp index c6e579c9df..b521f8285f 100644 --- a/source/lib/sysdep/acpi.cpp +++ b/source/lib/sysdep/acpi.cpp @@ -51,7 +51,7 @@ static inline void* CallWithSafetyBlanket(UnsafeFunction func, PCV_u8 mem, size_ #endif } -static void* TransactPhysicalMemory(u64 physicalAddress, size_t numBytes, UnsafeFunction func, void* arg = 0) +static void* TransactPhysicalMemory(uintptr_t physicalAddress, size_t numBytes, UnsafeFunction func, void* arg = 0) { PCV_u8 mem = (PCV_u8)mahaf_MapPhysicalMemory(physicalAddress, numBytes); if(!mem) @@ -168,7 +168,7 @@ static inline void* UnsafeAllocateCopyOfTable(PCV_u8 mem, size_t numBytes, void* // caller is responsible for verifying the table is valid and using // DeallocateTable to free it. -static const AcpiTable* AllocateCopyOfTable(u64 physicalAddress) +static const AcpiTable* AllocateCopyOfTable(uintptr_t physicalAddress) { // ACPI table sizes are not known until they've been mapped. since that // is slow, we don't always want to do it twice. the solution is to map @@ -229,7 +229,7 @@ static bool VerifyTable(const AcpiTable* table, const char* signature = 0) } -static const AcpiTable* GetTable(u64 physicalAddress, const char* signature = 0) +static const AcpiTable* GetTable(uintptr_t physicalAddress, const char* signature = 0) { const AcpiTable* table = AllocateCopyOfTable(physicalAddress); if(VerifyTable(table, signature)) diff --git a/source/lib/sysdep/ia32/ia32.cpp b/source/lib/sysdep/ia32/ia32.cpp index 1132dd309f..1150962d9f 100644 --- a/source/lib/sysdep/ia32/ia32.cpp +++ b/source/lib/sysdep/ia32/ia32.cpp @@ -202,7 +202,7 @@ public: } }; -static void DetectIdentifierString(char* identifierString) +static void DetectIdentifierString(char* identifierString, size_t maxChars) { // get brand string (if available) // note: ia32_asm_cpuid writes 4 u32s directly to identifierString - @@ -214,9 +214,6 @@ static void DetectIdentifierString(char* identifierString) ia32_asm_cpuid(0x80000004, u32_string+8)) have_brand_string = true; - // note: we previously verified max_chars is long enough, so copying - // short literals into it is safe. - // fall back to manual detect of CPU type because either: // - CPU doesn't support brand string (we use a flag to indicate this // rather than comparing against a default value because it is safer); @@ -235,15 +232,15 @@ static void DetectIdentifierString(char* identifierString) if(family == 6) { if(model == 3 || model == 7) - SAFE_STRCPY(identifierString, "AMD Duron"); + strcpy_s(identifierString, maxChars, "AMD Duron"); else if(model <= 5) - SAFE_STRCPY(identifierString, "AMD Athlon"); + strcpy_s(identifierString, maxChars, "AMD Athlon"); else { if(ia32_cap(IA32_CAP_AMD_MP)) - SAFE_STRCPY(identifierString, "AMD Athlon MP"); + strcpy_s(identifierString, maxChars, "AMD Athlon MP"); else - SAFE_STRCPY(identifierString, "AMD Athlon XP"); + strcpy_s(identifierString, maxChars, "AMD Athlon XP"); } } break; @@ -253,13 +250,13 @@ static void DetectIdentifierString(char* identifierString) if(family == 6) { if(model == 1) - SAFE_STRCPY(identifierString, "Intel Pentium Pro"); + strcpy_s(identifierString, maxChars, "Intel Pentium Pro"); else if(model == 3 || model == 5) - SAFE_STRCPY(identifierString, "Intel Pentium II"); + strcpy_s(identifierString, maxChars, "Intel Pentium II"); else if(model == 6) - SAFE_STRCPY(identifierString, "Intel Celeron"); + strcpy_s(identifierString, maxChars, "Intel Celeron"); else - SAFE_STRCPY(identifierString, "Intel Pentium III"); + strcpy_s(identifierString, maxChars, "Intel Pentium III"); } break; } @@ -282,7 +279,7 @@ const char* cpu_IdentifierString() // 3 calls x 4 registers x 4 bytes = 48 static char identifierString[48+1] = {'\0'}; if(identifierString[0] == '\0') - DetectIdentifierString(identifierString); + DetectIdentifierString(identifierString, ARRAY_SIZE(identifierString)); return identifierString; } diff --git a/source/lib/sysdep/ia32/ia32.h b/source/lib/sysdep/ia32/ia32.h index 966f03437e..0990386386 100644 --- a/source/lib/sysdep/ia32/ia32.h +++ b/source/lib/sysdep/ia32/ia32.h @@ -16,6 +16,7 @@ #endif #include "ia32_asm.h" +#include "lib/config2.h" // CONFIG2_IA32_RETURN64_EDX_EAX /** @@ -113,7 +114,7 @@ LIB_API u64 ia32_rdtsc_safe(void); * but potentially differs between multiple CPUs) **/ LIB_API u64 ia32_rdtsc(); // only for CppDoc's benefit -#if CONFIG_RETURN64_EDX_EAX +#if CONFIG2_IA32_RETURN64_EDX_EAX # define ia32_rdtsc ia32_asm_rdtsc_edx_eax #else # define ia32_rdtsc ia32_rdtsc_safe diff --git a/source/lib/sysdep/unix/udbg.cpp b/source/lib/sysdep/unix/udbg.cpp index 5a79fcd4e2..037d3ee9cc 100644 --- a/source/lib/sysdep/unix/udbg.cpp +++ b/source/lib/sysdep/unix/udbg.cpp @@ -30,7 +30,7 @@ LibError udbg_resolve_symbol(void* UNUSED(ptr_of_interest), char* UNUSED(sym_nam } -void unix_debug_break() +void debug_break() { kill(getpid(), SIGTRAP); } diff --git a/source/lib/sysdep/unix/udbg.h b/source/lib/sysdep/unix/udbg.h index 55fe3efa94..5dc7e895d7 100644 --- a/source/lib/sysdep/unix/udbg.h +++ b/source/lib/sysdep/unix/udbg.h @@ -3,10 +3,6 @@ #ifndef INCLUDED_UDBG #define INCLUDED_UDBG -#define debug_break unix_debug_break - -extern void unix_debug_break(void); - extern void udbg_launch_debugger(); #endif // #ifndef INCLUDED_UDBG diff --git a/source/lib/sysdep/win/tests/test_wdbg_sym.h b/source/lib/sysdep/win/tests/test_wdbg_sym.h index 881083cc8e..bd9109ea08 100644 --- a/source/lib/sysdep/win/tests/test_wdbg_sym.h +++ b/source/lib/sysdep/win/tests/test_wdbg_sym.h @@ -47,7 +47,7 @@ class TestWdbgSym : public CxxTest::TestSuite // note: prefer simple error (which also generates stack trace) to // exception, because it is guaranteed to work (no issues with the // debugger swallowing exceptions). - //DISPLAY_ERROR(L"wdbg_sym self test: check if stack trace below is ok."); + //DEBUG_DISPLAY_ERROR(L"wdbg_sym self test: check if stack trace below is ok."); //RaiseException(0xf001,0,0,0); // note: we don't want any kind of dialog to be raised, because diff --git a/source/lib/sysdep/win/wdbg.cpp b/source/lib/sysdep/win/wdbg.cpp index ccb2aaf7e6..2c2d0da66a 100644 --- a/source/lib/sysdep/win/wdbg.cpp +++ b/source/lib/sysdep/win/wdbg.cpp @@ -2,30 +2,21 @@ * ========================================================================= * File : wdbg.cpp * Project : 0 A.D. - * Description : Win32 debug support code and exception handler. + * Description : Win32 debug support code. * ========================================================================= */ // license: GPL; see lib/license.txt #include "precompiled.h" -#include "wdbg.h" +#include "lib/debug.h" #include "lib/bits.h" #include "win.h" #include "wutil.h" +#include "winit.h" - -// protects the breakpoint helper thread. -static void lock() -{ - win_lock(WDBG_CS); -} - -static void unlock() -{ - win_unlock(WDBG_CS); -} +WINIT_REGISTER_CRITICAL_INIT(wdbg_Init); static NT_TIB* get_tib() @@ -45,17 +36,30 @@ static NT_TIB* get_tib() //----------------------------------------------------------------------------- -// debug memory allocator +// debug heap //----------------------------------------------------------------------------- -// check heap integrity (independently of mmgr). -// errors are reported by the CRT or via debug_display_error. +static void debug_heap_init() +{ + uint flags = 0; + flags |= _CRTDBG_ALLOC_MEM_DF; // enable checks at deallocation time + flags |= _CRTDBG_LEAK_CHECK_DF; // report leaks at exit +#if CONFIG_PARANOIA + flags |= _CRTDBG_CHECK_ALWAYS_DF; // check during every heap operation (slow!) + flags |= _CRTDBG_DELAY_FREE_MEM_DF; // blocks cannot be reused +#endif + _CrtSetDbgFlag(flags); +} + + void debug_heap_check() { int ret; __try { - ret = _heapchk(); + // NB: this is a no-op if !_CRTDBG_ALLOC_MEM_DF. + // we could call _heapchk but that would catch fewer errors. + ret = _CrtCheckMemory(); } __except(EXCEPTION_EXECUTE_HANDLER) { @@ -63,288 +67,7 @@ void debug_heap_check() } if(ret != _HEAPOK) - DISPLAY_ERROR(L"debug_heap_check: heap is corrupt"); -} - - -// call at any time; from then on, the specified checks will be performed. -// if not called, the default is DEBUG_HEAP_NONE, i.e. do nothing. -void debug_heap_enable(DebugHeapChecks what) -{ - // note: if mmgr is enabled, crtdbg.h will not have been included. - // in that case, we do nothing here - this interface is too basic to - // control mmgr; use its API instead. -#if !CONFIG_USE_MMGR && HAVE_VC_DEBUG_ALLOC - uint flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - switch(what) - { - case DEBUG_HEAP_NONE: - // note: do not set flags to zero because we might trash some - // important flag value. - flags &= ~(_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_DELAY_FREE_MEM_DF | - _CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF); - break; - case DEBUG_HEAP_NORMAL: - flags |= _CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF; - break; - case DEBUG_HEAP_ALL: - flags |= (_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_DELAY_FREE_MEM_DF | - _CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF); - break; - default: - debug_assert("debug_heap_enable: invalid what"); - } - _CrtSetDbgFlag(flags); -#else - UNUSED2(what); -#endif // HAVE_DEBUGALLOC -} - - -//----------------------------------------------------------------------------- -// thread suspension - -// suspend a thread, execute a user callback, revive the thread. - -// to avoid deadlock, be VERY CAREFUL to avoid anything that may block, -// including locks taken by the OS (e.g. malloc, GetProcAddress). -typedef LibError (*WhileSuspendedFunc)(HANDLE hThread, void* user_arg); - -struct WhileSuspendedParam -{ - HANDLE hThread; - WhileSuspendedFunc func; - void* user_arg; -}; - - -static void* while_suspended_thread_func(void* user_arg) -{ - debug_set_thread_name("suspender"); - - WhileSuspendedParam* param = (WhileSuspendedParam*)user_arg; - - DWORD err = SuspendThread(param->hThread); - // abort, since GetThreadContext only works if the target is suspended. - if(err == (DWORD)-1) - { - debug_assert(0); // while_suspended_thread_func: SuspendThread failed - return (void*)(intptr_t)-1; - } - // target is now guaranteed to be suspended, - // since the Windows counter never goes negative. - - LibError ret = param->func(param->hThread, param->user_arg); - - WARN_IF_FALSE(ResumeThread(param->hThread)); - - return (void*)(intptr_t)ret; -} - - -static LibError call_while_suspended(WhileSuspendedFunc func, void* user_arg) -{ - int err; - - // we need a real HANDLE to the target thread for use with - // Suspend|ResumeThread and GetThreadContext. - // alternative: DuplicateHandle on the current thread pseudo-HANDLE. - // this way is a bit more obvious/simple. - const DWORD access = THREAD_GET_CONTEXT|THREAD_SET_CONTEXT|THREAD_SUSPEND_RESUME; - HANDLE hThread = OpenThread(access, FALSE, GetCurrentThreadId()); - if(hThread == INVALID_HANDLE_VALUE) - WARN_RETURN(ERR::FAIL); - - WhileSuspendedParam param = { hThread, func, user_arg }; - - pthread_t thread; - WARN_ERR(pthread_create(&thread, 0, while_suspended_thread_func, ¶m)); - - void* ret; - err = pthread_join(thread, &ret); - debug_assert(err == 0 && ret == 0); - - return (LibError)(intptr_t)ret; -} - - -//----------------------------------------------------------------------------- -// breakpoints -//----------------------------------------------------------------------------- - -// breakpoints are set by storing the address of interest in a -// debug register and marking it 'enabled'. -// -// the first problem is, they are only accessible from Ring0; -// we get around this by updating their values via SetThreadContext. -// that in turn requires we suspend the current thread, -// spawn a helper to change the registers, and resume. - -// parameter passing to helper thread. currently static storage, -// but the struct simplifies switching to a queue later. -struct BreakInfo -{ - uintptr_t addr; - DbgBreakType type; - - // determines what brk_thread_func will do. - // set/reset by debug_remove_all_breaks. - bool want_all_disabled; -}; - -static BreakInfo brk_info; - -// Local Enable bits of all registers we enabled (used when restoring all). -static DWORD brk_all_local_enables; - -// IA-32 limit; will need to update brk_enable_in_ctx if this changes. -static const uint MAX_BREAKPOINTS = 4; - - -// remove all breakpoints enabled by debug_set_break from . -// called while target is suspended. -static LibError brk_disable_all_in_ctx(BreakInfo* UNUSED(bi), CONTEXT* context) -{ - context->Dr7 &= ~brk_all_local_enables; - return INFO::OK; -} - - -// find a free register, set type according to and -// mark it as enabled in . -// called while target is suspended. -static LibError brk_enable_in_ctx(BreakInfo* bi, CONTEXT* context) -{ - uint reg; // index (0..3) of first free reg - uint LE; // local enable bit for - - // find free debug register. - for(reg = 0; reg < MAX_BREAKPOINTS; reg++) - { - LE = BIT(reg*2); - // .. this one is currently not in use. - if((context->Dr7 & LE) == 0) - goto have_reg; - } - WARN_RETURN(ERR::LIMIT); -have_reg: - - // store breakpoint address in debug register. - DWORD addr = (DWORD)bi->addr; - // .. note: treating Dr0..Dr3 as an array is unsafe due to - // possible struct member padding. - switch(reg) - { - case 0: context->Dr0 = addr; break; - case 1: context->Dr1 = addr; break; - case 2: context->Dr2 = addr; break; - case 3: context->Dr3 = addr; break; - NODEFAULT; - } - - // choose breakpoint settings: - // .. type - uint rw = 0; - switch(bi->type) - { - case DBG_BREAK_CODE: - rw = 0; break; - case DBG_BREAK_DATA: - rw = 1; break; - case DBG_BREAK_DATA_WRITE: - rw = 3; break; - NODEFAULT; - } - // .. length (determine from addr's alignment). - // note: IA-32 requires len=0 for code breakpoints. - uint len = 0; - if(bi->type != DBG_BREAK_CODE) - { - const uint alignment = (uint)(bi->addr % 4); - // assume 2 byte range - if(alignment == 2) - len = 1; - // assume 4 byte range - else if(alignment == 0) - len = 3; - // else: 1 byte range; len already set to 0 - } - - // update Debug Control register - const uint shift = (16 + reg*4); - // .. clear previous contents of this reg's field - // (in case the previous user didn't do so on disabling). - context->Dr7 &= ~(0xFu << shift); - // .. write settings - context->Dr7 |= ((len << 2)|rw) << shift; - // .. mark as enabled - context->Dr7 |= LE; - - brk_all_local_enables |= LE; - return INFO::OK; -} - - -// carry out the request stored in the BreakInfo* parameter. -// called while target is suspended. -static LibError brk_do_request(HANDLE hThread, void* arg) -{ - LibError ret; - BreakInfo* bi = (BreakInfo*)arg; - - CONTEXT context; - context.ContextFlags = CONTEXT_DEBUG_REGISTERS; - if(!GetThreadContext(hThread, &context)) - WARN_RETURN(ERR::FAIL); - -#if ARCH_IA32 - if(bi->want_all_disabled) - ret = brk_disable_all_in_ctx(bi, &context); - else - ret = brk_enable_in_ctx (bi, &context); -#else -#error "port" -#endif - - if(!SetThreadContext(hThread, &context)) - WARN_RETURN(ERR::FAIL); - - RETURN_ERR(ret); - return INFO::OK; -} - - -// arrange for a debug exception to be raised when is accessed -// according to . -// for simplicity, the length (range of bytes to be checked) is -// derived from addr's alignment, and is typically 1 machine word. -// breakpoints are a limited resource (4 on IA-32); abort and -// return ERR::LIMIT if none are available. -LibError debug_set_break(void* p, DbgBreakType type) -{ - lock(); - - brk_info.addr = (uintptr_t)p; - brk_info.type = type; - LibError ret = call_while_suspended(brk_do_request, &brk_info); - - unlock(); - return ret; -} - - -// remove all breakpoints that were set by debug_set_break. -// important, since these are a limited resource. -LibError debug_remove_all_breaks() -{ - lock(); - - brk_info.want_all_disabled = true; - LibError ret = call_while_suspended(brk_do_request, &brk_info); - brk_info.want_all_disabled = false; - - unlock(); - return ret; + DEBUG_DISPLAY_ERROR(L"debug_heap_check: heap is corrupt"); } @@ -417,7 +140,7 @@ void debug_puts(const char* text) // 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 wdbg_set_thread_name(const char* name) +void debug_set_thread_name(const char* name) { // we pass information to the debugger via a special exception it // swallows. if not running under one, bail now to avoid @@ -444,3 +167,10 @@ void wdbg_set_thread_name(const char* name) debug_assert(0); // thread name hack doesn't work under this debugger } } + + +static LibError wdbg_Init() +{ + debug_heap_init(); + return INFO::OK; +} diff --git a/source/lib/sysdep/win/wdbg.h b/source/lib/sysdep/win/wdbg.h deleted file mode 100644 index 4969f75a7e..0000000000 --- a/source/lib/sysdep/win/wdbg.h +++ /dev/null @@ -1,23 +0,0 @@ -/** - * ========================================================================= - * File : wdbg.h - * Project : 0 A.D. - * Description : Win32 debug support code and exception handler. - * ========================================================================= - */ - -// license: GPL; see lib/license.txt - -#ifndef INCLUDED_WDBG -#define INCLUDED_WDBG - -#if MSC_VERSION -# define debug_break() __asm { int 3 } -#else -# error "port this or define to implementation function" -#endif - - -extern void wdbg_set_thread_name(const char* name); - -#endif // #ifndef INCLUDED_WDBG diff --git a/source/lib/sysdep/win/wdbg_sym.cpp b/source/lib/sysdep/win/wdbg_sym.cpp index 1b70bc0cbd..86a4cdb198 100644 --- a/source/lib/sysdep/win/wdbg_sym.cpp +++ b/source/lib/sysdep/win/wdbg_sym.cpp @@ -46,18 +46,6 @@ WINIT_REGISTER_MAIN_SHUTDOWN(wdbg_sym_Shutdown); // nested stack traces are ignored and only the error is displayed. -// protects the non-reentrant dbghelp library. -static void lock() -{ - win_lock(WDBG_SYM_CS); -} - -static void unlock() -{ - win_unlock(WDBG_SYM_CS); -} - - //---------------------------------------------------------------------------- // dbghelp //---------------------------------------------------------------------------- @@ -162,7 +150,7 @@ static LibError debug_resolve_symbol_lk(void* ptr_of_interest, char* sym_name, c SYMBOL_INFOW* sym = &sp.si; if(SymFromAddrW(hProcess, addr, 0, sym)) { - snprintf(sym_name, DBG_SYMBOL_LEN, "%ws", sym->Name); + sprintf_s(sym_name, DBG_SYMBOL_LEN, "%ws", sym->Name); successes++; } } @@ -184,7 +172,7 @@ static LibError debug_resolve_symbol_lk(void* ptr_of_interest, char* sym_name, c // problem and is balanced by not having to do this from every // call site (full path is too long to display nicely). const char* base_name = path_name_only(line_info.FileName); - snprintf(file, DBG_FILE_LEN, "%s", base_name); + sprintf_s(file, DBG_FILE_LEN, "%s", base_name); successes++; } @@ -208,10 +196,8 @@ static LibError debug_resolve_symbol_lk(void* ptr_of_interest, char* sym_name, c // the PDB implementation is rather slow (~500µs). LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int* line) { - lock(); - LibError ret = debug_resolve_symbol_lk(ptr_of_interest, sym_name, file, line); - unlock(); - return ret; + WinScopedLock lock(WDBG_SYM_CS); + return debug_resolve_symbol_lk(ptr_of_interest, sym_name, file, line); } @@ -468,34 +454,20 @@ static LibError nth_caller_cb(const STACKFRAME64* sf, void* user_arg) return INFO::OK; } - -// return address of the Nth function on the call stack. -// if is nonzero, it is assumed to be a platform-specific -// representation of execution state (e.g. Win32 CONTEXT) and tracing -// starts there; this is useful for exceptions. -// otherwise, tracing starts at the current stack position, and the given -// number of stack frames (i.e. functions) above the caller are skipped. -// used by mmgr to determine what function requested each allocation; -// this is fast enough to allow that. void* debug_get_nth_caller(uint skip, void* pcontext) { - lock(); - + WinScopedLock lock(WDBG_SYM_CS); void* func; skip_this_frame(skip, pcontext); - LibError err = walk_stack(nth_caller_cb, &func, skip, (const CONTEXT*)pcontext); - - unlock(); - return (err == INFO::OK)? func : 0; + LibError ret = walk_stack(nth_caller_cb, &func, skip, (const CONTEXT*)pcontext); + return (ret == INFO::OK)? func : 0; } -////////////////////////////////////////////////////////////////////////////// -// +//----------------------------------------------------------------------------- // helper routines for symbol value dump -// -////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- // overflow is impossible in practice, but check for robustness. // keep in sync with DumpState. @@ -1444,7 +1416,7 @@ static LibError udt_dump_std(const wchar_t* wtype_name, const u8* p, size_t size // convert to char since debug_stl doesn't support wchar_t. char ctype_name[DBG_SYMBOL_LEN]; - snprintf(ctype_name, ARRAY_SIZE(ctype_name), "%ws", wtype_name); + sprintf_s(ctype_name, ARRAY_SIZE(ctype_name), "%ws", wtype_name); // display contents of STL containers // .. get element type @@ -1481,7 +1453,7 @@ not_valid_container: // .. some other error encountered else { - snprintf(buf, ARRAY_SIZE(buf), "error %d while analyzing ", err); + sprintf_s(buf, ARRAY_SIZE(buf), "error %d while analyzing ", err); text = buf; } out(L"(%hs%hs)", text, debug_stl_simplify_name(ctype_name)); @@ -1771,35 +1743,9 @@ static LibError dump_sym(DWORD type_id, const u8* p, DumpState state) } -////////////////////////////////////////////////////////////////////////////// -// +//----------------------------------------------------------------------------- // stack trace -// -////////////////////////////////////////////////////////////////////////////// - -// output the symbol's name and value via dump_sym*. -// called from dump_frame_cb for each local symbol; lock is held. -static BOOL CALLBACK dump_sym_cb(SYMBOL_INFO* sym, ULONG UNUSED(size), void* UNUSED(ctx)) -{ - out_latch_pos(); // see decl - mod_base = sym->ModBase; - const u8* p = (const u8*)sym->Address; - DumpState state; - - INDENT; - LibError err = dump_sym(sym->Index, p, state); - dump_error(err, p); - if(err == INFO::SYM_SUPPRESS_OUTPUT) - UNINDENT; - else - out(L"\r\n"); - - return TRUE; // continue -} - - -////////////////////////////////////////////////////////////////////////////// - +//----------------------------------------------------------------------------- struct IMAGEHLP_STACK_FRAME2 : public IMAGEHLP_STACK_FRAME { @@ -1821,6 +1767,26 @@ struct IMAGEHLP_STACK_FRAME2 : public IMAGEHLP_STACK_FRAME } }; +// output the symbol's name and value via dump_sym*. +// called from dump_frame_cb for each local symbol; lock is held. +static BOOL CALLBACK dump_sym_cb(SYMBOL_INFO* sym, ULONG UNUSED(size), void* UNUSED(ctx)) +{ + out_latch_pos(); // see decl + mod_base = sym->ModBase; + const u8* p = (const u8*)sym->Address; + DumpState state; + + INDENT; + LibError err = dump_sym(sym->Index, p, state); + dump_error(err, p); + if(err == INFO::SYM_SUPPRESS_OUTPUT) + UNINDENT; + else + out(L"\r\n"); + + return TRUE; // continue +} + // called by walk_stack for each stack frame static LibError dump_frame_cb(const STACKFRAME64* sf, void* UNUSED(user_arg)) { @@ -1869,23 +1835,21 @@ return INFO::OK; static uintptr_t already_in_progress; if(!cpu_CAS(&already_in_progress, 0, 1)) return ERR::REENTERED; // NOWARN - lock(); out_init(buf, max_chars); ptr_reset_visited(); + WinScopedLock lock(WDBG_SYM_CS); skip_this_frame(skip, pcontext); LibError ret = walk_stack(dump_frame_cb, 0, skip, (const CONTEXT*)pcontext); - unlock(); already_in_progress = 0; return ret; } - - +//----------------------------------------------------------------------------- // write out a "minidump" containing register and stack state; this enables // examining the crash in a debugger. called by wdbg_exception_filter. @@ -1893,12 +1857,15 @@ return INFO::OK; // lock must be held. void wdbg_sym_write_minidump(EXCEPTION_POINTERS* exception_pointers) { - lock(); + WinScopedLock lock(WDBG_SYM_CS); OsPath path = OsPath(ah_get_log_dir())/"crashlog.dmp"; HANDLE hFile = CreateFile(path.string().c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0); if(hFile == INVALID_HANDLE_VALUE) - goto fail; + { + DEBUG_DISPLAY_ERROR(L"wdbg_sym_write_minidump: unable to create crashlog.dmp."); + return; + } MINIDUMP_EXCEPTION_INFORMATION mei; mei.ThreadId = GetCurrentThreadId(); @@ -1912,16 +1879,13 @@ void wdbg_sym_write_minidump(EXCEPTION_POINTERS* exception_pointers) HANDLE hProcess = GetCurrentProcess(); DWORD pid = GetCurrentProcessId(); if(!MiniDumpWriteDump(hProcess, pid, hFile, MiniDumpNormal, &mei, 0, 0)) - { -fail: - DISPLAY_ERROR(L"Unable to generate minidump."); - } + DEBUG_DISPLAY_ERROR(L"wdbg_sym_write_minidump: unable to generate minidump."); CloseHandle(hFile); - unlock(); } +//----------------------------------------------------------------------------- static LibError wdbg_sym_Init() { diff --git a/source/lib/sysdep/win/wdir_watch.cpp b/source/lib/sysdep/win/wdir_watch.cpp index 19933c00f8..ebbc06a28b 100644 --- a/source/lib/sysdep/win/wdir_watch.cpp +++ b/source/lib/sysdep/win/wdir_watch.cpp @@ -159,13 +159,11 @@ static Events* pending_events; static void AllocStaticObjects() { STATIC_STORAGE(ss, 200); -#include "lib/nommgr.h" void* addr1 = static_calloc(&ss, sizeof(Watches)); watches = new(addr1) Watches; void* addr2 = static_calloc(&ss, sizeof(Events)); pending_events = new(addr2) Events; -#include "lib/mmgr.h" } static void FreeStaticObjects() diff --git a/source/lib/sysdep/win/wdll_delay_load.cpp b/source/lib/sysdep/win/wdll_delay_load.cpp index 370e9f0ae0..7d6d9e9ad3 100644 --- a/source/lib/sysdep/win/wdll_delay_load.cpp +++ b/source/lib/sysdep/win/wdll_delay_load.cpp @@ -181,8 +181,6 @@ CountOfImports(PCImgThunkData pitdBase) { extern "C" PUnloadInfo __puiHead = 0; -#include "lib/nommgr.h" - struct ULI : public UnloadInfo { ULI(PCImgDelayDescr pidd_) @@ -213,8 +211,6 @@ struct ULI : public UnloadInfo } }; -#include "lib/mmgr.h" - // For our own internal use, we convert to the old // format for convenience. @@ -354,9 +350,7 @@ extern "C" FARPROC WINAPI __delayLoadHelper2(PCImgDelayDescr pidd, FARPROC* ppfn if (hmodT != hmod) { // add lib to unload list if we have unload data if (pidd->rvaUnloadIAT) { -#include "lib/nommgr.h" new ULI(pidd); -#include "lib/mmgr.h" } } else { diff --git a/source/lib/sysdep/win/whrt/counter.cpp b/source/lib/sysdep/win/whrt/counter.cpp index f138f5ffc1..51d35b79bd 100644 --- a/source/lib/sysdep/win/whrt/counter.cpp +++ b/source/lib/sysdep/win/whrt/counter.cpp @@ -35,8 +35,6 @@ static ICounter* ConstructCounterAt(uint id, void* address, size_t size) { // rationale for placement new: see call site. -#include "lib/nommgr.h" // MMGR interferes with placement new - // counters are chosen according to the following order. rationale: // - TSC must come before QPC and PMT to make sure a bug in the latter on // Pentium systems doesn't come up. @@ -63,8 +61,6 @@ static ICounter* ConstructCounterAt(uint id, void* address, size_t size) default: return 0; } - -#include "lib/mmgr.h" } diff --git a/source/lib/sysdep/win/wposix/crt_posix.h b/source/lib/sysdep/win/wposix/crt_posix.h index ada18d0484..94ed4b1ccb 100644 --- a/source/lib/sysdep/win/wposix/crt_posix.h +++ b/source/lib/sysdep/win/wposix/crt_posix.h @@ -22,7 +22,7 @@ #define __STDC__ 1 #include // _open etc. -#include // _getcwd, _rmdir +#include // _rmdir #undef __STDC__ #define __STDC__ 0 diff --git a/source/lib/sysdep/win/wposix/waio.cpp b/source/lib/sysdep/win/wposix/waio.cpp index 256c53f0f1..15f71e8afa 100644 --- a/source/lib/sysdep/win/wposix/waio.cpp +++ b/source/lib/sysdep/win/wposix/waio.cpp @@ -51,14 +51,14 @@ public: debug_assert(fd > 2); debug_assert(GetFileSize(hFile, 0) != INVALID_FILE_SIZE); - WinScopedLock lock; + WinScopedLock lock(WAIO_CS); std::pair ret = m_map.insert(std::make_pair(fd, hFile)); debug_assert(ret.second); // fd better not already have been associated } void Dissociate(int fd) { - WinScopedLock lock; + WinScopedLock lock(WAIO_CS); const size_t numRemoved = m_map.erase(fd); debug_assert(numRemoved == 1); } @@ -69,7 +69,7 @@ public: **/ HANDLE Get(int fd) const { - WinScopedLock lock; + WinScopedLock lock(WAIO_CS); Map::const_iterator it = m_map.find(fd); if(it == m_map.end()) return INVALID_HANDLE_VALUE; diff --git a/source/lib/sysdep/win/wposix/wposix.cpp b/source/lib/sysdep/win/wposix/wposix.cpp index 988f73bde7..9f3a5128e2 100644 --- a/source/lib/sysdep/win/wposix/wposix.cpp +++ b/source/lib/sysdep/win/wposix/wposix.cpp @@ -12,7 +12,6 @@ #include "wposix.h" #include "wposix_internal.h" -#include "crt_posix.h" // _getcwd #include "lib/bits.h" WINIT_REGISTER_CRITICAL_INIT(wposix_Init); // wposix -> error handling @@ -104,20 +103,6 @@ long sysconf(int name) } -//----------------------------------------------------------------------------- - -#ifdef REDEFINED_NEW -# include "lib/nommgr.h" -#endif -char* getcwd(char* buf, size_t buf_size) -{ - return _getcwd(buf, (int)buf_size); -} -#ifdef REDEFINED_NEW -# include "lib/mmgr.h" -#endif - - //----------------------------------------------------------------------------- static LibError wposix_Init() diff --git a/source/lib/sysdep/win/wposix/wposix.h b/source/lib/sysdep/win/wposix/wposix.h index 19d394d809..6d35eca880 100644 --- a/source/lib/sysdep/win/wposix/wposix.h +++ b/source/lib/sysdep/win/wposix/wposix.h @@ -35,8 +35,6 @@ // misc routines -extern char* getcwd(char*, size_t); - // user tests if available via #ifdef; can't use enum. #define _SC_PAGESIZE 1 #define _SC_PAGE_SIZE 1 diff --git a/source/lib/sysdep/win/wposix/wpthread.cpp b/source/lib/sysdep/win/wposix/wpthread.cpp index d1981217d8..9cba1a0418 100644 --- a/source/lib/sysdep/win/wposix/wpthread.cpp +++ b/source/lib/sysdep/win/wposix/wpthread.cpp @@ -231,9 +231,8 @@ again: // initializer returns pthread_mutex_t directly and CRITICAL_SECTIONS // shouldn't be copied. // -// note: must not use new/malloc to allocate the critical section -// because mmgr.cpp uses a mutex and must not be called to allocate -// anything before it is initialized. +// note: we use win_alloc instead of new because the (no longer extant) +// memory manager used a pthread_mutex. pthread_mutex_t pthread_mutex_initializer() { diff --git a/source/lib/sysdep/win/wsdl.cpp b/source/lib/sysdep/win/wsdl.cpp index 9fe10ee60e..ed08d1d13c 100644 --- a/source/lib/sysdep/win/wsdl.cpp +++ b/source/lib/sysdep/win/wsdl.cpp @@ -11,7 +11,7 @@ #include "precompiled.h" #include "lib/external_libraries/sdl.h" -#if CONFIG_USE_WSDL +#if CONFIG2_WSDL #include #include @@ -1230,4 +1230,4 @@ static LibError wsdl_Shutdown() return INFO::OK; } -#endif // #if CONFIG_USE_WSDL +#endif // #if CONFIG2_WSDL diff --git a/source/lib/sysdep/win/wseh.cpp b/source/lib/sysdep/win/wseh.cpp index a75be32d99..c1a130b2fb 100644 --- a/source/lib/sysdep/win/wseh.cpp +++ b/source/lib/sysdep/win/wseh.cpp @@ -9,7 +9,7 @@ // license: GPL; see lib/license.txt #include "precompiled.h" -#include "wdbg.h" +#include "wseh.h" #include "lib/byte_order.h" // FOURCC #include "lib/sysdep/cpu.h" @@ -217,7 +217,7 @@ static void GetExceptionLocus(const EXCEPTION_POINTERS* ep, // // note: keep memory allocs and locking to an absolute minimum, because // they may deadlock the process! -LONG WINAPI wseh_ExceptionFilter(EXCEPTION_POINTERS* ep) +long __stdcall wseh_ExceptionFilter(struct _EXCEPTION_POINTERS* ep) { // OutputDebugString raises an exception, which OUGHT to be swallowed // by WaitForDebugEvent but sometimes isn't. if we see it, ignore it. @@ -241,7 +241,7 @@ LONG WINAPI wseh_ExceptionFilter(EXCEPTION_POINTERS* ep) // we'll report this problem first and then try to display the // exception info regardless (maybe dbghelp won't blow up). if(win_is_locked(WDBG_SYM_CS) == 1) - DISPLAY_ERROR(L"Exception raised while critical section is held - may deadlock.."); + DEBUG_DISPLAY_ERROR(L"Exception raised while critical section is held - may deadlock.."); // extract details from ExceptionRecord. wchar_t descriptionBuf[150]; diff --git a/source/lib/sysdep/win/wseh.h b/source/lib/sysdep/win/wseh.h index 7ce4b7b0ac..c66ea80e36 100644 --- a/source/lib/sysdep/win/wseh.h +++ b/source/lib/sysdep/win/wseh.h @@ -11,7 +11,8 @@ #ifndef INCLUDED_WSEH #define INCLUDED_WSEH -extern LONG WINAPI wseh_ExceptionFilter(EXCEPTION_POINTERS* ep); +struct _EXCEPTION_POINTERS; +extern long __stdcall wseh_ExceptionFilter(_EXCEPTION_POINTERS* ep); EXTERN_C int wseh_EntryPoint(); diff --git a/source/lib/sysdep/win/wutil.cpp b/source/lib/sysdep/win/wutil.cpp index f43de64be6..2bec83ff13 100644 --- a/source/lib/sysdep/win/wutil.cpp +++ b/source/lib/sysdep/win/wutil.cpp @@ -55,29 +55,29 @@ void win_free(void* p) static CRITICAL_SECTION cs[NUM_CS]; static bool cs_valid; -void win_lock(uint idx) +void win_lock(WinLockId id) { - debug_assert(idx < NUM_CS && "win_lock: invalid critical section index"); - if(cs_valid) - EnterCriticalSection(&cs[idx]); -} - -void win_unlock(uint idx) -{ - debug_assert(idx < NUM_CS && "win_unlock: invalid critical section index"); - if(cs_valid) - LeaveCriticalSection(&cs[idx]); -} - -int win_is_locked(uint idx) -{ - debug_assert(idx < NUM_CS && "win_is_locked: invalid critical section index"); if(!cs_valid) - return -1; - BOOL got_it = TryEnterCriticalSection(&cs[idx]); - if(got_it) - LeaveCriticalSection(&cs[idx]); - return !got_it; + return; + EnterCriticalSection(&cs[id]); +} + +void win_unlock(WinLockId id) +{ + if(!cs_valid) + return; + LeaveCriticalSection(&cs[id]); +} + +bool win_is_locked(WinLockId id) +{ + if(!cs_valid) + return false; + const BOOL successfullyEntered = TryEnterCriticalSection(&cs[id]); + if(!successfullyEntered) + return true; // still locked + LeaveCriticalSection(&cs[id]); + return false; // probably not locked } @@ -270,16 +270,6 @@ static void FreeUser32Dll() //----------------------------------------------------------------------------- // memory -// note: has no effect if config.h's HAVE_VC_DEBUG_ALLOC is 0. -static void EnableMemoryTracking() -{ -#if CONFIG_PARANOIA - debug_heap_enable(DEBUG_HEAP_ALL); -#elif !defined(NDEBUG) - debug_heap_enable(DEBUG_HEAP_NORMAL); -#endif -} - static void EnableLowFragmentationHeap() { #if WINVER >= 0x0501 @@ -488,8 +478,6 @@ static LibError wutil_Init() ForciblyLoadUser32Dll(); - EnableMemoryTracking(); - EnableLowFragmentationHeap(); ReadCommandLine(); diff --git a/source/lib/sysdep/win/wutil.h b/source/lib/sysdep/win/wutil.h index 2d09dfd141..4dca9b5adf 100644 --- a/source/lib/sysdep/win/wutil.h +++ b/source/lib/sysdep/win/wutil.h @@ -31,46 +31,36 @@ extern void win_free(void* p); // // critical sections used by win-specific code -enum +enum WinLockId { - ONCE_CS, WAIO_CS, - WDBG_CS, - WDBG_SYM_CS, + WDBG_SYM_CS, // protects (non-reentrant) dbghelp.dll NUM_CS }; -extern void win_lock(uint idx); -extern void win_unlock(uint idx); +extern void win_lock(WinLockId id); +extern void win_unlock(WinLockId id); -// used in a desperate attempt to avoid deadlock in wdbg_exception_handler. -extern int win_is_locked(uint idx); +// used in a desperate attempt to avoid deadlock in wseh. +extern bool win_is_locked(WinLockId id); -// thread safe, usable in constructors -#define WIN_ONCE(code)\ -{\ - win_lock(ONCE_CS);\ - static bool ONCE_init_; /* avoid name conflict */\ - if(!ONCE_init_)\ - {\ - ONCE_init_ = true;\ - code;\ - }\ - win_unlock(ONCE_CS);\ -} - -struct WinScopedLock +class WinScopedLock { - WinScopedLock() +public: + WinScopedLock(WinLockId id) + : m_id(id) { - win_lock(WAIO_CS); + win_lock(m_id); } ~WinScopedLock() { - win_unlock(WAIO_CS); + win_unlock(m_id); } + +private: + WinLockId m_id; }; diff --git a/source/lib/timer.cpp b/source/lib/timer.cpp index 891096a29a..e12e5c89ef 100644 --- a/source/lib/timer.cpp +++ b/source/lib/timer.cpp @@ -24,7 +24,8 @@ #if OS_UNIX # include #endif -#if ARCH_IA32 && CONFIG_TIMER_ALLOW_RDTSC +#include "lib/config2.h" // CONFIG2_TIMER_ALLOW_RDTSC +#if ARCH_IA32 && CONFIG2_TIMER_ALLOW_RDTSC # include "lib/sysdep/ia32/ia32.h" // ia32_rdtsc #endif @@ -162,12 +163,12 @@ ScopeTimer::~ScopeTimer() // therefore, on systems with SpeedStep active, measurements of I/O or other // non-CPU bound activity may be skewed. this is ok because the timer is // only used for profiling; just be aware of the issue. -// if this is a problem, disable CONFIG_TIMER_ALLOW_RDTSC. +// if this is a problem, disable CONFIG2_TIMER_ALLOW_RDTSC. // // note that overflow isn't an issue either way (63 bit cycle counts // at 10 GHz cover intervals of 29 years). -#if ARCH_IA32 && CONFIG_TIMER_ALLOW_RDTSC +#if ARCH_IA32 && CONFIG2_TIMER_ALLOW_RDTSC void TimerUnit::SetToZero() { diff --git a/source/main.cpp b/source/main.cpp index e2a8cb7977..e135873336 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -107,7 +107,7 @@ return false; // nothing to do; will return false below } else if(ret < 0) - DISPLAY_ERROR(L"Archive build failed"); + DEBUG_DISPLAY_ERROR(L"Archive build failed"); else if(ret == INFO::OK) g_GUI.SendEventToAll("archivebuildercomplete"); // in progress diff --git a/source/ps/GameSetup/Atlas.cpp b/source/ps/GameSetup/Atlas.cpp index 9da794ea52..8aaf3a4410 100644 --- a/source/ps/GameSetup/Atlas.cpp +++ b/source/ps/GameSetup/Atlas.cpp @@ -14,7 +14,7 @@ DllLoader atlas_dll("AtlasUI"); enum AtlasRunFlags { // used by ATLAS_RunIfOnCmdLine; makes any error output go through - // DISPLAY_ERROR rather than a GUI dialog box (because GUI init was + // DEBUG_DISPLAY_ERROR rather than a GUI dialog box (because GUI init was // skipped to reduce load time). ATLAS_NO_GUI = 1 }; @@ -26,9 +26,9 @@ static void ATLAS_Run(const CmdLineArgs& args, int flags = 0) if(!atlas_dll.LoadDLL()) { if(flags & ATLAS_NO_GUI) - DISPLAY_ERROR(L"The Atlas UI was not successfully loaded and therefore cannot be started as requested."); + DEBUG_DISPLAY_ERROR(L"The Atlas UI was not successfully loaded and therefore cannot be started as requested."); else - DISPLAY_ERROR(L"The Atlas UI was not successfully loaded and therefore cannot be started as requested.");// TODO: implement GUI error message + DEBUG_DISPLAY_ERROR(L"The Atlas UI was not successfully loaded and therefore cannot be started as requested.");// TODO: implement GUI error message return; } diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index 10f249dbf3..33c774ae5d 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -863,7 +863,6 @@ void Shutdown(uint flags) timer_DisplayClientTotals(); // should be last, since the above use them - debug_shutdown(); SAFE_DELETE(g_Logger); delete &g_Profiler; delete &g_ProfileViewer; @@ -1013,13 +1012,13 @@ void Init(const CmdLineArgs& args, uint flags) L" The game may still work, though - you are welcome to try at your own risk." L" If not or it doesn't look right, upgrade your graphics card."; swprintf(buf, ARRAY_SIZE(buf), fmt, missing); - DISPLAY_ERROR(buf); + DEBUG_DISPLAY_ERROR(buf); // TODO: i18n } if (!ogl_HaveExtension("GL_ARB_texture_env_crossbar")) { - DISPLAY_ERROR( + DEBUG_DISPLAY_ERROR( L"The GL_ARB_texture_env_crossbar extension doesn't appear to be available on your computer." L" Shadows are not available and overall graphics quality might suffer." L" You are advised to try installing newer drivers and/or upgrade your graphics card."); @@ -1071,12 +1070,6 @@ void Init(const CmdLineArgs& args, uint flags) // Register a few Game/Network JS globals g_ScriptingHost.SetGlobal("g_GameAttributes", OBJECT_TO_JSVAL(g_GameAttributes.GetScript())); } - - - // Check for heap corruption after every allocation. Very, very slowly. - // (And it highlights the allocation just after the one you care about, - // so you need to run it again and tell it to break on the one before.) -// debug_heap_enable(DEBUG_HEAP_ALL); InitInput(); diff --git a/source/ps/XML/XML.h b/source/ps/XML/XML.h index b843ae3b0b..11310ed481 100644 --- a/source/ps/XML/XML.h +++ b/source/ps/XML/XML.h @@ -20,9 +20,6 @@ #ifndef INCLUDED_XML #define INCLUDED_XML -// Temporarily undefine new, because the Xerces headers don't like it -#include "lib/nommgr.h" - // temporarily go down to W3 because Xerces (in addition to all its other // failings) isn't W4-clean. #if MSC_VERSION @@ -52,8 +49,6 @@ #pragma warning(pop) // back to W4 #endif -#include "lib/mmgr.h" // restore malloc/new macros - #include "XercesErrorHandler.h" #include "ps/CStr.h" #include "lib/file/vfs/vfs_path.h" diff --git a/source/ps/XML/XMLUtils.cpp b/source/ps/XML/XMLUtils.cpp index f8f5eeeb0f..23bdca1a55 100644 --- a/source/ps/XML/XMLUtils.cpp +++ b/source/ps/XML/XMLUtils.cpp @@ -71,9 +71,7 @@ BinInputStream *CVFSInputSource::makeStream() const if(!m_pBuffer) return 0; -#include "lib/nommgr.h" // BinMemInputStream has its own operator new return new BinMemInputStream((XMLByte *)m_pBuffer.get(), (unsigned int)m_BufferSize, BinMemInputStream::BufOpt_Reference); -#include "lib/mmgr.h" } #define IS_PATH_SEP(_chr) (_chr == '/' || _chr == '\\') @@ -91,9 +89,7 @@ const char *prevpathcomp(const char *end, const char *beginning) InputSource *CVFSEntityResolver::resolveEntity(const XMLCh *const UNUSED(publicId), const XMLCh *const systemId) { -#include "lib/nommgr.h" CVFSInputSource *ret=new CVFSInputSource(); -#include "lib/mmgr.h" char *path=XMLString::transcode(systemId); char *orgpath=path; diff --git a/source/ps/XML/XercesErrorHandler.cpp b/source/ps/XML/XercesErrorHandler.cpp index 3d70895e3b..6605ba34db 100644 --- a/source/ps/XML/XercesErrorHandler.cpp +++ b/source/ps/XML/XercesErrorHandler.cpp @@ -7,7 +7,6 @@ Xerces Error Handler for Pyrogenesis (and the GUI) // --------------------------------------------------------------------------- #include "precompiled.h" -#include "lib/nommgr.h" #include "XercesErrorHandler.h" #include diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index f8fa031776..73241a6cfa 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -1574,7 +1574,7 @@ ogl_tex_transform_to(textures[i], flags & ~TEX_DXT); } // .. not first: make sure texture size matches else if(base != this_width || bpp != this_bpp) - DISPLAY_ERROR(L"Alpha maps are not identically sized (including pixel depth)"); + DEBUG_DISPLAY_ERROR(L"Alpha maps are not identically sized (including pixel depth)"); } // diff --git a/source/scripting/ScriptableComplex.inl b/source/scripting/ScriptableComplex.inl index 278df29fad..fd9038f8d8 100644 --- a/source/scripting/ScriptableComplex.inl +++ b/source/scripting/ScriptableComplex.inl @@ -940,9 +940,7 @@ void CJSComplex::AddProperty( const CStrW& PropertyName, jsval Valu { DeletePreviouslyAssignedProperty( PropertyName ); void* mem = jscomplexproperty_suballoc(); -#include "lib/nommgr.h" CJSDynamicComplexProperty* newProp = new(mem) CJSValComplexProperty( Value, false ); -#include "lib/mmgr.h" m_Properties[PropertyName] = newProp; ReflectorTable::iterator it; @@ -1091,9 +1089,7 @@ void MemberAddPropertyImpl( IJSComplex* obj, const CStrW& PropertyName, PropType { ((T*)obj)->DeletePreviouslyAssignedProperty( PropertyName ); void* mem = jscomplexproperty_suballoc(); -#include "lib/nommgr.h" obj->m_Properties[PropertyName] = new(mem) CJSComplexProperty( Native, PropAllowInheritance, Update, Refresh ); -#include "lib/mmgr.h" } // PropertyName must not already exist! (verified in debug build) @@ -1102,9 +1098,7 @@ void MemberAddReadOnlyPropertyImpl( IJSComplex* obj, const CStrW& PropertyName, { ((T*)obj)->DeletePreviouslyAssignedProperty( PropertyName ); void* mem = jscomplexproperty_suballoc(); -#include "lib/nommgr.h" obj->m_Properties[PropertyName] = new(mem) CJSComplexProperty( Native, PropAllowInheritance, Update, Refresh ); -#include "lib/mmgr.h" } #endif diff --git a/source/tools/atlas/GameInterface/Shareable.h b/source/tools/atlas/GameInterface/Shareable.h index d16f76647e..f3ca23a718 100644 --- a/source/tools/atlas/GameInterface/Shareable.h +++ b/source/tools/atlas/GameInterface/Shareable.h @@ -45,17 +45,9 @@ after their definition. #include #include -// We want to use placement new, which breaks when compiling Debug configurations -// in the game and in wx, and they both need different workarounds. +// we want to use placement new without grief // (Duplicated in SharedMemory.h) -#ifdef new -# define SHAREABLE_USED_NOMMGR -# ifdef __WXWINDOWS__ -# undef new -# else -# include "lib/nommgr.h" -# endif -#endif +#undef new namespace AtlasMessage { @@ -295,13 +287,4 @@ public: } -#ifdef SHAREABLE_USED_NOMMGR -# ifdef __WXWINDOWS__ // TODO: portability to non-Windows wx -# define new new( _NORMAL_BLOCK, __FILE__, __LINE__) -# else -# include "mmgr.h" -# endif -# undef SHAREABLE_USED_NOMMGR -#endif - #endif // INCLUDED_SHAREABLE diff --git a/source/tools/atlas/GameInterface/SharedMemory.h b/source/tools/atlas/GameInterface/SharedMemory.h index d948889259..f16202abf0 100644 --- a/source/tools/atlas/GameInterface/SharedMemory.h +++ b/source/tools/atlas/GameInterface/SharedMemory.h @@ -1,17 +1,9 @@ #ifndef INCLUDED_SHAREDMEMORY #define INCLUDED_SHAREDMEMORY -// We want to use placement new, which breaks when compiling Debug configurations -// in the game and in wx, and they both need different workarounds. +// we want to use placement new without grief // (Duplicated in Shareable.h) -#ifdef new -# define SHAREABLE_USED_NOMMGR -# ifdef __WXWINDOWS__ -# undef new -# else -# include "lib/nommgr.h" -# endif -#endif +#undef new namespace AtlasMessage { @@ -40,25 +32,4 @@ template void ShareableDelete(T* p) } - -#ifdef SHAREABLE_USED_NOMMGR -// # ifdef __WXWINDOWS__ // TODO: portability to non-Windows wx -// # define new new( _NORMAL_BLOCK, __FILE__, __LINE__) -// # else -// # include "mmgr.h" -// # endif -// Actually, we don't want to redefine 'new', because it conflicts with all users -// of SHAREABLE_NEW. So just leave it undefined, and put up with the less -// informative leak messages. -# undef SHAREABLE_USED_NOMMGR -// Oh, but we don't want other game headers to include mmgr.h again. -// So let's just cheat horribly and remove the options which cause it to -// redefine new. -# undef HAVE_VC_DEBUG_ALLOC -# define HAVE_VC_DEBUG_ALLOC 0 -# undef CONFIG_USE_MMGR -# define CONFIG_USE_MMGR 0 -#endif - - #endif // INCLUDED_SHAREDMEMORY