]> git.proxmox.com Git - rustc.git/blame - src/librustc_codegen_llvm/metadata.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / librustc_codegen_llvm / metadata.rs
CommitLineData
9fa01778
XL
1use crate::llvm;
2use crate::llvm::{False, ObjectFile, mk_section_iter};
3use crate::llvm::archive_ro::ArchiveRO;
7cac9316 4use rustc::middle::cstore::MetadataLoader;
83c7162d 5use rustc_target::spec::Target;
7cac9316 6
0531ce1d 7use rustc_data_structures::owning_ref::OwningRef;
48663c56 8use rustc_codegen_ssa::METADATA_FILENAME;
60c5eb7d
XL
9use log::debug;
10use rustc_data_structures::rustc_erase_owner;
48663c56 11
7cac9316 12use std::path::Path;
7cac9316 13use std::slice;
a1dfa0c6 14use rustc_fs_util::path_to_c_string;
7cac9316 15
0531ce1d
XL
16pub use rustc_data_structures::sync::MetadataRef;
17
7cac9316
XL
18pub struct LlvmMetadataLoader;
19
20impl MetadataLoader for LlvmMetadataLoader {
0531ce1d 21 fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
7cac9316
XL
22 // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
23 // internally to read the file. We also avoid even using a memcpy by
24 // just keeping the archive along while the metadata is in use.
25 let archive = ArchiveRO::open(filename)
26 .map(|ar| OwningRef::new(box ar))
3b2f2976
XL
27 .map_err(|e| {
28 debug!("llvm didn't like `{}`: {}", filename.display(), e);
29 format!("failed to read rlib metadata in '{}': {}", filename.display(), e)
30 })?;
7cac9316
XL
31 let buf: OwningRef<_, [u8]> = archive
32 .try_map(|ar| {
33 ar.iter()
34 .filter_map(|s| s.ok())
35 .find(|sect| sect.name() == Some(METADATA_FILENAME))
36 .map(|s| s.data())
37 .ok_or_else(|| {
3b2f2976
XL
38 debug!("didn't find '{}' in the archive", METADATA_FILENAME);
39 format!("failed to read rlib metadata: '{}'",
40 filename.display())
41 })
7cac9316 42 })?;
0531ce1d 43 Ok(rustc_erase_owner!(buf))
7cac9316
XL
44 }
45
46 fn get_dylib_metadata(&self,
47 target: &Target,
48 filename: &Path)
0531ce1d 49 -> Result<MetadataRef, String> {
7cac9316 50 unsafe {
a1dfa0c6 51 let buf = path_to_c_string(filename);
b7449926
XL
52 let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr())
53 .ok_or_else(|| format!("error reading library: '{}'", filename.display()))?;
7cac9316
XL
54 let of = ObjectFile::new(mb)
55 .map(|of| OwningRef::new(box of))
56 .ok_or_else(|| format!("provided path not an object file: '{}'",
0bf4aa26 57 filename.display()))?;
7cac9316 58 let buf = of.try_map(|of| search_meta_section(of, target, filename))?;
0531ce1d 59 Ok(rustc_erase_owner!(buf))
7cac9316
XL
60 }
61 }
62}
63
64fn search_meta_section<'a>(of: &'a ObjectFile,
65 target: &Target,
66 filename: &Path)
67 -> Result<&'a [u8], String> {
68 unsafe {
69 let si = mk_section_iter(of.llof);
70 while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
416331ca 71 let mut name_buf = None;
7cac9316 72 let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
416331ca
XL
73 let name = name_buf.map_or(
74 String::new(), // We got a NULL ptr, ignore `name_len`.
75 |buf| String::from_utf8(
76 slice::from_raw_parts(buf.as_ptr() as *const u8,
77 name_len as usize)
78 .to_vec()
79 ).unwrap()
80 );
7cac9316
XL
81 debug!("get_metadata_section: name {}", name);
82 if read_metadata_section_name(target) == name {
83 let cbuf = llvm::LLVMGetSectionContents(si.llsi);
84 let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
85 // The buffer is valid while the object file is around
86 let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz);
87 return Ok(buf);
88 }
89 llvm::LLVMMoveToNextSection(si.llsi);
90 }
91 }
92 Err(format!("metadata not found: '{}'", filename.display()))
93}
94
95pub fn metadata_section_name(target: &Target) -> &'static str {
96 // Historical note:
97 //
98 // When using link.exe it was seen that the section name `.note.rustc`
99 // was getting shortened to `.note.ru`, and according to the PE and COFF
100 // specification:
101 //
102 // > Executable images do not use a string table and do not support
103 // > section names longer than 8 characters
104 //
105 // https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx
106 //
107 // As a result, we choose a slightly shorter name! As to why
108 // `.note.rustc` works on MinGW, that's another good question...
109
110 if target.options.is_like_osx {
111 "__DATA,.rustc"
112 } else {
113 ".rustc"
114 }
115}
116
117fn read_metadata_section_name(_target: &Target) -> &'static str {
118 ".rustc"
119}