OK, hãy tưởng tượng rằng điểm ngắt của tôi objc_exception_throw
vừa được kích hoạt. Tôi đang ngồi ở lời nhắc của trình gỡ lỗi và tôi muốn nhận thêm một số thông tin về đối tượng ngoại lệ. Tôi tìm nó ở đâu?
OK, hãy tưởng tượng rằng điểm ngắt của tôi objc_exception_throw
vừa được kích hoạt. Tôi đang ngồi ở lời nhắc của trình gỡ lỗi và tôi muốn nhận thêm một số thông tin về đối tượng ngoại lệ. Tôi tìm nó ở đâu?
Câu trả lời:
Đối tượng ngoại lệ được chuyển vào dưới dạng đối số đầu tiên objc_exception_throw
. LLDB cung cấp $arg1
.. $argn
biến để tham chiếu đến các đối số trong quy ước gọi đúng, giúp việc in chi tiết ngoại lệ trở nên đơn giản:
(lldb) po $arg1
(lldb) po [$arg1 name]
(lldb) po [$arg1 reason]
Đảm bảo chọn objc_exception_throw
khung trong ngăn xếp cuộc gọi trước khi thực hiện các lệnh này. Xem "Gỡ lỗi nâng cao và Trình vệ sinh địa chỉ" trong video phiên WWDC15 để xem phần này được thực hiện trên sân khấu.
Thông tin lỗi thời
Nếu bạn đang sử dụng GDB, cú pháp để tham chiếu đến đối số đầu tiên phụ thuộc vào quy ước gọi của kiến trúc mà bạn đang chạy. Nếu bạn đang gỡ lỗi trên thiết bị iOS thực, con trỏ tới đối tượng đang được đăng ký r0
. Để in hoặc gửi tin nhắn, hãy sử dụng cú pháp đơn giản sau:
(gdb) po $r0
(gdb) po [$r0 name]
(gdb) po [$r0 reason]
Trên iPhone Simulator, tất cả các đối số của hàm đều được chuyển vào ngăn xếp, vì vậy cú pháp khủng khiếp hơn đáng kể. Biểu thức ngắn nhất mà tôi có thể xây dựng để đạt được nó là *(id *)($ebp + 8)
. Để làm cho mọi thứ bớt đau đớn hơn, tôi khuyên bạn nên sử dụng một biến tiện lợi:
(gdb) set $exception = *(id *)($ebp + 8)
(gdb) po $exception
(gdb) po [$exception name]
(gdb) po [$exception reason]
Bạn cũng có thể đặt $exception
tự động bất cứ khi nào điểm ngắt được kích hoạt bằng cách thêm danh sách lệnh vào objc_exception_throw
điểm ngắt.
(Lưu ý rằng trong tất cả các trường hợp tôi đã kiểm tra, đối tượng ngoại lệ cũng có trong eax
và edx
đăng ký tại thời điểm điểm ngắt xảy ra. Tuy nhiên, tôi không chắc điều đó sẽ luôn như vậy.)
Thêm từ bình luận bên dưới:
Trong lldb , chọn khung ngăn xếp cho objc_exception_throw
và sau đó nhập lệnh này:
(lldb) po *(id *)($esp + 4)
objc_exception_throw
trong LLĐB : po *(id *)($esp + 4)
.
objc_exception_throw
).
po $eax
hoạt động đối với tôi trong trình mô phỏng dưới dạng mặt dây chuyền $r0
khi ở trên thiết bị.
trên trình mô phỏng mới (iOS 8, 64bit) xcode 6 im bằng cách sử dụng trong khung ngoại lệ: objc_exception_throw
po $rax
ở 32bit:
po $eax
Rax là gì?
Rax là một thanh ghi 64bits thay thế cho eax cũ
Làm thế nào để tìm thấy tất cả các đăng ký?
register read
Tại thời điểm viết bài này, bài đăng này là bài đăng hàng đầu trên Google của tôi về: ngoại lệ in lldb . Do đó, tôi đang thêm câu trả lời này vào tài khoản cho lldb và x86_64.
Nỗ lực của tôi để tìm ngoại lệ bằng cách sử dụng po $eax
với error: Couldn't materialize struct: Couldn't read eax (materialize)
. Các nỗ lực khác được mô tả trong các tài liệu liên kết từ các câu trả lời trước đó cũng không thành công.
Điều quan trọng là đầu tiên tôi phải nhấp vào objc_exception_throw
khung trong chuỗi chính của mình. lldb không bắt đầu trong khung đó.
Trong tất cả các ví dụ tìm kiếm và làm theo của tôi, mục blog này là mục đầu tiên giải thích mọi thứ theo cách phù hợp với tôi. Nó hiện đại hơn, được đăng vào tháng 8 năm 2012.
Nếu bạn có một câu lệnh bắt, hãy đặt một điểm ngắt vào đó và bạn có thể kiểm tra đối tượng ngoại lệ tại điểm đó.
Nếu bạn không có tuyên bố nắm bắt, hãy tiếp tục.
Bạn sẽ nhận được một thông báo trong thiết bị đầu cuối của mình như sau:
Chấm dứt ứng dụng do không có ngoại lệ 'NSInvalidArgumentException', lý do: ' * - [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: cố gắng chèn đối tượng nil từ các đối tượng [0]'
Tuy nhiên , có thể bạn đang tìm cách kiểm tra nó mà không cần tiếp tục vì bạn sẽ mất dấu vết ngăn xếp đẹp mắt khi ứng dụng bị chấm dứt.
Đối với điều đó, có vẻ như câu trả lời của Fnord là tốt nhất, nhưng tôi đã không thể làm cho nó hoạt động trong LLDB.