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.
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
-pgstyle 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:
After:
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.