0

I create a simple example trying to get the first argument of the method, if it works I plan to extend it to any number of arguments:

+ (void)simpleTest:(NSInteger)teamId {

    unsigned int argumentCount = method_getNumberOfArguments(class_getClassMethod([self class], _cmd));
    
    for (unsigned int i = 2; i < argumentCount; i++) {
        const char *argumentType = method_copyArgumentType(class_getClassMethod([self class], _cmd), i);
        
        if (strcmp(argumentType, @encode(NSInteger)) == 0) {
            NSInteger argumentValue = *((NSInteger *)(((uintptr_t)self) + sizeof(void *) * i));
            NSLog(@"Argument %d: %ld", i - 1, (long)argumentValue);
        }
        
        free((void *)argumentType);
    }


}

I call it like this:

[self simpleTest:22];

the log print:

Argument 1: 140703128941760

I think the problem happens at the piece of code where I want to get 'argumentValue', but I don`t know how to fix it.

itenyh
  • 1,921
  • 2
  • 23
  • 38
  • 2
    `self` is a pointer to your class containing function `+simpleTest`. Why should the argument to a function be located at a certain offset behind `self`? Its probably located on the stack or in a register depending on the ABI to call a function... – mschmidt Jul 21 '23 at 07:50
  • After thinking more about it, I think you are confusing `self` -- which is a pointer to your class -- with the _location_ of the first implicit argument. I.e. you probably want something like `((uintptr_t)&self) + sizeof ...`. However, even if the implicit argument is located on the stack, the compiler may return the location of a local copy of the argument rather than the actual argument location. – mschmidt Jul 21 '23 at 11:36
  • 1
    What you're looking for is varargs. I'm duping this to the question that answers that. Please comment here if you believe there is more to your question and we can reopen this one. The code you're writing here relies on a particular parameter passing approach that is neither correct (see mschmidt's discussion of the ABI), nor reliable if it happened to be correct. But it's luckily also unnecessary. – Rob Napier Jul 21 '23 at 12:56
  • @Rob Napier I want to get the arguments of existing method dynamically which is not created with varargs. – itenyh Jul 24 '23 at 01:24
  • @mschmidt I think I only care about the value of the argument that passed in – itenyh Jul 24 '23 at 01:32
  • Each platform has its own convention for passing arguments, and it depends on the number and types of the arguments. If you're working with aarch64, start with the [ABI](https://github.com/ARM-software/abi-aa/blob/844a79fd4c77252a11342709e3b27b2c9f590cf1/aapcs64/aapcs64.rst), taking into account [Apple's differences](https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms). You'll probably want to skip down to section 6.8 to get started. A major reason for varargs to provide a consistent way to do this. Note many things are passed in registers, not the stack. – Rob Napier Jul 24 '23 at 01:32
  • If you can update your question to cover the specific architecture(s) you're looking for, and what kinds of arguments (will it always be series of 64-bit integers, or could it be arbitrary things?), it would be reasonable to reopen this. It tends to be a bit tedious and fiddly, so I don't know if you'll get an answer, but it would be a different question. Some sense of why you're doing this might help us get you onto an easier path. – Rob Napier Jul 24 '23 at 01:41
  • @RobNapier Generally speaking, I want to save the method name and the arguments of any method, then I could 'reproduce' the method at any time with NSInvocation instance created with the saved method name and arguments – itenyh Jul 24 '23 at 02:46
  • I'm not 100% what you're trying to build here, but I strongly suspect what you really want is an NSProxy-based surrogate object that implements `forwardInvocation:`. This will create the NSInvocation for you, and you can then pass that along to the underlying object and also save it. For more details, see https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105 – Rob Napier Jul 24 '23 at 14:32
  • And don't forget about [NSUndoManager](https://developer.apple.com/documentation/foundation/nsundomanager?language=objc), which is possibly relevant to problems in this space. – Rob Napier Jul 24 '23 at 14:34
  • For some simple implementations of this, see the trampolines in https://github.com/iosptl/ios7ptl/tree/master/ch24-DeepObjC/ObserverTrampoline. – Rob Napier Jul 24 '23 at 14:46

0 Answers0