0

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

这个函数的签名是:

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 的文字。

4

1 回答 1

0

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

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

  2. 恐慌信息很有趣:

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

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

祝你好运!

于 2013-10-31T04:11:17.217 回答