mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-10-14 07:17:44 +00:00
move debug_microlog to debug.cpp, call it debug_wprintf_mem. move MICROLOG define to pyrogenesis.h.
major cleanup+documenting in debug.h; added breakpoint interface. sysdep: moved debug_out definition to udbg.cpp This was SVN commit r2287.
This commit is contained in:
@@ -26,6 +26,43 @@
|
||||
// so that our allocations don't cause infinite recursion.
|
||||
|
||||
|
||||
// needed when writing crashlog
|
||||
static const size_t LOG_CHARS = 16384;
|
||||
wchar_t debug_log[LOG_CHARS];
|
||||
wchar_t* debug_log_pos = debug_log;
|
||||
|
||||
// write to memory buffer (fast)
|
||||
void debug_wprintf_mem(const wchar_t* fmt, ...)
|
||||
{
|
||||
const ssize_t chars_left = (ssize_t)LOG_CHARS - (debug_log_pos-debug_log);
|
||||
assert2(chars_left >= 0);
|
||||
|
||||
// potentially not enough room for the new string; throw away the
|
||||
// older half of the log. we still protect against overflow below.
|
||||
if(chars_left < 512)
|
||||
{
|
||||
const size_t copy_size = sizeof(wchar_t) * LOG_CHARS/2;
|
||||
wchar_t* const middle = &debug_log[LOG_CHARS/2];
|
||||
memcpy(debug_log, middle, copy_size);
|
||||
memset(middle, 0, copy_size);
|
||||
debug_log_pos -= LOG_CHARS/2; // don't assign middle (may leave gap)
|
||||
}
|
||||
|
||||
// write into buffer (in-place)
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int len = vswprintf(debug_log_pos, chars_left-2, fmt, args);
|
||||
va_end(args);
|
||||
if(len < 0)
|
||||
{
|
||||
debug_warn("debug_wprintf_mem: vswprintf failed");
|
||||
return;
|
||||
}
|
||||
debug_log_pos += len+2;
|
||||
wcscpy(debug_log_pos-2, L"\r\n"); // safe
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// storage for and construction of strings describing a symbol
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
+61
-23
@@ -1,10 +1,23 @@
|
||||
// platform-independent debug interface
|
||||
// Copyright (c) 2002-2005 Jan Wassenberg
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef DEBUG_H_INCLUDED
|
||||
#define DEBUG_H_INCLUDED
|
||||
|
||||
// we need to include the platform-specific version here, so it can
|
||||
// define debug_break. if it can be implemented as a macro (e.g. on ia32),
|
||||
// the debugger will break directly at the target, instead of one function
|
||||
// below it as with a conventional implementation.
|
||||
#ifdef _WIN32
|
||||
# include "win/wdbg.h"
|
||||
#else
|
||||
@@ -16,10 +29,27 @@
|
||||
// assert
|
||||
//
|
||||
|
||||
// notify the user that an assertion failed.
|
||||
// displays a stack trace with local variables on Windows.
|
||||
// return values: 0 = continue; 1 = suppress; 2 = break
|
||||
// .. or exits the program if the user so chooses.
|
||||
enum FailedAssertUserChoice
|
||||
{
|
||||
// ignore, continue as if nothing happened.
|
||||
ASSERT_CONTINUE,
|
||||
|
||||
// ignore and do not report again for this assert.
|
||||
ASSERT_SUPPRESS,
|
||||
// note: non-persistent; only applicable during this program run.
|
||||
|
||||
// trigger breakpoint, i.e. enter debugger.
|
||||
ASSERT_BREAK,
|
||||
|
||||
// exit the program immediately.
|
||||
ASSERT_EXIT
|
||||
// note: carried out by debug_assert_failed;
|
||||
// testing for it in assert2 would bloat code.
|
||||
};
|
||||
|
||||
// notify the user that an assertion failed; displays a
|
||||
// stack trace with local variables.
|
||||
// returns one of FailedAssertUserChoice or exits the program.
|
||||
extern int debug_assert_failed(const char* source_file, int line, const char* assert_expr);
|
||||
|
||||
// recommended use: assert2(expr && "descriptive string")
|
||||
@@ -29,10 +59,10 @@ STMT(\
|
||||
if(!suppress__ && !(expr))\
|
||||
switch(debug_assert_failed(__FILE__, __LINE__, #expr))\
|
||||
{\
|
||||
case 1:\
|
||||
case ASSERT_SUPPRESS:\
|
||||
suppress__ = 1;\
|
||||
break;\
|
||||
case 2:\
|
||||
case ASSERT_BREAK:\
|
||||
debug_break();\
|
||||
break;\
|
||||
}\
|
||||
@@ -43,13 +73,13 @@ STMT(\
|
||||
// output
|
||||
//
|
||||
|
||||
// output to the debugger (may take ~1 ms!)
|
||||
extern void debug_out(const char* fmt, ...);
|
||||
// write to the debugger output window (may take ~1 ms!)
|
||||
extern void debug_printf(const char* fmt, ...);
|
||||
|
||||
// log to memory buffer (fast)
|
||||
#define MICROLOG debug_microlog
|
||||
extern void debug_microlog(const wchar_t* fmt, ...);
|
||||
// write to memory buffer (fast)
|
||||
extern void debug_wprintf_mem(const wchar_t* fmt, ...);
|
||||
|
||||
// warn of unexpected state. less error-prone than assert(!"text");
|
||||
#define debug_warn(str) assert2(0 && (str))
|
||||
|
||||
|
||||
@@ -57,7 +87,10 @@ extern void debug_microlog(const wchar_t* fmt, ...);
|
||||
// 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()
|
||||
|
||||
|
||||
@@ -66,18 +99,23 @@ extern void debug_microlog(const wchar_t* fmt, ...);
|
||||
// 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
|
||||
|
||||
// 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 direct access to hardware breakpoints.
|
||||
|
||||
// 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,
|
||||
DBG_BREAK_DATA_WRITE = 1,
|
||||
DBG_BREAK_DATA = DBG_BREAK_DATA_WRITE|2
|
||||
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 <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.
|
||||
extern int debug_set_break(void* addr, DbgBreakType type);
|
||||
|
||||
|
||||
@@ -85,8 +123,8 @@ extern int debug_set_break(void* addr, DbgBreakType type);
|
||||
// memory
|
||||
//
|
||||
|
||||
// independent of mmgr, endeavor to
|
||||
|
||||
// check heap integrity (independently of mmgr).
|
||||
// errors are reported by the CRT, e.g. via assert.
|
||||
extern void debug_check_heap(void);
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
|
||||
// portable output routines (win.cpp overrides these)
|
||||
// misc. portable versions (win.cpp overrides these)
|
||||
|
||||
void display_msg(const char* caption, const char* msg)
|
||||
{
|
||||
@@ -26,22 +26,6 @@ void wdisplay_msg(const wchar_t* caption, const wchar_t* msg)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void debug_out(const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
void debug_check_heap()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int get_executable_name(char* n_path, size_t buf_size)
|
||||
{
|
||||
UNUSED(n_path);
|
||||
@@ -52,36 +36,6 @@ int get_executable_name(char* n_path, size_t buf_size)
|
||||
#endif // #ifndef _WIN32
|
||||
|
||||
|
||||
const size_t MICROLOG_SIZE = 16384;
|
||||
wchar_t MicroBuffer[MICROLOG_SIZE];
|
||||
size_t MicroBuffer_off = 0;
|
||||
|
||||
void debug_microlog(const wchar_t *fmt, ...)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
va_list argp;
|
||||
wchar_t buffer[512];
|
||||
|
||||
va_start(argp, fmt);
|
||||
vswprintf(buffer, sizeof(buffer)-2, fmt, argp);
|
||||
va_end(argp);
|
||||
|
||||
wcscat(buffer, L"\r\n");
|
||||
|
||||
int len = (int)wcslen(buffer);
|
||||
|
||||
// Lose half of the old data if the log's too big
|
||||
if (MicroBuffer_off + len >= MICROLOG_SIZE)
|
||||
{
|
||||
memcpy(&MicroBuffer, (void*)&MicroBuffer[MICROLOG_SIZE/2], sizeof(wchar_t)*MICROLOG_SIZE/2);
|
||||
memset(&MicroBuffer[MICROLOG_SIZE/2], 0, sizeof(wchar_t)*MICROLOG_SIZE/2);
|
||||
MicroBuffer_off -= MICROLOG_SIZE/2;
|
||||
}
|
||||
memcpy(&MicroBuffer[MicroBuffer_off], buffer, sizeof(wchar_t)*len);
|
||||
MicroBuffer_off += len;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
Reference in New Issue
Block a user