+static const struct parsed_proto *resolve_icall(int i, int opcnt,
+ int *pp_i, int *multi_src)
+{
+ const struct parsed_proto *pp = NULL;
+ int search_advice = 0;
+ int offset = -1;
+ char name[256];
+ char s_reg[4];
+ int reg, len;
+ int ret;
+
+ *multi_src = 0;
+ *pp_i = -1;
+
+ switch (ops[i].operand[0].type) {
+ case OPT_REGMEM:
+ // try to resolve struct member calls
+ ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
+ s_reg, &offset, &len);
+ if (ret == 2 && len == strlen(ops[i].operand[0].name))
+ {
+ reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
+ if (reg >= 0) {
+ struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
+ int j = -1;
+ ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
+ if (ret != 1)
+ break;
+ if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
+ && ops[j].operand[0].lmod == OPLM_DWORD
+ && ops[j].pp == NULL) // no hint
+ {
+ // allow one simple dereference (directx)
+ reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
+ ops[j].operand[1].name);
+ if (reg < 0)
+ break;
+ struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
+ int k = -1;
+ ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
+ if (ret != 1)
+ break;
+ j = k;
+ }
+ if (ops[j].op != OP_MOV)
+ break;
+ if (ops[j].operand[0].lmod != OPLM_DWORD)
+ break;
+ if (ops[j].pp != NULL) {
+ // type hint in asm
+ pp = ops[j].pp;
+ }
+ else if (ops[j].operand[1].type == OPT_REGMEM) {
+ // allow 'hello[ecx]' - assume array of same type items
+ ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
+ name, s_reg);
+ if (ret != 2)
+ break;
+ pp = proto_parse(g_fhdr, name, g_quiet_pp);
+ }
+ else if (ops[j].operand[1].type == OPT_LABEL)
+ pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
+ else
+ break;
+ if (pp == NULL)
+ break;
+ if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
+ pp = NULL;
+ break;
+ }
+ pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
+ }
+ break;
+ }
+ // fallthrough
+ case OPT_LABEL:
+ case OPT_OFFSET:
+ pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
+ if (!search_advice)
+ break;
+ // fallthrough
+ default:
+ scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
+ pp_i, multi_src);
+ break;
+ }
+
+ return pp;
+}
+