return !nosave;
}
-static void out_toasm_x86(FILE *f, char *sym, struct parsed_proto *pp)
+static void out_toasm_x86(FILE *f, char *sym, const struct parsed_proto *pp)
{
int must_save = 0;
int sarg_ofs = 1; // stack offset to args, in DWORDs
fprintf(f, "\tret\n\n");
}
-static void out_fromasm_x86(FILE *f, char *sym, struct parsed_proto *pp)
+static void out_fromasm_x86(FILE *f, char *sym, const struct parsed_proto *pp)
{
int sarg_ofs = 1; // stack offset to args, in DWORDs
int argc_repush;
int main(int argc, char *argv[])
{
FILE *fout, *fsyms_to, *fsyms_from, *fhdr;
- struct parsed_proto pp;
+ const struct parsed_proto *pp;
char line[256];
char sym[256];
int ret;
if (sym[0] == 0 || sym[0] == ';' || sym[0] == '#')
continue;
- ret = proto_parse(fhdr, sym, &pp);
- if (ret)
+ pp = proto_parse(fhdr, sym);
+ if (pp == NULL)
goto out;
- out_toasm_x86(fout, sym, &pp);
- proto_release(&pp);
+ out_toasm_x86(fout, sym, pp);
}
fprintf(fout, "# from asm\n\n");
if (sym[0] == 0 || sym[0] == ';' || sym[0] == '#')
continue;
- ret = proto_parse(fhdr, sym, &pp);
- if (ret)
+ pp = proto_parse(fhdr, sym);
+ if (pp == NULL)
goto out;
- out_fromasm_x86(fout, sym, &pp);
- proto_release(&pp);
+ out_fromasm_x86(fout, sym, pp);
}
ret = 0;
static const char *hdrfn;
static int hdrfline = 0;
-static int find_protostr(char *dst, size_t dlen, FILE *fhdr,
- const char *fname, const char *sym_)
+static int b_pp_c_handler(char *proto, const char *fname);
+
+static int do_protostrs(FILE *fhdr, const char *fname)
{
- const char *sym = sym_;
const char *finc_name;
+ const char *hdrfn_saved;
+ char protostr[256];
FILE *finc;
- int symlen;
int line = 0;
int ret;
char *p;
- if (sym[0] == '_' && strncmp(fname, "stdc", 4) == 0)
- sym++;
- symlen = strlen(sym);
+ hdrfn_saved = hdrfn;
+ hdrfn = fname;
- rewind(fhdr);
-
- while (fgets(dst, dlen, fhdr))
+ while (fgets(protostr, sizeof(protostr), fhdr))
{
line++;
- if (strncmp(dst, "//#include ", 11) == 0) {
- finc_name = dst + 11;
+ if (strncmp(protostr, "//#include ", 11) == 0) {
+ finc_name = protostr + 11;
p = strpbrk(finc_name, "\r\n ");
if (p != NULL)
*p = 0;
fname, line, finc_name);
continue;
}
- ret = find_protostr(dst, dlen, finc,
- finc_name, sym_);
+ ret = do_protostrs(finc, finc_name);
fclose(finc);
- if (ret == 0)
+ if (ret < 0)
break;
continue;
}
- if (strncmp(sskip(dst), "//", 2) == 0)
+ if (strncmp(sskip(protostr), "//", 2) == 0)
+ continue;
+
+ p = protostr + strlen(protostr);
+ for (p--; p >= protostr && my_isblank(*p); --p)
+ *p = 0;
+ if (p < protostr)
continue;
- p = strstr(dst, sym);
- if (p != NULL && p > dst
- && (my_isblank(p[-1]) || my_issep(p[-1]))
- && (my_isblank(p[symlen]) || my_issep(p[symlen])))
+ hdrfline = line;
+
+ ret = b_pp_c_handler(protostr, hdrfn);
+ if (ret < 0)
break;
}
- hdrfline = line;
- if (feof(fhdr))
- return -1;
+ hdrfn = hdrfn_saved;
- p = dst + strlen(dst);
- for (p--; p > dst && my_isblank(*p); --p)
- *p = 0;
+ if (feof(fhdr))
+ return 0;
- return 0;
+ return -1;
}
static int get_regparm(char *dst, size_t dlen, char *p)
len = strlen(known_type_mod[i]);
if (strncmp(n, known_type_mod[i], len) != 0)
continue;
+ if (!my_isblank(n[len]))
+ continue;
n += len;
while (my_isblank(*n))
hdrfn, hdrfline, (p - protostr) + 1);
return -1;
}
- p = sskip(p + 1);
+ p++;
+ // XXX: skipping extra asterisks, for now
+ while (*p == '*')
+ p++;
+ p = sskip(p);
}
p = next_idt(buf, sizeof(buf), p);
}
if (pp->is_fptr) {
+ if (*p == '[') {
+ // not really ret_type is array, but ohwell
+ pp->ret_type.is_array = 1;
+ p = strchr(p + 1, ']');
+ if (p == NULL) {
+ printf("%s:%d:%zd: ']' expected\n",
+ hdrfn, hdrfline, (p - protostr) + 1);
+ return -1;
+ }
+ p = sskip(p + 1);
+ }
if (*p != ')') {
printf("%s:%d:%zd: ')' expected\n",
hdrfn, hdrfline, (p - protostr) + 1);
return p - protostr;
}
-static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp)
+static int pp_name_cmp(const void *p1, const void *p2)
+{
+ const struct parsed_proto *pp1 = p1, *pp2 = p2;
+ return strcmp(pp1->name, pp2->name);
+}
+
+static struct parsed_proto *pp_cache;
+static int pp_cache_size;
+static int pp_cache_alloc;
+
+static int b_pp_c_handler(char *proto, const char *fname)
+{
+ int ret;
+
+ if (pp_cache_size >= pp_cache_alloc) {
+ pp_cache_alloc = pp_cache_alloc * 2 + 64;
+ pp_cache = realloc(pp_cache, pp_cache_alloc
+ * sizeof(pp_cache[0]));
+ my_assert_not(pp_cache, NULL);
+ memset(pp_cache + pp_cache_size, 0,
+ (pp_cache_alloc - pp_cache_size)
+ * sizeof(pp_cache[0]));
+ }
+
+ ret = parse_protostr(proto, &pp_cache[pp_cache_size]);
+ if (ret < 0)
+ return -1;
+
+ pp_cache_size++;
+ return 0;
+}
+
+static void build_pp_cache(FILE *fhdr)
{
- char protostr[256];
int ret;
- memset(pp, 0, sizeof(*pp));
+ rewind(fhdr);
+
+ ret = do_protostrs(fhdr, hdrfn);
+ if (ret < 0)
+ exit(1);
+
+ qsort(pp_cache, pp_cache_size, sizeof(pp_cache[0]), pp_name_cmp);
+}
+
+static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym)
+{
+ const struct parsed_proto *pp_ret;
+ struct parsed_proto pp_search;
+
+ if (pp_cache == NULL)
+ build_pp_cache(fhdr);
+
+ if (sym[0] == '_') // && strncmp(fname, "stdc", 4) == 0)
+ sym++;
- ret = find_protostr(protostr, sizeof(protostr), fhdr, hdrfn, sym);
- if (ret != 0) {
+ strcpy(pp_search.name, sym);
+ pp_ret = bsearch(&pp_search, pp_cache, pp_cache_size,
+ sizeof(pp_cache[0]), pp_name_cmp);
+ if (pp_ret == NULL)
printf("%s: sym '%s' is missing\n", hdrfn, sym);
- return ret;
+
+ return pp_ret;
+}
+
+struct parsed_proto *proto_clone(const struct parsed_proto *pp_c)
+{
+ struct parsed_proto *pp;
+ int i;
+
+ pp = malloc(sizeof(*pp));
+ my_assert_not(pp, NULL);
+ memcpy(pp, pp_c, sizeof(*pp)); // lazy..
+
+ // do the actual deep copy..
+ for (i = 0; i < pp_c->argc; i++) {
+ if (pp_c->arg[i].reg != NULL) {
+ pp->arg[i].reg = strdup(pp_c->arg[i].reg);
+ my_assert_not(pp->arg[i].reg, NULL);
+ }
+ if (pp_c->arg[i].type.name != NULL) {
+ pp->arg[i].type.name = strdup(pp_c->arg[i].type.name);
+ my_assert_not(pp->arg[i].type.name, NULL);
+ }
+ if (pp_c->arg[i].fptr != NULL) {
+ pp->arg[i].fptr = malloc(sizeof(*pp->arg[i].fptr));
+ my_assert_not(pp->arg[i].fptr, NULL);
+ memcpy(pp->arg[i].fptr, pp_c->arg[i].fptr,
+ sizeof(*pp->arg[i].fptr));
+ }
}
+ if (pp_c->ret_type.name != NULL)
+ pp->ret_type.name = strdup(pp_c->ret_type.name);
- return parse_protostr(protostr, pp) < 0 ? -1 : 0;
+ return pp;
}
-static void proto_release(struct parsed_proto *pp)
+static inline void proto_release(struct parsed_proto *pp)
{
int i;
}
if (pp->ret_type.name != NULL)
free(pp->ret_type.name);
+ free(pp);
}
static int g_eqcnt;
static char g_labels[MAX_OPS][32];
static struct label_ref g_label_refs[MAX_OPS];
-static struct parsed_proto g_func_pp;
+static const struct parsed_proto *g_func_pp;
static struct parsed_data *g_func_pd;
static int g_func_pd_cnt;
static char g_func[256];
{
static const char *dword_types[] = {
"int", "_DWORD", "DWORD", "HANDLE", "HWND", "HMODULE",
+ "WPARAM", "UINT",
};
static const char *word_types[] = {
"uint16_t", "int16_t",
int *regmask, int *regmask_indirect,
char words[16][256], int wordc, int w, unsigned int op_flags)
{
- struct parsed_proto pp;
+ const struct parsed_proto *pp;
enum opr_lenmod tmplmod;
unsigned long number;
int ret, len;
// most likely var in data segment
opr->type = OPT_LABEL;
- ret = proto_parse(g_fhdr, opr->name, &pp);
- if (ret == 0) {
- if (pp.is_fptr) {
+ pp = proto_parse(g_fhdr, opr->name);
+ if (pp != NULL) {
+ if (pp->is_fptr) {
opr->lmod = OPLM_DWORD;
opr->is_ptr = 1;
}
else {
- if (!guess_lmod_from_c_type(&tmplmod, &pp.type))
+ if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
anote("unhandled C type '%s' for '%s'\n",
- pp.type.name, opr->name);
+ pp->type.name, opr->name);
if (opr->lmod == OPLM_UNSPEC)
opr->lmod = tmplmod;
opr->size_lt = 1;
}
}
- opr->is_ptr = pp.type.is_ptr;
- opr->is_array = pp.type.is_array;
+ opr->is_ptr = pp->type.is_ptr;
+ opr->is_array = pp->type.is_array;
}
- proto_release(&pp);
if (opr->lmod == OPLM_UNSPEC)
guess_lmod_from_name(opr);
if (offset > stack_ra)
{
arg_i = (offset - stack_ra - 4) / 4;
- if (arg_i < 0 || arg_i >= g_func_pp.argc_stack)
+ if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
{
- if (g_func_pp.is_vararg && arg_i == g_func_pp.argc_stack && is_lea) {
+ if (g_func_pp->is_vararg
+ && arg_i == g_func_pp->argc_stack && is_lea)
+ {
// should be va_list
if (cast[0] == 0)
cast = "(u32)";
if (ofs_reg[0] != 0)
ferr(po, "offset reg on arg access?\n");
- for (i = arg_s = 0; i < g_func_pp.argc; i++) {
- if (g_func_pp.arg[i].reg != NULL)
+ for (i = arg_s = 0; i < g_func_pp->argc; i++) {
+ if (g_func_pp->arg[i].reg != NULL)
continue;
if (arg_s == arg_i)
break;
arg_s++;
}
- if (i == g_func_pp.argc)
+ if (i == g_func_pp->argc)
ferr(po, "arg %d not in prototype?\n", arg_i);
- popr->is_ptr = g_func_pp.arg[i].type.is_ptr;
+ popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
switch (popr->lmod)
{
}
// common problem
- guess_lmod_from_c_type(&tmp_lmod, &g_func_pp.arg[i].type);
+ guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
if ((offset & 3) && tmp_lmod != OPLM_DWORD)
ferr(po, "bp_arg arg/w offset %d and type '%s'\n",
- offset, g_func_pp.arg[i].type.name);
+ offset, g_func_pp->arg[i].type.name);
}
else
{
struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
struct parsed_opr *last_arith_dst = NULL;
char buf1[256], buf2[256], buf3[256], cast[64];
+ const struct parsed_proto *pp_c;
struct parsed_proto *pp, *pp_tmp;
struct parsed_data *pd;
const char *tmpname;
g_bp_frame = g_sp_frame = g_stack_fsz = 0;
- ret = proto_parse(fhdr, funcn, &g_func_pp);
- if (ret)
+ g_func_pp = proto_parse(fhdr, funcn);
+ if (g_func_pp == NULL)
ferr(ops, "proto_parse failed for '%s'\n", funcn);
- fprintf(fout, "%s ", g_func_pp.ret_type.name);
+ fprintf(fout, "%s ", g_func_pp->ret_type.name);
if (g_ida_func_attr & IDAFA_NORETURN)
fprintf(fout, "noreturn ");
fprintf(fout, "%s(", funcn);
- for (i = 0; i < g_func_pp.argc; i++) {
+ for (i = 0; i < g_func_pp->argc; i++) {
if (i > 0)
fprintf(fout, ", ");
- fprintf(fout, "%s a%d", g_func_pp.arg[i].type.name, i + 1);
+ fprintf(fout, "%s a%d", g_func_pp->arg[i].type.name, i + 1);
}
- if (g_func_pp.is_vararg) {
+ if (g_func_pp->is_vararg) {
if (i > 0)
fprintf(fout, ", ");
fprintf(fout, "...");
pp->arg[arg].type.name = strdup("int");
}
else {
- ret = proto_parse(fhdr, tmpname, pp);
- if (ret)
+ pp_c = proto_parse(fhdr, tmpname);
+ if (pp_c == NULL)
ferr(po, "proto_parse failed for call '%s'\n", tmpname);
+ pp = proto_clone(pp_c);
}
// look for and make use of esp adjust
fprintf(fout, " union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n",
(g_stack_fsz + 3) / 4, (g_stack_fsz + 1) / 2, g_stack_fsz);
- if (g_func_pp.is_vararg)
+ if (g_func_pp->is_vararg)
fprintf(fout, " va_list ap;\n");
// declare arg-registers
- for (i = 0; i < g_func_pp.argc; i++) {
- if (g_func_pp.arg[i].reg != NULL) {
+ for (i = 0; i < g_func_pp->argc; i++) {
+ if (g_func_pp->arg[i].reg != NULL) {
reg = char_array_i(regs_r32,
- ARRAY_SIZE(regs_r32), g_func_pp.arg[i].reg);
+ ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
if (reg < 0)
- ferr(ops, "arg '%s' is not a reg?\n", g_func_pp.arg[i].reg);
+ ferr(ops, "arg '%s' is not a reg?\n", g_func_pp->arg[i].reg);
regmask_arg |= 1 << reg;
fprintf(fout, " u32 %s = (u32)a%d;\n",
- g_func_pp.arg[i].reg, i + 1);
+ g_func_pp->arg[i].reg, i + 1);
had_decl = 1;
}
}
// declare other regs - special case for eax
if (!((regmask | regmask_arg) & 1)
- && !IS(g_func_pp.ret_type.name, "void"))
+ && !IS(g_func_pp->ret_type.name, "void"))
{
fprintf(fout, " u32 eax = 0;\n");
had_decl = 1;
if (had_decl)
fprintf(fout, "\n");
- if (g_func_pp.is_vararg) {
- if (g_func_pp.argc_stack == 0)
+ if (g_func_pp->is_vararg) {
+ if (g_func_pp->argc_stack == 0)
ferr(ops, "vararg func without stack args?\n");
- fprintf(fout, " va_start(ap, a%d);\n", g_func_pp.argc);
+ fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
}
// output ops
else if (!IS(pp->ret_type.name, "void")) {
if (po->flags & OPF_TAIL) {
fprintf(fout, "return ");
- if (g_func_pp.ret_type.is_ptr != pp->ret_type.is_ptr)
- fprintf(fout, "(%s)", g_func_pp.ret_type.name);
+ if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
+ fprintf(fout, "(%s)", g_func_pp->ret_type.name);
}
else {
fprintf(fout, "eax = ");
break;
case OP_RET:
- if (g_func_pp.is_vararg)
+ if (g_func_pp->is_vararg)
fprintf(fout, " va_end(ap);\n");
- if (IS(g_func_pp.ret_type.name, "void")) {
+ if (IS(g_func_pp->ret_type.name, "void")) {
if (i != opcnt - 1 || label_pending)
fprintf(fout, " return;");
}
- else if (g_func_pp.ret_type.is_ptr) {
+ else if (g_func_pp->ret_type.is_ptr) {
fprintf(fout, " return (%s)eax;",
- g_func_pp.ret_type.name);
+ g_func_pp->ret_type.name);
}
else
fprintf(fout, " return eax;");
if (ops[i].op == OP_CALL) {
pp = ops[i].datap;
- if (pp) {
+ if (pp)
proto_release(pp);
- free(pp);
- }
}
}
- proto_release(&g_func_pp);
+ g_func_pp = NULL;
}
static void set_label(int i, const char *name)
WINBASEAPI HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR);
WINBASEAPI HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCWSTR);
WINBASEAPI LPVOID WINAPI CreateFiber(SIZE_T,LPFIBER_START_ROUTINE,LPVOID);
-#if (_WIN32_WINNT >= 0x0400)
WINBASEAPI LPVOID WINAPI CreateFiberEx(SIZE_T,SIZE_T,DWORD,LPFIBER_START_ROUTINE,LPVOID);
-#endif
WINBASEAPI HANDLE WINAPI CreateFileA(LPCSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE);
WINBASEAPI HANDLE WINAPI CreateFileW(LPCWSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE);
WINBASEAPI BOOL WINAPI CreateProcessA(LPCSTR,LPSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,PVOID,LPCSTR,LPSTARTUPINFOA,LPPROCESS_INFORMATION);