GDB (API)
/home/stan/gdb/src/gdb/tui/tui-disasm.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines