1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2016 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
29 #include <mach/shared_region.h>
30 #include <mach/mach_vm.h>
31 #include <libkern/OSAtomic.h>
33 #include "dyld_process_info.h"
34 #include "dyld_process_info_internal.h"
35 #include "dyld_images.h"
36 #include "dyld_priv.h"
38 #include "LaunchCache.h"
40 #include "AllImages.h"
43 typedef void (^Notify
)(bool unload
, uint64_t timestamp
, uint64_t machHeader
, const uuid_t uuid
, const char* path
);
44 typedef void (^NotifyExit
)();
45 typedef void (^NotifyMain
)();
49 // Object used for monitoring another processes dyld loads
51 struct __attribute__((visibility("hidden"))) dyld_process_info_notify_base
53 static dyld_process_info_notify_base
* make(task_t task
, dispatch_queue_t queue
, Notify notify
, NotifyExit notifyExit
, kern_return_t
* kr
);
54 ~dyld_process_info_notify_base();
56 bool incRetainCount() const;
57 bool decRetainCount() const;
59 void setNotifyMain(NotifyMain notifyMain
) const { _notifyMain
= notifyMain
; }
61 // override new and delete so we don't need to link with libc++
62 static void* operator new(size_t sz
) { return malloc(sz
); }
63 static void operator delete(void* p
) { return free(p
); }
66 dyld_process_info_notify_base(dispatch_queue_t queue
, Notify notify
, NotifyExit notifyExit
, task_t task
);
67 kern_return_t
makePorts();
68 kern_return_t
pokeSendPortIntoTarget();
69 kern_return_t
unpokeSendPortInTarget();
70 void setMachSourceOnQueue();
72 mutable int32_t _retainCount
;
73 dispatch_queue_t _queue
;
75 NotifyExit _notifyExit
;
76 mutable NotifyMain _notifyMain
;
78 dispatch_source_t _machSource
;
79 uint64_t _portAddressInTarget
;
80 mach_port_t _sendPortInTarget
; // target is process being watched for image loading/unloading
81 mach_port_t _receivePortInMonitor
; // monitor is process being notified of image loading/unloading
85 dyld_process_info_notify_base::dyld_process_info_notify_base(dispatch_queue_t queue
, Notify notify
, NotifyExit notifyExit
, task_t task
)
86 : _retainCount(1), _queue(queue
), _notify(notify
), _notifyExit(notifyExit
), _notifyMain(NULL
), _targetTask(task
), _machSource(NULL
), _portAddressInTarget(0), _sendPortInTarget(0), _receivePortInMonitor(0)
88 dispatch_retain(_queue
);
91 dyld_process_info_notify_base::~dyld_process_info_notify_base()
94 dispatch_source_cancel(_machSource
);
95 dispatch_release(_machSource
);
98 if ( _portAddressInTarget
) {
99 unpokeSendPortInTarget();
100 _portAddressInTarget
= 0;
102 if ( _sendPortInTarget
) {
103 _sendPortInTarget
= 0;
105 dispatch_release(_queue
);
106 if ( _receivePortInMonitor
!= 0 ) {
107 mach_port_deallocate(mach_task_self(), _receivePortInMonitor
);
108 _receivePortInMonitor
= 0;
112 bool dyld_process_info_notify_base::incRetainCount() const
114 int32_t newCount
= OSAtomicIncrement32(&_retainCount
);
115 return ( newCount
== 1 );
118 bool dyld_process_info_notify_base::decRetainCount() const
120 int32_t newCount
= OSAtomicDecrement32(&_retainCount
);
121 return ( newCount
== 0 );
125 dyld_process_info_notify_base
* dyld_process_info_notify_base::make(task_t task
, dispatch_queue_t queue
, Notify notify
, NotifyExit notifyExit
, kern_return_t
* kr
)
127 dyld_process_info_notify_base
* obj
= new dyld_process_info_notify_base(queue
, notify
, notifyExit
, task
);
129 if ( kern_return_t r
= obj
->makePorts() ) {
135 obj
->setMachSourceOnQueue();
137 if ( kern_return_t r
= obj
->pokeSendPortIntoTarget() ) {
153 kern_return_t
dyld_process_info_notify_base::makePorts()
155 // Allocate a port to listen on in this monitoring task
156 if ( kern_return_t r
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &_receivePortInMonitor
) )
159 // Add send rights for replying
160 if ( kern_return_t r
= mach_port_insert_right(mach_task_self(), _receivePortInMonitor
, _receivePortInMonitor
, MACH_MSG_TYPE_MAKE_SEND
) )
163 // Allocate a name in the target. We need a new name to add send rights to
164 if ( kern_return_t r
= mach_port_allocate(_targetTask
, MACH_PORT_RIGHT_DEAD_NAME
, &_sendPortInTarget
) )
167 // Deallocate the dead name
168 if ( kern_return_t r
= mach_port_mod_refs(_targetTask
, _sendPortInTarget
, MACH_PORT_RIGHT_DEAD_NAME
, -1) )
171 // Make the dead name a send right to our listening port
172 if ( kern_return_t r
= mach_port_insert_right(_targetTask
, _sendPortInTarget
, _receivePortInMonitor
, MACH_MSG_TYPE_MAKE_SEND
) )
175 // Notify us if the target dies
176 mach_port_t previous
= MACH_PORT_NULL
;
177 if ( kern_return_t r
= mach_port_request_notification(_targetTask
, _sendPortInTarget
, MACH_NOTIFY_DEAD_NAME
, 0, _receivePortInMonitor
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &previous
))
180 //fprintf(stderr, "_sendPortInTarget=%d, _receivePortInMonitor=%d\n", _sendPortInTarget, _receivePortInMonitor);
186 void dyld_process_info_notify_base::setMachSourceOnQueue()
188 NotifyExit exitHandler
= _notifyExit
;
189 _machSource
= dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV
, _receivePortInMonitor
, 0, _queue
);
190 dispatch_source_set_event_handler(_machSource
, ^{
191 // This event handler block has an implicit reference to "this"
192 // if incrementing the count goes to one, that means the object may have already been destroyed
193 if ( incRetainCount() )
195 uint8_t messageBuffer
[DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE
];
196 mach_msg_header_t
* h
= (mach_msg_header_t
*)messageBuffer
;
198 kern_return_t r
= mach_msg(h
, MACH_RCV_MSG
, 0, sizeof(messageBuffer
), _receivePortInMonitor
, MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
199 if ( r
== KERN_SUCCESS
) {
200 //fprintf(stderr, "received message id=0x%X, size=%d\n", h->msgh_id, h->msgh_size);
201 if ( h
->msgh_id
== DYLD_PROCESS_INFO_NOTIFY_LOAD_ID
|| h
->msgh_id
== DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID
) {
202 // run notifier block for each [un]load image
203 const dyld_process_info_notify_header
* header
= (dyld_process_info_notify_header
*)messageBuffer
;
204 const dyld_process_info_image_entry
* entries
= (dyld_process_info_image_entry
*)&messageBuffer
[header
->imagesOffset
];
205 const char* const stringPool
= (char*)&messageBuffer
[header
->stringsOffset
];
206 for (unsigned i
=0; i
< header
->imageCount
; ++i
) {
207 bool isUnload
= (h
->msgh_id
== DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID
);
208 _notify(isUnload
, header
->timestamp
, entries
[i
].loadAddress
, entries
[i
].uuid
, stringPool
+ entries
[i
].pathStringOffset
);
210 // reply to dyld, so it can continue
211 mach_msg_header_t replyHeader
;
212 replyHeader
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, MACH_MSG_TYPE_MAKE_SEND
);
213 replyHeader
.msgh_id
= 0;
214 replyHeader
.msgh_local_port
= MACH_PORT_NULL
;
215 replyHeader
.msgh_remote_port
= h
->msgh_remote_port
;
216 replyHeader
.msgh_reserved
= 0;
217 replyHeader
.msgh_size
= sizeof(replyHeader
);
218 mach_msg(&replyHeader
, MACH_SEND_MSG
| MACH_SEND_TIMEOUT
, replyHeader
.msgh_size
, 0, MACH_PORT_NULL
, 100, MACH_PORT_NULL
);
220 else if ( h
->msgh_id
== DYLD_PROCESS_INFO_NOTIFY_MAIN_ID
) {
221 if ( _notifyMain
!= NULL
) {
224 // reply to dyld, so it can continue
225 mach_msg_header_t replyHeader
;
226 replyHeader
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, MACH_MSG_TYPE_MAKE_SEND
);
227 replyHeader
.msgh_id
= 0;
228 replyHeader
.msgh_local_port
= MACH_PORT_NULL
;
229 replyHeader
.msgh_remote_port
= h
->msgh_remote_port
;
230 replyHeader
.msgh_reserved
= 0;
231 replyHeader
.msgh_size
= sizeof(replyHeader
);
232 mach_msg(&replyHeader
, MACH_SEND_MSG
| MACH_SEND_TIMEOUT
, replyHeader
.msgh_size
, 0, MACH_PORT_NULL
, 100, MACH_PORT_NULL
);
234 else if ( h
->msgh_id
== MACH_NOTIFY_PORT_DELETED
) {
235 mach_port_t deadPort
= ((mach_port_deleted_notification_t
*)h
)->not_port
;
236 //fprintf(stderr, "received message id=MACH_NOTIFY_PORT_DELETED, size=%d, deadPort=%d\n", h->msgh_size, deadPort);
237 if ( deadPort
== _sendPortInTarget
) {
238 // target process died. Clean up ports
239 _sendPortInTarget
= 0;
240 mach_port_deallocate(mach_task_self(), _receivePortInMonitor
);
241 _receivePortInMonitor
= 0;
242 _portAddressInTarget
= 0;
243 // notify that target is gone
248 fprintf(stderr
, "received unknown message id=0x%X, size=%d\n", h
->msgh_id
, h
->msgh_size
);
251 if ( decRetainCount() )
254 dispatch_resume(_machSource
);
258 kern_return_t
dyld_process_info_notify_base::pokeSendPortIntoTarget()
260 // get location on all_image_infos in target task
261 task_dyld_info_data_t taskDyldInfo
;
262 mach_msg_type_number_t count
= TASK_DYLD_INFO_COUNT
;
263 kern_return_t r
= task_info(_targetTask
, TASK_DYLD_INFO
, (task_info_t
)&taskDyldInfo
, &count
);
267 // remap the page containing all_image_infos into this process r/w
268 mach_vm_address_t mappedAddress
= 0;
269 mach_vm_size_t mappedSize
= taskDyldInfo
.all_image_info_size
;
270 vm_prot_t curProt
= VM_PROT_NONE
;
271 vm_prot_t maxProt
= VM_PROT_NONE
;
272 r
= mach_vm_remap(mach_task_self(), &mappedAddress
, mappedSize
, 0, VM_FLAGS_ANYWHERE
| VM_FLAGS_RETURN_DATA_ADDR
,
273 _targetTask
, taskDyldInfo
.all_image_info_addr
, false, &curProt
, &maxProt
, VM_INHERIT_NONE
);
276 if ( curProt
!= (VM_PROT_READ
|VM_PROT_WRITE
) )
277 return KERN_PROTECTION_FAILURE
;
279 // atomically set port into all_image_info_struct
280 static_assert(sizeof(mach_port_t
) == sizeof(uint32_t), "machport size not 32-bits");
282 mach_vm_address_t mappedAddressToPokePort
= 0;
283 if ( taskDyldInfo
.all_image_info_format
== TASK_DYLD_ALL_IMAGE_INFO_32
)
284 mappedAddressToPokePort
= mappedAddress
+ offsetof(dyld_all_image_infos_32
,notifyMachPorts
);
286 mappedAddressToPokePort
= mappedAddress
+ offsetof(dyld_all_image_infos_64
,notifyMachPorts
);
288 // use first available slot
289 bool slotFound
= false;
290 for (int slotIndex
=0; slotIndex
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slotIndex
) {
291 if ( OSAtomicCompareAndSwap32Barrier(0, _sendPortInTarget
, (volatile int32_t*)mappedAddressToPokePort
) ) {
295 mappedAddressToPokePort
+= sizeof(uint32_t);
298 mach_vm_deallocate(mach_task_self(), mappedAddress
, mappedSize
);
299 return KERN_UREFS_OVERFLOW
;
301 _portAddressInTarget
= taskDyldInfo
.all_image_info_addr
+ mappedAddressToPokePort
- mappedAddress
;
302 //fprintf(stderr, "poked port %d into target at address 0x%llX\n", _sendPortInTarget, _portAddressInTarget);
303 mach_vm_deallocate(mach_task_self(), mappedAddress
, mappedSize
);
309 kern_return_t
dyld_process_info_notify_base::unpokeSendPortInTarget()
311 // remap the page containing all_image_infos into this process r/w
312 mach_vm_address_t mappedAddress
= 0;
313 mach_vm_size_t mappedSize
= sizeof(mach_port_t
);
314 vm_prot_t curProt
= VM_PROT_NONE
;
315 vm_prot_t maxProt
= VM_PROT_NONE
;
316 kern_return_t r
= mach_vm_remap(mach_task_self(), &mappedAddress
, mappedSize
, 0, VM_FLAGS_ANYWHERE
| VM_FLAGS_RETURN_DATA_ADDR
,
317 _targetTask
, _portAddressInTarget
, false, &curProt
, &maxProt
, VM_INHERIT_NONE
);
320 if ( curProt
!= (VM_PROT_READ
|VM_PROT_WRITE
) )
321 return KERN_PROTECTION_FAILURE
;
323 OSAtomicCompareAndSwap32Barrier(_sendPortInTarget
, 0, (volatile int32_t*)mappedAddress
);
325 //fprintf(stderr, "cleared port %d from target\n", _sendPortInTarget);
326 mach_vm_deallocate(mach_task_self(), mappedAddress
, mappedSize
);
332 dyld_process_info_notify
_dyld_process_info_notify(task_t task
, dispatch_queue_t queue
,
333 void (^notify
)(bool unload
, uint64_t timestamp
, uint64_t machHeader
, const uuid_t uuid
, const char* path
),
334 void (^notifyExit
)(),
337 return dyld_process_info_notify_base::make(task
, queue
, notify
, notifyExit
, kr
);
340 void _dyld_process_info_notify_main(dyld_process_info_notify object
, void (^notifyMain
)())
342 object
->setNotifyMain(notifyMain
);
345 void _dyld_process_info_notify_retain(dyld_process_info_notify object
)
347 object
->incRetainCount();
350 void _dyld_process_info_notify_release(dyld_process_info_notify object
)
352 // Note if _machSource is currently handling a message, the retain count will not be zero
353 // and object will instead be deleted when handling is done.
354 if ( object
->decRetainCount() )
367 static mach_port_t sNotifyReplyPorts
[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
];
368 static bool sZombieNotifiers
[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
];
370 static void notifyMonitoringDyld(bool unloading
, unsigned portSlot
, const launch_cache::DynArray
<loader::ImageInfo
>& imageInfos
)
372 if ( sZombieNotifiers
[portSlot
] )
375 unsigned entriesSize
= (unsigned)imageInfos
.count()*sizeof(dyld_process_info_image_entry
);
376 unsigned pathsSize
= 0;
377 for (uintptr_t i
=0; i
< imageInfos
.count(); ++i
) {
378 launch_cache::Image
image(imageInfos
[i
].imageData
);
379 pathsSize
+= (strlen(image
.path()) + 1);
381 unsigned totalSize
= (sizeof(dyld_process_info_notify_header
) + MAX_TRAILER_SIZE
+ entriesSize
+ pathsSize
+ 127) & -128; // align
382 if ( totalSize
> DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE
) {
383 // Putting all image paths into one message would make buffer too big.
384 // Instead split into two messages. Recurse as needed until paths fit in buffer.
385 unsigned imageHalfCount
= (unsigned)imageInfos
.count()/2;
386 const launch_cache::DynArray
<loader::ImageInfo
> firstHalf(imageHalfCount
, (loader::ImageInfo
*)&imageInfos
[0]);
387 const launch_cache::DynArray
<loader::ImageInfo
> secondHalf(imageInfos
.count() - imageHalfCount
, (loader::ImageInfo
*)&imageInfos
[imageHalfCount
]);
388 notifyMonitoringDyld(unloading
, portSlot
, firstHalf
);
389 notifyMonitoringDyld(unloading
, portSlot
, secondHalf
);
392 // build buffer to send
393 dyld_all_image_infos
* allImageInfo
= gAllImages
.oldAllImageInfo();
394 uint8_t buffer
[totalSize
];
395 dyld_process_info_notify_header
* header
= (dyld_process_info_notify_header
*)buffer
;
397 header
->imageCount
= (uint32_t)imageInfos
.count();
398 header
->imagesOffset
= sizeof(dyld_process_info_notify_header
);
399 header
->stringsOffset
= sizeof(dyld_process_info_notify_header
) + entriesSize
;
400 header
->timestamp
= allImageInfo
->infoArrayChangeTimestamp
;
401 dyld_process_info_image_entry
* entries
= (dyld_process_info_image_entry
*)&buffer
[header
->imagesOffset
];
402 char* const pathPoolStart
= (char*)&buffer
[header
->stringsOffset
];
403 char* pathPool
= pathPoolStart
;
404 for (uintptr_t i
=0; i
< imageInfos
.count(); ++i
) {
405 launch_cache::Image
image(imageInfos
[i
].imageData
);
406 strcpy(pathPool
, image
.path());
407 uint32_t len
= (uint32_t)strlen(pathPool
);
408 memcpy(entries
->uuid
, image
.uuid(), sizeof(uuid_t
));
409 entries
->loadAddress
= (uint64_t)imageInfos
[i
].loadAddress
;
410 entries
->pathStringOffset
= (uint32_t)(pathPool
- pathPoolStart
);
411 entries
->pathLength
= len
;
412 pathPool
+= (len
+1);
415 // lazily alloc reply port
416 if ( sNotifyReplyPorts
[portSlot
] == 0 ) {
417 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &sNotifyReplyPorts
[portSlot
]) )
418 mach_port_insert_right(mach_task_self(), sNotifyReplyPorts
[portSlot
], sNotifyReplyPorts
[portSlot
], MACH_MSG_TYPE_MAKE_SEND
);
419 //log("allocated reply port %d\n", sNotifyReplyPorts[portSlot]);
421 //log("found port to send to\n");
422 mach_msg_header_t
* h
= (mach_msg_header_t
*)buffer
;
423 h
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND
); // MACH_MSG_TYPE_MAKE_SEND_ONCE
424 h
->msgh_id
= unloading
? DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID
: DYLD_PROCESS_INFO_NOTIFY_LOAD_ID
;
425 h
->msgh_local_port
= sNotifyReplyPorts
[portSlot
];
426 h
->msgh_remote_port
= allImageInfo
->notifyPorts
[portSlot
];
427 h
->msgh_reserved
= 0;
428 h
->msgh_size
= (mach_msg_size_t
)sizeof(buffer
);
429 //log("sending to port[%d]=%d, size=%d, reply port=%d, id=0x%X\n", portSlot, allImageInfo->notifyPorts[portSlot], h->msgh_size, sNotifyReplyPorts[portSlot], h->msgh_id);
430 kern_return_t sendResult
= mach_msg(h
, MACH_SEND_MSG
| MACH_RCV_MSG
| MACH_RCV_TIMEOUT
, h
->msgh_size
, h
->msgh_size
, sNotifyReplyPorts
[portSlot
], 2000, MACH_PORT_NULL
);
431 //log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size);
432 if ( sendResult
== MACH_SEND_INVALID_DEST
) {
433 // sender is not responding, detatch
434 //log("process requesting notification gone. deallocation send port %d and receive port %d\n", allImageInfo->notifyPorts[portSlot], sNotifyReplyPorts[portSlot]);
435 mach_port_deallocate(mach_task_self(), allImageInfo
->notifyPorts
[portSlot
]);
436 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[portSlot
]);
437 allImageInfo
->notifyPorts
[portSlot
] = 0;
438 sNotifyReplyPorts
[portSlot
] = 0;
440 else if ( sendResult
== MACH_RCV_TIMED_OUT
) {
441 // client took too long, ignore him from now on
442 sZombieNotifiers
[portSlot
] = true;
443 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[portSlot
]);
444 sNotifyReplyPorts
[portSlot
] = 0;
448 void AllImages::notifyMonitorMain()
450 dyld_all_image_infos
* allImageInfo
= gAllImages
.oldAllImageInfo();
451 for (int slot
=0; slot
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) {
452 if ( (allImageInfo
->notifyPorts
[slot
] != 0 ) && !sZombieNotifiers
[slot
] ) {
453 if ( sNotifyReplyPorts
[slot
] == 0 ) {
454 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &sNotifyReplyPorts
[slot
]) )
455 mach_port_insert_right(mach_task_self(), sNotifyReplyPorts
[slot
], sNotifyReplyPorts
[slot
], MACH_MSG_TYPE_MAKE_SEND
);
456 //dyld::log("allocated reply port %d\n", sNotifyReplyPorts[slot]);
458 //dyld::log("found port to send to\n");
459 uint8_t messageBuffer
[sizeof(mach_msg_header_t
) + MAX_TRAILER_SIZE
];
460 mach_msg_header_t
* h
= (mach_msg_header_t
*)messageBuffer
;
461 h
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND
); // MACH_MSG_TYPE_MAKE_SEND_ONCE
462 h
->msgh_id
= DYLD_PROCESS_INFO_NOTIFY_MAIN_ID
;
463 h
->msgh_local_port
= sNotifyReplyPorts
[slot
];
464 h
->msgh_remote_port
= allImageInfo
->notifyPorts
[slot
];
465 h
->msgh_reserved
= 0;
466 h
->msgh_size
= (mach_msg_size_t
)sizeof(messageBuffer
);
467 //dyld::log("sending to port[%d]=%d, size=%d, reply port=%d, id=0x%X\n", slot, allImageInfo->notifyPorts[slot], h->msgh_size, sNotifyReplyPorts[slot], h->msgh_id);
468 kern_return_t sendResult
= mach_msg(h
, MACH_SEND_MSG
| MACH_RCV_MSG
| MACH_RCV_TIMEOUT
, h
->msgh_size
, h
->msgh_size
, sNotifyReplyPorts
[slot
], 2000, MACH_PORT_NULL
);
469 //dyld::log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size);
470 if ( sendResult
== MACH_SEND_INVALID_DEST
) {
471 // sender is not responding, detatch
472 //dyld::log("process requesting notification gone. deallocation send port %d and receive port %d\n", allImageInfo->notifyPorts[slot], sNotifyReplyPorts[slot]);
473 mach_port_deallocate(mach_task_self(), allImageInfo
->notifyPorts
[slot
]);
474 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
475 allImageInfo
->notifyPorts
[slot
] = 0;
476 sNotifyReplyPorts
[slot
] = 0;
478 else if ( sendResult
== MACH_RCV_TIMED_OUT
) {
479 // client took too long, ignore him from now on
480 sZombieNotifiers
[slot
] = true;
481 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
482 sNotifyReplyPorts
[slot
] = 0;
488 void AllImages::notifyMonitorLoads(const launch_cache::DynArray
<loader::ImageInfo
>& newImages
)
490 // notify each monitoring process
491 dyld_all_image_infos
* allImageInfo
= gAllImages
.oldAllImageInfo();
492 for (int slot
=0; slot
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) {
493 if ( allImageInfo
->notifyPorts
[slot
] != 0 ) {
494 notifyMonitoringDyld(false, slot
, newImages
);
496 else if ( sNotifyReplyPorts
[slot
] != 0 ) {
497 // monitoring process detached from this process, so release reply port
498 //dyld::log("deallocated reply port %d\n", sNotifyReplyPorts[slot]);
499 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
500 sNotifyReplyPorts
[slot
] = 0;
501 sZombieNotifiers
[slot
] = false;
506 void AllImages::notifyMonitorUnloads(const launch_cache::DynArray
<loader::ImageInfo
>& unloadingImages
)
508 // notify each monitoring process
509 dyld_all_image_infos
* allImageInfo
= gAllImages
.oldAllImageInfo();
510 for (int slot
=0; slot
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) {
511 if ( allImageInfo
->notifyPorts
[slot
] != 0 ) {
512 notifyMonitoringDyld(true, slot
, unloadingImages
);
514 else if ( sNotifyReplyPorts
[slot
] != 0 ) {
515 // monitoring process detached from this process, so release reply port
516 //dyld::log("deallocated reply port %d\n", sNotifyReplyPorts[slot]);
517 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
518 sNotifyReplyPorts
[slot
] = 0;
519 sZombieNotifiers
[slot
] = false;