214 lines
14 KiB
MQL5
214 lines
14 KiB
MQL5
|
#ifndef LIB_DBG_DEBUG_MACROS_MQH_INCLUDED
|
||
|
#define LIB_DBG_DEBUG_MACROS_MQH_INCLUDED
|
||
|
#property version "5.10"
|
||
|
/**********************************************************************************
|
||
|
* Copyright (C) 2020 Dominik Egert <info@freie-netze.de>
|
||
|
*
|
||
|
* This file is the debugger main user macros include file.
|
||
|
*
|
||
|
* Lisence applied: GPLv2
|
||
|
* https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||
|
*
|
||
|
* Author Dominik Egert / Freie Netze UG.
|
||
|
**********************************************************************************
|
||
|
*
|
||
|
* Version: 5.10
|
||
|
* State: public
|
||
|
*
|
||
|
* File information
|
||
|
* ================
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//*********************************************************************************************************************************************************/
|
||
|
// BEGIN Debugging macros
|
||
|
//
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Debugger helpers
|
||
|
//
|
||
|
#ifndef LIB_DEBUG_INCLUDE_STUB
|
||
|
|
||
|
// Stringify macro helper
|
||
|
#define DBG_TO_STRING(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s", __DBG_STRINGIFY_MACRO(x));
|
||
|
|
||
|
// Custom register enum resolver macro
|
||
|
#ifdef __MQL5__
|
||
|
#define DBG_ENUM_RESOLVER(x) namespace dbg_lib { const string LIB_DBG_NAMESPACE_DEF(dbg_lib, var_out)(const string name, x val, const int shift = 0, const string prefix = "", const int offset = 0, const bool hex = DBG_HEX_OUTPUT) { return(LIB_DBG_NAMESPACE_DEF(dbg_lib, enum_to_string)(name, val, shift, prefix, offset, hex)); }; }
|
||
|
|
||
|
#else
|
||
|
#define DBG_ENUM_RESOLVER(x) const string LIB_DBG_NAMESPACE_DEF(dbg_lib, var_out)(const string name, x val, const int shift = 0, const string prefix = "", const int offset = 0, const bool hex = DBG_HEX_OUTPUT) { return(LIB_DBG_NAMESPACE_DEF(dbg_lib, enum_to_string)(name, val, shift, prefix, offset, hex)); }
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// Debug to string functions
|
||
|
#define DBG_STR(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, x)
|
||
|
#define DBG_STR_IF(c, x) ((c) ? LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, LIB_DBG_NAMESPACE(dbg_lib, dbg_StringFormat)("$$DBG_IF(%s)$$ :--> %s", #c, x)) : NULL)
|
||
|
#define DBG_STR_VAR(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, LIB_DBG_NAMESPACE(dbg_lib, var_out)(__DBG_STRINGIFY_MACRO((x)), (x)), "=", DBG_MSG_FORMAT_RIGHT_COLUMN_SPACER)
|
||
|
#define DBG_STR_VAR_IF(c, x) ((c) ? LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, LIB_DBG_NAMESPACE(dbg_lib, dbg_StringFormat)("$$DBG_IF(%s)$$ :--> %s", #c, LIB_DBG_NAMESPACE(dbg_lib, var_out)(__DBG_STRINGIFY_MACRO((x)), (x))), "=", DBG_MSG_FORMAT_RIGHT_COLUMN_SPACER) : NULL)
|
||
|
#define DBG_STR_PERSIST(x) DBG_STR(x)
|
||
|
#define DBG_STR_BITS(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, LIB_DBG_NAMESPACE(dbg_lib, var_out)(__DBG_STRINGIFY_MACRO((x)), (x), 0, "", 0, false), "=", DBG_MSG_FORMAT_RIGHT_COLUMN_SPACER)
|
||
|
#define DBG_STR_ERRCODE(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, LIB_DBG_NAMESPACE(dbg_lib, var_out)(__DBG_STRINGIFY_MACRO((x)), LIB_DBG_NAMESPACE(dbg_lib, dbg_errcode_to_name)(x)), "=", DBG_MSG_FORMAT_RIGHT_COLUMN_SPACER)
|
||
|
|
||
|
// Debug std out
|
||
|
#define DBG_MSG(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR(x));
|
||
|
#define DBG_MSG_IF(c, x) { if(c) { LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR_IF(c, x)); } }
|
||
|
#define DBG_MSG_VAR(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR_VAR(x));
|
||
|
#define DBG_MSG_VAR_IF(c, x) { if(c) { LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR_VAR_IF(c, x)); } }
|
||
|
#define DBG_MSG_PERSIST(x) DBG_MSG(x)
|
||
|
#define DBG_MSG_BITS(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR_BITS(x))
|
||
|
#define DBG_MSG_ERRCODE(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR_ERRCODE(x), true)
|
||
|
|
||
|
// Var dump macro
|
||
|
#define DBG_MSG_LISTDUMP(x, y) LIB_DBG_NAMESPACE(dbg_lib, list_dump_arrays)(x, #x, y, #y, __FILE__, __FUNCTION__, __LINE__, DBG_MSG_VAR_ARRAY_LIMIT(x))
|
||
|
|
||
|
// Tracing inside ()-condition statements
|
||
|
#define DBG_MSG_EVAL(x) (LIB_DBG_NAMESPACE(dbg_lib, dbg_eval_return)(__FILE__, __FUNCTION__, __LINE__, __DBG_STRINGIFY_MACRO(x), x))
|
||
|
#define DBG_MSG_EVAL_IF(c, x) (LIB_DBG_NAMESPACE(dbg_lib, dbg_eval_return)(__FILE__, __FUNCTION__, __LINE__, __DBG_STRINGIFY_MACRO(x), x, c))
|
||
|
#define DBG_MSG_EVAL_CMNT(m, x) (LIB_DBG_NAMESPACE(dbg_lib, dbg_eval_return)(__FILE__, __FUNCTION__, __LINE__, __DBG_STRINGIFY_MACRO(x), x, true, m))
|
||
|
#define DBG_MSG_EVAL_IF_CMNT(c, m, x) (LIB_DBG_NAMESPACE(dbg_lib, dbg_eval_return)(__FILE__, __FUNCTION__, __LINE__, __DBG_STRINGIFY_MACRO(x), x, c, m))
|
||
|
|
||
|
// Array check macro
|
||
|
#define DBG_MSG_ARRAY_OUT_OF_RANGE(x, y) { if((y < NULL) || (y >= LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x))) { DBG_MSG(LIB_DBG_NAMESPACE(dbg_lib, dbg_StringFormat)("%s{%i] :--> ARRAY OUT OF RANGE", __DBG_STRINGIFY_MACRO(x), y)); DBG_MSG_VAR(x); } }
|
||
|
|
||
|
// Program uninit reason tracing
|
||
|
#define DBG_SET_UNINIT_REASON(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_uninit_reason) = x;
|
||
|
#define DBG_MSG_UNINIT_RESOLVER if(_StopFlag) { DBG_MSG_VAR(_StopFlag); } LIB_DBG_NAMESPACE(dbg_lib, uninit_text)(__FUNCTION__, -1);
|
||
|
|
||
|
// Include-File loader tracing
|
||
|
#ifdef __MQL5__
|
||
|
#define DBG_FILE_VARNAME(x) dbg_file_loader_##x
|
||
|
#define DBG_MSG_TRACE_FILE_LOADER static bool DBG_FILE_VARNAME(__COUNTER__) = LIB_DBG_NAMESPACE(dbg_lib, dbg_print_file_trace)(__FILE__);
|
||
|
|
||
|
#else
|
||
|
#define DBG_MSG_TRACE_FILE_LOADER
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// MQL-API function tracer macro
|
||
|
#ifndef DBG_MSG_MQLFUNC
|
||
|
#define DBG_MSG_MQLFUNC(x, id) dbg_mql_api_call_tracer.trace_call_details(__LINE__, id, __FILE__, __FUNCTION__, #x, DBG_MQLAPI_VERSION).x
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Assert support
|
||
|
//
|
||
|
|
||
|
// Generic assert definition
|
||
|
#define DBG_GENERIC_ASSERT(condition, message) { if(!(condition)) { string msg = LIB_DBG_NAMESPACE(dbg_lib, dbg_StringFormat)(DBG_OUTPUT_STRING, ((#condition == "") ? "" : #condition + " "), DBG_CODE_LOCATION_STRING, message);
|
||
|
|
||
|
// Call modal dialog and div/zero!
|
||
|
#define DBG_ASSERT(condition, message) DBG_GENERIC_ASSERT(condition, message) LIB_DBG_NAMESPACE(dbg_lib, dbg_Alert)(DBG_ASSERT_MSG_TXT + " " + msg); DBG_CRASH_CODE; } }
|
||
|
|
||
|
// Print out information
|
||
|
#define DBG_ASSERT_LOG(condition, message) DBG_GENERIC_ASSERT(condition, message) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s%s %s", DBG_OUTPUT_PREFIX + DBG_OUTPUT_PREFIX, DBG_ASSERT_MSG_TXT, msg); } }
|
||
|
|
||
|
// Print info and abort execution by return;
|
||
|
#define DBG_ASSERT_RETURN(condition, message) DBG_GENERIC_ASSERT(condition, message) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s%s %s", DBG_OUTPUT_PREFIX + DBG_OUTPUT_PREFIX, DBG_ASSERT_MSG_TXT, msg); return; } }
|
||
|
|
||
|
// Print info and abort execution by return;
|
||
|
#define DBG_ASSERT_RETURN_VAR(condition, message, return_value) DBG_GENERIC_ASSERT(condition, message) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s%s %s", DBG_OUTPUT_PREFIX + DBG_OUTPUT_PREFIX, DBG_ASSERT_MSG_TXT, msg); return(return_value); } }
|
||
|
|
||
|
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Software inherited brakepoints
|
||
|
//
|
||
|
|
||
|
// Debugging macros
|
||
|
#define DBG_SOFT_BREAKPOINT { LIB_DBG_NAMESPACE(dbg_lib, BreakPoint)(__LINE__, __FILE__); if(IS_DEBUG_MODE) { DebugBreak(); } else { DBG_SLEEP_SECONDS(DBG_SOFT_BKP_TIMEOUT); } }
|
||
|
#define DBG_SOFT_BREAKPOINT_TS(timestamp) { LIB_DBG_NAMESPACE(dbg_lib, BreakPoint)(__LINE__, __FILE__, LIB_DBG_NAMESPACE(dbg_lib, dbg_StringToTime)(timestamp)); DBG_SOFT_BREAKPOINT }
|
||
|
#define DBG_SOFT_BREAKPOINT_CONDITION(x) { if((x) && (LIB_DBG_NAMESPACE(dbg_lib, BreakPoint)(__LINE__, __FILE__, LIB_DBG_NAMESPACE(dbg_lib, dbg_TimeCurrent)() + DBG_SOFT_BKP_TIMEOUT))) { DBG_SOFT_BREAKPOINT; } }
|
||
|
#define DBG_SOFT_BREAKPOINT_EXEC_TIME(x) { DBG_SOFT_BREAKPOINT_CONDITION(LIB_DBG_NAMESPACE(dbg_lib, ExecTime)(x)); LIB_DBG_NAMESPACE(dbg_lib, ExecTime)(NULL); }
|
||
|
|
||
|
// Conditional break debugging macros
|
||
|
#define DBG_BREAK_CALL_COUNTER(x) if(dbg_lib_func_call_count == x) { DebugBreak(); }
|
||
|
#define DBG_BREAK_IF(x) if(x) { DebugBreak(); }
|
||
|
|
||
|
#ifdef __MQL5__
|
||
|
#define DBG_BREAK_CONDITION_CREATE(x, y) namespace dbg_lib { static bool dbg_cond_ID_state_##x = false; static bool dbg_cond_ID_enabled_##x = y; }
|
||
|
#define DBG_BREAK_CONDITION_ACTIVATE(x, y) do { dbg_lib::dbg_cond_ID_state_##x |= (y); } while(false)
|
||
|
#define DBG_BREAK_CONDITION_DEACTIVATE(x, y) do { dbg_lib::dbg_cond_ID_state_##x = !(y); } while(false)
|
||
|
#define DBG_BREAK_CONDITION_ON_ID(x) do { if(dbg_lib::dbg_cond_ID_state_##x && dbg_lib::dbg_cond_ID_enabled_##x) { DebugBreak(); } } while(false)
|
||
|
#define DBG_BREAK_CONDITION_ON_ID_RESET(x) do { if(dbg_lib::dbg_cond_ID_state_##x && dbg_lib::dbg_cond_ID_enabled_##x) { dbg_lib::dbg_cond_ID_state_##x = false; DebugBreak(); } } while(false)
|
||
|
|
||
|
#else
|
||
|
#define DBG_BREAK_CONDITION_CREATE(x, y) static bool dbg_cond_ID_state_##x = false; static bool dbg_cond_ID_enabled_##x = y;
|
||
|
#define DBG_BREAK_CONDITION_ACTIVATE(x, y) dbg_cond_ID_state_##x |= (y);
|
||
|
#define DBG_BREAK_CONDITION_DEACTIVATE(x, y) dbg_cond_ID_state_##x = !(y);
|
||
|
#define DBG_BREAK_CONDITION_ON_ID(x) { if(dbg_cond_ID_state_##x && dbg_cond_ID_enabled_##x) { DebugBreak(); } }
|
||
|
#define DBG_BREAK_CONDITION_ON_ID_RESET(x) { if(dbg_cond_ID_state_##x && dbg_cond_ID_enabled_##x) { dbg_cond_ID_state_##x = false; DebugBreak(); } }
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// Array out of range stop macro
|
||
|
#define DBG_BREAK_ARRAY_OUT_OF_RANGE(x, y) { if((LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x) <= (y)) || ((y) < NULL)) { DBG_MSG_VARDUMP(x); DBG_MSG_VAR(typename_raw(x)); DBG_MSG_VAR(LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x)); DBG_MSG_VAR((y)); DebugBreak(); } }
|
||
|
/*
|
||
|
#ifdef __MQL5__
|
||
|
#define DBG_BREAK_ARRAY_OUT_OF_RANGE(x, y) { const int arr_size = LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x); if((arr_size <= y) || (y < NULL)) { LIB_DBG_NAMESPACE(dbg_lib, dbg_ArrayPrint)(x, _Digits, (arr_size < 5) ? NULL : (arr_size - 5), NULL); DBG_MSG_VAR(typename_raw(x)); DBG_MSG_VAR(LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x)); DBG_MSG_VAR(y); DebugBreak(); } }
|
||
|
#else
|
||
|
#define DBG_BREAK_ARRAY_OUT_OF_RANGE(x, y) { if((LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x) <= y) || (y < NULL)) { DBG_MSG_VARDUMP(x); DBG_MSG_VAR(typename_raw(x)); DBG_MSG_VAR(LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x)); DBG_MSG_VAR(y); DebugBreak(); } }
|
||
|
#endif
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Loop tracing
|
||
|
//
|
||
|
|
||
|
// Init loop trace
|
||
|
#define DBG_TRACE_LOOP_BEGIN_ID(x) int _dbg_loop_start##x = 0x00; int _dbg_loop_finish##x = 0x00; ulong _dbg_loop_runtime##x = LIB_DBG_NAMESPACE(dbg_lib, dbg_GetMicrosecondCount)();
|
||
|
#define DBG_TRACE_LOOP_BEGIN DBG_TRACE_LOOP_BEGIN_ID(__FUNCTION__)
|
||
|
|
||
|
// Count loop heads
|
||
|
#define DBG_TRACE_LOOP_START_ID(x) _dbg_loop_start##x++;
|
||
|
#define DBG_TRACE_LOOP_START DBG_TRACE_LOOP_START_ID(__FUNCTION__)
|
||
|
|
||
|
// Count loop footers
|
||
|
#define DBG_TRACE_LOOP_FINISH_ID(x) _dbg_loop_finish##x++;
|
||
|
#define DBG_TRACE_LOOP_FINISH DBG_TRACE_LOOP_FINISH_ID(__FUNCTION__)
|
||
|
|
||
|
// Print loop stats
|
||
|
#define DBG_TRACE_LOOP_END_ID(x) DBG_MSG(LIB_DBG_NAMESPACE(dbg_lib, dbg_StringFormat)("Iterations begin: %i; Iterations end: %i; Runtime: %i microseconds.", _dbg_loop_start##x, _dbg_loop_finish##x, (LIB_DBG_NAMESPACE(dbg_lib, dbg_GetMicrosecondCount)() - _dbg_loop_runtime##x)));
|
||
|
#define DBG_TRACE_LOOP_END DBG_TRACE_LOOP_END_ID(__FUNCTION__)
|
||
|
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
//
|
||
|
// END Debugging support
|
||
|
//*********************************************************************************************************************************************************/
|
||
|
#endif // LIB_DBG_DEBUG_MACROS_MQH_INCLUDED
|