Rust · 6032 bytes Raw Blame History
1 use std::fs;
2 use std::path::{Path, PathBuf};
3 use std::process::Command;
4 use std::sync::atomic::{AtomicU64, Ordering};
5
6 static COUNTER: AtomicU64 = AtomicU64::new(0);
7
8 fn temp_root(prefix: &str) -> PathBuf {
9 let id = COUNTER.fetch_add(1, Ordering::Relaxed);
10 let root = std::env::temp_dir().join(format!("{}_{}_{}", prefix, std::process::id(), id));
11 fs::create_dir_all(&root).expect("create temp root");
12 root
13 }
14
15 fn afs_as() -> Command {
16 Command::new(env!("CARGO_BIN_EXE_afs-as"))
17 }
18
19 fn run_failure_snapshot(name: &str, src: &str, expected: &str) {
20 let root = temp_root("afs_diag_snapshot");
21 let input = root.join(name);
22 fs::write(&input, src).expect("write input");
23
24 let output = afs_as().arg(&input).output().expect("run afs-as");
25 assert_eq!(
26 output.status.code(),
27 Some(1),
28 "stdout:\n{}",
29 String::from_utf8_lossy(&output.stdout)
30 );
31
32 let stderr = normalize_stderr(&String::from_utf8_lossy(&output.stderr), &input);
33 assert_eq!(stderr, expected);
34 }
35
36 fn normalize_stderr(stderr: &str, input: &Path) -> String {
37 stderr.replace(input.to_str().expect("input path"), "<input>")
38 }
39
40 #[test]
41 fn snapshot_unsupported_directive() {
42 run_failure_snapshot(
43 "unsupported-directive.s",
44 ".text\n.unknown_directive\n",
45 "<input>:2:1: error: unsupported directive '.unknown_directive'\n.unknown_directive\n^\n",
46 );
47 }
48
49 #[test]
50 fn snapshot_unsupported_cfi_directive() {
51 run_failure_snapshot(
52 "unsupported-cfi.s",
53 ".cfi_escape 0x1\n",
54 "<input>:1:1: error: unsupported CFI directive '.cfi_escape' (supported: .cfi_startproc, .cfi_endproc, .cfi_def_cfa, .cfi_def_cfa_offset, .cfi_def_cfa_register, .cfi_offset, .cfi_restore, .cfi_adjust_cfa_offset)\n.cfi_escape 0x1\n^\n",
55 );
56 }
57
58 #[test]
59 fn snapshot_unsupported_relocation_modifier_for_adrp() {
60 run_failure_snapshot(
61 "unsupported-reloc-modifier.s",
62 ".text\nadrp x0, _foo@TLSGD\n",
63 "<input>:2:20: error: unsupported relocation modifier '@TLSGD' for adrp symbol operand\nadrp x0, _foo@TLSGD\n ^\n",
64 );
65 }
66
67 #[test]
68 fn snapshot_unsupported_register_offset_modifier() {
69 run_failure_snapshot(
70 "unsupported-register-offset.s",
71 ".text\nldr x0, [x1, x2, ror #1]\n",
72 "<input>:2:22: error: unsupported register offset modifier 'ror'\nldr x0, [x1, x2, ror #1]\n ^\n",
73 );
74 }
75
76 #[test]
77 fn snapshot_unsupported_section() {
78 run_failure_snapshot(
79 "unsupported-section.s",
80 ".section __TEXT,__foo\n.space 16\n",
81 "<input>:1:1: error: unsupported section __TEXT,__foo (supported sections: __TEXT,__text, __TEXT,__cstring, __TEXT,__literal16, __TEXT,__const, __DATA,__data, __DATA,__const, __DATA,__thread_data, __DATA,__thread_vars, __DATA,__thread_bss, __DATA,__bss)\n.section __TEXT,__foo\n^\n",
82 );
83 }
84
85 #[test]
86 fn snapshot_unsupported_section_attr() {
87 run_failure_snapshot(
88 "unsupported-section-attr.s",
89 ".section __TEXT,__text,regular,garbage\nret\n",
90 "<input>:1:39: error: unsupported section attributes for __TEXT,__text: garbage (supported attrs: regular, pure_instructions)\n.section __TEXT,__text,regular,garbage\n ^\n",
91 );
92 }
93
94 #[test]
95 fn snapshot_unsupported_loh_kind() {
96 run_failure_snapshot(
97 "unsupported-loh-kind.s",
98 ".loh UnknownKind Lloh0\n",
99 "<input>:1:18: error: unsupported .loh kind 'UnknownKind' (supported: AdrpAdd, AdrpLdr, AdrpLdrGot, AdrpLdrGotLdr)\n.loh UnknownKind Lloh0\n ^\n",
100 );
101 }
102
103 #[test]
104 fn snapshot_unsupported_build_version_platform() {
105 run_failure_snapshot(
106 "unsupported-build-version-platform.s",
107 ".build_version ios, 11, 0\n",
108 "<input>:1:1: error: unsupported .build_version platform 'ios' (supported: macos)\n.build_version ios, 11, 0\n^\n",
109 );
110 }
111
112 #[test]
113 fn snapshot_zerofill_requires_zero_fill_section() {
114 run_failure_snapshot(
115 "bad-zerofill-section.s",
116 ".zerofill __DATA,__data,_bad,8,2\n",
117 "<input>:1:1: error: .zerofill requires a zero-fill section, got __DATA,__data\n.zerofill __DATA,__data,_bad,8,2\n^\n",
118 );
119 }
120
121 #[test]
122 fn snapshot_zerofill_alignment_too_large() {
123 run_failure_snapshot(
124 "zerofill-alignment-too-large.s",
125 ".zerofill __DATA,__bss,_bad,8,31\n",
126 "<input>:1:1: error: zerofill alignment power 31 too large (max 30)\n.zerofill __DATA,__bss,_bad,8,31\n^\n",
127 );
128 }
129
130 #[test]
131 fn snapshot_tbss_alignment_too_large() {
132 run_failure_snapshot(
133 "tbss-alignment-too-large.s",
134 ".tbss _tls_counter$tlv$init, 8, 31\n",
135 "<input>:1:1: error: zerofill alignment power 31 too large (max 30)\n.tbss _tls_counter$tlv$init, 8, 31\n^\n",
136 );
137 }
138
139 #[test]
140 fn snapshot_text_section_requires_regular_with_pure_instructions() {
141 run_failure_snapshot(
142 "text-section-missing-regular.s",
143 ".section __TEXT,__text,pure_instructions\nret\n",
144 "<input>:1:41: error: section __TEXT,__text requires 'regular' when using 'pure_instructions'\n.section __TEXT,__text,pure_instructions\n ^\n",
145 );
146 }
147
148 #[test]
149 fn snapshot_external_literal_target_requires_local_label() {
150 run_failure_snapshot(
151 "literal-local-label.s",
152 ".text\nldr x0, _ext\n",
153 "<input>:2:1: error: ldr literal target '_ext' requires an assembler-local label\nldr x0, _ext\n^\n",
154 );
155 }
156
157 #[test]
158 fn snapshot_branch_target_must_be_aligned() {
159 run_failure_snapshot(
160 "misaligned-branch.s",
161 ".text\nb done\n.byte 0\ndone:\nret\n",
162 "<input>:2:1: error: branch offset 5 is not 4-byte aligned\nb done\n^\n",
163 );
164 }
165
166 #[test]
167 fn snapshot_branch_target_must_be_in_range() {
168 run_failure_snapshot(
169 "branch-out-of-range.s",
170 ".text\ncbz x0, done\n.space 1048576\ndone:\nret\n",
171 "<input>:2:1: error: branch offset 1048580 is out of range for 19-bit immediate\ncbz x0, done\n^\n",
172 );
173 }
174