2 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 #ifndef _DYLD_PROCESS_INFO_
24 #define _DYLD_PROCESS_INFO_
28 #include <mach/mach.h>
29 #include <dispatch/dispatch.h>
30 #include <uuid/uuid.h>
32 //FIXME we should include dyld_priv.h, but we need to do this to workaround a header search path bug in tapi
33 typedef uint32_t dyld_platform_t
;
40 // Beginning in iOS 10.0 and Mac OS X 10.12, this is how lldb figures out mach-o binaries are in a process:
42 // When attaching to an existing process, lldb uses _dyld_process_info_create() to get the current list of images
43 // in a process, then falls into the start up case.
45 // When starting a process, lldb starts the process suspended, finds the "_dyld_debugger_notification" symbol in
46 // dyld, sets a break point on it, then resumes the process. Dyld will call _dyld_debugger_notification() with
47 // a list of images that were just added or removed from the process. Dyld calls this function before running
48 // any initializers in the image, so the debugger will have a chance to set break points in the image.
52 enum dyld_notify_mode
{ dyld_notify_adding
=0, dyld_notify_removing
=1, dyld_notify_remove_all
=2 };
53 // void _dyld_debugger_notification(enum dyld_notify_mode, unsigned long count, uint64_t machHeaders[]);
57 struct dyld_process_cache_info
{
58 uuid_t cacheUUID
; // UUID of cache used by process
59 uint64_t cacheBaseAddress
; // load address of dyld shared cache
60 bool noCache
; // process is running without a dyld cache
61 bool privateCache
; // process is using a private copy of its dyld cache
63 typedef struct dyld_process_cache_info dyld_process_cache_info
;
65 struct dyld_process_aot_cache_info
{
67 uint64_t cacheBaseAddress
;
69 typedef struct dyld_process_aot_cache_info dyld_process_aot_cache_info
;
72 dyld_process_state_not_started
= 0x00, // process is suspended, dyld has not started running yet
73 dyld_process_state_dyld_initialized
= 0x10, // dyld has initialzed itself
74 dyld_process_state_terminated_before_inits
= 0x20, // process was terminated due missing library or symbol before it got to main()
75 dyld_process_state_libSystem_initialized
= 0x30, // dyld has run libSystem's initializer
76 dyld_process_state_running_initializers
= 0x40, // dyld is running other initializers
77 dyld_process_state_program_running
= 0x50, // dyld has finished and jumped into main()
78 dyld_process_state_dyld_terminated
= 0x60 // process was terminated by dyld post-main (e.g. bad lazying binding info)
81 struct dyld_process_state_info
{
82 uint64_t timestamp
; // mach_absolute_time of last time dyld change to image list
83 uint32_t imageCount
; // number of images currently loaded into process
84 uint32_t initialImageCount
; // number of images statically loaded into process (before any dlopen() calls)
85 uint8_t dyldState
; // one of dyld_process_state_* values
87 typedef struct dyld_process_state_info dyld_process_state_info
;
90 typedef const struct dyld_process_info_base
* dyld_process_info
;
93 // Generate a dyld_process_info object for specified task.
95 // The timestamp parameter is an optimization to not spend the time to gather all the image information
96 // if the process image list has not changed since the last call. If timestamp is zero, this function
97 // always gathers the full process info. If timestamp is non-zero, this function will check if the target
98 // task's image list has changed since that time. If is has not changed, the function returns NULL and
99 // kern_return_t is KERN_SUCCESS. If it has changed, the function gathers the full image info.
100 // The kernelError parameter can be NULL for clients that don't care why it failed.
102 extern dyld_process_info
_dyld_process_info_create(task_t task
, uint64_t timestamp
, kern_return_t
* kernelError
);
104 // retain/release dyld_process_info for specified task
105 extern void _dyld_process_info_release(dyld_process_info info
);
106 extern void _dyld_process_info_retain(dyld_process_info info
);
108 // fill in struct with basic info about dyld in the process
109 extern void _dyld_process_info_get_state(dyld_process_info info
, dyld_process_state_info
* stateInfo
);
111 // fill in struct with info about dyld cache in use by process
112 extern void _dyld_process_info_get_cache(dyld_process_info info
, dyld_process_cache_info
* cacheInfo
);
114 // fill in struct with info about aot cache in use by process
115 extern void _dyld_process_info_get_aot_cache(dyld_process_info info
, dyld_process_aot_cache_info
* aotCacheInfo
);
117 // iterate all images in process
118 extern void _dyld_process_info_for_each_image(dyld_process_info info
, void (^callback
)(uint64_t machHeaderAddress
, const uuid_t uuid
, const char* path
));
120 // iterate all aot images in process
121 extern void _dyld_process_info_for_each_aot_image(dyld_process_info info
, bool (^callback
)(uint64_t x86Address
, uint64_t aotAddress
, uint64_t aotSize
, uint8_t* aotImageKey
, size_t aotImageKeySize
)) __API_UNAVAILABLE(ios
, tvos
, watchos
) __API_UNAVAILABLE(bridgeos
);
123 // iterate all segments in an image
124 extern void _dyld_process_info_for_each_segment(dyld_process_info info
, uint64_t machHeaderAddress
, void (^callback
)(uint64_t segmentAddress
, uint64_t segmentSize
, const char* segmentName
));
126 // returns 0 if the platform cannot be determined, otherwise returns the platform of the remote process
127 extern dyld_platform_t
_dyld_process_info_get_platform(dyld_process_info info
) SPI_AVAILABLE(macos(10.15), ios(13.0), tvos(13.0), watchos(6.0), bridgeos(4.0));
129 typedef const struct dyld_process_info_notify_base
* dyld_process_info_notify
;
132 // Request notifications if image list changes in target process. Each time a load or unload happens in the target taks,
133 // the notify block will be called in this process. If the process exits, the notifyExit block will be called.
134 // If the notifications cannot be set up, this function will return NULL, and the reason in the kernError parameter.
135 // The kernelError parameter can be NULL for clients that don't care why it failed.
136 // If you want to stop receiving notifications, call _dyld_process_info_notify_release().
138 extern dyld_process_info_notify
_dyld_process_info_notify(task_t task
, dispatch_queue_t queue
,
139 void (^notify
)(bool unload
, uint64_t timestamp
, uint64_t machHeader
, const uuid_t uuid
, const char* path
),
140 void (^notifyExit
)(void),
141 kern_return_t
* kernelError
);
142 // add block to call right before main() is entered.
143 // does nothing if process is already in main().
144 extern void _dyld_process_info_notify_main(dyld_process_info_notify objc
, void (^notifyMain
)(void));
147 // stop notifications and invalid dyld_process_info_notify object
148 extern void _dyld_process_info_notify_release(dyld_process_info_notify object
);
149 extern void _dyld_process_info_notify_retain(dyld_process_info_notify object
);
156 #endif /* _DYLD_PROCESS_INFO_ */