void dump_asm( std::ostream& out, sasm::disas::disas* disas, const sasm::elf::elf& e, const std::string& section_name ) { auto sect = e.sections[section_name]; out << std::endl << "Section " << sect.name << ":" << std::endl; disas->set_addr(sect.vaddr); while (disas->get_addr() < sect.vaddr + sect.size) { dump_addr(out, disas, e); auto ins = disas->next_instr(); ins->dump_asm(out); out << std::endl; delete ins; } }
int main(int argc, char** argv) { /* Parse args. */ sasm::utils::arg_parse ap; ap.add_options() ('f', true, "the file to work on", true) ('d', false, "disassemble the file") ('j', true, "which section to disassemble") ('s', false, "dump the file's symbol table") ; ap.parse(argc, argv); auto ap_res = ap.get_results(); /* Map the file and create the corresponding elf object. */ sasm::utils::mapped_file f(ap.get_results()['f'].arg); f.map(); sasm::elf::elf e(f); /* Create the disassembler with the elf object. */ auto disas = sasm::disas::factory(e); /* Dump asm. */ if (ap_res['d'].matched) { if (ap_res['j'].matched) dump_asm(std::cout, disas, e, ap_res['j'].arg); else for (auto& sect : e.sections) if (sect.flags & SHF_EXECINSTR) dump_asm(std::cout, disas, e, sect.name); } /* Dump symtab. */ if (ap_res['s'].matched) for (auto& sym : e.symtab) std::cout << "0x" << std::hex << sym.addr << std::dec << ": " << sym.name << std::endl; delete disas; }
void pp_op_meta (const bytecode_data_header_t *bytecode_data_p, vm_instr_counter_t oc, op_meta opm, bool rewrite) { bc_to_print_header_p = bytecode_data_p; dump_asm (oc, opm.op); printf (" // "); switch (opm.op.op_idx) { PP_OP (VM_OP_ADDITION, "%s = %s + %s;"); PP_OP (VM_OP_SUBSTRACTION, "%s = %s - %s;"); PP_OP (VM_OP_DIVISION, "%s = %s / %s;"); PP_OP (VM_OP_MULTIPLICATION, "%s = %s * %s;"); PP_OP (VM_OP_REMAINDER, "%s = %s %% %s;"); PP_OP (VM_OP_UNARY_MINUS, "%s = -%s;"); PP_OP (VM_OP_UNARY_PLUS, "%s = +%s;"); PP_OP (VM_OP_B_SHIFT_LEFT, "%s = %s << %s;"); PP_OP (VM_OP_B_SHIFT_RIGHT, "%s = %s >> %s;"); PP_OP (VM_OP_B_SHIFT_URIGHT, "%s = %s >>> %s;"); PP_OP (VM_OP_B_AND, "%s = %s & %s;"); PP_OP (VM_OP_B_OR, "%s = %s | %s;"); PP_OP (VM_OP_B_XOR, "%s = %s ^ %s;"); PP_OP (VM_OP_B_NOT, "%s = ~ %s;"); PP_OP (VM_OP_LOGICAL_NOT, "%s = ! %s;"); PP_OP (VM_OP_EQUAL_VALUE, "%s = %s == %s;"); PP_OP (VM_OP_NOT_EQUAL_VALUE, "%s = %s != %s;"); PP_OP (VM_OP_EQUAL_VALUE_TYPE, "%s = %s === %s;"); PP_OP (VM_OP_NOT_EQUAL_VALUE_TYPE, "%s = %s !== %s;"); PP_OP (VM_OP_LESS_THAN, "%s = %s < %s;"); PP_OP (VM_OP_GREATER_THAN, "%s = %s > %s;"); PP_OP (VM_OP_LESS_OR_EQUAL_THAN, "%s = %s <= %s;"); PP_OP (VM_OP_GREATER_OR_EQUAL_THAN, "%s = %s >= %s;"); PP_OP (VM_OP_INSTANCEOF, "%s = %s instanceof %s;"); PP_OP (VM_OP_IN, "%s = %s in %s;"); PP_OP (VM_OP_POST_INCR, "%s = %s++;"); PP_OP (VM_OP_POST_DECR, "%s = %s--;"); PP_OP (VM_OP_PRE_INCR, "%s = ++%s;"); PP_OP (VM_OP_PRE_DECR, "%s = --%s;"); PP_OP (VM_OP_THROW_VALUE, "throw %s;"); PP_OP (VM_OP_REG_VAR_DECL, "%d tmp regs, %d local variable regs, %d argument variable regs"); PP_OP (VM_OP_VAR_DECL, "var %s;"); PP_OP (VM_OP_RETVAL, "return %s;"); PP_OP (VM_OP_RET, "ret;"); PP_OP (VM_OP_PROP_GETTER, "%s = %s[%s];"); PP_OP (VM_OP_PROP_SETTER, "%s[%s] = %s;"); PP_OP (VM_OP_DELETE_VAR, "%s = delete %s;"); PP_OP (VM_OP_DELETE_PROP, "%s = delete %s.%s;"); PP_OP (VM_OP_TYPEOF, "%s = typeof %s;"); PP_OP (VM_OP_WITH, "with (%s);"); PP_OP (VM_OP_FOR_IN, "for_in (%s);"); case VM_OP_IS_TRUE_JMP_UP: printf ("if (%s) goto %d;", VAR (1), oc - OC (2, 3)); break; case VM_OP_IS_FALSE_JMP_UP: printf ("if (%s == false) goto %d;", VAR (1), oc - OC (2, 3)); break; case VM_OP_IS_TRUE_JMP_DOWN: printf ("if (%s) goto %d;", VAR (1), oc + OC (2, 3)); break; case VM_OP_IS_FALSE_JMP_DOWN: printf ("if (%s == false) goto %d;", VAR (1), oc + OC (2, 3)); break; case VM_OP_JMP_UP: printf ("goto %d;", oc - OC (1, 2)); break; case VM_OP_JMP_DOWN: printf ("goto %d;", oc + OC (1, 2)); break; case VM_OP_JMP_BREAK_CONTINUE: printf ("goto_nested %d;", oc + OC (1, 2)); break; case VM_OP_TRY_BLOCK: printf ("try (end: %d);", oc + OC (1, 2)); break; case VM_OP_ASSIGNMENT: { printf ("%s = ", VAR (1)); switch (opm.op.data.assignment.type_value_right) { case OPCODE_ARG_TYPE_STRING: printf ("'%s': STRING;", VAR (3)); break; case OPCODE_ARG_TYPE_NUMBER: printf ("%s: NUMBER;", VAR (3)); break; case OPCODE_ARG_TYPE_NUMBER_NEGATE: printf ("-%s: NUMBER;", VAR (3)); break; case OPCODE_ARG_TYPE_SMALLINT: printf ("%d: SMALLINT;", opm.op.data.assignment.value_right); break; case OPCODE_ARG_TYPE_SMALLINT_NEGATE: printf ("-%d: SMALLINT;", opm.op.data.assignment.value_right); break; case OPCODE_ARG_TYPE_VARIABLE: printf ("%s : TYPEOF(%s);", VAR (3), VAR (3)); break; case OPCODE_ARG_TYPE_SIMPLE: { switch (opm.op.data.assignment.value_right) { case ECMA_SIMPLE_VALUE_NULL: printf ("null"); break; case ECMA_SIMPLE_VALUE_FALSE: printf ("false"); break; case ECMA_SIMPLE_VALUE_TRUE: printf ("true"); break; case ECMA_SIMPLE_VALUE_UNDEFINED: printf ("undefined"); break; case ECMA_SIMPLE_VALUE_ARRAY_HOLE: printf ("hole"); break; default: JERRY_UNREACHABLE (); } printf (": SIMPLE;"); break; } } break; } case VM_OP_CALL_N: { vargs_num = opm.op.data.call_n.arg_list; seen_vargs = 0; break; } case VM_OP_CONSTRUCT_N: { if (opm.op.data.construct_n.arg_list == 0) { pp_printf ("%s = new %s;", opm.op, opm.lit_id, oc, 1); } else { vargs_num = opm.op.data.construct_n.arg_list; seen_vargs = 0; } break; } case VM_OP_FUNC_DECL_N: { if (opm.op.data.func_decl_n.arg_list == 0) { printf ("function %s ();", VAR (1)); } else { vargs_num = opm.op.data.func_decl_n.arg_list; seen_vargs = 0; } break; } case VM_OP_FUNC_EXPR_REF: { printf ("%s = function ();", VAR (1)); break; } case VM_OP_FUNC_EXPR_N: { if (opm.op.data.func_expr_n.arg_list == 0) { if (opm.op.data.func_expr_n.name_lit_idx == VM_IDX_EMPTY) { printf ("%s = function ();", VAR (1)); } else { pp_printf ("%s = function %s ();", opm.op, opm.lit_id, oc, 1); } } else { vargs_num = opm.op.data.func_expr_n.arg_list; seen_vargs = 0; } break; } case VM_OP_ARRAY_DECL: { if (opm.op.data.array_decl.list_1 == 0 && opm.op.data.array_decl.list_2 == 0) { printf ("%s = [];", VAR (1)); } else { vargs_num = (((int) opm.op.data.array_decl.list_1 << JERRY_BITSINBYTE) + (int) opm.op.data.array_decl.list_2); seen_vargs = 0; } break; } case VM_OP_OBJ_DECL: { if (opm.op.data.obj_decl.list_1 == 0 && opm.op.data.obj_decl.list_2 == 0) { printf ("%s = {};", VAR (1)); } else { vargs_num = (((int) opm.op.data.obj_decl.list_1 << JERRY_BITSINBYTE) + (int) opm.op.data.obj_decl.list_2); seen_vargs = 0; } break; } case VM_OP_META: { switch (opm.op.data.meta.type) { case OPCODE_META_TYPE_UNDEFINED: { printf ("unknown meta;"); break; } case OPCODE_META_TYPE_CALL_SITE_INFO: case OPCODE_META_TYPE_VARG: case OPCODE_META_TYPE_VARG_PROP_DATA: case OPCODE_META_TYPE_VARG_PROP_GETTER: case OPCODE_META_TYPE_VARG_PROP_SETTER: { if (opm.op.data.meta.type != OPCODE_META_TYPE_CALL_SITE_INFO) { seen_vargs++; } if (seen_vargs == vargs_num) { bool found = false; vm_instr_counter_t start = oc; while ((int16_t) start >= 0 && !found) { start--; switch (bc_get_instr (bytecode_data_p, start).op_idx) { case VM_OP_CALL_N: case VM_OP_CONSTRUCT_N: case VM_OP_FUNC_DECL_N: case VM_OP_FUNC_EXPR_N: case VM_OP_ARRAY_DECL: case VM_OP_OBJ_DECL: { found = true; break; } } } vm_instr_t start_op = bc_get_instr (bytecode_data_p, start); switch (start_op.op_idx) { case VM_OP_CALL_N: { pp_printf ("%s = %s (", start_op, NULL, start, 1); break; } case VM_OP_CONSTRUCT_N: { pp_printf ("%s = new %s (", start_op, NULL, start, 1); break; } case VM_OP_FUNC_DECL_N: { pp_printf ("function %s (", start_op, NULL, start, 1); break; } case VM_OP_FUNC_EXPR_N: { if (start_op.data.func_expr_n.name_lit_idx == VM_IDX_EMPTY) { pp_printf ("%s = function (", start_op, NULL, start, 1); } else { pp_printf ("%s = function %s (", start_op, NULL, start, 1); } break; } case VM_OP_ARRAY_DECL: { pp_printf ("%s = [", start_op, NULL, start, 1); break; } case VM_OP_OBJ_DECL: { pp_printf ("%s = {", start_op, NULL, start, 1); break; } default: { JERRY_UNREACHABLE (); } } for (vm_instr_counter_t counter = start; counter <= oc; counter++) { vm_instr_t meta_op = bc_get_instr (bytecode_data_p, counter); switch (meta_op.op_idx) { case VM_OP_META: { switch (meta_op.data.meta.type) { case OPCODE_META_TYPE_CALL_SITE_INFO: { opcode_call_flags_t call_flags = (opcode_call_flags_t) meta_op.data.meta.data_1; if (call_flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG) { pp_printf ("this_arg = %s", meta_op, NULL, counter, 3); } if (call_flags & OPCODE_CALL_FLAGS_DIRECT_CALL_TO_EVAL_FORM) { printf ("['direct call to eval' form]"); } break; } case OPCODE_META_TYPE_VARG: { pp_printf ("%s", meta_op, NULL, counter, 2); break; } case OPCODE_META_TYPE_VARG_PROP_DATA: { pp_printf ("%s:%s", meta_op, NULL, counter, 2); break; } case OPCODE_META_TYPE_VARG_PROP_GETTER: { pp_printf ("%s = get %s ();", meta_op, NULL, counter, 2); break; } case OPCODE_META_TYPE_VARG_PROP_SETTER: { pp_printf ("%s = set (%s);", meta_op, NULL, counter, 2); break; } default: { continue; } } if (counter != oc) { printf (", "); } break; } } } switch (start_op.op_idx) { case VM_OP_ARRAY_DECL: { printf ("];"); break; } case VM_OP_OBJ_DECL: { printf ("};"); break; } default: { printf (");"); } } } break; } case OPCODE_META_TYPE_END_WITH: { printf ("end with;"); break; } case OPCODE_META_TYPE_END_FOR_IN: { printf ("end for-in;"); break; } case OPCODE_META_TYPE_FUNCTION_END: { printf ("function end: %d;", oc + OC (2, 3)); break; } case OPCODE_META_TYPE_CATCH: { printf ("catch end: %d;", oc + OC (2, 3)); break; } case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER: { printf ("catch (%s);", VAR (2)); break; } case OPCODE_META_TYPE_FINALLY: { printf ("finally end: %d;", oc + OC (2, 3)); break; } case OPCODE_META_TYPE_END_TRY_CATCH_FINALLY: { printf ("end try"); break; } default: { JERRY_UNREACHABLE (); } } break; } default: { JERRY_UNREACHABLE (); } } if (rewrite) { printf (" // REWRITE"); } printf ("\n"); }