Linux 驱动扫描所有线程调用栈

测试环境

root@:curtis# uname -a
Linux curtis-Aspire-E5-471G 5.15.0-52-generic #58~20.04.1-Ubuntu SMP Thu Oct 13 13:09:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
root@:curtis# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.3 LTS
Release:        20.04
Codename:       focal

Linux 通过proc文件系统,将进程的栈信息透给用户态,调用链如下所示。

root@:curtis# cat /proc/self/stack
[<0>] proc_pid_stack+0x9a/0xf0
[<0>] proc_single_show+0x52/0xc0
[<0>] seq_read_iter+0x124/0x450
[<0>] seq_read+0xfd/0x150
[<0>] vfs_read+0xa0/0x1a0
[<0>] ksys_read+0x67/0xf0
[<0>] __x64_sys_read+0x1a/0x20
[<0>] do_syscall_64+0x5c/0xc0
[<0>] entry_SYSCALL_64_after_hwframe+0x61/0xcb

从调用栈上来看,最终调用的是函数proc_pid_stack

#ifdef CONFIG_STACKTRACE#define MAX_STACK_TRACE_DEPTH	64static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns,struct pid *pid, struct task_struct *task)
{unsigned long *entries;int err;/** The ability to racily run the kernel stack unwinder on a running task* and then observe the unwinder output is scary; while it is useful for* debugging kernel issues, it can also allow an attacker to leak kernel* stack contents.* Doing this in a manner that is at least safe from races would require* some work to ensure that the remote task can not be scheduled; and* even then, this would still expose the unwinder as local attack* surface.* Therefore, this interface is restricted to root.*/if (!file_ns_capable(m->file, &init_user_ns, CAP_SYS_ADMIN))return -EACCES;entries = kmalloc_array(MAX_STACK_TRACE_DEPTH, sizeof(*entries),GFP_KERNEL);if (!entries)return -ENOMEM;err = lock_trace(task);if (!err) {unsigned int i, nr_entries;nr_entries = stack_trace_save_tsk(task, entries,MAX_STACK_TRACE_DEPTH, 0);for (i = 0; i < nr_entries; i++) {seq_printf(m, "[<0>] %pB\n", (void *)entries[i]);}unlock_trace(task);}kfree(entries);return err;
}
#endif

从函数的定义来看需要将内核调试选项CONFIG_STACKTRACE打开,核心程序调用的是stack_trace_save_tsk函数,为非导出函数,如何使用未导出函数之前的文章有介绍过。

/*** stack_trace_save_tsk - Save a task stack trace into a storage array* @task:	The task to examine* @store:	Pointer to storage array* @size:	Size of the storage array* @skipnr:	Number of entries to skip at the start of the stack trace** Return: Number of trace entries stored*/
unsigned int stack_trace_save_tsk(struct task_struct *task,unsigned long *store, unsigned int size,unsigned int skipnr)
{struct stack_trace trace = {.entries	= store,.max_entries	= size,/* skip this function if they are tracing us */.skip	= skipnr + (current == task),};save_stack_trace_tsk(task, &trace);return trace.nr_entries;
}

主要代码逻辑

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/sched/signal.h>#include "trace.h"#define MAX_STACK_TRACE_DEPTH 64unsigned int (*stack_trace_save_tsk_ptr)(struct task_struct *task,unsigned long *store, unsigned int size,unsigned int skipnr);int print_stack(struct task_struct *task)
{unsigned long *entries;unsigned int i, nr_entries;entries = kmalloc_array(MAX_STACK_TRACE_DEPTH, sizeof(*entries), GFP_KERNEL);if (!entries)return -ENOMEM;nr_entries = stack_trace_save_tsk_ptr(task, entries,MAX_STACK_TRACE_DEPTH, 0);printk("PID = %d, COMM = %s\n", task->pid, task->comm);for (i = 0; i < nr_entries; i++) {printk(" [<0>] %pB\n", (void *)entries[i]);}kfree(entries);return 0;
}int query_stack(void)
{int ret = 0;struct task_struct *g, *t;do_each_thread(g, t) {print_stack(t);	} while_each_thread(g, t);return ret;
}static int __init stack_trace_init(void)
{int ret = 0;ret = init_kallsyms_lookup_func();if (ret < 0) {printk("get kallsyms_lookup_name addr failed\n");return -1;}stack_trace_save_tsk_ptr = find_func("stack_trace_save_tsk");if (stack_trace_save_tsk_ptr == NULL) {printk("get stack_trace_save_tsk addr failed\n");return -1;}ret = query_stack();if (ret < 0) {printk("query stack failed\n");return ret;}printk("stack trace init\n");return 0;
}static void __exit stack_trace_exit(void)
{printk("stack trace exit\n");	
}module_init(stack_trace_init);
module_exit(stack_trace_exit);
MODULE_LICENSE("GPL");

