Intel processors starting from that 80386 have 8 special registers, which make it possible, up to four independent, linear addresses to specify. The processor compares and generates the values in these registers automatically with addressed addresses with agreement an interrupt 1. Which events such an interrupt release (e.g. writing or read accesses) can thereby by the programmer be specified. In the following a short overview of the Debug registers is to be given.
Fig. 1 represents the different functions of the Debug registers DR0..DR7.
Fig. 1: Debug register
All Debug registers can be addressed exclusively via MOV instructions and are independent of possible task changes, i.e. they are restored with a task change not automatically secured and/or.
Registers DR0... dr3 can be used, in order to specify addresses. The processor compares all address accesses with the values specified in these registers and implements the action, which was stopped in the DR7 register. Values in registers DR0... dr3 contain linear addresses, show thus the offset portion used by the appropriate program. Thus comparisons above the Paging mechanism and agree therefore with the logical processing of the programs take place.
Registers DR4 and DR5 are not used.
For any reason if an interrupt 1 was released, can be determined by the evaluation of the bits in the register DR6, which event released the interrupt. The structure of the register is represented in fig. 2.
Fig. 2: The structure of the status register
The meaning of the individual bits is shown in table 1.
|Bit||Reason for interrupt 1|
|BT||A task change was released and the T (Trap) bit new tasks one set, compared also with chapter 2.3 multitasking.|
|BS||Single step interrupt, i.e. the TF bit in the EFLA gs register are set. Thus with each instruction an interrupt is released.|
|BD||If this bit is set, the Intel in-Circuit-emulator (ICE) is active and the Debug registers can not be used. In this case the Debug registers can be read, each write access release however an interrupt 1. With the Intel ICE it acts around equipment, which is inserted into the processor base and like "more normally" a processor behaves, however of another computer steers itself.|
|B3||One accessed in the address defined over DR3.|
|B2||One accessed in the address defined over DR2.|
|B1||One accessed in the address defined over DR1.|
|B0||One accessed in the address defined over DR0.|
Note: Bits in the register DR6 are set by the processor, must be put back however e.g. by a debugger explicitly.
In an address specified in registers DR0..DR3 it was accessed contents of the register specify DR7 whether and/or how the processor reacts to it. Abb. 3 represents the structure of the DR7 of register.
Fig. 3: The structure of the Debug register 7
Over those in each case 2 bits long fields LENx can for everyone of the addresses (DR0... dr3) be specified, which memory capacity is addressed (see with table 2).
|00||Byte: Interrupt 1 is implemented only if a program accesses accurately (particulars) the byte, which is specified by the address.|
|01||Word: Interrupt 1 is implemented, if the byte with the address x and/or the byte with the address x+1 one accesses. The address held in the appropriate Debug register must be even-numbered.|
|11||Dword: Interrupt 1 is implemented, if the address range x to x+3 one accesses. The address held in the appropriate Debug register must be ganzahlig by four divisible.|
Over the fields R/Wx can be specified further for each critical point address, which access method releases an interrupt. Possible values are represented thereby in table 3.
|00||Read access: A critical point when reading instructions presupposes that the field LENx likewise contains the value 00 and the address specified in DRx shows that to the first byte of the instruction Opcodes and/or to the first prefix.|
|10||reserved (starting from PENTIUM: I/O writing or read access)|
|11||Writing or read access|
The bits Lx and/or Gx indicate finally whether and/or how the processor is to react to positive address comparisons. The critical points defined in registers DRx can be activated either locally (i.e. Lx set) and/or global (Gx set). If both bits are neglected, the processor reacts to positively failing address comparisons by setting appropriate bits in the register DR6, releases however no interrupt.
The distinction between global and local critical points is necessary only when using multitasking. During on global critical points (Gx set) independently of possible task changes one reacts, set Lx-bits with each task change are put back. In this way critical points can be limited to certain processes. That however also presupposes that an appropriate debugger must react to task changes, in order to set appropriate Lx-bits again.
The bits LE (local Exact) and/or GE (global Exact) are responsible for all four critical points and solve a problem, which results from the internal parallelism during command decoding by the processor: By the address x if a critical point is recognized and thus if an Debug interrupt is released, register CS:EIP already contains the address (those is handed over the interrupt Handler) of the next or instruction after the next. If one of the two bits is set, decoding is so far retarded that (correct) the address can be reconstructed still safe. While the GE bit applies global to all tasks, the LE bit is put back with a task change.
The sample programs debug_01.asm to debug_04.asm are to clarify the application of the Debug registers. Apart from the assembler examples also the equivalent C-programs debug_01.c to debug_04.c are available (more over the use of C, in connection with the Protected mode, you experience under Protected mode and C ).
The processor reacts to positively failing address comparisons, if the appropriate bits are set in the register DR7, with the releasing of an exception 1 (debugger interrupt).
If a program, usually thus a debugger and/or here the sample program debug_01 , is whereupon to react, then an appropriate exception Handler must be made available. Beside such exception Handler for the debugger interrupt 1 debug_01 makes a Handler available also for all further exception.
If an exception is released, each Handler accomplishes the following actions:
The general exception Handler brings then all further register contents on the stack, in order to convert and register into a storage area in the data segment it later into hexadecimal values. Afterwards the exception Handler releases a jump into the material mode and spends before the return to the DOS the exception text on the screen, prepared in the Protected mode.
The only difference of a "normal" exception Handlers to the exception Handler of the Debug interrupt 1 exists in the sample program in the fact that this picks out and on the screen spends additionally the Debug registers DR0 to DR3, DR6 and DR7.
In this way can be determined then, which BREAK POINT was reached and/or which event the interrupt released.
Sample program debug_01.asm calls the Debug interrupt 1 over the assembler instruction INT 1 to test the the exception Handler. In the C-program debug_01.c the macro BREAK POINT is used, which is made available in the file pmode.h and likewise INT assembled 1.
While debug_01 tested only the exception Handler, sample program 2 (debug_02 ) was to set a genuine BREAK POINT. In addition the Debug register DR0 is set on a function and register DR7 on "BREAK POINT with code access" is initialized. While the assembler example debug_02.asm makes these changes directly, the function is to the C-program debug_02.c set_drx (out pmode.c ) at the disposal. This function is to be discussed in the further more near.
The function set_drx expects four parameters:
After the function was called, it changes the pointer of function (void * dst), which an offset in the code segment corresponds, into a linear 32Bit-Adresse over. The function uses for it the macro cslin2rel out pmode.h , which converts the handed over address, as to it the starting offset address of the code segment is added. The in such a way determined value is assigned through int to the x selected Debug registers later. Next the function examines whether the handed over variables possess int rw and int len valid values. If the function states the fact that it concerns with one of the handed over values an invalid returns the function without change with ' return '.
Subsequently, the values are converted int len and int rw into a format needed for register DR7 ( rw in the lower 2 bits and len in the upper 2 bits). In dependence of the value int x then 4 bits just computed the long value one rotates accordingly, one sets the appropriate global Enable bits and one writes the value into the DR7 register.
If the main program debug_02.c tries to then call the appropriate function, that recognizes the processor and reacts with the call of the debugger interrupt 1. Opposite the exception Handler from debug_01 the exception Handler belonging to the sample program debug_02 evaluates the bits in the register DR6 and gives additionally still the reason for the release of the interrupt in form of a text stringer out (e.g. "access to BREAK POINT 0").
Im Gegensatz zu Beispielprogramm debug_02 initialisiert das Programm debug_03 die Debug-Register so, daß ein Interrupt 1 bei einem Schreibzugriff auf eine globale Variable (int global_test) ausgelöst wird. Die Funktion set_drx wurde dafür so geändert, daß sie jetzt lineare 32Bit-Breakpoint-Adressen erwartet. Eventuelle Umrechnungen müssen deshalb vor (!) der Übergabe an set_drx durchgeführt werden. Dazu stellt pmode.h neben dem bekannten Makro cslin2rel das Makros dslin2rel bereit. dslin2rel rechnet Offsetadressen in das Datensegment in lineare 32Bit-Adressen um, indem die lineare Startadresse des Datensegments zur übergebenen Adresse addiert wird.
Auch Beispielprogramm 3 liegt in einer C- (debug_03.c) sowie in einer Assembler-Version (debug_03.asm) vor.
Das vierte Beispielprogramm debug_04 zeigt eine Möglichkeit, den Inhalt einer Variablen bzw. im Allgemeinen einer Speicheradresse zu überwachen. debug_04 setzt dazu, ähnlich debug_03, einen "Schreibzugriffs-Breakpoint" auf eine globale Variable im Datensegment (int global_test). Damit lösen Schreibzugriffe auf diese Variable den Debugger-Interrupt 1 aus. Der entsprechende Exception-Handler kehrt nun nicht in den Realmode und zu DOS zurück, sondern gibt den Inhalt der entsprechenden Speicherzelle aus und beendet den Exception-Handler mit IRET. Dadurch wird das entsprechende Programm fortgesetzt.
Die Programme debug_04.c bzw. debug_04.asm greifen nun in einer Zählschleife auf die Variable global_test zu und lösen damit Exceptions aus. Der jeweilige Variableninhalt wird dabei vom Exception-Handler auf dem Bildschirm dargestellt.