This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch] Fix crash on empty DWARF expressions NULL DATA vs. zero SIZE
- From: Jan Kratochvil <jan dot kratochvil at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Wed, 13 Jul 2011 18:04:35 +0200
- Subject: [patch] Fix crash on empty DWARF expressions NULL DATA vs. zero SIZE
Hi,
GDB could crash as shown in the testcase.
#1 0x0000000000750274 in dwarf_expr_eval (ctx=0x4175ce0, addr=0x0, len=4796440) at dwarf2expr.c:365
^^^
Indication of empty (<optimized out>) or otherwise invalid DWARF expressions
some code expects to be NULL address, some code expects it to be zero size and
another code checks for either NULL address or zero size. And some code
creates them just with zero size (and non-NULL address), other code creates
them with NULL address and undefined (=non-zero) size; some code creates them
with both NULL address and zero size.
I found safer indicator to be zero size, therefore unified to code on this
indicator. Removed address clearing as redundant and confusing now.
No regressions on {x86_64,x86_64-m32,i686}-fedora15-linux-gnu.
Thanks,
Jan
gdb/
2011-07-13 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix empty DWARF expressions DATA vs. SIZE conditionals.
* dwarf2loc.c (dwarf2_find_location_expression): Clear *LOCEXPR_LENGTH.
(dwarf_expr_frame_base_1): Indicate unavailability via zero *LENGTH.
(locexpr_tracepoint_var_ref): Check only zero SIZE, not zero DATA.
(loclist_read_variable, loclist_tracepoint_var_ref): Do not check for
zero DATA.
* dwarf2loc.h (struct dwarf2_locexpr_baton): Comment DATA vs. SIZE
validity.
* dwarf2read.c (struct dwarf_block): Comment DATA validity.
(dwarf2_fetch_die_location_block, dwarf2_symbol_mark_computed): Do not
clear DATA on zero SIZE.
gdb/testsuite/
2011-07-13 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix empty DWARF expressions DATA vs. SIZE conditionals.
* gdb.dwarf2/dw2-op-call.S (arraycallnoloc, arraynoloc): New DIEs.
(loclist): New.
(4): New abbrev.
* gdb.dwarf2/dw2-op-call.exp: Remove variable srcfile and executable.
Use prepare_for_testing, remove clean_restart.
(p arraynoloc, p arraycallnoloc): New tests.
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -109,7 +109,10 @@ dwarf2_find_location_expression (struct dwarf2_loclist_baton *baton,
/* An end-of-list entry. */
if (low == 0 && high == 0)
- return NULL;
+ {
+ *locexpr_length = 0;
+ return NULL;
+ }
/* Otherwise, a location expression entry. */
low += base_address;
@@ -194,7 +197,7 @@ dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc,
const gdb_byte **start, size_t *length)
{
if (SYMBOL_LOCATION_BATON (framefunc) == NULL)
- *start = NULL;
+ *length = 0;
else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_loclist_funcs)
{
struct dwarf2_loclist_baton *symbaton;
@@ -213,10 +216,10 @@ dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc,
*start = symbaton->data;
}
else
- *start = NULL;
+ *length = 0;
}
- if (*start == NULL)
+ if (*length == 0)
error (_("Could not find the frame base for \"%s\"."),
SYMBOL_NATURAL_NAME (framefunc));
}
@@ -2788,7 +2791,7 @@ locexpr_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
- if (dlbaton->data == NULL || dlbaton->size == 0)
+ if (dlbaton->size == 0)
value->optimized_out = 1;
else
dwarf2_compile_expr_to_ax (ax, value, gdbarch, addr_size,
@@ -2821,11 +2824,8 @@ loclist_read_variable (struct symbol *symbol, struct frame_info *frame)
CORE_ADDR pc = frame ? get_frame_address_in_block (frame) : 0;
data = dwarf2_find_location_expression (dlbaton, &size, pc);
- if (data == NULL)
- val = allocate_optimized_out_value (SYMBOL_TYPE (symbol));
- else
- val = dwarf2_evaluate_loc_desc (SYMBOL_TYPE (symbol), frame, data, size,
- dlbaton->per_cu);
+ val = dwarf2_evaluate_loc_desc (SYMBOL_TYPE (symbol), frame, data, size,
+ dlbaton->per_cu);
return val;
}
@@ -2938,7 +2938,7 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
data = dwarf2_find_location_expression (dlbaton, &size, ax->scope);
- if (data == NULL || size == 0)
+ if (size == 0)
value->optimized_out = 1;
else
dwarf2_compile_expr_to_ax (ax, value, gdbarch, addr_size, data, data + size,
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -80,10 +80,12 @@ struct value *dwarf2_evaluate_loc_desc (struct type *type,
struct dwarf2_locexpr_baton
{
- /* Pointer to the start of the location expression. */
+ /* Pointer to the start of the location expression. Valid only if SIZE is
+ not zero. */
const gdb_byte *data;
- /* Length of the location expression. */
+ /* Length of the location expression. For optimized out expressions it is
+ zero. */
unsigned long size;
/* The compilation unit containing the symbol whose location
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -712,6 +712,8 @@ struct function_range
struct dwarf_block
{
unsigned int size;
+
+ /* Valid only if SIZE is not zero. */
gdb_byte *data;
};
@@ -13838,7 +13840,6 @@ dwarf2_fetch_die_location_block (unsigned int offset,
{
/* DWARF: "If there is no such attribute, then there is no effect.". */
- retval.data = NULL;
retval.size = 0;
}
else if (attr_form_is_section_offset (attr))
@@ -14970,7 +14971,6 @@ dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
dwarf2_invalid_attrib_class_complaint ("location description",
SYMBOL_NATURAL_NAME (sym));
baton->size = 0;
- baton->data = NULL;
}
SYMBOL_COMPUTED_OPS (sym) = &dwarf2_locexpr_funcs;
--- a/gdb/testsuite/gdb.dwarf2/dw2-op-call.S
+++ b/gdb/testsuite/gdb.dwarf2/dw2-op-call.S
@@ -72,10 +72,30 @@ array3: .2byte 3
.uleb128 array3-array1 /* <uconst> */
2:
+ .uleb128 3 /* Abbrev: DW_TAG_variable */
+ .ascii "arraycallnoloc\0" /* DW_AT_name */
+ .4byte .L2byte_type-.Lcu1_begin /* DW_AT_type */
+ .byte 2f - 1f /* DW_AT_location */
+1: .byte 0x99 /* DW_OP_call4 */
+ .4byte .Larraynoloc-.Lcu1_begin /* <current CU offset> */
+2:
+
+.Larraynoloc:
+ .uleb128 4 /* Abbrev: DW_TAG_variable-loclist */
+ .ascii "arraynoloc\0" /* DW_AT_name */
+ .4byte .L2byte_type-.Lcu1_begin /* DW_AT_type */
+ .4byte loclist /* DW_AT_location */
+
.byte 0 /* End of children of CU */
.Lcu1_end:
+/* Location list. */
+ .section .debug_loc
+loclist:
+ /* Location list end. */
+ .4byte 0, 0
+
/* Abbrev table */
.section .debug_abbrev
.Labbrev1_begin:
@@ -115,5 +135,17 @@ array3: .2byte 3
.byte 0x0 /* Terminator */
.byte 0x0 /* Terminator */
+ .uleb128 4 /* Abbrev code */
+ .uleb128 0x34 /* DW_TAG_variable-loclist */
+ .byte 0 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x2 /* DW_AT_location */
+ .uleb128 0x06 /* DW_FORM_data4 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
.byte 0x0 /* Terminator */
.byte 0x0 /* Terminator */
--- a/gdb/testsuite/gdb.dwarf2/dw2-op-call.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-op-call.exp
@@ -22,15 +22,17 @@ if {![dwarf2_support]} {
}
set testfile "dw2-op-call"
-set srcfile ${testfile}.S
-set executable ${testfile}.x
-
-if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objdir}/${subdir}/${executable}" object {nodebug}] != "" } {
+if { [prepare_for_testing ${testfile}.exp ${testfile} [list ${testfile}.S main.c] {nodebug}] } {
return -1
}
-clean_restart $executable
-
gdb_test "p array1" " = 1"
gdb_test "p array2" " = 2" "array2 using DW_OP_call2"
gdb_test "p array3" " = 3" "array3 using DW_OP_call4"
+
+# Location lists need PC.
+if ![runto_main] {
+ return -1
+}
+gdb_test "p arraynoloc" " = <optimized out>"
+gdb_test "p arraycallnoloc" {Asked for position 0 of stack, stack only has 0 elements on it\.}