Auto merge of #69718 - arlosi:debughash, r=eddyb
Add hash of source files in debug info LLVM supports placing the hash of source files inside the debug info. This information can be used by a debugger to verify that the source code matches the executable. This change adds support for both hash algorithms supported by LLVM, MD5 and SHA1, controlled by a target option. * DWARF only supports MD5 * LLVM IR supports MD5 and SHA1 (and SHA256 in LLVM 11). * CodeView (.PDB) supports MD5, SHA1, and SHA256. Fixes #68980. Tracking issue: #70401 rustc dev guide PR with further details: https://github.com/rust-lang/rustc-dev-guide/pull/623
This commit is contained in:
commit
6050e523ba
64
Cargo.lock
64
Cargo.lock
@ -87,12 +87,6 @@ dependencies = [
|
||||
"scoped_threadpool",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.4.7"
|
||||
@ -187,11 +181,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.3.3"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
|
||||
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"byte-tools",
|
||||
"byteorder",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"byte-tools",
|
||||
]
|
||||
|
||||
@ -240,9 +245,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
version = "0.2.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
|
||||
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
@ -897,9 +902,9 @@ checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.7.6"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
|
||||
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
@ -1226,9 +1231,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.9.0"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
|
||||
checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
@ -1962,6 +1967,17 @@ version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdbook"
|
||||
version = "0.3.5"
|
||||
@ -2250,6 +2266,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6a04cb71e910d0034815600180f62a95bf6e67942d7ab52a166a68c7d7e9cd0"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "1.2.1"
|
||||
@ -2467,9 +2489,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.1.0"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5a3492a4ed208ffc247adcdcc7ba2a95be3104f58877d0d02f0df39bf3efb5e"
|
||||
checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
|
||||
dependencies = [
|
||||
"maplit",
|
||||
"pest",
|
||||
@ -4155,11 +4177,13 @@ dependencies = [
|
||||
"arena",
|
||||
"cfg-if",
|
||||
"log",
|
||||
"md-5",
|
||||
"rustc_data_structures",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"scoped-tls",
|
||||
"serialize",
|
||||
"sha-1",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
@ -4535,14 +4559,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.7.0"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded"
|
||||
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"byte-tools",
|
||||
"digest",
|
||||
"fake-simd",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -0,0 +1,11 @@
|
||||
# `src-hash-algorithm`
|
||||
|
||||
The tracking issue for this feature is: [#70401](https://github.com/rust-lang/rust/issues/70401).
|
||||
|
||||
------------------------
|
||||
|
||||
The `-Z src-hash-algorithm` compiler flag controls which algorithm is used when hashing each source file. The hash is stored in the debug info and can be used by a debugger to verify the source code matches the executable.
|
||||
|
||||
Supported hash algorithms are: `md5`, and `sha1`. Note that not all hash algorithms are supported by all debug info formats.
|
||||
|
||||
By default, the compiler chooses the hash algorithm based on the target specification.
|
@ -41,7 +41,7 @@ use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::config::{self, DebugInfo};
|
||||
use rustc_span::symbol::{Interner, Symbol};
|
||||
use rustc_span::{self, FileName, Span};
|
||||
use rustc_span::{self, FileName, SourceFileHash, Span};
|
||||
use rustc_target::abi::{Abi, Align, DiscriminantKind, HasDataLayout, Integer, LayoutOf};
|
||||
use rustc_target::abi::{Int, Pointer, F32, F64};
|
||||
use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
|
||||
@ -751,6 +751,14 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp
|
||||
metadata
|
||||
}
|
||||
|
||||
fn hex_encode(data: &[u8]) -> String {
|
||||
let mut hex_string = String::with_capacity(data.len() * 2);
|
||||
for byte in data.iter() {
|
||||
write!(&mut hex_string, "{:02x}", byte).unwrap();
|
||||
}
|
||||
hex_string
|
||||
}
|
||||
|
||||
pub fn file_metadata(
|
||||
cx: &CodegenCx<'ll, '_>,
|
||||
file_name: &FileName,
|
||||
@ -758,6 +766,8 @@ pub fn file_metadata(
|
||||
) -> &'ll DIFile {
|
||||
debug!("file_metadata: file_name: {}, defining_crate: {}", file_name, defining_crate);
|
||||
|
||||
let source_file = cx.sess().source_map().get_source_file(file_name);
|
||||
let hash = source_file.as_ref().map(|f| &f.src_hash);
|
||||
let file_name = Some(file_name.to_string());
|
||||
let directory = if defining_crate == LOCAL_CRATE {
|
||||
Some(cx.sess().working_dir.0.to_string_lossy().to_string())
|
||||
@ -766,17 +776,18 @@ pub fn file_metadata(
|
||||
// independent of the compiler's working directory one way or another.
|
||||
None
|
||||
};
|
||||
file_metadata_raw(cx, file_name, directory)
|
||||
file_metadata_raw(cx, file_name, directory, hash)
|
||||
}
|
||||
|
||||
pub fn unknown_file_metadata(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
|
||||
file_metadata_raw(cx, None, None)
|
||||
file_metadata_raw(cx, None, None, None)
|
||||
}
|
||||
|
||||
fn file_metadata_raw(
|
||||
cx: &CodegenCx<'ll, '_>,
|
||||
file_name: Option<String>,
|
||||
directory: Option<String>,
|
||||
hash: Option<&SourceFileHash>,
|
||||
) -> &'ll DIFile {
|
||||
let key = (file_name, directory);
|
||||
|
||||
@ -789,6 +800,17 @@ fn file_metadata_raw(
|
||||
let file_name = file_name.as_deref().unwrap_or("<unknown>");
|
||||
let directory = directory.as_deref().unwrap_or("");
|
||||
|
||||
let (hash_kind, hash_value) = match hash {
|
||||
Some(hash) => {
|
||||
let kind = match hash.kind {
|
||||
rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5,
|
||||
rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1,
|
||||
};
|
||||
(kind, hex_encode(hash.hash_bytes()))
|
||||
}
|
||||
None => (llvm::ChecksumKind::None, String::new()),
|
||||
};
|
||||
|
||||
let file_metadata = unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateFile(
|
||||
DIB(cx),
|
||||
@ -796,6 +818,9 @@ fn file_metadata_raw(
|
||||
file_name.len(),
|
||||
directory.as_ptr().cast(),
|
||||
directory.len(),
|
||||
hash_kind,
|
||||
hash_value.as_ptr().cast(),
|
||||
hash_value.len(),
|
||||
)
|
||||
};
|
||||
|
||||
@ -920,6 +945,9 @@ pub fn compile_unit_metadata(
|
||||
name_in_debuginfo.len(),
|
||||
work_dir.as_ptr().cast(),
|
||||
work_dir.len(),
|
||||
llvm::ChecksumKind::None,
|
||||
ptr::null(),
|
||||
0,
|
||||
);
|
||||
|
||||
let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
|
||||
|
@ -546,6 +546,15 @@ pub enum ThreadLocalMode {
|
||||
LocalExec,
|
||||
}
|
||||
|
||||
/// LLVMRustChecksumKind
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub enum ChecksumKind {
|
||||
None,
|
||||
MD5,
|
||||
SHA1,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
type Opaque;
|
||||
}
|
||||
@ -1640,6 +1649,9 @@ extern "C" {
|
||||
FilenameLen: size_t,
|
||||
Directory: *const c_char,
|
||||
DirectoryLen: size_t,
|
||||
CSKind: ChecksumKind,
|
||||
Checksum: *const c_char,
|
||||
ChecksumLen: size_t,
|
||||
) -> &'a DIFile;
|
||||
|
||||
pub fn LLVMRustDIBuilderCreateSubroutineType(
|
||||
|
@ -22,7 +22,7 @@ use rustc_session::parse::CrateConfig;
|
||||
use rustc_session::CrateDisambiguator;
|
||||
use rustc_session::{config, early_error, filesearch, output, DiagnosticOutput, Session};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap};
|
||||
use rustc_span::source_map::{FileLoader, SourceMap};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
use std::env;
|
||||
@ -62,15 +62,13 @@ pub fn create_session(
|
||||
lint_caps: FxHashMap<lint::LintId, lint::Level>,
|
||||
descriptions: Registry,
|
||||
) -> (Lrc<Session>, Lrc<Box<dyn CodegenBackend>>, Lrc<SourceMap>) {
|
||||
let loader = file_loader.unwrap_or(box RealFileLoader);
|
||||
let source_map = Lrc::new(SourceMap::with_file_loader(loader, sopts.file_path_mapping()));
|
||||
let mut sess = session::build_session_with_source_map(
|
||||
let (mut sess, source_map) = session::build_session_with_source_map(
|
||||
sopts,
|
||||
input_path,
|
||||
descriptions,
|
||||
source_map.clone(),
|
||||
diagnostic_output,
|
||||
lint_caps,
|
||||
file_loader,
|
||||
);
|
||||
|
||||
let codegen_backend = get_codegen_backend(&sess);
|
||||
|
@ -61,7 +61,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
|
||||
cnum,
|
||||
// Do not hash the source as it is not encoded
|
||||
src: _,
|
||||
src_hash,
|
||||
ref src_hash,
|
||||
external_src: _,
|
||||
start_pos,
|
||||
end_pos: _,
|
||||
|
@ -18,9 +18,10 @@ use rustc_feature::UnstableFeatures;
|
||||
use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
|
||||
use rustc_span::source_map::{FileName, FilePathMapping};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::SourceFileHashAlgorithm;
|
||||
|
||||
use rustc_errors::emitter::HumanReadableErrorType;
|
||||
use rustc_errors::{ColorConfig, FatalError, Handler, HandlerFlags};
|
||||
use rustc_errors::{ColorConfig, HandlerFlags};
|
||||
|
||||
use std::collections::btree_map::{
|
||||
Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
|
||||
@ -748,25 +749,30 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo
|
||||
user_cfg
|
||||
}
|
||||
|
||||
pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
|
||||
pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config {
|
||||
let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
|
||||
sp.struct_fatal(&format!("Error loading target specification: {}", e))
|
||||
.help("Use `--print target-list` for a list of built-in targets")
|
||||
.emit();
|
||||
FatalError.raise();
|
||||
early_error(
|
||||
error_format,
|
||||
&format!(
|
||||
"Error loading target specification: {}. \
|
||||
Use `--print target-list` for a list of built-in targets",
|
||||
e
|
||||
),
|
||||
)
|
||||
});
|
||||
|
||||
let ptr_width = match &target.target_pointer_width[..] {
|
||||
"16" => 16,
|
||||
"32" => 32,
|
||||
"64" => 64,
|
||||
w => sp
|
||||
.fatal(&format!(
|
||||
w => early_error(
|
||||
error_format,
|
||||
&format!(
|
||||
"target specification was invalid: \
|
||||
unrecognized target-pointer-width {}",
|
||||
w
|
||||
))
|
||||
.raise(),
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
Config { target, ptr_width }
|
||||
@ -1971,7 +1977,8 @@ impl PpMode {
|
||||
crate mod dep_tracking {
|
||||
use super::{
|
||||
CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
|
||||
OutputTypes, Passes, Sanitizer, SwitchWithOptPath, SymbolManglingVersion,
|
||||
OutputTypes, Passes, Sanitizer, SourceFileHashAlgorithm, SwitchWithOptPath,
|
||||
SymbolManglingVersion,
|
||||
};
|
||||
use crate::lint;
|
||||
use crate::utils::NativeLibraryKind;
|
||||
@ -2049,6 +2056,7 @@ crate mod dep_tracking {
|
||||
impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
|
||||
impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
|
||||
impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
|
||||
impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
|
||||
|
||||
impl_dep_tracking_hash_for_sortable_vec_of!(String);
|
||||
impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
|
||||
|
@ -10,6 +10,7 @@ use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel
|
||||
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::SourceFileHashAlgorithm;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
@ -283,12 +284,14 @@ macro_rules! options {
|
||||
Some("one of: `disabled`, `trampolines`, or `aliases`");
|
||||
pub const parse_symbol_mangling_version: Option<&str> =
|
||||
Some("either `legacy` or `v0` (RFC 2603)");
|
||||
pub const parse_src_file_hash: Option<&str> =
|
||||
Some("either `md5`, or `sha1`");
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod $mod_set {
|
||||
use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
|
||||
SymbolManglingVersion, CFGuard};
|
||||
SymbolManglingVersion, CFGuard, SourceFileHashAlgorithm};
|
||||
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
@ -622,6 +625,14 @@ macro_rules! options {
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
fn parse_src_file_hash(slot: &mut Option<SourceFileHashAlgorithm>, v: Option<&str>) -> bool {
|
||||
match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
|
||||
Some(hash_kind) => *slot = Some(hash_kind),
|
||||
_ => return false,
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
) }
|
||||
|
||||
@ -961,4 +972,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
"use new LLVM pass manager"),
|
||||
link_native_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
|
||||
"Link native libraries in the linker invocation."),
|
||||
src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
|
||||
"hash algorithm of source files in debug info (`md5`, or `sha1`)"),
|
||||
}
|
||||
|
@ -20,7 +20,8 @@ use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType};
|
||||
use rustc_errors::json::JsonEmitter;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::{self, MultiSpan, Span};
|
||||
use rustc_span::source_map::{self, FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
|
||||
use rustc_span::SourceFileHashAlgorithm;
|
||||
use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple};
|
||||
|
||||
use std::cell::{self, RefCell};
|
||||
@ -870,16 +871,15 @@ pub fn build_session(
|
||||
local_crate_source_file: Option<PathBuf>,
|
||||
registry: rustc_errors::registry::Registry,
|
||||
) -> Session {
|
||||
let file_path_mapping = sopts.file_path_mapping();
|
||||
|
||||
build_session_with_source_map(
|
||||
sopts,
|
||||
local_crate_source_file,
|
||||
registry,
|
||||
Lrc::new(source_map::SourceMap::new(file_path_mapping)),
|
||||
DiagnosticOutput::Default,
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.0
|
||||
}
|
||||
|
||||
fn default_emitter(
|
||||
@ -956,10 +956,10 @@ pub fn build_session_with_source_map(
|
||||
sopts: config::Options,
|
||||
local_crate_source_file: Option<PathBuf>,
|
||||
registry: rustc_errors::registry::Registry,
|
||||
source_map: Lrc<source_map::SourceMap>,
|
||||
diagnostics_output: DiagnosticOutput,
|
||||
lint_caps: FxHashMap<lint::LintId, lint::Level>,
|
||||
) -> Session {
|
||||
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
|
||||
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
|
||||
) -> (Session, Lrc<SourceMap>) {
|
||||
// FIXME: This is not general enough to make the warning lint completely override
|
||||
// normal diagnostic warnings, since the warning lint can also be denied and changed
|
||||
// later via the source code.
|
||||
@ -977,23 +977,33 @@ pub fn build_session_with_source_map(
|
||||
DiagnosticOutput::Default => None,
|
||||
DiagnosticOutput::Raw(write) => Some(write),
|
||||
};
|
||||
|
||||
let target_cfg = config::build_target_config(&sopts, sopts.error_format);
|
||||
let host_triple = TargetTriple::from_triple(config::host_triple());
|
||||
let host = Target::search(&host_triple).unwrap_or_else(|e| {
|
||||
early_error(sopts.error_format, &format!("Error loading host specification: {}", e))
|
||||
});
|
||||
|
||||
let loader = file_loader.unwrap_or(Box::new(RealFileLoader));
|
||||
let hash_kind = sopts.debugging_opts.src_hash_algorithm.unwrap_or_else(|| {
|
||||
if target_cfg.target.options.is_like_msvc {
|
||||
SourceFileHashAlgorithm::Sha1
|
||||
} else {
|
||||
SourceFileHashAlgorithm::Md5
|
||||
}
|
||||
});
|
||||
let source_map = Lrc::new(SourceMap::with_file_loader_and_hash_kind(
|
||||
loader,
|
||||
sopts.file_path_mapping(),
|
||||
hash_kind,
|
||||
));
|
||||
let emitter = default_emitter(&sopts, registry, &source_map, write_dest);
|
||||
|
||||
let diagnostic_handler = rustc_errors::Handler::with_emitter_and_flags(
|
||||
let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags(
|
||||
emitter,
|
||||
sopts.debugging_opts.diagnostic_handler_flags(can_emit_warnings),
|
||||
);
|
||||
|
||||
build_session_(sopts, local_crate_source_file, diagnostic_handler, source_map, lint_caps)
|
||||
}
|
||||
|
||||
fn build_session_(
|
||||
sopts: config::Options,
|
||||
local_crate_source_file: Option<PathBuf>,
|
||||
span_diagnostic: rustc_errors::Handler,
|
||||
source_map: Lrc<source_map::SourceMap>,
|
||||
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
|
||||
) -> Session {
|
||||
let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.debugging_opts.self_profile
|
||||
{
|
||||
let directory =
|
||||
@ -1015,13 +1025,7 @@ fn build_session_(
|
||||
None
|
||||
};
|
||||
|
||||
let host_triple = TargetTriple::from_triple(config::host_triple());
|
||||
let host = Target::search(&host_triple).unwrap_or_else(|e| {
|
||||
span_diagnostic.fatal(&format!("Error loading host specification: {}", e)).raise()
|
||||
});
|
||||
let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
|
||||
|
||||
let parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map);
|
||||
let parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map.clone());
|
||||
let sysroot = match &sopts.maybe_sysroot {
|
||||
Some(sysroot) => sysroot.clone(),
|
||||
None => filesearch::get_or_default_sysroot(),
|
||||
@ -1135,7 +1139,7 @@ fn build_session_(
|
||||
|
||||
validate_commandline_args_with_session_available(&sess);
|
||||
|
||||
sess
|
||||
(sess, source_map)
|
||||
}
|
||||
|
||||
// If it is useful to have a Session available already for validating a
|
||||
|
@ -19,3 +19,5 @@ scoped-tls = "1.0"
|
||||
unicode-width = "0.1.4"
|
||||
cfg-if = "0.1.2"
|
||||
log = "0.4"
|
||||
sha-1 = "0.8"
|
||||
md-5 = "0.8"
|
||||
|
@ -47,9 +47,14 @@ use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::cmp::{self, Ordering};
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::hash::Hash;
|
||||
use std::ops::{Add, Sub};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use md5::Md5;
|
||||
use sha1::Digest;
|
||||
use sha1::Sha1;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@ -874,6 +879,70 @@ impl ExternalSource {
|
||||
#[derive(Debug)]
|
||||
pub struct OffsetOverflowError;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub enum SourceFileHashAlgorithm {
|
||||
Md5,
|
||||
Sha1,
|
||||
}
|
||||
|
||||
impl FromStr for SourceFileHashAlgorithm {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<SourceFileHashAlgorithm, ()> {
|
||||
match s {
|
||||
"md5" => Ok(SourceFileHashAlgorithm::Md5),
|
||||
"sha1" => Ok(SourceFileHashAlgorithm::Sha1),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rustc_data_structures::impl_stable_hash_via_hash!(SourceFileHashAlgorithm);
|
||||
|
||||
/// The hash of the on-disk source file used for debug info.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub struct SourceFileHash {
|
||||
pub kind: SourceFileHashAlgorithm,
|
||||
value: [u8; 20],
|
||||
}
|
||||
|
||||
impl SourceFileHash {
|
||||
pub fn new(kind: SourceFileHashAlgorithm, src: &str) -> SourceFileHash {
|
||||
let mut hash = SourceFileHash { kind, value: Default::default() };
|
||||
let len = hash.hash_len();
|
||||
let value = &mut hash.value[..len];
|
||||
let data = src.as_bytes();
|
||||
match kind {
|
||||
SourceFileHashAlgorithm::Md5 => {
|
||||
value.copy_from_slice(&Md5::digest(data));
|
||||
}
|
||||
SourceFileHashAlgorithm::Sha1 => {
|
||||
value.copy_from_slice(&Sha1::digest(data));
|
||||
}
|
||||
}
|
||||
hash
|
||||
}
|
||||
|
||||
/// Check if the stored hash matches the hash of the string.
|
||||
pub fn matches(&self, src: &str) -> bool {
|
||||
Self::new(self.kind, src) == *self
|
||||
}
|
||||
|
||||
/// The bytes of the hash.
|
||||
pub fn hash_bytes(&self) -> &[u8] {
|
||||
let len = self.hash_len();
|
||||
&self.value[..len]
|
||||
}
|
||||
|
||||
fn hash_len(&self) -> usize {
|
||||
match self.kind {
|
||||
SourceFileHashAlgorithm::Md5 => 16,
|
||||
SourceFileHashAlgorithm::Sha1 => 20,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A single source in the `SourceMap`.
|
||||
#[derive(Clone)]
|
||||
pub struct SourceFile {
|
||||
@ -889,7 +958,7 @@ pub struct SourceFile {
|
||||
/// The complete source code.
|
||||
pub src: Option<Lrc<String>>,
|
||||
/// The source code's hash.
|
||||
pub src_hash: u128,
|
||||
pub src_hash: SourceFileHash,
|
||||
/// The external source code (used for external crates, which will have a `None`
|
||||
/// value as `self.src`.
|
||||
pub external_src: Lock<ExternalSource>,
|
||||
@ -987,7 +1056,8 @@ impl Decodable for SourceFile {
|
||||
let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
|
||||
let name_was_remapped: bool =
|
||||
d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?;
|
||||
let src_hash: u128 = d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?;
|
||||
let src_hash: SourceFileHash =
|
||||
d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?;
|
||||
let start_pos: BytePos =
|
||||
d.read_struct_field("start_pos", 3, |d| Decodable::decode(d))?;
|
||||
let end_pos: BytePos = d.read_struct_field("end_pos", 4, |d| Decodable::decode(d))?;
|
||||
@ -1062,14 +1132,12 @@ impl SourceFile {
|
||||
unmapped_path: FileName,
|
||||
mut src: String,
|
||||
start_pos: BytePos,
|
||||
hash_kind: SourceFileHashAlgorithm,
|
||||
) -> Self {
|
||||
// Compute the file hash before any normalization.
|
||||
let src_hash = SourceFileHash::new(hash_kind, &src);
|
||||
let normalized_pos = normalize_src(&mut src, start_pos);
|
||||
|
||||
let src_hash = {
|
||||
let mut hasher: StableHasher = StableHasher::new();
|
||||
hasher.write(src.as_bytes());
|
||||
hasher.finish::<u128>()
|
||||
};
|
||||
let name_hash = {
|
||||
let mut hasher: StableHasher = StableHasher::new();
|
||||
name.hash(&mut hasher);
|
||||
@ -1125,10 +1193,7 @@ impl SourceFile {
|
||||
} = &mut *external_src
|
||||
{
|
||||
if let Some(src) = src {
|
||||
let mut hasher: StableHasher = StableHasher::new();
|
||||
hasher.write(src.as_bytes());
|
||||
|
||||
if hasher.finish::<u128>() == self.src_hash {
|
||||
if self.src_hash.matches(&src) {
|
||||
*src_kind = ExternalSourceKind::Present(Lrc::new(src));
|
||||
return true;
|
||||
}
|
||||
|
@ -141,27 +141,31 @@ pub struct SourceMap {
|
||||
// This is used to apply the file path remapping as specified via
|
||||
// `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`.
|
||||
path_mapping: FilePathMapping,
|
||||
|
||||
/// The algorithm used for hashing the contents of each source file.
|
||||
hash_kind: SourceFileHashAlgorithm,
|
||||
}
|
||||
|
||||
impl SourceMap {
|
||||
pub fn new(path_mapping: FilePathMapping) -> SourceMap {
|
||||
SourceMap {
|
||||
used_address_space: AtomicU32::new(0),
|
||||
files: Default::default(),
|
||||
file_loader: Box::new(RealFileLoader),
|
||||
Self::with_file_loader_and_hash_kind(
|
||||
Box::new(RealFileLoader),
|
||||
path_mapping,
|
||||
}
|
||||
SourceFileHashAlgorithm::Md5,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn with_file_loader(
|
||||
pub fn with_file_loader_and_hash_kind(
|
||||
file_loader: Box<dyn FileLoader + Sync + Send>,
|
||||
path_mapping: FilePathMapping,
|
||||
hash_kind: SourceFileHashAlgorithm,
|
||||
) -> SourceMap {
|
||||
SourceMap {
|
||||
used_address_space: AtomicU32::new(0),
|
||||
files: Default::default(),
|
||||
file_loader,
|
||||
path_mapping,
|
||||
hash_kind,
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,6 +279,7 @@ impl SourceMap {
|
||||
unmapped_path,
|
||||
src,
|
||||
Pos::from_usize(start_pos),
|
||||
self.hash_kind,
|
||||
));
|
||||
|
||||
let mut files = self.files.borrow_mut();
|
||||
@ -296,7 +301,7 @@ impl SourceMap {
|
||||
&self,
|
||||
filename: FileName,
|
||||
name_was_remapped: bool,
|
||||
src_hash: u128,
|
||||
src_hash: SourceFileHash,
|
||||
name_hash: u128,
|
||||
source_len: usize,
|
||||
cnum: CrateNum,
|
||||
|
@ -706,6 +706,30 @@ impl<T: Decodable> Decodable for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for [u8; 20] {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_seq(self.len(), |s| {
|
||||
for (i, e) in self.iter().enumerate() {
|
||||
s.emit_seq_elt(i, |s| e.encode(s))?
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for [u8; 20] {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<[u8; 20], D::Error> {
|
||||
d.read_seq(|d, len| {
|
||||
assert!(len == 20);
|
||||
let mut v = [0u8; 20];
|
||||
for i in 0..len {
|
||||
v[i] = d.read_seq_elt(i, |d| Decodable::decode(d))?;
|
||||
}
|
||||
Ok(v)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Encodable> Encodable for Cow<'a, [T]>
|
||||
where
|
||||
[T]: ToOwned<Owned = Vec<T>>,
|
||||
|
@ -640,6 +640,25 @@ static DICompileUnit::DebugEmissionKind fromRust(LLVMRustDebugEmissionKind Kind)
|
||||
}
|
||||
}
|
||||
|
||||
enum class LLVMRustChecksumKind {
|
||||
None,
|
||||
MD5,
|
||||
SHA1,
|
||||
};
|
||||
|
||||
static Optional<DIFile::ChecksumKind> fromRust(LLVMRustChecksumKind Kind) {
|
||||
switch (Kind) {
|
||||
case LLVMRustChecksumKind::None:
|
||||
return None;
|
||||
case LLVMRustChecksumKind::MD5:
|
||||
return DIFile::ChecksumKind::CSK_MD5;
|
||||
case LLVMRustChecksumKind::SHA1:
|
||||
return DIFile::ChecksumKind::CSK_SHA1;
|
||||
default:
|
||||
report_fatal_error("bad ChecksumKind.");
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" uint32_t LLVMRustDebugMetadataVersion() {
|
||||
return DEBUG_METADATA_VERSION;
|
||||
}
|
||||
@ -686,9 +705,15 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit(
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile(
|
||||
LLVMRustDIBuilderRef Builder,
|
||||
const char *Filename, size_t FilenameLen,
|
||||
const char *Directory, size_t DirectoryLen) {
|
||||
const char *Directory, size_t DirectoryLen, LLVMRustChecksumKind CSKind,
|
||||
const char *Checksum, size_t ChecksumLen) {
|
||||
Optional<DIFile::ChecksumKind> llvmCSKind = fromRust(CSKind);
|
||||
Optional<DIFile::ChecksumInfo<StringRef>> CSInfo{};
|
||||
if (llvmCSKind)
|
||||
CSInfo.emplace(*llvmCSKind, StringRef{Checksum, ChecksumLen});
|
||||
return wrap(Builder->createFile(StringRef(Filename, FilenameLen),
|
||||
StringRef(Directory, DirectoryLen)));
|
||||
StringRef(Directory, DirectoryLen),
|
||||
CSInfo));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
|
@ -22,7 +22,7 @@ fn main() {
|
||||
}
|
||||
|
||||
// Here we check that local debuginfo is mapped correctly.
|
||||
// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: "/the/cwd/")
|
||||
// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: "/the/cwd/"
|
||||
|
||||
// And here that debuginfo from other crates are expanded to absolute paths.
|
||||
// CHECK: !DIFile(filename: "/the/aux-src/remap_path_prefix_aux.rs", directory: "")
|
||||
// CHECK: !DIFile(filename: "/the/aux-src/remap_path_prefix_aux.rs", directory: ""
|
||||
|
@ -11,4 +11,4 @@ pub fn foo() {
|
||||
}
|
||||
|
||||
// Here we check that local debuginfo is mapped correctly.
|
||||
// CHECK: !DIFile(filename: "/the/aux-src/xcrate-generic.rs", directory: "")
|
||||
// CHECK: !DIFile(filename: "/the/aux-src/xcrate-generic.rs", directory: ""
|
||||
|
@ -0,0 +1,6 @@
|
||||
// compile-flags: -g -Z src-hash-algorithm=md5
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
pub fn test() {}
|
||||
// CHECK: checksumkind: CSK_MD5
|
@ -0,0 +1,6 @@
|
||||
// compile-flags: -g -Z src-hash-algorithm=sha1
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
pub fn test() {}
|
||||
// CHECK: checksumkind: CSK_SHA1
|
@ -26,7 +26,6 @@ const LICENSES: &[&str] = &[
|
||||
const EXCEPTIONS: &[(&str, &str)] = &[
|
||||
("mdbook", "MPL-2.0"), // mdbook
|
||||
("openssl", "Apache-2.0"), // cargo, mdbook
|
||||
("arrayref", "BSD-2-Clause"), // mdbook via handlebars via pest
|
||||
("toml-query", "MPL-2.0"), // mdbook
|
||||
("toml-query_derive", "MPL-2.0"), // mdbook
|
||||
("is-match", "MPL-2.0"), // mdbook
|
||||
@ -74,6 +73,9 @@ const WHITELIST: &[&str] = &[
|
||||
"backtrace",
|
||||
"backtrace-sys",
|
||||
"bitflags",
|
||||
"block-buffer",
|
||||
"block-padding",
|
||||
"byte-tools",
|
||||
"byteorder",
|
||||
"c2-chacha",
|
||||
"cc",
|
||||
@ -87,15 +89,18 @@ const WHITELIST: &[&str] = &[
|
||||
"crossbeam-queue",
|
||||
"crossbeam-utils",
|
||||
"datafrog",
|
||||
"digest",
|
||||
"dlmalloc",
|
||||
"either",
|
||||
"ena",
|
||||
"env_logger",
|
||||
"fake-simd",
|
||||
"filetime",
|
||||
"flate2",
|
||||
"fortanix-sgx-abi",
|
||||
"fuchsia-zircon",
|
||||
"fuchsia-zircon-sys",
|
||||
"generic-array",
|
||||
"getopts",
|
||||
"getrandom",
|
||||
"hashbrown",
|
||||
@ -111,6 +116,7 @@ const WHITELIST: &[&str] = &[
|
||||
"lock_api",
|
||||
"log",
|
||||
"log_settings",
|
||||
"md-5",
|
||||
"measureme",
|
||||
"memchr",
|
||||
"memmap",
|
||||
@ -118,6 +124,7 @@ const WHITELIST: &[&str] = &[
|
||||
"miniz_oxide",
|
||||
"nodrop",
|
||||
"num_cpus",
|
||||
"opaque-debug",
|
||||
"parking_lot",
|
||||
"parking_lot_core",
|
||||
"pkg-config",
|
||||
@ -150,6 +157,7 @@ const WHITELIST: &[&str] = &[
|
||||
"semver-parser",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"sha-1",
|
||||
"smallvec",
|
||||
"stable_deref_trait",
|
||||
"syn",
|
||||
@ -159,6 +167,7 @@ const WHITELIST: &[&str] = &[
|
||||
"termion",
|
||||
"termize",
|
||||
"thread_local",
|
||||
"typenum",
|
||||
"ucd-util",
|
||||
"unicode-normalization",
|
||||
"unicode-script",
|
||||
|
Loading…
Reference in New Issue
Block a user