본문 바로가기
Borland

액세스바이올레이션 발생시 뜨는 주소값으로 에러난 라인 찾기

by leo21c 2009. 3. 5.
[600] [펌] 액세스바이올레이션 발생시 뜨는 주소값으로 에러난 라인 찾기
김태선 [jsdkts] 1710 읽음 2006-04-29 23:12
델마당 팁인데, 빌더도 거진 동일한 사항이라 펌합니다.

기사 작성자: 양병규
[팁] 액세스바이올뢔이션 발생시 뜨는 주소값으로 에러난 라인 찾기....
내려받기 : 액세스바이올뢔이션.zip (209768 바이트) -> 파일은 원문 주소를 클릭해서 보세용.

어떻게 보면 기본인것같은데.. 의외로 많은 분들이 잘 모르시는 것같아서... 이야기해봅니다.

액세스바이올뢔이션 에러가 발생하면 에러난 위치의 주소값을 16진수로 보여줍니다.

그 화면을 본 사용자는 큰일 난줄알고 바로 연락하는 경우가 많은데...

그 화면의 내용을 줄줄줄 다 읽어주기도하고....

보통은 캡쳐해서 보내주기도하는데...

정작 그걸 보는 개발자는 그 숫자가 의미하는게 뭔지도 잘모르고..

그걸 가지고 뭘해야하는지도 잘 모르는 경우가 많습니다.

자... 잔소리 그만하고..... ^^;

...

메모리 주소값을 설명하는것이므로.... 정확한 주소값으로 설명하기위해...첨부한 소스를 가지고 설명하겠습니다.

(참고로 델파이7입니다. 다른 버전에서는 여기서 설명하는 메모리주소값과 다른 주소값이 나올겁니다만... 내용은 동일합니다.)

자...

소스를 열어봅시다.

Form1Create에서는 Label1.Caption 에다가 HInstance를 IntToHex로 보여주게했고...(그냥 참고하라고....)

Button1Click에서는 다음과 같이 코딩해서 액세스바이올뢔이션에러가 뜨게했습니다.


--------------------------------------------------------------------------------

31: procedure TForm1.Button1Click(Sender: TObject);
32: var
33: P: Pointer;
34: i: Integer;
35: S: String;
36: begin
37:
38: P := Pointer( 99999999 );
39:
40: i := Integer( P^ );
41:
42: S := IntToStr( i );
43:
44: end;

--------------------------------------------------------------------------------
// C++ 같으면 이런 코드로 엑세스바이올레이션 에러를 낼수 있죠.
{
char *p;
*p = 'A';
}

자 컴파일해보면 Label1에는 $00400000 라고 써있고...

버튼을 클릭해보면

Access violation at address 0044EBA9 in module 'Project1.exe' read of address 05FF5E0FF

라는 에러가 뜰겁니다.

여기서 말하는 address 0044EBA9 ...

이 주소값으로 소스코드의 어느 유닛 몇번째 라인인지를 알 수 있는데....

그냥은 알수없고....

...

● 프로젝트 옵션을 엽니다. (Shift+Control+F11, Project->Options)

● Linker 탭을 엽니다.

● Map file 을 젤 밑에꺼 Detailed를 클릭합니다.

● Build Alll

그리고나서 소스코드가 있는 폴더에 보면 Project1.map라는 파일이 만들어져 있을겁니다.

그걸 메모장으로 엽니다.

다른 건 다른 자료들 찾아서 공부해 보시고.... 여기서 설명하는건 맵파일의 젤 아랫부분입니다.

젤 아랫부분에는 다음과 같이 나와있습니다.


--------------------------------------------------------------------------------

Line numbers for Unit1(Unit1.pas) segment .text

27 0001:0004DB00 28 0001:0004DB18 29 0001:0004DB70 36 0001:0004DB90
38 0001:0004DBA4 40 0001:0004DBA9 42 0001:0004DBAB 44 0001:0004DBD2
46 0001:0004DC08 46 0001:0004DC0F

