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.
This commit is contained in:
parent
3d571150ae
commit
9269be9ee3
@ -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"
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#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 T> 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
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
64
source/lib/config2.h
Normal file
64
source/lib/config2.h
Normal file
@ -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
|
@ -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 <string> (must remain valid) with <symbol>, 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 <name> 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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -572,9 +572,7 @@ template<class T> 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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
#include "lib/allocators/pool.h"
|
||||
#include "lib/timer.h" // timer_Time
|
||||
#include "lib/nommgr.h" // placement new
|
||||
|
||||
/*virtual*/ ITrace::~ITrace()
|
||||
{
|
||||
|
@ -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));
|
||||
|
@ -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<u8> buf);
|
||||
|
||||
|
@ -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().
|
||||
*
|
||||
|
@ -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
|
@ -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
|
@ -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 <string>
|
||||
#include <sstream>
|
||||
#include <typeinfo>
|
||||
#include <valarray>
|
||||
#include <valarray>
|
||||
|
||||
// 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"
|
||||
|
@ -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.");
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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");\
|
||||
)
|
||||
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 <context>.
|
||||
// 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 <bi> and
|
||||
// mark it as enabled in <context>.
|
||||
// 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 <reg>
|
||||
|
||||
// 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 <addr> is accessed
|
||||
// according to <type>.
|
||||
// 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;
|
||||
}
|
||||
|
@ -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
|
@ -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 <context> 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()
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
#define __STDC__ 1
|
||||
|
||||
#include <io.h> // _open etc.
|
||||
#include <direct.h> // _getcwd, _rmdir
|
||||
#include <direct.h> // _rmdir
|
||||
|
||||
#undef __STDC__
|
||||
#define __STDC__ 0
|
||||
|
@ -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<Map::iterator, bool> 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;
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "precompiled.h"
|
||||
#include "lib/external_libraries/sdl.h"
|
||||
|
||||
#if CONFIG_USE_WSDL
|
||||
#if CONFIG2_WSDL
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
@ -1230,4 +1230,4 @@ static LibError wsdl_Shutdown()
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
#endif // #if CONFIG_USE_WSDL
|
||||
#endif // #if CONFIG2_WSDL
|
||||
|
@ -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];
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -24,7 +24,8 @@
|
||||
#if OS_UNIX
|
||||
# include <unistd.h>
|
||||
#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()
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
||||
|
@ -7,7 +7,6 @@ Xerces Error Handler for Pyrogenesis (and the GUI)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "lib/nommgr.h"
|
||||
|
||||
#include "XercesErrorHandler.h"
|
||||
#include <iostream>
|
||||
|
@ -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)");
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -940,9 +940,7 @@ void CJSComplex<T, ReadOnly>::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<PropType, ReadOnly>( 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<PropType, true>( Native, PropAllowInheritance, Update, Refresh );
|
||||
#include "lib/mmgr.h"
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -45,17 +45,9 @@ after their definition.
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// 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
|
||||
|
@ -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<typename T> 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
|
||||
|
Loading…
Reference in New Issue
Block a user