簡體   English   中英

使用Xcode的All Exceptions斷點時忽略某些異常

[英]Ignore certain exceptions when using Xcode's All Exceptions breakpoint

我在Xcode中配置了一個All Exceptions斷點:

在Xcode斷點痛苦中配置的異常斷點的屏幕截圖,配置為在拋出異常時發出聲音

有時候Xcode會停在一條線上:

[managedObjectContext save:&error];

具有以下回溯:

backtrace顯示NSPersistentStoreCoordinator在保存調用中拋出異常:

但如果單擊“繼續”,程序將繼續運行,就好像什么也沒發生

如何忽略這些“正常”異常,但仍然讓調試器在我自己的代碼中停止異常?

(我知道發生這種情況是因為Core Data內部拋出並捕獲異常,並且Xcode只是在拋出異常時遵循暫停程序的請求。但是,我想忽略這些,所以我可以回到調試我自己的代碼!)

版主:這類似於“Xcode 4異常斷點過濾” ,但我認為這個問題需要很長時間才能解決問題並且沒有任何有用的答案。 它們可以聯系起來嗎?

對於核心數據異常,我通常做的是從Xcode中刪除“All Exceptions”斷點,而是:

  1. objc_exception_throw上添加一個符號斷點
  2. 將斷點上的條件設置為(BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"])

配置的斷點應如下所示: 配置斷點

這將忽略用於控制流的任何私有Core Data異常(由類名稱為_NSCoreData前綴_NSCoreData )。 請注意,相應的寄存器將取決於您運行的目標設備/模擬器。請查看此表以供參考。

請注意,此技術可以輕松適應其他條件。 棘手的部分在於制作BOOL和NSException強制轉換以使lldb對條件感到滿意。

我編寫了一個lldb腳本,它允許您使用更簡單的語法選擇性地忽略Objective-C異常,並且它可以處理OS X,iOS模擬器以及32位和64位ARM。

安裝

  1. 將此腳本放在~/Library/lldb/ignore_specified_objc_exceptions.py或其他有用的地方。
import lldb
import re
import shlex

# This script allows Xcode to selectively ignore Obj-C exceptions
# based on any selector on the NSException instance

def getRegister(target):
    if target.triple.startswith('x86_64'):
        return "rdi"
    elif target.triple.startswith('i386'):
        return "eax"
    elif target.triple.startswith('arm64'):
        return "x0"
    else:
        return "r0"

def callMethodOnException(frame, register, method):
    return frame.EvaluateExpression("(NSString *)[(NSException *)${0} {1}]".format(register, method)).GetObjectDescription()

def filterException(debugger, user_input, result, unused):
    target = debugger.GetSelectedTarget()
    frame = target.GetProcess().GetSelectedThread().GetFrameAtIndex(0)

    if frame.symbol.name != 'objc_exception_throw':
        # We can't handle anything except objc_exception_throw
        return None

    filters = shlex.split(user_input)

    register = getRegister(target)


    for filter in filters:
        method, regexp_str = filter.split(":", 1)
        value = callMethodOnException(frame, register, method)

        if value is None:
            output = "Unable to grab exception from register {0} with method {1}; skipping...".format(register, method)
            result.PutCString(output)
            result.flush()
            continue

        regexp = re.compile(regexp_str)

        if regexp.match(value):
            output = "Skipping exception because exception's {0} ({1}) matches {2}".format(method, value, regexp_str)
            result.PutCString(output)
            result.flush()

            # If we tell the debugger to continue before this script finishes,
            # Xcode gets into a weird state where it won't refuse to quit LLDB,
            # so we set async so the script terminates and hands control back to Xcode
            debugger.SetAsync(True)
            debugger.HandleCommand("continue")
            return None

    return None

def __lldb_init_module(debugger, unused):
    debugger.HandleCommand('command script add --function ignore_specified_objc_exceptions.filterException ignore_specified_objc_exceptions')
  1. 將以下內容添加到~/.lldbinit

    command script import ~/Library/lldb/ignore_specified_objc_exceptions.py

    如果將其保存在其他~/Library/lldb/ignore_specified_objc_exceptions.py ,請使用正確的路徑替換~/Library/lldb/ignore_specified_objc_exceptions.py

用法

  • 在Xcode中,添加一個斷點來捕獲所有Objective-C異常
  • 編輯斷點並使用以下命令添加Debugger命令: ignore_specified_objc_exceptions name:NSAccessibilityException className:NSSomeException
  • 其中,這將忽略例外NSException -name匹配NSAccessibilityException OR -className匹配NSSomeException

它應該看起來像這樣:

屏幕截圖顯示了根據說明在Xcode中設置的斷點

在您的情況下,您將使用ignore_specified_objc_exceptions className:_NSCoreData

有關腳本和更多詳細信息,請參見http://chen.do/blog/2013/09/30/selectively-ignoring-objective-c-exceptions-in-xcode/

這里有一個替代的快速答案,當你有一個代碼塊時,例如第三方庫引發了你想要忽略的多個異常:

  1. 設置兩個斷點,一個在您要忽略的異常拋出代碼塊之前和之后。
  2. 運行程序,直到它在異常處停止,並在調試器控制台中鍵入“斷點列表”,並找到“所有異常”斷點的編號,它應如下所示:

2:names = {'objc_exception_throw','__ cxa_throw'},locations = 2選項:禁用2.1:where = libobjc.A.dylib objc_exception_throw, address = 0x00007fff8f8da6b3, unresolved, hit count = 0 2.2: where = libc++abi.dylib __cxa_throw,address = 0x00007fff8d19fab7,unresolved,hit count = 0

  1. 這意味着它是斷點2.現在在xcode中,編輯第一個斷點(在拋出異常代碼之前)並將操作更改為“debugger command”並輸入'breakpoint disable 2'(並設置'自動繼續...'復選框)。

  2. 對違規行后的斷點執行相同操作,並使用命令'breakpoint enable 2'。

所有斷點異常現在將打開和關閉,因此它僅在您需要時才會激活。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM