X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fcode.c;h=30143f71eddc452f6e1211d84937cfdbcab228cc;hb=526504e079a22cfa2981d86575dd6daf77f74931;hp=02d8975dd55bb817f5bdeb7bfb335e5a8edbee2c;hpb=8648c60b64ea2f83579d2e04b563235d1d7d837b;p=swftools.git diff --git a/lib/as3/code.c b/lib/as3/code.c index 02d8975..30143f7 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" @@ -129,9 +152,7 @@ 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}, @@ -173,6 +194,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}; @@ -248,7 +277,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); @@ -532,7 +561,8 @@ typedef struct { int stackpos; int scopepos; code_t*code; - char seen; + char flags; + char error; } stackpos_t; typedef struct { @@ -573,13 +603,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); @@ -600,10 +633,11 @@ 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); + 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); @@ -614,7 +648,7 @@ static char callcode(currentstats_t*stats, int pos, int stack, int scope) return 1; } - stats->stack[pos].seen = 1; + stats->stack[pos].flags |= FLAG_SEEN; stats->stack[pos].stackpos = stack; stats->stack[pos].scopepos = scope; @@ -626,6 +660,7 @@ 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); /* if we would do true verification (if we would be a vm), this is @@ -647,12 +682,12 @@ static char callcode(currentstats_t*stats, int pos, int stack, int scope) if(op->flags & OP_NEED_ACTIVATION) stats->flags |= FLAGS_ACTIVATION; - if(c->opcode == OP_NEWCLASS) { + if(c->opcode == OPCODE_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) { + if(c->opcode == OPCODE_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; @@ -675,17 +710,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; } @@ -695,6 +735,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; } @@ -705,6 +746,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; } @@ -713,6 +755,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; } @@ -730,7 +773,7 @@ static char callcode(currentstats_t*stats, int pos, int stack, int scope) return 1; } -static currentstats_t* code_get_stats(code_t*code, exception_list_t*exceptions) +static currentstats_t* code_get_stats(code_t*code, abc_exception_list_t*exceptions) { code = code_find_start(code); int num = 0; @@ -779,10 +822,10 @@ static currentstats_t* code_get_stats(code_t*code, exception_list_t*exceptions) free(current); return 0; } - exception_list_t*e = exceptions; + abc_exception_list_t*e = exceptions; while(e) { - if(e->exception->target) - callcode(current, e->exception->target->pos, 1, 0); + if(e->abc_exception->target) + callcode(current, e->abc_exception->target->pos, 1, 0); e = e->next; } @@ -797,9 +840,9 @@ void stats_free(currentstats_t*stats) } } -int code_dump(code_t*c, exception_list_t*exceptions, abc_file_t*file, char*prefix, FILE*fo) +int code_dump(code_t*c, abc_exception_list_t*exceptions, abc_file_t*file, char*prefix, FILE*fo) { - exception_list_t*e = exceptions; + abc_exception_list_t*e = exceptions; c = code_find_start(c); currentstats_t*stats = code_get_stats(c, exceptions); @@ -811,11 +854,11 @@ int code_dump(code_t*c, exception_list_t*exceptions, abc_file_t*file, char*prefi e = exceptions; while(e) { - if(c==e->exception->from) + if(c==e->abc_exception->from) fprintf(fo, "%s TRY {\n", prefix); - if(c==e->exception->target) { - char*s1 = multiname_tostring(e->exception->exc_type); - char*s2 = multiname_tostring(e->exception->var_name); + if(c==e->abc_exception->target) { + char*s1 = multiname_tostring(e->abc_exception->exc_type); + char*s2 = multiname_tostring(e->abc_exception->var_name); fprintf(fo, "%s CATCH(%s %s)\n", prefix, s1, s2); free(s1); free(s2); @@ -832,7 +875,9 @@ int code_dump(code_t*c, exception_list_t*exceptions, abc_file_t*file, char*prefi int i=0; if(stats) { - fprintf(fo, "%s%5d) %c %d:%d %s ", prefix, c->pos, stats->stack[c->pos].seen?'x':'|', + 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); @@ -914,9 +959,9 @@ int code_dump(code_t*c, exception_list_t*exceptions, abc_file_t*file, char*prefi e = exceptions; while(e) { - if(c==e->exception->to) { - if(e->exception->target) - fprintf(fo, "%s } // END TRY (HANDLER: %d)\n", prefix, e->exception->target->pos); + if(c==e->abc_exception->to) { + if(e->abc_exception->target) + fprintf(fo, "%s } // END TRY (HANDLER: %d)\n", prefix, e->abc_exception->target->pos); else fprintf(fo, "%s } // END TRY (HANDLER: 00000000)\n", prefix); } @@ -930,7 +975,7 @@ int code_dump(code_t*c, exception_list_t*exceptions, abc_file_t*file, char*prefi return 1; } -codestats_t* code_get_statistics(code_t*code, exception_list_t*exceptions) +codestats_t* code_get_statistics(code_t*code, abc_exception_list_t*exceptions) { currentstats_t*current = code_get_stats(code, exceptions); if(!current) @@ -972,12 +1017,21 @@ void codestats_print(codestats_t*stats) 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 toappend; + return code_end(toappend); if(!toappend) - return code; + return code_end(code); //find end of first list while(code->next) { code = code->next; @@ -989,6 +1043,6 @@ code_t* code_append(code_t*code, code_t*toappend) } code->next = start; start->prev = code; - return toappend; + return code_end(toappend); }