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