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