This section contains the following sections:
The example files provide a demonstration kernel extension and a program to load, execute, and unload the extension. These programs may be compiled, linked, and executed as indicated in the following material. Note, to use these programs to follow the examples you need a machine with a C compiler, a console, and running with a KDB kernel enabled for debugging. To use the KDB Kernel Debugger you will need exclusive use of the machine.
Examples using the KDB Kernel Debugger with the demonstration programs are included in each of the following sections. The examples are shown in tables which contain two columns. The first column of the table contains an indication of the system prompt and the user input to perform each step. The second column of each table explains the function of the command and includes example output, where applicable. In the examples, since only the console is used, the demo program is switched between the background and the foreground as needed.
The files listed below are used in examples throughout this section.
To build the demonstration programs:
This script produces:
The following sections describe compilation and link options used in the comp_link script in more detail and also cover using the map and list files.
Assembler listing and map files are useful tools for debugging using the KDB Kernel Debugger. In order to create the assembler list file during compilation, use the -qlist option. Also use the -qsource option to get the C source listing in the same file:
cc -c -DEBUG -D_KERNEL -DIBMR2 demokext.c -qsource -qlist
In order to obtain a map file, use the -bmap:FileName option for the link editor. The following example creates a map file of demokext.map:
ld -o demokext demokext.o -edemokext -bimport:/lib/syscalls.exp \ -bimport:/lib/kernex.exp -lcsys -bexport:demokext.exp -bmap:demokext.map
The assembler and source listing is used to correlate any C source line with the corresponding assembler lines. The following is a portion of the list file, created by the cc command used earlier, for the demonstration kernel extension. This information is included in the compilation listing because of the -qsource option for the cc command. The left column is the line number in the source code:
. . 63 | case 1: /* Increment */ 64 | sprintf(buf, "Before increment: j=%d demokext_j=%d\n", 65 | j, demokext_j); 66 | write_log(fpp, buf, &bytes_written); 67 | demokext_j++; 68 | j++; 69 | sprintf(buf, "After increment: j=%d demokext_j=%d\n", 70 | j, demokext_j); 71 | write_log(fpp, buf, &bytes_written); 72 | break; . .
The following is the assembler listing for the corresponding C code shown above. This information was included in the compilation listing because of the -qlist option used on the cc command earlier.
. . 64| 0000B0 l 80BF0030 2 L4A gr5=j(gr31,48) 64| 0000B4 l 83C20008 1 L4A gr30=.demokext_j(gr2,0) 64| 0000B8 l 80DE0000 2 L4A gr6=demokext_j(gr30,0) 64| 0000BC ai 30610048 1 AI gr3=gr1,72 64| 0000C0 ai 309F005C 1 AI gr4=gr31,92 64| 0000C4 bl 4BFFFF3D 0 CALL gr3=sprintf,4,buf",gr3,""5",gr4-gr6,sprintf",gr1,cr[01567]",gr0",gr4"-gr12",fp0"-fp13" 64| 0000C8 cror 4DEF7B82 1 66| 0000CC l 80610040 1 L4A gr3=fpp(gr1,64) 66| 0000D0 ai 30810048 1 AI gr4=gr1,72 66| 0000D4 ai 30A100AC 1 AI gr5=gr1,172 66| 0000D8 bl 4800018D 0 CALL gr3=write_log,3,gr3,buf",gr4,bytes_written",gr5,write_log",gr1,cr[01567]",gr0",gr4"-gr12",fp0"-fp13" 66| 0000DC cal 387E0000 2 LR gr3=gr30 67| 0000E0 l 80830000 1 L4A gr4=demokext_j(gr3,0) 67| 0000E4 ai 30840001 2 AI gr4=gr4,1 67| 0000E8 st 90830000 1 ST4A demokext_j(gr3,0)=gr4 68| 0000EC l 809F0030 1 L4A gr4=j(gr31,48) 68| 0000F0 ai 30A40001 2 AI gr5=gr4,1 68| 0000F4 st 90BF0030 1 ST4A j(gr31,48)=gr5 69| 0000F8 l 80C30000 1 L4A gr6=demokext_j(gr3,0) 69| 0000FC ai 30610048 1 AI gr3=gr1,72 69| 000100 ai 309F0084 1 AI gr4=gr31,132 69| 000104 bl 4BFFFEFD 0 CALL gr3=sprintf,4,buf",gr3,""6",gr4-gr6,sprintf",gr1,cr[01567]",gr0",gr4"-gr12",fp0"-fp13" 69| 000108 cror 4DEF7B82 1 71| 00010C l 80610040 1 L4A gr3=fpp(gr1,64) 71| 000110 ai 30810048 1 AI gr4=gr1,72 71| 000114 ai 30A100AC 1 AI gr5=gr1,172 71| 000118 bl 4800014D 0 CALL gr3=write_log,3,gr3,buf",gr4,bytes_written",gr5,write_log",gr1,cr[01567]",gr0",gr4"-gr12",fp0"-fp13" 72| 00011C b 48000098 1 B CL.8,-1 . .
With both the assembler listing and the C source listing, the assembly instructions associated with each C statement may be found. As an example, consider the C source line at line 67 of the demonstration kernel extension:
67 | demokext_j++;
The corresponding assembler instructions are:
67| 0000E0 l 80830000 1 L4A gr4=demokext_j(gr3,0) 67| 0000E4 ai 30840001 2 AI gr4=gr4,1 67| 0000E8 st 90830000 1 ST4A demokext_j(gr3,0)=gr4
The offsets of these instructions within the demonstration kernel extension (demokext) are 0000E0, 0000E4, and 0000E8.
The binder map file is a symbol map in address order format. Each symbol listed in the map file has a storage class (CL) and a type (TY) associated with it.
Storage classes correspond to the XMC_XX variables defined in the syms.h file. Each storage class belongs to one of the following section types:
.text | Contains read-only data (instructions). Addresses listed in this section
use the beginning of the .text section as origin. The .text
section can contain one of the following storage class (CL)
values:
| ||||||||||||||
.data | Contains read-write initialized data. Addresses listed in this section
use the beginning of the .data section as origin. The .data
section can contain one of the following storage class (CL)
values:
| ||||||||||||||
.bss | Contains read-write uninitialized data. Addresses listed in this section use
the beginning of the .data section as origin. The .bss section
contain one of the following storage class (CL) values:
|
Types correspond to the XTY_XX variables defined in the syms.h file. The type (TY) can be one of the following values:
ER | External Reference |
LD | Label Definition |
SD | Section Definition |
CM | BSS Common Definition |
The following is the map file for the demonstration kernel extension. This file was created because of the -bmap:demokext.map option of the ld command shown earlier.
1 ADDRESS MAP FOR demokext 2 *IE ADDRESS LENGTH AL CL TY Sym# NAME SOURCE-FIL E(OBJECT) or IMPORT-FILE{SHARED-OBJECT} 3 --- -------- ------ -- -- -- ----- ------------------------- ------------------------------------------------- 4 I ER S1 _system_configuration /lib/syscalls.exp{/unix} 5 I ER S2 fp_open /lib/kernex.exp{/unix} 6 I ER S3 fp_close /lib/kernex.exp{/unix} 7 I ER S4 fp_write /lib/kernex.exp{/unix} 8 I ER S5 sprintf /lib/kernex.exp{/unix} 9 00000000 000360 2 PR SD S6 <> demokext.c(demokext.o) 10 00000000 PR LD S7 .demokext 11 00000210 PR LD S8 .close_log 12 00000264 PR LD S9 .write_log 13 000002F4 PR LD S10 .open_log 14 00000360 000108 5 PR SD S11 .strcpy strcpy.s(/usr/lib/libcsys.a[strcpy.o]) 15 00000468 000028 2 GL SD S12 <.sprintf> glink.s(/usr/lib/glink.o) 16 00000468 GL LD S13 .sprintf 17 00000490 000028 2 GL SD S14 <.fp_close> glink.s(/usr/lib/glink.o) 18 00000490 GL LD S15 .fp_close 19 000004C0 0000F8 5 PR SD S16 .strlen strlen.s(/usr/lib/libcsys.a[strlen.o]) 20 000005B8 000028 2 GL SD S17 <.fp_write> glink.s(/usr/lib/glink.o) 21 000005B8 GL LD S18 .fp_write 22 000005E0 000028 2 GL SD S19 <.fp_open> glink.s(/usr/lib/glink.o) 23 000005E0 GL LD S20 .fp_open 24 00000000 0000F9 3 RW SD S21 <_$STATIC> demokext.c(demokext.o) 25 E 000000FC 000004 2 RW SD S22 demokext_j demokext.c(demokext.o) 26 * 00000100 00000C 2 DS SD S23 demokext demokext.c(demokext.o) 27 0000010C 000000 2 T0 SD S24 <TOC> 28 0000010C 000004 2 TC SD S25 <_$STATIC> 29 00000110 000004 2 TC SD S26 <_system_configuration> 30 00000114 000004 2 TC SD S27 <demokext_j> 31 00000118 000004 2 TC SD S28 <sprintf> 32 0000011C 000004 2 TC SD S29 <fp_close> 33 00000120 000004 2 TC SD S30 <fp_write> 34 00000124 000004 2 TC SD S31 <fp_open>
In the above map file, the .data section starts at the statement for line 24:
24 00000000 0000F9 3 RW SD S21 <_$STATIC> demokext.c(demokext.o)
The TOC (Table Of Contents) starts at the statement for line 27:
27 0000010C 000000 2 T0 SD S24 <TOC>
Setting a breakpoint is essential for debugging kernel extensions. To set a breakpoint, use the following sequence of steps:
The process of locating the assembler instruction and getting its offset is explained in the previous section. To continue with the demokext example, we will set a break at the C source line 67, which increments the variable demokext_j. The list file indicates that this line starts at an offset of 0xE0. So the next step is to determine the address where the kernel extension is loaded.
To determine the address at which a kernel extension has been loaded, use the following procedure. First, find the load point (the entry point) of the executable kernel extension. This is a label supplied with the -e option for the ld command. In the example this is the demokext routine.
Use one of the following methods to locate the address of this load point and set a breakpoint at the appropriate offset from this point.
Normally, with the KDB Kernel Debugger a breakpoint may be set directly by using the b subcommand in conjunction with the routine name and the offset. For example, b demokext+4 will set a break at the instruction 4 bytes from the beginning of the demokext routine.
The KDB lke subcommand displays a list of loaded kernel extensions. To find the address of the modules for a particular extension use the KDB subcommand lke entry_number, where entry_number is the extension number of interest. In the displayed data is a list of Process Trace Backs which shows the beginning addresses of routines contained in the extension.
If the kernel extension is not stripped the KDB Kernel Debugger may be used to locate the address of the load point by name. For example the subcommand nm demokext returns the address of the demokext routine after it is loaded. This address may then be used to set a breakpoint.
Another method to locate the address of the entry point for a kernel extension is to use the value of the kmid pointer returned by the sysconfig(SYS_KLOAD) subroutine when the kernel extension is loaded. The kmid pointer points to the address of the load point routine. Hence to get the address of the load point, print the kmid value during the sysconfig call from the configuration method; in the current example, this is the demo.c module. Then go into the KDB Kernel Debugger and display the value pointed to by kmid.
If the kernel extension is a device driver, use the KDB devsw subcommand to locate the desired address. The devsw subcommand lists all the function addresses for the device driver (that are in the dev switch table). Usually the config routine will be the load point routine.
MAJ#010 OPEN CLOSE READ WRITE 0123DE04 0123DC04 0123DB20 0123DA3C IOCTL STRATEGY TTY SELECT 0123D090 01244DF0 00000000 00059774 CONFIG PRINT DUMP MPX 0123E8C8 00059774 00059774 00059774 REVOKE DSDPTR SELPTR OPTS 00059774 00000000 00000000 00000002
The following provides examples of each of the above methods using the demo and demokext routines compiled earlier. Note, the following must be run as the root user. For this example, assume that a break is to be set at line 67, which has an offset from the beginning of demokext of 0xE0.
Prompt and Console Input | Function and Example Output |
---|---|
Load the demokext kernel extension | |
$ ./demo | Run the demo program, this loads the demokext extension. Note, the value printed for kmid, this is used later in this example. |
$ <CTRL-Z> | Stop the demo program. |
$ bg | Put the demo program in the background. |
$ <CTRL-\> | Activate KDB, use the appropriate key sequence for your configuration. You should have a KDB prompt on completion of this step. |
Set a breakpoint using Method 1 | |
KDB(0)> b demokext+E0 | Set a breakpoint using the symbol demokext. This is the easiest and most common way of setting a breakpoint within KDB. KDB responds with an indication of the address where the break is set. |
KDB(0)> b | List all breakpoints. KDB displays a list of all breakpoints currently active. |
KDB(0)> ca | This clears all breakpoints |
KDB(0)> b | List all breakpoints. KDB indicates there are no active breakpoints. |
Set a breakpoint using Method 2 | |
KDB(0)> lke | List loaded extensions. The output from this subcommand will be similar to:
ADDRESS FILE FILESIZE FLAGS MODULE NAME 1 04E17F80 01303F00 000007F0 00000272 ./demokext 2 04E17E80 0503A000 00000E88 00000248 /unix 3 04E17C00 04FA3000 00071B34 00000272 /usr/lib/drivers/nfs.ext 4 04E17A80 05021000 00000E88 00000248 /unix 5 04E17800 01303B98 00000348 00000272 /usr/lib/drivers/nfs_kdes.ext 6 04E17B80 04F96000 00000E34 00000248 /unix 7 04E17500 01301A10 0000217C 00000272 /etc/drivers/blockset64 . . Enter <CTRL-C> to exit the KDB Kernel Debugger paging function, if more than one page of data is present. You may exit the paging function at any time by using <CTRL-C>. Pressing <ENTER> displays the next page of data; <SPACE> displays the next line of data. Additionally, the number of lines per page may be changed using the set screen_size xx subcommand; where xx is the number of lines to be be considered a page. |
KDB(0)> lke 1 | List detailed information about the extension of interest. The parameter
to the lke subcommand is the slot number for the ./demokext
entry from the previous step. The output from this command will be similar to:
ADDRESS FILE FILESIZE FLAGS MODULE NAME 1 04E17F80 01303F00 000007F0 00000272 ./demokext le_flags....... TEXT KERNELEX DATAINTEXT DATA DATAEXISTS le_next........ 04E17E80 le_fp.......... 00000000 le_filename.... 04E17FD8 le_file........ 01303F00 le_filesize.... 000007F0 le_data........ 013045C8 le_tid......... 00000000 le_datasize.... 00000128 le_usecount.... 00000003 le_loadcount... 00000001 le_ndepend..... 00000001 le_maxdepend... 00000001 le_ule......... 0502E000 le_deferred.... 00000000 le_exports..... 0502E000 le_de.......... 6C696263 le_searchlist.. B0000420 le_dlusecount.. 00000000 le_dlindex..... 00002F6C le_lex......... 00000000 le_fh.......... 00000000 le_depend.... @ 04E17FD4 TOC@........... 013046D4 <PROCESS TRACE BACKS> .demokext 01304040 .close_log 013041FC .write_log 01304240 .open_log 013042B4 .strcpy 01304320 .sprintf.glink 01304428 .fp_close.glink 01304450 .strlen 01304480 .fp_write.glink 01304578 .fp_open.glink 013045A0 From the PROCESS TRACE BACKS we see that the first instruction of demokext is at 01304040. So the break for line 67 would be at this address plus E0. |
KDB(0)> b 01304040+e0 | Set the break at the desired location. KDB responds with an indication of the address that the breakpoint is at. |
KDB(0)> ca | Clear all breakpoints. |
Set a breakpoint using Method 3 | |
KDB(0)> nm demokext | This translates a symbol to an effective address. The output from this
subcommand will be similar to:
Symbol Address : 01304040 TOC Address : 013046D4 The value of the symbol demokext is the address of the first instruction of the demokext routine. So this value can be used to set a breakpoint, just as in the previous example. |
KDB(0)> b 01304040+e0 | Set the break at the desired location. KDB responds with an indication of the address that the breakpoint is at. |
KDB(0)> dw 01304040+e0 | Display the word at the breakpoint. KDB will respond with something
similar to:
01304120: 80830000 30840001 90830000 809F0030 ....0..........0 This can then be checked against the assembly code in the listing to verify that the break is set at the correct location. |
KDB(0)> ca | Clear all breakpoints. |
Set a breakpoint using Method 4 | |
KDB(0)> dw 1304748 | Display the memory at the address returned as the kmid from the sysconfig
routine at the beginning of this example. KDB responds with something
similar to:
demokext+000000: 01304040 01304754 00000000 01304648 .0@@.0GT.....0FHThe first word of data displayed is the address of the first instruction of the demokext routine. Note, the data displayed is at the location demokext+000000. This corresponds to line 26 of the map presented earlier. However, the most important thing to note is that demokext+000000 and .demokext+000000 are not the same address. The location .demokext+000000 corresponds to line 10 of the map and is the address of the first instruction for the demokext routine. |
KDB(0)> b 01304040+e0 | Set the break at the location indicated from the previous command plus the offset to get to line 67. KDB responds with an indication of the address that the breakpoint is at. |
ca | Clear all breakpoints. |
Set a breakpoint using Method 5 | |
KDB(0)> devsw 1 | Display the device switch table for the first entry. Note, the demonstration
program that is being used is not a device driver; so this example just uses the
addresses of the first device driver in the device switch table and is not
related in any way to the demonstration program. The KDB devsw command displays
data similar to:
Slot address 50006040 MAJ#001 OPEN CLOSE READ WRITE .syopen .nulldev .syread .sywrite IOCTL STRATEGY TTY SELECT .syioctl .nodev 00000000 .syselect CONFIG PRINT DUMP MPX .nodev .nodev .nodev .nodev REVOKE DSDPTR SELPTR OPTS .nodev 00000000 00000000 00000012 |
KDB(0)> b .syopen+20 | Set a breakpoint at an offset of 0x20 from the beginning of the open routine for the first device driver in the device switch table. Note, KDB responds with an indication of where the break was set. |
KDB(0)> ca | Clear all breakpoints. |
KDB(0)> ns | Turn off symbolic name translation. |
KDB(0)> devsw 1 | Display the device switch table for the first device driver again. This
time, with symbolic name translation turned off addresses instead of names
will be displayed. The output from this subcommand is similar to:
Slot address 50006040 MAJ#001 OPEN CLOSE READ WRITE 00208858 00059750 002086D4 0020854C IOCTL STRATEGY TTY SELECT 00208290 00059774 00000000 00208224 CONFIG PRINT DUMP MPX |
KDB(0)> b 00208858+20 | Set a break at an offset of 0x20 from the beginning of the open routine for the first device driver in the device switch table. This will set the same break that was set at the beginning of Set a breakpoint using Method 5. KDB responds with an indication of where the break was set. |
KDB(0)> ns | Toggle symbolic name translation on. |
KDB(0)> ca | Clear all breaks. |
KDB(0)> g | Exit the KDB Kernel Debugger and let the system resume normal execution. |
Unload the demokext kernel extension | |
$ fg | Bring the demo program to the foreground. Note, it will be waiting for user input of 0 to unload and exit, 1 to increment counters, or 2 decrement counters (the prompt will not be redisplayed, since it was shown prior to stopping the program and placing it in the background). |
./demo 0 | Enter a value of 0 to indicate that the kernel extension is to be unloaded and that the demo program is to terminate. |
Global data may be accessed by several methods. In this section three methods are presented to access global data. The demo and demokext programs continue to be used in the illustrations in this section. In particular, the variable demokext_j (which is exported) is used in the examples.
The first method presented demonstrates the simpliest method of access for global data. The second method presented demonstrates accessing global data using the TOC and the map file. This method requires that the system is stopped in the KDB Kernel Debugger within a procedure of the kernel extension to be debugged. Finally, the third method demonstrates a way to access global data using the map file, but without using the TOC.
Access of global variables within KDB is very simple. The variables may be accessed directly by name. For example to display the value of demokext_j the subcommand "dw demokext_j" may be used. If demokext_j was an array, a specific value could be viewed by adding the appropriate offset. For example, "dw demokext_j+20". Access to individual elements of a structure is accomplished by adding the proper offset to the base address for the variable.
To locate the address of global data using the address of the TOC and the map requires that the system be stopped in the KDB Kernel Debugger within a routine of the kernel extension to be debugged. This may be accomplished by setting a breakpoint within the kernel extension, as discussed in the previous section. When the KDB Kernel Debugger is invoked, general purpose register number 2 points to the address of the TOC. From the map file the offset from the start of the TOC to the desired TOC entry may be calculated. Knowing this offset and the address at which the TOC starts allows the address of the TOC entry for the desired global variable to be calculated. Then the address of the TOC entry for the desired variable may be examined to determine the address of the data.
Example
As an example, assume that the KDB Kernel Debugger has been invoked because of a breakpoint at line 67 of the demokext routine and that the value for general purpose register number 2 is 0x01304754. Then to find the address of the demokext_j data requires the following:
Unlike the procedure outlined in method 2, this method may be used at any time. This method requires the map file and the address at which the kernel extension has been loaded. Note, this method works because of the manner in which a kernel extension is loaded. Therefore, it may not work if the procedure for loading a kernel extension changes.
This method relies on the assumption that the address of a global variable
may be found by using the formula:
Addr of variable = Addr of the last function before the variable in the map + Length of the function + Offset of the variable
To illustrate this calculation, refer to the following section of the map file for the demokext kernel extension.
20 000005B8 000028 2 GL SD S17 <.fp_write> glink.s(/usr/lib/glink.o) 21 000005B8 GL LD S18 .fp_write 22 000005E0 000028 2 GL SD S19 <.fp_open> glink.s(/usr/lib/glink.o) 23 000005E0 GL LD S20 .fp_open 24 00000000 0000F9 3 RW SD S21 <_$STATIC> demokext.c(demokext.o) 25 E 000000FC 000004 2 RW SD S22 demokext_j demokext.c(demokext.o) 26 * 00000100 00000C 2 DS SD S23 demokext demokext.c(demokext.o) 27 0000010C 000000 2 T0 SD S24 <TOC> 28 0000010C 000004 2 TC SD S25 <_$STATIC> 29 00000110 000004 2 TC SD S26 <_system_configuration>
The last function in the .text section is at lines 22-23. The offset of this function from the map is 0x000005E0 (line 22, column 2). The length of the function is 0x000028 (Line 22, column 3). The offset of the demokext_j variable is 0x000000FC (line 25, column 2). So the offset from the load point value to demokext_j is:
0x000005E0 + 0x000028 + 0x000000FC = 0x00000704
Adding this offset to the load point value of the demokext kernel extension yields the address of the data for demokext_j. Assuming a load point value of 0x01304040 (as used in previous examples), this would indicate that the data for demokext_j was located at:
0x01304040 + 0x00000704 = 0x01304744
Note that in Method 2, using the TOC, the address of the address of the data for demokext_j was calculated; while in Method 3 simply the address of the data for demokext_j was found. Also note that Method 1 is the primary method of access of global data when using the KDB Kernel Debugger. The other methods are mainly described to show alternatives and to allow the use of additional KDB subcommands in the following examples.
Prompt and Console Input | Function and Example Output |
---|---|
Load the demokext kernel extension | |
$ ./demo | Run the demo program, this loads the demokext extension. |
$ <CTRL-Z> | Stop the demo program. |
$ bg | Put the demo program in the background. |
$ <CTRL-\> | Activate KDB, use the appropriate key sequence for your configuration. You should have a KDB prompt on completion of this step. |
Viewing/Modifying Global Data using Method 1 | |
KDB(0)> dw demokext_j | Display a word at the address of the demokext_j variable. Since
the kernel extension was just loaded this variable should have a value of 99
and the KDB Kernel Debugger should display that value. The data displayed
should be similar to the following:
demokext_j+000000: 00000063 01304040 01304754 00000000 ...c.0@@.0GT.... |
KDB(0)> ns | Turn off symbolic name translation. |
KDB(0)> dw demokext_j | This will again display the word at the address of the demokext_j
variable, except with symbolic name translation turned off. So the data
displayed should be similar to:
01304744: 00000063 01304040 01304754 00000000 ...c.0@@.0GT.... |
KDB(0)> ns | Turn symbolic name translation on. |
KDB(0)> mw demokext_j | Modify the word at the address of the demokext_j variable. The KDB
Kernel Debugger displays the current value of the word and waits for user
input to change the value. The data displayed should be:
01304744: 00000063 = A new value may then be entered. After a new value is entered, the next word of memory is displayed for possible modification. To end memory modification a period (.) is entered. So to complete this step, enter a value of 64 (100 decimal) for the first address and then enter a period to end modification. |
Viewing/Modifying Global Data using Method 2 | |
KDB(0)> b demokext+e0 | Set a break at line 67 of the demokext routine (see the examples in the previous section). Breaking at this location will insure that the KDB Kernel Debugger is invoked while within the demokext routines. Then we can get the value of General Purpose Register 2, to determine the address of the TOC. |
KDB(0)> g | Exit the KDB Kernel Debugger. This exits the debugger and we can then bring the demo program to the foreground and choose a selection to cause the demokext routine to be called for configuration. Since a break has been set this will cause the KDB Kernel Debugger to be invoked. |
$ fg | Bring the demo program to the foreground. |
./demo 1 | Enter a value of 1 to select the option to increment the counters within the demokext kernel extension. This causes a break at line 67 of demokext. |
KDB(0)> dr | Display the general purpose registers. The data displayed should be
similar to the following:
r0 : 0130411C r1 : 2FF3B210 r2 : 01304754 r3 : 01304744 r4 : 0047B180 r5 : 0047B230 r6 : 000005FB r7 : 000DD300 r8 : 000005FB r9 : 000DD300 r10 : 00000000 r11 : 00000000 r12 : 013042F4 r13 : DEADBEEF r14 : 00000001 r15 : 2FF22D80 r16 : 2FF22D88 r17 : 00000000 r18 : DEADBEEF r19 : DEADBEEF r20 : DEADBEEF r21 : DEADBEEF r22 : DEADBEEF r23 : DEADBEEF r24 : 2FF3B6E0 r25 : 2FF3B400 r26 : 10000574 r27 : 22222484 r28 : E3001E30 r29 : E6001800 r30 : 01304744 r31 : 01304648Using the map, the offset to the TOC entry for demokext_j from the start of the TOC was 0x00000008 (see the above text concerning Method 2). Adding this offset to the value displayed for r2 indicates that the TOC entry of interest is at: 0x0130475C. Note, the KDB Kernel Debugger may be used to perform the addition. In this case the subcommand to use would be hcal @r2+8. |
KDB(0)> dw 0130475C | Display the TOC entry for demokext_j. This entry will contain the
address of the data for demokext_j. The data displayed should be
similar to:
TOC+000008: 01304744 000BCB34 00242E94 001E0518 .0GD...4.$...... The value for the first word displayed is the address of the data for the demokext_j variable. |
KDB(0)> dw 01304744 | Display the data for demokext_j. The data displayed should indicate
that the value for demokext_j is still 0x0000064, which we set it to
earlier. This is because the breakpoint set was in the demokext routine prior
to demokext_j being incremented. The data displayed should be similar to:
demokext_j+000000: 00000064 01304040 01304754 00000000 ...d.0@@.0GT.... |
KDB(0)> ca | Clear all breakpoints. |
KDB(0)> g | Exit the kernel debugger. Be careful here, when we exit, the demo program will still be in the foreground and there will be a prompt for the next option. Also note that the kernel extension is going to run and increment demokext_j; so next time it should have a value of 0x00000065. |
Enter choice: <CTRL-Z> | Enter <CTRL-Z> to stop the demo program. |
$ bg | Place the demo program in the background. |
Viewing/Modifying Global Data using Method 3 | |
$ <CTRL-\> | Activate KDB, use the appropriate key sequence for your configuration. You should have a KDB prompt on completion of this step. |
KDB(0)> dw demokext+704 | Display the data for the demokext_j variable. The 704 value
is calculated from the map (refer to the above text for Method 3). This
offset is then added to the load point of the demokext routine. Though there
are numerous ways to find this address, in this case the simpliest is to
just use the symbolic name; to review other options refer back to the
Setting Breakpoints section. As mentioned, earlier the value
for demokext_j should now be 0x00000065. The data displayed should be
similar to:
demokext_j+000000: 00000065 01304040 01304754 00000000 ...e.0@@.0GT.... |
KDB(0)> g | Exit the KDB Kernel Debugger. |
$ fg | Bring the demo program to the foreground. |
./demo 0 | Enter an option of 0 to unload the demokext kernel extension and exit. |
The stack trace gives the stack history. This provides the sequence of procedure calls leading to the current IAR. The Saved LR is the address of the instruction calling this procedure. You can use the map file to locate the name of the procedure. Note that the first stack frame shown is almost always useless, since data either has not been saved yet, or is from a previous call. The last function preceding the Saved LR is the function that called the procedure.
The following is a concise view of the stack:
Low | |Stack grows at Addresses | |this end. |--------------------| Callee's stack -> 0 | Back chain | pointer 4 | Saved CR | 8 | Saved LR | 12-16 | Reserved |<---LINK AREA (callee) 20 | SAVED TOC | |--------------------| Space for P1-P8 | P1 | OUTPUT ARGUMENT AREA is always reserved | ... |<---(Used by callee to | Pn | construct argument | Callee's | | stack | <--- LOCAL STACK AREA | area | |--------------------| | | (Possible word wasted |--------------------| for alignment.) -8*nfprs-4*ngprs --> | Caller's GPR | Rfirst = R13 for full save | save area | save | max 19 words | R31 |--------------------| -8*nfprs --> | Caller's FPR | Ffirst = F14 for a | save area | full save | max 18 dblwds | F31 |--------------------| Caller's stack -> 0 | Back chain | pointer 4 | Saved CR | 8 | Saved LR | 12-16 | Reserved |<---LINK AREA (caller) 20 | Saved TOC | |--------------------| Space for P1-P8 24 | P1 | INPUT PARAMETER AREA is always reserved | ... | <---(Callee's input | Pn | parameters found |--------------------| here. Is also | Caller's | caller's arg area.) | stack | High | area | Addresses |
To illustrate some of the capabilities of the KDB Kernel Debugger for viewing the stack use the demo program and demokext kernel extension again. This time a break will be set in the write_log routine.
Prompt and Console Input | Function and Example Output |
---|---|
Load the demokext kernel extension | |
$ ./demo | Run the demo program, this loads the demokext extension. |
$ <CTRL-Z> | Stop the demo program. |
$ bg | Put the demo program in the background. |
$ <CTRL-\> | Activate KDB, use the appropriate key sequence for your configuration. You should have a KDB prompt on completion of this step. |
Set and execute to a breakpoint in write_log | |
KDB(0)> b demokext+280 | Set a break at line 117 of demokext.c; this is the first line of write_log. The offset of 0x00000280 was determined from the list file as described in earlier sections. |
KDB(0)> g | Exit the KDB Kernel Debugger. |
$ fg | Bring the demo program to the foreground. |
./demo 1 | Select option 1 to increment the counters in the kernel extension demokext. This causes the KDB Kernel Debugger to be invoked; stopped at the breakpoint set in write_log. |
View the stack | |
KDB(0)> stack | This displays the stack for the current process, which was the the demo
program calling the demokext kernel extension (since there was a break set).
The stack trace back displays the routines called and even traces back
through system calls. The displayed data should be similar to:
thread+001800 STACK: [013042C0]write_log+00001C (10002040, 2FF3B258, 2FF3B2BC) [013040B0]demokext+000070 (00000001, 2FF3B338) [001E3BF4]config_kmod+0000F0 (??, ??, ??) [001E3FA8]sysconfig+000140 (??, ??, ??) [000039D8].sys_call+000000 () [10000570]main+000280 (??, ??) [10000188]__start+000088 () |
KDB(0)> s 4 | This subcommand steps 4 instructions. This should get into a strlen call. If it doesn't, continue stepping until strlen is entered. |
KDB(0)> stack | Reexamine the stack. It should now include the strlen call and should
be similar to:
thread+001800 STACK: [01304500]strlen+000000 () [013042CC]write_log+000028 (10002040, 2FF3B258, 2FF3B2BC) [013040B0]demokext+000070 (00000001, 2FF3B338) [001E3BF4]config_kmod+0000F0 (??, ??, ??) [001E3FA8]sysconfig+000140 (??, ??, ??) [000039D8].sys_call+000000 () [10000570]main+000280 (??, ??) [10000188]__start+000088 () |
KDB(0)> set display_stack_frames | This subcommand toggles a KDB Kernel Debugger option to display the top (lower addresses) 64 bytes for each stack frame. |
KDB(0)> stack | Redisplay the stack with the display_stack_frames option turned on.
The output should be similar to:
thread+001800 STACK: [01304510]strlen+000000 () ======================================================================= 2FF3B1C0: 2FF3 B210 2FF3 B380 0130 4364 0000 0000 /.../....0Cd.... 2FF3B1D0: 2FF3 B230 0130 4754 0023 AD5C 2222 2082 /..0.0GT.#.\"" . 2FF3B1E0: 0012 0000 2FF3 B400 0000 0480 0000 510C ..../.........Q. 2FF3B1F0: 2FF3 B260 4A22 2860 001D CEC8 0000 153C /..`J"(`.......< ======================================================================= [013042CC]write_log+000028 (10002040, 2FF3B258, 2FF3B2BC) ======================================================================= 2FF3B210: 2FF3 B2E0 0000 0003 0130 40B4 0000 0000 /........0@..... 2FF3B220: 0000 0000 2FF3 B380 1000 2040 2FF3 B258 ..../..... @/..X 2FF3B230: 2FF3 B2BC 0000 0000 001E 5968 0000 0000 /.........Yh.... 2FF3B240: 0000 0000 0027 83E8 0048 5358 007F FFFF .....'...HSX.... ======================================================================= [013040B0]demokext+000070 (00000001, 2FF3B338) ======================================================================= 2FF3B2E0: 2FF3 B370 2233 4484 001E 3BF8 0000 0000 /..p"3D...;..... 2FF3B2F0: 0000 0000 0027 83E8 0000 0001 2FF3 B338 .....'....../..8 2FF3B300: E300 1E30 0000 0020 2FF1 F9F8 2FF1 F9FC ...0... /.../... 2FF3B310: 8000 0000 0000 0001 2FF1 F780 0000 3D20 ......../.....= [001E3BF4]config_kmod+0000F0 (??, ??, ??) ======================================================================= 2FF3B370: 2FF3 B3C0 0027 83E8 001E 3FAC 2FF2 2FF8 /....'....?././. 2FF3B380: 0000 0002 2FF3 B400 F014 8912 0000 0FFE ..../........... 2FF3B390: 2FF3 B388 0000 153C 0000 0001 2000 7758 /......<.... .wX 2FF3B3A0: 0000 0000 0000 09B4 0000 0FFE 0000 0000 ................ ======================================================================= [001E3FA8]sysconfig+000140 (??, ??, ??) ======================================================================= 2FF3B3C0: 2FF2 1AA0 0002 D0B0 0000 39DC 2222 2022 /.........9."" " 2FF3B3D0: 0000 3E7C 0000 0000 2000 9CF8 2000 9D08 ..>|.... ... ... 2FF3B3E0: 2000 A1D8 0000 0000 0000 0000 0000 0000 ............... 2FF3B3F0: 0000 0000 0024 FA90 0000 0000 0000 0000 .....$.......... ======================================================================= [000039D8].sys_call+000000 () ======================================================================= 2FF21AA0: 2FF2 2D30 0000 0000 1000 0574 0000 0000 /.-0.......t.... 2FF21AB0: 0000 0000 2000 0B14 2000 08AC 2FF2 1AE0 .... ... .../... 2FF21AC0: 0000 000E F014 992D 6F69 6365 3A20 0000 .......-oice: .. 2FF21AD0: FFFF FFFF D012 D1C0 0000 0000 0000 0000 ................ ======================================================================= [10000570]main+000280 (??, ??) ======================================================================= 2FF22D30: 0000 0000 0000 0000 1000 018C 0000 0000 ................ 2FF22D40: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 2FF22D50: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 2FF22D60: 0000 0000 0000 0000 0000 0000 0000 0000 ................ ======================================================================= [10000188]__start+000088 () The displayed data can be interpreted using the diagram presented at the first of this section. |
KDB(0)> set display_stack_frames | Toggle the display_stack_frames option off. |
KDB(0)> set display_stacked_regs | This subcommand toggles a KDB Kernel Debugger option to display the registers saved in each stack frame. |
KDB(0)> stack | Redisplay the stack with the display_stacked_regs option activated.
The display should be similar to:
thread+001800 STACK: [01304510]strlen+000010 () [013042CC]write_log+000028 (10002040, 2FF3B258, 2FF3B2BC) r30 : 00000000 r31 : 01304648 [013040B0]demokext+000070 (00000001, 2FF3B338) r30 : 00000000 r31 : 00000000 [001E3BF4]config_kmod+0000F0 (??, ??, ??) r30 : 00000005 r31 : 2FF21AF8 [001E3FA8]sysconfig+000140 (??, ??, ??) r30 : 04DAE000 r31 : 00000000 [000039D8].sys_call+000000 () [10000570]main+000280 (??, ??) r25 : DEADBEEF r26 : DEADBEEF r27 : DEADBEEF r28 : DEADBEEF r29 : DEADBEEF r30 : DEADBEEF r31 : DEADBEEF [10000188]__start+000088 () |
KDB(0)> set display_stacked_regs | Toggle the display_stacked_regs option off. |
KDB(0)> dw @r1 90 | Display the stack in raw format. Note, the address for the stack is
in general purpose register 1, so that may be used. The address could also
have been obtained from the output when the display_stack_frames option was
set. This subcommand displays 0x90 words of the stack in hex and ascii.
The output should be similar to the following:
2FF3B1C0: 2FF3B210 2FF3B380 01304364 00000000 /.../....0Cd.... 2FF3B1D0: 2FF3B230 01304754 0023AD5C 22222082 /..0.0GT.#.\"" . 2FF3B1E0: 00120000 2FF3B400 00000480 0000510C ..../.........Q. 2FF3B1F0: 2FF3B260 4A222860 001DCEC8 0000153C /..`J"(`.......< 2FF3B200: 00000000 00000000 00000000 01304648 .............0FH 2FF3B210: 2FF3B2E0 00000003 013040B4 00000000 /........0@..... 2FF3B220: 00000000 2FF3B380 10002040 2FF3B258 ..../..... @/..X 2FF3B230: 2FF3B2BC 00000000 001E5968 00000000 /.........Yh.... 2FF3B240: 00000000 002783E8 00485358 007FFFFF .....'...HSX.... 2FF3B250: 10002040 00000000 64656D6F 6B657874 .. @....demokext 2FF3B260: 20776173 2063616C 6C656420 666F7220 was called for 2FF3B270: 636F6E66 69677572 6174696F 6E0A0000 configuration... 2FF3B280: 00000000 00000000 00001000 2FF3B390 ............/... 2FF3B290: 2FF3B2E0 00040003 001CE9EC 314C0000 /...........1L.. 2FF3B2A0: 2FF3B2E0 002783E8 2FF3B338 00000000 /....'../..8.... 2FF3B2B0: 00000000 2E746578 74000000 10000100 .....text....... 2FF3B2C0: 10000100 00000710 00000100 00000000 ................ 2FF3B2D0: 00000000 2FF3B380 00000000 00000000 ..../........... 2FF3B2E0: 2FF3B370 22334484 001E3BF8 00000000 /..p"3D...;..... 2FF3B2F0: 00000000 002783E8 00000001 2FF3B338 .....'....../..8 2FF3B300: E3001E30 00000020 2FF1F9F8 2FF1F9FC ...0... /.../... 2FF3B310: 80000000 00000001 2FF1F780 00003D20 ......../.....= 2FF3B320: 2FF21AE8 00000010 01304748 00000001 /........0GH.... 2FF3B330: 2FF21AE8 00000010 2FF3B320 FFFFFFFF /......./.. .... 2FF3B340: 00000001 00000000 00000000 00000000 ................ 2FF3B350: 00000010 00001C08 00000000 00000000 ................ 2FF3B360: 00000031 82222824 00000005 2FF21AF8 ...1."($..../... 2FF3B370: 2FF3B3C0 002783E8 001E3FAC 2FF22FF8 /....'....?././. 2FF3B380: 00000002 2FF3B400 F0148912 00000FFE ..../........... 2FF3B390: 2FF3B388 0000153C 00000001 20007758 /......<.... .wX 2FF3B3A0: 00000000 000009B4 00000FFE 00000000 ................ 2FF3B3B0: 00000010 E6001800 04DAE000 00000000 ................ 2FF3B3C0: 2FF21AA0 0002D0B0 000039DC 22222022 /.........9."" " 2FF3B3D0: 00003E7C 00000000 20009CF8 20009D08 ..>|.... ... ... 2FF3B3E0: 2000A1D8 00000000 00000000 00000000 ............... 2FF3B3F0: 00000000 0024FA90 00000000 00000000 .....$.......... This portion of the stack may be interpreted using the diagram at the beginning of this section. |
KDB(0)> ca | Clear all breakpoints. |
KDB(0)> g | Exit the kernel debugger. Upon exitting the debugger the prompt from the demo program should be displayed. |
Enter choice: 0 | Enter an choice of 0 to unload the kernel extension and quit. |