누구든지 gdb의이 동작을 설명 할 수 있습니까?
900 memset(&new_ckpt_info,'\0',sizeof(CKPT_INFO));
(gdb)
**903 prev_offset = cp_node->offset;**
(gdb)
**905 m_CPND_CKPTINFO_READ(ckpt_info,(char *)cb->shm_addr.ckpt_addr+sizeof(CKPT_** HDR),i_offset);
(gdb)
**903 prev_offset = cp_node->offset;**
(gdb)
**905 m_CPND_CKPTINFO_READ(ckpt_info,(char *)cb->shm_addr.ckpt_addr+sizeof(CKPT_ HDR),i_offset);**
(gdb)
**908 bitmap_offset = client_hdl/32;**
(gdb)
**910 bitmap_value = cpnd_client_bitmap_set(client_hdl%32);**
(gdb)
**908 bitmap_offset = client_hdl/32;**
(gdb)
**910 bitmap_value = cpnd_client_bitmap_set(client_hdl%32);**
(gdb)
**908 bitmap_offset = client_hdl/32;**
(gdb)
**910 bitmap_value = cpnd_client_bitmap_set(client_hdl%32);**
(gdb)
913 found = cpnd_find_exact_ckptinfo(cb , &ckpt_info , bitmap_offset , &offset , &prev_offset);
(gdb)
916 if(!found)
(gdb) p found
$1 = <value optimized out>
(gdb) set found=0
Left operand of assignment is not an lvalue.
903 행을 실행 한 후 905908910에 대해 동일한 작업을 다시 실행하는 이유는 무엇입니까?
또 다른 물건은 found
A는 bool
, 타입 변수 왜 그것을 보여주고있다 value optimized out
? 의 값도 설정할 수 없습니다 found
.
이것은 컴파일러 최적화 인 것 같습니다 (이 경우에는 -O2
). 여전히 값을 found
어떻게 설정할 수 있습니까?
답변
최적화 된 코드를 디버깅하려면 어셈블리 / 기계 언어를 배우십시오.
GDB TUI 모드를 사용하십시오. 마이너스와 Enter를 입력하면 GDB 사본이 활성화됩니다. 그런 다음 Cx 2를 입력합니다 (즉, Control을 누른 상태에서 X를 누른 다음 둘 다 놓은 다음 2를 누릅니다). 그러면 분할 소스 및 디스 어셈블리 디스플레이가됩니다. 그런 다음 및를 사용 stepi
하여 nexti
한 번에 하나의 기계 명령을 이동하십시오. Cx o를 사용하여 TUI 창 사이를 전환합니다.
CPU의 기계어 및 함수 호출 규칙에 대한 PDF를 다운로드하십시오. 함수 인수 및 반환 값으로 수행되는 작업을 빠르게 인식하는 방법을 배우게됩니다.
다음과 같은 GDB 명령을 사용하여 레지스터 값을 표시 할 수 있습니다. p $eax
답변
최적화없이 재 컴파일합니다 (gcc의 -O0).
답변
발견 된 것을 “휘발성”으로 선언하십시오 . 이것은 컴파일러에게 최적화하지 않도록 지시해야합니다.
volatile int found = 0;
답변
컴파일러는 최적화가 켜져있는 상태에서 매우 영리한 작업을 시작합니다. 디버거는 변수가 레지스터에 저장되는 최적화 된 방식으로 인해 앞뒤로 점프하는 코드를 많이 보여줍니다. 이것이 디버거가 액세스 할 수있는 직접 메모리 위치가 아닌 레지스터간에 영리하게 분산되어 있기 때문에 변수를 설정할 수없는 (또는 경우에 따라 값을 볼 수없는) 이유 일 것입니다.
최적화없이 컴파일 하시겠습니까?
답변
일반적으로 이와 같이 계산 된 직후 분기에서 사용되는 부울 값은 실제로 변수에 저장되지 않습니다. 대신 컴파일러 는 이전 비교에서 설정된 조건 코드에서 직접 분기합니다 . 예를 들면
int a = SomeFunction();
bool result = --a >= 0; // use subtraction as example computation
if ( result )
{
foo();
}
else
{
bar();
}
return;
일반적으로 다음과 같이 컴파일됩니다.
call .SomeFunction ; calls to SomeFunction(), which stores its return value in eax
sub eax, 1 ; subtract 1 from eax and store in eax, set S (sign) flag if result is negative
jl ELSEBLOCK ; GOTO label "ELSEBLOCK" if S flag is set
call .foo ; this is the "if" black, call foo()
j FINISH ; GOTO FINISH; skip over the "else" block
ELSEBLOCK: ; label this location to the assembler
call .bar
FINISH: ; both paths end up here
ret ; return
“bool”이 실제로 어디에도 저장되지 않는지 확인하십시오.
답변
당신은 발견의 가치를 거의 설정할 수 없습니다. 최적화 된 프로그램을 디버깅하는 것은 문제의 가치가 거의 없습니다. 컴파일러는 소스 코드와 일치하지 않는 방식으로 코드를 재 배열 할 수 있습니다 (동일한 결과를 생성하는 것 제외). 따라서 디버거를 끝까지 혼란스럽게 만들 수 있습니다.
답변
최적화 된 프로그램을 디버깅 할 때 (버그가 디버그 빌드에 나타나지 않는 경우 필요할 수 있음) 종종 생성 된 어셈블리 컴파일러를 이해해야합니다.
귀하의 특별한 경우,의 반환 값은 반환 값 cpnd_find_exact_ckptinfo
을 위해 플랫폼에서 사용되는 레지스터에 저장됩니다. 에 ix86
, 그 것이다 %eax
. On x86_64
: %rax
, etc. 위의 경우에 해당하지 않는 경우 ‘[귀하의 프로세서] 프로 시저 호출 규칙’을 Google에 표시해야 할 수 있습니다.
해당 레지스터를 검사하고 GDB
설정할 수 있습니다. 예 ix86
:
(gdb) p $eax
(gdb) set $eax = 0