专业编程基础技术教程

网站首页 > 基础教程 正文

Linux库函数调用工具—ltrace命令

ccvgpt 2024-10-12 13:33:16 基础教程 8 ℃


1、简介

ltrace的功能是能够跟踪进程的库函数调用,它会显现出哪个库函数被调用,而strace则是跟踪程序的每个系统调用。ltrace与strace使用的技术大体相同,但ltrace在对支持fork和clone方面,不如strace。strace在收到frok和clone等系统调用后,做了相应的处理,而ltrace没有。

Linux库函数调用工具—ltrace命令

2、安装

?[root@RedHat_test ~]# yum install ltrace

3、ltrace命令常用格式

?[root@RedHat_test ~]# man ltrace
?-a?:?对齐具体某个列的返回值。
?-c?:?计算时间和调用,并在程序退出时打印摘要。
?-C?:?解码低级别名称(内核级)为用户级名称。
?-d?:?打印调试信息。
?-e?:?改变跟踪的事件。
?-f?:?跟踪子进程。
?-h?:?打印帮助信息。
?-i?:?打印指令指针,当库调用时。
?-l?:?只打印某个库中的调用。
?-L?:?不打印库调用。
?-n,?--indent=NR?:?对每个调用级别嵌套以NR个空格进行缩进输出。
?-o,?--output=file?:?把输出定向到文件。
?-p?:?PID 附着在值为PID的进程号上进行ltrace。
?-r?:?打印相对时间戳。
?-s?:?STRLEN 设置打印的字符串最大长度。
?-S?:?显示系统调用。
?-t,?-tt,?-ttt?:?打印绝对时间戳。
?-T?:?输出每个调用过程的时间开销。
?-u?:?USERNAME 使用某个用户id或组ID来运行命令。
?-V,?--version?:?打印版本信息,然后退出。

4、程序实例

1.编写一个程序,打印Hello Word

?[root@RedHat_test ~]# vim hello.c
?#include <stdio.h>
?
?int main() {
?
?printf("Hello Word\n");
?return?0;
?}

2.用gcc编译

?[root@RedHat_test ~]# gcc hello.c -o hello

3.调用ltrace

