This article introduces common methods for manually debugging kernel bugs based on your own practices and online articles.
1. Steps
1). Collect oops output, system. Map,/proc/ksyms, vmlinux,/proc/modules
2). Use ksymoops to interpret oops
Instructions is/usr/src/Linux/documentation/oops-tracing.txt
Ksymoops (8) man page (http://www.die.net/doc/linux/man/man8/ksymoops.8.html)
2. Simple Analysis
1) ksymoops disassembles the Code Section
2) The EIP points to the failing instruction
3) The Call trace section shows how you got there
Caution: noise on the stack?
3. Locate the error code
Oops example
C source code
Int test_read_proc (char * Buf, char ** start, off_t offset, int count, int * EOF, void * Data)
{Int * PTR; PTR = 0; printk ("% d/N", * PTR );
Return 0;
}
Write a kernel module program test. C and use the above code to create a file under/proc.
This function is called when the file is read to generate the following Oops:
Unable to handle kernel Null Pointer Dereference at virtual address 00000000
C2483069 <--- EIP (instruction pointer or program counter)
* PVDF = 00000000
Oops: 0000
CPU:
0
EIP: 0010: [IPv6 :__ insmod_00006_o/lib/modules/2.4.10-4 GB/kernel/NET/IPv6
IPv6 ++ 472895383/96]
Eflags: 00010283
Eax: db591f98 EBX: de2aeb60 ECx: de2aeb80 edX: c2483060
ESI: 00000c00 EDI: d41d0000 EBP: db591f5c ESP: db591f4c
DS: 0018 ES: 0018 SS: 0018
Process CAT (PID: 1986, stackpage = db591000)
STACK: c012ca65 000001f0 ffffffea 00000000 00001000 c014e878 d41d0000 db591f98
00000000 00000c00 db591f94 00000000 de2aeb60 ffffffea 00000000 00001000
Deae6f40 00000000 00000000 00000000 c01324d6 de2aeb60 0804db50 00001000
Call trace: [_ alloc_pages + 65/452] [proc_file_read + 204/420] [sys_read + 146/200]
[System_call + 51/64]
Code: A1 00 00 00 00 50 68 10 31 48 C2 E8 67 38 C9 FD 31 C0 89 EC
Use ksysmoops to obtain the function address of the inland river. (You can also read the/proc/kallsym or/proc/ksyms file to check the function address of the export)
Using defaults from ksymoops-T elf32-i386-A i386
Code; 00000000 before first symbol
00000000 <_ EIP>
:
Code; 00000000 before first symbol
0: A1 00 00 00 mov 0x0, % eax
Code; 00000004 before first symbol
5: 50 push % eax
Code; 00000006 before first symbol
6: 68 10 31 48 C2 push $0xc2483110
Code; 0000000a before first symbol
B: E8 67 38 C9 FD call fdc93877
<_ EIP + 0xfdc93877> fdc93876 <end_of_code + 1e1fa3d8/???>
Code; 00000010 before first symbol
10: 31 C0 XOR % eax, % eax
Code; 00000012 before first symbol
12: 89 EC mov % EBP, % ESP
C2483060 test_read_proc [test]
C2483000 _ insmod_test_o/home/Ross/prog/test. o_m3 [test]
C2483110 _ insmod_test_s.rodata_l68 [test]
C2483060 _ insmod_test_s.text_l176 [test]
C2483080 Foo [test]
De79c340 ip6_frag_mem [IPv6]
De783d00 addrconf_del_ifaddr [IPv6]
De78a5bc ipv6_packet_init [IPv6]
De78fd70 ipv6_sock_mc_drop [IPv6]
De781ee4 ip6_call_ra_chain [IPv6]
It can be seen that the EIP c2483069 is in the test_read_proc function of the [test] module.
(EIP)-(base ADDR of routine)
C2483069-c2483060 = 9
Next, disassemble test. O and find the code error line with the offset of 9.
Find the error code and use objdump:
Excerpt from "objdump-d test. O"
Test. O:
File
Format elf32-i386
Disassembly of section. Text:
00000000 <test_read_proc>:
0: 55 push % EBP
1: 89 E5 mov % ESP, % EBP
3: 83 EC 08 Sub $0x8, % ESP
6: 83 C4 F8 add $0xfffffff8, % ESP
9: A1 00 00 00 00 mov 0x0, % eax
E: 50 push % eax
F: 68 00 00 00 push $0x0
C source code
Int test_read_proc (char * Buf, char ** start, off_t offset, int count, int * EOF, void * Data)
{Int * PTR; PTR = 0; printk ("% d/N", * PTR );
Return 0;
}