[TCWG CI] Regression caused by binutils: PR28149, debug info with wrong file association: commit 51298b330327a568358da069d9808f51c6cb1672 Author: Alan Modra amodra@gmail.com
PR28149, debug info with wrong file association
Results regressed to # reset_artifacts: -10 # build_abe binutils: -9 # build_abe stage1: -5 # build_abe qemu: -2 # linux_n_obj: 6363 # First few build errors in logs:
from # reset_artifacts: -10 # build_abe binutils: -9 # build_abe stage1: -5 # build_abe qemu: -2 # linux_n_obj: 7116 # linux build successful: all # linux boot successful: boot
THIS IS THE END OF INTERESTING STUFF. BELOW ARE LINKS TO BUILDS, REPRODUCTION INSTRUCTIONS, AND THE RAW COMMIT.
This commit has regressed these CI configurations: - tcwg_kernel/gnu-master-aarch64-lts-defconfig
First_bad build: https://ci.linaro.org/job/tcwg_kernel-gnu-bisect-gnu-master-aarch64-lts-defc... Last_good build: https://ci.linaro.org/job/tcwg_kernel-gnu-bisect-gnu-master-aarch64-lts-defc... Baseline build: https://ci.linaro.org/job/tcwg_kernel-gnu-bisect-gnu-master-aarch64-lts-defc... Even more details: https://ci.linaro.org/job/tcwg_kernel-gnu-bisect-gnu-master-aarch64-lts-defc...
Reproduce builds: <cut> mkdir investigate-binutils-51298b330327a568358da069d9808f51c6cb1672 cd investigate-binutils-51298b330327a568358da069d9808f51c6cb1672
# Fetch scripts git clone https://git.linaro.org/toolchain/jenkins-scripts
# Fetch manifests and test.sh script mkdir -p artifacts/manifests curl -o artifacts/manifests/build-baseline.sh https://ci.linaro.org/job/tcwg_kernel-gnu-bisect-gnu-master-aarch64-lts-defc... --fail curl -o artifacts/manifests/build-parameters.sh https://ci.linaro.org/job/tcwg_kernel-gnu-bisect-gnu-master-aarch64-lts-defc... --fail curl -o artifacts/test.sh https://ci.linaro.org/job/tcwg_kernel-gnu-bisect-gnu-master-aarch64-lts-defc... --fail chmod +x artifacts/test.sh
# Reproduce the baseline build (build all pre-requisites) ./jenkins-scripts/tcwg_kernel-build.sh @@ artifacts/manifests/build-baseline.sh
# Save baseline build state (which is then restored in artifacts/test.sh) mkdir -p ./bisect rsync -a --del --delete-excluded --exclude /bisect/ --exclude /artifacts/ --exclude /binutils/ ./ ./bisect/baseline/
cd binutils
# Reproduce first_bad build git checkout --detach 51298b330327a568358da069d9808f51c6cb1672 ../artifacts/test.sh
# Reproduce last_good build git checkout --detach 5cdb4f14426a99ec8fcba843fa503efdc55fa078 ../artifacts/test.sh
cd .. </cut>
Full commit (up to 1000 lines): <cut> commit 51298b330327a568358da069d9808f51c6cb1672 Author: Alan Modra amodra@gmail.com Date: Fri Sep 17 09:08:15 2021 +0930
PR28149, debug info with wrong file association
gcc-11 and gcc-12 pass -gdwarf-5 to gas, in order to prime gas for DWARF 5 level debug info. Unfortunately it seems there are cases where the compiler does not emit a .file or .loc dwarf debug directive before any machine instructions. (Note that the .file directive typically emitted as the first line of assembly output doesn't count as a dwarf debug directive. The dwarf .file has a file number before the file name string.)
This patch delays allocation of file numbers for gas generated line debug info until the end of assembly, thus avoiding any clashes with compiler generated file numbers. Two fixes for test case source are necessary; A .loc can't use a file number that hasn't already been specified with .file.
A followup patch will remove all the gas generated line info on seeing a .file directive.
PR 28149 * dwarf2dbg.c (num_of_auto_assigned): Delete. (current): Update initialisation. (set_or_check_view): Replace all accesses to view with u.view. (dwarf2_consume_line_info): Likewise. (dwarf2_directive_loc): Likewise. Assert that we aren't generating line info. (dwarf2_gen_line_info_1): Don't call set_or_check_view on gas generated line entries. (dwarf2_gen_line_info): Set and track filenames for gas generated line entries. Simplify generation of labels. (get_directory_table_entry): Use filename_cmp when comparing dirs. (do_allocate_filenum): New function. (dwarf2_where): Set u.filename and filenum to -1 for gas generated line entries. (dwarf2_directive_filename): Remove num_of_auto_assigned handling. (process_entries): Update view field access. Call do_allocate_filenum. * dwarf2dbg.h (struct dwarf2_line_info): Add filename field in union aliasing view. * testsuite/gas/i386/dwarf2-line-3.s: Add .file directive. * testsuite/gas/i386/dwarf2-line-4.s: Likewise. * testsuite/gas/i386/dwarf2-line-4.d: Update expected output. * testsuite/gas/i386/dwarf4-line-1.d: Likewise. * testsuite/gas/i386/dwarf5-line-1.d: Likewise. * testsuite/gas/i386/dwarf5-line-2.d: Likewise. --- gas/dwarf2dbg.c | 152 ++++++++++++++++++--------------- gas/dwarf2dbg.h | 7 +- gas/testsuite/gas/i386/dwarf2-line-3.s | 1 + gas/testsuite/gas/i386/dwarf2-line-4.d | 5 +- gas/testsuite/gas/i386/dwarf2-line-4.s | 1 + gas/testsuite/gas/i386/dwarf4-line-1.d | 4 +- gas/testsuite/gas/i386/dwarf5-line-1.d | 4 +- gas/testsuite/gas/i386/dwarf5-line-2.d | 3 +- 8 files changed, 105 insertions(+), 72 deletions(-)
diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c index 9e3437b8948..c6303ba94a6 100644 --- a/gas/dwarf2dbg.c +++ b/gas/dwarf2dbg.c @@ -207,7 +207,6 @@ struct file_entry static struct file_entry *files; static unsigned int files_in_use; static unsigned int files_allocated; -static unsigned int num_of_auto_assigned;
/* Table of directories used by .debug_line. */ static char ** dirs = NULL; @@ -233,7 +232,7 @@ static struct dwarf2_line_info current = { 1, 1, 0, 0, DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, - 0, NULL + 0, { NULL } };
/* This symbol is used to recognize view number forced resets in loc @@ -342,7 +341,7 @@ set_or_check_view (struct line_entry *e, struct line_entry *p, /* First, compute !(E->label > P->label), to tell whether or not we're to reset the view number. If we can't resolve it to a constant, keep it symbolic. */ - if (!p || (e->loc.view == force_reset_view && force_reset_view)) + if (!p || (e->loc.u.view == force_reset_view && force_reset_view)) { viewx.X_op = O_constant; viewx.X_add_number = 0; @@ -367,9 +366,9 @@ set_or_check_view (struct line_entry *e, struct line_entry *p, } }
- if (S_IS_DEFINED (e->loc.view) && symbol_constant_p (e->loc.view)) + if (S_IS_DEFINED (e->loc.u.view) && symbol_constant_p (e->loc.u.view)) { - expressionS *value = symbol_get_value_expression (e->loc.view); + expressionS *value = symbol_get_value_expression (e->loc.u.view); /* We can't compare the view numbers at this point, because in VIEWX we've only determined whether we're to reset it so far. */ @@ -404,16 +403,16 @@ set_or_check_view (struct line_entry *e, struct line_entry *p, { expressionS incv;
- if (!p->loc.view) + if (!p->loc.u.view) { - p->loc.view = symbol_temp_make (); - gas_assert (!S_IS_DEFINED (p->loc.view)); + p->loc.u.view = symbol_temp_make (); + gas_assert (!S_IS_DEFINED (p->loc.u.view)); }
memset (&incv, 0, sizeof (incv)); incv.X_unsigned = 1; incv.X_op = O_symbol; - incv.X_add_symbol = p->loc.view; + incv.X_add_symbol = p->loc.u.view; incv.X_add_number = 1;
if (viewx.X_op == O_constant) @@ -430,16 +429,16 @@ set_or_check_view (struct line_entry *e, struct line_entry *p, } }
- if (!S_IS_DEFINED (e->loc.view)) + if (!S_IS_DEFINED (e->loc.u.view)) { - symbol_set_value_expression (e->loc.view, &viewx); - S_SET_SEGMENT (e->loc.view, expr_section); - symbol_set_frag (e->loc.view, &zero_address_frag); + symbol_set_value_expression (e->loc.u.view, &viewx); + S_SET_SEGMENT (e->loc.u.view, expr_section); + symbol_set_frag (e->loc.u.view, &zero_address_frag); }
/* Define and attempt to simplify any earlier views needed to compute E's. */ - if (h && p && p->loc.view && !S_IS_DEFINED (p->loc.view)) + if (h && p && p->loc.u.view && !S_IS_DEFINED (p->loc.u.view)) { struct line_entry *h2; /* Reverse the list to avoid quadratic behavior going backwards @@ -459,7 +458,9 @@ set_or_check_view (struct line_entry *e, struct line_entry *p, break; set_or_check_view (r, r->next, NULL); } - while (r->next && r->next->loc.view && !S_IS_DEFINED (r->next->loc.view) + while (r->next + && r->next->loc.u.view + && !S_IS_DEFINED (r->next->loc.u.view) && (r = r->next));
/* Unreverse the list, so that we can go forward again. */ @@ -475,14 +476,14 @@ set_or_check_view (struct line_entry *e, struct line_entry *p, view of the previous subsegment. */ if (r == h) continue; - gas_assert (S_IS_DEFINED (r->loc.view)); - resolve_expression (symbol_get_value_expression (r->loc.view)); + gas_assert (S_IS_DEFINED (r->loc.u.view)); + resolve_expression (symbol_get_value_expression (r->loc.u.view)); } while (r != p && (r = r->next));
/* Now that we've defined and computed all earlier views that might be needed to compute E's, attempt to simplify it. */ - resolve_expression (symbol_get_value_expression (e->loc.view)); + resolve_expression (symbol_get_value_expression (e->loc.u.view)); } }
@@ -518,10 +519,8 @@ dwarf2_gen_line_info_1 (symbolS *label, struct dwarf2_line_info *loc)
/* Subseg heads are chained to previous subsegs in dwarf2_finish. */ - if (loc->view && lss->head) - set_or_check_view (e, - (struct line_entry *)lss->ptail, - lss->head); + if (loc->filenum != -1u && loc->u.view && lss->head) + set_or_check_view (e, (struct line_entry *) lss->ptail, lss->head);
*lss->ptail = e; lss->ptail = &e->next; @@ -532,9 +531,6 @@ dwarf2_gen_line_info_1 (symbolS *label, struct dwarf2_line_info *loc) void dwarf2_gen_line_info (addressT ofs, struct dwarf2_line_info *loc) { - static unsigned int line = -1; - static unsigned int filenum = -1; - symbolS *sym;
/* Early out for as-yet incomplete location information. */ @@ -552,20 +548,35 @@ dwarf2_gen_line_info (addressT ofs, struct dwarf2_line_info *loc) symbols apply to assembler code. It is necessary to emit duplicate line symbols when a compiler asks for them, because GDB uses them to determine the end of the prologue. */ - if (debug_type == DEBUG_DWARF2 - && line == loc->line && filenum == loc->filenum) - return; + if (debug_type == DEBUG_DWARF2) + { + static unsigned int line = -1; + static const char *filename = NULL; + + if (line == loc->line) + { + if (filename == loc->u.filename) + return; + if (filename_cmp (filename, loc->u.filename) == 0) + { + filename = loc->u.filename; + return; + } + }
- line = loc->line; - filenum = loc->filenum; + line = loc->line; + filename = loc->u.filename; + }
if (linkrelax) { - char name[120]; + static int label_num = 0; + char name[32];
/* Use a non-fake name for the line number location, so that it can be referred to by relocations. */ - sprintf (name, ".Loc.%u.%u", line, filenum); + sprintf (name, ".Loc.%u", label_num); + label_num++; sym = symbol_new (name, now_seg, frag_now, ofs); } else @@ -624,13 +635,15 @@ get_directory_table_entry (const char *dirname, { const char * pwd = file0_dirname ? file0_dirname : getpwd ();
- if (dwarf_level >= 5 && strcmp (dirname, pwd) != 0) + if (dwarf_level >= 5 && filename_cmp (dirname, pwd) != 0) { - /* In DWARF-5 the 0 entry in the directory table is expected to be - the same as the DW_AT_comp_dir (which is set to the current build - directory). Since we are about to create a directory entry that - is not the same, allocate the current directory first. - FIXME: Alternatively we could generate an error message here. */ + /* In DWARF-5 the 0 entry in the directory table is + expected to be the same as the DW_AT_comp_dir (which + is set to the current build directory). Since we are + about to create a directory entry that is not the + same, allocate the current directory first. + FIXME: Alternatively we could generate an error + message here. */ (void) get_directory_table_entry (pwd, NULL, strlen (pwd), true); d = 1; @@ -745,14 +758,30 @@ allocate_filenum (const char * pathname) if (!assign_file_to_slot (i, file, dir)) return -1;
- num_of_auto_assigned++; - last_used = i; last_used_dir_len = dir_len;
return i; }
+/* Run through the list of line entries starting at E, allocating + file entries for gas generated debug. */ + +static void +do_allocate_filenum (struct line_entry *e) +{ + do + { + if (e->loc.filenum == -1u) + { + e->loc.filenum = allocate_filenum (e->loc.u.filename); + e->loc.u.view = NULL; + } + e = e->next; + } + while (e); +} + /* Allocate slot NUM in the .debug_line file table to FILENAME. If DIRNAME is not NULL or there is a directory component to FILENAME then this will be stored in the directory table, if not already present. @@ -929,17 +958,12 @@ dwarf2_where (struct dwarf2_line_info *line) { if (debug_type == DEBUG_DWARF2) { - const char *filename; - - memset (line, 0, sizeof (*line)); - filename = as_where (&line->line); - line->filenum = allocate_filenum (filename); - /* FIXME: We should check the return value from allocate_filenum. */ + line->u.filename = as_where (&line->line); + line->filenum = -1u; line->column = 0; line->flags = DWARF2_FLAG_IS_STMT; line->isa = current.isa; line->discriminator = current.discriminator; - line->view = NULL; } else *line = current; @@ -1018,7 +1042,7 @@ dwarf2_consume_line_info (void) | DWARF2_FLAG_PROLOGUE_END | DWARF2_FLAG_EPILOGUE_BEGIN); current.discriminator = 0; - current.view = NULL; + current.u.view = NULL; }
/* Called for each (preferably code) label. If dwarf2_loc_mark_labels @@ -1060,7 +1084,6 @@ dwarf2_directive_filename (void) char *filename; const char * dirname = NULL; int filename_len; - unsigned int i;
/* Continue to accept a bare string and pass it off. */ SKIP_WHITESPACE (); @@ -1132,18 +1155,6 @@ dwarf2_directive_filename (void) return NULL; }
- if (num_of_auto_assigned) - { - /* Clear slots auto-assigned before the first .file <NUMBER> - directive was seen. */ - if (files_in_use != (num_of_auto_assigned + 1)) - abort (); - for (i = 1; i < files_in_use; i++) - files[i].filename = NULL; - files_in_use = 0; - num_of_auto_assigned = 0; - } - if (! allocate_filename_to_slot (dirname, filename, (unsigned int) num, with_md5)) return NULL; @@ -1191,6 +1202,11 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) return; }
+ /* debug_type will be turned off by dwarf2_directive_filename, and + if we don't have a dwarf style .file then files_in_use will be + zero and the above error will trigger. */ + gas_assert (debug_type == DEBUG_NONE); + current.filenum = filenum; current.line = line; current.discriminator = 0; @@ -1333,7 +1349,7 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) S_SET_VALUE (sym, 0); symbol_set_frag (sym, &zero_address_frag); } - current.view = sym; + current.u.view = sym; } else { @@ -1347,10 +1363,9 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED)
demand_empty_rest_of_line (); dwarf2_any_loc_directive_seen = dwarf2_loc_directive_seen = true; - debug_type = DEBUG_NONE;
/* If we were given a view id, emit the row right away. */ - if (current.view) + if (current.u.view) dwarf2_emit_insn (0); }
@@ -1984,7 +1999,7 @@ process_entries (segT seg, struct line_entry *e) frag_ofs = S_GET_VALUE (lab);
if (last_frag == NULL - || (e->loc.view == force_reset_view && force_reset_view + || (e->loc.u.view == force_reset_view && force_reset_view /* If we're going to reset the view, but we know we're advancing the PC, we don't have to force with set_address. We know we do when we're at the same @@ -2850,16 +2865,19 @@ dwarf2_finish (void) struct line_subseg *lss = s->head; struct line_entry **ptail = lss->ptail;
+ if (lss->head && SEG_NORMAL (s->seg)) + do_allocate_filenum (lss->head); + /* Reset the initial view of the first subsection of the section. */ - if (lss->head && lss->head->loc.view) + if (lss->head && lss->head->loc.u.view) set_or_check_view (lss->head, NULL, NULL);
while ((lss = lss->next) != NULL) { /* Link the first view of subsequent subsections to the previous view. */ - if (lss->head && lss->head->loc.view) + if (lss->head && lss->head->loc.u.view) set_or_check_view (lss->head, !s->head ? NULL : (struct line_entry *)ptail, s->head ? s->head->head : NULL); diff --git a/gas/dwarf2dbg.h b/gas/dwarf2dbg.h index 14d770c40dd..700d9dec5cb 100644 --- a/gas/dwarf2dbg.h +++ b/gas/dwarf2dbg.h @@ -36,7 +36,12 @@ struct dwarf2_line_info unsigned int isa; unsigned int flags; unsigned int discriminator; - symbolS *view; + /* filenum == -1u chooses filename, otherwise view. */ + union + { + symbolS *view; + const char *filename; + } u; };
/* Implements the .file FILENO "FILENAME" directive. FILENO can be 0 diff --git a/gas/testsuite/gas/i386/dwarf2-line-3.s b/gas/testsuite/gas/i386/dwarf2-line-3.s index 2085ef93940..e933719fbc3 100644 --- a/gas/testsuite/gas/i386/dwarf2-line-3.s +++ b/gas/testsuite/gas/i386/dwarf2-line-3.s @@ -7,6 +7,7 @@ main: .cfi_startproc nop + .file 1 "dwarf2-test.c" .loc 1 1 ret .cfi_endproc diff --git a/gas/testsuite/gas/i386/dwarf2-line-4.d b/gas/testsuite/gas/i386/dwarf2-line-4.d index c0c85f4639f..a01fd0540f3 100644 --- a/gas/testsuite/gas/i386/dwarf2-line-4.d +++ b/gas/testsuite/gas/i386/dwarf2-line-4.d @@ -33,11 +33,14 @@ Raw dump of debug contents of section .z?debug_line:
The File Name Table (offset 0x.*): Entry Dir Time Size Name - 1 1 0 0 dwarf2-line-4.s + 1 0 0 0 dwarf2-test.c + 2 1 0 0 dwarf2-line-4.s
Line Number Statements: + [0x.*] Set File Name to entry 2 in the File Name Table [0x.*] Extended opcode 2: set Address to 0x0 [0x.*] Special opcode 13: advance Address by 0 to 0x0 and Line by 8 to 9 + [0x.*] Set File Name to entry 1 in the File Name Table [0x.*] Advance Line by -8 to 1 [0x.*] Special opcode 19: advance Address by 1 to 0x1 and Line by 0 to 1 [0x.*] Advance PC by 1 to 0x2 diff --git a/gas/testsuite/gas/i386/dwarf2-line-4.s b/gas/testsuite/gas/i386/dwarf2-line-4.s index 89bb62d9db7..7348f4be62c 100644 --- a/gas/testsuite/gas/i386/dwarf2-line-4.s +++ b/gas/testsuite/gas/i386/dwarf2-line-4.s @@ -7,6 +7,7 @@ main: .cfi_startproc nop + .file 1 "dwarf2-test.c" .loc 1 1 ret .cfi_endproc diff --git a/gas/testsuite/gas/i386/dwarf4-line-1.d b/gas/testsuite/gas/i386/dwarf4-line-1.d index 4f8321e9bfd..8199efbb0c2 100644 --- a/gas/testsuite/gas/i386/dwarf4-line-1.d +++ b/gas/testsuite/gas/i386/dwarf4-line-1.d @@ -36,12 +36,14 @@ Raw dump of debug contents of section .z?debug_line: Entry Dir Time Size Name 1 0 0 0 foo.c 2 0 0 0 foo.h + 3 1 0 0 dwarf4-line-1.s
Line Number Statements: + [0x.*] Set File Name to entry 2 in the File Name Table [0x.*] Extended opcode 2: set Address to 0x0 [0x.*] Advance Line by 81 to 82 [0x.*] Copy - [0x.*] Set File Name to entry 2 in the File Name Table + [0x.*] Set File Name to entry 3 in the File Name Table [0x.*] Advance Line by -73 to 9 [0x.*] Special opcode 19: advance Address by 1 to 0x1 and Line by 0 to 9 [0x.*] Advance PC by 3 to 0x4 diff --git a/gas/testsuite/gas/i386/dwarf5-line-1.d b/gas/testsuite/gas/i386/dwarf5-line-1.d index f57fc47d269..2c2cf5696c4 100644 --- a/gas/testsuite/gas/i386/dwarf5-line-1.d +++ b/gas/testsuite/gas/i386/dwarf5-line-1.d @@ -36,12 +36,14 @@ Raw dump of debug contents of section .z?debug_line: 0 (indirect line string, offset: 0x.*): .*/gas/testsuite 1 (indirect line string, offset: 0x.*): .*/gas/testsuite/gas/i386
- The File Name Table (offset 0x.*, lines 2, columns 3): + The File Name Table (offset 0x.*, lines 3, columns 3): Entry Dir MD5 Name 0 0 0xbbd69fc03ce253b2dbaab2522dd519ae (indirect line string, offset: 0x.*): core.c 1 0 0x0 (indirect line string, offset: 0x.*): types.h + 2 1 0x0 (indirect line string, offset: 0x.*): dwarf5-line-1.s
Line Number Statements: + [0x.*] Set File Name to entry 2 in the File Name Table [0x.*] Extended opcode 2: set Address to 0x0 [0x.*] Special opcode 8: advance Address by 0 to 0x0 and Line by 3 to 4 [0x.*] Advance PC by 1 to 0x1 diff --git a/gas/testsuite/gas/i386/dwarf5-line-2.d b/gas/testsuite/gas/i386/dwarf5-line-2.d index 2f96df510d0..85f98c8ab9c 100644 --- a/gas/testsuite/gas/i386/dwarf5-line-2.d +++ b/gas/testsuite/gas/i386/dwarf5-line-2.d @@ -36,9 +36,10 @@ Raw dump of debug contents of section .z?debug_line: 0 (indirect line string, offset: 0x.*): .*/gas/testsuite 1 (indirect line string, offset: 0x.*): .*/gas/testsuite/gas/i386
- The File Name Table (offset 0x.*, lines 1, columns 3): + The File Name Table (offset 0x.*, lines 2, columns 3): Entry Dir MD5 Name 0 0 0xbbd69fc03ce253b2dbaab2522dd519ae (indirect line string, offset: 0x.*): core.c + 1 1 0x0 (indirect line string, offset: .*): dwarf5-line-2.s
Line Number Statements: [0x.*] Extended opcode 2: set Address to 0x0 </cut>