static int dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout, struct disassemble_info * di, CORE_ADDR low, CORE_ADDR high, int how_many, int flags, struct ui_stream *stb) { int num_displayed = 0; CORE_ADDR pc; /* parts of the symbolic representation of the address */ int unmapped; int offset; int line; struct cleanup *ui_out_chain; for (pc = low; pc < high;) { char *filename = NULL; char *name = NULL; QUIT; if (how_many >= 0) { if (num_displayed >= how_many) break; else num_displayed++; } ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); ui_out_text (uiout, pc_prefix (pc)); ui_out_field_core_addr (uiout, "address", gdbarch, pc); if (!build_address_symbolic (gdbarch, pc, 0, &name, &offset, &filename, &line, &unmapped)) { /* We don't care now about line, filename and unmapped. But we might in the future. */ ui_out_text (uiout, " <"); if ((flags & DISASSEMBLY_OMIT_FNAME) == 0) ui_out_field_string (uiout, "func-name", name); ui_out_text (uiout, "+"); ui_out_field_int (uiout, "offset", offset); ui_out_text (uiout, ">:\t"); } else ui_out_text (uiout, ":\t"); if (filename != NULL) xfree (filename); if (name != NULL) xfree (name); ui_file_rewind (stb->stream); if (flags & DISASSEMBLY_RAW_INSN) { CORE_ADDR old_pc = pc; bfd_byte data; int status; const char *spacer = ""; /* Build the opcodes using a temporary stream so we can write them out in a single go for the MI. */ struct ui_stream *opcode_stream = ui_out_stream_new (uiout); struct cleanup *cleanups = make_cleanup_ui_out_stream_delete (opcode_stream); pc += gdbarch_print_insn (gdbarch, pc, di); for (;old_pc < pc; old_pc++) { status = (*di->read_memory_func) (old_pc, &data, 1, di); if (status != 0) (*di->memory_error_func) (status, old_pc, di); fprintf_filtered (opcode_stream->stream, "%s%02x", spacer, (unsigned) data); spacer = " "; } ui_out_field_stream (uiout, "opcodes", opcode_stream); ui_out_text (uiout, "\t"); do_cleanups (cleanups); } else pc += gdbarch_print_insn (gdbarch, pc, di); ui_out_field_stream (uiout, "inst", stb); ui_file_rewind (stb->stream); do_cleanups (ui_out_chain); ui_out_text (uiout, "\n"); } return num_displayed; }
/* * First, disassemble all instructions of the function and store them in buffer * Second, follow and calculate register values at each instruction * Finally, display all disassembled instruction with annotation of object context */ int decode_insns(struct decode_control_block* decode_cb) { unsigned int insn_index, i; int num_insns = 0; struct gdbarch *gdbarch = decode_cb->gdbarch; struct ui_out *uiout = decode_cb->uiout; // Disassemble the whole function even if user chooses // only a subset of it num_insns += dump_insns(decode_cb); // copy known function parameters init_reg_table(decode_cb->param_regs); init_stack_vars(); g_reg_table.cur_regs[RIP]->has_value = 1; // Annotate the context of each instruction for (insn_index = 0; insn_index < g_num_insns; insn_index++) { int cur_insn = 0; struct ca_dis_insn* insn = &g_insns_buffer[insn_index]; // update program counter for RIP-relative instruction // RIP points to the address of the next instruction before executing current one if (insn_index + 1 < g_num_insns) set_reg_value_at_pc(RIP, (insn+1)->pc, insn->pc); // user may set some register values deliberately if (decode_cb->user_regs) { if (insn->pc == decode_cb->low || (insn_index + 1 < g_num_insns && g_insns_buffer[insn_index + 1].pc > decode_cb->low) ) { if (insn->pc == decode_cb->func_start) set_reg_table_at_pc(decode_cb->user_regs, 0); else set_reg_table_at_pc(decode_cb->user_regs, insn->pc); } } // analyze and update register context affected by this instruction if (decode_cb->innermost_frame) { if (insn->pc == decode_cb->current) cur_insn = 1; } else if (insn_index + 1 < g_num_insns && g_insns_buffer[insn_index + 1].pc == decode_cb->current) cur_insn = 1; process_one_insn(insn, cur_insn); if (cur_insn) { // return the register context back to caller for (i = 0; i < TOTAL_REGS; i++) { struct ca_reg_value* reg = g_reg_table.cur_regs[i]; if (reg->has_value) { // only pass on values, symbol may be out of context in another function struct ca_reg_value* dst = &decode_cb->param_regs[i]; memcpy(dst, reg, sizeof(struct ca_reg_value)); dst->sym_name = NULL; } } } } if (decode_cb->verbose) validate_reg_table(); // display disassembled insns for (insn_index = 0; insn_index < g_num_insns; insn_index++) { struct ca_dis_insn* insn = &g_insns_buffer[insn_index]; // parts of the symbolic representation of the address int unmapped; int offset; int line; char *filename = NULL; char *name = NULL; if (insn->pc >= decode_cb->high) break; else if (insn->pc >= decode_cb->low) { // instruction address + offset ui_out_text(uiout, pc_prefix(insn->pc)); ui_out_field_core_addr(uiout, "address", gdbarch, insn->pc); if (!build_address_symbolic(gdbarch, insn->pc, 0, &name, &offset, &filename, &line, &unmapped)) { ui_out_text(uiout, " <"); //if (decode_cb->verbose) // ui_out_field_string(uiout, "func-name", name); ui_out_text(uiout, "+"); ui_out_field_int(uiout, "offset", offset); ui_out_text(uiout, ">:\t"); } else ui_out_message(uiout, 0, "<+%ld>:\t", insn->pc - decode_cb->func_start); // disassembled instruction with annotation print_one_insn(insn, uiout); if (filename != NULL) free(filename); if (name != NULL) free(name); } } reset_reg_table(); reset_stack_vars(); return num_insns; }