自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

內(nèi)核調(diào)測(cè)工具Kprobe之實(shí)踐篇

系統(tǒng)
debug內(nèi)核函數(shù)變量的時(shí)候最常用的是添加log,用printk看下相關(guān)的信息,但是這種方式往往需要重新編譯內(nèi)核,然后再啟動(dòng)設(shè)備。

[[381473]]

本文轉(zhuǎn)載自微信公眾號(hào)「人人都是極客」,作者布道師Peter。轉(zhuǎn)載本文請(qǐng)聯(lián)系人人都是極客公眾號(hào)。   

 Kprobe介紹

debug內(nèi)核函數(shù)變量的時(shí)候最常用的是添加log,用printk看下相關(guān)的信息,但是這種方式往往需要重新編譯內(nèi)核,然后再啟動(dòng)設(shè)備。

而Kprobe可以在運(yùn)行的內(nèi)核中動(dòng)態(tài)插入探測(cè)點(diǎn),執(zhí)行你預(yù)定義的操作。可以跟蹤內(nèi)核幾乎所有的代碼地址,并且當(dāng)斷點(diǎn)被擊中后會(huì)響應(yīng)處理函數(shù)。

使用kprobe最常用的就是查詢函數(shù)調(diào)用的參數(shù)和返回值。

目前,使用kprobe可以通過兩種方式:

  • 第一種是開發(fā)人員自行編寫內(nèi)核模塊,向內(nèi)核注冊(cè)探測(cè)點(diǎn),探測(cè)函數(shù)可根據(jù)需要自行定制,使用靈活方便;
  • 第二種方式是使用kprobes on trace,這種方式是kprobe和Ftrace結(jié)合使用,即可以通過kprobe來優(yōu)化Ftrace來跟蹤函數(shù)的調(diào)用。

編寫kprobe探測(cè)模塊

Kprobe結(jié)構(gòu)體與API介紹

  1. struct hlist_node hlist:被用于kprobe全局hash,索引值為被探測(cè)點(diǎn)的地址; 
  2. struct list_head list:用于鏈接同一被探測(cè)點(diǎn)的不同探測(cè)kprobe; 
  3. kprobe_opcode_t *addr:被探測(cè)點(diǎn)的地址; 
  4. const char *symbol_name:被探測(cè)函數(shù)的名字; 
  5. unsigned int offset:被探測(cè)點(diǎn)在函數(shù)內(nèi)部的偏移,用于探測(cè)函數(shù)內(nèi)部的指令,如果該值為0表示函數(shù)的入口; 
  6. kprobe_pre_handler_t pre_handler:在被探測(cè)點(diǎn)指令執(zhí)行之前調(diào)用的回調(diào)函數(shù); 
  7. kprobe_post_handler_t post_handler:在被探測(cè)指令執(zhí)行之后調(diào)用的回調(diào)函數(shù); 
  8. kprobe_fault_handler_t fault_handler:在執(zhí)行pre_handler、post_handler或單步執(zhí)行被探測(cè)指令時(shí)出現(xiàn)內(nèi)存異常則會(huì)調(diào)用該回調(diào)函數(shù); 
  9. kprobe_break_handler_t break_handler:在執(zhí)行某一kprobe過程中觸發(fā)了斷點(diǎn)指令后會(huì)調(diào)用該函數(shù),用于實(shí)現(xiàn)jprobe; 
  10. kprobe_opcode_t opcode:保存的被探測(cè)點(diǎn)原始指令; 
  11. struct arch_specific_insn ainsn:被復(fù)制的被探測(cè)點(diǎn)的原始指令,用于單步執(zhí)行,架構(gòu)強(qiáng)相關(guān)(可能包含指令模擬函數(shù)); 
  12. u32 flags:狀態(tài)標(biāo)記。 
  1. int register_kprobe(struct kprobe *kp)      //向內(nèi)核注冊(cè)kprobe探測(cè)點(diǎn) 
  2. void unregister_kprobe(struct kprobe *kp)   //卸載kprobe探測(cè)點(diǎn) 
  3. int register_kprobes(struct kprobe **kps, int num)     //注冊(cè)探測(cè)函數(shù)向量,包含多個(gè)探測(cè)點(diǎn) 
  4. void unregister_kprobes(struct kprobe **kps, int num)  //卸載探測(cè)函數(shù)向量,包含多個(gè)探測(cè)點(diǎn) 
  5. int disable_kprobe(struct kprobe *kp)       //臨時(shí)暫停指定探測(cè)點(diǎn)的探測(cè) 
  6. int enable_kprobe(struct kprobe *kp)        //恢復(fù)指定探測(cè)點(diǎn)的探測(cè) 

