>  기사  >  시스템 튜토리얼  >  Linux 커널의 예외 정보: Oops에 대한 자세한 설명

Linux 커널의 예외 정보: Oops에 대한 자세한 설명

王林
王林앞으로
2024-02-10 12:00:28657검색

Oops는 Linux 커널의 특수 오류 메시지로 널 포인터 역참조, 불법 메모리 액세스, 0으로 나누기 오류 등 커널에서 치명적이지 않은 예외가 발생했음을 나타내는 데 사용됩니다. Oops가 발생한다는 것은 일반적으로 커널에 버그가 있거나 드라이버에 문제가 있어 시스템이 불안정하거나 충돌을 일으킬 수 있음을 의미합니다. 이번 글에서는 웁스의 형식, 내용, 이유, 분류 등 리눅스 커널에서의 웁스의 원리와 특징을 소개하고, 사용법과 주의사항에 대한 예를 들어보겠습니다.

Linux 커널의 예외 정보: Oops에 대한 자세한 설명

Linux 커널 개발에서 Oops란 무엇인가요? 사실 말하는 주인공이 리눅스가 된다는 점 외에는 위의 설명과 본질적인 차이는 없다. 좀 더 치명적인 문제가 발생하면 Linux 커널은 "죄송합니다. 제가 망쳤습니다."라고 변명하듯이 말할 것입니다. 커널 패닉이 발생하면 Linux 커널은 Oops 정보를 인쇄하고 현재 레지스터 상태, 스택 콘텐츠 및 전체 호출 추적을 표시하여 오류를 찾는 데 도움이 됩니다.

이제 예를 살펴보겠습니다. 이 기사의 주인공인 앗, 이 예제의 유일한 기능은 널 포인터 참조 오류를 생성하는 것입니다.

으아아아

분명히 오류는 8번째 줄입니다.

다음으로 이 모듈을 컴파일하고 insmod를 사용하여 커널 공간에 삽입했습니다. 예상대로 Oops가 나타났습니다.

[ 100.243737] 버그: (null)

에서 커널 NULL 포인터 역참조를 처리할 수 없습니다.

[100.244985] IP: [] hello_init+0x5/0x11 [안녕]

[ 100.262266] *pde = 00000000

[100.288395] 이런: 0002 [#1] SMP

[ 100.305468] 마지막 sysfs 파일: /sys/devices/virtual/sound/timer/uevent

[ 100.325955] 연결된 모듈: hello(+) vmblock vsock vmmemctl vmhgfs acpiphp snd_ens1371 gameport snd_ac97_codec ac97_bus snd_pcm_oss snd_mixer_oss snd_pcm snd_seq_dummy snd_seq_oss snd_se q_mid i snd_rawmidi snd_seq_midi_event snd_seq snd_timer snd_seq_device ppdev psmouse serio_raw fbcon 타일블릿 글꼴 bitblit Softcursor snd parport_pc soundcore snd_page_alloc vmci i2c_piix4 vga16fb vgastate intel_agp agpgart shpchp lp parport 플로피 pcnet32 mii mptspi mptscsih mptbase scsi_transport_spi vmxnet

[ 100.472178] [ 100.494931] Pid: 1586, comm: insmod 오염되지 않음 (2.6.32-21-generic #32-Ubuntu) VMware 가상 플랫폼

[100.540018] EIP: 0060:[] EFLAGS: 00010246 CPU: 0

[ 100.562844] EIP는 hello_init+0x5/0x11 [hello]에 있습니다.

[ 100.584351] EAX: 00000000 EBX: ffffffffc ECX: f82cf040 EDX: 00000001

[ 100.609358] ESI: f82cf040 EDI: 00000000 EBP: f1b9ff5c ESP: f1b9ff5c

[ 100.631467] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068

[ 100.657664] insmod 프로세스(pid: 1586, ti=f1b9e000 task=f137b340 task.ti=f1b9e000)

[100.706083] 스택:

[ 100.731783] f1b9ff88 c0101131 f82cf040 c076d240 fffffffc f82cf040 0072cff4 f82d2000

[ 100.759324]fffffffc f82cf040 0072cff4 f1b9ffac c0182340 f19638f8 f137b340 f19638c0

[100.811396]00000004 09cc9018 09cc9018 00020000 f1b9e000 c01033ec 09cc9018 00015324

[100.891922] 통화 추적:

[ 100.916257] [] ? do_one_initcall+0x31/0x190

[ 100.943670] [] ? hello_init+0x0/0x11 [안녕]

[ 100.970905] [] ?sys_init_module+0xb0/0x210

[ 100.995542] [] ?syscall_call+0x7/0xb

[ 101.024087] 코드: 05 00 00 00 00 01 00 00 00 5d c3 00 00 00 00 00 00 00 00 00 00

[ 101.079592] EIP: [] hello_init+0x5/0x11 [hello] SS:ESP 0068:f1b9ff5c

[101.134682] CR2: 0000000000000000

[ 101.158929] —[ 추적 종료 e294b69a66d752cb ]—

앗, 이게 어떤 버그인지 먼저 설명한 뒤, 버그가 발생한 위치를 지적했는데, "IP: [] hello_init+0x5/0x11 [hello]" 입니다.

여기서 문제 분석에 도움이 되는 보조 도구인 objdump를 사용해야 합니다. objdump를 사용하여 디스어셈블할 수 있으며 명령 형식은 다음과 같습니다.

objdump -S hello.o

下面是hello.o反汇编的结果,而且是和C代码混排的,非常的直观。

hello.o:     file format elf32-i386


Disassembly of section .init.text:

00000000 :
#include 
#include 

static int __init hello_init(void)
{
   0: 55                    push   %ebp
 int *p = 0;
 
 *p = 1;
 
 return 0;
}
   1: 31 c0                 xor    %eax,%eax
#include 
#include 

static int __init hello_init(void)
{
   3: 89 e5                 mov    %esp,%ebp
 int *p = 0;
 
 *p = 1;
   5: c7 05 00 00 00 00 01  movl   $0x1,0x0
   c: 00 00 00 
 
 return 0;
}
   f: 5d                    pop    %ebp
  10: c3                    ret    

Disassembly of section .exit.text:

00000000 :

static void __exit hello_exit(void)
{
   0: 55                    push   %ebp
   1: 89 e5                 mov    %esp,%ebp
   3: e8 fc ff ff ff        call   4 
 return;
}
   8: 5d                    pop    %ebp
   9: c3                    ret    

对照Oops的提示,我们可以很清楚的看到,出错的位置hello_init+0x5的汇编代码是:

5:c7 05 00 00 00 00 01 movl   $0x1,0x0

这句代码的作用是把数值1存入0这个地址,这个操作当然是非法的。

我们还能看到它对应的c代码是:

*p = 1;

Bingo!在Oops的帮助下我们很快就解决了问题。

我们再回过头来检查一下上面的Oops,看看Linux内核还有没有给我们留下其他的有用信息。

Oops: 0002 [#1]

这里面,0002表示Oops的错误代码(写错误,发生在内核空间),#1表示这个错误发生一次。

Oops的错误代码根据错误的原因会有不同的定义,本文中的例子可以参考下面的定义(如果发现自己遇到的Oops和下面无法对应的话,最好去内核代码里查找):

* error_code:
* bit 0 == 0 means no page found, 1 means protection fault
* bit 1 == 0 means read, 1 means write
* bit 2 == 0 means kernel, 1 means user-mode
* bit 3 == 0 means data, 1 means instruction

有时候,Oops还会打印出Tainted信息。这个信息用来指出内核是因何种原因被tainted(直译为“玷污”)。具体的定义如下:

1: ‘G’ if all modules loaded have a GPL or compatible license, ‘P’ if any proprietary module has been loaded. Modules without a MODULE_LICENSE or with a MODULE_LICENSE that is not recognised by insmod as GPL compatible are assumed to be proprietary.
2: ‘F’ if any module was force loaded by “insmod -f”, ‘ ‘ if all modules were loaded normally.
3: ‘S’ if the oops occurred on an SMP kernel running on hardware that hasn’t been certified as safe to run multiprocessor. Currently this occurs only on various Athlons that are not SMP capable.
4: ‘R’ if a module was force unloaded by “rmmod -f”, ‘ ‘ if all modules were unloaded normally.
5: ‘M’ if any processor has reported a Machine Check Exception, ‘ ‘ if no Machine Check Exceptions have occurred.
6: ‘B’ if a page-release function has found a bad page reference or some unexpected page flags.
7: ‘U’ if a user or user application specifically requested that the Tainted flag be set, ‘ ‘ otherwise.
8: ‘D’ if the kernel has died recently, i.e. there was an OOPS or BUG.
9: ‘A’ if the ACPI table has been overridden.
10: ‘W’ if a warning has previously been issued by the kernel. (Though some warnings may set more specific taint flags.)
11: ‘C’ if a staging driver has been loaded.
12: ‘I’ if the kernel is working around a severe bug in the platform firmware (BIOS or similar).

기본적으로 이 Tainted 정보는 커널 개발자를 위해 예약되어 있습니다. 사용자가 Linux를 사용할 때 Oops를 발견하면 디버깅을 위해 Oops의 내용을 커널 개발자에게 보낼 수 있습니다. 이 Tainted 정보를 기반으로 커널 개발자는 커널 패닉이 발생할 때 커널이 실행되는 환경을 결정할 수 있습니다. 우리가 자체 드라이버를 디버깅한다면 이 정보는 의미가 없을 것입니다.

이 문서의 예는 매우 간단합니다. 발생한 후 다운타임이 발생하지 않았으므로 dmesg에서 전체 정보를 볼 수 있습니다. 그러나 이러한 오류 메시지는 파일에 저장될 시간이 없으며 전원을 끄면 더 이상 볼 수 없습니다. 손으로 쓰거나 사진을 찍는 등 다른 방법으로만 기록할 수 있습니다.

더 나쁜 상황이 있습니다. 정보가 너무 많으면 한 페이지의 화면이 완전히 표시되지 않습니다. 전체 내용을 어떻게 볼 수 있나요? 첫 번째 방법은 grub에서 vga 매개변수를 사용하여 화면에 더 많은 콘텐츠를 표시할 수 있도록 더 높은 해상도를 지정하는 것입니다. 분명히 이 방법은 너무 많은 문제를 해결할 수 없습니다. 두 번째 방법은 두 대의 시스템을 사용하여 직렬 포트를 통해 디버깅 시스템의 죄송합니다 정보를 호스트 화면에 인쇄하는 것입니다. 그러나 현재 대부분의 노트북에는 직렬 포트가 없으며 이 솔루션에도 큰 제한이 있습니다. 세 번째 방법은 오류가 발생할 때 커널 덤프 도구 kdump를 사용하여 파일에 메모리 및 CPU 레지스터의 내용을 덤프하는 것입니다. 문제를 분석하기 위해 gdb를 사용합니다.

커널 드라이버를 개발하는 과정에서 마주칠 수 있는 문제는 종류가 다양하고, 디버깅 방법도 다양합니다. 이런, 리눅스 커널이 우리에게 주는 알림인데 우리는 이를 잘 활용해야 합니다.

이 글을 통해 우리는 커널의 문제를 진단하고 디버그하는 데 사용할 수 있는 Linux 커널의 Oops의 원리와 특성에 대해 배웠습니다. 실제 요구 사항에 따라 적절한 도구를 선택하고 Oops 정보 저장 및 분석, 기호 테이블 및 소스 코드를 사용하여 문제 찾기, 모듈 매개 변수 및 커널 매개 변수를 사용하여 커널 동작 조정 등과 같은 몇 가지 기본 원칙을 따라야 합니다. 죄송합니다. Linux 커널의 일반적인 오류 메시지는 커널의 상태와 예외를 반영할 수 있으며 커널의 품질과 안정성을 향상시킬 수도 있습니다. 이 글이 여러분에게 도움이 되고 영감을 줄 수 있기를 바랍니다.

위 내용은 Linux 커널의 예외 정보: Oops에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 lxlinux.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제