1*eb293b8fSAndroid Build Coastguard Worker /*
2*eb293b8fSAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*eb293b8fSAndroid Build Coastguard Worker *
4*eb293b8fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*eb293b8fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*eb293b8fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*eb293b8fSAndroid Build Coastguard Worker *
8*eb293b8fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*eb293b8fSAndroid Build Coastguard Worker *
10*eb293b8fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*eb293b8fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*eb293b8fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*eb293b8fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*eb293b8fSAndroid Build Coastguard Worker * limitations under the License.
15*eb293b8fSAndroid Build Coastguard Worker */
16*eb293b8fSAndroid Build Coastguard Worker
17*eb293b8fSAndroid Build Coastguard Worker #include <elf.h>
18*eb293b8fSAndroid Build Coastguard Worker #include <string.h>
19*eb293b8fSAndroid Build Coastguard Worker #include <sys/mman.h>
20*eb293b8fSAndroid Build Coastguard Worker #include <unistd.h>
21*eb293b8fSAndroid Build Coastguard Worker
22*eb293b8fSAndroid Build Coastguard Worker #include <atomic>
23*eb293b8fSAndroid Build Coastguard Worker #include <memory>
24*eb293b8fSAndroid Build Coastguard Worker #include <string>
25*eb293b8fSAndroid Build Coastguard Worker #include <thread>
26*eb293b8fSAndroid Build Coastguard Worker #include <vector>
27*eb293b8fSAndroid Build Coastguard Worker
28*eb293b8fSAndroid Build Coastguard Worker #include <android-base/test_utils.h>
29*eb293b8fSAndroid Build Coastguard Worker
30*eb293b8fSAndroid Build Coastguard Worker #include <gtest/gtest.h>
31*eb293b8fSAndroid Build Coastguard Worker
32*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Elf.h>
33*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/MapInfo.h>
34*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Maps.h>
35*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Memory.h>
36*eb293b8fSAndroid Build Coastguard Worker
37*eb293b8fSAndroid Build Coastguard Worker #include "ElfFake.h"
38*eb293b8fSAndroid Build Coastguard Worker #include "ElfTestUtils.h"
39*eb293b8fSAndroid Build Coastguard Worker #include "utils/MemoryFake.h"
40*eb293b8fSAndroid Build Coastguard Worker #include "utils/OfflineUnwindUtils.h"
41*eb293b8fSAndroid Build Coastguard Worker
42*eb293b8fSAndroid Build Coastguard Worker namespace unwindstack {
43*eb293b8fSAndroid Build Coastguard Worker
44*eb293b8fSAndroid Build Coastguard Worker class MapInfoGetBuildIDTest : public ::testing::Test {
45*eb293b8fSAndroid Build Coastguard Worker protected:
SetUp()46*eb293b8fSAndroid Build Coastguard Worker void SetUp() override {
47*eb293b8fSAndroid Build Coastguard Worker tf_.reset(new TemporaryFile);
48*eb293b8fSAndroid Build Coastguard Worker
49*eb293b8fSAndroid Build Coastguard Worker std::shared_ptr<Memory> memory(new MemoryFake);
50*eb293b8fSAndroid Build Coastguard Worker elf_ = new ElfFake(memory);
51*eb293b8fSAndroid Build Coastguard Worker elf_interface_ = new ElfInterfaceFake(memory);
52*eb293b8fSAndroid Build Coastguard Worker elf_->FakeSetInterface(elf_interface_);
53*eb293b8fSAndroid Build Coastguard Worker elf_container_.reset(elf_);
54*eb293b8fSAndroid Build Coastguard Worker map_info_ = MapInfo::Create(0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, tf_->path);
55*eb293b8fSAndroid Build Coastguard Worker }
56*eb293b8fSAndroid Build Coastguard Worker
57*eb293b8fSAndroid Build Coastguard Worker void MultipleThreadTest(std::string expected_build_id);
58*eb293b8fSAndroid Build Coastguard Worker
59*eb293b8fSAndroid Build Coastguard Worker ElfFake* elf_;
60*eb293b8fSAndroid Build Coastguard Worker ElfInterfaceFake* elf_interface_;
61*eb293b8fSAndroid Build Coastguard Worker std::unique_ptr<ElfFake> elf_container_;
62*eb293b8fSAndroid Build Coastguard Worker std::shared_ptr<MapInfo> map_info_;
63*eb293b8fSAndroid Build Coastguard Worker std::unique_ptr<TemporaryFile> tf_;
64*eb293b8fSAndroid Build Coastguard Worker };
65*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MapInfoGetBuildIDTest,no_elf_and_no_valid_elf_in_memory)66*eb293b8fSAndroid Build Coastguard Worker TEST_F(MapInfoGetBuildIDTest, no_elf_and_no_valid_elf_in_memory) {
67*eb293b8fSAndroid Build Coastguard Worker auto info = MapInfo::Create(0x1000, 0x2000, 0, PROT_READ, "");
68*eb293b8fSAndroid Build Coastguard Worker
69*eb293b8fSAndroid Build Coastguard Worker EXPECT_EQ("", info->GetBuildID());
70*eb293b8fSAndroid Build Coastguard Worker EXPECT_EQ("", info->GetPrintableBuildID());
71*eb293b8fSAndroid Build Coastguard Worker }
72*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MapInfoGetBuildIDTest,from_elf)73*eb293b8fSAndroid Build Coastguard Worker TEST_F(MapInfoGetBuildIDTest, from_elf) {
74*eb293b8fSAndroid Build Coastguard Worker map_info_->set_elf(elf_container_.release());
75*eb293b8fSAndroid Build Coastguard Worker elf_interface_->FakeSetBuildID("FAKE_BUILD_ID");
76*eb293b8fSAndroid Build Coastguard Worker
77*eb293b8fSAndroid Build Coastguard Worker EXPECT_EQ("FAKE_BUILD_ID", map_info_->GetBuildID());
78*eb293b8fSAndroid Build Coastguard Worker EXPECT_EQ("46414b455f4255494c445f4944", map_info_->GetPrintableBuildID());
79*eb293b8fSAndroid Build Coastguard Worker }
80*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MapInfoGetBuildIDTest,from_elf_no_sign_extension)81*eb293b8fSAndroid Build Coastguard Worker TEST_F(MapInfoGetBuildIDTest, from_elf_no_sign_extension) {
82*eb293b8fSAndroid Build Coastguard Worker map_info_->set_elf(elf_container_.release());
83*eb293b8fSAndroid Build Coastguard Worker
84*eb293b8fSAndroid Build Coastguard Worker std::string build_id = {static_cast<char>(0xfa), static_cast<char>(0xab), static_cast<char>(0x12),
85*eb293b8fSAndroid Build Coastguard Worker static_cast<char>(0x02)};
86*eb293b8fSAndroid Build Coastguard Worker elf_interface_->FakeSetBuildID(build_id);
87*eb293b8fSAndroid Build Coastguard Worker
88*eb293b8fSAndroid Build Coastguard Worker EXPECT_EQ("\xFA\xAB\x12\x2", map_info_->GetBuildID());
89*eb293b8fSAndroid Build Coastguard Worker EXPECT_EQ("faab1202", map_info_->GetPrintableBuildID());
90*eb293b8fSAndroid Build Coastguard Worker }
91*eb293b8fSAndroid Build Coastguard Worker
MultipleThreadTest(std::string expected_build_id)92*eb293b8fSAndroid Build Coastguard Worker void MapInfoGetBuildIDTest::MultipleThreadTest(std::string expected_build_id) {
93*eb293b8fSAndroid Build Coastguard Worker static constexpr size_t kNumConcurrentThreads = 100;
94*eb293b8fSAndroid Build Coastguard Worker
95*eb293b8fSAndroid Build Coastguard Worker std::string build_id_values[kNumConcurrentThreads];
96*eb293b8fSAndroid Build Coastguard Worker std::vector<std::thread*> threads;
97*eb293b8fSAndroid Build Coastguard Worker
98*eb293b8fSAndroid Build Coastguard Worker std::atomic_bool wait;
99*eb293b8fSAndroid Build Coastguard Worker wait = true;
100*eb293b8fSAndroid Build Coastguard Worker // Create all of the threads and have them do the GetLoadBias at the same time
101*eb293b8fSAndroid Build Coastguard Worker // to make it likely that a race will occur.
102*eb293b8fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumConcurrentThreads; i++) {
103*eb293b8fSAndroid Build Coastguard Worker std::thread* thread = new std::thread([i, this, &wait, &build_id_values]() {
104*eb293b8fSAndroid Build Coastguard Worker while (wait)
105*eb293b8fSAndroid Build Coastguard Worker ;
106*eb293b8fSAndroid Build Coastguard Worker build_id_values[i] = map_info_->GetBuildID();
107*eb293b8fSAndroid Build Coastguard Worker });
108*eb293b8fSAndroid Build Coastguard Worker threads.push_back(thread);
109*eb293b8fSAndroid Build Coastguard Worker }
110*eb293b8fSAndroid Build Coastguard Worker
111*eb293b8fSAndroid Build Coastguard Worker // Set them all going and wait for the threads to finish.
112*eb293b8fSAndroid Build Coastguard Worker wait = false;
113*eb293b8fSAndroid Build Coastguard Worker for (auto thread : threads) {
114*eb293b8fSAndroid Build Coastguard Worker thread->join();
115*eb293b8fSAndroid Build Coastguard Worker delete thread;
116*eb293b8fSAndroid Build Coastguard Worker }
117*eb293b8fSAndroid Build Coastguard Worker
118*eb293b8fSAndroid Build Coastguard Worker // Now verify that all of the elf files are exactly the same and valid.
119*eb293b8fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumConcurrentThreads; i++) {
120*eb293b8fSAndroid Build Coastguard Worker EXPECT_EQ(expected_build_id, build_id_values[i]) << "Thread " << i << " mismatched.";
121*eb293b8fSAndroid Build Coastguard Worker }
122*eb293b8fSAndroid Build Coastguard Worker }
123*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MapInfoGetBuildIDTest,multiple_thread_elf_exists)124*eb293b8fSAndroid Build Coastguard Worker TEST_F(MapInfoGetBuildIDTest, multiple_thread_elf_exists) {
125*eb293b8fSAndroid Build Coastguard Worker map_info_->set_elf(elf_container_.release());
126*eb293b8fSAndroid Build Coastguard Worker elf_interface_->FakeSetBuildID("FAKE_BUILD_ID");
127*eb293b8fSAndroid Build Coastguard Worker
128*eb293b8fSAndroid Build Coastguard Worker MultipleThreadTest("FAKE_BUILD_ID");
129*eb293b8fSAndroid Build Coastguard Worker }
130*eb293b8fSAndroid Build Coastguard Worker
InitElfData(int fd)131*eb293b8fSAndroid Build Coastguard Worker static void InitElfData(int fd) {
132*eb293b8fSAndroid Build Coastguard Worker Elf32_Ehdr ehdr;
133*eb293b8fSAndroid Build Coastguard Worker TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM);
134*eb293b8fSAndroid Build Coastguard Worker ehdr.e_shoff = 0x2000;
135*eb293b8fSAndroid Build Coastguard Worker ehdr.e_shnum = 3;
136*eb293b8fSAndroid Build Coastguard Worker ehdr.e_shentsize = sizeof(Elf32_Shdr);
137*eb293b8fSAndroid Build Coastguard Worker ehdr.e_shstrndx = 2;
138*eb293b8fSAndroid Build Coastguard Worker off_t offset = 0;
139*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(offset, lseek(fd, offset, SEEK_SET));
140*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(static_cast<ssize_t>(sizeof(ehdr)), write(fd, &ehdr, sizeof(ehdr)));
141*eb293b8fSAndroid Build Coastguard Worker
142*eb293b8fSAndroid Build Coastguard Worker char note_section[128];
143*eb293b8fSAndroid Build Coastguard Worker Elf32_Nhdr note_header = {};
144*eb293b8fSAndroid Build Coastguard Worker note_header.n_namesz = sizeof("GNU");
145*eb293b8fSAndroid Build Coastguard Worker note_header.n_descsz = sizeof("ELF_BUILDID") - 1;
146*eb293b8fSAndroid Build Coastguard Worker note_header.n_type = NT_GNU_BUILD_ID;
147*eb293b8fSAndroid Build Coastguard Worker memcpy(¬e_section, ¬e_header, sizeof(note_header));
148*eb293b8fSAndroid Build Coastguard Worker size_t note_offset = sizeof(note_header);
149*eb293b8fSAndroid Build Coastguard Worker memcpy(¬e_section[note_offset], "GNU", note_header.n_namesz);
150*eb293b8fSAndroid Build Coastguard Worker note_offset += note_header.n_namesz;
151*eb293b8fSAndroid Build Coastguard Worker memcpy(¬e_section[note_offset], "ELF_BUILDID", note_header.n_descsz);
152*eb293b8fSAndroid Build Coastguard Worker
153*eb293b8fSAndroid Build Coastguard Worker Elf32_Shdr shdr = {};
154*eb293b8fSAndroid Build Coastguard Worker shdr.sh_type = SHT_NOTE;
155*eb293b8fSAndroid Build Coastguard Worker shdr.sh_name = 0x500;
156*eb293b8fSAndroid Build Coastguard Worker shdr.sh_offset = 0xb000;
157*eb293b8fSAndroid Build Coastguard Worker shdr.sh_size = sizeof(note_section);
158*eb293b8fSAndroid Build Coastguard Worker offset += ehdr.e_shoff + sizeof(shdr);
159*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(offset, lseek(fd, offset, SEEK_SET));
160*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(static_cast<ssize_t>(sizeof(shdr)), write(fd, &shdr, sizeof(shdr)));
161*eb293b8fSAndroid Build Coastguard Worker
162*eb293b8fSAndroid Build Coastguard Worker // The string data for section header names.
163*eb293b8fSAndroid Build Coastguard Worker memset(&shdr, 0, sizeof(shdr));
164*eb293b8fSAndroid Build Coastguard Worker shdr.sh_type = SHT_STRTAB;
165*eb293b8fSAndroid Build Coastguard Worker shdr.sh_name = 0x20000;
166*eb293b8fSAndroid Build Coastguard Worker shdr.sh_offset = 0xf000;
167*eb293b8fSAndroid Build Coastguard Worker shdr.sh_size = 0x1000;
168*eb293b8fSAndroid Build Coastguard Worker offset += sizeof(shdr);
169*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(offset, lseek(fd, offset, SEEK_SET));
170*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(static_cast<ssize_t>(sizeof(shdr)), write(fd, &shdr, sizeof(shdr)));
171*eb293b8fSAndroid Build Coastguard Worker
172*eb293b8fSAndroid Build Coastguard Worker offset = 0xf500;
173*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(offset, lseek(fd, offset, SEEK_SET));
174*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(static_cast<ssize_t>(sizeof(".note.gnu.build-id")),
175*eb293b8fSAndroid Build Coastguard Worker write(fd, ".note.gnu.build-id", sizeof(".note.gnu.build-id")));
176*eb293b8fSAndroid Build Coastguard Worker
177*eb293b8fSAndroid Build Coastguard Worker offset = 0xb000;
178*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(offset, lseek(fd, offset, SEEK_SET));
179*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(static_cast<ssize_t>(sizeof(note_section)),
180*eb293b8fSAndroid Build Coastguard Worker write(fd, note_section, sizeof(note_section)));
181*eb293b8fSAndroid Build Coastguard Worker }
182*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MapInfoGetBuildIDTest,from_memory)183*eb293b8fSAndroid Build Coastguard Worker TEST_F(MapInfoGetBuildIDTest, from_memory) {
184*eb293b8fSAndroid Build Coastguard Worker InitElfData(tf_->fd);
185*eb293b8fSAndroid Build Coastguard Worker
186*eb293b8fSAndroid Build Coastguard Worker EXPECT_EQ("ELF_BUILDID", map_info_->GetBuildID());
187*eb293b8fSAndroid Build Coastguard Worker EXPECT_EQ("454c465f4255494c444944", map_info_->GetPrintableBuildID());
188*eb293b8fSAndroid Build Coastguard Worker }
189*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MapInfoGetBuildIDTest,multiple_thread_elf_exists_in_memory)190*eb293b8fSAndroid Build Coastguard Worker TEST_F(MapInfoGetBuildIDTest, multiple_thread_elf_exists_in_memory) {
191*eb293b8fSAndroid Build Coastguard Worker InitElfData(tf_->fd);
192*eb293b8fSAndroid Build Coastguard Worker
193*eb293b8fSAndroid Build Coastguard Worker MultipleThreadTest("ELF_BUILDID");
194*eb293b8fSAndroid Build Coastguard Worker }
195*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MapInfoGetBuildIDTest,real_elf)196*eb293b8fSAndroid Build Coastguard Worker TEST_F(MapInfoGetBuildIDTest, real_elf) {
197*eb293b8fSAndroid Build Coastguard Worker auto map_info = MapInfo::Create(0x1000, 0x20000, 0, PROT_READ | PROT_WRITE,
198*eb293b8fSAndroid Build Coastguard Worker GetOfflineFilesDirectory() + "empty_arm64/libc.so");
199*eb293b8fSAndroid Build Coastguard Worker EXPECT_EQ("6df0590c4920f4c7b9f34fe833f37d54", map_info->GetPrintableBuildID());
200*eb293b8fSAndroid Build Coastguard Worker }
201*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MapInfoGetBuildIDTest,in_device_map)202*eb293b8fSAndroid Build Coastguard Worker TEST_F(MapInfoGetBuildIDTest, in_device_map) {
203*eb293b8fSAndroid Build Coastguard Worker auto map_info =
204*eb293b8fSAndroid Build Coastguard Worker MapInfo::Create(0x1000, 0x20000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
205*eb293b8fSAndroid Build Coastguard Worker GetOfflineFilesDirectory() + "empty_arm64/libc.so");
206*eb293b8fSAndroid Build Coastguard Worker EXPECT_EQ("", map_info->GetPrintableBuildID());
207*eb293b8fSAndroid Build Coastguard Worker }
208*eb293b8fSAndroid Build Coastguard Worker
209*eb293b8fSAndroid Build Coastguard Worker } // namespace unwindstack
210