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