Làm thế nào để một trình sửa lỗi làm việc?


170

Tôi cứ tự hỏi làm thế nào để một trình sửa lỗi hoạt động? Một phần có thể được 'đính kèm' để chạy thực thi. Tôi hiểu rằng trình biên dịch dịch mã sang ngôn ngữ máy, nhưng làm thế nào để trình gỡ lỗi 'biết' nó đang được gắn vào cái gì?


5
Bài viết của Eli đã chuyển đến eli.thegreenplace.net/2011/01/23/how-debuggers-work-part-1
Oktalist

@Oktalist Bài viết này thú vị nhưng chỉ nói về sự trừu tượng hóa cấp API để gỡ lỗi trên Linux. Tôi đoán OP muốn biết thêm về mui xe.
smwikipedia

Câu trả lời:


96

Các chi tiết về cách trình gỡ lỗi hoạt động sẽ phụ thuộc vào những gì bạn đang gỡ lỗi và hệ điều hành là gì. Để gỡ lỗi gốc trên Windows, bạn có thể tìm thấy một số chi tiết về MSDN: API gỡ lỗi Win32 .

Người dùng cho trình gỡ lỗi biết quy trình nào sẽ đính kèm, theo tên hoặc theo ID tiến trình. Nếu đó là một tên thì trình gỡ lỗi sẽ tra cứu ID tiến trình và bắt đầu phiên gỡ lỗi thông qua một cuộc gọi hệ thống; trong Windows, đây sẽ là DebugActiveProcess .

Sau khi được đính kèm, trình gỡ lỗi sẽ vào một vòng lặp sự kiện giống như bất kỳ giao diện người dùng nào, nhưng thay vì các sự kiện đến từ hệ thống cửa sổ, HĐH sẽ tạo ra các sự kiện dựa trên những gì xảy ra trong quá trình được gỡ lỗi - ví dụ: xảy ra ngoại lệ. Xem WaitForDebugEvent .

Trình gỡ lỗi có thể đọc và ghi bộ nhớ ảo của tiến trình đích và thậm chí điều chỉnh các giá trị đăng ký của nó thông qua các API do HĐH cung cấp. Xem danh sách các chức năng sửa lỗi cho Windows.

Trình gỡ lỗi có thể sử dụng thông tin từ các tệp ký hiệu để dịch từ địa chỉ sang tên biến và vị trí trong mã nguồn. Thông tin tệp biểu tượng là một bộ API riêng biệt và không phải là một phần cốt lõi của HĐH. Trên Windows, điều này thông qua SDK truy cập giao diện gỡ lỗi .

Nếu bạn đang gỡ lỗi một môi trường được quản lý (.NET, Java, v.v.), quy trình thường sẽ trông tương tự, nhưng các chi tiết thì khác, vì môi trường máy ảo cung cấp API gỡ lỗi thay vì HĐH cơ bản.


5
Câu hỏi này nghe có vẻ ngu ngốc nhưng làm thế nào để HĐH theo dõi nếu đạt được một địa chỉ cụ thể trong chương trình. Ví dụ: một breackpoint được đặt trên địa chỉ 0x7710cafe. Khi con trỏ lệnh thay đổi HĐH (hoặc có thể CPU) sẽ phải so sánh con trỏ lệnh với tất cả các địa chỉ điểm ngắt, hoặc tôi có nhầm không? Cái này hoạt động ra sao ..?
hiển thị

3
@StefanFalk Tôi đã viết một câu trả lời đề cập đến một số chi tiết cấp thấp hơn (trên x86).
Jonathon Reinhart

Bạn có thể giải thích chính xác cách ánh xạ tên biến đến địa chỉ? Ứng dụng có sử dụng cùng một địa chỉ bộ nhớ cho các biến mỗi khi chạy không? Tôi đã luôn cho rằng nó chỉ tìm thấy ánh xạ từ bộ nhớ khả dụng nhưng chưa bao giờ thực sự nghĩ về việc các byte sẽ ánh xạ trực tiếp đến cùng một vị trí trong không gian bộ nhớ của ứng dụng hay không. Có vẻ như đó sẽ là một vấn đề an ninh lớn.
Đường James Joshua

