GDB - Hướng dẫn nhanh

Trình gỡ lỗi là một chương trình chạy các chương trình khác, cho phép người dùng thực hiện quyền kiểm soát các chương trình này và kiểm tra các biến khi có vấn đề.

GNU Debugger, còn được gọi là gdb, là trình gỡ lỗi phổ biến nhất cho hệ thống UNIX để gỡ lỗi các chương trình C và C ++.

GNU Debugger giúp bạn nhận thông tin về những điều sau:

  • Nếu một kết xuất lõi đã xảy ra, thì câu lệnh hoặc biểu thức nào đã xảy ra chương trình?

  • Nếu xảy ra lỗi khi thực thi một hàm, dòng nào của chương trình chứa lệnh gọi hàm đó và các tham số là gì?

  • Giá trị của các biến chương trình tại một điểm cụ thể trong quá trình thực thi chương trình là gì?

  • Kết quả của một biểu thức cụ thể trong một chương trình là gì?

Cách GDB gỡ lỗi?

GDB cho phép bạn chạy chương trình đến một thời điểm nhất định, sau đó dừng lại và in ra giá trị của một số biến nhất định tại điểm đó, hoặc lướt qua chương trình từng dòng một và in ra giá trị của từng biến sau khi thực hiện từng dòng.

GDB sử dụng một giao diện dòng lệnh đơn giản.

Điểm cần lưu ý

  • Mặc dù GDB có thể giúp bạn tìm ra các lỗi liên quan đến rò rỉ bộ nhớ, nhưng nó không phải là công cụ để phát hiện rò rỉ bộ nhớ.

  • GDB không thể được sử dụng cho các chương trình biên dịch có lỗi và nó không giúp sửa các lỗi đó.

Trước khi tiến hành cài đặt, hãy kiểm tra xem bạn đã cài đặt gdb trên hệ thống Unix của mình chưa bằng cách ra lệnh sau:

$gdb -help

Nếu GDB được cài đặt, thì nó sẽ hiển thị tất cả các tùy chọn có sẵn trong GDB của bạn. Nếu GDB chưa được cài đặt, hãy tiến hành cài đặt mới.

Bạn có thể cài đặt GDB trên hệ thống của mình bằng cách làm theo các bước đơn giản được thảo luận bên dưới.

step 1: Đảm bảo rằng bạn có các điều kiện tiên quyết để cài đặt gdb:

  • Trình biên dịch C tuân thủ ANSI (nên dùng gcc - lưu ý rằng gdb có thể gỡ lỗi mã do các trình biên dịch khác tạo)

  • 115 MB dung lượng đĩa trống được yêu cầu trên phân vùng mà bạn sẽ xây dựng gdb.

  • 20 MB dung lượng đĩa trống được yêu cầu trên phân vùng mà bạn sẽ cài đặt gdb.

  • Chương trình giải nén của GNU, gzip

  • Các make tiện ích - phiên bản GNU được biết là hoạt động mà không có vấn đề gì, những phiên bản khác cũng có thể làm được.

step 2: Tải xuống bản phân phối nguồn gdb từ ftp.gnu.org/gnu/gdb. (Chúng tôi đã sử dụng gdb-6.6.tar.gz cho các hướng dẫn này.) Đặt các tệp phân phối vào thư mục bản dựng của bạn.

step 3:Trong thư mục xây dựng của bạn, hãy giải nén gdb-6.6.tar.gz và giải nén các tệp nguồn từ kho lưu trữ. Sau khi giải nén xong các tệp, hãy thay đổi thư mục làm việc của bạn thành thư mục gdb-6.6 được tạo tự động trong thư mục xây dựng của bạn.

$ build> gzip -d gdb-6.6.tar.gz 
$ build> tar xfv gdb-6.6.tar 
$ build> cd gdb-6.6

step 4: Chạy tập lệnh cấu hình để định cấu hình cây nguồn cho nền tảng của bạn.

$ gdb-6.6> .⁄configure

step 5: Xây dựng gdb bằng cách sử dụng make tiện ích.

$ gdb-6.6> make

step 6: Đăng nhập với quyền root và cài đặt gdb bằng lệnh sau.

