調試 – 觀察Linux內核中的變量(內存地址)更改,並在更改時打印堆棧跟蹤?【轉】


轉自:https://www.jb51.cc/linux/394057.html

調試 – 觀察Linux內核中的變量(內存地址)更改,並在更改時打印堆棧跟蹤?

發布時間:2019-06-11 發布網站:腳本之家

腳本之家收集整理的這篇文章主要介紹了調試 – 觀察Linux內核中的變量(內存地址)更改,並在更改時打印堆棧跟蹤?腳本之家小編覺得挺不錯的,現在分享給大家,也給大家做個參考。

我想以某種方式“監視” Linux內核中的變量(或內存地址)(確切地說是內核模塊/驅動程序);並找出改變它的原因 – 基本上,當變量改變時打印出堆棧跟蹤.

例如,在this answer年末列出的內核模塊testjiffy-hr.c中,我想在每次runco​​unt變量更改時打印出堆棧跟蹤;希望堆棧跟蹤然后會提到testjiffy_timer_function,這確實是改變該變量的函數.

 

現在,我知道我可以使用kgdb連接到在虛擬機中運行的調試Linux內核,甚至可以設置斷點(所以希望也是觀察點) – 但問題是我實際上想要調試ALSA驅動程序,特別是播放dma_area緩沖區(我得到了一些意想不到的數據) – 這對時間非常敏感;並且運行調試內核本身會弄亂時間(更不用說在虛擬機中運行它)了.

這里更大的問題是回放dma_area指針僅在回放操作期間(或者換句話說,在_start和_stop處理程序之間)存在 – 所以我必須在每個_start回調中記錄dma_area地址,然后以某種方式“在播放操作期間安排“用於”觀看“.

所以我希望有一種方法可以直接在驅動程序代碼中執行此類操作 – 例如,在此_start回調中添加一些代碼來記錄dma_area指針,並將其用作啟動“watch”的命令的參數改變;從相應的回調函數打印堆棧跟蹤. (我知道這也會影響時間,但我希望它能夠“輕松”,不會過多地影響“實時”驅動程序操作).

所以我的問題是:在Linux內核中進行調試的這種技術是否存在?

如果不是:是否可以設置硬件(或軟件)中斷,該中斷會對特定內存地址的更改做出反應?然后,我可以設置這樣的中斷處理程序,可以打印出堆棧跟蹤嗎? (雖然,我認為整個上下文在IRQ處理程序運行時會發生變化,因此可能會出現堆棧跟蹤錯誤)?

如果沒有:是否還有其他技術,這將允許我打印進程的堆棧跟蹤,該跟蹤更改存儲在內核中給定內存位置的值(希望在實時的非調試內核中)?

解決方法

非常感謝 @CosminRatiuEugene的回復;多虧了那些,我發現:

> debugging – Linux kernel hardware break points – Stack Overflow
> Hardware Breakpoint (or watchpoint) – The Linux Kernel Archives

…我可以用它來開發我在這里發布的示例,testhrarr.c內核模塊/驅動程序和Makefile(下面).它表明硬件觀察點跟蹤可以通過兩種方式實現:使用perf程序,它可以不變地探測驅動程序;或者通過向驅動程序添加一些硬件斷點代碼(在示例中,由HWDEBUG_STACK定義變量包含).

 

本質上,調試像int這樣的標准原子變量類型(如runco​​unt變量)的內容很簡單,只要它們被定義為內核模塊中的全局變量,因此它們最終全局顯示為內核符號.因此,下面的代碼將testhrarr_添加為變量的前綴(以避免命名沖突).但是,由於需要解除引用,調試數組的內容可能有點棘手 – 這就是本文演示的內容,調試testhrarr_arr數組的第一個字節.它完成於:

  1. $echo `cat /etc/lsb-release`
  2. DISTRIB_ID=Ubuntu DISTRIB_RELEASE=11.04 DISTRIB_CODENAME=natty DISTRIB_DESCRIPTION="Ubuntu 11.04"
  3. $uname -a
  4. Linux mypc 2.6.38-16-generic #67-Ubuntu SMP Thu Sep 6 18:00:43 UTC 2012 i686 i686 i386 GNU/Linux
  5. $cat /proc/cpuinfo | grep "model name"
  6. model name : Intel(R) Atom(TM) CPU N450 @ 1.66GHz
  7. model name : Intel(R) Atom(TM) CPU N450 @ 1.66GHz

testhrarr模塊基本上在模塊初始化時為小數組分配內存,設置定時器函數,並公開/ proc / testhrarr_proc文件(使用較新的proc_create接口).然后,嘗試從/ proc / testhrarr_proc文件(例如,使用cat)讀取將觸發計時器功能,該功能將修改testhrarr_arr數組值,並將消息轉儲到/ var / log / syslog.我們期望testhrarr_arr [0]在操作期間會改變三次;一次在testhrarr_startup中,兩次在testhrarr_timer_function中(由於換行).

