1 /**
2 * Copyright (c) 2021-2025 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 <cstddef>
17 #include "disassembler.h"
18
19 namespace ark::disasm {
GetETSMetadata(const std::map<std::string,pandasm::Function> & functionTable)20 void Disassembler::GetETSMetadata(const std::map<std::string, pandasm::Function> &functionTable)
21 {
22 for (auto &pair : functionTable) {
23 if (pair.second.language == ark::panda_file::SourceLang::ETS) {
24 const auto methodId =
25 pair.second.IsStatic() ? methodStaticNameToId_[pair.first] : methodInstanceNameToId_[pair.first];
26
27 GetETSMetadata(const_cast<pandasm::Function *>(&pair.second), methodId);
28 }
29 }
30 }
GeteTSMetadata()31 void Disassembler::GeteTSMetadata()
32 {
33 LOG(DEBUG, DISASSEMBLER) << "\n[getting ETS-specific metadata]\n";
34
35 for (auto &pair : prog_.recordTable) {
36 if (pair.second.language == ark::panda_file::SourceLang::ETS) {
37 const auto recordId = recordNameToId_[pair.first];
38
39 if (file_->IsExternal(recordId)) {
40 continue;
41 }
42
43 GetETSMetadata(&pair.second, recordId);
44
45 panda_file::ClassDataAccessor classAccessor(*file_, recordId);
46
47 size_t fieldIdx = 0;
48 classAccessor.EnumerateFields([&](panda_file::FieldDataAccessor &fieldAccessor) {
49 GetETSMetadata(&pair.second.fieldList[fieldIdx++], fieldAccessor.GetFieldId());
50 });
51 }
52 }
53 GetETSMetadata(prog_.functionStaticTable);
54 GetETSMetadata(prog_.functionInstanceTable);
55 }
56
GetETSMetadata(pandasm::Record * record,const panda_file::File::EntityId & recordId)57 void Disassembler::GetETSMetadata(pandasm::Record *record, const panda_file::File::EntityId &recordId)
58 {
59 LOG(DEBUG, DISASSEMBLER) << "[getting ETS metadata]\nrecord id: " << recordId;
60 if (record == nullptr) {
61 LOG(ERROR, DISASSEMBLER) << "> nullptr recieved!";
62 return;
63 }
64
65 panda_file::ClassDataAccessor classAccessor(*file_, recordId);
66 const auto recordName = GetFullRecordName(classAccessor.GetClassId());
67 SetETSAttributes(record, recordId);
68 AnnotationList annList {};
69 LOG(DEBUG, DISASSEMBLER) << "[getting ets annotations]\nrecord id: " << recordId;
70
71 classAccessor.EnumerateAnnotations([&](panda_file::File::EntityId id) {
72 const auto annListPart = GetETSAnnotation(id, "class");
73 annList.reserve(annList.size() + annListPart.size());
74 annList.insert(annList.end(), annListPart.begin(), annListPart.end());
75 });
76
77 classAccessor.EnumerateRuntimeAnnotations([&](panda_file::File::EntityId id) {
78 const auto annListPart = GetETSAnnotation(id, "runtime");
79 annList.reserve(annList.size() + annListPart.size());
80 annList.insert(annList.end(), annListPart.begin(), annListPart.end());
81 });
82
83 if (!annList.empty()) {
84 RecordAnnotations recordEtsAnn {};
85 recordEtsAnn.annList = std::move(annList);
86 progAnn_.recordAnnotations.emplace(recordName, std::move(recordEtsAnn));
87 }
88 }
89
SetETSAttributes(pandasm::Record * record,const panda_file::File::EntityId & recordId) const90 void Disassembler::SetETSAttributes(pandasm::Record *record, const panda_file::File::EntityId &recordId) const
91 {
92 // id of std.core.Object
93 [[maybe_unused]] static const size_t OBJ_ENTITY_ID = 0;
94
95 panda_file::ClassDataAccessor classAccessor(*file_, recordId);
96 uint32_t accFlags = classAccessor.GetAccessFlags();
97 if ((accFlags & ACC_INTERFACE) != 0) {
98 record->metadata->SetAttribute("ets.interface");
99 }
100 if ((accFlags & ACC_ABSTRACT) != 0) {
101 record->metadata->SetAttribute("ets.abstract");
102 }
103 if ((accFlags & ACC_ANNOTATION) != 0) {
104 record->metadata->SetAttribute("ets.annotation");
105 }
106 if ((accFlags & ACC_ENUM) != 0) {
107 record->metadata->SetAttribute("ets.enum");
108 }
109 if ((accFlags & ACC_SYNTHETIC) != 0) {
110 record->metadata->SetAttribute("ets.synthetic");
111 }
112
113 if (classAccessor.GetSuperClassId().GetOffset() != OBJ_ENTITY_ID) {
114 const auto superClassName = GetFullRecordName(classAccessor.GetSuperClassId());
115 record->metadata->SetAttributeValue("ets.extends", superClassName);
116 }
117
118 classAccessor.EnumerateInterfaces([&](panda_file::File::EntityId id) {
119 const auto ifaceName = GetFullRecordName(id);
120 record->metadata->SetAttributeValue("ets.implements", ifaceName);
121 });
122 }
123
GetETSMetadata(pandasm::Function * method,const panda_file::File::EntityId & methodId)124 void Disassembler::GetETSMetadata(pandasm::Function *method, const panda_file::File::EntityId &methodId)
125 {
126 LOG(DEBUG, DISASSEMBLER) << "[getting ETS metadata]\nmethod id: " << methodId;
127 if (method == nullptr) {
128 LOG(ERROR, DISASSEMBLER) << "> nullptr recieved!";
129 return;
130 }
131
132 panda_file::MethodDataAccessor methodAccessor(*file_, methodId);
133 SetETSAttributes(method, methodId);
134 AnnotationList annList {};
135 LOG(DEBUG, DISASSEMBLER) << "[getting ETS annotations]\nmethod id: " << methodId;
136
137 methodAccessor.EnumerateAnnotations([&](panda_file::File::EntityId id) {
138 const auto annListPart = GetETSAnnotation(id, "class");
139 annList.reserve(annList.size() + annListPart.size());
140 annList.insert(annList.end(), annListPart.begin(), annListPart.end());
141 });
142
143 methodAccessor.EnumerateRuntimeAnnotations([&](panda_file::File::EntityId id) {
144 const auto annListPart = GetETSAnnotation(id, "runtime");
145 annList.reserve(annList.size() + annListPart.size());
146 annList.insert(annList.end(), annListPart.begin(), annListPart.end());
147 });
148
149 if (!annList.empty()) {
150 const auto methodName = GetMethodSignature(methodId);
151 progAnn_.methodAnnotations.emplace(methodName, std::move(annList));
152 }
153 }
154
SetETSAttributes(pandasm::Function * method,const panda_file::File::EntityId & methodId) const155 void Disassembler::SetETSAttributes(pandasm::Function *method, const panda_file::File::EntityId &methodId) const
156 {
157 panda_file::MethodDataAccessor methodAccessor(*file_, methodId);
158 uint32_t accFlags = methodAccessor.GetAccessFlags();
159 if ((accFlags & ACC_ABSTRACT) != 0) {
160 method->metadata->SetAttribute("ets.abstract");
161 }
162 }
163
GetETSMetadata(pandasm::Field * field,const panda_file::File::EntityId & fieldId)164 void Disassembler::GetETSMetadata(pandasm::Field *field, const panda_file::File::EntityId &fieldId)
165 {
166 LOG(DEBUG, DISASSEMBLER) << "[getting ETS metadata]\nfield id: " << fieldId;
167 if (field == nullptr) {
168 LOG(ERROR, DISASSEMBLER) << "> nullptr recieved!";
169 return;
170 }
171
172 panda_file::FieldDataAccessor fieldAccessor(*file_, fieldId);
173 SetETSAttributes(field, fieldId);
174 AnnotationList annList {};
175
176 LOG(DEBUG, DISASSEMBLER) << "[getting ETS annotations]\nfield id: " << fieldId;
177
178 fieldAccessor.EnumerateAnnotations([&](panda_file::File::EntityId id) {
179 const auto annListPart = GetETSAnnotation(id, "class");
180 annList.reserve(annList.size() + annListPart.size());
181 annList.insert(annList.end(), annListPart.begin(), annListPart.end());
182 });
183
184 fieldAccessor.EnumerateRuntimeAnnotations([&](panda_file::File::EntityId id) {
185 const auto annListPart = GetETSAnnotation(id, "runtime");
186 annList.reserve(annList.size() + annListPart.size());
187 annList.insert(annList.end(), annListPart.begin(), annListPart.end());
188 });
189
190 if (!annList.empty()) {
191 const auto recordName = GetFullRecordName(fieldAccessor.GetClassId());
192 const auto fieldName = StringDataToString(file_->GetStringData(fieldAccessor.GetNameId()));
193 progAnn_.recordAnnotations[recordName].fieldAnnotations.emplace(fieldName, std::move(annList));
194 }
195 }
196
SetETSAttributes(pandasm::Field * field,const panda_file::File::EntityId & fieldId) const197 void Disassembler::SetETSAttributes(pandasm::Field *field, const panda_file::File::EntityId &fieldId) const
198 {
199 panda_file::FieldDataAccessor fieldAccessor(*file_, fieldId);
200 uint32_t accFlags = fieldAccessor.GetAccessFlags();
201 if ((accFlags & ACC_VOLATILE) != 0) {
202 field->metadata->SetAttribute("ets.volatile");
203 }
204 if ((accFlags & ACC_ENUM) != 0) {
205 field->metadata->SetAttribute("ets.enum");
206 }
207 if ((accFlags & ACC_TRANSIENT) != 0) {
208 field->metadata->SetAttribute("ets.transient");
209 }
210 if ((accFlags & ACC_SYNTHETIC) != 0) {
211 field->metadata->SetAttribute("ets.synthetic");
212 }
213 }
214
HandleArrayAnnotation(panda_file::AnnotationDataAccessor & annotationAccessor,AnnotationList & annList,size_t i)215 void Disassembler::HandleArrayAnnotation(panda_file::AnnotationDataAccessor &annotationAccessor,
216 AnnotationList &annList, size_t i)
217 {
218 const auto values = annotationAccessor.GetElement(i).GetArrayValue();
219 for (size_t idx = 0; idx < values.GetCount(); ++idx) {
220 const auto val = values.Get<panda_file::File::EntityId>(idx);
221 const auto annDefinition = GetETSAnnotation(val, "");
222 for (const auto &elem : annDefinition) {
223 annList.push_back(elem);
224 }
225 }
226 }
227
EnumerateAnnotations(panda_file::AnnotationDataAccessor & annotationAccessor,AnnotationList & annList,const std::string & type,const panda_file::File::EntityId & annotationId)228 void Disassembler::EnumerateAnnotations(panda_file::AnnotationDataAccessor &annotationAccessor, AnnotationList &annList,
229 const std::string &type, const panda_file::File::EntityId &annotationId)
230 {
231 const auto className = GetFullRecordName(annotationAccessor.GetClassId());
232 for (size_t i = 0; i < annotationAccessor.GetCount(); ++i) {
233 // element
234 const auto elemNameId = annotationAccessor.GetElement(i).GetNameId();
235 auto elemType = AnnotationTagToString(annotationAccessor.GetTag(i).GetItem());
236 const bool isArray = elemType.back() == ']';
237
238 // 2 last characters are '[' & ']' if annotation is an array
239 const auto elemCompType = elemType.substr(0, elemType.length() - 2);
240
241 // adding necessary annotations
242 if (elemType == "annotations") {
243 const auto val = annotationAccessor.GetElement(i).GetScalarValue().Get<panda_file::File::EntityId>();
244 for (const auto &elem : GetETSAnnotation(val, "")) {
245 annList.push_back(elem);
246 }
247 }
248 if (isArray && elemCompType == "annotation") {
249 HandleArrayAnnotation(annotationAccessor, annList, i);
250 }
251 if (!type.empty()) {
252 annList.push_back({"ets.annotation.type", type});
253 }
254
255 annList.push_back({"ets.annotation.class", className});
256
257 annList.push_back({"ets.annotation.id", "id_" + std::to_string(annotationId.GetOffset())});
258 annList.push_back({"ets.annotation.element.name", StringDataToString(file_->GetStringData(elemNameId))});
259 // type
260 if (isArray) {
261 elemType = "array";
262 annList.push_back({"ets.annotation.element.type", elemType});
263 annList.push_back({"ets.annotation.element.array.component.type", elemCompType});
264 // values
265 const auto values = annotationAccessor.GetElement(i).GetArrayValue();
266 for (size_t idx = 0; idx < values.GetCount(); ++idx) {
267 annList.push_back({"ets.annotation.element.value", ArrayValueToString(values, elemCompType, idx)});
268 }
269 } else {
270 annList.push_back({"ets.annotation.element.type", elemType});
271 // value
272 if (elemType != "void") {
273 const auto value = annotationAccessor.GetElement(i).GetScalarValue();
274 annList.push_back({"ets.annotation.element.value", ScalarValueToString(value, elemType)});
275 }
276 }
277 }
278 }
279
280 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
GetETSAnnotation(const panda_file::File::EntityId & annotationId,const std::string & type)281 AnnotationList Disassembler::GetETSAnnotation(const panda_file::File::EntityId &annotationId, const std::string &type)
282 {
283 LOG(DEBUG, DISASSEMBLER) << "[getting ets annotation]\nid: " << annotationId;
284 panda_file::AnnotationDataAccessor annotationAccessor(*file_, annotationId);
285 AnnotationList annList {};
286 // annotation
287
288 const auto className = GetFullRecordName(annotationAccessor.GetClassId());
289
290 if (annotationAccessor.GetCount() == 0) {
291 if (!type.empty()) {
292 annList.push_back({"ets.annotation.type", type});
293 }
294 annList.push_back({"ets.annotation.class", className});
295 annList.push_back({"ets.annotation.id", "id_" + std::to_string(annotationId.GetOffset())});
296 }
297
298 EnumerateAnnotations(annotationAccessor, annList, type, annotationId);
299
300 return annList;
301 }
302
303 } // namespace ark::disasm