2019-02-18 03:58:58 +09:00
|
|
|
|
use crate::llvm;
|
|
|
|
|
use crate::llvm::archive_ro::ArchiveRO;
|
2019-12-22 17:42:04 -05:00
|
|
|
|
use crate::llvm::{mk_section_iter, False, ObjectFile};
|
2020-03-29 16:41:09 +02:00
|
|
|
|
use rustc_middle::middle::cstore::MetadataLoader;
|
2017-12-08 21:18:21 +02:00
|
|
|
|
use rustc_target::spec::Target;
|
2017-04-26 23:22:45 +02:00
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
|
use rustc_codegen_ssa::METADATA_FILENAME;
|
|
|
|
|
use rustc_data_structures::owning_ref::OwningRef;
|
2019-10-22 08:51:35 -07:00
|
|
|
|
use rustc_data_structures::rustc_erase_owner;
|
2020-08-05 17:05:53 +05:30
|
|
|
|
use tracing::debug;
|
2019-03-30 13:03:52 +01:00
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
|
use rustc_fs_util::path_to_c_string;
|
2017-04-26 23:22:45 +02:00
|
|
|
|
use std::path::Path;
|
|
|
|
|
use std::slice;
|
|
|
|
|
|
2018-03-03 06:17:06 +01:00
|
|
|
|
pub use rustc_data_structures::sync::MetadataRef;
|
|
|
|
|
|
2017-04-26 23:22:45 +02:00
|
|
|
|
pub struct LlvmMetadataLoader;
|
|
|
|
|
|
|
|
|
|
impl MetadataLoader for LlvmMetadataLoader {
|
2018-03-03 06:17:06 +01:00
|
|
|
|
fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
|
2017-04-26 23:22:45 +02:00
|
|
|
|
// Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
|
|
|
|
|
// internally to read the file. We also avoid even using a memcpy by
|
|
|
|
|
// just keeping the archive along while the metadata is in use.
|
2019-12-23 16:26:53 +01:00
|
|
|
|
let archive =
|
|
|
|
|
ArchiveRO::open(filename).map(|ar| OwningRef::new(Box::new(ar))).map_err(|e| {
|
|
|
|
|
debug!("llvm didn't like `{}`: {}", filename.display(), e);
|
|
|
|
|
format!("failed to read rlib metadata in '{}': {}", filename.display(), e)
|
|
|
|
|
})?;
|
2019-12-22 17:42:04 -05:00
|
|
|
|
let buf: OwningRef<_, [u8]> = archive.try_map(|ar| {
|
|
|
|
|
ar.iter()
|
|
|
|
|
.filter_map(|s| s.ok())
|
|
|
|
|
.find(|sect| sect.name() == Some(METADATA_FILENAME))
|
|
|
|
|
.map(|s| s.data())
|
|
|
|
|
.ok_or_else(|| {
|
|
|
|
|
debug!("didn't find '{}' in the archive", METADATA_FILENAME);
|
|
|
|
|
format!("failed to read rlib metadata: '{}'", filename.display())
|
|
|
|
|
})
|
|
|
|
|
})?;
|
2018-03-03 06:17:06 +01:00
|
|
|
|
Ok(rustc_erase_owner!(buf))
|
2017-04-26 23:22:45 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
|
fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
|
2017-04-26 23:22:45 +02:00
|
|
|
|
unsafe {
|
2018-11-29 08:09:28 -05:00
|
|
|
|
let buf = path_to_c_string(filename);
|
2018-07-10 19:19:17 +03:00
|
|
|
|
let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr())
|
|
|
|
|
.ok_or_else(|| format!("error reading library: '{}'", filename.display()))?;
|
2019-12-23 16:26:53 +01:00
|
|
|
|
let of =
|
|
|
|
|
ObjectFile::new(mb).map(|of| OwningRef::new(Box::new(of))).ok_or_else(|| {
|
|
|
|
|
format!("provided path not an object file: '{}'", filename.display())
|
|
|
|
|
})?;
|
2017-04-26 23:22:45 +02:00
|
|
|
|
let buf = of.try_map(|of| search_meta_section(of, target, filename))?;
|
2018-03-03 06:17:06 +01:00
|
|
|
|
Ok(rustc_erase_owner!(buf))
|
2017-04-26 23:22:45 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
|
fn search_meta_section<'a>(
|
|
|
|
|
of: &'a ObjectFile,
|
|
|
|
|
target: &Target,
|
|
|
|
|
filename: &Path,
|
|
|
|
|
) -> Result<&'a [u8], String> {
|
2017-04-26 23:22:45 +02:00
|
|
|
|
unsafe {
|
|
|
|
|
let si = mk_section_iter(of.llof);
|
|
|
|
|
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
|
2019-03-27 15:57:14 +01:00
|
|
|
|
let mut name_buf = None;
|
2017-04-26 23:22:45 +02:00
|
|
|
|
let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
|
2019-03-27 15:57:14 +01:00
|
|
|
|
let name = name_buf.map_or(
|
2019-06-24 23:15:37 +02:00
|
|
|
|
String::new(), // We got a NULL ptr, ignore `name_len`.
|
2019-12-22 17:42:04 -05:00
|
|
|
|
|buf| {
|
|
|
|
|
String::from_utf8(
|
|
|
|
|
slice::from_raw_parts(buf.as_ptr() as *const u8, name_len as usize)
|
|
|
|
|
.to_vec(),
|
|
|
|
|
)
|
|
|
|
|
.unwrap()
|
|
|
|
|
},
|
2019-06-24 23:15:37 +02:00
|
|
|
|
);
|
2017-04-26 23:22:45 +02:00
|
|
|
|
debug!("get_metadata_section: name {}", name);
|
|
|
|
|
if read_metadata_section_name(target) == name {
|
|
|
|
|
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
|
|
|
|
|
let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
|
|
|
|
|
// The buffer is valid while the object file is around
|
|
|
|
|
let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz);
|
|
|
|
|
return Ok(buf);
|
|
|
|
|
}
|
|
|
|
|
llvm::LLVMMoveToNextSection(si.llsi);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Err(format!("metadata not found: '{}'", filename.display()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn metadata_section_name(target: &Target) -> &'static str {
|
|
|
|
|
// Historical note:
|
|
|
|
|
//
|
|
|
|
|
// When using link.exe it was seen that the section name `.note.rustc`
|
|
|
|
|
// was getting shortened to `.note.ru`, and according to the PE and COFF
|
|
|
|
|
// specification:
|
|
|
|
|
//
|
|
|
|
|
// > Executable images do not use a string table and do not support
|
|
|
|
|
// > section names longer than 8 characters
|
|
|
|
|
//
|
2019-12-25 15:35:54 +00:00
|
|
|
|
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
|
2017-04-26 23:22:45 +02:00
|
|
|
|
//
|
|
|
|
|
// As a result, we choose a slightly shorter name! As to why
|
|
|
|
|
// `.note.rustc` works on MinGW, that's another good question...
|
|
|
|
|
|
2020-11-08 14:27:51 +03:00
|
|
|
|
if target.is_like_osx { "__DATA,.rustc" } else { ".rustc" }
|
2017-04-26 23:22:45 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn read_metadata_section_name(_target: &Target) -> &'static str {
|
|
|
|
|
".rustc"
|
|
|
|
|
}
|