@@ -5,6 +5,10 @@
* Support for tracepoints on aarch64-linux was added in GDBserver.
+* Mixed source disassembly output has been changed.
+ Disassembled instructions are now printed in program order,
+ and source for all relevant files are now printed.
+
*** Changes in GDB 7.10
* Support for process record-replay and reverse debugging on aarch64*-linux*
@@ -24,6 +24,7 @@
#include "disasm.h"
#include "gdbcore.h"
#include "dis-asm.h"
+#include "source.h"
/* Disassemble functions.
FIXME: We should get rid of all the duplicate code in gdb that does
@@ -36,11 +37,75 @@
struct dis_line_entry
{
+ struct symtab *symtab;
int line;
- CORE_ADDR start_pc;
- CORE_ADDR end_pc;
};
+/* Hash function for dis_line_entry. */
+
+static hashval_t
+hash_dis_line_entry (const void *item)
+{
+ const struct dis_line_entry *dle = item;
+
+ return htab_hash_pointer (dle->symtab) + dle->line;
+}
+
+/* Equal function for dis_line_entry. */
+
+static int
+eq_dis_line_entry (const void *item_lhs, const void *item_rhs)
+{
+ const struct dis_line_entry *lhs = item_lhs;
+ const struct dis_line_entry *rhs = item_rhs;
+
+ return (lhs->symtab == rhs->symtab
+ && lhs->line == rhs->line);
+}
+
+/* Create the table to manage lines for mixed source/disassembly. */
+
+static htab_t
+allocate_dis_line_table (void)
+{
+ return htab_create_alloc (41,
+ hash_dis_line_entry, eq_dis_line_entry,
+ xfree, xcalloc, xfree);
+}
+
+/* Add DLE to TABLE.
+ Returns 1 if added, 0 if already present. */
+
+static void
+maybe_add_dis_line_entry (htab_t table, struct symtab *symtab, int line)
+{
+ void **slot;
+ struct dis_line_entry dle, *dlep;
+
+ dle.symtab = symtab;
+ dle.line = line;
+ slot = htab_find_slot (table, &dle, INSERT);
+ if (*slot == NULL)
+ {
+ dlep = XNEW (struct dis_line_entry);
+ dlep->symtab = symtab;
+ dlep->line = line;
+ *slot = dlep;
+ }
+}
+
+/* Return non-zero if SYMTAB, LINE are in TABLE. */
+
+static int
+line_has_code_p (htab_t table, struct symtab *symtab, int line)
+{
+ struct dis_line_entry dle;
+
+ dle.symtab = symtab;
+ dle.line = line;
+ return htab_find (table, &dle) != NULL;
+}
+
/* Like target_read_memory, but slightly different parameters. */
static int
dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
@@ -67,36 +132,11 @@ dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
}
static int
-compare_lines (const void *mle1p, const void *mle2p)
-{
- struct dis_line_entry *mle1, *mle2;
- int val;
-
- mle1 = (struct dis_line_entry *) mle1p;
- mle2 = (struct dis_line_entry *) mle2p;
-
- /* End of sequence markers have a line number of 0 but don't want to
- be sorted to the head of the list, instead sort by PC. */
- if (mle1->line == 0 || mle2->line == 0)
- {
- val = mle1->start_pc - mle2->start_pc;
- if (val == 0)
- val = mle1->line - mle2->line;
- }
- else
- {
- val = mle1->line - mle2->line;
- if (val == 0)
- val = mle1->start_pc - mle2->start_pc;
- }
- return val;
-}
-
-static int
dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
struct disassemble_info * di,
CORE_ADDR low, CORE_ADDR high,
- int how_many, int flags, struct ui_file *stb)
+ int how_many, int flags, struct ui_file *stb,
+ CORE_ADDR *end_pc)
{
int num_displayed = 0;
CORE_ADDR pc;
@@ -182,6 +222,9 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
do_cleanups (ui_out_chain);
ui_out_text (uiout, "\n");
}
+
+ if (end_pc != NULL)
+ *end_pc = pc;
return num_displayed;
}
@@ -192,10 +235,9 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
static void
do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
- struct disassemble_info *di, int nlines,
- struct linetable_entry *le,
+ struct disassemble_info *di,
+ struct symtab *main_symtab,
CORE_ADDR low, CORE_ADDR high,
- struct symtab *symtab,
int how_many, int flags, struct ui_file *stb)
{
int newlines = 0;
@@ -206,143 +248,169 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
int next_line = 0;
int num_displayed = 0;
enum print_source_lines_flags psl_flags = 0;
+ struct cleanup *cleanups;
struct cleanup *ui_out_chain;
- struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
- struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0);
-
- if (flags & DISASSEMBLY_FILENAME)
- psl_flags |= PRINT_SOURCE_LINES_FILENAME;
-
- mle = (struct dis_line_entry *) alloca (nlines
- * sizeof (struct dis_line_entry));
+ struct cleanup *ui_out_tuple_chain;
+ struct cleanup *ui_out_list_chain;
+ CORE_ADDR pc;
+ struct symtab *last_symtab;
+ int last_line;
+ htab_t dis_line_table;
- /* Copy linetable entries for this function into our data
- structure, creating end_pc's and setting out_of_order as
- appropriate. */
+ gdb_assert (main_symtab != NULL && SYMTAB_LINETABLE (main_symtab) != NULL);
- /* First, skip all the preceding functions. */
+ /* First pass is to collect the list of all source files and lines.
+ We do this so that we can only print lines containing code once.
+ We try to print the source text leading up to the next instruction,
+ but if that text is for code that will be disassembled later, then
+ we'll want to defer printing it until later where it's used. */
- for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
+ dis_line_table = allocate_dis_line_table ();
+ cleanups = make_cleanup_htab_delete (dis_line_table);
- /* Now, copy all entries before the end of this function. */
+ pc = low;
- for (; i < nlines - 1 && le[i].pc < high; i++)
+ while (pc < high)
{
- if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
- continue; /* Ignore duplicates. */
-
- /* Skip any end-of-function markers. */
- if (le[i].line == 0)
- continue;
-
- mle[newlines].line = le[i].line;
- if (le[i].line > le[i + 1].line)
- out_of_order = 1;
- mle[newlines].start_pc = le[i].pc;
- mle[newlines].end_pc = le[i + 1].pc;
- newlines++;
- }
+ struct symtab_and_line sal;
+ int length;
- /* If we're on the last line, and it's part of the function,
- then we need to get the end pc in a special way. */
+ sal = find_pc_line (pc, 0);
+ length = gdb_insn_length (gdbarch, pc);
+ pc += length;
- if (i == nlines - 1 && le[i].pc < high)
- {
- mle[newlines].line = le[i].line;
- mle[newlines].start_pc = le[i].pc;
- sal = find_pc_line (le[i].pc, 0);
- mle[newlines].end_pc = sal.end;
- newlines++;
+ if (sal.symtab != NULL)
+ maybe_add_dis_line_entry (dis_line_table, sal.symtab, sal.line);
}
- /* Now, sort mle by line #s (and, then by addresses within
- lines). */
-
- if (out_of_order)
- qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
+ /* Second pass prints the disassembly. */
- /* Now, for each line entry, emit the specified lines (unless
- they have been emitted before), followed by the assembly code
- for that line. */
+ if (flags & DISASSEMBLY_FILENAME)
+ psl_flags |= PRINT_SOURCE_LINES_FILENAME;
+ ui_out_text (uiout, symtab_to_filename_for_display (main_symtab));
+ ui_out_text (uiout, ":\n");
ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
- for (i = 0; i < newlines; i++)
+ ui_out_tuple_chain = make_cleanup (null_cleanup, NULL);
+ ui_out_list_chain = make_cleanup (null_cleanup, NULL);
+
+ last_symtab = main_symtab;
+ last_line = 0;
+ pc = low;
+
+ while (pc < high)
{
- /* Print out everything from next_line to the current line. */
- if (mle[i].line >= next_line)
+ struct linetable_entry *le = NULL;
+ struct symtab_and_line sal;
+ CORE_ADDR end_pc;
+ int start_preceding_line_to_display = 0;
+ int end_preceding_line_to_display = 0;
+ int new_line = 0;
+
+ sal = find_pc_line (pc, 0);
+
+ if (sal.symtab != last_symtab)
{
- if (next_line != 0)
+ /* New source file. */
+ do_cleanups (ui_out_chain);
+ ui_out_text (uiout, symtab_to_filename_for_display (sal.symtab));
+ ui_out_text (uiout, ":\n");
+ ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout,
+ "asm_insns");
+ new_line = 1;
+ }
+ else
+ {
+ /* Same source file as last time. */
+ if (sal.symtab != NULL)
{
- /* Just one line to print. */
- if (next_line == mle[i].line)
+ if (sal.line > last_line + 1 && last_line != 0)
{
- ui_out_tuple_chain
- = make_cleanup_ui_out_tuple_begin_end (uiout,
- "src_and_asm_line");
- print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags);
+ int l;
+
+ /* Several preceding source lines. Print the trailing ones
+ not associated with code that we'll print later. */
+ for (l = sal.line - 1; l > last_line; --l)
+ {
+ if (line_has_code_p (dis_line_table, sal.symtab, l))
+ break;
+ }
+ if (l < sal.line - 1)
+ {
+ start_preceding_line_to_display = l + 1;
+ end_preceding_line_to_display = sal.line;
+ }
}
+ if (sal.line != last_line)
+ new_line = 1;
else
{
- /* Several source lines w/o asm instructions associated. */
- for (; next_line < mle[i].line; next_line++)
- {
- struct cleanup *ui_out_list_chain_line;
- struct cleanup *ui_out_tuple_chain_line;
-
- ui_out_tuple_chain_line
- = make_cleanup_ui_out_tuple_begin_end (uiout,
- "src_and_asm_line");
- print_source_lines (symtab, next_line, next_line + 1,
- psl_flags);
- ui_out_list_chain_line
- = make_cleanup_ui_out_list_begin_end (uiout,
- "line_asm_insn");
- do_cleanups (ui_out_list_chain_line);
- do_cleanups (ui_out_tuple_chain_line);
- }
- /* Print the last line and leave list open for
- asm instructions to be added. */
- ui_out_tuple_chain
+ /* Same source line as last time. This can happen, depending
+ on the debug info. */
+ }
+ }
+ }
+
+ if (new_line)
+ {
+ if (sal.symtab == last_symtab)
+ {
+ do_cleanups (ui_out_list_chain);
+ do_cleanups (ui_out_tuple_chain);
+ }
+ if (start_preceding_line_to_display > 0)
+ {
+ /* Several source lines w/o asm instructions associated. */
+ int l;
+ struct cleanup *ui_out_list_chain_line;
+ struct cleanup *ui_out_tuple_chain_line;
+
+ gdb_assert (sal.symtab != NULL);
+ for (l = start_preceding_line_to_display;
+ l < end_preceding_line_to_display;
+ ++l)
+ {
+ ui_out_tuple_chain_line
= make_cleanup_ui_out_tuple_begin_end (uiout,
"src_and_asm_line");
- print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags);
+ print_source_lines (sal.symtab, l, l + 1, psl_flags);
+ ui_out_list_chain_line
+ = make_cleanup_ui_out_list_begin_end (uiout,
+ "line_asm_insn");
+ do_cleanups (ui_out_list_chain_line);
+ do_cleanups (ui_out_tuple_chain_line);
}
}
+ ui_out_tuple_chain
+ = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line");
+ if (sal.symtab != NULL)
+ print_source_lines (sal.symtab, sal.line, sal.line + 1, psl_flags);
else
- {
- ui_out_tuple_chain
- = make_cleanup_ui_out_tuple_begin_end (uiout,
- "src_and_asm_line");
- print_source_lines (symtab, mle[i].line, mle[i].line + 1, psl_flags);
- }
-
- next_line = mle[i].line + 1;
+ ui_out_text (uiout, _("--- no source info for this pc ---\n"));
ui_out_list_chain
= make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
}
- num_displayed += dump_insns (gdbarch, uiout, di,
- mle[i].start_pc, mle[i].end_pc,
- how_many, flags, stb);
+ if (sal.end != 0)
+ end_pc = min (sal.end, high);
+ else
+ end_pc = pc + 1;
+ num_displayed += dump_insns (gdbarch, uiout, di, pc, end_pc,
+ how_many, flags, stb, &end_pc);
+ pc = end_pc;
- /* When we've reached the end of the mle array, or we've seen the last
- assembly range for this source line, close out the list/tuple. */
- if (i == (newlines - 1) || mle[i + 1].line > mle[i].line)
- {
- do_cleanups (ui_out_list_chain);
- do_cleanups (ui_out_tuple_chain);
- ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
- ui_out_list_chain = make_cleanup (null_cleanup, 0);
- ui_out_text (uiout, "\n");
- }
if (how_many >= 0 && num_displayed >= how_many)
break;
+
+ last_symtab = sal.symtab;
+ last_line = sal.line;
}
+
do_cleanups (ui_out_chain);
+ do_cleanups (cleanups);
}
-
static void
do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
struct disassemble_info * di,
@@ -355,7 +423,7 @@ do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
num_displayed = dump_insns (gdbarch, uiout, di, low, high, how_many,
- flags, stb);
+ flags, stb, NULL);
do_cleanups (ui_out_chain);
}
@@ -411,26 +479,21 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
struct cleanup *cleanups = make_cleanup_ui_file_delete (stb);
struct disassemble_info di = gdb_disassemble_info (gdbarch, stb);
struct symtab *symtab;
- struct linetable_entry *le = NULL;
int nlines = -1;
/* Assume symtab is valid for whole PC range. */
symtab = find_pc_line_symtab (low);
if (symtab != NULL && SYMTAB_LINETABLE (symtab) != NULL)
- {
- /* Convert the linetable to a bunch of my_line_entry's. */
- le = SYMTAB_LINETABLE (symtab)->item;
- nlines = SYMTAB_LINETABLE (symtab)->nitems;
- }
+ nlines = SYMTAB_LINETABLE (symtab)->nitems;
if (!(flags & DISASSEMBLY_SOURCE) || nlines <= 0
|| symtab == NULL || SYMTAB_LINETABLE (symtab) == NULL)
do_assembly_only (gdbarch, uiout, &di, low, high, how_many, flags, stb);
else if (flags & DISASSEMBLY_SOURCE)
- do_mixed_source_and_assembly (gdbarch, uiout, &di, nlines, le, low,
- high, symtab, how_many, flags, stb);
+ do_mixed_source_and_assembly (gdbarch, uiout, &di, symtab, low, high,
+ how_many, flags, stb);
do_cleanups (cleanups);
gdb_flush (gdb_stdout);
@@ -8082,20 +8082,19 @@ program is stopped just after function prologue:
@smallexample
(@value{GDBP}) disas /m main
Dump of assembler code for function main:
+hello.c:
5 @{
0x08048330 <+0>: push %ebp
0x08048331 <+1>: mov %esp,%ebp
0x08048333 <+3>: sub $0x8,%esp
0x08048336 <+6>: and $0xfffffff0,%esp
0x08048339 <+9>: sub $0x10,%esp
-
6 printf ("Hello.\n");
=> 0x0804833c <+12>: movl $0x8048440,(%esp)
0x08048343 <+19>: call 0x8048284 <puts@@plt>
-
7 return 0;
-8 @}
0x08048348 <+24>: mov $0x0,%eax
+8 @}
0x0804834d <+29>: leave
0x0804834e <+30>: ret
@@ -59,7 +59,7 @@ void do_nothing (void)
int main ()
{
- callee1 (2, "A string argument.", 3.5);
+ callee1 (2, "A string argument.", 3.5); /* callee1-1 */
callee1 (2, "A string argument.", 3.5);
do_nothing (); /* Hello, World! */
@@ -93,7 +93,7 @@ mi_gdb_test "-interpreter-exec console \"set listsize 1\"" \
# {.*\~"32[ \t(\\t)]*callee1.*\\n".*\^done }
mi_gdb_test "-interpreter-exec console \"list\"" \
- ".*\~\"$line_main_body\[\\\\t \]*callee1.*;\\\\n\".*\\^done" \
+ ".*\~\"$line_main_body\[\\\\t \]*callee1.*; /\\* callee1-1 \\*/\\\\n\".*\\^done" \
"-interpreter-exec console \"list\""
mi_execute_to "exec-continue" "breakpoint-hit" "callee4" "" ".*basics.c" $line_callee4_body \
@@ -116,6 +116,7 @@ proc test_disassembly_mixed {} {
global decimal
global fullname_syntax
+ set line_mixed_range [gdb_get_line_number "callee1-1"]
set line_callee2_head [gdb_get_line_number "callee2 ("]
set line_callee2_open_brace [expr $line_callee2_head + 1]
@@ -128,12 +129,14 @@ proc test_disassembly_mixed {} {
"002\\^done,asm_insns=\\\[src_and_asm_line=\{line=\"$line_callee2_open_brace\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[\{address=\"$hex\",func-name=\"callee2\",offset=\"0\",inst=\".*\"\}.*\\\]\}.*,src_and_asm_line=\{line=\"$decimal\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[.*\{address=\"$hex\",func-name=\"callee2\",offset=\"$decimal\",inst=\".*\"\}\\\]\}\\\]" \
"data-disassemble file, line assembly mixed"
- #
- # In mixed mode, the lowest level of granularity is the source line.
- # So we are going to get the disassembly for the source line at
- # which we are now, even if we have specified that the range is only 2 insns.
- #
- mi_gdb_test "003-data-disassemble -s \$pc -e \"\$pc+4\" -- 1" \
+ global expect_out
+ mi_gdb_test "-interpreter-exec console \"info line $line_mixed_range\"" \
+ ".* starts at address ($hex) .* ends at ($hex).*\\^done" \
+ "info line mixed-range"
+ set mixed_start $expect_out(3,string)
+ set mixed_end $expect_out(4,string)
+
+ mi_gdb_test "003-data-disassemble -s $mixed_start -e $mixed_end -- 1" \
"003\\^done,asm_insns=\\\[src_and_asm_line=\{line=\"$decimal\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[\{address=\"$hex\",func-name=\"main\",offset=\"$decimal\",inst=\".*\"\}.*\{address=\"$hex\",func-name=\"main\",offset=\"$decimal\",inst=\".*\"\}\\\]\}\\\]" \
"data-disassemble range assembly mixed"
}
@@ -144,6 +147,7 @@ proc test_disassembly_mixed_with_opcodes {} {
global decimal
global fullname_syntax
+ set line_mixed_range [gdb_get_line_number "callee1-1"]
set line_callee2_head [gdb_get_line_number "callee2 ("]
set line_callee2_open_brace [expr $line_callee2_head + 1]
@@ -156,12 +160,14 @@ proc test_disassembly_mixed_with_opcodes {} {
"002\\^done,asm_insns=\\\[src_and_asm_line=\{line=\"$line_callee2_open_brace\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[\{address=\"$hex\",func-name=\"callee2\",offset=\"0\",opcodes=\".*\",inst=\".*\"\}.*\\\]\}.*,src_and_asm_line=\{line=\"$decimal\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[.*\{address=\"$hex\",func-name=\"callee2\",offset=\"$decimal\",opcodes=\".*\",inst=\".*\"\}\\\]\}\\\]" \
"data-disassemble file, line assembly mixed with opcodes"
- #
- # In mixed mode, the lowest level of granularity is the source line.
- # So we are going to get the disassembly for the source line at
- # which we are now, even if we have specified that the range is only 2 insns.
- #
- mi_gdb_test "003-data-disassemble -s \$pc -e \"\$pc+4\" -- 3" \
+ global expect_out
+ mi_gdb_test "-interpreter-exec console \"info line $line_mixed_range\"" \
+ ".* starts at address ($hex) .* ends at ($hex).*\\^done" \
+ "info line mixed-range with opcodes"
+ set mixed_start $expect_out(3,string)
+ set mixed_end $expect_out(4,string)
+
+ mi_gdb_test "003-data-disassemble -s $mixed_start -e $mixed_end -- 3" \
"003\\^done,asm_insns=\\\[src_and_asm_line=\{line=\"$decimal\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[\{address=\"$hex\",func-name=\"main\",offset=\"$decimal\",opcodes=\".*\",inst=\".*\"\}.*\{address=\"$hex\",func-name=\"main\",offset=\"$decimal\",opcodes=\".*\",inst=\".*\"\}\\\]\}\\\]" \
"data-disassemble range assembly mixed with opcodes"
}