X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=plugin%2Fsaveasm.cpp;h=bfe7e364c1b68203096ddc35787510baf22f8c47;hb=66bdb2b07a1f50833ad79ea71a378dafd79030e6;hp=f8d2639f8f1408c86ea11eb9d05db1ef2cc9c625;hpb=1402b79d1054d696bc2e8f2e1d02f90eb5d21643;p=ia32rtools.git diff --git a/plugin/saveasm.cpp b/plugin/saveasm.cpp index f8d2639..bfe7e36 100644 --- a/plugin/saveasm.cpp +++ b/plugin/saveasm.cpp @@ -1,3 +1,11 @@ +/* + * ia32rtools + * (C) notaz, 2013,2014 + * + * This work is licensed under the terms of 3-clause BSD license. + * See COPYING file in the top-level directory. + */ + #define NO_OBSOLETE_FUNCS #include #include @@ -8,12 +16,16 @@ #include #include #include +#include #include #include #define IS_START(w, y) !strncmp(w, y, strlen(y)) #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +static char **name_cache; +static size_t name_cache_size; + // non-local branch targets static ea_t *nonlocal_bt; static int nonlocal_bt_alloc; @@ -28,11 +40,21 @@ static int idaapi init(void) //-------------------------------------------------------------------------- static void idaapi term(void) { + size_t i; + if (nonlocal_bt != NULL) { free(nonlocal_bt); nonlocal_bt = NULL; } nonlocal_bt_alloc = 0; + + if (name_cache != NULL) { + for (i = 0; i < name_cache_size; i++) + free(name_cache[i]); + free(name_cache); + name_cache = NULL; + } + name_cache_size = 0; } //-------------------------------------------------------------------------- @@ -43,6 +65,9 @@ static const char *reserved_names[] = { "offset", "aam", "text", + "size", + "c", + "align", }; static int is_name_reserved(const char *name) @@ -81,10 +106,11 @@ static int is_insn_jmp(uint16 itype) return itype == NN_jmp || (NN_ja <= itype && itype <= NN_jz); } -static void do_def_line(char *buf, size_t buf_size, const char *line) +static void do_def_line(char *buf, size_t buf_size, const char *line, + ea_t ea) { - char *endp = NULL; - ea_t ea, *ea_ret; + ea_t *ea_ret; + char *p; int len; tag_remove(line, buf, buf_size); // remove color codes @@ -95,18 +121,91 @@ static void do_def_line(char *buf, size_t buf_size, const char *line) } memmove(buf, buf + 9, len - 9 + 1); // rm address - if (IS_START(buf, "loc_")) { - ea = strtoul(buf + 4, &endp, 16); - if (ea != 0 && *endp == ':') { - ea_ret = (ea_t *)bsearch(&ea, nonlocal_bt, nonlocal_bt_cnt, - sizeof(nonlocal_bt[0]), nonlocal_bt_cmp); - if (ea_ret != 0) { - if (endp[1] != ' ') - msg("no trailing blank in '%s'\n", buf); - else - endp[1] = ':'; - } + p = buf; + while (*p && *p != ' ' && *p != ':') + p++; + if (*p == ':') { + ea_ret = (ea_t *)bsearch(&ea, nonlocal_bt, nonlocal_bt_cnt, + sizeof(nonlocal_bt[0]), nonlocal_bt_cmp); + if (ea_ret != 0) { + if (p[1] != ' ') + msg("no trailing blank in '%s'\n", buf); + else + p[1] = ':'; + } + } +} + +static int name_cache_cmp(const void *p1, const void *p2) +{ + // masm ignores case, so do we + return stricmp(*(char * const *)p1, *(char * const *)p2); +} + +static void rebuild_name_cache(void) +{ + size_t i, newsize; + void *tmp; + + // build a sorted name cache + newsize = get_nlist_size(); + if (newsize > name_cache_size) { + tmp = realloc(name_cache, newsize * sizeof(name_cache[0])); + if (tmp == NULL) { + msg("OOM for name cache\n"); + return; } + name_cache = (char **)tmp; + } + for (i = 0; i < name_cache_size; i++) + free(name_cache[i]); + for (i = 0; i < newsize; i++) + name_cache[i] = strdup(get_nlist_name(i)); + + name_cache_size = newsize; + qsort(name_cache, name_cache_size, sizeof(name_cache[0]), + name_cache_cmp); +} + +static void my_rename(ea_t ea, char *name) +{ + char buf[256]; + char *p, **pp; + int n = 0; + + qsnprintf(buf, sizeof(buf), "%s", name); + do { + p = buf; + pp = (char **)bsearch(&p, name_cache, name_cache_size, + sizeof(name_cache[0]), name_cache_cmp); + if (pp == NULL) + break; + + qsnprintf(buf, sizeof(buf), "%s_g%d", name, n); + n++; + } + while (n < 100); + + if (n == 100) + msg("rename failure? '%s'\n", name); + + do_name_anyway(ea, buf); + rebuild_name_cache(); +} + +static void make_align(ea_t ea) +{ + ea_t tmp_ea; + int n; + + tmp_ea = next_head(ea, inf.maxEA); + if ((tmp_ea & 0x03) == 0) { + n = calc_max_align(tmp_ea); + if (n > 4) // masm doesn't like more.. + n = 4; + msg("%x: align %d\n", ea, 1 << n); + do_unknown(ea, DOUNK_SIMPLE); + doAlign(ea, tmp_ea - ea, n); } } @@ -114,6 +213,7 @@ static void idaapi run(int /*arg*/) { // isEnabled(ea) // address belongs to disassembly // ea_t ea = get_screen_ea(); + // extern foo; // foo = DecodeInstruction(ScreenEA()); FILE *fout = NULL; int fout_line = 0; @@ -129,6 +229,7 @@ static void idaapi run(int /*arg*/) uval_t idx; int i, o, m, n; int ret; + char **pp; char *p; nonlocal_bt_cnt = 0; @@ -146,8 +247,11 @@ static void idaapi run(int /*arg*/) idx = get_first_struc_idx(); } + rebuild_name_cache(); + // 1st pass: walk through all funcs - func = get_func(inf.minEA); + ea = inf.minEA; + func = get_func(ea); while (func != NULL) { func_tail_iterator_t fti(func); @@ -192,13 +296,16 @@ static void idaapi run(int /*arg*/) } } - tmp_ea = get_name_ea(ea, buf); - if (tmp_ea == 0 || tmp_ea == ~0) + p = buf; + pp = (char **)bsearch(&p, name_cache, name_cache_size, + sizeof(name_cache[0]), name_cache_cmp); + if (pp == NULL) continue; - msg("%x: from %x: renaming '%s'\n", tmp_ea, ea, buf); - qstrncat(buf, "_g", sizeof(buf)); - set_name(tmp_ea, buf); + tmp_ea = get_name_ea(BADADDR, *pp); + msg("%x: renaming '%s' because of '%s' at %x\n", + tmp_ea, *pp, buf, ea); + my_rename(tmp_ea, *pp); } } @@ -236,7 +343,10 @@ static void idaapi run(int /*arg*/) if (cmd.Operands[o].type == o_mem) { tmp_ea = cmd.Operands[o].addr; flags_t tmp_ea_flags = get_flags_novalue(tmp_ea); - if (!isUnknown(tmp_ea_flags)) { + // ..but base float is ok.. + int is_flt = isDwrd(tmp_ea_flags) || isFloat(tmp_ea_flags); + if (!is_flt && !isUnknown(tmp_ea_flags)) + { buf[0] = 0; get_name(ea, tmp_ea, buf, sizeof(buf)); msg("%x: undefining %x '%s'\n", ea, tmp_ea, buf); @@ -245,23 +355,43 @@ static void idaapi run(int /*arg*/) } } } - // detect code alignment else if (cmd.itype == NN_lea) { + // detect code alignment if (cmd.Operands[0].reg == cmd.Operands[1].reg && cmd.Operands[1].type == o_displ && cmd.Operands[1].addr == 0) { - tmp_ea = next_head(ea, inf.maxEA); - if ((tmp_ea & 0x03) == 0) { - n = calc_max_align(tmp_ea); - if (n > 4) // masm doesn't like more.. - n = 4; - msg("%x: align %d\n", ea, 1 << n); - do_unknown(ea, DOUNK_SIMPLE); - doAlign(ea, tmp_ea - ea, n); + // lea eax, [eax+0] + make_align(ea); + } + else if (!isDefArg1(ea_flags) + && cmd.Operands[1].type == o_mem // why o_mem? + && cmd.Operands[1].dtyp == dt_dword) + { + if (inf.minEA <= cmd.Operands[1].addr + && cmd.Operands[1].addr < inf.maxEA) + { + // lea to segments, like ds:58D6A8h[edx*8] + msg("%x: lea offset to %x\n", ea, cmd.Operands[1].addr); + op_offset(ea, 1, REF_OFF32); + } + else + { + // ds:0[eax*8] -> [eax*8+0] + msg("%x: dropping ds: for %x\n", ea, cmd.Operands[1].addr); + op_hex(ea, 1); } } } + else if (cmd.itype == NN_mov && cmd.segpref == 0x1e // 2e? + && cmd.Operands[0].type == o_reg + && cmd.Operands[1].type == o_reg + && cmd.Operands[0].dtyp == cmd.Operands[1].dtyp + && cmd.Operands[0].reg == cmd.Operands[1].reg) + { + // db 2Eh; mov eax, eax + make_align(ea); + } // find non-local branches if (is_insn_jmp(cmd.itype) && cmd.Operands[0].type == o_near) @@ -332,10 +462,27 @@ static void idaapi run(int /*arg*/) continue; } - if (is_name_reserved(name)) { + // rename vars with '?@' (funcs are ok) + int change_qat = 0; + ea_flags = get_flags_novalue(ea); + if (!isCode(ea_flags) && strpbrk(name, "?@")) + change_qat = 1; + + if (change_qat || is_name_reserved(name)) { msg("%x: renaming name '%s'\n", ea, name); - qsnprintf(buf, sizeof(buf), "%s_g", name); - set_name(ea, buf); + qsnprintf(buf, sizeof(buf), "%s", name); + + if (change_qat) { + for (p = buf; *p != 0; p++) { + if (*p == '?' || *p == '@') { + qsnprintf(buf2, sizeof(buf2), "%02x", (unsigned char)*p); + memmove(p + 1, p, strlen(p) + 1); + memcpy(p, buf2, 2); + } + } + } + + my_rename(ea, buf); } } @@ -365,7 +512,7 @@ static void idaapi run(int /*arg*/) ln.set_place(&pl); n = ln.get_linecnt(); for (i = 0; i < n - 1; i++) { - do_def_line(buf, sizeof(buf), ln.down()); + do_def_line(buf, sizeof(buf), ln.down(), ea); if (strstr(buf, "include")) continue; @@ -383,15 +530,16 @@ static void idaapi run(int /*arg*/) qstrncpy(p, "include imports.inc", sizeof(buf) - (p - buf)); fout_line++; qfprintf(fout, "\n%s\n", buf); - continue; + i++; + break; } } pl.lnnum = i; for (;;) { - int drop_large = 0, drop_rva = 0, set_scale = 0, jmp_near = 0; - int word_imm = 0, dword_imm = 0, do_pushf = 0; + int drop_large = 0, do_rva = 0, set_scale = 0, jmp_near = 0; + int word_imm = 0, dword_imm = 0, do_pushf = 0, do_nops = 0; if ((ea >> 14) != ui_ea_block) { ui_ea_block = ea >> 14; @@ -449,17 +597,23 @@ static void idaapi run(int /*arg*/) if (get_word(ea + opr.offb) == (ushort)opr.value) word_imm = 1; } + else if (opr.type == o_displ && opr.addr == 0 + && opr.offb != 0 && opr.hasSIB && opr.sib == 0x24) + { + // uses [esp+0] with 0 encoded into op + do_nops++; + } } } else { // not code if (isOff0(ea_flags)) - drop_rva = 1; + do_rva = 1; } pass: n = ln.get_linecnt(); for (i = pl.lnnum; i < n; i++) { - do_def_line(buf, sizeof(buf), ln.down()); + do_def_line(buf, sizeof(buf), ln.down(), ea); char *fw; for (fw = buf; *fw != 0 && *fw == ' '; ) @@ -471,11 +625,12 @@ pass: if (p != NULL) memmove(p, p + 6, strlen(p + 6) + 1); } - while (drop_rva) { + while (do_rva) { p = strstr(fw, " rva "); if (p == NULL) break; - memmove(p, p + 4, strlen(p + 4) + 1); + memmove(p + 4 + 3, p + 4, strlen(p + 4) + 1); + memcpy(p + 1, "offset", 6); } if (set_scale) { p = strchr(fw, '['); @@ -490,7 +645,9 @@ pass: } } else if (jmp_near) { - p = strchr(fw, 'j'); + p = NULL; + if (fw != buf && fw[0] == 'j') + p = fw; while (p && *p != ' ') p++; while (p && *p == ' ') @@ -498,6 +655,7 @@ pass: if (p != NULL) { memmove(p + 9, p, strlen(p) + 1); memcpy(p, "near ptr ", 9); + jmp_near = 0; } } if (word_imm) { @@ -527,7 +685,12 @@ pass: } } - if (fw[0] == 'e' && IS_START(fw, "end") && fw[3] == ' ') { + if (fw[0] == 'a' && IS_START(fw, "assume cs")) { + // "assume cs" causes problems with ext syms + memmove(fw + 1, fw, strlen(fw) + 1); + *fw = ';'; + } + else if (fw[0] == 'e' && IS_START(fw, "end") && fw[3] == ' ') { fout_line++; qfprintf(fout, "include public.inc\n\n"); @@ -539,6 +702,9 @@ pass: qfprintf(fout, "%s\n", buf); } + while (do_nops-- > 0) + qfprintf(fout, " nop ; adj\n"); + // note: next_head skips some undefined stuff ea = next_not_tail(ea); // correct? if (ea == BADADDR)