2 use crate::llvm::{False, ObjectFile, mk_section_iter};
3 use crate::llvm::archive_ro::ArchiveRO;
4 use rustc::middle::cstore::MetadataLoader;
5 use rustc_target::spec::Target;
7 use rustc_data_structures::owning_ref::OwningRef;
8 use rustc_codegen_ssa::METADATA_FILENAME;
13 use rustc_fs_util::path_to_c_string;
15 pub use rustc_data_structures::sync::MetadataRef;
17 pub struct LlvmMetadataLoader;
19 impl MetadataLoader for LlvmMetadataLoader {
20 fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
21 // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
22 // internally to read the file. We also avoid even using a memcpy by
23 // just keeping the archive along while the metadata is in use.
24 let archive = ArchiveRO::open(filename)
25 .map(|ar| OwningRef::new(box ar))
27 debug!("llvm didn't like `{}`: {}", filename.display(), e);
28 format!("failed to read rlib metadata in '{}': {}", filename.display(), e)
30 let buf: OwningRef<_, [u8]> = archive
33 .filter_map(|s| s.ok())
34 .find(|sect| sect.name() == Some(METADATA_FILENAME))
37 debug!("didn't find '{}' in the archive", METADATA_FILENAME);
38 format!("failed to read rlib metadata: '{}'",
42 Ok(rustc_erase_owner!(buf))
45 fn get_dylib_metadata(&self,
48 -> Result<MetadataRef, String> {
50 let buf = path_to_c_string(filename);
51 let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr())
52 .ok_or_else(|| format!("error reading library: '{}'", filename.display()))?;
53 let of = ObjectFile::new(mb)
54 .map(|of| OwningRef::new(box of))
55 .ok_or_else(|| format!("provided path not an object file: '{}'",
56 filename.display()))?;
57 let buf = of.try_map(|of| search_meta_section(of, target, filename))?;
58 Ok(rustc_erase_owner!(buf))
63 fn search_meta_section<'a>(of: &'a ObjectFile,
66 -> Result<&'a [u8], String> {
68 let si = mk_section_iter(of.llof);
69 while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
70 let mut name_buf = ptr::null();
71 let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
72 let name = slice::from_raw_parts(name_buf as *const u8, name_len as usize).to_vec();
73 let name = String::from_utf8(name).unwrap();
74 debug!("get_metadata_section: name {}", name);
75 if read_metadata_section_name(target) == name {
76 let cbuf = llvm::LLVMGetSectionContents(si.llsi);
77 let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
78 // The buffer is valid while the object file is around
79 let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz);
82 llvm::LLVMMoveToNextSection(si.llsi);
85 Err(format!("metadata not found: '{}'", filename.display()))
88 pub fn metadata_section_name(target: &Target) -> &'static str {
91 // When using link.exe it was seen that the section name `.note.rustc`
92 // was getting shortened to `.note.ru`, and according to the PE and COFF
95 // > Executable images do not use a string table and do not support
96 // > section names longer than 8 characters
98 // https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx
100 // As a result, we choose a slightly shorter name! As to why
101 // `.note.rustc` works on MinGW, that's another good question...
103 if target.options.is_like_osx {
110 fn read_metadata_section_name(_target: &Target) -> &'static str {