int gdb_print_insn (CORE_ADDR memaddr, struct ui_file *stream) { struct ui_stream *stb = ui_out_stream_new (uiout); struct cleanup *cleanups = make_cleanup_ui_out_stream_delete (stb); struct disassemble_info di = gdb_disassemble_info (current_gdbarch, stb->stream); // struct disassemble_info di = gdb_disassemble_info (current_gdbarch, stream); struct disassemble_info * di2 = &di; struct cleanup *ui_out_chain; ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); int i; CORE_ADDR old_pc = memaddr; CORE_ADDR oldmemaddr = memaddr; bfd_byte data; int status; ui_file_rewind (stb->stream); memaddr = TARGET_PRINT_INSN (memaddr, &di); oldmemaddr += memaddr; for (; old_pc < oldmemaddr; old_pc ++) { status = (*di2->read_memory_func) (old_pc, &data, 1, di2); if (status != 0) (*di2->memory_error_func) (status, old_pc, di2); ui_out_message (uiout, 0, " %02x", (unsigned)data); } i = memaddr; for (; i<10; i++) ui_out_text(uiout, " "); ui_out_text (uiout, " "); ui_out_field_stream(uiout, "inst", stb); ui_file_rewind (stb->stream); do_cleanups (ui_out_chain); return memaddr; // return TARGET_PRINT_INSN (memaddr, &di); }
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_field_core_addr (uiout, "address", gdbarch, pc); if (!build_address_symbolic (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, " <"); 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; 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); ui_out_message (uiout, 0, " %02x", (unsigned)data); } ui_out_text (uiout, "\t"); } 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; }
/* * Display a disassembled instruction with annotation */ static void print_one_insn(struct ca_dis_insn* insn, struct ui_out* uiout) { int i, pos; struct ca_operand* dst_op; ui_out_text(uiout, insn->dis_string); pos = strlen(insn->dis_string); if (pos < MAX_SPACING) ui_out_spaces(uiout, MAX_SPACING - pos); ui_out_text(uiout, " ## "); if (insn->num_operand == 0) { ui_out_text(uiout, "\n"); return; } // special case /*if (insn->call) { // reminder that $rax is set to return value after a "call" instruction // if the called function has an integer return value // (unfortunately return type is not known for a function) ui_out_text(uiout, "(%rax=? on return) "); }*/ dst_op = &insn->operands[0]; // annotation of object context if (insn->annotate) { size_t ptr_sz = g_ptr_bit >> 3; int has_value = 0; size_t val = 0xcdcdcdcd; int op_size = insn->op_size; const char* symname = NULL; struct win_type type = {0,0}; int is_vptr = 0; char* name_to_free = NULL; // update register context by "pc" set_current_reg_pointers(insn); // Get the instruction's destination value/symbol/type if (dst_op->type == CA_OP_MEMORY) { // if the destination is a known local variable if (is_stack_address(dst_op)) { address_t addr = get_address(dst_op); struct ca_stack_var* sval = get_stack_var(addr); if (sval) { symname = sval->sym_name; type = sval->type; } else { /*struct symbol* sym; struct object_reference aref; memset(&aref, 0, sizeof(aref)); aref.vaddr = addr; aref.value = 0; aref.target_index = -1; sym = get_stack_sym(&aref, NULL, NULL); if (sym) { symname = SYMBOL_PRINT_NAME (sym); type = SYMBOL_TYPE(sym); }*/ get_stack_sym_and_type(addr, &symname, &type); } } // could it be a known heap object if (!symname && !type.mod_base) { // this function will allocate buffer for the symbol name if any, remember to free it get_op_symbol_type(dst_op, 0, &name_to_free, &type, NULL); symname = name_to_free; } // Since flag insn->annotate is set, dst_op's value should be calculated val = get_op_value(dst_op, op_size); has_value = 1; } else if (dst_op->type == CA_OP_REGISTER) { struct ca_reg_value* dst_reg = get_reg_at_pc(dst_op->reg.index, insn->pc); if (dst_reg) { symname = dst_reg->sym_name; type = dst_reg->type; is_vptr = dst_reg->vptr; if (dst_reg->has_value) { has_value = 1; val = dst_reg->value; } } } else if (dst_op->type == CA_OP_IMMEDIATE) { val = get_op_value(dst_op, op_size); has_value = 1; } if (dst_op->type != CA_OP_IMMEDIATE) { // Name and value (if known) of destination print_one_operand(uiout, dst_op, op_size); if (has_value) ui_out_message(uiout, 0, "="PRINT_FORMAT_POINTER, val); else ui_out_text(uiout, "=?"); } // Symbol or type of destination if (dst_op->type == CA_OP_REGISTER && dst_op->reg.index == RSP) { if (val == g_debug_context.sp) ui_out_text(uiout, " End of function prologue"); ui_out_text(uiout, "\n"); } else { // symbol or type is known if (symname || type.mod_base) { ui_out_text(uiout, "("); if (symname) { ui_out_message(uiout, 0, "symbol=\"%s\"", symname); } if (type.mod_base) { //CHECK_TYPEDEF(type); if (symname) ui_out_text(uiout, " "); ui_out_text(uiout, "type=\""); /*if (is_vptr) { const char * type_name = type_name_no_tag(type); if (type_name) ui_out_message(uiout, 0, "vtable for %s", type_name); else { ui_out_text(uiout, "vtable for "); print_type_name (type); } } else*/ print_type_name (type); ui_out_text(uiout, "\""); } ui_out_text(uiout, ")\n"); } // whatever we can get form the value else { address_t location = 0; int offset = 0; //if (insn->num_operand > 1) //{ // struct ca_operand* src_op = &insn->operands[1]; // get_location(src_op, &location, &offset); //} print_op_value_context (val, op_size > 0 ? op_size : ptr_sz, location, offset, insn->lea); } } if (name_to_free) free (name_to_free); }
/* * 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; }
static int dump_insns (struct ui_out *uiout, struct disassemble_info * di, CORE_ADDR low, CORE_ADDR high, int how_many, 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; struct cleanup *table_chain; struct cleanup *tuple_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_field_core_addr (uiout, "address", pc); if (!build_address_symbolic (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, " <"); ui_out_field_string (uiout, "func-name", name); ui_out_text (uiout, "+"); ui_out_field_int (uiout, "offset", offset); ui_out_text (uiout, ">: "); } else ui_out_text (uiout, ": "); if (filename != NULL) xfree (filename); if (name != NULL) xfree (name); ui_file_rewind (stb->stream); // dump the disassembly raw bytes - ripped from gnu gdb latest cvs version // fG! - 12/08/2009 // save the initial disassembly address CORE_ADDR old_pc = pc; bfd_byte data; int status; int i; // this will return the disassembled instructions, but it will be buffered into the stream // pc will hold the final address after the disassembly, so we can compute the length of the instruction // the macro returns the number of bytes disassembled pc += TARGET_PRINT_INSN (pc, di); i = pc - old_pc; // read the bytes from the initial address to the final address 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); // print the raw bytes ui_out_message (uiout, 0, " %02x", (unsigned)data); } // to align the output... gdb tables don't work correctly :( for (; i < 10 ; i++) ui_out_text(uiout, " "); ui_out_text(uiout, " "); // now we can finally print the buffered stream 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; }