This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PR gas/13024: internal error with branch swapping and double .locs
- From: Richard Sandiford <rdsandiford at googlemail dot com>
- To: binutils at sourceware dot org
- Date: Mon, 05 Sep 2011 20:20:28 +0100
- Subject: PR gas/13024: internal error with branch swapping and double .locs
The recent patch to adjust the dwarf info for swapped MIPS branches
triggered an internal error on code like:
.file 1 "foo.c"
.cfi_startproc
.ent foo
.type foo, @function
foo:
.loc 1 1 0 # A
move $2,$4
.loc 1 2 0 # B
.loc 1 3 0 # C
j $31
.end foo
.cfi_endproc
We correctly adjust the location of C when swapping the branch.
The problem is that we emit B's line_entry as soon as we parse C,
and we unconditionally associate it with the end of the current frag.
We then have entries whose addresses zig around (0, 4, then 0 again).
I did wonder whether MIPS should follow ia64 and xtensa in taking a
copy of the current .loc information, then reemitting it when we
know the order. But that won't help here. We don't know at point C
whether the swap will take place or not, so the current handling of B
is always going to be wrong for one case (swap or don't swap).
This patch instead creates a list of pending line entries. When
emitting the current .loc for a given label, we do the same for all
previous pending .locs. When we consume the current .loc, we emit all
earlier pending ones at the end of the current frag. This preserves the
current behaviour of the external interface, as used by ia64 and xtensa
among others. (I wonder whether they'd actually want to take a list of
pending .locs, but I'll leave that for the port maintainers to decide.)
Tested on mipsisa32-elf (both binutils and gcc, where it fixes
several failures), xtensa-elf, ia64-linux-gnu and x86_64-linux-gnu.
Applied.
Richard
gas/
PR gas/13024
* dwarf2dbg.c (pending_lines, pending_lines_tail): New variables.
(dwarf2_gen_line_info_1): Delete.
(dwarf2_push_line, dwarf2_flush_pending_lines): New functions.
(dwarf2_gen_line_info, dwarf2_emit_label): Use them.
(dwarf2_consume_line_info): Call dwarf2_flush_pending_lines.
(dwarf2_directive_loc): Push previous .locs instead of generating
them immediately.
gas/testsuite/
* gas/mips/loc-swap-2.s, gas/mips/loc-swap-2.d,
gas/mips/micromips@loc-swap-2.d,
gas/mips/mips16@loc-swap-2.d: New test.
* gas/mips/mips.exp: Run it.
Index: gas/dwarf2dbg.c
===================================================================
--- gas/dwarf2dbg.c 2011-09-03 12:56:13.000000000 +0100
+++ gas/dwarf2dbg.c 2011-09-03 15:08:11.000000000 +0100
@@ -207,6 +207,10 @@ static struct dwarf2_line_info current =
0
};
+/* Lines that are at the same location as CURRENT, and which are waiting
+ for a label. */
+static struct line_entry *pending_lines, **pending_lines_tail = &pending_lines;
+
/* The size of an address on the target. */
static unsigned int sizeof_address;
@@ -280,22 +284,47 @@ get_line_subseg (segT seg, subsegT subse
return lss;
}
-/* Record an entry for LOC occurring at LABEL. */
+/* Push LOC onto the pending lines list. */
static void
-dwarf2_gen_line_info_1 (symbolS *label, struct dwarf2_line_info *loc)
+dwarf2_push_line (struct dwarf2_line_info *loc)
{
- struct line_subseg *lss;
struct line_entry *e;
e = (struct line_entry *) xmalloc (sizeof (*e));
e->next = NULL;
- e->label = label;
+ e->label = NULL;
e->loc = *loc;
- lss = get_line_subseg (now_seg, now_subseg);
- *lss->ptail = e;
- lss->ptail = &e->next;
+ *pending_lines_tail = e;
+ pending_lines_tail = &(*pending_lines_tail)->next;
+}
+
+/* Emit all pending line information. LABEL is the label with which the
+ lines should be associated, or null if they should be associated with
+ the current position. */
+
+static void
+dwarf2_flush_pending_lines (symbolS *label)
+{
+ if (pending_lines)
+ {
+ struct line_subseg *lss;
+ struct line_entry *e;
+
+ if (!label)
+ label = symbol_temp_new (now_seg, 0, frag_now);
+
+ for (e = pending_lines; e; e = e->next)
+ e->label = label;
+
+ lss = get_line_subseg (now_seg, now_subseg);
+ *lss->ptail = pending_lines;
+ lss->ptail = pending_lines_tail;
+
+ pending_lines = NULL;
+ pending_lines_tail = &pending_lines;
+ }
}
/* Record an entry for LOC occurring at OFS within the current fragment. */
@@ -306,8 +335,6 @@ dwarf2_gen_line_info (addressT ofs, stru
static unsigned int line = -1;
static unsigned int filenum = -1;
- symbolS *sym;
-
/* Early out for as-yet incomplete location information. */
if (loc->filenum == 0 || loc->line == 0)
return;
@@ -323,8 +350,8 @@ dwarf2_gen_line_info (addressT ofs, stru
line = loc->line;
filenum = loc->filenum;
- sym = symbol_temp_new (now_seg, ofs, frag_now);
- dwarf2_gen_line_info_1 (sym, loc);
+ dwarf2_push_line (loc);
+ dwarf2_flush_pending_lines (symbol_temp_new (now_seg, ofs, frag_now));
}
/* Returns the current source information. If .file directives have
@@ -385,6 +412,11 @@ dwarf2_emit_insn (int size)
void
dwarf2_consume_line_info (void)
{
+ /* If the consumer has stashed the current location away for later use,
+ assume that any earlier location information should be associated
+ with ".". */
+ dwarf2_flush_pending_lines (NULL);
+
/* Unless we generate DWARF2 debugging information for each
assembler line, we only emit one line symbol for one LOC. */
dwarf2_loc_directive_seen = FALSE;
@@ -416,7 +448,8 @@ dwarf2_emit_label (symbolS *label)
loc.flags |= DWARF2_FLAG_BASIC_BLOCK;
- dwarf2_gen_line_info_1 (label, &loc);
+ dwarf2_push_line (&loc);
+ dwarf2_flush_pending_lines (label);
dwarf2_consume_line_info ();
}
@@ -576,7 +609,7 @@ dwarf2_directive_loc (int dummy ATTRIBUT
/* If we see two .loc directives in a row, force the first one to be
output now. */
if (dwarf2_loc_directive_seen)
- dwarf2_emit_insn (0);
+ dwarf2_push_line (¤t);
filenum = get_absolute_expression ();
SKIP_WHITESPACE ();
Index: gas/testsuite/gas/mips/loc-swap-2.s
===================================================================
--- /dev/null 2011-09-05 19:47:55.002782251 +0100
+++ gas/testsuite/gas/mips/loc-swap-2.s 2011-09-05 20:00:22.000000000 +0100
@@ -0,0 +1,21 @@
+ .file 1 "loc-swap-2.s"
+ .cfi_startproc
+ .ent foo
+ .type foo,@function
+foo:
+ .loc 1 7
+ move $5,$6
+ .loc 1 9
+ .loc 1 10
+ jr $4
+
+ .loc 1 13
+ move $4,$7
+ .loc 1 14
+ .loc 1 15
+ bnez $4,foo
+
+ .loc 1 17
+ li $5,1
+ .end foo
+ .cfi_endproc
Index: gas/testsuite/gas/mips/loc-swap-2.d
===================================================================
--- /dev/null 2011-09-05 19:47:55.002782251 +0100
+++ gas/testsuite/gas/mips/loc-swap-2.d 2011-09-05 19:55:09.000000000 +0100
@@ -0,0 +1,49 @@
+#PROG: readelf
+#readelf: -wl
+#name: MIPS DWARF-2 location information with branch swapping (2)
+#as: -32
+#source: loc-swap-2.s
+
+Raw dump of debug contents of section .debug_line:
+
+ Offset: 0x0
+ Length: 60
+ DWARF Version: 2
+ Prologue Length: 35
+ Minimum Instruction Length: 1
+ Initial value of 'is_stmt': 1
+ Line Base: -5
+ Line Range: 14
+ Opcode Base: 13
+
+ Opcodes:
+ Opcode 1 has 0 args
+ Opcode 2 has 1 args
+ Opcode 3 has 1 args
+ Opcode 4 has 1 args
+ Opcode 5 has 1 args
+ Opcode 6 has 0 args
+ Opcode 7 has 0 args
+ Opcode 8 has 0 args
+ Opcode 9 has 1 args
+ Opcode 10 has 0 args
+ Opcode 11 has 0 args
+ Opcode 12 has 1 args
+
+ The Directory Table is empty.
+
+ The File Name Table:
+ Entry Dir Time Size Name
+ 1 0 0 0 loc-swap-2.s
+
+ Line Number Statements:
+ Extended opcode 2: set Address to 0x0
+ Special opcode 11: advance Address by 0 to 0x0 and Line by 6 to 7
+ Special opcode 7: advance Address by 0 to 0x0 and Line by 2 to 9
+ Special opcode 6: advance Address by 0 to 0x0 and Line by 1 to 10
+ Special opcode 120: advance Address by 8 to 0x8 and Line by 3 to 13
+ Special opcode 62: advance Address by 4 to 0xc and Line by 1 to 14
+ Special opcode 6: advance Address by 0 to 0xc and Line by 1 to 15
+ Special opcode 119: advance Address by 8 to 0x14 and Line by 2 to 17
+ Advance PC by 4 to 0x18
+ Extended opcode 1: End of Sequence
Index: gas/testsuite/gas/mips/micromips@loc-swap-2.d
===================================================================
--- /dev/null 2011-09-05 19:47:55.002782251 +0100
+++ gas/testsuite/gas/mips/micromips@loc-swap-2.d 2011-09-05 20:03:01.000000000 +0100
@@ -0,0 +1,49 @@
+#PROG: readelf
+#readelf: -wl
+#name: MIPS DWARF-2 location information with branch swapping (2)
+#as: -32
+#source: loc-swap-2.s
+
+Raw dump of debug contents of section .debug_line:
+
+ Offset: 0x0
+ Length: 60
+ DWARF Version: 2
+ Prologue Length: 35
+ Minimum Instruction Length: 1
+ Initial value of 'is_stmt': 1
+ Line Base: -5
+ Line Range: 14
+ Opcode Base: 13
+
+ Opcodes:
+ Opcode 1 has 0 args
+ Opcode 2 has 1 args
+ Opcode 3 has 1 args
+ Opcode 4 has 1 args
+ Opcode 5 has 1 args
+ Opcode 6 has 0 args
+ Opcode 7 has 0 args
+ Opcode 8 has 0 args
+ Opcode 9 has 1 args
+ Opcode 10 has 0 args
+ Opcode 11 has 0 args
+ Opcode 12 has 1 args
+
+ The Directory Table is empty.
+
+ The File Name Table:
+ Entry Dir Time Size Name
+ 1 0 0 0 loc-swap-2.s
+
+ Line Number Statements:
+ Extended opcode 2: set Address to 0x1
+ Special opcode 11: advance Address by 0 to 0x1 and Line by 6 to 7
+ Special opcode 35: advance Address by 2 to 0x3 and Line by 2 to 9
+ Special opcode 6: advance Address by 0 to 0x3 and Line by 1 to 10
+ Special opcode 64: advance Address by 4 to 0x7 and Line by 3 to 13
+ Special opcode 34: advance Address by 2 to 0x9 and Line by 1 to 14
+ Special opcode 6: advance Address by 0 to 0x9 and Line by 1 to 15
+ Special opcode 63: advance Address by 4 to 0xd and Line by 2 to 17
+ Advance PC by 1 to 0xe
+ Extended opcode 1: End of Sequence
Index: gas/testsuite/gas/mips/mips16@loc-swap-2.d
===================================================================
--- /dev/null 2011-09-05 19:47:55.002782251 +0100
+++ gas/testsuite/gas/mips/mips16@loc-swap-2.d 2011-09-05 20:02:53.000000000 +0100
@@ -0,0 +1,49 @@
+#PROG: readelf
+#readelf: -wl
+#name: MIPS DWARF-2 location information with branch swapping (2)
+#as: -32
+#source: loc-swap-2.s
+
+Raw dump of debug contents of section .debug_line:
+
+ Offset: 0x0
+ Length: 60
+ DWARF Version: 2
+ Prologue Length: 35
+ Minimum Instruction Length: 1
+ Initial value of 'is_stmt': 1
+ Line Base: -5
+ Line Range: 14
+ Opcode Base: 13
+
+ Opcodes:
+ Opcode 1 has 0 args
+ Opcode 2 has 1 args
+ Opcode 3 has 1 args
+ Opcode 4 has 1 args
+ Opcode 5 has 1 args
+ Opcode 6 has 0 args
+ Opcode 7 has 0 args
+ Opcode 8 has 0 args
+ Opcode 9 has 1 args
+ Opcode 10 has 0 args
+ Opcode 11 has 0 args
+ Opcode 12 has 1 args
+
+ The Directory Table is empty.
+
+ The File Name Table:
+ Entry Dir Time Size Name
+ 1 0 0 0 loc-swap-2.s
+
+ Line Number Statements:
+ Extended opcode 2: set Address to 0x1
+ Special opcode 11: advance Address by 0 to 0x1 and Line by 6 to 7
+ Special opcode 7: advance Address by 0 to 0x1 and Line by 2 to 9
+ Special opcode 6: advance Address by 0 to 0x1 and Line by 1 to 10
+ Special opcode 64: advance Address by 4 to 0x5 and Line by 3 to 13
+ Special opcode 34: advance Address by 2 to 0x7 and Line by 1 to 14
+ Special opcode 6: advance Address by 0 to 0x7 and Line by 1 to 15
+ Special opcode 35: advance Address by 2 to 0x9 and Line by 2 to 17
+ Advance PC by 1 to 0xa
+ Extended opcode 1: End of Sequence
Index: gas/testsuite/gas/mips/mips.exp
===================================================================
--- gas/testsuite/gas/mips/mips.exp 2011-09-05 20:02:34.000000000 +0100
+++ gas/testsuite/gas/mips/mips.exp 2011-09-05 20:02:36.000000000 +0100
@@ -885,6 +885,7 @@ if { [istarget mips*-*-vxworks*] } {
run_dump_test_arches "loc-swap" [mips_arch_list_all]
run_dump_test_arches "loc-swap-dis" \
[mips_arch_list_all]
+ run_dump_test_arches "loc-swap-2" [mips_arch_list_all]
}
if $has_newabi {