Add missing Debuginfo to PDB debug file on windows.

Set Arg0 and CommandLineArgs in MCTargetoptions so LLVM outputs correct CL and CMD in LF_DEBUGINFO instead of empty/invalid values.
This commit is contained in:
Florian Schmiderer 2023-07-03 13:11:27 +02:00
parent f91c53d738
commit 4cdc633301
16 changed files with 117 additions and 1 deletions

View File

@ -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(),
)
};

View File

@ -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>,

View File

@ -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,

View File

@ -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) {

View File

@ -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 {

View File

@ -68,6 +68,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se
None,
"",
None,
Default::default(),
);
(sess, cfg)
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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 @@ impl Options {
json_unused_externs,
scrape_examples_options,
unstable_features,
expanded_args: args,
};
let render_options = RenderOptions {
output,

View File

@ -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,
}
}

View File

@ -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();

View File

@ -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| {

View 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'

View File

@ -0,0 +1,2 @@
fn main() {
}

View File

@ -0,0 +1 @@
"main.rs" "-g" "--crate-name" "my_crate_name" "--crate-type" "bin" "-C" "metadata=dc9ef878b0a48666" "--out-dir"