GDB (API)
|
00001 /* Disassemble support for GDB. 00002 00003 Copyright (C) 2000-2013 Free Software Foundation, Inc. 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #include "defs.h" 00021 #include "target.h" 00022 #include "value.h" 00023 #include "ui-out.h" 00024 #include "gdb_string.h" 00025 #include "disasm.h" 00026 #include "gdbcore.h" 00027 #include "dis-asm.h" 00028 00029 /* Disassemble functions. 00030 FIXME: We should get rid of all the duplicate code in gdb that does 00031 the same thing: disassemble_command() and the gdbtk variation. */ 00032 00033 /* This Structure is used to store line number information. 00034 We need a different sort of line table from the normal one cuz we can't 00035 depend upon implicit line-end pc's for lines to do the 00036 reordering in this function. */ 00037 00038 struct dis_line_entry 00039 { 00040 int line; 00041 CORE_ADDR start_pc; 00042 CORE_ADDR end_pc; 00043 }; 00044 00045 /* Like target_read_memory, but slightly different parameters. */ 00046 static int 00047 dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len, 00048 struct disassemble_info *info) 00049 { 00050 return target_read_memory (memaddr, myaddr, len); 00051 } 00052 00053 /* Like memory_error with slightly different parameters. */ 00054 static void 00055 dis_asm_memory_error (int status, bfd_vma memaddr, 00056 struct disassemble_info *info) 00057 { 00058 memory_error (status, memaddr); 00059 } 00060 00061 /* Like print_address with slightly different parameters. */ 00062 static void 00063 dis_asm_print_address (bfd_vma addr, struct disassemble_info *info) 00064 { 00065 struct gdbarch *gdbarch = info->application_data; 00066 00067 print_address (gdbarch, addr, info->stream); 00068 } 00069 00070 static int 00071 compare_lines (const void *mle1p, const void *mle2p) 00072 { 00073 struct dis_line_entry *mle1, *mle2; 00074 int val; 00075 00076 mle1 = (struct dis_line_entry *) mle1p; 00077 mle2 = (struct dis_line_entry *) mle2p; 00078 00079 /* End of sequence markers have a line number of 0 but don't want to 00080 be sorted to the head of the list, instead sort by PC. */ 00081 if (mle1->line == 0 || mle2->line == 0) 00082 { 00083 val = mle1->start_pc - mle2->start_pc; 00084 if (val == 0) 00085 val = mle1->line - mle2->line; 00086 } 00087 else 00088 { 00089 val = mle1->line - mle2->line; 00090 if (val == 0) 00091 val = mle1->start_pc - mle2->start_pc; 00092 } 00093 return val; 00094 } 00095 00096 static int 00097 dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout, 00098 struct disassemble_info * di, 00099 CORE_ADDR low, CORE_ADDR high, 00100 int how_many, int flags, struct ui_file *stb) 00101 { 00102 int num_displayed = 0; 00103 CORE_ADDR pc; 00104 00105 /* parts of the symbolic representation of the address */ 00106 int unmapped; 00107 int offset; 00108 int line; 00109 struct cleanup *ui_out_chain; 00110 00111 for (pc = low; pc < high;) 00112 { 00113 char *filename = NULL; 00114 char *name = NULL; 00115 00116 QUIT; 00117 if (how_many >= 0) 00118 { 00119 if (num_displayed >= how_many) 00120 break; 00121 else 00122 num_displayed++; 00123 } 00124 ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); 00125 00126 if ((flags & DISASSEMBLY_OMIT_PC) == 0) 00127 ui_out_text (uiout, pc_prefix (pc)); 00128 ui_out_field_core_addr (uiout, "address", gdbarch, pc); 00129 00130 if (!build_address_symbolic (gdbarch, pc, 0, &name, &offset, &filename, 00131 &line, &unmapped)) 00132 { 00133 /* We don't care now about line, filename and 00134 unmapped. But we might in the future. */ 00135 ui_out_text (uiout, " <"); 00136 if ((flags & DISASSEMBLY_OMIT_FNAME) == 0) 00137 ui_out_field_string (uiout, "func-name", name); 00138 ui_out_text (uiout, "+"); 00139 ui_out_field_int (uiout, "offset", offset); 00140 ui_out_text (uiout, ">:\t"); 00141 } 00142 else 00143 ui_out_text (uiout, ":\t"); 00144 00145 if (filename != NULL) 00146 xfree (filename); 00147 if (name != NULL) 00148 xfree (name); 00149 00150 ui_file_rewind (stb); 00151 if (flags & DISASSEMBLY_RAW_INSN) 00152 { 00153 CORE_ADDR old_pc = pc; 00154 bfd_byte data; 00155 int status; 00156 const char *spacer = ""; 00157 00158 /* Build the opcodes using a temporary stream so we can 00159 write them out in a single go for the MI. */ 00160 struct ui_file *opcode_stream = mem_fileopen (); 00161 struct cleanup *cleanups = 00162 make_cleanup_ui_file_delete (opcode_stream); 00163 00164 pc += gdbarch_print_insn (gdbarch, pc, di); 00165 for (;old_pc < pc; old_pc++) 00166 { 00167 status = (*di->read_memory_func) (old_pc, &data, 1, di); 00168 if (status != 0) 00169 (*di->memory_error_func) (status, old_pc, di); 00170 fprintf_filtered (opcode_stream, "%s%02x", 00171 spacer, (unsigned) data); 00172 spacer = " "; 00173 } 00174 ui_out_field_stream (uiout, "opcodes", opcode_stream); 00175 ui_out_text (uiout, "\t"); 00176 00177 do_cleanups (cleanups); 00178 } 00179 else 00180 pc += gdbarch_print_insn (gdbarch, pc, di); 00181 ui_out_field_stream (uiout, "inst", stb); 00182 ui_file_rewind (stb); 00183 do_cleanups (ui_out_chain); 00184 ui_out_text (uiout, "\n"); 00185 } 00186 return num_displayed; 00187 } 00188 00189 /* The idea here is to present a source-O-centric view of a 00190 function to the user. This means that things are presented 00191 in source order, with (possibly) out of order assembly 00192 immediately following. */ 00193 00194 static void 00195 do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout, 00196 struct disassemble_info *di, int nlines, 00197 struct linetable_entry *le, 00198 CORE_ADDR low, CORE_ADDR high, 00199 struct symtab *symtab, 00200 int how_many, int flags, struct ui_file *stb) 00201 { 00202 int newlines = 0; 00203 struct dis_line_entry *mle; 00204 struct symtab_and_line sal; 00205 int i; 00206 int out_of_order = 0; 00207 int next_line = 0; 00208 int num_displayed = 0; 00209 enum print_source_lines_flags psl_flags = 0; 00210 struct cleanup *ui_out_chain; 00211 struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0); 00212 struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0); 00213 00214 if (flags & DISASSEMBLY_FILENAME) 00215 psl_flags |= PRINT_SOURCE_LINES_FILENAME; 00216 00217 mle = (struct dis_line_entry *) alloca (nlines 00218 * sizeof (struct dis_line_entry)); 00219 00220 /* Copy linetable entries for this function into our data 00221 structure, creating end_pc's and setting out_of_order as 00222 appropriate. */ 00223 00224 /* First, skip all the preceding functions. */ 00225 00226 for (i = 0; i < nlines - 1 && le[i].pc < low; i++); 00227 00228 /* Now, copy all entries before the end of this function. */ 00229 00230 for (; i < nlines - 1 && le[i].pc < high; i++) 00231 { 00232 if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc) 00233 continue; /* Ignore duplicates. */ 00234 00235 /* Skip any end-of-function markers. */ 00236 if (le[i].line == 0) 00237 continue; 00238 00239 mle[newlines].line = le[i].line; 00240 if (le[i].line > le[i + 1].line) 00241 out_of_order = 1; 00242 mle[newlines].start_pc = le[i].pc; 00243 mle[newlines].end_pc = le[i + 1].pc; 00244 newlines++; 00245 } 00246 00247 /* If we're on the last line, and it's part of the function, 00248 then we need to get the end pc in a special way. */ 00249 00250 if (i == nlines - 1 && le[i].pc < high) 00251 { 00252 mle[newlines].line = le[i].line; 00253 mle[newlines].start_pc = le[i].pc; 00254 sal = find_pc_line (le[i].pc, 0); 00255 mle[newlines].end_pc = sal.end; 00256 newlines++; 00257 } 00258 00259 /* Now, sort mle by line #s (and, then by addresses within 00260 lines). */ 00261 00262 if (out_of_order) 00263 qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines); 00264 00265 /* Now, for each line entry, emit the specified lines (unless 00266 they have been emitted before), followed by the assembly code 00267 for that line. */ 00268 00269 ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns"); 00270 00271 for (i = 0; i < newlines; i++) 00272 { 00273 /* Print out everything from next_line to the current line. */ 00274 if (mle[i].line >= next_line) 00275 { 00276 if (next_line != 0) 00277 { 00278 /* Just one line to print. */ 00279 if (next_line == mle[i].line) 00280 { 00281 ui_out_tuple_chain 00282 = make_cleanup_ui_out_tuple_begin_end (uiout, 00283 "src_and_asm_line"); 00284 print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags); 00285 } 00286 else 00287 { 00288 /* Several source lines w/o asm instructions associated. */ 00289 for (; next_line < mle[i].line; next_line++) 00290 { 00291 struct cleanup *ui_out_list_chain_line; 00292 struct cleanup *ui_out_tuple_chain_line; 00293 00294 ui_out_tuple_chain_line 00295 = make_cleanup_ui_out_tuple_begin_end (uiout, 00296 "src_and_asm_line"); 00297 print_source_lines (symtab, next_line, next_line + 1, 00298 psl_flags); 00299 ui_out_list_chain_line 00300 = make_cleanup_ui_out_list_begin_end (uiout, 00301 "line_asm_insn"); 00302 do_cleanups (ui_out_list_chain_line); 00303 do_cleanups (ui_out_tuple_chain_line); 00304 } 00305 /* Print the last line and leave list open for 00306 asm instructions to be added. */ 00307 ui_out_tuple_chain 00308 = make_cleanup_ui_out_tuple_begin_end (uiout, 00309 "src_and_asm_line"); 00310 print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags); 00311 } 00312 } 00313 else 00314 { 00315 ui_out_tuple_chain 00316 = make_cleanup_ui_out_tuple_begin_end (uiout, 00317 "src_and_asm_line"); 00318 print_source_lines (symtab, mle[i].line, mle[i].line + 1, psl_flags); 00319 } 00320 00321 next_line = mle[i].line + 1; 00322 ui_out_list_chain 00323 = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn"); 00324 } 00325 00326 num_displayed += dump_insns (gdbarch, uiout, di, 00327 mle[i].start_pc, mle[i].end_pc, 00328 how_many, flags, stb); 00329 00330 /* When we've reached the end of the mle array, or we've seen the last 00331 assembly range for this source line, close out the list/tuple. */ 00332 if (i == (newlines - 1) || mle[i + 1].line > mle[i].line) 00333 { 00334 do_cleanups (ui_out_list_chain); 00335 do_cleanups (ui_out_tuple_chain); 00336 ui_out_tuple_chain = make_cleanup (null_cleanup, 0); 00337 ui_out_list_chain = make_cleanup (null_cleanup, 0); 00338 ui_out_text (uiout, "\n"); 00339 } 00340 if (how_many >= 0 && num_displayed >= how_many) 00341 break; 00342 } 00343 do_cleanups (ui_out_chain); 00344 } 00345 00346 00347 static void 00348 do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout, 00349 struct disassemble_info * di, 00350 CORE_ADDR low, CORE_ADDR high, 00351 int how_many, int flags, struct ui_file *stb) 00352 { 00353 int num_displayed = 0; 00354 struct cleanup *ui_out_chain; 00355 00356 ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns"); 00357 00358 num_displayed = dump_insns (gdbarch, uiout, di, low, high, how_many, 00359 flags, stb); 00360 00361 do_cleanups (ui_out_chain); 00362 } 00363 00364 /* Initialize the disassemble info struct ready for the specified 00365 stream. */ 00366 00367 static int ATTRIBUTE_PRINTF (2, 3) 00368 fprintf_disasm (void *stream, const char *format, ...) 00369 { 00370 va_list args; 00371 00372 va_start (args, format); 00373 vfprintf_filtered (stream, format, args); 00374 va_end (args); 00375 /* Something non -ve. */ 00376 return 0; 00377 } 00378 00379 static struct disassemble_info 00380 gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file) 00381 { 00382 struct disassemble_info di; 00383 00384 init_disassemble_info (&di, file, fprintf_disasm); 00385 di.flavour = bfd_target_unknown_flavour; 00386 di.memory_error_func = dis_asm_memory_error; 00387 di.print_address_func = dis_asm_print_address; 00388 /* NOTE: cagney/2003-04-28: The original code, from the old Insight 00389 disassembler had a local optomization here. By default it would 00390 access the executable file, instead of the target memory (there 00391 was a growing list of exceptions though). Unfortunately, the 00392 heuristic was flawed. Commands like "disassemble &variable" 00393 didn't work as they relied on the access going to the target. 00394 Further, it has been supperseeded by trust-read-only-sections 00395 (although that should be superseeded by target_trust..._p()). */ 00396 di.read_memory_func = dis_asm_read_memory; 00397 di.arch = gdbarch_bfd_arch_info (gdbarch)->arch; 00398 di.mach = gdbarch_bfd_arch_info (gdbarch)->mach; 00399 di.endian = gdbarch_byte_order (gdbarch); 00400 di.endian_code = gdbarch_byte_order_for_code (gdbarch); 00401 di.application_data = gdbarch; 00402 disassemble_init_for_target (&di); 00403 return di; 00404 } 00405 00406 void 00407 gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout, 00408 char *file_string, int flags, int how_many, 00409 CORE_ADDR low, CORE_ADDR high) 00410 { 00411 struct ui_file *stb = mem_fileopen (); 00412 struct cleanup *cleanups = make_cleanup_ui_file_delete (stb); 00413 struct disassemble_info di = gdb_disassemble_info (gdbarch, stb); 00414 /* To collect the instruction outputted from opcodes. */ 00415 struct symtab *symtab = NULL; 00416 struct linetable_entry *le = NULL; 00417 int nlines = -1; 00418 00419 /* Assume symtab is valid for whole PC range. */ 00420 symtab = find_pc_symtab (low); 00421 00422 if (symtab != NULL && symtab->linetable != NULL) 00423 { 00424 /* Convert the linetable to a bunch of my_line_entry's. */ 00425 le = symtab->linetable->item; 00426 nlines = symtab->linetable->nitems; 00427 } 00428 00429 if (!(flags & DISASSEMBLY_SOURCE) || nlines <= 0 00430 || symtab == NULL || symtab->linetable == NULL) 00431 do_assembly_only (gdbarch, uiout, &di, low, high, how_many, flags, stb); 00432 00433 else if (flags & DISASSEMBLY_SOURCE) 00434 do_mixed_source_and_assembly (gdbarch, uiout, &di, nlines, le, low, 00435 high, symtab, how_many, flags, stb); 00436 00437 do_cleanups (cleanups); 00438 gdb_flush (gdb_stdout); 00439 } 00440 00441 /* Print the instruction at address MEMADDR in debugged memory, 00442 on STREAM. Returns the length of the instruction, in bytes, 00443 and, if requested, the number of branch delay slot instructions. */ 00444 00445 int 00446 gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr, 00447 struct ui_file *stream, int *branch_delay_insns) 00448 { 00449 struct disassemble_info di; 00450 int length; 00451 00452 di = gdb_disassemble_info (gdbarch, stream); 00453 length = gdbarch_print_insn (gdbarch, memaddr, &di); 00454 if (branch_delay_insns) 00455 { 00456 if (di.insn_info_valid) 00457 *branch_delay_insns = di.branch_delay_insns; 00458 else 00459 *branch_delay_insns = 0; 00460 } 00461 return length; 00462 } 00463 00464 static void 00465 do_ui_file_delete (void *arg) 00466 { 00467 ui_file_delete (arg); 00468 } 00469 00470 /* Return the length in bytes of the instruction at address MEMADDR in 00471 debugged memory. */ 00472 00473 int 00474 gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR addr) 00475 { 00476 static struct ui_file *null_stream = NULL; 00477 00478 /* Dummy file descriptor for the disassembler. */ 00479 if (!null_stream) 00480 { 00481 null_stream = ui_file_new (); 00482 make_final_cleanup (do_ui_file_delete, null_stream); 00483 } 00484 00485 return gdb_print_insn (gdbarch, addr, null_stream, NULL); 00486 } 00487 00488 /* fprintf-function for gdb_buffered_insn_length. This function is a 00489 nop, we don't want to print anything, we just want to compute the 00490 length of the insn. */ 00491 00492 static int ATTRIBUTE_PRINTF (2, 3) 00493 gdb_buffered_insn_length_fprintf (void *stream, const char *format, ...) 00494 { 00495 return 0; 00496 } 00497 00498 /* Initialize a struct disassemble_info for gdb_buffered_insn_length. */ 00499 00500 static void 00501 gdb_buffered_insn_length_init_dis (struct gdbarch *gdbarch, 00502 struct disassemble_info *di, 00503 const gdb_byte *insn, int max_len, 00504 CORE_ADDR addr) 00505 { 00506 init_disassemble_info (di, NULL, gdb_buffered_insn_length_fprintf); 00507 00508 /* init_disassemble_info installs buffer_read_memory, etc. 00509 so we don't need to do that here. 00510 The cast is necessary until disassemble_info is const-ified. */ 00511 di->buffer = (gdb_byte *) insn; 00512 di->buffer_length = max_len; 00513 di->buffer_vma = addr; 00514 00515 di->arch = gdbarch_bfd_arch_info (gdbarch)->arch; 00516 di->mach = gdbarch_bfd_arch_info (gdbarch)->mach; 00517 di->endian = gdbarch_byte_order (gdbarch); 00518 di->endian_code = gdbarch_byte_order_for_code (gdbarch); 00519 00520 disassemble_init_for_target (di); 00521 } 00522 00523 /* Return the length in bytes of INSN. MAX_LEN is the size of the 00524 buffer containing INSN. */ 00525 00526 int 00527 gdb_buffered_insn_length (struct gdbarch *gdbarch, 00528 const gdb_byte *insn, int max_len, CORE_ADDR addr) 00529 { 00530 struct disassemble_info di; 00531 00532 gdb_buffered_insn_length_init_dis (gdbarch, &di, insn, max_len, addr); 00533 00534 return gdbarch_print_insn (gdbarch, addr, &di); 00535 }