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

Phi*_*vin 76 iphone xcode ios

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

在Xcode断点痛苦中配置的异常断点的屏幕截图,配置为在抛出异常时发出声音

有时候Xcode会停在一条线上:

[managedObjectContext save:&error];
Run Code Online (Sandbox Code Playgroud)

具有以下回溯:

backtrace显示NSPersistentStoreCoordinator在保存调用中抛出异常:

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

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

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

版主:这类似于"Xcode 4异常断点过滤",但我认为这个问题需要很长时间才能解决问题并且没有任何有用的答案.它们可以联系起来吗?

Bla*_*ers 86

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

  1. 添加符号断点 objc_exception_throw
  2. 在断点上设置条件为 (BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"])

配置的断点应如下所示: 配置断点

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

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

  • 在iPhone6上使用iOS 8.2的Xcode 6.2要求我将```$ r0```改为```$ x0```(如下所示:http://www.sealiesoftware.com/blog/archive/2013/ 9月12日/ objc_explain_So_you_crashed_in_objc_msgSend_iPhone_5s_Edition.html).因此条件变为:````(BOOL)(!(BOOL)[[(NSException*)$ x0 className] hasPrefix:@"_ NSCoreData"])``` (4认同)

che*_*ndo 39

我编写了一个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')
Run Code Online (Sandbox Code Playgroud)
  1. 将以下内容添加到~/.lldbinit:

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

    ~/Library/lldb/ignore_specified_objc_exceptions.py如果您将其保存在其他位置,请替换为正确的路径.

用法

  • 在Xcode中,添加一个断点来捕获所有Objective-C异常
  • 编辑断点并使用以下命令添加调试器命令: ignore_specified_objc_exceptions name:NSAccessibilityException className:NSSomeException
  • 这将忽略NSException -name匹配NSAccessibilityExceptionOR -className匹配的异常NSSomeException

它应该看起来像这样:

屏幕截图显示了根据说明在Xcode中设置的断点

在你的情况下,你会使用 ignore_specified_objc_exceptions className:_NSCoreData

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


jam*_*rez 12

这里有一个替代的快速答案,当你有一个代码块时,例如第三方库引发了你想要忽略的多个异常:

  1. 设置两个断点,一个在您要忽略的异常抛出代码块之前和之后.
  2. 运行程序,直到它在异常处停止,并在调试器控制台中键入"断点列表",并找到"所有异常"断点的编号,它应如下所示:

2:名称= { 'objc_exception_throw', '__cxa_throw'},位置= 2选项:禁用2.1:其中= libobjc.A.dylib objc_exception_throw, address = 0x00007fff8f8da6b3, unresolved, hit count = 0 2.2: where = libc++abi.dylib__cxa_throw,地址= 0x00007fff8d19fab7,没有得到解决,命中计数= 0

  1. 这意味着它是断点2.现在在Xcode,编辑第一个断点(异常抛出代码之前),改变行动,以"调试程序命令"并键入"断点禁用2"(并设置"自动继续..."复选框).

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

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