0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

objtrace使用方法与代码分析

Linux阅码场 来源:Linux阅码场 作者:陈松 2022-06-21 09:08 次阅读

作者介绍:

陈松,毕业于天津大学精密仪器专业。先后在索尼爱立信,意法爱立信和华为技术有限公司任软件工程师,软件架构师等职务,主要负责手机内核和应用的开发工作。2019年加入麒麟,现任装备事业部软件工程师,主要负责实时内核研发和新技术预研等工作。

1、objtrace和Ftrace的关系

我们在内核代码调试过程中,经常会遇到需要跟踪函数参数值变化的情况,objtrace是一个非常有创造性的工具,它可以将我们从笨重的调试工作中解脱出来,让我们能够很简洁,直观而且优雅的找到我们期望在代码中发现的内容。

Kprobe和function tracer共建于ftrace的基础设施,objtrace将二者巧妙的结合起来,在开发者设置了kprobe的时候,objtrace打开了function tracer,并注册了回调函数。

当代码运行到kprobe关联的函数的时候,objtrace将开发者所设定的参数的地址,偏移量,大小等信息保存起来。

之后,当内核代码运行到任何一个function tracer可以跟踪的函数的时候,objtrace都会将该函数的参数依次取出来,与已经存储的,需要跟踪的参数的地址进行比对,如果发现符合条件的话,就将参数的值打印到ftrace中。

2、如何获取objtrace源代码

Objtrace的源码最早由阅码场资深用户JeffXie提交给内核社区,大家可以在github上找到,大家可以下载,编译,试用,很便捷。目前objtrace应该已经到了v12,大家找到v12的分支即可。作者之前一直在v10上调试,下载代码的命令:git clone -b objtrace-v10 https://github.com/x-lugoo/linux.git

3、功能描述

我们在开发和调试代码的过程中,经常会遇到一个场景,变量在函数之间传递的过程中,我们需要追踪这个变量的值变化的过程,比如下面这个例子中的bio:

bio_add_page(struct bio *bio ...) -->__bio_try_merge_page(bio ...) -->         bio_flagged(bio...)   __bio_add_page(bio...)...

通常,我们会增加很多printk,然后编译安装内核,重启。如果有的函数分支忽略掉的话,还需要再增加printk,再次编译安装内核和重启,是不是很笨重?

内核中的kprobe提供了可以不用修改代码而直接查看函数参数值的方法:

cd /sys/kernel/debug/tracingecho 'p bio_add_page arg1=$arg1 arg2=$arg2' > ./kprobe_eventsecho 1 > events/kprobes/p_bio_add_page_0/enablecat your_file > /dev/nullcat trace
     jbd2/sda5-8-220     [000] ...1. 55531.677782: p_bio_add_page_0: (bio_add_page+0x0/0x90) arg1=0xffff8ecac98aba00 arg2=0xfffff58a0122a400     jbd2/sda5-8-220     [000] ...1. 55531.677786: p_bio_add_page_0: (bio_add_page+0x0/0x90) arg1=0xffff8ecac98abc00 arg2=0xfffff58a04141140     jbd2/sda5-8-220     [000] ...1. 55531.677790: p_bio_add_page_0: (bio_add_page+0x0/0x90) arg1=0xffff8ecac98ab100 arg2=0xfffff58a02e9f880     jbd2/sda5-8-220     [000] ...1. 55531.677794: p_bio_add_page_0: (bio_add_page+0x0/0x90) arg1=0xffff8ecac98ab300 arg2=0xfffff58a041d1b00     jbd2/sda5-8-220     [000] ...1. 55531.677798: p_bio_add_page_0: (bio_add_page+0x0/0x90) arg1=0xffff8ecac98ab600 arg2=0xfffff58a04141280...

Kprobe利用了ftrace中function tracer的架构,将代码段中__fentry__(或__mcount)替换为kprobe_ftrace_handler,kprobe_ftrace_handler将函数名称和参数值打印到了ftraceringbuffer之中。

