我有一个 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 的文字。