GDB (API)
|
00001 /* Disassembly display. 00002 00003 Copyright (C) 1998-2013 Free Software Foundation, Inc. 00004 00005 Contributed by Hewlett-Packard Company. 00006 00007 This file is part of GDB. 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 3 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00021 00022 #include "defs.h" 00023 #include "arch-utils.h" 00024 #include "symtab.h" 00025 #include "breakpoint.h" 00026 #include "frame.h" 00027 #include "value.h" 00028 #include "source.h" 00029 #include "disasm.h" 00030 #include "gdb_string.h" 00031 #include "tui/tui.h" 00032 #include "tui/tui-data.h" 00033 #include "tui/tui-win.h" 00034 #include "tui/tui-layout.h" 00035 #include "tui/tui-winsource.h" 00036 #include "tui/tui-stack.h" 00037 #include "tui/tui-file.h" 00038 #include "tui/tui-disasm.h" 00039 #include "progspace.h" 00040 00041 #include "gdb_curses.h" 00042 00043 struct tui_asm_line 00044 { 00045 CORE_ADDR addr; 00046 char *addr_string; 00047 char *insn; 00048 }; 00049 00050 /* Function to set the disassembly window's content. 00051 Disassemble count lines starting at pc. 00052 Return address of the count'th instruction after pc. */ 00053 static CORE_ADDR 00054 tui_disassemble (struct gdbarch *gdbarch, struct tui_asm_line *asm_lines, 00055 CORE_ADDR pc, int count) 00056 { 00057 struct ui_file *gdb_dis_out; 00058 00059 /* Now init the ui_file structure. */ 00060 gdb_dis_out = tui_sfileopen (256); 00061 00062 /* Now construct each line. */ 00063 for (; count > 0; count--, asm_lines++) 00064 { 00065 if (asm_lines->addr_string) 00066 xfree (asm_lines->addr_string); 00067 if (asm_lines->insn) 00068 xfree (asm_lines->insn); 00069 00070 print_address (gdbarch, pc, gdb_dis_out); 00071 asm_lines->addr = pc; 00072 asm_lines->addr_string = xstrdup (tui_file_get_strbuf (gdb_dis_out)); 00073 00074 ui_file_rewind (gdb_dis_out); 00075 00076 pc = pc + gdb_print_insn (gdbarch, pc, gdb_dis_out, NULL); 00077 00078 asm_lines->insn = xstrdup (tui_file_get_strbuf (gdb_dis_out)); 00079 00080 /* Reset the buffer to empty. */ 00081 ui_file_rewind (gdb_dis_out); 00082 } 00083 ui_file_delete (gdb_dis_out); 00084 return pc; 00085 } 00086 00087 /* Find the disassembly address that corresponds to FROM lines above 00088 or below the PC. Variable sized instructions are taken into 00089 account by the algorithm. */ 00090 static CORE_ADDR 00091 tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from) 00092 { 00093 CORE_ADDR new_low; 00094 int max_lines; 00095 int i; 00096 struct tui_asm_line *asm_lines; 00097 00098 max_lines = (from > 0) ? from : - from; 00099 if (max_lines <= 1) 00100 return pc; 00101 00102 asm_lines = (struct tui_asm_line*) alloca (sizeof (struct tui_asm_line) 00103 * max_lines); 00104 memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines); 00105 00106 new_low = pc; 00107 if (from > 0) 00108 { 00109 tui_disassemble (gdbarch, asm_lines, pc, max_lines); 00110 new_low = asm_lines[max_lines - 1].addr; 00111 } 00112 else 00113 { 00114 CORE_ADDR last_addr; 00115 int pos; 00116 struct minimal_symbol *msymbol; 00117 00118 /* Find backward an address which is a symbol and for which 00119 disassembling from that address will fill completely the 00120 window. */ 00121 pos = max_lines - 1; 00122 do { 00123 new_low -= 1 * max_lines; 00124 msymbol = lookup_minimal_symbol_by_pc_section (new_low, 0).minsym; 00125 00126 if (msymbol) 00127 new_low = SYMBOL_VALUE_ADDRESS (msymbol); 00128 else 00129 new_low += 1 * max_lines; 00130 00131 tui_disassemble (gdbarch, asm_lines, new_low, max_lines); 00132 last_addr = asm_lines[pos].addr; 00133 } while (last_addr > pc && msymbol); 00134 00135 /* Scan forward disassembling one instruction at a time until 00136 the last visible instruction of the window matches the pc. 00137 We keep the disassembled instructions in the 'lines' window 00138 and shift it downward (increasing its addresses). */ 00139 if (last_addr < pc) 00140 do 00141 { 00142 CORE_ADDR next_addr; 00143 00144 pos++; 00145 if (pos >= max_lines) 00146 pos = 0; 00147 00148 next_addr = tui_disassemble (gdbarch, &asm_lines[pos], 00149 last_addr, 1); 00150 00151 /* If there are some problems while disassembling exit. */ 00152 if (next_addr <= last_addr) 00153 break; 00154 last_addr = next_addr; 00155 } while (last_addr <= pc); 00156 pos++; 00157 if (pos >= max_lines) 00158 pos = 0; 00159 new_low = asm_lines[pos].addr; 00160 } 00161 for (i = 0; i < max_lines; i++) 00162 { 00163 xfree (asm_lines[i].addr_string); 00164 xfree (asm_lines[i].insn); 00165 } 00166 return new_low; 00167 } 00168 00169 /* Function to set the disassembly window's content. */ 00170 enum tui_status 00171 tui_set_disassem_content (struct gdbarch *gdbarch, CORE_ADDR pc) 00172 { 00173 enum tui_status ret = TUI_FAILURE; 00174 int i; 00175 int offset = TUI_DISASM_WIN->detail.source_info.horizontal_offset; 00176 int max_lines; 00177 CORE_ADDR cur_pc; 00178 struct tui_gen_win_info *locator = tui_locator_win_info_ptr (); 00179 int tab_len = tui_default_tab_len (); 00180 struct tui_asm_line *asm_lines; 00181 int insn_pos; 00182 int addr_size, max_size; 00183 char *line; 00184 00185 if (pc == 0) 00186 return TUI_FAILURE; 00187 00188 ret = tui_alloc_source_buffer (TUI_DISASM_WIN); 00189 if (ret != TUI_SUCCESS) 00190 return ret; 00191 00192 TUI_DISASM_WIN->detail.source_info.gdbarch = gdbarch; 00193 TUI_DISASM_WIN->detail.source_info.start_line_or_addr.loa = LOA_ADDRESS; 00194 TUI_DISASM_WIN->detail.source_info.start_line_or_addr.u.addr = pc; 00195 cur_pc = (CORE_ADDR) (((struct tui_win_element *) 00196 locator->content[0])->which_element.locator.addr); 00197 00198 max_lines = TUI_DISASM_WIN->generic.height - 2; /* Account for 00199 hilite. */ 00200 00201 /* Get temporary table that will hold all strings (addr & insn). */ 00202 asm_lines = (struct tui_asm_line*) alloca (sizeof (struct tui_asm_line) 00203 * max_lines); 00204 memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines); 00205 00206 tui_disassemble (gdbarch, asm_lines, pc, max_lines); 00207 00208 /* See what is the maximum length of an address and of a line. */ 00209 addr_size = 0; 00210 max_size = 0; 00211 for (i = 0; i < max_lines; i++) 00212 { 00213 size_t len = strlen (asm_lines[i].addr_string); 00214 00215 if (len > addr_size) 00216 addr_size = len; 00217 00218 len = strlen (asm_lines[i].insn) + tab_len; 00219 if (len > max_size) 00220 max_size = len; 00221 } 00222 max_size += addr_size + tab_len; 00223 00224 /* Allocate memory to create each line. */ 00225 line = (char*) alloca (max_size); 00226 insn_pos = (1 + (addr_size / tab_len)) * tab_len; 00227 00228 /* Now construct each line. */ 00229 for (i = 0; i < max_lines; i++) 00230 { 00231 struct tui_win_element *element; 00232 struct tui_source_element *src; 00233 int cur_len; 00234 00235 element = (struct tui_win_element *) TUI_DISASM_WIN->generic.content[i]; 00236 src = &element->which_element.source; 00237 strcpy (line, asm_lines[i].addr_string); 00238 cur_len = strlen (line); 00239 00240 /* Add spaces to make the instructions start on the same 00241 column. */ 00242 while (cur_len < insn_pos) 00243 { 00244 strcat (line, " "); 00245 cur_len++; 00246 } 00247 00248 strcat (line, asm_lines[i].insn); 00249 00250 /* Now copy the line taking the offset into account. */ 00251 if (strlen (line) > offset) 00252 strcpy (src->line, &line[offset]); 00253 else 00254 src->line[0] = '\0'; 00255 00256 src->line_or_addr.loa = LOA_ADDRESS; 00257 src->line_or_addr.u.addr = asm_lines[i].addr; 00258 src->is_exec_point = asm_lines[i].addr == cur_pc; 00259 00260 /* See whether there is a breakpoint installed. */ 00261 src->has_break = (!src->is_exec_point 00262 && breakpoint_here_p (current_program_space->aspace, 00263 pc) 00264 != no_breakpoint_here); 00265 00266 xfree (asm_lines[i].addr_string); 00267 xfree (asm_lines[i].insn); 00268 } 00269 TUI_DISASM_WIN->generic.content_size = i; 00270 return TUI_SUCCESS; 00271 } 00272 00273 00274 /* Function to display the disassembly window with disassembled code. */ 00275 void 00276 tui_show_disassem (struct gdbarch *gdbarch, CORE_ADDR start_addr) 00277 { 00278 struct symtab *s = find_pc_symtab (start_addr); 00279 struct tui_win_info *win_with_focus = tui_win_with_focus (); 00280 struct tui_line_or_address val; 00281 00282 val.loa = LOA_ADDRESS; 00283 val.u.addr = start_addr; 00284 tui_add_win_to_layout (DISASSEM_WIN); 00285 tui_update_source_window (TUI_DISASM_WIN, gdbarch, s, val, FALSE); 00286 00287 /* If the focus was in the src win, put it in the asm win, if the 00288 source view isn't split. */ 00289 if (tui_current_layout () != SRC_DISASSEM_COMMAND 00290 && win_with_focus == TUI_SRC_WIN) 00291 tui_set_win_focus_to (TUI_DISASM_WIN); 00292 00293 return; 00294 } 00295 00296 00297 /* Function to display the disassembly window. */ 00298 void 00299 tui_show_disassem_and_update_source (struct gdbarch *gdbarch, 00300 CORE_ADDR start_addr) 00301 { 00302 struct symtab_and_line sal; 00303 00304 tui_show_disassem (gdbarch, start_addr); 00305 if (tui_current_layout () == SRC_DISASSEM_COMMAND) 00306 { 00307 struct tui_line_or_address val; 00308 00309 /* Update what is in the source window if it is displayed too, 00310 note that it follows what is in the disassembly window and 00311 visa-versa. */ 00312 sal = find_pc_line (start_addr, 0); 00313 val.loa = LOA_LINE; 00314 val.u.line_no = sal.line; 00315 tui_update_source_window (TUI_SRC_WIN, gdbarch, sal.symtab, val, TRUE); 00316 if (sal.symtab) 00317 { 00318 set_current_source_symtab_and_line (&sal); 00319 tui_update_locator_fullname (symtab_to_fullname (sal.symtab)); 00320 } 00321 else 00322 tui_update_locator_fullname ("?"); 00323 } 00324 00325 return; 00326 } 00327 00328 void 00329 tui_get_begin_asm_address (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p) 00330 { 00331 struct tui_gen_win_info *locator; 00332 struct tui_locator_element *element; 00333 struct gdbarch *gdbarch = get_current_arch (); 00334 CORE_ADDR addr; 00335 00336 locator = tui_locator_win_info_ptr (); 00337 element = &((struct tui_win_element *) 00338 locator->content[0])->which_element.locator; 00339 00340 if (element->addr == 0) 00341 { 00342 struct minimal_symbol *main_symbol; 00343 00344 /* Find address of the start of program. 00345 Note: this should be language specific. */ 00346 main_symbol = lookup_minimal_symbol ("main", NULL, NULL); 00347 if (main_symbol == 0) 00348 main_symbol = lookup_minimal_symbol ("MAIN", NULL, NULL); 00349 if (main_symbol == 0) 00350 main_symbol = lookup_minimal_symbol ("_start", NULL, NULL); 00351 if (main_symbol) 00352 addr = SYMBOL_VALUE_ADDRESS (main_symbol); 00353 else 00354 addr = 0; 00355 } 00356 else /* The target is executing. */ 00357 { 00358 gdbarch = element->gdbarch; 00359 addr = element->addr; 00360 } 00361 00362 *gdbarch_p = gdbarch; 00363 *addr_p = addr; 00364 } 00365 00366 /* Determine what the low address will be to display in the TUI's 00367 disassembly window. This may or may not be the same as the low 00368 address input. */ 00369 CORE_ADDR 00370 tui_get_low_disassembly_address (struct gdbarch *gdbarch, 00371 CORE_ADDR low, CORE_ADDR pc) 00372 { 00373 int pos; 00374 00375 /* Determine where to start the disassembly so that the pc is about 00376 in the middle of the viewport. */ 00377 pos = tui_default_win_viewport_height (DISASSEM_WIN, DISASSEM_COMMAND) / 2; 00378 pc = tui_find_disassembly_address (gdbarch, pc, -pos); 00379 00380 if (pc < low) 00381 pc = low; 00382 return pc; 00383 } 00384 00385 /* Scroll the disassembly forward or backward vertically. */ 00386 void 00387 tui_vertical_disassem_scroll (enum tui_scroll_direction scroll_direction, 00388 int num_to_scroll) 00389 { 00390 if (TUI_DISASM_WIN->generic.content != NULL) 00391 { 00392 struct gdbarch *gdbarch = TUI_DISASM_WIN->detail.source_info.gdbarch; 00393 CORE_ADDR pc; 00394 tui_win_content content; 00395 struct tui_line_or_address val; 00396 int dir; 00397 00398 content = (tui_win_content) TUI_DISASM_WIN->generic.content; 00399 00400 pc = content[0]->which_element.source.line_or_addr.u.addr; 00401 num_to_scroll++; 00402 dir = (scroll_direction == FORWARD_SCROLL) 00403 ? num_to_scroll : -num_to_scroll; 00404 00405 val.loa = LOA_ADDRESS; 00406 val.u.addr = tui_find_disassembly_address (gdbarch, pc, dir); 00407 tui_update_source_window_as_is (TUI_DISASM_WIN, gdbarch, 00408 NULL, val, FALSE); 00409 } 00410 }