Pages

Thursday, May 11, 2006

AIX Kernel Debug - II

After a not so brief hiatus, I am back. Exams got over recently, and now I have a bit of free time to update the kernel debugging notes. So this one is about viewing kernel data using kdb.

The AIX kdb pages [link] list three different ways in which you can view kernel data from userspace. If its global data, and has been duly exported with a .exp file at link time, then its as simple as using the variable name. However, since global data is not usually exported this way, and we do not want to recompile a module just to debug, we would look at the other options.

Both the other methods require using a mapfile. A mapfile is a list of symbols in the kernel module, and their addresses (only relative), that can be generated while linking the module ( using the -bloadmap:{mapfile} option.)

Once that is done, this is how a mapfile looks like

*IE ADDRESS LENGTH AL CL TY Sym# NAME SOURCE-FILE(OBJECT) or IMPORT-FILE{SHARED-OBJECT}
--- -------- ------ -- -- -- ----- ------------------------- -------------------------------------------------
I ER S1 getgidx /lib/syscalls.exp{/unix}
I ER S2 getuidx /lib/syscalls.exp{/unix}
I ER S3 _system_configuration /lib/syscalls.exp{/unix}
...
...
000007A4 PR LD S58 <.qlog_write>
000007E4 PR LD S59 .qlog_disable_console_logging
00000824 PR LD S60 .qlog_enable_console_logging
00000864 PR LD S61 .qlog_get_log_types
...
... 000033DC 000004 2 TC SD S506 <> 000033E0 0001EC 3 RW CM S507 g_qlog_cntl qlog.c(qlib.lib) 000035CC 000004 2 RW CM S508 kern_config kernel_config.c(kconf.lib) 000035D0 00002C 3 RW CM S509 <_$static_bss> sc_dnlc.c(dnlc.lib)
000035FC 000004 2 RW CM S510 workflow_id kernel_config.c(kconf.lib)


Understandably, there are several classes of symbols in this file, indicating program code, glues, readonly and readwrite data. The PR LD or the GL LD class indicates program code or glue code, and is the text segment. The offsets that appear here are relative to the offset of the program entry point, which you specified as -binit:{ entrypoint } while linking.

So if you know the load address of the entry point, you can calculate the addresses for each function. And the lke command lets you do that, in kdb

(0)> lke
ADDRESS FILE FILESIZE FLAGS MODULE NAME

1 024F8000 02A1C000 0000F6E0 00000242 /usr/local/solidcore/s3/modules/scdrv
2 024F8F00 029D6000 00009348 00000252 random32/usr/lib/drivers/random
3 0219DF00 029B6000 000009AC 00100248 /unix
4 024F8E00 0286A000 001229D0 00000252 nfs.ext32/usr/lib/drivers/nfs.ext


So to find out where scdrv loads, Use the number that appears in the first coloum

(0)> lke 1
ADDRESS FILE FILESIZE FLAGS MODULE NAME

1 024F8000 02A1C000 0000F6E0 00000242 /usr/local/solidcore/s3/modules/scdrv
le_flags....... TEXT DATA DATAEXISTS
le_next........ 024F8F00 le_lex......... 00000000
le_fp.......... 00000000 le_fh.......... 00000000
le_file........ 02A1C000 le_filesize.... 0000F6E0
le_data........ 02A280D8 le_datasize.... 00003608
le_ldr......... 02A2C000 le_ldr_size.... 0x1141 (4417)
le_exports..... 00000000 le_entrypoint.. 02A2B268
le_usecount.... 1 le_loadcount... 1
le_ndepend..... 1 le_maxdepend... 1
le_filename.... 024F8060 le_depend.... @ 024F805C
TOC@........... 02A2B34C
process trace backs
.scdrv 02A1C160 .scdrv_fini 02A1C2A0

This address, when added to the relative addresses in the map file, gives us the load location of the functions.