用例kprobe_example.c分析與演示

linux內(nèi)核源碼中提供了kprobe的用例 samples/kprobes/kprobe_example.c

  1. /* For each probe you need to allocate a kprobe structure */ 
  2. static struct kprobe kp = { 
  3.  .symbol_name = "do_fork"
  4. }; 
  5.   
  6. static int __init kprobe_init(void) 
  7.  int ret; 
  8.  kp.pre_handler = handler_pre; 
  9.  kp.post_handler = handler_post; 
  10.  kp.fault_handler = handler_fault; 
  11.   
  12.  ret = register_kprobe(&kp); 
  13.  if (ret < 0) { 
  14.   printk(KERN_INFO "register_kprobe failed, returned %d\n", ret); 
  15.   return ret; 
  16.  } 
  17.  printk(KERN_INFO "Planted kprobe at %p\n", kp.addr); 
  18.  return 0; 
  19.   
  20. static void __exit kprobe_exit(void) 
  21.  unregister_kprobe(&kp); 
  22.  printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr); 
  23.   
  24. module_init(kprobe_init) 
  25. module_exit(kprobe_exit) 
  26. MODULE_LICENSE("GPL"); 

程序中定義了一個(gè)struct kprobe結(jié)構(gòu)實(shí)例kp并初始化其中的symbol_name字段為“do_fork”,表明它將要探測(cè)do_fork函數(shù)。在模塊的初始化函數(shù)中,注冊(cè)了 pre_handler、post_handler和fault_handler這3個(gè)回調(diào)函數(shù)分別為handler_pre、handler_post和handler_fault,最后調(diào)用register_kprobe注冊(cè)。在模塊的卸載函數(shù)中調(diào)用unregister_kprobe函數(shù)卸載kp探測(cè)點(diǎn)。

  1. static int handler_pre(struct kprobe *p, struct pt_regs *regs) 
  2. ...... 
  3. #ifdef CONFIG_ARM64 
  4.  pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx," 
  5.    " pstate = 0x%lx\n"
  6.   p->symbol_name, p->addr, (long)regs->pc, (long)regs->pstate); 
  7. #endif 
  8.  
  9.  /* A dump_stack() here will give a stack backtrace */ 
  10.  return 0; 

handler_pre回調(diào)函數(shù)的第一個(gè)入?yún)⑹亲?cè)的struct kprobe探測(cè)實(shí)例,第二個(gè)參數(shù)是保存的觸發(fā)斷點(diǎn)前的寄存器狀態(tài),它在do_fork函數(shù)被調(diào)用之前被調(diào)用,該函數(shù)僅僅是打印了被探測(cè)點(diǎn)的地址,保存的個(gè)別寄存器參數(shù)。

  1. static void handler_post(struct kprobe *p, struct pt_regs *regs, 
  2.     unsigned long flags) 
  3. ...... 
  4. #ifdef CONFIG_ARM64 
  5.  pr_info("<%s> post_handler: p->addr = 0x%p, pstate = 0x%lx\n"
  6.   p->symbol_name, p->addr, (long)regs->pstate); 
  7. #endif 

handler_post回調(diào)函數(shù)的前兩個(gè)入?yún)⑼琱andler_pre,第三個(gè)參數(shù)目前尚未使用,全部為0;該函數(shù)在do_fork函數(shù)調(diào)用之后被調(diào)用,這里打印的內(nèi)容同handler_pre類似。

  1. static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr) 
  2.  pr_info("fault_handler: p->addr = 0x%p, trap #%dn", p->addr, trapnr); 
  3.  /* Return 0 because we don't handle the fault. */ 
  4.  return 0; 

