LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

GDB调试Breakpoints之Catchpoints

关键词:breakpoint、catchpoint、catch、throw、assert、load/unload、fork/vfork/exec、syscall、signal等等。

Breakpoints能让程序执行到后暂停流程,包括Breakpoints、Watchpoints、Catchpoints。

Catchpoints是一种特殊的Breakpoints,当某种特殊的事件产生后停止程序执行。

除了设置Catchpoints,其他对Catchpoints的管理方式类似于Breakpoints。

 

测试环境:Ubuntu 16.04, GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1。

1. 设置Catchpoints

Breakpoints, Watchpoints, and Catchpoints》、《Setting catchpoints》、《Signals》、《Stopping and Starting Multi-thread Programs》。

 在gdb中通过help catch可以看出支持哪些种类的events:

catch assert -- Catch failed Ada assertions
catch catch -- Catch an exception
catch exception -- Catch Ada exceptions
catch exec -- Catch calls to exec
catch fork -- Catch calls to fork
catch load -- Catch loads of shared libraries
catch rethrow -- Catch an exception
catch signal -- Catch signals by their names and/or numbers
catch syscall -- Catch system calls by their names and/or numbers
catch throw -- Catch an exception
catch unload -- Catch unloads of shared libraries
catch vfork -- Catch calls to vfork

catch/throw都是捕获exception,但是区别是:throw是The throwing of a C++ exception,catch是The catching of a C++ exception。

通过info break可以查看设置的Catchpoints。

有时候通过catch捕获到异常,此时已经进入异常处理函数中,有可能栈并不能指示确切发生了什么。

这时候可以通过在__raise_exception()打断点,能看到更直接的现场。

2. 构造Catchpoints

2.1 catch和throw

C++的异常有很多,下面以bad_function_call为例。

对如下程序编译:g++ -o bad_function_call bad_function_call.cc -g -Wall --std=c++11。

// bad_function_call example
#include <iostream>     // std::cout
#include <functional>   // std::function, std::plus, std::bad_function_call

int main () {
  std::function<int(int,int)> foo = std::plus<int>();
  std::function<int(int,int)> bar;

  try {
    std::cout << foo(10,20) << '\n';
    std::cout << bar(10,20) << '\n';
  } catch (std::bad_function_call& e) {
    std::cout << "ERROR: Bad function call\n";
  }

  return 0;
}

在gdb中设置catch catch和catch throw之后结果如下:

(gdb) r
Starting program: /home/al/temp/catch/bad_function_call 
30

Catchpoint 2 (exception thrown), 0x00007ffff7ae28bd in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) bt full
#0  0x00007ffff7ae28bd in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
No symbol table info available.
#1  0x00007ffff7b0b8b2 in std::__throw_bad_function_call() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
No symbol table info available.
#2  0x0000000000400f44 in std::function<int (int, int)>::operator()(int, int) const (this=0x7fffffffdb00, __args#0=10, __args#1=20) at /usr/include/c++/5/functional:2266
No locals.
#3  0x0000000000400c74 in main () at bad_function_call.cc:11
        foo = {<std::_Maybe_unary_or_binary_function<int, int, int>> = {<std::binary_function<int, int, int>> = {<No data fields>}, <No data fields>}, <std::_Function_base> = {static _M_max_size = 16, static _M_max_align = 8, 
            _M_functor = {_M_unused = {_M_object = 0x470, _M_const_object = 0x470, _M_function_pointer = 0x470, 
                _M_member_pointer = (void (std::_Undefined_class::*)(std::_Undefined_class * const)) 0x470, this adjustment 4295032831}, _M_pod_data = "p\004\000\000\000\000\000\000\377\377\000\000\001\000\000"}, 
            _M_manager = 0x40104b <std::_Function_base::_Base_manager<std::plus<int> >::_M_manager(std::_Any_data&, std::_Any_data const&, std::_Manager_operation)>}, 
          _M_invoker = 0x400ff3 <std::_Function_handler<int (int, int), std::plus<int> >::_M_invoke(std::_Any_data const&, int&&, int&&)>}
        bar = {<std::_Maybe_unary_or_binary_function<int, int, int>> = {<std::binary_function<int, int, int>> = {<No data fields>}, <No data fields>}, <std::_Function_base> = {static _M_max_size = 16, static _M_max_align = 8, 
            _M_functor = {_M_unused = {_M_object = 0x2, _M_const_object = 0x2, _M_function_pointer = 0x2, _M_member_pointer = (void (std::_Undefined_class::*)(std::_Undefined_class * const)) 0x2, this adjustment 4199101}, 
              _M_pod_data = "\002\000\000\000\000\000\000\000\275\022@\000\000\000\000"}, _M_manager = 0x0}, _M_invoker = 0x0}
