Import IORegistryEntrySearchCFProperty from Macapi.IOKit in Delphi for OSX64

拥有回忆 提交于 2021-02-09 10:42:31

问题


I used this import definition in OSX32 successfully:

uses
  MacApi.ObjectiveC,
  MacApi.Foundation,
  Macapi.CoreFoundation,
  Macapi.Mach,
  Macapi.IOKit;

type
  io_iterator_t = io_object_t;
  io_name_t = array[0..127] of AnsiChar;

function IORegistryEntrySearchCFProperty(entry: io_registry_entry_t;
  plane: io_name_t; key: CFStringRef; allocator: CFAllocatorRef;
  options: IOOptionBits): CFTypeRef; cdecl;
  external libIOKit name _PU + 'IORegistryEntrySearchCFProperty';

function IOServiceGetMatchingServices(masterPort: mach_port_t;
  matching: CFDictionaryRef; var existing: io_iterator_t): kern_return_t; cdecl;
  external libIOKit name _PU + 'IOServiceGetMatchingServices';

function IOIteratorNext(name: io_iterator_t): io_object_t; cdecl;
  external libIOKit name _PU + 'IOIteratorNext';

const
  kIOSerialBSDServiceValue = 'IOSerialBSDClient';
  kIOSerialBSDTypeKey      = 'IOSerialBSDClientType';
  kIOSerialBSDModemType    = 'IOModemSerialStream';
  kIOUSBDeviceClassName    = 'IOUSBDevice';
  kIOCalloutDeviceKey      = 'IOCalloutDevice';
  kIOTTYDeviceKey          = 'IOTTYDevice';
  kIOServicePlane          = 'IOService';
  kUSBInterfaceNumber      = 'bInterfaceNumber';
  kUSBVendorID             = 'idVendor';
  kUSBProductID            = 'idProduct';

  kIORegistryIterateRecursively = $00000001;
  kIORegistryIterateParents       = $00000002;

Since the migration to OSX64 I get a read access violation within the function IORegistryEntrySearchCFProperty.

From my point of view, there is no change in the parameters of IORegistryEntrySearchCFProperty from 32bit to 64bit.

The API function is used to read out vendor ID and the product ID of a USB device:

function TSerialInterface.SearchUSBSerialDevice(const Service: string; VendorID, ProductID: cardinal): integer;
var
  MatchingDictionary: CFMutableDictionaryRef;
  Iter: io_iterator_t;
  USBRef: io_service_t;
  ret: kern_return_t;
  ResAsCFString: CFTypeRef;
  aBsdPath: PAnsiChar;
  Bsd: array[0..1024] of AnsiChar;
  sBsd: string;
  VID, PID: Int32;
begin
  result := 0;
  MatchingDictionary := IOServiceMatching(kIOSerialBSDServiceValue);
  ret := IOServiceGetMatchingServices(kIOMasterPortDefault,
    CFDictionaryRef(MatchingDictionary), Iter);
  if (ret = KERN_SUCCESS) and (Iter <> 0) then
  begin
    try
      repeat
        USBRef := IOIteratorNext(Iter);
        if USBRef <> 0 then
        begin
          // USB device found
          Bsd[0] := #0;
          VID := 0;
          PID := 0;
          ResAsCFString := IORegistryEntryCreateCFProperty(USBRef,
            CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
          if assigned(ResAsCFString) then
          begin
            aBsdPath := CFStringGetCStringPtr(ResAsCFString,
              kCFStringEncodingASCII);
            if assigned(aBsdPath) then
              sBsd := string(aBsdPath)
            else if CFStringGetCString(ResAsCFString, @Bsd[0], sizeof(Bsd),
                kCFStringEncodingASCII) then
              sBsd := string(Bsd)
            else
              sBsd := ''; // Invalid device path
          end;
          ResAsCFString := IORegistryEntrySearchCFProperty(USBRef,
            kIOServicePlane, CFSTR(kUSBVendorID), kCFAllocatorDefault,
            kIORegistryIterateRecursively + kIORegistryIterateParents);
          if assigned(ResAsCFString) then
            if not CFNumberGetValue(ResAsCFString, kCFNumberIntType, @VID) then
              VID := 0;
          ResAsCFString := IORegistryEntrySearchCFProperty(USBRef,
            kIOServicePlane, CFSTR(kUSBProductID), kCFAllocatorDefault,
            kIORegistryIterateRecursively + kIORegistryIterateParents);
          if assigned(ResAsCFString) then
            if not CFNumberGetValue(ResAsCFString, kCFNumberIntType, @PID) then
              PID := 0;
          Log.d(name + ': USBDevice "' + sBsd + '" VID/PID: ' + IntToHex(VID) + '/' + IntToHex(PID));
        end;
      until USBRef = 0;
    finally
      IOObjectRelease(Iter);
    end;
 end; 

I have implemented the above function also with C in XCode and can run this code without any troubles.

At exception (EAccessViolation: Access violation at address 00007FFF3A929716, accessing adress 000000000000000000) I see the following call stack in the Delphi IDE:

*System._DbgExcNotify(int, void*, System.SmallString<(unsigned char)255>*, void*, void*)(0,0x00000001039035e0,0x00000001012fa22e,0x00007fff3a929716,0x0000000000000000)
System.NotifyReRaise(System.TObject*, void*)(0x00000001039035e0,0x00007fff3a929716)
System._RaiseAtExcept(System.TObject*, void*)(0x00000001039035e0,0x00007fff3a929716)
System.Internal.Excutils.SignalConverter(NativeUInt, NativeUInt, NativeUInt)(140734176073494,0,11)
:000000010003CDE0 System::Internal::Excutils::GetExceptionObject(NativeUInt, NativeUInt, unsigned long)
:00007FFF3D27B2A0 IORegistryEntrySearchCFProperty
Serialinterface.TSerialInterface.SearchComPortForUSB(System.UnicodeString, unsigned int, unsigned int)(0x000000020978e5e0,'USBser',2283,65287)* 

For deeper analyze, I have added here the generated assembler code of a small test procedure that calls IORegistryEntrySearchCFProperty.

Object Pascal in Unit3.pas:

procedure Test
var
  USBRef: io_service_t;
  key: CFStringRef;
  allocator: CFAllocatorRef;
  ResAsCFString: CFTypeRef;
begin
  USBRef := 0;
  key := CFSTR(kUSBVendorID);
  allocator := kCFAllocatorDefault;
  ResAsCFString := IORegistryEntrySearchCFProperty(USBRef,
    kIOServicePlane, key, allocator, 0);   
end;

The Delphi debugger CPU view shows the disassembled x64 code:

Unit3.pas.38: USBRef := 0;
000000010079CC43 C745FC00000000   mov dword ptr [rbp - 0x4], 0x0
Unit3.pas.39: key := CFSTR(kUSBVendorID);
000000010079CC4A 488D355B881000   lea rsi, [rip + 0x10885b]; __unnamed_1 + 12
000000010079CC51 488D7DD8         lea rdi, [rbp - 0x28]
000000010079CC55 E8E69987FF       call 0x100016640; System.UTF8Encode(System.UnicodeString) at System.pas:39603
000000010079CC5A EB00             jmp 0x10079cc5c; <+44> at Unit3.pas:39
000000010079CC5C 488B7DD8         mov rdi, qword ptr [rbp - 0x28]
000000010079CC60 E85B9B87FF       call 0x1000167c0; System._LStrToPChar(System.AnsiStringT<(unsigned short)0>) at System.pas:28783
000000010079CC65 48898538FFFFFF   mov qword ptr [rbp - 0xc8], rax
000000010079CC6C EB00             jmp 0x10079cc6e; <+62> at Unit3.pas:39
000000010079CC6E 488BBD38FFFFFF   mov rdi, qword ptr [rbp - 0xc8]
000000010079CC75 E8767789FF       call 0x1000343f0; Macapi::Corefoundation::__CFStringMakeConstantString(char*)
000000010079CC7A 48898530FFFFFF   mov qword ptr [rbp - 0xd0], rax
000000010079CC81 EB00             jmp 0x10079cc83; <+83> at Unit3.pas:39
000000010079CC83 488B8530FFFFFF   mov rax, qword ptr [rbp - 0xd0]
000000010079CC8A 488945F0         mov qword ptr [rbp - 0x10], rax
Unit3.pas.40: allocator := kCFAllocatorDefault;
000000010079CC8E E8AD7A89FF       call 0x100034740; Macapi.Corefoundation.kCFAllocatorDefault() at CFBaseImpl.inc:65
000000010079CC93 48898528FFFFFF   mov qword ptr [rbp - 0xd8], rax
000000010079CC9A EB00             jmp 0x10079cc9c; <+108> at Unit3.pas:40
000000010079CC9C 488B8528FFFFFF   mov rax, qword ptr [rbp - 0xd8]
000000010079CCA3 488945E8         mov qword ptr [rbp - 0x18], rax
Unit3.pas.41: ResAsCFString := IORegistryEntrySearchCFProperty(USBRef,
000000010079CCA7 8B7DFC           mov edi, dword ptr [rbp - 0x4]
000000010079CCAA 0F28057F881000   movaps xmm0, xmmword ptr [rip + 0x10887f]; __unnamed_2 + 112
000000010079CCB1 0F2945C0         movaps xmmword ptr [rbp - 0x40], xmm0
000000010079CCB5 0F280564881000   movaps xmm0, xmmword ptr [rip + 0x108864]; __unnamed_2 + 96
000000010079CCBC 0F2945B0         movaps xmmword ptr [rbp - 0x50], xmm0
000000010079CCC0 0F280549881000   movaps xmm0, xmmword ptr [rip + 0x108849]; __unnamed_2 + 80
000000010079CCC7 0F2945A0         movaps xmmword ptr [rbp - 0x60], xmm0
000000010079CCCB 0F28052E881000   movaps xmm0, xmmword ptr [rip + 0x10882e]; __unnamed_2 + 64
000000010079CCD2 0F294590         movaps xmmword ptr [rbp - 0x70], xmm0
000000010079CCD6 0F280513881000   movaps xmm0, xmmword ptr [rip + 0x108813]; __unnamed_2 + 48
000000010079CCDD 0F294580         movaps xmmword ptr [rbp - 0x80], xmm0
000000010079CCE1 0F2805F8871000   movaps xmm0, xmmword ptr [rip + 0x1087f8]; __unnamed_2 + 32
000000010079CCE8 0F298570FFFFFF   movaps xmmword ptr [rbp - 0x90], xmm0
000000010079CCEF 0F2805DA871000   movaps xmm0, xmmword ptr [rip + 0x1087da]; __unnamed_2 + 16
000000010079CCF6 0F298560FFFFFF   movaps xmmword ptr [rbp - 0xa0], xmm0
000000010079CCFD 0F2805BC871000   movaps xmm0, xmmword ptr [rip + 0x1087bc]; __unnamed_2
000000010079CD04 0F298550FFFFFF   movaps xmmword ptr [rbp - 0xb0], xmm0
000000010079CD0B 488B75F0         mov rsi, qword ptr [rbp - 0x10]
000000010079CD0F 488B55E8         mov rdx, qword ptr [rbp - 0x18]
000000010079CD13 4889E1           mov rcx, rsp
000000010079CD16 0F2845C0         movaps xmm0, xmmword ptr [rbp - 0x40]
000000010079CD1A 0F114170         movups xmmword ptr [rcx + 0x70], xmm0
000000010079CD1E 0F2845B0         movaps xmm0, xmmword ptr [rbp - 0x50]
000000010079CD22 0F114160         movups xmmword ptr [rcx + 0x60], xmm0
000000010079CD26 0F2845A0         movaps xmm0, xmmword ptr [rbp - 0x60]
000000010079CD2A 0F114150         movups xmmword ptr [rcx + 0x50], xmm0
000000010079CD2E 0F284590         movaps xmm0, xmmword ptr [rbp - 0x70]
000000010079CD32 0F114140         movups xmmword ptr [rcx + 0x40], xmm0
000000010079CD36 0F288550FFFFFF   movaps xmm0, xmmword ptr [rbp - 0xb0]
000000010079CD3D 0F288D60FFFFFF   movaps xmm1, xmmword ptr [rbp - 0xa0]
000000010079CD44 0F289570FFFFFF   movaps xmm2, xmmword ptr [rbp - 0x90]
000000010079CD4B 0F285D80         movaps xmm3, xmmword ptr [rbp - 0x80]
000000010079CD4F 0F115930         movups xmmword ptr [rcx + 0x30], xmm3
000000010079CD53 0F115120         movups xmmword ptr [rcx + 0x20], xmm2
000000010079CD57 0F114910         movups xmmword ptr [rcx + 0x10], xmm1
000000010079CD5B 0F1101           movups xmmword ptr [rcx], xmm0
000000010079CD5E 31C9             xor ecx, ecx
> Register content here
>   RBP: 00007FFEEFBFEA80
>   RSP: 00007FFEEFBFEA00 
> Memory content here
>   00007FFEEFBFEA00 49 4F 53 65 72 76 69 63  IOServic
>   00007FFEEFBFEA08 65 00 00 00 00 00 00 00  e.......
000000010079CD60 E82BFEFFFF       call 0x10079cb90; Macapi::Iokit2::IORegistryEntrySearchCFProperty(unsigned int, System::StaticArray<char, 128>, __CFString*, __CFAllocator*, unsigned int)
> Access violation at address 00007FFF2ADD716, accessing address 0
000000010079CD65 48898520FFFFFF   mov qword ptr [rbp - 0xe0], rax
000000010079CD6C EB00             jmp 0x10079cd6e; <+318> at Unit3.pas:41
000000010079CD6E 488B8520FFFFFF   mov rax, qword ptr [rbp - 0xe0]
000000010079CD75 488945E0         mov qword ptr [rbp - 0x20], rax
000000010079CD79 EB37             jmp 0x10079cdb2; <+386> at Unit3.pas:41
000000010079CD7B 89D1             mov ecx, edx
000000010079CD7D 48898540FFFFFF   mov qword ptr [rbp - 0xc0], rax
000000010079CD84 898D48FFFFFF     mov dword ptr [rbp - 0xb8], ecx
000000010079CD8A 488D7DD8         lea rdi, [rbp - 0x28]
000000010079CD8E E81D9F87FF       call 0x100016cb0; System._LStrClr(void*) at System.pas:25402
000000010079CD93 8B8D48FFFFFF     mov ecx, dword ptr [rbp - 0xb8]
000000010079CD99 488BBD40FFFFFF   mov rdi, qword ptr [rbp - 0xc0]
000000010079CDA0 48898518FFFFFF   mov qword ptr [rbp - 0xe8], rax
000000010079CDA7 898D14FFFFFF     mov dword ptr [rbp - 0xec], ecx
000000010079CDAD E8863B0100       call 0x1007b0938; symbol stub for: _Unwind_Resume
000000010079CDB2 488D45D8         lea rax, [rbp - 0x28]
Unit3.pas.47: end;
000000010079CDB6 4889C7           mov rdi, rax
000000010079CDB9 E8F29E87FF       call 0x100016cb0; System._LStrClr(void*) at System.pas:25402
000000010079CDBE 48898508FFFFFF   mov qword ptr [rbp - 0xf8], rax
000000010079CDC5 4881C480010000   add rsp, 0x180
000000010079CDCC 5D               pop rbp
000000010079CDCD C3               ret 

Do I have shown all concerned registers? (Unfortunately, I'm too far away from understanding the details of this x64 code).

Compared to the following C code written in XCode:

void Test(void)
{
    io_service_t usbRef = 0;
    CFStringRef key = CFSTR("idVendor");
    CFAllocatorRef allocator = kCFAllocatorDefault;
    CFTypeRef cf_vendor;

    cf_vendor = IORegistryEntrySearchCFProperty(usbRef, kIOServicePlane, key, allocator, 0);
}

Generates this x64 assembly code:

    0x100001c40 <+0>:  pushq  %rbp
    0x100001c41 <+1>:  movq   %rsp, %rbp
    0x100001c44 <+4>:  subq   $0x20, %rsp
    0x100001c48 <+8>:  xorl   %r8d, %r8d
    0x100001c4b <+11>: movq   0x3c6(%rip), %rax         ; (void *)0x00007fff2fc755f0: kCFAllocatorDefault
    0x100001c52 <+18>: leaq   0x4f7(%rip), %rcx         ; @"idVendor"
    0x100001c59 <+25>: movl   $0x0, -0x4(%rbp)
    0x100001c60 <+32>: movq   %rcx, -0x10(%rbp)
    0x100001c64 <+36>: movq   (%rax), %rax
    0x100001c67 <+39>: movq   %rax, -0x18(%rbp)
->  0x100001c6b <+43>: movl   -0x4(%rbp), %edi
    0x100001c6e <+46>: movq   -0x10(%rbp), %rdx
    0x100001c72 <+50>: movq   -0x18(%rbp), %rcx
    0x100001c76 <+54>: leaq   0x263(%rip), %rsi         ; "IOService"
    0x100001c7d <+61>: callq  0x100001d12               ; symbol stub for: IORegistryEntrySearchCFProperty
    0x100001c82 <+66>: movq   %rax, -0x20(%rbp)
    0x100001c86 <+70>: addq   $0x20, %rsp
    0x100001c8a <+74>: popq   %rbp
    0x100001c8b <+75>: retq  

Compared to the x86 code generated by Delphi 32bit compiler of the pascal test procedure which works as expected:

Unit3.pas.38: USBRef := 0;
004BB6E1 33C0             xor eax,eax
004BB6E3 8945FC           mov [ebp-$04],eax
Unit3.pas.39: key := CFSTR(kUSBVendorID);
004BB6E6 6810000000       push $00000010
004BB6EB 55               push ebp
004BB6EC 68EDFEEFBE       push $beeffeed
004BB6F1 83C4F4           add esp,-$0c
004BB6F4 83C4FC           add esp,-$04
004BB6F7 8D55E8           lea edx,[ebp-$18]
004BB6FA 8D83A0B74B00     lea eax,[ebx+Test + $DC]
004BB700 E8276EB6FF       call UTF8Encode
004BB705 83C404           add esp,$04
004BB708 8B45E8           mov eax,[ebp-$18]
004BB70B 83C4FC           add esp,-$04
004BB70E E85904B6FF       call @LStrToPChar
004BB713 83C404           add esp,$04
004BB716 50               push eax
004BB717 E8A0AD4400       call $009064bc
004BB71C 83C41C           add esp,$1c
004BB71F FE4424F4         inc byte ptr [esp-$0c]
004BB723 8945EC           mov [ebp-$14],eax
004BB726 8B45EC           mov eax,[ebp-$14]
004BB729 8945F8           mov [ebp-$08],eax
Unit3.pas.40: allocator := kCFAllocatorDefault;
004BB72C 83C4F4           add esp,-$0c
004BB72F E8602EB7FF       call kCFAllocatorDefault
004BB734 83C40C           add esp,$0c
004BB737 8945F4           mov [ebp-$0c],eax
Unit3.pas.41: ResAsCFString := IORegistryEntrySearchCFProperty(USBRef,
004BB73A 6820000000       push $00000020
004BB73F 55               push ebp
004BB740 68EDFEEFBE       push $beeffeed
004BB745 83C4F4           add esp,-$0c
004BB748 6A00             push $00
004BB74A 8B45F4           mov eax,[ebp-$0c]
004BB74D 50               push eax
004BB74E 8B45F8           mov eax,[ebp-$08]
004BB751 50               push eax
004BB752 8D83B4B74B00     lea eax,[ebx+Test + $F0]
> Register content here
>  EAX: 004BB7B4
>Memory content here:
>  004BB7B4 49 4F 53 65 72 76 69 63  IOServic
>  004BB7BC 65 00 00 00 00 00 00 00  e.......
004BB758 50               push eax
004BB759 8B45FC           mov eax,[ebp-$04]
004BB75C 50               push eax
004BB75D E8BEA84400       call $00906020
004BB762 83C42C           add esp,$2c
004BB765 FE4424F4         inc byte ptr [esp-$0c]
004BB769 8945F0           mov [ebp-$10],eax
Unit3.pas.47: end;
004BB76C 688FB74B00       push $004bb78f
004BB771 011C24           add [esp],ebx
004BB774 8D45E8           lea eax,[ebp-$18]
004BB777 83C4F8           add esp,-$08
004BB77A E86DF7B5FF       call @LStrClr
004BB77F 83C408           add esp,$08
004BB782 C3               ret 

Maybe someone can give me a tip, what I have to pay attention to here.


回答1:


The issue was in the declaration of the type io_name_t. For the Delphi MacOS64 in the procedure declaration, an array of AnsiChar is no longer identical to a PAnsiChar. The following solution works now:

type
  io_name_t = PAnsiChar;

function IORegistryEntrySearchCFProperty(entry: io_registry_entry_t;
  plane: io_name_t; key: CFStringRef; allocator: CFAllocatorRef;
  options: IOOptionBits): CFTypeRef; cdecl;
  external libIOKit name _PU + 'IORegistryEntrySearchCFProperty';


来源:https://stackoverflow.com/questions/57612931/import-ioregistryentrysearchcfproperty-from-macapi-iokit-in-delphi-for-osx64

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!