【问题标题】:Occasional OSX kernel panic in RetrieveINQUIRYData()Retrieve INQUIRY Data() 中偶尔出现 OS X 内核崩溃
【发布时间】:2013-10-29 12:18:51
【问题描述】:

我有一个 SCSI 驱动程序,它在启动过程中调用 IOSCSIPrimaryCommandsDevice::RetrieveINQUIRYData()。有时,在测试期间拔出、弹出、重新插入和滥用设备后,会发生内核崩溃。

这个函数的signature是:

bool RetrieveINQUIRYData (
    UInt8 EVPD,
    UInt8 inquiryPage,
    UInt8 * inquiryBuffer,
    UInt16 * dataSize);

调用这个的例程是这样开始的。它模仿来自IOSCSITargetDevice.cpp的PublishUnitSerialNumber

void MyDriverClass::PublishUnitSerialNumber ( IOService *             object )
{
    bool                            result                                  = false;
    SCSICmd_INQUIRY_Page80_Header * data                                    = NULL;
    IOBufferMemoryDescriptor *      buffer                                  = NULL;
    OSString *                      string                                  = NULL;
    char                            serialNumber[kINQUIRY_MaximumDataSize]  = { 0 };
    UInt16                          length                                  = 0;
    SInt16                          serialLength                            = 0;

    DEBUG_LOG("%s[%p]::%s(%p)\n", getName(), this, __FUNCTION__, object);

    buffer = IOBufferMemoryDescriptor::withCapacity ( kINQUIRY_MaximumDataSize, kIODirectionIn );
    require( buffer != NULL, ErrorExit );

    data = (SCSICmd_INQUIRY_Page80_Header*) buffer->getBytesNoCopy();
    length = kINQUIRY_MaximumDataSize;

    require(data != NULL, ReleaseBuffer);

    bzero ( data, kINQUIRY_MaximumDataSize );

    result = RetrieveINQUIRYData ( 0x01,
                                      kINQUIRY_Page80_PageCode,
                                      ( UInt8 * ) data,
                                      &length ); //PANIC IN HERE!

    require ( result, ReleaseBuffer );
    require ( ( data->PAGE_CODE == kINQUIRY_Page80_PageCode ), ReleaseBuffer );

这在大多数情况下都有效,只是偶尔会出现恐慌。 GDB 回溯没有帮助,因为该函数中没有符号,所以我只知道它是在另一个函数调用之后。我也找不到这个函数的源代码——我认为它是闭源 IOKit 代码的一部分。

#0  Debugger (message=0x8001003b <Address 0x8001003b out of bounds>) at /SourceCache/xnu/xnu-1504.15.3/osfmk/i386/AT386/model_dep.c:867
#1  0xffffff8000204d15 in panic (str=0xffffff800057ecb8 "Kernel trap at 0x%016llx, type %d=%s, registers:\nCR0: 0x%016llx, CR2: 0x%016llx, CR3: 0x%016llx, CR4: 0x%016llx\nRAX: 0x%016llx, RBX: 0x%016llx, RCX: 0x%016llx, RDX: 0x%016llx\nRSP: 0x%016llx, RBP: 0x%0"...) at /SourceCache/xnu/xnu-1504.15.3/osfmk/kern/debug.c:303
#2  0xffffff80002d1208 in panic_trap [inlined] () at :1100
#3  0xffffff80002d1208 in kernel_trap (state=<value temporarily unavailable, due to optimizations>) at /SourceCache/xnu/xnu-1504.15.3/osfmk/i386/trap.c:1001
#4  0xffffff80002e3f4a in trap_from_kernel () at pmap.h:215
#5  0xffffff7f808040b6 in ?? ()
#6  0xffffff7f80804b8b in ?? ()
#7  0xffffff7f80f1324c in com_company_driver_myDriver::PublishUnitSerialNumber (this=0xffffff80130e0600, object=0xffffff8015375000) at /Volumes/user/src/driver/MyDriver.cpp:106
#8  0xffffff7f80f13553 in com_company_driver_myDriver::start (this=0xffffff80130e0600, provider=0xffffff8015375000) at /Volumes/user/src/driver/MyDriver.cpp:53
#9  0xffffff800052d5a6 in IOService::startCandidate (this=0x2710, service=0xe) at /SourceCache/xnu/xnu-1504.15.3/iokit/Kernel/IOService.cpp:2879
#10 0xffffff800052dcb1 in IOService::probeCandidates (this=0xffffff8015375000, matches=<value temporarily unavailable, due to optimizations>) at /SourceCache/xnu/xnu-1504.15.3/iokit/Kernel/IOService.cpp:2798
...
...

在调用RetrieveINQUIRYData() 之前我应该​​检查或做哪些我在上面的代码中没有做的事情?据我所知,所有的指针都被检查为 NULL,长度设置为常量,唯一的另一个参数是 EVPD 的文字。

【问题讨论】:

    标签: macos driver kernel-extension scsi


    【解决方案1】:

    我不熟悉 SCSI 堆栈,但这里有一些想法:

    1. 即使是封闭源代码的 kext 也有基本的调试符号。因此,如果您 add-kext 来自 /System/Library/Extensions/ 的相关 kext,您至少应该获得函数/方法名称(以及签名,如果 C++)。你当然不会得到行号,但你会得到函数反汇编边界等。

    2. 恐慌信息很有趣:

    #0 Debugger (message=0x8001003b &lt;Address 0x8001003b out of bounds&gt;) at /SourceCache/xnu/xnu-1504.15.3/osfmk/i386/AT386/model_dep.c:867

    在 10.6.8 源中,我找不到该消息的来源,因此我不太确定预期的界限以及此要求的来源。看起来它可能是一个物理地址 - 您是否可以插入一些 kprintf 调试输出来转储缓冲区的 getPhysicalSegment(0, NULL, 0) 结果并查看它是否与触发 KP 的地址匹配?如果不是这样,请查看您是否可以找出导致崩溃的指令以及错误地址的来源。

    祝你好运!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-21
      • 2018-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-23
      相关资源
      最近更新 更多