gdb: Reject non-base type operands in typed DWARF expressions
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_gdb_build--master-arm |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_gdb_check--master-arm |
success
|
Test passed
|
| linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 |
success
|
Test passed
|
Commit Message
DWARF typed expression operators require a type operand that names a
DW_TAG_base_type DIE. This applies to DW_OP_const_type,
DW_OP_regval_type, DW_OP_deref_type, and the nonzero type operands of
DW_OP_convert and DW_OP_reinterpret.
dwarf_expr_context::get_base_type documents that contract, but its
implementation accepted any DIE that resolved to a GDB type. As a
result, typed expression operators could accept non-base DIEs such as
DW_TAG_structure_type.
Add dwarf2_get_base_type to resolve the referenced DIE, reject invalid or
non-base DIEs, and return the corresponding base type. Use it from the
DWARF expression evaluator.
Add a DWARF assembler test covering DW_OP_const_type with a
DW_TAG_structure_type type operand.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34375
Signed-off-by: Jielun Wu <firmiana402@gmail.com>
---
gdb/dwarf2/expr.c | 9 +-
gdb/dwarf2/read.c | 38 ++++++++
gdb/dwarf2/read.h | 8 ++
.../gdb.dwarf2/dw2-typed-op-invalid-type.exp | 89 +++++++++++++++++++
4 files changed, 137 insertions(+), 7 deletions(-)
create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-typed-op-invalid-type.exp
@@ -857,13 +857,8 @@ dwarf_expr_context::get_base_type (cu_offset die_cu_off)
if (this->m_per_cu == nullptr)
return builtin_type (this->m_per_objfile->objfile->arch ())->builtin_int;
- struct type *result = dwarf2_get_die_type (die_cu_off, this->m_per_cu,
- this->m_per_objfile);
-
- if (result == nullptr)
- error (_("Could not find type for operation"));
-
- return result;
+ return dwarf2_get_base_type (die_cu_off, this->m_per_cu,
+ this->m_per_objfile);
}
/* See expr.h. */
@@ -17146,6 +17146,44 @@ dwarf2_get_die_type (cu_offset die_offset, dwarf2_per_cu *per_cu,
return get_die_type_at_offset (die_offset_sect, per_cu, per_objfile);
}
+/* See read.h. */
+
+struct type *
+dwarf2_get_base_type (cu_offset die_offset, dwarf2_per_cu *per_cu,
+ dwarf2_per_objfile *per_objfile)
+{
+ dwarf2_cu *cu = per_objfile->get_cu (per_cu);
+ if (cu == nullptr)
+ cu = load_cu (per_cu, per_objfile, false);
+
+ /* A dummy CU has no DIE tree to inspect. This helper needs a real CU
+ to validate the referenced DIE's tag. */
+ gdb_assert (cu != nullptr);
+
+ sect_offset sect_off = cu->section_offset () + to_underlying (die_offset);
+ if (!cu->header.offset_in_unit_p (sect_off))
+ error (_(DWARF_ERROR_PREFIX
+ "DIE at %s referenced by typed DWARF expression operation is "
+ "outside the current CU in module %s"),
+ sect_offset_str (sect_off), objfile_name (per_objfile->objfile));
+
+ die_info *die = follow_die_offset ({ &cu->section (), sect_off }, &cu);
+ if (die == nullptr)
+ error (_(DWARF_ERROR_PREFIX
+ "Cannot find DIE at %s referenced by typed DWARF expression "
+ "operation in module %s"),
+ sect_offset_str (sect_off), objfile_name (per_objfile->objfile));
+
+ if (die->tag != DW_TAG_base_type)
+ error (_(DWARF_ERROR_PREFIX
+ "DIE at %s referenced by typed DWARF expression operation has "
+ "tag '%s', not DW_TAG_base_type in module %s"),
+ sect_offset_str (sect_off), dwarf_tag_name (die->tag),
+ objfile_name (per_objfile->objfile));
+
+ return read_type_die (die, cu);
+}
+
/* Fill in the missing details in SIG_TYPE from DWO_FILE.
Error out if there isn't a type unit with the appropriate signature in
@@ -1202,6 +1202,14 @@ dwarf2_per_objfile *get_dwarf2_per_objfile (struct objfile *objfile);
struct type *dwarf2_get_die_type (cu_offset die_offset, dwarf2_per_cu *per_cu,
dwarf2_per_objfile *per_objfile);
+/* Return the type of the DW_TAG_base_type DIE at DIE_OFFSET in the CU
+ named by PER_CU. Throw an exception if the DIE is invalid or does
+ not represent a base type. */
+
+struct type *dwarf2_get_base_type (cu_offset die_offset,
+ dwarf2_per_cu *per_cu,
+ dwarf2_per_objfile *per_objfile);
+
/* Given an index in .debug_addr, fetch the value.
NOTE: This can be called during dwarf expression evaluation,
long after the debug information has been read, and thus per_cu->cu
new file mode 100644
@@ -0,0 +1,89 @@
+# Copyright 2026 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/>.
+
+# Test that typed DWARF expression operations reject type operands that
+# do not reference a DW_TAG_base_type DIE.
+
+load_lib dwarf.exp
+
+require dwarf2_support
+
+standard_testfile main.c -dw.S
+
+set asm_file [standard_output_file $srcfile2]
+
+Dwarf::assemble $asm_file {
+ cu {} {
+ compile_unit {} {
+ declare_labels int_label struct_label
+
+ int_label: base_type {
+ DW_AT_name "int"
+ DW_AT_encoding @DW_ATE_signed
+ DW_AT_byte_size 4 DW_FORM_sdata
+ }
+
+ struct_label: structure_type {
+ DW_AT_name "not_a_base_type"
+ DW_AT_byte_size 4 DW_FORM_sdata
+ } {
+ member {
+ DW_AT_name "field"
+ DW_AT_type :$int_label
+ DW_AT_data_member_location 0 DW_FORM_sdata
+ }
+ }
+
+ DW_TAG_variable {
+ DW_AT_name "bad_struct_const"
+ DW_AT_type :$struct_label
+ DW_AT_external 1 DW_FORM_flag
+ DW_AT_location {
+ variable _constants
+ variable _cu_label
+
+ _op .byte $_constants(DW_OP_const_type)
+ _op .uleb128 "$struct_label - $_cu_label"
+ _op .byte 4
+ _op .byte 1
+ _op .byte 2
+ _op .byte 3
+ _op .byte 4
+ DW_OP_stack_value
+ } SPECIAL_expr
+ }
+ }
+ }
+}
+
+if {[build_executable ${testfile}.exp ${testfile} \
+ [list $srcfile $asm_file] {nodebug}]} {
+ return
+}
+
+clean_restart ${testfile}
+
+if {![runto_main]} {
+ return
+}
+
+set base_type_error \
+ "DWARF Error: DIE at $hex referenced by typed DWARF "
+append base_type_error \
+ "expression operation has tag 'DW_TAG_structure_type', not "
+append base_type_error \
+ "DW_TAG_base_type .*"
+
+gdb_test "print bad_struct_const" $base_type_error