$ gdb-6.6> make install

step 7: Nếu được yêu cầu, dung lượng đĩa có thể được lấy lại bằng cách xóa thư mục bản dựng gdb và tệp lưu trữ sau khi cài đặt xong.

$ gdb-6.6> cd .. 
$ build> rm -r gdb-6.6 
$ build> rm gdb-6.6.tar

Bây giờ bạn đã cài đặt gdb trên hệ thống của mình và nó đã sẵn sàng để sử dụng.

A Debugging Symbol Tableánh xạ các hướng dẫn trong chương trình nhị phân đã biên dịch tới biến, hàm hoặc dòng tương ứng của chúng trong mã nguồn. Ánh xạ này có thể là:

  • Chỉ dẫn chương trình ⇒ tên mặt hàng, loại mặt hàng, tệp gốc, số dòng được xác định.

Bảng biểu tượng có thể được nhúng vào chương trình hoặc được lưu trữ dưới dạng tệp riêng biệt. Vì vậy, nếu bạn định gỡ lỗi chương trình của mình, thì bạn phải tạo một bảng biểu tượng mà sẽ có thông tin cần thiết để gỡ lỗi chương trình.

Chúng ta có thể suy ra các dữ kiện sau về bảng ký hiệu:

  • Một bảng ký hiệu hoạt động cho một phiên bản cụ thể của chương trình - nếu chương trình thay đổi, một bảng mới phải được tạo.

  • Các bản dựng gỡ lỗi thường lớn hơn và chậm hơn các bản dựng bán lẻ (không gỡ lỗi); bản dựng gỡ lỗi chứa bảng ký hiệu và thông tin phụ trợ khác.

  • Nếu bạn muốn gỡ lỗi một chương trình nhị phân mà bạn không tự biên dịch, bạn phải lấy các bảng ký hiệu từ tác giả.

Để GDB có thể đọc từng dòng thông tin từ bảng ký hiệu, chúng ta cần biên dịch nó khác một chút. Thông thường, chúng tôi biên dịch các chương trình của mình dưới dạng:

gcc hello.cc -o hello

Thay vì làm điều này, chúng ta cần biên dịch với cờ -g như hình dưới đây:

gcc -g hello.cc -o hello

GDB cung cấp một danh sách lớn các lệnh, tuy nhiên các lệnh sau là những lệnh được sử dụng thường xuyên nhất:

  • b main - Đặt một điểm ngắt ở đầu chương trình

  • b - Đặt một điểm ngắt ở dòng hiện tại

  • b N - Đặt một điểm ngắt tại dòng N

  • b +N - Đặt điểm ngắt N dòng xuống dòng hiện tại

  • b fn - Đặt một điểm ngắt ở đầu hàm "fn"

  • d N - Xóa số điểm ngắt N

  • info break - danh sách các điểm ngắt

  • r - Chạy chương trình cho đến khi một điểm ngắt hoặc lỗi

  • c - Tiếp tục chạy chương trình cho đến điểm ngắt hoặc lỗi tiếp theo

  • f - Chạy cho đến khi chức năng hiện tại kết thúc

  • s - Chạy dòng tiếp theo của chương trình

  • s N - Chạy N dòng tiếp theo của chương trình

  • n - Giống như s, nhưng nó không bước vào các chức năng

  • u N - Chạy cho đến khi bạn nhận được N dòng trước dòng hiện tại

  • p var - In giá trị hiện tại của biến "var"

  • bt - In dấu vết ngăn xếp

  • u - Tăng một cấp độ trong ngăn xếp

  • d - Đi xuống một cấp độ trong ngăn xếp

  • q - Thoát gdb

