segfault 커널 로그 메시지를 읽는 방법
이것은 매우 간단한 질문이 될 수 있습니다. 다음과 같은 segfault 오류를 생성하는 응용 프로그램을 디버깅하려고합니다. kern.log
kernel: myapp[15514]: segfault at 794ef0 ip 080513b sp 794ef0 error 6 in myapp[8048000+24000]
내 질문은 다음과 같습니다.
segfault의 diff 오류 번호에 대한 문서가 있습니까?이 경우 오류 6이지만 오류 4, 5를 보았습니다.
정보의 의미는 무엇입니까
at bf794ef0 ip 0805130b sp bf794ef0 and myapp[8048000+24000]
?
지금까지 심볼로 컴파일 할 수 있었는데, 내가 할 때 x 0x8048000+24000
심볼을 반환하는 것이 올바른 방법입니까? 지금까지 내 가정은 다음과 같습니다.
- sp = 스택 포인터?
- ip = 명령 포인터
- at = ????
- myapp [8048000 + 24000] = 심볼 주소?
보고서가 공유 라이브러리가 아닌 프로그램을 가리키는 경우
addr2line -e myapp 080513b
오류가 발생한 위치를 확인하려면 실행 (및 주어진 다른 명령 포인터 값에 대해 반복)합니다. 더 나은 방법은 디버그 계측 된 빌드를 얻고 gdb와 같은 디버거에서 문제를 재현하는 것입니다.
공유 라이브러리 인 경우
에서 libfoo.so[NNNNNN+YYYY]
일부는이 NNNNNN
라이브러리가로드 된 곳입니다. 명령어 포인터 ( ip
) 에서 이것을 빼면 .so
잘못된 명령어 의 오프셋을 얻을 수 있습니다. 그런 다음 objdump -DCgl libfoo.so
해당 오프셋에서 명령어를 사용 하고 검색 할 수 있습니다 . asm 레이블에서 어떤 기능인지 쉽게 알아낼 수 있어야합니다. 에 .so
최적화가없는 경우 addr2line -e libfoo.so <offset>
.
오류의 의미
다음은 필드 분석입니다.
address
- 코드가 액세스하려고 메모리의 위치는 (그것은 가능성이 높습니다10
그리고11
우리가 올바른 값으로 설정 될 것으로 예상 포인터의 오프셋이 있지만있는 대신에 가리키는0
)ip
-명령 포인터, 즉. 이 작업을 수행하려는 코드가있는 곳에sp
-스택 포인터error
-아키텍처 별 플래그arch/*/mm/fault.c
플랫폼을 참조하십시오 .
내 제한된 지식을 바탕으로 귀하의 가정이 정확합니다.
sp
= 스택 포인터ip
= 명령 포인터myapp[8048000+24000]
= 주소
문제를 디버깅하는 경우 코드를 수정하여 코어 덤프를 생성하거나 충돌시 스택 역 추적 을 기록합니다 . GDB에서 프로그램을 실행 (또는 첨부) 할 수도 있습니다.
오류 코드는 페이지 폴트에 대한 아키텍처 오류 코드 일 뿐이며 아키텍처에 따라 다릅니다. 그것들은 종종 arch/*/mm/fault.c
커널 소스에 문서화되어 있습니다. 내 사본 Linux/arch/i386/mm/fault.c
에는 error_code에 대한 다음 정의가 있습니다.
- 비트 0 == 0은 페이지가 없음을 의미하고 1은 보호 오류를 의미합니다.
- 비트 1 == 0은 읽기, 1은 쓰기를 의미합니다.
- 비트 2 == 0은 커널, 1은 사용자 모드를 의미합니다.
내 사본은 Linux/arch/x86_64/mm/fault.c
다음 을 추가합니다.
- 비트 3 == 1은 오류가 명령 페치임을 의미합니다.
공유 라이브러리 인 경우
불행히도 당신은 물에 빠져 있습니다. 사후 동적 링커에 의해 라이브러리가 메모리에 배치 된 위치를 알 수 없습니다 .
음, 바이너리가 아니라 객체에서 정보를 검색 할 가능성이 여전히 있습니다. 그러나 객체의 기본 주소가 필요합니다. 그리고이 정보는 여전히 link_map 구조의 coredump 내에 있습니다.
따라서 먼저 link_map 구조체를 GDB로 가져오고 싶습니다. 따라서 디버그 기호로 프로그램을 컴파일하고 GDB에 추가해 보겠습니다.
link.c
#include <link.h>
toto(){struct link_map * s = 0x400;}
get_baseaddr_from_coredump.sh
#!/bin/bash
BINARY=$(which myapplication)
IsBinPIE ()
{
readelf -h $1|grep 'Type' |grep "EXEC">/dev/null || return 0
return 1
}
Hex2Decimal ()
{
export number="`echo "$1" | sed -e 's:^0[xX]::' | tr '[a-f]' '[A-F]'`"
export number=`echo "ibase=16; $number" | bc`
}
GetBinaryLength ()
{
if [ $# != 1 ]; then
echo "Error, no argument provided"
fi
IsBinPIE $1 || (echo "ET_EXEC file, need a base_address"; exit 0)
export totalsize=0
# Get PT_LOAD's size segment out of Program Header Table (ELF format)
export sizes="$(readelf -l $1 |grep LOAD |awk '{print $6}'|tr '\n' ' ')"
for size in $sizes
do Hex2Decimal "$size"; export totalsize=$(expr $number + $totalsize); export totalsize=$(expr $number + $totalsize)
done
return $totalsize
}
if [ $# = 1 ]; then
echo "Using binary $1"
IsBinPIE $1 && (echo "NOT ET_EXEC, need a base_address..."; exit 0)
BINARY=$1
fi
gcc -g3 -fPIC -shared link.c -o link.so
GOTADDR=$(readelf -S $BINARY|grep -E '\.got.plt[ \t]'|awk '{print $4}')
echo "First do the following command :"
echo file $BINARY
echo add-symbol-file ./link.so 0x0
read
echo "Now copy/paste the following into your gdb session with attached coredump"
cat <<EOF
set \$linkmapaddr = *(0x$GOTADDR + 4)
set \$mylinkmap = (struct link_map *) \$linkmapaddr
while (\$mylinkmap != 0)
if (\$mylinkmap->l_addr)
printf "add-symbol-file .%s %#.08x\n", \$mylinkmap->l_name, \$mylinkmap->l_addr
end
set \$mylinkmap = \$mylinkmap->l_next
end
GDB 명령 세트 내에서 전체 link_map 내용을 인쇄합니다.
그 자체로는 비정상적으로 보일 수 있지만 우리가 관련된 공유 객체의 base_addr을 사용하면 다른 GDB 인스턴스에서 관련된 공유 객체를 직접 디버깅하여 주소에서 더 많은 정보를 얻을 수 있습니다. 기호의 idee를 갖도록 첫 번째 gdb를 유지하십시오.
NOTE : the script is rather incomplete i suspect you may add to the second parameter of add-symbol-file printed the sum with this value :
readelf -S $SO_PATH|grep -E '\.text[ \t]'|awk '{print $5}'
where $SO_PATH is the first argument of the add-symbol-file
Hope it helps
참고URL : https://stackoverflow.com/questions/2179403/how-do-you-read-a-segfault-kernel-log-message
'IT Share you' 카테고리의 다른 글
C ++-십진수를 이진으로 변환 (0) | 2020.12.02 |
---|---|
삽입시 Postgres 오류-오류 : "UTF8"인코딩에 대한 잘못된 바이트 시퀀스 : 0x00 (0) | 2020.12.01 |
GraphViz에서 범례 / 키 만들기 (0) | 2020.12.01 |
피클과 선반의 차이점은 무엇입니까? (0) | 2020.12.01 |
lib의 JAR 내부에서 JSP를 제공 할 수 있습니까? 아니면 해결 방법이 있습니까? (0) | 2020.12.01 |