Skip to content

Commit 636c3db

Browse files
authored
Merge pull request #209 from madsmtm/demangle-assembly-tests
Demangle symbols in assembly tests
2 parents 38e41e5 + d6c7309 commit 636c3db

File tree

2 files changed

+174
-2
lines changed

2 files changed

+174
-2
lines changed

test-assembly/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ license = "MIT"
1010
build = "build.rs"
1111

1212
[features]
13-
run = ["cargo_metadata"]
13+
run = ["cargo_metadata", "rustc-demangle", "regex", "lazy_static"]
1414

1515
[dependencies]
1616
cargo_metadata = { version = "0.14", optional = true }
17+
rustc-demangle = { version = "0.1", optional = true }
18+
regex = { version = "1.6", optional = true }
19+
lazy_static = { version = "1.4.0", optional = true }

test-assembly/src/lib.rs

Lines changed: 170 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ pub fn read_assembly<P: AsRef<Path>>(path: P) -> io::Result<String> {
5858
// they're uninteresting for out use-case.
5959
//
6060
// See https://github.com/rust-lang/rust/blob/1.59.0/compiler/rustc_codegen_llvm/src/back/write.rs#L978-L1074
61-
Ok(strip_section(&s, "__LLVM"))
61+
let s = strip_section(&s, "__LLVM");
62+
let s = demangle_assembly(&s);
63+
Ok(s)
6264
}
6365

