gdb 코어 디버깅



1. 머리말 :
일부 프로그램은 컴파일이 가능하지만 런타임시 세그먼트 오류 (세그먼트 오류)가 나타납니다. 이는 일반적으로 포인터 오류로 인해 발생합니다.
그러나 파일-> 라인을 표시하는 컴파일 오류와는 다르지만 정보가 없습니다. , 이는 우리의 어려운 디버깅합니다.

2. GDB :
. 한 가지 방법은 단계적으로 찾기 위해 GDB 단계를 사용하는 것입니다
이 짧은 코드에서 가능하다,하지만 당신은 하나 개의 코드 만수 라인에 의해 단계의 하나가, 당신이 생각 이제부터 프로그래머라는 이름을 싫어하고 그를 디버거라고 부른다 ..
우리는 더 나은 방법, 즉 코어 파일이있다.

3. ulimit :
시스템이 신호 중단으로 인해 오류를 일으키도록하려면 코어 파일이 생성 될 때 셸에서 다음을 설정해야합니다.
# 코어 크기를 무제한으로 설정
ulimit -c 무제한 #
파일 크기를 무제한으로 설정
ulimit unlimited

루트 권한이 필요하며 ubuntu에서 인터럽트를 다시 열 때마다 다시 입력해야합니다. 위의 첫 번째 명령으로 코어 크기를 무제한으로 설정

4. gdb를 사용하여 코어 파일보기 :
다음은 런타임 신호로 인한 오류 발생시 코어 덤프가 발생할 수 있습니다. 코어 덤프가 발생한 후
gdb를 사용하여 core 파일 .gdb
[exec file] [core file] 파일 에서 코어 덤프를 유발 한 행을 찾으려면
다음과 같이합니다.
gdb ./test test.core
gdb를 입력 한 후 bt 명령을 사용하여 역 추적을보고 프로그램이 실행중인 위치를 확인하고 코어 덤프 파일-> 줄을 찾습니다.

5. gdb를 사용하여 실시간으로 프로세스의 충돌 정보를 관찰합니다 .
프로세스를 시작합니다 .
gdb- p PID
c to
run the process to crash
gdb 충돌 정보
bt 가 표시됩니다.

간단히 말해 segfault 는 잘못된 메모리 세그먼트에 액세스하는 것입니다. 일반적으로 권한이 없거나 해당 물리적 ​​메모리가 전혀 없습니다. 특히 0 주소에 액세스하는 것이

일반적 입니다. 일반적으로 세그먼트 오류는 액세스 된 메모리가 시스템에서이 프로그램에 부여한 메모리 공간을 초과 함을 의미합니다. 일반적으로이 값은 48 비트 레지스터 인 32 비트 인 gdtr에 의해 저장됩니다. 마지막 13 비트는 gdt에 해당하는 첨자를 저장합니다. 마지막 3 비트에는 프로그램이 메모리에 있는지 여부와 CPU에있는 프로그램의 실행 수준이 포함됩니다. 가리키는 것은 64 비트를 단위로하는 테이블이며, 프로그램은이 테이블에 저장됩니다. 실행중인 코드 세그먼트와 데이터 세그먼트의 시작 주소, 해당 세그먼트 제한 및 페이지 스와핑, 프로그램 실행 수준 및 메모리 단위 등 프로그램에 범위를 벗어난 액세스 권한이 있으면 CPU가 해당 예외 보호를 생성하므로 세분화 오류가 나타납니다.

다음과 같은 프로그래밍 방식은 기본적으로 포인터를 잘못 사용하여 발생하는 세분화 오류가 발생하기 쉽습니다.

1) 시스템 데이터 영역에 대한 액세스, 특히
가장 일반적인 데이터를 쓰기위한 시스템 메모리 주소의 보호는 주소 0에 대한 포인터를 제공하는 것입니다.
2) 메모리 경계 (배열 경계, 불일치 변수 유형 등)에 대한 액세스 메모리 영역이

솔루션에 속하지 않습니다.

C / C ++로 프로그램을 작성할 때 대부분의 메모리 관리 작업을 수행해야합니다. 사실, 메모리 관리는 비교적 지루한 작업입니다. 아무리 똑똑하고 경험이 있더라도 필연적으로 여기에서 작은 실수를 할 수 있으며 이러한 실수는 일반적으로 매우 간단하고 제거하기 쉽습니다. 그러나 수동 "디버그"는 비효율적이고 성가신 경우가 많습니다.이 기사에서는 메모리 액세스 범위를 벗어난 오류 인 "세그먼트 오류"에서 이러한 "세그먼트 오류"문을 빠르게 찾는 방법에 대해 설명합니다.
다음은 segfault가있는 다음 프로그램 중 하나에 대한 몇 가지 디버깅 방법을 소개합니다.

코드 복사

dummy_function (무효)
{
부호없는 문자 * ptr = 0x00;
* ptr = 0x00;
}
int main (무효)
{
dummy_function ();
반환 0;
}

코드 복사

 


숙련 된 C / C ++ 프로그래머로서 위 코드의 버그는 매우 명확해야합니다. 주소 0으로 메모리 영역을 조작하려고 시도하기 때문이며이 메모리 영역은 일반적으로 액세스 할 수없는 금지 영역입니다. 물론 잘못 될 것입니다. 우리는 그것을 컴파일하고 실행하려고했습니다 :
xiaosuo @ gentux test $ ./a.out
Segmentation error
예상대로 잘못되어 종료되었습니다.
1. gdb를 사용하여 단계별로 segfaults 찾기 :
이 방법은 또한 널리 알려져 있고 대중에게 널리 사용됩니다. 첫째, 디버깅 정보가있는 실행 프로그램이 필요하므로 컴파일에 "-g -rdynamic"매개 변수를 추가합니다. 그런 다음 gdb를 사용하여 새로 컴파일 된 프로그램을 디버깅하고 실행합니다. 특정 단계는 다음과 같습니다.
xiaosuo @ gentux test $ gcc -g -rdynamic dc
xiaosuo @ gentux test $ gdb ./a.out
GNU gdb 6.5
Copyright (C) 2006 자유 소프트웨어 재단, 주식
GDB는 GNU 일반 공중 사용 허가서에 의해 덮여 무료 소프트웨어입니다, 당신은하는
변경 및 / 또는 특정 조건 하에서 그것의 복사본을 배포 오신 것을 환영합니다.
입력 조건을보고 "복사 보여".
절대적으로있다 GDB에 대한 보증이 없습니다. 자세한 내용을 보려면 "show Warranty"를 입력하십시오.
이 GDB는 "i686-pc-linux-gnu"로 구성되었습니다 ... 호스트 libthread_db 라이브러리 "/lib/libthread_db.so.1"사용.

(gdb) r
시작 프로그램 : /home/xiaosuo/test/a.out

