;--- CDBA, CDB-like debugger which uses the MS debug engine API.
;--- The source may also be used to create NTSDA, the NTSD variant.
;--- The source uses WinInc assembly include files.
.386
.model flat,stdcall
option casemap:none
option proc:private
.nolist
.nocref
WIN32_LEAN_AND_MEAN equ 1
include windows.inc
include dbgeng.inc
include dbghelp.inc ;needed for SYMOPT_ values
include stdlib.inc
include string.inc
include stdio.inc
.list
.cref
includelib kernel32.lib
includelib msvcrt.lib
includelib dbgeng.lib
includelib uuid.lib
DEF_PROCESS_FLAGS equ DEBUG_PROCESS
USEPROCESS2 equ 0 ;1=use IDebugClient5 interface
;--- macros
lf equ 10
cr equ 13
CStr macro text:VARARG
local xxx
.const
xxx db text,0
.code
exitm <offset xxx>
endm
dprintf macro fstr, items:VARARG
ifdef _DEBUG
pushad
ifnb <items>
invoke printf, CStr(fstr), items
else
invoke printf, CStr(fstr)
endif
popad
endif
endm
;--- event objects
CDebugEventCallbacks struct
IDebugEventCallbacks <>
cnt dword ?
CDebugEventCallbacks ends
CDebugInputCallbacks struct
IDebugInputCallbacks <>
cnt dword ?
CDebugInputCallbacks ends
CDebugOutputCallbacks struct
IDebugOutputCallbacks <>
cnt dword ?
CDebugOutputCallbacks ends
.data
pDebugClient PDEBUG_CLIENT NULL
pDebugControl PDEBUG_CONTROL NULL
pDebugSymbols PDEBUG_SYMBOLS NULL
;pDebugEventCallbacks PDEBUG_EVENT_CALLBACKS NULL
;pDebugInputCallbacks PDEBUG_INPUT_CALLBACKS NULL
;pDebugOutputCallbacks PDEBUG_OUTPUT_CALLBACKS NULL
opbuf DEBUG_CREATE_PROCESS_OPTIONS < DEF_PROCESS_FLAGS, 0, 0, 0 >
pszFile dd NULL
pid dd 0 ;-p process ID
pszSymbolPath dd NULL ;-y
pszSrcPath dd NULL ;-srcpath
pszLogFile dd NULL ;-logo
pszCommand dd NULL ;-c
pszCmdFile dd NULL ;-cf
attachflgs dd 0 ;-pv
clflgs dd 0
bStateChanged db 0
;--- clflgs values
CLF_DUMP equ 1 ;-z
CLF_LINES equ 2 ;-lines
CLF_IGNORE_INITIAL_BP equ 4 ;-g
CLF_IGNORE_FINAL_BP equ 8 ;-G
CLF_BP_AT_ENTRY equ 16;-j
CLF_ATTACH_ID equ 32;-p
.const
DebugEventCallbacksVtbl label IDebugEventCallbacksVtbl
dd QueryInterface@DebugEventCallbacks
dd AddRef@DebugEventCallbacks
dd Release@DebugEventCallbacks
dd GetInterestMask@DebugEventCallbacks
dd Breakpoint@DebugEventCallbacks
dd Exception@DebugEventCallbacks
dd CreateThread@DebugEventCallbacks
dd ExitThread@DebugEventCallbacks
dd CreateProcess@DebugEventCallbacks
dd ExitProcess@DebugEventCallbacks
dd LoadModule@DebugEventCallbacks
dd UnloadModule@DebugEventCallbacks
dd SystemError@DebugEventCallbacks
dd SessionStatus@DebugEventCallbacks
dd ChangeDebuggeeState@DebugEventCallbacks
dd ChangeEngineState@DebugEventCallbacks
dd ChangeSymbolState@DebugEventCallbacks
DebugInputCallbacksVtbl label IDebugInputCallbacksVtbl
dd QueryInterface@DebugInputCallbacks
dd AddRef@DebugInputCallbacks
dd Release@DebugInputCallbacks
dd StartInput@DebugInputCallbacks
dd EndInput@DebugInputCallbacks
DebugOutputCallbacksVtbl label IDebugOutputCallbacksVtbl
dd QueryInterface@DebugOutputCallbacks
dd AddRef@DebugOutputCallbacks
dd Release@DebugOutputCallbacks
dd Output@DebugOutputCallbacks
;--- filter values for event INITIAL_BREAKPOINT
specfilters label DEBUG_SPECIFIC_FILTER_PARAMETERS
DEBUG_SPECIFIC_FILTER_PARAMETERS < DEBUG_FILTER_BREAK, DEBUG_FILTER_GO_HANDLED >
ifdef ?NTSD
pgm equ <"NTSD">
else
pgm equ <"CDB">
endif
szUsage label byte
db pgm,"A v0.78, Public Domain, japheth 2009.",lf
db pgm,"-like debugger based on MS Debug Engine API.",lf
if USEPROCESS2
db "Needs a somewhat recent version of DbgEng.dll,",lf
db "which one might find in 'Debugging Tools for Windows'.",lf
endif
db "usage: ",pgm,"A [ options ] filename",lf
db "options:",lf
db " -2: run debuggee in separate console window",lf
db " -c ""<command>"": executes command at first debugger prompt",lf
db " -cf <file>: execute script file at first debugger prompt",lf
db " -g: ignore initial breakpoint",lf
db " -G: ignore final breakpoint",lf
db " -j: set breakpoint at program entry",lf
db " -lines: load line number info",lf
db " -logo <logfile>: open new log file",lf
db " -p <pid>: attach to a process",lf
db " -pv: noninvasive attachs",lf
db " -srcpath <source_path>: set source search path",lf
db " -y <symbols_path>: set symbols search path",lf
db " -z: assume file is a dump file",lf
db 0
.code
;--- get ONE argument from commandline
getarg proc uses esi edi cmdline:ptr BYTE, buffer:ptr byte, maxlen:dword
local bQuote:BYTE
mov edi, buffer
mov edx, maxlen
add edx, edi
dec edx
mov bQuote, 0
.while ( byte ptr [esi] && ( edi < edx ) )
lodsb
.if ( al == bQuote )
.break .if ( al != [esi] )
inc esi
stosb
.elseif ( al == '"' || al == "'" )
mov bQuote, al
.elseif ( !bQuote && ( al == ' ' || al == 9 ) )
.break
.else
stosb
.endif
.endw
mov al,0
stosb
.while ( byte ptr [esi] == ' ' || byte ptr [esi] == 9 )
inc esi
.endw
mov eax, esi
ret
align 4
getarg endp
;--- get arguments from commandline until 'file' argument found
getargs proc uses esi cmdline:ptr byte
local nextarg:dword
local buffer[260]:byte
mov esi, cmdline
invoke getarg, esi, addr buffer, sizeof buffer ;skip first arg
mov esi, eax
.while ( byte ptr [esi] )
invoke getarg, esi, addr buffer, sizeof buffer
mov nextarg, eax
dprintf <"getargs: >%s<",lf>,addr buffer
mov al, buffer
.if ( al == '-' || al == '/' )
mov esi, offset cmdlineoptions
.while (dword ptr [esi])
lodsd
lea ecx, buffer+1
invoke strcmp, eax, ecx
.break .if ( eax == 0 )
add esi,4 ;skip option address
.endw
.if ( eax == 0 )
lodsd
call eax
.if ( CARRY? )
xor eax, eax
ret
.endif
.else
invoke printf, CStr("unknown option %s",lf), addr buffer
xor eax, eax
ret
.endif
.else
invoke strlen, addr buffer
inc eax
invoke malloc, eax
.if ( !eax )
invoke printf, CStr("out of memory",lf)
xor eax,eax
ret
.endif
mov pszFile, eax
invoke strcpy, pszFile, addr buffer
.break
.endif
mov esi, nextarg
.endw
mov eax, esi
ret
align 4
cmdlineoptions label dword
dd CStr("2"), offset set_2
dd CStr("c"), offset set_c
dd CStr("cf"), offset set_cf
dd CStr("G"), offset set_G
dd CStr("g"), offset set_g
dd CStr("j"), offset set_j
dd CStr("lines"), offset set_lines
dd CStr("logo"), offset set_logo
dd CStr("p"), offset set_p
dd CStr("pv"), offset set_pv
dd CStr("srcpath"), offset set_srcpath
dd CStr("y"), offset set_y
dd CStr("z"), offset set_z
dd NULL
;--- get additional file parameter for an option
;--- eax = address of variable where to store param
getfilearg:
push eax
mov esi, nextarg
invoke getarg, esi, addr buffer, sizeof buffer
mov nextarg, eax
invoke strlen, addr buffer
inc eax
invoke malloc, eax
pop edx
.if ( eax )
mov [edx], eax
mov edx, eax
invoke strcpy, edx, addr buffer
.endif
retn
;--- cmdline option stubs
set_2:
or opbuf.CreateFlags, CREATE_NEW_CONSOLE
retn
set_c:
mov eax, offset pszCommand
call getfilearg
clc
retn
set_cf:
mov eax, offset pszCmdFile
call getfilearg
clc
retn
set_G:
or clflgs, CLF_IGNORE_FINAL_BP
retn
set_g:
or clflgs, CLF_IGNORE_INITIAL_BP
retn
set_j:
or clflgs, CLF_BP_AT_ENTRY
retn
set_lines:
or clflgs, CLF_LINES
retn
set_logo:
mov eax, offset pszLogFile
call getfilearg
clc
retn
set_p:
mov esi, nextarg
invoke getarg, esi, addr buffer, sizeof buffer
mov nextarg, eax
.if ( buffer == 0 )
invoke printf, CStr("process ID missing",lf)
stc
retn
.endif
invoke atoi, addr buffer
.if ( eax == 0 )
invoke printf, CStr("bad process ID",lf)
stc
retn
.endif
or clflgs, CLF_ATTACH_ID
mov pid, eax
retn
set_pv:
or attachflgs, DEBUG_ATTACH_NONINVASIVE
retn
set_srcpath:
mov eax, offset pszSrcPath
call getfilearg
clc
retn
set_y:
mov eax, offset pszSymbolPath
call getfilearg
clc
retn
set_z:
or clflgs, CLF_DUMP
retn
align 4
getargs endp
;--- make Ctrl-C break into debugger when debuggee is running
myctrlhandler proc dwCtrlType:dword
local dwStatus:dword
.if ( pDebugControl )
if 0
invoke vf( pDebugControl, IDebugControl, GetExecutionStatus ), addr dwStatus
mov eax, dwStatus
.if ( eax == DEBUG_STATUS_GO || eax == DEBUG_STATUS_STEP_OVER || \
eax == DEBUG_STATUS_STEP_INTO || eax == DEBUG_STATUS_STEP_BRANCH )
invoke vf( pDebugControl, IDebugControl, SetInterrupt ), DEBUG_INTERRUPT_ACTIVE
invoke printf, CStr("^C",lf)
.endif
else
invoke vf( pDebugControl, IDebugControl, SetInterrupt ), DEBUG_INTERRUPT_ACTIVE
invoke printf, CStr("^C",lf)
endif
mov eax,1
ret
.endif
xor eax, eax
ret
align 4
myctrlhandler endp
main proc c uses ebx
local rc:byte
local cmdline:dword
local dwRead:dword
local buffer[256]:byte
local szCurrDir[260]:byte
ifdef ?NTSD
invoke AllocConsole
invoke freopen, CStr("CONIN$"), CStr("r"), stdin
invoke freopen, CStr("CONOUT$"), CStr("w"), stdout
endif
mov rc,1
invoke GetCommandLine
dprintf <"cmdline:>%s<",lf>, eax
invoke getargs, eax
and eax, eax
jz exit_
.if ( pszFile == NULL && pid == 0 )
invoke printf, CStr("%s"), addr szUsage
jmp exit_
.endif
mov cmdline, eax
;--- create objects IDebugClient(5), IDebugControl, IDebugSymbols
if USEPROCESS2
invoke DebugCreate, addr IID_IDebugClient5, addr pDebugClient
else
invoke DebugCreate, addr IID_IDebugClient, addr pDebugClient
endif
.if ( eax != S_OK )
if USEPROCESS2
invoke printf, CStr("unable to create IDebugClient5 object. DbgEng.dll too old?",lf)
else
invoke printf, CStr("unable to create IDebugClient object.",lf)
endif
jmp exit_
.endif
invoke vf( pDebugClient, IDebugClient, QueryInterface), addr IID_IDebugControl, addr pDebugControl
.if ( eax != S_OK )
invoke printf, CStr("IDebugClient:QueryInterface failed [%X]",lf), eax
jmp exit_
.endif
invoke vf( pDebugClient, IDebugClient, QueryInterface), addr IID_IDebugSymbols, addr pDebugSymbols
.if ( eax != S_OK )
invoke printf, CStr("IDebugClient:QueryInterface failed [%X]",lf), eax
jmp exit_
.endif
;--- create and set callback objects Event, Input, Output
invoke malloc, sizeof CDebugEventCallbacks
.if ( !eax )
invoke printf, CStr("out of memory",lf)
jmp exit_
.endif
mov [eax].CDebugEventCallbacks.lpVtbl, offset DebugEventCallbacksVtbl
mov [eax].CDebugEventCallbacks.cnt, 0
invoke vf( pDebugClient, IDebugClient, SetEventCallbacks ), eax
.if ( eax != S_OK )
invoke printf, CStr("IDebugClient:SetEventCallbacks failed [%X]",lf), eax
.endif
invoke malloc, sizeof CDebugInputCallbacks
.if ( !eax )
invoke printf, CStr("out of memory",lf)
jmp exit_
.endif
mov [eax].CDebugInputCallbacks.lpVtbl, offset DebugInputCallbacksVtbl
mov [eax].CDebugInputCallbacks.cnt, 0
invoke vf( pDebugClient, IDebugClient, SetInputCallbacks ), eax
.if ( eax != S_OK )
invoke printf, CStr("IDebugClient:SetInputCallbacks failed [%X]",lf), eax
.endif
invoke malloc, sizeof CDebugOutputCallbacks
.if ( !eax )
invoke printf, CStr("out of memory",lf)
jmp exit_
.endif
mov [eax].CDebugOutputCallbacks.lpVtbl, offset DebugOutputCallbacksVtbl
mov [eax].CDebugOutputCallbacks.cnt, 0
invoke vf( pDebugClient, IDebugClient, SetOutputCallbacks ), eax
.if ( eax != S_OK )
invoke printf, CStr("IDebugClient:SetOutputCallbacks failed [%X]",lf), eax
.endif
if 0
invoke vf( pDebugClient, IDebugClient, SetOutputMask ), DEBUG_OUTPUT_NORMAL or DEBUG_OUTPUT_ERROR or DEBUG_OUTPUT_WARNING or DEBUG_OUTPUT_VERBOSE or DEBUG_OUTPUT_PROMPT
.if ( eax != S_OK )
invoke printf, CStr("IDebugClient:SetOutputMask failed [%X]",lf), eax
.endif
endif
;--- open log file if requested
.if ( pszLogFile )
invoke vf( pDebugControl, IDebugControl, OpenLogFile ), pszLogFile, FALSE
.if ( eax != S_OK )
invoke printf, CStr("IDebugControl:OpenLogFile(%s) failed [%X]",lf), pszLogFile, eax
.endif
.endif
;--- set specific filters
;--- make debugger break at initial bp
.if ( !(clflgs & CLF_IGNORE_INITIAL_BP) )
invoke vf( pDebugControl, IDebugControl, SetSpecificFilterParameters ), DEBUG_FILTER_INITIAL_BREAKPOINT, 1, addr specfilters
.if ( eax != S_OK )
invoke printf, CStr("IDebugControl:SetSpecificFilterParameters() failed [%X]",lf), eax
.endif
.endif
invoke SetConsoleCtrlHandler, offset myctrlhandler, TRUE
;--- set optional symbol path and source path
.if ( pszSymbolPath )
invoke vf( pDebugSymbols, IDebugSymbols, SetSymbolPath ), pszSymbolPath
.if ( eax != S_OK )
invoke printf, CStr("IDebugSymbols:SetSymbolPath(%s) failed [%X]",lf), pszSymbolPath, eax
.endif
.endif
.if ( pszSrcPath )
invoke vf( pDebugSymbols, IDebugSymbols, SetSourcePath ), pszSrcPath
.if ( eax != S_OK )
invoke printf, CStr("IDebugSymbols:SetSourcePath(%s) failed [%X]",lf), pszSrcPath, eax
.endif
.endif
;--- make symbol options compatible with MS CDB
invoke vf( pDebugSymbols, IDebugSymbols, AddSymbolOptions ), \
SYMOPT_CASE_INSENSITIVE or SYMOPT_UNDNAME or SYMOPT_DEFERRED_LOADS or SYMOPT_FAIL_CRITICAL_ERRORS
.if ( eax != S_OK )
invoke printf, CStr("IDebugSymbols:AddSymbolOptions() failed [%X]",lf), eax
.endif
;--- try to open the file
.if ( clflgs & CLF_DUMP )
invoke vf( pDebugClient, IDebugClient, OpenDumpFile ), pszFile
.if ( eax != S_OK )
invoke printf, CStr("IDebugClient:OpenDumpFile(%s) failed [%X]",lf), pszFile, eax
jmp exit_
.endif
.else
.if ( clflgs & CLF_LINES )
invoke vf( pDebugSymbols, IDebugSymbols, AddSymbolOptions ), SYMOPT_LOAD_LINES
.endif
xor ecx, ecx
.if ( clflgs & CLF_ATTACH_ID )
invoke vf( pDebugClient, IDebugClient, AttachProcess ), ecx::ecx,\
pid, attachflgs
.if ( eax != S_OK )
invoke printf, CStr("IDebugClient:AttachProcess2(%u) failed [%X]",lf), pid, eax
jmp exit_
.endif
.else
if USEPROCESS2
;--- requires IDebugClient5
invoke vf( pDebugClient, IDebugClient5, CreateProcess2 ), ecx::ecx, cmdline, addr opbuf, \
sizeof DEBUG_CREATE_PROCESS_OPTIONS, NULL, NULL
.if ( eax != S_OK )
invoke printf, CStr("IDebugClient:CreateProcess2(%s) failed [%X]",lf), pszFile, eax
jmp exit_
.endif
else
invoke vf( pDebugClient, IDebugClient, CreateProcess ), ecx::ecx, cmdline, \
opbuf.CreateFlags
.if ( eax != S_OK )
invoke printf, CStr("IDebugClient:CreateProcess(%s) failed [%X]",lf), pszFile, eax
jmp exit_
.endif
endif
.endif
.endif
invoke vf( pDebugControl, IDebugControl, WaitForEvent ), 0, INFINITE
mov rc,0
;--- process optional -c and -cf arguments
.if ( pszCommand )
invoke vf( pDebugControl, IDebugControl, Execute ), DEBUG_OUTCTL_THIS_CLIENT, pszCommand, 0
.endif
.if ( pszCmdFile )
invoke vf( pDebugControl, IDebugControl, ExecuteCommandFile ), DEBUG_OUTCTL_THIS_CLIENT, pszCmdFile, DEBUG_EXECUTE_ECHO
.endif
;--- main loop: read input and let the debug engine interpret it
.while (1)
invoke vf( pDebugControl, IDebugControl, GetExecutionStatus ), addr dwRead
.if ( eax != S_OK )
invoke printf, CStr("IDebugControl:GetExecutionStatus failed [%X]",lf), eax
.break
.endif
mov eax, dwRead
;--- exit loop if user pressed 'q'
.break .if ( eax == DEBUG_STATUS_NO_DEBUGGEE )
;--- if a debuggee runs, call WaitEvent and don't prompt
.if ( eax == DEBUG_STATUS_GO || eax == DEBUG_STATUS_STEP_OVER || \
eax == DEBUG_STATUS_STEP_INTO || eax == DEBUG_STATUS_STEP_BRANCH )
invoke vf( pDebugControl, IDebugControl, WaitForEvent ), 0, INFINITE
.continue .if ( eax == S_OK )
; E_UNEXPECTED is returned if target has finished
.if ( eax != E_UNEXPECTED )
invoke printf, CStr("IDebugControl:WaitForEvent failed [%X]",lf), eax
.endif
.break
.endif
;--- if debuggee state has changed, display registers and current instruction
.if ( bStateChanged )
mov bStateChanged, 0
invoke vf( pDebugControl, IDebugControl, OutputCurrentState ), DEBUG_OUTCTL_THIS_CLIENT, DEBUG_CURRENT_DEFAULT
.endif
;--- prompt for user input and run it
invoke vf( pDebugControl, IDebugControl, OutputPrompt ), DEBUG_OUTCTL_THIS_CLIENT, NULL
invoke vf( pDebugControl, IDebugControl, Input ), addr buffer, sizeof buffer, addr dwRead
.if ( eax != S_OK )
invoke printf, CStr("IDebugControl:Input failed [%X]",lf), eax
.elseif ( dwRead )
invoke vf( pDebugControl, IDebugControl, Execute ), DEBUG_OUTCTL_THIS_CLIENT, addr buffer, 0
.endif
.endw
exit_:
.if ( pDebugClient )
.if ( pDebugSymbols )
invoke vf( pDebugSymbols, IUnknown, Release )
.endif
.if ( pDebugControl )
invoke vf( pDebugControl, IUnknown, Release )
.endif
invoke vf( pDebugClient, IUnknown, Release )
.endif
ifdef ?NTSD
@DefProto _CRTIMP, _getch, c, , <>
.if ( rc )
invoke printf, CStr(pgm,"A exiting - press enter ---")
.repeat
invoke _getch
.until eax == cr
.endif
invoke FreeConsole
endif
movzx eax, rc
ret
align 4
main endp
;--- IDebugEventCallbacks methods
QueryInterface@DebugEventCallbacks proc uses esi edi this_:ptr, pIID:ptr IID, pObject:ptr ptr
dprintf <"QueryInterface@DebugEventCallbacks called",lf>
mov ecx,4
mov esi, pIID
mov edi, offset IID_IDebugEventCallbacks
repz cmpsd
jz ok
mov ecx,4
mov esi, pIID
mov edi, offset IID_IUnknown
repz cmpsd
jz ok
mov eax, E_NOINTERFACE
ret
ok:
invoke vf( this_, IUnknown, AddRef )
mov edx, this_
mov ecx, pObject
mov [ecx], edx
mov eax, S_OK
ret
align 4
QueryInterface@DebugEventCallbacks endp
AddRef@DebugEventCallbacks proc this_:ptr
dprintf <"AddRef@DebugEventCallbacks called",lf>
mov ecx, this_
inc [ecx].CDebugEventCallbacks.cnt
mov eax, [ecx].CDebugEventCallbacks.cnt
ret
align 4
AddRef@DebugEventCallbacks endp
Release@DebugEventCallbacks proc this_:ptr
dprintf <"Release@DebugEventCallbacks called",lf>
mov ecx, this_
dec [ecx].CDebugEventCallbacks.cnt
mov eax, [ecx].CDebugEventCallbacks.cnt
.if ( eax == 0 )
invoke free, ecx
xor eax, eax
.endif
ret
align 4
Release@DebugEventCallbacks endp
GetInterestMask@DebugEventCallbacks proc this_:ptr, Mask_:ptr DWORD
dprintf <"GetInterestMask@DebugEventCallbacks called",lf>
mov ecx, this_
mov edx, Mask_
mov dword ptr [edx], DEBUG_EVENT_BREAKPOINT or DEBUG_EVENT_EXCEPTION or \
DEBUG_EVENT_CREATE_PROCESS or DEBUG_EVENT_EXIT_PROCESS or \
DEBUG_EVENT_LOAD_MODULE or DEBUG_EVENT_UNLOAD_MODULE or \
DEBUG_EVENT_SYSTEM_ERROR or DEBUG_EVENT_SESSION_STATUS or \
DEBUG_EVENT_CHANGE_DEBUGGEE_STATE or DEBUG_EVENT_CHANGE_ENGINE_STATE
mov eax, S_OK
ret
align 4
GetInterestMask@DebugEventCallbacks endp
;--- breakpoints, exceptions and system errors break into the debugger
Breakpoint@DebugEventCallbacks proc this_:ptr, brp:ptr ptr
dprintf <"Breakpoint@DebugEventCallbacks called",lf>
mov eax, DEBUG_STATUS_BREAK
ret
align 4
Breakpoint@DebugEventCallbacks endp
Exception@DebugEventCallbacks proc this_:ptr, exc:ptr ptr, firstchance:DWORD
dprintf <"Exception@DebugEventCallbacks(%X, %u)",lf>, exc, firstchance
mov eax, DEBUG_STATUS_BREAK
ret
align 4
Exception@DebugEventCallbacks endp
CreateThread@DebugEventCallbacks proc this_:ptr, handle:qword, dataofs:qword, startofs:qword
dprintf <"CreateThread@DebugEventCallbacks(%I64X, %I64X, %I64X)",lf>, handle, dataofs, startofs
mov eax, DEBUG_STATUS_NO_CHANGE
ret
align 4
CreateThread@DebugEventCallbacks endp
ExitThread@DebugEventCallbacks proc this_:ptr, exitcode:dword
dprintf <"ExitThread@DebugEventCallbacks(%u)",lf>, exitcode
mov eax, DEBUG_STATUS_NO_CHANGE
ret
align 4
ExitThread@DebugEventCallbacks endp
CreateProcess@DebugEventCallbacks proc this_:ptr, filehandle:qword, handle:qword,
base:qword, modsize:dword, modname:ptr BYTE, imagename:ptr BYTE,
checksum:dword, timedate:dword, initialthread:qword, threaddata:qword,
startofs:qword
local brkp:PDEBUG_BREAKPOINT
dprintf <"CreateProcess@DebugEventCallbacks(%I64X, %s, %I64X)",lf>, base, imagename, startofs
if 0
invoke printf, CStr("process entry address: %I64X",lf), startofs
endif
;--- set breakpoint on program entry?
.if ( clflgs & CLF_BP_AT_ENTRY )
mov eax, dword ptr startofs+0
or eax, dword ptr startofs+4
.if ( eax )
invoke vf( pDebugControl, IDebugControl, AddBreakpoint ), DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, addr brkp
.if ( eax == S_OK )
invoke vf( brkp, IDebugBreakpoint, SetOffset ), startofs
invoke vf( brkp, IDebugBreakpoint, AddFlags ), DEBUG_BREAKPOINT_ENABLED or DEBUG_BREAKPOINT_ONE_SHOT
.else
invoke printf, CStr("IDebugControl:AddBreakpoint failed [%X]",lf), eax
.endif
.endif
.endif
mov eax, DEBUG_STATUS_NO_CHANGE
ret
align 4
CreateProcess@DebugEventCallbacks endp
ExitProcess@DebugEventCallbacks proc this_:ptr, exitcode:dword
dprintf <"ExitProcess@DebugEventCallbacks(%u)",lf>, exitcode
.if ( clflgs & CLF_IGNORE_FINAL_BP )
mov eax, DEBUG_STATUS_NO_CHANGE
.else
mov eax, DEBUG_STATUS_BREAK
.endif
ret
align 4
ExitProcess@DebugEventCallbacks endp
LoadModule@DebugEventCallbacks proc this_:ptr, fh:qword, base:qword, modsize:dword,
modname:ptr BYTE, imagename:ptr BYTE, checksum:dword, timedate:dword
dprintf <"LoadModule@DebugEventCallbacks(%I64X, %s)",lf>, base, imagename
mov eax, DEBUG_STATUS_NO_CHANGE
ret
align 4
LoadModule@DebugEventCallbacks endp
UnloadModule@DebugEventCallbacks proc this_:ptr, imagename:ptr BYTE, base:qword
dprintf <"UnloadModule@DebugEventCallbacks(%s, %X)",lf>, imagename, base
mov eax, DEBUG_STATUS_NO_CHANGE
ret
align 4
UnloadModule@DebugEventCallbacks endp
SystemError@DebugEventCallbacks proc this_:ptr, error:dword, level:dword
dprintf <"SystemError@DebugEventCallbacks called",lf>
mov eax, DEBUG_STATUS_BREAK
ret
align 4
SystemError@DebugEventCallbacks endp
SessionStatus@DebugEventCallbacks proc this_:ptr, status:dword
dprintf <"SessionStatus@DebugEventCallbacks(%X)",lf>, status
mov eax, DEBUG_STATUS_NO_CHANGE ;return value is ignored
ret
align 4
SessionStatus@DebugEventCallbacks endp
ChangeDebuggeeState@DebugEventCallbacks proc this_:ptr, flags:dword, arg:qword
dprintf <"ChangeDebuggeeState@DebugEventCallbacks(%X, %I64X)",lf>, flags, arg
mov bStateChanged, 1
mov eax, DEBUG_STATUS_NO_CHANGE ;return value is ignored
ret
align 4
ChangeDebuggeeState@DebugEventCallbacks endp
ChangeEngineState@DebugEventCallbacks proc this_:ptr, flags:dword, arg:qword
dprintf <"ChangeEngineState@DebugEventCallbacks(%X, %I64X)",lf>, flags, arg
mov eax, DEBUG_STATUS_NO_CHANGE ;return value is ignored
ret
align 4
ChangeEngineState@DebugEventCallbacks endp
ChangeSymbolState@DebugEventCallbacks proc this_:ptr, flags:dword, arg:qword
dprintf <"ChangeSymbolState@DebugEventCallbacks(%X, %I64X)",lf>, flags, arg
mov eax, DEBUG_STATUS_NO_CHANGE ;return value is ignored
ret
align 4
ChangeSymbolState@DebugEventCallbacks endp
;--- IDebugInputCallbacks methods
QueryInterface@DebugInputCallbacks proc uses esi edi this_:ptr, pIID:ptr IID, pObject:ptr ptr
dprintf <"QueryInterface@DebugInputCallbacks called",lf>
mov ecx,4
mov esi, pIID
mov edi, offset IID_IDebugInputCallbacks
repz cmpsd
jz ok
mov ecx,4
mov esi, pIID
mov edi, offset IID_IUnknown
repz cmpsd
jz ok
mov eax, E_NOINTERFACE
ret
ok:
invoke vf( this_, IUnknown, AddRef )
mov edx, this_
mov ecx, pObject
mov [ecx], edx
mov eax, S_OK
ret
align 4
QueryInterface@DebugInputCallbacks endp
AddRef@DebugInputCallbacks proc this_:ptr
dprintf <"AddRef@DebugInputCallbacks called",lf>
mov ecx, this_
inc [ecx].CDebugInputCallbacks.cnt
mov eax, [ecx].CDebugInputCallbacks.cnt
ret
align 4
AddRef@DebugInputCallbacks endp
Release@DebugInputCallbacks proc this_:ptr
dprintf <"Release@DebugInputCallbacks called",lf>
mov ecx, this_
dec [ecx].CDebugInputCallbacks.cnt
mov eax, [ecx].CDebugInputCallbacks.cnt
.if ( eax == 0 )
invoke free, ecx
xor eax, eax
.endif
ret
align 4
Release@DebugInputCallbacks endp
;--- read one line from file or pipe
ReadLine proc uses edi fh:dword, buffer:dword, maxlen:dword, bytesread:ptr dword
local dwRead:dword
invoke fflush, stdout
mov edi, buffer
.while ( maxlen )
invoke ReadFile, fh, edi, 1, addr dwRead, 0
.break .if ( eax == 0 || dwRead == 0 )
.continue .if ( byte ptr [edi] == cr )
inc edi
dec maxlen
.break .if ( byte ptr [edi-1] == lf )
.endw
sub edi, buffer
mov edx, bytesread
mov [edx], edi
mov eax, edi
ret
align 4
ReadLine endp
StartInput@DebugInputCallbacks proc uses ebx this_:ptr, BufferSize:DWORD
local dwRead:dword
local dwEsp:dword
invoke GetStdHandle, STD_INPUT_HANDLE
mov ebx, eax
dprintf <"StartInput@DebugInputCallbacks(%u)",lf>, BufferSize
mov dwEsp, esp
mov eax, BufferSize
add eax, 3+4
and al, 0FCh
sub esp, eax
invoke GetFileType, ebx
mov edx, esp
mov byte ptr [edx], 0
mov dwRead, 0
;--- if input isn't a device, read ONE line only
.if ( eax != FILE_TYPE_CHAR )
invoke ReadLine, ebx, edx, BufferSize, addr dwRead
.else
invoke ReadFile, ebx, edx, BufferSize, addr dwRead, NULL
.endif
mov ecx, dwRead
.if ( ecx )
; remove CR/LF
.while (ecx && ( byte ptr [esp+ecx-1] == lf || byte ptr [esp+ecx-1] == cr ))
mov byte ptr [esp+ecx-1],0
dec ecx
.endw
.endif
invoke vf( pDebugControl, IDebugControl, ReturnInput ), esp
.if ( eax != S_OK )
invoke printf, CStr("IDebugControl:ReturnInput failed [%X]",lf), eax
.endif
mov edx, esp
dprintf <"StartInput@DebugInputCallbacks: dwRead=%u, read=>%s<",lf>, dwRead, edx
mov esp, dwEsp
exit_:
mov eax, S_OK
ret
align 4
StartInput@DebugInputCallbacks endp
EndInput@DebugInputCallbacks proc this_:ptr
; dprintf <"EndInput@DebugInputCallbacks called",lf>
mov eax, S_OK
ret
align 4
EndInput@DebugInputCallbacks endp
;--- IDebugOutputCallbacks methods
QueryInterface@DebugOutputCallbacks proc uses esi edi this_:ptr, pIID:ptr IID, pObject:ptr ptr
dprintf <"QueryInterface@DebugOutputCallbacks called",lf>
mov ecx,4
mov esi, pIID
mov edi, offset IID_IDebugOutputCallbacks
repz cmpsd
jz ok
mov ecx,4
mov esi, pIID
mov edi, offset IID_IUnknown
repz cmpsd
jz ok
mov eax, E_NOINTERFACE
ret
ok:
invoke vf( this_, IUnknown, AddRef )
mov edx, this_
mov ecx, pObject
mov [ecx], edx
mov eax, S_OK
ret
align 4
QueryInterface@DebugOutputCallbacks endp
AddRef@DebugOutputCallbacks proc this_:ptr
dprintf <"AddRef@DebugOutputCallbacks called",lf>
mov ecx, this_
inc [ecx].CDebugOutputCallbacks.cnt
mov eax, [ecx].CDebugOutputCallbacks.cnt
ret
align 4
AddRef@DebugOutputCallbacks endp
Release@DebugOutputCallbacks proc this_:ptr
dprintf <"Release@DebugOutputCallbacks called",lf>
mov ecx, this_
dec [ecx].CDebugOutputCallbacks.cnt
mov eax, [ecx].CDebugOutputCallbacks.cnt
.if ( eax == 0 )
invoke free, ecx
xor eax, eax
.endif
ret
align 4
Release@DebugOutputCallbacks endp
Output@DebugOutputCallbacks proc c this_:ptr, Mask_:DWORD, Text:ptr BYTE
; dprintf <"Output@DebugOutputCallbacks called",lf>
invoke printf, CStr("%s"), Text
mov eax, S_OK
ret
align 4
Output@DebugOutputCallbacks endp
start proc c
invoke main
invoke ExitProcess, eax
start endp
end start
|