2013-08-07 31 views
10

Khi tôi nhận được báo cáo sự cố, phần vi phạm của tôi đôi khi sẽ trông như thế này, thay vì hiển thị cho tôi số dòng thực tế, mặc dù báo cáo sự cố được symbolicated:Làm cách nào tôi có thể tìm thấy địa chỉ của dấu vết ngăn xếp trong LLDB cho iOS

-[ViewController myMethod:] + 47 

để gỡ lỗi này, tôi cần phải biết những gì dòng mã của tôi điều này thể hiện vì vậy mà tôi có thể kiểm tra bằng mắt nó, đặt một breakpoint vv

một cách tốt là gì thế nào để có được địa chỉ của một phương pháp cộng với bù đắp, như được hiển thị ở trên, bằng cách sử dụng LLDB?

LƯU Ý: câu hỏi này KHÔNG phải là bản sao của how to read a crash report. Tôi biết cách đọc báo cáo sự cố. Tôi hỏi rất cụ thể làm thế nào để có được dòng tương ứng bằng cách sử dụng LLDB. Không có gì trong các câu trả lời khác cho thấy làm thế nào để làm điều đó. Chúng khá chi tiết và đi sâu vào tất cả mọi thứ về xử lý các báo cáo sự cố và gỡ lỗi nói chung, nhưng không hiển thị những bước cụ thể nào trên LLDB. Vui lòng không sao chép lỗi này.

+0

Tôi sắp cung cấp cho bạn một câu trả lời khủng khiếp, nhưng khả thi trong các tình huống chặt chẽ. Chuyển đổi số đó sang thập phân, sau đó chia cho bit bus. Tôi sẽ gọi đó là "số lượng các dòng lệnh mà tôi phải đi qua". Tất nhiên, có một bù đắp khác dựa trên những gì chính xác được lưu trữ giữa mọi thứ. Tôi đã có năm 2020, cuối cùng là 128. Vì vậy, về cơ bản "một cách xuống". Tôi tìm thấy một khu vực không được bảo vệ đúng cách, và về cơ bản nó đã giúp tôi khắc phục sự cố của tôi. Guesstimation –

Trả lời

6

Đây là điều tôi đã tìm thấy đã làm việc:

Trước tiên, bạn cần tìm địa chỉ của chính phương thức đó.

image lookup -v -F "-[ViewController myMethod:]" 

trong kết quả bạn sẽ thấy rất nhiều thông tin, nhưng phần nhiều sẽ cung cấp cho bạn muốn, bạn muốn

... range = [0x000708c0-0x00070c6c) ... 

(nơi 0x000708c0 là địa chỉ của phương pháp)

Bây giờ thêm số tiền đã cho là 47, chỉ cần sử dụng LLDB để thực hiện việc đó cho bạn:

(lldb) p/x 0x000708c0 + 47 
(int) $0 = 0x000708ef 

và bạn nhận được câu trả lời, t ông xúc phạm dòng là trên 0x000708ef

Hoặc tốt hơn, dựa trên câu trả lời Jason Molenda của, là chỉ cần đi thẳng đến việc niêm yết mã, mà sẽ hiển thị số dòng:

(lldb) source list -a `0x000708c0 + 47` 

EDIT: cải thiện dựa trên câu trả lời từ Jason Molenda

7

Các bước của bạn (image lookup + p/x addr + offset) sẽ cung cấp cho bạn địa chỉ thô như bạn đã tìm thấy. Nhưng bản báo cáo sự cố ban đầu có thể bao gồm một địa chỉ trước phương thức + offset --- nó cũng dễ dàng để trượt nhị phân của bạn đến địa chỉ chính xác bằng cách sử dụng target modules load. Ở cuối báo cáo sự cố phải có danh sách các hình ảnh nhị phân có trong chương trình, bao gồm địa chỉ tải và UUID.

Nhưng quan trọng hơn, trong khi địa chỉ đẹp thì điều bạn thực sự sau là vị trí nguồn. Trong trường hợp đó, một khi bạn đã xác định đúng địa chỉ cho phương pháp (hoặc trượt nó vào địa chỉ phù hợp qua target modules load), bạn có thể sử dụng source list

(lldb) so l -a `addr + offset` 

Tôi đang sử dụng các ký hiệu backtick đây mà không một trong đánh giá biểu thức dòng. Có một phím tắt tiện dụng cho hầu hết các lệnh mà phải mất một địa chỉ: nếu bạn bỏ qua không gian, bạn có thể viết biểu thức mà không backticks:

(lldb) so l -a addr+offset 

Bạn cũng có thể sử dụng image lookup với một địa chỉ.Nếu bạn có thông tin gỡ lỗi, điều này sẽ cho bạn biết vị trí hiện tại của các biến là gì tại thời điểm này. Tại sao điều này hữu ích? Bởi vì hầu hết các báo cáo sự cố bao gồm bối cảnh đăng ký tại sự cố và vì vậy bất kỳ biến nào hiện có trong sổ đăng ký được cung cấp cho bạn (-v là cần thiết để nhận tất cả thông tin vị trí đăng ký).

