static void bb_formation_eh_pass (MonoMethodHeader *header, MonoSimpleBasicBlock *bb, MonoSimpleBasicBlock **root, MonoMethod *method, MonoError *error) { int i; int end = header->code_size; /*We must split at all points to verify for targets in the middle of an instruction*/ for (i = 0; i < header->num_clauses; ++i) { MonoExceptionClause *clause = header->clauses + i; MonoSimpleBasicBlock *try_block, *handler; if (!(try_block = bb_split (bb, bb, root, clause->try_offset, TRUE, method, error))) return; handler = bb_split (bb, try_block, root, clause->handler_offset, FALSE, method, error); if (!handler) return; handler->dead = FALSE; if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) { MonoSimpleBasicBlock *filter = bb_split (bb, try_block, root, clause->data.filter_offset, FALSE, method, error); if (!filter) return; filter->dead = FALSE; } if (clause->try_offset + clause->try_len < end && !bb_split (bb, try_block, root, clause->try_offset + clause->try_len, FALSE, method, error)) return; if (clause->handler_offset + clause->handler_len < end && !bb_split (bb, handler, root, clause->handler_offset + clause->handler_len, FALSE, method, error)) return; } }
int convert_tableswitch(struct parse_context *ctx) { struct tableswitch_info info; struct tableswitch *table; struct basic_block *master_bb; struct basic_block *default_bb; struct basic_block *b1; struct basic_block *b2; get_tableswitch_info(ctx->code, ctx->offset, &info); ctx->buffer->pos += info.insn_size; default_bb = find_bb(ctx->cu, ctx->offset + info.default_target); if (!default_bb) goto fail_default_bb; master_bb = ctx->bb; b1 = bb_split(master_bb, master_bb->end); b2 = bb_split(b1, master_bb->end); assert(b1 && b2); master_bb->has_branch = true; b1->has_branch = true; b2->has_branch = true; bb_add_successor(master_bb, default_bb ); bb_add_successor(master_bb, b1); bb_add_successor(b1, default_bb ); bb_add_successor(b1, b2); for (unsigned int i = 0; i < info.count; i++) { struct basic_block *target_bb; int32_t target; target = read_s32(info.targets + i * 4); target_bb = find_bb(ctx->cu, ctx->offset + target); if (!bb_successors_contains(b2, target_bb)) bb_add_successor(b2, target_bb); } table = alloc_tableswitch(&info, ctx->cu, b2, ctx->offset); if (!table) return -ENOMEM; struct statement *if_lesser_stmt; struct statement *if_greater_stmt; struct statement *stmt; struct expression *pure_index; pure_index = get_pure_expr(ctx, stack_pop(ctx->bb->mimic_stack)); if_lesser_stmt = branch_if_lesser_stmt(default_bb, pure_index, info.low); if (!if_lesser_stmt) goto fail_lesser_stmt; expr_get(pure_index); if_greater_stmt = branch_if_greater_stmt(default_bb, pure_index, info.high); if (!if_greater_stmt) goto fail_greater_stmt; stmt = alloc_statement(STMT_TABLESWITCH); if (!stmt) goto fail_stmt; expr_get(pure_index); stmt->index = &pure_index->node; stmt->table = table; do_convert_statement(master_bb, if_lesser_stmt, ctx->offset); do_convert_statement(b1, if_greater_stmt, ctx->offset); do_convert_statement(b2, stmt, ctx->offset); return 0; fail_stmt: free_statement(if_greater_stmt); fail_greater_stmt: free_statement(if_lesser_stmt); fail_lesser_stmt: free_tableswitch(table); fail_default_bb: return -1; }
static void bb_formation_il_pass (const unsigned char *start, const unsigned char *end, MonoSimpleBasicBlock *bb, MonoSimpleBasicBlock **root, MonoMethod *method, MonoError *error) { unsigned const char *ip = start; int value, size; guint cli_addr, offset; MonoSimpleBasicBlock *branch, *next, *current; const MonoOpcode *opcode; current = bb; while (ip < end) { cli_addr = ip - start; size = mono_opcode_value_and_size (&ip, end, &value); if (size < 0) { mono_error_set_not_verifiable (error, method, "Invalid instruction %x", *ip); return; } while (current && cli_addr >= current->end) current = current->next; g_assert (current); opcode = &mono_opcodes [value]; switch (opcode->argument) { case MonoInlineNone: ip++; if (!mono_opcode_has_static_branch (value) || ip >= end) break; if (!(next = bb_split (bb, current, root, ip - start, FALSE, method, error))) return; bb_unlink (current, next); current = next; break; case MonoInlineString: case MonoInlineType: case MonoInlineField: case MonoInlineTok: case MonoInlineSig: case MonoShortInlineR: case MonoInlineI: ip += 5; break; case MonoInlineMethod: ip += 5; if (value != MONO_CEE_JMP || ip >= end) break; if (!(next = bb_split (bb, current, root, ip - start, FALSE, method, error))) return; bb_unlink (current, next); current = next; break; case MonoInlineVar: ip += 3; break; case MonoShortInlineVar: case MonoShortInlineI: ip += 2; break; case MonoInlineR: case MonoInlineI8: ip += 9; break; case MonoShortInlineBrTarget: case MonoInlineBrTarget: if (opcode->argument == MonoShortInlineBrTarget) { offset = cli_addr + 2 + (signed char)ip [1]; ip += 2; } else { offset = cli_addr + 5 + (gint32)read32 (ip + 1); ip += 5; } branch = bb_split (bb, current, root, offset, TRUE, method, error); if (!branch) return; /*If we splitted the current BB*/ if (offset < cli_addr && branch->start > current->start) current = branch; if (ip < end) { next = bb_split (bb, current, root, ip - start, opcode->flow_type != MONO_FLOW_BRANCH, method, error); if (!next) return; } else { next = NULL; } bb_link (current, branch); if (next && opcode->flow_type == MONO_FLOW_BRANCH && next != branch) { bb_unlink (current, next); current = next; } break; case MonoInlineSwitch: { MonoSimpleBasicBlock *tmp; guint32 j, n = read32 (ip + 1); ip += 5; offset = cli_addr + 5 + 4 * n; if (!(next = bb_split (bb, current, root, offset, TRUE, method, error))) return; bb_link (current, next); tmp = next; for (j = 0; j < n; ++j) { if (ip >= end) { mono_error_set_not_verifiable (error, method, "Invalid switch instruction %x", cli_addr); return; } if (!(next = bb_split (bb, next, root, offset + (gint32)read32 (ip), TRUE, method, error))) return; bb_link (current, next); ip += 4; } current = tmp; break; } default: mono_error_set_not_verifiable (error, method, "Invalid instruction %x", *ip); return; } } if (ip != end) mono_error_set_not_verifiable (error, method, "Invalid last instruction"); }
int convert_lookupswitch(struct parse_context *ctx) { struct lookupswitch_info info; struct lookupswitch *table; struct basic_block *master_bb; struct basic_block *default_bb; struct basic_block *b1; get_lookupswitch_info(ctx->code, ctx->offset, &info); ctx->buffer->pos += info.insn_size; default_bb = find_bb(ctx->cu, ctx->offset + info.default_target); if (!default_bb) goto fail_default_bb; master_bb = ctx->bb; b1 = bb_split(master_bb, master_bb->end); assert(b1); b1->has_branch = true; bb_add_successor(master_bb, default_bb ); bb_add_successor(master_bb, b1); for (unsigned int i = 0; i < info.count; i++) { struct basic_block *target_bb; int32_t target; target = read_lookupswitch_target(&info, i); target_bb = find_bb(ctx->cu, ctx->offset + target); if (!bb_successors_contains(b1, target_bb)) bb_add_successor(b1, target_bb); } table = alloc_lookupswitch(&info, ctx->cu, b1, ctx->offset); if (!table) return -ENOMEM; struct statement *if_null_stmt; struct statement *stmt; struct expression *key; struct expression *bsearch; struct expression *pure_bsearch; key = stack_pop(ctx->bb->mimic_stack); bsearch = lookupswitch_bsearch_expr(key, table); if (!bsearch) return -1; pure_bsearch = get_pure_expr(ctx, bsearch); if_null_stmt = branch_if_null_stmt(default_bb, pure_bsearch); if (!if_null_stmt) goto fail_null_stmt; stmt = alloc_statement(STMT_LOOKUPSWITCH_JUMP); if (!stmt) goto fail_stmt; expr_get(pure_bsearch); stmt->lookupswitch_target = &pure_bsearch->node; convert_statement(ctx, if_null_stmt); do_convert_statement(b1, stmt, ctx->offset); return 0; fail_stmt: free_statement(if_null_stmt); fail_null_stmt: free_lookupswitch(table); fail_default_bb: return -1; }