编辑
2024-12-17
工作知识
0
请注意,本文编写于 171 天前,最后修改于 171 天前,其中某些信息可能已经过时。

目录

一.确定代码
二.确定这些函数是否stap识别
三.编写stap脚本
四 运行stap脚本
参考链接

之前说明了systemtap在ubuntu上安装和测试的基本方法,这个以具体的内核函数的观察来实践一把,主要完成ubuntu上观测鼠标移动和亮度设置函数调用。主要步骤如下

  1. 通过代码确定鼠标移动和亮度设置的内核代码函数

  2. 通过stap -L确定stap是否能够识别这些函数

  3. 编写stap脚本,在函数call的时候进行一些新的打印

  4. 运行stap脚本,在ubuntu上滑动鼠标和调节亮度触发观测点

一.确定代码

鼠标移动代码

drivers/gpu/drm/radeon/radeon_cursor.c radeon_crtc_cursor_move

亮度调节代码

drivers/gpu/drm/radeon/atombios_encoders.c atombios_set_backlight_level

二.确定这些函数是否stap识别

鼠标移动

# stap -L 'module("radeon").function("radeon_crtc_cursor_move")' module("radeon").function("radeon_crtc_cursor_move@drivers/gpu/drm/radeon/radeon_cursor.c:264") $crtc:struct drm_crtc* $x:int $y:int

亮度调节

# stap -L 'module("radeon").function("atombios_set_backlight_level")' module("radeon").function("atombios_set_backlight_level@drivers/gpu/drm/radeon/atombios_encoders.c:94") $radeon_encoder:struct radeon_encoder* $level:u8 $args:DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS

三.编写stap脚本

在确定了stap能够识别这个函数之后,可以写观测脚本如下

观测鼠标移动

probe module("radeon").function("radeon_crtc_cursor_move").call { printf("[func]%s :", probefunc()); printf("x=%d y=%d\n", $x, $y); print_backtrace(); }

这里打印了函数名称,函数的入参x和y,函数的堆栈

观测亮度调节

probe module("radeon").function("atombios_set_backlight_level").call { printf("[func]%s \n", probefunc()); printf("level=%d \n", $level); printf("encoder_id=%d \n", $radeon_encoder->encoder_id); print_backtrace(); }

四 运行stap脚本

stap -v test.stp

运行到pass 5时,可以开始进行测试了

这时候滑动鼠标和通过系统设置调节亮度时,stap这里会打印如下的日志

鼠标的

[func]radeon_crtc_cursor_move :x=779 y=428 0xffffffffc03daab0 : radeon_crtc_cursor_move+0x0/0x50 [radeon] 0xffffffffc01785d4 0xffffffffc01785d4 0xffffffffc01789da 0xffffffffc015d30e 0xffffffffc015d5a7 0xffffffffc03b204e : radeon_drm_ioctl+0x4e/0x80 [radeon] 0xffffffffa0135021 : __x64_sys_ioctl+0x91/0xc0 [kernel] 0xffffffffa09f2ed1 : do_syscall_64+0x61/0xb0 [kernel] 0xffffffffa0c0007c : entry_SYSCALL_64_after_hwframe+0x44/0xae [kernel]

亮度的

[func]atombios_set_backlight_level level=156 encoder_id=33 0xffffffffc042ba70 : atombios_set_backlight_level+0x0/0x180 [radeon] 0xffffffffc042bc20 : radeon_atom_backlight_update_status+0x30/0x40 [radeon] 0xffffffffa045206b : backlight_device_set_brightness+0x6b/0xd0 [kernel] 0xffffffffa0452131 : brightness_store+0x61/0x80 [kernel] 0xffffffffa058bc57 : dev_attr_store+0x17/0x30 [kernel] 0xffffffffa01e007e : sysfs_kf_write+0x3e/0x50 [kernel] 0xffffffffa01df188 : kernfs_fop_write_iter+0x138/0x1c0 [kernel] 0xffffffffa011b377 : new_sync_write+0x117/0x1b0 [kernel] 0xffffffffa011db55 : vfs_write+0x185/0x250 [kernel] 0xffffffffa011dda7 : ksys_write+0x67/0xe0 [kernel] 0xffffffffa011de3a : __x64_sys_write+0x1a/0x20 [kernel] 0xffffffffa09f2ed1 : do_syscall_64+0x61/0xb0 [kernel] 0xffffffffa0c0007c : entry_SYSCALL_64_after_hwframe+0x44/0xae [kernel] 0xffffffffa0c0007c : entry_SYSCALL_64_after_hwframe+0x44/0xae [kernel] 0xffffffffa0451b50 : brightness_show+0x0/0x30 [kernel] 0xffffffffa058c80d : dev_attr_show+0x1d/0x40 [kernel] 0xffffffffa01e0841 : sysfs_kf_seq_show+0xa1/0x100 [kernel] 0xffffffffa01de9e7 : kernfs_seq_show+0x27/0x30 [kernel] 0xffffffffa014ba00 : seq_read_iter+0x120/0x450 [kernel] 0xffffffffa01df4a0 : kernfs_fop_read_iter+0x150/0x1b0 [kernel] 0xffffffffa011b1d0 : new_sync_read+0x110/0x1a0 [kernel] 0xffffffffa011d93e : vfs_read+0xfe/0x190 [kernel] 0xffffffffa011dc87 : ksys_read+0x67/0xe0 [kernel] 0xffffffffa011dd1a : __x64_sys_read+0x1a/0x20 [kernel] 0xffffffffa09f2ed1 : do_syscall_64+0x61/0xb0 [kernel] 0xffffffffa0c0007c : entry_SYSCALL_64_after_hwframe+0x44/0xae [kernel] 0xffffffffa0c0007c : entry_SYSCALL_64_after_hwframe+0x44/0xae [kernel]

至此,就可以通过stap完成对内核函数的观测。只要stap能够识别到内核的函数,就能正常的观测。

这里再解释一下stap默认的函数意思

1.kernel.function("function") 这是指的内核的功能函数 2.module("module").function("function") 这是模块的功能函数 3.probe begin { printf ("hello world\n") } 在观测前打印 4.thread_indent() 返回时间戳+进程名+线程id 例如 1159 ftp(7223) 5.target() 如果stap使用 stap -x PID 这里可以用 if (pid() == target()) 来筛选观测的应用 6.$var 是表述一个变量 例如 printf("x=%d y=%d\n", $x, $y); 这个变量可以通过stap -L 查看到,然后根据实际情况去printf就行 print_backtrace() 打印内核堆栈回溯 ppfunc() 返回从中解析的函数名

如果想观测一个内核文件所有的函数是否被调用,可以

probe module("radeon").function("*@drivers/gpu/drm/radeon/radeon_cursor.c").call

这里格式应该是

function@path:line

如果取

*@path 也就是 *@drivers/gpu/drm/radeon/radeon_cursor.c

代表这个文件的所有函数都观测

参考链接

https://sourceware.org/systemtap/tutorial/tutorialli1.html
https://spacewander.gitbooks.io/systemtapbeginnersguide_zh/content/
https://sourceware.org/systemtap/tapsets/
https://sourceware.org/systemtap/examples/
https://sourceware.org/systemtap/SystemTap_Beginners_Guide/
https://sourceware.org/systemtap/langref/
https://sourceware.org/systemtap/man/index.html

当然,stap也可以观测用户程序,后续有时间再演示吧