(lldb) im loo -v -a addr+offset 

Cuối cùng - điều này sẽ không hoạt động vì bạn đang xử lý tên phương pháp mục tiêu-C - nhưng với tên hàm C đơn giản, bạn có thể thực hiện số học bù trừ trong dòng miễn là bạn đặt tên hàm vào một kiểu con trỏ (không phải là C hợp lệ để thêm một bù đắp cho một con trỏ hàm). ví dụ.

(lldb) so l -a (char*)main+10 
+0

Khi tôi chạy một ứng dụng trong XCode và thực hiện lệnh này: im loo -v -a $ pc Tôi nhận được kết quả hiển thị biến, nhưng tôi không thấy sao cho phù hợp với những gì trong sổ đăng ký . Nó liệt kê vị trí của họ nhưng không phải là những gì có thể được đăng ký. Biến: id = {0x000000a4}, tên = "tự", loại = "ViewController * const", vị trí = DW_OP_fbreg (8), decl = ViewController.m: 30 vì vậy tôi dường như không nhận được bất kỳ "đăng ký thông tin vị trí". Tôi có làm điều gì sai? – Skotch

+1

Có, các mô tả vị trí nằm trong ngôn ngữ biểu thức DWARF, tôi quên đề cập đến điều đó. "fbreg" có nghĩa là "khung cơ sở reg", lldb cung cấp cho bạn một "$ fp" bí danh đăng ký mà có lẽ sẽ là điều đúng. Nếu bạn đang gỡ lỗi quy trình 32 bit (cánh tay, Trình mô phỏng), bạn sẽ thực hiện 'x/x $ fp + 8' - nếu bạn đang gỡ lỗi quy trình 64 bit (x86_64), bạn sẽ thực hiện' x/gx $ fp + 8' để xem giá trị. '$ fp + 8' là địa chỉ của bộ nhớ ngăn xếp, lệnh' x' (bí danh cho 'bộ nhớ đọc') đọc 4 byte (' x') hoặc 8 byte ('gx') bộ nhớ tại địa chỉ đó. –

+0

Vì tra cứu hình ảnh sẽ không cho bạn biết biến nào đang được lưu trữ trong sổ đăng ký, tôi đoán chúng tôi nên xóa nhận xét về việc sử dụng ngữ cảnh đăng ký từ báo cáo sự cố. Có lẽ có nhiều cách khác để làm điều đó, nhưng điều đó thực sự nằm ngoài phạm vi của câu hỏi. Bạn có phiền không nếu tôi chỉnh sửa câu trả lời của bạn để xóa phần đó? – Skotch

2

[lưu ý chỉ làm việc này nếu bạn lưu Lưu trữ trong XCode của tất cả các bản xây dựng bạn phát hành]

Thông tin bạn cần phải thu thập đầu tiên:

  • APPNAME: tên ngắn ứng dụng của bạn như được thấy trong thư mục Archive (thường là tên XCode Target; bạn sẽ thấy nó ngay khi bạn nhìn vào thư mục Archive trong Finder bên dưới).
  • CRASHING_FUNCTION_NAME: tên của chức năng thể hiện trong vô dụng của Apple backtrace (trong ví dụ của OP, -[ViewController myMethod:])
  • ARCH: Kiến trúc của thiết bị đó bị rơi. Nhiều khả năng giá trị phù hợp là armv7 hoặc arm64. Nếu bạn không biết, hãy thử cả hai.

