Linux下重量级命令strace使用介绍

经常使用LINUX的朋友或许经常会疑问:linux是怎么样执行一条命令并得到正确输出结果的呢?
比如你输入一个pwd,得到的是当前路径,输入一个env显示的是系统环境变量等等,那你想知道他们是怎么样执行的吗?
go ahead!!
首先:
我们先看下一个重量级的系统调用函数execve(),具体的参数和返回值请大家使用man execve命令来查询吧。
如下程序就是来自实例文档:
[www.linuxidc.com @linux]$cat yuexe.c 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
    char *newargv[] = { NULL, "hello", "world", NULL };
    char *newenviron[] = { NULL };

    if (argc != 2) {
    fprintf(stderr, "Usage: %s <file-to-exec>\n", argv[0]);
    exit(EXIT_FAILURE);
    }
    newargv[0] = argv[1];
    execve(argv[1], newargv, newenviron);
    perror("execve");  /* execve() only returns on error */
    exit(EXIT_FAILURE);
}


编译成功后可以得到可执行文件:yuexe
[www.linuxidc.com @linux]$ls
grap.c  Hello  helloscons.c  helloscons.o  helloSina.h  SConstruct  weibo.h  yuexe  yuexe.c  yuexe.o
查看命令yuexe执行Hello程序的内核调用过程如下:

[www.linuxidc.com @linux]$sudo strace ./yuexe Hello

[sudo] password for yuchao:
execve("./yuexe", ["./yuexe", "Hello"], [/* 17 vars */]) = 0
brk(0)                                  = 0x84e3000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77b6000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=103314, ...}) = 0
mmap2(NULL, 103314, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb779c000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/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@n\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1421892, ...}) = 0
mmap2(NULL, 1427880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x45f000
mmap2(0x5b6000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x157) = 0x5b6000
mmap2(0x5b9000, 10664, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x5b9000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb779b000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb779b6c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0x5b6000, 8192, PROT_READ)    = 0
mprotect(0x8049000, 4096, PROT_READ)    = 0
mprotect(0xd3f000, 4096, PROT_READ)    = 0
munmap(0xb779c000, 103314)              = 0
execve("Hello", ["Hello", "hello", "world"], [/* 0 vars */]) = 0
brk(0)                                  = 0x8cf0000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77fb000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=103314, ...}) = 0
mmap2(NULL, 103314, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb77e1000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/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@n\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1421892, ...}) = 0
mmap2(NULL, 1427880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb3c000
mmap2(0xc93000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x157) = 0xc93000
mmap2(0xc96000, 10664, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xc96000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77e0000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb77e06c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, 
seg_not_present:0, useable:1}) = 0
mprotect(0xc93000, 8192, PROT_READ)    = 0
mprotect(0x8049000, 4096, PROT_READ)    = 0
mprotect(0xb1c000, 4096, PROT_READ)    = 0
munmap(0xb77e1000, 103314)              = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 5), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77fa000
write(1, "Hell Scons,I'm YuChao\n", 22Hell Scons,I'm YuChao
) = 22
write(1, "Hello SINA,I'm YuChao\n", 22Hello SINA,I'm YuChao
) = 22
write(1, "Hell weibo,I'm YuChao\n", 22Hell weibo,I'm YuChao
) = 22
exit_group(0)                          = ?

