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