使用 tracer 進行除錯¶
版權所有 2024 Google LLC.
- 作者:
Steven Rostedt <rostedt@goodmis.org>
- 許可證:
GNU 自由文件許可證,版本 1.2(在 GPL v2 下雙重許可)
編寫於: 6.12
簡介¶
跟蹤基礎設施對於除錯 Linux 核心非常有用。本文件用於新增各種使用 tracer 進行除錯的方法。
首先,請確保已掛載 tracefs 檔案系統
$ sudo mount -t tracefs tracefs /sys/kernel/tracing
使用 trace_printk()¶
trace_printk() 是一個非常輕量級的實用程式,可以在核心中的任何上下文中使用,除了“noinstr”部分。 它可以在 normal、softirq、interrupt 甚至 NMI 上下文中使用。 跟蹤資料以無鎖的方式寫入跟蹤環形緩衝區。 為了使其更輕量級,在可能的情況下,它只會記錄格式字串的指標,並將原始引數儲存到緩衝區中。 當讀取環形緩衝區時,將對格式和引數進行後處理。 這樣,trace_printk() 格式轉換不會在熱路徑中完成,而是在記錄跟蹤時完成。
trace_printk() 僅用於除錯,永遠不應新增到核心的子系統中。 如果您需要除錯跟蹤,請新增跟蹤事件。 如果在核心中找到 trace_printk(),則以下內容將出現在 dmesg 中
**********************************************************
** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **
** **
** trace_printk() being used. Allocating extra memory. **
** **
** This means that this is a DEBUG kernel and it is **
** unsafe for production use. **
** **
** If you see this message and you are not debugging **
** the kernel, report this immediately to your vendor! **
** **
** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **
**********************************************************
除錯核心崩潰¶
當核心崩潰發生時,有多種方法可以獲取系統的狀態。 這可能來自 printk 中的 oops 訊息,或者可以使用 kexec/kdump。 但這些只顯示了崩潰時發生的事情。 瞭解崩潰發生之前的過程可能非常有用。 預設情況下,跟蹤環形緩衝區是一個迴圈緩衝區,它將使用較新的事件覆蓋較舊的事件。 當發生崩潰時,環形緩衝區的內容將是導致崩潰的所有事件。
有幾個核心命令列引數可以用來幫助解決這個問題。 第一個是“ftrace_dump_on_oops”。 這會將跟蹤環形緩衝區轉儲到控制檯上的 oops 發生時。 如果控制檯被記錄在某個地方,這可能很有用。 如果使用序列控制檯,則必須確保環形緩衝區相對較小,否則轉儲環形緩衝區可能需要幾分鐘到幾小時才能完成。 這是一個核心命令列的示例
ftrace_dump_on_oops trace_buf_size=50K
請注意,跟蹤緩衝區由每個 CPU 的緩衝區組成,其中每個緩衝區被分成子緩衝區,預設大小為 PAGE_SIZE。 上面的 trace_buf_size 選項將每個 CPU 的緩衝區設定為 50K,因此,在具有 8 個 CPU 的機器上,總共是 400K。
跨啟動的持久緩衝區¶
如果系統記憶體允許,可以在記憶體中的特定位置指定跟蹤環形緩衝區。 如果該位置在啟動時相同並且記憶體未被修改,則可以從以下啟動中檢索跟蹤緩衝區。 有兩種方法可以保留記憶體供環形緩衝區使用。
更可靠的方法(在 x86 上)是使用“memmap”核心命令列選項保留記憶體,然後將該記憶體用於 trace_instance。 這需要對系統的物理記憶體佈局有一定的瞭解。 使用此方法的優點是,環形緩衝區的記憶體將始終相同
memmap==12M$0x284500000 trace_instance=boot_map@0x284500000:12M
上面的 memmap 在物理記憶體位置 0x284500000 保留了 12 兆位元組的記憶體。 然後,trace_instance 選項將在同一位置使用相同數量的保留記憶體建立一個跟蹤例項“boot_map”。 由於環形緩衝區被分成每個 CPU 的緩衝區,因此 12 兆位元組將在這些 CPU 之間平均分配。 如果您有 8 個 CPU,則每個 CPU 的環形緩衝區的大小為 1.5 兆位元組。 請注意,這也包括元資料,因此環形緩衝區實際使用的記憶體量會略小一些。
另一種更通用但不太強大的方法是在啟動時使用“reserve_mem”選項分配環形緩衝區對映
reserve_mem=12M:4096:trace trace_instance=boot_map@trace
上面的 reserve_mem 選項將在啟動時找到 12 兆位元組可用記憶體,並按 4096 位元組對齊。 它會將此記憶體標記為“trace”,供以後的命令列選項使用。
trace_instance 選項建立一個“boot_map”例項,並將使用 reserve_mem 保留的標記為“trace”的記憶體。 這種方法更通用,但可能不太可靠。 由於 KASLR,reserve_mem 保留的記憶體可能不在同一位置。 如果發生這種情況,則環形緩衝區將不是來自上一次啟動,而是會被重置。
有時,透過使用更大的對齊方式,可以防止 KASLR 以某種方式移動事物,從而移動 reserve_mem 的位置。 透過使用更大的對齊方式,您可能會發現緩衝區的位置更穩定。
reserve_mem=12M:0x2000000:trace trace_instance=boot_map@trace
在啟動時,將驗證為環形緩衝區保留的記憶體。 它將透過一系列測試來確保環形緩衝區包含有效資料。 如果是,它將設定它以使其可以從例項讀取。 如果任何測試失敗,它將清除整個環形緩衝區並將其初始化為新的。
這種對映記憶體的佈局可能因核心而異,因此只有相同的核心才能保證在保留對映時正常工作。 切換到不同的核心版本可能會發現不同的佈局,並將緩衝區標記為無效。
注意:對映的地址和大小對於架構而言都必須是頁面對齊的。
在啟動例項中使用 trace_printk()¶
預設情況下,trace_printk() 的內容進入頂層跟蹤例項。 但此例項永遠不會跨啟動保留。 為了擁有 trace_printk() 內容和一些其他的內部跟蹤進入保留的緩衝區(如轉儲堆疊),可以從核心命令列將例項設定為 trace_printk() 目的地,或者透過 trace_printk_dest 選項在啟動後進行設定。
啟動後
echo 1 > /sys/kernel/tracing/instances/boot_map/options/trace_printk_dest
從核心命令列
reserve_mem=12M:4096:trace trace_instance=boot_map^traceprintk^traceoff@trace
如果從核心命令列進行設定,建議也使用“traceoff”標誌停用跟蹤,並在啟動後啟用跟蹤。 否則,來自最新啟動的跟蹤將與來自上一次啟動的跟蹤混合,這可能會使讀取變得混亂。