Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 无核心文件分割错误分析_Linux_Debugging_Linux Kernel_Crash_Crash Dumps - Fatal编程技术网

Linux 无核心文件分割错误分析

Linux 无核心文件分割错误分析,linux,debugging,linux-kernel,crash,crash-dumps,Linux,Debugging,Linux Kernel,Crash,Crash Dumps,假设我的二进制文件在一个客户站点上运行,在那里我无法使用ulimit-c启用core dump生成。在这样的现实场景中,工程师如何调试分段错误?有没有其他方法可以调试或识别没有生成核心转储的崩溃。在过去,我曾多次遇到这种限制。必须调查分段故障,或者更一般地说,异常进程终止,并警告核心转储不可用 对于本演练选择的Linux平台,我想到了几个原因: 核心转储生成被完全禁用(使用limits.conf或ulimit) 目标目录(当前工作目录或/proc/sys/kernel/core_pattern

假设我的二进制文件在一个客户站点上运行,在那里我无法使用
ulimit-c
启用
core dump
生成。在这样的现实场景中,工程师如何调试
分段错误
?有没有其他方法可以调试或识别没有生成
核心转储的崩溃。

在过去,我曾多次遇到这种限制。必须调查分段故障,或者更一般地说,异常进程终止,并警告核心转储不可用

对于本演练选择的Linux平台,我想到了几个原因:

  • 核心转储生成被完全禁用(使用
    limits.conf
    ulimit
  • 目标目录(当前工作目录或
    /proc/sys/kernel/core_pattern
    中的目录)不存在或由于文件系统权限或SELinux无法访问
  • 目标文件系统磁盘空间不足,导致部分转储
对于所有这些,最终结果都是一样的:没有(有效的)内核转储可用于分析。幸运的是,存在一种用于事后调试的变通方法,这种方法有可能节省时间,但鉴于其固有的局限性,您的里程可能因情况而异

识别故障指令 以下示例包含一个典型的可用内存错误后使用:

#include <iostream>

struct Test
{
  const std::string &m_value;

  Test(const std::string &value):
    m_value(value)
  {
  }

  void print()
  {
    std::cout << m_value << std::endl;
  }
};

int main()
{
  std::string *value = new std::string("this is a test");
  Test test(*value);
  delete value;
  test.print();
  return 0;
}
当进程由于访问冲突而终止时,Linux内核会创建一个日志条目,该条目可通过
dmesg
访问,并且根据系统的配置,还可以通过syslog(通常是
/var/log/messages
)访问。示例(使用
-O0
编译)创建以下条目:

$ dmesg | grep segfault
[80440.957955] a.out[7098]: segfault at ffffffffffffffe8 ip 00007f9f2c2b56a3 sp 00007ffc3e75bc48 error 5 in libstdc++.so.6.0.19[7f9f2c220000+e9000]
来自
arch/x86/mm/fault.c
的相应Linux内核源代码:

    printk("%s%s[%d]: segfault at %lx ip %px sp %px error %lx",
        loglvl, tsk->comm, task_pid_nr(tsk), address,
        (void *)regs->ip, (void *)regs->sp, error_code);
错误(
error\u code
)显示了触发器是什么。它是一个特定于CPU的位集()。在我们的例子中,值
5
101
二进制)表示错误地址
0xFFFFFFFFFFFFFFFF8
表示的页面已映射,但由于页面保护而无法访问,并尝试读取


日志消息标识执行错误指令的模块:
libstdc++.so.6.0.1
。该示例是在没有优化的情况下编译的,因此调用
std::basic\u ostream&std::operator希望这有帮助!让我知道你是否回答了你的问题,或者我是否应该详细说明一个具体方面。谢谢你的回答。这是非常描述性的,并且很好地解释了概念。谢谢。我用一个简单的程序
int main(){char*ptr;*ptr='a';//这个segfaults}
dmesg
显示了
0 ip 000055cdcfe6d602 sp 00007ffc298bae20错误6在a.out[55cdcfe6d000+1000]中的segfault。我做了一个减法000055cdcfe6d602-55cdcfe6d000,这使我得到了正确的指令。然而,我在这里确实有一些疑问。为什么rip在
dmesg
gdb
中显示两个值。在gdb
rip 0x55554602 0x55554602
中,在dmesg中,它是
000055cdcfe6d602
。这是否意味着在
gdb
中,它将
rip
包含在它自己的进程加法区域中,但在
dmesg
中,它相对于整个内核是相对的
rip
?这是因为gdb默认禁用ASLR。您可以通过
将禁用随机化设置为off
禁用该功能。然后,基址将不是
0x554000
<代码>$rip
始终是绝对值。
    printk("%s%s[%d]: segfault at %lx ip %px sp %px error %lx",
        loglvl, tsk->comm, task_pid_nr(tsk), address,
        (void *)regs->ip, (void *)regs->sp, error_code);
  400bef:       e8 4c fd ff ff          callq  400940 <_ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RK
SbIS4_S5_T1_E@plt>
ip 00007f9f2c2b56a3 [...] error 5 in
   ^^^^^^^^^^^^^^^^ 
  libstdc++.so.6.0.19[7f9f2c220000+e9000]                                     
                      ^^^^^^^^^^^^
0x7f9f2c2b56a3-0x7f9f2c220000=0x956a3
$ objdump --demangle -d /usr/lib64/libstdc++.so.6
[...]
00000000000956a0 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, s
td::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<ch
ar>, std::allocator<char> > const&)@@GLIBCXX_3.4>:
   956a0:       48 8b 36                mov    (%rsi),%rsi
   956a3:       48 8b 56 e8             mov    -0x18(%rsi),%rdx
   ^^^^^
   956a7:       e9 24 4e fc ff          jmpq   5a4d0 <std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)@plt>
   956ac:       0f 1f 40 00             nopl   0x0(%rax)
