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