]>
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 | 8 | use rustc_codegen_ssa::METADATA_FILENAME; |
60c5eb7d XL |
9 | use log::debug; |
10 | use rustc_data_structures::rustc_erase_owner; | |
48663c56 | 11 | |
7cac9316 | 12 | use std::path::Path; |
7cac9316 | 13 | use std::slice; |
a1dfa0c6 | 14 | use rustc_fs_util::path_to_c_string; |
7cac9316 | 15 | |
0531ce1d XL |
16 | pub use rustc_data_structures::sync::MetadataRef; |
17 | ||
7cac9316 XL |
18 | pub struct LlvmMetadataLoader; |
19 | ||
20 | impl 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 | ||
64 | fn 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 | ||
95 | pub 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 | ||
117 | fn read_metadata_section_name(_target: &Target) -> &'static str { | |
118 | ".rustc" | |
119 | } |