handler_fault回調(diào)函數(shù)會(huì)在執(zhí)行handler_pre、handler_post或單步執(zhí)行do_fork時(shí)出現(xiàn)錯(cuò)誤時(shí)調(diào)用,這里第三個(gè)參數(shù)時(shí)具體發(fā)生錯(cuò)誤的trap number,與架構(gòu)相關(guān)。

加載到內(nèi)核中后,隨便在終端上敲一個(gè)命令,可以看到dmesg中打印如下信息:

  1. <6>pre_handler: p->addr = 0xc0439cc0, ip = c0439cc1, flags = 0x246 
  2. <6>post_handler: p->addr = 0xc0439cc0, flags = 0x246 
  3. <6>pre_handler: p->addr = 0xc0439cc0, ip = c0439cc1, flags = 0x246 
  4. <6>post_handler: p->addr = 0xc0439cc0, flags = 0x246 
  5. <6>pre_handler: p->addr = 0xc0439cc0, ip = c0439cc1, flags = 0x246 
  6. <6>post_handler: p->addr = 0xc0439cc0, flags = 0x246 

可以看到被探測(cè)點(diǎn)的地址為0xc0439cc0,用以下命令確定這個(gè)地址就是do_fork的入口地址。

  1. echo 0 > /proc/sys/kernel/kptr_restrict 
  2. cat /proc/kallsyms | grep do_fork 
  3. c0439cc0 T do_fork 

kprobes on trace

  • /sys/kernel/debug/kprobes/list: 列出內(nèi)核中已經(jīng)設(shè)置kprobe斷點(diǎn)的函數(shù)
  • /sys/kernel/debug/kprobes/enabled: kprobe開啟/關(guān)閉開關(guān)
  • /sys/kernel/debug/kprobes/blacklist: kprobe黑名單(無法設(shè)置斷點(diǎn)函數(shù))
  • /proc/sys/debug/kprobes-optimization: Turn kprobes optimization ON/OFF

Documentation/trace/kprobetrace.txt

使用前確定內(nèi)核CONFIG打開:CONFIG_KPROBE_EVENT=y

/sys/kernel/debug/tracing/kprobe_events:添加斷點(diǎn)接口 

/sys/kernel/debug/tracing/events/kprobes/enabled:斷點(diǎn)使能開關(guān) 

/sys/kernel/debug/tracing/trace:查看trace日志接口

