• 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 
17 #include "file_ext.h"
18 #include "panda_file_external.h"
19 #include "libpandafile/file-inl.h"
20 #include "libpandafile/class_data_accessor-inl.h"
21 #include "libpandafile/method_data_accessor-inl.h"
22 #include "libpandafile/code_data_accessor-inl.h"
23 #include "libpandafile/debug_helpers.h"
24 #include "libpandabase/utils/logger.h"
25 #include "libpandabase/os/native_stack.h"
26 #include <map>
27 
28 namespace ark::panda_file::ext {
29 
30 struct MethodSymEntry {
31     ark::panda_file::File::EntityId id;
32     uint32_t length {0};
33     std::string name;
34 };
35 
36 }  // namespace ark::panda_file::ext
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 struct PandaFileExt {
43 public:
PandaFileExtPandaFileExt44     explicit PandaFileExt(std::unique_ptr<const ark::panda_file::File> &&pandaFile) : pandaFile_(std::move(pandaFile))
45     {
46     }
47 
GetExtFileLineNumberPandaFileExt48     size_t GetExtFileLineNumber(ark::panda_file::MethodDataAccessor mda, uint32_t bcOffset)
49     {
50         return ark::panda_file::debug_helpers::GetLineNumber(mda, bcOffset, pandaFile_.get());
51     }
52 
QueryMethodSymByOffsetPandaFileExt53     ark::panda_file::ext::MethodSymEntry *QueryMethodSymByOffset(uint64_t offset)
54     {
55         auto it = methodSymbols_.upper_bound(offset);
56         if (it != methodSymbols_.end() && offset >= it->second.id.GetOffset()) {
57             return &it->second;
58         }
59 
60         // Enmuate all methods and put them to local cache.
61         ark::panda_file::ext::MethodSymEntry *found = nullptr;
62 
63         auto callBack = [this, offset, &found](ark::panda_file::MethodDataAccessor &mda) -> void {
64             if (mda.GetCodeId().has_value()) {
65                 ark::panda_file::CodeDataAccessor ca {*pandaFile_, mda.GetCodeId().value()};
66                 ark::panda_file::ext::MethodSymEntry entry;
67                 entry.id = mda.GetCodeId().value();
68                 entry.length = ca.GetCodeSize();
69                 entry.name = std::string(ark::utf::Mutf8AsCString(pandaFile_->GetStringData(mda.GetNameId()).data));
70 
71                 auto ret = methodSymbols_.emplace(offset, entry);
72                 if (mda.GetCodeId().value().GetOffset() <= offset &&
73                     offset < mda.GetCodeId().value().GetOffset() + ca.GetCodeSize()) {
74                     found = &ret.first->second;
75                 }
76             }
77         };
78 
79         for (uint32_t id : pandaFile_->GetClasses()) {
80             if (pandaFile_->IsExternal(ark::panda_file::File::EntityId(id))) {
81                 continue;
82             }
83 
84             ark::panda_file::ClassDataAccessor cda {*pandaFile_, ark::panda_file::File::EntityId(id)};
85             cda.EnumerateMethods(callBack);
86         }
87         return found;
88     }
89 
EnumerateAllMethodsPandaFileExt90     ark::panda_file::ext::MethodSymEntry *EnumerateAllMethods(uint32_t id, uint64_t offset,
91                                                               ark::panda_file::ext::MethodSymEntry *found)
92     {
93         ark::panda_file::ClassDataAccessor cda {*pandaFile_, ark::panda_file::File::EntityId(id)};
94         cda.EnumerateMethods([this, &cda, &offset, &found](ark::panda_file::MethodDataAccessor &mda) -> void {
95             if (mda.GetCodeId().has_value()) {
96                 ark::panda_file::CodeDataAccessor ca {*pandaFile_, mda.GetCodeId().value()};
97                 ark::panda_file::ext::MethodSymEntry entry;
98                 entry.id = mda.GetCodeId().value();
99                 entry.length = ca.GetCodeSize();
100                 entry.name = std::string(ark::utf::Mutf8AsCString(pandaFile_->GetStringData(mda.GetNameId()).data));
101 
102                 auto ret = methodSymbols_.emplace(offset, entry);
103                 if (mda.GetCodeId().value().GetOffset() <= offset &&
104                     offset < mda.GetCodeId().value().GetOffset() + ca.GetCodeSize()) {
105                     size_t lineNumber = GetExtFileLineNumber(mda, offset - mda.GetCodeId().value().GetOffset());
106                     found = &ret.first->second;
107                     ark::panda_file::File::EntityId idNew(lineNumber);
108                     auto nameId = cda.GetDescriptor();
109                     found->id = idNew;
110                     found->name = ark::os::native_stack::ChangeJaveStackFormat(reinterpret_cast<const char *>(nameId)) +
111                                   "." + found->name;
112                 }
113             }
114         });
115 
116         return found;
117     }
118 
QueryMethodSymAndLineByOffsetPandaFileExt119     ark::panda_file::ext::MethodSymEntry *QueryMethodSymAndLineByOffset(uint64_t offset)
120     {
121         auto it = methodSymbols_.upper_bound(offset);
122         if (it != methodSymbols_.end() && offset >= it->second.id.GetOffset()) {
123             return &it->second;
124         }
125 
126         // Enmuate all methods and put them to local cache.
127         ark::panda_file::ext::MethodSymEntry *found = nullptr;
128         for (uint32_t id : pandaFile_->GetClasses()) {
129             if (pandaFile_->IsExternal(ark::panda_file::File::EntityId(id))) {
130                 continue;
131             }
132 
133             found = EnumerateAllMethods(id, offset, found);
134         }
135         return found;
136     }
137 
QueryAllMethodSymsPandaFileExt138     std::vector<struct MethodSymInfoExt> QueryAllMethodSyms()
139     {
140         // Enmuate all methods and put them to local cache.
141         std::vector<ark::panda_file::ext::MethodSymEntry> res;
142         for (uint32_t id : pandaFile_->GetClasses()) {
143             if (pandaFile_->IsExternal(ark::panda_file::File::EntityId(id))) {
144                 continue;
145             }
146             ark::panda_file::ClassDataAccessor cda {*pandaFile_, ark::panda_file::File::EntityId(id)};
147             cda.EnumerateMethods([&](ark::panda_file::MethodDataAccessor &mda) -> void {
148                 if (mda.GetCodeId().has_value()) {
149                     ark::panda_file::CodeDataAccessor ca {*pandaFile_, mda.GetCodeId().value()};
150                     std::stringstream ss;
151                     std::string_view cname(ark::utf::Mutf8AsCString(pandaFile_->GetStringData(mda.GetClassId()).data));
152                     if (!cname.empty()) {
153                         ss << cname.substr(0, cname.size() - 1);
154                     }
155                     ss << "." << ark::utf::Mutf8AsCString(pandaFile_->GetStringData(mda.GetNameId()).data);
156                     res.push_back({mda.GetCodeId().value(), ca.GetCodeSize(), ss.str()});
157                 }
158             });
159         }
160 
161         std::vector<struct MethodSymInfoExt> methodInfo;
162         methodInfo.reserve(res.size());
163         for (auto const &me : res) {
164             struct MethodSymInfoExt msi {};
165             msi.offset = me.id.GetOffset();
166             msi.length = me.length;
167             msi.name = me.name;
168             methodInfo.push_back(msi);
169         }
170         return methodInfo;
171     }
172 
173 private:
174     std::map<uint64_t, ark::panda_file::ext::MethodSymEntry> methodSymbols_;
175     std::unique_ptr<const ark::panda_file::File> pandaFile_;
176 };
177 
OpenPandafileFromMemoryExt(void * addr,const uint64_t * size,const std::string & fileName,PandaFileExt ** pandaFileExt)178 bool OpenPandafileFromMemoryExt(void *addr, const uint64_t *size, [[maybe_unused]] const std::string &fileName,
179                                 PandaFileExt **pandaFileExt)
180 {
181     if (pandaFileExt == nullptr) {
182         return false;
183     }
184 
185     ark::os::mem::ConstBytePtr ptr(
186         reinterpret_cast<std::byte *>(addr), *size,
187         []([[maybe_unused]] std::byte *paramBuffer, [[maybe_unused]] size_t paramSize) noexcept {});
188     auto pf = ark::panda_file::File::OpenFromMemory(std::move(ptr));
189     if (pf == nullptr) {
190         return false;
191     }
192 
193     auto pfExt = std::make_unique<PandaFileExt>(std::move(pf));
194     *pandaFileExt = pfExt.release();
195     return true;
196 }
197 
OpenPandafileFromFdExt(int fd,uint64_t offset,const std::string & fileName,PandaFileExt ** pandaFileExt)198 bool OpenPandafileFromFdExt([[maybe_unused]] int fd, [[maybe_unused]] uint64_t offset, const std::string &fileName,
199                             PandaFileExt **pandaFileExt)
200 {
201     auto pf = ark::panda_file::OpenPandaFile(fileName);
202     if (pf == nullptr) {
203         return false;
204     }
205 
206     auto pfExt = std::make_unique<PandaFileExt>(std::move(pf));
207     *pandaFileExt = pfExt.release();
208     return true;
209 }
210 
QueryMethodSymByOffsetExt(struct PandaFileExt * pf,uint64_t offset,struct MethodSymInfoExt * methodInfo)211 bool QueryMethodSymByOffsetExt(struct PandaFileExt *pf, uint64_t offset, struct MethodSymInfoExt *methodInfo)
212 {
213     auto entry = pf->QueryMethodSymByOffset(offset);
214     if ((entry != nullptr) && (methodInfo != nullptr)) {
215         methodInfo->offset = entry->id.GetOffset();
216         methodInfo->length = entry->length;
217         methodInfo->name = entry->name;
218         return true;
219     }
220     return false;
221 }
222 
QueryMethodSymAndLineByOffsetExt(struct PandaFileExt * pf,uint64_t offset,struct MethodSymInfoExt * methodInfo)223 bool QueryMethodSymAndLineByOffsetExt(struct PandaFileExt *pf, uint64_t offset, struct MethodSymInfoExt *methodInfo)
224 {
225     auto entry = pf->QueryMethodSymAndLineByOffset(offset);
226     if ((entry != nullptr) && (methodInfo != nullptr)) {
227         methodInfo->offset = entry->id.GetOffset();
228         methodInfo->length = entry->length;
229         methodInfo->name = entry->name;
230         return true;
231     }
232     return false;
233 }
234 
QueryAllMethodSymsExt(PandaFileExt * pf,MethodSymInfoExtCallBack callback,void * userData)235 void QueryAllMethodSymsExt(PandaFileExt *pf, MethodSymInfoExtCallBack callback, void *userData)
236 {
237     auto methodInfos = pf->QueryAllMethodSyms();
238     for (auto mi : methodInfos) {
239         callback(&mi, userData);
240     }
241 }
242 
243 #ifdef __cplusplus
244 }  // extern "C"
245 #endif
246