• [optimize]使用systemtap调试用户态程序


    用户态调试

    原文地址:[optimize]使用systemtap调试用户态程序

     

    摘要

    systemtap既能调试内核,也能调试用户态. 然后有if有判断有循环.可编程就代表什么都行,那么给我一个用gdb的理由? 另外,世界之大,请不要忘记DTrace,linux 4.9之后支持.

    新手扫盲文档:https://sourceware.org/systemtap/SystemTap_Beginners_Guide/index.html

    由于我非常懒,所以只写了些例子在下面.建议先读一下上面的文档知道一下基本概念,之后再读我下面的例子,便基本可以进行简单的实践了.

     

    用户态调试的依赖条件

    3.5之前的linux需要打开内核选项CONFIG_UTRACE

     grep CONFIG_UTRACE /boot/config-`uname -r`

    3.5之后的linux需要打开内核选项CONFIG_UPROBES, CONFIG_UTRACE从这个版本开始被废弃.

     grep CONFIG_UPROBES /boot/config-`uname -r`

     

    其他

    需要特别强调的是,systemtap除了跟踪函数以外,还可以跟踪行噢,使用:

    process("a.out").statement("*@main.c:100")

    例子1:最简单的调试用户态程序

     stap -d /usr/sbin/ls --ldd -e 'probe process("ls").function("xmalloc") {print_usyms(ubacktrace())}' -c "ls /"

    例子2:查看可以用来调试的函数

    stap -L 'process("./nginx").function("*")'  // 查看nginx里的所有函数.并带着参数
    stap -l 'process("./nginx").function("*")' // 同上,但是不带参数.

    例子3:第一个简单的跟踪例子

    [root@T9 sbin]# stap -e 'probe process("./nginx").function("ngx_process_events_and_timers"){print("test: xxx
    ")}'
    test: xxx
    test: xxx
    ...

    下面的每次运行,会触发上面的打印信息.

    [root@T9 sbin]# curl 127.0.0.1:5000
    <html>
    <head><title>400 The plain HTTP request was sent to HTTPS port</title></head>
    <body>
    <center><h1>400 Bad Request</h1></center>
    <center>The plain HTTP request was sent to HTTPS port</center>
    <hr><center>JDCLOUD_ALB</center>
    </body>
    </html>

     

    例子4:打印变量

    找到这个变量的引用
    [root@T9 sbin]# stap -L 'process("./nginx").function("ngx_http_process_request_header") '
    process("/root/OUTPUT_alb/sbin/nginx").function("ngx_http_process_request_header@src/http/ngx_http_request.c:2184") $r:ngx_http_request_t*
    [root@T9 sbin]# stap -L 'process("./nginx").function("ngx_http_process_request_header").return '
    process("/root/OUTPUT_alb/sbin/nginx").function("ngx_http_process_request_header@src/http/ngx_http_request.c:2184").return $return:ngx_int_t $r:ngx_http_request_t*
    自动扩展打印,上面的变量 
    [root@T9 sbin]# stap -e 'probe process("./nginx").function("ngx_http_process_request_headers").return {print($$vars, "
    ");}' 
    WARNING: confusing usage, consider @entry($$vars) in .return probe: identifier '$$vars' at <input>:1:85
     source: probe process("./nginx").function("ngx_http_process_request_headers").return {print($$vars, "
    ");}
                                                                                                 ^
    rev=0x55714398b950 p=0x30 len=0x0 n=0x14 rc=0x7ffea5393130 rv=0x557142aab232 h=0x5571439283d0 c=0x557142a3d91a hh=0x557143928488 r=0x3c0 cscf=0x5571439283d0 cmcf=0x7ffea5393160
    ^C[root@T9 sbin]# stap -e 'probe process("./nginx").function("ngx_http_process_request_headers").return {print($n, "
    ");}'  
    WARNING: confusing usage, consider @entry($n) in .return probe: identifier '$n' at <input>:1:85
     source: probe process("./nginx").function("ngx_http_process_request_headers").return {print($n, "
    ");}
                                                                                                 ^
    20
    20

    例子5:使用脚本

    [root@T9 sbin]# cat nginx.stp
    //probe process("./nginx").function("ngx_http_process_request_headers") {
    probe process("./nginx").function("ngx_http_parse_header_line") {
            print($$vars, "
    ");
            print(user_string($b->pos), "
    ");
            exit();
    }
    [root@T9 sbin]# stap -v nginx.stp 
    Pass 1: parsed user script and 474 library scripts using 245204virt/42624res/3472shr/39252data kb, in 440usr/40sys/491real ms.
    Pass 2: analyzed script: 1 probe, 13 functions, 1 embed, 0 globals using 248112virt/46600res/4496shr/42160data kb, in 40usr/10sys/39real ms.
    Pass 3: using cached /root/.systemtap/cache/cd/stap_cd35c88067ad0752258f5c08e9a79aa9_4346.c
    Pass 4: using cached /root/.systemtap/cache/cd/stap_cd35c88067ad0752258f5c08e9a79aa9_4346.ko
    Pass 5: starting run.
    r=0x557143928420 b=0x557143915520 allow_underscores=0x0 c=0x0 ch=0x0 p=0x557143969d60 hash=0x55714398b950 i=0x557142a3da19 state=0x0 lowcase=[...]
    User-Agent: curl/7.29.0
    Host: 127.0.0.1:5000
    Accept: */*
    
    
    Pass 5: run completed in 20usr/60sys/6613real ms.
    [root@T9 sbin]# 

     

    例子6:复杂的变量打印

    [root@T9 sbin]# cat nginx.conn.stp  
    //probe process("./nginx").function("ngx_http_process_request_headers") {
    probe process("./nginx").function("ngx_http_init_connection").return {
            print(@entry($$vars), "
    ");
            print("sa_family: ",  @entry($c->local_sockaddr->sa_family), "
    ");
            print("conn: ",  @entry($c$$), "
    ");
            print("conn.local_sockaddr: ",  @cast(@entry($c->local_sockaddr), "struct sockaddr_in")$, "
    ");
            print("local port: ",  @cast(@entry($c->local_sockaddr), "struct sockaddr_in")->sin_port, "
    ");
            print("port: ",  @cast(@entry($c->sockaddr), "struct sockaddr_in")->sin_port, "
    ");
    //      exit();
    }
    [root@T9 sbin]# stap -v nginx.conn.stp                                   
    Pass 1: parsed user script and 474 library scripts using 245204virt/42624res/3472shr/39252data kb, in 440usr/20sys/473real ms.
    Pass 2: analyzed script: 2 probes, 56 functions, 3 embeds, 12 globals using 373612virt/172304res/4824shr/167660data kb, in 1190usr/420sys/1612real ms.
    Pass 3: using cached /root/.systemtap/cache/d6/stap_d6e87115e317f5b8522d63cd053dc232_19996.c
    Pass 4: using cached /root/.systemtap/cache/d6/stap_d6e87115e317f5b8522d63cd053dc232_19996.ko
    Pass 5: starting run.
    c=0x557143969e70 i=0x0 rev=0xf sin=0x0 port=0x557143969e70 addr=0x5571439154c1 ctx=0x557143915450 hc=0xf sin6=0x557143919ee8 addr6=0x557143915450 cscf=0x557143919f40
    sa_family: 2
    conn: {.data=0x0, .read=0x55714398b9b0, .write=0x5571439979c0, .fd=3, .recv=0x557142a7d60a, .send=0x557142a7df72, .recv_chain=0x557142a7d8d4, .send_chain=0x557142a88625, 
    .listening=0x557143917960, .sent=0, .revt=0, .log=0x557143915460, .pool=0x557143915400, .type=1, .sockaddr=0x557143915450, .socklen=16, .addr_text={.len=9, 
    .data="127.0.0.1377377377"}, .proxy_protocol_addr={.len=0, .data=0x0}, .proxy_protocol_port=0, .ssl=0x0, .asynch=0, .async_fd=0, .udp=0x0, .local_sockaddr=0x5571439581f0, 
    .local_socklen=16
    conn.local_sockaddr: {.sin_family=2, .sin_port=35091, .sin_addr={...}, .sin_zero=[...]}
    local port: 35091
    port: 6311

     

    例子7:条件判断的例子

    使用如下命令操作,分别访问端口5000,和5001.会有不同的打印日志:

    [root@T9 sbin]# curl -q 127.0.0.1:5000 >/dev/null 
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100   254  100   254    0     0   240k      0 --:--:-- --:--:-- --:--:--  248k
    [root@T9 sbin]# curl -q 127.0.0.1:5001 >/dev/null 
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100   612  100   612    0     0   386k      0 --:--:-- --:--:-- --:--:--  597k

    打印输出:

    [root@T9 sbin]# cat nginx.conn.stp
    //probe process("./nginx").function("ngx_http_process_request_headers") {
    
    global server_port = 0
    
    probe process("./nginx").function("ngx_http_init_connection").return {
            print(@entry($$vars), "
    ");
            print("sa_family: ",  @entry($c->local_sockaddr->sa_family), "
    ");
            print("conn: ",  @entry($c$$), "
    ");
            print("conn.local_sockaddr: ",  @cast(@entry($c->local_sockaddr), "struct sockaddr_in")$, "
    ");
            print("local port: ",  @cast(@entry($c->local_sockaddr), "struct sockaddr_in")->sin_port, "
    ");
            print("port: ",  @cast(@entry($c->sockaddr), "struct sockaddr_in")->sin_port, "
    ");
    
            server_port = @cast(@entry($c->local_sockaddr), "struct sockaddr_in")->sin_port;
    
            // 34835 35091
            if (server_port == 34835) {
                    printf("hahahahaha 5000: %d
    ", server_port);
            }
            printf("ennnnnnnnnnnnnnnnnd
    ");
    //      exit();
    }
    [root@T9 sbin]# stap -v nginx.conn.stp
    Pass 1: parsed user script and 474 library scripts using 245204virt/42628res/3472shr/39252data kb, in 400usr/20sys/424real ms.
    Pass 2: analyzed script: 2 probes, 57 functions, 3 embeds, 15 globals using 373624virt/172320res/4828shr/167672data kb, in 1120usr/350sys/1509real ms.
    Pass 3: using cached /root/.systemtap/cache/b3/stap_b3bb3ceb4342deea4b0c8d77121e806b_21075.c
    Pass 4: using cached /root/.systemtap/cache/b3/stap_b3bb3ceb4342deea4b0c8d77121e806b_21075.ko
    Pass 5: starting run.
    c=0x557143969d60 i=0x0 rev=0xf sin=0x0 port=0x557143969d60 addr=0x5571439154c1 ctx=0x557143915450 hc=0xf sin6=0x557143919ee8 addr6=0x557143915450 cscf=0x557143919f40
    sa_family: 2
    conn: {.data=0x0, .read=0x55714398b950, .write=0x557143997960, .fd=3, .recv=0x557142a7d60a, .send=0x557142a7df72, .recv_chain=0x557142a7d8d4, .send_chain=0x557142a88625, 
    .listening=0x557143917828, .sent=0, .revt=0, .log=0x557143915460, .pool=0x557143915400, .type=1, .sockaddr=0x557143915450, .socklen=16, .addr_text={.len=9, .data="127.0.0.1377377377"}, 
    .proxy_protocol_addr={.len=0, .data=0x0}, .proxy_protocol_port=0, .ssl=0x0, .asynch=0, .async_fd=0, .udp=0x0, .local_sockaddr=0x5571439581a0, .local_socklen=16
    conn.local_sockaddr: {.sin_family=2, .sin_port=34835, .sin_addr={...}, .sin_zero=[...]}
    local port: 34835
    port: 8864
    hahahahaha 5000: 34835
    ennnnnnnnnnnnnnnnnd
    c=0x557143969d60 i=0x0 rev=0xf sin=0x0 port=0x557143969d60 addr=0x5571439154c1 ctx=0x557143915450 hc=0xf sin6=0x557143919ee8 addr6=0x557143915450 cscf=0x557143919f40
    sa_family: 2
    conn: {.data=0x0, .read=0x55714398b950, .write=0x557143997960, .fd=3, .recv=0x557142a7d60a, .send=0x557142a7df72, .recv_chain=0x557142a7d8d4, .send_chain=0x557142a88625, 
    .listening=0x557143917960, .sent=0, .revt=0, .log=0x557143915460, .pool=0x557143915400, .type=1, .sockaddr=0x557143915450, .socklen=16, .addr_text={.len=9, .data="127.0.0.1377377377"}, 
    .proxy_protocol_addr={.len=0, .data=0x0}, .proxy_protocol_port=0, .ssl=0x0, .asynch=0, .async_fd=0, .udp=0x0, .local_sockaddr=0x5571439581f0, .local_socklen=16
    conn.local_sockaddr: {.sin_family=2, .sin_port=35091, .sin_addr={...}, .sin_zero=[...]}
    local port: 35091
    port: 9895
    ennnnnnnnnnnnnnnnnd
     
  • 相关阅读:
    Nokia Lumia 800销售反馈 苹果iPhone、三星Galaxy不敌800设计
    各大网站用户数据库被爆,遭大量网友下载
    最美发明家:GPS、手机通讯网都源自她的发明
    iPhone5或明年下半年发布 配备iOS6和A6芯片
    保存文件到手机内存
    2012年十大科技趋势:NFC、语音控制与弯曲屏
    电脑报独家报道:宽带升级全国真相调查
    Android的电话拨号器
    Java程序员成长之路(接口与抽象类究竟有什么区别)
    联系人相关
  • 原文地址:https://www.cnblogs.com/hugetong/p/14109525.html
Copyright © 2020-2023  润新知