I'm trying to write a DTrace script that will show me the parameter passed to -[NSURLConnection sendSynchronousRequest:returningResponse:error:]
and I can't find a struct that works for extracting the string out of the passed in NSString
parameter. This question has an answer that works for OS X applications, but it does not work for my application which is using the iOS simulator.
Although I'm looking for a solution to this specific example, I'm much more interested in learning the best way to define / discover the underlying memory structure for any given Objective-C object. As you can see from the OS X test app I wrote, an NSString
parameter does not always have the raw string data in the same place. In the case where it's __NSCFString
is appears to be located (length prefixed) at 16 bytes in. In the case where it's a __NSCFConstant
string it's somewhere else that's not immediately obvious looking at the raw memory dump.
If there are structs defined in system headers that will show me what I'm looking for that would be good first step but I'm thinking that LLDB ought to be able to show me useful hints as well.
In theory, Class-dump should be able to examine a Mach-O file and report the declarations for your Objective C classes.
When I last tried to use Class-dump I didn't have any success; I can't remember exactly why but I now see that there's a possible alternative, namely Hopper. In any case, after reading the article Abusing the Objective C runtime, I used gdb to inspect the address space; unlike you, I used DTrace to stop a process on entry to a method and then examined the memory addressed by arg2. If, in your case, you can't see a reasonable string then I suggest that you look for pointers and follow them.
Note that your question used the phrase "DTrace-compatible". That raises an interesting point: dtrace(1) is a compiler and it is not obliged to pack structures in the same way as whatever was used to build your victim. On Solaris, dtrace(1) conforms to the ABI of the given platform, be it SPARC or x86. I haven't investigated its behaviour on MacOS but it might be different, so bear this in mind, particularly if dtrace gives you unexpected results.
The compiler can make virtually everything with ObjC code as long as it conforms to public definition of objective c runtime.
I think you've chosen wrong object to start your study: NSString (along with NSNumber) has multiple versions which are chosen depending on your usage. E.g. your compile-time constant NSString is likely represented as:
You can also find your constant NSString (or CFString) by checking the __cfstring segment, e.g. via otool
otool -s __DATA __cfstring
.I don't know of any method that would allow you to decompile any ObjC object into C-struct form. My suggestion is to look how various fields of the objects are accessed by disassembling your program. E.g. you could add breakpoint to setters and getters of your properties.
If you feel comfortable, you may also study source code of the compiler responsible for making high level code into intermediate (in case of LLVM based compiler) representation: CGObjCMac, CGObjC, CGObjCRuntime.