심볼파일에 소스 인덱싱을 하기 위해서 해야할 건 다 했는데 인덱싱이 안된다. (프로그램 설치 및 Path 지정, 파일 수정 등)


"zero source files found" 에러만 계속 뱉어내서 3일을 헤매다가 펄은 모르지만 그냥 분석해보기로 결정.


svnindex.cmd 는 svn.pm 을 호출하므로 이 파일을 열어봤다.


일반적으로 한글 지원을 위해 수정해야 하는 것으로 알고 있는 부분은 Path: 와 Revision: 이다.

m/^Path:[\s\t]*(.*)$/i

m/^Revision:[\s\t]*(\d*)$/i

이 부분을 다음과 같이 수정해야 한다.

m/^Path|^경로:[\s\t]*(.*)$/i

m/^Revision|^리비전:[\s\t]*(\d*)$/i

[m/정규표현식/i]는 다른 언어에서도 사용하는 방식의 정규표현식이라 한눈에 알아봤다.

'^'는 라인의 시작, '$'는 라인의 끝과 매치된다. (http://www.rubular.com/ 에서 아래쪽에 나오는 원문으로 확인 가능)

예전에는 [|경로, |리비전] 처럼 '^'를 추가하지 않아도 됐는데, 어느 순간부터 안 되어서 내가 수정했다.


그럼 이 정규표현식을 사용할 원문은 어디서 가져올까?

분명 svn.exe 명령어를 사용한 결과일 것이다.

$$self{'SVNCMD'} = "svn.exe";

...

open($hProcess, "$$self{'SVNCMD'} info -R \"$SourceRoot\"|")

이걸로 해당 명령어는 [svn.exe info -R "소스루트경로"] 임을 알 수 있다.

(사실 "|"가 뭔지 몰라서 넣어봤지만 명령 구문이 올바르지 않다고 한다)


커맨드창에서 해당 명령어를 입력해보니 정보가 쭉 나오는데, 다 볼 필요는 없을 것 같아서 Ctrl+C로 중단했다.

파일 하나의 출력을 보니 다음과 같았다.

경로: relative_path\source_file.c

이름: source_file.c

작업 사본의 루트 경로: C:\absolute_path

URL: http://source_server_url/svn/XXX/trunk/relative_path\source_file.c

저장소 루트: http://source_server_url/svn/XXX

저장소 UUID: 00000000-0000-0000-0000-000000000000

리비전: 863

노드 종류: 파일

스케쥴: 일반

마지막 수정 작업자: ldevil63

마지막 수정 리비전: 852

마지막 수정 일자: 2012-12-06 17:23:34 +0900 (2012-12-06, 목)

마지막 내용 수정 일자: 2013-01-03 10:51:37 +0900 (2013-01-03, 목)

체크섬: 28ea7d26eac7015034cc15075cd11faa630f5646


여기서 출력 결과가 한글이기 때문에 위에서 처럼 정규표현식 구문을 수정했던 것이다.

svn.exe가 영문이라면 경로:Path:로, 리비전:Revision:으로 출력된다.


pdb 파일을 텍스트 에디터로 열어서 확인해보면 소스 경로는 절대경로로 입력되어 있다. (srctool.exe를 사용해도 확인 가능)

하지만 여기서 찾은 경로 값은 상대경로이다.


예전에 잘 되었을 때의 pdb 파일을 열어보니 다음과 같은 식으로 입력되어 있다.

C:\absolute_path\relative_path\source_file.c*http://source_server_url/*svn/XXX/trunk/relative_path\source_file.c*863

이것도 절대경로...


그런데 svn.pm에서 위 부분을 삽입하는 부분은 조금 이상하다.

@{$$self{'FILE_LOOKUP_TABLE'}{lc $LocalFile}} = ( { }, "$LocalFile*$FileRepository*$FileRelative*$FileRevision");

앞 부분은 잘 모르겠고, 뒤의 변수들 값을 찾아보니, 다른 건 다 일치하는데 $LocalFile은 상대경로였다.

if ( $curline =~ m/^Path|^경로:[\s\t]*(.*)$/i ) {

    $LocalFile = lc $1;

    ...

}

참고로 $1은 정규표현식에서 매칭된 문자열의 첫번째 괄호 부분이다.

따라서 제일 처음의 "relative_path\source_file.c" 이다.


절대경로로 변경해서 해보려고 svn.pm 파일을 수정하였다. (일부만 발췌)

my $LocalFile;

my $LocalFilePathRelative;

my $LocalFilePathAbsolute;

...

if ( $curline =~ m/^(Path|경로):[\s\t]*(.*)$/i ) {

    $LocalFilePathRelative = lc $2;

    ...

    # Parse Working Copy Path

    if ( $curline =~ m/^(Working Copy Root Path|작업 사본의 루트 경로):[\s\t]*(.*)$/i ) {

        $LocalFilePathAbsolute = lc $2;

        $LocalFile = $LocalFilePathAbsolute . "\\" . $LocalFilePathRelative;

    }

}


절대경로로 변경하고 나니 잘된다 ㅋㅋ

=========================================================================================================================================

하다보니 또 안되는 경우가 생겼다.

svn info 명령을 실행하는 위치가 작업 사본의 루트이면 경로: 의 값이 상대경로로 나오고, 그 외에는 다음처럼 절대경로로 나온다.

경로: C:\absolute_path\relative_path\source_file.c

이름: source_file.c

작업 사본의 루트 경로: C:\absolute_path

URL: http://source_server_url/svn/XXX/trunk/relative_path\source_file.c

저장소 루트: http://source_server_url/svn/XXX

저장소 UUID: 00000000-0000-0000-0000-000000000000

리비전: 863

노드 종류: 파일

스케쥴: 일반

마지막 수정 작업자: ldevil63

마지막 수정 리비전: 852

마지막 수정 일자: 2012-12-06 17:23:34 +0900 (2012-12-06, 목)

마지막 내용 수정 일자: 2013-01-03 10:51:37 +0900 (2013-01-03, 목)

체크섬: 28ea7d26eac7015034cc15075cd11faa630f5646


절대경로의 루트부분이 중복되어 입력되어 다음과 같은 이상한 경로가 입력된다.

C:\absolute_pathC:\absolute_path\relative_path\source_file.c

따라서 소스 위치가 아닌 곳에서 소스 인덱싱을 하는 경우에는 정상동작을 하지 않을 것이다.


아래와 같이 작업 사본의 루트 경로 위치에 따라 입력하도록 svn.pm을 다시 수정하였다.

    # Parse Working Copy Path

    if ( $curline =~ m/^(Working Copy Root Path|작업 사본의 루트 경로):[\s\t]*(.*)$/i ) {

        $LocalFilePathAbsolute = lc $2;

        if ( index ($LocalFilePathRelative, $LocalFilePathAbsolute) != -1)  {

            $LocalFile = $LocalFilePathRelative;

        } else {

            $LocalFile = $LocalFilePathAbsolute . "\\" . $LocalFilePathRelative;

        }

    }

첨부된 파일은 다시 수정된 svn.pm 파일이다.

svn.pm


이상 기록 끝.


=========================================================================================================================================

다른 회사에서 해봤더니 또 안되는 경우가 발생!

삽질 엄청 하다가 알아낸 결론은... GIt 때문이었다.

망할 Git 의 bin 디렉토리에 perl.exe가 있어서 발생한 오류 ㅠ_ㅠ 

Git 을 설치했다면 Path에 ActivePerl 의 경로가 앞에 오도록 설정해주면 된다.



GDB 명령어에 대해 정리한 자료
http://freemmer.tistory.com/31
다음은 콘솔 프로젝트를 기준으로 작성되었다.

  1. 일반 콘솔에서 (MFC에서는 필요없음) 메모리 릭 출력하는 방법
    1. 추가해야 할 헤더

      #include <stdlib.h>

      #include <crtdbg.h>
    2. 메모리 릭 정보를 출력하고자 하는 라인에 추가할 함수나 매크로
      1) 종료할 때 Dump를 미리 지시하는 매크로 (시작시 호출)
        _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
      2) 명시적으로 메모리 릭 정보의 출력을 지시하는 함수 (종료시 호출)
        _CrtDumpMemoryLeaks();

  2. 다음 그림처럼 출력된 메모리 릭 정보에서 할당한 라인의 정보가 나오지 않을 경우

    1. malloc의 경우 (2가지 방법)
      1. 프로젝트 설정의 전처리기에 _CRTDBG_MAP_ALLOC 을 추가해준다.
        MSDN에서는 #define _CRTDBG_MAP_ALLOC 을 1번에서 추가한 헤더위에 정의하면 된다고 하였지만 실제로는 되지 않았다.
      2. 다음 코드를 추가한다.
        #if _DEBUG
        #define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
        #endif

    2. new의 경우
      1. 다음 코드를 추가한다.
        #if _DEBUG

        #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
        #endif
        malloc의 경우와 비슷하게 _CRTDBG_MAP_ALLOC_NEW를 추가하면 crtdbg.h의 인라인 operator new가 불리게 되어 항상 crtdbg.h의 operator new에서 할당받은 것으로 나오므로 쓸모가 없어진다.
  3. 2번과 같은 문제를 할당된 순서(위 그림에서 {106}, {104})를 통해 Break를 거는 방법
    1. 최대한 빨리 _crtBreakAlloc 에 값을 설정한다.
      (/MD 옵션으로 컴파일 했을 경우 {,,msvcr71d.dll}_crtBreakAllocdp에 값을 설정한다)
      _crtBreakAlloc = 104; // 104번째 동적 할당 되었을 경우 break됨
    2. _CrtSetBreakAlloc(104); 으로 설정해도 된다.
    3. 상황에 따라 할당 순서가 달라지는 경우도 많이 생기기 때문에 엉뚱한 곳을 가리킬 수 있으니 사용할 때 주의해야 한다.

위 글을 읽어보는 것도 귀찮다면 다음 두가지만 추가한다.

  • 할당 함수를 사용하기 전에 다음 코드 추가
    #include <stdlib.h>
    #include <crtdbg.h>

    // 해제가 되지 않은 메모리의 할당 위치를 알기 위해 파일과 라인넘버를 입력하는 작업
    #if _DEBUG

    #define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
    #if defined(__cplusplus)
    #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
    #endif
    #endif

  • 프로그램 시작 부분에 다음 코드 추가
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); // 정상 종료시 해제되지 않은 메모리 정보 출력한다
    // _CrtSetBreakAlloc(104); // 104 번째 할당 시 Break가 걸린다

다음은 예제로 사용한 소스와 실행 결과이다.


Detected memory leaks!
Dumping objects ->
c:\documents and settings\digicaps\my documents\visual studio 2005\projects\temptestcode\temptestcode\temptestcode.cpp(29) : {106} normal block at 0x003A9F40, 13 bytes long.
 Data: <Memory Leak! > 4D 65 6D 6F 72 79 20 4C 65 61 6B 21 00
c:\documents and settings\digicaps\my documents\visual studio 2005\projects\temptestcode\temptestcode\temptestcode.cpp(24) : {104} normal block at 0x003A9EF0, 13 bytes long.
 Data: <Memory Leak! > 4D 65 6D 6F 72 79 20 4C 65 61 6B 21 00