Line numbers for Project1(C:\Documents and Settings\양병규\바탕 화면\새 폴더\Project1.dpr) segment .text

9 0001:0004DE18 10 0001:0004DE28 11 0001:0004DE34 12 0001:0004DE4C
13 0001:0004DE58

Bound resource files

c:\program files\borland\delphi7\Lib\Buttons.res
c:\program files\borland\delphi7\Lib\ExtDlgs.res
c:\program files\borland\delphi7\Lib\Controls.res
Unit1.dfm
Project1.res
Project1.drf


Program entry point at 0001:0004DE18

--------------------------------------------------------------------------------


이 중에서도 젤 윗 라인을 보면

Line numbers for Unit1(Unit1.pas) segment .text 라고 되어있는데...

말 그대로 소스코드의 라인들의 주소값들이 나와있습니다.

27 0001:0004DB00 이거는

27라인의 0001번째 글자부터의 소스코드가 0004DB00번지로 만들어졌다....라는 뜻입니다.

...

자... 에러가 난 주소가 얼마였져?

$0044EBA9 였군요....

이 주소 값에서 HInstance인 $00400000를 뺍니다.

그리고 PE포맷의 헤더등 불필요한 앞부분 사이즈인 $1000 도 뺍니다.

그러면

$0004DBA9 가 됩니다.

Line numbers for Unit1(Unit1.pas)에서 이 주소 $0004DBA9를 찾아봅시다.

몇라인인가요?

40 0001:0004DBA9 이라고 되어있습니다.

고로 에러가 난 부분은 Unit1의 40라인 0001번째 글자부터...입니다.

그 부분의 소스는

i := Integer( P^ );

입니다.

XP, 2000에서 HInstance는 항상 $00400000 이고,

델파이로 만들어진 EXE의 PE헤더정보는 항상 $1000 바이트입니다. 그러므로....

에러가 난 주소는 = 에러화면에 나온 주소 - $00401000 하면 됩니다.


이렇게 찾으시면 되는데...........

map파일이 있어야하므로 프로그램을 배포하기 전에 맵파일을 만들어두셔야합니다.

혹은 안만들었어도 나중에 만들면 되는데...

단, 소스코드가 최종 컴파일됐을때의 모양 그대로 있어야겠지요....

그리고,

맵에 라인별 주소값은 컴파일 할 당시 실제로 컴파일한 유닛들만 나옵니다.

그러므로 Graphics.pas와 같이 Lib 경로에 Dcu만 있고 pas는 없는 유닛들은 포함되지 않습니다. 바꿔말하면 Graphics.pas 도 맵에 라인별 주소값을 남기려면 그 유닛도 컴파일이 되도록.. 프로젝트 경로에 같이 두던가 Lib에 Graphics.pas를 넣던가하면 됩니다.

끝.


댓글중 가치 있는것:

민성기//
좋은내용 감사합니다. ^^;;
덧붙이면 IDE에서 실행시킨 상태에서 Search->Find Error 메뉴를 선택하고 주소값을 넣어줘도 에러 위치로 바로 갈 수 있어요. ^^;
물론 이 경우도 해당 소스를 보관하고 있어야... 2006/04/29 X

// C++빌더는 Search->Goto Address 를 사용하면 됩니다. 그기에 0x4b1a2b 식으로 에러난 주소를 기재하면 됩니다.

양병규//
민성기님이 뉘시드라.......^^ (얼굴본지 넘 오래되서리... 기억이 가물가물... ^^ )
그 Find Error가 디버깅중에만 동작하는 지라... 저처럼 델파이 디버거 싫어하는 사람이나 혹은 빵집처럼 ^^ 소스코드 버전이 수십가지로 보관되어있는 경우에는... 구버전에서 찾아서 새 버전에서 수정해야하므로... 이거 열었다 저거 열었다...당췌 헷갈려서리.... ^^;
걍 맵하고 소스코드로 찾는게 낫드라구여....
(언제 얼굴보나.... --; )