Tại sao GDB nhảy không thể đoán trước giữa các dòng và các biến in là “<giá trị được tối ưu hóa>”?


84

Bất cứ ai có thể giải thích hành vi này của 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.

Tại sao sau khi thực hiện dòng 903, nó lại thực thi tương tự cho 905 908 910?

Điều khác là foundlà một boolbiến kiểu, vậy tại sao nó được hiển thị value optimized out? Tôi cũng không thể đặt giá trị của found.

Đây dường như là một tối ưu hóa trình biên dịch (trong trường hợp này là của nó -O2); làm thế nào tôi vẫn có thể đặt giá trị của found?


8
khi gỡ lỗi, thông thường, bạn nên biên dịch với -O0 vì việc tối ưu hóa dẫn đến loại vấn đề đó.
LiraNuna

Câu trả lời:


115

Để gỡ lỗi mã được tối ưu hóa, hãy tìm hiểu hợp ngữ / ngôn ngữ máy.

Sử dụng chế độ GDB TUI. Bản sao GDB của tôi cho phép nó khi tôi nhập dấu trừ và Enter. Sau đó gõ Cx 2 (đó là giữ Control và nhấn X, thả cả hai và sau đó nhấn 2). Điều đó sẽ đưa nó vào nguồn phân tách và hiển thị tháo rời. Sau đó, sử dụng stepinextidi chuyển một lệnh máy tại một thời điểm. Sử dụng Cx o để chuyển đổi giữa các cửa sổ TUI.

Tải xuống tệp PDF về ngôn ngữ máy của CPU của bạn và các quy ước gọi hàm. Bạn sẽ nhanh chóng học cách nhận ra những gì đang được thực hiện với các đối số hàm và giá trị trả về.

Bạn có thể hiển thị giá trị của một thanh ghi bằng cách sử dụng lệnh GDB như p $eax


Tôi vẫn gặp sự cố "đã tối ưu hóa" và giá trị biến không được hiển thị trong các cửa sổ khác, nhưng, đó là một thông tin tuyệt vời, cảm ơn!
Tom Brito

16
@TomBrito: Tối ưu hóa có nghĩa là biến không có trong bộ nhớ. Nó có thể chỉ nằm trong thanh ghi CPU, có nghĩa là bạn cần đọc quá trình tháo rời và in các giá trị thanh ghi để tìm thấy nó.
Zan Lynx

@Zan Lynx: Tôi không chắc mình đồng ý với phân tích của bạn. Các ký hiệu DWARF có đủ thông tin để trích xuất các giá trị từ các thanh ghi. Có lẽ điều có nghĩa ở đây là trình biên dịch đã xác định rằng biến có thể được loại bỏ một cách an toàn khi thời gian thực thi đạt đến dòng hiện tại. Trong trường hợp đó, bộ lưu trữ nơi biến tồn tại có thể đã được sử dụng lại cho việc khác. Tôi nghĩ bạn đúng rằng điều này thường chỉ xảy ra nếu biến đã được đăng ký.
Ian Ni-Lewis

@ IanNi-Lewis: Tôi không biết bạn đang sử dụng phiên bản DWARF nào nhưng theo kinh nghiệm của tôi, GDB không thể in một biến đã được lưu trữ vào thanh ghi.
Zan Lynx

Tôi chắc rằng bạn đúng. Kinh nghiệm của tôi với DWARF đến từ việc viết trình phân tích cú pháp của riêng tôi, không phải từ việc sử dụng gdb, vì vậy tôi thực sự không biết gdb có khả năng gì.
Ian Ni-Lewis

75

Biên dịch lại mà không cần tối ưu hóa (-O0 trên gcc).


17
Thậm chí -O0 có thể tạo ra mã được tối ưu hóa (đang cố gắng đấu tranh với điều này ngay bây giờ), mặc dù tôi không chắc tại sao.
Chris Gregg

@ChrisGregg Tôi cũng gặp vấn đề tương tự! Bạn đã tìm ra vấn đề là gì chưa?
Paolo M

1
@paolom có ​​vẻ như nó có thể là một vấn đề lớn, vì vậy tôi đã biên dịch với g ++ thay vì mục đích gỡ lỗi, rất tiếc.
Chris Gregg

Thường thì đây không phải là một giải pháp - đặc biệt nếu bạn có một kết xuất cốt lõi từ quá trình sản xuất và / hoặc bạn không thể tái tạo vấn đề trên môi trường phát triển.
smbear

39

Khai báo tìm thấy là "dễ bay hơi". Điều này sẽ thông báo cho trình biên dịch KHÔNG tối ưu hóa nó.

volatile int found = 0;

1
Ngay cả khi tôi khai báo một số biến "dễ bay hơi" trong trình gỡ lỗi gdb, nó cho thấy nó là biến được tối ưu hóa! Còn có cái này nữa không?
M.Rez

11

Trình biên dịch sẽ bắt đầu thực hiện những điều rất thông minh với tính năng tối ưu được bật. Trình gỡ lỗi sẽ hiển thị mã nhảy về phía trước và ngược lại rất nhiều do cách tối ưu hóa các biến được lưu trữ trong thanh ghi. Đây có thể là lý do tại sao bạn không thể đặt biến của mình (hoặc trong một số trường hợp thấy giá trị của nó) vì nó đã được phân phối khéo léo giữa các thanh ghi để tăng tốc độ, thay vì có vị trí bộ nhớ trực tiếp mà trình gỡ lỗi có thể truy cập.

Biên dịch mà không có tối ưu hóa?


6

Thông thường, các giá trị boolean được sử dụng trong các nhánh ngay sau khi chúng được tính toán như vậy sẽ không bao giờ thực sự được lưu trữ trong các biến. Thay vào đó, trình biên dịch chỉ phân nhánh trực tiếp các mã điều kiện đã được đặt từ so sánh trước đó. Ví dụ,

int a = SomeFunction();
bool result = --a >= 0; // use subtraction as example computation
if ( result ) 
{
   foo(); 
}
else
{
   bar();
}
return;

Thường biên dịch thành một cái gì đó như:

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

Lưu ý rằng "bool" không bao giờ thực sự được lưu trữ ở đâu.


4

Bạn khá nhiều không thể đặt giá trị của tìm thấy. Gỡ lỗi các chương trình được tối ưu hóa hiếm khi đáng gặp rắc rối, trình biên dịch có thể sắp xếp lại mã theo những cách mà nó sẽ không tương ứng với mã nguồn (ngoại trừ việc tạo ra cùng một kết quả), do đó gây nhầm lẫn cho các trình gỡ lỗi.


4

Khi gỡ lỗi các chương trình được tối ưu hóa (có thể cần thiết nếu lỗi không hiển thị trong các bản dựng gỡ lỗi), bạn thường phải hiểu trình biên dịch hợp ngữ được tạo.

Trong trường hợp cụ thể của bạn, giá trị trả về của cpnd_find_exact_ckptinfosẽ được lưu trữ trong sổ đăng ký được sử dụng trên nền tảng của bạn cho các giá trị trả về. Vào ix86, đó sẽ là %eax. Bật x86_64:%rax , vv Bạn có thể cần phải google cho '[vi xử lý của bạn] thủ tục gọi hội nghị' nếu nó không có ở trên.

Bạn có thể kiểm tra đăng ký đó GDBvà bạn có thể thiết lập nó. Vd ix86:

(gdb) p $eax
(gdb) set $eax = 0 

0

Tôi đang sử dụng QtCreator với gdb.

Thêm

QMAKE_CXXFLAGS += -O0
QMAKE_CXXFLAGS -= -O1
QMAKE_CXXFLAGS -= -O2
QMAKE_CXXFLAGS -= -O3

Hoạt động tốt cho tôi

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.