From 7250f9a95b864cd2cda5dda6ce19e370e93b82d1 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 22 Jan 2021 17:21:13 +0100 Subject: [PATCH] ntdll: Add some more section information data. Signed-off-by: Alexandre Julliard --- dlls/kernel32/tests/loader.c | 30 +++++++++---- dlls/kernelbase/process.c | 2 +- dlls/ntdll/tests/info.c | 16 +++++-- dlls/ntdll/unix/virtual.c | 33 +++++++------- include/wine/server_protocol.h | 10 +++-- include/winternl.h | 13 ++++-- server/mapping.c | 79 ++++++++++++++++++---------------- server/protocol.def | 8 ++-- server/trace.c | 12 +++--- 9 files changed, 121 insertions(+), 82 deletions(-) diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 67fd62ef6aa..47fb3cf4649 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -411,12 +411,19 @@ static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HE ok( image.SubSystemType == nt_header->OptionalHeader.Subsystem, "%u: SubSystemType wrong %08x / %08x\n", id, image.SubSystemType, nt_header->OptionalHeader.Subsystem ); - ok( image.SubsystemVersionLow == nt_header->OptionalHeader.MinorSubsystemVersion, - "%u: SubsystemVersionLow wrong %04x / %04x\n", id, - image.SubsystemVersionLow, nt_header->OptionalHeader.MinorSubsystemVersion ); - ok( image.SubsystemVersionHigh == nt_header->OptionalHeader.MajorSubsystemVersion, - "%u: SubsystemVersionHigh wrong %04x / %04x\n", id, - image.SubsystemVersionHigh, nt_header->OptionalHeader.MajorSubsystemVersion ); + ok( image.MinorSubsystemVersion == nt_header->OptionalHeader.MinorSubsystemVersion, + "%u: MinorSubsystemVersion wrong %04x / %04x\n", id, + image.MinorSubsystemVersion, nt_header->OptionalHeader.MinorSubsystemVersion ); + ok( image.MajorSubsystemVersion == nt_header->OptionalHeader.MajorSubsystemVersion, + "%u: MajorSubsystemVersion wrong %04x / %04x\n", id, + image.MajorSubsystemVersion, nt_header->OptionalHeader.MajorSubsystemVersion ); + ok( image.MajorOperatingSystemVersion == nt_header->OptionalHeader.MajorOperatingSystemVersion || + broken( !image.MajorOperatingSystemVersion), /* before win10 */ + "%u: MajorOperatingSystemVersion wrong %04x / %04x\n", id, + image.MajorOperatingSystemVersion, nt_header->OptionalHeader.MajorOperatingSystemVersion ); + ok( image.MinorOperatingSystemVersion == nt_header->OptionalHeader.MinorOperatingSystemVersion, + "%u: MinorOperatingSystemVersion wrong %04x / %04x\n", id, + image.MinorOperatingSystemVersion, nt_header->OptionalHeader.MinorOperatingSystemVersion ); ok( image.ImageCharacteristics == nt_header->FileHeader.Characteristics, "%u: ImageCharacteristics wrong %04x / %04x\n", id, image.ImageCharacteristics, nt_header->FileHeader.Characteristics ); @@ -457,11 +464,19 @@ static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HE else ok( !S(U(image)).ComPlusNativeReady, "%u: wrong ComPlusNativeReady flags %02x\n", id, U(image).ImageFlags ); + if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC && + (cor_header->Flags & COMIMAGE_FLAGS_32BITPREFERRED)) + ok( S(U(image)).ComPlusPrefer32bit || + broken( !image.MajorOperatingSystemVersion ), /* before win10 */ + "%u: wrong ComPlusPrefer32bit flags %02x\n", id, U(image).ImageFlags ); + else + ok( !S(U(image)).ComPlusPrefer32bit, "%u: wrong ComPlusPrefer32bit flags %02x\n", id, U(image).ImageFlags ); } else { ok( !S(U(image)).ComPlusILOnly, "%u: wrong ComPlusILOnly flags %02x\n", id, U(image).ImageFlags ); ok( !S(U(image)).ComPlusNativeReady, "%u: wrong ComPlusNativeReady flags %02x\n", id, U(image).ImageFlags ); + ok( !S(U(image)).ComPlusPrefer32bit, "%u: wrong ComPlusPrefer32bit flags %02x\n", id, U(image).ImageFlags ); } if (!(nt_header->OptionalHeader.SectionAlignment % page_size)) ok( !S(U(image)).ImageMappedFlat, "%u: wrong ImageMappedFlat flags %02x\n", id, U(image).ImageFlags ); @@ -483,9 +498,6 @@ static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HE "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, U(image).ImageFlags ); ok( !S(U(image)).BaseBelow4gb, "%u: wrong BaseBelow4gb flags %02x\n", id, U(image).ImageFlags ); - /* FIXME: needs more work: */ - /* image.GpValue */ - map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1); status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL ); ok( !status, "NtQuerySection failed err %x\n", status ); diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 992d50af0bc..4a254a011f8 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -879,7 +879,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH GetProcessVersion( DWORD pid ) &info, sizeof(info), NULL ); if (!set_ntstatus( status )) return 0; - return MAKELONG( info.SubsystemVersionLow, info.SubsystemVersionHigh ); + return MAKELONG( info.MinorSubsystemVersion, info.MajorSubsystemVersion ); } diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 4379d8a84c6..de9ebb5879c 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -1728,10 +1728,18 @@ static void test_query_process_image_info(void) ok( status == STATUS_SUCCESS, "got %08x\n", status); ok( len == sizeof(info), "wrong len %u\n", len ); - ok( info.SubsystemVersionHigh == nt->OptionalHeader.MajorSubsystemVersion, "wrong major version %x/%x\n", - info.SubsystemVersionHigh, nt->OptionalHeader.MajorSubsystemVersion ); - ok( info.SubsystemVersionLow == nt->OptionalHeader.MinorSubsystemVersion, "wrong minor version %x/%x\n", - info.SubsystemVersionLow, nt->OptionalHeader.MinorSubsystemVersion ); + ok( info.MajorSubsystemVersion == nt->OptionalHeader.MajorSubsystemVersion, + "wrong major version %x/%x\n", + info.MajorSubsystemVersion, nt->OptionalHeader.MajorSubsystemVersion ); + ok( info.MinorSubsystemVersion == nt->OptionalHeader.MinorSubsystemVersion, + "wrong minor version %x/%x\n", + info.MinorSubsystemVersion, nt->OptionalHeader.MinorSubsystemVersion ); + ok( info.MajorOperatingSystemVersion == nt->OptionalHeader.MajorOperatingSystemVersion, + "wrong major OS version %x/%x\n", + info.MajorOperatingSystemVersion, nt->OptionalHeader.MajorOperatingSystemVersion ); + ok( info.MinorOperatingSystemVersion == nt->OptionalHeader.MinorOperatingSystemVersion, + "wrong minor OS version %x/%x\n", + info.MinorOperatingSystemVersion, nt->OptionalHeader.MinorOperatingSystemVersion ); } static void test_query_process_debug_object_handle(int argc, char **argv) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 785583a340a..e96bda722f6 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4094,22 +4094,23 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) */ void virtual_fill_image_information( const pe_image_info_t *pe_info, SECTION_IMAGE_INFORMATION *info ) { - info->TransferAddress = wine_server_get_ptr( pe_info->entry_point ); - info->ZeroBits = pe_info->zerobits; - info->MaximumStackSize = pe_info->stack_size; - info->CommittedStackSize = pe_info->stack_commit; - info->SubSystemType = pe_info->subsystem; - info->SubsystemVersionLow = pe_info->subsystem_low; - info->SubsystemVersionHigh = pe_info->subsystem_high; - info->GpValue = pe_info->gp; - info->ImageCharacteristics = pe_info->image_charact; - info->DllCharacteristics = pe_info->dll_charact; - info->Machine = pe_info->machine; - info->ImageContainsCode = pe_info->contains_code; - info->ImageFlags = pe_info->image_flags; - info->LoaderFlags = pe_info->loader_flags; - info->ImageFileSize = pe_info->file_size; - info->CheckSum = pe_info->checksum; + info->TransferAddress = wine_server_get_ptr( pe_info->entry_point ); + info->ZeroBits = pe_info->zerobits; + info->MaximumStackSize = pe_info->stack_size; + info->CommittedStackSize = pe_info->stack_commit; + info->SubSystemType = pe_info->subsystem; + info->MinorSubsystemVersion = pe_info->subsystem_minor; + info->MajorSubsystemVersion = pe_info->subsystem_major; + info->MajorOperatingSystemVersion = pe_info->osversion_major; + info->MinorOperatingSystemVersion = pe_info->osversion_minor; + info->ImageCharacteristics = pe_info->image_charact; + info->DllCharacteristics = pe_info->dll_charact; + info->Machine = pe_info->machine; + info->ImageContainsCode = pe_info->contains_code; + info->ImageFlags = pe_info->image_flags; + info->LoaderFlags = pe_info->loader_flags; + info->ImageFileSize = pe_info->file_size; + info->CheckSum = pe_info->checksum; #ifndef _WIN64 /* don't return 64-bit values to 32-bit processes */ if (pe_info->machine == IMAGE_FILE_MACHINE_AMD64 || pe_info->machine == IMAGE_FILE_MACHINE_ARM64) { diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 9f05a9f340d..0dd5803a79e 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -740,9 +740,10 @@ typedef struct mem_size_t stack_commit; unsigned int zerobits; unsigned int subsystem; - unsigned short subsystem_low; - unsigned short subsystem_high; - unsigned int gp; + unsigned short subsystem_minor; + unsigned short subsystem_major; + unsigned short osversion_major; + unsigned short osversion_minor; unsigned short image_charact; unsigned short dll_charact; unsigned short machine; @@ -760,6 +761,7 @@ typedef struct #define IMAGE_FLAGS_ImageDynamicallyRelocated 0x04 #define IMAGE_FLAGS_ImageMappedFlat 0x08 #define IMAGE_FLAGS_BaseBelow4gb 0x10 +#define IMAGE_FLAGS_ComPlusPrefer32bit 0x20 #define IMAGE_FLAGS_WineBuiltin 0x40 #define IMAGE_FLAGS_WineFakeDll 0x80 @@ -6188,7 +6190,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 652 +#define SERVER_PROTOCOL_VERSION 653 /* ### protocol_version end ### */ diff --git a/include/winternl.h b/include/winternl.h index a7b0e04aade..d692febbb0d 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -2409,6 +2409,9 @@ typedef enum _SECTION_INFORMATION_CLASS { SectionBasicInformation, SectionImageInformation, + SectionRelocationInformation, + SectionOriginalBaseInformation, + SectionInternalImageInformation } SECTION_INFORMATION_CLASS; typedef struct _SECTION_BASIC_INFORMATION { @@ -2423,9 +2426,10 @@ typedef struct _SECTION_IMAGE_INFORMATION { SIZE_T MaximumStackSize; SIZE_T CommittedStackSize; ULONG SubSystemType; - WORD SubsystemVersionLow; - WORD SubsystemVersionHigh; - ULONG GpValue; + USHORT MinorSubsystemVersion; + USHORT MajorSubsystemVersion; + USHORT MajorOperatingSystemVersion; + USHORT MinorOperatingSystemVersion; USHORT ImageCharacteristics; USHORT DllCharacteristics; USHORT Machine; @@ -2440,7 +2444,8 @@ typedef struct _SECTION_IMAGE_INFORMATION { UCHAR ImageDynamicallyRelocated : 1; UCHAR ImageMappedFlat : 1; UCHAR BaseBelow4gb : 1; - UCHAR Reserved : 3; + UCHAR ComPlusPrefer32bit : 1; + UCHAR Reserved : 2; } DUMMYSTRUCTNAME; } DUMMYUNIONNAME; ULONG LoaderFlags; diff --git a/server/mapping.c b/server/mapping.c index 6c2e7a1fd2b..4e38e8e40da 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -637,21 +637,23 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s clr_va = nt.opt.hdr32.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress; clr_size = nt.opt.hdr32.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size; - mapping->image.base = nt.opt.hdr32.ImageBase; - mapping->image.entry_point = nt.opt.hdr32.ImageBase + nt.opt.hdr32.AddressOfEntryPoint; - mapping->image.map_size = ROUND_SIZE( nt.opt.hdr32.SizeOfImage ); - mapping->image.stack_size = nt.opt.hdr32.SizeOfStackReserve; - mapping->image.stack_commit = nt.opt.hdr32.SizeOfStackCommit; - mapping->image.subsystem = nt.opt.hdr32.Subsystem; - mapping->image.subsystem_low = nt.opt.hdr32.MinorSubsystemVersion; - mapping->image.subsystem_high = nt.opt.hdr32.MajorSubsystemVersion; - mapping->image.dll_charact = nt.opt.hdr32.DllCharacteristics; - mapping->image.contains_code = (nt.opt.hdr32.SizeOfCode || - nt.opt.hdr32.AddressOfEntryPoint || - nt.opt.hdr32.SectionAlignment & page_mask); - mapping->image.header_size = nt.opt.hdr32.SizeOfHeaders; - mapping->image.checksum = nt.opt.hdr32.CheckSum; - mapping->image.image_flags = 0; + mapping->image.base = nt.opt.hdr32.ImageBase; + mapping->image.entry_point = nt.opt.hdr32.ImageBase + nt.opt.hdr32.AddressOfEntryPoint; + mapping->image.map_size = ROUND_SIZE( nt.opt.hdr32.SizeOfImage ); + mapping->image.stack_size = nt.opt.hdr32.SizeOfStackReserve; + mapping->image.stack_commit = nt.opt.hdr32.SizeOfStackCommit; + mapping->image.subsystem = nt.opt.hdr32.Subsystem; + mapping->image.subsystem_minor = nt.opt.hdr32.MinorSubsystemVersion; + mapping->image.subsystem_major = nt.opt.hdr32.MajorSubsystemVersion; + mapping->image.osversion_minor = nt.opt.hdr32.MinorOperatingSystemVersion; + mapping->image.osversion_major = nt.opt.hdr32.MajorOperatingSystemVersion; + mapping->image.dll_charact = nt.opt.hdr32.DllCharacteristics; + mapping->image.contains_code = (nt.opt.hdr32.SizeOfCode || + nt.opt.hdr32.AddressOfEntryPoint || + nt.opt.hdr32.SectionAlignment & page_mask); + mapping->image.header_size = nt.opt.hdr32.SizeOfHeaders; + mapping->image.checksum = nt.opt.hdr32.CheckSum; + mapping->image.image_flags = 0; if (nt.opt.hdr32.SectionAlignment & page_mask) mapping->image.image_flags |= IMAGE_FLAGS_ImageMappedFlat; if ((nt.opt.hdr32.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) && @@ -677,21 +679,23 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s clr_va = nt.opt.hdr64.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress; clr_size = nt.opt.hdr64.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size; - mapping->image.base = nt.opt.hdr64.ImageBase; - mapping->image.entry_point = nt.opt.hdr64.ImageBase + nt.opt.hdr64.AddressOfEntryPoint; - mapping->image.map_size = ROUND_SIZE( nt.opt.hdr64.SizeOfImage ); - mapping->image.stack_size = nt.opt.hdr64.SizeOfStackReserve; - mapping->image.stack_commit = nt.opt.hdr64.SizeOfStackCommit; - mapping->image.subsystem = nt.opt.hdr64.Subsystem; - mapping->image.subsystem_low = nt.opt.hdr64.MinorSubsystemVersion; - mapping->image.subsystem_high = nt.opt.hdr64.MajorSubsystemVersion; - mapping->image.dll_charact = nt.opt.hdr64.DllCharacteristics; - mapping->image.contains_code = (nt.opt.hdr64.SizeOfCode || - nt.opt.hdr64.AddressOfEntryPoint || - nt.opt.hdr64.SectionAlignment & page_mask); - mapping->image.header_size = nt.opt.hdr64.SizeOfHeaders; - mapping->image.checksum = nt.opt.hdr64.CheckSum; - mapping->image.image_flags = 0; + mapping->image.base = nt.opt.hdr64.ImageBase; + mapping->image.entry_point = nt.opt.hdr64.ImageBase + nt.opt.hdr64.AddressOfEntryPoint; + mapping->image.map_size = ROUND_SIZE( nt.opt.hdr64.SizeOfImage ); + mapping->image.stack_size = nt.opt.hdr64.SizeOfStackReserve; + mapping->image.stack_commit = nt.opt.hdr64.SizeOfStackCommit; + mapping->image.subsystem = nt.opt.hdr64.Subsystem; + mapping->image.subsystem_minor = nt.opt.hdr64.MinorSubsystemVersion; + mapping->image.subsystem_major = nt.opt.hdr64.MajorSubsystemVersion; + mapping->image.osversion_minor = nt.opt.hdr64.MinorOperatingSystemVersion; + mapping->image.osversion_major = nt.opt.hdr64.MajorOperatingSystemVersion; + mapping->image.dll_charact = nt.opt.hdr64.DllCharacteristics; + mapping->image.contains_code = (nt.opt.hdr64.SizeOfCode || + nt.opt.hdr64.AddressOfEntryPoint || + nt.opt.hdr64.SectionAlignment & page_mask); + mapping->image.header_size = nt.opt.hdr64.SizeOfHeaders; + mapping->image.checksum = nt.opt.hdr64.CheckSum; + mapping->image.image_flags = 0; if (nt.opt.hdr64.SectionAlignment & page_mask) mapping->image.image_flags |= IMAGE_FLAGS_ImageMappedFlat; if ((nt.opt.hdr64.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) && @@ -706,7 +710,6 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s mapping->image.image_charact = nt.FileHeader.Characteristics; mapping->image.machine = nt.FileHeader.Machine; mapping->image.zerobits = 0; /* FIXME */ - mapping->image.gp = 0; /* FIXME */ mapping->image.file_size = file_size; mapping->image.loader_flags = clr_va && clr_size; mapping->image.__pad = 0; @@ -733,12 +736,16 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s (clr.Flags & COMIMAGE_FLAGS_ILONLY)) { mapping->image.image_flags |= IMAGE_FLAGS_ComPlusILOnly; - if (nt.opt.hdr32.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC && - !(clr.Flags & COMIMAGE_FLAGS_32BITREQUIRED)) + if (nt.opt.hdr32.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - mapping->image.image_flags |= IMAGE_FLAGS_ComPlusNativeReady; - if (cpu_mask & CPU_FLAG(CPU_x86_64)) mapping->image.cpu = CPU_x86_64; - else if (cpu_mask & CPU_FLAG(CPU_ARM64)) mapping->image.cpu = CPU_ARM64; + if (!(clr.Flags & COMIMAGE_FLAGS_32BITREQUIRED)) + { + mapping->image.image_flags |= IMAGE_FLAGS_ComPlusNativeReady; + if (cpu_mask & CPU_FLAG(CPU_x86_64)) mapping->image.cpu = CPU_x86_64; + else if (cpu_mask & CPU_FLAG(CPU_ARM64)) mapping->image.cpu = CPU_ARM64; + } + if (clr.Flags & COMIMAGE_FLAGS_32BITPREFERRED) + mapping->image.image_flags |= IMAGE_FLAGS_ComPlusPrefer32bit; } } diff --git a/server/protocol.def b/server/protocol.def index a3708f20705..e6c23aa77b0 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -756,9 +756,10 @@ typedef struct mem_size_t stack_commit; unsigned int zerobits; unsigned int subsystem; - unsigned short subsystem_low; - unsigned short subsystem_high; - unsigned int gp; + unsigned short subsystem_minor; + unsigned short subsystem_major; + unsigned short osversion_major; + unsigned short osversion_minor; unsigned short image_charact; unsigned short dll_charact; unsigned short machine; @@ -776,6 +777,7 @@ typedef struct #define IMAGE_FLAGS_ImageDynamicallyRelocated 0x04 #define IMAGE_FLAGS_ImageMappedFlat 0x08 #define IMAGE_FLAGS_BaseBelow4gb 0x10 +#define IMAGE_FLAGS_ComPlusPrefer32bit 0x20 #define IMAGE_FLAGS_WineBuiltin 0x40 #define IMAGE_FLAGS_WineFakeDll 0x80 diff --git a/server/trace.c b/server/trace.c index e059b709e8f..4c1ff57186b 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1255,12 +1255,14 @@ static void dump_varargs_pe_image_info( const char *prefix, data_size_t size ) dump_uint64( ",map_size=", &info.map_size ); dump_uint64( ",stack_size=", &info.stack_size ); dump_uint64( ",stack_commit=", &info.stack_commit ); - fprintf( stderr, ",zerobits=%08x,subsystem=%08x,subsystem_low=%04x,subsystem_high=%04x,gp=%08x" - ",image_charact=%04x,dll_charact=%04x,machine=%04x,contains_code=%u,image_flags=%02x" + fprintf( stderr, ",zerobits=%08x,subsystem=%08x,subsystem_minor=%04x,subsystem_major=%04x" + ",osversion_major=%04x,osversion_minor=%04x,image_charact=%04x,dll_charact=%04x,machine=%04x" + ",contains_code=%u,image_flags=%02x" ",loader_flags=%08x,header_size=%08x,file_size=%08x,checksum=%08x", - info.zerobits, info.subsystem, info.subsystem_low, info.subsystem_high, info.gp, - info.image_charact, info.dll_charact, info.machine, info.contains_code, info.image_flags, - info.loader_flags, info.header_size, info.file_size, info.checksum ); + info.zerobits, info.subsystem, info.subsystem_minor, info.subsystem_major, + info.osversion_major, info.osversion_minor, info.image_charact, info.dll_charact, + info.machine, info.contains_code, info.image_flags, info.loader_flags, + info.header_size, info.file_size, info.checksum ); dump_client_cpu( ",cpu=", &info.cpu ); fputc( '}', stderr ); remove_data( size );