@JamesJoshuaStreet Tôi sẽ tưởng tượng rằng đó là một chi tiết dành riêng cho trình gỡ lỗi.
moonman239

Câu trả lời này tiết lộ một cái gì đó. Nhưng tôi nghĩ op quan tâm nhiều hơn đến một số chi tiết cấp thấp hơn là một số trừu tượng API.
smwikipedia

63

Như tôi hiểu nó:

Đối với các điểm dừng phần mềm trên x86, trình gỡ lỗi thay thế byte đầu tiên của lệnh bằng CC( int3). Điều này được thực hiện với WriteProcessMemorytrên Windows. Khi CPU nhận được lệnh đó và thực thi lệnh int3này, điều này khiến CPU tạo ra ngoại lệ gỡ lỗi. HĐH nhận được ngắt này, nhận ra quá trình đang được gỡ lỗi và thông báo cho quá trình gỡ lỗi mà điểm dừng bị tấn công.

Sau khi điểm dừng được nhấn và quá trình dừng lại, trình gỡ lỗi sẽ xem danh sách các điểm dừng của nó và thay thế CCbằng byte đã có ở đó. Trình gỡ lỗi thiết lập TF, Cờ bẫy trong EFLAGS(bằng cách sửa đổi CONTEXT) và tiếp tục quá trình. Cờ bẫy khiến CPU tự động tạo ngoại lệ một bước ( INT 1) cho lệnh tiếp theo.

Khi quá trình được gỡ lỗi dừng lại vào lần tiếp theo, trình gỡ lỗi lại thay thế byte đầu tiên của lệnh breakpoint CCvà quá trình tiếp tục.

Tôi không chắc liệu đây có chính xác là cách nó được triển khai bởi tất cả các trình gỡ lỗi hay không, nhưng tôi đã viết một chương trình Win32 để tự gỡ lỗi bằng cơ chế này. Hoàn toàn vô dụng, nhưng giáo dục.


25

Trong Linux, gỡ lỗi một quy trình bắt đầu bằng lệnh gọi hệ thống ptrace (2) . Bài viết này có một hướng dẫn tuyệt vời về cách sử dụng ptraceđể thực hiện một số cấu trúc gỡ lỗi đơn giản.


1
Có phải (2)cho chúng tôi biết một cái gì đó nhiều hơn (hoặc ít hơn) so với "ptrace là một cuộc gọi hệ thống"?
Lazer

5
@eSKay, không không thực sự. Đây (2)là số phần thủ công. Xem en.wikipedia.org/wiki/Man_page#Manual_sections để biết mô tả về các phần thủ công.
Adam Rosenfield

2
@AdamRosenfield Ngoại trừ thực tế là phần 2 cụ thể là "Các cuộc gọi hệ thống". Vì vậy, gián tiếp, vâng, nó cho chúng ta biết đó ptracelà một cuộc gọi hệ thống.
Jonathon Reinhart

1
Thực tế hơn, điều này (2)cho chúng ta biết rằng chúng ta có thể gõ man 2 ptracevà lấy đúng trang chủ - không quan trọng ở đây vì không có gì khác ptraceđể định hướng, nhưng để so sánh man printfvới man 3 printfLinux.
mỏng

9

Nếu bạn đang dùng HĐH Windows, một tài nguyên tuyệt vời cho việc này sẽ là "Gỡ lỗi ứng dụng cho Microsoft .NET và Microsoft Windows" của John Robbins:

(hoặc thậm chí phiên bản cũ hơn: "Ứng dụng gỡ lỗi" )

Cuốn sách có một chương về cách một trình gỡ lỗi hoạt động bao gồm mã cho một vài trình gỡ lỗi đơn giản (nhưng hoạt động).

