PrivateFrameworks/vmutils.framework/

Ever wondered how heap works?
Well, it looks for objects on the heap and prints statistics about them. Fine, but I'd like something more, like getting the address of the objects inside the process heap.

While trying to figure our how heap is implemented, I bumped into the vmutils private framework.
It looks like this framework is the one supporting most of the process introspection tools, including heap, leaks and sampler.
In fact, here's a crude but working sampler app (vmutil.h is created with class-dump and massaged into compiling):


cristi:~/Programming/test diciu$ cat vmutil.m
#import
#import "vmutil.h"

int main()
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSProcInfo * pi = [[NSProcInfo alloc] initWithPid:282];
NSLog(@"%@", [pi envVars]);

NSLog(@"%@", [pi name]);
NSLog(@"%@", [pi procTableName]);

NSLog(@"%@", [pi _searchForImage]);
NSLog(@"%@", [pi image]);

NSLog(@"Creating sampler");
NSSampler * sampler = [[NSSampler alloc] initWithPid:282];
NSLog(@"%u", [sampler sampleTask]);

[sampler _initStatistics];
// 3 seconds duration, every 500 milliseconds
[sampler sampleForDuration:3 interval:500];

CallNode * c = [sampler stopSamplingAndReturnCallNode];
NSLog(@"First call node: name: %@, browserName: %@, sc: %@, %@",
[c name], [c browserName], [c sortedChildrenWithPseudoNode], [c fullOutputWithThreshold:2]);

NSLog(@"Stopped sampler");
//NSLog(@"Raw backtraces: %@", [sampler rawBacktraces]);

NSLog(@"Print sampler stats");
[sampler printStatistics];


[pool release];
}



cristi:~/Programming/test diciu$ gcc vmutil.m -framework Cocoa /System/Library/PrivateFrameworks/vmutils.framework/vmutils
In file included from vmutil.m:2:
vmutil.h:190: warning: declaration does not declare anything
vmutil.h:191: warning: declaration does not declare anything


Running our crude sampler (we use sudo because NSSampler requires superuser access):

cristi:~/Programming/test diciu$ sudo ./a.out
Password:
2007-04-03 09:00:19.804 a.out[293] (
"TERM_PROGRAM=Apple_Terminal",
"TERM=xterm-color",
"SHELL=/bin/bash",
"SHLVL=1",
"HOME=/Users/diciu",
"LOGNAME=diciu",
"CVS_RSH=ssh",
"_=/Applications/LoudHush.app/Contents/MacOS/LoudHush"
)
2007-04-03 09:00:19.806 a.out[293] LoudHush
2007-04-03 09:00:19.806 a.out[293] LoudHush
2007-04-03 09:00:19.806 a.out[293] 1043
2007-04-03 09:00:19.912 a.out[293] NSImage 0x3184a0 Size={64, 64} Reps=(
NSBitmapImageRep 0x31eb30 Size={128, 128} ColorSpace=NSDeviceRGBColorSpace BPS=8 BPP=32 Pixels=128x128 Alpha=YES Planar=NO Format=0,
NSBitmapImageRep 0x31fa40 Size={48, 48} ColorSpace=NSDeviceRGBColorSpace BPS=8 BPP=32 Pixels=48x48 Alpha=YES Planar=NO Format=0,
NSBitmapImageRep 0x31f670 Size={32, 32} ColorSpace=NSDeviceRGBColorSpace BPS=8 BPP=32 Pixels=32x32 Alpha=YES Planar=NO Format=0,
NSBitmapImageRep 0x31fdb0 Size={16, 16} ColorSpace=NSDeviceRGBColorSpace BPS=8 BPP=32 Pixels=16x16 Alpha=YES Planar=NO Format=0
)
2007-04-03 09:00:19.919 a.out[293] NSImage 0x3185d0 Size={64, 64} Reps=(
NSBitmapImageRep 0x31c9e0 Size={128, 128} ColorSpace=NSDeviceRGBColorSpace BPS=8 BPP=32 Pixels=128x128 Alpha=YES Planar=NO Format=0,
NSBitmapImageRep 0x31ed40 Size={48, 48} ColorSpace=NSDeviceRGBColorSpace BPS=8 BPP=32 Pixels=48x48 Alpha=YES Planar=NO Format=0,
NSBitmapImageRep 0x31fd40 Size={32, 32} ColorSpace=NSDeviceRGBColorSpace BPS=8 BPP=32 Pixels=32x32 Alpha=YES Planar=NO Format=0,
NSBitmapImageRep 0x320130 Size={16, 16} ColorSpace=NSDeviceRGBColorSpace BPS=8 BPP=32 Pixels=16x16 Alpha=YES Planar=NO Format=0
)
2007-04-03 09:00:19.919 a.out[293] Creating sampler
2007-04-03 09:00:20.270 a.out[293] 0
2007-04-03 09:00:24.982 a.out[293] First call node: name: , browserName: 29865 , sc: (
,
,
,
,

), Call graph:
5973 Thread_2c37
5973 _pthread_body
5973 iaxc_processor
5884 iaxc_millisleep
5883 mach_wait_until
5883 mach_wait_until
1 nanosleep
1 mach_absolute_time
1 __nanotime
1 __nanotime
87 iaxc_processor
2 iaxc_process_calls
1 put_iaxc_lock
1 put_iaxc_lock
1 recvfrom
1 recvfrom
5973 Thread_2e23
5973 start
5973 _start
5973 NSApplicationMain
5973 -[NSApplication run]
5973 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]
[..]



Unfortunately heap is a bit more complicated as it caches the memory it analyzes (can't figure out why, maybe that's how it does instance counting) - because of this cache everything gets tangles up into array ranges and what not.

There are lots of other interesting things in the vmutils framework, both in objective C and plain C such as

  • -[NSMachOTaskImage cnameOfSymbolWithAddress:(unsigned int)fp8]

  • task_get_malloc_ptrs