• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "file-inl.h"
17 #include "file_items.h"
18 #include "file_item_container.h"
19 #include "file_reader.h"
20 #include "utils/string_helpers.h"
21 #include "zip_archive.h"
22 #include "file.h"
23 
24 #include "assembly-emitter.h"
25 #include "assembly-parser.h"
26 
27 #include <cstdint>
28 #ifdef PANDA_TARGET_MOBILE
29 #include <unistd.h>
30 #endif
31 
32 #include <vector>
33 
34 #include <gtest/gtest.h>
35 
36 namespace ark::panda_file::test {
37 
GetPandaFile(std::vector<uint8_t> * data)38 static std::unique_ptr<const File> GetPandaFile(std::vector<uint8_t> *data)
39 {
40     os::mem::ConstBytePtr ptr(reinterpret_cast<std::byte *>(data->data()), data->size(),
41                               [](std::byte *, size_t) noexcept {});
42     return File::OpenFromMemory(std::move(ptr));
43 }
44 
GetEmptyPandaFileBytes()45 static std::vector<uint8_t> GetEmptyPandaFileBytes()
46 {
47     pandasm::Parser p;
48 
49     auto source = R"()";
50 
51     std::string srcFilename = "src.pa";
52     auto res = p.Parse(source, srcFilename);
53     ASSERT(p.ShowError().err == pandasm::Error::ErrorType::ERR_NONE);
54 
55     auto pf = pandasm::AsmEmitter::Emit(res.Value());
56     ASSERT(pf != nullptr);
57 
58     std::vector<uint8_t> data {};
59     const auto headerPtr = reinterpret_cast<const uint8_t *>(pf->GetHeader());
60     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
61     data.assign(headerPtr, headerPtr + sizeof(File::Header));
62 
63     ASSERT(data.size() == sizeof(File::Header));
64 
65     return data;
66 }
67 
CreateOrAddZipPandaFile(std::vector<uint8_t> * data,const char * zipArchiveName,const char * filename,int append,int level)68 int CreateOrAddZipPandaFile(std::vector<uint8_t> *data, const char *zipArchiveName, const char *filename, int append,
69                             int level)
70 {
71     return CreateOrAddFileIntoZip(zipArchiveName, filename, data, append, level);
72 }
73 
CheckAnonMemoryName(const char * zipArchiveName)74 bool CheckAnonMemoryName([[maybe_unused]] const char *zipArchiveName)
75 {
76     // check if [annon:panda-classes.abc extracted in memory from /xx/__OpenPandaFileFromZip__.zip]
77 #ifdef PANDA_TARGET_MOBILE
78     bool result = false;
79     const char *prefix = "[anon:panda-";
80     int pid = getpid();
81     std::stringstream ss;
82     ss << "/proc/" << pid << "/maps";
83     std::ifstream f;
84     f.open(ss.str(), std::ios::in);
85     EXPECT_TRUE(f.is_open());
86     for (std::string line; std::getline(f, line);) {
87         if (line.find(prefix) != std::string::npos && line.find(zipArchiveName) != std::string::npos) {
88             result = true;
89         }
90     }
91     f.close();
92     return result;
93 #else
94     return true;
95 #endif
96 }
97 
TEST(File,OpenMemory)98 TEST(File, OpenMemory)
99 {
100     {
101         auto data = GetEmptyPandaFileBytes();
102         auto ptr = GetPandaFile(&data);
103         EXPECT_NE(ptr, nullptr);
104     }
105 
106     {
107         auto data = GetEmptyPandaFileBytes();
108         data[0] = 0x0;  // Corrupt magic
109 
110         auto ptr = GetPandaFile(&data);
111         EXPECT_EQ(ptr, nullptr);
112     }
113 }
114 
TEST(File,GetClassByName)115 TEST(File, GetClassByName)
116 {
117     ItemContainer container;
118 
119     std::vector<std::string> names = {"C", "B", "A"};
120     std::vector<ClassItem *> classes;
121     classes.reserve(names.size());
122 
123     for (auto &name : names) {
124         classes.push_back(container.GetOrCreateClassItem(name));
125     }
126 
127     MemoryWriter memWriter;
128 
129     ASSERT_TRUE(container.Write(&memWriter));
130 
131     // Read panda file from memory
132 
133     auto data = memWriter.GetData();
134     auto pandaFile = GetPandaFile(&data);
135     ASSERT_NE(pandaFile, nullptr);
136 
137     for (size_t i = 0; i < names.size(); i++) {
138         EXPECT_EQ(pandaFile->GetClassId(reinterpret_cast<const uint8_t *>(names[i].c_str())).GetOffset(),
139                   classes[i]->GetOffset());
140     }
141 }
142 
TEST(File,OpenPandaFile)143 TEST(File, OpenPandaFile)
144 {
145     // Create ZIP
146     auto data = GetEmptyPandaFileBytes();
147     int ret;
148     const char *zipFilename = "__OpenPandaFile__.zip";
149     const char *filename1 = ARCHIVE_FILENAME;
150     const char *filename2 = "classses2.abc";  // just for testing.
151     ret = CreateOrAddZipPandaFile(&data, zipFilename, filename1, APPEND_STATUS_CREATE, Z_BEST_COMPRESSION);
152     ASSERT_EQ(ret, 0);
153     ret = CreateOrAddZipPandaFile(&data, zipFilename, filename2, APPEND_STATUS_ADDINZIP, Z_BEST_COMPRESSION);
154     ASSERT_EQ(ret, 0);
155 
156     // Open from ZIP
157     auto pf = OpenPandaFile(zipFilename);
158     EXPECT_NE(pf, nullptr);
159     EXPECT_STREQ((pf->GetFilename()).c_str(), zipFilename);
160     remove(zipFilename);
161 }
162 
TEST(File,OpenPandaFileFromZipNameAnonMem)163 TEST(File, OpenPandaFileFromZipNameAnonMem)
164 {
165     // Create ZIP
166     auto data = GetEmptyPandaFileBytes();
167     int ret;
168     const char *zipFilename = "__OpenPandaFileFromZipNameAnonMem__.zip";
169     const char *filename1 = ARCHIVE_FILENAME;
170     ret = CreateOrAddZipPandaFile(&data, zipFilename, filename1, APPEND_STATUS_CREATE, Z_BEST_COMPRESSION);
171     ASSERT_EQ(ret, 0);
172 
173     // Open from ZIP
174     auto pf = OpenPandaFile(zipFilename);
175     EXPECT_NE(pf, nullptr);
176     EXPECT_STREQ((pf->GetFilename()).c_str(), zipFilename);
177     ASSERT_TRUE(CheckAnonMemoryName(zipFilename));
178     remove(zipFilename);
179 }
180 
TEST(File,OpenPandaFileOrZip)181 TEST(File, OpenPandaFileOrZip)
182 {
183     // Create ZIP
184     auto data = GetEmptyPandaFileBytes();
185     int ret;
186     const char *zipFilename = "__OpenPandaFileOrZip__.zip";
187     const char *filename1 = ARCHIVE_FILENAME;
188     const char *filename2 = "classes2.abc";  // just for testing.
189     ret = CreateOrAddZipPandaFile(&data, zipFilename, filename1, APPEND_STATUS_CREATE, Z_BEST_COMPRESSION);
190     ASSERT_EQ(ret, 0);
191     ret = CreateOrAddZipPandaFile(&data, zipFilename, filename2, APPEND_STATUS_ADDINZIP, Z_BEST_COMPRESSION);
192     ASSERT_EQ(ret, 0);
193 
194     // Open from ZIP
195     auto pf = OpenPandaFileOrZip(zipFilename);
196     EXPECT_NE(pf, nullptr);
197     EXPECT_STREQ((pf->GetFilename()).c_str(), zipFilename);
198     remove(zipFilename);
199 }
200 
TEST(File,OpenPandaFileUncompressed)201 TEST(File, OpenPandaFileUncompressed)
202 {
203     // Create ZIP
204     auto data = GetEmptyPandaFileBytes();
205     std::cout << "pandafile size = " << data.size() << std::endl;
206     int ret;
207     const char *zipFilename = "__OpenPandaFileUncompressed__.zip";
208     const char *filename1 = ARCHIVE_FILENAME;
209     const char *filename2 = "class.abc";  // just for testing.
210     ret = CreateOrAddZipPandaFile(&data, zipFilename, filename2, APPEND_STATUS_CREATE, Z_NO_COMPRESSION);
211     ASSERT_EQ(ret, 0);
212     ret = CreateOrAddZipPandaFile(&data, zipFilename, filename1, APPEND_STATUS_ADDINZIP, Z_NO_COMPRESSION);
213     ASSERT_EQ(ret, 0);
214 
215     // Open from ZIP
216     auto pf = OpenPandaFileOrZip(zipFilename);
217     EXPECT_NE(pf, nullptr);
218     EXPECT_STREQ((pf->GetFilename()).c_str(), zipFilename);
219     remove(zipFilename);
220 }
221 
TEST(File,LineNumberProgramDeduplication)222 TEST(File, LineNumberProgramDeduplication)
223 {
224     pandasm::Parser p;
225 
226     auto source = R"delim(
227         .function void foo() {
228             return.void
229         }
230 
231         .function void bar() {
232             return.void
233         }
234     )delim";
235 
236     std::string srcFilename = "src.pa";
237     auto res = p.Parse(source, srcFilename);
238     ASSERT(p.ShowError().err == pandasm::Error::ErrorType::ERR_NONE);
239 
240     ASSERT_EQ(res.Value().functionTable.size(), 2);
241     for (auto &a : res.Value().functionTable) {
242         ASSERT_TRUE(a.second.HasDebugInfo());
243     }
244 
245     auto pf = pandasm::AsmEmitter::Emit(res.Value());
246     ASSERT(pf != nullptr);
247 
248     auto reader = FileReader(std::move(pf));
249 
250     ASSERT_TRUE(reader.ReadContainer());
251 
252     int lnpCnt = 0;
253 
254     ASSERT_NE(reader.GetItems()->size(), 0);
255 
256     for (const auto &a : *reader.GetItems()) {
257         const auto typ = a.second->GetItemType();
258         if (typ == ItemTypes::LINE_NUMBER_PROGRAM_ITEM) {
259             lnpCnt++;
260         }
261     }
262 
263     reader.GetContainerPtr()->ComputeLayout();
264     reader.GetContainerPtr()->DeduplicateCodeAndDebugInfo();
265 
266     ASSERT_EQ(lnpCnt, 1);
267 }
268 
269 }  // namespace ark::panda_file::test
270