Skip to content

Rust string type support #2060

Description

@namhyung

As Rust is getting more and more widely used, we need to support its string types properly. The first target would be string literals (&str). The actual type is a slice of u8 which consists of a pointer and a length. So it'd take 2 words (i.e. registers or stack slots) for an entry.

I'd propose a new type specifier "r" for rust string literals (slices). I've tested it with a simple Rust program (debug build), but a problem is the DWARF location is meaningful only when it's generated with -pg style option because sometimes the frame base register was RSP (stack pointer) but the stack is setup in the function prologue which is too late for uftrace (dynamic tracing).

Anyway, the type parsing and record/replay itself is fine so I'd like to share the code first. It's in review/rust-str-v1 branch.

Here's an example output.

Before:

$ uftrace -a -P. -F inlinestat::main  target/debug/inlinestat
# DURATION     TID      FUNCTION
            [  15376] | inlinestat::main() {
            [  15376] |   clap_builder::derive::Parser::parse() {
            [  15376] |     _<inlinestat::Cli>::command() {
            [  15376] |       clap_builder::builder::command::Command::new(&str{...}) {
            [  15376] |         _<T>::into(&str{...}) {
            [  15376] |           _<clap_builder::builder::str::Str>::from(&str{...}) {
            [  15376] |             clap_builder::builder::str::Str::from_static_ref(&str{...}) {
   0.598 us [  15376] |               clap_builder::builder::str::inner::Inner::from_static_ref(&str{...}) = Inner{...};
   2.205 us [  15376] |             } = Str{...}; /* clap_builder::builder::str::Str::from_static_ref */
   2.886 us [  15376] |           } = Str{...}; /* _<clap_builder::builder::str::Str>::from */
   3.917 us [  15376] |         } = Str{...}; /* _<T>::into */
            [  15376] |         clap_builder::builder::command::Command::new::new_inner(Str{...}) {
            [  15376] |           _<clap_builder::builder::command::Command>::default() {
            [  15376] |             _<clap_builder::builder::str::Str>::default() {
            [  15376] |               clap_builder::builder::str::_<impl core::default::Default for clap_builder::builder::str::inner::Inner>::default() {
   0.131 us [  15376] |                 clap_builder::builder::str::inner::Inner::from_static_ref(&str{...}) = Inner{...};
   0.601 us [  15376] |               } = Inner{...}; /* clap_builder::builder::str::_<impl core::default::Default for clap_builder::builder::str::inner::Inner>::default */
   1.287 us [  15376] |             } = Str{...}; /* _<clap_builder::builder::str::Str>::default */
   0.303 us [  15376] |             _<core::option::Option<T>>::default() = Option{...};
   0.198 us [  15376] |             _<core::option::Option<T>>::default() = Option{...};
   0.068 us [  15376] |             _<core::option::Option<T>>::default() = Option{...};
   ...

After:

$ uftrace -a -P. -F inlinestat::main  target/debug/inlinestat
# DURATION     TID      FUNCTION
            [  12214] | inlinestat::main() {
            [  12214] |   clap_builder::derive::Parser::parse() {
            [  12214] |     _<inlinestat::Cli>::command() {
            [  12214] |       clap_builder::builder::command::Command::new("(<CF>P<BB><FD>^?") {
            [  12214] |         _<T>::into("inlinestat") {
            [  12214] |           _<clap_builder::builder::str::Str>::from("inlinestat") {
            [  12214] |             clap_builder::builder::str::Str::from_static_ref("inlinestat") {
   0.401 us [  12214] |               clap_builder::builder::str::inner::Inner::from_static_ref("inlinestat") = Inner{...};
   2.369 us [  12214] |             } = Str{...}; /* clap_builder::builder::str::Str::from_static_ref */
   3.738 us [  12214] |           } = Str{...}; /* _<clap_builder::builder::str::Str>::from */
   5.376 us [  12214] |         } = Str{...}; /* _<T>::into */
            [  12214] |         clap_builder::builder::command::Command::new::new_inner(Str{...}) {
            [  12214] |           _<clap_builder::builder::command::Command>::default() {
            [  12214] |             _<clap_builder::builder::str::Str>::default() {
            [  12214] |               clap_builder::builder::str::_<impl core::default::Default for clap_builder::builder::str::inner::Inner>::default() {
  57.740 us [  12214] |                 clap_builder::builder::str::inner::Inner::from_static_ref("") = Inner{...};
  58.311 us [  12214] |               } = Inner{...}; /* clap_builder::builder::str::_<impl core::default::Default for clap_builde>
  59.257 us [  12214] |             } = Str{...}; /* _<clap_builder::builder::str::Str>::default */
   0.338 us [  12214] |             _<core::option::Option<T>>::default() = Option{...};
   0.198 us [  12214] |             _<core::option::Option<T>>::default() = Option{...};
   0.093 us [  12214] |             _<core::option::Option<T>>::default() = Option{...};
   ...

The first one in Command::new() is broken but others looks fine. Note that Rust strings are NOT terminated by a NUL character. So it won't print correctly unless it read the string length correctly.

It would be a separate work to fix the location of stack arguments.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions