Tôi nên tìm hiểu thêm về gỡ lỗi? [đóng cửa]


8

Để gỡ lỗi chương trình của tôi, tôi chủ yếu sử dụng các phương pháp sau:

  1. Sử dụng printf (hoặc tương đương trong các ngôn ngữ khác) để kiểm tra giá trị của biến sau một câu lệnh cụ thể hoặc để kiểm tra xem chương trình nhập câu lệnh có điều kiện hay vòng lặp.

  2. Sử dụng đồng hồ / điểm dừng khi sử dụng IDE.

Tôi có thể giải quyết các vấn đề bằng các phương pháp trên. Nhưng tôi đã nhận thấy rằng có hai loại bản dựng - gỡ lỗi và phát hành. Từ tên tôi có thể hiểu rằng gỡ lỗi xây dựng sẽ hữu ích trong việc gỡ lỗi. Ngoài ra tôi đã đọc rằng bản dựng gỡ lỗi lưu trữ một cái gì đó gọi là thông tin và biểu tượng bảng biểu tượng.

Làm cách nào để sử dụng bản dựng gỡ lỗi để gỡ lỗi? Có bất kỳ kỹ thuật sửa lỗi nào khác mà tôi nên học không?


Sự khác biệt phụ thuộc vào nền tảng. Đối với Java, sự khác biệt là nhỏ. Đối với C, nó có thể rất khác

2
bạn đang viết mã trên ngôn ngữ / nền tảng nào?
DXM

Câu trả lời:


7

Tìm hiểu trình gỡ lỗi của bạn

Nó thực sự hữu ích để nắm bắt được trình gỡ lỗi, cho dù đó là dựa trên văn bản, IDE đầy đủ hoặc một số pha trộn của chúng. Bạn không cung cấp nhiều chi tiết vì vậy tôi sẽ mô tả trường hợp chung:

1) Điểm dừng

Ngoài việc chỉ dừng lại ở một dòng mã, nhiều trình gỡ lỗi cho phép bạn chỉ định ngắt khi có một điều kiện phát sinh (ví dụ: "x> 5"), sau khi một số lần chuyển qua mã hoặc khi một số bộ nhớ thay đổi giá trị. Điều này rất hữu ích để hiểu làm thế nào mã của bạn rơi vào trạng thái xấu, ví dụ như xem khi nào một con trỏ trở nên rỗng thay vì bắt gặp sự cố khi nó bị hủy đăng ký.

2) Bước qua mã

Bạn có thể bước vào các hàm, theo từng dòng mã, nhảy qua các dòng ('đặt câu lệnh tiếp theo') và sau đó 'lên' ra khỏi các hàm. Đó là một cách thực sự mạnh mẽ để theo dõi quá trình thực thi mã của bạn để kiểm tra xem nó có làm đúng như bạn nghĩ không :-)

3) Đánh giá biểu thức

Vì vậy, bạn có thể đặt các biến vào danh sách / cửa sổ Xem và xem giá trị của chúng thay đổi khi bạn đạt điểm dừng hoặc bước qua mã, nhưng bạn cũng thường có thể thực hiện các đánh giá biểu thức phức tạp, ví dụ: "x + y / 5" sẽ được đánh giá. Một số trình gỡ lỗi cho phép bạn đặt các lệnh gọi chức năng vào danh sách theo dõi. Bạn có thể thực hiện những việc như "time ()", "MyFunction (...)", "time ()" và nhận thời gian đồng hồ về thời gian mà chức năng của bạn mất.

4) Ngoại lệ và xử lý tín hiệu

Vì vậy, nếu ngôn ngữ của bạn hỗ trợ các ngoại lệ và / hoặc tín hiệu, bạn thường có thể định cấu hình trình gỡ lỗi để biết cách phản ứng với điều này. Một số trình gỡ lỗi cho phép bạn xâm nhập vào mã tại thời điểm ngoại lệ sắp xảy ra, thay vì sau khi nó không bị bắt. Điều này hữu ích để theo dõi các vấn đề kỳ lạ như lỗi "Không tìm thấy tệp" vì chương trình đang chạy như một tài khoản người dùng khác.

5) Gắn vào một quy trình / cốt lõi

