xref: /aosp_15_r20/system/unwinding/libunwindstack/tests/MapInfoGetBuildIDTest.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
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(&note_section, &note_header, sizeof(note_header));
148*eb293b8fSAndroid Build Coastguard Worker   size_t note_offset = sizeof(note_header);
149*eb293b8fSAndroid Build Coastguard Worker   memcpy(&note_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(&note_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