Vì tôi không quen thuộc với các chi tiết về gỡ lỗi Unix / Linux, nên công cụ này hoàn toàn không thể áp dụng cho các hệ điều hành khác. Nhưng tôi đoán rằng như là một giới thiệu về một chủ đề rất phức tạp, các khái niệm - nếu không phải là chi tiết và API - nên 'chuyển' sang hầu hết mọi hệ điều hành.


3

Một nguồn có giá trị khác để hiểu gỡ lỗi là hướng dẫn sử dụng CPU Intel (Hướng dẫn dành cho nhà phát triển phần mềm kiến ​​trúc Intel® 64 và IA-32). Trong tập 3, chương 16, nó đã giới thiệu phần hỗ trợ gỡ lỗi, chẳng hạn như các ngoại lệ đặc biệt và các thanh ghi gỡ lỗi phần cứng. Sau đây là từ chương đó:

Cờ T (bẫy), TSS - Tạo ngoại lệ gỡ lỗi (#DB) khi thực hiện một nỗ lực để chuyển sang một tác vụ với cờ T được đặt trong TSS của nó.

Tôi không chắc liệu Window hay Linux có sử dụng cờ này hay không, nhưng rất thú vị khi đọc chương đó.

Hy vọng điều này sẽ giúp được ai đó.


2

Tôi nghĩ có hai câu hỏi chính để trả lời ở đây:

1. Làm thế nào trình gỡ lỗi biết rằng một ngoại lệ xảy ra?

Khi một ngoại lệ xảy ra trong một quá trình đang được gỡ lỗi, trình gỡ lỗi sẽ được HĐH thông báo trước khi bất kỳ trình xử lý ngoại lệ người dùng nào được xác định trong quy trình đích sẽ có cơ hội phản hồi ngoại lệ đó. Nếu trình gỡ lỗi chọn không xử lý thông báo ngoại lệ (cơ hội đầu tiên) này, trình tự gửi ngoại lệ sẽ tiếp tục và luồng đích sẽ có cơ hội xử lý ngoại lệ nếu nó muốn làm như vậy. Nếu ngoại lệ SEH không được xử lý bởi quy trình đích, trình gỡ lỗi sau đó được gửi một sự kiện gỡ lỗi khác, được gọi là thông báo cơ hội thứ hai, để thông báo cho nó rằng một ngoại lệ chưa được xử lý xảy ra trong quy trình đích. Nguồn

nhập mô tả hình ảnh ở đây


2. Làm thế nào trình gỡ lỗi biết làm thế nào để dừng trên một điểm dừng?

Câu trả lời đơn giản là: Khi bạn đặt điểm dừng vào chương trình, trình gỡ lỗi sẽ thay thế mã của bạn tại thời điểm đó bằng lệnh int3 là phần mềm bị gián đoạn . Như một hiệu ứng, chương trình bị đình chỉ và trình gỡ lỗi được gọi.


1

Hiểu biết của tôi là khi bạn biên dịch một ứng dụng hoặc tệp DLL, bất cứ thứ gì nó biên dịch để chứa các ký hiệu đại diện cho các hàm và các biến.

Khi bạn có bản dựng gỡ lỗi, các biểu tượng này chi tiết hơn nhiều so với khi đó là bản dựng phát hành, do đó cho phép trình gỡ lỗi cung cấp cho bạn thêm thông tin. Khi bạn đính kèm trình gỡ lỗi vào một tiến trình, nó sẽ xem xét các hàm nào hiện đang được truy cập và giải quyết tất cả các biểu tượng gỡ lỗi có sẵn từ đây (vì nó biết các phần bên trong của tệp được biên dịch trông như thế nào, nó có thể xác định được những gì có thể có trong bộ nhớ , với nội dung của ints, float, chuỗi, v.v.). Giống như poster đầu tiên đã nói, thông tin này và cách các biểu tượng này hoạt động phụ thuộc rất nhiều vào môi trường và ngôn ngữ.


2
Đây chỉ là về các biểu tượng. Có rất nhiều, rất nhiều để gỡ lỗi hơn các biểu tượng.
Jonathon Reinhart
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.