enum mi_cmd_result mi_cmd_symbol_list_lines (char *command, char **argv, int argc) { char *filename; struct symtab *s; int i; struct cleanup *cleanup_stack, *cleanup_tuple; if (argc != 1) error (_("mi_cmd_symbol_list_lines: Usage: SOURCE_FILENAME")); filename = argv[0]; s = lookup_symtab (filename); if (s == NULL) error (_("mi_cmd_symbol_list_lines: Unknown source file name.")); /* Now, dump the associated line table. The pc addresses are already sorted by increasing values in the symbol table, so no need to perform any other sorting. */ cleanup_stack = make_cleanup_ui_out_list_begin_end (uiout, "lines"); if (LINETABLE (s) != NULL && LINETABLE (s)->nitems > 0) for (i = 0; i < LINETABLE (s)->nitems; i++) { cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); ui_out_field_core_addr (uiout, "pc", LINETABLE (s)->item[i].pc); ui_out_field_int (uiout, "line", LINETABLE (s)->item[i].line); do_cleanups (cleanup_tuple); } do_cleanups (cleanup_stack); return MI_CMD_DONE; }
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; }
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; }
enum mi_cmd_result mi_cmd_data_read_memory (char *command, char **argv, int argc) { struct cleanup *cleanups = make_cleanup (null_cleanup, NULL); CORE_ADDR addr; long total_bytes; long nr_cols; long nr_rows; char word_format; struct type *word_type; long word_size; char word_asize; char aschar; gdb_byte *mbuf; int nr_bytes; long offset = 0; int optind = 0; char *optarg; enum opt { OFFSET_OPT }; static struct mi_opt opts[] = { {"o", OFFSET_OPT, 1}, 0 }; while (1) { int opt = mi_getopt ("mi_cmd_data_read_memory", argc, argv, opts, &optind, &optarg); if (opt < 0) break; switch ((enum opt) opt) { case OFFSET_OPT: offset = atol (optarg); break; } } argv += optind; argc -= optind; if (argc < 5 || argc > 6) { mi_error_message = xstrprintf ("mi_cmd_data_read_memory: Usage: ADDR WORD-FORMAT WORD-SIZE NR-ROWS NR-COLS [ASCHAR]."); return MI_CMD_ERROR; } /* Extract all the arguments. */ /* Start address of the memory dump. */ addr = parse_and_eval_address (argv[0]) + offset; /* The format character to use when displaying a memory word. See the ``x'' command. */ word_format = argv[1][0]; /* The size of the memory word. */ word_size = atol (argv[2]); switch (word_size) { case 1: word_type = builtin_type_int8; word_asize = 'b'; break; case 2: word_type = builtin_type_int16; word_asize = 'h'; break; case 4: word_type = builtin_type_int32; word_asize = 'w'; break; case 8: word_type = builtin_type_int64; word_asize = 'g'; break; default: word_type = builtin_type_int8; word_asize = 'b'; } /* The number of rows */ nr_rows = atol (argv[3]); if (nr_rows <= 0) { mi_error_message = xstrprintf ("mi_cmd_data_read_memory: invalid number of rows."); return MI_CMD_ERROR; } /* number of bytes per row. */ nr_cols = atol (argv[4]); if (nr_cols <= 0) { mi_error_message = xstrprintf ("mi_cmd_data_read_memory: invalid number of columns."); return MI_CMD_ERROR; } /* The un-printable character when printing ascii. */ if (argc == 6) aschar = *argv[5]; else aschar = 0; /* create a buffer and read it in. */ total_bytes = word_size * nr_rows * nr_cols; mbuf = xcalloc (total_bytes, 1); make_cleanup (xfree, mbuf); nr_bytes = target_read (¤t_target, TARGET_OBJECT_MEMORY, NULL, mbuf, addr, total_bytes); if (nr_bytes <= 0) { do_cleanups (cleanups); mi_error_message = xstrdup ("Unable to read memory."); return MI_CMD_ERROR; } /* output the header information. */ ui_out_field_core_addr (uiout, "addr", addr); ui_out_field_int (uiout, "nr-bytes", nr_bytes); ui_out_field_int (uiout, "total-bytes", total_bytes); ui_out_field_core_addr (uiout, "next-row", addr + word_size * nr_cols); ui_out_field_core_addr (uiout, "prev-row", addr - word_size * nr_cols); ui_out_field_core_addr (uiout, "next-page", addr + total_bytes); ui_out_field_core_addr (uiout, "prev-page", addr - total_bytes); /* Build the result as a two dimentional table. */ { struct ui_stream *stream = ui_out_stream_new (uiout); struct cleanup *cleanup_list_memory; int row; int row_byte; cleanup_list_memory = make_cleanup_ui_out_list_begin_end (uiout, "memory"); for (row = 0, row_byte = 0; row < nr_rows; row++, row_byte += nr_cols * word_size) { int col; int col_byte; struct cleanup *cleanup_tuple; struct cleanup *cleanup_list_data; cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); ui_out_field_core_addr (uiout, "addr", addr + row_byte); /* ui_out_field_core_addr_symbolic (uiout, "saddr", addr + row_byte); */ cleanup_list_data = make_cleanup_ui_out_list_begin_end (uiout, "data"); for (col = 0, col_byte = row_byte; col < nr_cols; col++, col_byte += word_size) { if (col_byte + word_size > nr_bytes) { ui_out_field_string (uiout, NULL, "N/A"); } else { ui_file_rewind (stream->stream); print_scalar_formatted (mbuf + col_byte, word_type, word_format, word_asize, stream->stream); ui_out_field_stream (uiout, NULL, stream); } } do_cleanups (cleanup_list_data); if (aschar) { int byte; ui_file_rewind (stream->stream); for (byte = row_byte; byte < row_byte + word_size * nr_cols; byte++) { if (byte >= nr_bytes) { fputc_unfiltered ('X', stream->stream); } else if (mbuf[byte] < 32 || mbuf[byte] > 126) { fputc_unfiltered (aschar, stream->stream); } else fputc_unfiltered (mbuf[byte], stream->stream); } ui_out_field_stream (uiout, "ascii", stream); } do_cleanups (cleanup_tuple); } ui_out_stream_delete (stream); do_cleanups (cleanup_list_memory); } do_cleanups (cleanups); return MI_CMD_DONE; }
static void darwin_debug_regions_recurse (task_t task) { mach_vm_address_t r_addr; mach_vm_address_t r_start; mach_vm_size_t r_size; natural_t r_depth; mach_msg_type_number_t r_info_size; vm_region_submap_short_info_data_64_t r_info; kern_return_t kret; int ret; struct cleanup *table_chain; struct ui_out *uiout = current_uiout; table_chain = make_cleanup_ui_out_table_begin_end (uiout, 9, -1, "regions"); if (gdbarch_addr_bit (target_gdbarch ()) <= 32) { ui_out_table_header (uiout, 10, ui_left, "start", "Start"); ui_out_table_header (uiout, 10, ui_left, "end", "End"); } else { ui_out_table_header (uiout, 18, ui_left, "start", "Start"); ui_out_table_header (uiout, 18, ui_left, "end", "End"); } ui_out_table_header (uiout, 3, ui_left, "min-prot", "Min"); ui_out_table_header (uiout, 3, ui_left, "max-prot", "Max"); ui_out_table_header (uiout, 5, ui_left, "inheritence", "Inh"); ui_out_table_header (uiout, 9, ui_left, "share-mode", "Shr"); ui_out_table_header (uiout, 1, ui_left, "depth", "D"); ui_out_table_header (uiout, 3, ui_left, "submap", "Sm"); ui_out_table_header (uiout, 0, ui_noalign, "tag", "Tag"); ui_out_table_body (uiout); r_start = 0; r_depth = 0; while (1) { const char *tag; struct cleanup *row_chain; r_info_size = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; r_size = -1; kret = mach_vm_region_recurse (task, &r_start, &r_size, &r_depth, (vm_region_recurse_info_t) &r_info, &r_info_size); if (kret != KERN_SUCCESS) break; row_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "regions-row"); ui_out_field_core_addr (uiout, "start", target_gdbarch (), r_start); ui_out_field_core_addr (uiout, "end", target_gdbarch (), r_start + r_size); ui_out_field_string (uiout, "min-prot", unparse_protection (r_info.protection)); ui_out_field_string (uiout, "max-prot", unparse_protection (r_info.max_protection)); ui_out_field_string (uiout, "inheritence", unparse_inheritance (r_info.inheritance)); ui_out_field_string (uiout, "share-mode", unparse_share_mode (r_info.share_mode)); ui_out_field_int (uiout, "depth", r_depth); ui_out_field_string (uiout, "submap", r_info.is_submap ? _("sm ") : _("obj")); tag = unparse_user_tag (r_info.user_tag); if (tag) ui_out_field_string (uiout, "tag", tag); else ui_out_field_int (uiout, "tag", r_info.user_tag); do_cleanups (row_chain); if (!ui_out_is_mi_like_p (uiout)) ui_out_text (uiout, "\n"); if (r_info.is_submap) r_depth++; else r_start += r_size; } do_cleanups (table_chain); }
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; }