【问题标题】:Find the main thread while debugging core file调试核心文件时找到主线程
【发布时间】:2023-05-14 13:40:01
【问题描述】:

我有一个程序,其中主线程创建了很多线程。它崩溃了,我正在调试核心文件。崩溃发生在一个子线程中。为了找到原因,我需要知道主线程是否还活着。有什么方法可以找出最初的线程是哪个线程?

【问题讨论】:

    标签: multithreading gdb parent-child core


    【解决方案1】:

    有什么方法可以找出最初的线程是哪个线程?

    当有 100 个线程时,我使用以下技术来查看它们:

    (gdb) shell rm gdb.txt
    (gdb) set logging on   # GDB output will go to gdb.txt
    (gdb) thread apply all where
    

    现在将gdb.txt 加载到您选择的编辑器或寻呼机中,查找main 等。

    【讨论】:

      【解决方案2】:

      作为基于 UNIX 系统的通用方法,接受的答案按预期工作。

      在 Linux(以及选择类似 POSIX 线程实现策略的操作系统)上,识别主线程可能要简单得多。通常,核心转储的文件名包含故障进程的 PID (e.g. core.<pid>),除非核心模式 (/proc/sys/kernel/core_pattern) 已更改。这样,您就可以使用thread find <pid> 可靠地确定主线程:

      $ gdb executable core.24533
      [...]
      (gdb) thread find 24533
      Thread 7 has target id 'Thread 0x7f8ae2169740 (LWP 24533)'
      (gdb) thread 7
      [Switching to thread 7 (Thread 0x7f8ae2169740 (LWP 24533))]
      #0  0x00007f8ae1d40017 in pthread_join (threadid=140234458433280, thread_return=0x0) at pthread_join.c:90
      90      lll_wait_tid (pd->tid);
      (gdb) bt
      #0  0x00007f8ae1d40017 in pthread_join (threadid=140234458433280, thread_return=0x0) at pthread_join.c:90
      #1  0x00007f8ae1ae40f7 in __gthread_join (__value_ptr=0x0, __threadid=<optimized out>)
          at /usr/src/debug/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/x86_64-redhat-linux/bits/gthr-default.h:668
      #2  std::thread::join (this=this@entry=0x5595aac42990) at ../../../../../libstdc++-v3/src/c++11/thread.cc:107
      #3  0x00005595a9681468 in operator() (t=..., __closure=<optimized out>) at segv.cxx:31
      #4  for_each<__gnu_cxx::__normal_iterator<std::thread*, std::vector<std::thread> >, ThreadPool::wait()::__lambda1> (__last=..., __first=..., __f=...)
          at /usr/include/c++/4.8.2/bits/stl_algo.h:4417
      #5  wait (this=0x7ffcac67d860) at segv.cxx:32
      #6  main (argc=<optimized out>, argv=<optimized out>) at segv.cxx:75
      
      

      如果文件名缺少 PID,它可以从核心转储本身中恢复。 PID 存储在注释部分 (PT_NOTE)。 NT_PRSTATUSNT_PRPSINFO 都包含 PID。在多个线程的情况下,NT_PRSTATUS 存在于包括主线程在内的每个单独的线程并且顺序未指定,另一方面,NT_PRPSINFO 仅存在一次。

      Linux x86_64 的定义(pr_pid 是我们感兴趣的领域):

      struct elf_prpsinfo
      {
              char    pr_state;       /* numeric process state */
              char    pr_sname;       /* char for pr_state */
              char    pr_zomb;        /* zombie */
              char    pr_nice;        /* nice val */
              unsigned long pr_flag;  /* flags */
              __kernel_uid_t  pr_uid;
              __kernel_gid_t  pr_gid;
              pid_t   pr_pid, pr_ppid, pr_pgrp, pr_sid;
              /* Lots missing */
              char    pr_fname[16];   /* filename of executable */
              char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
      };
      

      eu-readelf -nelfutils提供)可用于从NT_PRPSINFO中提取PID:

      $ eu-readelf -n core
      [...]
        CORE                 136  PRPSINFO
          state: 2, sname: D, zomb: 0, nice: 0, flag: 0x0000000040402504
          uid: 0, gid: 0, pid: 24533, ppid: 17322, pgrp: 24533, sid: 17299
                               ^^^^^
          fname: segv, psargs: ./segv 2 
      [...]
      

      【讨论】:

      • 作为调试具有 1000 多个线程的应用程序的人,这非常有用并且可以节省大量时间。非常感谢您回答以前接受的问题!