到这里可以看得很清楚,每个系统调用的过程,由于linux内核不允许用户态进程直接访问硬件资源,当用户进程需要访问系统硬件资源时采用系统调用,每个系统调用都有调用参数和返回值,如果想了解系统调用的具体含义请man 之。
如上可以看到:write(1,“Hell Scons,I'm YuChao\n",22 Hell Scons.....等等

另外,这个命令还可以用于优化系统网络时候使用,用于调用时候的效率考虑,用参数:strace -c ***可以看到具体的进程调用统计情况。

比如我查看我的本地web服务器的启动执行的内核调用过程:

$sudo strace -i -q -r -f -F -v -T -o strace_start strace /opt/lampp/lampp start
通过strace -c统计监控你的优化是否生效:
$sudo strace -c -o count_file /opt/lampp/lampp start

最后,当发生个http请求的时候,很多时候希望得到这个http请求发生了多少次数据库SELECT操作,是否在同一个mysql connection连接里面完成。

命令使用如下:

//-10321是mysqld的进程号,为了看到整条SQL语句,我们通过-s 1024希望输出更多内容
#strace -f -F -ff -o strace-mysqld -s 1024 -p 10321
#find . -name "strace-mysqld*" -type f -print |xargs grep -n "SELECT.*FROM wp_"
./strace-mysqld.19203:64:
read(19, "\3SELECT option_name, option_value FROM wp_options WHERE autoload = 'yes'", 72) = 72
./strace-mysqld.19203:165:
read(19, "\3SELECT * FROM wp_users WHERE user_login = 'admin'", 50) = 50
./strace-mysqld.19203:184:
read(19, "\3SELECT meta_key, meta_value FROM wp_usermeta WHERE user_id = 1", 63) = 63
./strace-mysqld.19203:295:
read(19, "\3SELECT option_value FROM wp_options WHERE option_name = 'rewrite_rules' LIMIT 1", 80) = 80
./strace-mysqld.19203:311:
read(19, "\3 SELECT  wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.ID = 501
    AND wp_posts.post_type = 'post'  ORDER BY wp_posts.post_date DESC ", 136) = 136
... (这里省去了一些)

通过如上的演示,你或许也看到了这个命令的厉害了,只能说linux是open的,你喜欢怎么做就怎么做,不行你就去修改linux kernel来打造自己的版本吧,如果你再配合gdb来使用,就更high了。


from:http://www.linuxidc.com/Linux/2012-10/71823.htm


本文来自 csdn ucser,    http://blog.csdn.net/perfectpdl   转载注明出处,谢谢.


有一段时间没弄Android了,整理一下,把之前 用GDB调试 Android jni程序过程共享一下:


Android 应用层为JAVA语言,但有时需要C/C++实现一些特定功能,比如视频编解码,此时需要借助JAVA的JNI技术,用JAVA语言调用c/C++程序,

而C/C++程序库 调试通常用GDB,不例外,Android 平台也提供了调试 JNI的功能,步骤如下:


1.  把 android:debuggable="true" 设置到  AndroidManifest.xml  文件的 <application> 标签,

2. NDK-BUILD 执行编译动态库时时 后面带上 NDK_DEBUG=1

3.  Application.mk 文件中 添加 APP_OPTIM := debug 

4. 启动Android设备上的 gdb server : gdbserver :5055 --attach PID

    参数为监听端口 5055, 要调试进程号  PID,

5. 在 宿主机上 执行 adb forward tcp:5055 tcp:5055

    连接到GDB  server.

6. 启动客户端 GBD :

arm-linux-androideabi-gdb

7. 设置库路径:

set solib-search-path obj/local/armeabi/libMySharedLib.so

 target remote :5055


哦了,进入调试 过程吧 :)


下面就以GDB调试Rild为例,来说明如何调试Native进程。

说明

#cmd     表明该命令运行于android设备控制台上
$cmd     表明该命令运行于Linux PC控制台上
(gdb)cmd 表明该命令运行于GDB控制台上

1. 调试已运行的rild

#ps | grep rild

得到rild的进程rild-pid

#gdbserver :5039 --attach rild-pid

或者调试新的rild进程

#gdbserver :5039 rild

2. 用ADB设置转发端口

$adb forward tcp:5039 tcp:5039

3. 在android的platform目录下

$prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-gdb
out/target/product/saarbmg1/symbols/system/bin/rild

4. 设置符号表

(gdb)set solib-absolute-prefix /home/loginname/android-platform/out/target/product/saarbmg1/symbols
(gdb)set solib-search-path /home/loginname/android-platform/out/target/product/saarbmg1/symbols/system/lib

5. 与GDB server连接

(gdb)target remote :5039
(gdb)shared

后面就可以进行调试了

下面是常用的gdb调试命令

(gdb)help [cmd]                            显示命令cmd的帮助
(gdb)bt                                    显示调用堆栈
(gdb)next|n                                执行下一代码
(gdb)step|s                                执行到下一行代码
(gdb)run|r                                 继续运行
(gdb)jump lineno                           执行到指定行为止
(gdb)break|b lineno|function if condifion  设置断点
(gdb)directory|dir dir1:dir2               指定源文件搜索路径

那么如何调试浏览器webkit等android应用的native代码呢?答案是肯定的,笔者成功单步调试了webkit的代码。


你可能感兴趣的:(Linux下重量级命令strace使用介绍)