使用Xcode的All Exceptions断点时忽略某些异常

时间:2013-01-17 01:06:01

标签: iphone ios xcode

我在Xcode中配置了一个All Exceptions断点:

screenshot of an exception breakpoint configured in Xcode breakpoint pain, configured to make a sound when an exception is thrown

有时Xcode会停在以下一行:

[managedObjectContext save:&error];

带有以下回溯:

backtrace showing NSPersistentStoreCoordinator throwing an exception inside the call to save:

但如果单击“继续”,程序将继续运行,好像什么也没发生。

如何忽略这些“正常”异常,但仍然让调试器在我自己的代码中停止异常?

(我知道发生这种情况是因为Core Data内部抛出并捕获异常,并且Xcode只是在抛出异常时我的请求暂停程序。但是,我想忽略这些,所以我可以回到调试我自己的代码!)

主持人:这类似于"Xcode 4 exception breakpoint filtering",但我认为这个问题需要很长时间才能解决问题并且没有任何有用的答案。它们可以链接吗?

3 个答案:

答案 0 :(得分:86)

对于核心数据异常,我通常做的是从Xcode中删除“All Exceptions”断点,而不是:

  1. objc_exception_throw
  2. 上添加符号断点
  3. 将断点的条件设置为(BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"])
  4. 配置的断点应如下所示: Configuring the Breakpoint

    这将忽略用于控制流的任何私有Core Data异常(由类名称为前缀_NSCoreData确定)。请注意,相应的寄存器将取决于您运行的目标设备/模拟器。请查看this table以供参考。

    请注意,此技术可以轻松适应其他条件。棘手的部分在于制作BOOL和NSException强制转换以使lldb对条件感到满意。

答案 1 :(得分:38)

我编写了一个lldb脚本,它允许您使用更简单的语法选择性地忽略Objective-C异常,并且它可以处理OS X,iOS模拟器以及32位和64位ARM。

安装

  1. 将此脚本放在~/Library/lldb/ignore_specified_objc_exceptions.py或有用的地方。
  2. 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保存在其他地方,请使用正确的路径替换ignore_specified_objc_exceptions name:NSAccessibilityException className:NSSomeException

    2. 用法

      • 在Xcode中,添加断点以捕获所有 Objective-C 例外
      • 编辑断点并使用以下命令添加Debugger命令: NSException
      • 这会忽略-name NSAccessibilityException匹配-classNameNSSomeException匹配ignore_specified_objc_exceptions className:_NSCoreData
      • 的例外情况

      看起来应该是这样的:

      Screenshot showing a breakpoint set in Xcode per the instructions

      在您的情况下,您将使用{{1}}

      有关脚本和更多详细信息,请参阅http://chen.do/blog/2013/09/30/selectively-ignoring-objective-c-exceptions-in-xcode/

答案 2 :(得分:10)

如果您有一段代码,可以选择以下快速解答:第三方库,它会抛出您想要忽略的多个异常:

  1. 设置两个断点,一个在您要忽略的异常抛出代码块之前和之后。
  2. 运行程序,直到它停止异常,然后输入“断点列表”'进入调试器控制台,找到所有异常的数量'断点,它应该是这样的:
  3.   

    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中,编辑第一个断点(在抛出异常代码之前)并将操作更改为“调试器命令”。并输入'断点禁用2' (并设置'自动继续...'复选框)。

    2. 对违规行后的断点执行相同操作,并使用命令'断点启用2'。

    3. 所有断点异常现在将打开和关闭,因此它只在您需要时才会激活。