Linux日志重定向和调用堆栈信息或核心转储

huangapple go评论82阅读模式
英文:

Linux log redirect and call stack info or core dump

问题

有一些问题我需要你的帮助,请让我先描述一下。

  1. 程序(test)源代码:
#include <stddef.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    char * a = NULL;
    printf("print a:\n");
    printf("%c\n", *a);
}
  1. 在bash中执行:
[root@localhost test]# ./test
print a:
Segmentation fault (core dumped)
  1. 重定向到test.log
[root@localhost test]# ./test > test.log 2>&1
Segmentation fault (core dumped)
[root@localhost test]# cat test.log
[root@localhost test]# 
  1. 使用stdbuf
[root@localhost test]# stdbuf -o0 ./test > test.log 2>&1
Segmentation fault (core dumped)
[root@localhost test]# cat test.log
print a:
[root@localhost test]# 
  1. 使用shell脚本test.sh
[root@localhost test]# cat test.sh 
./test
[root@localhost test]# ./test.sh > test.log 2>&1
[root@localhost test]# cat test.log 
./test.sh: line 1: 63426 Segmentation fault (core dumped) ./test
[root@localhost test]#
  1. test.sh中使用stdbuf
[root@localhost test]# cat test.sh
stdbuf -o0 ./test
[root@localhost test]# ./test.sh > test.log 2>&1
[root@localhost test]# more test.log 
print a:
./test.sh: line 1: 16761 Segmentation fault (core dumped) stdbuf -o0 ./test
[root@localhost test]# 
  1. 我的环境:
[root@localhost test]# cat /etc/redhat-release 
CentOS Linux release 7.3.1611 (Core)
[root@localhost test]# uname -a
Linux localhost.localdomain 3.10.0-1127.19.1.el7.x86_64 #1 SMP Tue Aug 25 17:23:54 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

现在我希望test.log的内容是:

print a:
Segmentation fault (core dumped)

并且不使用stdbuf(我认为它可能会影响性能)。

另外,我希望在遇到段错误和其他类似错误时,能够通过程序生成核心文件或调用堆栈,而不是使用"ulimit -c unlimited"命令。我知道可以通过捕获信号来解决这个问题,但我不知道哪些信号表示错误和退出。非常感谢。

英文:

There are some problems I need your help with. Please let me describe it first.

  1. program(test) source:
#include &lt;stddef.h&gt;
#include &lt;stdio.h&gt;

int main(int argc, char *argv[])
{
    char * a = NULL;
    printf(&quot;print a:\n&quot;);
    printf(&quot;%c\n&quot;, *a);
}

2.excute it in bash

[root@localhost test]# ./test
print a:
Segmentation fault (core dumped)

3.direct to test.log

[root@localhost test]# ./test &gt; test.log 2&gt;&amp;1
Segmentation fault (core dumped)
[root@localhost test]# cat test.log
[root@localhost test]# 

4.use stdbuf

[root@localhost test]# stdbuf -o0 ./test &gt; test.log 2&gt;&amp;1
Segmentation fault (core dumped)
[root@localhost test]# cat test.log
print a:
[root@localhost test]# 

5.use shell script test.sh

[root@localhost test]# cat test.sh 
./test
[root@localhost test]# ./test.sh &gt; test.log 2&gt;&amp;1
[root@localhost test]# cat test.log 
./test.sh: line 1: 63426 Segmentation fault      (core dumped) ./test
[root@localhost test]#

6.use stdbuf in test.sh

[root@localhost test]# cat test.sh
stdbuf -o0 ./test
[root@localhost test]# ./test.sh &gt; test.log 2&gt;&amp;1
[root@localhost test]# more test.log 
print a:
./test.sh: line 1: 16761 Segmentation fault      (core dumped) stdbuf -o0 ./test
[root@localhost test]# 
  1. my env
[root@localhost test]# cat /etc/redhat-release 
CentOS Linux release 7.3.1611 (Core)
[root@localhost test]# uname -a
Linux localhost.localdomain 3.10.0-1127.19.1.el7.x86_64 #1 SMP Tue Aug 25 17:23:54 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

Now I want test.log content is :

print a:
Segmentation fault (core dumped)

and don't use stdbuf(I think it maybe affect performance).

On the other hand, I expect that when encountering segfaults and other similar errors, I can use programmatically generate core or call stack instead of using "ulimit -c unlimited". I understand that it can be solved by catching signals, but I don't know which signals represent errors and exits. thank you all.

答案1

得分: 1

"Segmentation fault (core dumped)"消息是由shell生成的,而不是您运行的程序。

要获得您想要的结果,您需要在子shell中运行程序,并将子shell的输出重定向到日志文件中。然而,有时候当作为子shell运行时,shell会保持安静(不生成错误消息)。通过对Bash的实验可以发现,除非您付出很大的努力,否则它不会保持安静。

在Korn Shell中,您可以使用以下命令来获得所需的结果(在RHEL 7.4上测试通过):

(./test) > test.log 2>&1

请注意,将输出重定向到文件(或管道)可能意味着标准输出不再是行缓冲的,而是完全缓冲的。而且在核心转储时,您可能无法在程序终止之前刷新标准输出,因此待处理的I/O可能会被缓冲而不会发送到日志文件中。

通过对Bash的实验可以发现,上述命令不起作用,也就是说,shell的错误消息仍然会出现在终端上,而不是日志文件中。

创建一个类似于以下脚本(我将其称为ex-crash.sh,用于执行crash):

(./crash) > log 2>&1

它可以以多种方式运行:

$ bash ex-crash.sh
ex-crash.sh: line 1:  2646 Segmentation fault      (core dumped) ( ./crash ) > log 2>&1
$ (bash ex-crash.sh >log2 2>&1)
$ cat log2
ex-crash.sh: line 1:  2675 Segmentation fault      (core dumped) ( ./crash ) > log 2>&1
$ (bash ex-crash.sh) >log2 2>&1
$ cat log2
ex-crash.sh: line 1:  2946 Segmentation fault      (core dumped) ( ./crash ) > log 2>&1
$ bash ex-crash.sh >log2 2>&1
$ cat log2
ex-crash.sh: line 1:  3310 Segmentation fault      (core dumped) ( ./crash ) > log 2>&1
$

这表明脚本的错误输出可以重定向到文件中,命令行中的子shell并不是必要的。您还可以尝试不包含子shell的ex-crash.sh版本。在尝试更简单的版本之前,我被引导到了更复杂的调用方式。(PID号的大跳变是因为其他人在机器上编译一个大项目。)

生成堆栈跟踪将由程序完成。它将捕获信号并调用堆栈跟踪代码,然后退出,可能通过调用abort()来实现。这可能不是100%安全的——堆栈可能已被破坏。您需要决定要捕获哪些信号。当然,您将使用sigaction()。您需要考虑如何处理SIGABRT、SIGQUIT、SIGFPE、SIGILL、SIGIOT、SIGBUS和SIGSEGV(以及可能的SIGSYS、SIGTRAP、SIGXCPU和SIGXFSZ)信号。您的代码将需要检查它们在您的系统上是否定义。您应该熟悉POSIX Signal Concepts以及<signal.h>中的规范。头文件规范中的表格指定了哪些信号会导致进程的“异常终止”并带有“附加操作”(即核心转储部分)。

您需要调查可用的堆栈跟踪库。GNU C库提供了一组backtrace函数。可能还有其他库。您不会想自己编写堆栈跟踪代码。

英文:

The "Segmentation fault (core dumped)" message is generated by the shell, not the program you run.

To get your desired result, you have to run the program in a sub-shell and redirect the output of the sub-shell to the log file. However, sometimes the shell shuts up (doesn't generate the error message) when run as a sub-shell. And experimentation with Bash shows that it doesn't shut up unless you work really hard.

With Korn Shell, you can use this to get the desired result (it worked on RHEL 7.4):

(./test) &gt;test.log 2&gt;&amp;1

Note that redirecting the output to a file (or a pipe) probably means that standard output ceases to be line buffered and becomes fully buffered. And with a core dump, you probably won't get the standard output flushed before the program terminates — so pending I/O may be buffered and not sent to the log file.

Experimenting with Bash shows that the command shown above does not work, in the sense that the shell's error message still appears on the terminal, not in the log file.

Create a script similar to this (I called it ex-crash.sh, for executing crash):

(./crash) &gt;log 2&gt;&amp;1

It can be run in a variety of ways:

$ bash ex-crash.sh
ex-crash.sh: line 1:  2646 Segmentation fault      (core dumped) ( ./crash ) &gt; log 2&gt;&amp;1
$ (bash ex-crash.sh &gt;log2 2&gt;&amp;1)
$ cat log2
ex-crash.sh: line 1:  2675 Segmentation fault      (core dumped) ( ./crash ) &gt; log 2&gt;&amp;1
$ (bash ex-crash.sh) &gt;log2 2&gt;&amp;1
$ cat log2
ex-crash.sh: line 1:  2946 Segmentation fault      (core dumped) ( ./crash ) &gt; log 2&gt;&amp;1
$ bash ex-crash.sh &gt;log2 2&gt;&amp;1
$ cat log2
ex-crash.sh: line 1:  3310 Segmentation fault      (core dumped) ( ./crash ) &gt; log 2&gt;&amp;1
$

This shows that the error output from the script can be redirected to a file — the sub-shells on the command line are not necessary to do that. You could experiment with versions of ex-crash.sh that don't include the sub-shell, too. I got side-tracked into more complex invocations before trying the simpler ones. (The large jumps in the PID numbers occur because someone else is compiling a big project on the machine.)

Generating a stack trace will have to be done by the program. It will have to catch the signal and invoke the stack trace code and exit, possibly by calling abort(). That may not be 100% safe — the stack may be corrupted. You'll need to decide which signals you want to catch. You'l be using sigaction(), of course. You'll need to think about dealing with the SIGABRT, SIGQUIT, SIGFPE, SIGILL, SIGIOT, SIGBUS and SIGSEGV (and maybe SIGSYS, SIGTRAP, SIGXCPU and SIGXFSZ) signals. Your code will need to check if they are defined on your system. You should become familiar with POSIX Signal Concepts and the specification in &lt;signal.h&gt;. The table in the header specification specifies which signals give "abnormal termination" of the process "with additional actions" (which is the core dump part).

You'll need to investigate which stack trace libraries are available for you. The GNU C Library provides a set of backtrace functions. There are probably other libraries too. You won't want to write your own.

答案2

得分: 0

现在我想要测试.log文件的内容是:

通过捕获信号,但我不知道哪些信号代表错误

SIGSEGV信号代表分段错误。如果你希望程序打印一些内容,请处理SIGSEGV信号。

英文:

> Now I want test.log content is :

> by catching signals, but I don't know which signals represent errors

SIGSEGV signal represents segmentation fault. If you want your program to print something, handle SIGSEGV.

huangapple
  • 本文由 发表于 2023年8月9日 11:31:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76864389.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定