Bắt đầu: Bắt đầu và Dừng

  • gcc -g myprogram.c

    • Biên dịch myprogram.c với tùy chọn gỡ lỗi (-g). Bạn vẫn nhận được a.out, nhưng nó chứa thông tin gỡ lỗi cho phép bạn sử dụng các biến và tên hàm bên trong GDB, thay vì vị trí bộ nhớ thô (không thú vị).

  • gdb a.out

    • Mở GDB với tệp a.out, nhưng không chạy chương trình. Bạn sẽ thấy một lời nhắc (gdb) - tất cả các ví dụ đều từ lời nhắc này.

  • r

  • r arg1 arg2

  • r <file1

    • Ba cách để chạy “a.out”, đã được tải trước đó. Bạn có thể chạy nó trực tiếp (r), truyền đối số (r arg1 arg2) hoặc nguồn cấp dữ liệu trong một tệp. Bạn thường sẽ đặt các điểm ngắt trước khi chạy.

  • help

  • điểm ngắt h

    • Liệt kê các chủ đề trợ giúp (trợ giúp) hoặc nhận trợ giúp về một chủ đề cụ thể (điểm ngắt h). GDB được ghi chép đầy đủ.

  • q - Thoát GDB

Bước qua Mã

Bước cho phép bạn theo dõi đường dẫn chương trình của mình và truy cập mã bị lỗi hoặc trả về đầu vào không hợp lệ.

  • l

  • l 50

  • tôi là chức năng của tôi

    • Liệt kê 10 dòng mã nguồn cho dòng hiện tại (l), một dòng cụ thể (l 50) hoặc cho một chức năng (l my Chức năng).

  • kế tiếp

    • Chạy chương trình cho đến dòng tiếp theo, sau đó tạm dừng. Nếu dòng hiện tại là một hàm, nó thực thi toàn bộ hàm, sau đó tạm dừng.next rất tốt cho việc xem qua mã của bạn một cách nhanh chóng.

  • bươc

    • Chạy lệnh tiếp theo, không chạy dòng. Nếu lệnh hiện tại đang thiết lập một biến, nó giống nhưnext. Nếu đó là một hàm, nó sẽ nhảy vào hàm, thực hiện câu lệnh đầu tiên, sau đó tạm dừng.step rất tốt cho việc tìm hiểu chi tiết về mã của bạn.

  • hoàn thành

    • Kết thúc việc thực thi chức năng hiện tại, sau đó tạm dừng (còn gọi là bước ra ngoài). Hữu ích nếu bạn vô tình bước vào một chức năng.

Điểm ngắt hoặc Điểm theo dõi

Các điểm ngắt đóng một vai trò quan trọng trong việc gỡ lỗi. Họ tạm dừng (ngắt) một chương trình khi nó đạt đến một điểm nhất định. Bạn có thể kiểm tra và thay đổi các biến và tiếp tục thực thi. Điều này rất hữu ích khi một số lỗi đầu vào xảy ra hoặc đầu vào phải được kiểm tra.

  • nghỉ 45

  • phá vỡ chức năng của tôi

    • Đặt một điểm ngắt ở dòng 45 hoặc tại chức năng của tôi. Chương trình sẽ tạm dừng khi nó đạt đến điểm ngắt.
  • xem x == 3

    • Đặt điểm theo dõi, điểm này sẽ tạm dừng chương trình khi điều kiện thay đổi (khi x == 3 thay đổi). Các điểm giám sát là tuyệt vời cho một số đầu vào nhất định (myPtr! = NULL) mà không cần phải ngắt mỗi lần gọi hàm.

  • tiếp tục

    • Tiếp tục thực thi sau khi bị tạm dừng bởi một điểm ngắt / điểm giám sát. Chương trình sẽ tiếp tục cho đến khi nó chạm đến điểm ngắt / điểm theo dõi tiếp theo.

  • xóa N

    • Xóa điểm ngắt N (các điểm ngắt được đánh số khi được tạo).

Đặt biến

Xem và thay đổi các biến trong thời gian chạy là một phần quan trọng của gỡ lỗi. Thử cung cấp đầu vào không hợp lệ cho các chức năng hoặc chạy các trường hợp thử nghiệm khác để tìm ra nguyên nhân gốc rễ của sự cố. Thông thường, bạn sẽ xem / đặt các biến khi chương trình bị tạm dừng.

  • in x

    • In giá trị hiện tại của biến x. Có thể sử dụng các tên biến ban đầu là lý do tại sao cờ (-g) là cần thiết; các chương trình được biên dịch thường xuyên có thông tin này bị xóa

  • đặt x = 3

  • đặt x = y

    • Đặt x thành một giá trị đã đặt (3) hoặc cho một biến khác (y)
  • gọi my Chức năng ()

  • gọi hàm myother (x)

  • gọi strlen (mystring)

    • Gọi các chức năng hệ thống hoặc do người dùng xác định. Điều này cực kỳ hữu ích, nhưng hãy cẩn thận khi gọi các hàm lỗi.

  • hiển thị x

    • Liên tục hiển thị giá trị của biến x, được hiển thị sau mỗi bước hoặc khi tạm dừng. Hữu ích nếu bạn liên tục kiểm tra một giá trị nhất định.

  • undisplay x

    • Loại bỏ hiển thị liên tục của một biến được hiển thị bằng lệnh hiển thị.

