[PATCH] gdb: Reject non-base type operands in typed DWARF expressions
Jielun Wu <[email protected]> Wed, 5 Aug 2026 15:59:33 +0800
| Newsgroups | gmane.comp.gdb.patches |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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 diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c index 3a6b8f58199..3fd7672bb2f 100644 --- a/gdb/dwarf2/expr.c +++ b/gdb/dwarf2/expr.c @@ -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. */ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index ca475f53745..3571f407a53 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -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 diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index 15dd2abf3a1..ea43ada9d2f 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -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 diff --git a/gdb/testsuite/gdb.dwarf2/dw2-typed-op-invalid-type.exp b/gdb/testsuite/gdb.dwarf2/dw2-typed-op-invalid-type.exp new file mode 100644 index 00000000000..cc147b98eca --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-typed-op-invalid-type.exp @@ -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 -- 2.34.1