Gỡ lỗi Xcode 4.2 không biểu thị cuộc gọi ngăn xếp


140

Tôi gặp vấn đề với gỡ lỗi Xcode 4.2 trong trình giả lập / thiết bị iOS 5. Đoạn mã sau gặp sự cố, như mong đợi:

NSArray *arr=[NSArray array];
[arr objectAtIndex:100];

Trong iOS 4, tôi nhận được một dấu vết ngăn xếp hữu ích của các số hex. Nhưng trong iOS 5, nó chỉ mang lại cho tôi:

*** First throw call stack:
(0x16b4052 0x1845d0a 0x16a0674 0x294c 0x6f89d6 0x6f98a6 0x708743 0x7091f8 0x7fcaa9 0x2257fa9 0x16881c5 0x15ed022 0x15eb90a 0x15eadb4 0x15eaccb 0x6f02a7 0x6faa93 0x2889 0x2805)

Cảm ơn.

Câu trả lời:


256

Không có gì tôi đã thử sẽ khắc phục điều này (đã thử cả trình biên dịch, cả trình gỡ lỗi, v.v.) Sau khi nâng cấp XCode cho bản cập nhật iOS 5, dường như không có dấu vết ngăn xếp nào hoạt động.

Tuy nhiên, tôi đã tìm thấy một cách giải quyết hiệu quả - tạo trình xử lý ngoại lệ của riêng tôi (cũng hữu ích cho các lý do khác). Đầu tiên, tạo một hàm sẽ xử lý lỗi và xuất nó ra bàn điều khiển (cũng như bất cứ điều gì khác mà bạn muốn làm với nó):

void uncaughtExceptionHandler(NSException *exception) {
    NSLog(@"CRASH: %@", exception);
    NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    // Internal error reporting
}

Tiếp theo, thêm trình xử lý ngoại lệ cho đại biểu ứng dụng của bạn:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{   
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
    // Normal launch stuff
}

Đó là nó!

Nếu điều này không hiệu quả, thì chỉ có hai lý do có thể :

  1. Một cái gì đó đang ghi đè NSSetUncaughtExceptionHandlercuộc gọi của bạn (chỉ có thể có một trình xử lý cho toàn bộ ứng dụng của bạn). Ví dụ, một số thư viện của bên thứ 3 thiết lập unsaughtExceptionHandler của riêng họ. Vì vậy, hãy thử đặt nó ở END của didFinishLaunchingWithOptionschức năng của bạn (hoặc vô hiệu hóa có chọn lọc các thư viện bên thứ 3). Hoặc tốt hơn nữa, đặt điểm dừng mang tính biểu tượng NSSetUncaughtExceptionHandlerđể nhanh chóng xem ai đang gọi nó. Những gì bạn có thể muốn làm là sửa đổi cái hiện tại của bạn thay vì thêm cái khác.
  2. Bạn đang không thực sự gặp phải một ngoại lệ (ví dụ, EXC_BAD_ACCESSkhông một ngoại lệ; tín dụng để bình luận @Erik B, bên dưới)

1
Rất vui khi nghe nó :) Tôi thấy nó hữu ích khi viết nhật ký sự cố vào một tệp và nhắc người dùng gửi nó trong lần khởi chạy tiếp theo (chỉ trong chế độ phát hành, để không bị gỡ lỗi). Điều này cho phép tôi nhận được các báo cáo lỗi tuyệt vời ... và người dùng biết rằng vấn đề của họ đang được giải quyết :)
Zane Claes

2
Điều này dường như không hoạt động - uncaughtExceptionHandlerthói quen không bao giờ được gọi.
Licks nóng

1
Bạn có thể vui lòng cụ thể hơn về cách sử dụng nó? Nó dường như không làm việc cho tôi.
Danut Pralea

1
XCode khá buồn không hiển thị điều này cho chúng tôi.
Authman Apatira

1
Nhiều đánh giá cao! Thật khó hiểu khi Apple không triển khai loại chức năng thô sơ này vào IDE.
devios1

110

Có một tùy chọn hữu ích là thêm Điểm dừng ngoại lệ (sử dụng dấu + ở dưới cùng của Bộ điều hướng Breakpoint). Điều này sẽ phá vỡ mọi Ngoại lệ (hoặc bạn có thể đặt điều kiện). Tôi không biết lựa chọn này là mới trong 4.2 hay cuối cùng tôi chỉ nhận thấy nó cố gắng giải quyết vấn đề biểu tượng bị thiếu.

Khi bạn đạt điểm dừng này, bạn có thể sử dụng Bộ điều hướng gỡ lỗi để điều hướng ngăn xếp cuộc gọi, kiểm tra các biến, v.v. như bình thường.

Nếu bạn muốn có một ngăn xếp cuộc gọi được tượng trưng phù hợp để sao chép / dán hoặc tương tự, backtrace gdb sẽ hoạt động tốt từ đó:

(gdb) bt
#0  0x01f84cf0 in objc_exception_throw ()
#1  0x019efced in -[NSObject doesNotRecognizeSelector:] ()

(Vân vân)


3
Điều này làm việc hoàn hảo cho tôi cho đến nay. Trình gỡ lỗi tạm dừng trên đường gặp sự cố bây giờ, không cần backtrace.
Tim

1
Điều này hoàn toàn làm việc cho tôi quá. Cảm ơn bạn rất nhiều, tôi đã phát điên khi không có điểm dừng này ...
William Denniss

+1 cho nó hoạt động. Nó không cung cấp cho bạn một thông báo lỗi tốt như vậy giải thích lý do của ngoại lệ, nhưng đó là một sự khởi đầu ...
Nicu Surdu

bạn là HotD của tôi @WiseOldDuck.
Maverick1

Điều này khôi phục hành vi dự kiến ​​cho tôi. LƯU Ý: Cũng nhớ thêm lại điểm dừng này trong các dự án mới!
MechEthan

46

Có một tính năng mới trên trình gỡ lỗi. Bạn có thể đặt điểm dừng bất cứ khi nào có ngoại lệ được ném và dừng thực thi ngay tại đó, giống như đã xảy ra trên 4.0.

Trên "Breakpoint Navigator", thêm "Điểm dừng ngoại lệ" và chỉ cần nhấn "Xong" trên cửa sổ bật lên tùy chọn.

Đó là tất cả!

PS: Trong một số trường hợp, tốt hơn là chỉ phá vỡ các trường hợp ngoại lệ Objective-C.


Chắc chắn đây là giải pháp cho tôi.
bradgonesurfing

Đây là vấn đề đối với tôi. Một đồng nghiệp và tôi chia sẻ cùng một dự án Xcode và tôi hỏi anh ta nếu anh ta gặp vấn đề, và anh ta đã không làm vậy. Sự khác biệt là dự án của anh ấy đã phá vỡ các trường hợp ngoại lệ khách quan (objc_exception_throw)
móng

Bạn chỉ cần tìm một lỗi không thể tìm thấy. Cảm ơn bạn rất nhiều. Tôi đã được tìm kiếm khắp nơi một cái gì đó như thế này.
rjgonzo

1
Công việc này như một cái duyên vậy! Đó chính xác là những gì tôi đang tìm kiếm, điều này tốt hơn là thêm Trình xử lý ngoại lệ vì việc thêm Điểm dừng có thể đưa bạn đến đúng nơi ngoại lệ được ném, trình xử lý ngoại lệ hoạt động nhưng chỉ cho bạn một ý tưởng.
im8bit

21

Đây là một giải pháp nữa, không quá thanh lịch như trước đây, nhưng nếu bạn không thêm các điểm dừng ngoại lệ hoặc trình xử lý, thì đó chỉ là một cách để đi.
Khi ứng dụng gặp sự cố và bạn nhận được ngăn xếp cuộc gọi ném đầu tiên (bằng số hex), hãy nhập vào bảng điều khiển Xcode info line *hex(không quên 0xtrình xác định dấu sao và hex), ví dụ:

(gdb) info line *0x2658
Line 15 of "path/to/file/main.m" starts at address 0x25f2 <main+50>
and ends at 0x267e <main+190>.

Nếu bạn đang sử dụng lldb , bạn có thể nhập image lookup -a hex(không có dấu sao trong tình huống này) và bạn nhận được đầu ra tương tự.

Với phương pháp này, bạn có thể di chuyển từ đỉnh ngăn xếp (sẽ có khoảng 5-7 bộ truyền ngoại lệ hệ thống) đến chức năng của bạn gây ra sự cố và xác định chính xác tệp và dòng mã.

