Import IORegistryEntrySearchCFProperty from Macapi.IOKit in Delphi for OSX64

  

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.

Comments are closed.