1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use rustc::middle::cstore::MetadataLoader;
use rustc_target::spec::Target;
use llvm;
use llvm::{False, ObjectFile, mk_section_iter};
use llvm::archive_ro::ArchiveRO;
use rustc_data_structures::owning_ref::OwningRef;
use std::path::Path;
use std::ptr;
use std::slice;
use rustc_fs_util::path2cstr;
pub use rustc_data_structures::sync::MetadataRef;
pub const METADATA_FILENAME: &str = "rust.metadata.bin";
pub struct LlvmMetadataLoader;
impl MetadataLoader for LlvmMetadataLoader {
fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
let archive = ArchiveRO::open(filename)
.map(|ar| OwningRef::new(box ar))
.map_err(|e| {
debug!("llvm didn't like `{}`: {}", filename.display(), e);
format!("failed to read rlib metadata in '{}': {}", filename.display(), e)
})?;
let buf: OwningRef<_, [u8]> = archive
.try_map(|ar| {
ar.iter()
.filter_map(|s| s.ok())
.find(|sect| sect.name() == Some(METADATA_FILENAME))
.map(|s| s.data())
.ok_or_else(|| {
debug!("didn't find '{}' in the archive", METADATA_FILENAME);
format!("failed to read rlib metadata: '{}'",
filename.display())
})
})?;
Ok(rustc_erase_owner!(buf))
}
fn get_dylib_metadata(&self,
target: &Target,
filename: &Path)
-> Result<MetadataRef, String> {
unsafe {
let buf = path2cstr(filename);
let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr())
.ok_or_else(|| format!("error reading library: '{}'", filename.display()))?;
let of = ObjectFile::new(mb)
.map(|of| OwningRef::new(box of))
.ok_or_else(|| format!("provided path not an object file: '{}'",
filename.display()))?;
let buf = of.try_map(|of| search_meta_section(of, target, filename))?;
Ok(rustc_erase_owner!(buf))
}
}
}
fn search_meta_section<'a>(of: &'a ObjectFile,
target: &Target,
filename: &Path)
-> Result<&'a [u8], String> {
unsafe {
let si = mk_section_iter(of.llof);
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
let mut name_buf = ptr::null();
let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
let name = slice::from_raw_parts(name_buf as *const u8, name_len as usize).to_vec();
let name = String::from_utf8(name).unwrap();
debug!("get_metadata_section: name {}", name);
if read_metadata_section_name(target) == name {
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz);
return Ok(buf);
}
llvm::LLVMMoveToNextSection(si.llsi);
}
}
Err(format!("metadata not found: '{}'", filename.display()))
}
pub fn metadata_section_name(target: &Target) -> &'static str {
if target.options.is_like_osx {
"__DATA,.rustc"
} else {
".rustc"
}
}
fn read_metadata_section_name(_target: &Target) -> &'static str {
".rustc"
}