Repository navigation
Description
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
tromey commentedon Apr 18, 2016
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 Smight result in a methodcrate::S.Add::add.However, there doesn't seem to be a way to tell whether this is
std::ops::Addor 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.
tromey commentedon Jan 11, 2019
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
implof a trait for some type using the existingDW_TAG_interface_type(and not namespace as is curently done). This would then be attached to the type usingDW_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:
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.
Grunthos commentedon Oct 3, 2024
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?
bjorn3 commentedon Oct 3, 2024
This issue is specifically about traits.
x.is_some()doesn't use any traits. Forx.is_some()maybeis_somewas never called on this specific type and thus never codegened?Grunthos commentedon Oct 3, 2024
Thanks for the quick reply:
Examining self.parent.is_some() results in the error.
lquinn2015 commentedon Dec 13, 2024
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
I've also tried things like p s.1.buf but the raw string data really complicates stuff
tromey commentedon Dec 17, 2024
This one seems to just be a gdb bug. I filed https://sourceware.org/bugzilla/show_bug.cgi?id=32471
tromey commentedon Jan 18, 2025
I've been working on LLVM again and I had another idea here. Rather than attaching interfaces to
DITypebase class, it might be less invasive to come up with a kind ofDIInterfaceswrapper 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.tromey commentedon Nov 20, 2025
I have a decent chunk of this LLVM patch written but now I wonder if this information is even available in MIR.
bjorn3 commentedon Nov 20, 2025
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.
tromey commentedon Nov 20, 2025
Thanks. I haven't really looked at the rustc side at all yet, I'll try to dig around for this.
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.
xlambein commentedon Oct 28, 2026
@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.
tromey commentedon Oct 28, 2026
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
DIInterfaceHoldingTypethat 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 ofDW_AT_inheritanceattributes 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.