;--- 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 [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected]tCallbacks dd [email protected] dd [email protected] DebugInputCallbacksVtbl label IDebugInputCallbacksVtbl dd [email protected] dd [email protected] dd [email protected] dd [email protected] dd [email protected] DebugOutputCallbacksVtbl label IDebugOutputCallbacksVtbl dd [email protected] dd [email protected] dd [email protected] dd [email protected] ;--- 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 [email protected] proc uses esi edi this_:ptr, pIID:ptr IID, pObject:ptr ptr dprintf <"[email protected] 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 [email protected] endp [email protected] proc this_:ptr dprintf <"[email protected] called",lf> mov ecx, this_ inc [ecx].CDebugEventCallbacks.cnt mov eax, [ecx].CDebugEventCallbacks.cnt ret align 4 [email protected] endp [email protected] proc this_:ptr dprintf <"[email protected] 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 [email protected] endp [email protected] proc this_:ptr, Mask_:ptr DWORD dprintf <"[email protected] 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 [email protected] endp ;--- breakpoints, exceptions and system errors break into the debugger [email protected] proc this_:ptr, brp:ptr ptr dprintf <"[email protected] called",lf> mov eax, DEBUG_STATUS_BREAK ret align 4 [email protected] endp [email protected] proc this_:ptr, exc:ptr ptr, firstchance:DWORD dprintf <"[email protected](%X, %u)",lf>, exc, firstchance mov eax, DEBUG_STATUS_BREAK ret align 4 [email protected] endp [email protected] proc this_:ptr, handle:qword, dataofs:qword, startofs:qword dprintf <"[email protected](%I64X, %I64X, %I64X)",lf>, handle, dataofs, startofs mov eax, DEBUG_STATUS_NO_CHANGE ret align 4 [email protected] endp [email protected]ntCallbacks proc this_:ptr, exitcode:dword dprintf <"[email protected](%u)",lf>, exitcode mov eax, DEBUG_STATUS_NO_CHANGE ret align 4 [email protected] endp [email protected] 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 <"[email protected](%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 [email protected] endp [email protected] proc this_:ptr, exitcode:dword dprintf <"[email protected](%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 [email protected] endp [email protected] proc this_:ptr, fh:qword, base:qword, modsize:dword, modname:ptr BYTE, imagename:ptr BYTE, checksum:dword, timedate:dword dprintf <"[email protected](%I64X, %s)",lf>, base, imagename mov eax, DEBUG_STATUS_NO_CHANGE ret align 4 [email protected] endp [email protected] proc this_:ptr, imagename:ptr BYTE, base:qword dprintf <"[email protected](%s, %X)",lf>, imagename, base mov eax, DEBUG_STATUS_NO_CHANGE ret align 4 [email protected] endp [email protected] proc this_:ptr, error:dword, level:dword dprintf <"[email protected] called",lf> mov eax, DEBUG_STATUS_BREAK ret align 4 [email protected] endp [email protected] proc this_:ptr, status:dword dprintf <"[email protected](%X)",lf>, status mov eax, DEBUG_STATUS_NO_CHANGE ;return value is ignored ret align 4 [email protected] endp [email protected] proc this_:ptr, flags:dword, arg:qword dprintf <"[email protected](%X, %I64X)",lf>, flags, arg mov bStateChanged, 1 mov eax, DEBUG_STATUS_NO_CHANGE ;return value is ignored ret align 4 [email protected] endp [email protected] proc this_:ptr, flags:dword, arg:qword dprintf <"[email protected](%X, %I64X)",lf>, flags, arg mov eax, DEBUG_STATUS_NO_CHANGE ;return value is ignored ret align 4 [email protected] endp [email protected] proc this_:ptr, flags:dword, arg:qword dprintf <"[email protected](%X, %I64X)",lf>, flags, arg mov eax, DEBUG_STATUS_NO_CHANGE ;return value is ignored ret align 4 [email protected] endp ;--- IDebugInputCallbacks methods [email protected] proc uses esi edi this_:ptr, pIID:ptr IID, pObject:ptr ptr dprintf <"[email protected] 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 [email protected] endp [email protected] proc this_:ptr dprintf <"[email protected] called",lf> mov ecx, this_ inc [ecx].CDebugInputCallbacks.cnt mov eax, [ecx].CDebugInputCallbacks.cnt ret align 4 [email protected] endp [email protected] proc this_:ptr dprintf <"[email protected] 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 [email protected] 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 [email protected] proc uses ebx this_:ptr, BufferSize:DWORD local dwRead:dword local dwEsp:dword invoke GetStdHandle, STD_INPUT_HANDLE mov ebx, eax dprintf <"[email protected](%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 <"[email protected]: dwRead=%u, read=>%s<",lf>, dwRead, edx mov esp, dwEsp exit_: mov eax, S_OK ret align 4 [email protected] endp [email protected] proc this_:ptr ; dprintf <"[email protected] called",lf> mov eax, S_OK ret align 4 [email protected] endp ;--- IDebugOutputCallbacks methods [email protected] proc uses esi edi this_:ptr, pIID:ptr IID, pObject:ptr ptr dprintf <"[email protected] 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 [email protected] endp [email protected] proc this_:ptr dprintf <"[email protected] called",lf> mov ecx, this_ inc [ecx].CDebugOutputCallbacks.cnt mov eax, [ecx].CDebugOutputCallbacks.cnt ret align 4 [email protected] endp [email protected]Callbacks proc this_:ptr dprintf <"[email protected] 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 [email protected] endp [email protected] proc c this_:ptr, Mask_:DWORD, Text:ptr BYTE ; dprintf <"[email protected] called",lf> invoke printf, CStr("%s"), Text mov eax, S_OK ret align 4 [email protected] endp start proc c invoke main invoke ExitProcess, eax start endp end start |