1 | //===- llvm/unittest/BinaryFormat/TestFileMagic.cpp - File magic tests ----===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/ADT/SmallString.h" |
10 | #include "llvm/ADT/StringRef.h" |
11 | #include "llvm/BinaryFormat/Magic.h" |
12 | #include "llvm/Support/FileSystem.h" |
13 | #include "llvm/Support/Path.h" |
14 | |
15 | #include "gtest/gtest.h" |
16 | |
17 | using namespace llvm; |
18 | namespace fs = llvm::sys::fs; |
19 | |
20 | #define ASSERT_NO_ERROR(x) \ |
21 | if (std::error_code ASSERT_NO_ERROR_ec = x) { \ |
22 | SmallString<128> MessageStorage; \ |
23 | raw_svector_ostream Message(MessageStorage); \ |
24 | Message << #x ": did not return errc::success.\n" \ |
25 | << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \ |
26 | << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \ |
27 | GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \ |
28 | } else { \ |
29 | } |
30 | |
31 | class MagicTest : public testing::Test { |
32 | protected: |
33 | /// Unique temporary directory in which all created filesystem entities must |
34 | /// be placed. It is removed at the end of each test (must be empty). |
35 | SmallString<128> TestDirectory; |
36 | |
37 | void SetUp() override { |
38 | ASSERT_NO_ERROR( |
39 | fs::createUniqueDirectory("file-system-test" , TestDirectory)); |
40 | // We don't care about this specific file. |
41 | errs() << "Test Directory: " << TestDirectory << '\n'; |
42 | errs().flush(); |
43 | } |
44 | |
45 | void TearDown() override { ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); } |
46 | }; |
47 | |
48 | const char archive[] = "!<arch>\x0A" ; |
49 | const char big_archive[] = "<bigaf>\x0A" ; |
50 | const char bitcode[] = "\xde\xc0\x17\x0b" ; |
51 | const char coff_object[] = "\x00\x00......" ; |
52 | const char coff_bigobj[] = |
53 | "\x00\x00\xff\xff\x00\x02......" |
54 | "\xc7\xa1\xba\xd1\xee\xba\xa9\x4b\xaf\x20\xfa\xf6\x6a\xa4\xdc\xb8" ; |
55 | const char coff_import_library[] = "\x00\x00\xff\xff...." ; |
56 | const char elf_relocatable[] = {0x7f, 'E', 'L', 'F', 1, 2, 1, 0, 0, |
57 | 0, 0, 0, 0, 0, 0, 0, 0, 1}; |
58 | |
59 | const char goff_object[] = "\x03\xF0\x00" ; |
60 | const char macho_universal_binary[] = "\xca\xfe\xba\xbe...\x00" ; |
61 | const char macho_object[] = |
62 | "\xfe\xed\xfa\xce........\x00\x00\x00\x01............" ; |
63 | const char macho_executable[] = |
64 | "\xfe\xed\xfa\xce........\x00\x00\x00\x02............" ; |
65 | const char macho_fixed_virtual_memory_shared_lib[] = |
66 | "\xfe\xed\xfa\xce........\x00\x00\x00\x03............" ; |
67 | const char macho_core[] = |
68 | "\xfe\xed\xfa\xce........\x00\x00\x00\x04............" ; |
69 | const char macho_preload_executable[] = |
70 | "\xfe\xed\xfa\xce........\x00\x00\x00\x05............" ; |
71 | const char macho_dynamically_linked_shared_lib[] = |
72 | "\xfe\xed\xfa\xce........\x00\x00\x00\x06............" ; |
73 | const char macho_dynamic_linker[] = |
74 | "\xfe\xed\xfa\xce........\x00\x00\x00\x07............" ; |
75 | const char macho_bundle[] = |
76 | "\xfe\xed\xfa\xce........\x00\x00\x00\x08............" ; |
77 | const char macho_dsym_companion[] = |
78 | "\xfe\xed\xfa\xce........\x00\x00\x00\x0a............" ; |
79 | const char macho_kext_bundle[] = |
80 | "\xfe\xed\xfa\xce........\x00\x00\x00\x0b............" ; |
81 | const char windows_resource[] = |
82 | "\x00\x00\x00\x00\x020\x00\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00" ; |
83 | const char macho_dynamically_linked_shared_lib_stub[] = |
84 | "\xfe\xed\xfa\xce........\x00\x00\x00\x09............" ; |
85 | const char ms_dos_stub_broken[] = "\x4d\x5a\x20\x20" ; |
86 | const char pdb[] = "Microsoft C/C++ MSF 7.00\r\n\x1a" |
87 | "DS\x00\x00\x00" ; |
88 | const char tapi_file[] = "--- !tapi-tbd-v1\n" ; |
89 | const char tapi_file_tbd_v1[] = "---\narchs: [" ; |
90 | const char spirv_object_le[] = "\x03\x02\x23\x07" ; |
91 | const char spirv_object_be[] = "\x07\x23\x02\x03" ; |
92 | |
93 | TEST_F(MagicTest, Magic) { |
94 | struct type { |
95 | const char *filename; |
96 | const char *magic_str; |
97 | size_t magic_str_len; |
98 | file_magic magic; |
99 | } types[] = { |
100 | #define DEFINE(magic) {#magic, magic, sizeof(magic), file_magic::magic} |
101 | DEFINE(archive), |
102 | {.filename: "big_archive" , .magic_str: big_archive, .magic_str_len: sizeof(big_archive), .magic: file_magic::archive}, |
103 | DEFINE(bitcode), |
104 | DEFINE(coff_object), |
105 | {.filename: "coff_bigobj" , .magic_str: coff_bigobj, .magic_str_len: sizeof(coff_bigobj), |
106 | .magic: file_magic::coff_object}, |
107 | DEFINE(coff_import_library), |
108 | DEFINE(elf_relocatable), |
109 | DEFINE(goff_object), |
110 | DEFINE(macho_universal_binary), |
111 | DEFINE(macho_object), |
112 | DEFINE(macho_executable), |
113 | DEFINE(macho_fixed_virtual_memory_shared_lib), |
114 | DEFINE(macho_core), |
115 | DEFINE(macho_preload_executable), |
116 | DEFINE(macho_dynamically_linked_shared_lib), |
117 | DEFINE(macho_dynamic_linker), |
118 | DEFINE(macho_bundle), |
119 | DEFINE(macho_dynamically_linked_shared_lib_stub), |
120 | DEFINE(macho_dsym_companion), |
121 | DEFINE(macho_kext_bundle), |
122 | {.filename: "spirv_object_le" , .magic_str: spirv_object_le, .magic_str_len: sizeof(spirv_object_le), |
123 | .magic: file_magic ::spirv_object}, |
124 | {.filename: "spirv_object_be" , .magic_str: spirv_object_be, .magic_str_len: sizeof(spirv_object_be), |
125 | .magic: file_magic ::spirv_object}, |
126 | DEFINE(windows_resource), |
127 | DEFINE(pdb), |
128 | {.filename: "ms_dos_stub_broken" , .magic_str: ms_dos_stub_broken, .magic_str_len: sizeof(ms_dos_stub_broken), |
129 | .magic: file_magic::unknown}, |
130 | DEFINE(tapi_file), |
131 | {.filename: "tapi_file_tbd_v1" , .magic_str: tapi_file_tbd_v1, .magic_str_len: sizeof(tapi_file_tbd_v1), |
132 | .magic: file_magic::tapi_file}, |
133 | #undef DEFINE |
134 | }; |
135 | |
136 | // Create some files filled with magic. |
137 | for (type *i = types, *e = types + std::size(types); i != e; |
138 | ++i) { |
139 | SmallString<128> file_pathname(TestDirectory); |
140 | llvm::sys::path::append(path&: file_pathname, a: i->filename); |
141 | std::error_code EC; |
142 | raw_fd_ostream file(file_pathname, EC, sys::fs::OF_None); |
143 | ASSERT_FALSE(file.has_error()); |
144 | StringRef magic(i->magic_str, i->magic_str_len); |
145 | file << magic; |
146 | file.close(); |
147 | EXPECT_EQ(i->magic, identify_magic(magic)); |
148 | ASSERT_NO_ERROR(fs::remove(Twine(file_pathname))); |
149 | } |
150 | } |
151 | |