调用栈打印示例。

[781162.407668] PID = 107085, COMM = sudo
[781162.407670]  [<0>] do_sys_poll+0x486/0x610
[781162.407675]  [<0>] __x64_sys_ppoll+0xac/0xe0
[781162.407679]  [<0>] do_syscall_64+0x5c/0xc0
[781162.407684]  [<0>] entry_SYSCALL_64_after_hwframe+0x61/0xcb
[781162.407696] PID = 107086, COMM = insmod
[781162.407698]  [<0>] print_stack+0x58/0x90 [trace]
[781162.407705]  [<0>] query_stack+0x2d/0x70 [trace]
[781162.407712]  [<0>] stack_trace_init+0x55/0x1000 [trace]
[781162.407719]  [<0>] do_one_initcall+0x48/0x1e0
[781162.407726]  [<0>] do_init_module+0x52/0x230
[781162.407733]  [<0>] load_module+0x138d/0x1610
[781162.407739]  [<0>] __do_sys_finit_module+0xbf/0x120
[781162.407746]  [<0>] __x64_sys_finit_module+0x1a/0x20
[781162.407752]  [<0>] do_syscall_64+0x5c/0xc0
[781162.407757]  [<0>] entry_SYSCALL_64_after_hwframe+0x61/0xcb

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/83571.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode做题笔记145. 二叉树的后序遍历

给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 思路一&#xff1a;递归 c语言解法 void postorder(struct TreeNode *root, int *res, int *resSize) {if (root NULL) {return;}postorder(root->left, res, resSize);postorder(root->right, …

机器学习:PCA(Principal Component Analysis主成分)降维

参考&#xff1a;PCA降维原理 操作步骤与优缺点_TranSad的博客-CSDN博客 PCA降维算法_偶尔努力翻身的咸鱼的博客-CSDN博客 需要提前了解的数学知识&#xff1a; 一、PCA的主要思想 PCA&#xff0c;即主成分分析方法&#xff0c;是一种使用最广泛的数据降维算法。PCA的主要思想…

qt 6知识集

1.Use multi-arg instead [clazy-qstring-arg] 存在过个arg&#xff0c;连写形式如下&#xff1a; QString("%1 %2").arg(a).arg(b);QString("%1 %2").arg(a, b); // one less temporary heap allocation详见参考文献[1]。 参考文献 [1] qstring-arg

【element-ui】el-date-picker 之picker-options时间选择区间禁用效果的实现

element-ui 时间选择器的时间区间禁用dom层引入:picker-option <el-date-pickerv-model"searchFormObj.workTime"clearablevalue-formate"yyyy-MM-dd":picker-options"pickerOptions"placeholder"请选择时间" ></el-date-pi…

基于深度强化学习的四旋翼无人机航线跟随

源自&#xff1a;指挥与控制学报 作者&#xff1a;杨志鹏 李波 甘志刚 梁诗阳 “人工智能技术与咨询” 发布 摘 要 针对无人机在空中执行航线跟随任务时无法对未知环境作出合理应对措施等问题, 提出了一种基于深度强化学习的四 旋翼无人机航线跟随方法. 通过无人机受力…

SpringMVC之JSON数据返回与异常处理机制---全方面讲解

一&#xff0c;JSON数据返回的理解 在Spring MVC中&#xff0c;当需要将数据以JSON格式返回给客户端时&#xff0c;可以使用ResponseBody注解或RestController注解将Controller方法的返回值直接转化为JSON格式并返回。这使得开发者可以方便地将Java对象转换为JSON&#xff0c;并…

【C++】STL之vector操作

文章目录 简介vector中的成员类型模板参数头文件的包含构造函数vector的访问方式&#xff1a;下标[ ]迭代器范围for 交换swap 简介 vector是stl中的一种数组容器&#xff0c;vector在英文中有矢量的意思&#xff0c;但实际上在数据结构中就是一种类似于数组的结构&#xff1b;…

AI大模型服务应用场景

大模型是指模型具有庞大的参数规模和复杂程度的机器学习模型。在深度学习领域&#xff0c;大模型通常是指具有数百万到数十亿参数的神经网络模型。这些模型通常在各种领域&#xff0c;例如自然语言处理、图像识别和语音识别等&#xff0c;表现出高度准确和广泛的泛化能力。伴随…

Jmeter系列-定时器Timers的基本介绍(11)

