Xcode macOS:删除文件时的断点
在我用Objective-C编写的旧macOS应用程序中,我正在调试一个重复出现的问题,即在系统框架调用期间过早删除文件包。为了获得线索,我希望在删除文件时让调试器中断。为此,我在Xcode中的以下符号处设置了符号断点:Xcode macOS:删除文件时的断点,xcode,debugging,cocoa,nsfilemanager,unlink,Xcode,Debugging,Cocoa,Nsfilemanager,Unlink,在我用Objective-C编写的旧macOS应用程序中,我正在调试一个重复出现的问题,即在系统框架调用期间过早删除文件包。为了获得线索,我希望在删除文件时让调试器中断。为此,我在Xcode中的以下符号处设置了符号断点: unlink unlinkat -[NSFileManager removeItemAtPath:error:] -[NSFileManager removeItemAtURL:error:] 所有这些断点都按预期解析为实际断点,当文件按预期删除时,它们按预期中断。但在麻烦的
unlink
unlinkat
-[NSFileManager removeItemAtPath:error:]
-[NSFileManager removeItemAtURL:error:]
所有这些断点都按预期解析为实际断点,当文件按预期删除时,它们按预期中断。但在麻烦的过早删除文件期间,不会发生中断
macOS中是否有其他可以删除文件的函数,我应该为其添加断点
背景资料:
在对新复制(如文件>复制)但从未在保存的文档包之前调用[super saveDocument]
时,我的自定义NSDocument子类中会出现此问题。此类文档包驻留在~/Library/Autosave Information/
中,当一切正常时,将一直保留在那里,直到出现“保存”面板并随后被取消。但是,在错误情况下,当用户单击“保存”“文件”>“保存”(或自动保存)时,软件包会立即消失,这显然会导致稍后的错误,表明删除的软件包无法移动到“保存”面板返回的路径
我还尝试在该包出现后,在单击文件>保存之前,将其POSIX权限更改为octal 500。我的想法是它不能被删除,我还打开了所有的异常和错误断点,希望神秘的删除程序能在调试器控制台上发出嘎嘎声。结果:软件包没有被删除,正如我所假设的,保存操作成功了。但没有任何声音。因此,这个神秘的删除器确实是个问题,但显然它既隐蔽又宽容:(
2019年7月19日更新:
在找到其他事情做了5天之后,我决定咬紧牙关,按照Ken Thomases的建议使用DTrace。它起了作用,向我显示主题文件包中的所有文件都是通过调用libsystem\u kernel.dylib\u unlink
删除的,而-[NSFileManager removietematpath:error:
又调用了DTrace
我不知道为什么我在这些函数上的断点没有因为这些调用而中断,除了可能在堆栈跟踪的底部有一条线索,提到“xpc”。这个文件删除是否可能是由xpc助手进程完成的?DTrace是否也探测被探测进程的助手进程?这将非常令人惊讶
以下是DTrace会议记录摘要:
Air2 jk$ sudo dtrace -n 'syscall::unlink*:entry,syscall::rmdir:entry,syscall::rename:entry { printf("time=%d arg=%s\n", timestamp/1000000000, copyinstr(arg0)); ustack(100); }' -p `pgrep MyApp`
Password:
dtrace: description 'syscall::unlink*:entry,syscall::rmdir:entry,syscall::rename:entry ' matched 4 probes
CPU ID FUNCTION:NAME
1 178 unlink:entry time=6562 arg=/Users/jk/Library/Autosave Information/Unsaved MyApp Document.bmco
libsystem_kernel.dylib`__unlink+0xa
libremovefile.dylib`__removefile_tree_walker+0x147
libremovefile.dylib`removefile+0x99
Foundation`-[NSFilesystemItemRemoveOperation main]+0xba
Foundation`__NSOPERATION_IS_INVOKING_MAIN__+0x11
Foundation`-[NSOperation start]+0x2db
Foundation`-[NSFileManager removeItemAtPath:error:]+0x54
AppKit`__90-[NSDocumentController(NSInternal) _autoreopenDocumentsFromRecords:withCompletionHandler:]_block_invoke_2+0x90
AppKit`__89-[NSDocumentController reopenDocumentForURL:withContentsOfURL:display:completionHandler:]_block_invoke_2+0xa6
AppKit`___NSMainRunLoopPerformBlockInModes_block_invoke+0x19
CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__+0xc
CoreFoundation`__CFRunLoopDoBlocks+0x17b
CoreFoundation`__CFRunLoopRun+0xae8
CoreFoundation`CFRunLoopRunSpecific+0x1f3
HIToolbox`RunCurrentEventLoopInMode+0x124
HIToolbox`ReceiveNextEventCommon+0x164
HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter+0x40
AppKit`_DPSNextEvent+0x3de
AppKit`-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]+0x548
ViewBridge`-[NSViewServiceApplication nextEventMatchingMask:untilDate:inMode:dequeue:]+0x5f
AppKit`-[NSApplication run]+0x292
AppKit`NSApplicationMain+0x309
libxpc.dylib`_xpc_objc_main.cold.3+0x38
libxpc.dylib`_xpc_objc_main+0x203
libxpc.dylib`_xpc_copy_xpcservice_dictionary
ViewBridge`xpc_connection_handler
ViewBridge`NSViewServiceApplicationMain+0xbff
com.apple.appkit.xpc.openAndSavePanelService`main+0xc0
libdyld.dylib`start+0x1
com.apple.appkit.xpc.openAndSavePanelService`0x1
(该成绩单中的调用显然试图取消与文件包的链接,我认为这可能会失败,因为文件包不是空的。接下来是几个类似的调用,遍历文件包树,删除每个节点,最后重复该调用删除文件包,显然成功。)
更新2019-08-06
虽然我们现在知道问题的低级原因,但我们仍然不知道高级原因。我发现问题(过早删除
~/Library/Autosave Information
中的临时文档文件)只发生在macOS 10.15 Beta 4-5(当前版本)中只有在关闭app Sandbox的情况下才能构建应用程序。当app Sandbox打开时,相关的自动保存信息
位于应用程序容器中的不同位置,因此这应该是一个很好的线索!通过一个小的演示应用程序,核心数据,基于文档,这个问题很容易重现,我已经向苹果提交了一个简短的视频eo.如果任何人有苹果的线路,请将他们的注意力转移到FB6937676!重命名操作将使源路径不再引用文件(看起来源路径上的文件已被删除)。它还可以取消链接/删除目标路径上的文件,尽管它将替换为源路径上的文件。因此,这将是rename()
,rename()
,rename ex\u np()
,以及rename atx\u np()
当然,rmdir()
显然,有一个隐藏的delete()
系统调用。它被描述为“使用Carbon语义从文件系统中删除一个名称”。框架可能正在使用它。谢谢你,肯。我为你提到的所有六个函数都添加了断点(包括rmdir
,因为我刚刚记得我的文档是一个包)。但仍然没有中断。我在苹果开源XNU内核中发现了delete()
函数。它确实有一个非常奇怪的声明:int delete(user\u addr\u t path)no\u SYSCALL\u STUB;}{private delete(Carbon semantics)
。断点导航器不会将symboldelete
解析为delete()
。相当隐蔽。我明天会进一步研究它。您可以使用的另一个工具是DTrace。它在很大程度上被系统完整性保护(SIP)所阉割,但您可以在不完全禁用SIP的情况下重新启用它。然后,您可以使用errinfo
或dtruss
现成的基于DTrace的工具。如果这些工具没有提供您要查找的确切信息,您可以直接使用DTrace
和一行或小脚本来获取更多信息。谢谢。@kenthomass与往常一样正确。DTraCE在某种程度上工作在断点失败的地方。我在编辑中解释了这个问题。我很高兴你找到了罪犯。我确实认为保存面板已经过时了,但不会想到它会删除任何东西!当你警告你正在重写现有文档时,你选择替换吗?g XPC服务中的系统调用:它根本不遵循流程。默认情况下,syscall
提供程序观察整个系统,而不是指定的流程。您必须在探测器上设置一个类似于/pid=$target/
的条件,以关注t