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

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

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(我认为它可能会影响性能)。

另一方面,我期望在遇到segfaults和其他类似错误时,可以以编程方式生成core文件或调用堆栈,而不是使用"ulimit -c unlimited"。我了解可以通过捕获信号来解决这个问题,但我不知道哪些信号代表错误和退出。谢谢大家。

英文:

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

  1. program(test) source:
#include <stddef.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    char * a = NULL;
    printf("print a:\n");
    printf("%c\n", *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 > test.log 2>&1
Segmentation fault (core dumped)
[root@localhost test]# cat test.log
[root@localhost test]# 

4.use 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]# 

5.use shell script 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]#

6.use stdbuf in test.sh

[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. 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

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-2.html
匿名

发表评论

匿名网友

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

确定