鍍金池/ 教程/ Linux/ 程序調(diào)試
進(jìn)程管理工具
objdump 二進(jìn)制文件分析
scp 跨機(jī)遠(yuǎn)程拷貝
crontab 定時任務(wù)
readelf elf文件格式分析
pstack 跟蹤進(jìn)程棧
系統(tǒng)管理及IPC資源管理
vmstat 監(jiān)視內(nèi)存使用情況
strace 跟蹤進(jìn)程中的系統(tǒng)調(diào)用
sar 找出系統(tǒng)瓶頸的利器
ipcs 查詢進(jìn)程間通信狀態(tài)
ps 進(jìn)程查看器
性能優(yōu)化
wget 文件下載
top linux下的任務(wù)管理器
磁盤管理
size 查看程序內(nèi)存映像大小
free 查詢可用內(nèi)存
文件及目錄管理
iostat 監(jiān)視I/O子系統(tǒng)
性能監(jiān)控
程序構(gòu)建
學(xué)會使用命令幫助
gdb 調(diào)試?yán)?/span>
網(wǎng)絡(luò)工具
nm 目標(biāo)文件格式分析
lsof 一切皆文件
用戶管理工具
程序調(diào)試
ldd 查看程序依賴庫
文本處理

程序調(diào)試

進(jìn)程調(diào)試

gdb 程序交互調(diào)試

GDB是一個由GNU開源組織發(fā)布的、UNIX/LINUX操作系統(tǒng)下的、基于命令行的、功能強(qiáng)大的程序調(diào)試工具。

對于一名Linux下工作的c++程序員,gdb是必不可少的工具;

GDB中的命令固然很多,但我們只需掌握其中十個左右的命令,就大致可以完成日常的基本的程序調(diào)試工作。

以下從一個完整的調(diào)試過程簡單說明最基本的幾個命令;

$gdb programmer     # 啟動gdb
>break main         # 設(shè)置斷點
>run                # 運行調(diào)試程序
>next               # 單步調(diào)試
>print var1         # 在調(diào)試過程中,我們需要查看當(dāng)前某個變量值的時候,使用print 命令打印該值
>list               # 顯示當(dāng)前調(diào)試處的源代碼 
>info b             # 顯示當(dāng)前斷點設(shè)置情況

當(dāng)你完成了第一個程序調(diào)試之后,你當(dāng)然會需要更多的命令:關(guān)于gdb常用命令及各種調(diào)試方法詳見 :ref:gdb ;

同時,你需要更高效的調(diào)試:常用的調(diào)試命令都會有單字符的縮寫,使用縮寫更方便;同時,直接敲回車表示重復(fù)執(zhí)行上一步命令;這在單步調(diào)試時非常有用;

pstack 跟蹤??臻g

pstack是一個腳本工具,可顯示每個進(jìn)程的棧跟蹤。pstack 命令必須由相應(yīng)進(jìn)程的屬主或 root 運行。其核心實現(xiàn)就是使用了gdb以及thread apply all bt命令;

語法

$pstrack <program-pid>

示例

$ pstack 4551
Thread 7 (Thread 1084229984 (LWP 4552)):
#0  0x000000302afc63dc in epoll_wait () from /lib64/tls/libc.so.6
#1  0x00000000006f0730 in ubEPollExpoll ()
#2  0x00000000006f172a in ubNetReactorcallback ()
#3  0x00000000006fbbbb in ubUBTaskCALLBACK ()
#4  0x000000302b80610a in start_thread () from /lib64/tls/libpthread.so.0
#5  0x000000302afc6003 in clone () from /lib64/tls/libc.so.6
#6  0x0000000000000000 in ?? ()

strace 分析系統(tǒng)調(diào)用

strace常用來跟蹤進(jìn)程執(zhí)行時的系統(tǒng)調(diào)用和所接收的信號。在Linux世界,進(jìn)程不能直接訪問硬件設(shè)備,當(dāng)進(jìn)程需要訪問硬件設(shè)備(比如讀取磁盤文件,接收網(wǎng)絡(luò)數(shù)據(jù)等等)時,必須由用戶態(tài)模式切換至內(nèi)核態(tài)模式,通過系統(tǒng)調(diào)用訪問硬件設(shè)備。strace可以跟蹤到一個進(jìn)程產(chǎn)生的系統(tǒng)調(diào)用,包括參數(shù),返回值,執(zhí)行消耗的時間。

完整程序

strace -o output.txt -T -tt -e trace=all -p 28979

跟蹤28979進(jìn)程的所有系統(tǒng)調(diào)用(-e trace=all),并統(tǒng)計系統(tǒng)調(diào)用的花費時間,以及開始時間(以可視化的時分秒格式顯示),最后將記錄結(jié)果存在output.txt文件里面。

查看進(jìn)程正在做什么(實時輸出進(jìn)程執(zhí)行系統(tǒng)調(diào)用的情況)

$strace -p <process-pid>

關(guān)于strace的詳細(xì)介紹,詳見 :ref:strace ;

目標(biāo)文件分析

nm

nm用來列出目標(biāo)文件的符號清單。

$nm myProgrammer
08049f28 d _DYNAMIC
08049ff4 d _GLOBAL_OFFSET_TABLE_
080484dc R _IO_stdin_used
         w _Jv_RegisterClasses
08049f18 d __CTOR_END__
08049f14 d __CTOR_LIST__
08049f20 D __DTOR_END__
08049f1c d __DTOR_LIST__
080485e0 r __FRAME_END__
08049f24 d __JCR_END__
08049f24 d __JCR_LIST__
0804a014 A __bss_start
0804a00c D __data_start
08048490 t __do_global_ctors_aux
08048360 t __do_global_dtors_aux
0804a010 D __dso_handle
         w __gmon_start__
08048482 T __i686.get_pc_thunk.bx
08049f14 d __init_array_end
08049f14 d __init_array_start
08048480 T __libc_csu_fini
08048410 T __libc_csu_init
         U __libc_start_main@@GLIBC_2.0
0804a014 A _edata
0804a01c A _end
080484bc T _fini
080484d8 R _fp_hw
080482b4 T _init
08048330 T _start
0804a014 b completed.6086
0804a00c W data_start
0804a018 b dtor_idx.6088
080483c0 t frame_dummy
080483e4 T main
         U printf@@GLIBC_2.0

這些包含可執(zhí)行代碼的段稱為正文段。同樣地,數(shù)據(jù)段包含了不可執(zhí)行的信息或數(shù)據(jù)。另一種類型的段,稱為 BSS 段,它包含以符號數(shù)據(jù)開頭的塊。對于 nm 命令列出的每個符號,它們的值使用十六進(jìn)制來表示(缺省行為),并且在該符號前面加上了一個表示符號類型的編碼字符。

常見的各種編碼包括:

  • A 表示絕對 (absolute),這意味著不能將該值更改為其他的連接;
  • B 表示 BSS 段中的符號;
  • C 表示引用未初始化的數(shù)據(jù)的一般符號。

可以將目標(biāo)文件中所包含的不同的部分劃分為段。段可以包含可執(zhí)行代碼、符號名稱、初始數(shù)據(jù)值和許多其他類型的數(shù)據(jù)。有關(guān)這些類型的數(shù)據(jù)的詳細(xì)信息,可以閱讀 UNIX 中 nm 的 man 頁面,其中按照該命令輸出中的字符編碼分別對每種類型進(jìn)行了描述。

在目標(biāo)文件階段,即使是一個簡單的 Hello World 程序,其中也包含了大量的細(xì)節(jié)信息。nm 程序可用于列舉符號及其類型和值,但是,要更仔細(xì)地研究目標(biāo)文件中這些命名段的內(nèi)容,需要使用功能更強(qiáng)大的工具。

其中兩種功能強(qiáng)大的工具是 objdump 和 readelf 程序。

關(guān)于nm工具的參數(shù)說明及更多示例詳見 :ref:nm ;

objdump

ogjdump工具用來顯示二進(jìn)制文件的信息,就是以一種可閱讀的格式讓你更多地了解二進(jìn)制文件可能帶有的附加信息。

$objdump -d myprogrammer
a.out:     file format elf32-i386

Disassembly of section .init:

080482b4 <_init>:
 80482b4:   53                      push   %ebx
 80482b5:   83 ec 08                sub    $0x8,%esp
 80482b8:   e8 00 00 00 00          call   80482bd <_init+0x9>
 80482bd:   5b                      pop    %ebx
 80482be:   81 c3 37 1d 00 00       add    $0x1d37,%ebx
 80482c4:   8b 83 fc ff ff ff       mov    -0x4(%ebx),%eax
 80482ca:   85 c0                   test   %eax,%eax
 80482cc:   74 05                   je     80482d3 <_init+0x1f>
 80482ce:   e8 3d 00 00 00          call   8048310 <__gmon_start__@plt>
 80482d3:   e8 e8 00 00 00          call   80483c0 <frame_dummy>
 80482d8:   e8 b3 01 00 00          call   8048490 <__do_global_ctors_aux>
 80482dd:   83 c4 08                add    $0x8,%esp
 80482e0:   5b                      pop    %ebx
 80482e1:   c3                      ret    

Disassembly of section .plt:
...

每個可執(zhí)行代碼段將在需要特定的事件時執(zhí)行,這些事件包括庫的初始化和該程序本身主入口點。

對于那些著迷于底層編程細(xì)節(jié)的程序員來說,這是一個功能非常強(qiáng)大的工具,可用于研究編譯器和匯編器的輸出。細(xì)節(jié)信息,比如這段代碼中所顯示的這些信息,可以揭示有關(guān)本地處理器本身運行方式的很多內(nèi)容。對該處理器制造商提供的技術(shù)文檔進(jìn)行深入的研究,您可以收集關(guān)于一些有價值的信息,通過這些信息可以深入地了解內(nèi)部的運行機(jī)制,因為功能程序提供了清晰的輸出。

關(guān)于objdump工具的參數(shù)說明及更多示例詳見 :ref:objdump ;

readelf

這個工具和objdump命令提供的功能類似,但是它顯示的信息更為具體,并且它不依賴BFD庫(BFD庫是一個GNU項目,它的目標(biāo)就是希望通過一種統(tǒng)一的接口來處理不同的目標(biāo)文件);

$readelf -all a.out
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x8048330
  Start of program headers:          52 (bytes into file)
  Start of section headers:          4412 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         9
  Size of section headers:           40 (bytes)
  Number of section headers:         30
  Section header string table index: 27

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 000020 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          080481cc 0001cc 000050 10   A  6   1  4
  [ 6] .dynstr           STRTAB          0804821c 00021c 00004c 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          08048268 000268 00000a 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         08048274 000274 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             08048294 000294 000008 08   A  5   0  4
  [10] .rel.plt          REL             0804829c 00029c 000018 08   A  5  12  4
  [11] .init             PROGBITS        080482b4 0002b4 00002e 00  AX  0   0  4
  [12] .plt              PROGBITS        080482f0 0002f0 000040 04  AX  0   0 16
  [13] .text             PROGBITS        08048330 000330 00018c 00  AX  0   0 16
  [14] .fini             PROGBITS        080484bc 0004bc 00001a 00  AX  0   0  4
  [15] .rodata           PROGBITS        080484d8 0004d8 000011 00   A  0   0  4
  [16] .eh_frame_hdr     PROGBITS        080484ec 0004ec 000034 00   A  0   0  4
  [17] .eh_frame         PROGBITS        08048520 000520 0000c4 00   A  0   0  4
  [18] .ctors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
  [19] .dtors            PROGBITS        08049f1c 000f1c 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        08049f24 000f24 000004 00  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049f28 000f28 0000c8 08  WA  6   0  4
  [22] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        08049ff4 000ff4 000018 04  WA  0   0  4
  [24] .data             PROGBITS        0804a00c 00100c 000008 00  WA  0   0  4
  [25] .bss              NOBITS          0804a014 001014 000008 00  WA  0   0  4
  [26] .comment          PROGBITS        00000000 001014 00002a 01  MS  0   0  1
  [27] .shstrtab         STRTAB          00000000 00103e 0000fc 00      0   0  1
  [28] .symtab           SYMTAB          00000000 0015ec 000410 10     29  45  4
  [29] .strtab           STRTAB          00000000 0019fc 0001f9 00      0   0  1
  ...

ELF Header 為該文件中所有段入口顯示了詳細(xì)的摘要。在列舉出這些 Header 中的內(nèi)容之前,您可以看到 Header 的具體數(shù)目。在研究一個較大的目標(biāo)文件時,該信息可能非常有用。

除了所有這些段之外,編譯器可以將調(diào)試信息放入到目標(biāo)文件中,并且還可以顯示這些信息。輸入下面的命令,仔細(xì)分析編譯器的輸出(假設(shè)您扮演了調(diào)試程序的角色)

$readelf --debug-dump a.out | more 

調(diào)試工具,如 GDB,可以讀取這些調(diào)試信息,并且當(dāng)程序在調(diào)試器中運行的同時,您可以使用該工具顯示更具描述性的標(biāo)記,而不是對代碼進(jìn)行反匯編時的原始地址值。

關(guān)于readelf工具的參數(shù)說明及更多示例詳見 :ref:`readelf` ;

size 查看程序內(nèi)存占用

size這個工具用來查看程序運行時各個段的實際內(nèi)存占用

$size a.out
text       data     bss     dec     hex filename
1146        256       8    1410     582 a.out