Vì vậy, đôi khi bạn phải sử dụng trình gỡ lỗi để nhảy vào một quy trình hiện có đang diễn ra. Nếu bạn có mã nguồn gần đó và các biểu tượng gỡ lỗi vẫn còn nguyên vẹn, bạn có thể đi sâu vào như thể bạn đã bắt đầu trình gỡ lỗi ở vị trí đầu tiên. Điều này cũng tương tự đối với các bãi chứa lõi, ngoại trừ bạn thường không thể tiếp tục gỡ lỗi trong các kết xuất đó (quá trình đã chết).

Xây dựng cấu hình

Có một số biến thể xây dựng bạn có thể thực hiện thông qua bật hoặc tắt các tính năng như biểu tượng gỡ lỗi, tối ưu hóa và các cờ trình biên dịch khác:

1) Gỡ lỗi

Theo truyền thống, đây là một bản dựng đơn giản không có đặc điểm đặc biệt, giúp dễ dàng gỡ lỗi và dự đoán. Nó thay đổi một chút theo nền tảng, nhưng có thể có thêm một số phòng đầu, ví dụ như phân bổ và kích thước bộ đệm để đảm bảo độ tin cậy. Thông thường, một biểu tượng trình biên dịch như DEBUG hoặc có điều kiện ("Gỡ lỗi") sẽ xuất hiện để mã cụ thể gỡ lỗi được kéo vào. Đây thường là bản dựng được vận chuyển, với các ký hiệu cấp độ chức năng, đặc biệt là nếu độ tin cậy và / hoặc độ lặp lại là liên quan.

2) Phát hành / Tối ưu hóa bản dựng

Kích hoạt tối ưu hóa trình biên dịch cho phép một số cơ sở tạo mã cấp thấp trong trình biên dịch tạo mã nhanh hơn hoặc nhỏ hơn dựa trên các giả định về mã của bạn. Tốc độ tăng có thể không liên quan nếu lựa chọn thuật toán của bạn kém, nhưng đối với các tính toán chuyên sâu, điều này có thể tạo ra sự khác biệt thông qua Loại bỏ Subexpression và Unrolling thông thường, v.v. Đôi khi các giả định được đưa ra bởi trình tối ưu hóa không tương thích với mã của bạn và vì vậy trình tối ưu hóa phải được giảm xuống một notch. Lỗi trình biên dịch trong mã được tối ưu hóa cũng là một vấn đề trong quá khứ.

3) Xây dựng thiết bị / hồ sơ

Mã của bạn được xây dựng với mã thiết bị cụ thể để đo số lần một chức năng được gọi và thời gian sử dụng trong chức năng đó. Mã do trình biên dịch tạo ra này được viết ra ở cuối quá trình để phân tích. Đôi khi việc sử dụng một công cụ phần mềm chuyên dụng cho việc này dễ dàng hơn - xem bên dưới. Loại xây dựng này không bao giờ được vận chuyển.

4) Xây dựng an toàn / Đã kiểm tra

Tất cả các 'van an toàn' được bật thông qua các ký hiệu tiền xử lý hoặc cài đặt trình biên dịch. Ví dụ, các tham số chức năng kiểm tra macro của ASSERT, các trình lặp kiểm tra các bộ sưu tập không được sửa đổi, các hoàng yến được đưa vào ngăn xếp để phát hiện tham nhũng, phân bổ heap được chứa đầy các giá trị sentinel (0xdeadbeef là một số đáng nhớ) để phát hiện tham nhũng heap. Đối với những khách hàng gặp vấn đề dai dẳng chỉ có thể sao chép trên trang của họ, đây là một điều hữu ích.

5) Xây dựng tính năng

Nếu bạn có các khách hàng khác nhau có các yêu cầu khác nhau về sản phẩm phần mềm của mình, thì việc xây dựng cho mỗi khách hàng thực hiện các phần khác nhau khi thử nghiệm là điều phổ biến. Ví dụ: một khách hàng muốn chức năng Ngoại tuyến và một khách hàng khác chỉ muốn Trực tuyến. Điều quan trọng là kiểm tra cả hai cách nếu mã được xây dựng khác nhau.

Ghi nhật ký và truy tìm

