* [PATCH] gdb: Reject non-base type operands in typed DWARF expressions
@ 2026-08-05 7:59 Jielun Wu
2026-10-23 18:32 ` Tom Tromey
0 siblings, 1 reply; 2+ messages in thread
From: Jielun Wu @ 2026-08-05 7:59 UTC (permalink / raw)
To: gdb-patches
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
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
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [PATCH] gdb: Reject non-base type operands in typed DWARF expressions
2026-08-05 7:59 [PATCH] gdb: Reject non-base type operands in typed DWARF expressions Jielun Wu
@ 2026-10-23 18:32 ` Tom Tromey
0 siblings, 0 replies; 2+ messages in thread
From: Tom Tromey @ 2026-10-23 18:32 UTC (permalink / raw)
To: Jielun Wu; +Cc: gdb-patches
>>>>> Jielun Wu <firmiana402@gmail.com> writes:
> 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.
Thanks.
> 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.
I wonder whether this is truly worth checking; or at least whether it is
worth checking in this way.
> +/* 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);
This re-reads all the DIEs, which may be expensive. But the only reason
this would be needed is to check a DWARF constraint.
It doesn't really matter, I think, if gdb accepts a "reasonable"
expression that isn't technically correct according to DWARF. gdb does
similar things in many places already, there are a bunch of supported
DWARF extensions.
Now, at the same time, we may not want to allow any old type to be
returned. But this could be done by looking for "base-like" types --
basically scalars of various kinds -- and rejecting others.
Full checking of this kind of thing could be done in a dwarflint tool,
should that ever end up being real.
> + _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
See that other patch, a handler should be written for this.
Tom
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-23 18:33 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-05 7:59 [PATCH] gdb: Reject non-base type operands in typed DWARF expressions Jielun Wu
2026-10-23 18:32 ` Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox