4 // Virtual Memory Wrapper
6 // Copyright (c) 2004, Charles McGarvey
7 // All rights reserved.
9 // Redistribution and use in source and binary forms, with or without modification, are
10 // permitted provided that the following conditions are met:
12 // 1. Redistributions of source code must retain the above copyright notice, this list
13 // of conditions and the following disclaimer.
15 // 2. Redistributions in binary form must reproduce the above copyright notice, this
16 // list of conditions and the following disclaimer in the documentation and/or other
17 // materials provided with the distribution.
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22 // SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33 #include <mach/mach_traps.h> // for task_for_pid(3)
34 #include <signal.h> // for stop(2)
36 static __inline__ vm_map_t
_VMTaskFromPID( pid_t process
)
40 if ( task_for_pid( current_task(), process
, &task
) == KERN_SUCCESS
) {
46 static __inline__ VMRegion
_VMMakeRegionWithAttributes( pid_t process
, mach_vm_address_t address
, mach_vm_size_t size
, unsigned attribs
)
49 region._process
= process
;
50 region._address
= address
;
52 region._attributes
= attribs
;
56 unsigned _VMAttributesFromAddress( pid_t process
, mach_vm_address_t address
);
59 const VMRegion VMNullRegion
= { 0, 0, 0, 0 };
63 #pragma mark VMRegion Functions
64 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
66 VMRegion
VMMakeRegion( pid_t process
, mach_vm_address_t address
, mach_vm_size_t size
)
69 region._process
= process
;
70 region._address
= address
;
72 region._attributes
= _VMAttributesFromAddress( process
, address
);
76 BOOL VMRegionSetData( VMRegion region
, NSData
*data
)
78 // get the size that should be used (to prevent from writing past the region)
79 mach_vm_size_t size
= (mach_vm_size_t
)[data length
];
80 size
= (size
> region._size
)? region._size
: size
;
82 return VMWriteBytes( region._process
, region._address
, [data bytes
], size
);
85 NSString
*VMStringFromRegion( VMRegion region
)
87 return [NSString stringWithFormat
:@
"{pid:%i,%p,%u,}", region._process
, region._address
, region._size
];
92 #pragma mark Utility VM Functions
93 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
95 unsigned VMCountRegions( pid_t process
)
98 VMRegion prev
= VMNullRegion
;
101 while ( VMRegionIsNotNull( region
= VMNextRegion( process
, prev
) ) )
110 unsigned VMCountRegionsWithAttributes( pid_t process
, unsigned attribs
)
113 VMRegion prev
= VMNullRegion
;
116 while ( VMRegionIsNotNull( region
= VMNextRegionWithAttributes( process
, prev
, attribs
) ) )
126 VMRegion
VMNextRegion( pid_t process
, VMRegion previous
)
128 vm_map_t task
= _VMTaskFromPID( process
);
129 unsigned attribs
= 0;
131 kern_return_t result
;
133 mach_vm_address_t address
= 0x0;
134 mach_vm_size_t size
= 0;
135 vm_region_basic_info_data_64_t info
;
136 mach_msg_type_number_t infoCnt
= VM_REGION_BASIC_INFO_COUNT_64
;
137 mach_port_t object_name
= 0;
139 if ( !VMEqualRegions( previous
, VMNullRegion
) ) {
140 address
= previous._address
+ previous._size
;
143 // get the next region
144 result
= mach_vm_region( task
, &address
, &size
, VM_REGION_BASIC_INFO_64
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
);
146 if ( result
== KERN_SUCCESS
) {
147 // get the attributes
148 if ( info.protection
& VM_PROT_READ
) {
149 attribs |
= VMREGION_READABLE
;
151 if ( info.protection
& VM_PROT_WRITE
) {
152 attribs |
= VMREGION_WRITABLE
;
154 if ( info.protection
& VM_PROT_EXECUTE
) {
155 attribs |
= VMREGION_EXECUTABLE
;
158 return _VMMakeRegionWithAttributes( process
, address
, size
, attribs
);
164 VMRegion
VMNextRegionWithAttributes( pid_t process
, VMRegion previous
, unsigned attribs
)
168 while ( VMRegionIsNotNull( region
= VMNextRegion( process
, previous
) ) )
170 if ( (attribs
& region._attributes
) == attribs
) {
171 // pass back this region if the attributes match
181 NSData
*VMReadData( pid_t process
, mach_vm_address_t address
, mach_vm_size_t size
)
183 vm_map_t task
= _VMTaskFromPID( process
);
184 kern_return_t result
;
187 mach_vm_size_t actualSize
;
189 // create a local block to hold the incoming data
190 buffer
= (void *)malloc( (size_t)size
);
197 result
= mach_vm_read_overwrite( task
, address
, size
, (vm_offset_t
)buffer
, &actualSize
);
198 if ( result
!= KERN_SUCCESS
) {
204 // everything seems to be peachy, so return the data
205 return [[[NSData alloc
] initWithBytesNoCopy
:buffer length
:actualSize freeWhenDone
:YES
] autorelease
];
208 BOOL VMReadBytes( pid_t process
, mach_vm_address_t address
, void *bytes
, mach_vm_size_t
*size
)
210 vm_map_t task
= _VMTaskFromPID( process
);
211 kern_return_t result
;
212 mach_vm_size_t staticsize
= *size
;
215 result
= mach_vm_read_overwrite( task
, address
, staticsize
, (vm_offset_t
)bytes
, size
);
216 if ( result
!= KERN_SUCCESS
) {
223 BOOL VMWriteData( pid_t process
, mach_vm_address_t address
, NSData
*data
)
225 return VMWriteBytes( process
, address
, [data bytes
], [data length
] );
228 BOOL VMWriteBytes( pid_t process
, mach_vm_address_t address
, const void *bytes
, mach_vm_size_t size
)
230 vm_map_t task
= _VMTaskFromPID( process
);
231 kern_return_t result
;
233 // attempt to write the bytes and return success/failure
234 result
= mach_vm_write( task
, address
, (vm_offset_t
)bytes
, size
);
235 return (result
== KERN_SUCCESS
);
239 unsigned _VMAttributesFromAddress( pid_t process
, mach_vm_address_t address
)
241 vm_map_t task
= _VMTaskFromPID( process
);
242 unsigned attribs
= 0;
244 kern_return_t result
;
246 mach_vm_size_t size
= 0;
247 vm_region_basic_info_data_64_t info
;
248 mach_msg_type_number_t infoCnt
= VM_REGION_BASIC_INFO_COUNT_64
;
249 mach_port_t object_name
= 0;
251 // get the next region
252 result
= mach_vm_region( task
, &address
, &size
, VM_REGION_BASIC_INFO_64
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
);
254 if ( result
== KERN_SUCCESS
) {
255 // get the attributes
256 if ( info.protection
& VM_PROT_READ
) {
257 attribs |
= VMREGION_READABLE
;
259 if ( info.protection
& VM_PROT_WRITE
) {
260 attribs |
= VMREGION_WRITABLE
;
262 if ( info.protection
& VM_PROT_EXECUTE
) {
263 attribs |
= VMREGION_EXECUTABLE
;
265 // return the region attributes