Skip to content

Implement debuginfo path remapping #38348

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
@@ -253,6 +253,7 @@ top_level_options!(
// Include the debug_assertions flag into dependency tracking, since it
// can influence whether overflow checks are done or not.
debug_assertions: bool [TRACKED],
debug_prefix_map: Option<(String, String)> [TRACKED],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only allows a single remapping. It needs to allow an arbitrary number of remappings to be useful.

debuginfo: DebugInfoLevel [TRACKED],
lint_opts: Vec<(String, lint::Level)> [TRACKED],
lint_cap: Option<lint::Level> [TRACKED],
@@ -445,6 +446,7 @@ pub fn basic_options() -> Options {
libs: Vec::new(),
unstable_features: UnstableFeatures::Disallow,
debug_assertions: true,
debug_prefix_map: None,
actually_rustdoc: false,
}
}
@@ -801,6 +803,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
"optimize with possible levels 0-3, s, or z"),
debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
"explicitly enable the cfg(debug_assertions) directive"),
debug_prefix_map: String = ("".to_string(), parse_string, [TRACKED],
"remap OLD to NEW in debug info (OLD=NEW)"),
inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
"set the inlining threshold for"),
panic: Option<PanicStrategy> = (None, parse_panic_strategy,
@@ -1423,6 +1427,20 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
}
};
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);

let debug_prefix_map = if !cg.debug_prefix_map.is_empty() {
let mut parts = cg.debug_prefix_map.splitn(2, '=');
let old = parts.next().unwrap();
let new = match parts.next() {
Some(new) => new,
None => early_error(error_format,
"-C debug-prefix-map value must be of the format `OLD=NEW`"),
};
Some((old.to_string(), new.to_string()))
} else {
None
};

let debuginfo = if matches.opt_present("g") {
if cg.debuginfo.is_some() {
early_error(error_format, "-g and -C debuginfo both provided");
@@ -1539,6 +1557,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
libs: libs,
unstable_features: UnstableFeatures::from_environment(),
debug_assertions: debug_assertions,
debug_prefix_map: debug_prefix_map,
actually_rustdoc: false,
},
cfg)
@@ -1714,6 +1733,7 @@ mod dep_tracking {
impl_dep_tracking_hash_via_hash!(Option<bool>);
impl_dep_tracking_hash_via_hash!(Option<usize>);
impl_dep_tracking_hash_via_hash!(Option<String>);
impl_dep_tracking_hash_via_hash!(Option<(String, String)>);
impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
20 changes: 17 additions & 3 deletions src/librustc_trans/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
@@ -657,6 +657,15 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
metadata
}

fn remap_path(sess: &Session, path: &str) -> String {
for (old, new) in sess.opts.debug_prefix_map.clone() {
if path.starts_with(&old) {
return new + &path[old.len()..];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems unnecessary to clone the whole map first; it would be better to iterate references, then only clone the "new" once we've found a match.

}
path.to_string()
}

pub fn file_metadata(cx: &CrateContext, path: &str, full_path: &Option<String>) -> DIFile {
// FIXME (#9639): This needs to handle non-utf8 paths
let work_dir = cx.sess().working_dir.to_str().unwrap();
@@ -669,7 +678,10 @@ pub fn file_metadata(cx: &CrateContext, path: &str, full_path: &Option<String>)
}
});

file_metadata_(cx, path, file_name, &work_dir)
let sess = cx.sess();
let remap_file_name = remap_path(sess, file_name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ends up matching against a full path rather than the path passed on the command line. The let file_name expression above ends up using the full_path parameter if its present (which it always appears to be) rather than the relative path (which it goes to some lengths to make relative to work_dir). I'm not sure what the larger intent is here, but the effect is that this doesn't work as expected.

It looks like this was done deliberately in 24e7491 by @luser. This suggests that path remapping should be done in absolute space - though the code is pretty inconsistent. If full_path is None, then I think the resulting path will be relative.

let remap_dir = remap_path(sess, work_dir);
file_metadata_(cx, path, &remap_file_name, &remap_dir)
}

pub fn unknown_file_metadata(cx: &CrateContext) -> DIFile {
@@ -759,7 +771,7 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext,
debug_context: &CrateDebugContext,
sess: &Session)
-> DIDescriptor {
let work_dir = &sess.working_dir;
let work_dir = sess.working_dir.to_str().unwrap();
let compile_unit_name = match sess.local_crate_source_file {
None => fallback_path(scc),
Some(ref abs_path) => {
@@ -781,12 +793,14 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext,
}
};

let work_dir = remap_path(sess, work_dir);

debug!("compile_unit_metadata: {:?}", compile_unit_name);
let producer = format!("rustc version {}",
(option_env!("CFG_VERSION")).expect("CFG_VERSION"));

let compile_unit_name = compile_unit_name.as_ptr();
let work_dir = path2cstr(&work_dir);
let work_dir = CString::new(work_dir).unwrap();
let producer = CString::new(producer).unwrap();
let flags = "\0";
let split_name = "\0";