ホームページ  >  記事  >  システムチュートリアル  >  Linuxカーネルの例外情報:Oopsの詳細説明

Linuxカーネルの例外情報:Oopsの詳細説明

王林
王林転載
2024-02-10 12:00:28657ブラウズ

Oops は、Linux カーネルの特別なエラー メッセージです。ヌル ポインター逆参照、不正なメモリ アクセス、ゼロ除算エラーなど、致命的ではない例外がカーネルで発生したことを示すために使用されます。 Oops の発生は通常、カーネルにバグがあるか、ドライバーに問題があることを意味しており、システムが不安定になったりクラッシュしたりする可能性があります。この記事では、LinuxカーネルにおけるOopsの原理や特徴、Oopsの形式、内容、理由、分類などを紹介し、使用例や注意点などを紹介します。

Linuxカーネルの例外情報:Oopsの詳細説明

Linux カーネル開発における問題とは何ですか?実際、話す主人公が Linux になることを除けば、上記の説明と本質的な違いはありません。より致命的な問題が発生すると、Linux カーネルは「おっと、ごめんなさい、失敗してしまいました。」と申し訳なさそうに私たちに言います。カーネル パニックが発生すると、Linux カーネルは Oops 情報を出力し、現在のレジスタ ステータス、スタックの内容、および完全な呼び出しトレースを表示します。これは、エラーの特定に役立ちます。

次に、例を見てみましょう。この記事の主役を強調するために、おっと、この例の唯一の機能は、null ポインター参照エラーを作成することです。

リーリー

明らかに、エラーは 8 行目です。

次に、このモジュールをコンパイルし、insmod を使用してカーネル空間に挿入します。予想どおり、「おっと」というメッセージが表示されます。

#「

[ 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_seq_midi snd _rawmidi snd_seq_midi_event snd_seq snd_timer snd_seq_device ppdev psmouse serio_raw fbcon tileblit フォント bitblit ソフトカーソル snd parport_pc サウンドコア 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 ffffffffc f82cf040 0072cff4 f82d2000

[100.759324]ffffffffc 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).

基本的に、この汚染された情報はカーネル開発者のために予約されています。 Linux を使用しているときにユーザーが Oops に遭遇した場合、デバッグのために Oops の内容をカーネル開発者に送信できます。カーネル開発者は、この汚染された情報に基づいて、カーネルがパニックになったときにカーネルが実行されている環境を判断できる可能性があります。独自のドライバーをデバッグするだけの場合、この情報は無意味になります。

この記事の例は非常に単純ですが、発生後にダウンタイムが発生しなかったため、dmesg から完全な情報を表示できます。しかし、多くの場合、Oop が発生するとシステムがダウンし、このとき、これらのエラー メッセージはファイルに保存される時間がなく、電源を切ると表示されなくなります。手書きか写真撮影という他の方法でのみ記録できます。

さらに悪い状況です。Oops 情報が多すぎると、1 ページの画面が完全に表示されなくなります。どうすれば完全なコンテンツを表示できますか? 1 つ目の方法は、grub の vga パラメータを使用してより高い解像度を指定し、より多くのコンテンツを画面に表示できるようにすることです。明らかに、この方法では実際にはあまり多くの問題を解決できません。2 番目の方法は、2 台のマシンを使用して、デバッグ マシンの Oops 情報をシリアル ポート経由でホスト画面に出力することです。しかし、現在ほとんどのラップトップにはシリアル ポートがなく、この解決策にも大きな制限があります。3 番目の方法は、カーネル ダンプ ツール kdump を使用して、Oops が発生したときにメモリと CPU レジスタの内容をファイルにダンプすることです。 gdb を使用して問題を分析します。

カーネルドライバーの開発過程で遭遇する可能性のある問題は、さまざまな奇妙であり、デバッグ方法も多岐にわたります。

この記事を通じて、カーネルの問題の診断とデバッグに使用できる、Linux カーネルの Oops の原理と特性について学びました。実際のニーズに基づいて適切なツールを選択し、Oops 情報の保存と分析、シンボル テーブルとソース コードを使用して問題を特定する、モジュール パラメーターとカーネル パラメーターを使用してカーネルの動作を調整するなど、いくつかの基本原則に従う必要があります。 Oops は Linux カーネルの一般的なエラー メッセージで、カーネルのステータスと例外を反映し、カーネルの品質と安定性を向上させることもできます。この記事があなたにとって有益であり、インスピレーションとなることを願っています。

以上がLinuxカーネルの例外情報:Oopsの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlxlinux.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。