file 文件類型查詢

這個工具用于查看文件的類型;

比如我們在64位機(jī)器上發(fā)現(xiàn)了一個32位的庫,鏈接不上,這就有問題了:

$file a.out
a.out: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped

也可以查看Core文件是由哪個程序生成

$file core.22355

strings 查詢數(shù)據(jù)中的文本信息

一個文件中包含二進(jìn)制數(shù)據(jù)和文本數(shù)據(jù),如果只需要查看其文本信息,使用這個命令就很方便;過濾掉非字符數(shù)據(jù),將文本信息輸出

$strings <objfile>

fuser 顯示文件使用者

顯示所有正在使用著指定的file, file system 或者 sockets的進(jìn)程信息;

$fuser -m -u redis-server
redis-server: 11552rce(weber) 22912rce(weber) 25501rce(weber)

使用了-m和-u選項,用來查找所有正在使用redis-server的所有進(jìn)程的PID以及該進(jìn)程的OWNER;

fuser通常被用在診斷系統(tǒng)的"resource busy"問題。如果你希望kill所有正在使用某一指定的file, file system or sockets的進(jìn)程的時候,你可以使用-k選項

$fuser –k /path/to/your/filename

xxd 十六進(jìn)制顯示數(shù)據(jù)

以十六進(jìn)制方式顯示文件,只顯示文本信息

$xxd a.out 
0000000: 7f45 4c46 0101 0100 0000 0000 0000 0000  .ELF............
0000010: 0200 0300 0100 0000 3083 0408 3400 0000  ........0...4...
0000020: 3c11 0000 0000 0000 3400 2000 0900 2800  <.......4. ...(.
0000030: 1e00 1b00 0600 0000 3400 0000 3480 0408  ........4...4...
0000040: 3480 0408 2001 0000 2001 0000 0500 0000  4... ... .......
0000050: 0400 0000 0300 0000 5401 0000 5481 0408  ........T...T...
...    

od

通常使用od命令查看特殊格式的文件內(nèi)容。通過指定該命令的不同選項可以以十進(jìn)制、八進(jìn)制、十六進(jìn)制和ASCII碼來顯示文件。

參數(shù)說明:

-A 指定地址基數(shù),包括:

  • d 十進(jìn)制
  • o 八進(jìn)制(系統(tǒng)默認(rèn)值)
  • x 十六進(jìn)制
  • n 不打印位移值

-t 指定數(shù)據(jù)的顯示格式,主要的參數(shù)有:

  • c ASCII字符或反斜杠序列
  • d 有符號十進(jìn)制數(shù)
  • f 浮點數(shù)
  • o 八進(jìn)制(系統(tǒng)默認(rèn)值為02)
  • u 無符號十進(jìn)制數(shù)
  • x 十六進(jìn)制數(shù) 除了選項c以外的其他選項后面都可以跟一個十進(jìn)制數(shù)n,指定每個顯示值所包含的字節(jié)數(shù)。

說明:od命令系統(tǒng)默認(rèn)的顯示方式是八進(jìn)制,這也是該命令的名稱由來(Octal Dump)。但這不是最有用的顯示方式,用ASCII碼和十六進(jìn)制組合的方式能提供更有價值的信息輸出。

以十六進(jìn)制和字符同時顯示

$od -Ax -tcx4 a.c 
000000   #   i   n   c   l   u   d   e       <   s   t   d   i   o   .
              636e6923        6564756c        74733c20        2e6f6964
000010   h   >  \n  \n   v   o   i   d       m   a   i   n   (   )  \n
              0a0a3e68        64696f76        69616d20        0a29286e
000020   {  \n  \t   i   n   t       i       =       5   ;  \n  \t   p
              69090a7b        6920746e        35203d20        70090a3b
000030   r   i   n   t   f   (   "   h   e   l   l   o   ,   %   d   "
              746e6972        68222866        6f6c6c65        2264252c
000040   ,   i   )   ;  \n   }  \n
              3b29692c        000a7d0a
000047

以字符方式顯示

$od -c a.c
0000000   #   i   n   c   l   u   d   e       <   s   t   d   i   o   .
0000020   h   >  \n  \n   v   o   i   d       m   a   i   n   (   )  \n
0000040   {  \n  \t   i   n   t       i       =       5   ;  \n  \t   p
0000060   r   i   n   t   f   (   "   h   e   l   l   o   ,   %   d   "
0000100   ,   i   )   ;  \n   }  \n
0000107

注:類似命令還有hexdump(十六進(jìn)制輸出)