規(guī)則:

  1. Synopsis of kprobe_events------------------------- 
  2.   p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS]  : Set a probe 
  3.   r[:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS]             : Set a return probe 
  4.   -:[GRP/]EVENT                                         : Clear a probe 
  5.  
  6.  GRP            : Group name. If omitted, use "kprobes" for it. 
  7.  EVENT          : Event name. If omitted, the event name is generated 
  8.                   based on SYM+offs or MEMADDR. 
  9.  MOD            : Module name which has given SYM. 
  10.  SYM[+offs]     : Symbol+offset where the probe is inserted. 
  11.  MEMADDR        : Address where the probe is inserted. 
  12.  
  13.  FETCHARGS      : Arguments. Each probe can have up to 128 args. 
  14.   %REG          : Fetch register REG 
  15.   @ADDR         : Fetch memory at ADDR (ADDR should be in kernel) 
  16.   @SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbol) 
  17.   $stackN       : Fetch Nth entry of stack (N >= 0) 
  18.   $stack        : Fetch stack address. 
  19.   $retval       : Fetch return value.(*) 
  20.   $comm         : Fetch current task comm. 
  21.   +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**) 
  22.   NAME=FETCHARG : Set NAME as the argument name of FETCHARG. 
  23.   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types 
  24.                   (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types 
  25.                   (x8/x16/x32/x64), "string" and bitfield are supported. 
  26.  
  27.   (*) only for return probe. 
  28.   (**) this is useful for fetching a field of data structures. 

查看對(duì)應(yīng)的模塊:

  1. 130|mek_8q:/sys/kernel/debug/tracing # cat /proc/devices 
  2. Character devices: 
  3.   1 mem 
  4.   4 /dev/vc/0 
  5.   4 tty 
  6.   4 ttyS 
  7.   5 /dev/tty 
  8.   5 /dev/console 
  9.   5 /dev/ptmx 
  10.   7 vcs 
  11.  10 misc 
  12.  13 input 
  13.  29 fb 
  14.  81 video4linux 
  15.  89 i2c 
  16.  90 mtd 
  17. 108 ppp 
  18. 116 alsa 

可以在System.map文件里找一下有沒有你要觀察的內(nèi)核函數(shù)方法。這個(gè)文件其實(shí)相當(dāng)于內(nèi)核的符號(hào)表(symbol table)。如果拿不準(zhǔn)內(nèi)核方法名的時(shí)候可以在這里面grep一下看看。

  1. mek_8q:/ # cat /proc/kallsyms | grep do_sys_open 
  2. 0000000000000000 T do_sys_open 

以do_sys_open為例添加kprobe為例:

  1. 添加kprobe: 
  2. echo 'p:myprobe do_sys_open' > /sys/kernel/debug/tracing/kprobe_events 
  3. 添加kretprobe,返回值是數(shù)字: 
  4. echo 'r:myretprobe do_sys_open $retval' > /sys/kernel/debug/tracing/kprobe_events 
  5. 添加kretprobe,返回值是字符串: 
  6. echo 'r:myprobe getname +0($retval):string' > /sys/kernel/debug/tracing/kprobe_events 
  7. 刪除添加的kprobe: 
  8. echo '-:myprobe' > /sys/kernel/debug/tracing/events/kprobe_events 

執(zhí)行:

  1. cd /sys/kernel/debug/tracing 
  2. echo 'p:myprobe do_sys_open' > kprobe_events 
  3. echo 'r:myretprobe do_sys_open $retval' > kprobe_events 
  4. echo 1 > tracing_on 
  5. echo 1 > events/kprobes/myprobe/enable 

結(jié)果為:

刪除注冊(cè)的kprobe:

  1. echo 0 > /sys/kernel/debug/tracing/events/kprobes/myprobe/enable 
  2. echo 0 > /sys/kernel/debug/tracing/events/kprobes/myretprobe/enable 
  3. echo '-:myprobe' > /sys/kernel/debug/tracing/events/kprobe_events 
  4. echo '-:myretprobe' > /sys/kernel/debug/tracing/events/kprobe_events 

 

責(zé)任編輯:武曉燕 來源: 人人都是極客
相關(guān)推薦

2021-02-20 20:51:24

工具內(nèi)核kprobe

2022-03-21 09:40:48

TektonJenkinsPipeline

2022-04-08 09:53:56

TektonJenkinsKubesphere

2010-07-29 09:57:34

SCVMM虛擬機(jī)

2022-04-14 07:51:39

TektonTaskRun

2009-12-07 14:53:07

RHEL網(wǎng)絡(luò)安裝

2022-03-10 13:57:23

TektonJenkinsPipeline

2017-10-17 14:02:30

jvm調(diào)優(yōu)工具

2010-07-20 08:49:00

Objective C

2019-06-12 10:15:19

運(yùn)維開發(fā)Linux

2023-06-27 15:02:47

2011-03-18 11:21:48

2021-03-04 08:39:21

SparkRDD調(diào)優(yōu)

2023-11-29 20:19:35

實(shí)踐云計(jì)算

2021-11-07 23:49:19

SQL數(shù)據(jù)庫(kù)工具

2011-07-27 14:10:43

javascript

2021-11-15 04:00:07

Linux 內(nèi)核動(dòng)態(tài)

2009-08-07 10:28:03

2010-11-30 11:26:49

2021-04-08 09:32:17

鴻蒙HarmonyOS應(yīng)用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)