Re: Patching an application (long)
Re: Patching an application (long)
- Subject: Re: Patching an application (long)
- From: Adam Atlas <email@hidden>
- Date: Thu, 16 Jan 2003 08:20:07 -0800
Hi Sven,
libPatch is deprecated and unsupported. Its author, Ed Wynne, was ordered to stop maintaining and distributing it by Apple (who he works for). Not only that, but it is basically nonfunctional on Mac OS X. A runtime-level modification you may want to look at is Method Swizzling, posted on CocoaDev:
http://cocoadev.com/index.pl?MethodSwizzling
If that also doesn't work for you, you could license APE from Unsanity. Licenses are free, if the product it is used in is freeware. If you're only doing this within your own app (you don't need your code to run in other programs), contact them about Ape Lite, a shared-library version which is more lightweight and better for that purpose. (Ape Lite is not listed on their site; you need to contact them about it.) Before that, I do suggest you try Method Swizzling.
Since these things are more hacky than general discussion on this list, I recommend the extendamac-macosx list for questions like this. See
http://lists.sourceforge.net/lists/listinfo/extendamac-macosx
>
Date: Thu, 16 Jan 2003 13:09:41 +0100
>
Subject: Patching an application (long)
>
From: "Sven A. Schmidt" <email@hidden>
>
To: "'email@hidden'" <email@hidden>
>
>
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.