1130803Smarcel/* Disassembly display. 2130803Smarcel 3130803Smarcel Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software 4130803Smarcel Foundation, Inc. 5130803Smarcel 6130803Smarcel Contributed by Hewlett-Packard Company. 7130803Smarcel 8130803Smarcel This file is part of GDB. 9130803Smarcel 10130803Smarcel This program is free software; you can redistribute it and/or modify 11130803Smarcel it under the terms of the GNU General Public License as published by 12130803Smarcel the Free Software Foundation; either version 2 of the License, or 13130803Smarcel (at your option) any later version. 14130803Smarcel 15130803Smarcel This program is distributed in the hope that it will be useful, 16130803Smarcel but WITHOUT ANY WARRANTY; without even the implied warranty of 17130803Smarcel MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18130803Smarcel GNU General Public License for more details. 19130803Smarcel 20130803Smarcel You should have received a copy of the GNU General Public License 21130803Smarcel along with this program; if not, write to the Free Software 22130803Smarcel Foundation, Inc., 59 Temple Place - Suite 330, 23130803Smarcel Boston, MA 02111-1307, USA. */ 24130803Smarcel 25130803Smarcel#include "defs.h" 26130803Smarcel#include "symtab.h" 27130803Smarcel#include "breakpoint.h" 28130803Smarcel#include "frame.h" 29130803Smarcel#include "value.h" 30130803Smarcel#include "source.h" 31130803Smarcel#include "disasm.h" 32130803Smarcel#include "gdb_string.h" 33130803Smarcel#include "tui/tui.h" 34130803Smarcel#include "tui/tui-data.h" 35130803Smarcel#include "tui/tui-win.h" 36130803Smarcel#include "tui/tui-layout.h" 37130803Smarcel#include "tui/tui-winsource.h" 38130803Smarcel#include "tui/tui-stack.h" 39130803Smarcel#include "tui/tui-file.h" 40130803Smarcel 41130803Smarcel#include "gdb_curses.h" 42130803Smarcel 43130803Smarcelstruct tui_asm_line 44130803Smarcel{ 45130803Smarcel CORE_ADDR addr; 46130803Smarcel char* addr_string; 47130803Smarcel char* insn; 48130803Smarcel}; 49130803Smarcel 50130803Smarcel/* Function to set the disassembly window's content. 51130803Smarcel Disassemble count lines starting at pc. 52130803Smarcel Return address of the count'th instruction after pc. */ 53130803Smarcelstatic CORE_ADDR 54130803Smarceltui_disassemble (struct tui_asm_line* asm_lines, CORE_ADDR pc, int count) 55130803Smarcel{ 56130803Smarcel struct ui_file *gdb_dis_out; 57130803Smarcel 58130803Smarcel /* now init the ui_file structure */ 59130803Smarcel gdb_dis_out = tui_sfileopen (256); 60130803Smarcel 61130803Smarcel /* Now construct each line */ 62130803Smarcel for (; count > 0; count--, asm_lines++) 63130803Smarcel { 64130803Smarcel if (asm_lines->addr_string) 65130803Smarcel xfree (asm_lines->addr_string); 66130803Smarcel if (asm_lines->insn) 67130803Smarcel xfree (asm_lines->insn); 68130803Smarcel 69130803Smarcel print_address (pc, gdb_dis_out); 70130803Smarcel asm_lines->addr = pc; 71130803Smarcel asm_lines->addr_string = xstrdup (tui_file_get_strbuf (gdb_dis_out)); 72130803Smarcel 73130803Smarcel ui_file_rewind (gdb_dis_out); 74130803Smarcel 75130803Smarcel pc = pc + gdb_print_insn (pc, gdb_dis_out); 76130803Smarcel 77130803Smarcel asm_lines->insn = xstrdup (tui_file_get_strbuf (gdb_dis_out)); 78130803Smarcel 79130803Smarcel /* reset the buffer to empty */ 80130803Smarcel ui_file_rewind (gdb_dis_out); 81130803Smarcel } 82130803Smarcel ui_file_delete (gdb_dis_out); 83130803Smarcel return pc; 84130803Smarcel} 85130803Smarcel 86130803Smarcel/* Find the disassembly address that corresponds to FROM lines 87130803Smarcel above or below the PC. Variable sized instructions are taken 88130803Smarcel into account by the algorithm. */ 89130803Smarcelstatic CORE_ADDR 90130803Smarceltui_find_disassembly_address (CORE_ADDR pc, int from) 91130803Smarcel{ 92130803Smarcel CORE_ADDR new_low; 93130803Smarcel int max_lines; 94130803Smarcel int i; 95130803Smarcel struct tui_asm_line* asm_lines; 96130803Smarcel 97130803Smarcel max_lines = (from > 0) ? from : - from; 98130803Smarcel if (max_lines <= 1) 99130803Smarcel return pc; 100130803Smarcel 101130803Smarcel asm_lines = (struct tui_asm_line*) alloca (sizeof (struct tui_asm_line) 102130803Smarcel * max_lines); 103130803Smarcel memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines); 104130803Smarcel 105130803Smarcel new_low = pc; 106130803Smarcel if (from > 0) 107130803Smarcel { 108130803Smarcel tui_disassemble (asm_lines, pc, max_lines); 109130803Smarcel new_low = asm_lines[max_lines - 1].addr; 110130803Smarcel } 111130803Smarcel else 112130803Smarcel { 113130803Smarcel CORE_ADDR last_addr; 114130803Smarcel int pos; 115130803Smarcel struct minimal_symbol* msymbol; 116130803Smarcel 117130803Smarcel /* Find backward an address which is a symbol 118130803Smarcel and for which disassembling from that address will fill 119130803Smarcel completely the window. */ 120130803Smarcel pos = max_lines - 1; 121130803Smarcel do { 122130803Smarcel new_low -= 1 * max_lines; 123130803Smarcel msymbol = lookup_minimal_symbol_by_pc_section (new_low, 0); 124130803Smarcel 125130803Smarcel if (msymbol) 126130803Smarcel new_low = SYMBOL_VALUE_ADDRESS (msymbol); 127130803Smarcel else 128130803Smarcel new_low += 1 * max_lines; 129130803Smarcel 130130803Smarcel tui_disassemble (asm_lines, new_low, max_lines); 131130803Smarcel last_addr = asm_lines[pos].addr; 132130803Smarcel } while (last_addr > pc && msymbol); 133130803Smarcel 134130803Smarcel /* Scan forward disassembling one instruction at a time 135130803Smarcel until the last visible instruction of the window 136130803Smarcel matches the pc. We keep the disassembled instructions 137130803Smarcel in the 'lines' window and shift it downward (increasing 138130803Smarcel its addresses). */ 139130803Smarcel if (last_addr < pc) 140130803Smarcel do 141130803Smarcel { 142130803Smarcel CORE_ADDR next_addr; 143130803Smarcel 144130803Smarcel pos++; 145130803Smarcel if (pos >= max_lines) 146130803Smarcel pos = 0; 147130803Smarcel 148130803Smarcel next_addr = tui_disassemble (&asm_lines[pos], last_addr, 1); 149130803Smarcel 150130803Smarcel /* If there are some problems while disassembling exit. */ 151130803Smarcel if (next_addr <= last_addr) 152130803Smarcel break; 153130803Smarcel last_addr = next_addr; 154130803Smarcel } while (last_addr <= pc); 155130803Smarcel pos++; 156130803Smarcel if (pos >= max_lines) 157130803Smarcel pos = 0; 158130803Smarcel new_low = asm_lines[pos].addr; 159130803Smarcel } 160130803Smarcel for (i = 0; i < max_lines; i++) 161130803Smarcel { 162130803Smarcel xfree (asm_lines[i].addr_string); 163130803Smarcel xfree (asm_lines[i].insn); 164130803Smarcel } 165130803Smarcel return new_low; 166130803Smarcel} 167130803Smarcel 168130803Smarcel/* Function to set the disassembly window's content. */ 169130803Smarcelenum tui_status 170130803Smarceltui_set_disassem_content (CORE_ADDR pc) 171130803Smarcel{ 172130803Smarcel enum tui_status ret = TUI_FAILURE; 173130803Smarcel int i; 174130803Smarcel int offset = TUI_DISASM_WIN->detail.source_info.horizontal_offset; 175130803Smarcel int line_width, max_lines; 176130803Smarcel CORE_ADDR cur_pc; 177130803Smarcel struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); 178130803Smarcel int tab_len = tui_default_tab_len (); 179130803Smarcel struct tui_asm_line* asm_lines; 180130803Smarcel int insn_pos; 181130803Smarcel int addr_size, max_size; 182130803Smarcel char* line; 183130803Smarcel 184130803Smarcel if (pc == 0) 185130803Smarcel return TUI_FAILURE; 186130803Smarcel 187130803Smarcel ret = tui_alloc_source_buffer (TUI_DISASM_WIN); 188130803Smarcel if (ret != TUI_SUCCESS) 189130803Smarcel return ret; 190130803Smarcel 191130803Smarcel TUI_DISASM_WIN->detail.source_info.start_line_or_addr.addr = pc; 192130803Smarcel cur_pc = (CORE_ADDR) 193130803Smarcel (((struct tui_win_element *) locator->content[0])->which_element.locator.addr); 194130803Smarcel 195130803Smarcel max_lines = TUI_DISASM_WIN->generic.height - 2; /* account for hilite */ 196130803Smarcel 197130803Smarcel /* Get temporary table that will hold all strings (addr & insn). */ 198130803Smarcel asm_lines = (struct tui_asm_line*) alloca (sizeof (struct tui_asm_line) 199130803Smarcel * max_lines); 200130803Smarcel memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines); 201130803Smarcel 202130803Smarcel line_width = TUI_DISASM_WIN->generic.width - 1; 203130803Smarcel 204130803Smarcel tui_disassemble (asm_lines, pc, max_lines); 205130803Smarcel 206130803Smarcel /* See what is the maximum length of an address and of a line. */ 207130803Smarcel addr_size = 0; 208130803Smarcel max_size = 0; 209130803Smarcel for (i = 0; i < max_lines; i++) 210130803Smarcel { 211130803Smarcel size_t len = strlen (asm_lines[i].addr_string); 212130803Smarcel if (len > addr_size) 213130803Smarcel addr_size = len; 214130803Smarcel 215130803Smarcel len = strlen (asm_lines[i].insn) + tab_len; 216130803Smarcel if (len > max_size) 217130803Smarcel max_size = len; 218130803Smarcel } 219130803Smarcel max_size += addr_size + tab_len; 220130803Smarcel 221130803Smarcel /* Allocate memory to create each line. */ 222130803Smarcel line = (char*) alloca (max_size); 223130803Smarcel insn_pos = (1 + (addr_size / tab_len)) * tab_len; 224130803Smarcel 225130803Smarcel /* Now construct each line */ 226130803Smarcel for (i = 0; i < max_lines; i++) 227130803Smarcel { 228130803Smarcel struct tui_win_element * element; 229130803Smarcel struct tui_source_element* src; 230130803Smarcel int cur_len; 231130803Smarcel 232130803Smarcel element = (struct tui_win_element *) TUI_DISASM_WIN->generic.content[i]; 233130803Smarcel src = &element->which_element.source; 234130803Smarcel strcpy (line, asm_lines[i].addr_string); 235130803Smarcel cur_len = strlen (line); 236130803Smarcel 237130803Smarcel /* Add spaces to make the instructions start on the same column */ 238130803Smarcel while (cur_len < insn_pos) 239130803Smarcel { 240130803Smarcel strcat (line, " "); 241130803Smarcel cur_len++; 242130803Smarcel } 243130803Smarcel 244130803Smarcel strcat (line, asm_lines[i].insn); 245130803Smarcel 246130803Smarcel /* Now copy the line taking the offset into account */ 247130803Smarcel if (strlen (line) > offset) 248130803Smarcel strcpy (src->line, &line[offset]); 249130803Smarcel else 250130803Smarcel src->line[0] = '\0'; 251130803Smarcel 252130803Smarcel src->line_or_addr.addr = asm_lines[i].addr; 253130803Smarcel src->is_exec_point = asm_lines[i].addr == cur_pc; 254130803Smarcel 255130803Smarcel /* See whether there is a breakpoint installed. */ 256130803Smarcel src->has_break = (!src->is_exec_point 257130803Smarcel && breakpoint_here_p (pc) != no_breakpoint_here); 258130803Smarcel 259130803Smarcel xfree (asm_lines[i].addr_string); 260130803Smarcel xfree (asm_lines[i].insn); 261130803Smarcel } 262130803Smarcel TUI_DISASM_WIN->generic.content_size = i; 263130803Smarcel return TUI_SUCCESS; 264130803Smarcel} 265130803Smarcel 266130803Smarcel 267130803Smarcel/* Function to display the disassembly window with disassembled code. */ 268130803Smarcelvoid 269130803Smarceltui_show_disassem (CORE_ADDR start_addr) 270130803Smarcel{ 271130803Smarcel struct symtab *s = find_pc_symtab (start_addr); 272130803Smarcel struct tui_win_info * win_with_focus = tui_win_with_focus (); 273130803Smarcel union tui_line_or_address val; 274130803Smarcel 275130803Smarcel val.addr = start_addr; 276130803Smarcel tui_add_win_to_layout (DISASSEM_WIN); 277130803Smarcel tui_update_source_window (TUI_DISASM_WIN, s, val, FALSE); 278130803Smarcel /* 279130803Smarcel ** if the focus was in the src win, put it in the asm win, if the 280130803Smarcel ** source view isn't split 281130803Smarcel */ 282130803Smarcel if (tui_current_layout () != SRC_DISASSEM_COMMAND && win_with_focus == TUI_SRC_WIN) 283130803Smarcel tui_set_win_focus_to (TUI_DISASM_WIN); 284130803Smarcel 285130803Smarcel return; 286130803Smarcel} 287130803Smarcel 288130803Smarcel 289130803Smarcel/* Function to display the disassembly window. */ 290130803Smarcelvoid 291130803Smarceltui_show_disassem_and_update_source (CORE_ADDR start_addr) 292130803Smarcel{ 293130803Smarcel struct symtab_and_line sal; 294130803Smarcel 295130803Smarcel tui_show_disassem (start_addr); 296130803Smarcel if (tui_current_layout () == SRC_DISASSEM_COMMAND) 297130803Smarcel { 298130803Smarcel union tui_line_or_address val; 299130803Smarcel 300130803Smarcel /* 301130803Smarcel ** Update what is in the source window if it is displayed too, 302130803Smarcel ** note that it follows what is in the disassembly window and visa-versa 303130803Smarcel */ 304130803Smarcel sal = find_pc_line (start_addr, 0); 305130803Smarcel val.line_no = sal.line; 306130803Smarcel tui_update_source_window (TUI_SRC_WIN, sal.symtab, val, TRUE); 307130803Smarcel if (sal.symtab) 308130803Smarcel { 309130803Smarcel set_current_source_symtab_and_line (&sal); 310130803Smarcel tui_update_locator_filename (sal.symtab->filename); 311130803Smarcel } 312130803Smarcel else 313130803Smarcel tui_update_locator_filename ("?"); 314130803Smarcel } 315130803Smarcel 316130803Smarcel return; 317130803Smarcel} 318130803Smarcel 319130803SmarcelCORE_ADDR 320130803Smarceltui_get_begin_asm_address (void) 321130803Smarcel{ 322130803Smarcel struct tui_gen_win_info * locator; 323130803Smarcel struct tui_locator_element * element; 324130803Smarcel CORE_ADDR addr; 325130803Smarcel 326130803Smarcel locator = tui_locator_win_info_ptr (); 327130803Smarcel element = &((struct tui_win_element *) locator->content[0])->which_element.locator; 328130803Smarcel 329130803Smarcel if (element->addr == 0) 330130803Smarcel { 331130803Smarcel struct minimal_symbol *main_symbol; 332130803Smarcel 333130803Smarcel /* Find address of the start of program. 334130803Smarcel Note: this should be language specific. */ 335130803Smarcel main_symbol = lookup_minimal_symbol ("main", NULL, NULL); 336130803Smarcel if (main_symbol == 0) 337130803Smarcel main_symbol = lookup_minimal_symbol ("MAIN", NULL, NULL); 338130803Smarcel if (main_symbol == 0) 339130803Smarcel main_symbol = lookup_minimal_symbol ("_start", NULL, NULL); 340130803Smarcel if (main_symbol) 341130803Smarcel addr = SYMBOL_VALUE_ADDRESS (main_symbol); 342130803Smarcel else 343130803Smarcel addr = 0; 344130803Smarcel } 345130803Smarcel else /* the target is executing */ 346130803Smarcel addr = element->addr; 347130803Smarcel 348130803Smarcel return addr; 349130803Smarcel} 350130803Smarcel 351130803Smarcel/* Determine what the low address will be to display in the TUI's 352130803Smarcel disassembly window. This may or may not be the same as the 353130803Smarcel low address input. */ 354130803SmarcelCORE_ADDR 355130803Smarceltui_get_low_disassembly_address (CORE_ADDR low, CORE_ADDR pc) 356130803Smarcel{ 357130803Smarcel int pos; 358130803Smarcel 359130803Smarcel /* Determine where to start the disassembly so that the pc is about in the 360130803Smarcel middle of the viewport. */ 361130803Smarcel pos = tui_default_win_viewport_height (DISASSEM_WIN, DISASSEM_COMMAND) / 2; 362130803Smarcel pc = tui_find_disassembly_address (pc, -pos); 363130803Smarcel 364130803Smarcel if (pc < low) 365130803Smarcel pc = low; 366130803Smarcel return pc; 367130803Smarcel} 368130803Smarcel 369130803Smarcel/* Scroll the disassembly forward or backward vertically. */ 370130803Smarcelvoid 371130803Smarceltui_vertical_disassem_scroll (enum tui_scroll_direction scroll_direction, 372130803Smarcel int num_to_scroll) 373130803Smarcel{ 374130803Smarcel if (TUI_DISASM_WIN->generic.content != NULL) 375130803Smarcel { 376130803Smarcel CORE_ADDR pc; 377130803Smarcel tui_win_content content; 378130803Smarcel struct symtab *s; 379130803Smarcel union tui_line_or_address val; 380130803Smarcel int max_lines, dir; 381130803Smarcel struct symtab_and_line cursal = get_current_source_symtab_and_line (); 382130803Smarcel 383130803Smarcel content = (tui_win_content) TUI_DISASM_WIN->generic.content; 384130803Smarcel if (cursal.symtab == (struct symtab *) NULL) 385130803Smarcel s = find_pc_symtab (get_frame_pc (deprecated_selected_frame)); 386130803Smarcel else 387130803Smarcel s = cursal.symtab; 388130803Smarcel 389130803Smarcel /* account for hilite */ 390130803Smarcel max_lines = TUI_DISASM_WIN->generic.height - 2; 391130803Smarcel pc = content[0]->which_element.source.line_or_addr.addr; 392130803Smarcel dir = (scroll_direction == FORWARD_SCROLL) ? max_lines : - max_lines; 393130803Smarcel 394130803Smarcel val.addr = tui_find_disassembly_address (pc, dir); 395130803Smarcel tui_update_source_window_as_is (TUI_DISASM_WIN, s, val, FALSE); 396130803Smarcel } 397130803Smarcel} 398