• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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