Object dump complete.
'[3428] TempTestCode.exe: 네이티브' 프로그램이 0 (0x0) 코드에서 끝났습니다.

오늘 당했던 일을 먼저....
솔루션의 프로젝트 구성은 이랬다.
 
프로젝트 1 : native C++ library (unmanaged code)
프로젝트 2 : wrapper Class (managed code) 
프로젝트 3 : C#
 
이때 wrapper class에서 native 함수를 호출하면 꼭 비관리코드에서 관리코드를 읽거나 쓰려고 했다는 예외가 발생했다.
호출되는 native c++ 함수에서 브레이크포인트를 걸어보니 그곳에서 걸리지 않았다.
그럼 호출 자체가 문제가 있다는건데 라이브러리를 바로 쓰는건데 왜 호출이 안되지?
마샬링으로 넘어오는 버퍼가 관리힙에 있는 건가? MSDN 설명으로는 그렇지는 않은데...
caller가 관리코드라 비관리코드 호출 후 caller로 돌아올 때 리턴코드가 영향을 끼치나?
관리코드에서는 비관리코드를 아예 호출할 수 없는건가? 등등으로 고민했다.
 
찾아봐도 딱히 답도 없고... 짜증이 머리 꼭대기에 오를때쯤. (아니, 이미 꼭대기에 올라 있었다)
별 기대없이 호출되는 native c++의 함수 내부를 비워봤더니 정상적으로 호출이 되는것이 아닌가!
왜?!?! 젠장!! 분명히 native c++ 함수 시작 부분에 걸어 놓은 브레이크포인트에는 안 걸렸는데!!
 
다시 확인해보니, 디버깅 모드로 시작과 동시에 그 브레이크포인트는 disable 되고 있었다... orz
뭐 아직 왜 예외 메시지가 그렇게 나오는지는 모르겠다.
예외의 원인은 널포인터 참조였는데, 예외가 저딴식으로 나오면 안되지... ㅡ_ㅡ;
난 이래서 try catch가 너무 싫다.
 
검색해보니 혼합모드 디버깅 자료는 널리고 널렸더라.. 제길.
요것때문에 시간 낭비한 걸 생각하면... ㅠ_ㅠ
 
혼합모드 디버깅
1. 시작 프로젝트의 설정에서 [비관리코드 디버깅 사용] 체크
2. native c++ 프로젝트 설정에서 [디버깅 형식] 을 네이티브 or 혼합 or 자동으로


싸이 블로그 백업 [하zi 2008.09.10 16:26]

프로그램에 문제가 생겼다.
왜 그런가 살펴봤더니 포인터가 NULL을 가르키고 있었다.
가벼운(?) 마음으로 살포시 NULL 체크를 해줬다. ^^v
버그 해결~
이라는 오류에 빠져들지 말자.
 
위에서 말한 상황에서는 현재의 상태를 수정한 것이지 문제를 수정한 것이 아니다.
위의 문제가 발생하고 있는 상태를 감염되었다고 한다.
물론 감염원은 현재의 상태를 만들어낸 결함이다.
 
디버깅을 할 때 주의할 점이 현재의 상태를 수정하려고 하지 말고, 현재의 상태를 만들어낸 결함을 찾아서 수정해야 한다는 것이다. 현재의 상태만 수정한다면 감염의 상태를 다음 프로세스에 넘겨주는 꼴이 된다.
디버깅을 할 때는 꼭 추적을 통해 감염원, 즉 결함을 찾아서 수정을 해야한다.
 
디버깅의 7단계
추적, 재현, 자동화, 근원 찾기, 집중, 격리, 정정
 
어떤 PPT를 보다가 나온건데, 뭐.. 난 저 단계를 아직 잘 모르겠다. (안봤다 ㅡㅡ;;)
하나 수정하는데 그렇게 많이 신경써야하나 싶다. 시간나면 함 보고...
 
내게 디버깅의 단계는 다음과 같다.
재현, 추적, 근원 찾기, 정정, 확인, 자동 검출 코드 추가.


싸이 블로그 백업 [하zi 2008.08.27 22:13]

+ Recent posts