?[root@RedHat_test ~]# ltrace ./hello
?__libc_start_main(0x40051d,?1, 0x7ffff6212798, 0x400540 <unfinished ...>
?puts("Hello Word"Hello Word
?) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??=11
?+++exited (status?0)?+++
?-----------------------------------------------------------------------------------------
?# 我们看到程序调用了puts();库函数做了输出
?-----------------------------------------------------------------------------------------

5、打印系统调用

?root@RedHat_test ~]# ltrace -S ./hello
?brk@SYS(nil) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??=0x1a31000
?mmap@SYS(nil,?4096,?3,?34,?-1,?0) ? ? ? ? ? ? ? ?=0x7f08c3f98000
?access@SYS("/etc/ld.so.preload",?04) ? ? ? ? ? ??=-2
?open@SYS("/etc/ld.so.cache",?524288,?01) ? ? ? ??=3
?fstat@SYS(3, 0x7ffc660983a0) ? ? ? ? ? ? ? ? ? ??=0
?mmap@SYS(nil,?35957,?1,?2,?3,?0) ? ? ? ? ? ? ? ??=0x7f08c3f8f000
?close@SYS(3) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??=0
?open@SYS("/lib64/libc.so.6",?524288,?030376330520)?=3
?read@SYS(3,?"\177ELF\002\001\001\003",?832) ? ? ?=832
?fstat@SYS(3, 0x7ffc66098400) ? ? ? ? ? ? ? ? ? ??=0
?mmap@SYS(nil,?3981792,?5,?2050,?3,?0) ? ? ? ? ? ?=0x7f08c39ab000
?mprotect@SYS(0x7f08c3b6d000,?2097152,?0) ? ? ? ??=0
?mmap@SYS(0x7f08c3d6d000,?24576,?3,?2066,?3,?1843200)?=0x7f08c3d6d000
?mmap@SYS(0x7f08c3d73000,?16864,?3,?50,?-1,?0) ? ?=0x7f08c3d73000
?close@SYS(3) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??=0
?mmap@SYS(nil,?4096,?3,?34,?-1,?0) ? ? ? ? ? ? ? ?=0x7f08c3f8e000
?mmap@SYS(nil,?8192,?3,?34,?-1,?0) ? ? ? ? ? ? ? ?=0x7f08c3f8c000
?arch_prctl@SYS(4098, 0x7f08c3f8c740, 0x7f08c3f8d050,?34)?=0
?mprotect@SYS(0x7f08c3d6d000,?16384,?1) ? ? ? ? ??=0
?mprotect@SYS(0x600000,?4096,?1) ? ? ? ? ? ? ? ? ?=0
?mprotect@SYS(0x7f08c3f99000,?4096,?1) ? ? ? ? ? ?=0
?munmap@SYS(0x7f08c3f8f000,?35957) ? ? ? ? ? ? ? ?=0
?__libc_start_main(0x40051d,?1, 0x7ffc66099d58, 0x400540 <unfinished ...>
?puts("Hello Word"<unfinished ...>
?fstat@SYS(1, 0x7ffc66099b00) ? ? ? ? ? ? ? ? ? ??=0
?mmap@SYS(nil,?4096,?3,?34,?-1,?0) ? ? ? ? ? ? ? ?=0x7f08c3f97000
?write@SYS(1,?"Hello Word\n", 11Hello Word
?) ? ? ? ? ? ? ? ??=11
?<... puts resumed> ) ? ? ? ? ? ? ? ? ? ? ? ? ? ??=11
?exit_group@SYS(0 <no return ...>
?+++exited (status?0)?+++
?----------------------------------------------------------------------------------------
?# 我们看到它实际是用SYS_write系统调用来做打印输出,其实write()函数是SYS_write的封装,SYS_write是真正的系统调用。
?----------------------------------------------------------------------------------------

6、判断ltrace/strace的耗时

?[root@RedHat_test ~]# ltrace -c dd if=/dev/urandom of=/dev/null count=1000
?记录了1000+0的读入
?记录了1000+0的写出
?512000字节(512 kB)已复制,0.461573 秒,1.1 MB/秒
?% time ? ? seconds usecs/call ? ? calls ? ? ?function
?---------------------------------------------------------
?53.36 ? ?0.473710 ? ? ?473710? ? ? ??1__libc_start_main
?16.11 ? ?0.142987 ? ? ? ??142? ? ?1000read
?15.57 ? ?0.138234 ? ? ? ??138? ? ?1000write
?13.45 ? ?0.119368 ? ? ? ??119? ? ?1000memcpy
??0.12 ? ?0.001034 ? ? ? ??258? ? ? ??4sigaction
??0.11 ? ?0.001001 ? ? ? ?1001? ? ? ??1exit
??0.10 ? ?0.000873 ? ? ? ??218? ? ? ??4__errno_location
??0.09 ? ?0.000798 ? ? ? ??399? ? ? ??2dcgettext
??0.09 ? ?0.000764 ? ? ? ??191? ? ? ??4close
??0.08 ? ?0.000678 ? ? ? ??678? ? ? ??1setlocale
??0.07 ? ?0.000654 ? ? ? ??218? ? ? ??3strchr
??0.07 ? ?0.000590 ? ? ? ??196? ? ? ??3__fprintf_chk
??0.06 ? ?0.000539 ? ? ? ??107? ? ? ??5strlen
??0.06 ? ?0.000533 ? ? ? ??266? ? ? ??2open
??0.06 ? ?0.000507 ? ? ? ??253? ? ? ??2dup2
??0.05 ? ?0.000445 ? ? ? ??222? ? ? ??2malloc
??0.05 ? ?0.000433 ? ? ? ??216? ? ? ??2sigismember
??0.05 ? ?0.000417 ? ? ? ??208? ? ? ??2sigaddset
??0.04 ? ?0.000335 ? ? ? ??167? ? ? ??2clock_gettime
??0.03 ? ?0.000266 ? ? ? ??266? ? ? ??1getenv
??0.03 ? ?0.000245 ? ? ? ??245? ? ? ??1lseek
??0.03 ? ?0.000240 ? ? ? ??240? ? ? ??1bindtextdomain
??0.03 ? ?0.000232 ? ? ? ??232? ? ? ??1sigemptyset
??0.03 ? ?0.000231 ? ? ? ??231? ? ? ??1__cxa_atexit
??0.03 ? ?0.000229 ? ? ? ??229? ? ? ??1textdomain
??0.03 ? ?0.000228 ? ? ? ??114? ? ? ??2localeconv
??0.03 ? ?0.000224 ? ? ? ??112? ? ? ??2__freading
??0.03 ? ?0.000222 ? ? ? ??222? ? ? ??1getpagesize
??0.02 ? ?0.000220 ? ? ? ??220? ? ? ??1strrchr
??0.02 ? ?0.000219 ? ? ? ??219? ? ? ??1getopt_long
??0.02 ? ?0.000216 ? ? ? ??216? ? ? ??1__strtoul_internal
??0.02 ? ?0.000209 ? ? ? ??209? ? ? ??1__ctype_b_loc
??0.01 ? ?0.000122 ? ? ? ??122? ? ? ??1dcngettext
??0.01 ? ?0.000122 ? ? ? ??122? ? ? ??1fclose
??0.01 ? ?0.000119 ? ? ? ??119? ? ? ??1__sprintf_chk
??0.01 ? ?0.000116 ? ? ? ??116? ? ? ??1__fpending
??0.01 ? ?0.000109 ? ? ? ??109? ? ? ??1fileno
??0.01 ? ?0.000108 ? ? ? ??108? ? ? ??1memmove
??0.01 ? ?0.000105 ? ? ? ??105? ? ? ??1exit_group
??0.01 ? ?0.000094 ? ? ? ? ?94? ? ? ??1fflush
?---------------------------------------------------------
?100.00 ? ?0.887776 ? ? ? ? ? ? ? ? ?3063total
?----------------------------------------------------------------------------------------
?# 用-c选项,ltrace输出由进程创建的库调用,输出结果以调用过程的时间为准进行排序,因为是从urandom设备上读,这是一种产生随机数的设备,完成后,写入null设备。所以读过程花费了较多的时间。使用ltrace去捕获运行时函数,就好像在进程上系上一个调试工具,它占用了ltrace大量的时间,这里ltrace一共消耗了0.887776秒
?----------------------------------------------------------------------------------------
?[root@RedHat_test ~]# strace -c dd if=/dev/urandom of=/dev/null count=1000
?记录了1000+0的读入
?记录了1000+0的写出
?512000字节(512 kB)已复制,0.0776944 秒,6.6 MB/秒
?% time ? ? seconds usecs/call ? ? calls ? errors syscall
?--------------------------------------------------------------
?66.07 ? ?0.010263 ? ? ? ? ?10? ? ?1003? ? ? ? ? read
?31.67 ? ?0.004920 ? ? ? ? ??5? ? ?1003? ? ? ? ??write
??1.20 ? ?0.000186 ? ? ? ? ?19? ? ? ?10? ? ? ??2open
??0.33 ? ?0.000052 ? ? ? ? ??5? ? ? ?11? ? ? ? ? close
??0.23 ? ?0.000036 ? ? ? ? ??3? ? ? ?11? ? ? ? ? mmap
??0.15 ? ?0.000024 ? ? ? ? ??4? ? ? ??6? ? ? ? ? fstat
??0.13 ? ?0.000020 ? ? ? ? ??5? ? ? ??4? ? ? ? ? brk
??0.08 ? ?0.000013 ? ? ? ? ??7? ? ? ??2? ? ? ? ? munmap
??0.08 ? ?0.000013 ? ? ? ? ??7? ? ? ??2? ? ? ? ? dup2
??0.04 ? ?0.000006 ? ? ? ? ??6? ? ? ??1? ? ? ? ? lseek
??0.00 ? ?0.000000 ? ? ? ? ??0? ? ? ??4? ? ? ? ? mprotect
??0.00 ? ?0.000000 ? ? ? ? ??0? ? ? ??4? ? ? ? ? rt_sigaction
??0.00 ? ?0.000000 ? ? ? ? ??0? ? ? ??1? ? ? ??1access
??0.00 ? ?0.000000 ? ? ? ? ??0? ? ? ??1? ? ? ? ? execve
??0.00 ? ?0.000000 ? ? ? ? ??0? ? ? ??1? ? ? ? ? arch_prctl
?--------------------------------------------------------------
?100.00 ? ?0.015533 ? ? ? ? ? ? ? ? ?2064? ? ? ??3total
?----------------------------------------------------------------------------------------
?# strace一共消耗了0.015533秒,strace把性能提升了80倍,这主要是strace在跟踪系统调用的时候不需要动态库,而ltrace是根据动态库来分析程序运行的。所以ltrace也只能跟踪动态库,不能跟踪静态库。事实上我们用ltrace和strace都可以发现程序在哪个系统调用时发生了性能瓶径。
?----------------------------------------------------------------------------------------

7、ltrace/strace的相同点

ltrace与strace都可以指定PID,即对运行中的程序进行跟踪。

ltrace与strace都可以跟踪程序fork或clone子进程。

ltrace是用-f参数,而strace是用-f(fork/clone)和-F(vfork)。

关于运维学习、分享、交流,笔者开通了微信公众号【运维猫】,感兴趣的朋友可以关注下,欢迎加入,建立属于我们自己的小圈子,一起学运维知识。

Tags:

最近发表
标签列表