| 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 |