저는 디버깅을 위해 코어 덤프를 사용하고 있습니다. gdb에서는 코어 덤프뿐만 아니라 실행 파일도 제공해야 합니다. 왜 이런거야? 코어 덤프에 프로세스에서 사용하는 모든 메모리가 포함되어 있는 경우 코어 덤프에 실행 파일이 포함되어 있습니까? 전체 exe가 메모리에 로드된다는 보장이 없거나(단일 실행 파일은 일반적으로 그다지 크지 않지만), 결국 코어 덤프에 관련 메모리가 모두 포함되어 있지 않을 수도 있습니다. 기호에 대한 것입니까(아마도 메모리에 제대로 로드되지 않았을 수 있음)?
답변1
코어 덤프는 프로그램의 메모리 공간을 덤프한 것에 불과하며, 모든 것이 어디에 있는지 안다면 이를 사용할 수 있습니다.
실행 파일을 사용하는 이유는 메모리(즉, 코어 파일)의 위치(논리 주소 측면)를 설명하기 때문입니다.
이 명령을 사용하면 objdump
조사 중인 실행 가능 개체에 대한 메타데이터가 덤프됩니다. a.out이라는 실행 가능 개체를 예로 들어 보겠습니다.
objdump -h a.out
헤더 정보만 덤프하려면 다음과 같은 섹션이 표시됩니다.. 데이터또는.bss또는. 텍스트(더있다). 이는 객체에서 다양한 부분을 찾을 수 있는 위치, 프로세스 주소 공간에서 로드되어야 하는 위치, 특정 부분(예: .data .text)에 대해 로드되어야 하는 부분을 커널 로더에 알려줍니다. (.bss 섹션에는 파일의 데이터가 포함되어 있지 않지만 초기화되지 않은 데이터를 위해 프로세스에서 예약된 메모리 양을 나타내며 0으로 채워집니다.)
실행 가능한 객체 파일의 레이아웃은 표준 ELF를 따릅니다.
objdump -x a.out
- 모든 것을 버려라
실행 가능 객체에 여전히 기호 테이블이 포함되어 있는 경우(제거되지 않았으며 AC 소스 컴파일을 가정하여 디버그 빌드를 생성하는 man strip
데 사용하는 경우 ) 예를 들어 변수가 있는 경우 기호 이름으로 핵심 내용을 확인할 수 있습니다. /버퍼 이름은 다음과 같습니다.-g
gcc
입력 라인소스 코드에서 이 이름을 사용하여 gdb
내용을 볼 수 있습니다. 즉, gdb
우리는 프로그램 초기화 데이터 세그먼트로부터의 오프셋을 알고 있습니다.입력 라인이 변수의 시작과 길이입니다.
추가 읽기제1조, 제2조, 실질적인 내용은 물론이고실행 가능 및 연결 형식(ELF) 사양.
아래 @mirabilos 댓글 이후 업데이트되었습니다.
하지만 아래와 같이 심볼 테이블을 사용하면
$ gdb --batch -s a.out -c core -q -ex "x buf1"
생산
0x601060 <buf1>: 0x72617453
그러면 심볼테이블을 사용하지 않고 주소를 직접 확인하지 않고,
$ gdb --batch -c core -q -ex "x 0x601060"
생산
0x601060: 0x72617453
두 번째 명령에서는 심볼 테이블을 사용하지 않고 직접 메모리를 확인했습니다.
또한 @user580082의 답변에 추가 설명이 추가되어 투표할 것임을 알 수 있습니다.
답변2
코어 파일은 프로세스가 종료될 때 스택 이미지, 메모리 맵 및 레지스터의 스냅샷입니다. 그 내용은 주어진 방식으로 조작될 수 있습니다핵심 매뉴얼 페이지. 기본적으로 개인 매핑, 공유 매핑 및 ELF 헤더 정보는 코어 파일에 덤프됩니다.
당신의 질문에 대답, gdb에 실행 파일이 필요한 이유는 valgrind와 같은 바이너리 명령어를 읽고 해석하여 실행을 시뮬레이션하는 것이 아니라 프로세스의 상위 프로세스가 되어 런타임 시 프로세스의 동작을 제어하기 때문입니다. 이는 코어 파일을 사용하여 충돌 중에 프로세스의 메모리 맵과 프로세서 상태를 결정합니다.
Linux에서 상위 프로세스는 하위 프로세스에 대한 추가 정보, 특히 ptrace 기능을 얻을 수 있습니다. 이를 통해 디버거는 프로세스에 대한 하위 수준 정보(예: 메모리 읽기/쓰기, 레지스터 변경, 신호 맵 변경, 중지 등)에 액세스할 수 있습니다. 그 실행 등
디버거의 작동 방식을 읽고 나면 더 많은 핵심 파일이 있지만 실행 파일의 요구 사항을 이해할 수 있습니다.
답변3
(다른 좋은 답변 외에도)
최신 Linux(및 많은 Unix 유사) 시스템에서는 디버깅 정보(기호 유형, 소스 코드 위치, 변수 유형 등에 대한 메타데이터 포함)가 위치합니다.난쟁이형식으로 위치하며매우 낮은 주파수실행 파일(또는 ELF 공유 라이브러리)은 특정 옵션을 사용하여 컴파일됩니다 -g
. 디버깅하려는 프로그램을 컴파일하는 것이 좋습니다 -g3 -O0
. 아마도 -fno-inline
최근 버전을 사용하는 경우일 것입니다.걸프 협력 협의회-O2 -g1
; 그러나 GCC를 사용하면 최적화 및 디버그 정보를 사용 하여 컴파일할 수도 있습니다.하이젠베르크).
이 정보를 입력하지 않는 것이 매우 현명합니다.핵무기core
동일한 실행 파일이 다양한 코어 파일을 가질 수 있기 때문입니다(많은 사용자가 오류 보고서를 작성하고 대부분은 덤프를 작성하는 널리 사용되는 소프트웨어를 상상해 보십시오). 반품코어(5)파일은 커널에 의해 덤프되며 커널은 DWARF 섹션의 존재에 신경 쓰지 않아야 합니다.엘프(5)실행 가능합니다(이러한 부분은 매핑되지 않았기 때문에가상 주소 공간불완전한프로세스코어를 어딘가에 버려라신호(7)). 디버깅 정보를 넣을 수도 있습니다.분리파일(실행 파일 제외).
그런데, GDB는 가능합니다괴로운디버깅 정보 없이 실행 파일을 디버깅하기 위한 코어 덤프입니다. 그러나 실제로는 프로그래밍 언어와 해당 컴파일러에서 제공하는 기호 수준이 아닌 기계어 코드 수준에서 디버깅하고 있습니다.
답변4
실행 파일은 실행 중에 쓰기 금지되어 있으므로 실행 중인 프로세스에서는 해당 파일을 변경할 수 없습니다. 또한 여러 프로세스가 동일한 이미지를 실행할 때 코드 페이지(및 상수)는 대부분 한 번 메모리에 로드되어야 합니다. 단일 프로세스가 이미지를 실행하더라도 모든 페이지를 RAM에 로드하지는 않습니다(페이징 요청). 그러나 실행 파일의 일부 부분(예: 디버깅 정보)은 RAM에 전혀 로드할 필요가 없습니다.
이러한 모든 이유로 인해 의미가 있습니다.아니요각 코어 덤프 파일에 실행 파일을 복사하십시오. 이는 어쨌든 "공통 요소"입니다.
따라서 코드(예 disassemble
: ) 를 표시하려면 gdb
코드 페이지가 필요합니다. 이론적으로 코어 덤프에 요청 페이징 코드만 포함된 경우 실패한 프로그램 부분을 나열할 수 있으며 호출 코드 페이지도 "호출"되었을 수 있으므로 해당 부분만 확인할 수 있습니다. 프로그램이 실패했습니다.
gdb
코드 주소를 소스 파일, 줄 및 변수 이름과 연결하려면 디버깅 기호(있는 경우) 도 필요합니다.
마지막으로 동적 라이브러리를 사용할 때 코어 덤프에는 모든 라이브러리도 포함되어야 합니다.