每天学点GDB(八)

本文涉及的产品
公网NAT网关,每月750个小时 15CU
应用型负载均衡 ALB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
简介: 本文简述如何用ptrace来写一个非常简单的trace工具,用以trace程序的具体运行过程。以及描述两个gdb集成测试环境。

<一>A really simple tracing debugger

在上一篇文章中讲到了ptrace,那么我们完全可以用ptrace来写一个非常简单的trace工具,用以trace程序的具体运行过程。

用它可以很清楚的回答,使用glibc编译后的hello world是从什么地方开始运行的。

(注:本文内容根据“A really simple tracing debugger"翻译而来,具体链接见参考资料一节)

itrace.c

#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>

#include <sys/user.h>
#include <sys/ptrace.h>

int main(int argc, char **argv)
{
  int pid = fork();
  if(pid == 0) {
    if(ptrace(PTRACE_TRACEME) < 0) {
      perror("ptrace");
      _exit(1);
    }
    execvp(argv[1], argv + 1);
    perror("exec");
    _exit(1);
  }
  while(1) {
    int status;
    struct user_regs_struct regs;
    if(waitpid(pid, &status, 0) < 0)
      perror("waitpid");
    if(!WIFSTOPPED(status))
      break;
    if(ptrace(PTRACE_GETREGS, pid, 0, &regs) < 0)
      perror("ptrace/GETREGS");
    printf("%lx %lx\n", regs.eip, regs.esp);
    if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0) < 0)
      perror("ptrace/SINGLESTEP");
  }
  return 0;
}

编译:

gcc -m32 itrace.c -o itrace

译者注: -m32表示编译成32位格式,如果是在64位机器上,不需要加此选项,同时将itrace.c源码中的eip和esp转换为rip,rsp.

hellow.c

#include <stdio.h>
int main() { 
  printf("Hello, world!\n");
  return 0;
}

编译:

gcc -static -o hellow hellow.c

译者注: itrace保持一致,itrace如果是按32位格式来编译的,此处也应该一样。

测试运行

./itrace ./hellow | addr2line -e ./hellow -f | grep -v "??\|:?" | uniq

说明如下:

addr2line 是将地址转换为相应的源码。运行的结果很长,所以就不打算没有贴出来了。

treeify

为了让运行结果在显示的时候能够更好的反映出调用关系,根据堆栈(%esp)中的信息采用python脚本将其层次化的打印出来。

import subprocess
import sys

def read():
    for line in sys.stdin:
        try:
            regs = [int(x, 16) for x in line.split(" ")]
            yield {"eip": regs[0], "esp": regs[1]}
        # Ignore lines interspersed with other output!
        except (ValueError, IndexError):
            pass

