您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)Linux中strace命令怎么用,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
strace命令 是一個(gè)集診斷、調(diào)試、統(tǒng)計(jì)與一體的工具,我們可以使用strace對(duì)應(yīng)用的系統(tǒng)調(diào)用和信號(hào)傳遞的跟蹤結(jié)果來(lái)對(duì)應(yīng)用進(jìn)行分析,以達(dá)到解決問(wèn)題或者是了解應(yīng)用工作過(guò)程的目的。
跟蹤系統(tǒng)調(diào)用和信號(hào)
當(dāng)然strace與專業(yè)的調(diào)試工具比如說(shuō)gdb之類的是沒(méi)法相比的,因?yàn)樗皇且粋€(gè)專業(yè)的調(diào)試器。
strace的最簡(jiǎn)單的用法就是執(zhí)行一個(gè)指定的命令,在指定的命令結(jié)束之后它也就退出了。在命令執(zhí)行的過(guò)程中,strace會(huì)記錄和解析命令進(jìn)程的所有系統(tǒng)調(diào)用以及這個(gè)進(jìn)程所接收到的所有的信號(hào)值。
strace [ -dffhiqrtttTvxx ] [ -acolumn ] [ -eexpr ] ...
[ -ofile ] [-ppid ] ... [ -sstrsize ] [ -uusername ]
[ -Evar=val ] ... [ -Evar ]...
[command [ arg ... ] ]
strace -c [ -eexpr ] ... [ -Ooverhead ] [ -Ssortby ]
[ command [ arg... ] ]
-c 統(tǒng)計(jì)每一系統(tǒng)調(diào)用的所執(zhí)行的時(shí)間,次數(shù)和出錯(cuò)的次數(shù)等.
-d 輸出strace關(guān)于標(biāo)準(zhǔn)錯(cuò)誤的調(diào)試信息.
-f 跟蹤由fork調(diào)用所產(chǎn)生的子進(jìn)程.
-ff 如果提供-o filename,則所有進(jìn)程的跟蹤結(jié)果輸出到相應(yīng)的filename.pid中,pid是各進(jìn)程的進(jìn)程號(hào).
-F 嘗試跟蹤vfork調(diào)用.在-f時(shí),vfork不被跟蹤.
-h 輸出簡(jiǎn)要的幫助信息.
-i 輸出系統(tǒng)調(diào)用的入口指針.
-q 禁止輸出關(guān)于脫離的消息.
-r 打印出相對(duì)時(shí)間關(guān)于,,每一個(gè)系統(tǒng)調(diào)用.
-t 在輸出中的每一行前加上時(shí)間信息.
-tt 在輸出中的每一行前加上時(shí)間信息,微秒級(jí).
-ttt 微秒級(jí)輸出,以秒了表示時(shí)間.
-T 顯示每一調(diào)用所耗的時(shí)間.
-v 輸出所有的系統(tǒng)調(diào)用.一些調(diào)用關(guān)于環(huán)境變量,狀態(tài),輸入輸出等調(diào)用由于使用頻繁,默認(rèn)不輸出.
-V 輸出strace的版本信息.
-x 以十六進(jìn)制形式輸出非標(biāo)準(zhǔn)字符串
-xx 所有字符串以十六進(jìn)制形式輸出.
-a column 設(shè)置返回值的輸出位置.默認(rèn) 為40.
-e expr 指定一個(gè)表達(dá)式,用來(lái)控制如何跟蹤.格式:[qualifier=][!]value1[,value2]...
qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用來(lái)限定的符號(hào)或數(shù)字.默認(rèn)的 qualifier是 trace.感嘆號(hào)是否定符號(hào).例如:-eopen等價(jià)于 -e trace=open,表示只跟蹤open調(diào)用.而-etrace!=open 表示跟蹤除了open以外的其他調(diào)用.有兩個(gè)特殊的符號(hào) all 和 none. 注意有些shell使用!來(lái)執(zhí)行歷史記錄里的命令,所以要使用\\.
-e trace=set 只跟蹤指定的系統(tǒng) 調(diào)用.例如:-e trace=open,close,rean,write表示只跟蹤這四個(gè)系統(tǒng)調(diào)用.默認(rèn)的為set=all.
-e trace=file 只跟蹤有關(guān)文件操作的系統(tǒng)調(diào)用.
-e trace=process 只跟蹤有關(guān)進(jìn)程控制的系統(tǒng)調(diào)用.
-e trace=network 跟蹤與網(wǎng)絡(luò)有關(guān)的所有系統(tǒng)調(diào)用.
-e strace=signal 跟蹤所有與系統(tǒng)信號(hào)有關(guān)的 系統(tǒng)調(diào)用
-e trace=ipc 跟蹤所有與進(jìn)程通訊有關(guān)的系統(tǒng)調(diào)用
-e abbrev=set 設(shè)定strace輸出的系統(tǒng)調(diào)用的結(jié)果集.-v 等與 abbrev=none.默認(rèn)為abbrev=all.
-e raw=set 將指定的系統(tǒng)調(diào)用的參數(shù)以十六進(jìn)制顯示.
-e signal=set 指定跟蹤的系統(tǒng)信號(hào).默認(rèn)為all.如 signal=!SIGIO(或者signal=!io),表示不跟蹤SIGIO信號(hào).
-e read=set 輸出從指定文件中讀出 的數(shù)據(jù).例如: -e read=3,5
-e write=set 輸出寫入到指定文件中的數(shù)據(jù).
-o filename 將strace的輸出寫入文件filename
-p pid 跟蹤指定的進(jìn)程pid.
-s strsize 指定輸出的字符串的最大長(zhǎng)度.默認(rèn)為32.文件名一直全部輸出.
-u username 以u(píng)sername的UID和GID執(zhí)行被跟蹤的命令
追蹤系統(tǒng)調(diào)用
現(xiàn)在我們做一個(gè)很簡(jiǎn)單的程序來(lái)演示strace的基本用法。這個(gè)程序的C語(yǔ)言代碼如下:
# filename test.c #include
int main()
{
int a;
scanf("%d", &a);
printf("%09d\n", a);
return 0;
}
然后我們用gcc -o test test.c編譯一下,得到一個(gè)可執(zhí)行的文件test。然后用strace調(diào)用執(zhí)行:
strace ./test
執(zhí)行期間會(huì)要求你輸入一個(gè)整數(shù),我們輸入99,最后得到如下的結(jié)果:
// 直接執(zhí)行test的結(jié)果
oracle@orainst[orcl]:~ $./test
// 執(zhí)行的結(jié)果
99 000000099
// 通過(guò)strace執(zhí)行test的結(jié)果
oracle@orainst[orcl]:~ $strace ./test
// strace的trace結(jié)果
execve("./test", ["./test"], [/* 41 vars */]) = 0 uname({sys="Linux", node="orainst.desktop.mycompany.com", ...}) = 0 brk(0) = 0x8078000
fstat64(3, {st_mode=S_IFREG|0644, st_size=65900, ...}) = 0 old_mmap(NULL, 65900, PROT_READ, MAP_PRIVATE, 3, 0) = 0xbf5ef000
close(3) = 0 open("/lib/tls/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\200X\1"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1571692, ...}) = 0 old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xbf5ee000
old_mmap(NULL, 1275340, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0xa02000
old_mmap(0xb34000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x132000) = 0xb34000
old_mmap(0xb37000, 9676, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb37000
close(3) = 0 set_thread_area({entry_number:-1 -> 6, base_addr:0xbf5ee740, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 munmap(0xbf5ef000, 65900) = 0 fstat64(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xbf5ff000
read(0, 99 "99\n", 1024) = 3 fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xbf5fe000
write(1, "000000099\n", 10000000099 ) = 10 munmap(0xbf5fe000, 4096) = 0 exit_group(0) = ?
從trace結(jié)構(gòu)可以看到,系統(tǒng)首先調(diào)用execve開(kāi)始一個(gè)新的進(jìn)行,接著進(jìn)行些環(huán)境的初始化操作,最后停頓在”read(0,”上面,這也就是執(zhí)行到了我們的scanf函數(shù),等待我們輸入數(shù)字呢,在輸入完99之后,在調(diào)用write函數(shù)將格式化后的數(shù)值”000000099″輸出到屏幕,最后調(diào)用exit_group退出進(jìn)行,完成整個(gè)程序的執(zhí)行過(guò)程。
跟蹤信號(hào)傳遞
我們還是使用上面的那個(gè)test程序,來(lái)觀察進(jìn)程接收信號(hào)的情況。還是先strace ./test,等到等待輸入的畫面的時(shí)候不要輸入任何東西,然后打開(kāi)另外一個(gè)窗口,輸入如下的命令
killall test
這時(shí)候就能看到我們的程序推出了,最后的trace結(jié)果如下:
oracle@orainst[orcl]:~
$strace ./test
execve("./test", ["./test"], [/* 41 vars */]) = 0 uname({sys="Linux", node="orainst.desktop.mycompany.com", ...}) = 0 brk(0) = 0x9ae2000
old_mmap(NULL, 65900, PROT_READ, MAP_PRIVATE, 3, 0) = 0xbf5ef000
close(3) = 0 open("/lib/tls/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\200X\1"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1571692, ...}) = 0 old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xbf5ee000
old_mmap(NULL, 1275340, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x2e9000
old_mmap(0x41b000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x132000) = 0x41b000
old_mmap(0x41e000, 9676, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x41e000
close(3) = 0 set_thread_area({entry_number:-1 -> 6, base_addr:0xbf5ee740, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 munmap(0xbf5ef000, 65900) = 0 fstat64(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xbf5ff000
read(0, 0xbf5ff000, 1024) = ? ERESTARTSYS (To be restarted)
--- SIGTERM (Terminated) @ 0 (0) --- +++ killed by SIGTERM +++
trace中很清楚的告訴你test進(jìn)程”+++ killed by SIGTERM +++”。
系統(tǒng)調(diào)用統(tǒng)計(jì)
strace不光能追蹤系統(tǒng)調(diào)用,通過(guò)使用參數(shù)-c,它還能將進(jìn)程所有的系統(tǒng)調(diào)用做一個(gè)統(tǒng)計(jì)分析給你,下面就來(lái)看看strace的統(tǒng)計(jì),這次我們執(zhí)行帶-c參數(shù)的strace:
strace -c ./test
最后能得到這樣的trace結(jié)果:
oracle@orainst[orcl]:~
$strace -c ./test
execve("./test", ["./test"], [/* 41 vars */]) = 0 % time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ---------------- 45.90 0.000140 5 27 25 open
34.43 0.000105 4 24 21 stat64
7.54 0.000023 5 5 old_mmap
2.62 0.000008 8 1 munmap
1.97 0.000006 6 1 uname
1.97 0.000006 2 3 fstat64
1.64 0.000005 3 2 1 read
1.31 0.000004 2 2 close
0.98 0.000003 3 1 brk
0.98 0.000003 3 1 mmap2
0.66 0.000002 2 1 set_thread_area
------ ----------- ----------- --------- --------- ---------------- 100.00 0.000305 68 47 total
這里很清楚的告訴你調(diào)用了那些系統(tǒng)函數(shù),調(diào)用次數(shù)多少,消耗了多少時(shí)間等等這些信息,這個(gè)對(duì)我們分析一個(gè)程序來(lái)說(shuō)是非常有用的。
除了-c參數(shù)之外,strace還提供了其他有用的參數(shù)給我們,讓我們能很方便的得到自己想要的信息,下面就對(duì)那些常用的參數(shù)一一做個(gè)介紹。
重定向輸出
參數(shù)-o用在將strace的結(jié)果輸出到文件中,如果不指定-o參數(shù)的話,默認(rèn)的輸出設(shè)備是STDERR,也就是說(shuō)使用”-o filename”和” 2>filename”的結(jié)果是一樣的。
# 這兩個(gè)命令都是將strace結(jié)果輸出到文件test.txt中 strace -c -o test.txt ./test
strace -c ./test 2>test.txt
對(duì)系統(tǒng)調(diào)用進(jìn)行計(jì)時(shí)
strace可以使用參數(shù)-T將每個(gè)系統(tǒng)調(diào)用所花費(fèi)的時(shí)間打印出來(lái),每個(gè)調(diào)用的時(shí)間花銷現(xiàn)在在調(diào)用行最右邊的尖括號(hào)里面。
oracle@orainst[orcl]:~
$strace -T ./test
// 這里只摘錄部分結(jié)果
read(0, 1 "1\n", 1024) = 2 fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xbf5fe000
write(1, "000000001\n", 10000000001 ) = 10 munmap(0xbf5fe000, 4096) = 0 exit_group(0) = ?
系統(tǒng)調(diào)用的時(shí)間
這是一個(gè)很有用的功能,strace會(huì)將每次系統(tǒng)調(diào)用的發(fā)生時(shí)間記錄下來(lái),只要使用-t/tt/ttt三個(gè)參數(shù)就可以看到效果了,具體的例子可以自己去嘗試。
參數(shù)名 | 輸出樣式 | 說(shuō)明 |
---|---|---|
-t | 10:33:04 exit_group(0) | 輸出結(jié)果精確到秒 |
-tt | 10:33:48.159682 exit_group(0) | 輸出結(jié)果精確到微妙 |
-ttt | 1262169244.788478 exit_group(0) | 精確到微妙,而且時(shí)間表示為unix時(shí)間戳 |
截?cái)噍敵?/span>
-s參數(shù)用于指定trace結(jié)果的每一行輸出的字符串的長(zhǎng)度,下面看看test程序中-s參數(shù)對(duì)結(jié)果有什么影響,現(xiàn)指定-s為20,然后在read的是是很我們輸入一個(gè)超過(guò)20個(gè)字符的數(shù)字串
strace -s 20 ./test
read(0, 2222222222222222222222222 // 我們輸入的2一共有25個(gè)
"22222222222222222222"..., 1024) = 26 // 而我們看到的結(jié)果中2只有20個(gè)
trace一個(gè)現(xiàn)有的進(jìn)程
strace不光能自己初始化一個(gè)進(jìn)程進(jìn)行trace,還能追蹤現(xiàn)有的進(jìn)程,參數(shù)-p就是取這個(gè)作用的,用法也很簡(jiǎn)單,具體如下。
strace -p pid
說(shuō)了那么多的功能和參數(shù),現(xiàn)在我們來(lái)一個(gè)實(shí)用點(diǎn)的,就是研究下Oracle的lgwr進(jìn)程,看看這個(gè)進(jìn)程是不是像文檔所說(shuō)的那樣沒(méi)3s鐘寫一次log文件,考慮到lgwr寫日志的觸發(fā)條件比較多,我們需要找一個(gè)空閑的Oracle實(shí)例做這個(gè)實(shí)驗(yàn)。
我們先要得到lgwr進(jìn)程的pid,運(yùn)行下面的命令
ps -ef|grep lgwr
oracle 5912 1 0 Nov12 ? 00:14:56 ora_lgwr_orcl
得到lgwr的pid是5912,現(xiàn)在啟動(dòng)strace,然后將trace的幾個(gè)輸出到lgwr.txt文件中,執(zhí)行下面的命令
strace -tt -s 10 -o lgwr.txt -p 5912
過(guò)一會(huì)之后停止strace,然后查看結(jié)果。由于輸出的結(jié)果比較多,為了方便我們只看Oracle寫入log文件時(shí)用的pwrite函數(shù)的調(diào)用
grep pwrite\(20 lgwr.txt
等等,為什么grep的時(shí)候用的是”pwrite(2″呢?,因?yàn)槲抑牢疫@個(gè)機(jī)器打開(kāi)的當(dāng)前的log文件的句柄編號(hào)都是2開(kāi)始的。具體查找方法是先使用下面的語(yǔ)句找出當(dāng)前活動(dòng)的日志文件都有哪些:
select member, v$log.status from v$log, v$logfile where v$log.group#=v$logfile.group#;
得到
MEMBER STATUS
-------------------------------------------------- ---------------- /db/databases/orcl/redo-01-a/redo-t01-g03-m1.log INACTIVE
/db/databases/orcl/redo-03-a/redo-t01-g03-m2.log INACTIVE
/db/databases/orcl/redo-02-a/redo-t01-g02-m1.log CURRENT
/db/databases/orcl/redo-04-a/redo-t01-g02-m2.log CURRENT
/db/databases/orcl/redo-01-a/redo-t01-g01-m1.log INACTIVE
/db/databases/orcl/redo-03-a/redo-t01-g01-m2.log INACTIVE
/db/databases/orcl/redo-02-a/redo-t01-g04-m1.log INACTIVE
/db/databases/orcl/redo-04-a/redo-t01-g04-m2.log INACTIVE
然后到/proc中去找打開(kāi)文件的句柄:
ll /proc/.5912/fd/
得到
lrwx------ 1 oracle dba 64 Dec 30 10:55 18 -> /db/databases/orcl/redo-01-a/redo-t01-g01-m1.log
lrwx------ 1 oracle dba 64 Dec 30 10:55 19 -> /db/databases/orcl/redo-03-a/redo-t01-g01-m2.log
lrwx------ 1 oracle dba 64 Dec 30 10:55 20 -> /db/databases/orcl/redo-02-a/redo-t01-g02-m1.log
lrwx------ 1 oracle dba 64 Dec 30 10:55 21 -> /db/databases/orcl/redo-04-a/redo-t01-g02-m2.log
lrwx------ 1 oracle dba 64 Dec 30 10:55 22 -> /db/databases/orcl/redo-01-a/redo-t01-g03-m1.log
lrwx------ 1 oracle dba 64 Dec 30 10:55 23 -> /db/databases/orcl/redo-03-a/redo-t01-g03-m2.log
lrwx------ 1 oracle dba 64 Dec 30 10:55 24 -> /db/databases/orcl/redo-02-a/redo-t01-g04-m1.log
lrwx------ 1 oracle dba 64 Dec 30 10:55 25 -> /db/databases/orcl/redo-04-a/redo-t01-g04-m2.log
現(xiàn)在能看到我機(jī)器當(dāng)前日志文件的句柄分別是20和21。
現(xiàn)在我們得到如下結(jié)果
11:13:55.603245 pwrite(20, "\1\"\0\0J!"..., 1536, 4363264) = 1536 11:13:55.603569 pwrite(21, "\1\"\0\0J!"..., 1536, 4363264) = 1536 11:13:55.606888 pwrite(20, "\1\"\0\0M!"..., 1536, 4364800) = 1536 11:13:55.607172 pwrite(21, "\1\"\0\0M!"..., 1536, 4364800) = 1536 11:13:55.607934 pwrite(20, "\1\"\0\0P!"..., 1536, 4366336) = 1536 11:13:55.608199 pwrite(21, "\1\"\0\0P!"..., 1536, 4366336) = 1536 11:13:55.610260 pwrite(20, "\1\"\0\0S!"..., 1536, 4367872) = 1536 11:13:55.610530 pwrite(21, "\1\"\0\0S!"..., 1536, 4367872) = 1536 11:14:00.602446 pwrite(20, "\1\"\0\0V!"..., 1536, 4369408) = 1536 11:14:00.602750 pwrite(21, "\1\"\0\0V!"..., 1536, 4369408) = 1536 11:14:00.606386 pwrite(20, "\1\"\0\0Y!"..., 1536, 4370944) = 1536 11:14:00.606676 pwrite(21, "\1\"\0\0Y!"..., 1536, 4370944) = 1536 11:14:00.607900 pwrite(20, "\1\"\0\0\\"..., 1024, 4372480) = 1024 11:14:00.608161 pwrite(21, "\1\"\0\0\\"..., 1024, 4372480) = 1024 11:14:00.608816 pwrite(20, "\1\"\0\0^!"..., 1024, 4373504) = 1024 11:14:00.609071 pwrite(21, "\1\"\0\0^!"..., 1024, 4373504) = 1024 11:14:00.611142 pwrite(20, "\1\"\0\0`!"..., 1536, 4374528) = 1536 11:14:00.611454 pwrite(21, "\1\"\0\0`!"..., 1536, 4374528) = 1536 11:14:05.602804 pwrite(20, "\1\"\0\0c!"..., 1024, 4376064) = 1024 11:14:05.603119 pwrite(21, "\1\"\0\0c!"..., 1024, 4376064) = 1024 11:14:05.607731 pwrite(20, "\1\"\0\0e!"..., 1024, 4377088) = 1024 11:14:05.608020 pwrite(21, "\1\"\0\0e!"..., 1024, 4377088) = 1024 11:14:05.608690 pwrite(20, "\1\"\0\0g!"..., 1024, 4378112) = 1024 11:14:05.608962 pwrite(21, "\1\"\0\0g!"..., 1024, 4378112) = 1024 11:14:05.611022 pwrite(20, "\1\"\0\0i!"..., 1536, 4379136) = 1536 11:14:05.611283 pwrite(21, "\1\"\0\0i!"..., 1536, 4379136) = 1536
關(guān)于“Linux中strace命令怎么用”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。