1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <gtest/gtest.h>
30
31 #include <link.h>
32
TEST(link,dl_iterate_phdr_early_exit)33 TEST(link, dl_iterate_phdr_early_exit) {
34 static size_t call_count = 0;
35 ASSERT_EQ(123, dl_iterate_phdr([](dl_phdr_info*, size_t, void*) { ++call_count; return 123; },
36 nullptr));
37 ASSERT_EQ(1u, call_count);
38 }
39
TEST(link,dl_iterate_phdr)40 TEST(link, dl_iterate_phdr) {
41 struct Functor {
42 static int Callback(dl_phdr_info* i, size_t s, void* data) {
43 reinterpret_cast<Functor*>(data)->DoChecks(i, s);
44 return 0;
45 }
46 void DoChecks(dl_phdr_info* info, size_t s) {
47 ASSERT_EQ(sizeof(dl_phdr_info), s);
48
49 ASSERT_TRUE(info->dlpi_name != nullptr);
50
51 // Find the first PT_LOAD program header so we can find the ELF header.
52 for (ElfW(Half) i = 0; i < info->dlpi_phnum; ++i) {
53 const ElfW(Phdr)* phdr = reinterpret_cast<const ElfW(Phdr)*>(&info->dlpi_phdr[i]);
54 if (phdr->p_type == PT_LOAD) {
55 const ElfW(Ehdr)* ehdr = reinterpret_cast<const ElfW(Ehdr)*>(info->dlpi_addr +
56 phdr->p_vaddr);
57 // Does it look like an ELF file?
58 ASSERT_EQ(0, memcmp(ehdr, ELFMAG, SELFMAG));
59 // Does the e_phnum match what dl_iterate_phdr told us?
60 ASSERT_EQ(info->dlpi_phnum, ehdr->e_phnum);
61 break;
62 }
63 }
64 }
65 size_t count;
66 } f = {};
67 ASSERT_EQ(0, dl_iterate_phdr(Functor::Callback, &f));
68 }
69
70 #if __arm__
read_exidx_func(uintptr_t * entry)71 static uintptr_t read_exidx_func(uintptr_t* entry) {
72 int32_t offset = *entry;
73 // Sign-extend from int31 to int32.
74 if ((offset & 0x40000000) != 0) {
75 offset += -0x7fffffff - 1;
76 }
77 return reinterpret_cast<uintptr_t>(entry) + offset;
78 }
another_function_in_same_ELF_file()79 __attribute__((__unused__)) static void another_function_in_same_ELF_file() {}
80 #endif
81
TEST(link,dl_unwind_find_exidx)82 TEST(link, dl_unwind_find_exidx) {
83 #if __arm__
84 int count = 0;
85 struct eit_entry_t {
86 uintptr_t one;
87 uintptr_t two;
88 };
89 eit_entry_t* entries = reinterpret_cast<eit_entry_t*>(dl_unwind_find_exidx(
90 reinterpret_cast<_Unwind_Ptr>(read_exidx_func), &count));
91 ASSERT_TRUE(entries != nullptr);
92 ASSERT_GT(count, 0);
93
94 // Sanity checks
95 uintptr_t func = reinterpret_cast<uintptr_t>(read_exidx_func);
96 bool found = false;
97 for (int i = 0; i < count; ++i) {
98 // Entries must have bit 31 clear.
99 ASSERT_TRUE((entries[i].one & (1<<31)) == 0);
100
101 uintptr_t exidx_func = read_exidx_func(&entries[i].one);
102
103 // If our function is compiled for thumb, exception table contains our address - 1.
104 if (func == exidx_func || func == exidx_func + 1) found = true;
105
106 // Entries must be sorted. Some addresses may appear twice if function
107 // is compiled for arm.
108 if (i > 0) {
109 EXPECT_GE(exidx_func, read_exidx_func(&entries[i - 1].one)) << i;
110 }
111 }
112 ASSERT_TRUE(found);
113 #else
114 GTEST_LOG_(INFO) << "dl_unwind_find_exidx is an ARM-only API\n";
115 #endif
116 }
117