def addr2line(iterable):
    proc = subprocess.Popen(["addr2line", "-e", sys.argv[1], "-f"],
                            stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    for regs in iterable:
        proc.stdin.write("%x\n" % regs["eip"])
        a = proc.stdout.readline().rstrip("\n")
        b = proc.stdout.readline().rstrip("\n")
        regs["func"] = "%s %s" % (a, b)
        yield regs

def entry_points(iterable):
    funcs = {}
    # We treat the first address we see for the function as its entry
    # point, and only report those entries from this point on.
    for regs in iterable:
        func = regs["func"].split(":")[0]
        if funcs.setdefault(func, regs["eip"]) == regs["eip"]:
            yield regs

def add_nesting(iterable):
    stack = [2 ** 64]
    for regs in iterable:
        stack_pos = regs["esp"]
        if stack_pos < stack[-1]:
            stack.append(stack_pos)
        while stack_pos > stack[-1]:
            stack.pop()
        regs["indent"] = "  " * len(stack)
        yield regs

for x in add_nesting(entry_points(addr2line(read()))):
    print x["indent"], x["func"], "%x" % x["eip"]

运行

./itrace ./hellow|python2 ./treeify.py ./hellow

测试结果:

     _start /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/start.S:61 8048d40
       __libc_start_main ??:? 8048ea0
         _dl_aux_init ??:? 806e590
         _dl_discover_osversion ??:? 806f3b0
           uname ??:? 80921c0
             ?? ??:0 b77e0414
         index ??:? 805b250
           __x86.get_pc_thunk.bx /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:66 8048d70
           __init_cpu_features ??:? 806f570
         strncasecmp_l ??:? 80b5ac0
         strcmp ??:? 805b460
         memset ??:? 805ba70
         strcasecmp_l ??:? 805bc10
         bcmp ??:? 805b6b0
         strstr ??:? 806b080
         memchr ??:? 808ce90
           __x86.get_pc_thunk.bx /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:66 8048d70
         strrchr ??:? 808c660
           __x86.get_pc_thunk.bx /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:66 8048d70
         wcslen ??:? 808eae0
           __x86.get_pc_thunk.bx /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:66 8048d70
         __rawmemchr ??:? 805bcc0
           __x86.get_pc_thunk.bx /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:66 8048d70
         memmove ??:? 805b9d0
         __strnlen ??:? 808c620
           __x86.get_pc_thunk.bx /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:66 8048d70
         strcpy ??:? 805b4d0
         stpcpy ??:? 805bb30
         __pthread_initialize_minimal ??:? 80494d0
           __libc_setup_tls ??:? 8049240
             sbrk ??:? 806cd70
               __brk ??:? 80928e0
                 ?? ??:0 b77e0414
               __brk ??:? 80928e0
                 ?? ??:0 b77e0414
             memcpy ??:? 805bc50
         __libc_init_first ??:? 806f4b0
           __setfpucw ??:? 807ac00
           __libc_init_secure ??:? 806f360
           _dl_non_dynamic_init ??:? 806e7f0
             _dl_get_origin ??:? 809a800
               ?? ??:0 b77e0414
               malloc ??:? 8058f60
                 malloc_hook_ini malloc.o:? 805a020
                   ptmalloc_init.part.7 malloc.o:? 8059c20
                     __linkin_atfork ??:? 806e0f0
                 malloc ??:? 8058f60
                   _int_malloc malloc.o:? 8057060
                     malloc_consolidate malloc.o:? 80560b0
                     malloc_init_state malloc.o:? 80552e0
                     __default_morecore ??:? 805b230
                       sbrk ??:? 806cd70
                         __brk ??:? 80928e0
                           ?? ??:0 b77e0414
                     __default_morecore ??:? 805b230
                       sbrk ??:? 806cd70
                         __brk ??:? 80928e0
                           ?? ??:0 b77e0414
               mempcpy ??:? 805bb00
             getenv ??:? 804e240
               strlen ??:? 805b5f0
             _dl_new_object ??:? 80972a0
               strlen ??:? 805b5f0
               __calloc ??:? 8059720
                 _int_malloc malloc.o:? 8057060
                 __memset_sse2_rep ??:? 805f690
               memcpy ??:? 805bc50
             _dl_setup_hash ??:? 8097150
             strlen ??:? 805b5f0
             malloc ??:? 8058f60
               _int_malloc malloc.o:? 8057060
             memcpy ??:? 805bc50
             _dl_add_to_namespace_list ??:? 8097200
             getenv ??:? 804e240
               strlen ??:? 805b5f0
             _dl_init_paths ??:? 80951f0
               _dl_important_hwcaps ??:? 80991b0
                 malloc ??:? 8058f60
                   _int_malloc malloc.o:? 8057060
                 mempcpy ??:? 805bb00
               malloc ??:? 8058f60
                 _int_malloc malloc.o:? 8057060
               malloc ??:? 8058f60
                 _int_malloc malloc.o:? 8057060
             getenv ??:? 804e240
               strlen ??:? 805b5f0
             getenv ??:? 804e240
               strlen ??:? 805b5f0
             getenv ??:? 804e240
               strlen ??:? 805b5f0
             getenv ??:? 804e240
               strlen ??:? 805b5f0
             getenv ??:? 804e240
               strlen ??:? 805b5f0
           __init_misc ??:? 806dd90
             __strrchr_sse2_bsf ??:? 808d830
         __ctype_init ??:? 807abb0
         __cxa_atexit ??:? 804e5d0
           __new_exitfn ??:? 804e440
         __libc_csu_init ??:? 80494f0
           _init /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:63 8048190
             __x86.get_pc_thunk.bx /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:66 8048d70
           _init /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crtn.S:40 80481ae
           frame_dummy crtstuff.c:? 8048e20
             __register_frame_info_bases ??:? 80bd5a0
               __x86.get_pc_thunk.bx /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:66 8048d70
           register_tm_clones crtstuff.c:? 8048db0
           init_cacheinfo cacheinfo.o:? 8048b10
             handle_intel cacheinfo.o:? 806b380
               intel_check_word cacheinfo.o:? 806b0b0
               intel_check_word cacheinfo.o:? 806b0b0
               intel_check_word cacheinfo.o:? 806b0b0
               intel_check_word cacheinfo.o:? 806b0b0
             handle_intel cacheinfo.o:? 806b380
               intel_check_word cacheinfo.o:? 806b0b0
               intel_check_word cacheinfo.o:? 806b0b0
         _setjmp ??:? 804d970
         main ??:? 8048e7c
           puts ??:? 804f350
             strlen ??:? 805b5f0
             _IO_new_file_xsputn ??:? 8052470
               _IO_file_overflow ??:? 8052e60
                 _IO_doallocbuf ??:? 8053b10
                   _IO_file_doallocate ??:? 808a730
                     _IO_file_stat ??:? 8051f20
                       ___fxstat64 ??:? 806c300
                         ?? ??:0 b77e0414
                     __mmap ??:? 806ce60
                       ?? ??:0 b77e0414
                     _IO_setb ??:? 8053aa0
                 _IO_new_do_write ??:? 80527b0
               _IO_default_xsputn ??:? 8053bc0
         exit ??:? 804e420
           __run_exit_handlers ??:? 804e320
             __libc_csu_fini ??:? 8049590
               fini sdlerror.o:? 8048b00
               check_free.isra.0 sdlerror.o:? 80a6f30
               __do_global_dtors_aux crtstuff.c:? 8048df0
                 deregister_tm_clones crtstuff.c:? 8048d80
                 __deregister_frame_info_bases ??:? 80bd7c0
                   __x86.get_pc_thunk.bx /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:66 8048d70
             _fini /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:82 80bec78
               __x86.get_pc_thunk.bx /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crti.S:66 8048d70
             _fini /root/glibc/src/glibc-2.18/csu/../sysdeps/i386/crtn.S:45 80bec87
             _IO_cleanup ??:? 80543b0
               _IO_flush_all_lockp ??:? 8054190
                 _IO_file_overflow ??:? 8052e60
                   _IO_new_do_write ??:? 80527b0
                     new_do_write fileops.o:? 8051100
                       _IO_file_write ??:? 8051f50
                         __write ??:? 806c420
                           ?? ??:0 b77e0414
               _IO_file_setbuf ??:? 8051060
                 _IO_default_setbuf ??:? 8053d10
                   _IO_file_sync ??:? 8053060
                   _IO_setb ??:? 8053aa0
             _Exit ??:? 806ba24
               ?? ??:0 b77e0414

参考资料

  1. http://lackingrhoticity.blogspot.ca/2009/05/really-simple-tracing-debugger.html

<二>两个gdb集成测试环境

本节重点描述两个gdb集成测试环境。

有没有办法在一边调试的时候,一边显示对应的源码呢?有没有一种工具能够将gdb集成到ide中呢,本文就试图回答这些问题。

emacs gdb

在linux的世界里,emacs集成gdb来时行调试可是闻名已久,经过了不断的演进gud也变得越来越强大,越来越好使了。

那么如何进入gud呢,很简单在emacs中,输入M-x(也就是alt+x)后,输入gdb,然后回车。有一个简短的提示,无视直接回车即可。

 在gdb所在窗口设置断点,运行程序。

程序将在设置的断点处停止运行,此时在菜单中选择gud->gdb-mi->display other windows,呈现如下图所示的效果:

gdb tui

与上述的emacs+gdb比较起来,这个gdb tui可能默默无名。我也是在无意之中发现这个东东的,还是比较好使的, 最主要的是这个功能是gdb本身内置的。无须第三方工具。

如何进入gdb tui模式

gdb -tui ./prog

或者在进入gdb之后输入如下快捷键

c-x a

想同时显示源码和反汇编代码的话,就c-x 2或者执行相应的指令layout

写在后面的话

花了15篇文章的内容,将自己日常软件调试时使用到的gdb知识作了一个小结,希望对大家有用。同时俺徽沪一郎也希望大家在转载的时候能够注明原文出处,谢谢。

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
目录
相关文章
|
7月前
|
Linux 编译器 C语言
《Linux从练气到飞升》No.05 Linux编译器gcc/g++的使用及编译过程 【云边有个小卖部】上新
《Linux从练气到飞升》No.05 Linux编译器gcc/g++的使用及编译过程 【云边有个小卖部】上新
165 0
|
7月前
|
机器学习/深度学习 存储 NoSQL
【Linux系统编程】代码调试工具gdb--2
【Linux系统编程】代码调试工具gdb--2
|
7月前
|
机器学习/深度学习 NoSQL Linux
【Linux系统编程】代码调试工具gdb--1
【Linux系统编程】代码调试工具gdb--1
|
7月前
|
NoSQL IDE Linux
《Linux从练气到飞升》No.09 Linux调试器-gdb使用
《Linux从练气到飞升》No.09 Linux调试器-gdb使用
60 0
《Linux从练气到飞升》No.09 Linux调试器-gdb使用
|
Linux
Buildroot系列开发(四)Linux工具链剖析(下)
Buildroot系列开发(四)Linux工具链剖析
110 3
Buildroot系列开发(四)Linux工具链剖析(下)
|
NoSQL Linux 编译器
Linux工具学习之【gdb】
vim 可以编写代码,gcc/g++ 可以编译代码,此时只最后一件神器,就能进行完整的开发工作,那就是通过 gdb 调试代码,毕竟谁都不敢保证自己的代码没有问题,所以就有调试器这种东西帮助我们定位问题,进而解决问题
215 0
Linux工具学习之【gdb】
|
NoSQL Linux C语言
如何优♂雅地学习GDB调试(一)
本章我们将带着大家高雅的学一学令众多习惯图形化页面的朋友难受的 gdb 调试,这部分知识可以选择性学习学习,以后倘若遇到一些问题时能在 Linux 内简单调试,还是很香的。然后在讲讲 gcc 和 g++,系统讲解程序运行时的各个过程。
249 0
如何优♂雅地学习GDB调试(一)
|
存储 NoSQL JavaScript
如何优♂雅地学习GDB调试(二)
本章我们将带着大家高雅的学一学令众多习惯图形化页面的朋友难受的 gdb 调试,这部分知识可以选择性学习学习,以后倘若遇到一些问题时能在 Linux 内简单调试,还是很香的。然后在讲讲 gcc 和 g++,系统讲解程序运行时的各个过程。
218 0
如何优♂雅地学习GDB调试(二)
|
Linux 开发工具
Buildroot系列开发(四)Linux工具链剖析(上)
Buildroot系列开发(四)Linux工具链剖析
168 0
Buildroot系列开发(四)Linux工具链剖析(上)
|
NoSQL C++ 容器
每天学点GDB(五)
本节分享使用GDB来进行STL容器的调试。
1815 0