Vì vậy, có một số báo cáo hữu ích cho printf () và sau đó viết thông tin theo dõi toàn diện, có cấu trúc vào các tệp dữ liệu khi bạn đi. Thông tin này sau đó có thể được khai thác để hiểu hành vi / đặc điểm thời gian chạy của phần mềm của bạn. Nếu mã của bạn không gặp sự cố hoặc mất một chút thời gian để repro, thật hữu ích khi có một hình ảnh ví dụ như danh sách các chủ đề, chuyển trạng thái của chúng, phân bổ bộ nhớ, kích thước nhóm, bộ nhớ trống, số lần xử lý tệp, v.v. thực sự phụ thuộc vào kích thước, độ phức tạp và yêu cầu hiệu năng của ứng dụng của bạn, nhưng ví dụ, các nhà phát triển trò chơi muốn đảm bảo rằng không có "đột biến" trong việc sử dụng CPU hoặc bộ nhớ trong khi trò chơi đang diễn ra vì điều đó có thể sẽ ảnh hưởng đến tốc độ khung hình. Một số thông tin này được duy trì bởi hệ thống, một số bởi các thư viện và phần còn lại bởi mã.

Các công cụ khác

Không phải lúc nào bạn cũng phải tạo một bản dựng khác để bao quát các tình huống này: một số khía cạnh có thể được chọn trong thời gian chạy thông qua cấu hình quy trình (thủ thuật Windows Registry), làm cho các thư viện thay thế có mức độ ưu tiên cao hơn cho các thư viện tiêu chuẩn, ví dụ như đường dẫn trình tải hoặc sử dụng ICE phần mềm hoặc trình gỡ lỗi chuyên dụng để thăm dò phần mềm của bạn để biết các đặc điểm thời gian chạy (ví dụ: Intel v-Tune). Một số trong số này có chi phí lớn, một số là miễn phí - dtrace, công cụ Xcode.


6

Một bản dựng gỡ lỗi được xây dựng với các biểu tượng gỡ lỗi trong tệp thực thi. Về cơ bản điều đó có nghĩa là mọi dòng mã nguồn được liên kết với mã máy được tạo từ nó và tất cả tên của các biến và hàm được giữ. Trong GCC, điều này được thực hiện với -gcờ khi bạn biên dịch tệp nguồn. Một điều khác thường được thực hiện là tắt tối ưu hóa, điều này là do trình biên dịch thực hiện một số thủ thuật gọn gàng giúp chương trình của bạn chạy nhanh hơn, nhưng không thể gỡ lỗi. Trong GCC, điều này được thực hiện với -O0.

Công cụ hữu ích nhất mà tôi từng sử dụng để gỡ lỗi là gdb . Nó là một phiên bản văn bản của các điểm dừng IDE mà bạn đã đề cập. Bạn có thể làm nhiều hơn với gdb so với IDE có thể. Trong thực tế, một số IDE chỉ là một trình bao bọc xung quanh gdb, nhưng một số tính năng bị mất. Bạn có thể xem các vị trí bộ nhớ, lắp ráp in, in khung ngăn xếp, thay đổi xử lý tín hiệu và nhiều thứ khác. Nếu bạn nghiêm túc về việc gỡ lỗi, tôi sẽ học gdb hoặc một số chương trình gỡ lỗi dựa trên văn bản tương đương.

Một điều khác mà tôi thường thấy hữu ích là valgrind . Nó tìm thấy rò rỉ bộ nhớ và theo dõi xem bộ nhớ có được khởi tạo hay không. Bạn sử dụng nó với bản dựng gỡ lỗi của mình, bởi vì sau đó bạn nhận được số dòng nơi xảy ra những điều thú vị.


1
Có thật không? Mỗi lần tôi phải sử dụng GDB, tôi thấy đó là một bước lùi đáng kể từ sức mạnh và sự dễ sử dụng mà tôi có trong tầm tay với một trình gỡ lỗi dựa trên IDE tốt. Đặc biệt vì GDB là một công cụ rất chung chung, trong khi trình gỡ lỗi tích hợp có thể tận dụng việc biết các quy tắc của ngôn ngữ mà nó được thiết kế để cung cấp cho bạn phản hồi cụ thể hơn và phù hợp hơn.
Mason Wheeler

1
GDB được thiết kế rất nhiều cho C và C ++. Tôi đã sử dụng trình gỡ lỗi IDE khá lâu và chúng làm tôi thất vọng. Tôi thấy rằng tôi có nhiều quyền kiểm soát hơn đối với những gì tôi đang làm khi tôi sử dụng GDB.
Jarryd

2
@MasonWheeler, gdbcó thể viết được script, IDE thường thì không. Tôi không cần bất kỳ "sức mạnh" nào trong tầm tay khi máy tính có thể làm tất cả công việc cho tôi trong khi tôi đang nhấm nháp tách trà của mình.
SK-logic

3
@MasonWheeler, không, bạn đang làm gì đó sai khi nhấn "step- tests-step-tests " như điên. Thật dễ dàng hơn nhiều để viết một tập lệnh nhỏ để xác minh giả thuyết hiện tại của bạn về nguyên nhân của một vấn đề, hãy chạy nó (gần giống như cách bạn đang chạy các bài kiểm tra chức năng) và phân tích kết quả, lặp lại nếu cần. Tất cả các hình thức của một gỡ lỗi tương tác hầu như luôn luôn gần như vô dụng, ngay cả khi nó là một hậu quả của một bãi chứa cốt lõi. Một tập lệnh gỡ lỗi thông thường sẽ thiết lập một số điểm dừng, chạy, kiểm tra và định dạng độc đáo các giá trị tại các điểm dừng.
SK-logic

1
@Mason Wheeler, một đơn giản stack trace ( btgdb) trong hầu hết các trường hợp sẽ cung cấp cho bạn nhiều hơn, đủ thông tin cho một 0-giả thuyết (nếu đây không phải là trường hợp, mã của bạn là, tốt, thấp hơn nhiều so ngưỡng chất lượng không đạt tiêu chuẩn) . Tôi đã sử dụng trình gỡ lỗi kể từ VMS, đã thử tất cả các hương vị có thể, bao gồm cả một số quái thú cực kỳ kỳ lạ như gỡ lỗi thời gian, nhưng cho đến nay không thể tìm thấy bất kỳ hương vị nào thực sự hữu ích. Bạn đang kiểm tra các giả định của mình một cách tương tác - sau đó, bạn đang lãng phí thời gian của mình. Tôi đang kiểm tra các giả định của mình theo đợt (có thể nhiều song song), nhanh chóng và rất ít nỗ lực.
SK-logic

3

Có một kỹ thuật sửa lỗi cực kỳ mạnh mẽ, chưa được đề cập trong các câu trả lời khác. Nó có sẵn miễn phí cho một số môi trường phát triển, hoặc có thể được thêm vào với một hiệu ứng tương đối nhỏ cho hầu hết mọi thứ khác.

Điều này là một REPL nhúng, tốt nhất là cho phép kết nối bất cứ lúc nào thông qua một ổ cắm, chạy trong một luồng chuyên dụng và có thể sử dụng tất cả các hình thức phản ánh có thể cho mã đang chạy, sửa đổi hoặc thay thế hoàn toàn mã đang chạy, thêm những thứ mới, chạy chức năng, vv

Bạn sẽ có nó ngay lập tức nếu bạn viết mã, nói chung, Lisp, Smalltalk, Python, Ruby, v.v. Có thể nhúng một trình thông dịch nhẹ (giả sử, Lua, Guile, JavaScript hoặc Python) vào một ứng dụng gốc . Đối với các môi trường dựa trên JVM hoặc .NET, có rất nhiều trình biên dịch và trình thông dịch có thể nhúng được, và có một sự phản ánh khá mạnh mẽ miễn phí.

Cách tiếp cận này hiệu quả hơn nhiều so với các trình gỡ lỗi tương tác / lặp (như gdb, trình gỡ lỗi phòng thu trực quan, v.v.) và để có kết quả tốt nhất nên được sử dụng cùng với một cơ sở ghi nhật ký thích hợp và các xác nhận được đặt đúng.


nhưng không được sử dụng cùng với một hacker truy cập mạng của bạn. Hãy chắc chắn rằng bạn vô hiệu hóa điều này trong các bản dựng phát hành :)
gbjbaanb

@gbjbaanb, đó là những gì SSL được sử dụng cho. Đọc Viawebcâu chuyện - họ đã được hưởng lợi rất nhiều từ cách tiếp cận như vậy, có khả năng gỡ lỗi hệ thống sản xuất đang chạy.
SK-logic

2

Công cụ gỡ lỗi quan trọng nhất mà tôi từng sử dụng là kết xuất sự cố sau khi chết (kết xuất lõi trong Linux, dmp người dùng trong Windows).