6466
#[cfg(feature = "run")]
@@ -89,3 +91,170 @@ pub fn get_artifact(result_stream: &[u8], package: &str) -> PathBuf {
8991
pub fn get_artifact(_result_stream: &[u8], _package: &str) -> PathBuf {
9092
panic!("`run` feature must be enabled")
9193
}
94+
95+
/// VERY BRITTLE!
96+
#[cfg(feature = "run")]
97+
fn demangle_assembly(assembly: &str) -> String {
98+
use std::collections::HashMap;
99+
100+
use lazy_static::lazy_static;
101+
use regex::Captures;
102+
use regex::Regex;
103+
104+
lazy_static! {
105+
// All identifiers
106+
static ref RE_IDENT: Regex = Regex::new(r"[a-zA-Z_][a-zA-Z_0-9]*").unwrap();
107+
108+
// Replace crate ID that the compiler inserts
109+
//
110+
// Example: test_msg_send_static_sel[f7bb0e08e35403f3]::handle_with_sel::NAME_DATA
111+
// Becomes: test_msg_send_static_sel[CRATE_ID]::handle_with_sel::NAME_DATA
112+
static ref RE_CRATE_ID: Regex = Regex::new(r"\[.*\]").unwrap();
113+
114+
// Replace last part of symbol if it looks to be autogenerated
115+
//
116+
// Example: objc2_foundation::__string_macro::CFStringUtf16::as_ptr::hbadb49a829a98ec7
117+
// Becomes: objc2_foundation::__string_macro::CFStringUtf16::as_ptr::GENERATED_ID
118+
static ref RE_LAST: Regex = Regex::new(r"[a-z0-9]{17}$").unwrap();
119+
}
120+
121+
// Demangled name -> List of seen mangled names for this demangled name
122+
let mut demangle_unique: HashMap<String, Vec<String>> = HashMap::new();
123+
124+
// Find all identifiers, and attempt to demangle them
125+
RE_IDENT
126+
.replace_all(assembly, |caps: &Captures| {
127+
let ident = caps.get(0).unwrap().as_str();
128+
match rustc_demangle::try_demangle(ident) {
129+
Ok(s) => {
130+
let s = s.to_string();
131+
let s = RE_CRATE_ID.replace_all(&s, "[CRATE_ID]");
132+
let s = RE_LAST.replace(&s, "GENERATED_ID");
133+
let list_for_this_symbol = demangle_unique
134+
.entry(s.to_string())
135+
.or_insert_with(|| vec![ident.to_string()]);
136+
let unique_identifier = list_for_this_symbol
137+
.iter()
138+
.position(|x| x == ident)
139+
.unwrap_or_else(|| {
140+
list_for_this_symbol.push(ident.to_string());
141+
list_for_this_symbol.len() - 1
142+
});
143+
144+
format!("SYM({}, {})", s, unique_identifier)
145+
}
146+
Err(_) => ident.to_string(),
147+
}
148+
})
149+
.to_string()
150+
}
151+
152+
#[cfg(not(feature = "run"))]
153+
fn demangle_assembly(_s: &str) -> String {
154+
panic!("`run` feature must be enabled")
155+
}
156+
157+
#[cfg(test)]
158+
mod tests {
159+
#[cfg(feature = "run")]
160+
#[test]
161+
fn test_demangle() {
162+
use super::*;
163+
164+
let before = r#"
165+
.section __TEXT,__text,regular,pure_instructions
166+
.intel_syntax noprefix
167+
.globl _handle_with_sel
168+
.p2align 4, 0x90
169+
_handle_with_sel:
170+
push rbp
171+
mov rbp, rsp
172+
lea rsi, [rip + __RNvNvCslgFcLFxF7mp_24test_msg_send_static_sel15handle_with_sel9NAME_DATA]
173+
pop rbp
174+
jmp _objc_msgSend
175+
176+
.section __TEXT,__objc_methname,cstring_literals
177+
__RNvNvCslgFcLFxF7mp_24test_msg_send_static_sel15handle_with_sel9NAME_DATA:
178+
.asciz "someSelector"
179+
"#;
180+
181+
let after = r#"
182+
.section __TEXT,__text,regular,pure_instructions
183+
.intel_syntax noprefix
184+
.globl _handle_with_sel
185+
.p2align 4, 0x90
186+
_handle_with_sel:
187+
push rbp
188+
mov rbp, rsp
189+
lea rsi, [rip + SYM(test_msg_send_static_sel[CRATE_ID]::handle_with_sel::NAME_DATA, 0)]
190+
pop rbp
191+
jmp _objc_msgSend
192+
193+
.section __TEXT,__objc_methname,cstring_literals
194+
SYM(test_msg_send_static_sel[CRATE_ID]::handle_with_sel::NAME_DATA, 0):
195+
.asciz "someSelector"
196+
"#;
197+
let output = demangle_assembly(before);
198+
assert_eq!(output, after, "Got {}", output);
199+
200+
let before = r#"
201+
_get_ascii:
202+
stp x29, x30, [sp, #-16]!
203+
mov x29, sp
204+
Lloh0:
205+
adrp x0, l___unnamed_1@PAGE
206+
Lloh1:
207+
add x0, x0, l___unnamed_1@PAGEOFF
208+
mov w1, #3
209+
bl __ZN16objc2_foundation14__string_macro8is_ascii17h6ed9b17e599aba93E
210+
tbz w0, #0, LBB0_2
211+
Lloh2:
212+
adrp x0, __RNvNvCs9IkGjU4WDwV_14test_ns_string9get_ascii8CFSTRING@PAGE
213+
Lloh3:
214+
add x0, x0, __RNvNvCs9IkGjU4WDwV_14test_ns_string9get_ascii8CFSTRING@PAGEOFF
215+
ldp x29, x30, [sp], #16
216+
b __ZN16objc2_foundation14__string_macro13CFStringAscii6as_ptr17hb04bc801907abfefE
217+
LBB0_2:
218+
Lloh4:
219+
adrp x0, __RNvNvCs9IkGjU4WDwV_14test_ns_string9get_asciis_8CFSTRING@PAGE
220+
Lloh5:
221+
add x0, x0, __RNvNvCs9IkGjU4WDwV_14test_ns_string9get_asciis_8CFSTRING@PAGEOFF
222+
ldp x29, x30, [sp], #16
223+
b __ZN16objc2_foundation14__string_macro13CFStringUtf166as_ptr17h2d998f5fc92d4caaE
224+
.loh AdrpAdd Lloh0, Lloh1
225+
.loh AdrpAdd Lloh2, Lloh3
226+
.loh AdrpAdd Lloh4, Lloh5
227+
"#;
228+
229+
let after = r#"
230+
_get_ascii:
231+
stp x29, x30, [sp, #-16]!
232+
mov x29, sp
233+
Lloh0:
234+
adrp x0, l___unnamed_1@PAGE
235+
Lloh1:
236+
add x0, x0, l___unnamed_1@PAGEOFF
237+
mov w1, #3
238+
bl SYM(objc2_foundation::__string_macro::is_ascii::GENERATED_ID, 0)
239+
tbz w0, #0, LBB0_2
240+
Lloh2:
241+
adrp x0, SYM(test_ns_string[CRATE_ID]::get_ascii::CFSTRING, 0)@PAGE
242+
Lloh3:
243+
add x0, x0, SYM(test_ns_string[CRATE_ID]::get_ascii::CFSTRING, 0)@PAGEOFF
244+
ldp x29, x30, [sp], #16
245+
b SYM(objc2_foundation::__string_macro::CFStringAscii::as_ptr::GENERATED_ID, 0)
246+
LBB0_2:
247+
Lloh4:
248+
adrp x0, SYM(test_ns_string[CRATE_ID]::get_ascii::CFSTRING, 1)@PAGE
249+
Lloh5:
250+
add x0, x0, SYM(test_ns_string[CRATE_ID]::get_ascii::CFSTRING, 1)@PAGEOFF
251+
ldp x29, x30, [sp], #16
252+
b SYM(objc2_foundation::__string_macro::CFStringUtf16::as_ptr::GENERATED_ID, 0)
253+
.loh AdrpAdd Lloh0, Lloh1
254+
.loh AdrpAdd Lloh2, Lloh3
255+
.loh AdrpAdd Lloh4, Lloh5
256+
"#;
257+
let output = demangle_assembly(before);
258+
assert_eq!(output, after, "Got {}", output);
259+
}
260+
}

0 commit comments

Comments
 (0)