JNI 线程导致 SIGSEGV 赛普拉斯 fx2lp USB 芯片
JNI thread causing SIGSEGV Cypress fx2lp USB chip
我可以通过哪些方式调试此 JNI 代码?我看到它指出有问题的框架是 writeUSB 函数,但我没有发现任何问题。这个 Java 应用程序是为 Mac 编写的,它们是一个 JNI,用于与我们内部制造的硬件进行通信。我们硬件中的 USB 芯片来自 cypress fx2lp Cy64713。我不确定为什么这会导致 SIGSEGV...
这里全转储
http://pastebin.com/BbgK796a
此 JNI 的完整源代码在此处
https://bitbucket.org/snippets/partialdata/6L69r/ucs30interfacejni
当我插入我们的硬件时,这是 netbeans 中的调试器控制台,将其打开,然后调试应用程序。
向下滚动到堆栈跟踪的这一部分非常有用:
Stack: [0x000070000011a000,0x000070000021a000], sp=0x0000700000218010, free space=1016k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [UCS30InterfaceJNI.dylib+0x1146] _Z8writeUSBPP20IOUSBInterfaceStructPhi+0x46
C [UCS30InterfaceJNI.dylib+0xfcc] _Z15getSerialNumberPP20IOUSBInterfaceStruct+0x6c
C [UCS30InterfaceJNI.dylib+0x2b19] _Z14findUSBDevicesPc+0x259
C [UCS30InterfaceJNI.dylib+0x2f40] Java_ucs30interface_Main_findUCS30s+0x40
j ucs30interface.Main.findUCS30s()Ljava/lang/String;+0
尽管 C++ 编译器对参数名称进行了一些改动,但您可以看到程序失败时调用的函数的名称。
最上面的一个匹配类似 writeUSB(IOUSBInterfaceStruct**,int*) 的函数。找到一个这样的函数并寻找它使用指针的地方。该函数中的指针之一可能指向从未分配或已经释放的内存。
更新
如果您在顶级函数中看不到问题,则可能是在调用它的函数中。例如,如果调用它的函数 (getSerialNumber) 使用可能导致相同 SIGSEGV 的错误指针调用它。在使用 Netbeans 8.1 RC2 的 Linux 上,我可以使用调试器从 java 代码步进到 C++ 代码。您可以在 Mac 上尝试,但我不确定它是否有效。如果没有调试器,您可以使用 printf。在每行代码之间放一个。出现的印记在坏线之前,没有出现的印记在坏线之后。您应该确保所有 printf 都以 \n
结尾并刷新标准输出,否则当 SIGSEGV 发生时打印可能仍被缓冲。您还可以将该函数拆分为从该函数调用的更小的函数,这也有助于缩小范围。打印变量的值。作为字符串的命令需要在它来自的数组末尾之前有一个终止 0。您可能需要查看调用代码才能知道该数组的长度。接口是指向指针的指针可能会导致失败,因为它是错误的指针或指向错误的指针。问题可能出在函数 writeUSB 调用(如 WritePipe)中,如果该函数是内联的,它可能不会显示在堆栈跟踪中。
我可以通过哪些方式调试此 JNI 代码?我看到它指出有问题的框架是 writeUSB 函数,但我没有发现任何问题。这个 Java 应用程序是为 Mac 编写的,它们是一个 JNI,用于与我们内部制造的硬件进行通信。我们硬件中的 USB 芯片来自 cypress fx2lp Cy64713。我不确定为什么这会导致 SIGSEGV...
这里全转储 http://pastebin.com/BbgK796a
此 JNI 的完整源代码在此处 https://bitbucket.org/snippets/partialdata/6L69r/ucs30interfacejni
当我插入我们的硬件时,这是 netbeans 中的调试器控制台,将其打开,然后调试应用程序。
向下滚动到堆栈跟踪的这一部分非常有用:
Stack: [0x000070000011a000,0x000070000021a000], sp=0x0000700000218010, free space=1016k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [UCS30InterfaceJNI.dylib+0x1146] _Z8writeUSBPP20IOUSBInterfaceStructPhi+0x46
C [UCS30InterfaceJNI.dylib+0xfcc] _Z15getSerialNumberPP20IOUSBInterfaceStruct+0x6c
C [UCS30InterfaceJNI.dylib+0x2b19] _Z14findUSBDevicesPc+0x259
C [UCS30InterfaceJNI.dylib+0x2f40] Java_ucs30interface_Main_findUCS30s+0x40
j ucs30interface.Main.findUCS30s()Ljava/lang/String;+0
尽管 C++ 编译器对参数名称进行了一些改动,但您可以看到程序失败时调用的函数的名称。 最上面的一个匹配类似 writeUSB(IOUSBInterfaceStruct**,int*) 的函数。找到一个这样的函数并寻找它使用指针的地方。该函数中的指针之一可能指向从未分配或已经释放的内存。
更新
如果您在顶级函数中看不到问题,则可能是在调用它的函数中。例如,如果调用它的函数 (getSerialNumber) 使用可能导致相同 SIGSEGV 的错误指针调用它。在使用 Netbeans 8.1 RC2 的 Linux 上,我可以使用调试器从 java 代码步进到 C++ 代码。您可以在 Mac 上尝试,但我不确定它是否有效。如果没有调试器,您可以使用 printf。在每行代码之间放一个。出现的印记在坏线之前,没有出现的印记在坏线之后。您应该确保所有 printf 都以 \n
结尾并刷新标准输出,否则当 SIGSEGV 发生时打印可能仍被缓冲。您还可以将该函数拆分为从该函数调用的更小的函数,这也有助于缩小范围。打印变量的值。作为字符串的命令需要在它来自的数组末尾之前有一个终止 0。您可能需要查看调用代码才能知道该数组的长度。接口是指向指针的指针可能会导致失败,因为它是错误的指针或指向错误的指针。问题可能出在函数 writeUSB 调用(如 WritePipe)中,如果该函数是内联的,它可能不会显示在堆栈跟踪中。