* src/rtl/filebuf.c
! unlock HVM stack before locking local mutex and calling hb_fs*()
functions which also unlocks HVM. It fixes possible deadlock condition
when hb_gcAll( .T. ) is executed.
* include/hbapi.h
* src/vm/garbage.c
! changed mark function semantic.
Adding support for user defined mark function I created race condition
in MT GC code. It happens because blocks marked as deleted were not
scanned by GC mark code so their subitems where not accessible.
To fix it we have to change mark function semantic. Now mark function
can be executed also for blocks currently deleted. It means that GC
block destructor should clean references to just removed items and
subblocks. The best place to make it is clearing pointers to GC blocks
just after hb_itemRelease() or hb_gcRefFree().
It is save to clean the reference just before hb_itemRelease() or
hb_gcRefFree() but only for the single block passed to these functions.
It is not save to clear reference to more then one block and then
execute above functions.
+ check reference count after destructor execution for all blocks
not only arrays - warning it may exploit some wrong C code.
- removed not longer used hb_gcRefCheck() function.
* include/hbvm.h
* src/vm/hvm.c
+ added new internal function hb_vmLockForce()
! fixed to mark GC blocks with active threads
* src/vm/thread.c
* include/hbthread.h
% modified sync mutexes used by xBase++ signal class emulation
to not use item array internally
* updated mutex destructor to new GC mark semantic
! mark GT items if GT is bound with thread item
! fixed mutex notify/subscribe code to not change GC items
when HVM stack is unlocked
! use hb_vmLockForce() to eliminate potential deadlock
+ added new C function hb_threadEnterCriticalSectionGC().
It should be used instead of hb_threadEnterCriticalSection()
in code which manipulates GC items inside critical section.
It's slower but eliminates possible deadlock condition.
Please remember that remember that both functions cannot
be used for the same mutex. So if it's necessary to use
hb_threadEnterCriticalSectionGC() in one place then it
has to be used in all others when the same mutex is locked.
* src/vm/arrays.c
* src/vm/codebloc.c
* src/vm/hashes.c
* src/rtl/hbgtcore.c
* contrib/hbcurl/core.c
* contrib/hbexpat/core.c
* updated destructors to new GC mark semantic
* contrib/hbxpp/dllx.c
! fixed destructor for pointer item created by DllPrepareCall()
Now it respects reference counter.
; added note about real behavior of library handle destructor,
I haven't changed existing code behavior but maybe it should
be done.
* contrib/xhb/hbserv.c
* src/debug/dbgentry.c
* src/rdd/wacore.c
! fixed possible deadlocks by using hb_threadEnterCriticalSectionGC()
instead of hb_threadEnterCriticalSection().
* contrib/hbmemio/memio.c
! slightly modified hb_memfsDirectory() code to avoid race condition
without using hb_threadEnterCriticalSectionGC()
* src/vm/fm.c
% reduce the lock range in HB_FM_STAT builds
* src/rtl/hbsocket.c
! added missing HVM stack unlocking in hb_socketSelect() function
* src/rtl/gtxwc/gtxwc.c
! added few missing locks for version compiled with HB_XWC_XLIB_NEEDLOCKS
* src/rdd/dbtotal.prg
* allow to use symbols instead of codeblocks
* modified Harbour extension which uses ordKey() as default group
signature to work also without index. In such case all records
are summarized into single one.
; Most of above modifications were critical for stability of MT programs.
They should allow to activate GC in any place.
1843 lines
47 KiB
C
1843 lines
47 KiB
C
/*
|
|
* xHarbour Project source code:
|
|
* Debugger entry routine
|
|
*
|
|
* Copyright 2005 Phil Krylov <phil a t newstar.rinet.ru>
|
|
* www - http://www.xharbour.org
|
|
*
|
|
* 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, 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this software; see the file COPYING.txt. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
|
*
|
|
* As a special exception, the Harbour Project gives permission for
|
|
* additional uses of the text contained in its release of Harbour.
|
|
*
|
|
* The exception is that, if you link the Harbour libraries with other
|
|
* files to produce an executable, this does not by itself cause the
|
|
* resulting executable to be covered by the GNU General Public License.
|
|
* Your use of that executable is in no way restricted on account of
|
|
* linking the Harbour library code into it.
|
|
*
|
|
* This exception does not however invalidate any other reasons why
|
|
* the executable file might be covered by the GNU General Public License.
|
|
*
|
|
* This exception applies only to the code released by the Harbour
|
|
* Project under the name Harbour. If you copy code from other
|
|
* Harbour Project or Free Software Foundation releases into a copy of
|
|
* Harbour, as the General Public License permits, the exception does
|
|
* not apply to the code that you add in this way. To avoid misleading
|
|
* anyone as to the status of such modified files, you must delete
|
|
* this exception notice from them.
|
|
*
|
|
* If you write modifications of your own for Harbour, it is your choice
|
|
* whether to permit this exception to apply to your modifications.
|
|
* If you do not wish that, delete this exception notice.
|
|
*
|
|
*/
|
|
|
|
#include "hbapidbg.h"
|
|
#include "hbapiitm.h"
|
|
#include "hbapicls.h"
|
|
#include "hbapirdd.h"
|
|
#include "hbstack.h"
|
|
#include "hbvm.h"
|
|
#include "hbthread.h"
|
|
|
|
#include "hbdebug.ch"
|
|
#include "hbmacro.ch"
|
|
|
|
/* dummy function declaration */
|
|
static HB_BOOL hb_clsSetScope( HB_BOOL fScope )
|
|
{
|
|
return fScope;
|
|
}
|
|
|
|
#define HB_DBGINFO_DISABLE ( ( HB_DEBUGINFO * ) ( HB_PTRDIFF ) 0x01 )
|
|
|
|
#if defined( HB_OS_UNIX )
|
|
#define FILENAME_EQUAL( s1, s2 ) ( ! strcmp( ( s1 ), ( s2 ) ) )
|
|
#else
|
|
#define FILENAME_EQUAL( s1, s2 ) ( ! hb_stricmp( ( s1 ), ( s2 ) ) )
|
|
#endif
|
|
|
|
#define ARRAY_ADD( type, array, length ) \
|
|
( ( ++length == 1 ) ? ( array = ( type * ) hb_xgrab( sizeof( type ) ) ) : \
|
|
( ( array = ( type * ) hb_xrealloc( array, sizeof( type ) * length ) ) + \
|
|
length - 1 ) )
|
|
|
|
#define ARRAY_DEL( type, array, length, index ) \
|
|
do { \
|
|
if( ! --length ) \
|
|
hb_xfree( array ); \
|
|
else if( index < length ) \
|
|
memmove( array + index, array + index + 1, sizeof( type ) * ( length - index ) ); \
|
|
} while( 0 )
|
|
|
|
#define HB_DBGCOMMON_LOCK() hb_threadEnterCriticalSectionGC( &s_dbgMtx )
|
|
#define HB_DBGCOMMON_UNLOCK() hb_threadLeaveCriticalSection( &s_dbgMtx )
|
|
static HB_CRITICAL_NEW( s_dbgMtx );
|
|
|
|
typedef struct
|
|
{
|
|
char * szModule;
|
|
int nLine;
|
|
char * szFunction;
|
|
} HB_BREAKPOINT;
|
|
|
|
typedef struct
|
|
{
|
|
int nIndex;
|
|
PHB_ITEM xValue;
|
|
} HB_TRACEPOINT;
|
|
|
|
typedef struct
|
|
{
|
|
const char * szName;
|
|
char cType;
|
|
union
|
|
{
|
|
int num;
|
|
PHB_ITEM ptr;
|
|
} frame;
|
|
int nIndex;
|
|
} HB_VARINFO;
|
|
|
|
typedef struct
|
|
{
|
|
char * szExpr;
|
|
PHB_ITEM pBlock;
|
|
int nVars;
|
|
char ** aVars;
|
|
HB_VARINFO * aScopes;
|
|
} HB_WATCHPOINT;
|
|
|
|
typedef struct
|
|
{
|
|
char * szModule;
|
|
char * szFunction;
|
|
int nLine;
|
|
int nProcLevel;
|
|
int nLocals;
|
|
HB_VARINFO * aLocals;
|
|
int nStatics;
|
|
HB_VARINFO * aStatics;
|
|
} HB_CALLSTACKINFO;
|
|
|
|
typedef struct
|
|
{
|
|
char * szModule;
|
|
int nStatics;
|
|
HB_VARINFO * aStatics;
|
|
int nGlobals;
|
|
HB_VARINFO * aGlobals;
|
|
int nExternGlobals;
|
|
HB_VARINFO * aExternGlobals;
|
|
} HB_MODULEINFO;
|
|
|
|
typedef struct
|
|
{
|
|
int nModules;
|
|
HB_MODULEINFO * aModules;
|
|
PHB_ITEM pStopLines;
|
|
} HB_DBGCOMMONINFO;
|
|
|
|
typedef struct
|
|
{
|
|
HB_BOOL bQuit;
|
|
HB_BOOL bGo;
|
|
HB_BOOL bInside;
|
|
int nBreakPoints;
|
|
HB_BREAKPOINT * aBreak;
|
|
int nTracePoints;
|
|
HB_TRACEPOINT * aTrace;
|
|
int nWatchPoints;
|
|
HB_WATCHPOINT * aWatch;
|
|
HB_BOOL bTraceOver;
|
|
int nTraceLevel;
|
|
HB_BOOL bNextRoutine;
|
|
HB_BOOL bCodeBlock;
|
|
HB_BOOL bToCursor;
|
|
int nToCursorLine;
|
|
char * szToCursorModule;
|
|
int nProcLevel;
|
|
int nCallStackLen;
|
|
HB_CALLSTACKINFO * aCallStack;
|
|
HB_BOOL bCBTrace;
|
|
HB_BOOL ( * pFunInvoke )( void );
|
|
HB_BOOL bInitGlobals;
|
|
HB_BOOL bInitStatics;
|
|
HB_BOOL bInitLines;
|
|
PHB_DYNS pDbgEntry;
|
|
} HB_DEBUGINFO;
|
|
|
|
static HB_DBGCOMMONINFO s_common = { 0, NULL, NULL };
|
|
|
|
static PHB_ITEM hb_dbgActivateBreakArray( HB_DEBUGINFO * info );
|
|
static PHB_ITEM hb_dbgActivateModuleArray( void );
|
|
static PHB_ITEM hb_dbgActivateVarArray( int nVars, HB_VARINFO * aVars );
|
|
static void hb_dbgAddLocal( HB_DEBUGINFO * info, const char * szName, int nIndex, int nFrame );
|
|
static void hb_dbgAddModule( const char * szName );
|
|
static void hb_dbgAddStack( HB_DEBUGINFO * info, const char * szName, int nLine, int nProcLevel );
|
|
static void hb_dbgAddStatic( HB_DEBUGINFO * info, const char * szName, int nIndex, PHB_ITEM pFrame );
|
|
static void hb_dbgAddVar( int * nVars, HB_VARINFO ** aVars, const char * szName, char cType, int nIndex, int nFrame, PHB_ITEM pFrame );
|
|
static void hb_dbgAddStopLines( PHB_ITEM pItem );
|
|
static void hb_dbgEndProc( HB_DEBUGINFO * info );
|
|
static PHB_ITEM hb_dbgEval( HB_DEBUGINFO * info, HB_WATCHPOINT * watch );
|
|
static PHB_ITEM hb_dbgEvalMacro( const char * szExpr, PHB_ITEM pItem );
|
|
static PHB_ITEM hb_dbgEvalMakeBlock( HB_WATCHPOINT * watch );
|
|
static PHB_ITEM hb_dbgEvalResolve( HB_DEBUGINFO * info, HB_WATCHPOINT * watch );
|
|
static HB_BOOL hb_dbgIsAltD( void );
|
|
static int hb_dbgIsBreakPoint( HB_DEBUGINFO * info, const char * szModule, int nLine );
|
|
static HB_BOOL hb_dbgEqual( PHB_ITEM pItem1, PHB_ITEM pItem2 );
|
|
static void hb_dbgQuit( HB_DEBUGINFO * info );
|
|
static void hb_dbgRelease( void );
|
|
static PHB_ITEM hb_dbgVarGet( HB_VARINFO * scope );
|
|
static void hb_dbgVarSet( HB_VARINFO * scope, PHB_ITEM xNewValue );
|
|
|
|
static void hb_dbgActivate( HB_DEBUGINFO * info )
|
|
{
|
|
if( ! info->pDbgEntry )
|
|
{
|
|
info->pDbgEntry = hb_dynsymFind( "__DBGENTRY" );
|
|
if( info->pDbgEntry && ! hb_dynsymIsFunction( info->pDbgEntry ) )
|
|
info->pDbgEntry = NULL;
|
|
}
|
|
|
|
if( info->pDbgEntry )
|
|
{
|
|
PHB_ITEM aCallStack = hb_itemArrayNew( info->nCallStackLen );
|
|
PHB_ITEM aModules;
|
|
PHB_ITEM aBreak;
|
|
HB_BOOL bInside = info->bInside;
|
|
int i;
|
|
|
|
for( i = 0; i < info->nCallStackLen; i++ )
|
|
{
|
|
HB_CALLSTACKINFO * pEntry = &info->aCallStack[ i ];
|
|
PHB_ITEM aEntry = hb_itemArrayNew( 6 );
|
|
PHB_ITEM pItem;
|
|
|
|
hb_arraySetC( aEntry, 1, pEntry->szModule );
|
|
hb_arraySetC( aEntry, 2, pEntry->szFunction );
|
|
hb_arraySetNL( aEntry, 3, pEntry->nLine );
|
|
hb_arraySetNL( aEntry, 4, pEntry->nProcLevel );
|
|
|
|
pItem = hb_dbgActivateVarArray( pEntry->nLocals, pEntry->aLocals );
|
|
hb_arraySet( aEntry, 5, pItem );
|
|
hb_itemRelease( pItem );
|
|
|
|
pItem = hb_dbgActivateVarArray( pEntry->nStatics, pEntry->aStatics );
|
|
hb_arraySet( aEntry, 6, pItem );
|
|
hb_itemRelease( pItem );
|
|
|
|
hb_arraySet( aCallStack, info->nCallStackLen - i, aEntry );
|
|
hb_itemRelease( aEntry );
|
|
}
|
|
|
|
aModules = hb_dbgActivateModuleArray();
|
|
aBreak = hb_dbgActivateBreakArray( info );
|
|
|
|
hb_vmPushDynSym( info->pDbgEntry );
|
|
hb_vmPushNil();
|
|
hb_vmPushLong( HB_DBG_ACTIVATE );
|
|
hb_vmPushPointer( info );
|
|
hb_vmPushLong( info->nProcLevel );
|
|
hb_vmPush( aCallStack );
|
|
hb_vmPush( aModules );
|
|
hb_vmPush( aBreak );
|
|
|
|
hb_itemRelease( aCallStack );
|
|
hb_itemRelease( aModules );
|
|
hb_itemRelease( aBreak );
|
|
|
|
info->bInside = HB_TRUE;
|
|
hb_vmDo( 6 );
|
|
info->bInside = bInside;
|
|
}
|
|
}
|
|
|
|
|
|
static PHB_ITEM hb_dbgActivateBreakArray( HB_DEBUGINFO * info )
|
|
{
|
|
int i;
|
|
PHB_ITEM pArray = hb_itemArrayNew( info->nBreakPoints );
|
|
|
|
for( i = 0; i < info->nBreakPoints; i++ )
|
|
{
|
|
PHB_ITEM pBreak = hb_itemArrayNew( 3 );
|
|
|
|
if( ! info->aBreak[ i ].szFunction )
|
|
{
|
|
hb_arraySetNI( pBreak, 1, info->aBreak[ i ].nLine );
|
|
hb_arraySetC( pBreak, 2, info->aBreak[ i ].szModule );
|
|
}
|
|
else
|
|
hb_arraySetC( pBreak, 3, info->aBreak[ i ].szFunction );
|
|
|
|
hb_arraySet( pArray, i + 1, pBreak );
|
|
hb_itemRelease( pBreak );
|
|
}
|
|
return pArray;
|
|
}
|
|
|
|
|
|
static PHB_ITEM hb_dbgActivateModuleArray( void )
|
|
{
|
|
PHB_ITEM pArray;
|
|
int i;
|
|
|
|
HB_DBGCOMMON_LOCK();
|
|
|
|
pArray = hb_itemArrayNew( s_common.nModules );
|
|
|
|
for( i = 0; i < s_common.nModules; i++ )
|
|
{
|
|
PHB_ITEM pModule = hb_itemArrayNew( 4 );
|
|
PHB_ITEM item;
|
|
|
|
hb_arraySetC( pModule, 1, s_common.aModules[ i ].szModule );
|
|
|
|
item = hb_dbgActivateVarArray( s_common.aModules[ i ].nStatics,
|
|
s_common.aModules[ i ].aStatics );
|
|
hb_arraySet( pModule, 2, item );
|
|
hb_itemRelease( item );
|
|
|
|
item = hb_dbgActivateVarArray( s_common.aModules[ i ].nGlobals,
|
|
s_common.aModules[ i ].aGlobals );
|
|
hb_arraySet( pModule, 3, item );
|
|
hb_itemRelease( item );
|
|
|
|
item = hb_dbgActivateVarArray( s_common.aModules[ i ].nExternGlobals,
|
|
s_common.aModules[ i ].aExternGlobals );
|
|
hb_arraySet( pModule, 4, item );
|
|
hb_itemRelease( item );
|
|
|
|
hb_arraySet( pArray, i + 1, pModule );
|
|
hb_itemRelease( pModule );
|
|
}
|
|
|
|
HB_DBGCOMMON_UNLOCK();
|
|
|
|
return pArray;
|
|
}
|
|
|
|
|
|
static PHB_ITEM hb_dbgActivateVarArray( int nVars, HB_VARINFO * aVars )
|
|
{
|
|
int i;
|
|
PHB_ITEM pArray = hb_itemArrayNew( nVars );
|
|
|
|
for( i = 0; i < nVars; i++ )
|
|
{
|
|
PHB_ITEM aVar = hb_itemArrayNew( 4 );
|
|
|
|
hb_arraySetC( aVar, 1, aVars[ i ].szName );
|
|
hb_arraySetNL( aVar, 2, aVars[ i ].nIndex );
|
|
hb_arraySetCL( aVar, 3, &aVars[ i ].cType, 1 );
|
|
if( aVars[ i ].cType == 'S' )
|
|
hb_arraySet( aVar, 4, aVars[ i ].frame.ptr );
|
|
else
|
|
hb_arraySetNL( aVar, 4, aVars[ i ].frame.num );
|
|
|
|
hb_arraySet( pArray, i + 1, aVar );
|
|
hb_itemRelease( aVar );
|
|
}
|
|
return pArray;
|
|
}
|
|
|
|
|
|
void hb_dbgEntry( int nMode, int nLine, const char * szName, int nIndex, PHB_ITEM pFrame )
|
|
{
|
|
int i;
|
|
HB_ULONG nProcLevel;
|
|
char szProcName[ HB_SYMBOL_NAME_LEN + HB_SYMBOL_NAME_LEN + 5 ];
|
|
HB_DEBUGINFO ** infoPtr = ( HB_DEBUGINFO ** ) hb_stackDebugInfo();
|
|
HB_DEBUGINFO * info = *infoPtr;
|
|
HB_USHORT uiLine;
|
|
|
|
if( info == HB_DBGINFO_DISABLE )
|
|
return;
|
|
else if( nMode != HB_DBG_VMQUIT )
|
|
{
|
|
if( ! info )
|
|
{
|
|
info = *infoPtr = ( HB_DEBUGINFO * ) hb_xgrab( sizeof( HB_DEBUGINFO ) );
|
|
memset( info, 0, sizeof( HB_DEBUGINFO ) );
|
|
info->bCBTrace = HB_TRUE;
|
|
}
|
|
else if( info->bInside || info->bQuit )
|
|
return;
|
|
}
|
|
|
|
switch( nMode )
|
|
{
|
|
case HB_DBG_MODULENAME:
|
|
HB_TRACE( HB_TR_DEBUG, ( "MODULENAME %s", szName ) );
|
|
|
|
if( szName[ strlen( szName ) - 1 ] == ':' )
|
|
return;
|
|
|
|
hb_procinfo( 0, szProcName, &uiLine, NULL );
|
|
if( ! strncmp( szProcName, "(_INITSTATICS", 13 ) )
|
|
info->bInitStatics = HB_TRUE;
|
|
else if( ! strncmp( szProcName, "(_INITGLOBALS", 13 ) )
|
|
info->bInitGlobals = HB_TRUE;
|
|
else if( ! strncmp( szProcName, "(_INITLINES", 11 ) )
|
|
info->bInitLines = HB_TRUE;
|
|
|
|
if( info->bInitStatics || info->bInitGlobals )
|
|
hb_dbgAddModule( szName );
|
|
else if( ! strncmp( szProcName, "(b)", 3 ) )
|
|
info->bCodeBlock = HB_TRUE;
|
|
else if( info->bNextRoutine )
|
|
info->bNextRoutine = HB_FALSE;
|
|
|
|
hb_dbgAddStack( info, szName, uiLine, hb_dbg_ProcLevel() );
|
|
for( i = 0; i < info->nBreakPoints; i++ )
|
|
{
|
|
if( info->aBreak[ i ].szFunction
|
|
&& ! strcmp( info->aBreak[ i ].szFunction, szProcName ) )
|
|
{
|
|
hb_dbg_InvokeDebug( HB_TRUE );
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
|
|
case HB_DBG_LOCALNAME:
|
|
HB_TRACE( HB_TR_DEBUG, ( "LOCALNAME %s index %d", szName, nIndex ) );
|
|
|
|
hb_dbgAddLocal( info, szName, nIndex, hb_dbg_ProcLevel() );
|
|
return;
|
|
|
|
case HB_DBG_STATICNAME:
|
|
HB_TRACE( HB_TR_DEBUG, ( "STATICNAME %s index %d frame %p", szName, nIndex, pFrame ) );
|
|
|
|
hb_dbgAddStatic( info, szName, nIndex, pFrame );
|
|
return;
|
|
|
|
case HB_DBG_SHOWLINE:
|
|
{
|
|
HB_CALLSTACKINFO * pTop = &info->aCallStack[ info->nCallStackLen - 1 ];
|
|
HB_BOOL bOldClsScope;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "SHOWLINE %d", nLine ) );
|
|
|
|
nProcLevel = hb_dbg_ProcLevel();
|
|
|
|
/* Check if we've hit a tracepoint */
|
|
bOldClsScope = hb_clsSetScope( HB_FALSE );
|
|
for( i = 0; i < info->nTracePoints; i++ )
|
|
{
|
|
HB_TRACEPOINT * tp = &info->aTrace[ i ];
|
|
PHB_ITEM xValue;
|
|
|
|
xValue = hb_dbgEval( info, &info->aWatch[ tp->nIndex ] );
|
|
if( ! xValue )
|
|
xValue = hb_itemNew( NULL );
|
|
|
|
if( HB_ITEM_TYPE( xValue ) != HB_ITEM_TYPE( tp->xValue ) ||
|
|
! hb_dbgEqual( xValue, tp->xValue ) )
|
|
{
|
|
hb_itemCopy( tp->xValue, xValue );
|
|
hb_itemRelease( xValue );
|
|
|
|
pTop->nLine = nLine;
|
|
info->nProcLevel = nProcLevel - ( hb_dbgIsAltD() ? 2 : 0 );
|
|
info->bTraceOver = HB_FALSE;
|
|
info->bCodeBlock = HB_FALSE;
|
|
info->bGo = HB_FALSE;
|
|
if( info->bToCursor )
|
|
{
|
|
info->bToCursor = HB_FALSE;
|
|
hb_xfree( info->szToCursorModule );
|
|
}
|
|
info->bNextRoutine = HB_FALSE;
|
|
|
|
hb_dbgActivate( info );
|
|
return;
|
|
}
|
|
hb_itemRelease( xValue );
|
|
}
|
|
hb_clsSetScope( bOldClsScope );
|
|
|
|
if( hb_dbgIsBreakPoint( info, pTop->szModule, nLine ) >= 0 ||
|
|
hb_dbg_InvokeDebug( HB_FALSE ) ||
|
|
( info->pFunInvoke && info->pFunInvoke() ) )
|
|
{
|
|
info->bTraceOver = HB_FALSE;
|
|
if( info->bToCursor )
|
|
{
|
|
info->bToCursor = HB_FALSE;
|
|
hb_xfree( info->szToCursorModule );
|
|
}
|
|
info->bNextRoutine = HB_FALSE;
|
|
info->bGo = HB_FALSE;
|
|
}
|
|
|
|
/* Check if we must skip every level above info->nTraceLevel */
|
|
if( info->bTraceOver )
|
|
{
|
|
if( info->nTraceLevel < info->nCallStackLen )
|
|
return;
|
|
info->bTraceOver = HB_FALSE;
|
|
}
|
|
|
|
/* Check if we're skipping to a specific line of source */
|
|
if( info->bToCursor )
|
|
{
|
|
if( nLine == info->nToCursorLine
|
|
&& FILENAME_EQUAL( pTop->szModule, info->szToCursorModule ) )
|
|
{
|
|
hb_xfree( info->szToCursorModule );
|
|
info->bToCursor = HB_FALSE;
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
|
|
/* Check if'we skipping to the end of current routine */
|
|
if( info->bNextRoutine )
|
|
return;
|
|
|
|
if( info->bCodeBlock )
|
|
{
|
|
info->bCodeBlock = HB_FALSE;
|
|
if( ! info->bCBTrace )
|
|
return;
|
|
}
|
|
|
|
pTop->nLine = nLine;
|
|
if( ! info->bGo )
|
|
{
|
|
info->nProcLevel = nProcLevel - ( hb_dbgIsAltD() ? 2 : 0 );
|
|
hb_dbgActivate( info );
|
|
}
|
|
return;
|
|
}
|
|
|
|
case HB_DBG_ENDPROC:
|
|
if( info->bQuit )
|
|
return;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "ENDPROC %d", nLine ) );
|
|
|
|
if( info->bInitLines )
|
|
hb_dbgAddStopLines( hb_stackReturnItem() );
|
|
|
|
info->bCodeBlock = HB_FALSE;
|
|
info->bInitStatics = HB_FALSE;
|
|
info->bInitGlobals = HB_FALSE;
|
|
info->bInitLines = HB_FALSE;
|
|
hb_dbgEndProc( info );
|
|
return;
|
|
|
|
case HB_DBG_VMQUIT:
|
|
if( info )
|
|
{
|
|
hb_dbgQuit( info );
|
|
hb_xfree( info );
|
|
*infoPtr = HB_DBGINFO_DISABLE;
|
|
}
|
|
if( nIndex != 0 )
|
|
{
|
|
/* main thread exit and HVM cleanup, release common module info */
|
|
hb_dbgRelease();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
static const char * hb_dbgStripModuleName( const char * szName )
|
|
{
|
|
const char * ptr;
|
|
|
|
if( ( ptr = strrchr( szName, '/' ) ) != NULL )
|
|
szName = ptr + 1;
|
|
|
|
if( ( ptr = strrchr( szName, '\\' ) ) != NULL )
|
|
szName = ptr + 1;
|
|
|
|
return szName;
|
|
}
|
|
|
|
|
|
void hb_dbgAddBreak( void * handle, const char * szModule, int nLine, const char * szFunction )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
HB_BREAKPOINT * pBreak;
|
|
|
|
szModule = hb_dbgStripModuleName( szModule );
|
|
pBreak = ARRAY_ADD( HB_BREAKPOINT, info->aBreak, info->nBreakPoints );
|
|
pBreak->szModule = hb_strdup( szModule );
|
|
pBreak->nLine = nLine;
|
|
|
|
if( szFunction )
|
|
pBreak->szFunction = hb_strdup( szFunction );
|
|
else
|
|
pBreak->szFunction = NULL;
|
|
}
|
|
|
|
|
|
static void hb_dbgAddLocal( HB_DEBUGINFO * info, const char * szName, int nIndex, int nFrame )
|
|
{
|
|
if( info->bInitGlobals )
|
|
{
|
|
HB_MODULEINFO * module;
|
|
|
|
HB_DBGCOMMON_LOCK();
|
|
module = &s_common.aModules[ s_common.nModules - 1 ];
|
|
hb_dbgAddVar( &module->nGlobals, &module->aGlobals, szName,
|
|
'G', nIndex, hb_dbg_vmVarGCount(), NULL );
|
|
HB_DBGCOMMON_UNLOCK();
|
|
}
|
|
else
|
|
{
|
|
HB_CALLSTACKINFO * top = &info->aCallStack[ info->nCallStackLen - 1 ];
|
|
|
|
hb_dbgAddVar( &top->nLocals, &top->aLocals, szName, 'L', nIndex, nFrame, NULL );
|
|
}
|
|
}
|
|
|
|
|
|
static void hb_dbgAddModule( const char * szName )
|
|
{
|
|
char * szModuleName;
|
|
const char * szFuncName;
|
|
int iLen;
|
|
|
|
szName = hb_dbgStripModuleName( szName );
|
|
szFuncName = strrchr( szName, ':' );
|
|
iLen = szFuncName ? ( int ) ( szFuncName - szName ) : ( int ) strlen( szName );
|
|
szModuleName = hb_strndup( szName, iLen );
|
|
|
|
HB_DBGCOMMON_LOCK();
|
|
if( ! s_common.nModules || !FILENAME_EQUAL( s_common.aModules[ s_common.nModules - 1 ].szModule, szModuleName ) )
|
|
{
|
|
HB_MODULEINFO * pModule;
|
|
|
|
pModule = ARRAY_ADD( HB_MODULEINFO, s_common.aModules, s_common.nModules );
|
|
pModule->szModule = szModuleName;
|
|
pModule->nStatics = 0;
|
|
pModule->nGlobals = 0;
|
|
pModule->nExternGlobals = 0;
|
|
|
|
szModuleName = NULL;
|
|
}
|
|
HB_DBGCOMMON_UNLOCK();
|
|
|
|
if( szModuleName )
|
|
hb_xfree( szModuleName );
|
|
}
|
|
|
|
|
|
static void hb_dbgAddStack( HB_DEBUGINFO * info, const char * szName, int nLine, int nProcLevel )
|
|
{
|
|
char szBuff[ HB_SYMBOL_NAME_LEN + HB_SYMBOL_NAME_LEN + 5 ];
|
|
HB_CALLSTACKINFO * top;
|
|
const char * szFunction;
|
|
|
|
szName = hb_dbgStripModuleName( szName );
|
|
|
|
szFunction = strrchr( szName, ':' );
|
|
if( szFunction )
|
|
szFunction++;
|
|
|
|
top = ARRAY_ADD( HB_CALLSTACKINFO, info->aCallStack, info->nCallStackLen );
|
|
if( info->bCodeBlock )
|
|
{
|
|
memcpy( szBuff, "(b)", 3 );
|
|
hb_strncpy( szBuff + 3, szFunction, sizeof( szBuff ) - 4 );
|
|
top->szFunction = hb_strdup( szBuff );
|
|
}
|
|
else
|
|
{
|
|
if( szFunction )
|
|
{
|
|
top->szFunction = hb_strdup( szFunction );
|
|
}
|
|
else
|
|
{
|
|
/* We're in an (_INITSTATICSnnnnn) pseudo-function */
|
|
hb_procinfo( 0, szBuff, NULL, NULL );
|
|
top->szFunction = hb_strdup( szBuff );
|
|
}
|
|
}
|
|
|
|
if( szFunction )
|
|
top->szModule = hb_strndup( szName, szFunction - szName - 1 );
|
|
else
|
|
top->szModule = hb_strdup( szName );
|
|
|
|
top->nProcLevel = nProcLevel;
|
|
top->nLine = nLine;
|
|
top->nLocals = 0;
|
|
top->nStatics = 0;
|
|
}
|
|
|
|
|
|
static void hb_dbgAddStatic( HB_DEBUGINFO * info, const char * szName, int nIndex, PHB_ITEM pFrame )
|
|
{
|
|
if( info->bInitGlobals )
|
|
{
|
|
HB_MODULEINFO * module;
|
|
|
|
HB_DBGCOMMON_LOCK();
|
|
module = &s_common.aModules[ s_common.nModules - 1 ];
|
|
hb_dbgAddVar( &module->nExternGlobals, &module->aExternGlobals, szName,
|
|
'G', nIndex, hb_dbg_vmVarGCount(), NULL );
|
|
HB_DBGCOMMON_UNLOCK();
|
|
}
|
|
else if( info->bInitStatics )
|
|
{
|
|
HB_MODULEINFO * module;
|
|
|
|
HB_DBGCOMMON_LOCK();
|
|
module = &s_common.aModules[ s_common.nModules - 1 ];
|
|
hb_dbgAddVar( &module->nStatics, &module->aStatics, szName,
|
|
'S', nIndex, 0, pFrame );
|
|
HB_DBGCOMMON_UNLOCK();
|
|
}
|
|
else
|
|
{
|
|
HB_CALLSTACKINFO * top = &info->aCallStack[ info->nCallStackLen - 1 ];
|
|
|
|
hb_dbgAddVar( &top->nStatics, &top->aStatics, szName, 'S', nIndex, 0, pFrame );
|
|
}
|
|
}
|
|
|
|
|
|
static void hb_dbgAddStopLines( PHB_ITEM pItem )
|
|
{
|
|
HB_ISIZ i, nLinesLen;
|
|
|
|
HB_DBGCOMMON_LOCK();
|
|
|
|
if( ! s_common.pStopLines )
|
|
{
|
|
s_common.pStopLines = hb_itemNew( pItem );
|
|
}
|
|
else
|
|
{
|
|
HB_ISIZ j;
|
|
HB_ISIZ nItemLen = hb_itemSize( pItem );
|
|
|
|
nLinesLen = hb_itemSize( s_common.pStopLines );
|
|
|
|
for( i = 1; i <= nItemLen; i++ )
|
|
{
|
|
PHB_ITEM pEntry = hb_arrayGetItemPtr( pItem, i );
|
|
const char * szModule = hb_arrayGetCPtr( pEntry, 1 );
|
|
HB_BOOL bFound = HB_FALSE;
|
|
|
|
szModule = hb_dbgStripModuleName( szModule );
|
|
for( j = 1; j <= nLinesLen; j++ )
|
|
{
|
|
PHB_ITEM pLines = hb_arrayGetItemPtr( s_common.pStopLines, j );
|
|
|
|
if( FILENAME_EQUAL( hb_arrayGetCPtr( pLines, 1 ), szModule ) )
|
|
{
|
|
/* Merge stopline info */
|
|
HB_ISIZ nOrigMin = hb_arrayGetNS( pLines, 2 );
|
|
HB_ISIZ nNewMin = hb_arrayGetNS( pEntry, 2 );
|
|
HB_ISIZ nOrigLen = hb_arrayGetCLen( pLines, 3 );
|
|
HB_ISIZ nNewLen = hb_arrayGetCLen( pEntry, 3 );
|
|
HB_ISIZ nMin = HB_MIN( nNewMin, nOrigMin );
|
|
HB_ISIZ nMax = HB_MAX( nNewMin + ( nNewLen << 3 ) - 1,
|
|
nOrigMin + ( nOrigLen << 3 ) - 1 );
|
|
const char * pOrigBuffer = hb_arrayGetCPtr( pLines, 3 );
|
|
const char * pNewBuffer = hb_arrayGetCPtr( pEntry, 3 );
|
|
HB_ISIZ nLen = ( ( nMax - nMin ) >> 3 ) + 1;
|
|
HB_ISIZ k;
|
|
char * pBuffer = ( char * ) hb_xgrab( nLen + 1 );
|
|
|
|
hb_xmemset( pBuffer, 0, nLen );
|
|
|
|
/* the bitfields with line numbers should use
|
|
* 8bit alignment so it's safe to use byte copy
|
|
*/
|
|
memmove( &pBuffer[ ( nNewMin - nMin ) >> 3 ], pNewBuffer, nNewLen );
|
|
nOrigMin = ( nOrigMin - nMin ) >> 3;
|
|
for( k = 0; k < nOrigLen; k++ )
|
|
pBuffer[ nOrigMin + k ] |= pOrigBuffer[ k ];
|
|
|
|
hb_arraySetNS( pLines, 2, nMin );
|
|
if( ! hb_arraySetCLPtr( pLines, 3, pBuffer, nLen ) )
|
|
hb_xfree( pBuffer );
|
|
bFound = HB_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( ! bFound )
|
|
hb_arrayAddForward( s_common.pStopLines, pEntry );
|
|
}
|
|
}
|
|
nLinesLen = hb_itemSize( s_common.pStopLines );
|
|
for( i = 1; i <= nLinesLen; i++ )
|
|
{
|
|
PHB_ITEM pEntry = hb_arrayGetItemPtr( s_common.pStopLines, i );
|
|
const char * szModule = hb_arrayGetCPtr( pEntry, 1 );
|
|
|
|
if( szModule )
|
|
{
|
|
const char * szName = hb_dbgStripModuleName( szModule );
|
|
|
|
if( szName != szModule )
|
|
hb_arraySetCLPtr( pEntry, 1, hb_strdup( szName ), strlen( szName ) );
|
|
}
|
|
}
|
|
|
|
HB_DBGCOMMON_UNLOCK();
|
|
}
|
|
|
|
|
|
static void hb_dbgAddVar( int * nVars, HB_VARINFO ** aVars, const char * szName, char cType, int nIndex, int nFrame, PHB_ITEM pFrame )
|
|
{
|
|
HB_VARINFO * var;
|
|
|
|
var = ARRAY_ADD( HB_VARINFO, *aVars, *nVars );
|
|
var->szName = szName;
|
|
var->cType = cType;
|
|
var->nIndex = nIndex;
|
|
if( cType == 'S' )
|
|
var->frame.ptr = pFrame;
|
|
else
|
|
var->frame.num = nFrame;
|
|
}
|
|
|
|
|
|
void hb_dbgAddWatch( void * handle, const char * szExpr, HB_BOOL bTrace )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
HB_WATCHPOINT * pWatch;
|
|
|
|
pWatch = ARRAY_ADD( HB_WATCHPOINT, info->aWatch, info->nWatchPoints );
|
|
pWatch->szExpr = hb_strdup( szExpr );
|
|
pWatch->pBlock = NULL;
|
|
pWatch->nVars = 0;
|
|
|
|
if( bTrace )
|
|
{
|
|
HB_TRACEPOINT * pTrace = ARRAY_ADD( HB_TRACEPOINT, info->aTrace, info->nTracePoints );
|
|
|
|
pTrace->nIndex = info->nWatchPoints - 1;
|
|
pTrace->xValue = hb_dbgEval( info, pWatch );
|
|
}
|
|
}
|
|
|
|
|
|
static void hb_dbgClearWatch( HB_WATCHPOINT * pWatch )
|
|
{
|
|
hb_xfree( pWatch->szExpr );
|
|
|
|
if( pWatch->pBlock )
|
|
hb_itemRelease( pWatch->pBlock );
|
|
|
|
if( pWatch->nVars )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < pWatch->nVars; i++ )
|
|
hb_xfree( pWatch->aVars[ i ] );
|
|
|
|
hb_xfree( pWatch->aVars );
|
|
}
|
|
}
|
|
|
|
|
|
void hb_dbgDelBreak( void * handle, int nBreak )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
|
|
if( nBreak >= 0 && nBreak < info->nBreakPoints )
|
|
{
|
|
HB_BREAKPOINT * pBreak = &info->aBreak[ nBreak ];
|
|
|
|
hb_xfree( pBreak->szModule );
|
|
if( pBreak->szFunction )
|
|
hb_xfree( pBreak->szFunction );
|
|
|
|
ARRAY_DEL( HB_BREAKPOINT, info->aBreak, info->nBreakPoints, nBreak );
|
|
}
|
|
}
|
|
|
|
|
|
void hb_dbgDelWatch( void * handle, int nWatch )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
HB_WATCHPOINT * pWatch = &info->aWatch[ nWatch ];
|
|
int i;
|
|
|
|
hb_dbgClearWatch( pWatch );
|
|
ARRAY_DEL( HB_WATCHPOINT, info->aWatch, info->nWatchPoints, nWatch );
|
|
|
|
for( i = 0; i < info->nTracePoints; i++ )
|
|
{
|
|
HB_TRACEPOINT * pTrace = &info->aTrace[ i ];
|
|
|
|
if( pTrace->nIndex == nWatch )
|
|
{
|
|
if( pTrace->xValue )
|
|
hb_itemRelease( pTrace->xValue );
|
|
|
|
ARRAY_DEL( HB_TRACEPOINT, info->aTrace, info->nTracePoints, i );
|
|
i--;
|
|
}
|
|
else if( pTrace->nIndex > nWatch )
|
|
pTrace->nIndex--;
|
|
}
|
|
}
|
|
|
|
|
|
static void hb_dbgEndProc( HB_DEBUGINFO * info )
|
|
{
|
|
HB_CALLSTACKINFO * top;
|
|
|
|
if( ! info->nCallStackLen )
|
|
return;
|
|
|
|
top = &info->aCallStack[ --info->nCallStackLen ];
|
|
hb_xfree( top->szFunction );
|
|
hb_xfree( top->szModule );
|
|
|
|
if( top->nLocals )
|
|
hb_xfree( top->aLocals );
|
|
|
|
if( top->nStatics )
|
|
hb_xfree( top->aStatics );
|
|
|
|
if( ! info->nCallStackLen )
|
|
{
|
|
hb_xfree( info->aCallStack );
|
|
info->aCallStack = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
static HB_BOOL hb_dbgEqual( PHB_ITEM pItem1, PHB_ITEM pItem2 )
|
|
{
|
|
if( HB_ITEM_TYPE( pItem1 ) != HB_ITEM_TYPE( pItem2 ) )
|
|
return HB_FALSE;
|
|
if( HB_IS_NIL( pItem1 ) )
|
|
return HB_IS_NIL( pItem2 );
|
|
if( HB_IS_LOGICAL( pItem1 ) )
|
|
return hb_itemGetL( pItem1 ) == hb_itemGetL( pItem2 );
|
|
if( HB_IS_POINTER( pItem1 ) )
|
|
return hb_itemGetPtr( pItem1 ) == hb_itemGetPtr( pItem2 );
|
|
if( HB_IS_STRING( pItem1 ) )
|
|
return ! hb_itemStrCmp( pItem1, pItem2, HB_TRUE );
|
|
if( HB_IS_NUMINT( pItem1 ) )
|
|
return hb_itemGetNInt( pItem1 ) == hb_itemGetNInt( pItem2 );
|
|
if( HB_IS_NUMERIC( pItem1 ) )
|
|
return hb_itemGetND( pItem1 ) == hb_itemGetND( pItem2 );
|
|
if( HB_IS_ARRAY( pItem1 ) )
|
|
return hb_arrayId( pItem1 ) == hb_arrayId( pItem2 );
|
|
if( HB_IS_HASH( pItem1 ) )
|
|
return hb_hashId( pItem1 ) == hb_hashId( pItem2 );
|
|
return HB_FALSE;
|
|
}
|
|
|
|
|
|
static PHB_ITEM hb_dbgEval( HB_DEBUGINFO * info, HB_WATCHPOINT * watch )
|
|
{
|
|
PHB_ITEM xResult = NULL;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "expr %s", watch->szExpr ) );
|
|
|
|
/* Check if we have a cached pBlock */
|
|
if( ! watch->pBlock )
|
|
watch->pBlock = hb_dbgEvalMakeBlock( watch );
|
|
|
|
if( watch->pBlock )
|
|
{
|
|
PHB_ITEM aVars = hb_dbgEvalResolve( info, watch );
|
|
PHB_ITEM aNewVars = hb_itemArrayNew( watch->nVars );
|
|
HB_BOOL bInside = info->bInside;
|
|
int i;
|
|
|
|
hb_arrayCopy( aVars, aNewVars, NULL, NULL, NULL );
|
|
|
|
info->bInside = HB_TRUE;
|
|
xResult = hb_itemDo( watch->pBlock, 1, aNewVars );
|
|
info->bInside = bInside;
|
|
|
|
for( i = 0; i < watch->nVars; i++ )
|
|
{
|
|
PHB_ITEM xOldValue = hb_itemArrayGet( aVars, i + 1 );
|
|
PHB_ITEM xNewValue = hb_itemArrayGet( aNewVars, i + 1 );
|
|
|
|
if( ! hb_dbgEqual( xOldValue, xNewValue ) )
|
|
hb_dbgVarSet( &watch->aScopes[ i ], xNewValue );
|
|
|
|
hb_itemRelease( xOldValue );
|
|
hb_itemRelease( xNewValue );
|
|
}
|
|
|
|
hb_itemRelease( aVars );
|
|
hb_itemRelease( aNewVars );
|
|
if( watch->nVars )
|
|
hb_xfree( watch->aScopes );
|
|
}
|
|
return xResult;
|
|
}
|
|
|
|
|
|
static PHB_ITEM hb_dbgEvalMacro( const char * szExpr, PHB_ITEM pItem )
|
|
{
|
|
PHB_ITEM pStr;
|
|
const char * type;
|
|
|
|
pStr = hb_itemPutC( NULL, szExpr );
|
|
type = hb_macroGetType( pStr );
|
|
hb_itemRelease( pStr );
|
|
if( ! strcmp( type, "U" ) || ! strcmp( type, "UE" ) )
|
|
return NULL;
|
|
|
|
hb_vmPushString( szExpr, strlen( szExpr ) );
|
|
hb_macroGetValue( hb_stackItemFromTop( -1 ), 0, HB_SM_RT_MACRO );
|
|
hb_itemMove( pItem, hb_stackItemFromTop( -1 ) );
|
|
hb_stackPop();
|
|
|
|
return pItem;
|
|
}
|
|
|
|
|
|
#define IS_IDENT_START( c ) HB_ISFIRSTIDCHAR( ( HB_UCHAR ) ( c ) )
|
|
#define IS_IDENT_CHAR( c ) HB_ISNEXTIDCHAR( ( HB_UCHAR ) ( c ) )
|
|
|
|
static int hb_dbgEvalSubstituteVar( HB_WATCHPOINT * watch, char * szWord, int nStart, int nLen )
|
|
{
|
|
int j;
|
|
char * t;
|
|
|
|
for( j = 0; j < watch->nVars; j++ )
|
|
{
|
|
if( ! strcmp( szWord, watch->aVars[ j ] ) )
|
|
break;
|
|
}
|
|
|
|
if( j == watch->nVars )
|
|
*ARRAY_ADD( char *, watch->aVars, watch->nVars ) = szWord;
|
|
else
|
|
hb_xfree( szWord );
|
|
|
|
t = ( char * ) hb_xgrab( strlen( watch->szExpr ) - nLen + 9 + 1 );
|
|
memmove( t, watch->szExpr, nStart );
|
|
memmove( t + nStart, "__dbg[", 6 );
|
|
t[ nStart + 6 ] = '0' + ( char ) ( ( j + 1 ) / 10 );
|
|
t[ nStart + 7 ] = '0' + ( char ) ( ( j + 1 ) % 10 );
|
|
t[ nStart + 8 ] = ']';
|
|
hb_strncpy( t + nStart + 9, watch->szExpr + nStart + nLen, strlen( watch->szExpr ) - nLen - nStart );
|
|
hb_xfree( watch->szExpr );
|
|
watch->szExpr = t;
|
|
return nStart + 9;
|
|
}
|
|
|
|
|
|
static PHB_ITEM hb_dbgEvalMakeBlock( HB_WATCHPOINT * watch )
|
|
{
|
|
int i = 0;
|
|
PHB_ITEM pBlock;
|
|
HB_BOOL bAfterId = HB_FALSE;
|
|
char * s;
|
|
HB_ISIZ buffsize;
|
|
|
|
watch->nVars = 0;
|
|
while( watch->szExpr[ i ] )
|
|
{
|
|
char c = watch->szExpr[ i ];
|
|
|
|
if( IS_IDENT_START( c ) )
|
|
{
|
|
int nStart = i, nLen;
|
|
int j = i;
|
|
char * szWord;
|
|
|
|
while( c && IS_IDENT_CHAR( c ) )
|
|
{
|
|
j++;
|
|
c = watch->szExpr[ j ];
|
|
}
|
|
nLen = j - i;
|
|
i = j;
|
|
if( c )
|
|
{
|
|
while( watch->szExpr[ i ] == ' ' )
|
|
i++;
|
|
|
|
if( watch->szExpr[ i ] == '(' )
|
|
continue;
|
|
|
|
if( watch->szExpr[ i ] == '-' && watch->szExpr[ i + 1 ] == '>' )
|
|
{
|
|
i += 2;
|
|
|
|
while( ( c = watch->szExpr[ i ] ) != '\0' && IS_IDENT_CHAR( c ) )
|
|
i++;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
szWord = hb_strupr( hb_strndup( watch->szExpr + nStart, nLen ) );
|
|
i = hb_dbgEvalSubstituteVar( watch, szWord, nStart, nLen );
|
|
bAfterId = HB_TRUE;
|
|
continue;
|
|
}
|
|
if( c == '.' )
|
|
{
|
|
if( watch->szExpr[ i + 1 ]
|
|
&& strchr( "TtFf", watch->szExpr[ i + 1 ] )
|
|
&& watch->szExpr[ i + 2 ] == '.' )
|
|
{
|
|
i += 3;
|
|
}
|
|
else if( ! hb_strnicmp( watch->szExpr + i + 1, "OR.", 3 ) )
|
|
{
|
|
i += 4;
|
|
}
|
|
else if( ! hb_strnicmp( watch->szExpr + i + 1, "AND.", 4 )
|
|
|| ! hb_strnicmp( watch->szExpr + i + 1, "NOT.", 4 ) )
|
|
{
|
|
i += 5;
|
|
}
|
|
else
|
|
{
|
|
i++;
|
|
}
|
|
bAfterId = HB_FALSE;
|
|
continue;
|
|
}
|
|
if( c == ':'
|
|
|| ( c == '-' && watch->szExpr[ i + 1 ] == '>'
|
|
&& IS_IDENT_START( watch->szExpr[ i + 2 ] ) ) )
|
|
{
|
|
if( c == ':' && watch->szExpr[ i + 1 ] == ':' )
|
|
{
|
|
i = hb_dbgEvalSubstituteVar( watch, hb_strdup( "SELF" ), i, 1 );
|
|
bAfterId = HB_TRUE;
|
|
continue;
|
|
}
|
|
|
|
if( c == '-' )
|
|
i++;
|
|
|
|
i++;
|
|
|
|
while( watch->szExpr[ i ] && IS_IDENT_CHAR( watch->szExpr[ i ] ) )
|
|
i++;
|
|
|
|
bAfterId = HB_TRUE;
|
|
continue;
|
|
}
|
|
if( strchr( " !#$=<>(+-*/%^|,{&", c ) )
|
|
{
|
|
i++;
|
|
bAfterId = HB_FALSE;
|
|
continue;
|
|
}
|
|
if( c == '\'' || c == '\"' )
|
|
{
|
|
i++;
|
|
|
|
while( watch->szExpr[ i ] && watch->szExpr[ i ] != c )
|
|
i++;
|
|
|
|
if( watch->szExpr[ i ] )
|
|
i++;
|
|
|
|
bAfterId = HB_TRUE;
|
|
continue;
|
|
}
|
|
if( c == '[' )
|
|
{
|
|
i++;
|
|
if( bAfterId )
|
|
bAfterId = HB_FALSE;
|
|
else
|
|
{
|
|
while( watch->szExpr[ i ] && watch->szExpr[ i ] != ']' )
|
|
i++;
|
|
|
|
if( watch->szExpr[ i ] )
|
|
i++;
|
|
|
|
bAfterId = HB_TRUE;
|
|
}
|
|
continue;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
buffsize = 8 + strlen( watch->szExpr ) + 1;
|
|
|
|
s = ( char * ) hb_xgrab( buffsize + 1 );
|
|
hb_strncpy( s, "{|__dbg|", buffsize );
|
|
hb_strncat( s, watch->szExpr, buffsize );
|
|
hb_strncat( s, "}", buffsize );
|
|
pBlock = hb_itemNew( NULL );
|
|
|
|
if( ! hb_dbgEvalMacro( s, pBlock ) )
|
|
{
|
|
hb_itemRelease( pBlock );
|
|
pBlock = NULL;
|
|
}
|
|
hb_xfree( s );
|
|
|
|
return pBlock;
|
|
}
|
|
|
|
|
|
static PHB_ITEM hb_dbgEvalResolve( HB_DEBUGINFO * info, HB_WATCHPOINT * watch )
|
|
{
|
|
int i;
|
|
HB_CALLSTACKINFO * top = &info->aCallStack[ info->nCallStackLen - 1 ];
|
|
PHB_ITEM aVars = hb_itemArrayNew( watch->nVars );
|
|
HB_VARINFO * scopes;
|
|
HB_MODULEINFO * module = NULL;
|
|
int nProcLevel;
|
|
|
|
if( ! watch->nVars )
|
|
return aVars;
|
|
|
|
scopes = ( HB_VARINFO * ) hb_xgrab( watch->nVars * sizeof( HB_VARINFO ) );
|
|
nProcLevel = hb_dbg_ProcLevel();
|
|
|
|
HB_DBGCOMMON_LOCK();
|
|
|
|
for( i = 0; i < s_common.nModules; i++ )
|
|
{
|
|
if( FILENAME_EQUAL( s_common.aModules[ i ].szModule, top->szModule ) )
|
|
{
|
|
module = &s_common.aModules[ i ];
|
|
break;
|
|
}
|
|
}
|
|
|
|
for( i = 0; i < watch->nVars; i++ )
|
|
{
|
|
char * name = watch->aVars[ i ];
|
|
HB_VARINFO * var;
|
|
int j;
|
|
PHB_ITEM pItem;
|
|
|
|
for( j = 0; j < top->nLocals; j++ )
|
|
{
|
|
var = &top->aLocals[ j ];
|
|
if( ! strcmp( name, var->szName ) )
|
|
{
|
|
scopes[ i ].cType = 'L';
|
|
scopes[ i ].frame.num = nProcLevel - var->frame.num;
|
|
scopes[ i ].nIndex = var->nIndex;
|
|
hb_itemArrayPut( aVars, i + 1, hb_dbgVarGet( &scopes[ i ] ) );
|
|
break;
|
|
}
|
|
}
|
|
if( j < top->nLocals )
|
|
continue;
|
|
|
|
for( j = 0; j < top->nStatics; j++ )
|
|
{
|
|
var = &top->aStatics[ j ];
|
|
if( ! strcmp( name, var->szName ) )
|
|
{
|
|
scopes[ i ].cType = 'S';
|
|
scopes[ i ].frame.ptr = var->frame.ptr;
|
|
scopes[ i ].nIndex = var->nIndex;
|
|
hb_itemArrayPut( aVars, i + 1, hb_dbgVarGet( &scopes[ i ] ) );
|
|
break;
|
|
}
|
|
}
|
|
if( j < top->nStatics )
|
|
continue;
|
|
|
|
if( module )
|
|
{
|
|
for( j = 0; j < module->nStatics; j++ )
|
|
{
|
|
var = &module->aStatics[ j ];
|
|
if( ! strcmp( name, var->szName ) )
|
|
{
|
|
scopes[ i ].cType = 'S';
|
|
scopes[ i ].frame.ptr = var->frame.ptr;
|
|
scopes[ i ].nIndex = var->nIndex;
|
|
hb_itemArrayPut( aVars, i + 1, hb_dbgVarGet( &scopes[ i ] ) );
|
|
break;
|
|
}
|
|
}
|
|
if( j < module->nStatics )
|
|
continue;
|
|
|
|
for( j = 0; j < module->nGlobals; j++ )
|
|
{
|
|
var = &module->aGlobals[ j ];
|
|
if( ! strcmp( name, var->szName ) )
|
|
{
|
|
scopes[ i ].cType = 'G';
|
|
scopes[ i ].frame.num = var->frame.num;
|
|
scopes[ i ].nIndex = var->nIndex;
|
|
hb_itemArrayPut( aVars, i + 1, hb_dbgVarGet( &scopes[ i ] ) );
|
|
break;
|
|
}
|
|
}
|
|
if( j < module->nGlobals )
|
|
continue;
|
|
|
|
for( j = 0; j < module->nExternGlobals; j++ )
|
|
{
|
|
var = &module->aExternGlobals[ j ];
|
|
if( ! strcmp( name, var->szName ) )
|
|
{
|
|
scopes[ i ].cType = 'G';
|
|
scopes[ i ].frame.num = var->frame.num;
|
|
scopes[ i ].nIndex = var->nIndex;
|
|
hb_itemArrayPut( aVars, i + 1, hb_dbgVarGet( &scopes[ i ] ) );
|
|
break;
|
|
}
|
|
}
|
|
if( j < module->nExternGlobals )
|
|
continue;
|
|
}
|
|
|
|
scopes[ i ].cType = 'M';
|
|
scopes[ i ].szName = hb_dynsymGetSymbol( name )->szName;
|
|
|
|
pItem = hb_dbgVarGet( &scopes[ i ] );
|
|
|
|
if( pItem )
|
|
hb_itemArrayPut( aVars, i + 1, pItem );
|
|
|
|
if( scopes[ i ].cType == 'F' )
|
|
hb_itemRelease( pItem );
|
|
}
|
|
watch->aScopes = scopes;
|
|
|
|
HB_DBGCOMMON_UNLOCK();
|
|
|
|
return aVars;
|
|
}
|
|
|
|
|
|
PHB_ITEM hb_dbgGetExpressionValue( void * handle, const char * expression )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
PHB_ITEM result;
|
|
HB_WATCHPOINT point;
|
|
|
|
point.szExpr = hb_strdup( expression );
|
|
point.pBlock = NULL;
|
|
point.nVars = 0;
|
|
|
|
result = hb_dbgEval( info, &point );
|
|
|
|
hb_dbgClearWatch( &point );
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
PHB_ITEM hb_dbgGetSourceFiles( void * handle )
|
|
{
|
|
PHB_ITEM ret;
|
|
HB_ISIZ nModules;
|
|
HB_ISIZ i;
|
|
|
|
/* HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle; */
|
|
HB_SYMBOL_UNUSED( handle );
|
|
|
|
HB_DBGCOMMON_LOCK();
|
|
nModules = hb_itemSize( s_common.pStopLines );
|
|
ret = hb_itemArrayNew( nModules );
|
|
for( i = 1; i <= nModules; i++ )
|
|
hb_arraySet( ret, i, hb_arrayGetItemPtr( hb_arrayGetItemPtr( s_common.pStopLines, i ), 1 ) );
|
|
HB_DBGCOMMON_UNLOCK();
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
PHB_ITEM hb_dbgGetWatchValue( void * handle, int nWatch )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
|
|
return hb_dbgEval( info, &( info->aWatch[ nWatch ] ) );
|
|
}
|
|
|
|
|
|
static HB_BOOL hb_dbgIsAltD( void )
|
|
{
|
|
char szName[ HB_SYMBOL_NAME_LEN + HB_SYMBOL_NAME_LEN + 5 ];
|
|
|
|
hb_procinfo( 1, szName, NULL, NULL );
|
|
return ! strcmp( szName, "ALTD" );
|
|
}
|
|
|
|
|
|
static int hb_dbgIsBreakPoint( HB_DEBUGINFO * info, const char * szModule, int nLine )
|
|
{
|
|
int i;
|
|
|
|
/* szModule has stripped path here */
|
|
|
|
for( i = 0; i < info->nBreakPoints; i++ )
|
|
{
|
|
HB_BREAKPOINT * point = &info->aBreak[ i ];
|
|
|
|
if( point->nLine == nLine && FILENAME_EQUAL( szModule, point->szModule ) )
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
HB_BOOL hb_dbgIsValidStopLine( void * handle, const char * szModule, int nLine )
|
|
{
|
|
HB_BOOL fResult = HB_FALSE;
|
|
HB_ISIZ nModules;
|
|
HB_ISIZ i;
|
|
|
|
/* HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle; */
|
|
HB_SYMBOL_UNUSED( handle );
|
|
|
|
szModule = hb_dbgStripModuleName( szModule );
|
|
|
|
HB_DBGCOMMON_LOCK();
|
|
nModules = hb_itemSize( s_common.pStopLines );
|
|
for( i = 1; i <= nModules; i++ )
|
|
{
|
|
PHB_ITEM pEntry = hb_arrayGetItemPtr( s_common.pStopLines, i );
|
|
|
|
if( FILENAME_EQUAL( hb_arrayGetCPtr( pEntry, 1 ), szModule ) )
|
|
{
|
|
int nMin = hb_arrayGetNL( pEntry, 2 );
|
|
int nOfs = nLine - nMin;
|
|
|
|
if( nOfs >= 0 && ( HB_SIZE ) ( nOfs >> 3 ) < hb_arrayGetCLen( pEntry, 3 ) )
|
|
fResult = ( hb_arrayGetCPtr( pEntry, 3 )[ nOfs >> 3 ] & ( 1 << ( nOfs & 0x07 ) ) ) != 0;
|
|
|
|
break;
|
|
}
|
|
}
|
|
HB_DBGCOMMON_UNLOCK();
|
|
return fResult;
|
|
}
|
|
|
|
|
|
const char * hb_dbgGetModuleName( void * handle, const char * szName )
|
|
{
|
|
/* HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle; */
|
|
HB_SYMBOL_UNUSED( handle );
|
|
|
|
if( szName )
|
|
szName = hb_dbgStripModuleName( szName );
|
|
|
|
return szName;
|
|
}
|
|
|
|
|
|
static void hb_dbgQuit( HB_DEBUGINFO * info )
|
|
{
|
|
while( info->nWatchPoints )
|
|
{
|
|
hb_dbgDelWatch( info, info->nWatchPoints - 1 );
|
|
}
|
|
while( info->nBreakPoints )
|
|
{
|
|
hb_dbgDelBreak( info, info->nBreakPoints - 1 );
|
|
}
|
|
while( info->nCallStackLen )
|
|
{
|
|
hb_dbgEndProc( info );
|
|
}
|
|
if( info->bToCursor )
|
|
{
|
|
info->bToCursor = HB_FALSE;
|
|
hb_xfree( info->szToCursorModule );
|
|
}
|
|
}
|
|
|
|
|
|
static void hb_dbgRelease( void )
|
|
{
|
|
if( s_common.pStopLines )
|
|
{
|
|
hb_itemRelease( s_common.pStopLines );
|
|
s_common.pStopLines = NULL;
|
|
}
|
|
while( s_common.nModules )
|
|
{
|
|
int nModules = s_common.nModules - 1;
|
|
HB_MODULEINFO * module = &s_common.aModules[ nModules ];
|
|
if( module->nStatics )
|
|
{
|
|
hb_xfree( module->aStatics );
|
|
}
|
|
if( module->nGlobals )
|
|
{
|
|
hb_xfree( module->aGlobals );
|
|
}
|
|
if( module->nExternGlobals )
|
|
{
|
|
hb_xfree( module->aExternGlobals );
|
|
}
|
|
if( module->szModule )
|
|
{
|
|
hb_xfree( module->szModule );
|
|
}
|
|
ARRAY_DEL( HB_MODULEINFO, s_common.aModules, s_common.nModules, nModules );
|
|
}
|
|
}
|
|
|
|
|
|
void hb_dbgSetCBTrace( void * handle, HB_BOOL bCBTrace )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
|
|
info->bCBTrace = bCBTrace;
|
|
}
|
|
|
|
|
|
void hb_dbgSetGo( void * handle )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
|
|
info->bGo = HB_TRUE;
|
|
}
|
|
|
|
|
|
void hb_dbgSetInvoke( void * handle, HB_BOOL ( * pFunInvoke )( void ) )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
|
|
info->pFunInvoke = pFunInvoke;
|
|
}
|
|
|
|
|
|
void hb_dbgSetNextRoutine( void * handle )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
|
|
info->bNextRoutine = HB_TRUE;
|
|
}
|
|
|
|
|
|
void hb_dbgSetQuit( void * handle )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
|
|
info->bQuit = HB_TRUE;
|
|
}
|
|
|
|
|
|
void hb_dbgSetToCursor( void * handle, const char * szModule, int nLine )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
|
|
szModule = hb_dbgStripModuleName( szModule );
|
|
|
|
info->bToCursor = HB_TRUE;
|
|
info->szToCursorModule = hb_strdup( szModule );
|
|
info->nToCursorLine = nLine;
|
|
}
|
|
|
|
|
|
void hb_dbgSetTrace( void * handle )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
|
|
info->bTraceOver = HB_TRUE;
|
|
info->nTraceLevel = info->nCallStackLen;
|
|
}
|
|
|
|
|
|
void hb_dbgSetWatch( void * handle, int nWatch, const char * szExpr, HB_BOOL bTrace )
|
|
{
|
|
HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle;
|
|
HB_WATCHPOINT * pWatch = &info->aWatch[ nWatch ];
|
|
int i;
|
|
|
|
hb_dbgClearWatch( pWatch );
|
|
pWatch->szExpr = hb_strdup( szExpr );
|
|
pWatch->pBlock = NULL;
|
|
for( i = 0; i < info->nTracePoints; i++ )
|
|
{
|
|
HB_TRACEPOINT * pTrace = &info->aTrace[ i ];
|
|
|
|
if( pTrace->nIndex == nWatch )
|
|
{
|
|
if( pTrace->xValue )
|
|
hb_itemRelease( pTrace->xValue );
|
|
|
|
ARRAY_DEL( HB_TRACEPOINT, info->aTrace, info->nTracePoints, i );
|
|
break;
|
|
}
|
|
}
|
|
if( bTrace )
|
|
{
|
|
HB_TRACEPOINT * pTrace = ARRAY_ADD( HB_TRACEPOINT, info->aTrace, info->nTracePoints );
|
|
|
|
pTrace->nIndex = nWatch;
|
|
pTrace->xValue = hb_dbgEval( info, pWatch );
|
|
}
|
|
}
|
|
|
|
|
|
static PHB_ITEM hb_dbgVarGet( HB_VARINFO * scope )
|
|
{
|
|
switch( scope->cType )
|
|
{
|
|
case 'G':
|
|
return hb_dbg_vmVarGGet( scope->frame.num, scope->nIndex );
|
|
case 'L':
|
|
return hb_dbg_vmVarLGet( scope->frame.num, scope->nIndex );
|
|
case 'S':
|
|
return hb_dbg_vmVarSGet( scope->frame.ptr, scope->nIndex );
|
|
case 'M':
|
|
{
|
|
PHB_DYNS pDyn;
|
|
|
|
pDyn = hb_dynsymFind( scope->szName );
|
|
if( pDyn != NULL )
|
|
{
|
|
PHB_ITEM pItem = hb_memvarGetValueBySym( pDyn );
|
|
if( ! pItem )
|
|
{
|
|
pItem = hb_itemNew( NULL );
|
|
if( hb_rddFieldGet( pItem, hb_dynsymSymbol( pDyn ) ) == HB_SUCCESS )
|
|
{
|
|
scope->cType = 'F';
|
|
}
|
|
else
|
|
{
|
|
hb_itemRelease( pItem );
|
|
pItem = NULL;
|
|
}
|
|
}
|
|
return pItem;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static void hb_dbgVarSet( HB_VARINFO * scope, PHB_ITEM xNewValue )
|
|
{
|
|
switch( scope->cType )
|
|
{
|
|
case 'G':
|
|
case 'L':
|
|
case 'S':
|
|
hb_itemCopy( hb_dbgVarGet( scope ), xNewValue );
|
|
break;
|
|
case 'M':
|
|
{
|
|
PHB_DYNS pDynSym = hb_dynsymFind( "__MVPUT" );
|
|
|
|
if( pDynSym && hb_dynsymIsFunction( pDynSym ) )
|
|
{
|
|
hb_vmPushDynSym( pDynSym );
|
|
hb_vmPushNil();
|
|
hb_vmPushString( scope->szName, strlen( scope->szName ) );
|
|
hb_vmPush( xNewValue );
|
|
hb_vmDo( 2 );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* .prg functions
|
|
*/
|
|
HB_FUNC( __DBGSETENTRY )
|
|
{
|
|
hb_dbg_SetEntry( hb_dbgEntry );
|
|
}
|
|
|
|
HB_FUNC( __DBGSETGO )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_dbgSetGo( ptr );
|
|
}
|
|
|
|
HB_FUNC( __DBGSETTRACE )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_dbgSetTrace( ptr );
|
|
}
|
|
|
|
HB_FUNC( __DBGSETCBTRACE )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_dbgSetCBTrace( ptr, hb_parl( 2 ) );
|
|
}
|
|
|
|
HB_FUNC( __DBGSETNEXTROUTINE )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_dbgSetNextRoutine( ptr );
|
|
}
|
|
|
|
HB_FUNC( __DBGSETQUIT )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_dbgSetQuit( ptr );
|
|
}
|
|
|
|
HB_FUNC( __DBGSETTOCURSOR )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_dbgSetToCursor( ptr, hb_parc( 2 ), hb_parni( 3 ) );
|
|
}
|
|
|
|
HB_FUNC( __DBGGETEXPRVALUE )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
{
|
|
PHB_ITEM pItem;
|
|
|
|
if( HB_ISCHAR( 2 ) )
|
|
pItem = hb_dbgGetExpressionValue( hb_parptr( 1 ), hb_parc( 2 ) );
|
|
else
|
|
pItem = hb_dbgGetWatchValue( hb_parptr( 1 ), hb_parni( 2 ) - 1 );
|
|
|
|
if( pItem )
|
|
{
|
|
hb_storl( HB_TRUE, 3 );
|
|
hb_itemReturnRelease( pItem );
|
|
}
|
|
else
|
|
hb_storl( HB_FALSE, 3 );
|
|
}
|
|
}
|
|
|
|
HB_FUNC( __DBGGETSOURCEFILES )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_itemReturnRelease( hb_dbgGetSourceFiles( ptr ) );
|
|
}
|
|
|
|
HB_FUNC( __DBGISVALIDSTOPLINE )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_retl( hb_dbgIsValidStopLine( ptr, hb_parc( 2 ), hb_parni( 3 ) ) );
|
|
}
|
|
|
|
HB_FUNC( __DBGADDBREAK )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_dbgAddBreak( ptr, hb_parc( 2 ), hb_parni( 3 ), NULL );
|
|
}
|
|
|
|
HB_FUNC( __DBGDELBREAK )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_dbgDelBreak( ptr, hb_parni( 2 ) );
|
|
}
|
|
|
|
HB_FUNC( __DBGISBREAK )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_retni( hb_dbgIsBreakPoint( ( HB_DEBUGINFO * ) ptr,
|
|
hb_dbgStripModuleName( hb_parc( 2 ) ),
|
|
hb_parni( 3 ) ) );
|
|
}
|
|
|
|
HB_FUNC( __DBGGETBREAKPOINTS )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_itemReturnRelease( hb_dbgActivateBreakArray( ( HB_DEBUGINFO * ) ptr ) );
|
|
}
|
|
|
|
HB_FUNC( __DBGADDWATCH )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_dbgAddWatch( ptr, hb_parc( 2 ), hb_parl( 3 ) );
|
|
}
|
|
|
|
HB_FUNC( __DBGDELWATCH )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_dbgDelWatch( ptr, hb_parni( 2 ) );
|
|
}
|
|
|
|
HB_FUNC( __DBGSETWATCH )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_dbgSetWatch( ptr, hb_parni( 2 ), hb_parc( 3 ), hb_parl( 4 ) );
|
|
}
|
|
|
|
HB_FUNC( __DBGGETMODULENAME )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
hb_retc( hb_dbgGetModuleName( ptr, hb_parc( 2 ) ) );
|
|
}
|
|
|
|
HB_FUNC( __DBGMODULEMATCH )
|
|
{
|
|
void * ptr = hb_parptr( 1 );
|
|
|
|
if( ptr )
|
|
{
|
|
const char * szModule1 = hb_parc( 2 ),
|
|
* szModule2 = hb_parc( 3 );
|
|
|
|
hb_retl( szModule1 && szModule2 &&
|
|
FILENAME_EQUAL( hb_dbgStripModuleName( szModule1 ),
|
|
hb_dbgStripModuleName( szModule2 ) ) );
|
|
}
|
|
}
|
|
|
|
HB_FUNC( __DBGSENDMSG )
|
|
{
|
|
hb_dbg_objSendMessage( hb_parnl( 1 ), hb_param( 2, HB_IT_ANY ),
|
|
hb_param( 3, HB_IT_ANY ), 4 );
|
|
}
|