From 060efbbe3d059fd9eaf78255e1d27b9c62a442b8 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Sat, 1 Jul 2017 00:38:58 +0300 Subject: [PATCH] When writing assembly output demangled fn name in comments With this patch `--emit=asm` looks like this: ``` ; as core::ops::index::IndexMut>::index_mut __ZN106_$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$core..ops..index..IndexMut$LT$core..ops..range..RangeFull$GT$$GT$9index_mut17h8ecb05aacf724133E: ... Lcfi2: .cfi_def_cfa_register %rbp subq $16, %rsp ; as core::ops::deref::DerefMut>::deref_mut callq __ZN71_$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$core..ops..deref..DerefMut$GT$9deref_mut17heae350c695265f00E ``` Unlike writing LLVM IR, it is hard to plug into LLVM to output comments without duplicating large amount of LLVM code (because LLVM doesn't have hooks, or at least I haven't found them). So it is implemented by post-processing assembly text. cc https://github.com/integer32llc/rust-playground/issues/15 cc https://github.com/rust-lang/rust/pull/42971 r? nagisa --- src/librustc_trans/back/demangle.rs | 100 ++++++++++++++++++++++++++++ src/librustc_trans/back/write.rs | 8 +++ src/librustc_trans/lib.rs | 1 + 3 files changed, 109 insertions(+) create mode 100644 src/librustc_trans/back/demangle.rs diff --git a/src/librustc_trans/back/demangle.rs b/src/librustc_trans/back/demangle.rs new file mode 100644 index 0000000000000..1404cd1a4a01a --- /dev/null +++ b/src/librustc_trans/back/demangle.rs @@ -0,0 +1,100 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt::Write as fmt_Write; +use std::io; +use std::io::Read; +use std::io::Write as io_Write; +use std::fs; +use std::path::Path; + +use rustc_demangle; + +// find raw symbol in line +fn find_symbol_in_line(mut line: &str) -> Option<&str> { + while !line.is_empty() { + // Skip underscores, because on macOS compiler adds extra underscore, + // and rustc_demangle successfully demangles symbols without leading underscore. + let zn = match line.find("ZN") { + Some(pos) => pos, + None => return None, + }; + line = &line[zn..]; + + let mut pos = "ZN".len(); + + fn is_valid_char_in_symbol(c: u8) -> bool { + // symbol_names::sanitize contains complete list of valid chars + match c { + b'$' | b'.' | b'_' => true, + b'a' ... b'z' => true, + b'A' ... b'Z' => true, + b'0' ... b'9' => true, + _ => false, + } + } + + while pos != line.len() && is_valid_char_in_symbol(line.as_bytes()[pos]) { + pos += 1; + } + + if line.as_bytes()[pos - 1] == b'E' { + return Some(&line[..pos]); + } + + line = &line[pos..]; + } + + None +} + +fn demangle_asm_in_text(text: &str) -> String { + let mut r = String::new(); + for line in text.lines() { + // Do not comment comments. + if !line.starts_with(";") { + // Find a symbol, demangle at most one symbol on line. + if let Some(sym) = find_symbol_in_line(line) { + // If couldn't demangle, probably it is false positive in `find_symbol_in_line`. + if let Ok(dem) = rustc_demangle::try_demangle(sym) { + let mut start = String::new(); + if line.starts_with("\t") { + start.push_str(";\t"); + } else { + // If line is indented with spaces, keep indentation. + let leading_spaces = line.chars().filter(|&c| c == ' ').count(); + start.push_str("; "); + while start.len() < leading_spaces { + start.push(' '); + } + } + write!(r, "{}{:#}\n", start, dem).unwrap(); + } + } + } + r.push_str(line); + r.push_str("\n"); + } + r +} + +// Only error is IO error. +pub fn demangle_asm_in_file_in_place(path: &Path) -> io::Result<()> { + let mut file = fs::File::open(path)?; + let mut text = String::new(); + file.read_to_string(&mut text)?; + drop(file); // close + + let demangled = demangle_asm_in_text(&text); + + let mut file = fs::File::create(path)?; + file.write_all(demangled.as_bytes())?; + Ok(()) +} diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 562d7171156fe..9dc79fac4f0b3 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -30,6 +30,7 @@ use context::{is_pie_binary, get_reloc_model}; use jobserver::{Client, Acquired}; use crossbeam::{scope, Scope}; use rustc_demangle; +use back::demangle::demangle_asm_in_file_in_place; use std::cmp; use std::ffi::CString; @@ -569,6 +570,13 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_obj { llvm::LLVMDisposeModule(llmod); } + + // It is hard to plug into LLVM to print annotated assembly + // as it is done with IR, so annotation is performed on assembly file. + if let Err(e) = demangle_asm_in_file_in_place(&path) { + cgcx.handler.err( + &format!("failed to demangle in file {}: {:?}", path.display(), e)); + } } if write_obj { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 6acd10cb887f8..4e63d8ac10e2a 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -77,6 +77,7 @@ pub mod back { pub(crate) mod symbol_export; pub(crate) mod symbol_names; pub mod write; + mod demangle; pub mod rpath; }