简体   繁体   English

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

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

I have an All Exceptions breakpoint configured in Xcode: 我在Xcode中配置了一个All Exceptions断点:

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

Sometimes Xcode will stop on a line like: 有时候Xcode会停在一条线上:

[managedObjectContext save:&error];

with the following backtrace: 具有以下回溯:

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

but the program continues on as if nothing happened if you click Continue. 但如果单击“继续”,程序将继续运行,就好像什么也没发生

How can I ignore these "normal" exceptions, but still have the debugger stop on exceptions in my own code? 如何忽略这些“正常”异常,但仍然让调试器在我自己的代码中停止异常?

(I understand that this happens because Core Data internally throws and catches exceptions, and that Xcode is simply honoring my request to pause the program whenever an exception is thrown. However, I want to ignore these so I can get back to debugging my own code!) (我知道发生这种情况是因为Core Data内部抛出并捕获异常,并且Xcode只是在抛出异常时遵循暂停程序的请求。但是,我想忽略这些,所以我可以回到调试我自己的代码!)

Moderators: this is similar to "Xcode 4 exception breakpoint filtering" , but I think that question takes too long to get around to the point and doesn't have any useful answers. 版主:这类似于“Xcode 4异常断点过滤” ,但我认为这个问题需要很长时间才能解决问题并且没有任何有用的答案。 Can they be linked? 它们可以联系起来吗?

For Core Data exceptions, what I typically do is remove the "All Exceptions" breakpoint from Xcode and instead: 对于核心数据异常,我通常做的是从Xcode中删除“All Exceptions”断点,而是:

  1. Add a Symbolic Breakpoint on objc_exception_throw objc_exception_throw上添加一个符号断点
  2. Set a Condition on the Breakpoint to (BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"]) 将断点上的条件设置为(BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"])

The configured breakpoint should look something like this: 配置的断点应如下所示: 配置断点

This will ignore any private Core Data exceptions (as determined by the class name being prefixed by _NSCoreData ) that are used for control flow. 这将忽略用于控制流的任何私有Core Data异常(由类名称为_NSCoreData前缀_NSCoreData )。 Note that the appropriate register is going to be dependent on the target device / simulator that you are running in. Take a look at this table for reference. 请注意,相应的寄存器将取决于您运行的目标设备/模拟器。请查看此表以供参考。

Note that this technique can be adapted easily to other conditionals. 请注意,此技术可以轻松适应其他条件。 The tricky part was in crafting the BOOL and NSException casts to get lldb happy with the condition. 棘手的部分在于制作BOOL和NSException强制转换以使lldb对条件感到满意。

I wrote an lldb script that lets you selectively ignore Objective-C exceptions with a much simpler syntax, and it handles both OS X, iOS Simulator, and both 32bit and 64bit ARM. 我编写了一个lldb脚本,它允许您使用更简单的语法选择性地忽略Objective-C异常,并且它可以处理OS X,iOS模拟器以及32位和64位ARM。

Installation 安装

  1. Put this script in ~/Library/lldb/ignore_specified_objc_exceptions.py or somewhere useful. 将此脚本放在~/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. Add the following to ~/.lldbinit : 将以下内容添加到~/.lldbinit

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

    replacing ~/Library/lldb/ignore_specified_objc_exceptions.py with the correct path if you saved it somewhere else. 如果将其保存在其他~/Library/lldb/ignore_specified_objc_exceptions.py ,请使用正确的路径替换~/Library/lldb/ignore_specified_objc_exceptions.py

Usage 用法

  • In Xcode, add a breakpoint to catch all Objective-C exceptions 在Xcode中,添加一个断点来捕获所有Objective-C异常
  • Edit the breakpoint and add a Debugger Command with the following command: ignore_specified_objc_exceptions name:NSAccessibilityException className:NSSomeException 编辑断点并使用以下命令添加Debugger命令: ignore_specified_objc_exceptions name:NSAccessibilityException className:NSSomeException
  • This will ignore exceptions where NSException -name matches NSAccessibilityException OR -className matches NSSomeException 其中,这将忽略例外NSException -name匹配NSAccessibilityException OR -className匹配NSSomeException

It should look something like this: 它应该看起来像这样:

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

In your case, you would use ignore_specified_objc_exceptions className:_NSCoreData 在您的情况下,您将使用ignore_specified_objc_exceptions className:_NSCoreData

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

Here is an alternative quick answer for when you have a block of code eg a 3rd part library that throws multiple exceptions that you want to ignore: 这里有一个替代的快速答案,当你有一个代码块时,例如第三方库引发了你想要忽略的多个异常:

  1. Set two breakpoints, one before and one after the exception throwing block of code you want to ignore. 设置两个断点,一个在您要忽略的异常抛出代码块之前和之后。
  2. Run the program, until it stops at an exception, and type 'breakpoint list' into the debugger console, and find the number of the 'all exceptions' break point, it should look like this: 运行程序,直到它在异常处停止,并在调试器控制台中键入“断点列表”,并找到“所有异常”断点的编号,它应如下所示:

2: names = {'objc_exception_throw', '__cxa_throw'}, locations = 2 Options: disabled 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 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. This means it is breakpoint 2. Now in xcode, edit the first breakpoint (before the exception throwing code) and change the action to 'debugger command' and type in 'breakpoint disable 2' (and set 'automatically continue...' checkbox ). 这意味着它是断点2.现在在xcode中,编辑第一个断点(在抛出异常代码之前)并将操作更改为“debugger command”并输入'breakpoint disable 2'(并设置'自动继续...'复选框)。

  2. Do the same for the break point after the offending line and have the command 'breakpoint enable 2'. 对违规行后的断点执行相同操作,并使用命令'breakpoint enable 2'。

The all breakpoints exception will now turn on and off so it's only active when you need it. 所有断点异常现在将打开和关闭,因此它仅在您需要时才会激活。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM