DTrace objc:无效的探针说明符:“未引用$ 1”

时间:2019-08-02 15:15:05

标签: dtrace

由于某种原因,我需要确定在我的macOS应用中,当新复制的文档中首次出现“保存”面板时,macOS会删除临时自动保存的文档文件,这当然会导致以后保存失败。这是DTrace成绩单,我已经做了一些删节:

Air2 jk$ sudo dtrace -n 'syscall::unlink*:entry { printf("time=%d  execname=%s  arg=%s\n", timestamp/1000000000, execname, copyinstr(arg0)); ustack(100); }' -p `pgrep MyApp`
Password:
dtrace: description 'syscall::unlink*:entry' matched 4 probes
CPU     ID                    FUNCTION:NAME
  1    178                     unlink:entry time=6562  execname=com.apple.appkit  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
  

以上结果告诉我

(1)不是我的进程,而是一个名为com.apple.appkit或也许是com.apple.appkit.xpc.openAndSavePanelService的进程,它最终将调用unlink,并且

(2)在-[NSDocumentController reopenDocumentForURL:withContentsOfURL:display:completionHandler:]中执行Objective-C块时会发生这种情况。

我认为后者是解决问题的线索,因为应该没有什么可以重提的。因此,我想找出所谓的-[NSDocumentController reopenDocumentForURL:withContentsOfURL:display:completionHandler:]。上面的结果并不能说明这一点,因为这是一个块调用。

因此,我尝试使用一个Objective-C探针来编写另一个DTrace命令,只要此appkit进程调用-[NSDocumentController reopenDocumentForURL:withContentsOfURL:display:completionHandler:],该命令就会触发:

sudo dtrace -n 'objc$target:NSDocumentController:-reopenDocumentForURL?withContentsOfURL?display?completionHandler?:entry { printf("time=%d  arg=%s\n", timestamp/1000000000, copyinstr(arg0)); ustack(100); }' -p `pgrep appkit`
dtrace: invalid probe specifier objc$target:NSDocumentController:-reopenDocumentForURL?withContentsOfURL?display?completionHandler?:entry { printf("time=%d  arg=%s\n", timestamp/1000000000, copyinstr(arg0)); ustack(100); }: extraneous argument '7135' ($1 is not referenced)
  

但是正如您所看到的,它抱怨无效的探针说明符,并且没有引用 $ 1 -p显然可以正常工作,因为7135确实是Mac上运行的com.apple.appkit进程的进程的pid。我认为这是被引用的 $ 1 ,由于某种原因, $ target 并未按预期引用

因此,我改为按字面值指定了pid( objc7135 ),并且有效了(匹配1个探针),但是它没有捕获所需的调用,可能是因为调用由进程com.apple.appkit.xpc.openAndSavePanelService second 个正在运行的实例完成,只要发生保存或自动保存,该实例就会启动,当然,只要我将应用程序切换到终端以运行{{ 1}},并进行新的探查。因此,在我可以对其设置探针之前,该呼叫已经发生。啊!!!

如果我可以使DTrace命令正常工作,我认为它会附加到新启动的appkit进程中并给出我想要的答案。为什么我的DTrace命令给出该错误?

更新2019年8月7日:

好吧,我确定我寻找的原因实际上是macOS AppKit中的可重现错误,因此我提交了一个不错的新反馈,并祈祷苹果公司对其进行了修复。但是我仍然认为我的问题在这里是一个很好的DTrace问题,并且很乐意接受正确的答案:)

更新2019年8月9日:

我在transposit.com上尝试了@ahl的建议。意识到嵌套的DTrace调用将是反斜杠转义,我将原始的DTrace调用放在了一个名为DTraceMe.sh的文件中,然后运行了此命令:

ps


当我的应用程序显示麻烦的“保存”面板时,这可以修复错误消息并运行sudo dtrace -wn 'proc:::exec-success { if (execname == "com.apple.appkit") { printf("Launched: %s pid=%d\n", execname, pid); system("~/Desktop/Temp/DTraceMe.sh"); }}' 。真好!但是不幸的是,像往常一样,内部DTrace实例显然需要几秒钟来安装其探针(并打印 dtrace:blahblah匹配了1个探针)。因此,待布防时,我试图跟踪的对NSDocumentController的麻烦调用已经完成并且消失了。

好吧,我想,也许我可以通过运行一个lldb实例来终止新启动的com.apple.appkit进程足够长的时间,以使DTrace正常运行,该实例将附加到下一个启动的com.apple.appkit:

DTraceMe.sh


令我惊讶的是,实际上它确实中断了目标com.apple.appkit进程,并在启动后立即停止了该进程。 (当然,我已经禁用了系统完整性保护。)但是现在内部的DTrace实例立即告诉我,我的探针说明符与任何探针都不匹配,大概是因为com.apple.appkit在它同时不能与DTrace合作。由lldb停止。伤心。

2 个答案:

答案 0 :(得分:2)

似乎pgrep appkit返回了多个pid,它们可以解释$1 is not referenced错误。

跟踪新创建的流程可能很棘手,具体取决于您要尝试执行的操作。在这种情况下,建议您跟踪proc:::exec-success探针,然后使用system()操作触发dtrace命令的另一个实例,该实例跟踪新创建的进程

答案 1 :(得分:0)

我喜欢暴力破解方法。这将捕获所有unlink调用(除非某些东西正在清除很多文件,文件取消链接实际上很少见):

dtrace -n 'syscall::unlink*:entry { printf("time=%d arg=%s\n",
    timestamp/1000000000, copyinstr(arg0)); ustack(100); }'

将输出保存到文件中并通过它。

或者,如果您知道可执行文件的名称,则添加类似/ execname == "com.apple.appkit" /谓词的内容,以将探测限制为仅与谓词匹配的那些事件:

dtrace -n 'syscall::unlink*:entry / execname == "com.apple.appkit" /
    { printf("time=%d arg=%s\n", timestamp/1000000000, copyinstr(arg0)); ustack(100); }'