gdb: fix crash when getting the value of a label symbol
authorAndrew Burgess <aburgess@redhat.com>
Mon, 12 Dec 2022 14:05:22 +0000 (14:05 +0000)
committerAndrew Burgess <aburgess@redhat.com>
Fri, 16 Dec 2022 13:51:08 +0000 (13:51 +0000)
commitc3efaf0afd9d37004c42cdfd3ce0c1bfa979c45e
treee2b3eb1907fa8a3ad718dd0179881bc6d69d3a18
parente60a615dde5d6674a6488b74afe807a775551407
gdb: fix crash when getting the value of a label symbol

When the source program contains a goto label, it turns out it's
actually pretty hard for a user to find out more about that label.
For example:

  (gdb) p some_label
  No symbol "some_label" in current context.
  (gdb) disassemble some_label
  No symbol "some_label" in current context.
  (gdb) x/10i some_label
  No symbol "some_label" in current context.
  (gdb) break some_label
  Breakpoint 2 at 0x401135: file /tmp/py-label-symbol-value.c, line 35.

In all cases, some_label is a goto label within the current frame.
Only placing a breakpoint on the label worked.

This all seems a little strange to me, it feels like asking about a
goto label would not be an unreasonable thing for a user to do.

This commit doesn't fix any of the above issues, I mention them just
to provide a little context for why the following issue has probably
not been seen before.

It turns out there is one way a user can access the symbol for a goto
label, through the Python API:

  python frame = gdb.selected_frame()
  python frame_pc = frame.pc()
  python block = gdb.current_progspace().block_for_pc(frame_pc)
  python symbol,_ = gdb.lookup_symbol('some_label', block, gdb.SYMBOL_LABEL_DOMAIN)
  python print(str(symbol.value()))
  ../../src/gdb/findvar.c:204: internal-error: store_typed_address: Assertion `type->is_pointer_or_reference ()' failed.

The problem is that label symbols are created using the
builtin_core_addr type, which is a pure integer type.

When GDB tries to fetch the value of a label symbol then we end up in
findvar.c, in the function language_defn::read_var_value, in the
LOC_LABEL case.  From here store_typed_address is called to store the
address of the label into a value object with builtin_core_addr type.

The problem is that store_typed_address requires that the destination
type be a pointer or reference, which the builtin_core_addr type is
not.

Now it's not clear what type a goto label address should have, but
GCC has an extension that allows users to take the address of a goto
label (using &&), in that case the result is of type 'void *'.

I propose that when we convert the CORE_ADDR value to a GDB value
object, we use builtin_func_ptr type instead of builtin_core_addr,
this means the result will be of type 'void (*) ()'.  The benefit of
this approach is that when gdbarch_address_to_pointer is called the
target type will be correctly identified as a pointer to code, which
should mean any architecture specific adjustments are done correctly.

We can then cast the new value to 'void *' type with a call to
value_cast_pointer, this should not change the values bit
representation, but will just update the type.

After this asking for the value of a label symbol works just fine:

  (gdb) python print(str(symbol.value()))
  0x401135 <main+35>

And the type is maybe what we'd expect:

  (gdb) python print(str(symbol.value().type))
  void *
gdb/findvar.c
gdb/testsuite/gdb.python/py-label-symbol-value.c [new file with mode: 0644]
gdb/testsuite/gdb.python/py-label-symbol-value.exp [new file with mode: 0644]