In the previous blog, we introduced some commonly used commands and positioning methods when gdb debugs coredump through 3 examples. In this content, we will try to explore the principles of gdb debugging coredump and some of the things behind them.
Coredump principle
1. Introduction to coredump
In the previous blog, we also mentioned that coredump is called core dump, which is actually a memory snapshot during the process of running. When a process crashes, after the operating system receives an abnormal instruction, it will do the process before the process crashes. A memory snapshot saves this information in a file, which is a coredump file.
This file contains address information, register information, stack call information, etc. in the memory of the process.
The signals that can cause process coredump are:
first name |
Description |
ANSI C POSIX.1 |
SVR4 4.3 + BSD |
Default action |
SIGABRT |
Abort (abort) |
. . |
. . |
Terminate w/core |
SIGBUS |
hardware malfunction |
. |
. . |
Terminate w/core |
SIGEMT |
hardware malfunction |
|
. . |
Terminate w/core |
SIGFPE |
Arithmetic exception |
. . |
. . |
Terminate w/core |
SEAL |
Illegal hardware instruction |
. . |
. . |
Terminate w/core |
SIGIOT |
hardware malfunction |
|
. . |
Terminate w/core |
SIGQUIT |
Terminal exit |
. |
. . |
Terminate w/core |
SIGSEGV |
Invalid storage access |
. . |
. . |
Terminate w/core |
SIGSYS |
Invalid system call |
|
. . |
Terminate w/core |
SIGTRAP |
hardware malfunction |
|
. . |
Terminate w/core |
SIGXCPU |
CPU limit exceeded (setrlimit) |
|
. . |
Terminate w/core |
SIGXFSZ |
Exceed the file length limit (setrlimit) |
|
. . |
Terminate w/core |
For example, our most common segmentfault corresponds to the above SIGSEGV, which is the signal corresponding to the kill command 11.
All the above signals correspond to the kill command.
2. Coredump file format
1) Use the file command to view
root@ubuntu:/var/core_log# file core_DumpNewTest_1483768078_6527
core_DumpNewTest_1483768078_6527: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from './DumpNewTest'
As above, through the file command, you can see that this file is a core file and which process is generated at the same time
2) Try readelf to view
Readelf -h core* You can see that the type of core file is marked as
The following is the definition of the ELF.h header file
As shown in the figure, there is a byte that identifies the ELF file type.
As above, there are mainly 4 types of files in the ELF format. The value of e_type corresponding to the Core file is 4.
3) View the content of the core file
readelf -a core*
Use objdump -t to view,
objdump -t core*
As above, through readelf and objdump, we can see that compared with other ELF format files, the core file has a lot less head node information, and there is no symbol table information and debugging information.
But it records the loading address and address offset before the program, as well as information such as stack and register.
The principle of gdb
GDB consists of three parts:
(1) User interface, in addition to the traditional CLI interface, it also supports the mi interface (used by tools such as ddd)
(2) Symbol handling at the symbol handling layer, when gdb ./debugme, GDB will read The symbol information of the file, the following original code, the display of variables/functions/types are all performed by this part (everything you can do without live process).
(3) Target system handling. Operations including execution control, breakpoint setting, single-step execution, stack analysis, etc. are all performed in this part.
BFD provides support for gdb in several ways:
identifying executable and core files
BFD will identify a variety of file types, including a.out, coff, and several variants
thereof, as well as several kinds of core files.
access to sections of files
BFD parses the file headers to determine the names, virtual addresses, sizes,
and file locations of all the various named sections in files (such as the text
section or the data section). gdb simply calls BFD to read or write section x
at byte offset y for length z.
specialized core file support
BFD provides routines to determine the failing command name stored in a core
file, the signal with which the program failed, and whether a core file matches
(i.e. could be a core dump of) a particular executable file.
locating the symbol information
gdb uses an internal interface of BFD to determine where to find the symbol
information in an executable file or symbol-file. gdb itself handles the reading of symbols, since BFD does not “understand” debug symbols, but gdb uses
BFD’s cached information to find the symbols, string table, etc.
As above, in the official user manual of gdb, it is stated that gdb recognizes the core file through BFD, and at the same time determines the program crash command in the core file and the signal related to the crash through a set of existing mechanisms provided by BFD, and can determine Whether a core file matches an executable program. BFD also provides a set of interfaces for gdb to read symbol information in executable files.
As shown in the screenshot above, the regset_from_core_section interface provides the ability to read and parse the correct register information.
As above, gdb uses BFD and encapsulates and implements some interfaces by itself, which can identify and read core file information in combination with the executable file, and read the call stack, crash signals and commands from the core file. Register information and other content, and then find the matching symbol information from the executable file, so that when gdb debugs the core file, we can see the symbol corresponding to the address and the address offset instead of the hexadecimal number.
Gdb's dependence on BFD
According to the GDB official user manual above, gdb reads the stack, register and other information of the core file through BFD, so from this point of view, gdb is dependent on bfd.
From the header file:
Judging from the header file reference, gdb refers to the BFD header file. So I think it can be understood that GDB needs to rely on the BFD library.
But through ldd, but no dependencies are seen
As shown in the screenshot above, objudmp depends on bfd, but gdb cannot see the dependency of bfd. What's going on?
At the beginning, I thought it might be that gdb is indirectly dependent on bfd. I checked all the libraries that gdb depends on by ldd, but none of them depend on bfd, and even indirect dependencies should be seen through ldd. This problem has been troubled for a long time. Finally, I took a look at the source directory structure of gdb and found that there is actually BFD in the gdb source code, which means that gdb directly includes bfd.
As shown above, there is a separate BFD directory in the gdb source code, which contains the complete implementation of BFD. Therefore, gdb does not depend on the bfd library in the system, but it directly contains the complete implementation of bfd.
The following figure is the overall structure of gdb: