-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
db4aa92
commit eab6440
Showing
380 changed files
with
14,012 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>com.github.wdestroier</groupId> | ||
<artifactId>chamomile</artifactId> | ||
<version>1.0.0</version> | ||
<name>Chamomile assembler/disassembler</name> | ||
<description>A Java Virtual Machine class file assembler and disassembler</description> | ||
|
||
<properties> | ||
<maven.compiler.source>11</maven.compiler.source> | ||
<maven.compiler.target>11</maven.compiler.target> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
<version>1.18.16</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
46 changes: 46 additions & 0 deletions
46
src/main/java/com/github/wdestroier/chamomile/LinearSweepDisassembler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package com.github.wdestroier.chamomile; | ||
|
||
import java.io.BufferedInputStream; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import com.github.wdestroier.chamomile.instruction.Instruction; | ||
import com.github.wdestroier.chamomile.instruction.InstructionFactory; | ||
import com.github.wdestroier.chamomile.io.Endianness; | ||
import com.github.wdestroier.chamomile.io.MultiEndianInputStream; | ||
import com.github.wdestroier.chamomile.io.ShortArrayInputStream; | ||
|
||
import lombok.AllArgsConstructor; | ||
|
||
@AllArgsConstructor | ||
public class LinearSweepDisassembler { | ||
|
||
private InstructionFactory instructionFactory; | ||
|
||
public LinearSweepDisassembler() { | ||
this(new InstructionFactory()); | ||
} | ||
|
||
public List<Instruction<?>> disassemble(MultiEndianInputStream input) { | ||
var bytesRead = input.getBytesRead(); | ||
|
||
// Needs to be aligned to read the Tableswitch and Tablelookup instructions | ||
input.setBytesRead(0); | ||
|
||
var instructions = new ArrayList<Instruction<?>>(); | ||
|
||
while (input.available() > 0) { | ||
instructions.add(instructionFactory.getInstruction(input)); | ||
} | ||
|
||
input.setBytesRead(input.getBytesRead() + bytesRead); | ||
|
||
return instructions; | ||
} | ||
|
||
public List<Instruction<?>> disassemble(short... code) { | ||
return disassemble(new MultiEndianInputStream(new BufferedInputStream( | ||
new ShortArrayInputStream(code)), Endianness.BIG_ENDIAN)); | ||
} | ||
|
||
} |
24 changes: 24 additions & 0 deletions
24
src/main/java/com/github/wdestroier/chamomile/SinglePassAssembler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.github.wdestroier.chamomile; | ||
|
||
import java.util.List; | ||
|
||
import com.github.wdestroier.chamomile.instruction.Instruction; | ||
import com.github.wdestroier.chamomile.io.Endianness; | ||
import com.github.wdestroier.chamomile.io.MultiEndianOutputStream; | ||
import com.github.wdestroier.chamomile.io.ShortArrayOutputStream; | ||
|
||
public class SinglePassAssembler { | ||
|
||
public void assemble(List<Instruction<?>> instructions, MultiEndianOutputStream output) { | ||
instructions.forEach(instruction -> instruction.write(output)); | ||
} | ||
|
||
public short[] assemble(List<Instruction<?>> instructions) { | ||
var output = new ShortArrayOutputStream(); | ||
|
||
assemble(instructions, new MultiEndianOutputStream(output, Endianness.BIG_ENDIAN)); | ||
|
||
return output.toUnsignedByteArray(); | ||
} | ||
|
||
} |
152 changes: 152 additions & 0 deletions
152
src/main/java/com/github/wdestroier/chamomile/classfile/ClassFile.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package com.github.wdestroier.chamomile.classfile; | ||
|
||
import com.github.wdestroier.chamomile.classfile.attributeinfo.AttributeInfoFactory; | ||
import com.github.wdestroier.chamomile.classfile.constantkind.ConstantDouble; | ||
import com.github.wdestroier.chamomile.classfile.constantkind.ConstantLong; | ||
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructure; | ||
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructureFactory; | ||
import com.github.wdestroier.chamomile.io.MultiEndianInputStream; | ||
import com.github.wdestroier.chamomile.io.MultiEndianOutputStream; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Data | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
public class ClassFile implements PseudoStructure<ClassFile> { | ||
|
||
private long magic; | ||
private int minorVersion; | ||
private int majorVersion; | ||
private int constantPoolCount; | ||
private PseudoStructure<?>[] constantPool; | ||
private int accessFlags; | ||
private int thisClass; | ||
private int superClass; | ||
private int interfacesCount; | ||
private int[] interfaces; | ||
private int fieldsCount; | ||
private FieldInfo[] fields; | ||
private int methodsCount; | ||
private MethodInfo[] methods; | ||
private int attributesCount; | ||
private PseudoStructure<?>[] attributes; | ||
|
||
@Override | ||
public ClassFile read(MultiEndianInputStream input, PseudoStructureFactory pseudoStructureFactory) { | ||
//TODO ClassFileVerifier, MethodInfoVerifier ... | ||
|
||
magic = input.readUnsignedInt(); | ||
minorVersion = input.readUnsignedShort(); | ||
majorVersion = input.readUnsignedShort(); | ||
constantPoolCount = input.readUnsignedShort(); | ||
|
||
constantPool = new PseudoStructure<?>[constantPoolCount]; | ||
|
||
/* | ||
* cpInfo[0] is reserved | ||
* | ||
* https://stackoverflow.com/questions/56808432/why-is-the-constant-pool-in-java-classfile-indexed-from-1-and-not-0-what-is#:~:text=%22%5BI%5Dndexed%20from%201,index%20into%20the%20constant%20pool. | ||
* https://stackoverflow.com/questions/56808432/why-is-the-constant-pool-in-java-classfile-indexed-from-1-and-not-0-what-is#:~:text=2%20Answers&text=They%20skipped%20index%200%20so,%22catch%20all%22%20exception%20handlers. | ||
*/ | ||
for (var i = 1; i < constantPoolCount; i++) { | ||
var constantKind = constantPool[i] = pseudoStructureFactory.getConstantKind(input); | ||
|
||
// All 8-byte constants take up two entries in the constant_pool | ||
if (constantKind instanceof ConstantLong || constantKind instanceof ConstantDouble) { | ||
constantPool[++i] = null; | ||
} | ||
} | ||
|
||
accessFlags = input.readUnsignedShort(); | ||
|
||
/* | ||
* Must be a valid index in the constant pool table to a ConstantClass structure, | ||
* representing the class or interface defined by the class file | ||
*/ | ||
thisClass = input.readUnsignedShort(); | ||
superClass = input.readUnsignedShort(); | ||
interfacesCount = input.readUnsignedShort(); | ||
|
||
interfaces = new int[interfacesCount]; | ||
|
||
for (var i = 0; i < interfacesCount; i++) { | ||
interfaces[i] = input.readUnsignedShort(); | ||
} | ||
|
||
fieldsCount = input.readUnsignedShort(); | ||
|
||
pseudoStructureFactory.setAttributeInfoFactory( | ||
new AttributeInfoFactory(pseudoStructureFactory, this)); | ||
|
||
fields = new FieldInfo[fieldsCount]; | ||
|
||
for (var i = 0; i < fieldsCount; i++) { | ||
fields[i] = new FieldInfo().read(input, pseudoStructureFactory); | ||
} | ||
|
||
methodsCount = input.readUnsignedShort(); | ||
|
||
methods = new MethodInfo[methodsCount]; | ||
|
||
for (var i = 0; i < methodsCount; i++) { | ||
methods[i] = new MethodInfo().read(input, pseudoStructureFactory); | ||
} | ||
|
||
attributesCount = input.readUnsignedShort(); | ||
|
||
attributes = new PseudoStructure<?>[attributesCount]; | ||
|
||
for (var i = 0; i < attributesCount; i++) { | ||
attributes[i] = pseudoStructureFactory.getAttributeInfo(input); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
@Override | ||
public void write(MultiEndianOutputStream output) { | ||
output.writeUnsignedInt(magic); | ||
output.writeUnsignedShort(minorVersion); | ||
output.writeUnsignedShort(majorVersion); | ||
output.writeUnsignedShort(constantPoolCount); | ||
|
||
for (var constant : constantPool) { | ||
if (constant != null) { | ||
constant.write(output); | ||
} | ||
} | ||
|
||
output.writeUnsignedShort(accessFlags); | ||
output.writeUnsignedShort(thisClass); | ||
output.writeUnsignedShort(superClass); | ||
output.writeUnsignedShort(interfacesCount); | ||
|
||
for (var i : interfaces) { | ||
output.writeUnsignedShort(i); | ||
} | ||
|
||
output.writeUnsignedShort(fieldsCount); | ||
|
||
for (var field : fields) { | ||
field.write(output); | ||
} | ||
|
||
output.writeUnsignedShort(methodsCount); | ||
|
||
for (var method : methods) { | ||
method.write(output); | ||
} | ||
|
||
output.writeUnsignedShort(attributesCount); | ||
|
||
for (var attribute : attributes) { | ||
if (attribute != null) { | ||
attribute.write(output); | ||
} | ||
} | ||
} | ||
|
||
} |
52 changes: 52 additions & 0 deletions
52
src/main/java/com/github/wdestroier/chamomile/classfile/FieldInfo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.github.wdestroier.chamomile.classfile; | ||
|
||
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructure; | ||
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructureFactory; | ||
import com.github.wdestroier.chamomile.io.MultiEndianInputStream; | ||
import com.github.wdestroier.chamomile.io.MultiEndianOutputStream; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Data | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
public class FieldInfo implements PseudoStructure<FieldInfo> { | ||
|
||
private int accessFlags; | ||
private int nameIndex; | ||
private int descriptorIndex; | ||
private int attributesCount; | ||
private PseudoStructure<?>[] attributes; | ||
|
||
@Override | ||
public FieldInfo read(MultiEndianInputStream input, PseudoStructureFactory pseudoStructureFactory) { | ||
accessFlags = input.readUnsignedShort(); | ||
nameIndex = input.readUnsignedShort(); | ||
descriptorIndex = input.readUnsignedShort(); | ||
attributesCount = input.readUnsignedShort(); | ||
attributes = new PseudoStructure<?>[attributesCount]; | ||
|
||
for (var i = 0; i < attributesCount; i++) { | ||
attributes[i] = pseudoStructureFactory.getAttributeInfo(input); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
@Override | ||
public void write(MultiEndianOutputStream output) { | ||
output.writeUnsignedShort(accessFlags); | ||
output.writeUnsignedShort(nameIndex); | ||
output.writeUnsignedShort(descriptorIndex); | ||
output.writeUnsignedShort(attributesCount); | ||
|
||
for (var attribute : attributes) { | ||
if (attribute != null) { | ||
attribute.write(output); | ||
} | ||
} | ||
} | ||
|
||
} |
52 changes: 52 additions & 0 deletions
52
src/main/java/com/github/wdestroier/chamomile/classfile/MethodInfo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.github.wdestroier.chamomile.classfile; | ||
|
||
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructure; | ||
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructureFactory; | ||
import com.github.wdestroier.chamomile.io.MultiEndianInputStream; | ||
import com.github.wdestroier.chamomile.io.MultiEndianOutputStream; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Data | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
public class MethodInfo implements PseudoStructure<MethodInfo> { | ||
|
||
private int accessFlags; | ||
private int nameIndex; | ||
private int descriptorIndex; | ||
private int attributesCount; | ||
private PseudoStructure<?>[] attributes; | ||
|
||
@Override | ||
public MethodInfo read(MultiEndianInputStream input, PseudoStructureFactory pseudoStructureFactory) { | ||
accessFlags = input.readUnsignedShort(); | ||
nameIndex = input.readUnsignedShort(); | ||
descriptorIndex = input.readUnsignedShort(); | ||
attributesCount = input.readUnsignedShort(); | ||
attributes = new PseudoStructure<?>[attributesCount]; | ||
|
||
for (var i = 0; i < attributesCount; i++) { | ||
attributes[i] = pseudoStructureFactory.getAttributeInfo(input); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
@Override | ||
public void write(MultiEndianOutputStream output) { | ||
output.writeUnsignedShort(accessFlags); | ||
output.writeUnsignedShort(nameIndex); | ||
output.writeUnsignedShort(descriptorIndex); | ||
output.writeUnsignedShort(attributesCount); | ||
|
||
for (var attribute : attributes) { | ||
if (attribute != null) { | ||
attribute.write(output); | ||
} | ||
} | ||
} | ||
|
||
} |
38 changes: 38 additions & 0 deletions
38
...a/com/github/wdestroier/chamomile/classfile/attributeinfo/AnnotationDefaultAttribute.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.github.wdestroier.chamomile.classfile.attributeinfo; | ||
|
||
import com.github.wdestroier.chamomile.classfile.attributeinfo.annotation.ElementValue; | ||
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructure; | ||
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructureFactory; | ||
import com.github.wdestroier.chamomile.io.MultiEndianInputStream; | ||
import com.github.wdestroier.chamomile.io.MultiEndianOutputStream; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Data | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
public class AnnotationDefaultAttribute implements PseudoStructure<AnnotationDefaultAttribute> { | ||
|
||
private int attributeNameIndex; | ||
private long attributeLength; | ||
private ElementValue defaultValue; | ||
|
||
@Override | ||
public AnnotationDefaultAttribute read(MultiEndianInputStream input, PseudoStructureFactory pseudoStructureFactory) { | ||
attributeNameIndex = input.readUnsignedShort(); | ||
attributeLength = input.readUnsignedInt(); | ||
defaultValue = new ElementValue().read(input, pseudoStructureFactory); | ||
|
||
return this; | ||
} | ||
|
||
@Override | ||
public void write(MultiEndianOutputStream output) { | ||
output.writeUnsignedShort(attributeNameIndex); | ||
output.writeUnsignedInt(attributeLength); | ||
defaultValue.write(output); | ||
} | ||
|
||
} |
Oops, something went wrong.