(gdb) c
Continuing.

Catchpoint 1 (exception caught), 0x00007ffff7ae1711 in __cxa_begin_catch () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) bt full
#0  0x00007ffff7ae1711 in __cxa_begin_catch () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
No symbol table info available.
#1  0x0000000000400cd0 in main () at bad_function_call.cc:12
        e = @0x400d5b: <incomplete type>
        foo = {<std::_Maybe_unary_or_binary_function<int, int, int>> = {<std::binary_function<int, int, int>> = {<No data fields>}, <No data fields>}, <std::_Function_base> = {static _M_max_size = 16, static _M_max_align = 8, 
            _M_functor = {_M_unused = {_M_object = 0x470, _M_const_object = 0x470, _M_function_pointer = 0x470, 
                _M_member_pointer = (void (std::_Undefined_class::*)(std::_Undefined_class * const)) 0x470, this adjustment 4295032831}, _M_pod_data = "p\004\000\000\000\000\000\000\377\377\000\000\001\000\000"}, 
            _M_manager = 0x40104b <std::_Function_base::_Base_manager<std::plus<int> >::_M_manager(std::_Any_data&, std::_Any_data const&, std::_Manager_operation)>}, 
          _M_invoker = 0x400ff3 <std::_Function_handler<int (int, int), std::plus<int> >::_M_invoke(std::_Any_data const&, int&&, int&&)>}
        bar = {<std::_Maybe_unary_or_binary_function<int, int, int>> = {<std::binary_function<int, int, int>> = {<No data fields>}, <No data fields>}, <std::_Function_base> = {static _M_max_size = 16, static _M_max_align = 8, 
            _M_functor = {_M_unused = {_M_object = 0x2, _M_const_object = 0x2, _M_function_pointer = 0x2, _M_member_pointer = (void (std::_Undefined_class::*)(std::_Undefined_class * const)) 0x2, this adjustment 4199101}, 
              _M_pod_data = "\002\000\000\000\000\000\000\000\275\022@\000\000\000\000"}, _M_manager = 0x0}, _M_invoker = 0x0}

 可以看出catch throw比catch catch更接近异常现场。

std::exception》还包含了很多C++异常,通过catch throw/catch catch可以看到详细的异常栈。

2.2 assert异常

assert在当前环境下不支持,但是通过catch signal SIGABRT或者不使用都可以看到完整的异常栈信息。

#include <assert.h>

void g(int i) {
    assert(0);
}

void f(int i) {
    g(i);
}

int main(void) {
    f(1);
}

结果如下:

gcc -o assert assert.c -g 
gdb ./assert 

