Fix TUI use of "has_break" field
[external/binutils.git] / gdb / tui / tui-disasm.c
1 /* Disassembly display.
2
3    Copyright (C) 1998-2019 Free Software Foundation, Inc.
4
5    Contributed by Hewlett-Packard Company.
6
7    This file is part of GDB.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22 #include "defs.h"
23 #include "arch-utils.h"
24 #include "symtab.h"
25 #include "breakpoint.h"
26 #include "frame.h"
27 #include "value.h"
28 #include "source.h"
29 #include "disasm.h"
30 #include "tui/tui.h"
31 #include "tui/tui-data.h"
32 #include "tui/tui-win.h"
33 #include "tui/tui-layout.h"
34 #include "tui/tui-winsource.h"
35 #include "tui/tui-stack.h"
36 #include "tui/tui-file.h"
37 #include "tui/tui-disasm.h"
38 #include "progspace.h"
39 #include "objfiles.h"
40
41 #include "gdb_curses.h"
42
43 struct tui_asm_line 
44 {
45   CORE_ADDR addr;
46   char *addr_string;
47   char *insn;
48 };
49
50 /* Function to set the disassembly window's content.
51    Disassemble count lines starting at pc.
52    Return address of the count'th instruction after pc.  */
53 static CORE_ADDR
54 tui_disassemble (struct gdbarch *gdbarch, struct tui_asm_line *asm_lines,
55                  CORE_ADDR pc, int count)
56 {
57   string_file gdb_dis_out;
58
59   /* Now construct each line.  */
60   for (; count > 0; count--, asm_lines++)
61     {
62       xfree (asm_lines->addr_string);
63       xfree (asm_lines->insn);
64       
65       print_address (gdbarch, pc, &gdb_dis_out);
66       asm_lines->addr = pc;
67       asm_lines->addr_string = xstrdup (gdb_dis_out.c_str ());
68
69       gdb_dis_out.clear ();
70
71       pc = pc + gdb_print_insn (gdbarch, pc, &gdb_dis_out, NULL);
72
73       asm_lines->insn = xstrdup (gdb_dis_out.c_str ());
74
75       /* Reset the buffer to empty.  */
76       gdb_dis_out.clear ();
77     }
78   return pc;
79 }
80
81 /* Find the disassembly address that corresponds to FROM lines above
82    or below the PC.  Variable sized instructions are taken into
83    account by the algorithm.  */
84 static CORE_ADDR
85 tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
86 {
87   CORE_ADDR new_low;
88   int max_lines;
89   int i;
90   struct tui_asm_line *asm_lines;
91
92   max_lines = (from > 0) ? from : - from;
93   if (max_lines <= 1)
94      return pc;
95
96   asm_lines = XALLOCAVEC (struct tui_asm_line, max_lines);
97   memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines);
98
99   new_low = pc;
100   if (from > 0)
101     {
102       tui_disassemble (gdbarch, asm_lines, pc, max_lines);
103       new_low = asm_lines[max_lines - 1].addr;
104     }
105   else
106     {
107       CORE_ADDR last_addr;
108       int pos;
109       struct bound_minimal_symbol msymbol;
110               
111       /* Find backward an address which is a symbol and for which
112          disassembling from that address will fill completely the
113          window.  */
114       pos = max_lines - 1;
115       do {
116          new_low -= 1 * max_lines;
117          msymbol = lookup_minimal_symbol_by_pc_section (new_low, 0);
118
119          if (msymbol.minsym)
120             new_low = BMSYMBOL_VALUE_ADDRESS (msymbol);
121          else
122             new_low += 1 * max_lines;
123
124          tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
125          last_addr = asm_lines[pos].addr;
126       } while (last_addr > pc && msymbol.minsym);
127
128       /* Scan forward disassembling one instruction at a time until
129          the last visible instruction of the window matches the pc.
130          We keep the disassembled instructions in the 'lines' window
131          and shift it downward (increasing its addresses).  */
132       if (last_addr < pc)
133         do
134           {
135             CORE_ADDR next_addr;
136                  
137             pos++;
138             if (pos >= max_lines)
139               pos = 0;
140
141             next_addr = tui_disassemble (gdbarch, &asm_lines[pos],
142                                          last_addr, 1);
143
144             /* If there are some problems while disassembling exit.  */
145             if (next_addr <= last_addr)
146               break;
147             last_addr = next_addr;
148           } while (last_addr <= pc);
149       pos++;
150       if (pos >= max_lines)
151          pos = 0;
152       new_low = asm_lines[pos].addr;
153     }
154   for (i = 0; i < max_lines; i++)
155     {
156       xfree (asm_lines[i].addr_string);
157       xfree (asm_lines[i].insn);
158     }
159   return new_low;
160 }
161
162 /* Function to set the disassembly window's content.  */
163 enum tui_status
164 tui_set_disassem_content (struct gdbarch *gdbarch, CORE_ADDR pc)
165 {
166   int i;
167   int offset = TUI_DISASM_WIN->horizontal_offset;
168   int max_lines, line_width;
169   CORE_ADDR cur_pc;
170   struct tui_locator_window *locator = tui_locator_win_info_ptr ();
171   int tab_len = tui_tab_width;
172   struct tui_asm_line *asm_lines;
173   int insn_pos;
174   int addr_size, insn_size;
175   char *line;
176   
177   if (pc == 0)
178     return TUI_FAILURE;
179
180   tui_alloc_source_buffer (TUI_DISASM_WIN);
181
182   tui_source_window_base *base = TUI_DISASM_WIN;
183   base->gdbarch = gdbarch;
184   base->start_line_or_addr.loa = LOA_ADDRESS;
185   base->start_line_or_addr.u.addr = pc;
186   cur_pc = locator->addr;
187
188   /* Window size, excluding highlight box.  */
189   max_lines = TUI_DISASM_WIN->height - 2;
190   line_width = TUI_DISASM_WIN->width - 2;
191
192   /* Get temporary table that will hold all strings (addr & insn).  */
193   asm_lines = XALLOCAVEC (struct tui_asm_line, max_lines);
194   memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines);
195
196   tui_disassemble (gdbarch, asm_lines, pc, max_lines);
197
198   /* Determine maximum address- and instruction lengths.  */
199   addr_size = 0;
200   insn_size = 0;
201   for (i = 0; i < max_lines; i++)
202     {
203       size_t len = strlen (asm_lines[i].addr_string);
204
205       if (len > addr_size)
206         addr_size = len;
207
208       len = strlen (asm_lines[i].insn);
209       if (len > insn_size)
210         insn_size = len;
211     }
212
213   /* Align instructions to the same column.  */
214   insn_pos = (1 + (addr_size / tab_len)) * tab_len;
215
216   /* Allocate memory to create each line.  */
217   line = (char*) alloca (insn_pos + insn_size + 1);
218
219   /* Now construct each line.  */
220   TUI_DISASM_WIN->content.resize (max_lines);
221   for (i = 0; i < max_lines; i++)
222     {
223       int cur_len;
224
225       tui_source_element *src = &TUI_DISASM_WIN->content[i];
226       strcpy (line, asm_lines[i].addr_string);
227       cur_len = strlen (line);
228       memset (line + cur_len, ' ', insn_pos - cur_len);
229       strcpy (line + insn_pos, asm_lines[i].insn);
230
231       /* Now copy the line taking the offset into account.  */
232       xfree (src->line);
233       if (strlen (line) > offset)
234         src->line = xstrndup (&line[offset], line_width);
235       else
236         src->line = xstrdup ("");
237
238       src->line_or_addr.loa = LOA_ADDRESS;
239       src->line_or_addr.u.addr = asm_lines[i].addr;
240       src->is_exec_point = asm_lines[i].addr == cur_pc;
241
242       xfree (asm_lines[i].addr_string);
243       xfree (asm_lines[i].insn);
244     }
245   return TUI_SUCCESS;
246 }
247
248
249 /* Function to display the disassembly window with disassembled code.  */
250 void
251 tui_show_disassem (struct gdbarch *gdbarch, CORE_ADDR start_addr)
252 {
253   struct symtab *s = find_pc_line_symtab (start_addr);
254   struct tui_win_info *win_with_focus = tui_win_with_focus ();
255   struct tui_line_or_address val;
256
257   val.loa = LOA_ADDRESS;
258   val.u.addr = start_addr;
259   tui_add_win_to_layout (DISASSEM_WIN);
260   tui_update_source_window (TUI_DISASM_WIN, gdbarch, s, val, FALSE);
261
262   /* If the focus was in the src win, put it in the asm win, if the
263      source view isn't split.  */
264   if (tui_current_layout () != SRC_DISASSEM_COMMAND 
265       && win_with_focus == TUI_SRC_WIN)
266     tui_set_win_focus_to (TUI_DISASM_WIN);
267
268   return;
269 }
270
271
272 /* Function to display the disassembly window.  */
273 void
274 tui_show_disassem_and_update_source (struct gdbarch *gdbarch,
275                                      CORE_ADDR start_addr)
276 {
277   struct symtab_and_line sal;
278
279   tui_show_disassem (gdbarch, start_addr);
280   if (tui_current_layout () == SRC_DISASSEM_COMMAND)
281     {
282       struct tui_line_or_address val;
283
284       /* Update what is in the source window if it is displayed too,
285          note that it follows what is in the disassembly window and
286          visa-versa.  */
287       sal = find_pc_line (start_addr, 0);
288       val.loa = LOA_LINE;
289       val.u.line_no = sal.line;
290       tui_update_source_window (TUI_SRC_WIN, gdbarch, sal.symtab, val, TRUE);
291       if (sal.symtab)
292         {
293           set_current_source_symtab_and_line (sal);
294           tui_update_locator_fullname (symtab_to_fullname (sal.symtab));
295         }
296       else
297         tui_update_locator_fullname ("?");
298     }
299
300   return;
301 }
302
303 void
304 tui_get_begin_asm_address (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
305 {
306   struct tui_locator_window *locator;
307   struct gdbarch *gdbarch = get_current_arch ();
308   CORE_ADDR addr;
309
310   locator = tui_locator_win_info_ptr ();
311
312   if (locator->addr == 0)
313     {
314       struct bound_minimal_symbol main_symbol;
315
316       /* Find address of the start of program.
317          Note: this should be language specific.  */
318       main_symbol = lookup_minimal_symbol ("main", NULL, NULL);
319       if (main_symbol.minsym == 0)
320         main_symbol = lookup_minimal_symbol ("MAIN", NULL, NULL);
321       if (main_symbol.minsym == 0)
322         main_symbol = lookup_minimal_symbol ("_start", NULL, NULL);
323       if (main_symbol.minsym)
324         addr = BMSYMBOL_VALUE_ADDRESS (main_symbol);
325       else
326         addr = 0;
327     }
328   else                          /* The target is executing.  */
329     {
330       gdbarch = locator->gdbarch;
331       addr = locator->addr;
332     }
333
334   *gdbarch_p = gdbarch;
335   *addr_p = addr;
336 }
337
338 /* Determine what the low address will be to display in the TUI's
339    disassembly window.  This may or may not be the same as the low
340    address input.  */
341 CORE_ADDR
342 tui_get_low_disassembly_address (struct gdbarch *gdbarch,
343                                  CORE_ADDR low, CORE_ADDR pc)
344 {
345   int pos;
346
347   /* Determine where to start the disassembly so that the pc is about
348      in the middle of the viewport.  */
349   pos = tui_default_win_viewport_height (DISASSEM_WIN, DISASSEM_COMMAND) / 2;
350   pc = tui_find_disassembly_address (gdbarch, pc, -pos);
351
352   if (pc < low)
353     pc = low;
354   return pc;
355 }
356
357 /* Scroll the disassembly forward or backward vertically.  */
358 void
359 tui_disasm_window::do_scroll_vertical (int num_to_scroll)
360 {
361   if (!content.empty ())
362     {
363       CORE_ADDR pc;
364       struct tui_line_or_address val;
365
366       pc = content[0].line_or_addr.u.addr;
367       if (num_to_scroll >= 0)
368         num_to_scroll++;
369       else
370         --num_to_scroll;
371
372       val.loa = LOA_ADDRESS;
373       val.u.addr = tui_find_disassembly_address (gdbarch, pc, num_to_scroll);
374       tui_update_source_window_as_is (this, gdbarch,
375                                       NULL, val, FALSE);
376     }
377 }