aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Somedon <[email protected]>2020-12-11 14:14:42 +0000
committerEdwin Cheng <[email protected]>2021-03-04 01:05:23 +0000
commit6608acef719ea201d8d6ce9df7d8907aa770c959 (patch)
tree77492b99ecc7dc57b34b4d2a9e4a9fd7f8a908d7
parent7275750e42103b5877faeb0fcaff30c9f8a92ea1 (diff)
Read version of rustc that compiled proc macro
With Jay Somedon <[email protected]>
-rw-r--r--Cargo.lock28
-rw-r--r--crates/proc_macro_api/Cargo.toml2
-rw-r--r--crates/proc_macro_api/src/lib.rs82
3 files changed, 100 insertions, 12 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 799127891..b61fd2e98 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -80,7 +80,7 @@ dependencies = [
80 "cfg-if", 80 "cfg-if",
81 "libc", 81 "libc",
82 "miniz_oxide", 82 "miniz_oxide",
83 "object", 83 "object 0.23.0",
84 "rustc-demangle", 84 "rustc-demangle",
85] 85]
86 86
@@ -1010,6 +1010,16 @@ dependencies = [
1010 1010
1011[[package]] 1011[[package]]
1012name = "object" 1012name = "object"
1013version = "0.22.0"
1014source = "registry+https://github.com/rust-lang/crates.io-index"
1015checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
1016dependencies = [
1017 "flate2",
1018 "wasmparser",
1019]
1020
1021[[package]]
1022name = "object"
1013version = "0.23.0" 1023version = "0.23.0"
1014source = "registry+https://github.com/rust-lang/crates.io-index" 1024source = "registry+https://github.com/rust-lang/crates.io-index"
1015checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" 1025checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
@@ -1154,8 +1164,10 @@ dependencies = [
1154 "crossbeam-channel", 1164 "crossbeam-channel",
1155 "jod-thread", 1165 "jod-thread",
1156 "log", 1166 "log",
1167 "object 0.22.0",
1157 "serde", 1168 "serde",
1158 "serde_json", 1169 "serde_json",
1170 "snap",
1159 "stdx", 1171 "stdx",
1160 "tt", 1172 "tt",
1161] 1173]
@@ -1168,7 +1180,7 @@ dependencies = [
1168 "libloading", 1180 "libloading",
1169 "mbe", 1181 "mbe",
1170 "memmap2", 1182 "memmap2",
1171 "object", 1183 "object 0.23.0",
1172 "proc_macro_api", 1184 "proc_macro_api",
1173 "proc_macro_test", 1185 "proc_macro_test",
1174 "serde_derive", 1186 "serde_derive",
@@ -1541,6 +1553,12 @@ dependencies = [
1541] 1553]
1542 1554
1543[[package]] 1555[[package]]
1556name = "snap"
1557version = "1.0.4"
1558source = "registry+https://github.com/rust-lang/crates.io-index"
1559checksum = "dc725476a1398f0480d56cd0ad381f6f32acf2642704456f8f59a35df464b59a"
1560
1561[[package]]
1544name = "socket2" 1562name = "socket2"
1545version = "0.3.19" 1563version = "0.3.19"
1546source = "registry+https://github.com/rust-lang/crates.io-index" 1564source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1881,6 +1899,12 @@ dependencies = [
1881] 1899]
1882 1900
1883[[package]] 1901[[package]]
1902name = "wasmparser"
1903version = "0.57.0"
1904source = "registry+https://github.com/rust-lang/crates.io-index"
1905checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6"
1906
1907[[package]]
1884name = "winapi" 1908name = "winapi"
1885version = "0.3.9" 1909version = "0.3.9"
1886source = "registry+https://github.com/rust-lang/crates.io-index" 1910source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/crates/proc_macro_api/Cargo.toml b/crates/proc_macro_api/Cargo.toml
index f09726223..a72ae236a 100644
--- a/crates/proc_macro_api/Cargo.toml
+++ b/crates/proc_macro_api/Cargo.toml
@@ -19,3 +19,5 @@ jod-thread = "0.1.1"
19tt = { path = "../tt", version = "0.0.0" } 19tt = { path = "../tt", version = "0.0.0" }
20base_db = { path = "../base_db", version = "0.0.0" } 20base_db = { path = "../base_db", version = "0.0.0" }
21stdx = { path = "../stdx", version = "0.0.0" } 21stdx = { path = "../stdx", version = "0.0.0" }
22snap = "1"
23object = "0.22.0"
diff --git a/crates/proc_macro_api/src/lib.rs b/crates/proc_macro_api/src/lib.rs
index 2ea456fb0..cec854746 100644
--- a/crates/proc_macro_api/src/lib.rs
+++ b/crates/proc_macro_api/src/lib.rs
@@ -5,16 +5,11 @@
5//! is used to provide basic infrastructure for communication between two 5//! is used to provide basic infrastructure for communication between two
6//! processes: Client (RA itself), Server (the external program) 6//! processes: Client (RA itself), Server (the external program)
7 7
8mod rpc;
9mod process;
10pub mod msg; 8pub mod msg;
9mod process;
10mod rpc;
11 11
12use std::{ 12use std::{ffi::OsStr, fs::read as fsread, io::{self, Read}, path::{Path, PathBuf}, sync::Arc};
13 ffi::OsStr,
14 io,
15 path::{Path, PathBuf},
16 sync::Arc,
17};
18 13
19use base_db::{Env, ProcMacro}; 14use base_db::{Env, ProcMacro};
20use tt::{SmolStr, Subtree}; 15use tt::{SmolStr, Subtree};
@@ -23,6 +18,9 @@ use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread};
23 18
24pub use rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind}; 19pub use rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind};
25 20
21use object::read::{File as BinaryFile, Object, ObjectSection};
22use snap::read::FrameDecoder as SnapDecoder;
23
26#[derive(Debug, Clone)] 24#[derive(Debug, Clone)]
27struct ProcMacroProcessExpander { 25struct ProcMacroProcessExpander {
28 process: Arc<ProcMacroProcessSrv>, 26 process: Arc<ProcMacroProcessSrv>,
@@ -71,7 +69,10 @@ impl ProcMacroClient {
71 args: impl IntoIterator<Item = impl AsRef<OsStr>>, 69 args: impl IntoIterator<Item = impl AsRef<OsStr>>,
72 ) -> io::Result<ProcMacroClient> { 70 ) -> io::Result<ProcMacroClient> {
73 let (thread, process) = ProcMacroProcessSrv::run(process_path, args)?; 71 let (thread, process) = ProcMacroProcessSrv::run(process_path, args)?;
74 Ok(ProcMacroClient { process: Arc::new(process), thread }) 72 Ok(ProcMacroClient {
73 process: Arc::new(process),
74 thread,
75 })
75 } 76 }
76 77
77 pub fn by_dylib_path(&self, dylib_path: &Path) -> Vec<ProcMacro> { 78 pub fn by_dylib_path(&self, dylib_path: &Path) -> Vec<ProcMacro> {
@@ -98,8 +99,69 @@ impl ProcMacroClient {
98 dylib_path: dylib_path.into(), 99 dylib_path: dylib_path.into(),
99 }); 100 });
100 101
101 ProcMacro { name, kind, expander } 102 ProcMacro {
103 name,
104 kind,
105 expander,
106 }
102 }) 107 })
103 .collect() 108 .collect()
104 } 109 }
110
111 // This is used inside self.read_version() to locate the ".rustc" section
112 // from a proc macro crate's binary file.
113 fn read_section<'a>(&self, dylib_binary: &'a [u8], section_name: &str) -> &'a [u8] {
114 BinaryFile::parse(dylib_binary)
115 .unwrap()
116 .section_by_name(section_name)
117 .unwrap()
118 .data()
119 .unwrap()
120 }
121
122 // Check the version of rustc that was used to compile a proc macro crate's
123 // binary file.
124 // A proc macro crate binary's ".rustc" section has following byte layout:
125 // * [b'r',b'u',b's',b't',0,0,0,5] is the first 8 bytes
126 // * ff060000 734e6150 is followed, it's the snappy format magic bytes,
127 // means bytes from here(including this sequence) are compressed in
128 // snappy compression format. Version info is here inside, so decompress
129 // this.
130 // The bytes you get after decompressing the snappy format portion has
131 // following layout:
132 // * [b'r',b'u',b's',b't',0,0,0,5] is the first 8 bytes(again)
133 // * [crate root bytes] next 4 bytes is to store crate root position,
134 // according to rustc's source code comment
135 // * [length byte] next 1 byte tells us how many bytes we should read next
136 // for the version string's utf8 bytes
137 // * [version string bytes encoded in utf8] <- GET THIS BOI
138 // * [some more bytes that we don really care but still there] :-)
139 // Check this issue for more about the bytes layout:
140 // https://github.com/rust-analyzer/rust-analyzer/issues/6174
141 fn read_version(&self, dylib_path: &Path) -> String {
142 let dylib_binary = fsread(dylib_path).unwrap();
143
144 let dot_rustc = self.read_section(&dylib_binary, ".rustc");
145
146 let snappy_portion = &dot_rustc[8..];
147
148 let mut snappy_decoder = SnapDecoder::new(snappy_portion);
149
150 // the bytes before version string bytes, so this basically is:
151 // 8 bytes for [b'r',b'u',b's',b't',0,0,0,5]
152 // 4 bytes for [crate root bytes]
153 // 1 byte for length of version string
154 // so 13 bytes in total, and we should check the 13th byte
155 // to know the length
156 let mut bytes_before_version = [0u8; 13];
157 snappy_decoder
158 .read_exact(&mut bytes_before_version)
159 .unwrap();
160 let length = bytes_before_version[12]; // what? can't use -1 indexing?
161
162 let mut version_string_utf8 = vec![0u8; length as usize];
163 snappy_decoder.read_exact(&mut version_string_utf8).unwrap();
164 let version_string = String::from_utf8(version_string_utf8).unwrap();
165 version_string
166 }
105} 167}