(gdb) r Starting program: /home/al/temp/catch/assert assert: assert.c:4: g: Assertion `0' failed. Program received signal SIGABRT, Aborted. 0x00007ffff7a42438 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54 54 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory. (gdb) bt full #0 0x00007ffff7a42438 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54 resultvar = 0 pid = 9886 selftid = 9886 #1 0x00007ffff7a4403a in __GI_abort () at abort.c:89 save_stage = 2 act = {__sigaction_handler = {sa_handler = 0x4, sa_sigaction = 0x4}, sa_mask = {__val = {0, 0, 140737488345552, 0, 140737354096640, 4195853, 4, 4195855, 0, 0, 140737348441484, 140737349538576, 140737349552224, 896, 140737349538576, 4195853}}, sa_flags = -134258688, sa_restorer = 0x40060d} sigs = {__val = {32, 0 <repeats 15 times>}} #2 0x00007ffff7a3abe7 in __assert_fail_base (fmt=<optimized out>, assertion=assertion@entry=0x40060d "0", file=file@entry=0x400604 "assert.c", line=line@entry=4, function=function@entry=0x40060f <__PRETTY_FUNCTION__.1847> "g") at assert.c:92 str = 0x602080 "" total = 4096 #3 0x00007ffff7a3ac92 in __GI___assert_fail (assertion=0x40060d "0", file=0x400604 "assert.c", line=4, function=0x40060f <__PRETTY_FUNCTION__.1847> "g") at assert.c:101 No locals. #4 0x000000000040054a in g (i=1) at assert.c:4 __PRETTY_FUNCTION__ = "g" #5 0x000000000040055f in f (i=1) at assert.c:8 No locals. #6 0x0000000000400570 in main () at assert.c:12 No locals.

2.3 load和unload

#include <stdio.h>

void f(int i) {
    printf("%s i=%d\n", __func__, i);
}

int main(void) {
    f(1);
}

结果如下:

(gdb) i b
Num     Type           Disp Enb Address            What
1       catchpoint     keep y                      load of library
2       catchpoint     keep y                      unload of library
(gdb) r
Starting program: /home/al/temp/catch/load_unload 

Catchpoint 1
  Inferior loaded /lib/x86_64-linux-gnu/libc.so.6
dl_main (phdr=<optimized out>, phnum=<optimized out>, user_entry=<optimized out>, auxv=<optimized out>) at rtld.c:2206
2206    rtld.c: No such file or directory.
(gdb) c
Continuing.
f i=1
[Inferior 1 (process 10848) exited normally]

可以看出断住了load of libc.so,但是没有抓住unload of libc.so。

2.4 signal

对signal设置可以catch signal或者catch signal <sig num>,修改gdb对具体signal触发后的行为可以通过handle进行,具体参考《Signals》。

支持的signal可以通过catch signal,然后Tab查看:

32                   SIG107               SIG123               SIG43                SIG59                SIG75                SIG91                SIGEMT               SIGPROF              SIGUSR2
33                   SIG108               SIG124               SIG44                SIG60                SIG76                SIG92                SIGFPE               SIGPWR               SIGVTALRM
34                   SIG109               SIG125               SIG45                SIG61                SIG77                SIG93                SIGGRANT             SIGQUIT              SIGWAITING
EXC_ARITHMETIC       SIG110               SIG126               SIG46                SIG62                SIG78                SIG94                SIGHUP               SIGRETRACT           SIGWINCH
EXC_BAD_ACCESS       SIG111               SIG127               SIG47                SIG63                SIG79                SIG95                SIGILL               SIGSAK               SIGWIND
EXC_BAD_INSTRUCTION  SIG112               SIG32                SIG48                SIG64                SIG80                SIG96                SIGINFO              SIGSEGV              SIGXCPU
EXC_BREAKPOINT       SIG113               SIG33                SIG49                SIG65                SIG81                SIG97                SIGINT               SIGSOUND             SIGXFSZ
EXC_EMULATION        SIG114               SIG34                SIG50                SIG66                SIG82                SIG98                SIGIO                SIGSTOP              
EXC_SOFTWARE         SIG115               SIG35                SIG51                SIG67                SIG83                SIG99                SIGKILL              SIGSYS               
SIG100               SIG116               SIG36                SIG52                SIG68                SIG84                SIGABRT              SIGLOST              SIGTERM              
SIG101               SIG117               SIG37                SIG53                SIG69                SIG85                SIGALRM              SIGLWP               SIGTRAP              
SIG102               SIG118               SIG38                SIG54                SIG70                SIG86                SIGBUS               SIGMSG               SIGTSTP              
SIG103               SIG119               SIG39                SIG55                SIG71                SIG87                SIGCANCEL            SIGPHONE             SIGTTIN              
SIG104               SIG120               SIG40                SIG56                SIG72                SIG88                SIGCHLD              SIGPIPE              SIGTTOU              
SIG105               SIG121               SIG41                SIG57                SIG73                SIG89                SIGCONT              SIGPOLL              SIGURG               
SIG106               SIG122               SIG42                SIG58                SIG74                SIG90                SIGDANGER            SIGPRIO              SIGUSR1              

当前gdb对signal处理方式可以通过info signals查看:

SIGHUP        Yes    Yes    Yes        Hangup
SIGINT        Yes    Yes    No        Interrupt
SIGQUIT       Yes    Yes    Yes        Quit
SIGILL        Yes    Yes    Yes        Illegal instruction
SIGTRAP       Yes    Yes    No        Trace/breakpoint trap
SIGABRT       Yes    Yes    Yes        Aborted
SIGEMT        Yes    Yes    Yes        Emulation trap
SIGFPE        Yes    Yes    Yes        Arithmetic exception
SIGKILL       Yes    Yes    Yes        Killed
SIGBUS        Yes    Yes    Yes        Bus error
SIGSEGV       Yes    Yes    Yes        Segmentation fault
SIGSYS        Yes    Yes    Yes        Bad system call
SIGPIPE       Yes    Yes    Yes        Broken pipe
SIGALRM       No    No    Yes        Alarm clock
SIGTERM       Yes    Yes    Yes        Terminated
SIGURG        No    No    Yes        Urgent I/O condition
SIGSTOP       Yes    Yes    Yes        Stopped (signal)
SIGTSTP       Yes    Yes    Yes        Stopped (user)
SIGCONT       Yes    Yes    Yes        Continued
SIGCHLD       No    No    Yes        Child status changed
SIGTTIN       Yes    Yes    Yes        Stopped (tty input)
SIGTTOU       Yes    Yes    Yes        Stopped (tty output)
SIGIO         No    No    Yes        I/O possible
SIGXCPU       Yes    Yes    Yes        CPU time limit exceeded
SIGXFSZ       Yes    Yes    Yes        File size limit exceeded
SIGVTALRM     No    No    Yes        Virtual timer expired
SIGPROF       No    No    Yes        Profiling timer expired
SIGWINCH      No    No    Yes        Window size changed
SIGLOST       Yes    Yes    Yes        Resource lost
SIGUSR1       Yes    Yes    Yes        User defined signal 1
SIGUSR2       Yes    Yes    Yes        User defined signal 2
SIGPWR        Yes    Yes    Yes        Power fail/restart
SIGPOLL       No    No    Yes        Pollable event occurred
SIGWIND       Yes    Yes    Yes        SIGWIND
SIGPHONE      Yes    Yes    Yes        SIGPHONE
SIGWAITING    No    No    Yes        Process's LWPs are blocked
SIGLWP        No    No    Yes        Signal LWP
SIGDANGER     Yes    Yes    Yes        Swap space dangerously low
SIGGRANT      Yes    Yes    Yes        Monitor mode granted
SIGRETRACT    Yes    Yes    Yes        Need to relinquish monitor mode
SIGMSG        Yes    Yes    Yes        Monitor mode data available
SIGSOUND      Yes    Yes    Yes        Sound completed
SIGSAK        Yes    Yes    Yes        Secure attention
SIGPRIO       No    No    Yes        SIGPRIO
SIG33         Yes    Yes    Yes        Real-time event 33
SIG34         Yes    Yes    Yes        Real-time event 34
...

2.5 exec、fork、vfork、syscall

exec、fork、vfork并不等同于syscal的同名调用,是由c库函数的实现决定的。

# include <stdio.h>
# include<sys/types.h>
# include <unistd.h>
int main()
{
    pid_t pid=fork();

    if(pid==0)
        printf("Child\n");
    else
        printf("Father\n");
}

通过catch fork查看:

(gdb) catch fork 
Catchpoint 1 (fork)
(gdb) r
Starting program: /home/al/temp/catch/fork 

Catchpoint 1 (forked process 12992), 0x00007ffff7ad949a in __libc_fork () at ../sysdeps/nptl/fork.c:145
warning: Source file is more recent than executable.
(gdb) bt full
#0  0x00007ffff7ad949a in __libc_fork () at ../sysdeps/nptl/fork.c:145
        resultvar = 18446744073709551578
        pid = <optimized out>
        allp = 0x0
        multiple_threads = false
        runp = <optimized out>
        ppid = 0
        parentpid = 0
        __PRETTY_FUNCTION__ = "__libc_fork"
#1  0x0000000000400573 in main () at fork.c:6
        pid = 0

通过catch syscall查看:

(gdb) catch syscall fork
Catchpoint 1 (syscall 'fork' [57])
(gdb) catch syscall clone
Catchpoint 2 (syscall 'clone' [56])
(gdb) r
Starting program: /home/al/temp/catch/fork 

Catchpoint 2 (call to syscall clone), 0x00007ffff7ad949a in __libc_fork () at ../sysdeps/nptl/fork.c:145
warning: Source file is more recent than executable.
(gdb) bt full
#0  0x00007ffff7ad949a in __libc_fork () at ../sysdeps/nptl/fork.c:145
        resultvar = 18446744073709551578
        pid = <optimized out>
        allp = 0x0
        multiple_threads = false
        runp = <optimized out>
        ppid = 0
        parentpid = 0
        __PRETTY_FUNCTION__ = "__libc_fork"
#1  0x0000000000400573 in main () at fork.c:6
        pid = 0
(gdb) c
Continuing.
Child

Catchpoint 2 (returned from syscall clone), 0x00007ffff7ad949a in __libc_fork () at ../sysdeps/nptl/fork.c:145
(gdb) bt full
#0  0x00007ffff7ad949a in __libc_fork () at ../sysdeps/nptl/fork.c:145
        resultvar = 13452
        pid = <optimized out>
        allp = 0x0
        multiple_threads = false
        runp = <optimized out>
        ppid = 0
        parentpid = 0
        __PRETTY_FUNCTION__ = "__libc_fork"
#1  0x0000000000400573 in main () at fork.c:6
        pid = 0

可以看出C函数fork()对应的系统调用是clone()。

在gdb中catch syscall对所有syscall打断点,还可以单独对某个syscall打断点。可以在catch syscall基础上Tab显示当前所支持的syscall:

_llseek                 dup2                    getgroups               kill                    nanosleep               readdir                 sendfile                sigprocmask             umask
_newselect              execve                  getitimer               lchown                  nfsservctl              readlink                setdomainname           sigreturn               umount
_sysctl                 exit                    getpgid                 lchown32                nice                    readv                   setfsgid                sigsuspend              umount2
access                  fchdir                  getpgrp                 link                    oldfstat                reboot                  setfsuid                socketcall              uname
acct                    fchmod                  getpid                  lock                    oldlstat                rename                  setgid                  ssetmask                unlink
adjtimex                fchown                  getpmsg                 lseek                   oldolduname             restart_syscall         setgroups               stat                    uselib
afs_syscall             fcntl                   getppid                 lstat                   oldstat                 rmdir                   sethostname             stat64                  ustat
alarm                   fdatasync               getpriority             lstat64                 olduname                rt_sigaction            setitimer               statfs                  utime
bdflush                 flock                   getresgid               mkdir                   open                    rt_sigpending           setpgid                 stime                   vfork
break                   fork                    getresuid               mknod                   pause                   rt_sigprocmask          setpriority             stty                    vhangup
brk                     fstat                   getrlimit               mlock                   personality             rt_sigqueueinfo         setregid                swapoff                 vm86
capget                  fstat64                 getrusage               mlockall                pipe                    rt_sigreturn            setresgid               swapon                  vm86old
capset                  fstatfs                 getsid                  mmap                    poll                    rt_sigsuspend           setresuid               symlink                 wait4
chdir                   fsync                   gettimeofday            mmap2                   prctl                   rt_sigtimedwait         setreuid                sync                    waitpid
chmod                   ftime                   getuid                  modify_ldt              pread64                 sched_get_priority_max  setrlimit               sysfs                   write
chown                   ftruncate               getuid32                mount                   prof                    sched_get_priority_min  setsid                  sysinfo                 writev
chroot                  ftruncate64             gtty                    mprotect                profil                  sched_getparam          settimeofday            syslog                  
clone                   get_kernel_syms         idle                    mpx                     ptrace                  sched_getscheduler      setuid                  time                    
close                   getcwd                  init_module             mremap                  putpmsg                 sched_rr_get_interval   sgetmask                times                   
creat                   getdents                ioctl                   msync                   pwrite64                sched_setparam          sigaction               truncate                
create_module           getegid                 ioperm                  munlock                 query_module            sched_setscheduler      sigaltstack             truncate64              
delete_module           geteuid                 iopl                    munlockall              quotactl                sched_yield             signal                  ugetrlimit              
dup                     getgid                  ipc                     munmap                  read                    select                  sigpending              ulimit       

 

posted on 2020-10-11 00:00  ArnoldLu  阅读(2453)  评论(0编辑  收藏  举报

导航