; diamond, 2006 sys_debug_services: cmp eax, 9 ja @f jmp dword [sys_debug_services_table+eax*4] @@: ret sys_debug_services_table: dd debug_set_event_data dd debug_getcontext dd debug_setcontext dd debug_detach dd debug_suspend dd debug_resume dd debug_read_process_memory dd debug_write_process_memory dd debug_terminate dd debug_set_drx debug_set_event_data: ; in: ebx = pointer ; destroys eax mov eax, [CURRENT_TASK] shl eax, 8 mov [eax+0x80000+APPDATA.dbg_event_mem], ebx ret get_debuggee_slot: ; in: ebx=PID ; out: CF=1 if error ; CF=0 and eax=slot*0x20 if ok ; out: interrupts disabled cli mov eax, ebx call pid_to_slot test eax, eax jz .ret_bad shl eax, 5 push ebx mov ebx, [CURRENT_TASK] cmp [0x80000+eax*8+APPDATA.debugger_slot], ebx pop ebx jnz .ret_bad ; clc ; automatically ret .ret_bad: stc ret debug_detach: ; in: ebx=pid ; destroys eax,ebx call get_debuggee_slot jc .ret and dword [eax*8+0x80000+APPDATA.debugger_slot], 0 call do_resume .ret: sti ret debug_terminate: ; in: ebx=pid call get_debuggee_slot jc debug_detach.ret mov ebx, eax shr ebx, 5 push 2 pop eax jmp sys_system debug_suspend: ; in: ebx=pid ; destroys eax,ebx call get_debuggee_slot jc .ret mov bl, [CURRENT_TASK+eax+TASKDATA.state] ; process state test bl, bl jz .1 cmp bl, 5 jnz .ret mov bl, 2 .2: mov [CURRENT_TASK+eax+TASKDATA.state], bl .ret: sti ret .1: inc ebx jmp .2 do_resume: mov bl, [CURRENT_TASK+eax+TASKDATA.state] cmp bl, 1 jz .1 cmp bl, 2 jnz .ret mov bl, 5 .2: mov [CURRENT_TASK+eax+TASKDATA.state], bl .ret: ret .1: dec ebx jmp .2 debug_resume: ; in: ebx=pid ; destroys eax,ebx call get_debuggee_slot jc .ret call do_resume .ret: sti ret debug_getcontext: ; in: ; ebx=pid ; ecx=sizeof(CONTEXT) ; edx->CONTEXT ; destroys eax,ecx,edx,esi,edi cmp ecx, 28h jnz .ret add edx, std_application_base_address push ebx mov ebx, edx call check_region pop ebx dec eax jnz .ret call get_debuggee_slot jc .ret imul eax, tss_step/32 add eax, tss_data mov edi, edx cmp [eax+TSS._cs], app_code jnz .ring0 lea esi, [eax+TSS._eip] shr ecx, 2 rep movsd jmp .ret .ring0: ; note that following code assumes that all interrupt/exception handlers ; saves ring-3 context by push ds es, pushad in this order mov esi, [eax+TSS._esp0] ; top of ring0 stack: ring3 stack ptr (ss+esp), iret data (cs+eip+eflags), ds, es, pushad sub esi, 8+12+8+20h lodsd mov [edi+24h], eax lodsd mov [edi+20h], eax lodsd mov [edi+1Ch], eax lodsd lodsd mov [edi+14h], eax lodsd mov [edi+10h], eax lodsd mov [edi+0Ch], eax lodsd mov [edi+8], eax add esi, 8 lodsd mov [edi], eax lodsd lodsd mov [edi+4], eax lodsd mov [edi+18h], eax .ret: sti ret debug_setcontext: ; in: ; ebx=pid ; ecx=sizeof(CONTEXT) ; edx->CONTEXT ; destroys eax,ecx,edx,esi,edi cmp ecx, 28h jnz .ret add edx, std_application_base_address push ebx mov ebx, edx call check_region pop ebx dec eax jnz .ret call get_debuggee_slot jc .stiret imul eax, tss_step/32 add eax, tss_data mov esi, edx cmp [eax+TSS._cs], app_code jnz .ring0 lea edi, [eax+TSS._eip] shr ecx, 2 rep movsd jmp .stiret .ring0: mov edi, [eax+TSS._esp0] sub edi, 8+12+8+20h mov eax, [esi+24h] stosd mov eax, [esi+20h] stosd mov eax, [esi+1Ch] stosd scasd mov eax, [esi+14h] stosd mov eax, [esi+10h] stosd mov eax, [esi+0Ch] stosd mov eax, [esi+8] stosd add edi, 8 mov eax, [esi] stosd scasd mov eax, [esi+4] stosd mov eax, [esi+18h] stosd .stiret: sti .ret: ret debug_set_drx: call get_debuggee_slot jc .errret mov ebp, eax lea eax, [eax*8+0x80000+APPDATA.dbg_regs] ; [eax]=dr0, [eax+4]=dr1, [eax+8]=dr2, [eax+C]=dr3 ; [eax+10]=dr7 add edx, std_application_base_address jc .errret cmp cl, 3 ja .errret mov ebx, dr7 shr ebx, cl shr ebx, cl test ebx, 2 ; bit 1+2*index = G0..G3, global break enable jnz .errret2 test ch, ch jns .new ; clear breakpoint movzx ecx, cl add ecx, ecx and dword [eax+ecx*2], 0 ; clear DR btr dword [eax+10h], ecx ; clear L bit test byte [eax+10h], 55h jnz .okret imul eax, ebp, tss_step/32 and byte [eax + tss_data + TSS._trap], not 1 .okret: and dword [esp+36], 0 sti ret .errret: sti mov dword [esp+36], 1 ret .errret2: sti mov dword [esp+36], 2 ret .new: ; add new breakpoint ; cl=index; ch=flags; edx=address test ch, 0xF0 jnz .errret mov bl, ch and bl, 3 cmp bl, 2 jz .errret mov bl, ch shr bl, 2 cmp bl, 2 jz .errret test dl, bl jnz .errret or byte [eax+10h+1], 3 ; set GE and LE flags movzx ebx, ch movzx ecx, cl add ecx, ecx bts dword [eax+10h], ecx ; set L flag add ecx, ecx mov [eax+ecx], edx ; set DR shl ebx, cl mov edx, 0xF shl edx, cl not edx and [eax+10h+2], dx or [eax+10h+2], bx ; set R/W and LEN fields imul eax, ebp, tss_step/32 or byte [eax + tss_data + TSS._trap], 1 jmp .okret debug_read_process_memory: ; in: ; ebx=pid ; ecx=length ; esi->buffer in debugger ; edx=address in debuggee ; out: [esp+36]=sizeof(read) ; destroys all add esi, std_application_base_address push ebx mov ebx, esi call check_region pop ebx dec eax jnz .err call get_debuggee_slot jc .err shr eax, 5 mov ebx, esi call read_process_memory sti mov dword [esp+36], eax ret .err: or dword [esp+36], -1 ret debug_write_process_memory: ; in: ; ebx=pid ; ecx=length ; esi->buffer in debugger ; edx=address in debuggee ; out: [esp+36]=sizeof(write) ; destroys all add esi, std_application_base_address push ebx mov ebx, esi call check_region pop ebx dec eax jnz debug_read_process_memory.err call get_debuggee_slot jc debug_read_process_memory.err shr eax, 5 mov ebx, esi call write_process_memory sti mov [esp+36], eax ret debugger_notify: ; in: eax=debugger slot ; ecx=size of debug message ; [esp+4]..[esp+4+ecx]=message ; interrupts must be disabled! ; destroys all general registers ; interrupts remain disabled xchg ebp, eax mov edi, [timer_ticks] add edi, 500 ; 5 sec timeout .1: mov eax, ebp shl eax, 8 mov edx, [0x80000+eax+APPDATA.dbg_event_mem] test edx, edx jz .ret ; read buffer header push ecx push eax push eax mov eax, ebp mov ebx, esp mov ecx, 8 call read_process_memory cmp eax, ecx jz @f add esp, 12 jmp .ret @@: cmp dword [ebx], 0 jg @f .2: pop ecx pop ecx pop ecx cmp dword [CURRENT_TASK], 1 jnz .notos cmp [timer_ticks], edi jae .ret .notos: sti call change_task cli jmp .1 @@: mov ecx, [ebx+8] add ecx, [ebx+4] cmp ecx, [ebx] ja .2 ; advance buffer position push ecx mov ecx, 4 sub ebx, ecx mov eax, ebp add edx, ecx call write_process_memory pop eax ; write message mov eax, ebp add edx, ecx add edx, [ebx+8] add ebx, 20 pop ecx pop ecx pop ecx call write_process_memory ; new debug event mov eax, ebp shl eax, 8 or byte [0x80000+eax+APPDATA.event_mask+1], 1 ; set flag 100h .ret: ret debug_exc: ; int 1 = #DB save_ring3_context cld mov ax, os_data mov ds, ax mov es, ax mov eax, dr6 test ax, ax jns @f ; this is exception from task switch ; set DRx registers for task and continue mov eax, [CURRENT_TASK] shl eax, 8 add eax, 0x80000+APPDATA.dbg_regs mov ecx, [eax+0] mov dr0, ecx mov ecx, [eax+4] mov dr1, ecx mov ecx, [eax+8] mov dr2, ecx mov ecx, [eax+0Ch] mov dr3, ecx xor ecx, ecx mov dr6, ecx mov ecx, [eax+10h] mov dr7, ecx restore_ring3_context iretd @@: push eax xor eax, eax mov dr6, eax ; test if debugging cli mov eax, [CURRENT_TASK] shl eax, 8 mov eax, [0x80000+eax+APPDATA.debugger_slot] test eax, eax jnz .debug sti ; not debuggee => say error and terminate add esp, 28h+4 mov [error_interrupt], 1 call show_error_parameters mov edx, [TASK_BASE] mov byte [edx+TASKDATA.state], 4 jmp change_task .debug: ; we are debugged process, notify debugger and suspend ourself ; eax=debugger PID pop edx mov ebx, dr7 mov cl, not 1 .l1: test bl, 1 jnz @f and dl, cl @@: shr ebx, 2 add cl, cl inc ecx cmp cl, not 10h jnz .l1 push edx ; DR6 image mov ecx, [TASK_BASE] push dword [ecx+TASKDATA.pid] ; PID push 12 pop ecx push 3 ; 3 = debug exception call debugger_notify pop ecx pop ecx pop ecx mov edx, [TASK_BASE] mov byte [edx+TASKDATA.state], 1 ; suspended call change_task restore_ring3_context iretd