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