Ok đây là các bước:

  1. Trong XCode vào Window ... Organizer ... Lưu trữ
  2. Nhấp chuột phải vào Lưu trữ cho việc phát hành cho người dùng đâm có, và chọn Hiện tại Finder
  3. mở một shell Terminal và cd vào thư mục đó thể hiện trong Finder
  4. thực hiện như sau trong vỏ:

    01.235.
    lldb -arch ARCH Products/Applications/APPNAME.app/APPNAME 
    
  5. bên LLĐB thực hiện như sau:

    (lldb) add-dsym dSYMs/APPNAME.app.dSYM/Contents/Resources/DWARF/APPNAME 
    
    (lldb) disassemble --name CRASHING_FUNCTION_NAME 
    
  6. bây giờ bạn nhìn thấy một tháo gỡ phong phú với các biểu tượng, và lo and behold, mỗi dòng cho thấy số thập phân tương tự bù đắp như bản gốc vô dụng của Apple backtrace (trong Ops dụ, vô dụng bù đắp là 47), như trong:

    APPNAME[0xf4a7c] <+47>: ldr r0, [r0, r1] 
    
  7. bạn có thể có thể tìm ra các dòng mã nguồn tương ứng chỉ từ thông tin này, nếu tháo gỡ có eno ugh biểu tượng để giúp bạn tìm ra bạn đang ở đâu.

  8. nếu không, có một mẹo hay khác.Vượt qua địa chỉ của dòng hỏng:

    (lldb) image lookup -v --address 0xf4a7c 
    
  9. Bây giờ lldb cho bạn thấy một bộ sưu tập phong phú của thông tin --- phong phú hơn nhiều so với những gì được hiển thị bởi Apple đống vết lùi ngay cả khi họ làm chứa số dòng, và giàu hơn nhiều so với lldb source list --- về tất cả các dòng nguồn đã đóng góp cho hướng dẫn lắp ráp tại địa chỉ đó. Hãy chú ý đến cả hai phần SummaryLineEntry. Ví dụ:

    Address: APPNAME[0x000f4a7c] (APPNAME.__TEXT.__text + 963740) 
    Summary: APPNAME`myclass::myfunc(bool, bool) + 904 [inlined] std::__1::deque<mystruct, std::__1::allocator<mystruct> >::operator[](unsigned long) + 22 at myfile.cpp:37945 
         APPNAME`myclass::myfunc(bool, bool) + 882 [inlined] myinlinefunc(int) + 14 at myfile.cpp:65498 
         APPNAME`myclass::myfunc(bool, bool) + 868 at myfile.cpp:65498 
    Module: file = "/Users/myuser/mydir/arch/Products/Applications/APPNAME.app/APPNAME", arch = "armv7" 
    CompileUnit: id = {0x000483a4}, file = "/Users/myuser/mydir/myfile.cpp", language = "objective-c++" 
    Function: id = {0x0045edde}, name = "myfunc", range = [0x000f46f4-0x000f572a) 
    FuncType: id = {0x0045edde}, decl = myfile.cpp:65291, compiler_type = "void (_Bool, _Bool)" 
    Blocks: id = {0x0045edde}, range = [0x000f46f4-0x000f572a) 
         id = {0x0045f7d8}, ranges = [0x000f4936-0x000f51c0)[0x000f544c-0x000f5566)[0x000f5570-0x000f5698) 
         id = {0x0046044c}, ranges = [0x000f49c6-0x000f49ce)[0x000f49d6-0x000f49d8)[0x000f4a2e-0x000f4a38)[0x000f4a58-0x000f4a82), name = "myinlinefunc", decl = myfile.cpp:37938, mangled = _Z11myinlinefunci, demangled = myinlinefunc(int) 
         id = {0x00460460}, ranges = [0x000f4a58-0x000f4a64)[0x000f4a66-0x000f4a82), name = "operator[]", decl = deque:1675, mangled = _ZNSt3__15dequeI12mystructNS_9allocatorIS1_EEEixEm, demangled = std::__1::deque<mystruct, std::__1::allocator<mystruct> >::operator[](unsigned long) 
    LineEntry: [0x000f4a7c-0x000f4a82): /Applications/Xcode7.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/deque:1678:14 
    Symbol: id = {0x00000805}, range = [0x000f46f4-0x000f572a), name="myclass::myfunc(bool, bool)", mangled="_ZN7myclass7myfuncEbb" 
    Variable: id = {0x00460459}, name = "myvar1", type = "int", location =  , decl = myfile.cpp:37938 
    Variable: id = {0x0045f7dd}, name = "myvar2", type = "bool", location = , decl = myfile.cpp:65583 
    Variable: id = {0x0045edf2}, name = "this", type = "myclass *", location = [sp+56], decl = 
    Variable: id = {0x0045ee01}, name = "myvar3", type = "bool", location = , decl = myfile.cpp:65291 
    Variable: id = {0x0045ee0e}, name = "myvar4", type = "bool", location = , decl = myfile.cpp:65292 
    
  10. Trong ví dụ này dưới Summary, chúng ta có thể thấy đường mà bị rơi thực sự là một sự kết hợp của mã từ myclass::myfunc(), myinlinefunc()std::deque::operator[]. Đây là loại nghiền với nhau là rất phổ biến cho mã tối ưu hóa. Điều này thường đủ thông tin để tìm ra dòng mã nguồn vi phạm của bạn. Dưới LineEntry chúng ta thấy số dòng cho mã lồng nhau nhất đóng góp vào dòng lắp ráp đó, trong trường hợp này là trong mã STL std::deque, nhưng trong các trường hợp khác có thể là số dòng chính xác mà bạn muốn trong mã của mình.

  11. Bây giờ câu hỏi còn lại duy nhất là: tại sao trên trái đất Apple không chỉ làm điều này cho chúng ta trong backtrace gốc? Họ rõ ràng có tất cả thông tin này! Tại sao chúng khiến chúng ta nhảy qua những vòng như vậy? Họ đang giấu gì vậy?

Các vấn đề liên quan