如何理解 kernel panic 转储的 ARM 寄存器?
How to understand the ARM registers dumped by kernel panic?
在 ARM 平台上 Linux 内核 oops 后,寄存器被转储到控制台。但是我对分析这些寄存器感到困惑。
例如,
Unable to handle kernel paging request at virtual address 0b56e8b8
pgd = c0004000
[0b56e8b8] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT SMP ARM
......
pc : [<bf65e7c0>] lr : [<bf65ec14>] psr: 20000113
sp : c07059f0 ip : 00008d4c fp : c0705a3c
r10: 00000003 r9 : e8bcd800 r8 : e88b006c
r7 : 0000e203 r6 : c0705a44 r5 : e88b0000 r4 : 0b56e8b8
r3 : 00000000 r2 : 00000b56 r1 : e4592e10 r0 : e889570c
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 10c5787d Table: 69fec06a DAC: 00000015
SP: 0xc0705970:
5970 e8e70000 e45de100 00000181 00000180 c070599c bf65e7c0 20000113 ffffffff
5990 c07059dc e88b006c c0705a3c c07059a8 c000e318 c0008360 e889570c e4592e10
59b0 00000b56 00000000 0b56e8b8 e88b0000 c0705a44 0000e203 e88b006c e8bcd800
59d0 00000003 c0705a3c 00008d4c c07059f0 bf65ec14 bf65e7c0 20000113 ffffffff
59f0 e8b80000 e2030b56 00000000 e889570c 00000003 e88b006c c007eccc c007ebb4
5a10 00000000 eacc0480 e88b0000 00002098 e9c80480 e8c08000 00000000 e8bcdc80
5a30 c0705a5c c0705a40 bf65ec14 bf65e6c0 bf5e51c4 00000000 e88b0000 00000000
5a50 c0705a74 c0705a60 bf65ecfc bf65ebe4 e4554500 e4554500 c0705a84 c0705a78
R5: 0xe88aff80:
ff80 bf10f0b0 e8aca4c0 e88aff8c e88b1680 00000000 bf05b70c e87c3580 00000000
ffa0 bf095024 e87c3580 00000000 bf095024 e87c3580 00000000 bf095024 00000001
ffc0 00000004 ebd83000 00000793 e8cc2500 00000002 00000004 00000043 ffffffff
ffe0 40320354 be9ee8d8 00030444 40320380 20000010 00000000 70cfe821 70cfec21
0000 bf81e1f8 e88b0018 e88b000c e88e9a00 00000000 bf095024 00000000 fffffffe
0020 00000000 00000000 fffffffe 00000000 00000000 fffffffe 00000000 00000000
0040 00000001 e91dd000 00001073 0010051b 00080000 f1e4d900 00000001 00000002
0060 000000c8 6df9eca0 00008044 e8895700 00000040 00000026 00000003 0b56e8b8
R8: 0xe88affec:
ffec 40320380 20000010 00000000 70cfe821 70cfec21 bf81e1f8 e88b0018 e88b000c
000c e88e9a00 00000000 bf095024 00000000 fffffffe 00000000 00000000 fffffffe
002c 00000000 00000000 fffffffe 00000000 00000000 00000001 e91dd000 00001073
004c 0010051b 00060000 f1e4d900 00000001 00000002 000000c8 6df9eca0 00008044
006c e8895700 00000040 00000026 00000003 0b56e8b8 e4604000 0000026c 000000da
008c 00000000 21d7ff6e 000078a9 bf05add4 e88b0000 e88b0000 ebd02600 f1015a05
00ac 00000001 000000a6 000000c4 00000000 e88b0000 1e1e1e1e 1e1e1e1e 1e1e1e1e
00cc 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e
问题:
0xc0705970
在SP: 0xc0705970:
中代表什么?代码地址还是数据地址?在哪里可以找到?
为什么sp : c07059f0
不在SP
寄存器的开头或结尾?该寄存器中的堆栈是如何组织的?
每个寄存器的第一列是什么意思?如果代表相对地址,为什么不连续?
0b56e8b8
是指向页面的指针吗?如何在 R5
和 R8
中访问它?
如何在 OS 中使用寄存器取决于 ABI、a.k.a Application Binary Interface.
但是我们可以对转储给出一个快速的、非正式的和简化的解释。
我不是 Linux on ARM 方面的专家,但有些名字似乎很直观:
- sp 是 堆栈指针 。指向称为堆栈的有用内存区域的指针。
- fp 是 帧指针。例程用来访问局部变量的指针。
- lr 是 Link 注册。包含调用的 Return 地址的寄存器。
- nzCv 是标志,如果标志是大写,则设置,否则清除。
- n = 上次结果为阴性
- z = 上次结果为零
- C = 最后一个结果 needed/produced 一个进位
- v = 上次结果溢出
- IRQ on 表示启用硬件中断。
- FIRQ on 表示一些硬件中断使用快速上下文切换处理。
- Mode是CPU模式,说明代码是有权限的。
- 以下信息是内核设置的 CPU 的控制结构。
转储通过将 sp
、r5
和 r8
寄存器值视为指针并显示该地址的内存来帮助您。
例如,SP: 0xc0705970:
下面的块是 0xc0705970
处的内存转储。每行的格式如下:
第一列是当前地址。 只显示最后四位数字,因为很明显完整地址是什么(即没有歧义,地址从0xc0705970
开始)。
后面八列是从内存中转储的 32 位值。每行显示 32 字节内存。
例如通过查看
R5: 0xe88aff80:
ff80 bf10f0b0 e8aca4c0 e88aff8c e88b1680 00000000 bf05b70c e87c3580 00000000
ffa0 bf095024 e87c3580 00000000 bf095024 e87c3580 00000000 bf095024 00000001
ffc0 00000004 ebd83000 00000793 e8cc2500 00000002 00000004 00000043 ffffffff
ffe0 40320354 be9ee8d8 00030444 40320380 20000010 00000000 70cfe821 70cfec21
0000 bf81e1f8 e88b0018 e88b000c e88e9a00 00000000 bf095024 00000000 fffffffe
0020 00000000 00000000 fffffffe 00000000 00000000 fffffffe 00000000 00000000
0040 00000001 e91dd000 00001073 0010051b 00080000 f1e4d900 00000001 00000002
0060 000000c8 6df9eca0 00008044 e8895700 00000040 00000026 00000003 0b56e8b8
您可以看出 r5
指向的 32 位值是 0xbf10f0b0
或者 0xe88a0000
处的 32 位值是 0xbf81e1f8
或者 32 位0xe88a0028
处的值为 0xfffffffe
.
所有这些信息对恐慌代码的开发人员都很有用。
在 ARM 平台上 Linux 内核 oops 后,寄存器被转储到控制台。但是我对分析这些寄存器感到困惑。
例如,
Unable to handle kernel paging request at virtual address 0b56e8b8
pgd = c0004000
[0b56e8b8] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT SMP ARM
......
pc : [<bf65e7c0>] lr : [<bf65ec14>] psr: 20000113
sp : c07059f0 ip : 00008d4c fp : c0705a3c
r10: 00000003 r9 : e8bcd800 r8 : e88b006c
r7 : 0000e203 r6 : c0705a44 r5 : e88b0000 r4 : 0b56e8b8
r3 : 00000000 r2 : 00000b56 r1 : e4592e10 r0 : e889570c
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 10c5787d Table: 69fec06a DAC: 00000015
SP: 0xc0705970:
5970 e8e70000 e45de100 00000181 00000180 c070599c bf65e7c0 20000113 ffffffff
5990 c07059dc e88b006c c0705a3c c07059a8 c000e318 c0008360 e889570c e4592e10
59b0 00000b56 00000000 0b56e8b8 e88b0000 c0705a44 0000e203 e88b006c e8bcd800
59d0 00000003 c0705a3c 00008d4c c07059f0 bf65ec14 bf65e7c0 20000113 ffffffff
59f0 e8b80000 e2030b56 00000000 e889570c 00000003 e88b006c c007eccc c007ebb4
5a10 00000000 eacc0480 e88b0000 00002098 e9c80480 e8c08000 00000000 e8bcdc80
5a30 c0705a5c c0705a40 bf65ec14 bf65e6c0 bf5e51c4 00000000 e88b0000 00000000
5a50 c0705a74 c0705a60 bf65ecfc bf65ebe4 e4554500 e4554500 c0705a84 c0705a78
R5: 0xe88aff80:
ff80 bf10f0b0 e8aca4c0 e88aff8c e88b1680 00000000 bf05b70c e87c3580 00000000
ffa0 bf095024 e87c3580 00000000 bf095024 e87c3580 00000000 bf095024 00000001
ffc0 00000004 ebd83000 00000793 e8cc2500 00000002 00000004 00000043 ffffffff
ffe0 40320354 be9ee8d8 00030444 40320380 20000010 00000000 70cfe821 70cfec21
0000 bf81e1f8 e88b0018 e88b000c e88e9a00 00000000 bf095024 00000000 fffffffe
0020 00000000 00000000 fffffffe 00000000 00000000 fffffffe 00000000 00000000
0040 00000001 e91dd000 00001073 0010051b 00080000 f1e4d900 00000001 00000002
0060 000000c8 6df9eca0 00008044 e8895700 00000040 00000026 00000003 0b56e8b8
R8: 0xe88affec:
ffec 40320380 20000010 00000000 70cfe821 70cfec21 bf81e1f8 e88b0018 e88b000c
000c e88e9a00 00000000 bf095024 00000000 fffffffe 00000000 00000000 fffffffe
002c 00000000 00000000 fffffffe 00000000 00000000 00000001 e91dd000 00001073
004c 0010051b 00060000 f1e4d900 00000001 00000002 000000c8 6df9eca0 00008044
006c e8895700 00000040 00000026 00000003 0b56e8b8 e4604000 0000026c 000000da
008c 00000000 21d7ff6e 000078a9 bf05add4 e88b0000 e88b0000 ebd02600 f1015a05
00ac 00000001 000000a6 000000c4 00000000 e88b0000 1e1e1e1e 1e1e1e1e 1e1e1e1e
00cc 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e
问题:
0xc0705970
在SP: 0xc0705970:
中代表什么?代码地址还是数据地址?在哪里可以找到?为什么
sp : c07059f0
不在SP
寄存器的开头或结尾?该寄存器中的堆栈是如何组织的?每个寄存器的第一列是什么意思?如果代表相对地址,为什么不连续?
0b56e8b8
是指向页面的指针吗?如何在R5
和R8
中访问它?
如何在 OS 中使用寄存器取决于 ABI、a.k.a Application Binary Interface.
但是我们可以对转储给出一个快速的、非正式的和简化的解释。
我不是 Linux on ARM 方面的专家,但有些名字似乎很直观:
- sp 是 堆栈指针 。指向称为堆栈的有用内存区域的指针。
- fp 是 帧指针。例程用来访问局部变量的指针。
- lr 是 Link 注册。包含调用的 Return 地址的寄存器。
- nzCv 是标志,如果标志是大写,则设置,否则清除。
- n = 上次结果为阴性
- z = 上次结果为零
- C = 最后一个结果 needed/produced 一个进位
- v = 上次结果溢出
- IRQ on 表示启用硬件中断。
- FIRQ on 表示一些硬件中断使用快速上下文切换处理。
- Mode是CPU模式,说明代码是有权限的。
- 以下信息是内核设置的 CPU 的控制结构。
转储通过将 sp
、r5
和 r8
寄存器值视为指针并显示该地址的内存来帮助您。
例如,SP: 0xc0705970:
下面的块是 0xc0705970
处的内存转储。每行的格式如下:
第一列是当前地址。 只显示最后四位数字,因为很明显完整地址是什么(即没有歧义,地址从
0xc0705970
开始)。后面八列是从内存中转储的 32 位值。每行显示 32 字节内存。
例如通过查看
R5: 0xe88aff80:
ff80 bf10f0b0 e8aca4c0 e88aff8c e88b1680 00000000 bf05b70c e87c3580 00000000
ffa0 bf095024 e87c3580 00000000 bf095024 e87c3580 00000000 bf095024 00000001
ffc0 00000004 ebd83000 00000793 e8cc2500 00000002 00000004 00000043 ffffffff
ffe0 40320354 be9ee8d8 00030444 40320380 20000010 00000000 70cfe821 70cfec21
0000 bf81e1f8 e88b0018 e88b000c e88e9a00 00000000 bf095024 00000000 fffffffe
0020 00000000 00000000 fffffffe 00000000 00000000 fffffffe 00000000 00000000
0040 00000001 e91dd000 00001073 0010051b 00080000 f1e4d900 00000001 00000002
0060 000000c8 6df9eca0 00008044 e8895700 00000040 00000026 00000003 0b56e8b8
您可以看出 r5
指向的 32 位值是 0xbf10f0b0
或者 0xe88a0000
处的 32 位值是 0xbf81e1f8
或者 32 位0xe88a0028
处的值为 0xfffffffe
.
所有这些信息对恐慌代码的开发人员都很有用。