| 1 | // Copyright 2014 Renato Tegon Forti, Antony Polukhin. |
| 2 | // Copyright Antony Polukhin, 2015-2024. |
| 3 | // |
| 4 | // Distributed under the Boost Software License, Version 1.0. |
| 5 | // (See accompanying file LICENSE_1_0.txt |
| 6 | // or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 7 | |
| 8 | // For more information, see http://www.boost.org |
| 9 | |
| 10 | #include <boost/dll/detail/elf_info.hpp> |
| 11 | #include <boost/dll/detail/pe_info.hpp> |
| 12 | #include <boost/dll/detail/macho_info.hpp> |
| 13 | #include <boost/core/lightweight_test.hpp> |
| 14 | #include <boost/predef/os.h> |
| 15 | |
| 16 | #if BOOST_OS_WINDOWS |
| 17 | # include <windows.h> |
| 18 | #elif BOOST_OS_MACOS || BOOST_OS_IOS |
| 19 | # include <mach-o/loader.h> |
| 20 | # include <mach-o/nlist.h> |
| 21 | #elif BOOST_OS_QNX |
| 22 | // QNX's copy of <elf.h> and <link.h> reside in sys folder |
| 23 | # include <sys/elf.h> |
| 24 | #else |
| 25 | #include <elf.h> |
| 26 | #endif |
| 27 | |
| 28 | namespace dd = boost::dll::detail; |
| 29 | |
| 30 | template <class T1, class T2> |
| 31 | inline std::size_t get_offset(const T1& v1, const T2& v2) { |
| 32 | const unsigned char* p1 = reinterpret_cast<const unsigned char*>(&v1); |
| 33 | const unsigned char* p2 = reinterpret_cast<const unsigned char*>(&v2); |
| 34 | |
| 35 | if (p1 < p2) { |
| 36 | return static_cast<std::size_t>(p2 - p1); |
| 37 | } |
| 38 | |
| 39 | return static_cast<std::size_t>(p1 - p2); |
| 40 | } |
| 41 | |
| 42 | #define CHECK_FIELD(Field) \ |
| 43 | static_assert(sizeof(v1.Field) == sizeof(v2.Field), ""); \ |
| 44 | BOOST_TEST(get_offset(v1, v1.Field) == get_offset(v2, v2.Field)) \ |
| 45 | /**/ |
| 46 | |
| 47 | |
| 48 | // ELF structures |
| 49 | template <class T1, class T2> |
| 50 | void (const T1& v1, const T2& v2) { |
| 51 | static_assert(sizeof(T1) == sizeof(T2), "" ); |
| 52 | |
| 53 | CHECK_FIELD(e_ident); |
| 54 | CHECK_FIELD(e_type); |
| 55 | CHECK_FIELD(e_machine); |
| 56 | CHECK_FIELD(e_version); |
| 57 | CHECK_FIELD(e_entry); |
| 58 | CHECK_FIELD(e_phoff); |
| 59 | CHECK_FIELD(e_shoff); |
| 60 | CHECK_FIELD(e_flags); |
| 61 | CHECK_FIELD(e_ehsize); |
| 62 | CHECK_FIELD(e_phentsize); |
| 63 | CHECK_FIELD(e_phnum); |
| 64 | CHECK_FIELD(e_shentsize); |
| 65 | CHECK_FIELD(e_shnum); |
| 66 | CHECK_FIELD(e_shstrndx); |
| 67 | } |
| 68 | |
| 69 | template <class T1, class T2> |
| 70 | void (const T1& v1, const T2& v2) { |
| 71 | static_assert(sizeof(T1) == sizeof(T2), "" ); |
| 72 | |
| 73 | CHECK_FIELD(sh_name); |
| 74 | CHECK_FIELD(sh_type); |
| 75 | CHECK_FIELD(sh_flags); |
| 76 | CHECK_FIELD(sh_addr); |
| 77 | CHECK_FIELD(sh_offset); |
| 78 | CHECK_FIELD(sh_size); |
| 79 | CHECK_FIELD(sh_link); |
| 80 | CHECK_FIELD(sh_info); |
| 81 | CHECK_FIELD(sh_addralign); |
| 82 | CHECK_FIELD(sh_entsize); |
| 83 | } |
| 84 | |
| 85 | template <class T1, class T2> |
| 86 | void (const T1& v1, const T2& v2) { |
| 87 | static_assert(sizeof(T1) == sizeof(T2), "" ); |
| 88 | |
| 89 | CHECK_FIELD(st_name); |
| 90 | CHECK_FIELD(st_value); |
| 91 | CHECK_FIELD(st_size); |
| 92 | CHECK_FIELD(st_info); |
| 93 | CHECK_FIELD(st_other); |
| 94 | CHECK_FIELD(st_shndx); |
| 95 | } |
| 96 | |
| 97 | |
| 98 | // PE structures |
| 99 | template <class T> |
| 100 | void (const T& v1, const dd::IMAGE_DOS_HEADER_& v2) { |
| 101 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 102 | |
| 103 | CHECK_FIELD(e_magic); |
| 104 | CHECK_FIELD(e_cblp); |
| 105 | CHECK_FIELD(e_cp); |
| 106 | CHECK_FIELD(e_crlc); |
| 107 | CHECK_FIELD(e_cparhdr); |
| 108 | CHECK_FIELD(e_minalloc); |
| 109 | CHECK_FIELD(e_maxalloc); |
| 110 | CHECK_FIELD(e_ss); |
| 111 | CHECK_FIELD(e_sp); |
| 112 | CHECK_FIELD(e_csum); |
| 113 | CHECK_FIELD(e_ip); |
| 114 | CHECK_FIELD(e_cs); |
| 115 | CHECK_FIELD(e_lfarlc); |
| 116 | CHECK_FIELD(e_ovno); |
| 117 | CHECK_FIELD(e_res); |
| 118 | CHECK_FIELD(e_oemid); |
| 119 | CHECK_FIELD(e_oeminfo); |
| 120 | CHECK_FIELD(e_res2); |
| 121 | CHECK_FIELD(e_lfanew); |
| 122 | } |
| 123 | |
| 124 | template <class T> |
| 125 | void (const T& v1, const dd::IMAGE_FILE_HEADER_& v2) { |
| 126 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 127 | |
| 128 | CHECK_FIELD(Machine); |
| 129 | CHECK_FIELD(NumberOfSections); |
| 130 | CHECK_FIELD(TimeDateStamp); |
| 131 | CHECK_FIELD(PointerToSymbolTable); |
| 132 | CHECK_FIELD(NumberOfSymbols); |
| 133 | CHECK_FIELD(SizeOfOptionalHeader); |
| 134 | CHECK_FIELD(Characteristics); |
| 135 | } |
| 136 | |
| 137 | template <class T> |
| 138 | void (const T& v1, const dd::IMAGE_DATA_DIRECTORY_& v2) { |
| 139 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 140 | |
| 141 | CHECK_FIELD(VirtualAddress); |
| 142 | CHECK_FIELD(Size); |
| 143 | } |
| 144 | |
| 145 | template <class T> |
| 146 | void (const T& v1, const dd::IMAGE_EXPORT_DIRECTORY_& v2) { |
| 147 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 148 | |
| 149 | CHECK_FIELD(Characteristics); |
| 150 | CHECK_FIELD(TimeDateStamp); |
| 151 | CHECK_FIELD(MajorVersion); |
| 152 | CHECK_FIELD(MinorVersion); |
| 153 | CHECK_FIELD(Name); |
| 154 | CHECK_FIELD(Base); |
| 155 | CHECK_FIELD(NumberOfFunctions); |
| 156 | CHECK_FIELD(NumberOfNames); |
| 157 | CHECK_FIELD(AddressOfFunctions); |
| 158 | CHECK_FIELD(AddressOfNames); |
| 159 | CHECK_FIELD(AddressOfNameOrdinals); |
| 160 | } |
| 161 | |
| 162 | |
| 163 | template <class T> |
| 164 | void (const T& v1, const dd::IMAGE_SECTION_HEADER_& v2) { |
| 165 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 166 | |
| 167 | CHECK_FIELD(Name); |
| 168 | CHECK_FIELD(VirtualAddress); |
| 169 | CHECK_FIELD(SizeOfRawData); |
| 170 | CHECK_FIELD(PointerToRawData); |
| 171 | CHECK_FIELD(PointerToRelocations); |
| 172 | CHECK_FIELD(PointerToLinenumbers); |
| 173 | CHECK_FIELD(NumberOfRelocations); |
| 174 | CHECK_FIELD(NumberOfLinenumbers); |
| 175 | CHECK_FIELD(Characteristics); |
| 176 | } |
| 177 | |
| 178 | template <class T, class AddrT> |
| 179 | void (const T& v1, const dd::IMAGE_OPTIONAL_HEADER_template<AddrT>& v2) { |
| 180 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 181 | |
| 182 | CHECK_FIELD(Magic); |
| 183 | CHECK_FIELD(MajorLinkerVersion); |
| 184 | CHECK_FIELD(MinorLinkerVersion); |
| 185 | CHECK_FIELD(SizeOfCode); |
| 186 | CHECK_FIELD(SizeOfInitializedData); |
| 187 | CHECK_FIELD(SizeOfUninitializedData); |
| 188 | CHECK_FIELD(AddressOfEntryPoint); |
| 189 | CHECK_FIELD(ImageBase); |
| 190 | CHECK_FIELD(SectionAlignment); |
| 191 | CHECK_FIELD(FileAlignment); |
| 192 | CHECK_FIELD(MajorOperatingSystemVersion); |
| 193 | CHECK_FIELD(MinorOperatingSystemVersion); |
| 194 | CHECK_FIELD(MajorImageVersion); |
| 195 | CHECK_FIELD(MinorImageVersion); |
| 196 | CHECK_FIELD(MajorSubsystemVersion); |
| 197 | CHECK_FIELD(MinorSubsystemVersion); |
| 198 | CHECK_FIELD(Win32VersionValue); |
| 199 | CHECK_FIELD(SizeOfImage); |
| 200 | CHECK_FIELD(SizeOfHeaders); |
| 201 | CHECK_FIELD(CheckSum); |
| 202 | CHECK_FIELD(Subsystem); |
| 203 | CHECK_FIELD(DllCharacteristics); |
| 204 | CHECK_FIELD(SizeOfStackReserve); |
| 205 | CHECK_FIELD(SizeOfStackCommit); |
| 206 | CHECK_FIELD(SizeOfHeapReserve); |
| 207 | CHECK_FIELD(SizeOfHeapCommit); |
| 208 | CHECK_FIELD(LoaderFlags); |
| 209 | CHECK_FIELD(NumberOfRvaAndSizes); |
| 210 | CHECK_FIELD(DataDirectory); |
| 211 | } |
| 212 | |
| 213 | template <class T, class AddrT> |
| 214 | void (const T& v1, const dd::IMAGE_NT_HEADERS_template<AddrT>& v2) { |
| 215 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 216 | |
| 217 | CHECK_FIELD(Signature); |
| 218 | CHECK_FIELD(FileHeader); |
| 219 | CHECK_FIELD(OptionalHeader); |
| 220 | } |
| 221 | template <class T, class AddrT> |
| 222 | void (const T& v1, const dd::mach_header_template<AddrT>& v2) { |
| 223 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 224 | |
| 225 | CHECK_FIELD(magic); |
| 226 | CHECK_FIELD(cputype); |
| 227 | CHECK_FIELD(cpusubtype); |
| 228 | CHECK_FIELD(filetype); |
| 229 | CHECK_FIELD(ncmds); |
| 230 | CHECK_FIELD(sizeofcmds); |
| 231 | //CHECK_FIELD(flags); |
| 232 | } |
| 233 | |
| 234 | template <class T, class AddrT> |
| 235 | void generic_header_check(const T& v1, const dd::segment_command_template<AddrT>& v2) { |
| 236 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 237 | |
| 238 | CHECK_FIELD(cmd); |
| 239 | CHECK_FIELD(cmdsize); |
| 240 | CHECK_FIELD(segname); |
| 241 | CHECK_FIELD(vmaddr); |
| 242 | CHECK_FIELD(vmsize); |
| 243 | CHECK_FIELD(fileoff); |
| 244 | CHECK_FIELD(filesize); |
| 245 | CHECK_FIELD(maxprot); |
| 246 | CHECK_FIELD(initprot); |
| 247 | CHECK_FIELD(nsects); |
| 248 | CHECK_FIELD(flags); |
| 249 | } |
| 250 | |
| 251 | template <class T, class AddrT> |
| 252 | void (const T& v1, const dd::section_template<AddrT>& v2) { |
| 253 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 254 | |
| 255 | CHECK_FIELD(sectname); |
| 256 | CHECK_FIELD(segname); |
| 257 | CHECK_FIELD(addr); |
| 258 | CHECK_FIELD(size); |
| 259 | CHECK_FIELD(offset); |
| 260 | CHECK_FIELD(align); |
| 261 | CHECK_FIELD(reloff); |
| 262 | CHECK_FIELD(nreloc); |
| 263 | CHECK_FIELD(flags); |
| 264 | //CHECK_FIELD(reserved vs reserveed1&reserved2); |
| 265 | } |
| 266 | |
| 267 | template <class T> |
| 268 | void generic_header_check(const T& v1, const dd::symtab_command_& v2) { |
| 269 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 270 | |
| 271 | CHECK_FIELD(cmd); |
| 272 | CHECK_FIELD(cmdsize); |
| 273 | CHECK_FIELD(symoff); |
| 274 | CHECK_FIELD(nsyms); |
| 275 | CHECK_FIELD(stroff); |
| 276 | CHECK_FIELD(strsize); |
| 277 | } |
| 278 | |
| 279 | template <class T, class AddrT> |
| 280 | void (const T& v1, const dd::nlist_template<AddrT>& v2) { |
| 281 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 282 | |
| 283 | //CHECK_FIELD(n_strx); |
| 284 | CHECK_FIELD(n_type); |
| 285 | CHECK_FIELD(n_sect); |
| 286 | CHECK_FIELD(n_desc); |
| 287 | CHECK_FIELD(n_value); |
| 288 | } |
| 289 | |
| 290 | template <class T> |
| 291 | void generic_header_check(const T& v1, const dd::load_command_& v2) { |
| 292 | static_assert(sizeof(v1) == sizeof(v2), "" ); |
| 293 | |
| 294 | CHECK_FIELD(cmd); |
| 295 | CHECK_FIELD(cmdsize); |
| 296 | } |
| 297 | |
| 298 | |
| 299 | |
| 300 | // Unit Tests |
| 301 | int main(int /*argc*/, char* /*argv*/[]) { |
| 302 | |
| 303 | #if BOOST_OS_WINDOWS |
| 304 | generic_header_check(::IMAGE_DOS_HEADER(), dd::IMAGE_DOS_HEADER_()); |
| 305 | generic_header_check(::IMAGE_FILE_HEADER(), dd::IMAGE_FILE_HEADER_()); |
| 306 | generic_header_check(::IMAGE_DATA_DIRECTORY(), dd::IMAGE_DATA_DIRECTORY_()); |
| 307 | generic_header_check(::IMAGE_EXPORT_DIRECTORY(), dd::IMAGE_EXPORT_DIRECTORY_()); |
| 308 | generic_header_check(::IMAGE_SECTION_HEADER(), dd::IMAGE_SECTION_HEADER_()); |
| 309 | generic_header_check(::IMAGE_OPTIONAL_HEADER32(), dd::IMAGE_OPTIONAL_HEADER32_()); |
| 310 | generic_header_check(::IMAGE_OPTIONAL_HEADER64(), dd::IMAGE_OPTIONAL_HEADER64_()); |
| 311 | generic_header_check(::IMAGE_NT_HEADERS32(), dd::IMAGE_NT_HEADERS32_()); |
| 312 | generic_header_check(::IMAGE_NT_HEADERS64(), dd::IMAGE_NT_HEADERS64_()); |
| 313 | #elif BOOST_OS_MACOS || BOOST_OS_IOS |
| 314 | generic_header_check(::mach_header(), dd::mach_header_32_()); |
| 315 | generic_header_check(::mach_header_64(), dd::mach_header_64_()); |
| 316 | |
| 317 | generic_header_check(::segment_command(), dd::segment_command_32_()); |
| 318 | generic_header_check(::segment_command_64(), dd::segment_command_64_()); |
| 319 | |
| 320 | generic_header_check(::section(), dd::section_32_()); |
| 321 | generic_header_check(::section_64(), dd::section_64_()); |
| 322 | |
| 323 | generic_header_check(::load_command(), dd::load_command_()); |
| 324 | generic_header_check(::symtab_command(), dd::symtab_command_()); |
| 325 | |
| 326 | struct ::nlist nl32_var; |
| 327 | generic_header_check(nl32_var, dd::nlist_32_()); |
| 328 | struct ::nlist_64 nl64_var; |
| 329 | generic_header_check(nl64_var, dd::nlist_64_()); |
| 330 | |
| 331 | #else |
| 332 | elf_header_checks(v1: ::Elf32_Ehdr(), v2: dd::Elf32_Ehdr_()); |
| 333 | elf_header_checks(v1: ::Elf64_Ehdr(), v2: dd::Elf64_Ehdr_()); |
| 334 | |
| 335 | elf_sheader_checks(v1: ::Elf32_Shdr(), v2: dd::Elf32_Shdr_()); |
| 336 | elf_sheader_checks(v1: ::Elf64_Shdr(), v2: dd::Elf64_Shdr_()); |
| 337 | |
| 338 | elf_sym_header_checks(v1: ::Elf32_Sym(), v2: dd::Elf32_Sym_()); |
| 339 | elf_sym_header_checks(v1: ::Elf64_Sym(), v2: dd::Elf64_Sym_()); |
| 340 | #endif |
| 341 | |
| 342 | return boost::report_errors(); |
| 343 | } |
| 344 | |
| 345 | |