Ngoài ra, để có hiệu quả tương tự, bạn có thể sử dụng tiện ích atos trong thiết bị đầu cuối, chỉ cần gõ:

atos -o path/to/AplicationBundle.app/Executable 0xAdress1 0xAdress2 0xAdress3 ...

và bạn nhận được dấu vết ngăn xếp được ký hiệu hóa (ít nhất là đối với các chức năng bạn có các biểu tượng gỡ lỗi). Phương pháp này được ưa thích hơn, bởi vì bạn không có cho mỗi cuộc gọi địa chỉ info line, chỉ cần sao chép địa chỉ từ đầu ra của bàn điều khiển và dán chúng vào thiết bị đầu cuối.


9

Bạn có thể thêm Điểm dừng ngoại lệ (sử dụng dấu + ở dưới cùng của Bộ điều hướng điểm dừng) và thêm hành động bt cho nó (nhấp vào nút Thêm hành động, chọn Lệnh gỡ lỗi, nhập "bt" vào trường văn bản). Điều này sẽ hiển thị theo dõi ngăn xếp ngay khi một ngoại lệ được ném ra.


6

Đây là một vấn đề phổ biến, không nhận được dấu vết ngăn xếp trong 4.2. Bạn có thể thử trao đổi giữa LLDB và GDB để xem bạn có kết quả tốt hơn không.

Nộp báo cáo lỗi tại đây.

http://developer.apple.com/ormsreporter/

BIÊN TẬP:

Tôi tin rằng nếu bạn trao đổi trở lại LLVM GCC 4.2, bạn sẽ không thấy điều này xảy ra. Bạn có thể mất các tính năng bạn cần mặc dù.


vâng tôi đã thử chuyển đổi trình biên dịch, tuy nhiên vấn đề vẫn còn. nhưng dù sao cũng cảm ơn :)
cekisakurek

Ông đề nghị chuyển đổi trình gỡ lỗi, không phải trình biên dịch.
bames53

1
FYI: Trong trường hợp này, nó không liên quan gì đến phiên bản trình biên dịch hoặc trình gỡ lỗi mà bạn đang sử dụng. Đây là một thay đổi trong đầu ra giao diện điều khiển từ iOS.
clarkcox3

Thật thú vị khi có bao nhiêu trải nghiệm về điều này khác nhau - tôi nghĩ có một vài vấn đề. Tôi đã không thể khiến trình gỡ lỗi dừng lại ở điểm dừng ngoại lệ. Chuyển đổi từ GDB sang LLDB đã giải quyết vấn đề.
Matt

6

Sử dụng mã này trong chức năng chính của bạn:

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    int retVal;
    @try {
        retVal = UIApplicationMain(argc, argv, nil, nil);
    }
    @catch (NSException *exception) {
        NSLog(@"CRASH: %@", exception);
        NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    }
    @finally {
        [pool release];
    }
    return retVal;
}

Điều này dường như không hoạt động với bảng phân cảnh. 2012-06-04 20: 34: 52.211 Sự cố [1944: 207] Đại biểu ứng dụng phải triển khai thuộc tính cửa sổ nếu muốn sử dụng tệp bảng phân cảnh chính. 2012-06-04 20: 34: 52.213 Sự cố [1944: 207] Các ứng dụng dự kiến ​​sẽ có bộ điều khiển xem gốc khi kết thúc khởi chạy ứng dụng
macasas

6

Tại loại nhắc nhở bảng điều khiển gỡ lỗi của Xcode:

image lookup -a 0x1234

Và nó sẽ cho bạn thấy một cái gì đó như:

  Address: MyApp[0x00018eb0] (MyApp.__TEXT.__text + 91088)
  Summary: MyApp`-[MyViewController viewDidAppear:] + 192 at MyViewController.m:202

Cảm ơn, tôi đã thực sự tìm kiếm điều này. Đáng ngạc nhiên là không có phím tắt để hiển thị toàn bộ "ngăn xếp cuộc gọi đầu tiên" dưới dạng ngăn xếp cuộc gọi, vì tôi đoán có thể dễ dàng viết một tập lệnh lldb Python.
Ilya

1

Bật lại 'Biên dịch cho ngón tay cái' (cấu hình gỡ lỗi) làm việc cho tôi.

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.