Backtrace và thay đổi khung

Ngăn xếp là danh sách các lệnh gọi hàm hiện tại - nó cho bạn biết bạn đang ở đâu trong chương trình. Một khung lưu trữ chi tiết của một lệnh gọi hàm đơn lẻ, chẳng hạn như các đối số.

  • bt

    • Backtraceshoặc in ngăn xếp chức năng hiện tại để hiển thị bạn đang ở đâu trong chương trình hiện tại. Nếu hàm chính gọi hàm a (), gọi b (), gọi c (), dấu lùi là

  • c <= current location 
    b 
    a 
    main
  • up

  • xuống

    • Di chuyển đến khung tiếp theo lên hoặc xuống trong ngăn xếp hàm. Nếu bạn đang ởc, bạn có thể chuyển đến b hoặc là a để kiểm tra các biến cục bộ.

  • trở về

    • Trả về từ chức năng hiện tại.

Xử lý tín hiệu

Tín hiệu là các thông báo được đưa ra sau các sự kiện nhất định, chẳng hạn như bộ đếm thời gian hoặc lỗi. GDB có thể tạm dừng khi gặp tín hiệu; thay vào đó bạn có thể muốn bỏ qua chúng.

  • xử lý [signalname] [action]

  • xử lý SIGUSR1 nostop

  • xử lý mã số SIGUSR1

  • xử lý SIGUSR1 bỏ qua

    • Hướng dẫn GDB bỏ qua một tín hiệu nhất định (SIGUSR1) khi nó xảy ra. Có nhiều mức độ phớt lờ khác nhau.

Xem qua các ví dụ sau để hiểu quy trình gỡ lỗi một chương trình và lõi được kết xuất.

  • Ví dụ gỡ lỗi 1

    Ví dụ này trình bày cách bạn nắm bắt một lỗi đang xảy ra do một ngoại lệ được nêu ra trong khi chia cho 0.

  • Ví dụ gỡ lỗi 2

    Ví dụ này minh họa một chương trình có thể kết xuất lõi do bộ nhớ không được khởi tạo.

Cả hai chương trình đều được viết bằng C ++ và tạo ra kết xuất lõi do những lý do khác nhau. Sau khi xem qua hai ví dụ này, bạn sẽ có thể gỡ lỗi các chương trình C hoặc C ++ của mình tạo ra các kết xuất lõi.

Sau khi xem qua hướng dẫn này, bạn chắc hẳn đã hiểu rõ về cách gỡ lỗi chương trình C hoặc C ++ bằng GNU Debugger. Bây giờ sẽ rất dễ dàng để bạn tìm hiểu chức năng của các trình gỡ lỗi khác vì chúng rất giống với GDB. Bạn cũng nên xem qua các trình gỡ lỗi khác để làm quen với các tính năng của chúng.

Có khá nhiều trình gỡ lỗi tốt có sẵn trên thị trường:

  • DBX Debugger- Trình gỡ lỗi này được vận chuyển cùng với Sun Solaris và bạn có thể nhận được thông tin đầy đủ về trình gỡ lỗi này bằng cách sử dụng trang chủ của dbx, tức là man dbx .

  • DDD Debugger- Đây là phiên bản đồ họa của dbx và có sẵn miễn phí trên Linux. Để có một chi tiết đầy đủ, hãy sử dụng trang man của ddd, tức là man ddd .

Bạn có thể nhận được thông tin chi tiết toàn diện về GNU Debugger từ liên kết sau: Gỡ lỗi với GDB