gdb: handle invalid DWARF when compilation unit is missing
authorAndrew Burgess <andrew.burgess@embecosm.com>
Wed, 17 Mar 2021 16:48:25 +0000 (16:48 +0000)
committerAndrew Burgess <andrew.burgess@embecosm.com>
Mon, 22 Mar 2021 14:34:53 +0000 (14:34 +0000)
Replace an abort call in process_psymtab_comp_unit with a real error,
and add a test to cover this case.  The case is question is when badly
formed DWARF is missing a DW_TAG_compile_unit, DW_TAG_partial_unit, or
DW_TAG_type_unit as its top level tag.

I then tested with --target_board=readnow and added additional code to
also validate the top-level tag in this case.

I added an assert that would trigger for the readnow case before I
added the fix.  I suspect there's lots of places where badly formed
DWARF could result in the builder being nullptr when it shouldn't be,
but I only added this one assert, as this is the one that would have
helped me in this case.

gdb/ChangeLog:

* dwarf2/read.c (process_psymtab_comp_unit): Replace abort with an
error.
(process_full_comp_unit): Validate the top-level tag before
processing the first DIE.
(read_func_scope): Ensure we have a valid builder.

gdb/testsuite/ChangeLog:

* gdb.dwarf2/dw2-missing-cu-tag.c: New file.
* gdb.dwarf2/dw2-missing-cu-tag.exp: New file.

gdb/ChangeLog
gdb/dwarf2/read.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.dwarf2/dw2-missing-cu-tag.c [new file with mode: 0644]
gdb/testsuite/gdb.dwarf2/dw2-missing-cu-tag.exp [new file with mode: 0644]

index f3e7f3f8c594b30c24d99c36ae6f2b6587f0b202..1e076546c14b32c9df79f29578638a491e81da86 100644 (file)
@@ -1,3 +1,11 @@
+2021-03-22  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * dwarf2/read.c (process_psymtab_comp_unit): Replace abort with an
+       error.
+       (process_full_comp_unit): Validate the top-level tag before
+       processing the first DIE.
+       (read_func_scope): Ensure we have a valid builder.
+
 2021-03-22  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * objc-lang.c (objc_demangle): Renamed to
index acbc5fa1ad15e196598b231a6c9897e3b3639194..2bfb13d6d0ea14e81703d57e8af73d69e59c7e59 100644 (file)
@@ -7737,7 +7737,10 @@ process_psymtab_comp_unit (dwarf2_per_cu_data *this_cu,
       this_cu->unit_type = DW_UT_type;
       break;
     default:
-      abort ();
+      error (_("Dwarf Error: unexpected tag '%s' at offset %s [in module %s]"),
+            dwarf_tag_name (reader.comp_unit_die->tag),
+            sect_offset_str (reader.cu->per_cu->sect_off),
+            objfile_name (per_objfile->objfile));
     }
 
   if (reader.dummy_p)
@@ -9994,6 +9997,21 @@ process_full_comp_unit (dwarf2_cu *cu, enum language pretend_language)
 
   dwarf2_find_base_address (cu->dies, cu);
 
+  /* Before we start reading the top-level DIE, ensure it has a valid tag
+     type.  */
+  switch (cu->dies->tag)
+    {
+    case DW_TAG_compile_unit:
+    case DW_TAG_partial_unit:
+    case DW_TAG_type_unit:
+      break;
+    default:
+      error (_("Dwarf Error: unexpected tag '%s' at offset %s [in module %s]"),
+            dwarf_tag_name (cu->dies->tag),
+            sect_offset_str (cu->per_cu->sect_off),
+            objfile_name (per_objfile->objfile));
+    }
+
   /* Do line number decoding in read_file_scope () */
   process_die (cu->dies, cu);
 
@@ -13628,6 +13646,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
        }
     }
 
+  gdb_assert (cu->get_builder () != nullptr);
   newobj = cu->get_builder ()->push_context (0, lowpc);
   newobj->name = new_symbol (die, read_type_die (die, cu), cu,
                             (struct symbol *) templ_func);
index cb5dc81578cd70e65a1d09133e980711ad72e55a..848e089db4fff0b620dba22725cff8bce4306db5 100644 (file)
@@ -1,3 +1,8 @@
+2021-03-22  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * gdb.dwarf2/dw2-missing-cu-tag.c: New file.
+       * gdb.dwarf2/dw2-missing-cu-tag.exp: New file.
+
 2021-03-22  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * gdb.dwarf2/dw2-using-debug-str.c: New file.
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-missing-cu-tag.c b/gdb/testsuite/gdb.dwarf2/dw2-missing-cu-tag.c
new file mode 100644 (file)
index 0000000..a361f59
--- /dev/null
@@ -0,0 +1,25 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2021 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+int
+main (int argc, char **argv)
+{
+  asm ("main_label: .globl main_label");
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-missing-cu-tag.exp b/gdb/testsuite/gdb.dwarf2/dw2-missing-cu-tag.exp
new file mode 100644 (file)
index 0000000..8a11d1d
--- /dev/null
@@ -0,0 +1,76 @@
+# Copyright 2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This test creates some invalid DWARF, compiles this into an
+# executable, then tries to load the executable using the 'file'
+# command.  We expect to see an error from the DWARF parser.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use
+# gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+standard_testfile .c -dw.S
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    cu {} {
+       # We should have either one of DW_TAG_compile_unit,
+       # DW_TAG_partial_unit, or DW_TAG_type_unit here.
+       subprogram {
+           {external 1 flag}
+           {MACRO_AT_func {main}}
+       }
+    }
+}
+
+# Don't use prepare_for_testing here as we want to manually run the
+# file command (so we can check its output).
+if {[build_executable "failed to build executable" $testfile \
+        [list $srcfile $asm_file] {nodebug quiet}]} {
+    return -1
+}
+
+# Restart with no executable.
+clean_restart
+
+# This pattern is hit when GDB does not use -readnow (i.e. the default
+# behaviour).
+set pattern1 \
+    [multi_line \
+        "Reading symbols from \[^\r\n\]+" \
+        "Dwarf Error: unexpected tag 'DW_TAG_subprogram' at offset $hex \\\[\[^\r\n\]+\\\]" \
+        "\\(No debugging symbols \[^\r\n\]+\\)"]
+
+# This pattern is hit when GDB does use -readnow (e.g. running with
+# --target_board=readnow).
+set pattern2 \
+    [multi_line \
+        "Reading symbols from \[^\r\n\]+" \
+        "Expanding full symbols from \[^\r\n\]+" \
+        "Dwarf Error: unexpected tag 'DW_TAG_subprogram' at offset $hex \\\[\[^\r\n\]+\\\]"]
+
+# Load the executable, we expect an error from the DWARF parser.
+gdb_test_multiple "file $binfile" "file $testfile" {
+    -wrap -re $pattern1 {
+       pass $gdb_test_name
+    }
+    -re -wrap "$pattern2" {
+       pass $gdb_test_name
+    }
+}