2010-09-19 4 views
20

나는 소프트웨어 중단 점에 INT 3 (0xCC)이 사용되었다는 것을 읽었습니다.명령어가 패치 되었더라도 INT 3 (0xCC) 소프트웨어 브레이크 포인트를 사용할 때 디버거는 정확성을 어떻게 보장합니까?

메모리의 실제 프로그램 코드를 덮어 쓰면 디버거에서 설정합니다.

또한 INT 3은 스택에 푸시 된 주소가 INT3 명령어 다음에 오는 명령어의 주소임을 의미하는 "오류"예외가 아니라 "트랩"이라고 읽었습니다.

패치 된 명령을 다시 실행하지 않으면 디버거에서 정확성을 어떻게 보장합니까?

+0

누군가 GDB 소스 코드를 인용 해 주시겠습니까? :-) –

답변

26

중단 점이 실행 된 후에도 계속 실행하려면 두 가지 가능성이 있습니다. 중단 점은 한 번만 실행될 예정 이었거나 지속성이 있어야했습니다. 한 번만 실행될 예정이었던 경우 중단 점 명령으로 덮어 쓴 원래 값을 복원하고 수동으로 주소를 해당 명령의 주소로 조정합니다 (어떤 명령이 있었는지 상관없이 이 실행 된 내용은이 단일 바이트 중단 점 이었음을 기억하십시오. 조정은 항상 사소합니다.) 그런 다음 계속 실행합니다.

영구 중단 점이있는 것으로 가정하면 추가되는 주름이 하나 있습니다. 실행을 계속하기 전에 스택의 플래그에 단일 단계 (일명 트랩) 비트를 설정합니다. 즉, 브레이크 포인트가 설정된 하나의 명령어 만 실행되며 브레이크 포인트 인터럽트가 다시 발생합니다. 원래 명령의 첫 번째 바이트에 방금 패치 한 int 3 바이트를 복원하여 응답하고 (다시) 실행을 계속합니다.

+0

[GDB 내부 위키] (https://sourceware.org/gdb/wiki/Internals/Breakpoint%20Handling)에서도 언급 됨 : "사용자가 계속 말하면 GDB는 원래의 명령을 복원, 단일 단계, 트랩을 다시 삽입하고 계속하십시오. " –

2

일반적인 해결 방법은 디버거가 스택의 주소를 수정하고 (트랩에 의해 덮어 쓰여진 명령을 복원하는) 패치 된 명령을 실행하는 것입니다.

4

그런 종류의 것들에 대해 깊이 파고 들었으니 꽤 오랜 시간이 걸렸지 만, 다음 주소가 스택에 푸시되었다고 가정하면 디버거는 리턴 주소를 팝업하여 중단 점의 위치를 ​​파악할 수 있습니다 (INT 3 명령이 1 바이트 길이이기 때문에 반환 주소에서 1을 뺀) [편집 됨].

즉, 디버거가 반드시 스택의 주소로 돌아갈 필요는 없습니다. 원본 명령을 복원 한 다음 원래 위치에서 실행할 수 있습니다. 중단 점을 설정하려면 플래그에서 "트랩 비트"를 사용하여 다른 트랩이 생성되기 전에 하나의 명령 (원래의 덮어 쓰기 된 명령) 만 실행하면됩니다 (INT 3 다시 생각합니다). INT 3 명령은 실행을 올바르게 계속하기 전에 재설정 될 수 있습니다.

그러나 대부분의 경우 디버거는 어쨌든 트랩을 직접 처리하지 않는 시스템에서 작동합니다. 예를 들어 트랩이 발생한 위치를 알려주는 신호가 전달 될 수 있습니다. 대부분의 경우 OS가이 작업을 수행 할 방법이 없으므로 트랩 주소에서 "실제"주소 (즉 INT 3 명령어의 주소)를 파악해야 할 가능성이 큽니다.

여러 스레드가 관련된 경우 상황이 복잡해집니다. 이 경우 원래의 명령을 "제자리"로 복원하면 다른 스레드가 충돌 한 경우 중단 점이 누락 될 수 있습니다. 한 가지 해결책은 명령을 복원하기 전에 다른 모든 스레드를 중지하는 것입니다 (나중에 다시 시작하는 것).

+1

단일 스테핑은 INT 1 IIRC – ninjalj

관련 문제