我在Linux中有一个进程出现分段错误。我如何告诉它在发生故障时生成核心转储?
我在Linux中有一个进程出现分段错误。我如何告诉它在发生故障时生成核心转储?
Answers:
这取决于您使用的外壳。如果使用的是bash,则ulimit命令控制与程序执行有关的一些设置,例如是否应该转储core。如果您输入
ulimit -c unlimited
那么这将告诉bash它的程序可以转储任何大小的内核。您可以根据需要指定诸如52M的大小,而不是无限制的大小,但是实际上,这不是必需的,因为核心文件的大小可能永远不会成为您的问题。
在tcsh中,您可以输入
limit coredumpsize unlimited
如上所述,这里要问的真正问题是如何在未启用核心转储的系统上启用核心转储。在这里回答了这个问题。
如果您来这里是为了学习如何为挂起的进程生成核心转储,答案是
gcore <pid>
如果gcore在您的系统上不可用,则
kill -ABRT <pid>
不要使用kill -SEGV,因为这通常会调用信号处理程序,这使得诊断阻塞进程更加困难
-ABRT
与相比-SEGV
,调用信号处理程序的可能性更大,因为中止比段故障更有可能恢复。(如果您处理段错误,通常它会在处理程序退出后立即再次触发。)生成核心转储的更好信号选择是-QUIT
。
要检查在哪里生成核心转储,请运行:
sysctl kernel.core_pattern
要么:
cat /proc/sys/kernel/core_pattern
%e
进程名称和%t
系统时间在哪里。您可以更改它/etc/sysctl.conf
并通过重新加载sysctl -p
。
如果未生成核心文件(通过sleep 10 &
和进行测试killall -SIGSEGV sleep
),则通过以下方式检查限制ulimit -a
。
如果您的核心文件大小有限,请运行:
ulimit -c unlimited
使它不受限制。
然后再次测试,如果核心转储成功,则在分段错误指示之后您将看到“(核心转储)”,如下所示:
分段错误:11(核心已转储)
另请参阅:核心转储-但核心文件不在当前目录中?
在Ubuntu中,核心转储由Apport处理,可以位于中/var/crash/
。但是,默认情况下在稳定版本中禁用该功能。
有关更多详细信息,请检查:在Ubuntu哪里可以找到核心转储?。
对于macOS,请参阅:如何在Mac OS X中生成核心转储?
最后,我所做的就是在崩溃之前将gdb附加到该进程,然后在出现段错误时执行了generate-core-file
命令。强制生成核心转储。
ge
)
ulimit -c
为unlimited
,但是仍然没有创建generate-core-file
核心文件,gdb会话中的文件确实创建了核心文件,谢谢。
也许您可以用这种方式做到这一点,该程序演示了如何捕获分段错误并炮轰到调试器(这是底下使用的原始代码AIX
),并打印堆栈跟踪直至分段错误。您将需要更改sprintf
用于gdb
Linux 的变量。
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
static void signal_handler(int);
static void dumpstack(void);
static void cleanup(void);
void init_signals(void);
void panic(const char *, ...);
struct sigaction sigact;
char *progname;
int main(int argc, char **argv) {
char *s;
progname = *(argv);
atexit(cleanup);
init_signals();
printf("About to seg fault by assigning zero to *s\n");
*s = 0;
sigemptyset(&sigact.sa_mask);
return 0;
}
void init_signals(void) {
sigact.sa_handler = signal_handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGSEGV);
sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGBUS);
sigaction(SIGBUS, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGQUIT);
sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGHUP);
sigaction(SIGHUP, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGKILL);
sigaction(SIGKILL, &sigact, (struct sigaction *)NULL);
}
static void signal_handler(int sig) {
if (sig == SIGHUP) panic("FATAL: Program hanged up\n");
if (sig == SIGSEGV || sig == SIGBUS){
dumpstack();
panic("FATAL: %s Fault. Logged StackTrace\n", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
}
if (sig == SIGQUIT) panic("QUIT signal ended program\n");
if (sig == SIGKILL) panic("KILL signal ended program\n");
if (sig == SIGINT) ;
}
void panic(const char *fmt, ...) {
char buf[50];
va_list argptr;
va_start(argptr, fmt);
vsprintf(buf, fmt, argptr);
va_end(argptr);
fprintf(stderr, buf);
exit(-1);
}
static void dumpstack(void) {
/* Got this routine from http://www.whitefang.com/unix/faq_toc.html
** Section 6.5. Modified to redirect to file to prevent clutter
*/
/* This needs to be changed... */
char dbx[160];
sprintf(dbx, "echo 'where\ndetach' | dbx -a %d > %s.dump", getpid(), progname);
/* Change the dbx to gdb */
system(dbx);
return;
}
void cleanup(void) {
sigemptyset(&sigact.sa_mask);
/* Do any cleaning up chores here */
}
您可能还需要添加一个参数来获取gdb来转储核心,如本博客此处所示。
为了激活核心转储,请执行以下操作:
在 /etc/profile
注释行中:
# ulimit -S -c 0 > /dev/null 2>&1
在/etc/security/limits.conf
注释行中:
* soft core 0
执行cmd limit coredumpsize unlimited
并使用cmd进行检查limit
:
# limit coredumpsize unlimited
# limit
cputime unlimited
filesize unlimited
datasize unlimited
stacksize 10240 kbytes
coredumpsize unlimited
memoryuse unlimited
vmemoryuse unlimited
descriptors 1024
memorylocked 32 kbytes
maxproc 528383
#
要检查是否写入了核心文件,您可以使用cmd终止相关进程kill -s SEGV <PID>
(不需要,如果没有写入核心文件,可以将其用作检查):
# kill -s SEGV <PID>
一旦写入了核心文件,请确保在相关文件(1./2./3。)中再次停用coredump设置!
对于Ubuntu 14.04
检查核心转储是否启用:
ulimit -a
其中一行应为:
core file size (blocks, -c) unlimited
如果不 :
gedit ~/.bashrc
并添加ulimit -c unlimited
到文件末尾并保存,然后重新运行终端。
使用调试信息构建应用程序:
在Makefile中 -O0 -g
运行创建核心转储的应用程序(应在application_name文件附近创建名称为“ core”的核心转储文件):
./application_name
在gdb下运行:
gdb application_name core
ulimit -c unlimited
终端放在临时解决方案中,因为只有编辑~/.bashrc
需要终端restrart才能生效。
默认情况下,您将获得一个核心文件。检查进程的当前目录是否可写,否则将不创建任何核心文件。
最好使用系统调用以编程方式打开核心转储setrlimit
。
例:
#include <sys/resource.h>
bool enable_core_dump(){
struct rlimit corelim;
corelim.rlim_cur = RLIM_INFINITY;
corelim.rlim_max = RLIM_INFINITY;
return (0 == setrlimit(RLIMIT_CORE, &corelim));
}
ulimit -c unlimited
在命令行环境中运行,然后重新运行应用程序。
ulimit -c unlimited
。您也可以使用marco定义进行编译,enable_core_dump
如果发布时未定义该宏,则应用程序将不包含符号,并且您将获得核心转储替换为调试版本。
值得一提的是,如果您设置了systemd,则情况会有所不同。该设置通常将通过core_pattern
sysctl值通过管道传输核心文件systemd-coredump(8)
。核心文件大小rlimit通常已经配置为“无限制”。
然后可以使用检索核心转储coredumpctl(1)
。
核心转储的存储等由配置coredump.conf(5)
。在coredumpctl手册页中有一些如何获取核心文件的示例,但总之,它看起来像这样:
查找核心文件:
[vps@phoenix]~$ coredumpctl list test_me | tail -1
Sun 2019-01-20 11:17:33 CET 16163 1224 1224 11 present /home/vps/test_me
获取核心文件:
[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163
Ubuntu 19.04
所有其他答案本身并没有帮助我。但是以下总结完成了工作
创建~/.config/apport/settings
具有以下内容:
[main]
unpackaged=true
(这告诉apport还为自定义应用编写核心转储)
检查:ulimit -c
。如果输出0,请使用
ulimit -c unlimited
以防万一重启apport:
sudo systemctl restart apport
现在已将崩溃文件写入/var/crash/
。但是您不能将它们与gdb一起使用。要将它们与gdb一起使用,请使用
apport-unpack <location_of_report> <target_directory>
更多信息:
core_pattern
。请注意,重新启动时,该文件可能会被apport服务覆盖。ulimit -c
在尝试其他网络答案时,该值可能会自动更改。在设置核心转储创建过程中,请确保定期检查它。参考文献: