namhyung / uftrace

Function graph tracer for C/C++/Rust/Python
https://uftrace.github.io/slide/
GNU General Public License v2.0
2.96k stars 431 forks source link

Rust symbol demangling #655

Open honggyukim opened 5 years ago

honggyukim commented 5 years ago

I've found some symbols from Rust that are not human friendly. Please see.

$ cat rust-symbols.txt
_ZN12rustc_driver6driver34phase_2_configure_and_expand_inner28_$u7b$$u7b$closure$u7d$$u7d$17h19b3069eedb2aa0eE.llvm.10317035631373510462
_ZN13rustc_resolve6macros95_$LT$impl$u20$syntax..ext..base..Resolver$u20$for$u20$rustc_resolve..Resolver$LT$$u27$a$GT$$GT$36visit_ast_fragment_with_placeholders17hf0888d70da343677E
_ZN145_$LT$rustc_resolve..build_reduced_graph..BuildReducedGraphVisitor$LT$$u27$a$C$$u20$$u27$b$GT$$u20$as$u20$syntax..visit..Visitor$LT$$u27$a$GT$$GT$10visit_item17hb150e47151208e8cE
_ZN85_$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$alloc..vec..SpecExtend$LT$T$C$$u20$I$GT$$GT$9from_iter17h2062241170cc9962E
_ZN13rustc_resolve19build_reduced_graph55_$LT$impl$u20$rustc_resolve..Resolver$LT$$u27$a$GT$$GT$28populate_module_if_necessary17hbb441b810ef2f737E
_ZN13rustc_resolve6macros95_$LT$impl$u20$syntax..ext..base..Resolver$u20$for$u20$rustc_resolve..Resolver$LT$$u27$a$GT$$GT$15resolve_imports17h3828c95b196b1a3eE
_ZN12rustc_driver6driver27phase_3_run_analysis_passes17hdb2010f2e99be787E
_ZN4core3ptr18real_drop_in_place17h11c589efaa8cb821E
_ZN111_$LT$rustc_codegen_llvm..LlvmCodegenBackend$u20$as$u20$rustc_codegen_utils..codegen_backend..CodegenBackend$GT$21join_codegen_and_link17hd599938021451cc5E
_ZN50_$LT$F$u20$as$u20$alloc..boxed..FnBox$LT$A$GT$$GT$8call_box17h4c8a656ad87c3337E
_ZN13rustc_resolve19build_reduced_graph55_$LT$impl$u20$rustc_resolve..Resolver$LT$$u27$a$GT$$GT$28populate_module_if_necessary17hbb441b810ef2f737E
_ZN14rustc_metadata11cstore_impl48_$LT$impl$u20$rustc_metadata..cstore..CStore$GT$23item_children_untracked17h022dcfab3027e755E
_ZN14rustc_metadata7decoder55_$LT$impl$u20$rustc_metadata..cstore..CrateMetadata$GT$18each_child_of_item17h46b74a1d0f9a5866E
_ZN168_$LT$rustc_metadata..decoder..DecodeContext$LT$$u27$a$C$$u20$$u27$tcx$GT$$u20$as$u20$serialize..serialize..SpecializedDecoder$LT$syntax_pos..span_encoding..Span$GT$$GT$18specialized_decode17h4a6bd5763c741c0aE
_ZN14rustc_metadata7decoder55_$LT$impl$u20$rustc_metadata..cstore..CrateMetadata$GT$21imported_source_files17h8b761ab49aa0fdabE
_ZN85_$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$alloc..vec..SpecExtend$LT$T$C$$u20$I$GT$$GT$9from_iter17h62479432b9e0e63dE
_ZN84_$LT$core..iter..Map$LT$I$C$$u20$F$GT$$u20$as$u20$core..iter..iterator..Iterator$GT$4fold17h6bd1613295c5cc3bE
_ZN13rustc_resolve6macros95_$LT$impl$u20$syntax..ext..base..Resolver$u20$for$u20$rustc_resolve..Resolver$LT$$u27$a$GT$$GT$15resolve_imports17h3828c95b196b1a3eE
_ZN13rustc_resolve15resolve_imports14ImportResolver15resolve_imports17h1d147c237e1b06c0E
_ZN13rustc_resolve19build_reduced_graph55_$LT$impl$u20$rustc_resolve..Resolver$LT$$u27$a$GT$$GT$28populate_module_if_necessary17hbb441b810ef2f737E
_ZN14rustc_metadata11cstore_impl48_$LT$impl$u20$rustc_metadata..cstore..CStore$GT$23item_children_untracked17h022dcfab3027e755E
_ZN14rustc_metadata7decoder55_$LT$impl$u20$rustc_metadata..cstore..CrateMetadata$GT$18each_child_of_item17h46b74a1d0f9a5866E
_ZN168_$LT$rustc_metadata..decoder..DecodeContext$LT$$u27$a$C$$u20$$u27$tcx$GT$$u20$as$u20$serialize..serialize..SpecializedDecoder$LT$syntax_pos..span_encoding..Span$GT$$GT$18specialized_decode17h4a6bd5763c741c0aE
_ZN14rustc_metadata7decoder55_$LT$impl$u20$rustc_metadata..cstore..CrateMetadata$GT$21imported_source_files17h8b761ab49aa0fdabE
_ZN85_$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$alloc..vec..SpecExtend$LT$T$C$$u20$I$GT$$GT$9from_iter17h62479432b9e0e63dE
_ZN84_$LT$core..iter..Map$LT$I$C$$u20$F$GT$$u20$as$u20$core..iter..iterator..Iterator$GT$4fold17h6bd1613295c5cc3bE
_ZN46_$LT$std..thread..local..LocalKey$LT$T$GT$$GT$4with17hfa2112d7831da9bdE
_ZN12rustc_typeck11check_crate17hff96fb41fa5237f9E
_ZN5rustc4util6common4time17h53daeca5cf904c3eE
_ZN5rustc2ty5query8plumbing90_$LT$impl$u20$rustc..ty..context..TyCtxt$LT$$u27$a$C$$u20$$u27$gcx$C$$u20$$u27$tcx$GT$$GT$12try_get_with17he823459c511e55c5E
_ZN5rustc9dep_graph5graph8DepGraph14with_task_impl17ha513f9ddad293b48E.llvm.11170816418846394767
_ZN5rustc2ty5query148_$LT$impl$u20$rustc..ty..query..config..QueryAccessors$LT$$u27$tcx$GT$$u20$for$u20$rustc..ty..query..queries..typeck_item_bodies$LT$$u27$tcx$GT$$GT$7compute17h8927c0bd3e117e34E
_ZN5rustc2ty5query15__query_compute18typeck_item_bodies17h4a12575681458c30E
_ZN12rustc_typeck5check18typeck_item_bodies17hfaa6e0ab992179a2E.llvm.1176616955897659555
_ZN5rustc7session7Session12track_errors17h8b4edd454bed47f1E
_ZN5rustc2ty5query77_$LT$impl$u20$rustc..ty..query..queries..typeck_tables_of$LT$$u27$tcx$GT$$GT$6ensure17h373b726fedcc99c7E
_ZN5rustc2ty5query8plumbing90_$LT$impl$u20$rustc..ty..context..TyCtxt$LT$$u27$a$C$$u20$$u27$gcx$C$$u20$$u27$tcx$GT$$GT$12ensure_query17h73e08f33e6d1aa10E
_ZN5rustc2ty5query8plumbing90_$LT$impl$u20$rustc..ty..context..TyCtxt$LT$$u27$a$C$$u20$$u27$gcx$C$$u20$$u27$tcx$GT$$GT$12try_get_with17hb0ee0e148c611728E
_ZN5rustc9dep_graph5graph8DepGraph14with_task_impl17ha97b247d2a229a88E.llvm.14625429544829335148
_ZN5rustc2ty5query146_$LT$impl$u20$rustc..ty..query..config..QueryAccessors$LT$$u27$tcx$GT$$u20$for$u20$rustc..ty..query..queries..typeck_tables_of$LT$$u27$tcx$GT$$GT$7compute17h743c69d46831c5a5E

The demangling output looks as follows:

$ cat rust-symbols.txt | xargs ./misc/demangler
rustc_driver::driver::phase_2_configure_and_expand_inner::_{{closure}}
rustc_resolve::macros::_<impl syntax..ext..base..Resolver for rustc_resolve..Resolver<'a>>::visit_ast_fragment_with_placeholders
_<rustc_resolve..build_reduced_graph..BuildReducedGraphVisitor<'a, 'b> as syntax..visit..Visitor<'a>>::visit_item
_<alloc..vec..Vec<T> as alloc..vec..SpecExtend<T, I>>::from_iter
rustc_resolve::build_reduced_graph::_<impl rustc_resolve..Resolver<'a>>::populate_module_if_necessary
rustc_resolve::macros::_<impl syntax..ext..base..Resolver for rustc_resolve..Resolver<'a>>::resolve_imports
rustc_driver::driver::phase_3_run_analysis_passes
core::ptr::real_drop_in_place
_<rustc_codegen_llvm..LlvmCodegenBackend as rustc_codegen_utils..codegen_backend..CodegenBackend>::join_codegen_and_link
_<F as alloc..boxed..FnBox<A>>::call_box
rustc_resolve::build_reduced_graph::_<impl rustc_resolve..Resolver<'a>>::populate_module_if_necessary
rustc_metadata::cstore_impl::_<impl rustc_metadata..cstore..CStore>::item_children_untracked
rustc_metadata::decoder::_<impl rustc_metadata..cstore..CrateMetadata>::each_child_of_item
_<rustc_metadata..decoder..DecodeContext<'a, 'tcx> as serialize..serialize..SpecializedDecoder<syntax_pos..span_encoding..Span>>::specialized_decode
rustc_metadata::decoder::_<impl rustc_metadata..cstore..CrateMetadata>::imported_source_files
_<alloc..vec..Vec<T> as alloc..vec..SpecExtend<T, I>>::from_iter
_<core..iter..Map<I, F> as core..iter..iterator..Iterator>::fold
rustc_resolve::macros::_<impl syntax..ext..base..Resolver for rustc_resolve..Resolver<'a>>::resolve_imports
rustc_resolve::resolve_imports::ImportResolver::resolve_imports
rustc_resolve::build_reduced_graph::_<impl rustc_resolve..Resolver<'a>>::populate_module_if_necessary
rustc_metadata::cstore_impl::_<impl rustc_metadata..cstore..CStore>::item_children_untracked
rustc_metadata::decoder::_<impl rustc_metadata..cstore..CrateMetadata>::each_child_of_item
_<rustc_metadata..decoder..DecodeContext<'a, 'tcx> as serialize..serialize..SpecializedDecoder<syntax_pos..span_encoding..Span>>::specialized_decode
rustc_metadata::decoder::_<impl rustc_metadata..cstore..CrateMetadata>::imported_source_files
_<alloc..vec..Vec<T> as alloc..vec..SpecExtend<T, I>>::from_iter
_<core..iter..Map<I, F> as core..iter..iterator..Iterator>::fold
_<std..thread..local..LocalKey<T>>::with
rustc_typeck::check_crate
rustc::util::common::time
rustc::ty::query::plumbing::_<impl rustc..ty..context..TyCtxt<'a, 'gcx, 'tcx>>::try_get_with
rustc::dep_graph::graph::DepGraph::with_task_impl
rustc::ty::query::_<impl rustc..ty..query..config..QueryAccessors<'tcx> for rustc..ty..query..queries..typeck_item_bodies<'tcx>>::compute
rustc::ty::query::__query_compute::typeck_item_bodies
rustc_typeck::check::typeck_item_bodies
rustc::session::Session::track_errors
rustc::ty::query::_<impl rustc..ty..query..queries..typeck_tables_of<'tcx>>::ensure
rustc::ty::query::plumbing::_<impl rustc..ty..context..TyCtxt<'a, 'gcx, 'tcx>>::ensure_query
rustc::ty::query::plumbing::_<impl rustc..ty..context..TyCtxt<'a, 'gcx, 'tcx>>::try_get_with
rustc::dep_graph::graph::DepGraph::with_task_impl
rustc::ty::query::_<impl rustc..ty..query..config..QueryAccessors<'tcx> for rustc..ty..query..queries..typeck_tables_of<'tcx>>::compute

They might look okay but just uploaded if there's any chance to improve.

namhyung commented 5 years ago

You don't need to use xargs since it reads from stdin if no arg is given. :)

Anyway I also think it needs to simplify symbol like we do in C++. Following is some of my idea.

But I'm not 100% sure for this. Thoughts?

honggyukim commented 5 years ago

Looks better but not sure about it as I'm not familiar with Rust lang as of yet.

@quark-zju @ParkHanbum @taeguk Could you give us some thoughts for Rust symbol demangling as above?

taeguk commented 5 years ago
  • remove former in "as": _<foo as bar> --> bar

About this idea, there are some problematic things:

// except.rs
trait Trait {
    fn new() -> Self;

    fn foo(&self) {
        println!("Trait::foo()");
    }
    fn bar(&self);
}

struct Struct {
    var1: i32,
    var2: bool
}

impl Struct {
    fn method(&self) {
        println!("Struct::method()");
    }
}

impl Trait for Struct {
    fn new() -> Struct {
        println!("Struct::new()");
        Struct { var1: 3, var2: true }
    }
    fn bar(&self) {
        println!("Struct::bar()");
    }
}

fn main() {
    let s: Struct = Trait::new();   // Struct::new()
    s.foo();    // Trait::foo()
    s.bar();    // Struct::bar()
    s.method(); // Struct::method()
}
$ rustc -Z instrument-mcount -g -A dead_code except.rs
$ uftrace ./except
Struct::new()
Trait::foo()
Struct::bar()
Struct::method()
# DURATION     TID     FUNCTION
            [ 80895] | std::rt::lang_start() {
            [ 80895] |   std::rt::lang_start::_{{closure}}() {
            [ 80895] |     except::main() {
            [ 80895] |       _<except..Struct as except..Trait>::new() {
   0.092 us [ 80895] |         core::fmt::Arguments::new_v1();
  95.423 us [ 80895] |       } /* _<except..Struct as except..Trait>::new */
            [ 80895] |       except::Trait::foo() {
   0.081 us [ 80895] |         core::fmt::Arguments::new_v1();
   3.435 us [ 80895] |       } /* except::Trait::foo */
            [ 80895] |       _<except..Struct as except..Trait>::bar() {
   0.070 us [ 80895] |         core::fmt::Arguments::new_v1();
   1.467 us [ 80895] |       } /* _<except..Struct as except..Trait>::bar */
            [ 80895] |       except::Struct::method() {
   0.075 us [ 80895] |         core::fmt::Arguments::new_v1();
   1.367 us [ 80895] |       } /* except::Struct::method */
 102.681 us [ 80895] |     } /* except::main */
            [ 80895] |     _<() as std..process..Termination>::report() {
            [ 80895] |       _<std..process..ExitCode as std..process..Termination>::report() {
   0.064 us [ 80895] |         std::sys::unix::process::process_common::ExitCode::as_i32();
   0.399 us [ 80895] |       } /* _<std..process..ExitCode as std..process..Termination>::report */
   0.592 us [ 80895] |     } /* _<() as std..process..Termination>::report */
 103.621 us [ 80895] |   } /* std::rt::lang_start::_{{closure}} */
 379.175 us [ 80895] | } /* std::rt::lang_start */

If applying @namhyung's suggestion to _<except..Struct as except..Trait>::new() and _<except..Struct as except..Trait>::bar(), then they become except::Trait::new() and except::Trait::bar(). But I think it is bad because these results are different to the functions which actually called.

quark-zju commented 5 years ago

I'm not an expert in this area. But the current Rust symbols are kind of Rust implementation details. See https://github.com/rust-lang/rfcs/pull/2603. Things might change rapidly. I think it makes sense to not spend too much effort on things to be changed, and wait for the new, more standardized schema.

honggyukim commented 5 years ago

Hi @taeguk @quark-zju, thanks very much for your feedback. It seems to be more complicated than we thought. It'd be better to take time what to do after v0.9.2 release. Thanks a lot for your help!

namhyung commented 5 years ago

@taeguk do you think _<foo as bar> -> foo is more appropriate?

@quark-zju I don't know when it's finished but I think we still need to support older versions anyway. I agree that it should not spend too much effort but I'd like to make it more readable with a slight simplification if possible..

lu-zero commented 5 years ago

There is rust-demangle that could be used for a more accurate demangling.

namhyung commented 5 years ago

@lu-zero thanks for the comment. We have two demangler - 'simple' demangler shows more compact, readable name while 'full' demangler shows accurate name. I'm talking about the simple demangler here how we can improve readability.

Based on the observation above, I think it'd be better using _<foo as bar> -> foo unless it's not ().

lu-zero commented 5 years ago

Please notice that mangling rules will change soon

honggyukim commented 4 years ago

There is rust-demangle that could be used for a more accurate demangling.

As @lu-zero suggested, we can get some reference to implement rust demangler.

rustfilt also uses the same demangler.

namhyung commented 7 months ago

Current output is like below. And #1626 was filed for the new mangling scheme.

$ cat rust-symbols.txt | misc/demangler 
rustc_driver::driver::phase_2_configure_and_expand_inner::_{{closure}}
rustc_resolve::macros::_<impl syntax::ext::base::Resolver for rustc_resolve::Resolver<'a>>::visit_ast_fragment_with_placeholders
_<rustc_resolve::build_reduced_graph::BuildReducedGraphVisitor<'a, 'b>>::visit_item
_<alloc::vec::Vec<T>>::from_iter
rustc_resolve::build_reduced_graph::_<impl rustc_resolve::Resolver<'a>>::populate_module_if_necessary
rustc_resolve::macros::_<impl syntax::ext::base::Resolver for rustc_resolve::Resolver<'a>>::resolve_imports
rustc_driver::driver::phase_3_run_analysis_passes
core::ptr::real_drop_in_place
_<rustc_codegen_llvm::LlvmCodegenBackend>::join_codegen_and_link
_<F>::call_box
rustc_resolve::build_reduced_graph::_<impl rustc_resolve::Resolver<'a>>::populate_module_if_necessary
rustc_metadata::cstore_impl::_<impl rustc_metadata::cstore::CStore>::item_children_untracked
rustc_metadata::decoder::_<impl rustc_metadata::cstore::CrateMetadata>::each_child_of_item
_<rustc_metadata::decoder::DecodeContext<'a, 'tcx>>::specialized_decode
rustc_metadata::decoder::_<impl rustc_metadata::cstore::CrateMetadata>::imported_source_files
_<alloc::vec::Vec<T>>::from_iter
_<core::iter::Map<I, F>>::fold
rustc_resolve::macros::_<impl syntax::ext::base::Resolver for rustc_resolve::Resolver<'a>>::resolve_imports
rustc_resolve::resolve_imports::ImportResolver::resolve_imports
rustc_resolve::build_reduced_graph::_<impl rustc_resolve::Resolver<'a>>::populate_module_if_necessary
rustc_metadata::cstore_impl::_<impl rustc_metadata::cstore::CStore>::item_children_untracked
rustc_metadata::decoder::_<impl rustc_metadata::cstore::CrateMetadata>::each_child_of_item
_<rustc_metadata::decoder::DecodeContext<'a, 'tcx>>::specialized_decode
rustc_metadata::decoder::_<impl rustc_metadata::cstore::CrateMetadata>::imported_source_files
_<alloc::vec::Vec<T>>::from_iter
_<core::iter::Map<I, F>>::fold
_<std::thread::local::LocalKey<T>>::with
rustc_typeck::check_crate
rustc::util::common::time
rustc::ty::query::plumbing::_<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_get_with
rustc::dep_graph::graph::DepGraph::with_task_impl
rustc::ty::query::_<impl rustc::ty::query::config::QueryAccessors<'tcx> for rustc::ty::query::queries::typeck_item_bodies<'tcx>>::compute
rustc::ty::query::__query_compute::typeck_item_bodies
rustc_typeck::check::typeck_item_bodies
rustc::session::Session::track_errors
rustc::ty::query::_<impl rustc::ty::query::queries::typeck_tables_of<'tcx>>::ensure
rustc::ty::query::plumbing::_<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::ensure_query
rustc::ty::query::plumbing::_<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_get_with
rustc::dep_graph::graph::DepGraph::with_task_impl
rustc::ty::query::_<impl rustc::ty::query::config::QueryAccessors<'tcx> for rustc::ty::query::queries::typeck_tables_of<'tcx>>::compute
lu-zero commented 7 months ago

Looks good! I'd avoid adding the _ maybe though.

namhyung commented 7 months ago

Yeah, now it shows _<foo as bar> as _<foo>, maybe we can convert _< to <.