[ Bottom of Page | Previous Page | Next Page | Contents | Index | Library Home | Legal | Search ]

Kernel Extensions and Device Support Programming Concepts

#! /bin/ksh
# Script to build the demo executable and the demokext kernel extension.
cc -o demo demo.c
cc -c -DEBUG -D_KERNEL -DIBMR2 demokext.c -qsource -qlist
ld -o demokext demokext.o -edemokext -bimport:/lib/syscalls.exp -bimport:/lib/kernex.exp -lcsys -bexport:demokext.exp -bmap:demokext.map

Generating Maps and Listings

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

Compiler Listing

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.

Map File

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:
DB
Debug Table. Identifies a class of sections that has the same characteristics as read only data.
GL
Glue Code. Identifies a section that has the same characteristics as a program code. This type of section has code to interface with a routine in another module. Part of the interface code requirement is to maintain TOC addressability across the call.
PR
Program Code. Identifies the sections that provide executable instructions for the module.
R0
Read Only Data. Identifies the sections that contain constants that are not modified during execution.
TB
Reserved.
TI
Reserved.
XO
Extended Op. Identifies a section of code that is to be treated as a pseudo-machine instruction.
.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:
DS
Descriptor. Identifies a function descriptor. This information is used to describe function pointers in languages such as C and Fortran.
RW
Read Write Data. Identifies a section that contains data that is known to require change during execution.
SV
SVC. Identifies a section of code that is to be treated as a supervisory call.
T0
TOC Anchor. Used only by the predefined TOC symbol. Identifies the special symbol TOC. Used only by the TOC header.
TC
TOC Entry. Identifies address data that will reside in the TOC.
TD
TOC Data Entry. Identifies data that will reside in the TOC.
UA
Unclassified. Identifies data that contains data of an unknown storage class.
.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:
BS
BSS class. Identifies a section that contains uninitialized data.
UC
Unnamed Fortran Common. Identifies a section that contains read write data.

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-FILE(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 Breakpoints

The KDB Kernel Debugger creates a table of breakpoints that it maintains. When a breakpoint is set, the debugger temporarily replaces the corresponding instruction with the trap instruction. The instruction overlaid by the breakpoint operates when you issue any subcommand that would cause that instruction to be initiated.

For more information on setting or clearing breakpoints and execution control, see Breakpoints and Steps Subcommands.

Setting a breakpoint is essential for debugging kernel extensions. To set a breakpoint, use the following sequence of steps:

  1. Locate the assembler instruction corresponding to the C statement.
  2. Get the offset of the assembler instruction from the listing.
  3. Locate the address where the kernel extension is loaded.
  4. Add the address of the assembler instruction to the address where kernel extension is loaded.
  5. Set the breakpoint with the KDB b (break) subcommand.

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.

Determine the Location of your Kernel Extension

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.

The following examples use the demo and demokext routines compiled earlier.

Note
The following must be run as the root user. For these examples, assume that a break is to be set at line 67, which has an offset from the beginning of demokext of 0xE0.

To load the demokext kernel extension:

  1. Run the demo program by typing ./demo on the command line. This loads the demokext extension. Take note of the value printed for kmid, this is used later in this example.
    Note
    The default prompt at this time is $.
  2. Stop the demo program by entering Ctrl+Z on the keyboard.
  3. Put the demo program in the background by typing bg on the command line.
  4. Activate KDB using the appropriate key sequence for your configuration. You should have a KDB prompt on completion of this step.
    Note
    The default KDB propmt is KDB(0)>.

To unload the demokext kernel extension:

  1. At the $ prompt, bring the demo program to the foreground by typing fg on the command line. At this point, the prompt changes to ./demo.
  2. Enter 0 to unload and exit, 1 to increment counters, or 2 decrement counters. The prompt will not be redisplayed, because it was shown prior to stopping the program and placing it in the background. For the purposes of this example, enter 0 to indicate that the kernel extension is to be unloaded and that the demo program is to terminate.

Method 1: Using the b Subcommand

Normally, with the KDB Kernel Debugger a breakpoint can 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 subroutine.

Note
The default prompt is KDB(0)>.
  1. 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. To do this, type the following on the command line:
    b demokext+E0
  2. To view the list all active breakpoints type b on the command line.
  3. To clear the list all active breakpoints ca on the command line.
  4. To verfiy that there are no longer any active breakpoints type b on the command line.

Method 2: Using the lke Subcommand

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.

Note
The default prompt is KDB(0)>.
  1. List all loaded extensions by typing lke on the command line. The results should be similar to the following:
       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. Pressing Enter displays the next page of data; pressing the Spacebar displays the next line of data. The number of lines per page can be changed yb typing set screen_size nn on the command line; where nn is the number of lines per page.
  2. 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. To display information for slot 1, type the following on the command line:
    lke 1
    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.
  3. Set the break at the desired location, by typing the following on the command line:
    b 01304040+e0
    KDB dispalys the address at which the breakpoint is located.
  4. Clear all breakpoints by typing:
    ca

Method 3: Using the nm demokext Subcommand

If the kernel extension is not stripped, the KDB Kernel Debugger can be used to locate the address of the load point by name. For example, the nm demokext subcommand returns the address of the demokext routine after it is loaded. This address may then be used to set a breakpoint.

Note
The default prompt is KDB(0)>.
  1. To translate a symbol to an effective address, type the following on the command line:
    nm demokext
    The output will be similar to the following:
    Symbol Address : 01304040
       TOC Address : 013046D4
    The value of the symbol demokext is the address of the first instruction of the demokext routine. This value can be used to set a breakpoint.
  2. Set the break at the desired location by typing:
    b 01304040+e0
    KDB displays the address at which the breakpoint is set.
  3. Display the word at the breakpoint by typing:
    dw 01304040+e0
    The results will look similar to the following:
    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 to the correct location.
  4. Clear all breakpoints by typing:
    ca

Method 4: Using the kmid Pointer

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.

Note
The default prompt is KDB(0)>.
  1. Display the memory at the address returned as the kmid from the sysconfig subroutine at the beginning of this example, by typing:
    dw 1304748
    KDB responds with something similar to:
    demokext+000000: 01304040 01304754 00000000 01304648  .0@@.0GT.....0FH
    The 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.
  2. 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.
    b 01304040+e0
  3. Clear all breakpoints, by typing:
    ca

Method 5: Using the devsw Subcommand

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 subroutine will be the load point routine. For example,

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
Note
The default prompt is KDB(0)>.

To set a breakpoint:

  1. Display the device switch table for the first entry, by typing:
    devsw 1
    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
    Note
    The demonstration program that is being used is not a device driver; so this example uses the addresses of the first device driver in the device switch table and is not related in any way to the demonstration program.
  2. 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, by typing:
    b .syopen+20
    KDB displays the location of the break.
  3. Clear all breakpoints:
    ca
  4. Turn off symbolic name translation:
    ns
  5. Display the device switch table for the first device driver again:
    devsw 1
    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
  6. 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, by typing:
    b 00208858+20
    This will set the same break that was set at the beginning of this example. KDB displays the location of the break.
  7. Toggle symbolic name translation on:
    ns
  8. Clear all breaks:
    ca
  9. Exit the KDB Kernel Debugger and let the system resume normal execution, by typing:
    g

Viewing and Modifying Global Data

Global data can be accessed using several methods. The demo and demokext programs continue to be used in the examples 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.

Before trying any of the following examples, use the following procedure to load the demokext kernel extension:

  1. Run the demo program by typing ./demo on the command line. This loads the demokext extension.
    Note
    The default prompt at this time is $.
  2. Stop the demo program by entering Ctrl+Z on the keyboard.
  3. Put the demo program in the background by typing bg on the command line.
  4. Activate KDB using the appropriate key sequence for your configuration. You should have a KDB prompt on completion of this step.
    Note
    The default KDB propmt is KDB(0)>.

Method 1: Using the dw Subcommand

Access of global variables within KDB is very simple. The variables can be accessed directly by name. For example, the dw demokext_j subcommand can be used to display the value of demokext_j. If demokext_j is an array, a specific value can 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.

Note
The default prompt is KDB(0)>.
  1. Display a word at the address of the demokext_j variable:
    dw demokext_j
    Because 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....
  2. Turn off symbolic name translation:
    ns
  3. To display the word at the address of the demokext_j variable, type:
    dw demokext_j
    With symbolic name translation turned off, the data displayed should be similar to:
    01304744: 00000063 01304040 01304754 00000000  ...c.0@@.0GT....
  4. Turn symbolic name translation on, by typing:
    ns
  5. Modify the word at the address of the demokext_j variable by typing:
    mw demokext_j
    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 similar to the following:
    01304744:  00000063  =
    A new value can now 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. To complete this step, enter a value of 64 (100 decimal) for the first address and then enter a period to end modification.

Method 2: Using the TOC and Map File

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 can be accomplished by setting a breakpoint within the kernel extension. For more information, see Setting Breakpoints.

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 can 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 can be examined to determine the address of the data.

For 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.

To find the address of the demokext_j data complete the following:

  1. Calculate the offset from the beginning of the TOC to the TOC entry for demokext_j. From the map file, the TOC starts at 0x0000010C and the TOC entry for demokext_j is at 0x00000114. Therefore, the offset from the beginning of the TOC to the entry of interest is:
    0x00000114 - 0x0000010C = 0x00000008
  2. Calculate the address of the TOC entry for demokext_j. This is the current value of general purpose register 2 plus the offset calculated in the preceding step:
    0x01304754 + 0x00000008 = 0x0130475C
  3. Display the data at 0x0130475C. The data displayed is the address of the data for demokext_j.

To view and modify global data:

  1. At the KDB(0) prompt, set a break at line 67 of the demokext routine (see the examples in the previous section), by typing:
    b demokext+e0
    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.
  2. Exit the KDB Kernel Debugger by typing g on the command line. 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.
    Note
    At this point, the prompt changes to a dollar sign ($).
  3. Bring the demo program to the foreground by typing:
    fg
    Note
    At this point, the prompt changes to ./demo.
  4. 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 and the prompt to change to KDB(0).
  5. Display the general purpose registers by typing:
    dr
    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 : 01304648
    Using 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.
  6. Display the TOC entry for demokext_j by typing:
    dw 0130475C
    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.
  7. Display the data for demokext_j by typing:
    dw 01304744
    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....
  8. Clear all breakpoints:
    ca
  9. Exit the kernel debugger by typing g on the command line. 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.
  10. Enter Ctrl+Z to stop the demo program. At this point the prompt changes to a dollar sign ($).
  11. Place the demo program in the background by typing:
    bg

Method 3: Using the Map File

Unlike the procedure outlined in method 2, this method can be used at any time. This method requires that 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, this method might not work if the procedure for loading a kernel extension changes.

This method relies on the assumption that the address of a global variable can be found by using the following 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
In Method 2, 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 accessing global data when using the KDB Kernel Debugger. The other methods are described to show alternatives and to allow the use of additional KDB subcommands in the following examples.

To view global data:

  1. Activate KDB, use the appropriate key sequence for your configuration. You should have a KDB prompt on completion of this step.
  2. Display the data for the demokext_j variable by typing:
    dw demokext+704
    The 704 value is calculated from the map using the procedure listed above. 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 it is easiest to use the symbolic name. For other methods, see Setting Breakpoints. 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....
  3. Exit the KDB Kernel Debugger by typing g on the command line. At this point, the prompt changes to a dollar sign ($).
  4. Bring the demo program to the foreground:
    fg
    At this point, the prompt changes to ./demo.
  5. Enter 0 to unload the demokext kernel extension and exit.

Stack Trace

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. This time a break will be set in the write_log routine.

Before trying any of the following examples, use the following procedure to load the demokext kernel extension:

  1. Run the demo program by typing ./demo on the command line. This loads the demokext extension.
    Note
    The default prompt at this time is $.
  2. Stop the demo program by entering Ctrl+Z on the keyboard.
  3. Put the demo program in the background by typing bg on the command line.
  4. Activate KDB using the appropriate key sequence for your configuration. You should have a KDB prompt on completion of this step.
    Note
    The default KDB propmt is KDB(0)>.

To set and execute to a breakpoint in write_log:

  1. Set a break at line 117 of demokext.c; this is the first line of write_log by typing:
    b demokext+280
    Note
    The offset of 0x00000280 was determined from the list file as described in earlier sections.
  2. Exit the KDB Kernel Debugger by typing g on the command line. At this point the default prompt becomes a $.
  3. Bring the demo program to the foreground:
    fg
    At this point the default prompt changes to ./demo.
  4. 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.

To view the stack:

  1. Display the stack for the current process, which was the the demo program calling the demokext kernel extension (since there was a break set), by typing:
    stack
    The stack trace back displays the routines called and 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 ()
  2. To step back 4 instructions, type:
    s 4
    This should get into a strlen call. If it doesn't, continue stepping until strlen is entered.
  3. Reexamine the stack by typing:
    stack
    It should now include the strlen call and should look 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 ()
  4. Toggle the KDB Kernel Debugger option to display the top (lower addresses) 64 bytes for each stack frame by typing:
    set display_stack_frames
  5. Redisplay the stack with the display_stack_frames option turned on by typing:
    stack
    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.
  6. Toggle the display_stack_frames option off by typing:
    set display_stack_frames
  7. Toggle the KDB Kernel Debugger option to display the registers saved in each stack frame by typing:
    set display_stacked_regs
  8. Redisplay the stack with the display_stacked_regs option activated by typing:
    stack
    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 ()
  9. Toggle the display_stacked_regs option off by typing:
    set display_stacked_regs
  10. Display the stack in raw format by typing:
    dw @r1 90
    Note
    The address for the stack is in general purpose register 1, so that can 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.
  11. Clear all breakpoints by typing:
    ca
  12. Exit the kernel debugger by typing g on the command line. Upon exitting the debugger the prompt from the demo program is be displayed. The default prompt is ./demo.
  13. Enter an choice of 0 to unload the kernel extension and quit.

[ Top of Page | Previous Page | Next Page | Contents | Index | Library Home | Legal | Search ]