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