← Documents Documentation/admin-guide/bug-hunting.rst GitHub 원문 ↗

Linux 6.18.37 · Administration / Bug diagnosis

Bug hunting

Kernel Oops 확보와 GDB·objdump source lookup, report routing, klogd static·dynamic symbol resolution을 설명합니다.

Source pathDocumentation/admin-guide/bug-hunting.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

Capture and locate an Oops

bug-hunting.rst:1-240

Stack trace를 확보하고 debug info·GDB·objdump·decodecode로 source line을 찾습니다.

Report or fix

bug-hunting.rst:241-297

get_maintainer.pl로 report channel을 찾고 upstream patch 절차를 따릅니다.

klogd symbol resolution

bug-hunting.rst:298-370

System.map 기반 static translation과 module-layout 기반 dynamic translation을 설명합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 Bug hunting
2 ===========
3
4 Kernel bug reports often come with a stack dump like the one below::
5
6 ------------[ cut here ]------------
7 WARNING: CPU: 1 PID: 28102 at kernel/module.c:1108 module_put+0x57/0x70
8 Modules linked in: dvb_usb_gp8psk(-) dvb_usb dvb_core nvidia_drm(PO) nvidia_modeset(PO) snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd soundcore nvidia(PO) [last unloaded: rc_core]
9 CPU: 1 PID: 28102 Comm: rmmod Tainted: P WC O 4.8.4-build.1 #1
10 Hardware name: MSI MS-7309/MS-7309, BIOS V1.12 02/23/2009
11 00000000 c12ba080 00000000 00000000 c103ed6a c1616014 00000001 00006dc6
12 c1615862 00000454 c109e8a7 c109e8a7 00000009 ffffffff 00000000 f13f6a10
13 f5f5a600 c103ee33 00000009 00000000 00000000 c109e8a7 f80ca4d0 c109f617
14 Call Trace:
15 [<c12ba080>] ? dump_stack+0x44/0x64
16 [<c103ed6a>] ? __warn+0xfa/0x120
17 [<c109e8a7>] ? module_put+0x57/0x70
18 [<c109e8a7>] ? module_put+0x57/0x70
19 [<c103ee33>] ? warn_slowpath_null+0x23/0x30
20 [<c109e8a7>] ? module_put+0x57/0x70
21 [<f80ca4d0>] ? gp8psk_fe_set_frontend+0x460/0x460 [dvb_usb_gp8psk]
22 [<c109f617>] ? symbol_put_addr+0x27/0x50
23 [<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]
24 [<f80bb3bf>] ? dvb_usb_exit+0x2f/0xd0 [dvb_usb]
25 [<c13d03bc>] ? usb_disable_endpoint+0x7c/0xb0
26 [<f80bb48a>] ? dvb_usb_device_exit+0x2a/0x50 [dvb_usb]
27 [<c13d2882>] ? usb_unbind_interface+0x62/0x250
28 [<c136b514>] ? __pm_runtime_idle+0x44/0x70
29 [<c13620d8>] ? __device_release_driver+0x78/0x120
30 [<c1362907>] ? driver_detach+0x87/0x90
31 [<c1361c48>] ? bus_remove_driver+0x38/0x90
32 [<c13d1c18>] ? usb_deregister+0x58/0xb0
33 [<c109fbb0>] ? SyS_delete_module+0x130/0x1f0
34 [<c1055654>] ? task_work_run+0x64/0x80
35 [<c1000fa5>] ? exit_to_usermode_loop+0x85/0x90
36 [<c10013f0>] ? do_fast_syscall_32+0x80/0x130
37 [<c1549f43>] ? sysenter_past_esp+0x40/0x6a
38 ---[ end trace 6ebc60ef3981792f ]---
39
40 Such stack traces provide enough information to identify the line inside the
41 Kernel's source code where the bug happened. Depending on the severity of
42 the issue, it may also contain the word **Oops**, as on this one::
43
44 BUG: unable to handle kernel NULL pointer dereference at (null)
45 IP: [<c06969d4>] iret_exc+0x7d0/0xa59
46 *pdpt = 000000002258a001 *pde = 0000000000000000
47 Oops: 0002 [#1] PREEMPT SMP
48 ...
49
50 Despite being an **Oops** or some other sort of stack trace, the offended
51 line is usually required to identify and handle the bug. Along this chapter,
52 we'll refer to "Oops" for all kinds of stack traces that need to be analyzed.
53
54 If the kernel is compiled with ``CONFIG_DEBUG_INFO``, you can enhance the
55 quality of the stack trace by using file:`scripts/decode_stacktrace.sh`.
56
57 Modules linked in
58 -----------------
59
60 Modules that are tainted or are being loaded or unloaded are marked with
61 "(...)", where the taint flags are described in
62 file:`Documentation/admin-guide/tainted-kernels.rst`, "being loaded" is
63 annotated with "+", and "being unloaded" is annotated with "-".
64
65
66 Where is the Oops message is located?
67 -------------------------------------
68
69 Normally the Oops text is read from the kernel buffers by klogd and
70 handed to ``syslogd`` which writes it to a syslog file, typically
71 ``/var/log/messages`` (depends on ``/etc/syslog.conf``). On systems with
72 systemd, it may also be stored by the ``journald`` daemon, and accessed
73 by running ``journalctl`` command.
74
75 Sometimes ``klogd`` dies, in which case you can run ``dmesg > file`` to
76 read the data from the kernel buffers and save it. Or you can
77 ``cat /proc/kmsg > file``, however you have to break in to stop the transfer,
78 since ``kmsg`` is a "never ending file".
79
80 If the machine has crashed so badly that you cannot enter commands or
81 the disk is not available then you have three options:
82
83 (1) Hand copy the text from the screen and type it in after the machine
84 has restarted. Messy but it is the only option if you have not
85 planned for a crash. Alternatively, you can take a picture of
86 the screen with a digital camera - not nice, but better than
87 nothing. If the messages scroll off the top of the console, you
88 may find that booting with a higher resolution (e.g., ``vga=791``)
89 will allow you to read more of the text. (Caveat: This needs ``vesafb``,
90 so won't help for 'early' oopses.)
91
92 (2) Boot with a serial console (see
93 :ref:`Documentation/admin-guide/serial-console.rst <serial_console>`),
94 run a null modem to a second machine and capture the output there
95 using your favourite communication program. Minicom works well.
96
97 (3) Use Kdump (see Documentation/admin-guide/kdump/kdump.rst),
98 extract the kernel ring buffer from old memory with using dmesg
99 gdbmacro in Documentation/admin-guide/kdump/gdbmacros.txt.
100
101 Finding the bug's location
102 --------------------------
103
104 Reporting a bug works best if you point the location of the bug at the
105 Kernel source file. There are two methods for doing that. Usually, using
106 ``gdb`` is easier, but the Kernel should be pre-compiled with debug info.
107
108 gdb
109 ^^^
110
111 The GNU debugger (``gdb``) is the best way to figure out the exact file and line
112 number of the OOPS from the ``vmlinux`` file.
113
114 The usage of gdb works best on a kernel compiled with ``CONFIG_DEBUG_INFO``.
115 This can be set by running::
116
117 $ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO
118
119 On a kernel compiled with ``CONFIG_DEBUG_INFO``, you can simply copy the
120 EIP value from the OOPS::
121
122 EIP: 0060:[<c021e50e>] Not tainted VLI
123
124 And use GDB to translate that to human-readable form::
125
126 $ gdb vmlinux
127 (gdb) l *0xc021e50e
128
129 If you don't have ``CONFIG_DEBUG_INFO`` enabled, you use the function
130 offset from the OOPS::
131
132 EIP is at vt_ioctl+0xda8/0x1482
133
134 And recompile the kernel with ``CONFIG_DEBUG_INFO`` enabled::
135
136 $ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO
137 $ make vmlinux
138 $ gdb vmlinux
139 (gdb) l *vt_ioctl+0xda8
140 0x1888 is in vt_ioctl (drivers/tty/vt/vt_ioctl.c:293).
141 288 {
142 289 struct vc_data *vc = NULL;
143 290 int ret = 0;
144 291
145 292 console_lock();
146 293 if (VT_BUSY(vc_num))
147 294 ret = -EBUSY;
148 295 else if (vc_num)
149 296 vc = vc_deallocate(vc_num);
150 297 console_unlock();
151
152 or, if you want to be more verbose::
153
154 (gdb) p vt_ioctl
155 $1 = {int (struct tty_struct *, unsigned int, unsigned long)} 0xae0 <vt_ioctl>
156 (gdb) l *0xae0+0xda8
157
158 You could, instead, use the object file::
159
160 $ make drivers/tty/
161 $ gdb drivers/tty/vt/vt_ioctl.o
162 (gdb) l *vt_ioctl+0xda8
163
164 If you have a call trace, such as::
165
166 Call Trace:
167 [<ffffffff8802c8e9>] :jbd:log_wait_commit+0xa3/0xf5
168 [<ffffffff810482d9>] autoremove_wake_function+0x0/0x2e
169 [<ffffffff8802770b>] :jbd:journal_stop+0x1be/0x1ee
170 ...
171
172 this shows the problem likely is in the :jbd: module. You can load that module
173 in gdb and list the relevant code::
174
175 $ gdb fs/jbd/jbd.ko
176 (gdb) l *log_wait_commit+0xa3
177
178 .. note::
179
180 You can also do the same for any function call at the stack trace,
181 like this one::
182
183 [<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]
184
185 The position where the above call happened can be seen with::
186
187 $ gdb drivers/media/usb/dvb-usb/dvb-usb.o
188 (gdb) l *dvb_usb_adapter_frontend_exit+0x3a
189
190 objdump
191 ^^^^^^^
192
193 To debug a kernel, use objdump and look for the hex offset from the crash
194 output to find the valid line of code/assembler. Without debug symbols, you
195 will see the assembler code for the routine shown, but if your kernel has
196 debug symbols the C code will also be available. (Debug symbols can be enabled
197 in the kernel hacking menu of the menu configuration.) For example::
198
199 $ objdump -r -S -l --disassemble net/ipv4/tcp.o
200
201 .. note::
202
203 You need to be at the top level of the kernel tree for this to pick up
204 your C files.
205
206 If you don't have access to the source code you can still debug some crash
207 dumps using the following method (example crash dump output as shown by
208 Dave Miller)::
209
210 EIP is at +0x14/0x4c0
211 ...
212 Code: 44 24 04 e8 6f 05 00 00 e9 e8 fe ff ff 8d 76 00 8d bc 27 00 00
213 00 00 55 57 56 53 81 ec bc 00 00 00 8b ac 24 d0 00 00 00 8b 5d 08
214 <8b> 83 3c 01 00 00 89 44 24 14 8b 45 28 85 c0 89 44 24 18 0f 85
215
216 Put the bytes into a "foo.s" file like this:
217
218 .text
219 .globl foo
220 foo:
221 .byte .... /* bytes from Code: part of OOPS dump */
222
223 Compile it with "gcc -c -o foo.o foo.s" then look at the output of
224 "objdump --disassemble foo.o".
225
226 Output:
227
228 ip_queue_xmit:
229 push %ebp
230 push %edi
231 push %esi
232 push %ebx
233 sub $0xbc, %esp
234 mov 0xd0(%esp), %ebp ! %ebp = arg0 (skb)
235 mov 0x8(%ebp), %ebx ! %ebx = skb->sk
236 mov 0x13c(%ebx), %eax ! %eax = inet_sk(sk)->opt
237
238 file:`scripts/decodecode` can be used to automate most of this, depending
239 on what CPU architecture is being debugged.
240
241 Reporting the bug
242 -----------------
243
244 Once you find where the bug happened, by inspecting its location,
245 you could either try to fix it yourself or report it upstream.
246
247 In order to report it upstream, you should identify the bug tracker, if any, or
248 mailing list used for the development of the affected code. This can be done by
249 using the ``get_maintainer.pl`` script.
250
251 For example, if you find a bug at the gspca's sonixj.c file, you can get
252 its maintainers with::
253
254 $ ./scripts/get_maintainer.pl --bug -f drivers/media/usb/gspca/sonixj.c
255 Hans Verkuil <hverkuil@kernel.org> (odd fixer:GSPCA USB WEBCAM DRIVER,commit_signer:1/1=100%)
256 Mauro Carvalho Chehab <mchehab@kernel.org> (maintainer:MEDIA INPUT INFRASTRUCTURE (V4L/DVB),commit_signer:1/1=100%)
257 Tejun Heo <tj@kernel.org> (commit_signer:1/1=100%)
258 Bhaktipriya Shridhar <bhaktipriya96@gmail.com> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:4/4=100%,removed_lines:9/9=100%)
259 linux-media@vger.kernel.org (open list:GSPCA USB WEBCAM DRIVER)
260 linux-kernel@vger.kernel.org (open list)
261
262 Please notice that it will point to:
263
264 - The last developers that touched the source code (if this is done inside
265 a git tree). On the above example, Tejun and Bhaktipriya (in this
266 specific case, none really involved on the development of this file);
267 - The driver maintainer (Hans Verkuil);
268 - The subsystem maintainer (Mauro Carvalho Chehab);
269 - The driver and/or subsystem mailing list (linux-media@vger.kernel.org);
270 - The Linux Kernel mailing list (linux-kernel@vger.kernel.org);
271 - The bug reporting URIs for the driver/subsystem (none in the above example).
272
273 If the listing contains bug reporting URIs at the end, please prefer them over
274 email. Otherwise, please report bugs to the mailing list used for the
275 development of the code (linux-media ML) copying the driver maintainer (Hans).
276
277 If you are totally stumped as to whom to send the report, and
278 ``get_maintainer.pl`` didn't provide you anything useful, send it to
279 linux-kernel@vger.kernel.org.
280
281 Thanks for your help in making Linux as stable as humanly possible.
282
283 Fixing the bug
284 --------------
285
286 If you know programming, you could help us by not only reporting the bug,
287 but also providing us with a solution. After all, open source is about
288 sharing what you do and don't you want to be recognised for your genius?
289
290 If you decide to take this way, once you have worked out a fix please submit
291 it upstream.
292
293 Please do read
294 :ref:`Documentation/process/submitting-patches.rst <submittingpatches>` though
295 to help your code get accepted.
296
297
298 ---------------------------------------------------------------------------
299
300 Notes on Oops tracing with ``klogd``
301 ------------------------------------
302
303 In order to help Linus and the other kernel developers there has been
304 substantial support incorporated into ``klogd`` for processing protection
305 faults. In order to have full support for address resolution at least
306 version 1.3-pl3 of the ``sysklogd`` package should be used.
307
308 When a protection fault occurs the ``klogd`` daemon automatically
309 translates important addresses in the kernel log messages to their
310 symbolic equivalents. This translated kernel message is then
311 forwarded through whatever reporting mechanism ``klogd`` is using. The
312 protection fault message can be simply cut out of the message files
313 and forwarded to the kernel developers.
314
315 Two types of address resolution are performed by ``klogd``. The first is
316 static translation and the second is dynamic translation.
317 Static translation uses the System.map file.
318 In order to do static translation the ``klogd`` daemon
319 must be able to find a system map file at daemon initialization time.
320 See the klogd man page for information on how ``klogd`` searches for map
321 files.
322
323 Dynamic address translation is important when kernel loadable modules
324 are being used. Since memory for kernel modules is allocated from the
325 kernel's dynamic memory pools there are no fixed locations for either
326 the start of the module or for functions and symbols in the module.
327
328 The kernel supports system calls which allow a program to determine
329 which modules are loaded and their location in memory. Using these
330 system calls the klogd daemon builds a symbol table which can be used
331 to debug a protection fault which occurs in a loadable kernel module.
332
333 At the very minimum klogd will provide the name of the module which
334 generated the protection fault. There may be additional symbolic
335 information available if the developer of the loadable module chose to
336 export symbol information from the module.
337
338 Since the kernel module environment can be dynamic there must be a
339 mechanism for notifying the ``klogd`` daemon when a change in module
340 environment occurs. There are command line options available which
341 allow klogd to signal the currently executing daemon that symbol
342 information should be refreshed. See the ``klogd`` manual page for more
343 information.
344
345 A patch is included with the sysklogd distribution which modifies the
346 ``modules-2.0.0`` package to automatically signal klogd whenever a module
347 is loaded or unloaded. Applying this patch provides essentially
348 seamless support for debugging protection faults which occur with
349 kernel loadable modules.
350
351 The following is an example of a protection fault in a loadable module
352 processed by ``klogd``::
353
354 Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
355 Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
356 Aug 29 09:51:01 blizard kernel: *pde = 00000000
357 Aug 29 09:51:01 blizard kernel: Oops: 0002
358 Aug 29 09:51:01 blizard kernel: CPU: 0
359 Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
360 Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
361 Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
362 Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
363 Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
364 Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
365 Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
366 Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
367 Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
368 Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
369 Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
370
371

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

Stack trace와 Oops 판독

1-65

Kernel bug report에는 다음과 같은 stack dump가 자주 포함됩니다. 첫 줄은 warning이 발생한 source path·line과 `module_put+0x57/0x70`처럼 function 안의 offset/전체 function 길이를 보여 주고, 이어서 loaded module, CPU·PID·taint, hardware, call trace가 나옵니다.

Kernel bug reports often come with a stack dump like the one below::

	------------[ cut here ]------------
	WARNING: CPU: 1 PID: 28102 at kernel/module.c:1108 module_put+0x57/0x70
	Modules linked in: dvb_usb_gp8psk(-) dvb_usb dvb_core nvidia_drm(PO) nvidia_modeset(PO) snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd soundcore nvidia(PO) [last unloaded: rc_core]
	CPU: 1 PID: 28102 Comm: rmmod Tainted: P        WC O 4.8.4-build.1 #1
	Hardware name: MSI MS-7309/MS-7309, BIOS V1.12 02/23/2009
	 00000000 c12ba080 00000000 00000000 c103ed6a c1616014 00000001 00006dc6
	 c1615862 00000454 c109e8a7 c109e8a7 00000009 ffffffff 00000000 f13f6a10
	 f5f5a600 c103ee33 00000009 00000000 00000000 c109e8a7 f80ca4d0 c109f617
	Call Trace:
	 [<c12ba080>] ? dump_stack+0x44/0x64
	 [<c103ed6a>] ? __warn+0xfa/0x120
	 [<c109e8a7>] ? module_put+0x57/0x70
	 [<c109e8a7>] ? module_put+0x57/0x70
	 [<c103ee33>] ? warn_slowpath_null+0x23/0x30
	 [<c109e8a7>] ? module_put+0x57/0x70
	 [<f80ca4d0>] ? gp8psk_fe_set_frontend+0x460/0x460 [dvb_usb_gp8psk]
	 [<c109f617>] ? symbol_put_addr+0x27/0x50
	 [<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]
	 [<f80bb3bf>] ? dvb_usb_exit+0x2f/0xd0 [dvb_usb]
	 [<c13d03bc>] ? usb_disable_endpoint+0x7c/0xb0
	 [<f80bb48a>] ? dvb_usb_device_exit+0x2a/0x50 [dvb_usb]
	 [<c13d2882>] ? usb_unbind_interface+0x62/0x250
	 [<c136b514>] ? __pm_runtime_idle+0x44/0x70
	 [<c13620d8>] ? __device_release_driver+0x78/0x120
	 [<c1362907>] ? driver_detach+0x87/0x90
	 [<c1361c48>] ? bus_remove_driver+0x38/0x90
	 [<c13d1c18>] ? usb_deregister+0x58/0xb0
	 [<c109fbb0>] ? SyS_delete_module+0x130/0x1f0
	 [<c1055654>] ? task_work_run+0x64/0x80
	 [<c1000fa5>] ? exit_to_usermode_loop+0x85/0x90
	 [<c10013f0>] ? do_fast_syscall_32+0x80/0x130
	 [<c1549f43>] ? sysenter_past_esp+0x40/0x6a
	---[ end trace 6ebc60ef3981792f ]---

이 stack trace는 bug가 발생한 kernel source line을 찾기에 충분한 정보를 제공합니다. 문제 severity에 따라 다음처럼 `Oops`와 NULL pointer dereference, instruction pointer, page-table 정보가 포함될 수 있습니다.

Such stack traces provide enough information to identify the line inside the
Kernel's source code where the bug happened. Depending on the severity of
the issue, it may also contain the word **Oops**, as on this one::

	BUG: unable to handle kernel NULL pointer dereference at   (null)
	IP: [<c06969d4>] iret_exc+0x7d0/0xa59
	*pdpt = 000000002258a001 *pde = 0000000000000000
	Oops: 0002 [#1] PREEMPT SMP
	...

실제 형식이 Oops이든 다른 stack trace이든 bug를 식별하고 처리하려면 offending line이 보통 필요합니다. 이 문서에서는 분석이 필요한 모든 stack trace를 편의상 Oops라고 부릅니다.

Kernel을 `CONFIG_DEBUG_INFO`와 함께 compile했다면 `scripts/decode_stacktrace.sh`로 stack trace 품질을 높일 수 있습니다.

Oops evidence
EvidenceExampleUse
Source locationkernel/module.c:1108직접 file·line 확인
Function offsetmodule_put+0x57/0x70Symbol 안의 instruction 위치
Instruction pointerEIP/IP addressvmlinux와 GDB lookup
Call tracecaller function + offsets실행 경로와 module 판별
Taint and modulesTainted flags, module +/-지원 가능성과 load 상태 확인

Stack dump에서 source location을 찾는 핵심 단서입니다.

`Modules linked in`에서 tainted module 또는 현재 load/unload 중인 module은 괄호 안 annotation으로 표시합니다. Taint flag는 `Documentation/admin-guide/tainted-kernels.rst`에 설명되어 있고, `+`는 load 중, `-`는 unload 중임을 뜻합니다.

Module annotations
MarkerMeaning
(...)Taint 또는 load-state annotation
+Module being loaded
-Module being unloaded

Oops의 linked-module 목록에 붙는 marker입니다.

Oops message 위치와 crash log 확보

66-100

일반적으로 `klogd`가 kernel buffer에서 Oops text를 읽어 `syslogd`에 전달하고, `syslogd`가 `/etc/syslog.conf`에 따라 보통 `/var/log/messages`에 씁니다. Systemd system에서는 `journald`가 저장할 수 있으며 `journalctl`로 접근합니다.

`klogd`가 죽었다면 `dmesg > file`로 kernel buffer를 저장할 수 있습니다. `cat /proc/kmsg > file`도 가능하지만 `kmsg`는 끝나지 않는 file이므로 transfer를 중단하려면 interrupt해야 합니다.

Machine이 심하게 crash해 command를 입력할 수 없거나 disk를 사용할 수 없을 때는 세 방법이 있습니다. 첫째, screen text를 손으로 옮기거나 사진을 찍습니다. Message가 위로 사라지면 `vga=791` 같은 higher resolution이 더 많은 text를 보여 줄 수 있지만 `vesafb`가 필요하므로 early Oops에는 도움이 되지 않습니다.

둘째, `Documentation/admin-guide/serial-console.rst`에 따라 serial console로 boot하고 null-modem으로 두 번째 machine에 연결해 Minicom 같은 communication program으로 output을 capture합니다.

셋째, `Documentation/admin-guide/kdump/kdump.rst`의 Kdump를 사용하고 `Documentation/admin-guide/kdump/gdbmacros.txt`의 dmesg GDB macro로 old memory에서 kernel ring buffer를 추출합니다.

Crash-log capture methods
SituationMethodCaveat
Logging works/var/log/messages or journalctlDaemon configuration에 따라 위치가 다름
Shell worksdmesg > fileKernel buffer가 남아 있어야 함
Only /proc/kmsgcat /proc/kmsg > fileNever-ending stream을 중단해야 함
No command inputScreen copy/photo, optionally vga=791vesafb; early Oops 제외
Serial preparedSerial console + null modem + MinicomSecond machine 필요
Kdump preparedCrash dump + dmesg GDB macroKdump 사전 구성 필요

Machine 상태와 사전 준비에 맞는 Oops 확보 방법입니다.

Choose an Oops capture path
Persistent log availableRead syslog or journalSave full trace
Shell availableRun dmesg or read /proc/kmsgSave full trace
Machine unusableSerial console, Kdump, or screen captureRecover trace elsewhere

현재 machine에 남은 접근 수단부터 판단합니다.

GDB로 source file·line 찾기

101-189

Bug report는 kernel source file의 정확한 위치를 제시할 때 가장 유용합니다. 방법은 두 가지이며 보통 GDB가 쉽지만 kernel을 debug information과 함께 미리 compile해야 합니다. GNU debugger `gdb`는 `vmlinux`에서 Oops의 정확한 file과 line number를 찾는 가장 좋은 방법입니다.

`CONFIG_DEBUG_INFO`를 enable하려면 다음 config command를 사용합니다.

The usage of gdb works best on a kernel compiled with ``CONFIG_DEBUG_INFO``.
This can be set by running::

  $ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO

Debug info가 있는 kernel에서는 Oops의 EIP address를 복사해 `gdb vmlinux`에서 `list *address`로 변환합니다.

On a kernel compiled with ``CONFIG_DEBUG_INFO``, you can simply copy the
EIP value from the OOPS::

 EIP:    0060:[<c021e50e>]    Not tainted VLI

And use GDB to translate that to human-readable form::

  $ gdb vmlinux
  (gdb) l *0xc021e50e

Oops를 만들 때 debug info가 없었다면 Oops의 function offset을 사용합니다. 같은 source를 `CONFIG_DEBUG_INFO`로 다시 compile하고 `list *function+offset`을 실행하면 예제의 `drivers/tty/vt/vt_ioctl.c:293`과 주변 C source를 얻습니다.

If you don't have ``CONFIG_DEBUG_INFO`` enabled, you use the function
offset from the OOPS::

 EIP is at vt_ioctl+0xda8/0x1482

And recompile the kernel with ``CONFIG_DEBUG_INFO`` enabled::

  $ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO
  $ make vmlinux
  $ gdb vmlinux
  (gdb) l *vt_ioctl+0xda8
  0x1888 is in vt_ioctl (drivers/tty/vt/vt_ioctl.c:293).
  288	{
  289		struct vc_data *vc = NULL;
  290		int ret = 0;
  291
  292		console_lock();
  293		if (VT_BUSY(vc_num))
  294			ret = -EBUSY;
  295		else if (vc_num)
  296			vc = vc_deallocate(vc_num);
  297		console_unlock();

더 자세히 보려면 `p vt_ioctl`로 function address를 확인하고 address+offset을 list할 수 있습니다. 전체 `vmlinux` 대신 해당 object file만 build해 GDB로 열 수도 있습니다.

or, if you want to be more verbose::

  (gdb) p vt_ioctl
  $1 = {int (struct tty_struct *, unsigned int, unsigned long)} 0xae0 <vt_ioctl>
  (gdb) l *0xae0+0xda8

You could, instead, use the object file::

  $ make drivers/tty/
  $ gdb drivers/tty/vt/vt_ioctl.o
  (gdb) l *vt_ioctl+0xda8
GDB source lookup
CONFIG_DEBUG_INFO build + EIP addressgdb vmlinuxlist *0xc021e50eSource file and line
Oops has function+offset onlyRebuild vmlinux with DEBUG_INFOlist *vt_ioctl+0xda8Source file and line
Relevant object is knowngdb path/to/object.olist *function+offsetSource file and line

사용 가능한 symbol 정보와 artifact에 따라 lookup 식을 선택합니다.

Call trace의 `:jbd:` annotation은 문제가 jbd module에 있을 가능성을 보여 줍니다. 해당 `.ko`를 GDB에 load하고 relevant function+offset을 list합니다.

If you have a call trace, such as::

     Call Trace:
      [<ffffffff8802c8e9>] :jbd:log_wait_commit+0xa3/0xf5
      [<ffffffff810482d9>] autoremove_wake_function+0x0/0x2e
      [<ffffffff8802770b>] :jbd:journal_stop+0x1be/0x1ee
      ...

this shows the problem likely is in the :jbd: module. You can load that module
in gdb and list the relevant code::

  $ gdb fs/jbd/jbd.ko
  (gdb) l *log_wait_commit+0xa3

같은 방식은 stack trace의 어느 function call에도 적용됩니다. 예제의 `dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]`는 해당 object file을 열어 offset을 조회합니다.

.. note::

     You can also do the same for any function call at the stack trace,
     like this one::

	 [<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]

     The position where the above call happened can be seen with::

	$ gdb drivers/media/usb/dvb-usb/dvb-usb.o
	(gdb) l *dvb_usb_adapter_frontend_exit+0x3a
GDB artifacts
Trace clueGDB artifactExpression
Absolute EIP/IPvmlinuxl *<address>
Built-in function+offsetvmlinux or object.ol *function+offset
Module function+offsetmodule.ko or object.ol *function+offset

Trace 종류별로 열 artifact와 expression을 정리합니다.

objdump와 decodecode

190-240

Kernel debug에는 `objdump`를 사용해 crash output의 hexadecimal offset에 해당하는 code/assembler line을 찾을 수 있습니다. Debug symbol이 없으면 routine의 assembler만, 있으면 C code도 볼 수 있습니다. Debug symbol은 menu configuration의 kernel hacking menu에서 enable할 수 있습니다.

To debug a kernel, use objdump and look for the hex offset from the crash
output to find the valid line of code/assembler. Without debug symbols, you
will see the assembler code for the routine shown, but if your kernel has
debug symbols the C code will also be available. (Debug symbols can be enabled
in the kernel hacking menu of the menu configuration.) For example::

    $ objdump -r -S -l --disassemble net/ipv4/tcp.o

C file을 함께 찾으려면 kernel tree top level에서 command를 실행해야 합니다.

Source code에 접근할 수 없어도 Oops `Code:` byte를 `.byte` directive로 `foo.s`에 넣고 `gcc -c`로 object를 만든 다음 `objdump --disassemble`로 instruction을 복원할 수 있습니다. Oops의 angle bracket은 faulting instruction byte를 가리킵니다.

If you don't have access to the source code you can still debug some crash
dumps using the following method (example crash dump output as shown by
Dave Miller)::

     EIP is at 	+0x14/0x4c0
      ...
     Code: 44 24 04 e8 6f 05 00 00 e9 e8 fe ff ff 8d 76 00 8d bc 27 00 00
     00 00 55 57  56 53 81 ec bc 00 00 00 8b ac 24 d0 00 00 00 8b 5d 08
     <8b> 83 3c 01 00 00 89 44  24 14 8b 45 28 85 c0 89 44 24 18 0f 85

     Put the bytes into a "foo.s" file like this:

            .text
            .globl foo
     foo:
            .byte  .... /* bytes from Code: part of OOPS dump */

     Compile it with "gcc -c -o foo.o foo.s" then look at the output of
     "objdump --disassemble foo.o".

     Output:

     ip_queue_xmit:
         push       %ebp
         push       %edi
         push       %esi
         push       %ebx
         sub        $0xbc, %esp
         mov        0xd0(%esp), %ebp        ! %ebp = arg0 (skb)
         mov        0x8(%ebp), %ebx         ! %ebx = skb->sk
         mov        0x13c(%ebx), %eax       ! %eax = inet_sk(sk)->opt

CPU architecture에 따라 `scripts/decodecode`가 이 작업 대부분을 자동화할 수 있습니다.

Decode a crash instruction
Kernel object and source availableobjdump -r -S -l --disassembleMatch crash offsetC and assembly location
Only Oops Code bytes availableCreate foo.s with .byte valuesgcc -c to foo.oobjdump --disassemble or scripts/decodecode

Source·symbol 유무에 따른 disassembly 경로입니다.

Bug report 대상 찾기

241-282

Bug 위치를 찾은 뒤 직접 수정하거나 upstream에 report할 수 있습니다. Upstream report를 위해 해당 code 개발에 사용하는 bug tracker나 mailing list를 식별해야 하며 `get_maintainer.pl` script가 이를 도와줍니다.

예제는 gspca `sonixj.c`의 maintainer 정보를 조회합니다.

In order to report it upstream, you should identify the bug tracker, if any, or
mailing list used for the development of the affected code. This can be done by
using the ``get_maintainer.pl`` script.

For example, if you find a bug at the gspca's sonixj.c file, you can get
its maintainers with::

	$ ./scripts/get_maintainer.pl --bug -f drivers/media/usb/gspca/sonixj.c
	Hans Verkuil <hverkuil@kernel.org> (odd fixer:GSPCA USB WEBCAM DRIVER,commit_signer:1/1=100%)
	Mauro Carvalho Chehab <mchehab@kernel.org> (maintainer:MEDIA INPUT INFRASTRUCTURE (V4L/DVB),commit_signer:1/1=100%)
	Tejun Heo <tj@kernel.org> (commit_signer:1/1=100%)
	Bhaktipriya Shridhar <bhaktipriya96@gmail.com> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:4/4=100%,removed_lines:9/9=100%)
	linux-media@vger.kernel.org (open list:GSPCA USB WEBCAM DRIVER)
	linux-kernel@vger.kernel.org (open list)

결과에는 Git tree에서 최근 source를 건드린 developer, driver maintainer, subsystem maintainer, driver/subsystem mailing list, Linux Kernel mailing list, driver/subsystem bug-report URI가 포함될 수 있습니다. 최근 contributor가 실제 해당 file 개발에 관여한 사람은 아닐 수도 있습니다.

목록 끝에 bug-report URI가 있으면 email보다 우선합니다. 없으면 code 개발 mailing list에 report하고 driver maintainer를 copy합니다. 누구에게 보낼지 전혀 알 수 없고 `get_maintainer.pl`도 유용한 정보를 주지 못하면 `linux-kernel@vger.kernel.org`로 보냅니다.

Route an upstream bug report
Run get_maintainer.pl --bug -f <source>Bug-report URI existsUse URI
No URISend to development mailing listCC driver/subsystem maintainer
No useful resultSend to linux-kernel@vger.kernel.org

가장 구체적인 공식 report channel부터 선택합니다.

이러한 report는 Linux를 가능한 한 안정적으로 만드는 데 도움을 줍니다.

Bug 수정과 patch 제출

283-297

Programming을 안다면 bug report뿐 아니라 해결책도 제공할 수 있습니다. Fix를 만들었다면 upstream에 제출합니다.

Code가 받아들여질 가능성을 높이려면 `Documentation/process/submitting-patches.rst`를 반드시 읽습니다.

From diagnosis to accepted fix
Locate offending sourceDevelop and test fixRead submitting-patches.rstSubmit upstream

Source location을 확인한 뒤 project의 patch 절차를 따릅니다.

klogd address resolution

298-350

Linus와 kernel developer의 protection-fault 분석을 돕기 위해 `klogd`에는 fault processing 지원이 포함되어 있습니다. Full address resolution을 위해 적어도 `sysklogd` 1.3-pl3을 사용해야 합니다.

Protection fault가 발생하면 `klogd` daemon은 kernel log의 중요한 address를 symbolic equivalent로 자동 변환하고, 현재 reporting mechanism으로 전달합니다. 따라서 변환된 fault message를 log file에서 잘라 kernel developer에게 보낼 수 있습니다.

`klogd`는 static과 dynamic 두 종류 address resolution을 수행합니다. Static translation은 `System.map`을 사용하므로 daemon initialization 때 system map file을 찾을 수 있어야 합니다. Search 방식은 klogd man page를 참고합니다.

Dynamic translation은 loadable kernel module에 중요합니다. Module memory는 kernel dynamic pool에서 할당되므로 module start와 내부 function·symbol 위치가 고정되지 않습니다.

Kernel system call로 loaded module과 memory 위치를 알아낼 수 있습니다. `klogd`는 이를 사용해 loadable module에서 생긴 protection fault를 debug할 symbol table을 만듭니다. 최소한 fault를 만든 module 이름을 제공하고, module이 symbol을 export했다면 추가 symbolic information도 제공합니다.

klogd address resolution modes
ModeSymbol sourceRequirement
StaticSystem.mapDaemon init 때 matching map file 발견
DynamicLoaded-module system calls and exported symbolsCurrent module layout 반영

Built-in kernel과 loadable module은 서로 다른 symbol source를 사용합니다.

Module environment는 동적이므로 load/unload 때 `klogd`에 symbol refresh를 알려야 합니다. 실행 중 daemon에 refresh signal을 보내는 command-line option은 klogd manual에 설명되어 있습니다.

`sysklogd` distribution의 patch는 `modules-2.0.0` package가 module load/unload 때 자동으로 klogd에 signal하도록 수정합니다. 이를 적용하면 loadable-module protection fault debugging을 거의 seamless하게 지원합니다.

Dynamic module-symbol refresh
Module loaded or unloadedSignal klogdQuery current module addressesRefresh dynamic symbol tableResolve future module faults

Module layout 변화와 klogd symbol table을 동기화합니다.

klogd가 변환한 module Oops 예제

351-370

마지막 예제는 loadable module에서 발생한 protection fault를 `klogd`가 처리한 결과입니다. Virtual address paging request, CR3와 PDE, Oops code, CPU, symbolic EIP `oops:_oops+16/3868`, register, process, stack, symbolic call trace, machine code를 포함합니다.

The following is an example of a protection fault in a loadable module
processed by ``klogd``::

	Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
	Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
	Aug 29 09:51:01 blizard kernel: *pde = 00000000
	Aug 29 09:51:01 blizard kernel: Oops: 0002
	Aug 29 09:51:01 blizard kernel: CPU:    0
	Aug 29 09:51:01 blizard kernel: EIP:    0010:[oops:_oops+16/3868]
	Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
	Aug 29 09:51:01 blizard kernel: eax: 315e97cc   ebx: 003a6f80   ecx: 001be77b   edx: 00237c0c
	Aug 29 09:51:01 blizard kernel: esi: 00000000   edi: bffffdb3   ebp: 00589f90   esp: 00589f8c
	Aug 29 09:51:01 blizard kernel: ds: 0018   es: 0018   fs: 002b   gs: 002b   ss: 0018
	Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
	Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
	Aug 29 09:51:01 blizard kernel:        00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
	Aug 29 09:51:01 blizard kernel:        bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
	Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
	Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
Resolved module Oops fields
FieldExample meaning
Fault addressAccess할 수 없던 virtual address
EIPModule `oops`의 `_oops` function + offset
ProcessFault를 일으킨 task와 PID
Call TraceModule·kernel caller의 symbolic chain
CodeFault 주변 machine instruction bytes

klogd가 symbol을 붙여 분석 가능한 형태로 만든 핵심 field입니다.