본문 바로가기

개발 관련

Visual C++에서 디버그 정보 생성

Visual C++에서 디버그 정보 생성
GENERATING DEBUG INFORMATION WITH VISUAL C++

 

1. 디버그 정보 종류

2. 디버그 정보 포맷

3. 디버그 정보 생성 (general)

4. 디버그 정보 생성 (Visual C++ 6.0)

5. 디버그 정보 생성 (Visual C++ 2002, 2003, 2005)

6. 정적 라이브러리를 위한 디버그 정보

7. 실행파일의 디버그 정보 및 사이즈

8. .DBG 파일들

9. 디버거와 디버그 정보 포맷

10. Operation System 심볼

 

소개

개발자는 응용프로그램을 디버그하기 위해 디버거를 사용할 때다음과 같은 것들을 원한다.

한 단계씩 소스 코드를 실행하고소스 파일에 브레이크 포인트를 설정하며다양한 변수의 값(복잡한 사용자 정의 타입은 물론)을 조사하는 것.

그러나 실행파일은 대부분 기계어 명령어운영체제를 위한 헤더테이블과 같은 raw byte의 연속일 뿐이다또한 실행파일이 운영체제에 의해 로드되고 실행될 때다양한 목적(스택, …)을 위해 추가적으로 메모리를 사용한다그러나 이것들 역시 전부 raw byte이다.

 

그렇다면 디버거는 현재 실행하는 있는 CPU 명령어에 대응하는 소스파일과 라인의 위치를 어떻게 알 수 있을까또는함수 Y에 있는 로컬 변수 X에 대응하는 스택 메모리의 주소를 어떻게 알 수 있을까해답은 디버그 정보에 있다.실행하는 프로그램의 raw byte에 고수준 프로그래밍 언어를 링크시킨다.

 

1. 디버그 정보의 종류

단순하게여기서는 현재 마이크로소프트의 디버거와 인텔 x86 플랫폼에 대한 디버그 정보로 제한한다다음의 리스트는 현재 필자가 알고 있는 모든 디버그 정보이다.

 

디버그 정보

설명

Public 함수/변수

몇몇 컴파일 유닛(소스 파일)에 보이는 함수와 변수.

모든 함수와 변수는 위치와 이름을 디버그 정보에 저장한다.

Private 함수/변수

컴파일 유닛에 보이지 않는 것들을 포함한 모든 함수와 변수 (정적 함수정적 변수함수 파라미터 포함).

모든 함수와 변수는 위치와 사이즈이름을 디버그 정보에 저장한다.

소스파일/라인 정보

실행 파일의 위치에 대응하는 모든 소스파일의 라인에 매핑한다. (물론 주석처럼 모든 소스 라인이 매핑되는 것은 아니며디버그 정보에도 포함되지 않는다.)

타입 정보

모든 함수와 변수에 대해디버그 정보는 타입에 대한 추가 정보를 저장할 수 있다디버거는 변수나 함수 파라미터가 정수형문자열사용자 정의 타입 인지 등의 정보를 알려준다그리고 함수에 대해서는 파라미터의 수, calling convention, 함수 리턴 타입의 정보를 알려준다.

FPO 정보

