This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: problem with DW_OP_GNU_deref_type and dwarf's get_base_type callback


Hello,

I am investigating an issue we're seeing with GCC 4.7 where the compiler
produces a DW_OP_GNU_deref_type like this:

        .byte   0x5     # DW_AT_GNU_call_site_value
        .byte   0x91    # DW_OP_fbreg
        .sleb128 0
        .byte   0xf6    # DW_OP_GNU_deref_type
        .byte   0x4
        .uleb128 0x25

This is what we get when GDB tries to print the parameter value's
at entry:

    file_1.export_1 (param_1=99.0, param_1@entry=<error reading variable: Could not find type for DW_OP_GNU_const_type>, str=...) at file_1.adb:3

I think I tracked the problem down, but I am unsure of where the problem
should be fixed. So, here's what happens:

GDB finds the DW_OP_GNU_deref_type operand, and starts evaluating it.
This is in dwarf2expr.c:

        case DW_OP_GNU_deref_type:
          {
            [...]
            if (op == DW_OP_GNU_deref_type)
              {
                op_ptr = read_uleb128 (op_ptr, op_end, &type_die);
                type = dwarf_get_base_type (ctx, type_die, 0);
              }

Here, read_uleb128 returns 0x25, as expected, and the associated
die should be:

        .uleb128 0x2    # (DIE (0x25) DW_TAG_base_type)
        .byte   0x4     # DW_AT_byte_size
        .byte   0x4     # DW_AT_encoding
        .long   .LASF3  # DW_AT_name: "FLOAT_32"

However, dwarf_get_base_type fails to find it, and it's fairly easy
to figure out why: dwarf_get_base_type just calls ctx->funcs->get_base_type,
which is dwarf_expr_get_base_type. And the latter is merely a wrapper
around dwarf2_get_die_type:

> static struct type *
> dwarf_expr_get_base_type (struct dwarf_expr_context *ctx, size_t die_offset)
> {
>   struct dwarf_expr_baton *debaton = ctx->baton;
>
>   return dwarf2_get_die_type (die_offset, debaton->per_cu);
> }

And dwarf2_get_die_type (through get_die_type_at_offset) try to locate
the DIE by searching through the debug_types_type_hash by using that
same offset (0x25).

However, 0x25 is the offset within the unit, whereas the DIE was actually
inserted using the absolute offset. So the lookup fails.

First of all, I am a little surprised that an error like this would
have slipped in, and I am really wondering whether I might be missing
something. I looked at http://www.dwarfstd.org/doc/040408.1.html, to
see if maybe the offset was supposed to be relocated, but it does not
appear to be the case, the text is very explicit with the fact that
the value should be an offset to the start of the CU.

The fix seems relatively simple: Add the CU's offset to the deref's
offset. But where should this be done? There are several places:

  (1) when calling dwarf_get_base_type (making dwarf_get_base_type
      require an absolute offset rather than a relative one)

  (2) Inside dwarf_get_base_type, when calling ctx->funcs->get_base_type;
      The description of that callback is unclear as to whether the
      offset is expected to be absolute or not

  (3) Inside dwarf_expr_get_base_type, when calling dwarf2_get_die_type
      (dwarf_expr_get_base_type is the ctx->funcs->get_base_type callback);

  (4) Inside dwarf2_get_die_type, when calling get_die_type_at_offset

As unbelievable as option (4) might seem (this is an exported routine
from dwarf2read.c), it almost seems like the correct one. The function's
description reads:

> /* Return the type of the DIE at DIE_OFFSET in the CU named by
>    PER_CU.  */
>
> struct type *
> dwarf2_get_die_type (unsigned int die_offset,
>                      struct dwarf2_per_cu_data *per_cu)

It seems to me that DIE_OFFSET is expected to be a relative offset.
I've audited the uses of that function, and it is used exclusively
in dwarf2loc.c, either by dwarf_expr_get_base_type, or by
disassemble_dwarf_expression, when disassembling various DW_OP_GNU_*
operands, including our DW_OP_GNU_deref_type operand. And I also
checked dwarf_expr_get_base_type, and it's only used to get the base
type of the same DW_OP_GNU_* operands.

I tested the change, and lo and behold, on x86_64-linux, I get the
following fixes:

* gdb.arch:
+------------+------------+----------------------------------------------------+
|       FAIL | PASS       | amd64-entry-value.exp: entry: bt                   |
|       FAIL | PASS       | amd64-entry-value.exp: entry: p j                  |
|       FAIL | PASS       | amd64-entry-value.exp: entry: p j@entry            |
|       FAIL | PASS       | amd64-entry-value.exp: entry_stack: bt at entry    |
|       FAIL | PASS       | amd64-entry-value.exp: entry_stack: bt             |
|       FAIL | PASS       | amd64-entry-value.exp: entry_stack: p d9@entry     |
|       FAIL | PASS       | amd64-entry-value.exp: entry_stack: p da@entry     |
|       FAIL | PASS       | amd64-entry-value.exp: tailcall: bt                |
|       FAIL | PASS       | amd64-entry-value.exp: tailcall: p j               |
|       FAIL | PASS       | amd64-entry-value.exp: tailcall: p j@entry         |
+------------+------------+----------------------------------------------------+

(and it also fixes my problem).  Thoughts?

gdb/ChangeLog:

        * dwarf2read.c (dwarf2_get_die_type): Pass absolute offset
        in call to get_die_type_at_offset.

Thanks,
-- 
Joel
>From f074ef5b5e92d638e46a9e55c6b52a89ebe80141 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Mon, 5 Mar 2012 14:25:41 -0800
Subject: [PATCH] Pass absolute die offset in call to get_die_type_at_offset

gdb/ChangeLog:

        * dwarf2read.c (dwarf2_get_die_type): Pass absolute offset
        in call to get_die_type_at_offset.
---
 gdb/dwarf2read.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 3fa28b1..307d98e 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -14269,7 +14269,7 @@ dwarf2_get_die_type (unsigned int die_offset,
 		     struct dwarf2_per_cu_data *per_cu)
 {
   dw2_setup (per_cu->objfile);
-  return get_die_type_at_offset (die_offset, per_cu);
+  return get_die_type_at_offset (per_cu->offset + die_offset, per_cu);
 }
 
 /* Follow the signature attribute ATTR in SRC_DIE.
-- 
1.7.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]