X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fcode.c;h=205f07e2eef5bd38ad1b00a669280255924f204a;hb=b5e62783e6ff329b365dd4dc830983ab56a1b445;hp=0c97998ccfeaed3235907cc452db2bf00313257f;hpb=b66793aae0b5e65b24c1799083787e635e2b485d;p=swftools.git diff --git a/lib/as3/code.c b/lib/as3/code.c index 0c97998..205f07e 100644 --- a/lib/as3/code.c +++ b/lib/as3/code.c @@ -1,3 +1,26 @@ +/* code.c + + Routines for handling Flash2 AVM2 ABC Actionscript + + Extension module for the rfxswf library. + Part of the swftools package. + + Copyright (c) 2008 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include #include "code.h" #include "pool.h" @@ -20,14 +43,13 @@ n = u30 number of params i = u30 index into method info b = byte - s = short c = u30 index into class s = string (u30 index into strings) S = switch u = u30 r = register */ - + opcode_t opcodes[]={ {0xa0, "add", "", -2, 1, 0, 0}, {0xc5, "add_i", "", -2, 1, 0, 0}, @@ -130,7 +152,9 @@ opcode_t opcodes[]={ {0x57, "newactivation", "", 0, 1, 0, OP_NEED_ACTIVATION}, {0x56, "newarray", "n", 0, 1, 0, OP_STACK_ARGS}, {0x5a, "newcatch", "u", 0, 1, 0, 0}, //u = index into exception_info +#define OP_NEWCLASS 0x58 {0x58, "newclass", "c", -1, 1, 0, 0}, //c = index into class_info +#define OP_NEWFUNCTION 0x40 {0x40, "newfunction", "m", 0, 1, 0, 0}, //i = index into method_info {0x55, "newobject", "n", 0, 1, 0, OP_STACK_ARGS2}, {0x1e, "nextname", "", -2, 1, 0, 0}, @@ -140,17 +164,17 @@ opcode_t opcodes[]={ {0x29, "pop", "", -1, 0, 0, 0}, {0x1d, "popscope", "", 0, 0,-1, 0}, {0x24, "pushbyte", "b", 0, 1, 0, 0}, -{0x2f, "pushdouble", "u", 0, 1, 0, 0}, //index into floats +{0x2f, "pushdouble", "f", 0, 1, 0, 0}, //index into floats {0x27, "pushfalse", "", 0, 1, 0, 0}, -{0x2d, "pushint", "u", 0, 1, 0, 0}, //index into ints -{0x31, "pushnamespace", "u", 0, 1, 0, 0}, //index into namespace +{0x2d, "pushint", "I", 0, 1, 0, 0}, //index into ints +{0x31, "pushnamespace", "u", 0, 1, 0, 0}, //index into namespace TODO {0x28, "pushnan", "", 0, 1, 0, 0}, {0x20, "pushnull", "", 0, 1, 0, 0}, {0x30, "pushscope", "", -1, 0, 1, 0}, {0x25, "pushshort", "u", 0, 1, 0, 0}, {0x2c, "pushstring", "s", 0, 1, 0, 0}, {0x26, "pushtrue", "", 0, 1, 0, 0}, -{0x2e, "pushuint", "u", 0, 1, 0, 0}, //index into uints +{0x2e, "pushuint", "U", 0, 1, 0, 0}, //index into uints {0x21, "pushundefined", "", 0, 1, 0, 0}, {0x1c, "pushwith", "", -1, 0, 1, 0}, {0x48, "returnvalue", "", -1, 0, 0, OP_RETURN}, @@ -163,7 +187,7 @@ opcode_t opcodes[]={ {0xd7, "setlocal_3", "", -1, 0, 0, OP_REGISTER}, {0x6f, "setglobalslot", "u", -1, 0, 0, 0}, {0x61, "setproperty", "2", -2, 0, 0, OP_STACK_NS}, -{0x6d, "setslot", "2", -2, 0, 0, 0}, +{0x6d, "setslot", "u", -2, 0, 0, 0}, {0x05, "setsuper", "2", -2, 0, 0, OP_STACK_NS}, {0xac, "strictequals", "", -2, 1, 0, 0}, {0xa1, "subtract", "", -2, 1, 0, 0}, @@ -172,6 +196,14 @@ opcode_t opcodes[]={ {0x03, "throw", "", -1, 0, 0, OP_THROW}, {0x95, "typeof", "", -1, 1, 0, 0}, {0xa7, "urshift", "", -2, 1, 0, 0}, + +/* opcodes not documented, but seen in the wild */ +//0x53: seen in builtin.abc- followed by 0x01 (might be the number of stack params) +{0x53, "xxx1", "", -1, 0, 0, 0}, +{0x01, "xxx2", "", 0, 0, 0, 0}, + +/* dummy instruction. Warning: this one is not actually supported by flash */ +{0xff, "__break__", "", 0, 0, 0, OP_RETURN}, }; static U8 op2index[256] = {254}; @@ -247,7 +279,7 @@ code_t*code_parse(TAG*tag, int len, abc_file_t*file, pool_t*pool, codelookup_t** opcode_t*op = opcode_get(opcode); if(!op) { fprintf(stderr, "Can't parse opcode %02x\n", opcode); - return head; + continue; } //printf("%s\n", op->name);fflush(stdout); NEW(code_t,c); @@ -272,6 +304,14 @@ code_t*code_parse(TAG*tag, int len, abc_file_t*file, pool_t*pool, codelookup_t** data = (void*)(ptroff_t)swf_GetU30(tag); } else if(*p == '2') { //multiname data = multiname_clone(pool_lookup_multiname(pool, swf_GetU30(tag))); + } else if(*p == 'U') { //uint + data = (void*)(ptroff_t)pool_lookup_uint(pool, swf_GetU30(tag)); + } else if(*p == 'I') { //int + data = (void*)(ptroff_t)pool_lookup_int(pool, swf_GetU30(tag)); + } else if(*p == 'f') { //int + double*fp = malloc(sizeof(double)); + *fp = pool_lookup_float(pool, swf_GetU30(tag)); + data = fp; } else if(*p == 'm') { //method data = array_getvalue(file->methods, swf_GetU30(tag)); } else if(*p == 'c') { //classinfo @@ -376,7 +416,7 @@ void codelookup_free(codelookup_t*codelookup) code_t*code_find_start(code_t*c) { - while(c->prev) + while(c && c->prev) c=c->prev; return c; } @@ -393,7 +433,7 @@ void code_free(code_t*c) void*data = c->data[pos]; if(*p == '2') { //multiname multiname_destroy(data); - } else if(strchr("sD", *p)) { + } else if(strchr("sDf", *p)) { free(data); } else if(strchr("S", *p)) { lookupswitch_t*l = (lookupswitch_t*)data; @@ -415,7 +455,7 @@ static int opcode_write(TAG*tag, code_t*c, pool_t*pool, abc_file_t*file, int len char*p = op->params; int pos = 0; int len = 0; - + if(tag) swf_SetU8(tag, c->opcode); len++; @@ -437,6 +477,12 @@ static int opcode_write(TAG*tag, code_t*c, pool_t*pool, abc_file_t*file, int len } else if(*p == 'i') { //methodbody abc_method_body_t*m = (abc_method_body_t*)data; len += swf_SetU30(tag, m->index); + } else if(*p == 'I') { // int + len += swf_SetU30(tag, pool_register_int(pool, (ptroff_t)data)); + } else if(*p == 'U') { // uint + len += swf_SetU30(tag, pool_register_uint(pool, (ptroff_t)data)); + } else if(*p == 'f') { // float + len += swf_SetU30(tag, pool_register_float(pool, *(double*)data)); } else if(*p == 'u') { // integer len += swf_SetU30(tag, (ptroff_t)data); } else if(*p == 'r') { // integer @@ -517,7 +563,8 @@ typedef struct { int stackpos; int scopepos; code_t*code; - char seen; + char flags; + char error; } stackpos_t; typedef struct { @@ -526,6 +573,7 @@ typedef struct { int maxlocal; int maxstack; int maxscope; + int flags; } currentstats_t; static int stack_minus(code_t*c) @@ -557,13 +605,16 @@ static void handleregister(currentstats_t*stats, int reg) stats->maxlocal = reg+1; } +#define FLAG_SEEN 1 +#define FLAG_ERROR 2 + static void dumpstack(currentstats_t*stats) { int t; for(t=0;tnum;t++) { code_t*c = stats->stack[t].code; opcode_t*op = opcode_get(c->opcode); - printf("%5d) %c %d:%d %s", t, stats->stack[t].seen?'x':'|', + printf("%5d) %c %d:%d %s", t, (stats->stack[t].flags&FLAG_SEEN)?'x':'|', stats->stack[t].stackpos, stats->stack[t].scopepos, op->name); @@ -575,7 +626,7 @@ static void dumpstack(currentstats_t*stats) printf(" 00000000\n"); } if(op->params[0]=='2') { - printf(" %s", multiname_to_string(c->data[0])); + printf(" %s", multiname_tostring(c->data[0])); } printf("\n"); } @@ -584,19 +635,22 @@ static void dumpstack(currentstats_t*stats) static char callcode(currentstats_t*stats, int pos, int stack, int scope) { while(posnum) { - if(stats->stack[pos].seen) { + if(stats->stack[pos].flags&FLAG_SEEN) { if(stats->stack[pos].stackpos != stack || stats->stack[pos].scopepos != scope) { - dumpstack(stats); + //dumpstack(stats); + stats->stack[pos].flags |= FLAG_ERROR; fprintf(stderr, "Stack mismatch at pos %d\n", pos); fprintf(stderr, "Should be: %d:%d, is: %d:%d\n", stack, scope, stats->stack[pos].stackpos, stats->stack[pos].scopepos); - return 0; + + /* return error here if we do verification */ + //return 0; } return 1; } - stats->stack[pos].seen = 1; + stats->stack[pos].flags |= FLAG_SEEN; stats->stack[pos].stackpos = stack; stats->stack[pos].scopepos = scope; @@ -608,9 +662,13 @@ static char callcode(currentstats_t*stats, int pos, int stack, int scope) stack += stack_minus(c); if(stack<0) { + stats->stack[pos].flags |= FLAG_ERROR; fprintf(stderr, "error: stack underflow at %d (%s)\n", pos, op->name); - printf("error: stack underflow at %d (%s)\n", pos, op->name);exit(0); - return 0; + + /* if we would do true verification (if we would be a vm), this is + where we would return the error + return 0; + */ } stack += op->stack_plus; @@ -620,6 +678,22 @@ static char callcode(currentstats_t*stats, int pos, int stack, int scope) stats->maxstack = stack; if(scope > stats->maxscope) stats->maxscope = scope; + + if(op->flags & OP_SET_DXNS) + stats->flags |= FLAGS_SET_DXNS; + if(op->flags & OP_NEED_ACTIVATION) + stats->flags |= FLAGS_ACTIVATION; + + if(c->opcode == OP_NEWCLASS) { + abc_class_t*cls = (abc_class_t*)(c->data[0]); + if(scope > cls->init_scope_depth) + cls->init_scope_depth = scope; + } + if(c->opcode == OP_NEWFUNCTION) { + abc_method_t*m = (abc_method_t*)(c->data[0]); + if(m->body && scope > m->body->init_scope_depth) + m->body->init_scope_depth = scope; + } if(op->flags & OP_REGISTER) { char*p = op->params; @@ -638,17 +712,22 @@ static char callcode(currentstats_t*stats, int pos, int stack, int scope) } if(op->flags&OP_RETURN) { if(OP_RETURN==0x48/*returnvalue*/) { - if(stack!=1) + if(stack!=1) { + stats->stack[pos].flags |= FLAG_ERROR; fprintf(stderr, "return(value) with stackposition %d\n", stack); + } } else if(OP_RETURN==0x47) { - if(stack!=0) + if(stack!=0) { + stats->stack[pos].flags |= FLAG_ERROR; fprintf(stderr, "return(void) with stackposition %d\n", stack); + } } } if(op->flags & (OP_THROW|OP_RETURN)) return 1; if(op->flags & OP_JUMP) { if(!c->branch) { + stats->stack[pos].flags |= FLAG_ERROR; fprintf(stderr, "Error: Invalid jump target in instruction %s at position %d.\n", op->name, pos); return 0; } @@ -658,6 +737,7 @@ static char callcode(currentstats_t*stats, int pos, int stack, int scope) } if(op->flags & OP_BRANCH) { if(!c->branch) { + stats->stack[pos].flags |= FLAG_ERROR; fprintf(stderr, "Error: Invalid jump target in instruction %s at position %d\n", op->name, pos); return 0; } @@ -668,6 +748,7 @@ static char callcode(currentstats_t*stats, int pos, int stack, int scope) if(op->flags & OP_LOOKUPSWITCH) { lookupswitch_t*l = c->data[0]; if(!l->def) { + stats->stack[pos].flags |= FLAG_ERROR; fprintf(stderr, "Error: Invalid jump target in instruction %s at position %d\n", op->name, pos); return 0; } @@ -676,6 +757,7 @@ static char callcode(currentstats_t*stats, int pos, int stack, int scope) code_list_t*t = l->targets; while(t) { if(!t->code) { + stats->stack[pos].flags |= FLAG_ERROR; fprintf(stderr, "Error: Invalid jump target in instruction %s at position %d\n", op->name, pos); return 0; } @@ -708,6 +790,7 @@ static currentstats_t* code_get_stats(code_t*code, exception_list_t*exceptions) current->maxstack = 0; current->maxscope = 0; current->num = num; + current->flags = 0; //#define DEBUG_BYTES #ifdef DEBUG_BYTES @@ -718,7 +801,7 @@ static currentstats_t* code_get_stats(code_t*code, exception_list_t*exceptions) if(op->flags & (OP_JUMP|OP_BRANCH)) { printf("%5d) %s %08x\n", t, op->name, c->branch); } else if(op->params[0]=='2') { - printf("%5d) %s %s\n", t, op->name, multiname_to_string(c->data[0])); + printf("%5d) %s %s\n", t, op->name, multiname_tostring(c->data[0])); } else { printf("%5d) %s\n", t, op->name); } @@ -753,8 +836,10 @@ static currentstats_t* code_get_stats(code_t*code, exception_list_t*exceptions) void stats_free(currentstats_t*stats) { - free(stats->stack);stats->stack=0; - free(stats); + if(stats) { + free(stats->stack);stats->stack=0; + free(stats); + } } int code_dump(code_t*c, exception_list_t*exceptions, abc_file_t*file, char*prefix, FILE*fo) @@ -774,8 +859,8 @@ int code_dump(code_t*c, exception_list_t*exceptions, abc_file_t*file, char*prefi if(c==e->exception->from) fprintf(fo, "%s TRY {\n", prefix); if(c==e->exception->target) { - char*s1 = multiname_to_string(e->exception->exc_type); - char*s2 = multiname_to_string(e->exception->var_name); + char*s1 = multiname_tostring(e->exception->exc_type); + char*s2 = multiname_tostring(e->exception->var_name); fprintf(fo, "%s CATCH(%s %s)\n", prefix, s1, s2); free(s1); free(s2); @@ -791,10 +876,16 @@ int code_dump(code_t*c, exception_list_t*exceptions, abc_file_t*file, char*prefi char first = 1; int i=0; - fprintf(fo, "%s%5d) %c %d:%d %s ", prefix, c->pos, stats->stack[c->pos].seen?'x':'|', - stats->stack[c->pos].stackpos, - stats->stack[c->pos].scopepos, - op->name); + if(stats) { + int f = stats->stack[c->pos].flags; + fprintf(fo, "%s%5d) %c %d:%d %s ", prefix, c->pos, + (f&FLAG_ERROR)?'E':((f&FLAG_SEEN)?'+':'|'), + stats->stack[c->pos].stackpos, + stats->stack[c->pos].scopepos, + op->name); + } else { + fprintf(fo, "%s%5d) ? ?:? %s ", prefix, c->pos, op->name); + } while(*p) { void*data = c->data[i]; @@ -806,7 +897,7 @@ int code_dump(code_t*c, exception_list_t*exceptions, abc_file_t*file, char*prefi fprintf(fo, "%d params", n); } else if(*p == '2') { multiname_t*n = (multiname_t*)data; - char* m = multiname_to_string(n); + char* m = multiname_tostring(n); fprintf(fo, "%s", m); free(m); } else if(*p == 'm') { @@ -814,15 +905,18 @@ int code_dump(code_t*c, exception_list_t*exceptions, abc_file_t*file, char*prefi fprintf(fo, "[method %s]", m->name); } else if(*p == 'c') { abc_class_t*cls = (abc_class_t*)data; - char*classname = multiname_to_string(cls->classname); + char*classname = multiname_tostring(cls->classname); fprintf(fo, "[classinfo %s]", classname); free(classname); } else if(*p == 'i') { abc_method_body_t*b = (abc_method_body_t*)data; fprintf(fo, "[methodbody]"); - } else if(*p == 'u') { + } else if(*p == 'u' || *p == 'I' || *p == 'U') { int n = (ptroff_t)data; fprintf(fo, "%d", n); + } else if(*p == 'f') { + double f = *(double*)data; + fprintf(fo, "%f", f); } else if(*p == 'r') { int n = (ptroff_t)data; fprintf(fo, "r%d", n); @@ -888,11 +982,11 @@ codestats_t* code_get_statistics(code_t*code, exception_list_t*exceptions) currentstats_t*current = code_get_stats(code, exceptions); if(!current) return 0; - codestats_t*stats = malloc(sizeof(codestats_t)); + codestats_t*stats = rfx_calloc(sizeof(codestats_t)); stats->local_count = current->maxlocal; stats->max_stack = current->maxstack; - stats->init_scope_depth = 0; stats->max_scope_depth = current->maxscope; + stats->flags = current->flags; stats_free(current);current=0; return stats; @@ -910,6 +1004,7 @@ code_t* add_opcode(code_t*atag, U8 op) tmp->next = 0; if(atag) { tmp->prev = atag; + tmp->next = atag->next; atag->next = tmp; } else { tmp->prev = 0; @@ -921,7 +1016,35 @@ void codestats_print(codestats_t*stats) { printf("max_stack: %d\n", stats->max_stack); printf("local_count: %d\n", stats->local_count); - printf("init_scope_depth: %d\n", stats->init_scope_depth); - printf("max_scope_depth: %d\n", stats->max_scope_depth); + printf("scope_depth: %d\n", stats->max_scope_depth); +} + +code_t* code_end(code_t*code) +{ + if(!code) + return 0; + while(code->next) + code = code->next; + return code; +} + +code_t* code_append(code_t*code, code_t*toappend) +{ + if(!code) + return code_end(toappend); + if(!toappend) + return code_end(code); + //find end of first list + while(code->next) { + code = code->next; + } + code_t*start=toappend; + //and start of second list + while(start->prev) { + start = start->prev; + } + code->next = start; + start->prev = code; + return code_end(toappend); }