Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[feature] Jadx plugin extraction of method code #2305

Open
Devilx86 opened this issue Oct 13, 2024 · 4 comments
Open

[feature] Jadx plugin extraction of method code #2305

Devilx86 opened this issue Oct 13, 2024 · 4 comments

Comments

@Devilx86
Copy link

Describe your idea

Hello,
I am working on a Jadx plugin and I require extraction of method code alone. Similar to the ((JavaClass) node).getCode() a ((JavaMethod) node).getCode() or addition of a ((JavaMethod) node).getDefEndPos() would be helpful. Please let me know if there are any alternatives that I am not aware of which I could use.

Thanks

@skylot
Copy link
Owner

skylot commented Oct 13, 2024

I require extraction of method code alone

Sure. I will add this method.
As a workaround for now, you can use this code:

private String cutMethodCode(MethodNode mth, ICodeInfo codeInfo) {
	int startPos = getCommentStartPos(codeInfo, mth.getDefPosition());
	int stopPos = getMethodEnd(mth, codeInfo);
	return codeInfo.getCodeStr().substring(startPos, stopPos);
}

protected int getCommentStartPos(ICodeInfo codeInfo, int pos) {
	String emptyLine = "\n\n";
	int emptyLinePos = codeInfo.getCodeStr().lastIndexOf(emptyLine, pos);
	return emptyLinePos == -1 ? pos : emptyLinePos + emptyLine.length();
}

private int getMethodEnd(MethodNode mth, ICodeInfo codeInfo) {
	// skip nested nodes DEF/END until first unpaired END annotation (end of this method)
	Integer end = codeInfo.getCodeMetadata().searchDown(mth.getDefPosition() + 1, new BiFunction<>() {
		int nested = 0;

		@Override
		public Integer apply(Integer pos, ICodeAnnotation ann) {
			switch (ann.getAnnType()) {
				case DECLARATION:
					ICodeNodeRef node = ((NodeDeclareRef) ann).getNode();
					switch (node.getAnnType()) {
						case CLASS:
						case METHOD:
							nested++;
							break;
					}
					break;

				case END:
					if (nested == 0) {
						return pos;
					}
					nested--;
					break;
			}
			return null;
		}
	});
	return end != null ? end : codeInfo.getCodeStr().length();
}

@Devilx86
Copy link
Author

Devilx86 commented Oct 13, 2024

Thank you! @skylot

@skylot
Copy link
Owner

skylot commented Oct 17, 2024

Done. Added getCodeStr() method for MethodNode and JavaMethod classes. Check jadx snapshot version.

Although, it will not work for plugins running in jadx-cli because code metadata not added. It is possible to fix this by saving start/end method pos during codegen into new attribute, but for now I don't want to do this, because such case might be very rare. @Devilx86 if this affects you, let me know, and I will add this (maybe I will find a better approach).

@Devilx86
Copy link
Author

Thanks very much @skylot, this works for my usecase. Another issue I noticed is that the ((JavaClass) node).getCode() method returns an empty string for inner classes. I was able to get around this with a modified version of the code you have shared above

public static String getClassCode(ClassNode cls, ICodeInfo codeInfo) {
        int startPos = getCommentStartPos(codeInfo, cls.getDefPosition());
	int stopPos = getEndFrom(cls.getDefPosition(), codeInfo) + 1;
	return codeInfo.getCodeStr().substring(startPos, stopPos);
}

private static int getEndFrom(int startPosition, ICodeInfo codeInfo) {
	// skip nested nodes DEF/END until first unpaired END annotation (end of this method)
	Integer end = codeInfo.getCodeMetadata().searchDown(startPosition + 1, new BiFunction<>() {
	.....
}

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

2 participants