]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | use crate::llvm; |
2 | use crate::llvm::{False, ObjectFile, mk_section_iter}; | |
3 | use crate::llvm::archive_ro::ArchiveRO; | |
7cac9316 | 4 | use rustc::middle::cstore::MetadataLoader; |
83c7162d | 5 | use rustc_target::spec::Target; |
7cac9316 | 6 | |
0531ce1d | 7 | use rustc_data_structures::owning_ref::OwningRef; |
48663c56 XL |
8 | use rustc_codegen_ssa::METADATA_FILENAME; |
9 | ||
7cac9316 | 10 | use std::path::Path; |
7cac9316 | 11 | use std::slice; |
a1dfa0c6 | 12 | use rustc_fs_util::path_to_c_string; |
7cac9316 | 13 | |
0531ce1d XL |
14 | pub use rustc_data_structures::sync::MetadataRef; |
15 | ||
7cac9316 XL |
16 | pub struct LlvmMetadataLoader; |
17 | ||
18 | impl MetadataLoader for LlvmMetadataLoader { | |
0531ce1d | 19 | fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> { |
7cac9316 XL |
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)) | |
3b2f2976 XL |
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 | })?; | |
7cac9316 XL |
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(|| { | |
3b2f2976 XL |
36 | debug!("didn't find '{}' in the archive", METADATA_FILENAME); |
37 | format!("failed to read rlib metadata: '{}'", | |
38 | filename.display()) | |
39 | }) | |
7cac9316 | 40 | })?; |
0531ce1d | 41 | Ok(rustc_erase_owner!(buf)) |
7cac9316 XL |
42 | } |
43 | ||
44 | fn get_dylib_metadata(&self, | |
45 | target: &Target, | |
46 | filename: &Path) | |
0531ce1d | 47 | -> Result<MetadataRef, String> { |
7cac9316 | 48 | unsafe { |
a1dfa0c6 | 49 | let buf = path_to_c_string(filename); |
b7449926 XL |
50 | let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()) |
51 | .ok_or_else(|| format!("error reading library: '{}'", filename.display()))?; | |
7cac9316 XL |
52 | let of = ObjectFile::new(mb) |
53 | .map(|of| OwningRef::new(box of)) | |
54 | .ok_or_else(|| format!("provided path not an object file: '{}'", | |
0bf4aa26 | 55 | filename.display()))?; |
7cac9316 | 56 | let buf = of.try_map(|of| search_meta_section(of, target, filename))?; |
0531ce1d | 57 | Ok(rustc_erase_owner!(buf)) |
7cac9316 XL |
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 { | |
416331ca | 69 | let mut name_buf = None; |
7cac9316 | 70 | let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); |
416331ca XL |
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 | ); | |
7cac9316 XL |
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 | } |