diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 47cc5bd52e2..c49d322fc00 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -216,6 +216,24 @@ pub fn target_machine_factory( let force_emulated_tls = sess.target.force_emulated_tls; + // copy the exe path, followed by path all into one buffer + // null terminating them so we can use them as null terminated strings + let args_cstr_buff = { + let mut args_cstr_buff: Vec = Vec::new(); + let exe_path = std::env::current_exe().unwrap_or_default(); + let exe_path_str = exe_path.into_os_string().into_string().unwrap_or_default(); + + args_cstr_buff.extend_from_slice(exe_path_str.as_bytes()); + args_cstr_buff.push(0); + + for arg in sess.expanded_args.iter() { + args_cstr_buff.extend_from_slice(arg.as_bytes()); + args_cstr_buff.push(0); + } + + args_cstr_buff + }; + Arc::new(move |config: TargetMachineFactoryConfig| { let split_dwarf_file = path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0; @@ -242,6 +260,8 @@ pub fn target_machine_factory( use_init_array, split_dwarf_file.as_ptr(), force_emulated_tls, + args_cstr_buff.as_ptr() as *const c_char, + args_cstr_buff.len(), ) }; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 01cbf7d3b11..1f03c932cfd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2132,7 +2132,10 @@ extern "C" { UseInitArray: bool, SplitDwarfFile: *const c_char, ForceEmulatedTls: bool, + ArgsCstrBuff: *const c_char, + ArgsCstrBuffLen: usize, ) -> Option<&'static mut TargetMachine>; + pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine); pub fn LLVMRustAddLibraryInfo<'a>( PM: &PassManager<'a>, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index f485af00bca..3bf98c46dea 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -343,6 +343,12 @@ pub struct CodegenContext { pub split_debuginfo: rustc_target::spec::SplitDebuginfo, pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, + /// All commandline args used to invoke the compiler, with @file args fully expanded. + /// This will only be used within debug info, e.g. in the pdb file on windows + /// This is mainly useful for other tools that reads that debuginfo to figure out + /// how to call the compiler with the same arguments. + pub expanded_args: Vec, + /// Handler to use for diagnostics produced during codegen. pub diag_emitter: SharedEmitter, /// LLVM optimizations for which we want to print remarks. @@ -1108,6 +1114,7 @@ fn start_executing_work( incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()), cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(), coordinator_send, + expanded_args: tcx.sess.expanded_args.clone(), diag_emitter: shared_emitter.clone(), output_filenames: tcx.output_filenames(()).clone(), regular_module_config: regular_config, diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 1a16759d7f9..e56347ab38e 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -313,6 +313,7 @@ fn run_compiler( override_queries: None, make_codegen_backend, registry: diagnostics_registry(), + expanded_args: args, }; match make_input(&early_error_handler, &matches.free) { diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 5b417e008cf..a0f0b530bae 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -279,6 +279,12 @@ pub struct Config { /// Registry of diagnostics codes. pub registry: Registry, + + /// All commandline args used to invoke the compiler, with @file args fully expanded. + /// This will only be used within debug info, e.g. in the pdb file on windows + /// This is mainly useful for other tools that reads that debuginfo to figure out + /// how to call the compiler with the same arguments. + pub expanded_args: Vec, } // JUSTIFICATION: before session exists, only config @@ -317,6 +323,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.make_codegen_backend, registry.clone(), config.ice_file, + config.expanded_args, ); if let Some(parse_sess_created) = config.parse_sess_created { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index b53ba251bcd..ccf8b5630d4 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -68,6 +68,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se None, "", None, + Default::default(), ); (sess, cfg) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 5c9b39cdbe3..37e242c6e40 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -71,6 +71,7 @@ pub fn create_session( >, descriptions: Registry, ice_file: Option, + expanded_args: Vec, ) -> (Session, Box) { let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend { make_codegen_backend(&sopts) @@ -113,6 +114,7 @@ pub fn create_session( target_override, rustc_version_str().unwrap_or("unknown"), ice_file, + expanded_args, ); codegen_backend.init(&sess); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 8f8f1d8c04f..f01f351fa45 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -406,7 +406,8 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( bool RelaxELFRelocations, bool UseInitArray, const char *SplitDwarfFile, - bool ForceEmulatedTls) { + bool ForceEmulatedTls, + const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) { auto OptLevel = fromRust(RustOptLevel); auto RM = fromRust(RustReloc); @@ -462,12 +463,48 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.EmitStackSizeSection = EmitStackSizeSection; + + if (ArgsCstrBuff != nullptr) + { + int buffer_offset = 0; + assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0'); + + const size_t arg0_len = std::strlen(ArgsCstrBuff); + char* arg0 = new char[arg0_len + 1]; + memcpy(arg0, ArgsCstrBuff, arg0_len); + arg0[arg0_len] = '\0'; + buffer_offset += arg0_len + 1; + + const int num_cmd_arg_strings = + std::count(&ArgsCstrBuff[buffer_offset], &ArgsCstrBuff[ArgsCstrBuffLen], '\0'); + + std::string* cmd_arg_strings = new std::string[num_cmd_arg_strings]; + for (int i = 0; i < num_cmd_arg_strings; ++i) + { + assert(buffer_offset < ArgsCstrBuffLen); + const int len = std::strlen(ArgsCstrBuff + buffer_offset); + cmd_arg_strings[i] = std::string(&ArgsCstrBuff[buffer_offset], len); + buffer_offset += len + 1; + } + + assert(buffer_offset == ArgsCstrBuffLen); + + Options.MCOptions.Argv0 = arg0; + Options.MCOptions.CommandLineArgs = + llvm::ArrayRef(cmd_arg_strings, num_cmd_arg_strings); + } + TargetMachine *TM = TheTarget->createTargetMachine( Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel); return wrap(TM); } extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) { + + MCTargetOptions& MCOptions = unwrap(TM)->Options.MCOptions; + delete[] MCOptions.Argv0; + delete[] MCOptions.CommandLineArgs.data(); + delete unwrap(TM); } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 86db2edab7b..9bff9017881 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -204,6 +204,12 @@ pub struct Session { /// The version of the rustc process, possibly including a commit hash and description. pub cfg_version: &'static str, + + /// All commandline args used to invoke the compiler, with @file args fully expanded. + /// This will only be used within debug info, e.g. in the pdb file on windows + /// This is mainly useful for other tools that reads that debuginfo to figure out + /// how to call the compiler with the same arguments. + pub expanded_args: Vec, } pub struct PerfStats { @@ -1325,6 +1331,7 @@ pub fn build_session( target_override: Option, cfg_version: &'static str, ice_file: Option, + expanded_args: Vec, ) -> Session { // 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 @@ -1467,6 +1474,7 @@ pub fn build_session( target_features: Default::default(), unstable_target_features: Default::default(), cfg_version, + expanded_args, }; validate_commandline_args_with_session_available(&sess); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 1ce7efdfc20..974dc1c5135 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -157,6 +157,12 @@ pub(crate) struct Options { /// Note: this field is duplicated in `RenderOptions` because it's useful /// to have it in both places. pub(crate) unstable_features: rustc_feature::UnstableFeatures, + + /// All commandline args used to invoke the compiler, with @file args fully expanded. + /// This will only be used within debug info, e.g. in the pdb file on windows + /// This is mainly useful for other tools that reads that debuginfo to figure out + /// how to call the compiler with the same arguments. + pub(crate) expanded_args: Vec, } impl fmt::Debug for Options { @@ -744,6 +750,7 @@ impl Options { json_unused_externs, scrape_examples_options, unstable_features, + expanded_args: args, }; let render_options = RenderOptions { output, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index eadff37b592..7cd25ef444b 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -194,6 +194,7 @@ pub(crate) fn create_config( describe_lints, lint_cap, scrape_examples_options, + expanded_args, .. }: RustdocOptions, RenderOptions { document_private, .. }: &RenderOptions, @@ -291,6 +292,7 @@ pub(crate) fn create_config( make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, + expanded_args, } } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 36d5adb6304..bb7d26c541b 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -109,6 +109,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, + expanded_args: options.expanded_args.clone(), }; let test_args = options.test_args.clone(); diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs index 68132638759..1c9d33dcc8e 100644 --- a/tests/run-make-fulldeps/issue-19371/foo.rs +++ b/tests/run-make-fulldeps/issue-19371/foo.rs @@ -61,6 +61,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { override_queries: None, make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), + expanded_args: Default::default(), }; interface::run_compiler(config, |compiler| { diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/Makefile b/tests/run-make/pdb-buildinfo-cl-cmd/Makefile new file mode 100644 index 00000000000..a7be301a5b0 --- /dev/null +++ b/tests/run-make/pdb-buildinfo-cl-cmd/Makefile @@ -0,0 +1,16 @@ +include ../tools.mk + +# only-windows-msvc + +# tests if the pdb contains the following information in the LF_BUILDINFO: +# 1. the commandline args to compile it (cmd) +# 2. full path to the compiler (cl) + +# we just do a stringsearch on the pdb, as these need to show up at least once, as the LF_BUILDINFO is created for each cgu +# actual parsing would be better, but this is a simple and good enough solution for now + +all: + $(RUSTC_ORIGINAL) main.rs -g --crate-name my_crate_name --crate-type bin -C metadata=dc9ef878b0a48666 --out-dir $(TMPDIR) + cat '$(TMPDIR)/my_crate_name.pdb' | grep -F '$(RUSTC_ORIGINAL)' +# using a file containing the string so I don't have problems with escaping quotes and spaces + cat '$(TMPDIR)/my_crate_name.pdb' | grep -f 'stringlist.txt' diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/main.rs b/tests/run-make/pdb-buildinfo-cl-cmd/main.rs new file mode 100644 index 00000000000..f79c691f085 --- /dev/null +++ b/tests/run-make/pdb-buildinfo-cl-cmd/main.rs @@ -0,0 +1,2 @@ +fn main() { +} diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt b/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt new file mode 100644 index 00000000000..634e9f19e89 --- /dev/null +++ b/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt @@ -0,0 +1 @@ +"main.rs" "-g" "--crate-name" "my_crate_name" "--crate-type" "bin" "-C" "metadata=dc9ef878b0a48666" "--out-dir" \ No newline at end of file