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 uint32_t& retainCount() const { return _retainCount
; }
57 void setNotifyMain(NotifyMain notifyMain
) const { _notifyMain
= notifyMain
; }
59 // override new and delete so we don't need to link with libc++
60 static void* operator new(size_t sz
) { return malloc(sz
); }
61 static void operator delete(void* p
) { return free(p
); }
64 dyld_process_info_notify_base(dispatch_queue_t queue
, Notify notify
, NotifyExit notifyExit
, task_t task
);
65 kern_return_t
makePorts();
66 kern_return_t
pokeSendPortIntoTarget();
67 kern_return_t
unpokeSendPortInTarget();
68 void setMachSourceOnQueue();
70 mutable uint32_t _retainCount
;
71 dispatch_queue_t _queue
;
73 NotifyExit _notifyExit
;
74 mutable NotifyMain _notifyMain
;
76 dispatch_source_t _machSource
;
77 uint64_t _portAddressInTarget
;
78 mach_port_t _sendPortInTarget
; // target is process being watched for image loading/unloading
79 mach_port_t _receivePortInMonitor
; // monitor is process being notified of image loading/unloading
83 dyld_process_info_notify_base::dyld_process_info_notify_base(dispatch_queue_t queue
, Notify notify
, NotifyExit notifyExit
, task_t task
)
84 : _retainCount(1), _queue(queue
), _notify(notify
), _notifyExit(notifyExit
), _notifyMain(NULL
), _targetTask(task
), _machSource(NULL
), _portAddressInTarget(0), _sendPortInTarget(0), _receivePortInMonitor(0)
86 dispatch_retain(_queue
);
89 dyld_process_info_notify_base::~dyld_process_info_notify_base()
92 dispatch_release(_machSource
);
95 if ( _portAddressInTarget
) {
96 unpokeSendPortInTarget();
97 _portAddressInTarget
= 0;
99 if ( _sendPortInTarget
) {
100 _sendPortInTarget
= 0;
102 dispatch_release(_queue
);
103 if ( _receivePortInMonitor
!= 0 ) {
104 mach_port_deallocate(mach_task_self(), _receivePortInMonitor
);
105 _receivePortInMonitor
= 0;
110 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
)
112 dyld_process_info_notify_base
* obj
= new dyld_process_info_notify_base(queue
, notify
, notifyExit
, task
);
114 if ( kern_return_t r
= obj
->makePorts() ) {
120 obj
->setMachSourceOnQueue();
122 if ( kern_return_t r
= obj
->pokeSendPortIntoTarget() ) {
138 kern_return_t
dyld_process_info_notify_base::makePorts()
140 // Allocate a port to listen on in this monitoring task
141 if ( kern_return_t r
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &_receivePortInMonitor
) )
144 // Add send rights for replying
145 if ( kern_return_t r
= mach_port_insert_right(mach_task_self(), _receivePortInMonitor
, _receivePortInMonitor
, MACH_MSG_TYPE_MAKE_SEND
) )
148 // Allocate a name in the target. We need a new name to add send rights to
149 if ( kern_return_t r
= mach_port_allocate(_targetTask
, MACH_PORT_RIGHT_DEAD_NAME
, &_sendPortInTarget
) )
152 // Deallocate the dead name
153 if ( kern_return_t r
= mach_port_mod_refs(_targetTask
, _sendPortInTarget
, MACH_PORT_RIGHT_DEAD_NAME
, -1) )
156 // Make the dead name a send right to our listening port
157 if ( kern_return_t r
= mach_port_insert_right(_targetTask
, _sendPortInTarget
, _receivePortInMonitor
, MACH_MSG_TYPE_MAKE_SEND
) )
160 // Notify us if the target dies
161 mach_port_t previous
= MACH_PORT_NULL
;
162 if ( kern_return_t r
= mach_port_request_notification(_targetTask
, _sendPortInTarget
, MACH_NOTIFY_DEAD_NAME
, 0, _receivePortInMonitor
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &previous
))
165 //fprintf(stderr, "_sendPortInTarget=%d, _receivePortInMonitor=%d\n", _sendPortInTarget, _receivePortInMonitor);
171 void dyld_process_info_notify_base::setMachSourceOnQueue()
173 NotifyExit exitHandler
= _notifyExit
;
174 _machSource
= dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV
, _receivePortInMonitor
, 0, _queue
);
175 dispatch_source_set_event_handler(_machSource
, ^{
176 uint8_t messageBuffer
[DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE
];
177 mach_msg_header_t
* h
= (mach_msg_header_t
*)messageBuffer
;
179 kern_return_t r
= mach_msg(h
, MACH_RCV_MSG
, 0, sizeof(messageBuffer
), _receivePortInMonitor
, MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
180 if ( r
== KERN_SUCCESS
) {
181 //fprintf(stderr, "received message id=0x%X, size=%d\n", h->msgh_id, h->msgh_size);
182 if ( h
->msgh_id
== DYLD_PROCESS_INFO_NOTIFY_LOAD_ID
|| h
->msgh_id
== DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID
) {
183 // run notifier block for each [un]load image
184 const dyld_process_info_notify_header
* header
= (dyld_process_info_notify_header
*)messageBuffer
;
185 const dyld_process_info_image_entry
* entries
= (dyld_process_info_image_entry
*)&messageBuffer
[header
->imagesOffset
];
186 const char* const stringPool
= (char*)&messageBuffer
[header
->stringsOffset
];
187 for (unsigned i
=0; i
< header
->imageCount
; ++i
) {
188 bool isUnload
= (h
->msgh_id
== DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID
);
189 _notify(isUnload
, header
->timestamp
, entries
[i
].loadAddress
, entries
[i
].uuid
, stringPool
+ entries
[i
].pathStringOffset
);
191 // reply to dyld, so it can continue
192 mach_msg_header_t replyHeader
;
193 replyHeader
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, MACH_MSG_TYPE_MAKE_SEND
);
194 replyHeader
.msgh_id
= 0;
195 replyHeader
.msgh_local_port
= MACH_PORT_NULL
;
196 replyHeader
.msgh_remote_port
= h
->msgh_remote_port
;
197 replyHeader
.msgh_reserved
= 0;
198 replyHeader
.msgh_size
= sizeof(replyHeader
);
199 mach_msg(&replyHeader
, MACH_SEND_MSG
| MACH_SEND_TIMEOUT
, replyHeader
.msgh_size
, 0, MACH_PORT_NULL
, 100, MACH_PORT_NULL
);
201 else if ( h
->msgh_id
== DYLD_PROCESS_INFO_NOTIFY_MAIN_ID
) {
202 if ( _notifyMain
!= NULL
) {
205 // reply to dyld, so it can continue
206 mach_msg_header_t replyHeader
;
207 replyHeader
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, MACH_MSG_TYPE_MAKE_SEND
);
208 replyHeader
.msgh_id
= 0;
209 replyHeader
.msgh_local_port
= MACH_PORT_NULL
;
210 replyHeader
.msgh_remote_port
= h
->msgh_remote_port
;
211 replyHeader
.msgh_reserved
= 0;
212 replyHeader
.msgh_size
= sizeof(replyHeader
);
213 mach_msg(&replyHeader
, MACH_SEND_MSG
| MACH_SEND_TIMEOUT
, replyHeader
.msgh_size
, 0, MACH_PORT_NULL
, 100, MACH_PORT_NULL
);
215 else if ( h
->msgh_id
== MACH_NOTIFY_PORT_DELETED
) {
216 mach_port_t deadPort
= ((mach_port_deleted_notification_t
*)h
)->not_port
;
217 //fprintf(stderr, "received message id=MACH_NOTIFY_PORT_DELETED, size=%d, deadPort=%d\n", h->msgh_size, deadPort);
218 if ( deadPort
== _sendPortInTarget
) {
219 // target process died. Clean up ports
220 _sendPortInTarget
= 0;
221 mach_port_deallocate(mach_task_self(), _receivePortInMonitor
);
222 _receivePortInMonitor
= 0;
223 _portAddressInTarget
= 0;
224 // notify that target is gone
229 fprintf(stderr
, "received unknown message id=0x%X, size=%d\n", h
->msgh_id
, h
->msgh_size
);
233 dispatch_resume(_machSource
);
237 kern_return_t
dyld_process_info_notify_base::pokeSendPortIntoTarget()
239 // get location on all_image_infos in target task
240 task_dyld_info_data_t taskDyldInfo
;
241 mach_msg_type_number_t count
= TASK_DYLD_INFO_COUNT
;
242 kern_return_t r
= task_info(_targetTask
, TASK_DYLD_INFO
, (task_info_t
)&taskDyldInfo
, &count
);
246 // remap the page containing all_image_infos into this process r/w
247 mach_vm_address_t mappedAddress
= 0;
248 mach_vm_size_t mappedSize
= taskDyldInfo
.all_image_info_size
;
249 vm_prot_t curProt
= VM_PROT_NONE
;
250 vm_prot_t maxProt
= VM_PROT_NONE
;
251 r
= mach_vm_remap(mach_task_self(), &mappedAddress
, mappedSize
, 0, VM_FLAGS_ANYWHERE
| VM_FLAGS_RETURN_DATA_ADDR
,
252 _targetTask
, taskDyldInfo
.all_image_info_addr
, false, &curProt
, &maxProt
, VM_INHERIT_NONE
);
255 if ( curProt
!= (VM_PROT_READ
|VM_PROT_WRITE
) )
256 return KERN_PROTECTION_FAILURE
;
258 // atomically set port into all_image_info_struct
259 static_assert(sizeof(mach_port_t
) == sizeof(uint32_t), "machport size not 32-bits");
261 mach_vm_address_t mappedAddressToPokePort
= 0;
262 if ( taskDyldInfo
.all_image_info_format
== TASK_DYLD_ALL_IMAGE_INFO_32
)
263 mappedAddressToPokePort
= mappedAddress
+ offsetof(dyld_all_image_infos_32
,notifyMachPorts
);
265 mappedAddressToPokePort
= mappedAddress
+ offsetof(dyld_all_image_infos_64
,notifyMachPorts
);
267 // use first available slot
268 bool slotFound
= false;
269 for (int slotIndex
=0; slotIndex
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slotIndex
) {
270 if ( OSAtomicCompareAndSwap32Barrier(0, _sendPortInTarget
, (volatile int32_t*)mappedAddressToPokePort
) ) {
274 mappedAddressToPokePort
+= sizeof(uint32_t);
277 mach_vm_deallocate(mach_task_self(), mappedAddress
, mappedSize
);
278 return KERN_UREFS_OVERFLOW
;
280 _portAddressInTarget
= taskDyldInfo
.all_image_info_addr
+ mappedAddressToPokePort
- mappedAddress
;
281 //fprintf(stderr, "poked port %d into target at address 0x%llX\n", _sendPortInTarget, _portAddressInTarget);
282 mach_vm_deallocate(mach_task_self(), mappedAddress
, mappedSize
);
288 kern_return_t
dyld_process_info_notify_base::unpokeSendPortInTarget()
290 // remap the page containing all_image_infos into this process r/w
291 mach_vm_address_t mappedAddress
= 0;
292 mach_vm_size_t mappedSize
= sizeof(mach_port_t
);
293 vm_prot_t curProt
= VM_PROT_NONE
;
294 vm_prot_t maxProt
= VM_PROT_NONE
;
295 kern_return_t r
= mach_vm_remap(mach_task_self(), &mappedAddress
, mappedSize
, 0, VM_FLAGS_ANYWHERE
| VM_FLAGS_RETURN_DATA_ADDR
,
296 _targetTask
, _portAddressInTarget
, false, &curProt
, &maxProt
, VM_INHERIT_NONE
);
299 if ( curProt
!= (VM_PROT_READ
|VM_PROT_WRITE
) )
300 return KERN_PROTECTION_FAILURE
;
302 OSAtomicCompareAndSwap32Barrier(_sendPortInTarget
, 0, (volatile int32_t*)mappedAddress
);
304 //fprintf(stderr, "cleared port %d from target\n", _sendPortInTarget);
305 mach_vm_deallocate(mach_task_self(), mappedAddress
, mappedSize
);
311 dyld_process_info_notify
_dyld_process_info_notify(task_t task
, dispatch_queue_t queue
,
312 void (^notify
)(bool unload
, uint64_t timestamp
, uint64_t machHeader
, const uuid_t uuid
, const char* path
),
313 void (^notifyExit
)(),
316 return dyld_process_info_notify_base::make(task
, queue
, notify
, notifyExit
, kr
);
319 void _dyld_process_info_notify_main(dyld_process_info_notify object
, void (^notifyMain
)())
321 object
->setNotifyMain(notifyMain
);
324 void _dyld_process_info_notify_retain(dyld_process_info_notify object
)
326 object
->retainCount() += 1;
329 void _dyld_process_info_notify_release(dyld_process_info_notify object
)
331 object
->retainCount() -= 1;
332 if ( object
->retainCount() == 0 )
345 static mach_port_t sNotifyReplyPorts
[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
];
346 static bool sZombieNotifiers
[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
];
348 static void notifyMonitoringDyld(bool unloading
, unsigned portSlot
, const launch_cache::DynArray
<loader::ImageInfo
>& imageInfos
)
350 if ( sZombieNotifiers
[portSlot
] )
353 unsigned entriesSize
= (unsigned)imageInfos
.count()*sizeof(dyld_process_info_image_entry
);
354 unsigned pathsSize
= 0;
355 for (uintptr_t i
=0; i
< imageInfos
.count(); ++i
) {
356 launch_cache::Image
image(imageInfos
[i
].imageData
);
357 pathsSize
+= (strlen(image
.path()) + 1);
359 unsigned totalSize
= (sizeof(dyld_process_info_notify_header
) + MAX_TRAILER_SIZE
+ entriesSize
+ pathsSize
+ 127) & -128; // align
360 if ( totalSize
> DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE
) {
361 // Putting all image paths into one message would make buffer too big.
362 // Instead split into two messages. Recurse as needed until paths fit in buffer.
363 unsigned imageHalfCount
= (unsigned)imageInfos
.count()/2;
364 const launch_cache::DynArray
<loader::ImageInfo
> firstHalf(imageHalfCount
, (loader::ImageInfo
*)&imageInfos
[0]);
365 const launch_cache::DynArray
<loader::ImageInfo
> secondHalf(imageInfos
.count() - imageHalfCount
, (loader::ImageInfo
*)&imageInfos
[imageHalfCount
]);
366 notifyMonitoringDyld(unloading
, portSlot
, firstHalf
);
367 notifyMonitoringDyld(unloading
, portSlot
, secondHalf
);
370 // build buffer to send
371 dyld_all_image_infos
* allImageInfo
= gAllImages
.oldAllImageInfo();
372 uint8_t buffer
[totalSize
];
373 dyld_process_info_notify_header
* header
= (dyld_process_info_notify_header
*)buffer
;
375 header
->imageCount
= (uint32_t)imageInfos
.count();
376 header
->imagesOffset
= sizeof(dyld_process_info_notify_header
);
377 header
->stringsOffset
= sizeof(dyld_process_info_notify_header
) + entriesSize
;
378 header
->timestamp
= allImageInfo
->infoArrayChangeTimestamp
;
379 dyld_process_info_image_entry
* entries
= (dyld_process_info_image_entry
*)&buffer
[header
->imagesOffset
];
380 char* const pathPoolStart
= (char*)&buffer
[header
->stringsOffset
];
381 char* pathPool
= pathPoolStart
;
382 for (uintptr_t i
=0; i
< imageInfos
.count(); ++i
) {
383 launch_cache::Image
image(imageInfos
[i
].imageData
);
384 strcpy(pathPool
, image
.path());
385 uint32_t len
= (uint32_t)strlen(pathPool
);
386 memcpy(entries
->uuid
, image
.uuid(), sizeof(uuid_t
));
387 entries
->loadAddress
= (uint64_t)imageInfos
[i
].loadAddress
;
388 entries
->pathStringOffset
= (uint32_t)(pathPool
- pathPoolStart
);
389 entries
->pathLength
= len
;
390 pathPool
+= (len
+1);
393 // lazily alloc reply port
394 if ( sNotifyReplyPorts
[portSlot
] == 0 ) {
395 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &sNotifyReplyPorts
[portSlot
]) )
396 mach_port_insert_right(mach_task_self(), sNotifyReplyPorts
[portSlot
], sNotifyReplyPorts
[portSlot
], MACH_MSG_TYPE_MAKE_SEND
);
397 //log("allocated reply port %d\n", sNotifyReplyPorts[portSlot]);
399 //log("found port to send to\n");
400 mach_msg_header_t
* h
= (mach_msg_header_t
*)buffer
;
401 h
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND
); // MACH_MSG_TYPE_MAKE_SEND_ONCE
402 h
->msgh_id
= unloading
? DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID
: DYLD_PROCESS_INFO_NOTIFY_LOAD_ID
;
403 h
->msgh_local_port
= sNotifyReplyPorts
[portSlot
];
404 h
->msgh_remote_port
= allImageInfo
->notifyPorts
[portSlot
];
405 h
->msgh_reserved
= 0;
406 h
->msgh_size
= (mach_msg_size_t
)sizeof(buffer
);
407 //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);
408 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
);
409 //log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size);
410 if ( sendResult
== MACH_SEND_INVALID_DEST
) {
411 // sender is not responding, detatch
412 //log("process requesting notification gone. deallocation send port %d and receive port %d\n", allImageInfo->notifyPorts[portSlot], sNotifyReplyPorts[portSlot]);
413 mach_port_deallocate(mach_task_self(), allImageInfo
->notifyPorts
[portSlot
]);
414 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[portSlot
]);
415 allImageInfo
->notifyPorts
[portSlot
] = 0;
416 sNotifyReplyPorts
[portSlot
] = 0;
418 else if ( sendResult
== MACH_RCV_TIMED_OUT
) {
419 // client took too long, ignore him from now on
420 sZombieNotifiers
[portSlot
] = true;
421 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[portSlot
]);
422 sNotifyReplyPorts
[portSlot
] = 0;
426 void AllImages::notifyMonitorMain()
428 dyld_all_image_infos
* allImageInfo
= gAllImages
.oldAllImageInfo();
429 for (int slot
=0; slot
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) {
430 if ( (allImageInfo
->notifyPorts
[slot
] != 0 ) && !sZombieNotifiers
[slot
] ) {
431 if ( sNotifyReplyPorts
[slot
] == 0 ) {
432 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &sNotifyReplyPorts
[slot
]) )
433 mach_port_insert_right(mach_task_self(), sNotifyReplyPorts
[slot
], sNotifyReplyPorts
[slot
], MACH_MSG_TYPE_MAKE_SEND
);
434 //dyld::log("allocated reply port %d\n", sNotifyReplyPorts[slot]);
436 //dyld::log("found port to send to\n");
437 uint8_t messageBuffer
[sizeof(mach_msg_header_t
) + MAX_TRAILER_SIZE
];
438 mach_msg_header_t
* h
= (mach_msg_header_t
*)messageBuffer
;
439 h
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND
); // MACH_MSG_TYPE_MAKE_SEND_ONCE
440 h
->msgh_id
= DYLD_PROCESS_INFO_NOTIFY_MAIN_ID
;
441 h
->msgh_local_port
= sNotifyReplyPorts
[slot
];
442 h
->msgh_remote_port
= allImageInfo
->notifyPorts
[slot
];
443 h
->msgh_reserved
= 0;
444 h
->msgh_size
= (mach_msg_size_t
)sizeof(messageBuffer
);
445 //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);
446 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
);
447 //dyld::log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size);
448 if ( sendResult
== MACH_SEND_INVALID_DEST
) {
449 // sender is not responding, detatch
450 //dyld::log("process requesting notification gone. deallocation send port %d and receive port %d\n", allImageInfo->notifyPorts[slot], sNotifyReplyPorts[slot]);
451 mach_port_deallocate(mach_task_self(), allImageInfo
->notifyPorts
[slot
]);
452 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
453 allImageInfo
->notifyPorts
[slot
] = 0;
454 sNotifyReplyPorts
[slot
] = 0;
456 else if ( sendResult
== MACH_RCV_TIMED_OUT
) {
457 // client took too long, ignore him from now on
458 sZombieNotifiers
[slot
] = true;
459 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
460 sNotifyReplyPorts
[slot
] = 0;
466 void AllImages::notifyMonitorLoads(const launch_cache::DynArray
<loader::ImageInfo
>& newImages
)
468 // notify each monitoring process
469 dyld_all_image_infos
* allImageInfo
= gAllImages
.oldAllImageInfo();
470 for (int slot
=0; slot
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) {
471 if ( allImageInfo
->notifyPorts
[slot
] != 0 ) {
472 notifyMonitoringDyld(false, slot
, newImages
);
474 else if ( sNotifyReplyPorts
[slot
] != 0 ) {
475 // monitoring process detached from this process, so release reply port
476 //dyld::log("deallocated reply port %d\n", sNotifyReplyPorts[slot]);
477 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
478 sNotifyReplyPorts
[slot
] = 0;
479 sZombieNotifiers
[slot
] = false;
484 void AllImages::notifyMonitorUnloads(const launch_cache::DynArray
<loader::ImageInfo
>& unloadingImages
)
486 // notify each monitoring process
487 dyld_all_image_infos
* allImageInfo
= gAllImages
.oldAllImageInfo();
488 for (int slot
=0; slot
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) {
489 if ( allImageInfo
->notifyPorts
[slot
] != 0 ) {
490 notifyMonitoringDyld(true, slot
, unloadingImages
);
492 else if ( sNotifyReplyPorts
[slot
] != 0 ) {
493 // monitoring process detached from this process, so release reply port
494 //dyld::log("deallocated reply port %d\n", sNotifyReplyPorts[slot]);
495 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
496 sNotifyReplyPorts
[slot
] = 0;
497 sZombieNotifiers
[slot
] = false;