Share a bug location method that you may not know

Hello everyone, I am Mr. Chowder.

In the development of embedded Linux, using gdb to debug the core file is an effective method for locating program crashes. We also briefly mentioned this method in the previous article: Summary of 3 debugging methods for embedded segment faults!

Some knowledge can be simply understood before it is not used. When you actually use it, learn it in detail. Recently, I used gdb to debug the core file in my actual work. I encountered some problems and summarized them to share with you.

In this article, we will share a few points:

  • What is a core file?

  • How does the foreground process generate a core file?

  • How does the background process generate the core file?

  • How to debug core file?

  • Possible reasons for the limited useful information in the crash stack?

What is a core file?

Under Linux, when a program crashes, it will generally generate a core file in the specified directory. The core file is just a memory image (plus debugging information), which is mainly used for debugging.

How does the foreground process generate a core file?

In practice, our program can run in the foreground or in the background. There are some differences in the methods of generating core files for running programs in the foreground and in the background.

Foreground process: Generally speaking, the programs executed by the user in the shell using ./ are all foreground programs. The foreground program can be controlled by the user and can interact with the user during the running of the program. Its running priority is slightly higher than that of the background program. During the running of the foreground program, the user can use ctrl+c to terminate it.

core file configuration basic commands:

ulimit -c   # 查看core文件是否打开
ulimit -a   # 也可以查看core文件是否打开
ulimit -c 0 # 禁止产生core文件
ulimit -c unlimited  #设置core文件大小为不限制大小
ulimit -c 1024   #限制产生的core文件的大小不能超过1024KB

The dump file directory and naming rules of the core file can be set.

By configuring /proc/sys/kernel/core_uses_pid, you can control whether to add pid as an extension to the file name of the generated core file;

The storage location or file name of the formatted core file can be set by configuring /proc/sys/kernel/core_pattern.

for example:

  • Set whether to add pid as an extension to the file name of the core file

echo "1" > /proc/sys/kernel/core_uses_pid
  • Set the formatted core file save location or file name

echo "/var/core-%e-%p-%t" > /proc/sys/kernel/core_pattern

The meanings of the parameters %e, %p, and %t are as follows:

%p - insert pid into filename 添加pid
%u - insert current uid into filename 添加当前uid
%g - insert current gid into filename 添加当前gid
%s - insert signal that caused the coredump into the filename 添加导致产生core的信号
%t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
%h - insert hostname where the coredump happened into filename 添加主机名
%e - insert coredumping executable name into filename 添加可执行程序名

Let's start the actual operation:

Check whether the core file is open, and set the core file size to unlimited size:

4e26aa1979c003236c45ed0850ca7d9a.png

Set the save location or file name of the formatted core file:

7069c2cd9b5ed11f516e1e194975e2e8.png

Test code:

#include <stdio.h>

int main(int argc, char **argv)
{
    printf("==================segmentation fault test==================\n");

    int *p = NULL;
    *p = 1234;

    return 0;
}

Run the test program to generate the core file:

a69dfc52daece1aabceb82f86019f1a9.png

How does the background process generate the core file?

The way the background program generates the core file is different from that of the foreground program. I only found out about this a few days ago. The program on our device is set to run in the background automatically when it starts up. When the program crashes, no core file is generated. Later, after checking some information, I realized that the way the background program opens the core file is different.

Background process: background process is also called daemon process, which is a special process running in the background of the system. It is independent of the control terminal and periodically executes certain tasks or waits for certain events to be processed. The biggest feature of the background process is that it does not controlled by the terminal. It is generally used as a system service, such as the log management process rsyslogd, database service myspld, etc. Of course, some user programs need to be run in the background, and are generally placed in the /etc/ini.

The ulimit command has a scope of action. Ulimit limits the current shell process and its derived child processes. Therefore, modifying the coresize through ulimit is only for the child processes started under the current shell, and cannot affect the processes started under other shells.

Therefore, after we have configured the parameters for generating core dumps, the core can be generated normally when the process directly executed by the current shell crashes, but the self-starting programs in the background cannot be generated. In practice, embedded applications are generally booted It is self-starting, and the timing of sending crashes is also unpredictable, so this method cannot correctly capture the coredump file.

To generate a core dump file for a background process, the core dump function must be enabled in the process code, such as:

Swipe left and right to view all codes >>>

// 公众号:嵌入式大杂烩
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>

#define SHELL_CMD_CONF_CORE_FILE    "echo /var/core-%e-%p-%t > /proc/sys/kernel/core_pattern"
#define SHELL_CMD_DEL_CORE_FILE     "rm -f /var/core*"

static int enable_core_dump(void)
{
    int ret = -1;
    int resource = RLIMIT_CORE;
    struct rlimit rlim;

    rlim.rlim_cur = 1 ? RLIM_INFINITY : 0;
    rlim.rlim_max = 1 ? RLIM_INFINITY : 0;

    system(SHELL_CMD_DEL_CORE_FILE);

    if (0 != setrlimit(resource, &rlim))
    {
        printf("setrlimit error!\n");
        return -1;
    }
    else
    {
        system(SHELL_CMD_CONF_CORE_FILE);
        printf("SHELL_CMD_CONF_CORE_FILE\n");
        return 0;
    }

    return ret;
}

int main(int argc, char **argv)
{
    enable_core_dump();

    printf("==================segmentation fault test==================\n");

    int *p = NULL;
    *p = 1234;

    return 0;
}

Let the program run in the background at startup:

Create a new file S100Test in the development board /etc/init.d/ directory:

#!/bin/sh
cd /home
./test

To set the program to start automatically, please refer to our previous article: "Analysis of the program to start automatically"

Restart the device, and the core file can be generated when the program crashes:

dbe8f4929d6b49adf3eb30008bba1811.png 780abcb074021f986568d8b955a8a994.png

Debugging core files?

Transfer the core file to the PC, and use arm-linux-gnueabihf-gdb to debug the test program:

arm-linux-gnueabihf-gdb test
core-file core-test-190-119
17568fa7648ebc3ed829ce344c883b12.png 4581a48816913581867ca8d00b6fe1e2.png

Limited crash stack information?

This demo is relatively simple, and the problem can be quickly located. In practice, our program will depend on many dynamic libraries. At this time, we need to set the search path of the library when debugging.

These libraries need to correspond to the libraries on the board, it is best to use the libraries on the board. You can put the library used in the board into a certain path on the PC, for example, put it in the path of /home/LinuxZn/lib.

When we enter gdb, we can enter the following commands to set and view library information:

set solib-search-path /home/LinuxZn/lib
info sharedlibrary
7775dbfd474305b3020af331e712ddd0.png

Sometimes, after loading the library information, I still don't see a meaningful crash stack.

There are two things to confirm:

  • The application did not specify the -g option when compiling, resulting in no debugging information for the executable program.

  • The version of the libc library on the board is inconsistent with the version of the libc library used by the cross compiler.

If not, you can update the libc library used by the cross compiler to the board.

reference:

https://baijiahao.baidu.com/s?id=1661025717994426637&wfr=spider&for=pc
https://blog.csdn.net/lhl_blog/article/details/106542754

The above is the sharing of this time, looking forward to your three in a row!

2e8e23c5c479880163c6cb4b2c61ffc7.jpeg

679745bc2c76713bdecacce0036b4409.jpeg

Guess you like

Origin blog.csdn.net/weiqifa0/article/details/129869869