Patching an application (long)
Patching an application (long)
- Subject: Patching an application (long)
- From: "Sven A. Schmidt" <email@hidden>
- Date: Thu, 16 Jan 2003 13:09:41 +0100
Hi,
I'm trying to replace (or rather extend) a method implementation of an
application with my own.
I've actually made more progress than I expected and Objective-C/Cocoa
have impressed me time and time again on my way. But I'm not there, yet.
So far I have
- spied from the application which object I need, how to get it, and
which message I need to replace (with the great combination of tools
F-Script / F-Script-Anywhere).
- set up a project based on libPatch and managed to attach a bundle to
the running application.
In this bundle/library, I have defined a category on the target object
(OriginalObject) that replaces the method implementation in question.
E.g.
PatchController.m:
@implementation OriginalObject (MyExtension)
- (void)theMethod:(id)sender {...}
@end
Now, when I build the library, I get the linker error:
ld: Undefined symbols: .objc_class_name_OriginalObject
My first shot a fixing this was adding an empty implementation to
myObject.m:
@implementation OriginalObject
@end
This worked great. I could patch the application and my replacement
would be called. But this won't do, because I also need to call the
original method.
So next I tried the IMP caching trick from 'Cocoa Programming' which
stores the pointer to the original implementation in the category's
+load method before it is replaced with the new implementation.
The book warns that this is only tested on 10.1.3 or earlier and it
actually doesn't work. class_getInstanceMethod(...) returns null when I
call it in +load.
I can think of the following reasons:
1) Heed the warning. You're using 10.2 and are out of luck on this one.
2) Adding the empty implementation as linker fodder above actually
hides the original implementation
To further investigate I tried MethodSwizzle from cocoadev. This swaps
implementations between selectors that take similar parameters. No go,
either. class_getInstanceMethod returns nil for both selectors.
Now this puzzled me, so next I used the following to get a list of all
selectors (from 'Cocoa Programming', too, which seems to be as good as
it is big -- only had it for half a day but it's already a treasure
grove):
NSMutableArray *methodList( Class aClass ) {
NSMutableArray *result = [ NSMutableArray array ];
void *iterator = NULL;
struct objc_method_list *mlist;
while ( mlist = class_nextMethodList( aClass, &iterator ) ) {
const int numMethods = mlist->method_count;
int i;
for ( i = 0; i < numMethods; i++ ) {
Method currentMethod = &mlist->method_list[i];
[ result addObject: NSStringFromSelector( currentMethod->method_name
) ];
}
}
return result;
}
The array is empty. The runtime system does not know about the real
abilities of the object I'm trying to patch, at least not at the time
I'm calling 'methodList'.
So what can I do?
I have to add the empty implementation to silence the linker, since I
don't have any library to link against. Or maybe there something anlong
the lines of '-undefined suppress' as a linker switch?
In any case, I don't think I really hide the 'real' implementation,
since the application still runs and I can replace the original method
fine. I just can't find a way to get at the old implementation.
Is there a way other than in +load of the bundle to inspect the target
object? My best guess right now is that I'm looking to early. I tried
launching patch program and target application in different order but
that didn't change anything.
Should I use a different approach?
Any hints, suggestions, pointers greatly appreciated,
Sven
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.