home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / ddjmag / ddj9209.zip / DB.ASC < prev    next >
Text File  |  1992-08-17  |  14KB  |  402 lines

  1. _YOUR OWN PROTECTED-MODE DEBUGGER_
  2. by Rick Knoblaugh
  3.  
  4. [Listing One]
  5.  
  6. ;-----------------------------------------------------------------------------
  7. ;pass_thru - This procedure is JMPed to by any interrupt handler which wishes
  8. ;  to pass control to the original ISR per the interrupt vector table. Also, 
  9. ;  it checks to see if there are any breakpoints set on the int. If there are,
  10. ;  the int being passed through is checked to see if it matches the condition 
  11. ;  for the break point. If the condition for the break point is met, DR0 is 
  12. ;  used to cause a break at the ISR. Enter: See stack_area struc for stack 
  13. ;  layout. Any error code has been removed from stack. EIP on stack has been 
  14. ;  adjusted if necessary.
  15. ;-----------------------------------------------------------------------------
  16. pass_thru    proc    near
  17.         mov    bp, sp
  18.         pushad
  19.         call    adjust_ustack        ;adjust user stack
  20. ;returns with [esi][edx] pointing to user stack area
  21.         mov    cx, [bp].s_cs        ;put on user cs
  22.         mov    [esi][edx].user_cs, cx
  23.         mov    ecx, [bp].s_eip     ;put on ip
  24.         mov    [esi][edx].user_ip, cx
  25.         movzx    ebx, [bp].s_pushed_int    ;get int number
  26.         movzx    ecx, [ebx * 4].d_offset ;offset portion
  27.         mov    [bp].s_eip, ecx             
  28.         mov    cx, [ebx * 4].d_seg    ;segment portion
  29.         mov    [bp].s_cs, cx
  30.  
  31.         mov    cx, offset gdt_seg:sel_data
  32.         mov    fs, cx
  33.         assume    fs:data
  34.         push    fs     
  35.         cmp    fs:trap_clear, TRUE    ;tracing through an int?
  36.         jne    short pass_thru500          
  37.         mov    fs:trap_clear, FALSE    ;reset it
  38.         mov    fs:int1_active, TRUE    ;debugger active 
  39. ;If tracing through a software INT instruction, don't want the INT to
  40. ;be treated as one instruction (trap flag is cleared upon entering
  41. ;interrupts).  In order to single step starting with the first instruction
  42. ;of the ISR, move address of the first instruction onto the user's stack 
  43. ;and make user cs:ip on PL0 stack point to debugger int 1.
  44.         sub    edx, 6            ;flags, cs, ip
  45.         mov    [bp].s_esp, edx     ;adjust it
  46.         mov    ecx, [bp].s_eflags    ;put on flags
  47.         mov    [esi][edx].user_flags, cx
  48.         mov    cx, [bp].s_cs        ;put &ISR onto user's stack
  49.         mov    [esi][edx].user_cs, cx    
  50.         mov    ecx, [bp].s_eip     
  51.         mov    [esi][edx].user_ip, cx
  52.  
  53.         mov    cx, ZCODE        
  54.         mov    [bp].s_cs, cx        
  55.         mov    cx, offset int_1_isr 
  56.         movzx    ecx, cx
  57.         mov    [bp].s_eip, ecx
  58. pass_thru500:
  59.         pop    ds            ;get data seg (was fs)
  60.         assume    ds:data
  61.  
  62.         cmp    int1_active, TRUE    ;is debugger active?
  63.         je    short pass_thru999    ;if so, don't even think
  64.                         ;of breaking        
  65.         mov    cx, num_int_bp        ;number of defined int breaks
  66.         jcxz    pass_thru999        ;if no int type break points
  67.         mov    si, offset int_bpdat 
  68. pass_thru700:
  69.         cmp    [si].int_stat, ACTIVE    ;is break on int enabled?
  70.         jne    short pass_thru800
  71.         dec    cx
  72.         cmp    [si].int_num, bl    ;is this the int specified?
  73.         jne    short pass_thru800
  74.         cmp    [si].int_reg, NO_CONDITION ;no conditions?
  75.         je    short pass_thru750    ;if none go ahead and set break
  76.         mov    dx, [si].int_val    ;get data for comparison
  77.         cmp    [si].int_reg, INT_AL_COMP ;condition compare on al?
  78.         jne    short pass_thru730
  79.         cmp    al, dl            ;condition met?
  80.         je    pass_thru750           ;if so, go ahead and set break
  81.         jmp    short pass_thru800     ;if != look for more conditions 
  82. pass_thru730:
  83.         cmp    [si].int_reg, INT_AH_COMP ;condition compare on ah?
  84.         jne    short pass_thru740
  85.         cmp    ah, dl               ;condition met
  86.         je    short pass_thru750     ;if so, go ahead and set break
  87.         jmp    short pass_thru800     ;if != look for more conditions 
  88. pass_thru740:                       ;condition compare on ax
  89.         cmp    ax, dx
  90.         jne    short pass_thru800     ;if != look for more conditions 
  91. pass_thru750:
  92.         mov    ebx, [bp].s_eip     ;get offset and
  93.         movzx    edx, [bp].s_cs        ;segment of ISR
  94.         shl    edx, 4            ;convert to linear
  95.         add    edx, ebx
  96.  
  97.         mov    ch, 1            ;set debug register
  98.         mov    al, DEB_DAT_LEN1    ;exec breaks use 1 byte length
  99.         mov    ah, DEB_TYPE_EXEC
  100.         sub    cl, cl            ;debug reg zero 
  101.         call    do_debug_reg
  102.         jmp    short pass_thru999
  103. pass_thru800:
  104.         add    si, size info_int    ;advance to next int break
  105.         or    cl, cl            ;all int breaks checked?
  106.         jnz    short pass_thru700    ;if not, check the next one
  107. pass_thru999:                  
  108.         popad
  109.         add    sp, 2            ;get rid of int number
  110.         pop    bp
  111.         iretd               
  112. pass_thru    endp        
  113.  
  114.  
  115. [Listing Two]
  116.  
  117. ;-----------------------------------------------------------------------------
  118. ;gen_prot_isr - JMP here if int 0dh. Look for software int. If a software int
  119. ;   caused the exception then: If debugger is active, look for user software 
  120. ;   interrupts issued by PL3 layer of debugger. If int 15h function 89h deny.
  121. ;   If int 15h function 87h, emulate it. If none of these, simply route the 
  122. ;   interrupt per the real mode interrupt vector table. If exception was not 
  123. ;   caused by a software int and there are breakpoints defined on I/O accesses,
  124. ;   look for I/O instruction. If it is an I/O instruction, temporarily clear
  125. ;   the corresponding TSS I/O permission bit map bit and set trap flag to 
  126. ;   single step through the instruction. If other than software int or I/O, 
  127. ;   display cs:ip, 0dh and then halt.
  128. ;----------------------------------------------------------------------------
  129. gen_prot_isr    proc    near
  130.         pushad          
  131. ;Note: Don't use DX or AX below as DX may contain an I/O port address; in the
  132. ;  case of a software interrupt, AH will have a function code. Also, don't use
  133. ;  SI or CX as they are inputs for extended memory block move function
  134.         mov    bx, offset gdt_seg:sel_databs 
  135.         mov    ds, bx
  136.         movzx    ebx, [bp].e_cs    ;get cs of user instruction
  137.         shl    ebx, 4        ;make linear
  138.         add    ebx, [bp].e_eip ;add ip 
  139.         mov    bx, [ebx]    ;get bytes at cs:ip
  140.  
  141.         mov    di, offset gdt_seg:sel_data
  142.         mov    ds, di        ;debugger's data
  143.  
  144.         cmp    bl, INT_OPCODE
  145.         je    short gen_prot020        
  146.  
  147.         cmp    bl, INT3_OPCODE
  148.         jne    gen_prot150    ;go look for I/O instruction
  149.         mov    bh, 3        ;interrupt 3
  150. gen_prot020:
  151.         cmp    trace_count, 0    ;is debugger tracing?
  152.         je    short gen_prot040 ;if not, skip test below
  153. ;See if this software interrupt is the instruction through which the user
  154. ;is tracing. If it is, set flag.
  155.         mov    di, [bp].e_cs 
  156.         cmp    di, tuser_cs
  157.         jne    short gen_prot040
  158.         mov    edi, [bp].e_eip 
  159.         cmp    di, tuser_ip
  160.         jne    short gen_prot040
  161. ; Clear trap bit so that it will not be set on user stack. Note: If user is  
  162. ; doing a "trace n" where n is a number of instructions exceeding the number of
  163. ; instructions in the ISR, instructions executing upon return from ISR will 
  164. ; still be trapped through as the int 1 code will again set the trap flag.
  165.         btr    [bp].e_eflags, trapf
  166.         mov    trap_clear, TRUE
  167. gen_prot040:
  168.         inc    [bp].e_eip    ;get past the 0cdh (or 0cch)
  169.         cmp    bh, 3        ;int 3?
  170.         je    short gen_prot060 ;if so, only 1 byte
  171. gen_prot050:            
  172.         inc    [bp].e_eip 
  173. gen_prot060:            
  174.  
  175. ;See if the debugger is active and if this software interrupt is one of the
  176. ;ones used by the PL3 portion of the debugger to get PL0 services.
  177.         cmp    int1_active, TRUE    ;is debugger active?
  178.         jne    short gen_prot085
  179. ;Note:    In the event that an interrupt occuring while debugger is active
  180. ;    (e.g. timer) actually uses these user software interrupts,
  181. ;    code to verify caller would need to be added here.    
  182.         cmp    bh, 60h         ;do debug registers?
  183.         jne    short gen_prot080
  184.  
  185.         popad
  186.         call    do_debug_reg 
  187.         jmp    gen_prot299 
  188. gen_prot080:
  189.         cmp    bh, 61h         ;do I/O bit map?
  190.         jne    short gen_prot085
  191.  
  192.         popad
  193. ; Unlike accessing of debug registers, PL3 code could actually manipulate TSS
  194. ; I/O bit map directly. However, this interface keeps this in one location.
  195.         call    do_bit_map    
  196.         jmp    gen_prot299 
  197. gen_prot085:
  198.         cmp    bh, 15h         ;int 15?
  199.         jne    short gen_prot100
  200.         cmp    ah, 89h         ;request for protected mode?
  201.         jne    short gen_prot090
  202.                         ;if so, can't allow
  203.         bts    [bp].e_eflags, carry    ;set carry
  204.         popad
  205.         jmp    gen_prot299        ;and return
  206. gen_prot090:
  207.         cmp    ah, 87h         ;request for extended move? 
  208.         jne    short gen_prot100
  209.         call    emulate_blk_mov     ;if so, we must do it
  210.         popad
  211.         mov    ah, 0            ;default to success
  212.         jnz    gen_prot299        ;exit if success
  213.         mov    ah, 3            ;indicate a20 gate failed
  214.         jmp    gen_prot299        ;and return
  215. gen_prot100:
  216. ;Adjust stack so that error code goes away and int number retrieved from
  217. ;instruction goes in spot on stack where pushed int number is (for stacks
  218. ;with no error code).  Stack will be the way pass_thru routine likes it.
  219.         mov    ax, bx
  220.         mov    bx, [bp].e_pushed_bp
  221.         shl    ebx, 16         ;get into high word
  222.         mov    bl, ah            ;interrupt number
  223.         mov    [bp].e_errcode, ebx
  224.  
  225.         cmp    bl, 1            ;software int 1?
  226.         jne    short gen_prot140
  227. ; Check to see if we are already in debugger. This is to handle the unlikely
  228. ; case where there is an actual INT 1 instruction inside of an interrupt
  229. ; handler. If there is and debugger is active, instruction will be ignored.
  230.         popad
  231.         cmp    int1_active, TRUE    ;already in debugger? 
  232.         jne    short gen_prot130    ;if not, go enter int 1
  233.                             
  234.                         ;else ignore it by returning                
  235.         add    sp, 2            ;get rid of int number
  236.         pop    bp
  237.         iretd               
  238. gen_prot130:
  239.         add    sp, 4            ;error code gone         
  240.         mov    bp, sp
  241.         pushad
  242.         jmp    int_1_210        ;go enter int 1
  243. gen_prot140:
  244.         popad        
  245.         add    sp, 4            ;error code gone
  246.         jmp    pass_thru        ;route the int via vectors
  247. gen_prot150:
  248.         cmp    num_io_bp, 0        ;any I/O break points defined?
  249.         je    short gen_prot400    ;if not, don't look for I/O
  250.  
  251.         xor    ah, ah            ;use as string flag
  252.         cmp    bl, REP_PREFIX        ;rep ?
  253.         jne    short gen_prot190
  254.         mov    ah, STRING        ;only string type use rep
  255.         mov    bl, bh            ;get 2nd byte
  256. gen_prot190:
  257. ; If repeat prefix was found, ah now has a flag indicating only string type 
  258. ; I/O instructions should be expected and bl now contains the byte of object 
  259. ; code past the repeat prefix. Note: To be complete, this code should also 
  260. ; look for the operand-size prefix and segment overrides.
  261.         mov    si, offset io_table
  262.         mov    cx, IO_TAB_ENTRIES
  263. gen_prot200:
  264.         or    ah, ah            ;strings only?
  265.         jz    short gen_prot225    ;if not, go test
  266.  
  267.         test    [si].io_info, ah       ;if table entry is not a string
  268.         jz    short gen_prot300    ;type I/O, go try next one
  269. gen_prot225:
  270.         cmp    bl, [si].io_opcode 
  271.         jne    short gen_prot300
  272.         mov    io_instrucf, TRUE    ;instruction found
  273.         mov    cl, [si].io_info    ;get info about instruction
  274.  
  275.         mov    io_inst_info, cl
  276.         test    cl, CONSTANT        ;port number in instruction?    
  277.         jz    short gen_prot250    ;if not, we have it
  278.         movzx    dx, bh            ;get port
  279. gen_prot250:
  280.         mov    io_inst_port, dx  ;save port 
  281.         mov    cx, 1            ;number of bits
  282.         sub    ah, ah            ;indicate clear
  283.         call    do_bit_map     
  284. gen_prot260:
  285.         bts    [bp].e_eflags, trapf ;single step i/o
  286.         popad        
  287. gen_prot299:
  288.         add    sp, 2            ;int number pushed
  289.         pop    bp
  290.         add    sp, 4            ;error code
  291.         iretd
  292. gen_prot300:
  293.         add    si, size io_struc ;advance to next table entry
  294.         loop    gen_prot200
  295. gen_prot400:
  296. ;Also need to add code here to check for a few other exceptions (e.g.  
  297. ;the HLT instruction).
  298.         mov    ax, [bp].e_cs        ;get cs of user instruction
  299.         call    display_it
  300.         mov    eax, [bp].e_eip     ;add ip 
  301.         call    display_it
  302.         popad       
  303.         mov    ax, [bp].e_pushed_int
  304.         jmp    fatal_error
  305. gen_prot_isr    endp
  306.  
  307.  
  308.  
  309. [Listing Three]
  310.  
  311. ;-----------------------------------------------------------------------------
  312. ; do_debug_reg - enable/disable debug register for break point.
  313. ;    Enter: ch = 0 if clearing break point: ch = 1 if setting breakpoint; 
  314. ;    ch = 2 if setting up break point type and address, but not enabling yet;
  315. ;    ch = 3 get bn portion of debug status register into ax
  316. ;    If clearing and eax !=0, eax holds other bits to be cleared (used for 
  317. ;    also clearing ge or le bits). cl = debug register number (0-3) if setting 
  318. ;    also have: al = length (0=1 byte, 1=2 bytes, 3=4 bytes); ah = type 
  319. ;    (0=execution, 1=write, 3=read/write); edx = linear address for break
  320. ;    Also, if al='*' simply reactivate the breakpoint keeping the existing 
  321. ;    type and address. Exit: if disabling, specified debug register breakpoint
  322. ;    is disabled. If enabling, specified debug register is loaded and 
  323. ;    breakpoint is enabled. If getting debug status register, bn portion of
  324. ;    DR6 is returned in AX.
  325. ;  Save ebx.                                  
  326. ;-----------------------------------------------------------------------------
  327. do_debug_reg    proc    near
  328.         cmp    ch, 3            ;requesting status?
  329.         jne    short do_deb050     ;if not
  330.         mov    eax, dr6        ;debug status register
  331.         and    ax, 0fh         ;isolate bn status
  332.         ret                ;and return
  333. do_deb050:
  334.         push    ebx
  335.         mov    ebx, dr7        ;get debug control reg
  336.         cmp    ch, 1            ;determine function
  337.         jb    short do_deb850     ;if clear function go do it
  338.         ja    short do_deb100     ;setup, but not enable 
  339.         cmp    al, '*'         ;simply reset?
  340.         je    short do_deb850
  341. do_deb100:
  342.         push    cx            ;save function/reg #
  343.         push    edx            ;save linear address
  344.         mov    edx, 0fh        ;4 on bits
  345.         shl    cl, 2            ;reg # * bits associated    
  346.         add    cl, 16            ;upper portion of 32 bit reg
  347.         shl    edx, cl
  348.         not    edx            ;associated bits off
  349.         and    ebx, edx        ;in the dr7 value
  350.         shl    al, 2            ;length bits to len position
  351.         or    al, ah            ;put in the type
  352.         mov    dl, ah            ;save type
  353.         sub    ah, ah
  354.         shl    eax, cl         ;move len/rw to position
  355.         or    ebx, eax
  356.         or    dl, dl            ;execution type?
  357.         jz    short do_deb500     ;if so, don't need ge
  358.         bts    bx, ge_bit
  359. do_deb500:
  360.         pop    edx            ;restore linear address
  361.         pop    cx            ;and debug register #
  362.         cmp    cl, 1
  363.         je    short do_deb600
  364.         ja    short do_deb700
  365.         mov    dr0, edx
  366.         jmp    short do_deb800
  367. do_deb600:
  368.         mov    dr1, edx
  369.         jmp    short do_deb800
  370. do_deb700:
  371.         cmp    cl, 3
  372.         je    short do_deb750
  373.         mov    dr2, edx
  374.         jmp    short do_deb800
  375. do_deb750:
  376.         mov    dr3, edx
  377. do_deb800:
  378.         cmp    ch, 2            ;setup, but not enable?
  379.         je    short do_deb900     ;if so, skip enable
  380. do_deb850:
  381.         shl    cl, 1            ;get to global enable for #
  382.         inc    cl        
  383.         movzx    dx, cl            ;bit number to turn on
  384.         bts    bx, dx            ;set on in dr7 value
  385.         or    ch, ch            ;set function?
  386.         jnz    short do_deb900
  387.         btr    bx, dx            ;if not, disable break
  388.         or    ax, ax            ;clear ge or le?
  389.         jz    short do_deb900     ;if not continue
  390.         btr    bx, ax            ;if so, clear ge or le bit
  391. do_deb900:
  392.         mov    dr7, ebx        ;put adjusted value back    
  393.         pop    ebx
  394. do_deb999:
  395.         ret
  396. do_debug_reg    endp
  397.  
  398. isrcode     ends
  399.         end
  400. End Listings
  401.  
  402.