• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "panda_file_external.h"
17 #include "libpandafile/file-inl.h"
18 #include "libpandafile/class_data_accessor-inl.h"
19 #include "libpandafile/method_data_accessor-inl.h"
20 #include "libpandafile/code_data_accessor-inl.h"
21 #include <map>
22 
23 namespace panda::panda_file::ext {
24 
25 struct MethodSymEntry {
26     panda::panda_file::File::EntityId id_;
27     uint32_t length_ {0};
28     std::string name_;
29 };
30 
31 }  // namespace panda::panda_file::ext
32 
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 
37 struct PandaFileExt {
38 public:
PandaFileExtPandaFileExt39     explicit PandaFileExt(std::unique_ptr<const panda::panda_file::File> &&panda_file)
40         : panda_file_(std::move(panda_file))
41     {
42     }
43 
QueryMethodSymByOffsetPandaFileExt44     panda::panda_file::ext::MethodSymEntry *QueryMethodSymByOffset(uint64_t offset)
45     {
46         auto it = method_symbols_.upper_bound(offset);
47         if (it != method_symbols_.end() && offset >= it->second.id_.GetOffset()) {
48             return &it->second;
49         }
50 
51         // Enmuate all methods and put them to local cache.
52         panda::panda_file::ext::MethodSymEntry *found = nullptr;
53         for (uint32_t id : panda_file_->GetClasses()) {
54             if (panda_file_->IsExternal(panda::panda_file::File::EntityId(id))) {
55                 continue;
56             }
57             panda::panda_file::ClassDataAccessor cda {*panda_file_, panda::panda_file::File::EntityId(id)};
58             cda.EnumerateMethods([&](panda::panda_file::MethodDataAccessor &mda) -> void {
59                 if (mda.GetCodeId().has_value()) {
60                     panda::panda_file::CodeDataAccessor ca {*panda_file_, mda.GetCodeId().value()};
61                     panda::panda_file::ext::MethodSymEntry entry;
62                     entry.id_ = mda.GetCodeId().value();
63                     entry.length_ = ca.GetCodeSize();
64                     entry.name_ =
65                         std::string(panda::utf::Mutf8AsCString(panda_file_->GetStringData(mda.GetNameId()).data));
66 
67                     auto ret = method_symbols_.emplace(offset, entry);
68                     if (mda.GetCodeId().value().GetOffset() <= offset &&
69                         offset < mda.GetCodeId().value().GetOffset() + ca.GetCodeSize()) {
70                         found = &ret.first->second;
71                     }
72                 }
73             });
74         }
75         return found;
76     }
77 
QueryAllMethodSymsPandaFileExt78     std::vector<struct MethodSymInfoExt> QueryAllMethodSyms()
79     {
80         // Enmuate all methods and put them to local cache.
81         std::vector<panda::panda_file::ext::MethodSymEntry> res;
82         for (uint32_t id : panda_file_->GetClasses()) {
83             if (panda_file_->IsExternal(panda::panda_file::File::EntityId(id))) {
84                 continue;
85             }
86             panda::panda_file::ClassDataAccessor cda {*panda_file_, panda::panda_file::File::EntityId(id)};
87             cda.EnumerateMethods([&](panda::panda_file::MethodDataAccessor &mda) -> void {
88                 if (mda.GetCodeId().has_value()) {
89                     panda::panda_file::CodeDataAccessor ca {*panda_file_, mda.GetCodeId().value()};
90                     std::stringstream ss;
91                     std::string_view cname(
92                         panda::utf::Mutf8AsCString(panda_file_->GetStringData(mda.GetClassId()).data));
93                     if (!cname.empty()) {
94                         ss << cname.substr(0, cname.size() - 1);
95                     }
96                     ss << "." << panda::utf::Mutf8AsCString(panda_file_->GetStringData(mda.GetNameId()).data);
97                     res.push_back({mda.GetCodeId().value(), ca.GetCodeSize(), ss.str()});
98                 }
99             });
100         }
101 
102         std::vector<struct MethodSymInfoExt> method_info;
103         method_info.reserve(res.size());
104         for (auto const &me : res) {
105             struct MethodSymInfoExt msi {
106             };
107             msi.offset_ = me.id_.GetOffset();
108             msi.length_ = me.length_;
109             msi.name_ = me.name_;
110             method_info.push_back(msi);
111         }
112         return method_info;
113     }
114 
115 private:
116     std::map<uint64_t, panda::panda_file::ext::MethodSymEntry> method_symbols_;
117     std::unique_ptr<const panda::panda_file::File> panda_file_;
118 };
119 
OpenPandafileFromMemoryExt(void * addr,const uint64_t * size,const std::string & file_name,PandaFileExt ** panda_file_ext)120 bool OpenPandafileFromMemoryExt(void *addr, const uint64_t *size, [[maybe_unused]] const std::string &file_name,
121                                 PandaFileExt **panda_file_ext)
122 {
123     if (panda_file_ext == nullptr) {
124         return false;
125     }
126 
127     panda::os::mem::ConstBytePtr ptr(
128         reinterpret_cast<std::byte *>(addr), *size,
129         []([[maybe_unused]] std::byte *param_buffer, [[maybe_unused]] size_t param_size) noexcept {});
130     auto pf = panda::panda_file::File::OpenFromMemory(std::move(ptr));
131     if (pf == nullptr) {
132         return false;
133     }
134 
135     auto pf_ext = std::make_unique<PandaFileExt>(std::move(pf));
136     *panda_file_ext = pf_ext.release();
137     return true;
138 }
139 
OpenPandafileFromFdExt(int fd,uint64_t offset,const std::string & file_name,PandaFileExt ** panda_file_ext)140 bool OpenPandafileFromFdExt([[maybe_unused]] int fd, [[maybe_unused]] uint64_t offset, const std::string &file_name,
141                             PandaFileExt **panda_file_ext)
142 {
143     auto pf = panda::panda_file::File::Open(file_name);
144     if (pf == nullptr) {
145         return false;
146     }
147 
148     auto pf_ext = std::make_unique<PandaFileExt>(std::move(pf));
149     *panda_file_ext = pf_ext.release();
150     return true;
151 }
152 
QueryMethodSymByOffsetExt(struct PandaFileExt * pf,uint64_t offset,struct MethodSymInfoExt * method_info)153 bool QueryMethodSymByOffsetExt(struct PandaFileExt *pf, uint64_t offset, struct MethodSymInfoExt *method_info)
154 {
155     auto entry = pf->QueryMethodSymByOffset(offset);
156     if ((entry != nullptr) && (method_info != nullptr)) {
157         method_info->offset_ = entry->id_.GetOffset();
158         method_info->length_ = entry->length_;
159         method_info->name_ = entry->name_;
160         return true;
161     }
162     return false;
163 }
164 
QueryAllMethodSymsExt(PandaFileExt * pf,MethodSymInfoExtCallBack callback,void * user_data)165 void QueryAllMethodSymsExt(PandaFileExt *pf, MethodSymInfoExtCallBack callback, void *user_data)
166 {
167     auto method_infos = pf->QueryAllMethodSyms();
168     for (auto mi : method_infos) {
169         callback(&mi, user_data);
170     }
171 }
172 
173 #ifdef __cplusplus
174 }  // extern "C"
175 #endif
176