맵 파일을 이용한 충돌 위치 찾기 ( Finding crash point using the MAP file )
디버깅을 하다보면 참 난감한 상황에 빠질때가 많습니다. 프로그램이 실행 도중 크래시가 났을 경우 덤프와 심볼 파일이 있다면, 크래시가 발생한 위치와 원인을 손쉽게 찾아낼 수가 있지만, 그렇지 않다면 막막할 뿐입니다. 하지만 절망 하기에는 이릅니다. 크래시가 발생한 주소라도 있다면, 아직 희망의 끈이 있습니다. MAP 파일을 이용하면 크래시가 발생한 위치를 대략적으로 찾아낼 수 있기 때문이죠.
프로젝트 옵션에서 MAP 파일 관련 옵션은 기본적으로 비활성화 되어있습니다. 먼저 이 옵션을 아래와 같이 활성화 해주어야 MAP 파일이 생성됩니다.
이와 같이 설정후 빌드하면 MAP 파일이 생성되는데 심볼 파일과 함께 항상 잘 보관해두도록 합시다.
이제 이를 가지고 크래시 위치를 찾아내는 방법을 살펴보겠습니다. 먼저 크래시를 내야겠죠? 아래와 같이 간단하게 크래시를 유발시켜보겠습니다.
이런 메모리 해제를 두번씩이나 해제 해주고 있군요. 이 코드를 실행하면 아래와 같이 크래시가 펑~ 하고 납니다.
오류 내용을 잘 보시면 크래시 주소가 나와있습니다. 주소라도 남은게 다행입니다. 이제 MAP 파일을 통해 이 주소를 찾는 것입니다. 먼저 MAP 파일을 열어보겠습니다. MAP 파일은 일반 메모장등으로도 열어도 되지만, 좋은 Viewer 들도 많으니 그 것들을 이용해도 좋습니다. 여기서는 그냥 메모장으로 열겠습니다.
MAP 파일을 열어보면 조금 알아보기 힘든 내용들이 주르르륵~ 나오는데 겁먹을 필요 없습니다. 중요한 부분은 Publics by Value에 표시되는 함수명과 Rva+Base 에 표시되는 주소, 그리고 Lib:Object에 표시되는 모듈 이름 입니다.
위에서 크래시가 난 주소를 가지고, Rav+Base에서 크래시 주소의 바로 윗 주소를 찾습니다. 여기서는 00411f50 이군요. Public by Value의 함수명을 살펴보겠습니다. 조금 이상한 특수 문자들이 섞여있지만 ( ?? 같은 문자들은 C++ 데코레이션 문자들입니다 ) CBar 클래스의 SetFloat 함수라는 것을 파악할 수 있습니다.
별로 어렵지 않습니다. 덤프 파일과 심볼 파일 없이 크래시 주소만으로 문제가 되는 함수를 찾아낼 수 있었습니다(정확한 위치까지는 아니지만...).
참조 : Debugging Applications for Microsoft .net and Microsoft Windows