linux程序分析命令(一)
- **ldd:**用于打印共享庫依賴。這個命令會顯示出一個可執行文件所依賴的所有共享庫(動態鏈接庫),這對于解決運行時庫依賴問題非常有用。
- **nm:**用于列出對象文件的符號表。這個命令可以顯示出定義和引用的符號,對于理解程序結構和調試非常有幫助。
- objdump:顯示二進制文件的信息。這個命令可以用來顯示程序的匯編代碼、段信息等,對于底層分析和調試很有用。
- strace:跟蹤系統調用。通過這個命令,你可以看到一個程序執行時所有的系統調用,這對于理解程序如何與操作系統交互非常重要。
- ltrace:跟蹤庫函數調用。與strace類似,但是ltrace專注于跟蹤程序調用庫函數的情況。
- gdb:GNU調試器。這是一個功能強大的調試工具,可以讓你看到程序執行時的內部情況,比如變量的值、程序的執行流程等。
- valgrind:內存調試工具。這個工具主要用于檢測內存泄漏、內存損壞等問題,對于提高程序穩定性非常有幫助。
- readelf:顯示ELF格式文件的信息。這個命令可以顯示出ELF格式的二進制文件(如Linux下的可執行文件和共享庫)的詳細信息,包括段、節、符號等。
- file:確定文件類型。這個命令可以幫助你識別一個文件是二進制可執行文件、文本文件還是其他類型的文件。
- size:顯示二進制文件的段大小。這個命令會列出二進制文件各個段(如文本段、數據段)的大小,對于評估程序占用空間有一定幫助。
ldd命令
ldd命令是Linux下一個非常實用的工具,它用于顯示一個可執行文件或共享庫文件的依賴關系。基本上,它會列出程序運行所需要的所有共享庫。
下面是ldd的基本用法和一些常見的使用場景。
基本用法
#命令格式:
ldd [選項] 文件...
#文件...:指定要檢查的可執行文件或共享庫文件。
最簡單的用法是直接跟上你想要檢查的文件名:
ldd /path/to/your/program
#這條命令會列出/path/to/your/program這個程序所依賴的所有共享庫。
常見用法
檢查可執行文件的依賴庫:
ldd /usr/bin/ls
#這會顯示ls命令所依賴的所有共享庫。
檢查動態庫的依賴:
#如果你有一個共享庫文件(例如,libexample.so),你可以使用ldd來查看它依賴哪些其他庫:
ldd libexample.so
過濾輸出:
#如果你只對特定的依賴感興趣,可以使用管道和grep命令來過濾輸出。例如,如果你只想看看是否依賴于libc.so.6:
ldd /path/to/your/program | grep libc.so.6
解決“不是動態可執行文件”錯誤:
如果你嘗試對靜態鏈接的可執行文件使用ldd,你可能會收到一個錯誤消息說“不是動態可執行文件”。這意味著該文件沒有使用動態鏈接。在這種情況下,沒有依賴關系可以顯示。
使用ldd調試加載問題:
當你的程序因為缺少某個共享庫而不能啟動時,ldd可以幫助你快速識別缺少了哪個庫。然后,你可以安裝缺少的庫或調整環境變量來解決問題。
高級用法
- 使用LD_TRACE_LOADED_OBJECTS環境變量
ldd實際上是通過設置LD_TRACE_LOADED_OBJECTS=1環境變量來工作的。你可以直接使用這個環境變量來獲取相同的輸出,這在某些特殊情況下可能會有用:
LD_TRACE_LOADED_OBJECTS=1 /path/to/your/program
- 檢查程序如何使用特定的共享庫
如果你想要檢查一個程序是如何使用特定的共享庫的,可以結合使用ldd和nm命令。首先使用ldd找出依賴,然后用nm檢查符號信息:
ldd /path/to/your/program | grep libexample.so
nm -D /path/to/libexample.so
- 使用ldd進行安全檢查
雖然ldd主要用于依賴檢查,但它也可以幫助識別潛在的安全風險。例如,通過檢查程序依賴的庫是否都來自可信路徑,可以幫助識別可能的庫劫持或路徑注入問題。
ldd /path/to/your/program | grep -v "^/"
-
解決依賴問題
當你遇到因缺少共享庫而導致的程序啟動問題時,ldd可以幫助你快速定位缺少哪個庫。通過比較不同環境(例如,開發和生產)下的ldd輸出,你可以找出缺失的依賴。 -
結合使用strace
雖然不是ldd的直接用法,但結合使用strace可以幫助你深入了解程序在運行時的行為,包括它如何加載共享庫。通過觀察程序啟動過程中的系統調用strace /path/to/your/program 2>&1 | grep openat
nm 命令
nm命令在Linux中是一個非常有用的工具,它用于列出目標文件的符號表內容。符號表主要包含了程序中各種變量、函數的名稱、類型、地址等信息。
下面是nm命令的一些基本用法:
查看目標文件的符號表:
nm 目標文件名
這將列出目標文件中所有符號的名稱、類型和地址。
只顯示未定義的符號:
nm -u 目標文件名
這個選項 (-u) 只會列出那些未定義的符號,這對于找出缺失的鏈接非常有用。
按大小排序顯示符號:
nm --size-sort 目標文件名
使用 --size-sort 選項可以按照符號大小進行排序顯示,這有助于分析哪些符號占用了較多空間。
只顯示特定類型的符號:
nm --defined-only 目標文件名
通過 --defined-only 選項,可以只列出已定義的符號,忽略未定義的符號。
查看動態鏈接庫中的符號:
nm -D 動態鏈接庫文件名
-D 或 --dynamic 選項用于查看動態鏈接庫(.so 文件)中的符號。
過濾輸出結果:
nm 目標文件名 | grep 符號名稱
使用管道 (|) 和 grep 命令可以過濾輸出結果,僅顯示與特定符號名稱相關的行。
查看C++程序的符號:
nm -C 目標文件名
-C 或 --demangle 選項用于顯示C++程序中更易讀的符號名稱,因為C++編譯器通常會改變函數名(名字修飾)以支持重載等特性。
解析C++的符號名:
C++程序中的符號名經過編譯器處理后會變得難以閱讀。使用c++filt工具可以將這些符號名解析成更易于理解的形式。
nm 目標文件名 | c++filt
這樣可以使C++的復雜符號名變得可讀。
使用正則表達式過濾符號:
nm命令支持使用正則表達式來過濾顯示的符號,這在你想要查找符合特定模式的符號時非常有用。
nm 目標文件名 | grep '正則表達式'
例如,使用grep '^T’可以過濾出所有類型為T(即在文本段中的符號)的符號。
比較不同版本的二進制文件:
通過比較不同版本的二進制文件中的符號表,可以快速了解兩個版本之間增加或刪除了哪些功能。
nm -an 舊版本文件名 > old_symbols.txt
nm -an 新版本文件名 > new_symbols.txt
diff old_symbols.txt new_symbols.txt
這里,-a選項表示列出所有符號,包括調試符號;-n選項表示按照地址排序。
查看符號的大小:
#使用--print-size選項可以打印每個符號的大小,這對于分析程序占用空間非常有幫助。
nm --print-size 目標文件名
輸出格式化的信息:
#nm命令允許通過--format或者-f選項指定輸出格式,支持的格式包括bsd、sysv、posix等,這有助于根據需求調整輸出信息的格式。
nm --format=sysv 目標文件名
查找靜態庫中未使用的函數:
#創建一個包含所有符號的列表,然后使用nm檢查靜態庫(.a文件)中哪些函數未被使用。
nm --undefined-only 靜態庫文件名
這將列出所有未定義的符號,即可能未被使用的函數。