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