FOP(frame pointer omission, (스택프레임 포인터 생략최적화로 컴파일된 함수에 대해디버거가 함수의 stack frame의 사이즈를 결정하기 위한 어떤 데이터를 디버그 정보에 저장한다비록 frame pointer를 사용하지 않 을 때조차이 정보 없이 디버그는 최적화된 응용프로그램을 디버깅할 때 정확한 call stack을 보여줄 수 없다.

편집/계속 정보

이 정보는  studio 시스템이 Edit(편집) Continue(계속기능을 구현하는데 도움을 준다.

* ‘location(위치)’는 여러 의미가 있다함수에서는 항상 함수의 첫 byte 주소를 의미하며전역/정적 변수에서는 메모리에서 변수의 첫 byte 주소를 의미한다그리고 로컬 변수와 함수 파라미터는 보통 함수의 stack frame에서 미리 정의된 위치로부터 offset된 변수의 첫 byte 주소이다.

location의 다른 타입도 물론 가능하다(, register, TLS slot, metadata token).

 

2. 디버그 정보 포맷 (Debug information formats)

지금까지 디버거 정보의 종류를 알아보았으며이제 디버거 정보가 어떻게 저장되는지 살펴보자.

예전에는 마이크로소프트 개발 툴은 패키징된 다른 디버그 정보 포맷을 사용해왔다여기서는 널리 사용되는 COFF (Common Object File Format, 유닉스에서 사용되는 파일 포맷), CodeView, Program Database format에 대해 살펴본다.

앞으로 살펴볼 모든 포맷에 대해다음의 특징들을 주로 알아볼 것이다

-       어떤 종류의 디버그 정보가 이 포맷을 사용하여 저장될까?

-       과연 디버그 정보는 어디에 저장될까? (실행 파일 자체에아니면 따로?)

-       포맷이 문서화되어 있나없나?

 

COFF

모든 디버그 정보 포맷 중에 가장 오래된 것으로디버그 정보 중 딱 3가지 종류만 포함한다.

-       public 함수와 변수소스 파일과 라인 정보, FPO 정보

COFF 디버그 정보는 항상 실행 파일 자체에 저장되며별도의 파일에 저장될 수 없다.

이 포맷은 문서화되었으며문서는 아래 링크에서 볼 수 있다.

-        Microsoft Portable Executable and Common Object File Format Specification

 

CodeView

이건 새롭고 좀 더 복잡한 포맷이다. Edit Continue 데이터를 제외한 모든 이용 가능한 디버그 정보를 저장할 수 있다.

코드뷰 정보는 보통 실행 파일 자체에 저장되나실행파일에서 정보를 빼내서 파일(보통 .DBG 확장자를 갖는다)에 저장할 수도 있다.

코드뷰 포맷은 일부 문서화되어 있으며문서는 MSDN의 Visual C++ 5.0 Symbolic Debug Information Specification문서에 있다.

 

Program Database

세가지 디버그 정보 포맷 중 가장 새로운 것이다. Edit Continue 데이터를 포함한 가능한 모든 디버그 정보를 저장할 수 있다또한 incremental linking(증분 링크)을 지원한다. (다른 포맷에서는 불가능)

프로그램 데이터베이스 정보는 항상 실행파일과 별도로 파일(보통 .PDB 확장자)에 저장된다.

프로그램 데이터베이스 포맷은 문서화되어 있지 않는 대신특별한 프로그래밍 인터페이스(DbgHelp DIA)가 이용 가능하다.

현재 데이터베이스 포맷에는 종류가 있다첫 번째 버전은 종종 PDB 2.0이라 불리며, Visual Studio 6.0에서 사용된다두 번째 버전과 새로운 버전 (PDB7.0이라 불림) Visual Studio.NET에서 사용된다. PDB7.0 포맷은 하위 호환이 불가능하다 (Visual Studio 6.0 디버거는 읽을 수 없다)

 

다음의 테이블은 세가지 포맷에 대한 비교 데이터이다.

 

Format

Documented

Storage

Public functions and variables

Private functions and variables

Source files and lines

Type information

FPO information

EnC information

COFF

Yes

Executable

+

-

+

-

+

-

CodeView

Yes

Executable or separate file (.DBG)

+

+

+

+

+

-

Program Database

No

Separate file (.PDB)

+

+

+

+

+

+

 

 

3. 디버그 정보 생성 (Generating debug information)

 

Build process

전형적인 실행파일의 빌드 프로세스는 두 단계로 구성한다 – 컴파일과 링크.

 

먼저 컴파일러는 소스 파일을 파싱하고기계어 명령어를 만들어내며이는 오브젝트 파일에 저장된다다음으로 링커는 모든 이용 가능한 오브젝트 파일을 최종 실행 파일에 결합한다오브젝프 파일은 물론실제 오브젝트 파일의 모음이라 할 수 있는 라이브러리를 사용하도록 요구될 수도 있다전체 프로세스가 다음의 그림에 나와있다.

 

 

여기서실행 파일을 위한 디버그 정보는 다음 두 단계를 거쳐 생성된다.

먼저컴파일러가 모든 소스 파일에 대한 디버그 정보를 만들어 내도록 요청한다다음으로 링커가 모든 파일에 대한 디버그 정보를 실행 파일에 대한 디버그 정보에 병합시키도록 요구한다.

이 프로세스는 다음 그림과 같다.

 

 

 

디폴트 설정에선컴파일러와 링커는 디버그 정보를 만들어내진 않는다그래서 컴파일러와 링커가 모든 단계마다 원하는 디버그 정보를 만들어낼 수 있도록 명시해줘야 한다이 때 디버그 정보 종류디버그 정보 포맷디버그 정보 저장 파일들을 명시할 수 있다.

 

아래는 Microsoft Visual C++ 6.0 Microsoft Visual C++.NET(2002 and 2003)의 컴파일러와 링커 옵션에 대해 살펴본다.

 

 

4. Visual C++ 6.0

 

Compiler

아래 열거한 옵션 중 하나를 사용하면컴파일러는 소스 파일에 대한 디버그 정보를 만들게 된다.

 : /Zd, /Z7, /Zi, /ZI  (모든 옵션은 IDE에서 설정 가능)

-       /Zd 옵션 : COFF 포맷 사용오브젝트 파일에 결과 저장

-       /Z7 옵션 : CodeView 포맷 사용오브젝트 파일에 결과 저장

-       /Zi 옵션 ; Program Database 포맷 사용별도의 .PDB 파일에 저장

-       /ZI 옵션 : /Zi 옵션과 거의 동일, Edit Continue 데이터를 포함

/Zi /ZI 옵션에 의해 생성된 .PDB 파일 이름은 디폴트가 VC60.PDB 이지만, /Fd 컴파일러 옵션을 사용해서 변경할 수 있다.

 

이를 정리하면 다음과 같다.

Option

Format

Storage

Contents

/Zd

COFF

.OBJ file

  • Public functions and variables
  • Source file and line information
  • FPO information

/Z7

CodeView

.OBJ file

  • Public functions and variables
  • Private functions and variables
  • Source file and line information
  • Type information
  • FPO information

/Zi

Program Database

.PDB file

  • Public functions and variables
  • Private functions and variables
  • Source file and line information
  • Type information
  • FPO information

/ZI

Program Database

.PDB file

  • Public functions and variables
  • Private functions and variables
  • Source file and line information
  • Type information
  • FPO information
  • Edit and Continue data

 

 

Linker

실행 파일에 대한 디버그 정보를 위해선 다음의 옵션을 링커에 설정한다.

 : /debug, /debugtype, /pdb, /pdbtype (IDE에서 옵션 설정 가능)

 

-       /debug 옵션 : 링커에게 실행파일에 대한 디버그 정보를 생성할지 여부를 묻는다이 옵션이 설정되어 있지 않으면디버그 정보는 만들어지지 않으며다른 옵션은 무시된다.

 

-       /debugtype 옵션 : 생성된 디버그 정보에 대한 포맷을 명시한다.

 

-       debugtype : coff  => COFF 포맷 사용

 

-       /debugtype : cv  => CodeView 또는 Program Database 포맷 사용 (/pdb 옵션)

 

-       /debugtype : both  => COFF CodeView/Program Databse 포맷 둘다 사용

 

/debugtype:coff 옵션을 사용할 때 중요한 점은 파일과 라인 정보가 디버그 정보에 포함되지 않는다는 것이다비록 오브젝트 파일을 위해 생성한 디버그 정보를 포함되었을지라도그래서 소스 파일과 라인 정보가 필요하면 /debugtype:cv 또는 /debugtype:both 옵션을 사용해야 한다.

 

/pdb 옵션은 CodeView 또는 Program Database 포맷을 사용할지 여부이다. /pdb:none 이면 CodeView 포맷을 사용하고, /pdb:filename 이면 Program Databse 포맷을 사용한다이때 .PDB 파일을 명시한다. /debugtype:coff 옵션이 설정되어 있으면, /pdb 옵션은 무시된다.

 

/pdbtype 옵션은 하나 이상의 오브젝트 파일과 라이브러리에 대한 디버그 정보가 .PDB 파일에 저장될 때만 유효하다. /pdbtype:setp 옵션은 링커에게 디버그 정보를 원본 .PDB 파일에 남겨놓도록 하며실행 파일을 위한 .PDB 파일로 복사하지 않는다그 결과 링크 프로세스는 좀 더 빠르게 진행되지만모든 .PDB 파일은 실행파일을 성공적으로 디버그하길 원할 것이다디버그 정보 파일을 다수의 .PDB 파일들에 저장하지 않으려면, /pdbtype:con 옵션을 사용한다이 옵션은 링커가 모든 .PDB 파일들의 내용을 실행파일의 최종 .PDB파일로 복사할 것이다.

좀더 이해를 돕기 위해다음에 정리해 놓았다.

/debugtype

/pdb

Format

Storage

coff

/pdb:none (has no effect)

COFF

In the executable

coff

/pdb:filename (has no effect)

COFF

In the executable

cv

/pdb:none

CodeView

In the executable

cv

/pdb:filename

Program Database

In .PDB file

both

/pdb:none

COFF and CodeView

In the executable

both

/pdb:filename

COFF and Program Database

COFF information in the executable, Program Database information in .PDB file

 

 

5. Visual C++ 2002, 2003, 2005

Compiler

컴파일러는 아래의 옵션을 사용하여 소스파일의 디버그 정보를 만들게 된다.

: /Zd, /Z7, /Zi, /ZI

(모든 옵션은 IDE에서 설정가능하며, /Zd Visual C++ 2005에서 지원하지 않는다.)

 

-       /Z7 옵션 : CodeView 포맷 사용, object 파일에 결과 저장

-       /Zd, /Zi, /ZI 옵션 : Program Database 포맷 사용. .PDB 파일에 결과 저장

(3가지 옵션에 대한 차이점은 디버그 정보의 내용이 다르며아래 표 참조할 것)

 

/Zd, /Zi, /ZI 옵션으로 생성된 .PDB 파일은 디폴트가 각각 VC70.PDB, VC71.PDB, VC80.PDB 이다. (Visual Studio 버전에 따라 다름). 그러나 /Fd 컴파일러 옵션을 사용하여 변경할 수 있다.

주목할 점은 이러한 컴파일러의 새로운 버전들은 COFF 포맷을 사용하는 디버그 정보를 만들지 않는다.

 

요약 정보

Option

Format

Storage

Contents

/Z7

CodeView

.OBJ file

  • Public functions and variables
  • Private functions and variables
  • Source file and line information
  • Type information
  • FPO information

/Zd

Program Database

.PDB file

  • Public functions and variables
  • Source file and line information
  • FPO information

/Zi

Program Database

.PDB file

  • Public functions and variables
  • Private functions and variables
  • Source file and line information
  • Type information
  • FPO information

/ZI

Program Database

.PDB file

  • Public functions and variables
  • Private functions and variables
  • Source file and line information
  • Type information
  • FPO information
  • Edit and Continue data

 

 

Linker

다음의 옵션들은 링커에서 실행파일에 대한 디버그 정보를 생성할 때 사용한다.

 : /debug, /pdb, /pdbstripped (IDE에서 설정 가능)

 

-       /debug 옵션 : 실행파일에 대한 디버그 정보를 생성

이 옵션이 명시되지 않으면디버그 정보는 생성되지 않으며다른 옵션은 무시된다.

디버그 정보 포맷은 항상 Program Database이며항상 .PDB 파일에 저장된다.

링커는 디폴트로서 .PDB 파일의 이름으로 실행 파일의 이름을 사용한다.

.PDB 파일은 모든 디버그 정보의 내용을 포함할 수 있다.

 

-       /pdb 옵션 : .PDB 파일이름으로 디폴트 이름을 명시하지 않아도 된다.

 

-       /pdbstripped 옵션 : 추가적인 .PDB 파일을 생성하도록 한다그 내용은 다음의 내용으로 제한된다.

 

n  public function  variables

n  FPO 정보

 

주목할 점은 COFF CodeView 포맷은 더 이상 링커에 의해 지원되지 않는다.

 

6. Debug information for static libraries (정적 라이브러리를 위한 디버그 정보)

정적 라이브러리를 위한 디버그 정보를 만드는 프로세스는 실행파일보다 좀 더 단순하다그 이유는 링크 단계가 없기 때문이다컴파일러 버전과는 상관없이컴파일러가 정적 라이브러리를 위한 디버그 정보를 생성할지는 /Z* 옵션들(/Zd, /Z7, /Zi, /ZI) 중 하나를 사용할 수 있다.

 

여기서 한가지 고려해야 할 중요한 점은 디버그 정보가 어디에 저장되느냐 하는 것이다. /Z7이나 /Zd 옵션이 사용될 때디버그 정보는 .LIB 파일에 저장되며, /Zi  /ZI 옵션이 사용되면별도의 .PDB 파일에 저장된다. (파일 이름은 /Fd 옵션에서 명시)

 

7. Debug information and size of the executable (실행 파일의 디버그 정보와 사이즈)

실행파일을 위한 디버그 정보를 생성한다면실행 파일의 사이즈는 어떤 영향을 받을까?

그 대답은 디버그 정보를 저장하는 장소에 따라 다르며그 다음은 디버그 정보 포맷에 따라 다르다.

 

보통 COFF  CodeView 포맷을 사용하면디버그 정보는 실행 파일에 저장된다이 경우엔 실행 파일의 사이즈는 상당히 증가한다. (디버그 정보를 갖는 실행파일은 디버그 정보가 없는 실행파일보다 2배 이상 커진다.)

 

Program Database 포맷이 사용되면디버그 정보는 별도의 파일에 저장된다이 때 실행 파일의 사이즈는 거의 영향을 받지 않는다단지 몇 백 bytes 증가할 뿐이다그 이유는 디버그 정보를 갖는 파일의 위치를 디버거에게 알려주기 위한 작은 헤더만을 실행파일에 추가로 포함시킨다.

 

여기서 실행파일의 불필요한 팽창을 피할 필요가 있다.

/debug 링커 옵션을 사용하면 부작용이 생기는데디폴트 /opt:ref 옵션을 /opt:noref 옵션으로 변경한다는 것이다그 결과 디버그 정보 생성을 활성화하면 링커에 의해 수행되는 사이즈 최적화가 비활성화 된다그래서 사이즈 최적화를 다시 활성화시키려면, /opt:ref 옵션을 명시적으로 활성화시켜야 한다.

 

8. .DBG files

CodeView 포맷을 사용하면링커는 항상 실행파일에 디버그 정보를 저장한다그러나 Rebase라 불리는 팁을 사용하면디버그 정보를 별도의 .DBG 파일에 저장할 수 있다.

 

Rebase Visual Studio에 포함되어 있으며다양한 목적으로 사용된다그러나 디버그 정보를 추출하는데 사용되는 명령어는 아주 간단하다.

 

rebase –b BaseAddr –x SymbolDir [-p] ExeName

Option

Description

-b BaseAddr

Specifies the new base address of the executable. If you do not want to change the base address, specify the same address as the one currently used by the executable.

-x SymbolDir

Specifies the directory where the .DBG file will be stored. It is also possible to specify . (dot), which means the current directory.

-p

If this option is used, the .DBG file will contain only the following kinds of debug information:

  • public functions and variables
  • FPO information

Other kinds of debug information are discarded.

예를 들어다음 명령어는 DLL로부터 디버그 정보를 추출해서 현재 디렉토리의 .DBG 파일에 저장한다.

rebase –b 0x60000000 –x . MyDll.dll

 

9. Debuggers and debug information formats (디버거 및 디버그 정보 포맷)

응용프로그램에서 특정한 디버그 정보 포맷을 사용해야 할 때현재 사용하는 디버거가 그것을 이해할 수 있어야 한다다음 테이블은 가장 인기 있는 디버거와 지원하는 디버거 정보 포맷을 보여준다.

Debugger

COFF

CodeView

Program Database (2.0)

Program Database (7.0)

Visual Studio 2002, 2003, 2005

-

+

+

+

Visual C++ 6.0

+

+

+

-

WinDbg 6.3

+

Partial

+

+

WinDbg 6.3 디버거는 CodeView 포맷을 부분적으로만 지원한다단지 다음의 디버그 정보만을 읽을 수 있을 뿐이다.

-       public function and variables

-       FOP information

-       source files and lines

 

그래서 소스 코드를 단계화시키고 콜 스택을 볼 수 있지만타입 정보가 없기 때문에 변수의 값을 볼 수는 없다.

 

10. Operation system symbols (운영체제 심볼)

다음 표는 Windows 운영체제 컴포넌트의 심볼 파일에서 사용가능한 디버그 정보 포맷 리스트이다.

Operating system

Format

Windows NT 4.0

CodeView (.DBG files)

Windows 2000

CodeView (.DBG files) and Program Database (2.0)

Windows XP (including SP1 and SP1a)

Program Database (2.0)

Windows XP SP2

Program Database (7.0)

Windows 2003 Server

Program Database (2.0)

 

 

 

 

<출처>

http://www.debuginfo.com/articles/gendebuginfo.html#kindsofdebuginfo