[...]
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b686a3 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) () from /lib64/libstdc++.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-323.el7_9.x86_64 libgcc-4.8.5-44.el7.x86_64 libstdc++-4.8.5-44.el7.x86_64
(gdb) disass
Dump of assembler code for function _ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKSbIS4_S5_T1_E:
   0x00007ffff7b686a0 <+0>: mov    (%rsi),%rsi
=> 0x00007ffff7b686a3 <+3>: mov    -0x18(%rsi),%rdx
   0x00007ffff7b686a7 <+7>: jmpq   0x7ffff7b2d4d0 <_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l@plt>
End of assembler dump.
(gdb) print /x $rsi-0x18
$2 = 0xffffffffffffffe8
$ catchsegv ./a.out
*** Segmentation fault
Register dump:

 RAX: 0000000002158040   RBX: 0000000002158040   RCX: 0000000002158000
[...]
Backtrace:
/lib64/libstdc++.so.6(_ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKSbIS4_S5_T1_E+0x3)[0x7f1794fd36a3]
??:?(_ZN4Test5printEv)[0x400bf4]
??:?(main)[0x400b2d]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f179467a555]
??:?(_start)[0x4009e9]

Memory map:

00400000-00401000 r-xp 00000000 08:02 50331747 /home/user/a.out
[...]
7f1794f3e000-7f1795027000 r-xp 00000000 08:02 33600977 /usr/lib64/libstdc++.so.6.0.19
7f1795027000-7f1795227000 ---p 000e9000 08:02 33600977 /usr/lib64/libstdc++.so.6.0.19
7f1795227000-7f179522f000 r--p 000e9000 08:02 33600977 /usr/lib64/libstdc++.so.6.0.19
7f179522f000-7f1795231000 rw-p 000f1000 08:02 33600977 /usr/lib64/libstdc++.so.6.0.19
[...]
??:?(_ZN4Test5printEv)[0x400bf4]
$ objdump --demangle -d ./a.out
[...]
  400bea:       bf a0 20 60 00          mov    $0x6020a0,%edi
  400bef:       e8 4c fd ff ff          callq  400940 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std:
:char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_trai
ts<char>, std::allocator<char> > const&)@plt>
  400bf4:       be 70 09 40 00          mov    $0x400970,%esi
  ^^^^^^
  400bf9:       48 89 c7                mov    %rax,%rdi
  400bfc:       e8 5f fd ff ff          callq  400960 <std::ostream::operator<<(std::ostream& (*)(std::ostream&))@plt>
[...]
??:?(main)[0x400b2d]
$ objdump --demangle -d ./a.out
[...]
  400b1c:       e8 af fd ff ff          callq  4008d0 <operator delete(void*)@plt>
  400b21:       48 8d 45 d0             lea    -0x30(%rbp),%rax
  400b25:       48 89 c7                mov    %rax,%rdi
  400b28:       e8 a7 00 00 00          callq  400bd4 <Test::print()>
  400b2d:       b8 00 00 00 00          mov    $0x0,%eax
  ^^^^^^
  400b32:       eb 2a                   jmp    400b5e <main+0xb1>
[...]
[98161.650474] a.out[13185]: segfault at ffffffffffffffe8 ip 0000000000400a4b sp 00007ffc9e738270 error 5 in a.out[400000+1000]
  400a3e:       e8 dd fe ff ff          callq  400920 <operator delete(void*)@plt>
  400a43:       48 8b 33                mov    (%rbx),%rsi
  400a46:       bf a0 20 60 00          mov    $0x6020a0,%edi
  400a4b:       48 8b 56 e8             mov    -0x18(%rsi),%rdx
  ^^^^^^
  400a4f:       e8 4c ff ff ff          callq  4009a0 <std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)@plt>
  400a54:       48 89 c5                mov    %rax,%rbp
  400a57:       48 8b 00                mov    (%rax),%rax
  400a43:       48 8b 33                mov    (%rbx),%rsi
    operator<<(basic_ostream<_CharT, _Traits>& __os,
               const basic_string<_CharT, _Traits, _Alloc>& __str)
    {
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 586. string inserter not a formatted function
      return __ostream_insert(__os, __str.data(), __str.size());
  400a46:       bf a0 20 60 00          mov    $0x6020a0,%edi
  400a4b:       48 8b 56 e8             mov    -0x18(%rsi),%rdx
  ^^^^^^
  400a4f:       e8 4c ff ff ff          callq  4009a0 <std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)@plt>
  400a54:       48 89 c5                mov    %rax,%rbp
# compile with debug info
g++ segv.cxx -O3 -g
# create detached debug info
objcopy --only-keep-debug a.out a.out.debug
# remove debug info from executable
strip -g a.out
# re-add debug info to executable
eu-unstrip ./a.out ./a.out.debug -o ./a.out-debuginfo
# objdump with executable containing debug info
objdump --demangle -d ./a.out-debuginfo --source
$ gdb ./a.out
[...]
(gdb) disass 0x400a4b
Dump of assembler code for function main():
[...]
   0x0000000000400a43 <+67>:    mov    (%rbx),%rsi
   0x0000000000400a46 <+70>:    mov    $0x6020a0,%edi
   0x0000000000400a4b <+75>:    mov    -0x18(%rsi),%rdx
   0x0000000000400a4f <+79>:    callq  0x4009a0 <_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l@plt>
   0x0000000000400a54 <+84>:    mov    %rax,%rbp
(gdb) disass /m 0x400a4b
Dump of assembler code for function main():
[...]
21    Test test(*value);
22    delete value;
   0x0000000000400a25 <+37>:    test   %rbx,%rbx
   0x0000000000400a28 <+40>:    je     0x400a43 <main()+67>
   0x0000000000400a3b <+59>:    mov    %rbx,%rdi
   0x0000000000400a3e <+62>:    callq  0x400920 <_ZdlPv@plt>

23    test.print();
24    return 0;
25  }
   0x0000000000400a88 <+136>:   add    $0x18,%rsp
[...]
End of assembler dump.