Auto merge of #113492 - nebulark:pr_96475, r=petrochenkov
Add CL and CMD into to pdb debug info
Partial fix for https://github.com/rust-lang/rust/issues/96475
The Arg0 and CommandLineArgs of the MCTargetOptions cpp class are not set within bb548f9645/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp (L378)
This causes LLVM to not neither output any compiler path (cl) nor the arguments that were used when invoking it (cmd) in the PDB file.
This fix adds the missing information to the target machine so LLVM can use it.
This commit is contained in:
commit
9be4eac264
@ -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<u8> = 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(),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -2132,7 +2132,10 @@ pub fn LLVMRustCreateTargetMachine(
|
||||
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>,
|
||||
|
@ -343,6 +343,12 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
||||
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<String>,
|
||||
|
||||
/// 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<B: ExtraBackendMethods>(
|
||||
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,
|
||||
|
@ -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) {
|
||||
|
@ -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<String>,
|
||||
}
|
||||
|
||||
// JUSTIFICATION: before session exists, only config
|
||||
@ -317,6 +323,7 @@ pub fn run_compiler<R: Send>(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 {
|
||||
|
@ -68,6 +68,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se
|
||||
None,
|
||||
"",
|
||||
None,
|
||||
Default::default(),
|
||||
);
|
||||
(sess, cfg)
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ pub fn create_session(
|
||||
>,
|
||||
descriptions: Registry,
|
||||
ice_file: Option<PathBuf>,
|
||||
expanded_args: Vec<String>,
|
||||
) -> (Session, Box<dyn CodegenBackend>) {
|
||||
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);
|
||||
|
@ -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<std::string>(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);
|
||||
}
|
||||
|
||||
|
@ -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<String>,
|
||||
}
|
||||
|
||||
pub struct PerfStats {
|
||||
@ -1325,6 +1331,7 @@ pub fn build_session(
|
||||
target_override: Option<Target>,
|
||||
cfg_version: &'static str,
|
||||
ice_file: Option<PathBuf>,
|
||||
expanded_args: Vec<String>,
|
||||
) -> 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);
|
||||
|
@ -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<String>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Options {
|
||||
@ -744,6 +750,7 @@ fn println_condition(condition: Condition) {
|
||||
json_unused_externs,
|
||||
scrape_examples_options,
|
||||
unstable_features,
|
||||
expanded_args: args,
|
||||
};
|
||||
let render_options = RenderOptions {
|
||||
output,
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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| {
|
||||
|
16
tests/run-make/pdb-buildinfo-cl-cmd/Makefile
Normal file
16
tests/run-make/pdb-buildinfo-cl-cmd/Makefile
Normal file
@ -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'
|
2
tests/run-make/pdb-buildinfo-cl-cmd/main.rs
Normal file
2
tests/run-make/pdb-buildinfo-cl-cmd/main.rs
Normal file
@ -0,0 +1,2 @@
|
||||
fn main() {
|
||||
}
|
1
tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt
Normal file
1
tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt
Normal file
@ -0,0 +1 @@
|
||||
"main.rs" "-g" "--crate-name" "my_crate_name" "--crate-type" "bin" "-C" "metadata=dc9ef878b0a48666" "--out-dir"
|
Loading…
Reference in New Issue
Block a user