但还有一个问题,kprobe只能追踪变量在bio_add_page内的值,不能跟踪变量在其之后的变化。

国内社区的jeff老师近期开发了objtrace可以实现变量持续跟踪的功能,objtrace结合使用了kprobe和function tracer的功能,持续跟踪一个或多个变量,同时还可以设置偏移量,获取变量结构内部元素的值。

目前objtrace正在评审中,很快就会进入到内核代码树的主线。

4、使用方法

1)进入debugfs的目录:

cd /sys/kernel/debug/tracing

2)设置kprobe

echo 'p bio_add_page arg1=$arg1 arg2=$arg2' > ./kprobe_events查看kprobe:ls events/kprobes/ -al里面增加了p_bio_add_page_0cat events/kprobes/p_bio_add_page_0/trigger# Available triggers:# traceon traceoff snapshot stacktrace enable_event disable_event enable_hist disable_hist hist objtrace
可以看到除了原有的traceon traceoff snapshot stacktrace之外,增加了一个新的触发器objtrace

3)设置objtrace

echo 'objtracearg1,0x285 if comm == "cat"' > ./events/kprobes/p_bio_add_page_0/trigger表示在kprobe:bio_add_page需要跟踪第一个参数,也就是结构bio偏移量为0x28的变量的值。cat events/kprobes/p_bio_add_page_0/triggerobjtracearg1,0x28count=0 if comm == "cat"

4)触发

cat your_file > /dev/null  //读取一个大文件,触发bio_add_page,也就是内核需要调用到bio_add_page函数

5)查看日志

cat trace# tracer: nop## entries-in-buffer/entries-written: 309/401   #P:4##                                _-----=> irqs-off/BH-disabled#                               / _----=> need-resched#                              | / _---=> hardirq/softirq#                              || / _--=> preempt-depth#                              ||| / _-=> migrate-disable#                              |||| /     delay#           TASK-PID     CPU#  |||||  TIMESTAMP  FUNCTION#              | |         |   |||||     |         |    kworker/3:1H-79      [003] ...1.   248.076143: wbt_issue <-__rq_qos_issue object:0xffffa0c886cc8700 value:0x1000    kworker/3:1H-79      [003] ...1.   248.076143: blk_add_timer <-blk_mq_start_request object:0xffffa0c886cc8700 value:0x1000##### CPU 1 buffer started ####          -0       [001] .Ns2.   248.080898: bio_endio <-blk_update_request object:0xffffa0c886cc8700 value:0x0          -0       [001] .Ns2.   248.080900: __rq_qos_done_bio <-bio_endio object:0xffffa0c886cc8700 value:0x0          -0       [001] .Ns2.   248.080900: bio_uninit <-bio_endio object:0xffffa0c886cc8700 value:0x0          -0       [001] .Ns2.   248.080901: bio_uninit <-bio_endio object:0xffffa0c886cc8700 value:0x0          -0       [001] .Ns2.   248.080901: __rcu_read_lock <-bio_uninit object:0xffffa0c886cc8700 value:0x0-0[001].Ns2.248.080901:__rcu_read_lock<-bio_uninit object:0xffffa0c886cc8700 value:0x0

5、代码分析

5.1初始化

初始化就是让内核的ftrace架构知道有objtrace这样的一个trigger(触发器),当开发者创建一个kprobe的时候,在这个kprobetrigger目录下,会出现objtrace的选项。代码流程如下:

start_kernel -->trace_init -->trace_event_init -->event_trace_enable -->register_trigger_cmds -->register_trigger_object_cmd -- > register_event_command(&trigger_object_cmd); 注册trigger_object_cmdtrigger_object_cmd包含了event_command所需要的函数,如event_object_trigger_parse就是工程是输入objtrace:add...之后,将这个字符串解析的过程。static struct event_command trigger_object_cmd = {     .name           = "objtrace",     .trigger_type       = ETT_TRACE_OBJECT,     .flags          = EVENT_CMD_FL_NEEDS_REC,     .parse          = event_object_trigger_parse,     .reg            = register_trigger,     .unreg          = unregister_trigger,     .get_trigger_ops    = objecttrace_get_trigger_ops,     .set_filter     = set_trigger_filter, };
此外,start_kernel还有一个路径初始化objtrace的另一部分start_kernel -->early_trace_init -->tracer_alloc_buffers -->allocate_objtrace_dataallocate_objtrace_data中申请并初始化了一个结构体objtrace_data *obj_data,其中最重要的是obj_data->fops->func = trace_object_events_call,函数trace_object_events_call负责跟踪参数值并打印到ftrace的ring buffer中,可以说trace_object_events_call是objtrace中最重要的一个函数。注意,此时trace_object_events_call只是放到了obj_data->fops->func中,并没有开始使用。

5.2设置 “echo 'objtracearg1,0x285 if comm == "cat"' > ./events/kprobes/p_bio_add_page_0/trigger”

当开发者输入这个命令的时候,系统需要将 'objtracearg1,0x285 if comm == "cat"' 解析出来,并调用event_trigger_register注册到ftrace中,这样当内核走到bio_add_page这个函数的时候,就会触发kprobe。函数调用过程如下:我在event_trigger_set_filter中增加了一个WARN_ONCE,可以看到调用栈,同时在event_object_trigger_parse中增加了一个printk,看到一些变量。通常我都是使用function_grath来看代码调用的流程,但ftrace本身的函数不能使用ftrace来观测,这样会造成递归调用,很不幸不是,只能使用这种笨办法了:[  180.024670] chensong: event_object_trigger_parse add:arg1,0x285, objtrace_cmd:add[  180.024685] ------------[ cut here ]------------[  180.024688] chensong: set_trigger_filter, filter_str:if comm == "cat"[  180.024698] WARNING: CPU: 3 PID: 4332 at kernel/trace/trace_events_trigger.c:1056 set_trigger_filter+0x13d/0x170...[  180.024844] CPU: 3 PID: 4332 Comm: bash Not tainted 5.18.0-rc2-objtrace-v10+ #2[  180.024848] Hardware name: LENOVO YangTianT4900v-00/, BIOS FCKT65AUS 01/12/2015[  180.024851] RIP: 0010:set_trigger_filter+0x13d/0x170[  180.024856] Code: 83 c4 18 44 89 e0 5b 41 5c 41 5d 5d c3 48 89 fa 48 c7 c6 e0 15 23 84 48 c7 c7 15 e4 5a 84 c6 05 27 84 94 01 01 e8 d2 f7 9c 00 <0f> 0b 48 8b 45 d0 e9 f6 fe ff ff e8 73 57 a3 00 48 8b 7b 20 41 bc[  180.024859] RSP: 0018:ffffa28003a77d60 EFLAGS: 00010286...[  180.024879] CR2: 00007fbeb41fa020 CR3: 000000000a0f6003 CR4: 00000000001706e0[  180.024882] Call Trace:[  180.024884]  [  180.024888]  event_trigger_set_filter+0x22/0x30[  180.024894]  event_object_trigger_parse.cold+0x313/0x345[  180.024904]  trigger_process_regex+0xc1/0x110[  180.024908]  event_trigger_write+0x70/0xd0...[  180.024913]  vfs_write+0xc0/0x2b0[  180.024920]  ksys_write+0x67/0xe0[  180.024926]  __x64_sys_write+0x1a/0x20[  180.024931]  do_syscall_64+0x3b/0x90[  180.024937]  entry_SYSCALL_64_after_hwframe+0x44/0xae

event_object_trigger_parse首先解析objtracearg1,0x285,并将结果保存到变量trigger_data中,最后调用event_trigger_register,过程如下:

static int event_object_trigger_parse(struct event_command *cmd_ops,... {     struct event_trigger_data *trigger_data;     struct objtrace_trigger_data *obj_data;           ...     obj_data->field = field;                                             --- (1)     obj_data->obj_offset = offset;     obj_data->obj_value_type_size = obj_value_type_size;     obj_data->tr = file->tr;     snprintf(obj_data->objtrace_cmd, OBJTRACE_CMD_LEN, objtrace_cmd);
     trigger_data = event_trigger_alloc(cmd_ops, cmd, param, obj_data);   ---(2) ...     ret = event_trigger_set_filter(cmd_ops, file, filter, trigger_data); ---(3)     if (ret < 0)         goto out_free;
     ret = event_trigger_register(cmd_ops, file, glob, trigger_data);     ---(4)    ...    } int event_trigger_register(struct event_command *cmd_ops, {       return cmd_ops->reg(glob, trigger_data, file);                      ---(5) } int event_trigger_set_filter(struct event_command *cmd_ops, {       if (param && cmd_ops->set_filter)         return cmd_ops->set_filter(param, trigger_data, file);          ---(6)     return 0; }    
static struct event_command trigger_object_cmd = {    --- (7)    .name           = "objtrace",    .trigger_type       = ETT_TRACE_OBJECT,    .flags          = EVENT_CMD_FL_NEEDS_REC,    .parse          = event_object_trigger_parse,    .reg            = register_trigger,                                      .unreg          = unregister_trigger,    .get_trigger_ops    = objecttrace_get_trigger_ops,    .set_filter     = set_trigger_filter,                                };

  • (1)解析的结果放到objtrace_trigger_data中。

  • (2)同时,将objtrace_trigger_data放置到event_trigger_data中。

  • (3)注册filter,也就是if comm == "cat"

  • (4)注册trigger。

  • (5)event_trigger_register就是调用trigger_object_cmd中的.reg,也就是register_trigger

  • (6)event_trigger_set_filter就是调用trigger_object_cmd中的.set_filter,也就是set_trigger_filter

  • (7)trigger_object_cmd的定义。

objtrace还有一个重要的工作,就是要跟踪变量的流向,这个就超出了kprobe的功能范围,需要借助function tracer了,所以kprobe部分还有一个重要的工作,就是使能function tracer。我花了很多时间来找如何使能function tracer的,一直没有找到。但如果你了解function tracer的话,会知道在使能function tracer,必然会调用ftrace_replace_code来替换代码段,将__fentry__(或__mcount)替换为ftrace_call,那么我就在ftrace_replace_code中增加一个WARN,看一下调用栈:

增加调试代码:arch/x86/kernel/ftrace.c  +194  ftrace_replace_code    +static int counter = 0; void ftrace_replace_code(int enable) {                rec = ftrace_rec_iter_record(iter);+               WARN_ONCE(1, "chensong: ip:%pS 
", rec->ip);+               counter++;+               if (counter%100 == 0) +                 printk("chensong:%s, ip:%pS
", __FUNCTION__, rec->ip);输入echo 'objtracearg1,0x285 if comm == "cat"' > ./events/kprobes/p_bio_add_page_0/trigger后,得到调用栈[  168.674941] chensong: ip:__traceiter_initcall_level+0x0/0x40 [  168.674954] WARNING: CPU: 3 PID: 3032 at arch/x86/kernel/ftrace.c:205 ftrace_replace_code+0x10b/0x1d0...[  168.675108] CPU: 3 PID: 3032 Comm: bash Not tainted 5.18.0-rc2-objtrace-v10+ #6[  168.675112] Hardware name: LENOVO YangTianT4900v-00/, BIOS FCKT65AUS 01/12/2015[  168.675115] RIP: 0010:ftrace_replace_code+0x10b/0x1d0[  168.675121] Code: 89 fe 89 c7 e8 f7 97 b4 00 5b 41 5c 41 5d 41 5e 41 5f 5d c3 48 8b 30 48 c7 c7 78 c5 b8 a5 c6 05 f0 6e ab 01 01 e8 4f f3 b3 00 <0f> 0b eb 80 e8 bc d1 13 00 31 db 45 85 f6 49 c7 c6 30 32 49 a6 0f[  168.675124] RSP: 0018:ffffb8a90299fc78 EFLAGS: 00010286[  168.675128] RAX: 0000000000000000 RBX: ffffffffa6493230 RCX: 0000000000000000...[  168.675149] Call Trace:[  168.675151]  [  168.675156]  ftrace_modify_all_code+0xcc/0x160[  168.675165]  arch_ftrace_update_code+0x9/0x10[  168.675170]  ftrace_run_update_code+0x1a/0x70[  168.675176]  ftrace_startup_enable+0x2e/0x50[  168.675181]  ftrace_startup+0xa8/0x120[  168.675185]  register_ftrace_function+0x25/0x70[  168.675189]  event_object_trigger_init+0x32/0x50[  168.675194]  register_trigger+0x69/0xd0[  168.675200]  event_trigger_register+0x1c/0x20[  168.675204]  event_object_trigger_parse+0x323/0x390[  168.675211]  trigger_process_regex+0xc1/0x110[  168.675216]  event_trigger_write+0x70/0xd0[  168.675221]  vfs_write+0xc0/0x2b0[  168.675228]  ksys_write+0x67/0xe0[  168.675234]  __x64_sys_write+0x1a/0x20[  168.675240]  do_syscall_64+0x3b/0x90[168.675246]entry_SYSCALL_64_after_hwframe+0x44/0xae

这部分代码也是从register_trigger调用过来的,最终调用了

register_trigger -->event_object_trigger_init --> register_ftrace_function -->ftrace_modify_all_code其中,register_ftrace_function还将&tr->obj_data->fops注册到function tracer的框架中,那么函数调用function tracer时,function tracer会调用tr->obj_data->fops中的回调函数func,也就是在allocate_objtrace_data中赋值的trace_object_events_call函数,此时trace_object_events_call开始工作。

至此,function tracer被打开,以后内核中所有可以trace的函数,都将要走过function tracer这条路径,也就是每一个函数调用之后,都会运行到trace_object_events_call中。

5.3触发 “cat /home/kylin/workspace/opensource/linux-objtrace-jeff/kernel/sched/core.c > /dev/null”

本节是objtrace中最重要的一个环节,当kprobe和objtrace都设置好了,一旦内核调用到bio_add_page,就要开始跟踪bio这个变量了,objtrace是如何在原有的kprobe的基础上实现这个功能的呢?

我在阅读代码的时候,将这个过程分为两部分,一个是kprobe,另一个是function tracer,我们先来看看当kprobe被触发的时候,objtrace做了什么工作:

同样的,我还是使用了printk和WARN_ONCE来进行调试,我首先在函数set_trace_object中增加了一个WARN_ONCE,得到的调用栈如下:[  248.069971] chensong:set_trace_object, call stack of set trace object[  248.069980] WARNING: CPU: 3 PID: 4343 at kernel/trace/trace_object.c:162 trace_object_trigger+0x184/0x1a0....[  248.070450] Hardware name: LENOVO YangTianT4900v-00/, BIOS FCKT65AUS 01/12/2015[  248.070455] RIP: 0010:trace_object_trigger+0x184/0x1a0[  248.070462] Code: 7a ae 48 c7 c6 2d 69 3d ad e8 28 82 fe ff eb bc 48 c7 c6 60 05 43 ae 48 c7 c7 80 ce 7a ae c6 05 2c 11 95 01 01 e8 db 84 9d 00 <0f> 0b eb 9e 48 85 db 0f 84 16 ff ff ff 48 c7 c0 80 96 bc ae e9 d1[  248.070467] RSP: 0018:ffffb122007d36a8 EFLAGS: 00010086....[  248.070515] Call Trace:[  248.070520]  [  248.070533]  trace_object_count_trigger+0x1e/0x30[  248.070541]  event_triggers_call+0x5d/0xe0
[  248.070556]  trace_event_buffer_commit+0x1a2/0x260[  248.070573]  kprobe_trace_func+0x1ad/0x2a0[  248.070602]  kprobe_dispatcher+0x42/0x70

[  248.070610]  ? bio_add_page+0x1/0x90[  248.070622]  kprobe_ftrace_handler+0x168/0x1f0[  248.070629]  ? bio_add_page+0x5/0x90[  248.070636]  ? __bio_try_merge_page+0x140/0x140[  248.070648]  arch_ftrace_ops_list_func+0xe5/0x160[  248.070655]  ? submit_bh_wbc+0xca/0x140[  248.070677]  ftrace_regs_call+0x5/0x52[  248.070689] RIP: 0010:bio_add_page+0x1/0x90....[  248.070781]  ? bio_add_page+0x5/0x90[  248.070789]  ? submit_bh_wbc+0xca/0x140

我们可以看到,当bio_add_page被触发之后,进入和kprobe的调用路径:

bio_add_page -->ftrace_regs_call -->arch_ftrace_ops_list_func-->kprobe_ftrace_handler -->kprobe_dispatcher -->kprobe_trace_func -->event_triggers_call --> trace_object_count_trigger --> set_trace_object

其中trace_object_count_trigger也是trigger_object_cmd中定义的回调函数,在trigger条件符合被触发的时候被调用,我在set_trace_object中还增加了一个printk,打印obj的地址,也就是需要跟踪的变量的地址。

   static void set_trace_object(void *obj, int obj_offset,             int obj_value_type_size, struct trace_array *tr){     unsigned long flags;     struct object_instance *obj_ins;     struct objtrace_data *obj_data;
...     obj_ins = &obj_data->traced_obj[atomic_read(&obj_data->num_traced_obj)];     obj_ins->obj = obj;                                     --- (1)     printk("chensong:%s, obj:0x%lx", __FUNCTION__, obj);     obj_ins->obj_value_type_size = obj_value_type_size;     obj_ins->obj_offset = obj_offset;     obj_ins->tr = tr;     /* make sure the num_traced_obj update always appears after traced_obj update */     smp_wmb();     atomic_inc(&obj_data->num_traced_obj);
     //WARN_ONCE(1, "chensong:%s, call stack of set trace object
", __FUNCTION__); out:     raw_spin_unlock_irqrestore(&obj_data->obj_data_lock, flags); }

(1)这个时候内核已经走到了bio_add_page,所以已经知道了bio的地址了,所以需要将bio的地址保存到object_instance的obj中,object_instance中其余的元素保存偏移量,变量大小等信息。

接下来是function tracer的部分,在上一部分讲过,开发者运行命令“echo 'objtracearg1,0x285 if comm == "cat"' > ./events/kprobes/p_bio_add_page_0/trigger”之后,function tracer被打开,以后内核中所有可以trace的函数,都将要走过function tracer这条路径,每一个函数调用之后,都会运行到trace_object_events_call中,trace_object_events_call的代码如下:

static voidtrace_object_events_call(unsigned long ip, unsigned long parent_ip,        struct ftrace_ops *op, struct ftrace_regs *fregs){    struct pt_regs *pt_regs = ftrace_get_regs(fregs);    int cpu, n;        for (n = 0; n < max_args_num; n++) {            obj = regs_get_kernel_argument(pt_regs, n);                            --- (1)            if (object_exist((void *)obj, tr)) {                                       --- (2)         ...                if (get_object_value(&val, (void *)(obj + obj_offset), val_type_size))  --- (3)                    continue;
                submit_trace_object(ip, parent_ip, obj, val, tr);                     ---(4)            }...}static inline unsigned long regs_get_register(struct pt_regs *regs,                          unsigned int offset){    return *(unsigned long *)((unsigned long)regs + offset);     --- (5)}
static bool object_exist(void *obj, struct trace_array *tr){ ...    for (i = 0; i < max; i++) {        if (obj_data->traced_obj[i].obj == obj)                   --- (6)            return true;    }    return false;}

  • (1)Function tracer使能后,每个可以trace的函数都会调用到trace_object_events_call中,调用栈如下:

Any kernel tracable function -->ftrace_regs_call -->    arch_ftrace_ops_list_func -->          __ftrace_ops_list_func -->              op->func(ip, parent_ip, op, fregs); -->                    trace_object_events_call -->                           get_object_value

trace_object_events_call首先调用regs_get_kernel_argument,依次获得函数的参数,本例中为bio_add_page的参数。

  • (2)调用object_exist来检查是不是需要跟踪的变量,这个变量的地址在开发者输入cat file > /dev/null之后, 内核代码走到了bio_add_pagebio就会在set_trace_object中保存到了object_instanceobj中,所以在这个时候,后续函数如果使用了bioobject_exist返回为TRUE。如果内核代码没有走到过bio_add_page或者该函数的参数中没有bioobject_exist会返回FALSE

  • (3)获取变量值,保存到val中。

  • (4)调用submit_trace_object将value打印到ftrace的ringbuffer中。

  • (5)regs_get_kernel_argument最终会调用到regs_get_register中,返回指定参数的地址。

  • (6)object_exist通过比较地址来判断,当前函数的参数中是不是包含需要跟踪的变量。

好了,到此为止,objtrace的大部分工作都结束了,找到了变量,获得了它的值,并打印到ringbuffer中,很巧妙,避免了大量的printk和WARN这样笨重的方法。

但objtrace打开了所有函数的function tracer,每个函数都要去调用trace_object_events_call,还有调用object_exist进行变量的比对,会增加一定的系统开销,所以objtrace最好不用和性能调试的trace一起工作。

5.4打印 cat trace

从debugfs的trace文件中打印到中断,显示给开发者,调用栈如下:

[ 1617.394055] chensong:trace_object_print[ 1617.394073] WARNING: CPU: 2 PID: 4761 at kernel/trace/trace_output.c:1567 trace_object_print+0x73/0x90
[ 1617.394733] RIP: 0010:trace_object_print+0x73/0x90[ 1617.394749] Code: c6 83 b5 fa b8 e8 9d 0d 00 00 4c 89 e7 be 0a 00 00 00 e8 d0 0a 00 00 48 c7 c6 30 f5 c2 b8 48 c7 c7 90 b5 fa b8 e8 ec a6 9e 00 <0f> 0b 4c 89 e7 e8 23 37 ff ff 5b 41 5c 5d c3 0f 0b eb 97 66 2e 0f
[ 1617.394841] Call Trace:[ 1617.394850]  [ 1617.394864]  print_trace_line+0x25e/0x570[ 1617.394878]  ? ring_buffer_iter_advance+0x32/0x40[ 1617.394902]  s_show+0x4c/0x160[ 1617.394919]  seq_read_iter+0x2a3/0x450[ 1617.394947]  seq_read+0xee/0x120[ 1617.394983]  vfs_read+0xa7/0x1a0[ 1617.395006]  ksys_read+0x67/0xe0[ 1617.395029]  __x64_sys_read+0x1a/0x20[ 1617.395042]  do_syscall_64+0x3b/0x90[ 1617.395056]  entry_SYSCALL_64_after_hwframe+0x44/0xae

原文标题:Ftrace源码分析系列之objtrace

文章出处:【微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内核
    +关注

    关注

    3

    文章

    1309

    浏览量

    39844
  • 调试
    +关注

    关注

    7

    文章

    527

    浏览量

    33624
  • 源代码
    +关注

    关注

    94

    文章

    2926

    浏览量

    66061

原文标题:Ftrace源码分析系列之objtrace

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    TTL电路分析、工作原理、使用方法

    今天给大家分享的是: TTL电路的分析 、TTL电路 工作原理 、TTL电路 使用方法
    发表于 05-18 09:06 3921次阅读
    TTL电路<b class='flag-5'>分析</b>、工作原理、<b class='flag-5'>使用方法</b>

    频谱分析仪的工作原理和使用方法

    频谱分析仪的工作原理和使用方法
    发表于 07-16 22:04

    ComponentCodelab——Tablist的使用方法

    让开发者了解HarmonyOS应用开发常用布局和常用组件之Tablist的使用方法,体验从工程创建到代码、布局的编写,再到编译构建、部署和运行的全过程。
    发表于 05-08 22:04

    assessPort工具的使用方法

    这里主要讲assessPort这个工具的使用方法,所以代码方面就给官方给的准备1、将代码编译烧写到芯片中,这里assessPort只是个工具,和板子芯片版本没有关系。2、打开assessPort
    发表于 01-12 08:16

    简单分析linux内核中的结构体使用方法

    结构体的使用并不熟练,导致在linux开发中一头雾水。下面简单分析结构体的使用方法。1:结构体的定义struct 结构体名{ 成员列表; } 变量名列表;注意这里的变量名可以直接跟在后面也可以单独定义struct 结构体名 变量名 ;举例: ...
    发表于 01-19 08:26

    如何看懂源代码--(分析代码方法)

    如何看懂源代码--(分析代码方法) ________________________________________我们在写程式时,有不少时间都是在看别人的
    发表于 02-10 14:40 51次下载

    示波器的使用方法

    示波器的使用方法 1 示波器使用        本节介绍示波器的使用方法。示波器种类、型号很多,功能也不同。
    发表于 01-14 13:06 1.8w次阅读

    气相色谱仪的使用方法

    气相色谱仪的使用方法 一、色谱仪的安装 1.对色谱仪分析室的要求 (1)分析室周围不得有强磁场,易燃及强腐蚀性气体。 (2)室内环
    发表于 09-18 19:31 1853次阅读

    大众合、众合chunghop万能电视遥控器代码表及使用方法

    大众合、众合chunghop万能电视遥控器代码表及使用方法说明书 国内电视:长虹     000. 008. 009. 091. 092. 093
    发表于 08-01 16:33 9.4w次阅读

    传感器的使用方法及各种数据分析

    传感器的使用方法及各种数据分析 ①最小检测物体与透镜直径、灵
    发表于 03-03 14:54 7590次阅读

    示波器的使用方法

    数字万用表使用方法和示波器的使用方法详解。
    发表于 03-14 10:38 31次下载

    浅谈光耦的使用方法_章圣焰

    浅谈光耦的使用方法及设计电路的分析技巧
    发表于 10-16 13:44 6次下载

    xilinx 原语使用方法

    xilinx 原语使用方法
    发表于 10-17 08:57 11次下载
    xilinx 原语<b class='flag-5'>使用方法</b>

    示波器的使用方法(三):示波器的使用方法详解

    示波器的使用方法并非很难,重点在于正确使用示波器的使用方法。往期文章中,小编对模拟示波器的使用方法和数字示波器的使用方法均有所介绍。为增进大家对示波器的
    的头像 发表于 12-24 20:37 2474次阅读

    频谱分析仪的使用方法

    频谱分析仪的使用方法  频谱分析仪是一种用于测量电子信号频谱的仪器,广泛应用于通信、无线电、音频等领域。它可以分析信号的频率、幅度、相位等参数,帮助工程师进行信号
    的头像 发表于 09-19 16:03 1377次阅读