使用perf

使用make構建模塊后,您可以使用以下命令加載它:

  1. sudo insmod ./testhrarr.ko

此時,/ var / log / syslog將包含:

  1. kernel: [40277.199913] Init testhrarr: 0 ; HZ: 250 ; 1/HZ (ms): 4 ; hrres: 0.000000001
  2. kernel: [40277.199930] Addresses: _runcount 0xf84be22c ; _arr 0xf84be2a0 ; _arr[0] 0xed182a80 (0xed182a80) ; _timer_function 0xf84bc1c3 ; my_hrtimer 0xf84be260; my_hrt.f 0xf84be27c
  3. kernel: [40277.220329] HW Breakpoint for testhrarr_arr write installed (0xf84be2a0)

注意,只是將testhrarr_arr作為硬件觀察點的符號傳遞,掃描該變量的地址(0xf84be2a0),而不是數組的第一個元素的地址(0xed182a80)!因此,硬件斷點不會觸發 – 因此行為就好像硬件斷點代碼根本不存在(可以通過取消定義HWDEBUG_STACK來實現)!

因此,即使沒有通過內核模塊代碼設置的硬件斷點,我們仍然可以使用perf來觀察內存地址的變化 – 在perf中,我們指定我們要監視的地址(這里是testhrarr_arr的第一個元素的地址,0xed182a80),以及應該運行的進程:這里我們運行bash,所以我們可以執行cat / proc / testhrarr_proc,它將觸發內核模塊定時器,然后是sleep 0.5,這將允許定時器完成. -a參數也是必需的,否則可能會遺漏一些事件:

  1. $sudo perf record -a --call-graph --event=mem:0xed182a80:w bash -c 'cat /proc/testhrarr_proc ; sleep 0.5'
  2. testhrarr proc: startup
  3. [ perf record: Woken up 1 times to write data ]
  4. [ perf record: Captured and wrote 0.485 MB perf.data (~21172 samples) ]

此時,/ var / log / syslog還包含以下內容:

  1. [40822.114964] testhrarr_timer_function: testhrarr_runcount 0
  2. [40822.114980] testhrarr jiffies 10130528 ; ret: 1 ; ktnsec: 40822114975062
  3. [40822.118956] testhrarr_timer_function: testhrarr_runcount 1
  4. [40822.118977] testhrarr jiffies 10130529 ; ret: 1 ; ktnsec: 40822118973195
  5. [40822.122940] testhrarr_timer_function: testhrarr_runcount 2
  6. [40822.122956] testhrarr jiffies 10130530 ; ret: 1 ; ktnsec: 40822122951143
  7. [40822.126962] testhrarr_timer_function: testhrarr_runcount 3
  8. [40822.126978] testhrarr jiffies 10130531 ; ret: 1 ; ktnsec: 40822126973583
  9. [40822.130941] testhrarr_timer_function: testhrarr_runcount 4
  10. [40822.130961] testhrarr jiffies 10130532 ; ret: 1 ; ktnsec: 40822130955167
  11. [40822.134940] testhrarr_timer_function: testhrarr_runcount 5
  12. [40822.134962] testhrarr jiffies 10130533 ; ret: 1 ; ktnsec: 40822134958888
  13. [40822.138936] testhrarr_timer_function: testhrarr_runcount 6
  14. [40822.138958] testhrarr jiffies 10130534 ; ret: 1 ; ktnsec: 40822138955693
  15. [40822.142940] testhrarr_timer_function: testhrarr_runcount 7
  16. [40822.142962] testhrarr jiffies 10130535 ; ret: 1 ; ktnsec: 40822142959345
  17. [40822.146936] testhrarr_timer_function: testhrarr_runcount 8
  18. [40822.146957] testhrarr jiffies 10130536 ; ret: 1 ; ktnsec: 40822146954479
  19. [40822.150949] testhrarr_timer_function: testhrarr_runcount 9
  20. [40822.150970] testhrarr jiffies 10130537 ; ret: 1 ; ktnsec: 40822150963438
  21. [40822.154974] testhrarr_timer_function: testhrarr_runcount 10
  22. [40822.154988] testhrarr [ 5,7,9,11,13,]

要讀取perf(一個名為perf.data的文件)的捕獲,我們可以使用:

  1. $sudo perf report --call-graph flat --stdio
  2. No kallsyms or vmlinux with build-id 5031df4d8668bcc45a7bdb4023909c6f8e2d3d34 was found
  3. [testhrarr] with build id 5031df4d8668bcc45a7bdb4023909c6f8e2d3d34 not found,continuing without symbols
  4. Failed to open /bin/cat,continuing without symbols
  5. Failed to open /usr/lib/libpixman-1.so.0.20.2,continuing without symbols
  6. Failed to open /usr/lib/xorg/modules/drivers/intel_drv.so,continuing without symbols
  7. Failed to open /usr/bin/Xorg,continuing without symbols
  8. # Events: 5 unknown
  9. #
  10. # Overhead Command Shared Object Symbol
  11. # ........ ....... ............. ....................................
  12. #
  13. 87.50% Xorg [testhrarr] [k] testhrarr_timer_function
  14. 87.50%
  15. testhrarr_timer_function
  16. __run_hrtimer
  17. hrtimer_interrupt
  18. smp_apic_timer_interrupt
  19. apic_timer_interrupt
  20. 0x30185d
  21. 0x2ed701
  22. 0x2ed8cc
  23. 0x2edba0
  24. 0x9d0386
  25. 0x8126fc8
  26. 0x81217a1
  27. 0x811bdd3
  28. 0x8070aa7
  29. 0x806281c
  30. __libc_start_main
  31. 0x8062411
  32. 6.25% cat [testhrarr] [k] testhrarr_timer_function
  33. 6.25%
  34. testhrarr_timer_function
  35. testhrarr_proc_show
  36. seq_read
  37. proc_reg_read
  38. vfs_read
  39. sys_read
  40. syscall_call
  41. 0xaa2416
  42. 0x8049f4d
  43. __libc_start_main
  44. 0x8049081
  45. 3.12% swapper [testhrarr] [k] testhrarr_timer_function
  46. 3.12%
  47. testhrarr_timer_function
  48. __run_hrtimer
  49. hrtimer_interrupt
  50. smp_apic_timer_interrupt
  51. apic_timer_interrupt
  52. cpuidle_idle_call
  53. cpu_idle
  54. start_secondary
  55. 3.12% cat [testhrarr] [k] 0x356
  56. 3.12%
  57. 0xf84bc356
  58. 0xf84bc3a7
  59. seq_read
  60. proc_reg_read
  61. vfs_read
  62. sys_read
  63. syscall_call
  64. 0xaa2416
  65. 0x8049f4d
  66. __libc_start_main
  67. 0x8049081
  68. #
  69. # (For a higher level overview,try: perf report --sort comm,dso)
  70. #

因此,由於我們正在使用調試on(Makefile中的-g)構建內核模塊,所以即使實時內核不是調試內核,perf也不能找到該模塊的符號.所以它在大多數時候正確地將testhrarr_timer_function解釋為setter,雖然它沒有報告testhrarr_startup(但它報告了testhrarr_proc_show調用它).還有對0xf84bc3a7和0xf84bc356的引用無法解析;但請注意,模塊加載為0xf84bc000:

  1. $sudo cat /proc/modules | grep testhr
  2. testhrarr 13433 0 - Live 0xf84bc000

