반응형

Calling Convention

콜링컨벤션
스택을 이용하여 파라미터를 전달할 때 파라미터를 스택에 넣는 순서와 전달된 파라미터를 어느곳에서 해제할 것인지 등을 결정하는 방식

) __cdecl

C 또는 C++프로그램에서 파라미터 전달시 디폴트로 사용하는 방식으로 이 방식에 의한 파라미터 전달은 오른쪽에서 왼족 방향으로 이루어지게 되며 프로시저를 호출한 쪽에서 파라미터에 대한 해제를 책임진다.


main()

{

           Sum(1, 2);

}

 

 

int Sum( int a, int b )

{

           return a+b;

}

Main:

           push    2

           push    1

           call       sum

           add      esp, 8

 

Sum:

           push    ebp ( 이전 프로시저의 ebp값을 저장 )

           mov     ebp, esp( 이전 프로시저의 ebp값을, push한 시점의 esp를 현재 스택 프레임의 ebp로 설정)

           mov     eax, dword ptr[ebp+0x8]

           add      eax, dword ptr[ebp+0xc]

           pop      ebp

           ret

) __stdcall
Windows API의 프로시저에서 사용하는 방식으로 파라미터 전달은 __cdecl방식과 같이 오른쪽에서 왼쪽방향으로 스택에 저장하게 되지만 파라미터의 해제는 프로시저가 복귀되기 전에 이루어 진다.

main()

{

           Sum(1, 2);

}

 

int Sum( int a, int b )

{

           return a+b;

}

Main:

           push    2

           push    1

           call       sum

 

Sum:

           push    ebp

           mov     ebp, esp

           mov     eax, dword ptr[ebp+0x8]

           add      eax, dword ptr[ebp+0xc]

           pop      ebp

           ret       8

장점

- 함수의 독립성이 뛰어남. 즉 프로시저를 부르기 전에 스택에 파라미터를 쌓아놓고 그 프로시저를 부르기만 하면 그 함수가 리턴되어진 후에는 그 프로시저의 스택포인터(esp)가 이전 상태로 복원되어 있으므로, 복귀된 후에 호출한 프로시저에 대하여 더 이상 신경을 쓰지 않아도 된다.

- 스택을 해제하는 코드가 호출한 프로시저 안에 있으므로 만약 이 프로시저가 여러곳에서 호출된다 하더라도 스택을 해제하는 코드는 프로시저 내에 하나만 존재하므로, 결국 __cdecl 방식에 비해 코드의 크기가 줄어든다.

) __fastcall

__fastcall 방식에서는 처음 두개의 파라미터는 스택을 이용하지않고 ecx edx 레지스터를 사용하며 그 이상의 파라미터에 대해서만 오른쪽에서 왼쪽 방향으로 스택에 저장하게 된다. 이 방식에서의 스택 제거는 __stdcall과 동일하다

) 정리

Calling Convention

파라미터 전달

스택메모리 제거

__cdecl

오른쪽에서 왼쪽 방향으로 스택에 저장

호출한 쪽에서 처리

__stdcall

오른쪽에서 왼쪽 방향으로 스택에 저장

호출 당한 쪽에서 처리

__fastcall

처음 두개의 파라미터는 ecx edx 레지스터에 저장, 그 이상의 파라미터는 오른쪽에서 왼쪽 방향으로 스택에 저장

호출 당한 쪽에서 처리

 

 

 

반응형
반응형


이 그림을 이해하는 것만으로도 (물론 대부분의 경우 디버거가 해주겠지만) 디버거의 도움을 받지 않더라도 함수 호출관계, 파라미터, 변수 등에 대한 많은 부가 정보를 읽을 수 있습니다.

프로그램 경력이 미천할 때( 지금도 마찬가지 입니다만…) 드라이버 개발자 분께서 어셈코드를 보고, 파라미터가 몇 개인 함수고,,, 인자가 어쩌고~ 하시면서 분석하는 과정을 경이롭게 지켜보았던 적이 있었는데… calling convention stack frame의 구성에 대한 이해가 수반된다면 얼추 흉내는 낼 수 있을거 같습니다. .

 
2011/07/25 - [디버깅] - Stack Frame구성 - Stack Overflow

2011/07/18 - [디버깅] - [디버깅을 위한 기초지식 #4] Calling Convention

반응형
반응형

8086 명령어

 

 

 

 

 

ADD

Signed or Unsigned ADD

원천 오퍼랜드를 목적지 오퍼랜드에 더하고 그 결과를 목적지 오퍼랜드에 저장한다

AND

Logical AND

두 오퍼랜드에 대해 논리 AND를 수행하여 그 결과를 목적지 오퍼랜드에 저장한다

CALL

Call a Procedure

제어를 프로시져로 넘긴다. RET를 사용하여 제어를 CALL 다음의 명령어로 되돌린다

CMP

Compare Operands

길이가 같은 두 오퍼랜드를 비교한다. 원천 및 목적지 오퍼랜드는 변경되지 않는다

CMPS

Compare Byte or Word String

스트링을 한번에 한 바이트 또는 한 워드씩 비교한다

CMPSB

Compare Byte or Word String

스트링을 한번에 한 바이트 또는 한 워드씩 비교한다

CMPSW

Compare Byte or Word String

스트링을 한번에 한 바이트 또는 한 워드씩 비교한다

DEC

Decrement

목적지 오퍼랜드에서 1을 뺀다

DIV

Unsigned Division

부호없는 워드(AX)를 바이트로 나누거나 부호없는 더블워드(DX:AX)를 워드로 나눈다

IDIV

Signed Number Division

부호있는 워드(AX)를 바이트로 나누거나 부호있는 더블워드(DX:AX)를 워드로 나눈다

IMUL

Signed Number Multiplication

부호있는 바이트 또는 워드 원천 오퍼랜드를 AL 또는 AX에 있는 부호있는 바이트 또는 워드에 곱하여 그 결과를 AX 또는 DX:AX에 저장한다

INC

Increment

오퍼랜드에 의해 지정된 레지스터 또는 메모리 위치에 1을 더한다.

INT

Intettupt

실행을 256가지의 인터럽트중의 하나로 넘긴다

JUMP

Conditional Jump

어떤 조건이 만족되면 행선지 번지로 점프하도록 하는데 사용한다.

JMP

Unconditional Jump

새로운 번지로 제어를 무조건 넘기는데 사용한다. JMP CALL의 차이는, CALL 명령어는 CALL 다음의 명령어로 되돌아와 실행을 계속하는 반면 JMP는 되돌아오지 않는다

LEA

Load Effective Address

직접 메모리 오퍼랜드의 유효 번지를 목적지에 로드한다

LOCK

Lock System Bus Prefix

2개 이상의 프로세서가 있는 마이크로컴퓨터에서 한 프로세서가 명령어를 실행하고 있는 동안 다른 프로세서가 시스템 버스의 제어권을 빼앗지 못하도록 하기 위해 사용된다

LOOP

Loop until CX =0

CX 1 감소시킨 다음 CX가 아니면 오퍼랜드가 가리키는 곳으로 점프하며, 0일 경우에는 LOOP아래에 있는 다음 명령어를 실행 시킨다

MOV

Move

레지스터, 메모리 위치, 즉석 상수인 워드 또는 바이트를 레지스터 또는 메모리 위치에 복사한다.

MOVS

Move Byte or Word String

 

DS : SI가 가리키는 메모리의 위치로부터 바이트 또는 워드를 ES : DI가 가리키는 메모리 위치로 복사한다.

MOVSB

Move Byte or Word String

DS : SI가 가리키는 메모리의 위치로부터 바이트 또는 워드를 ES : DI가 가리키는 메모리 위치로 복사한다.

MOVSW

Move Byte or Word String

DS : SI가 가리키는 메모리의 위치로부터 바이트 또는 워드를 ES : DI가 가리키는 메모리 위치로 복사한다.

MUL

Unsigned Multiplication

오퍼랜드가 가리키는 부호 없는 바이트 또는 워드를 AL 또는 AX에 들어있는 바이트 또는 워드에 곱한 결과를 AX 또는 DX : AX 에 저장한다

NEG

Negate

오퍼랜드에 대해 2의 보수를 취한다

NOP

No Operation

아무 일도 수행하지 않는다

NOT

Logical NOT

오퍼랜드에 대해 1의 보수를 취한다

OR

Logical OR

두 오퍼랜드에 대해 비트끼리 논리 OR 연산을 수행하고 그 결과를 목적지 오퍼랜드에 저장한다

POP

POP Word

스택포인터가 가리키는 워드를 오퍼랜드가 가리키는 레지스터 메모리위치로 복사하고 SP 2 증가 시킨다

POPF

POP Flags off Stack

스택에 PUSH시켜 놓았던 비트를 플래그 레지스터로 복사한 다음에 SP2 증가 시킨다

PUSH

PUSH Word

스택에 원천 오퍼랜드의 워드를 복사하고 SP 2 감소시킨다

PUSHF

PUSH Flags onto Stack

SP 2 감소시킨 다음에 플래그 레지스터의 내용을 스택에 복사한다

RET

Return from a Procedure

앞서 CALL 명령어에 의해 호출되었던 피호출 프로시저로부터 호출프로시저로 복귀하는데 사용된다.

SHL

Shift Left

부호 없는 수에 사용되는 논리쉬프트로써 부호 비트도 데이터로 취급한다.

SHR

Shift Right

부호 없는 수에 사용되는 논리쉬프트로써 부호 비트도 데이터로 취급한다.

STOS

Store Byte or Word String

: AX, AL의 내용을 ES:DI가 가리키는 위치에 복사하고, DI 1또는 2 증가시킨다

STOSB

Store Byte or Word String

: AX, AL의 내용을 ES:DI가 가리키는 위치에 복사하고, DI 1또는 2 증가시킨다

STOSW

Store Byte or Word String

: AX, AL의 내용을 ES:DI가 가리키는 위치에 복사하고, DI 1또는 2 증가시킨다

SUB

Subtract

목적지 오퍼랜드로부터 원천 오퍼랜드를 빼서 그 결과를 목적지에 저장한다

TEST

Test Bits

두 오퍼랜드에 대해 논리 AND를 수행하고 플래그를 설정하지만 두 오퍼랜드의 내용은 변하지 않는다.

XCHG

Exchange

두 레지스터 또는 레지스터와 메모리 위치의 내용을 교환한다

XOR

Exclusive OR

두 오퍼랜드의 비트들에 대해 논리 XOR를 수행하여 그 결과를 목적지 오퍼랜드에 저장한다.

 

반응형
반응형

CPU 레지스터(8086)의 종류와 용도

Windows 구조와 원리(정덕영 저)

어셈 코드를 디버깅할 때, asm명령과 레지스터 몇가지만 알고 있어도 많은 도움이 됩니다.
이번 포스트에서는 x86 CPU레지스터에 대해 정리합니다.

범용 레지스터( General Register )

범용 레지스터는 연산 결과를 받을 수도 있으며, 연산에 사용되어질 수도 있는 레지스터로 과거 8bit컴퓨터에서는 연산 결과를 저장하기 위하여 특정 레지스터를 사용할 수 밖에 없었으나 8086에서는 범용 레지스터를 사용하여 모든 연산을 수행 할 수 있다

AX( AH, AL )

Accumulator Register

산술, 놀리 연산의 중심이 되는 레지스터이며, Input/Output 포트의 입출력 명령 또한 주로 이 레지스터를 사용한다.

BX( BH, BL )

Base Register

간접 번지 지정 시 번지 레지스터. 베이스 레지스터로 주로 사용된다

CX( CH, CL )

Count Register

루프와 같이 어떤 명령을 반복적으로 수행하고자 할 때 반복 횟수를 지정하는데 주로 사용된다

DX( DH, DL )

Data Register

간접 번지 지정에 의한 입출력 명령을 실행 할 때 번지 지정에 사용된다. 곱셈, 나눗셈을 할 때는 보조 어큐뮬레이터로 사용되이 지기도 한다.

포인터 레지스터

SP

Stack Pointer

현재까지 사용되어진 스택의 위치를 저장하기 위하여 사용되는 레지스터로 세그먼트 레지스터 SS와 함께 사용된다.

BP

Base Pointer

스택의 데이터를 액세스 하기 위해 사용된다.

인덱스 레지스터

SI, DI

Source Index

다른 범용 레지스터와 마찬가지로 연산과 간접 번지 지정에 사용된다. 그 밖에 문자열의 전송이나 비교 등을 하는 스트링 명령에서 SI source가 되는 문자열을 나타내고, DI destination이 되는 문자열의 번지를 표시하는데 쓰인다.

IP( 명령 포인터 )

IP

Instruction Pointer

이 레지스터는 언제나 다음에 실행할 명령이 들어 있는 메모리의 번지를 가리킨다. CS 세그먼트 레지스터와 한 쌍이 되어 실행 번지가 만들어 진다.

플래그 레지스터

8086에는 16비트로 된 플래그 레지스터가 준비되어 있다. 연산의 결과 및 시스템 제어를 위한 정보가 각각 배정되어 있다.

상태 플래그

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

O

D

I

T

S

Z

A

P

C

Flags

Status Flags

CF

Carry Flag

연산 명령 실행 후 최상위 비트(MSB)에 덧셈에 따른 자리올림(carry) 또는 뺄셈에 의한 빌림(borrow)이 생길 때 설정된다.

PF

Parity Flag

연산의 결과 하위 8비트 중에서 1로 되어 있는 비트의 개수가 짝수 개일 때 셋(1)되고, 홀수 개일 때는 리셋(0)된다.

AF

Auxiliary Flag

연산의 결과 하위 4비트에 자리올림 또는 빌림이 TODRURT을 경우 설정된다. 10진 연산 처리를 할 경우에 이용된다.

ZF

Zero Flag

연산 결과가 0이 될 때 설정된다. 비교 명령 등도 레지스터의 내용은 변경시키지 않지만 뺄셈이 이루어지므로 그 결과에 따라서 설정된다.

SF

Sing Flag

연산 결과 최상위 비트가 1일 때 설정되고, 0일 때 리셋된다. 부호가 있는 수치의 경우에는 최상위 비트(MSB) 1이면 음수를 표시한다.

OF

Overflow Flag

부호 연산 처리의 결과 부호부 2진 표시로 오버플로우가 생겼을 때 설정된다. 바이트 연산에서는 -128~+128, 워드 연산에서는 -32768~+32767의 범위를 초과했다는 것을 표시한다.

컨트롤 플래그

Flags

Status Flags

DF

Direction Flag

스트링 처리에서 연속하여 처리되는 문자열에 대해서 그 처리 방향을 표시한다. 스트링 명열의 실행에 앞서서 이 플래그를 설정도는 리셋하여 처리 방향을 정해 둔다. , DF 플래그가 0일 때에는 하위 번지로부터 상위 번지 쪽으로 처리되며, DF 플래그가 1일 때에는 상위 번지로부터 하위 번지 쪽으로 처리된다.

IF

Interrupt Flag

8086의 인터럽트 중에서 하드웨어로부터의 인터럽트에 관하여 제어를 한다. IF 플래그가 1일 때에는 인터럽트를 받아들이고, 0일 때에는 인터럽트를 받아들이지 않는다.

TF

Trap Flag

명령 실행 후 이 플래그가 세트되어 있으면 단일 스텝 인터럽트가 발생한다. 이 기능을 사용하면 하드웨어의 도움을 받을 필요 없이 프로그램을 한 명령씩 실행 시켜 동작을 확인할 수 있다.

세그먼트 레지스터

프로그램이 수행되기 위해서는 여러 가지 메모리 주소가 필요하다. 우선 현재 수행되고 있는 명령어의 위치를 나타내는 값, 프로그램이 사용하는 데이터가 있는 메모리 값, 그리고 함수 호출등을 휘한 스택의 위치를 나타내는 값 emddlekk.

8086은 어드레스 버스가 20비트로 구성되어 있어서 1MByte까지 메모리 번지를 나타낼 수 있으나 8086에 있는 레지스터는 16비트 밖에 되지 않아서 어떤 명령이 수행되어 메모리를 참조할 때에는 항상 다음과 같이 암시적 또는 명시적으로 세그먼트 레지스터가 개입된다.

세그먼트

오프셋

목적

CS( Code Segment )

IP

수행되어질 명령어의 위치

DS( Data Segment )

AX, BX, CX, DX와 같은 범용레지스터와 BX, DI,SI

데이터 주소 참조

SS( Stack Segment )

SP 또는 BP

스택 주소 참조

ES( E Segment )

스트링 명령어를 위한 DI

스트링 목적지 주소

 

반응형
반응형

이 카타고리에서는 WinDbg를 이용한 실제 디버깅 방법에 대해 다룰 계획이다.

 

그렇다면 내가 WinDbg를 잘 다루는가?

 

~얼대 아니다.

 

이제 겨우 WinDbg 커맨드에 대해 공부하고 있는 입장이니, 병아리라 봐야겠지.

 

그래도 해야하고, 또 재미를 느낄 수 있으니 하나하나 습득해 가는 지식들을 채워갈 요량이다.

 

우선, WinDbg카타고리에는 맞지 않을지 모르나,

 

내가 WinDbg 사용방법을 익히는 첫번째 이유가 드라이버 디버깅이기 때문에,

 

디버깅에 필요한 선수 지식부터 정리할 생각이다.

 

순서 대로 가자면, WinDbg 설치, 디버거 셋팅 등등이 선행되야겠지만,

 

지금 보고 있는 부분이 어셈블리 코드를 통한 디버깅, 콜스택 백 트레이싱, 덤프 분석 부분이기 때문에

 

이 과정에서 필요한 선수 지식에 대해 먼저 다룬다.

 

드라이버 하는 사람들에게는 기본인지 모르겠으나,

 

난 아직 기본이 안되서 인지, 맨땅에 헤딩이니 이해되는 부분부터 살살 정리 할란다.

 

... CPU레지스터, 스택 등등에 대한 내용이 되지 않을까 싶다.

 

생각보다 먼~나라 이야기만은 아닌거 같다.

 

 

반응형
반응형

ba(break on access)

 

ba 커맨드에 대해 설명하기 전에 한가지 재미있는(?혹은 식상할 수도) 코드를 보여드리려 합니다.

이 프로그램은 두 개의 전역변수를 가지고 있고, PrintGlobalVariable() 함수를 통해 두개의 전역변수를 출력합니다.

프로그램이 간단하니 어렵지 않게 출력 결과를 유추하실 수 있겠죠?

char g_szTitle[32] = "TestApp - User";

DWORD g_dwPort = 8080;

 

void PrintGlobalVariable();

 

int _tmain(int argc, _TCHAR* argv[])

{

             PrintGlobalVariable();

             strcpy(g_szTitle, "TestApp - GOODSMELL's COMPUTER!!!!");

             PrintGlobalVariable();

            

             return 0;

}

 

void PrintGlobalVariable()

{

             printf("g_szTitle = %s, g_dwPort  = %d\n", g_szTitle, g_dwPort);

}

 

예상하신 결과가 맞나요??

 

위의 프로그램은 아주 예전에 발생했던 문제를 간소화 해서 코딩한 것입니다.

프로그램의 타이틀은 [AppName + Remote컴퓨터명 + etc…] 형태로 되어있고, 지정된 포트를 통해 다른 컴퓨터에 접속하는 프로그램이었습니다만, 특정 컴퓨터(항상 이게 문제죠…!)에서 접속을 2회 이상시도하게 되면 접속이 되지 않는 문제 였습니다.

 

위 프로그램의 출력결과는 아래와 같습니다.


두번째 출력전에 한것이라곤 g_szTitle에 문자열을 복사한 것 뿐인데, 포트 값이 바뀌어 있네요..

이제 어느정도 감이 오시죠?

 

문제를 좀더 명확히 하기 위해 다음 한 줄의 코딩을 추가했습니다.

printf("g_szTitle address = %p, g_dwPort address = %p\n", g_szTitle, &g_dwPort);

 

출력 결과는 다음과 같습니다.


이제 문제가 명확해 졌군요.
g_szTitleg_dwPort는 다른 변수이지만 할당된 메모리 공간이 인접해 있습니다.

0x002B7058 – 0x002B7038 = 0x20(32) ,g_szTitle이 할당된 메모리(32byte)에 연속해서 g_dwPort(4byte)가 할당되어 있습니다. strcpy()함수 호출을 통해 35byte(g_szTitle:32byte)의 메모리를 변경했기때문에 g_dwPort 3byte를 덮어써 버린것이죠.  

g_szTitle(32bytes)

0x002B7038

g_dwPort(4bytes)

0x002B7058

 

 

 

 

 


위와 같은 문제가 아주 덩치가 큰 프로그램에서 발생한다고 하면, 사실 좀 난감합니다. 일단 어찌 어찌해서 g_dwPort가 변경되는 것 까지는 확인했다고 치겠습니다.

 

이 상황에서 ba 커맨드는 아주 유용합니다.

ba 커맨드의 사용포맷은 이렇습니다.(Access Size 는 붙여서 씁니다)

ba Access Size Address

n  Access

ü  e – excute(설정된 Address가 실행될 때 적중)

ü  r – read/write(설정된 AddressSize만큼 read or write 가 발생할때 적중)

ü  w - write(설정된 AddressSize만큼 write 가 발생할때 적중)

ü  I - io(설정된 Address io가 발생할때 적중) - widbg설명을 보니 port address등에 bp를 걸어 사용하면 되는듯 합니다만, 전 거의 그럴일이 없으니 pass~

n  Size

ü r/w - 1,2 or 4 (x86), 1,2,4 or 8 (x64)

ü 1e - 1

n  Address

ü  Memory 주소

 

자 그럼 위에서 하던 얘기를 마저 하겠습니다. 지금 상황에서는 다음과 같은 커맨드이면 될 것 같습니다.

ba w1 TestApp!g_dwPort

 

그럼 한 단계씩 디버깅해 보겠습니다.

n  [File>Open Excutable]메뉴를 이용해 TestApp.exe를 실행한후 wmail()함수에 breakpoint를 설정합니다. 

n  Wmain() breakpoint가 적중되면, g_dwPort ba커맨드로 breakpoint를 설정합니다.
계속 진행시키면 strcat+0xcd에서 breakpoint가 적중되었군요
.
strcpy
가 내부적으로 strcat을 호출하는가 봅니다.

 

n  그럼 이 시점에서의 CallStack strcat의 인자를 확인해 보겠습니다.
wmain
에서 호출된 strcat(strcpy)에 의해서 g_dwPort값이 변경되는 것을 알 수 있습니다
.
인자를 출력해 보니 역시나, g_szTitle에 복사하려던 문자열이네요.

 

ba 커맨드는 의외로 유용하게 사용 할 상황이 많이 있습니다. 저도 두번인가? 정말 유용하게 써먹었던 기억이 있습니다.^^
(아 그리고 string카피할때는 strncpy나 strcpy_s류의 함수를 쓰는게 좋은 습관인건 아시죠?)

 

 

 

아래는 ba관련 windbg도움말 입니다. 참고하세요.

ba (Break on Access)

The ba command sets a data breakpoint. This breakpoint is triggered when the specified memory is accessed.

Syntax

User-Mode

[~Thread] ba[ID] Access Size [Options] [Address [Passes]] ["CommandString"]

Kernel-Mode

ba[ID] Access Size [Options] [Address [Passes]] ["CommandString"]

Parameters

Thread
Specifies the thread that the breakpoint applies to. For more information about syntax, see Thread Syntax. You can specify threads only in user mode.
ID
Specifies an optional number that identifies the breakpoint. If you do not specify ID, the first available breakpoint number is used. You cannot add space between ba and the ID number. Each processor supports only a limited number of data breakpoints, but there is no restriction on the value of the ID number. If you enclose ID in square brackets ([]), ID can include any expression. For more information about the syntax, see Numerical Expression Syntax.
Access
Specifies the type of access that satisfies the breakpoint. This parameter can be one of the following values.
Option Action
e (execute) Breaks into the debugger when the CPU retrieves an instruction from the specified address.
r (read/write) Breaks into the debugger when the CPU reads or writes at the specified address.
w (write) Breaks into the debugger when the CPU writes at the specified address.
i (i/o) (Microsoft Windows XP and later versions, kernel mode only, x86-based systems only) Breaks into the debugger when the I/O port at the specified Address is accessed.

You cannot add space between Access and Size.

Note On Windows Server 2003 with Service Pack 1 (SP1), on an Itanium-based computer that uses WOW64 to emulate x86, data breakpoints do not work with the execute option but they do work with the read and write options.

Size
Specifies the size of the location, in bytes, to monitor for access. On an x86-based processor, this parameter can be 1, 2, or 4. However, if Access equals e, Size must be 1.

On an x64-based processor, this parameter can be 1, 2, 4, or 8. However, if Access equals e, Size must be 1.

On an Itanium-based processor, this parameter can be any power of 2, from 1 to 0x80000000.

You cannot add space between Access and Size.

Options
Specifies breakpoint options. You can use any number of the following options, except as indicated:
/1
Creates a "one-shot" breakpoint. After this breakpoint is triggered, the breakpoint is permanently removed from the breakpoint list.
/f PredNum
(Itanium only, user mode only) Specifies a predicate number. The breakpoint is predicated with the corresponding predicate register (for example, bp /f 4 address sets a breakpoint that is predicated with the p4 predicate register). For more information about predicate registers, see Itanium Architecture.
/p EProcess
(Kernel mode only) Specifies a process that is associated with this breakpoint. EProcess should be the actual address of the EPROCESS structure, not the PID. The breakpoint is triggered only if it is encountered in the context of this process.
/t EThread
(Kernel mode only) Specifies a thread that is associated with this breakpoint. EThread should be the actual address of the ETHREAD structure, not the thread ID. The breakpoint is triggered only if it is encountered in the context of this thread. If you use /p EProcess and /t EThread , you can enter them in either order.
/c MaxCallStackDepth
Causes the breakpoint to be active only when the call stack depth is less than MaxCallStackDepth. You cannot combine this option together with /C.
/C MinCallStackDepth
Causes the breakpoint to be active only when the call stack depth is larger than MinCallStackDepth. You cannot combine this option together with /c.
Address
Specifies any valid address. If the application accesses memory at this address, the debugger stops execution and displays the current values of all registers and flags. This address must be an offset and suitably aligned to match the Size parameter. (For example, if Size is 4, Address must be a multiple of 4.) If you omit Address, the current instruction pointer is used. For more information about the syntax, see Address and Address Range Syntax.
Passes
Specifies the number of times the breakpoint is passed by until it activates. This number can be any 16-bit value. The number of times the program counter passes through this point without breaking is one less than the value of this number. Therefore, omitting this number is the same as setting it equal to 1. Note also that this number counts only the times that the application executes past this point. Stepping or tracing past this point does not count. After the full count is reached, you can reset this number only by clearing and resetting the breakpoint.
CommandString
Specifies a list of commands to execute every time that the breakpoint is encountered the specified number of times. These commands are executed only if the breakpoint is hit after you issue a g (Go) command, instead of after a t (Trace) or p (Step) command. Debugger commands in CommandString can include parameters.

You must enclose this command string in quotation marks, and you should separate multiple commands by semicolons. You can use standard C control characters (such as \n and \"). Semicolons that are contained in second-level quotation marks (\") are interpreted as part of the embedded quoted string.

This parameter is optional

Environment

Modes User mode, kernel mode
Targets Live debugging only
Platforms All

Comments

The debugger uses the ID number to refer to the breakpoint in later bc (Breakpoint Clear), bd (Breakpoint Disable), and be (Breakpoint Enable) commands.

Use the bl (Breakpoint List) command to list all existing breakpoints, their ID numbers, and their status.

Use the .bpcmds (Display Breakpoint Commands) command to list all existing breakpoints, their ID numbers, and the commands that were used to create them.

The ba command provides the same functionality that the debug registers provide. You can break execution when the particular memory location is read from, written to, or executed.

The breakpoint is satisfied only when the access occurs at the given address and for the specified number of bytes. If the memory that is accessed overlaps the specified area to monitor, the breakpoint is not satisfied.

Although the size is required for all breakpoint types, an execute breakpoint is satisfied only if the address is the first byte in the instruction.

When you debug a multiprocessor system in kernel mode, breakpoints that you set by using bp (Set Breakpoint) or ba apply to all processors. For example, if the current processor is 3 and you type ba e1 MemoryAddress to put a breakpoint at MemoryAddress, any processor (not only processor 3) that executes at that address causes a breakpoint trap.

You cannot set the initial breakpoint in a user-mode process by using the ba command.

You cannot create multiple breakpoints at the same address that differ only in their CommandString values. However, you can create multiple breakpoints at the same address that have different restrictions (for example, different values of the /p, /t, /c, and /C options).

When you debug in kernel mode, the target computer distinguishes between user-mode and kernel-mode data breakpoints. A user-mode data breakpoint cannot affect kernel execution or memory access. A kernel-mode data breakpoint might affect user-mode execution or memory access, depending on whether the user-mode code is using the debug register state and whether there is a user-mode debugger that is attached.

To apply the current process' existing data breakpoints to a different register context, use the .apply_dbp (Apply Data Breakpoint to Context) command.

The following examples show the ba command. The following command sets a breakpoint for read access on 4 bytes of the variable myVar.

0:000> ba r4 myVar

The following command adds a breakpoint on all serial ports with addresses from 0x3F8 through 0x3FB. This breakpoint is triggered if anything is read or written to these ports.

kd> ba i4 3f8

Additional Information

For more information about and examples of using breakpoints, other breakpoint commands and methods of controlling breakpoints, and information about how to set breakpoints in user space from a kernel debugger, see Using Breakpoints. For more information about conditional breakpoints, see Setting a Conditional Breakpoint.

Build machine: CAPEBUILD
반응형

+ Recent posts