X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fcode.c;h=d9b35cf90c9c54de2e8c14944ab85231ec324a84;hb=71b5bc980e9f3fa962167da70043f0b16e253906;hp=d5c3acf698a1227b89fc12d3db41f170f2fb51d9;hpb=2b09bad438f6e9725584508726ca00c84eee75ae;p=swftools.git diff --git a/lib/as3/code.c b/lib/as3/code.c index d5c3acf..d9b35cf 100644 --- a/lib/as3/code.c +++ b/lib/as3/code.c @@ -45,6 +45,7 @@ i = u30 index into method info b = byte c = u30 index into class + N = u30 index into namespaces s = string (u30 index into strings) S = switch u = u30 @@ -166,7 +167,7 @@ opcode_t opcodes[]={ {0x2f, "pushdouble", "f", 0, 1, 0, 0}, //index into floats {0x27, "pushfalse", "", 0, 1, 0, 0}, {0x2d, "pushint", "I", 0, 1, 0, 0}, //index into ints -{0x31, "pushnamespace", "u", 0, 1, 0, 0}, //index into namespace TODO +{0x31, "pushnamespace", "N", 0, 1, 0, 0}, //index into namespace {0x28, "pushnan", "", 0, 1, 0, 0}, {0x20, "pushnull", "", 0, 1, 0, 0}, {0x30, "pushscope", "", -1, 0, 1, 0}, @@ -197,29 +198,28 @@ opcode_t opcodes[]={ {0xa7, "urshift", "", -2, 1, 0, 0}, /* opcodes not documented, but seen in the wild */ -//0x53: seen in builtin.abc -{0x53, "applytype", "n", -1, 1, 0, OP_STACK_ARGS}, +{0x53, "applytype", "n", -1, 1, 0, OP_STACK_ARGS}, //seen in builtin.abc /* dummy instructions. Warning: these are not actually supported by flash */ -{0xfd, "__fallthrough__", "s", 0, 0, 0, OP_INTERNAL}, -{0xfe, "__continue__", "s", 0, 0, 0, OP_RETURN|OP_INTERNAL}, +{0xfb, "__pushpackage__", "s", 0, 1, 0, OP_INTERNAL}, +{0xfc, "__rethrow__", "", 0, 0, 0, OP_THROW|OP_INTERNAL}, +{0xfd, "__fallthrough__", "s", 0, 0, 0, OP_INTERNAL}, +{0xfe, "__continue__", "s", 0, 0, 0, OP_RETURN|OP_INTERNAL}, {0xff, "__break__", "s", 0, 0, 0, OP_RETURN|OP_INTERNAL}, }; -static U8 op2index[256] = {254}; +static opcode_t* op2op[256] = {0,0,0}; -opcode_t* opcode_get(U8 op) +static inline opcode_t* opcode_get(U8 op) { int t; - if(op2index[0]==254) { - memset(op2index, 255, sizeof(op2index)); + if(!op2op[0x02]) { + memset(op2op, 0, sizeof(op2op)); for(t=0;tnext = c; + c->prev = code; code = c; } @@ -304,6 +305,8 @@ 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 == 'N') { //namespace + data = namespace_clone(pool_lookup_namespace(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 @@ -427,6 +430,8 @@ void code_free(code_t*c) void*data = c->data[pos]; if(*p == '2') { //multiname multiname_destroy(data); + } else if(*p == 'N') { //namespace + namespace_destroy(data); } else if(strchr("sDf", *p)) { free(data); } else if(strchr("S", *p)) { @@ -471,6 +476,9 @@ static int opcode_write(TAG*tag, code_t*c, pool_t*pool, abc_file_t*file, int len } else if(*p == '2') { //multiname multiname_t*m = (multiname_t*)data; len += swf_SetU30(tag, pool_register_multiname(pool, m)); + } else if(*p == 'N') { //namespace + namespace_t*ns = (namespace_t*)data; + len += swf_SetU30(tag, pool_register_namespace(pool, ns)); } else if(*p == 'm') { //method abc_method_t*m = (abc_method_t*)data; len += swf_SetU30(tag, m->index); @@ -630,6 +638,8 @@ static void dumpstack(currentstats_t*stats) } if(op->params[0]=='2') { printf(" %s", multiname_tostring(c->data[0])); + } else if(op->params[0]=='N') { + printf(" %s", namespace_tostring(c->data[0])); } printf("\n"); } @@ -805,6 +815,8 @@ static currentstats_t* code_get_stats(code_t*code, abc_exception_list_t*exceptio 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_tostring(c->data[0])); + } else if(op->params[0]=='N') { + printf("%5d) %s %s\n", t, op->name, namespace_tostring(c->data[0])); } else { printf("%5d) %s\n", t, op->name); } @@ -845,7 +857,17 @@ void stats_free(currentstats_t*stats) } } -int code_dump(code_t*c, abc_exception_list_t*exceptions, abc_file_t*file, char*prefix, FILE*fo) +int code_dump(code_t*c) +{ + code_t*cc = code_start(c); + while(cc) { + assert(!cc->next || cc->next->prev == cc); + cc = cc->next; + } + + return code_dump2(c, 0, 0, "", stdout); +} +int code_dump2(code_t*c, abc_exception_list_t*exceptions, abc_file_t*file, char*prefix, FILE*fo) { abc_exception_list_t*e = exceptions; c = code_start(c); @@ -903,13 +925,18 @@ int code_dump(code_t*c, abc_exception_list_t*exceptions, abc_file_t*file, char*p char* m = multiname_tostring(n); fprintf(fo, "%s", m); free(m); + } else if(*p == 'N') { + namespace_t*ns = (namespace_t*)data; + char* m = namespace_tostring(ns); + fprintf(fo, "%s", m); + free(m); } else if(*p == 'm') { abc_method_t*m = (abc_method_t*)data; - fprintf(fo, "[method %08x %s]", m, m->name); + fprintf(fo, "[method %08x %s]", m->index, m->name); } else if(*p == 'c') { abc_class_t*cls = (abc_class_t*)data; char*classname = multiname_tostring(cls->classname); - fprintf(fo, "[classinfo %s]", classname); + fprintf(fo, "[classinfo %08x %s]", cls->index, classname); free(classname); } else if(*p == 'i') { abc_method_body_t*b = (abc_method_body_t*)data; @@ -924,8 +951,8 @@ int code_dump(code_t*c, abc_exception_list_t*exceptions, abc_file_t*file, char*p int n = (ptroff_t)data; fprintf(fo, "r%d", n); } else if(*p == 'b') { - int b = (ptroff_t)data; - fprintf(fo, "%02x", b); + int b = (signed char)(ptroff_t)data; + fprintf(fo, "%d", b); } else if(*p == 'j') { if(c->branch) fprintf(fo, "->%d", c->branch->pos); @@ -943,7 +970,7 @@ int code_dump(code_t*c, abc_exception_list_t*exceptions, abc_file_t*file, char*p if(l->def) fprintf(fo, "default->%d", l->def->pos); else - fprintf(fo, "default->00000000", l->def->pos); + fprintf(fo, "default->00000000"); code_list_t*t = l->targets; while(t) { if(t->code) @@ -1006,13 +1033,15 @@ code_t* add_opcode(code_t*atag, U8 op) { code_t*tmp = (code_t*)rfx_calloc(sizeof(code_t)); tmp->opcode = op; - tmp->next = 0; if(atag) { tmp->prev = atag; tmp->next = atag->next; + if(tmp->next) + tmp->next->prev = tmp; atag->next = tmp; } else { tmp->prev = 0; + tmp->next = 0; } return tmp; } @@ -1073,23 +1102,34 @@ code_t*code_dup(code_t*c) { if(!c) return 0; - while(c->prev) c = c->prev; + dict_t*pos2pos = dict_new2(&ptr_type); code_t*last = 0; + c = code_start(c); + code_t*start = 0; + char does_branch = 0; while(c) { NEW(code_t, n); memcpy(n, c, sizeof(code_t)); + if(!start) + start=n; - opcode_t*op = opcode_get(c->opcode); - if(c->branch || c->opcode == OPCODE_LABEL) { - fprintf(stderr, "Error: Can't duplicate branching code\n"); - return 0; + if(c->opcode == OPCODE_LABEL || c->opcode == OPCODE_NOP) { + dict_put(pos2pos, c, n); + } + if(c->branch) { + does_branch = 1; } + + opcode_t*op = opcode_get(c->opcode); + char*p = op?op->params:""; int pos=0; while(*p) { if(*p == '2') { //multiname c->data[pos] = multiname_clone(c->data[pos]); + } else if(*p == 'N') { //multiname + c->data[pos] = namespace_clone(c->data[pos]); } else if(*p == 's') { c->data[pos] = string_dup3(c->data[pos]); } else if(*p == 'D') { @@ -1111,6 +1151,22 @@ code_t*code_dup(code_t*c) last = n; c = c->next; } + + if(does_branch) { + c = start; + while(c) { + if(c->branch) { + code_t*target = dict_lookup(pos2pos, c->branch); + if(!target) { + fprintf(stderr, "Error: Can't find branch target in code_dup\n"); + return 0; + } + c->branch = target; + } + c = c->next; + } + } + dict_destroy(pos2pos); return last; } @@ -1124,7 +1180,7 @@ code_t*code_cut(code_t*c) if(prev) prev->next=next; if(next) next->prev=prev; code_free(c); - + if(next) return code_end(next); else return prev; } @@ -1166,11 +1222,11 @@ code_t* cut_last_push(code_t*c) } else if(c->opcode == OPCODE_CALLSUPER) { c->opcode = OPCODE_CALLSUPERVOID; return c; - } else if(c->opcode == OPCODE_NEWOBJECT || - c->opcode == OPCODE_NEWARRAY) { + } else if((c->opcode == OPCODE_NEWOBJECT || + c->opcode == OPCODE_NEWARRAY) && + !c->data[0]) { // we can discard these if they're not eating up stack parameters - if(!c->data[0]) - return code_cutlast(c); + return code_cutlast(c); } else if(op->stack_minus ==0 && op->stack_plus == 0 && !(op->flags&~(OP_REGISTER|OP_SET_DXNS)) && c->prev) { // trim code *before* the kill, inclocal, declocal, dxns