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