Đây là một chủ đề thực sự phức tạp, vì vậy đây là một liên kết :

về cơ bản (trên Windows, nền tảng mà tôi có nhiều kinh nghiệm nhất là gỡ lỗi sau khi chết), bạn xây dựng các ứng dụng của mình bằng các ký hiệu được lưu trong một tệp riêng (tệp .pdb). Bạn giữ những thứ này an toàn (để không ai có thể dễ dàng thiết kế lại mã của bạn) và chờ sự cố. Khi nó (và bạn có DrWatson hoặc tương tự đang chạy để ghi lại sự cố và tạo tệp kết xuất), bạn tải tệp .dmp vào WinDbg (trình gỡ lỗi windows) cùng với các ký hiệu (và tùy chọn, đường dẫn đến mã nguồn) và nó sẽ hiển thị cho bạn vô số thông tin như ngăn xếp cuộc gọi, thanh ghi, biến, giá trị bộ nhớ, v.v ... Thật đẹp khi nó hoạt động.

Đối với bản dựng gỡ lỗi, tất cả điều này được thiết lập để tự động xảy ra. Bạn phải kích hoạt biểu tượng khi xây dựng phát hành. Các bản dựng gỡ lỗi cũng thêm các nội dung khác như bộ bảo vệ bộ nhớ (ngoại lệ kích hoạt là bạn cố gắng ghi vào chúng, điều này cho thấy bộ đệm tràn hoặc hỏng bộ nhớ thực sự dễ dàng; hoặc khẳng định cho những thứ không hoàn toàn đúng). Nói chung, mặc dù các bản dựng Debug dành cho các nhà phát triển để chạy và kiểm tra mã của họ trước khi chuyển nó vào.

Bây giờ đây là để gỡ lỗi mã gốc, mã .NET là một PiTA cho các công cụ sau khi chết như thế này, nhưng đôi khi bạn có thể lấy ra ngoại lệ .NET bằng cách tải sos .

Tất cả những thứ phức tạp, nhưng nó không quá tệ. Mặc dù vậy, đừng mong đợi GUI đẹp mắt, đây là sự đáng yêu của dòng lệnh.


2

Sử dụng printf (hoặc tương đương trong các ngôn ngữ khác) để kiểm tra giá trị của biến sau một câu lệnh cụ thể hoặc để kiểm tra xem chương trình nhập câu lệnh có điều kiện hay vòng lặp.

Bạn cũng nên sử dụng bất kỳ loại tuyên bố khẳng định nào được cung cấp.

Bạn cũng nên viết bài kiểm tra đơn vị.

Tôi có thể giải quyết các vấn đề bằng các phương pháp trên.

Hoàn hảo. Bạn biết tất cả mọi thứ bạn cần biết.

Có bất kỳ kỹ thuật sửa lỗi nào khác mà tôi nên học không?

Không. Không phải là bạn nên học. Bạn có thể tìm hiểu thêm nếu bạn nghĩ rằng nó sẽ giúp. Nhưng bạn không cần bất cứ thứ gì nhiều hơn những gì bạn có.

Trong hơn 30 năm qua, tôi chỉ sử dụng trình gỡ lỗi một vài lần (có thể là ba hoặc bốn). Và sau đó, tôi chỉ sử dụng nó để đọc các bãi đổ vỡ sau khi chết để tìm lệnh gọi thất bại.

Sử dụng trình gỡ lỗi không phải là một kỹ năng thiết yếu . Các tuyên bố in là đủ.


0

Dưới đây là danh sách nhanh các kỹ thuật:

  • Biểu đồ cuộc gọi tĩnh
  • Biểu đồ cuộc gọi động
  • Hồ sơ điểm nóng
  • Xem tin nhắn
  • Phát lại gỡ lỗi / thực hiện ngược
  • Quan điểm
  • Tracepoints

Bạn cũng có thể thực hiện các hành vi tùy chỉnh với các công cụ kiểu AOP, cũng như đi một chặng đường dài với một công cụ phân tích tĩnh tốt.


0

Tìm hiểu mọi thứ về công cụ sửa lỗi của bạn.

Chúng thường ẩn các tính năng thực sự mạnh mẽ có thể giúp bạn hiểu rõ hơn những gì đang xảy ra. (cụ thể là trình gỡ lỗi C ++ của Visual Studio)

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.