Mercurial > p > unluac > hgcode
changeset 520:a8191c4334b8
Custom typemap can be used
author | tehtmi |
---|---|
date | Fri, 15 Dec 2023 22:45:23 -0800 |
parents | 16ef31a2a27f |
children | 7f2f283699b5 |
files | src/unluac/Configuration.java src/unluac/Main.java src/unluac/assemble/Assembler.java src/unluac/assemble/Directive.java src/unluac/decompile/Disassembler.java src/unluac/decompile/Type.java src/unluac/decompile/TypeMap.java src/unluac/parse/BHeader.java |
diffstat | 8 files changed, 192 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/src/unluac/Configuration.java Fri Dec 15 19:05:25 2023 -0800 +++ b/src/unluac/Configuration.java Fri Dec 15 22:45:23 2023 -0800 @@ -27,6 +27,7 @@ public VariableMode variable; public boolean strict_scope; public boolean luaj; + public String typemap; public String opmap; public String output;
--- a/src/unluac/Main.java Fri Dec 15 19:05:25 2023 -0800 +++ b/src/unluac/Main.java Fri Dec 15 22:45:23 2023 -0800 @@ -54,6 +54,13 @@ } else { error("option \"" + arg + "\" doesn't have an argument", true); } + } else if(arg.equals("--typemap")) { + if(i + 1 < args.length) { + config.typemap = args[i + 1]; + i++; + } else { + error("option \"" + arg + "\" doesn't have an argument", true); + } } else if(arg.equals("--opmap")) { if(i + 1 < args.length) { config.opmap = args[i + 1]; @@ -148,13 +155,14 @@ print_unluac_string(System.out); print_usage(System.out); System.out.println("Available options are:"); - System.out.println(" --assemble assemble given disassembly listing"); - System.out.println(" --disassemble disassemble instead of decompile"); - System.out.println(" --nodebug ignore debugging information in input file"); - System.out.println(" --opmap <file> use opcode mapping specified in <file>"); - System.out.println(" --output <file> output to <file> instead of stdout"); - System.out.println(" --rawstring copy string bytes directly to output"); - System.out.println(" --luaj emulate Luaj's permissive parser"); + System.out.println(" --assemble assemble given disassembly listing"); + System.out.println(" --disassemble disassemble instead of decompile"); + System.out.println(" --nodebug ignore debugging information in input file"); + System.out.println(" --typemap <file> use type mapping specified in <file>"); + System.out.println(" --opmap <file> use opcode mapping specified in <file>"); + System.out.println(" --output <file> output to <file> instead of stdout"); + System.out.println(" --rawstring copy string bytes directly to output"); + System.out.println(" --luaj emulate Luaj's permissive parser"); } private static void print_unluac_string(PrintStream out) {
--- a/src/unluac/assemble/Assembler.java Fri Dec 15 19:05:25 2023 -0800 +++ b/src/unluac/assemble/Assembler.java Fri Dec 15 22:45:23 2023 -0800 @@ -17,6 +17,8 @@ import unluac.decompile.Op; import unluac.decompile.OpcodeMap; import unluac.decompile.OperandFormat; +import unluac.decompile.Type; +import unluac.decompile.TypeMap; import unluac.parse.BHeader; import unluac.parse.BInteger; import unluac.parse.BIntegerType; @@ -480,6 +482,7 @@ public int b_size; public int c_size; + public Map<Integer, Type> usertypemap; public Map<Integer, Op> useropmap; public boolean number_integral; @@ -506,7 +509,7 @@ } public void processHeaderDirective(Assembler a, Directive d) throws AssemblerException, IOException { - if(d != Directive.OP && processed_directives.contains(d)) { + if(!d.repeatable && processed_directives.contains(d)) { throw new AssemblerException("Duplicate " + d.name() + " directive"); } processed_directives.add(d); @@ -568,6 +571,19 @@ case FLOAT_FORMAT: lfloat = new LNumberType(a.getInteger(), false, NumberMode.MODE_FLOAT); break; + case TYPE: { + if(usertypemap == null) { + usertypemap = new HashMap<Integer, Type>(); + } + int typecode = a.getInteger(); + String name = a.getName(); + Type type = Type.get(name); + if(type == null) { + throw new AssemblerException("Unknown type name \"" + name + "\""); + } + usertypemap.put(typecode, type); + break; + } case OP: { if(useropmap == null) { useropmap = new HashMap<Integer, Op>(); @@ -640,10 +656,17 @@ sizeT = integer; } + TypeMap typemap; + if(usertypemap != null) { + typemap = new TypeMap(usertypemap); + } else { + typemap = version.getTypeMap(); + } + LHeader lheader = new LHeader(format, endianness, integer, sizeT, bool, number, linteger, lfloat, string, constant, abslineinfo, local, upvalue, function, extract); - BHeader header = new BHeader(version, lheader); + BHeader header = new BHeader(version, lheader, typemap); LFunction main = convert_function(header, this.main); - header = new BHeader(version, lheader, main); + header = new BHeader(version, lheader, typemap, main); header.write(out); }
--- a/src/unluac/assemble/Directive.java Fri Dec 15 19:05:25 2023 -0800 +++ b/src/unluac/assemble/Directive.java Fri Dec 15 22:45:23 2023 -0800 @@ -28,7 +28,8 @@ NUMBER_FORMAT(".number_format", DirectiveType.HEADER, 2), INTEGER_FORMAT(".integer_format", DirectiveType.HEADER, 1), FLOAT_FORMAT(".float_format", DirectiveType.HEADER, 1), - OP(".op", DirectiveType.HEADER, 2), + TYPE(".type", DirectiveType.HEADER, 2, true), + OP(".op", DirectiveType.HEADER, 2, true), FUNCTION(".function", DirectiveType.NEWFUNCTION, 1), SOURCE(".source", DirectiveType.FUNCTION, 1), LINEDEFINED(".linedefined", DirectiveType.FUNCTION, 1), @@ -44,12 +45,18 @@ UPVALUE(".upvalue", DirectiveType.FUNCTION, 2), ; Directive(String token, DirectiveType type, int argcount) { + this(token, type, argcount, false); + } + + Directive(String token, DirectiveType type, int argcount, boolean repeatable) { this.token = token; this.type = type; + this.repeatable = repeatable; } public final String token; public final DirectiveType type; + public final boolean repeatable; static Map<String, Directive> lookup;
--- a/src/unluac/decompile/Disassembler.java Fri Dec 15 19:05:25 2023 -0800 +++ b/src/unluac/decompile/Disassembler.java Fri Dec 15 22:45:23 2023 -0800 @@ -41,6 +41,17 @@ } out.println(); + if(function.header.typemap != function.header.version.getTypeMap()) { + TypeMap typemap = function.header.typemap; + for(int typecode = 0; typecode < typemap.size(); typecode++) { + Type type = typemap.get(typecode); + if(type != null) { + out.println(Directive.TYPE.token + "\t" + typecode + "\t" + type.name); + } + } + out.println(); + } + if(function.header.opmap != function.header.version.getOpcodeMap()) { OpcodeMap opmap = function.header.opmap; for(int opcode = 0; opcode < opmap.size(); opcode++) {
--- a/src/unluac/decompile/Type.java Fri Dec 15 19:05:25 2023 -0800 +++ b/src/unluac/decompile/Type.java Fri Dec 15 22:45:23 2023 -0800 @@ -1,14 +1,40 @@ package unluac.decompile; +import java.util.HashMap; +import java.util.Map; + public enum Type { - NIL, - BOOLEAN, - FALSE, - TRUE, - NUMBER, - FLOAT, - INTEGER, - STRING, - SHORT_STRING, - LONG_STRING; + NIL("nil"), + BOOLEAN("boolean"), + FALSE("false"), + TRUE("true"), + NUMBER("number"), + FLOAT("float"), + INTEGER("integer"), + STRING("string"), + SHORT_STRING("short_string"), + LONG_STRING("long_string"); + + private static Map<String, Type> lookup = null; + + public final String name; + + private Type(String name) { + this.name = name; + } + + private static void initialize_lookup() { + if(lookup == null) { + lookup = new HashMap<String, Type>(); + for(Type type : values()) { + lookup.put(type.name, type); + } + } + } + + public static Type get(String name) { + initialize_lookup(); + return lookup.get(name); + } + }
--- a/src/unluac/decompile/TypeMap.java Fri Dec 15 19:05:25 2023 -0800 +++ b/src/unluac/decompile/TypeMap.java Fri Dec 15 22:45:23 2023 -0800 @@ -1,5 +1,7 @@ package unluac.decompile; +import java.util.Map; + import unluac.Version; public class TypeMap { @@ -93,6 +95,55 @@ } } + public TypeMap(Map<Integer, Type> usertypemap) { + int maximum = 0; + for(Integer typecode : usertypemap.keySet()) { + maximum = Math.max(maximum, typecode); + } + types = new Type[maximum + 1]; + int user_nil = UNMAPPED; + int user_boolean = UNMAPPED; + int user_false = UNMAPPED; + int user_true = UNMAPPED; + int user_number = UNMAPPED; + int user_float = UNMAPPED; + int user_integer = UNMAPPED; + int user_string = UNMAPPED; + int user_short_string = UNMAPPED; + int user_long_string = UNMAPPED; + for(Map.Entry<Integer, Type> entry : usertypemap.entrySet()) { + int typecode = entry.getKey(); + Type type = entry.getValue(); + types[typecode] = type; + switch(type) { + case NIL: user_nil = typecode; break; + case BOOLEAN: user_boolean = typecode; break; + case FALSE: user_false = typecode; break; + case TRUE: user_true = typecode; break; + case NUMBER: user_number = typecode; break; + case FLOAT: user_float = typecode; break; + case INTEGER: user_integer = typecode; break; + case STRING: user_string = typecode; break; + case SHORT_STRING: user_short_string = typecode; break; + case LONG_STRING: user_long_string = typecode; break; + } + } + NIL = user_nil; + BOOLEAN = user_boolean; + FALSE = user_false; + TRUE = user_true; + NUMBER = user_number; + FLOAT = user_float; + INTEGER = user_integer; + STRING = user_string; + SHORT_STRING = user_short_string; + LONG_STRING = user_long_string; + } + + public int size() { + return types.length; + } + public Type get(int typecode) { if(typecode >= 0 && typecode < types.length) { return types[typecode];
--- a/src/unluac/parse/BHeader.java Fri Dec 15 19:05:25 2023 -0800 +++ b/src/unluac/parse/BHeader.java Fri Dec 15 22:45:23 2023 -0800 @@ -15,6 +15,7 @@ import unluac.decompile.CodeExtract; import unluac.decompile.Op; import unluac.decompile.OpcodeMap; +import unluac.decompile.Type; import unluac.decompile.TypeMap; @@ -48,11 +49,11 @@ public final LFunction main; - public BHeader(Version version, LHeader lheader) { - this(version, lheader, null); + public BHeader(Version version, LHeader lheader, TypeMap typemap) { + this(version, lheader, typemap, null); } - public BHeader(Version version, LHeader lheader, LFunction main) { + public BHeader(Version version, LHeader lheader, TypeMap typemap, LFunction main) { this.config = null; this.version = version; this.lheader = lheader; @@ -70,7 +71,7 @@ upvalue = lheader.upvalue; function = lheader.function; extractor = lheader.extractor; - typemap = version.getTypeMap(); + this.typemap = typemap; opmap = version.getOpcodeMap(); this.main = main; } @@ -109,38 +110,64 @@ function = lheader.function; extractor = lheader.extractor; - typemap = version.getTypeMap(); - - if(config.opmap != null) { - try { + try { + if(config.typemap != null) { + Tokenizer t = new Tokenizer(new FileInputStream(new File(config.typemap))); + String tok; + Map<Integer, Type> usertypemap = new HashMap<Integer, Type>(); + while((tok = t.next()) != null) { + if(tok.equals(".type")) { + tok = t.next(); + if(tok == null) throw new RuntimeException("Unexpected end of typemap file."); + int opcode; + try { + opcode = Integer.parseInt(tok); + } catch(NumberFormatException e) { + throw new RuntimeException("Excepted number in typemap file, got \"" + tok + "\"."); + } + tok = t.next(); + if(tok == null) throw new RuntimeException("Unexpected end of typemap file."); + Type type = Type.get(tok); + if(type == null) throw new RuntimeException("Unknown type name \"" + tok + "\" in typemap file."); + usertypemap.put(opcode, type); + } else { + throw new RuntimeException("Unexpected token \"" + tok + "\" + in typemap file."); + } + } + typemap = new TypeMap(usertypemap); + } else { + typemap = version.getTypeMap(); + } + + if(config.opmap != null) { Tokenizer t = new Tokenizer(new FileInputStream(new File(config.opmap))); String tok; Map<Integer, Op> useropmap = new HashMap<Integer, Op>(); while((tok = t.next()) != null) { if(tok.equals(".op")) { tok = t.next(); - if(tok == null) throw new IllegalStateException("Unexpected end of opmap file."); + if(tok == null) throw new RuntimeException("Unexpected end of opmap file."); int opcode; try { opcode = Integer.parseInt(tok); } catch(NumberFormatException e) { - throw new IllegalStateException("Excepted number in opmap file, got \"" + tok + "\"."); + throw new RuntimeException("Excepted number in opmap file, got \"" + tok + "\"."); } tok = t.next(); - if(tok == null) throw new IllegalStateException("Unexpected end of opmap file."); + if(tok == null) throw new RuntimeException("Unexpected end of opmap file."); Op op = version.getOpcodeMap().get(tok); - if(op == null) throw new IllegalStateException("Unknown op name \"" + tok + "\" in opmap file."); + if(op == null) throw new RuntimeException("Unknown op name \"" + tok + "\" in opmap file."); useropmap.put(opcode, op); } else { - throw new IllegalStateException("Unexpected token \"" + tok + "\" + in opmap file."); + throw new RuntimeException("Unexpected token \"" + tok + "\" + in opmap file."); } } opmap = new OpcodeMap(useropmap); - } catch(IOException e) { - throw new IllegalStateException(e.getMessage()); + } else { + opmap = version.getOpcodeMap(); } - } else { - opmap = version.getOpcodeMap(); + } catch(IOException e) { + throw new RuntimeException(e.getMessage()); } int upvalues = -1;