简介 JMeter中的定时器&#xff08;Timer&#xff09;是一种重要的元件&#xff0c;用于模拟用户在不同时间间隔内发送请求的场景。通过使用定时器&#xff0c;可以模拟负载、并发和容量等不同情况下的请求发送频率。 使用定时器 可以在取样器下添加定时器&#xff0c;这样定…

MySQL日常使用记录

1.时间 1.1.时间格式化 yyyy-MM-dd HH:mm:ss格式&#xff0c;如下&#xff1a; select date_format(now(), %Y-%m-%d %H:%i:%s) from dual;date_format函数是将date类型按照指定的格式转换成varchar类型 1.2.日期加减 当前天 1 天 select date_format(now(), %Y-%m-%d), …

C++中将类成员函数作为变量传递给函数

假设类ClassName有一个成员函数 void ClassName::funcname(int);通过typedef定义一个类成员函数指针类型,参数和返回值类型都要与成员函数对应 typedef void (ClassName::*FuncPtr)(int); // 定义类成员函数指针获取到的参数就是 FuncPtr pf

持安科技孙维伯:零信任理念下的实战攻防:ISC2023数字小镇演讲

近日&#xff0c;在ISC 2023第十一届互联网安全大会上&#xff0c;持安科技联合创始人孙维伯作为零信任办公安全赛道代表&#xff0c;亮相数字小镇New50&#xff0c;并发表《全方位防御&#xff1a;零信任理念下的实战攻防》主题演讲。 以下是本次演讲实录&#xff1a; 这几年…

系统灰度随笔记

系统灰度随笔记 这段时间系统重构&#xff0c;负责重构的其中一个模块需要与四个上游系统对接进行切换&#xff0c;虽然自己在这个过程中也设计了一套灰度方案来承接&#xff0c;将灰度的主动权控制在下游&#xff0c;但是很难同时应对四个上游系统&#xff0c;因为每个上游系…

Redis的介绍以及简单使用

Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的内存数据存储系统&#xff0c;它以键值对的形式将数据存在内存中&#xff0c;并提供灵活、高性能的数据访问方式。Redis具有高速读写能力和丰富的数据结构支持&#xff0c;可以广泛应用于缓存、消息队列、实…

vue的由来、vue教程和M-V-VM架构思想、vue的使用、nodejs

vue vue的由来 vue教程和M-V-VM架构思想 vue的初步简单使用 nodejs vue的由来 # 1 HTML(5)、CSS(3)、JavaScript(ES5、ES6、ES11)&#xff1a;编写一个个的页面 -> 给后端(PHP、Python、Go、Java) -> 后端嵌入模板语法 -> 后端渲染完数据 -> 返回数据给前端 ->…

ATLAS 200通过PCIE 接入RK3588-EP模式

ATLAS 200 作为算理模块&#xff0c;可以作为主/协处理器接入RK3588,有两种模式&#xff1a;RC 模式和EP模式 RC模式&#xff1a;rk3588 和 ATLAS 200 可分别独立处理自身业务数据&#xff0c;不存在业务互相依赖&#xff0c;二者可通过网络等方式进行通信&#xff0c;ATLAS …

【SpringCloud微服务全家桶学习笔记-服务注册zookeeper/consul】

SpringCloud微服务全家桶学习笔记 Eureka服务注册 gitee码云仓库 9.其他服务注册框架 &#xff08;1&#xff09;zookeeper安装与使用 zookeeper需安装在虚拟机上&#xff0c;建议使用CentOS&#xff0c;安装地址如下&#xff1a; zookeeper镜像源 选择第一个进入后下载ta…

WebSocke(简略笔记)

介绍 WebSocket是基于TCP的一种新的网络协议&#xff0c;实现了浏览器域服务器全双工通信——浏览器和服务器只需要完成一次握手&#xff0c;两者直接就可以创建持久性的连接&#xff0c;并进行双向数据传输。 Http协议和WebSocket协议对比&#xff1a; * HTTP是短连接 * We…

python经典百题之逆序打印字符串

题目&#xff1a;利用递归函数调用方式&#xff0c;将所输入的5个字符&#xff0c;以相反顺序打印出来。 方法1: 简单递归 def reverse_print(s, idx):if idx < 0:returnprint(s[idx], end"")reverse_print(s, idx - 1)input_str "hello" reverse_pr…

【核辐射监测】 隐私协议

【核辐射监测】隐私协议 1.个人信息的收集和使用 我们的应用程序不会收集用户的个人信息&#xff0c;包括姓名、地址、电子邮件地址、电话号码等。我们不会追踪用户的位置信息或共享用户的个人信息。 2. 非个人化信息的收集和使用 我们的应用程序可能会收集一些非个人化信息…