……並且該條目也以…開頭[k] 0x356;如果我們查看內核模塊的objdump:

  1. $objdump -S testhrarr.ko | less
  2. ...
  3. 00000323 :
  4. static void testhrarr_startup(void)
  5. {
  6. ...
  7. testhrarr_arr[0] = 0; //just the first element
  8. 34b: a1 80 00 00 00 mov 0x80,%eax
  9. 350: c7 00 00 00 00 00 movl $0x0,(%eax)
  10. hrtimer_start(&my_hrtimer,ktime_period_ns,HRTIMER_MODE_REL);
  11. 356: c7 04 24 01 00 00 00 movl $0x1,(%esp) **********
  12. 35d: 8b 15 1c 00 00 00 mov 0x1c,%edx
  13. ...
  14. 00000375 :
  15. static int testhrarr_proc_show(struct seq_file *m,void *v) {
  16. ...
  17. seq_printf(m,"testhrarr proc: startup\n");
  18. 38f: c7 44 24 04 79 00 00 movl $0x79,0x4(%esp)
  19. 396: 00
  20. 397: 8b 45 fc mov -0x4(%ebp),%eax
  21. 39a: 89 04 24 mov %eax,(%esp)
  22. 39d: e8 fc ff ff ff call 39e
  23. testhrarr_startup();
  24. 3a2: e8 7c ff ff ff call 323
  25. 3a7: eb 1c jmp 3c5 **********
  26. } else {
  27. seq_printf(m,"testhrarr proc: (is running,%d)\n",testhrarr_runcount);
  28. 3a9: a1 0c 00 00 00 mov 0xc,%eax
  29. ...

…所以0xf84bc356顯然是指hrtimer_start;和0xf84bc3a7 – > 3a7指其調用testhrarr_proc_show函數;值得慶幸的是. (請注意,我已經體驗過不同版本的驅動程序,_start可以顯示,而timer_function由純粹的地址表示;不確定是什么原因).

然而,perf的一個問題是,它給了我這些函數的統計“開銷”(不確定是什么意思 – 可能是在函數的進入和退出之間花費的時間?) – 但我真正想要的是堆棧跟蹤的日志是順序的.不確定是否可以為此設置perf – 但絕對可以使用內核模塊代碼來完成硬件斷點.

使用內核模塊HW斷點

HWDEBUG_STACK中的代碼實現了HW斷點的設置和處理.如上所述,符號ksym_name(如果未指定)的默認設置是testhrarr_arr,它根本不觸發硬件斷點.在insmod期間,可以在命令行中指定ksym_name參數;在這里我們可以注意到:

  1. $sudo rmmod testhrarr # remove module if still loaded
  2. $sudo insmod ./testhrarr.ko ksym=testhrarr_arr[0]

…在/ var / log / syslog中安裝了HW Breakpoint for testhrarr_arr [0]的結果(0x(null)); – 這意味着我們不能使用帶括號表示法的符號進行數組訪問;謝天謝地,這里的空指針只是意味着HW斷點將再次不會觸發;它不會完全崩潰操作系統:)

但是,有一個全局變量用於引用testhrarr_arr數組的第一個元素,稱為testhrarr_arr_first – 注意如何在代碼中專門處理此全局變量,並且需要取消引用,以便獲得正確的地址.所以我們這樣做:

  1. $sudo rmmod testhrarr # remove module if still loaded
  2. $sudo insmod ./testhrarr.ko ksym=testhrarr_arr_first

…並且syslog通知:

  1. kernel: [43910.509726] Init testhrarr: 0 ; HZ: 250 ; 1/HZ (ms): 4 ; hrres: 0.000000001
  2. kernel: [43910.509765] Addresses: _runcount 0xf84be22c ; _arr 0xf84be2a0 ; _arr[0] 0xedf6c5c0 (0xedf6c5c0) ; _timer_function 0xf84bc1c3 ; my_hrtimer 0xf84be260; my_hrt.f 0xf84be27c
  3. kernel: [43910.538535] HW Breakpoint for testhrarr_arr_first write installed (0xedf6c5c0)

…我們可以看到HW斷點設置為0xedf6c5c0,這是testhrarr_arr [0]的地址.現在,如果我們通過/ proc文件觸發驅動程序:

  1. $cat /proc/testhrarr_proc
  2. testhrarr proc: startup

…我們在syslog中獲取:

  1. kernel: [44069.735695] testhrarr_arr_first value is changed
  2. [44069.735711] Pid: 29320,comm: cat Not tainted 2.6.38-16-generic #67-Ubuntu
  3. [44069.735719] Call Trace:
  4. [44069.735737] [] ? sample_hbp_handler+0x2d/0x3b [testhrarr]
  5. [44069.735755] [] ? __perf_event_overflow+0x90/0x240
  6. [44069.735768] [] ? proc_alloc_inode+0x23/0x90
  7. [44069.735778] [] ? proc_alloc_inode+0x23/0x90
  8. [44069.735790] [] ? perf_swevent_event+0x136/0x140
  9. [44069.735801] [] ? perf_bp_event+0x70/0x80
  10. [44069.735812] [] ? prep_new_page+0x110/0x1a0
  11. [44069.735824] [] ? get_page_from_freelist+0x12e/0x320
  12. [44069.735836] [] ? seq_open+0x3d/0xa0
  13. [44069.735848] [] ? hw_breakpoint_handler.clone.0+0x102/0x130
  14. [44069.735861] [] ? hw_breakpoint_exceptions_notify+0x22/0x30
  15. [44069.735872] [] ? notifier_call_chain+0x45/0x60
  16. [44069.735883] [] ? atomic_notifier_call_chain+0x22/0x30
  17. [44069.735894] [] ? notify_die+0x2d/0x30
  18. [44069.735904] [] ? do_debug+0x88/0x180
  19. [44069.735915] [] ? debug_stack_correct+0x30/0x38
  20. [44069.735928] [] ? testhrarr_startup+0x33/0x52 [testhrarr]
  21. [44069.735940] [] ? testhrarr_proc_show+0x32/0x57 [testhrarr]
  22. [44069.735952] [] ? seq_read+0x145/0x390
  23. [44069.735963] [] ? seq_read+0x0/0x390
  24. [44069.735973] [] ? proc_reg_read+0x64/0xa0
  25. [44069.735985] [] ? vfs_read+0x9f/0x160
  26. [44069.735995] [] ? proc_reg_read+0x0/0xa0
  27. [44069.736003] [] ? sys_read+0x42/0x70
  28. [44069.736013] [] ? syscall_call+0x7/0xb
  29. [44069.736019] Dump stack from sample_hbp_handler
  30. [44069.740132] testhrarr_timer_function: testhrarr_runcount 0
  31. [44069.740146] testhrarr jiffies 10942435 ; ret: 1 ; ktnsec: 44069740142485
  32. [44069.740159] testhrarr_arr_first value is changed
  33. [44069.740169] Pid: 4302,comm: gnome-terminal Not tainted 2.6.38-16-generic #67-Ubuntu
  34. [44069.740176] Call Trace:
  35. [44069.740195] [] ? sample_hbp_handler+0x2d/0x3b [testhrarr]
  36. [44069.740213] [] ? __perf_event_overflow+0x90/0x240
  37. [44069.740227] [] ? perf_swevent_event+0x136/0x140
  38. [44069.740239] [] ? perf_bp_event+0x70/0x80
  39. [44069.740253] [] ? sched_clock_local+0xd3/0x1c0
  40. [44069.740267] [] ? format_decode+0x323/0x380
  41. [44069.740280] [] ? hw_breakpoint_handler.clone.0+0x102/0x130
  42. [44069.740292] [] ? hw_breakpoint_exceptions_notify+0x22/0x30
  43. [44069.740302] [] ? notifier_call_chain+0x45/0x60
  44. [44069.740313] [] ? atomic_notifier_call_chain+0x22/0x30
  45. [44069.740324] [] ? notify_die+0x2d/0x30
  46. [44069.740335] [] ? do_debug+0x88/0x180
  47. [44069.740345] [] ? debug_stack_correct+0x30/0x38
  48. [44069.740364] [] ? init_intel_cacheinfo+0x103/0x394
  49. [44069.740379] [] ? testhrarr_timer_function+0xed/0x160 [testhrarr]
  50. [44069.740391] [] ? __run_hrtimer+0x6f/0x190
  51. [44069.740404] [] ? testhrarr_timer_function+0x0/0x160 [testhrarr]
  52. [44069.740416] [] ? hrtimer_interrupt+0x108/0x240
  53. [44069.740430] [] ? smp_apic_timer_interrupt+0x56/0x8a
  54. [44069.740441] [] ? apic_timer_interrupt+0x31/0x38
  55. [44069.740453] [] ? _raw_spin_unlock_irqrestore+0x15/0x20
  56. [44069.740465] [] ? try_to_del_timer_sync+0x67/0xb0
  57. [44069.740476] [] ? del_timer_sync+0x29/0x50
  58. [44069.740486] [] ? flush_delayed_work+0x13/0x40
  59. [44069.740500] [] ? tty_flush_to_ldisc+0x12/0x20
  60. [44069.740510] [] ? n_tty_poll+0x4f/0x190
  61. [44069.740523] [] ? tty_poll+0x6d/0x90
  62. [44069.740531] [] ? n_tty_poll+0x0/0x190
  63. [44069.740542] [] ? do_poll.clone.3+0xd0/0x210
  64. [44069.740553] [] ? do_sys_poll+0x134/0x1e0
  65. [44069.740563] [] ? __pollwait+0x0/0xd0
  66. [44069.740572] [] ? pollwake+0x0/0x60
  67. ...
  68. [44069.740742] [] ? pollwake+0x0/0x60
  69. [44069.740757] [] ? rw_verify_area+0x6c/0x130
  70. [44069.740770] [] ? ktime_get_ts+0xf8/0x120
  71. [44069.740781] [] ? poll_select_set_timeout+0x64/0x70
  72. [44069.740793] [] ? sys_poll+0x5a/0xd0
  73. [44069.740804] [] ? syscall_call+0x7/0xb
  74. [44069.740815] [] ? init_intel_cacheinfo+0x23/0x394
  75. [44069.740822] Dump stack from sample_hbp_handler
  76. [44069.744130] testhrarr_timer_function: testhrarr_runcount 1
  77. [44069.744143] testhrarr jiffies 10942436 ; ret: 1 ; ktnsec: 44069744140055
  78. [44069.748132] testhrarr_timer_function: testhrarr_runcount 2
  79. [44069.748145] testhrarr jiffies 10942437 ; ret: 1 ; ktnsec: 44069748141271
  80. [44069.752131] testhrarr_timer_function: testhrarr_runcount 3
  81. [44069.752145] testhrarr jiffies 10942438 ; ret: 1 ; ktnsec: 44069752141164
  82. [44069.756131] testhrarr_timer_function: testhrarr_runcount 4
  83. [44069.756141] testhrarr jiffies 10942439 ; ret: 1 ; ktnsec: 44069756138318
  84. [44069.760130] testhrarr_timer_function: testhrarr_runcount 5
  85. [44069.760141] testhrarr jiffies 10942440 ; ret: 1 ; ktnsec: 44069760138469
  86. [44069.760154] testhrarr_arr_first value is changed
  87. [44069.760164] Pid: 4302,comm: gnome-terminal Not tainted 2.6.38-16-generic #67-Ubuntu
  88. [44069.760170] Call Trace:
  89. [44069.760187] [] ? sample_hbp_handler+0x2d/0x3b [testhrarr]
  90. [44069.760202] [] ? __perf_event_overflow+0x90/0x240
  91. [44069.760213] [] ? perf_swevent_event+0x136/0x140
  92. [44069.760224] [] ? perf_bp_event+0x70/0x80
  93. [44069.760235] [] ? sched_clock_local+0xd3/0x1c0
  94. [44069.760247] [] ? format_decode+0x323/0x380
  95. [44069.760258] [] ? hw_breakpoint_handler.clone.0+0x102/0x130
  96. [44069.760269] [] ? hw_breakpoint_exceptions_notify+0x22/0x30
  97. [44069.760279] [] ? notifier_call_chain+0x45/0x60
  98. [44069.760289] [] ? atomic_notifier_call_chain+0x22/0x30
  99. [44069.760299] [] ? notify_die+0x2d/0x30
  100. [44069.760308] [] ? do_debug+0x88/0x180
  101. [44069.760318] [] ? debug_stack_correct+0x30/0x38
  102. [44069.760334] [] ? init_intel_cacheinfo+0x103/0x394
  103. [44069.760345] [] ? testhrarr_timer_function+0xed/0x160 [testhrarr]
  104. [44069.760356] [] ? __run_hrtimer+0x6f/0x190
  105. [44069.760366] [] ? send_to_group.clone.1+0xf8/0x150
  106. [44069.760376] [] ? testhrarr_timer_function+0x0/0x160 [testhrarr]
  107. [44069.760387] [] ? hrtimer_interrupt+0x108/0x240
  108. [44069.760396] [] ? fsnotify+0x1a5/0x290
  109. [44069.760407] [] ? smp_apic_timer_interrupt+0x56/0x8a
  110. [44069.760416] [] ? apic_timer_interrupt+0x31/0x38
  111. [44069.760428] [] ? mem_cgroup_resize_limit+0x108/0x1c0
  112. [44069.760437] [] ? fput+0x0/0x30
  113. [44069.760446] [] ? sys_write+0x67/0x70
  114. [44069.760455] [] ? syscall_call+0x7/0xb
  115. [44069.760464] [] ? init_intel_cacheinfo+0x23/0x394
  116. [44069.760470] Dump stack from sample_hbp_handler
  117. [44069.764134] testhrarr_timer_function: testhrarr_runcount 6
  118. [44069.764147] testhrarr jiffies 10942441 ; ret: 1 ; ktnsec: 44069764144141
  119. [44069.768133] testhrarr_timer_function: testhrarr_runcount 7
  120. [44069.768146] testhrarr jiffies 10942442 ; ret: 1 ; ktnsec: 44069768142976
  121. [44069.772134] testhrarr_timer_function: testhrarr_runcount 8
  122. [44069.772148] testhrarr jiffies 10942443 ; ret: 1 ; ktnsec: 44069772144121
  123. [44069.776132] testhrarr_timer_function: testhrarr_runcount 9
  124. [44069.776145] testhrarr jiffies 10942444 ; ret: 1 ; ktnsec: 44069776141971
  125. [44069.780133] testhrarr_timer_function: testhrarr_runcount 10
  126. [44069.780141] testhrarr [ 5,]

…我們得到一個堆棧跟蹤正好三次 – 一次在testhrarr_startup期間,兩次在testhrarr_timer_function中:一次用於runco​​unt == 0,一次用於runco​​unt == 5,如預期的那樣.

嗯,希望這有助於某人,
干杯!

Makefile文件

  1. CONFIG_MODULE_FORCE_UNLOAD=y
  2.  
  3. # debug build:
  4. # "CFLAGS was changed ... Fix it to use EXTRA_CFLAGS."
  5. override EXTRA_CFLAGS+=-g -O0
  6.  
  7. obj-m += testhrarr.o
  8. #testhrarr-objs := testhrarr.o
  9.  
  10. all:
  11. @echo EXTRA_CFLAGS = $(EXTRA_CFLAGS)
  12. make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
  13.  
  14. clean:
  15. make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

testhrarr.c

  1. /*
  2. * [http://www.tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN189 The Linux Kernel Module Programming Guide]
  3. * https://stackoverflow.com/questions/16920238/reliability-of-linux-kernel-add-timer-at-resolution-of-one-jiffy/17055867#17055867
  4. * https://stackoverflow.com/questions/8516021/proc-create-example-for-kernel-module/18924359#18924359
  5. * http://lxr.free-electrons.com/source/samples/hw_breakpoint/data_breakpoint.c
  6. */
  7.  
  8.  
  9. #include <linux/module.h> /* Needed by all modules */
  10. #include <linux/kernel.h> /* Needed for KERN_INFO */
  11. #include <linux/init.h> /* Needed for the macros */
  12. #include <linux/jiffies.h>
  13. #include <linux/time.h>
  14. #include <linux/proc_fs.h> /* /proc entry */
  15. #include <linux/seq_file.h> /* /proc entry */
  16. #define ARRSIZE 5
  17. #define MAXRUNS 2*ARRSIZE
  18.  
  19. #include <linux/hrtimer.h>
  20.  
  21. #define HWDEBUG_STACK 1
  22.  
  23. #if (HWDEBUG_STACK == 1)
  24. #include <linux/perf_event.h>
  25. #include <linux/hw_breakpoint.h>
  26.  
  27. struct perf_event * __percpu *sample_hbp;
  28. static char ksym_name[KSYM_NAME_LEN] = "testhrarr_arr";
  29. module_param_string(ksym,ksym_name,KSYM_NAME_LEN,S_IRUGO);
  30. MODULE_PARM_DESC(ksym,"Kernel symbol to monitor; this module will report any"
  31. " write operations on the kernel symbol");
  32. #endif
  33.  
  34. static volatile int testhrarr_runcount = 0;
  35. static volatile int testhrarr_isRunning = 0;
  36.  
  37. static unsigned long period_ms;
  38. static unsigned long period_ns;
  39. static ktime_t ktime_period_ns;
  40. static struct hrtimer my_hrtimer;
  41.  
  42. static int* testhrarr_arr;
  43. static int* testhrarr_arr_first;
  44.  
  45. static enum hrtimer_restart testhrarr_timer_function(struct hrtimer *timer)
  46. {
  47. unsigned long tjnow;
  48. ktime_t kt_now;
  49. int ret_overrun;
  50.  
  51. printk(KERN_INFO
  52. " %s: testhrarr_runcount %d \n",__func__,testhrarr_runcount);
  53.  
  54. if (testhrarr_runcount < MAXRUNS) {
  55. tjnow = jiffies;
  56. kt_now = hrtimer_cb_get_time(&my_hrtimer);
  57. ret_overrun = hrtimer_forward(&my_hrtimer,kt_now,ktime_period_ns);
  58. printk(KERN_INFO
  59. " testhrarr jiffies %lu ; ret: %d ; ktnsec: %lld\n",tjnow,ret_overrun,ktime_to_ns(kt_now));
  60. testhrarr_arr[(testhrarr_runcount % ARRSIZE)] += testhrarr_runcount;
  61. testhrarr_runcount++;
  62. return HRTIMER_RESTART;
  63. }
  64. else {
  65. int i;
  66. testhrarr_isRunning = 0;
  67. // do not use KERN_DEBUG etc,if printk buffering until newline is desired!
  68. printk("testhrarr_arr [ ");
  69. for(i=0; i<ARRSIZE; i++) {
  70. printk("%d,",testhrarr_arr[i]);
  71. }
  72. printk("]\n");
  73. return HRTIMER_NORESTART;
  74. }
  75. }
  76.  
  77. static void testhrarr_startup(void)
  78. {
  79. if (testhrarr_isRunning == 0) {
  80. testhrarr_isRunning = 1;
  81. testhrarr_runcount = 0;
  82. testhrarr_arr[0] = 0; //just the first element
  83. hrtimer_start(&my_hrtimer,HRTIMER_MODE_REL);
  84. }
  85. }
  86.  
  87.  
  88. static int testhrarr_proc_show(struct seq_file *m,void *v) {
  89. if (testhrarr_isRunning == 0) {
  90. seq_printf(m,"testhrarr proc: startup\n");
  91. testhrarr_startup();
  92. } else {
  93. seq_printf(m,testhrarr_runcount);
  94. }
  95. return 0;
  96. }
  97.  
  98. static int testhrarr_proc_open(struct inode *inode,struct file *file) {
  99. return single_open(file,testhrarr_proc_show,NULL);
  100. }
  101.  
  102. static const struct file_operations testhrarr_proc_fops = {
  103. .owner = THIS_MODULE,.open = testhrarr_proc_open,.read = seq_read,.llseek = seq_lseek,.release = single_release,};
  104.  
  105.  
  106. #if (HWDEBUG_STACK == 1)
  107. static void sample_hbp_handler(struct perf_event *bp,struct perf_sample_data *data,struct pt_regs *regs)
  108. {
  109. printk(KERN_INFO "%s value is changed\n",ksym_name);
  110. dump_stack();
  111. printk(KERN_INFO "Dump stack from sample_hbp_handler\n");
  112. }
  113. #endif
  114.  
  115. static int __init testhrarr_init(void)
  116. {
  117. struct timespec tp_hr_res;
  118. #if (HWDEBUG_STACK == 1)
  119. struct perf_event_attr attr;
  120. #endif
  121.  
  122. period_ms = 1000/HZ;
  123. hrtimer_get_res(CLOCK_MONOTONIC,&tp_hr_res);
  124. printk(KERN_INFO
  125. "Init testhrarr: %d ; HZ: %d ; 1/HZ (ms): %ld ; hrres: %lld.%.9ld\n",testhrarr_runcount,HZ,period_ms,(long long)tp_hr_res.tv_sec,tp_hr_res.tv_nsec );
  126.  
  127. testhrarr_arr = (int*)kcalloc(ARRSIZE,sizeof(int),GFP_ATOMIC);
  128. testhrarr_arr_first = &testhrarr_arr[0];
  129.  
  130. hrtimer_init(&my_hrtimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);
  131. my_hrtimer.function = &testhrarr_timer_function;
  132. period_ns = period_ms*( (unsigned long)1E6L );
  133. ktime_period_ns = ktime_set(0,period_ns);
  134.  
  135. printk(KERN_INFO
  136. " Addresses: _runcount 0x%p ; _arr 0x%p ; _arr[0] 0x%p (0x%p) ; _timer_function 0x%p ; my_hrtimer 0x%p; my_hrt.f 0x%p\n",&testhrarr_runcount,&testhrarr_arr,&(testhrarr_arr[0]),testhrarr_arr_first,&testhrarr_timer_function,&my_hrtimer,&my_hrtimer.function);
  137.  
  138.  
  139. proc_create("testhrarr_proc",NULL,&testhrarr_proc_fops);
  140.  
  141.  
  142. #if (HWDEBUG_STACK == 1)
  143. hw_breakpoint_init(&attr);
  144. if (strcmp(ksym_name,"testhrarr_arr_first") == 0) {
  145. // just for testhrarr_arr_first - interpret the found symbol address
  146. // as int*,and dereference it to get the "real" address it points to
  147. attr.bp_addr = *((int*)kallsyms_lookup_name(ksym_name));
  148. } else {
  149. // the usual - address is kallsyms_lookup_name result
  150. attr.bp_addr = kallsyms_lookup_name(ksym_name);
  151. }
  152. attr.bp_len = HW_BREAKPOINT_LEN_1;
  153. attr.bp_type = HW_BREAKPOINT_W ; //| HW_BREAKPOINT_R;
  154.  
  155. sample_hbp = register_wide_hw_breakpoint(&attr,(perf_overflow_handler_t)sample_hbp_handler);
  156. if (IS_ERR((void __force *)sample_hbp)) {
  157. int ret = PTR_ERR((void __force *)sample_hbp);
  158. printk(KERN_INFO "Breakpoint registration failed\n");
  159. return ret;
  160. }
  161.  
  162. // explicit cast needed to show 64-bit bp_addr as 32-bit address
  163. // https://stackoverflow.com/questions/11796909/how-to-resolve-cast-to-pointer-from-integer-of-different-size-warning-in-c-co/11797103#11797103
  164. printk(KERN_INFO "HW Breakpoint for %s write installed (0x%p)\n",(void*)(uintptr_t)attr.bp_addr);
  165. #endif
  166.  
  167. return 0;
  168. }
  169.  
  170. static void __exit testhrarr_exit(void)
  171. {
  172. int ret_cancel = 0;
  173. kfree(testhrarr_arr);
  174. while( hrtimer_callback_running(&my_hrtimer) ) {
  175. ret_cancel++;
  176. }
  177. if (ret_cancel != 0) {
  178. printk(KERN_INFO " testhrarr Waited for hrtimer callback to finish (%d)\n",ret_cancel);
  179. }
  180. if (hrtimer_active(&my_hrtimer) != 0) {
  181. ret_cancel = hrtimer_cancel(&my_hrtimer);
  182. printk(KERN_INFO " testhrarr active hrtimer cancelled: %d (%d)\n",ret_cancel,testhrarr_runcount);
  183. }
  184. if (hrtimer_is_queued(&my_hrtimer) != 0) {
  185. ret_cancel = hrtimer_cancel(&my_hrtimer);
  186. printk(KERN_INFO " testhrarr queued hrtimer cancelled: %d (%d)\n",testhrarr_runcount);
  187. }
  188. remove_proc_entry("testhrarr_proc",NULL);
  189. #if (HWDEBUG_STACK == 1)
  190. unregister_wide_hw_breakpoint(sample_hbp);
  191. printk(KERN_INFO "HW Breakpoint for %s write uninstalled\n",ksym_name);
  192. #endif
  193. printk(KERN_INFO "Exit testhrarr\n");
  194. }
  195.  
  196. module_init(testhrarr_init);
  197. module_exit(testhrarr_exit);
  198.  
  199. MODULE_LICENSE("GPL");

總結

以上是腳本之家為你收集整理的調試 – 觀察Linux內核中的變量(內存地址)更改,並在更改時打印堆棧跟蹤?全部內容,希望文章能夠幫你解決調試 – 觀察Linux內核中的變量(內存地址)更改,並在更改時打印堆棧跟蹤?所遇到的程序開發問題。

如果覺得腳本之家網站內容還不錯,歡迎將腳本之家網站推薦給程序員好友。

本圖文內容來源於網友網絡收集整理提供,作為學習參考使用,版權屬於原作者。
如您喜歡交流學習經驗, 點擊鏈接加入腳本之家官方QQ群:1065694478


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM