Shapes Workshop
Shapes Workshop

Reputation: 23

Adding a parameter to function in Java Bytecode

I've got compiled .jar plugin with X.class file. X.class file contains a method Y with parameters Y(string s1, string s2....). I need to pass to one more string - so i launched reJ and dirtyJoe, edited a descriptor of my Y method, changed maximum local variables count from 8 to 9, added new local variable, set it same as previous variables, just gave it another index, edited code and saved the method. I packed it back into .jar file and tried to compile in Unity with new version of my plugin. Unfortunately - it gave me error saying my new variable is invalid -

EXCEPTION FROM SIMULATION:
local 0008: invalid

...at bytecode offset 00000036
locals[0000]: Ljava/lang/String;
locals[0001]: Ljava/lang/String;
locals[0002]: Ljava/lang/String;
locals[0003]: Ljava/lang/String;
locals[0004]: Ljava/lang/String;
locals[0005]: [B
locals[0006]: Landroid/net/Uri;
locals[0007]: Landroid/content/Intent;
locals[0008]: <invalid>
stack[0001]: Landroid/content/Intent;
stack[top0]: string{"android.intent.extra.TEXT"}
...while working on block 0036
...while working on method StartShareIntentMedia:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
...while processing StartShareIntentMedia (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
...while processing com/androidnative/features/social/common/SocialGate.class

That's my very first time with Java bytecode, hope i'll get some help. Thanks!

Upvotes: 1

Views: 2150

Answers (1)

Antimony
Antimony

Reputation: 39451

Editing bytecode is not for the faint of heart. I'd recommend reading the JVM specification before you start.

That being said, there are a couple things you could be doing wrong, based on your description.

At the beginning of the method, the method parameters are passed in in local variable slots 0..n-1. You can't just choose any index for your new local variable, you have to use the index after the last current parameter. If the bytecode is already using that slot for something else, you'll have to adjust all usages of it to something else. Alternatively, you can add a move sequence (i.e. aload n astore y) at the beginning of the method. This won't affect any usages of that slot as a local variable later in the method.

If you have debugging information, like a LocalVariableTable, you'll have to adjust all the references in that. If the bytecode has a StackMapTable you'll have to adjust that. Assuming the code isn't using invokedynamic, it's probably easier to just change the bytecode version back to 50.0 and remove the stack map table entirely.

Next up, you'll have to change the method descriptor. The descriptor essentially gives the signature of the method, and in bytecode, methods are always identified by the (class, name, descriptor) triple. You'll need to add a string in as a parameter at the end of the descriptor before the final closing parenthesis and return type. You'll have to add the new descriptor to the constant pool if it's not there already.

Then you'll have to adjust the definition of the method to reference the new descriptor, and also adjust every single place where that method is called (better hope that inheritance and reflection aren't involved!).

And of course, you'll also have to adjust every callsite to actually pass in the new parameter.

Upvotes: 3

Related Questions