[c] GDB가 줄 사이를 예측할 수없이 점프하고 변수를 “<value optimize out>”으로 출력하는 이유는 무엇입니까?

누구든지 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에 대해 동일한 작업을 다시 실행하는 이유는 무엇입니까?

또 다른 물건은 foundA는 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