Skip to content

gdb needs to know what traits a type implements #33014

Open

Description

@tromey

I'd like to make operator overloading work for Rust in gdb. That is, I'd like something like print x+y to call the appropriate method on the Add trait. I'd also like to make ordinary method calls work, where the method is defined in some trait that is impl'd for the concrete type of the object.

Right now I think this can't be done. There is no information in the debug info about what traits are implemented by a type.

Consider:

pub trait What {
    fn what(&self);
}

impl What for i32 {
    fn what(&self) {
        println!("{}", self);
    }
}

fn main() {
    let v = 23;
    let x = &v as &What;

    x.what();
    ()
}

Here i32 is described as just a base type:

 <1><5e7>: Abbrev Number: 16 (DW_TAG_base_type)
    <5e8>   DW_AT_name        : (indirect string, offset: 0x46a): i32
    <5ec>   DW_AT_encoding    : 5   (signed)
    <5ed>   DW_AT_byte_size   : 4

I think this might be a good spot to list all the impl'd traits. Perhaps they can be represented as DWARF interfaces; or maybe some Rust extension to DWARF would be preferable.

i32.What is emitted as a namespace:

 <2><2f>: Abbrev Number: 2 (DW_TAG_namespace)
    <30>   DW_AT_name        : (indirect string, offset: 0x48): i32.What

... but this isn't directly useful as it would require an iteration over all the namespace DIEs looking for matches. Maybe I could do this; but I'd rather not as it is very inefficient.

Activity

  1. tromey commented on Apr 18, 2016

    @tromey
    ContributorAuthor

    It occurred to me later that for operator overloading, I could perhaps just compute the method name directly in gdb. For example, impl Add for S might result in a method crate::S.Add::add.

    However, there doesn't seem to be a way to tell whether this is std::ops::Add or some other trait that happens to have the same name. For this, rustc would have to emit some extra debuginfo.

    I think it is still necessary to have information about traits attached to types, for other calls via traits.

  2. added
    A-debuginfoArea: Debugging information in compiled programs (DWARF, PDB, etc.)
    on Apr 19, 2016
  3. added
    C-enhancementCategory: An issue proposing an enhancement or a PR with one.
    C-bugCategory: This is a bug.
    C-feature-requestCategory: A feature request, i.e: not implemented / a PR.
    and removed
    C-enhancementCategory: An issue proposing an enhancement or a PR with one.
    C-bugCategory: This is a bug.
    on Jul 25, 2017
  4. tromey commented on Jan 11, 2019

    @tromey
    ContributorAuthor

    I thought I would write up a plan here; I probably am going to stop working on this, but this can serve as a guide to anyone picking it up in the future.

    The basic idea is to represent a concrete impl of a trait for some type using the existing DW_TAG_interface_type (and not namespace as is curently done). This would then be attached to the type using DW_TAG_inheritance.

    I started on an LLVM patch here: https://github.com/tromey/llvm/tree/interface-type. However, this patch is incomplete, as it does not allow interfaces to be attached to subroutine types, pointer types, or scalar types. Adding those would require a bigger change. Maybe the cleanest way would be to let the type base class hold any interface types. However, this is a pain due to the way this part of LLVM has been written. So perhaps handling this case-by-case on the concrete subclasses is simpler in practice.

    This approach will also require a small DWARF extension. DWARF 5, section 5.7.3, says:

    A class type or interface type entry that describes a derived, extended or
    implementing class or interface owns debugging information entries describing
    each of the classes or interfaces it is derived from, extending or implementing,
    respectively, ordered as they were in the source program. Each such entry has the
    tag DW_TAG_inheritance.

    This language is specific to class/structure/interface types. However, for Rust, this restriction should be lifted.

    It would make sense to file this as a DWARF issue; however, it may be best to wait until any patches have landed in LLVM first.

  5. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Apr 21, 2020
  6. Grunthos commented on Oct 3, 2024

    @Grunthos

    Not sure why this is a low priority item: I came across it as a result of trying to inspect x.is_some() in RustRover.

    Being able to debug basic variables is kind of a critical feature for any language, I would have thought. Or am I missing something? Is this bug report very narrow and is there another issue relating to the broader requirement to inspect variables in a debugger?

  7. bjorn3 commented on Oct 3, 2024

    @bjorn3
    Member

    This issue is specifically about traits. x.is_some() doesn't use any traits. For x.is_some() maybe is_some was never called on this specific type and thus never codegened?

  8. Grunthos commented on Oct 3, 2024

    @Grunthos

    Thanks for the quick reply:

            if self.parent.is_some() {
                println!("Not an orphan");
            }
            // Break point on next IF statement
            if let Some(parent) = &self.parent {
    

    Examining self.parent.is_some() results in the error.

  9. lquinn2015 commented on Dec 13, 2024

    @lquinn2015

    Even something like this seems really difficult consider it figure out how to pretty print the vector but doesn't yield a way to dig deeper in that data structure which might be very important

    Image

    I've also tried things like p s.1.buf but the raw string data really complicates stuff

  10. tromey commented on Dec 17, 2024

    @tromey
    ContributorAuthor

    Not sure why this is a low priority item: I came across it as a result of trying to inspect x.is_some() in RustRover.

    This one seems to just be a gdb bug. I filed https://sourceware.org/bugzilla/show_bug.cgi?id=32471

  11. tromey commented on Jan 18, 2025

    @tromey
    ContributorAuthor

    Maybe the cleanest way would be to let the type base class hold any interface types

    I've been working on LLVM again and I had another idea here. Rather than attaching interfaces to DIType base class, it might be less invasive to come up with a kind of DIInterfaces wrapper class that holds a base type and a bunch of interfaces. Then Rust variables and whatnot would use one of these as its type; and it would handle annotating the underlying type with interface info.

  12. tromey commented on Nov 20, 2025

    @tromey
    ContributorAuthor

    Maybe the cleanest way would be to let the type base class hold any interface types

    I've been working on LLVM again and I had another idea here. Rather than attaching interfaces to DIType base class, it might be less invasive to come up with a kind of DIInterfaces wrapper class that holds a base type and a bunch of interfaces. Then Rust variables and whatnot would use one of these as its type; and it would handle annotating the underlying type with interface info.

    I have a decent chunk of this LLVM patch written but now I wonder if this information is even available in MIR.

  13. bjorn3 commented on Nov 20, 2025

    @bjorn3
    Member

    When emitting debuginfo it should be possible to get a list of traits that a type implements from the local perspective, but I think it would be slow (iterating over all trait impls and trying if they match. may be optimized a bit to not look at every impl, but we did definitively have to look at every blanket impl) and it would only be from the local perspective. A downstream crate may be adding new impls for a type that the upstream crate can't know about when generating debuginfo.

  14. tromey commented on Nov 20, 2025

    @tromey
    ContributorAuthor

    When emitting debuginfo it should be possible to get a list of traits that a type implements from the local perspective, but I think it would be slow (iterating over all trait impls and trying if they match. may be optimized a bit to not look at every impl, but we did definitively have to look at every blanket impl) and it would only be from the local perspective.

    Thanks. I haven't really looked at the rustc side at all yet, I'll try to dig around for this.

    A downstream crate may be adding new impls for a type that the upstream crate can't know about when generating debuginfo.

    It's fine for types to be different in different DWARF compilation units. The main thing is if we can see all the relevant traits for the current CU.

  15. xlambein commented on Oct 28, 2026

    @xlambein

    @tromey What's the status on this? If no-one is actively working on trait support for gdb, I'm interested to pick up the work.

  16. tromey commented on Oct 28, 2026

    @tromey
    ContributorAuthor

    23. @tromey What's the status on this? If no-one is actively working on trait support for gdb, I'm interested to pick up the work.

    It's been a while since I looked at this.

    One thing to check is whether my complaint about inefficiency in the original report is even correct. Perhaps traits can already be meaningfully discovered by the debugger with some work.

    I like to think I was correct there, though. So then assuming the interface plan is the way to go, you can see my WIP LLVM branch: https://github.com/tromey/llvm-project/tree/rust-debug-interface. This is very incomplete, needs rebasing, does not compile, etc. Anyway the basic change there is that there's a new DIInterfaceHoldingType that wraps a type and also holds a list of interface types implemented by the wrapped type. The idea is that then the Rust compiler would use such a wrapper as the types for variables and such; and the LLVM DWARF writer would "invert" the relationship: write the wrapped type with a series of DW_AT_inheritance attributes attached. This would necessarily be a DWARF extension as DWARF doesn't allow this for base types, etc.

    After this work is complete -- but before submitting the LLVM patch upstream -- you'd have to change rustc to emit the resulting information. When working like this in the past, I also made the required gdb changes at this step, to ensure that everything worked end-to-end, but you may be able to get by with just the compiler and visual inspection of the DWARF.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-debuginfoArea: Debugging information in compiled programs (DWARF, PDB, etc.)A-trait-systemArea: Trait systemC-feature-requestCategory: A feature request, i.e: not implemented / a PR.P-lowLow priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions