Linux 内核空间问题调试:从基础工具到高级策略的进阶指南
概括地说,内核领域中的问题被归类为内核崩溃和错误。下图显示了可用于调试内核空间中问题的日志、命令行选项和转储。
您可以使用该命令生成内核日志。dmesg
要调试内核空间中的问题,建议使用 build。debug``debug
启用动态调试
debugfs 文件系统允许您通过在运行时启用日志来调试内核。在验证特定场景时,请使用 debugfs 文件系统启用特定时间段的日志。
默认情况下,动态 debugfs 处于禁用状态。要在内核中启用 debugfs,请执行以下作:
-
启用 kernel configuration 选项。
CONFIG_DYNAMIC_DEBUG
-
重新编译并重新刷写构建。
-
要挂载 debugfs 文件系统,请运行以下命令:
mount -o rw,remount /
mount -t debugfs none /sys/kernel/debug
要验证是否启用了动态调试,请验证以下节点是否存在:
cd /sys/kernel/debug/dynamic_debug
如果节点存在,请验证定义的日志:
cat /sys/kernel/debug/dynamic_debug/control
-
为需要调试的文件或函数启用调试日志。
例如:
-
要启用文件中的所有 debugfs 日志,请运行以下命令:
mdp.c
echo 'file mdp.c +p' > /sys/kernel/debug/dynamic_debug/control
-
要在文件中的第 2921 行启用日志,请运行以下命令:
mdp.c
echo 'file mdp.c line 2921 +p' > /sys/kernel/debug/dynamic_debug/control
-
-
使用命令验证日志或运行以下命令:
dmesg
cat /proc/kmsg
启用内核调试选项
可以启用内核配置选项来调试各种问题,例如内存泄漏、锁相关和 Mutex 问题。要查看可用的内核调试选项,请调用menuconfig
. 以下是一些调试选项:
Kernel hacking
[*] Kernel debugging
[*] Detect Soft Lockups
[ ] Collect scheduler statistics
[*] Debug slab memory allocations
[*] Memory leak debugging
[*] Mutex debugging, deadlock detection
[*] Spinlock debugging
[*] Sleep-inside-spinlock checking
[ ] kobject debugging
[ ] Highmem debugging
[ ] Compile the kernel with debug info
注意
如果您启用这些调试选项中的任何一个,内核会稍微变慢。因此,如果您注意到性能有任何下降,请禁用内核调试配置选项。
内核配置选项
下表列出了对调试有用的常见内核配置选项。
表:常见的内核调试配置选项
以下是指示常见内存问题的示例日志。
列出损坏
启用该选项后,可以识别以下指示列表损坏问题的崩溃签名。CONFIG_DEBUG_LIST
示例崩溃签名 1
<4> WARNING: at kernel/lib/list_debug.c:60 __list_del_entry+0xa0/0xd0()
<6> list_del corruption. prev->next should be c6fc374c, but was c18d804c
<6> Modules linked in: adsprpc
<6> [<c010cc94>] (unwind_backtrace+0x0/0x138) from [<c018ad54>] (warn_slowpath_common+0x4c/0x64)
<6> [<c018ad54>] (warn_slowpath_common+0x4c/0x64) from [<c018ae00>] (warn_slowpath_fmt+0x30/0x40)
<6> [<c018ae00>] (warn_slowpath_fmt+0x30/0x40) from [<c03b3128>] (__list_del_entry+0xa0/0xd0)
<6> [<c03b3128>] (__list_del_entry+0xa0/0xd0) from [<c01bc968>] (account_entity_dequeue+0x84/0x94)
<6> [<c01bc968>] (account_entity_dequeue+0x84/0x94) from [<c01bdaa4>] (dequeue_task_fair+0x64/0x190)
示例崩溃签名 2
<4>WARNING: at kernel/lib/list_debug.c:52 __list_del_entry+0x8c/0xac()
<4> list_del corruption, e240c500->prev is LIST_POISON2 (00200200)
<4> Modules linked in: wlan(PO) cfg80211 adsp_loader
<4> [<c001498c>] (unwind_backtrace+0x0/0x11c)
from [<c0068c90>] (warn_slowpath_common+0x4c/0x64)
<4> [<c0068c90>] (warn_slowpath_common+0x4c/0x64)
from [<c0068d28>] (warn_slowpath_fmt+0x2c/0x3c)
<4> [<c0068d28>] (warn_slowpath_fmt+0x2c/0x3c)
from [<c023ef94>] (__list_del_entry+0x8c/0xac)
<4> [<c023ef94>] (__list_del_entry+0x8c/0xac)
from [<c023efc0>] (list_del+0xc/0x24)
<4> [<c023efc0>] (list_del+0xc/0x24)
from [<c043c78c>] (binder_thread_read+0x488/0xb70)
<4> [<c043c78c>] (binder_thread_read+0x488/0xb70)
from [<c043d094>] (binder_ioctl+0x220/0x5b8)
示例崩溃签名 3
<4> WARNING: at kernel/lib/list_debug.c:47 __list_del_entry+0x90/0xb0()
<4> list_del corruption, d6ed3720->next is LIST_POISON1 (00100100)
<4> Modules linked in:
<4> [] (unwind_backtrace+0x0/0x12c) from [] (warn_slowpath_common+0x4c/0x64)
<4> [] (warn_slowpath_common+0x4c/0x64) from [] (warn_slowpath_fmt+0x2c/0x3c)
<4> [] (warn_slowpath_fmt+0x2c/0x3c) from [] (__list_del_entry+0x90/0xb0)
<4> [] (__list_del_entry+0x90/0xb0) from [] (list_del+0xc/0x28)
<4> [] (list_del+0xc/0x28) from [] (bam_mux_write_done+0x34/0x11c)
Spinlock 损坏问题
启用 and 内核配置选项后,可以识别以下指示自旋锁损坏问题的崩溃签名。CONFIG_DEBUG_SPINLOCK``CONFIG_DEBUG_MUTEXES
崩溃签名 1
<0>BUG: spinlock lockup on CPU#1, ndroid.launcher/1071
<0> lock: 0xd5e8f480, .magic: dead4ead, .owner: <none>/-1, .owner_cpu: -1
<4> [<c0734d84>] (spin_dump+0x74/0x84) from [<c028f8fc>]
(do_raw_spin_lock+0x144/0x188)
<4> [<c028f8fc>] (do_raw_spin_lock+0x144/0x188) from [<c0332594>] (kgsl_mmu_pt_get_flags+0x18/0x44)
<4> [<c0332594>] (kgsl_mmu_pt_get_flags+0x18/0x44) from [<c033c6c8>] (adreno_ringbuffer_submitcmd+0x168/0x228)
<4> [<c033c6c8>] (adreno_ringbuffer_submitcmd+0x168/0x228) from [<c033d9a4>] (sendcmd+0x3c/0x254)
崩溃签名 2
<0> BUG: spinlock lockup on CPU#2, kworker/2:0H/2910
<0> lock: kpss_clock_reg_lock+0x0/0x10, .magic: dead4ead, .owner:
kworker/3:0H/2904, .owner_cpu: 3
<6> kworker/2:0H (2910): undefined instruction: pc=c0963098
kernel BUG at kernel/lib/spinlock_debug.c:95!
<4> [<c0963098>] (spin_dump+0x7c/0x94) from [<c038e030>]
(do_raw_spin_lock+0xcc/0x164)
<4> [<c038e030>] (do_raw_spin_lock+0xcc/0x164) from [<c0972228>] (_raw_spin_lock_irqsave+0x20/0x28)
<4> [<c0972228>] (_raw_spin_lock_irqsave+0x20/0x28) from [<c011d4ac>] (__kpss_mux_set_sel+0x14/0x80)
<4> [<c011d4ac>] (__kpss_mux_set_sel+0x14/0x80) from [<c011d54c>] (kpss_mux_set_sel+0x18/0x20)
Slub poisoning问题
当CONFIG_SLUB
和CONFIG_SLUB_DEBUG
内核配置选项使能后,可以识别以下指示 slub poisoning问题的崩溃签名。
<3>[ 3438.930472] =====================================================================
<3>[ 3438.937628] BUG kmalloc-64 (Tainted: G W O): Poison overwritten
<3>[ 3438.944223] ---------------------------------------------------------------------
<3>[ 3438.944228]
<3>[ 3438.953861] INFO: 0xce308408-0xce30840b. First byte 0x0 instead of 0x6b
<3>[ 3438.960470] INFO: Allocated in kgsl_ioctl_drawctxt_create+0x2c/0x2ac age=4426 cpu=0 pid=21702
<3>[ 3438.968970] __slab_alloc.isra.37.constprop.43+0x4d4/0x534
<3>[ 3438.974435] kmem_cache_alloc_trace+0x240/0x258
<3>[ 3438.978947] kgsl_ioctl_drawctxt_create+0x2c/0x2ac
<3>[ 3438.983721] kgsl_ioctl+0xfc/0x324
<3>[ 3438.987108] do_vfs_ioctl+0x80/0x54c
<3>[ 3438.990669] sys_ioctl+0x38/0x5c
<3>[ 3438.993880] ret_fast_syscall+0x0/0x30
<3>[ 3438.997615] INFO: Freed in kgsl_release+0xb8/0xc0 age=10 cpu=3 pid=21842
<3>[ 3439.004298] __slab_free+0x30/0x308
<3>[ 3439.007770] kgsl_release+0xb8/0xc0
<3>[ 3439.011242] fput+0xcc/0x23c
<3>[ 3439.014106] filp_close+0x68/0x80
<3>[ 3439.017407] put_files_struct+0xd8/0x110
<3>[ 3439.021312] do_exit+0x164/0x860
<3>[ 3439.024524] do_group_exit+0x3c/0xb0
<3>[ 3439.028084] get_signal_to_deliver+0x2c4/0x59c
<3>[ 3439.032510] do_signal+0x90/0x480
<3>[ 3439.035809] do_notify_resume+0x50/0x5c
<3>[ 3439.039629] work_pending+0x24/0x28
<3>[ 3439.043101] INFO: Slab 0xc0fbcd20 objects=16 used=16 fp=0x (null) flags=0x0080
<3>[ 3439.050401] INFO: Object 0xce308400 @offset=1024 fp=0xce308900
<3>[ 3439.050405]
<3>[ 3439.057694] Bytes b4 ce3083f0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
<3>[ 3439.066457] Object ce308400: 6b 6b 6b 6b 6b 6b 6b 6b 00 00 00 00 6b 6b 6b 6b kkkkkkkk....kkkk
<3>[ 3439.075051] Object ce308410: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
<3>[ 3439.083639] Object ce308420: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
<3>[ 3439.092234] Object ce308430: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
<3>[ 3439.100828] Redzone ce308440: bb bb bb bb ....
<3>[ 3439.108463] Padding ce3084e8: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
<3>[ 3439.117145] Padding ce3084f8: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
<4>[ 3439.125144] [<c0014f78>] (unwind_backtrace+0x0/0x138) from [<c0150250>] (check_bytes_and_report+0xc0/0xe4)
<4>[ 3439.134771] [<c0150250>] (check_bytes_and_report+0xc0/0xe4) from [<c015042c>] (check_object+0x1b8/0x214)
<4>[ 3439.144237] [<c015042c>] (check_object+0x1b8/0x214) from [<c071b0bc>] (alloc_debug_processing+0x7c/0x150)
<4>[ 3439.153782] [<c071b0bc>] (alloc_debug_processing+0x7c/0x150) from [<c071bcc0>] (__slab_alloc.isra.37.constprop.43+0x4d4/0x534)
<4>[ 3439.165153] [<c071bcc0>] (__slab_alloc.isra.37.constprop.43+0x4d4/0x534) from [<c015221c>] (kmem_cache_alloc_trace+0x240/0x258)
<4>[ 3439.176611] [<c015221c>] (kmem_cache_alloc_trace+0x240/0x258) from [<c014668c>] (__get_vm_area_node.isra.26+0x84/0x174)
<4>[ 3439.187376] [<c014668c>] (__get_vm_area_node.isra.26+0x84/0x174) from [<c0147038>] (get_vm_area_caller+0x44/0x4c)
<4>[ 3439.197615] [<c0147038>] (get_vm_area_caller+0x44/0x4c) from [<c014739c>] (vmap+0x50/0x90)
<4>[ 3439.205866] [<c014739c>] (vmap+0x50/0x90) from [<c032a694>] (_kgsl_sharedmem_page_alloc+0x238/0x3d4)
<4>[ 3439.214979] [<c032a694>] (_kgsl_sharedmem_page_alloc+0x238/0x3d4) from [<c0323e44>] (_gpumem_alloc+0xb0/0xfc)
<4>[ 3439.224874] [<c0323e44>] (_gpumem_alloc+0xb0/0xfc) from [<c0323ed0>] (kgsl_ioctl_gpumem_alloc_id+0x40/0x1a8)
<4>[ 3439.234684] [<c0323ed0>] (kgsl_ioctl_gpumem_alloc_id+0x40/0x1a8) from [<c0321874>] (kgsl_ioctl+0xfc/0x324)
<4>[ 3439.244319] [<c0321874>] (kgsl_ioctl+0xfc/0x324) from [<c0167fe8>] (do_vfs_ioctl+0x80/0x54c)
<4>[ 3439.252738] [<c0167fe8>] (do_vfs_ioctl+0x80/0x54c) from [<c01684ec>] (sys_ioctl+0x38/0x5c)
<4>[ 3439.260986] [<c01684ec>] (sys_ioctl+0x38/0x5c) from [<c000eb00>] (ret_fast_syscall+0x0/0x30)
<3>[ 3439.269400] FIX kmalloc-64: Restoring 0xce308408-0xce30840b=0x6b
Page poisoning问题
当内核配置选项CONFIG_DEBUG_PAGEALLOC
和CONFIG_PAGE_POISONING
启用后,可以识别以下指示页面中毒问题的崩溃签名。
<1> Unable to handle kernel paging request at virtual address aaaaaaae
<1> pgd = e98b4000
<1> [aaaaaaae] *pgd=00000000
<0> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
<4> Modules linked in: adsp_loader exfat_fs(P) exfat_core(P)
<4> CPU: 1 Tainted: P W (3.4.0-628250-eng #1)
<4> PC is at pid_nr_ns+0xc/0x3c
<4> LR is at do_task_stat+0x248/0x83c
<4> pc : [<c00abda8>] lr : [<c018c15c>] psr: a0000093
CPU 参数
各种 CPU 参数,例如内核频率、CPU 调节器和 cpuidle 状态可帮助您更多地了解系统并相应地对其进行调整。
有关 CPU 参数的信息,请参阅 https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu。
内存
Linux 使用虚拟内存系统。因此,用户程序访问的地址与硬件直接使用的物理地址不对应。虚拟内存引入了一个间接层,它允许在系统上运行的程序分配除物理可用内存之外的额外内存。
内存管理实现涵盖以下方面:
-
内存中物理页的管理
-
Buddy 系统以大块分配内存
-
Slab、slub 和 slob 分配器分配较小的内存块
-
vmalloc 机制来分配不连续的内存块
-
进程的地址空间
/proc 文件系统
文件系统上提供了以下文件:/proc
/proc/meminfo
此文件提供有关内存分配和使用情况的信息。要查看此文件的内容,请运行以下命令:
cat /proc/meminfo
输出示例:
MemTotal: 3813532 kB
MemFree: 624836 kB
MemAvailable: 2098008 kB
Buffers: 40416 kB
Cached: 1484320 kB
SwapCached: 0 kB
Active: 1334816 kB
.
.
.
.
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 2431048 kB
Committed_AS: 99995284 kB
VmallocTotal: 258867136 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
CmaTotal: 163840 kB
CmaFree: 1368 kB
该文件中可用的参数详情请参见 https://docs.kernel.org/filesystems/proc.html。
/proc/vmstat 中
此文件显示内核中的详细虚拟内存统计信息。大多数统计信息仅在启用文件中的选项时可用。CONFIG_VM_EVENT_COUNTERS``init/Kconfig
要查看此文件的内容,请运行以下命令:
cat /proc/vmstat
输出示例:
nr_free_pages 156290
nr_alloc_batch 132
nr_inactive_anon 108
nr_active_anon 165006
nr_inactive_file 212275
nr_active_file 168709
nr_unevictable 64
nr_mlock 64
nr_anon_pages 164982
nr_mapped 90366
nr_file_pages 381184:
:
unevictable_pgs_mlocked 0
unevictable_pgs_munlocked 0
unevictable_pgs_cleared 0
unevictable_pgs_stranded 0
unevictable_pgs_mlockfreed 0
有关此文件中可用参数的详细信息, 请参阅 https://man7.org/linux/man-pages/man8/vmstat.8.html。
/proc/iomem 中
此文件显示系统的各种设备驱动程序的内存映射。要查看此文件的内容,请运行以下命令:
cat /proc/iomem
输出示例:
007781b8-007791b7 : vmpm
010aa000-010abfff : tsens_physical
010ac000-010ac003 : pshold-base
010ad000-010aefff : tsens_physical
01680000-0168ffff : /soc/arm,smmu-anoc1@1680000
016c0000-016fffff : /soc/arm,smmu-anoc2@16c0000
01d0101c-01d0101f : sp2soc_irq_status
01d01024-01d01027 : sp2soc_irq_clr
01d01028-01d0102b : sp2soc_irq_mask
.
.
.
0caa0000-0caa3fff : jpeg_hw
0caa4000-0caa47ff : fd_core
0caa5000-0caa53ff : fd_misc
0cd00000-0cd3ffff : /soc/arm,smmu-mmss@cd00000
17817000-17817fff : msm-watchdog
17900000-1790dfff : msm-gladiator-erp
80000000-857fffff : System RAM
80080000-817fffff : Kernel code
82330000-82945fff : Kernel data
88f00000-8aafffff : System RAM
95300000-17e3bffff : System RAM
/proc/vmallocinfo
此文件显示有关通过 或 进行虚拟地址分配的详细信息。要查看此文件的内容,请运行以下命令:vmalloc``ioremap
cat /proc/vmallocinfo
输出示例:
0xbf000000-0xbf002000 8192 module_alloc_update_bounds+0xc/0x5c pages=1 vmalloc
0xbf004000-0xbf008000 16384 module_alloc_update_bounds+0xc/0x5c pages=3 vmalloc
0xee800000-0xef800000 16777216 iotable_init+0x0/0xb0 phys=36800000 ioremap
0xf0000000-0xf0002000 8192 of_iomap+0x30/0x38 ioremap
0xf0002000-0xf0004000 8192 of_iomap+0x30/0x38 ioremap
0xf0004000-0xf000c000 32768 gen_pool_add_virt+0x48/0xb8 pages= 7 vmalloc
0xf000c000-0xf000e000 8192 msm_pm_setup_saved_state+0xcc/0x1bc ioremap
………………………
0xf0174000-0xf0176000 8192 msm_cpu_status_probe+0xd8/0x20c ioremap
0xf0f24000-0xf0f28000 16384 _kgsl_sharedmem_page_alloc+0xa0/0x41c pages=3 vmalloc
0xf0f39000-0xf0f3e000 20480 _kgsl_sharedmem_page_alloc+0xa0/0x41c pages=4 vmalloc
0xf0f61000-0xf0f66000 20480 _kgsl_sharedmem_page_alloc+0xa0/0x41c pages=4 vmalloc
……….
0xfa400000-0xfa600000 2097152 iotable_init+0x0/0xb0 phys=fa00000 ioremap
0xfa71e000-0xfa71f000 4096 iotable_init+0x0/0xb0 phys=f991e000 ioremap
0xfefd8000-0xff000000 163840 pcpu_get_vm_areas+0x0/0x56c vmalloc
memblock 接口
debugfs 文件系统上的接口提供有关系统中可用内存区域和保留内存区域的详细信息。此界面中提供了以下文件:memblock
-
[/sys/kernel/debug/memblock/memory 中]
-
[/sys/kernel/debug/memblock/reserved 中]
/sys/kernel/debug/memblock/memory 中
此文件提供有关 Linux 内核可见的所有可用内存区域(HLOS 和非 HLOS)的详细信息。要了解内核可访问的总内存,请计算每个区域的开始地址和结束地址之间的差异,并将值相加以获得占用的总 RAM。剩余内存(即设备的 RAM 大小与占用的 RAM 之间的差值)是非 HLOS 内存或其他子系统占用的内存。
要查看此文件的内容,请运行以下命令:
cat /sys/kernel/debug/memblock/memory
输出示例:
0: 0x0000000080000000..0x00000000857fffff
1: 0x0000000088f00000..0x000000008aafffff
2: 0x0000000095300000..0x000000017e3bffff
/sys/kernel/debug/memblock/reserved 中
此文件提供有关系统中所有预留内存区域的详细信息。
要查看此文件的内容,请运行以下命令:
cat /sys/kernel/debug/memblock/reserved
输出示例:
0: 0x0000000080080000..0x0000000082944fff
1: 0x0000000083200000..0x0000000083259bb4
2: 0x0000000083400000..0x00000000839506c9
3: 0x00000000f5800000..0x00000000ffbfffff
4: 0x00000000ffff7000..0x00000000ffffefff
5: 0x00000000ffffff40..0x00000000ffffff77
6: 0x00000000ffffff80..0x00000000ffffffb7
7: 0x00000000ffffffc0..0x00000000fffffff7
8: 0x0000000179258000..0x000000017d9fffff
9: 0x000000017da17000..0x000000017da1ffff
10: 0x000000017da20e00..0x000000017da26fff
11: 0x000000017da27300..0x000000017da2735f
12: 0x000000017da27380..0x000000017da273df
13: 0x000000017da27400..0x000000017da2755f
14: 0x000000017da27580..0x000000017da27587
15: 0x000000017da275c0..0x000000017da275c7
16: 0x000000017da29600..0x000000017da29924
17: 0x000000017da29940..0x000000017da29c64
18: 0x000000017da29c80..0x000000017da29fa4
19: 0x000000017da29fac..0x000000017da2a3f8
20: 0x000000017da2a3fc..0x000000017da2a42e
21: 0x000000017da2a430..0x000000017da2a45e
22: 0x000000017da2a460..0x000000017e3bffff
内存泄漏
要调试内核内存泄漏问题,请启用以下配置选项:
-
CONFIG_DEBUG_KMEMLEAK=y
-
CONFIG_DEBUG_KMEMLEAK_MEM_POOL_SIZE= 4000
-
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
默认情况下,内核线程每 10 分钟扫描一次内存,并打印找到的新的未引用对象的数量。例如
unreferenced object 0xec26f000 (size 4096):
comm "Binder_2", pid 4592, jiffies 8848 (age 336.710s)
hex dump (first 32 bytes):
ec 4d f8 c0 02 00 00 00 00 00 00 00 00 00 00 00 .M..............
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<c0126f70>] kmem_cache_alloc_trace+0x17c/0x238
[<c03059c4>] ddl_client_transact+0xd0/0x158
[<c0314a3c>] ddl_open+0x4c/0x194
[<c0302288>] vcd_init_client_context+0x14/0x9c
[<c02ffd10>] vcd_open_in_ready+0x3c/0x94
[<c02fd31c>] vcd_open+0x214/0x274
[<c031b244>] vid_dec_open_client+0x1d0/0x288
[<c031b3ac>] vid_dec_open+0x30/0x7c
[<c012ff70>] chrdev_open+0x10c/0x134
[<c012aa7c>] __dentry_open.isra.12+0x190/0x29c
[<c0138a78>] do_last.isra.29+0x690/0x6c0
[<c0138c70>] path_openat+0xb8/0x35c
[<c0138ff4>] do_filp_open+0x2c/0x78
[<c012b7a0>] do_sys_open+0xd8/0x170
[<c000df20>] ret_fast_syscall+0x0/0x30
[<ffffffff>] 0xffffffff
可以在启动时通过传递内核命令行来禁用该选项。KMEMLEAK``KMEMLEAK=off
有关该文件的详细信息,请参阅 https://www.kernel.org/doc/Documentation。kmemleak.txt
以下是可用于跟踪每页内存的分配器的其他内核配置选项:
-
CONFIG_PAGE_OWNER
-
CONFIG_PAGE_OWNER_ENABLE_DEFAULT
-
CONFIG_PAGE_EXTENSION
当存在多个分配时,在启用这些选项的情况下解析所有页面会有所帮助,这可能是内存泄漏问题。
内存损坏
要识别内存损坏问题,请启用以下内核配置选项:
-
CONFIG_PAGE_POISONING
-
CONFIG_SLUB_DEBUG_ON
-
CONFIG_DEBUG_LIST
-
CONFIG_SLUB_DEBUG
示例日志:
BUG <slab cache affected>: <What went wrong>
-----------------------------------------------
INFO: <corruption start>-<corruption_end> <more info>
INFO: Slab <address> <slab information>
INFO: Object <address> <object information>
INFO: Allocated in <kernel function> age=<jiffies since alloc> cpu=<allocated by cpu> pid=<pid of the process>
INFO: Freed in <kernel function> age=<jiffies since free> cpu=<freed by cpu> pid=<pid of the process>
有关 slub 调试的更多信息,请参阅 https://www.kernel.org/doc/Documentation 中提供。Documentation/vm/slub.txt
内存不足
当系统无法分配页面时,内核日志会显示如下消息:
<4>[12146.861355] Thread-430: page allocation failure: order:0, mode:0x10d2
<CALL STACK>
<4>[12146.951687] Mem-info:
<4>[12146.953909] Normal per-cpu:
<4>[12146.956686] CPU 0: hi: 186, btch: 31 usd: 61
<4>[12146.961489] CPU 1: hi: 186, btch: 31 usd: 0
<4>[12146.966235] HighMem per-cpu:
<4>[12146.969122] CPU 0: hi: 186, btch: 31 usd: 54
<4>[12146.973877] CPU 1: hi: 186, btch: 31 usd: 0
…….
<4>[12147.010770] Normal free:53192kB min:3508kB low:4384kB high:5260kB ……..
<4>[12147.050805] lowmem_reserve[]: 0 9022 9022
<4>[12147.054610] HighMem free:153360kB min:512kB low:1824kB high:3140kB ………
<4>[12147.095453] lowmem_reserve[]: 0 0 0
<4>[12147.098617] Normal: 118*4kB 232*8kB 161*16kB 110*32kB 34*64kB 9*128kB 10*256kB 6*512kB 7*1024kB 6*2048kB 4*4096kB = 53224kB
<4>[12147.115455] HighMem: 2774*4kB 11769*8kB 3005*16kB 1*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 153360kB
………………
这些消息表示系统无法分配请求的页面。日志消息的第一行提供了有关内存不足问题的几个详细信息。例如,在以下日志中:
<4>\[1214.855361\] 线程 4:页面分配失败:order:2,mode:0x10d2
-
order:表示页面的大小;在此示例中,2^2 x PAGE_SIZE (4 K) = 16 K
-
Linux 使用一个 buddy 分配器,它以 2 的幂数分配页面。
-
伙伴分配器的最大大小为 10 = 2^10 x 4 kB = 4 MB 的顺序。
-
对于 4 MB >分配,请使用备用分配方法,例如连续内存分配器 (CMA)。
-
-
对于高阶分配的失败,请检查内存是否可以几乎连续,而不是物理连续。
-
-
mode:指示请求的页面类型
-
mode
提供有关获取免费页面 (GFP) 标记的信息。在此示例中, 是 。mode``0x10d2
-
mode
是对分配中的所有 GFP 标志执行 OR 运算的结果。
-
-
系统中的可用页面
页面分配失败消息打印有关系统中可用页面大小的详细信息。
Normal: 118*4kB 232*8kB 161*16kB 110*32kB 34*64kB 9*128kB 10*256kB 6*512kB 7*1024kB 6*2048kB 4*4096kB = 53224kB
HighMem: 2774*4kB 11769*8kB 3005*16kB 1*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 153360kB
IOMMU 页面错误
IOMMU 也称为系统 MMU (SMMU)。它代表没有自己的 MMU 的子系统执行内存管理功能。
IOMMU 硬件块允许物理上不连续的页面备份几乎连续的内存。IOMMU 中的内存转换逻辑与 CPU MMU 中的逻辑相同。
IOMMU 页面错误是最常见的 IOMMU 问题。当需要访问的页面在页表中映射,但在内存中找不到时,会出现 IOMMU 页面错误。错误处理程序接收 IOMMU 的 context bank 实例,并转储此上下文的 registers。
以下日志指示 IOMMU 页面错误。
[ 47.228992] msm_iommu_v1: Unexpected IOMMU page fault!
[ 47.233115] msm_iommu_v1: name = mdp_iommu
[ 47.237238] msm_iommu_v1: context = mdp_0 (0)
[ 47.241507] msm_iommu_v1: Interesting registers:
[ 47.246149] msm_iommu_v1: FAR = 0000000000000000
[ 47.250970] msm_iommu_v1: PAR = 0000000000000000
[ 47.255834] msm_iommu_v1: FSR = 00000002 [TF ]
[ 47.260540] msm_iommu_v1: FSYNR0 = 000005a1 FSYNR1 = 00030005
[ 47.266528] msm_iommu_v1: TTBR0 = 0000000071a28000
[ 47.271370] msm_iommu_v1: TTBR1 = 0000000000000000
[ 47.276248] msm_iommu_v1: SCTLR = 00001043 ACTLR = 70000000
[ 47.282221] msm_iommu_v1: CBAR = 00000000 CBFRSYNRA = 00000000
[ 47.288521] msm_iommu_v1: PRRR = ff0a81a8 NMRR = 40e040e0
[ 47.294461] msm_iommu_v1: NOTE: Value actually unknown for CBAR
[ 47.300394] msm_iommu_v1: NOTE: Value actually unknown for CBFRSYNRA
[ 47.306717] msm_iommu_v1: Page table in DDR shows PA = 0
下表描述了日志消息中捕获的字段。
表 : IOMMU 页面故障日志中的信息
项目 | 描述 |
---|---|
name | 导致故障的硬件块的名称。 |
FAR | 故障地址寄存器 (FAR) 表示 发生故障。 |
FSR | 故障状态寄存器 (FSR) 指示以下内容:转换错误 (TF)、 访问权限错误 (APF) 、停止状态 (SS) |
FSR 是 IOMMU 调试中最重要的寄存器之一。此 register 具有读/写清除访问权限。该 register 上的读取作读取 register 中的值,而写入作清除写入数据中对应于 1s 的位,并保持对应于 0s 的位不变。此过程可防止在写入 register 以清除旧错误时意外清除新错误。此 register 中的一些有用位是:
表 : 故障状态寄存器中的位
位 | 描述 |
---|---|
[Bit 1]: TF | 翻译错误(页表条目无效) |
[Bit 2]: AFF | 访问故障 |
[Bit 3]: APF | 权限错误(写入只读区域) |
[Bit 4]: TLBMF | TLB 未命中故障 |
[Bit 5]: HTWDEEF | 硬件表走码错误外部故障 |
[Bit 6]: HTWSEEF | 硬件表走从站错误 外部故障 |
[Bit 7]: MHF | TLB 中的多次点击 |
[Bit 16]: SL | 二级故障(页表二级故障) |
[Bit 30]: SS | 停止状态 |
[Bit 31]: MULTI | 多个故障 |
、 、 和 标志表示正常作,而 、 、 和 标志表示存在问题。TF``APF``SL``TLBMF``HTWDEEF``HTWSEEF``MHF
IOMMU 页表
IOMMU 页表转储提供来自 FAR 的故障地址和内核日志中的寄存器转储。这个出错地址就是虚拟地址,对应的物理地址可以从页表中获取。从页表转储中,可以将正在访问的地址标识为已映射或未映射。每个 IOMMU 域都有一个页表。转储包括每个域的页表。目前有 6 个域。
以下是 page 表的示例转储。Domain: 2
Domain: 2 [L2 cache redirect for page tables is OFF]
0x00000000--0x0001ffff [0x00020000] [UNMAPPED]
0x00020000--0x01807fff [0x017e8000] A:0x82a8e000--0x84275fff [0x017e8000] [R/W][4K]
0x01808000--0x01939fff [0x00132000] A:0xf0c24000--0xf0d55fff [0x00132000] [R/W][4K]
0x0193a000--0x0199ffff [0x00066000] A:0xf13fa000--0xf145ffff [0x00066000] [R/W][4K]
0x019a0000--0x01e85fff [0x004e6000] A:0xf966e000--0xf9b53fff [0x004e6000] [R/W][4K]
0x01e86000--0x01ffffff [0x0017a000] [UNMAPPED]
0x02000000--0x02feffff [0x00ff0000] A:0xf5a22000--0xf6a11fff [0x00ff0000] [R/W][4K]
在此示例中,第一列表示虚拟地址,第二列表示连续物理地址的相应区域中的字节数,第三列表示物理地址。还提到了每个区域的权限。
堆栈损坏
当由于不正确的编码逻辑而访问堆栈中的内存位置时,会发生堆栈损坏,这会导致这些内存位置的值发生变化。堆栈损坏可能通过以下方式发生:
-
由于代码逻辑错误,所有堆栈内存都被消耗,内存写入堆栈边界之外,导致堆栈溢出。
-
访问越界的数组。
-
指向堆栈地址的未定义或已释放的指针。
-
调用方函数的返回地址已损坏。
要识别堆栈损坏问题,请启用以下内核配置选项:
-
CONFIG_STACKPROTECTOR
-
CONFIG_STACKPROTECTOR_STRONG
Kernel Address Sanitizer (KASAN) 实用程序还有助于识别 一些堆栈损坏问题。
函数跟踪器
函数跟踪器 (ftrace) 提供跟踪实用程序,用于在运行时执行系统范围的分析和跟踪。
要使用 ftrace,请启用以下配置选项:
-
CONFIG_FTRACE
-
CONFIG_HAVE_FUNCTION_TRACER
-
CONFIG_HAVE_FUNCTION_GRAPH_TRACER
-
CONFIG_HAVE_DYNAMIC_FTRACE
-
CONFIG_HAVE_FTRACE_MCOUNT_RECORD
以下是可以使用 ftrace 调试内核问题的一些作:
将 ftrace 信息转储到 kmsg 缓冲区
如需随时从源码中将 ftrace 信息转储到 kmsg 缓冲区中,请调用该函数。ftrace_dump(DUMP_ALL)
要增加 ftrace 环的缓冲区大小,请运行以下命令:
echo 200 > /sys/kernel/debug/tracing/buffer_size_kb
启用工作队列跟踪
要启用工作队列跟踪,请运行以下命令:
mount -t debugfs none /sys/kernel/debug
echo 1 > /sys/kernel/debug/tracing/events/workqueue/enable
echo workqueue:workqueue_queue_work > /sys/kernel/debug/tracing/set_event
cat /sys/kernel/debug/tracing/trace_pipe
cat /sys/kernel/debug/tracing/per_cpu/cpu1/trace
输出示例:
# tracer: nop
#
# entries-in-buffer/entries-written: 8682/8682 #P:1
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
<...>-4783 [001] d.s4 7524.354249: workqueue_queue_work: work struct=f2d91ee4 function=free_css_set_work workqueue=f6427d80 req_cpu=1 cpu=1
<idle>-0 [001] d.h4 7524.424196: workqueue_queue_work: work struct=c10c32a8 function=def_work_fn workqueue=f55c7880 req_cpu=1 cpu=4
e.process.gapps-4758 [001] dNs4 7524.454227: workqueue_queue_work: work struct=c4727fa4 function=free_css_set_work workqueue=f6427d80 req_cpu=1 cpu=1
Binder_D-1693 [001] d.s3 7524.504198: workqueue_queue_work: work struct=cec6275c function=do_dbs_timer workqueue=f5424680 req_cpu=1 cpu=1
<...>-4832 [001] d.h3 7524.574194: workqueue_queue_work: work struct=c10c32a8 function=def_work_fn workqueue=f55c7880 req_cpu=1 cpu=4