프로그램 수신 신호 SIGSEGV, 분할 오류
.dummy_function의 0x08048524 () at dc : 44
* ptr = 0x00;
(gdb)
오? ! 단계별 디버깅없이 오류가 발생한 dc 파일의 네 번째 줄을 찾은 것 같습니다. 사실 매우 간단합니다.
여기에서 SIGSEGV 신호 수신으로 인해 프로세스가 종료되었음을 알 수 있습니다. 문서 (man 7 신호)를 자세히 살펴보면 SIGSEGV의 기본 처리기 동작이 "세그먼트 오류"오류 메시지를 인쇄하고 Core 파일을 생성하는 것임을 알고 있으며 이로부터 방법 2를 생성했습니다.
2. Core 파일 분석 : Core 파일
이란 무엇입니까?
특정 신호의 기본 동작은 프로세스를 종료하고 코어 덤프 파일을 생성하는 것입니다. 프로세스가 종료 될 때 프로세스의 메모리 이미지가 포함 된 디스크 파일입니다. 프로세스가 코어를 덤프하도록하는 신호 목록은 다음과 같습니다. signal (7)에서 찾을 수 있습니다.
위의 정보는 man 페이지 (man 5 core)에서 발췌 한 것입니다. 하지만 이상하게도 내 시스템에서 코어 파일을 찾을 수 없습니다. 나중에 시스템에서 정크 파일의 수를 줄이기 위해 (저는 Gentoo를 좋아하는 이유 중 하나 인 청결 함이 있습니다) 코어 파일 생성이 금지되었고 다음 사항이 있는지 확인했습니다. 시스템의 코어 파일을 변경하십시오. 크기가 512K로 제한되어 있습니다. 다시 시도하십시오.
xiaosuo @ gentux test $ ulimit -c
0
xiaosuo @ gentux test $ ulimit -c 1000
xiaosuo @ gentux test $ ulimit -c
1000
xiaosuo @ gentux test $ ./a.out
세그먼트 오류 (코어 덤프 됨)
xiaosuo @ gentux test $ ls
a.out core dc fc gc pango.c test_iconv.c test_regex.c
코어 파일이 마침내 생성되었습니다. gdb를 사용하여 디버그합니다.
xiaosuo @ gentux test $ gdb ./a.out core
GNU gdb 6.5
Copyright (C) 2006 Free Software Foundation, Inc.
GDB는 GNU General Public License가 적용되는 무료 소프트웨어이며
변경 및 / 또는 배포 할 수 있습니다. 특정 조건에서 사본.
조건을 보려면 "show copying"을 입력하십시오.
GDB에 대한 보증은 전혀 없습니다. 자세한 내용을 보려면 "보증 표시"를 입력하십시오.
이 GDB는 "i686-pc-linux-gnu"로 구성되었습니다 ... 호스트 libthread_db 라이브러리 "/lib/libthread_db.so.1"사용.


경고 :로드 맵에 대한 경로 이름을 읽을 수 없습니다 : 输入 / 输出 错误.
/lib/libc.so.6에서 기호 읽기 ... 완료.
/lib/libc.so.6에 대한 기호로드 됨
/lib/ld-linux.so.2에서 기호 읽기 ... 완료.
/lib/ld-linux.so.2
Core에 대한로드 된 기호 가`./a.out '에 의해 생성되었습니다.
프로그램이 신호 11로 종료 됨, 세그멘테이션 오류.
# 0 0x08048524 in dummy_function () at dc : 4
4 * ptr = 0x00 ;
와우, 좋은 경험이긴하지만 한 번에 잘못된 위치를 찾았습니다. 이런 종류의 Linux / Unix 시스템 디자인에 감탄합니다.
그렇다면 생각해보십시오. Windows 시스템에서 IE를 사용할 때 특정 웹 페이지를 열 때 때때로 "런타임 오류"가 발생했습니다. 이때 컴퓨터에 Windows 컴파일러가 설치되어 있으면 팝업이 나타납니다. 대화 상자가 나오면 디버그 할 것인지 묻고, 예를 선택하면 컴파일러가 열리고 디버깅 상태로 들어가 디버깅을 시작합니다.
Linux에서 어떻게해야합니까? 내 두뇌는 매우 빠르게 회전하고 있으므로 SIGSEGV 처리기에서 gdb를 호출하도록하겠습니다. 세 번째 방법이 탄생했습니다.
3. 세분화 오류가 발생하면 디버깅을 시작합니다.
#include <stdio.h>
#include <stdlib. h>
#include <signal.h>
#include <string.h>

void dump (int signo)
{ char buf [1024]; char cmd [1024]; FILE * fh;




snprintf (buf, sizeof (buf), "/ proc / % d / cmdline", getpid ());
if (! (fh = fopen (buf, "r")))
exit (0);
if (! fgets (buf, sizeof (buf), fh))
exit (0);
fclose (fh);
if (buf [strlen (buf)-1] == '\ n')
buf [strlen (buf)-1] = '\ 0';
snprintf (cmd, sizeof (cmd), "gdb % s % d", buf, getpid ());
시스템 (cmd);

exit (0);
}

void
dummy_function (void)
{ unsigned char * ptr = 0x00; * ptr = 0x00; } int main (void) { signal (SIGSEGV, & dump); dummy_function (); 반환 0; }编译 运行 效果 如下 : xiaosuo @ gentux test $ gcc -g -rdynamic fc














xiaosuo @ gentux test $ ./a.out
GNU gdb 6.5
Copyright (C) 2006 Free Software Foundation, Inc.
GDB는 GNU General Public License가 적용되는 무료 소프트웨어이며
변경 및 / 또는 배포 할 수 있습니다. 특정 조건에서.
조건을 보려면 "show copying"을 입력하십시오.
GDB에 대한 보증은 전혀 없습니다. 자세한 내용을 보려면 "보증 표시"를 입력하십시오.
이 GDB는 "i686-pc-linux-gnu"로 구성되었습니다 ... 호스트 libthread_db 라이브러리 "/lib/libthread_db.so.1"사용.

프로그램에 연결 : /home/xiaosuo/test/a.out, process 9563
/lib/libc.so.6에서 기호 읽기 ... 완료.
/lib/libc.so.6에 대한 기호로드 됨
/lib/ld-linux.so.2에서 기호 읽기 ... 완료.
/lib/ld-linux.so.2
0xffffe410 in __kernel_vsyscall ()
(gdb) bt
# 0 0xffffe410 in __kernel_vsyscall ()
# 1 0xb7ee4b53 in waitpid () from /lib/libc.so.6
# 2 0xb7e925c9 in strtold_l () from /lib/libc.so.6
# 3 0x08048830 in dump (signo = 11) at fc : 22
# 4 <signal handler called>
# 5 0x0804884c in dummy_function () at fc : 31
# 6 0x08048886 in main () fc : 38에서는
어떻습니까? 아직도 멋지 니?
위의 방법은 모두 시스템에 gdb가 있다는 전제하에 수행됩니다. 사실, glibc는 스택의 내용을 덤프 할 수있는 이런 종류의 함수 클러스터를 제공합니다. 자세한 내용은 /usr/include/execinfo.h를 참조하십시오 (이 함수는 man 페이지에 제공되지 않습니다. it), gnu 매뉴얼을 통해 배울 수도 있습니다.
4. 역 추적 및 objdump를 사용한 분석 :
재 작성된 코드는 다음과 같습니다.
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

/ * 역 추적을 더 흥미롭게 만드는 더미 함수. * /
void
dummy_function (void)
{ unsigned char * ptr = 0x00; * ptr = 0x00; } void dump (int signo) { void * array [10]; size_t 크기; char ** 문자열; size_t i; 크기 = 역 추적 (배열, 10); strings = backtrace_symbols (배열, 크기); printf ( "% zd 개의 스택 프레임을 얻었습니다. \ n", 크기); for (i = 0; i <size; i ++) printf ( "% s \ n", 문자열 [i]); 무료 (문자열); exit (0); } int main (void) { signal (SIGSEGV, & dump); dummy_function ();






























return 0;
}
컴파일 및 실행 결과는 다음과 같습니다.
xiaosuo @ gentux test $ gcc -g -rdynamic gc
xiaosuo @ gentux test $
./a.out 5 개의 스택 프레임을
얻었습니다 . ./a.out(dump+0x19) [ 0x80486c2]
[0xffffe420]
./a.out(main+0x35) [0x804876f]
/lib/libc.so.6(__libc_start_main+0xe6) [0xb7e02866]
./a.out [0x8048601]
이번에는 약간 실망하실 수 있습니다 , 오류를 표시 할 충분한 정보를 제공하지 못한 것 같습니다. 걱정하지 마세요. 먼저 분석 할 수있는 항목을 살펴 보겠습니다. objdump 디스어셈블러를 사용하여 주소 0x804876f에 해당하는 코드 위치를 찾습니다.
xiaosuo @ gentux test $ objdump -d a.out

8048765 : e8 02 fe ff ff call 804856c <signal @ plt>
804876a : e8 25 ff ff ff call 8048694 <dummy_function>
804876f : b8 00 00 00 00 mov $ 0x0, % eax
8048774 : c9 leave
우리는 여전히 function (dummy_function) 오류가 발생한 곳, 정보가 완전하지는 않지만 아무것도없는 것보다 낫습니다!  

추천

출처blog.csdn.net/daocaokafei/article/details/114968316