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 <cstdint>
17 
18 #include "libpandafile/bytecode_instruction-inl.h"
19 #include "libpandafile/line_number_program.h"
20 #include "libpandafile/literal_data_accessor-inl.h"
21 #include "libpandafile/class_data_accessor-inl.h"
22 #include "libpandafile/proto_data_accessor-inl.h"
23 #include "libpandafile/code_data_accessor-inl.h"
24 #include "libpandafile/debug_data_accessor-inl.h"
25 #include "libpandafile/field_data_accessor-inl.h"
26 #include "libpandafile/method_data_accessor-inl.h"
27 
28 #include "file.h"
29 
30 #include "libpandabase/utils/utf.h"
31 
32 #include "libpandafile/file_reader.h"
33 
34 namespace panda::panda_file {
35 
ReadContainer()36 bool FileReader::ReadContainer()
37 {
38     if (!ReadClasses()) {
39         return false;
40     }
41     if (!ReadLiteralArrayItems()) {
42         return false;
43     }
44     if (!ReadIndexHeaders()) {
45         return false;
46     }
47 
48     ComputeLayoutAndUpdateIndices();
49 
50     return true;
51 }
52 
53 /* static */
CreateLiteralArrayItem(const LiteralDataAccessor::LiteralValue &lit_value, const LiteralTag &tag, File::EntityId array_id)54 bool FileReader::CreateLiteralArrayItem(const LiteralDataAccessor::LiteralValue &lit_value, const LiteralTag &tag,
55                                         File::EntityId array_id)
56 {
57     auto it = items_done_.find(array_id);
58     if (it != items_done_.end()) {
59         return true;
60     }
61 
62     LiteralArrayItem *item = container_.GetOrCreateLiteralArrayItem(std::to_string(array_id.GetOffset()));
63     items_done_.insert({array_id, static_cast<BaseItem *>(item)});
64 
65     File::EntityId id(std::get<uint32_t>(lit_value));
66     auto sp = file_->GetSpanFromId(id);
67 
68     std::vector<panda_file::LiteralItem> literal_array;
69     literal_array.emplace_back(static_cast<uint8_t>(tag));
70     switch (tag) {
71         case panda_file::LiteralTag::BOOL: {
72             auto v = helpers::Read<sizeof(bool)>(&sp);
73             literal_array.emplace_back(static_cast<uint8_t>(v));
74             break;
75         }
76         case panda_file::LiteralTag::TAGVALUE:
77         case panda_file::LiteralTag::ACCESSOR:
78         case panda_file::LiteralTag::NULLVALUE: {
79             auto v = helpers::Read<sizeof(uint8_t)>(&sp);
80             literal_array.emplace_back(v);
81             break;
82         }
83         case panda_file::LiteralTag::ARRAY_U1:
84         case panda_file::LiteralTag::ARRAY_I8:
85         case panda_file::LiteralTag::ARRAY_U8: {
86             auto len = helpers::Read<sizeof(uint32_t)>(&sp);
87             literal_array.emplace_back(len);
88             for (size_t i = 0; i < len; i++) {
89                 auto v = helpers::Read<sizeof(uint8_t)>(&sp);
90                 literal_array.emplace_back(v);
91             }
92             break;
93         }
94         case panda_file::LiteralTag::ARRAY_I16:
95         case panda_file::LiteralTag::ARRAY_U16: {
96             auto len = helpers::Read<sizeof(uint32_t)>(&sp);
97             literal_array.emplace_back(len);
98             for (size_t i = 0; i < len; i++) {
99                 auto v = helpers::Read<sizeof(uint16_t)>(&sp);
100                 literal_array.emplace_back(v);
101             }
102             break;
103         }
104         case panda_file::LiteralTag::INTEGER: {
105             auto v = helpers::Read<sizeof(uint32_t)>(&sp);
106             literal_array.emplace_back(v);
107             break;
108         }
109         case panda_file::LiteralTag::ARRAY_I32:
110         case panda_file::LiteralTag::ARRAY_U32:
111         case panda_file::LiteralTag::ARRAY_F32: {
112             auto len = helpers::Read<sizeof(uint32_t)>(&sp);
113             literal_array.emplace_back(len);
114             for (size_t i = 0; i < len; i++) {
115                 auto v = helpers::Read<sizeof(uint32_t)>(&sp);
116                 literal_array.emplace_back(v);
117             }
118             break;
119         }
120         case panda_file::LiteralTag::ARRAY_I64:
121         case panda_file::LiteralTag::ARRAY_U64:
122         case panda_file::LiteralTag::ARRAY_F64: {
123             auto len = helpers::Read<sizeof(uint32_t)>(&sp);
124             literal_array.emplace_back(len);
125             for (size_t i = 0; i < len; i++) {
126                 auto v = helpers::Read<sizeof(uint64_t)>(&sp);
127                 literal_array.emplace_back(v);
128             }
129             break;
130         }
131         case panda_file::LiteralTag::FLOAT: {
132             auto v = helpers::Read<sizeof(uint32_t)>(&sp);
133             literal_array.emplace_back(v);
134             break;
135         }
136         case panda_file::LiteralTag::DOUBLE: {
137             auto v = panda_file::helpers::Read<sizeof(uint64_t)>(&sp);
138             literal_array.emplace_back(v);
139             break;
140         }
141         case panda_file::LiteralTag::STRING: {
142             File::EntityId str_id(helpers::Read<sizeof(uint32_t)>(&sp));
143             auto data = file_->GetStringData(str_id);
144             std::string item_str(utf::Mutf8AsCString(data.data));
145             auto *string_item = container_.GetOrCreateStringItem(item_str);
146             literal_array.emplace_back(string_item);
147             break;
148         }
149         case panda_file::LiteralTag::ARRAY_STRING: {
150             auto len = helpers::Read<sizeof(uint32_t)>(&sp);
151             literal_array.emplace_back(len);
152             for (size_t i = 0; i < len; i++) {
153                 File::EntityId str_id(helpers::Read<sizeof(uint32_t)>(&sp));
154                 auto data = file_->GetStringData(str_id);
155                 std::string item_str(utf::Mutf8AsCString(data.data));
156                 auto *string_item = container_.GetOrCreateStringItem(item_str);
157                 literal_array.emplace_back(string_item);
158             }
159             break;
160         }
161         case panda_file::LiteralTag::METHOD:
162         case panda_file::LiteralTag::GETTER:
163         case panda_file::LiteralTag::SETTER:
164         case panda_file::LiteralTag::GENERATORMETHOD:
165         case panda_file::LiteralTag::ASYNCGENERATORMETHOD: {
166             File::EntityId method_id(helpers::Read<sizeof(uint32_t)>(&sp));
167             MethodDataAccessor method_acc(*file_, method_id);
168             File::EntityId class_id(method_acc.GetClassId());
169             auto *class_item = CreateClassItem(class_id);
170             literal_array.emplace_back(CreateMethodItem(class_item, method_id));
171             break;
172         }
173         default:
174             UNREACHABLE();
175     }
176 
177     item->AddItems(literal_array);
178 
179     return true;
180 }
181 
182 // NOLINTNEXTLINE(readability-function-size)
CreateAnnotationItem(File::EntityId ann_id)183 AnnotationItem *FileReader::CreateAnnotationItem(File::EntityId ann_id)
184 {
185     auto it = items_done_.find(ann_id);
186     if (it != items_done_.end()) {
187         return static_cast<AnnotationItem *>(it->second);
188     }
189 
190     AnnotationDataAccessor ann_acc(*file_, ann_id);
191     File::EntityId ann_class_id {ann_acc.GetClassId()};
192     AnnotationItem *ann_item = nullptr;
193 
194     if (!file_->IsExternal(ann_class_id)) {
195         auto *ann_class_item = CreateClassItem(ann_class_id);
196         ann_item = container_.CreateItem<AnnotationItem>(ann_class_item, std::vector<AnnotationItem::Elem>(),
197                                                          std::vector<AnnotationItem::Tag>());
198     } else {
199         auto *ann_class_item = CreateForeignClassItem(ann_class_id);
200         ann_item = container_.CreateItem<AnnotationItem>(ann_class_item, std::vector<AnnotationItem::Elem>(),
201                                                          std::vector<AnnotationItem::Tag>());
202     }
203 
204     ASSERT(ann_item != nullptr);
205 
206     items_done_.insert({ann_id, static_cast<BaseItem *>(ann_item)});
207 
208     std::vector<AnnotationItem::Elem> item_elements;
209     std::vector<AnnotationItem::Tag> tag_elements;
210 
211     for (size_t i = 0; i < ann_acc.GetCount(); i++) {
212         AnnotationDataAccessor::Tag ann_tag = ann_acc.GetTag(i);
213         AnnotationDataAccessor::Elem ann_elem = ann_acc.GetElement(i);
214         ValueItem *elem_value_item = nullptr;
215         switch (ann_tag.GetItem()) {
216             case '1':
217             case '2':
218             case '3': {
219                 auto scalar = ann_elem.GetScalarValue();
220                 elem_value_item = container_.GetOrCreateIntegerValueItem(scalar.Get<uint8_t>());
221                 break;
222             }
223             case '4':
224             case '5': {
225                 auto scalar = ann_elem.GetScalarValue();
226                 elem_value_item = container_.GetOrCreateIntegerValueItem(scalar.Get<uint16_t>());
227                 break;
228             }
229             case '6':
230             case '7': {
231                 auto scalar = ann_elem.GetScalarValue();
232                 elem_value_item = container_.GetOrCreateIntegerValueItem(scalar.Get<uint32_t>());
233                 break;
234             }
235             case '8':
236             case '9': {
237                 auto scalar = ann_elem.GetScalarValue();
238                 elem_value_item = container_.GetOrCreateLongValueItem(scalar.Get<uint64_t>());
239                 break;
240             }
241             case 'A': {
242                 auto scalar = ann_elem.GetScalarValue();
243                 elem_value_item = container_.GetOrCreateFloatValueItem(scalar.Get<float>());
244                 break;
245             }
246             case 'B': {
247                 auto scalar = ann_elem.GetScalarValue();
248                 elem_value_item = container_.GetOrCreateDoubleValueItem(scalar.Get<double>());
249                 break;
250             }
251             case 'C': {
252                 auto scalar = ann_elem.GetScalarValue();
253                 const File::EntityId str_id(scalar.Get<uint32_t>());
254                 auto data = file_->GetStringData(str_id);
255                 std::string item_str(utf::Mutf8AsCString(data.data));
256                 auto *str_item = container_.GetOrCreateStringItem(item_str);
257                 elem_value_item = container_.GetOrCreateIdValueItem(str_item);
258                 break;
259             }
260             case 'D': {
261                 auto scalar = ann_elem.GetScalarValue();
262                 const File::EntityId class_id {scalar.Get<uint32_t>()};
263                 elem_value_item = container_.GetOrCreateIdValueItem(CreateGenericClassItem(class_id));
264                 break;
265             }
266             case 'E': {
267                 auto scalar = ann_elem.GetScalarValue();
268                 const File::EntityId method_id {scalar.Get<uint32_t>()};
269                 MethodDataAccessor method_acc(*file_, method_id);
270                 auto *cls_item = CreateGenericClassItem(method_acc.GetClassId());
271                 elem_value_item = container_.GetOrCreateIdValueItem(CreateGenericMethodItem(cls_item, method_id));
272                 break;
273             }
274             case 'F': {
275                 auto scalar = ann_elem.GetScalarValue();
276                 const File::EntityId field_id {scalar.Get<uint32_t>()};
277                 FieldDataAccessor field_acc(*file_, field_id);
278                 auto *cls_item = CreateGenericClassItem(field_acc.GetClassId());
279                 elem_value_item = container_.GetOrCreateIdValueItem(CreateGenericFieldItem(cls_item, field_id));
280                 break;
281             }
282             case 'G': {
283                 auto scalar = ann_elem.GetScalarValue();
284                 const File::EntityId ann_item_id {scalar.Get<uint32_t>()};
285                 elem_value_item = container_.GetOrCreateIdValueItem(CreateAnnotationItem(ann_item_id));
286                 break;
287             }
288             case 'J': {
289                 LOG(FATAL, PANDAFILE) << "MethodHandle is not supported so far";
290                 break;
291             }
292             case '*': {
293                 elem_value_item = container_.GetOrCreateIntegerValueItem(0);
294                 break;
295             }
296             case 'K': {
297                 auto array = ann_elem.GetArrayValue();
298                 std::vector<ScalarValueItem> items;
299                 for (size_t j = 0; j < array.GetCount(); j++) {
300                     ScalarValueItem scalar(static_cast<uint32_t>(array.Get<uint8_t>(j)));
301                     items.emplace_back(std::move(scalar));
302                 }
303                 elem_value_item = static_cast<ValueItem *>(
304                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::U1), std::move(items)));
305                 break;
306             }
307             case 'L': {
308                 auto array = ann_elem.GetArrayValue();
309                 std::vector<ScalarValueItem> items;
310                 for (size_t j = 0; j < array.GetCount(); j++) {
311                     ScalarValueItem scalar(static_cast<uint32_t>(array.Get<uint8_t>(j)));
312                     items.emplace_back(std::move(scalar));
313                 }
314                 elem_value_item = static_cast<ValueItem *>(
315                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::I8), std::move(items)));
316                 break;
317             }
318             case 'M': {
319                 auto array = ann_elem.GetArrayValue();
320                 std::vector<ScalarValueItem> items;
321                 for (size_t j = 0; j < array.GetCount(); j++) {
322                     ScalarValueItem scalar(static_cast<uint32_t>(array.Get<uint8_t>(j)));
323                     items.emplace_back(std::move(scalar));
324                 }
325                 elem_value_item = static_cast<ValueItem *>(
326                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::U8), std::move(items)));
327                 break;
328             }
329             case 'N': {
330                 auto array = ann_elem.GetArrayValue();
331                 std::vector<ScalarValueItem> items;
332                 for (size_t j = 0; j < array.GetCount(); j++) {
333                     ScalarValueItem scalar(static_cast<uint32_t>(array.Get<uint16_t>(j)));
334                     items.emplace_back(std::move(scalar));
335                 }
336                 elem_value_item = static_cast<ValueItem *>(
337                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::I16), std::move(items)));
338                 break;
339             }
340             case 'O': {
341                 auto array = ann_elem.GetArrayValue();
342                 std::vector<ScalarValueItem> items;
343                 for (size_t j = 0; j < array.GetCount(); j++) {
344                     ScalarValueItem scalar(static_cast<uint32_t>(array.Get<uint16_t>(j)));
345                     items.emplace_back(std::move(scalar));
346                 }
347                 elem_value_item = static_cast<ValueItem *>(
348                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::U16), std::move(items)));
349                 break;
350             }
351             case 'P': {
352                 auto array = ann_elem.GetArrayValue();
353                 std::vector<ScalarValueItem> items;
354                 for (size_t j = 0; j < array.GetCount(); j++) {
355                     ScalarValueItem scalar(array.Get<uint32_t>(j));
356                     items.emplace_back(std::move(scalar));
357                 }
358                 elem_value_item = static_cast<ValueItem *>(
359                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::I32), std::move(items)));
360                 break;
361             }
362             case 'Q': {
363                 auto array = ann_elem.GetArrayValue();
364                 std::vector<ScalarValueItem> items;
365                 for (size_t j = 0; j < array.GetCount(); j++) {
366                     ScalarValueItem scalar(array.Get<uint32_t>(j));
367                     items.emplace_back(std::move(scalar));
368                 }
369                 elem_value_item = static_cast<ValueItem *>(
370                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::U32), std::move(items)));
371                 break;
372             }
373             case 'R': {
374                 auto array = ann_elem.GetArrayValue();
375                 std::vector<ScalarValueItem> items;
376                 for (size_t j = 0; j < array.GetCount(); j++) {
377                     ScalarValueItem scalar(array.Get<uint64_t>(j));
378                     items.emplace_back(std::move(scalar));
379                 }
380                 elem_value_item = static_cast<ValueItem *>(
381                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::I64), std::move(items)));
382                 break;
383             }
384             case 'S': {
385                 auto array = ann_elem.GetArrayValue();
386                 std::vector<ScalarValueItem> items;
387                 for (size_t j = 0; j < array.GetCount(); j++) {
388                     ScalarValueItem scalar(array.Get<uint64_t>(j));
389                     items.emplace_back(std::move(scalar));
390                 }
391                 elem_value_item = static_cast<ValueItem *>(
392                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::U64), std::move(items)));
393                 break;
394             }
395             case 'T': {
396                 auto array = ann_elem.GetArrayValue();
397                 std::vector<ScalarValueItem> items;
398                 for (size_t j = 0; j < array.GetCount(); j++) {
399                     ScalarValueItem scalar(array.Get<float>(j));
400                     items.emplace_back(std::move(scalar));
401                 }
402                 elem_value_item = static_cast<ValueItem *>(
403                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::F32), std::move(items)));
404                 break;
405             }
406             case 'U': {
407                 auto array = ann_elem.GetArrayValue();
408                 std::vector<ScalarValueItem> items;
409                 for (size_t j = 0; j < array.GetCount(); j++) {
410                     ScalarValueItem scalar(array.Get<double>(j));
411                     items.emplace_back(std::move(scalar));
412                 }
413                 elem_value_item = static_cast<ValueItem *>(
414                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::F64), std::move(items)));
415                 break;
416             }
417             case 'V': {
418                 auto array = ann_elem.GetArrayValue();
419                 std::vector<ScalarValueItem> items;
420                 for (size_t j = 0; j < array.GetCount(); j++) {
421                     const File::EntityId str_id(array.Get<uint32_t>(j));
422                     auto data = file_->GetStringData(str_id);
423                     std::string item_str(utf::Mutf8AsCString(data.data));
424                     items.emplace_back(ScalarValueItem(container_.GetOrCreateStringItem(item_str)));
425                 }
426                 elem_value_item = static_cast<ValueItem *>(
427                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
428                 break;
429             }
430             case 'W': {
431                 auto array = ann_elem.GetArrayValue();
432                 std::vector<ScalarValueItem> items;
433                 for (size_t j = 0; j < array.GetCount(); j++) {
434                     const File::EntityId class_id {array.Get<uint32_t>(j)};
435                     BaseClassItem *cls_item = nullptr;
436                     if (file_->IsExternal(class_id)) {
437                         cls_item = CreateForeignClassItem(class_id);
438                     } else {
439                         cls_item = CreateClassItem(class_id);
440                     }
441                     ASSERT(cls_item != nullptr);
442                     items.emplace_back(ScalarValueItem(cls_item));
443                 }
444                 elem_value_item = static_cast<ValueItem *>(
445                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
446                 break;
447             }
448             case 'X': {
449                 auto array = ann_elem.GetArrayValue();
450                 std::vector<ScalarValueItem> items;
451                 for (size_t j = 0; j < array.GetCount(); j++) {
452                     const File::EntityId method_id {array.Get<uint32_t>(j)};
453                     MethodDataAccessor method_acc(*file_, method_id);
454                     auto *cls_item = CreateGenericClassItem(method_acc.GetClassId());
455                     items.emplace_back(ScalarValueItem(CreateGenericMethodItem(cls_item, method_id)));
456                 }
457                 elem_value_item = static_cast<ValueItem *>(
458                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
459                 break;
460             }
461             case 'Y': {
462                 auto array = ann_elem.GetArrayValue();
463                 std::vector<ScalarValueItem> items;
464                 for (size_t j = 0; j < array.GetCount(); j++) {
465                     const File::EntityId field_id {array.Get<uint32_t>(j)};
466                     FieldDataAccessor field_acc(*file_, field_id);
467                     auto *cls_item = CreateGenericClassItem(field_acc.GetClassId());
468                     items.emplace_back(ScalarValueItem(CreateGenericFieldItem(cls_item, field_id)));
469                 }
470                 elem_value_item = static_cast<ValueItem *>(
471                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
472                 break;
473             }
474             case 'H': {
475                 // ARRAY can appear for empty arrays only
476                 ASSERT(ann_elem.GetArrayValue().GetCount() == 0);
477                 elem_value_item = static_cast<ValueItem *>(
478                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::VOID), std::vector<ScalarValueItem>()));
479                 break;
480             }
481             case 'Z': {
482                 auto array = ann_elem.GetArrayValue();
483                 std::vector<ScalarValueItem> items;
484                 for (size_t j = 0; j < array.GetCount(); j++) {
485                     const File::EntityId ann_item_id {array.Get<uint32_t>(j)};
486                     items.emplace_back(CreateAnnotationItem(ann_item_id));
487                 }
488                 elem_value_item = static_cast<ValueItem *>(
489                     container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
490                 break;
491             }
492             case '@': {
493                 // TODO(nsizov): support it
494                 LOG(FATAL, PANDAFILE) << "MethodHandle is not supported so far";
495                 break;
496             }
497                 // array
498             case 'I':
499                 // VOID(I) and ARRAY(H) value should not appear
500             default:
501                 UNREACHABLE();
502         }
503 
504         ASSERT(elem_value_item != nullptr);
505 
506         tag_elements.emplace_back(AnnotationItem::Tag(static_cast<char>(ann_tag.GetItem())));
507         File::EntityId name_id(ann_elem.GetNameId());
508         std::string annot_name_str(utf::Mutf8AsCString(file_->GetStringData(name_id).data));
509         auto elem_name_item = container_.GetOrCreateStringItem(annot_name_str);
510         item_elements.emplace_back(AnnotationItem::Elem(elem_name_item, elem_value_item));
511     }
512 
513     ann_item->SetElements(std::move(item_elements));
514     ann_item->SetTags(std::move(tag_elements));
515 
516     return ann_item;
517 }
518 
CreateParamTypeItem(ProtoDataAccessor *proto_acc, size_t param_num, size_t reference_num)519 TypeItem *FileReader::CreateParamTypeItem(ProtoDataAccessor *proto_acc, size_t param_num, size_t reference_num)
520 {
521     Type param_type = proto_acc->GetArgType(param_num);
522     TypeItem *param_type_item = nullptr;
523     if (param_type.IsPrimitive()) {
524         param_type_item = container_.GetOrCreatePrimitiveTypeItem(param_type);
525     } else {
526         const File::EntityId type_cls_id = proto_acc->GetReferenceType(reference_num);
527         if (file_->IsExternal(type_cls_id)) {
528             param_type_item = CreateForeignClassItem(type_cls_id);
529         } else {
530             param_type_item = CreateClassItem(type_cls_id);
531         }
532     }
533 
534     ASSERT(param_type_item != nullptr);
535 
536     return param_type_item;
537 }
538 
CreateMethodParamItems(ProtoDataAccessor *proto_acc, MethodDataAccessor *method_acc, size_t reference_num)539 std::vector<MethodParamItem> FileReader::CreateMethodParamItems(ProtoDataAccessor *proto_acc,
540                                                                 MethodDataAccessor *method_acc, size_t reference_num)
541 {
542     std::vector<MethodParamItem> param_items;
543 
544     for (size_t i = 0; i < proto_acc->GetNumArgs(); i++) {
545         TypeItem *param_type_item = CreateParamTypeItem(proto_acc, i, reference_num);
546         if (param_type_item->GetType().IsReference()) {
547             reference_num++;
548         }
549         param_items.emplace_back(MethodParamItem(param_type_item));
550     }
551 
552     auto param_ann_id = method_acc->GetParamAnnotationId();
553     if (param_ann_id) {
554         ParamAnnotationsDataAccessor param_acc(*file_, param_ann_id.value());
555         for (size_t i = 0; i < proto_acc->GetNumArgs(); i++) {
556             ParamAnnotationsDataAccessor::AnnotationArray ann_arr = param_acc.GetAnnotationArray(i);
557             ann_arr.EnumerateAnnotations([&](File::EntityId ann_id) {
558                 auto ann_item = CreateAnnotationItem(ann_id);
559                 param_items[i].AddAnnotation(ann_item);
560             });
561         }
562     }
563 
564     auto runtime_param_ann_id = method_acc->GetRuntimeParamAnnotationId();
565     if (runtime_param_ann_id) {
566         ParamAnnotationsDataAccessor param_acc(*file_, runtime_param_ann_id.value());
567         for (size_t i = 0; i < proto_acc->GetNumArgs(); i++) {
568             ParamAnnotationsDataAccessor::AnnotationArray ann_arr = param_acc.GetAnnotationArray(i);
569             ann_arr.EnumerateAnnotations([&](File::EntityId ann_id) {
570                 auto ann_item = CreateAnnotationItem(ann_id);
571                 param_items[i].AddRuntimeAnnotation(ann_item);
572             });
573         }
574     }
575 
576     return param_items;
577 }
578 
CreateDebugInfoItem(File::EntityId debug_info_id)579 DebugInfoItem *FileReader::CreateDebugInfoItem(File::EntityId debug_info_id)
580 {
581     auto it = items_done_.find(debug_info_id);
582     if (it != items_done_.end()) {
583         return static_cast<DebugInfoItem *>(it->second);
584     }
585 
586     auto *lnp_item = container_.CreateLineNumberProgramItem();
587     auto *debug_info_item = container_.CreateItem<DebugInfoItem>(lnp_item);
588     items_done_.insert({debug_info_id, static_cast<BaseItem *>(debug_info_item)});
589 
590     DebugInfoDataAccessor debug_acc(*file_, debug_info_id);
591 
592     debug_info_item->SetLineNumber(debug_acc.GetLineStart());
593     debug_acc.EnumerateParameters([&](File::EntityId param_id) {
594         auto data = file_->GetStringData(param_id);
595         std::string item_str(utf::Mutf8AsCString(data.data));
596         auto *string_item = container_.GetOrCreateStringItem(item_str);
597         debug_info_item->AddParameter(string_item);
598     });
599 
600     return debug_info_item;
601 }
602 
GetReturnTypeItem(Type ret_type, size_t &reference_num)603 TypeItem *FileReader::GetReturnTypeItem(Type ret_type, size_t &reference_num)
604 {
605     TypeItem *ret_type_item = nullptr;
606     if (ret_type.IsPrimitive()) {
607         ret_type_item = container_.GetOrCreatePrimitiveTypeItem(ret_type);
608     } else {
609         const File::EntityId type_cls_id = proto_acc.GetReferenceType(reference_num);
610         if (file_->IsExternal(type_cls_id)) {
611             ret_type_item = CreateForeignClassItem(type_cls_id);
612         } else {
613             ret_type_item = CreateClassItem(type_cls_id);
614         }
615         reference_num++;
616     }
617     return ret_type_item;
618 }
619 
EnumerateBlocks(MethodDataAccessor method_acc, MethodItem *method_item)620 void FileReader::EnumerateBlocks(MethodDataAccessor method_acc, MethodItem *method_item)
621 {
622     // quick check
623     auto code_id = method_acc.GetCodeId();
624     if (code_id == std::nullopt) {
625         return;
626     }
627 
628     CodeDataAccessor code_acc(*file_, code_id.value());
629     std::vector<uint8_t> instructions(code_acc.GetCodeSize());
630     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
631     instructions.assign(code_acc.GetInstructions(), code_acc.GetInstructions() + code_acc.GetCodeSize());
632     auto *code_item =
633         container_.CreateItem<CodeItem>(code_acc.GetNumVregs(), code_acc.GetNumArgs(), std::move(instructions));
634 
635     code_acc.EnumerateTryBlocks([&](CodeDataAccessor::TryBlock &try_block) {
636         std::vector<CodeItem::CatchBlock> catch_blocks;
637         try_block.EnumerateCatchBlocks([&](CodeDataAccessor::CatchBlock &catch_block) {
638             BaseClassItem *catch_type_item = nullptr;
639             auto type_idx = catch_block.GetTypeIdx();
640             if (type_idx != panda_file::INVALID_INDEX) {
641                 File::EntityId catch_cls_id = file_->ResolveClassIndex(method_id, catch_block.GetTypeIdx());
642                 catch_type_item = (file_->IsExternal(catch_cls_id)) ? CreateForeignClassItem(catch_cls_id) :
643                                                                       CreateClassItem(catch_cls_id);
644                 method_item->AddIndexDependency(catch_type_item);
645             }
646             // Add new CatchBlock
647             catch_blocks.emplace_back(CodeItem::CatchBlock(method_item, catch_type_item, catch_block.GetHandlerPc(),
648                                                            catch_block.GetCodeSize()));
649             return true;
650         });
651         code_item->AddTryBlock(
652             CodeItem::TryBlock(try_block.GetStartPc(), try_block.GetLength(), std::move(catch_blocks)));
653         return true;
654     });
655 
656     method_item->SetCode(code_item);
657 }
658 
CreateMethodItem(ClassItem *cls, File::EntityId method_id)659 MethodItem *FileReader::CreateMethodItem(ClassItem *cls, File::EntityId method_id)
660 {
661     // Check if we have done this method
662     auto it = items_done_.find(method_id);
663     if (it != items_done_.end()) {
664         return static_cast<MethodItem *>(it->second);
665     }
666 
667     MethodDataAccessor method_acc(*file_, method_id);
668     auto data = file_->GetStringData(method_acc.GetNameId());
669     std::string method_name(utf::Mutf8AsCString(data.data));
670     auto method_str_item = container_.GetOrCreateStringItem(method_name);
671 
672     ProtoDataAccessor proto_acc(*file_, method_acc.GetProtoId());
673     Type ret_type = proto_acc.GetReturnType();
674     size_t reference_num = 0;
675     TypeItem *ret_type_item = GetReturnTypeItem(ret_type, reference_num);
676     ASSERT(ret_type_item != nullptr);
677     auto param_items = CreateMethodParamItems(&proto_acc, &method_acc, reference_num);
678 
679     // Double check if we have done this method while computing params
680     auto it_check = items_done_.find(method_id);
681     if (it_check != items_done_.end()) {
682         return static_cast<MethodItem *>(it_check->second);
683     }
684 
685     auto proto_item = container_.GetOrCreateProtoItem(ret_type_item, param_items);
686     auto method_item =
687         cls->AddMethod(method_str_item, proto_item, method_acc.GetAccessFlags(), std::move(param_items));
688     if (method_item->HasRuntimeParamAnnotations()) {
689         container_.CreateItem<ParamAnnotationsItem>(method_item, true);
690     }
691 
692     if (method_item->HasParamAnnotations()) {
693         container_.CreateItem<ParamAnnotationsItem>(method_item, false);
694     }
695     items_done_.insert({method_id, static_cast<BaseItem *>(method_item)});
696 
697     method_acc.EnumerateAnnotations(
698         [&](File::EntityId ann_id) { method_item->AddAnnotation(CreateAnnotationItem(ann_id)); });
699 
700     method_acc.EnumerateRuntimeAnnotations(
701         [&](File::EntityId ann_id) { method_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); });
702 
703     method_acc.EnumerateTypeAnnotations(
704         [&](File::EntityId ann_id) { method_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); });
705 
706     method_acc.EnumerateRuntimeTypeAnnotations(
707         [&](File::EntityId ann_id) { method_item->AddRuntimeTypeAnnotation(CreateAnnotationItem(ann_id)); });
708 
709     EnumerateBlocks(method_acc, method_item);
710 
711     auto debug_info_id = method_acc.GetDebugInfoId();
712     if (debug_info_id) {
713         method_item->SetDebugInfo(CreateDebugInfoItem(debug_info_id.value()));
714     }
715 
716     auto source_lang = method_acc.GetSourceLang();
717     if (source_lang) {
718         method_item->SetSourceLang(source_lang.value());
719     }
720 
721     return method_item;
722 }
723 
CreateMethodHandleItem(File::EntityId mh_id)724 MethodHandleItem *FileReader::CreateMethodHandleItem(File::EntityId mh_id)
725 {
726     (void)mh_id;
727     ASSERT(false);
728     return nullptr;  // STUB
729 }
730 
CreateFieldItem(ClassItem *cls, File::EntityId field_id)731 FieldItem *FileReader::CreateFieldItem(ClassItem *cls, File::EntityId field_id)
732 {
733     auto it = items_done_.find(field_id);
734     if (it != items_done_.end()) {
735         return static_cast<FieldItem *>(it->second);
736     }
737 
738     FieldDataAccessor field_acc(*file_, field_id);
739 
740     auto data = file_->GetStringData(field_acc.GetNameId());
741     std::string string_name(utf::Mutf8AsCString(data.data));
742     auto *field_name = container_.GetOrCreateStringItem(string_name);
743     Type field_type = Type::GetTypeFromFieldEncoding(field_acc.GetType());
744 
745     TypeItem *field_type_item = nullptr;
746     if (field_type.IsReference()) {
747         File::EntityId type_id(field_acc.GetType());
748         if (file_->IsExternal(type_id)) {
749             field_type_item = CreateForeignClassItem(type_id);
750         } else {
751             field_type_item = CreateClassItem(type_id);
752             // Double check if we done this field while generated class item
753             auto it_check = items_done_.find(field_id);
754             if (it_check != items_done_.end()) {
755                 return static_cast<FieldItem *>(it_check->second);
756             }
757         }
758     } else {
759         field_type_item = container_.GetOrCreatePrimitiveTypeItem(field_type.GetId());
760     }
761 
762     ASSERT(field_type_item != nullptr);
763 
764     FieldItem *field_item = cls->AddField(field_name, field_type_item, field_acc.GetAccessFlags());
765     items_done_.insert({field_id, static_cast<BaseItem *>(field_item)});
766 
767     switch (field_type.GetId()) {
768         case Type::TypeId::U1:
769         case Type::TypeId::I8:
770         case Type::TypeId::U8:
771             SetIntegerFieldValue<uint8_t>(&field_acc, field_item);
772             break;
773         case Type::TypeId::I16:
774         case Type::TypeId::U16:
775             SetIntegerFieldValue<uint16_t>(&field_acc, field_item);
776             break;
777         case Type::TypeId::I32:
778         case Type::TypeId::U32:
779             SetIntegerFieldValue<uint32_t>(&field_acc, field_item);
780             break;
781         case Type::TypeId::I64:
782         case Type::TypeId::U64:
783             SetIntegerFieldValue<uint64_t>(&field_acc, field_item);
784             break;
785         case Type::TypeId::F32:
786             SetFloatFieldValue<float>(&field_acc, field_item);
787             break;
788         case Type::TypeId::F64:
789             SetFloatFieldValue<double>(&field_acc, field_item);
790             break;
791         case Type::TypeId::REFERENCE:
792             SetStringFieldValue(&field_acc, field_item);
793             break;
794         case Type::TypeId::TAGGED:
795         default:
796             UNREACHABLE();
797             break;
798     }
799 
800     field_acc.EnumerateAnnotations(
801         [&](File::EntityId ann_id) { field_item->AddAnnotation(CreateAnnotationItem(ann_id)); });
802 
803     field_acc.EnumerateRuntimeAnnotations(
804         [&](File::EntityId ann_id) { field_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); });
805 
806     field_acc.EnumerateRuntimeTypeAnnotations(
807         [&](File::EntityId ann_id) { field_item->AddRuntimeTypeAnnotation(CreateAnnotationItem(ann_id)); });
808 
809     field_acc.EnumerateTypeAnnotations(
810         [&](File::EntityId ann_id) { field_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); });
811 
812     return field_item;
813 }
814 
CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId method_id)815 ForeignMethodItem *FileReader::CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId method_id)
816 {
817     auto it = items_done_.find(method_id);
818     if (it != items_done_.end()) {
819         return static_cast<ForeignMethodItem *>(it->second);
820     }
821 
822     MethodDataAccessor method_acc(*file_, method_id);
823     auto data = file_->GetStringData(method_acc.GetNameId());
824     std::string method_name(utf::Mutf8AsCString(data.data));
825     auto *method_str_item = container_.GetOrCreateStringItem(method_name);
826 
827     ProtoDataAccessor proto_acc(*file_, method_acc.GetProtoId());
828     Type ret_type = proto_acc.GetReturnType();
829     size_t reference_num = 0;
830     TypeItem *ret_type_item = nullptr;
831     if (ret_type.IsPrimitive()) {
832         ret_type_item = container_.GetOrCreatePrimitiveTypeItem(ret_type);
833     } else {
834         const File::EntityId type_cls_id = proto_acc.GetReferenceType(reference_num);
835         if (file_->IsExternal(type_cls_id)) {
836             ret_type_item = CreateForeignClassItem(type_cls_id);
837         } else {
838             ret_type_item = CreateClassItem(type_cls_id);
839         }
840         reference_num++;
841     }
842     ASSERT(ret_type_item != nullptr);
843     auto param_items = CreateMethodParamItems(&proto_acc, &method_acc, reference_num);
844     // Double check if we done this method while computing params
845     auto it_check = items_done_.find(method_id);
846     if (it_check != items_done_.end()) {
847         return static_cast<ForeignMethodItem *>(it_check->second);
848     }
849     auto *proto_item = container_.GetOrCreateProtoItem(ret_type_item, param_items);
850 
851     auto *method_item =
852         container_.CreateItem<ForeignMethodItem>(fcls, method_str_item, proto_item, method_acc.GetAccessFlags());
853 
854     items_done_.insert({method_id, static_cast<BaseItem *>(method_item)});
855 
856     return method_item;
857 }
858 
CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId field_id)859 ForeignFieldItem *FileReader::CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId field_id)
860 {
861     auto it = items_done_.find(field_id);
862     if (it != items_done_.end()) {
863         return static_cast<ForeignFieldItem *>(it->second);
864     }
865 
866     FieldDataAccessor field_acc(*file_, field_id);
867 
868     auto data = file_->GetStringData(field_acc.GetNameId());
869     std::string string_name(utf::Mutf8AsCString(data.data));
870     auto *field_name = container_.GetOrCreateStringItem(string_name);
871     Type field_type = Type::GetTypeFromFieldEncoding(field_acc.GetType());
872     TypeItem *field_type_item = nullptr;
873     if (field_type.IsReference()) {
874         File::EntityId type_id(field_acc.GetType());
875         if (file_->IsExternal(type_id)) {
876             field_type_item = CreateForeignClassItem(type_id);
877         } else {
878             field_type_item = CreateClassItem(type_id);
879             // Double check if we done this field while generated class item
880             auto it_check = items_done_.find(field_id);
881             if (it_check != items_done_.end()) {
882                 return static_cast<ForeignFieldItem *>(it_check->second);
883             }
884         }
885     } else {
886         field_type_item = container_.GetOrCreatePrimitiveTypeItem(field_type.GetId());
887     }
888 
889     ASSERT(field_type_item != nullptr);
890 
891     auto *field_item = container_.CreateItem<ForeignFieldItem>(fcls, field_name, field_type_item);
892     items_done_.insert({field_id, static_cast<BaseItem *>(field_item)});
893 
894     return field_item;
895 }
896 
CreateForeignClassItem(File::EntityId class_id)897 ForeignClassItem *FileReader::CreateForeignClassItem(File::EntityId class_id)
898 {
899     auto it = items_done_.find(class_id);
900     if (it != items_done_.end()) {
901         return static_cast<ForeignClassItem *>(it->second);
902     }
903 
904     std::string class_name(utf::Mutf8AsCString(file_->GetStringData(class_id).data));
905     auto *class_item = container_.GetOrCreateForeignClassItem(class_name);
906 
907     items_done_.insert({class_id, static_cast<BaseItem *>(class_item)});
908 
909     return class_item;
910 }
911 
CreateSuperClassItem(ClassDataAccessor& class_acc, ClassItem* class_item, const std::string& class_name)912 void FileReader::CreateSuperClassItem(ClassDataAccessor& class_acc,
913                                       ClassItem* class_item,
914                                       const std::string& class_name)
915 {
916     auto super_class_id = class_acc.GetSuperClassId();
917     if (super_class_id.GetOffset() != 0) {
918         if (super_class_id.GetOffset() == class_id.GetOffset()) {
919             LOG(FATAL, PANDAFILE) << "Class " << class_name << " has cyclic inheritance";
920         }
921 
922         if (file_->IsExternal(super_class_id)) {
923             auto *super_class_item = CreateForeignClassItem(super_class_id);
924             class_item->SetSuperClass(super_class_item);
925         } else {
926             auto *super_class_item = CreateClassItem(super_class_id);
927             class_item->SetSuperClass(super_class_item);
928         }
929     }
930 }
931 
CreateClassItem(File::EntityId class_id)932 ClassItem *FileReader::CreateClassItem(File::EntityId class_id)
933 {
934     auto it = items_done_.find(class_id);
935     if (it != items_done_.end()) {
936         return static_cast<ClassItem *>(it->second);
937     }
938     ClassDataAccessor class_acc(*file_, class_id);
939 
940     std::string class_name(utf::Mutf8AsCString(file_->GetStringData(class_id).data));
941     auto *class_item = container_.GetOrCreateClassItem(class_name);
942 
943     items_done_.insert({class_id, static_cast<BaseItem *>(class_item)});
944 
945     class_item->SetAccessFlags(class_acc.GetAccessFlags());
946 
947     auto source_lang_opt = class_acc.GetSourceLang();
948     if (source_lang_opt) {
949         class_item->SetSourceLang(source_lang_opt.value());
950     }
951 
952     CreateSuperClassItem(class_acc, class_item, class_name);
953 
954     class_acc.EnumerateInterfaces([&](File::EntityId iface_id) {
955         if (file_->IsExternal(iface_id)) {
956             class_item->AddInterface(CreateForeignClassItem(iface_id));
957         } else {
958             class_item->AddInterface(CreateClassItem(iface_id));
959         }
960     });
961 
962     class_acc.EnumerateAnnotations(
963         [&](File::EntityId ann_id) { class_item->AddAnnotation(CreateAnnotationItem(ann_id)); });
964 
965     class_acc.EnumerateRuntimeAnnotations(
966         [&](File::EntityId ann_id) { class_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); });
967 
968     class_acc.EnumerateTypeAnnotations(
969         [&](File::EntityId ann_id) { class_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); });
970 
971     class_acc.EnumerateFields(
972         [&](FieldDataAccessor &field_acc) { CreateFieldItem(class_item, field_acc.GetFieldId()); });
973 
974     class_acc.EnumerateMethods(
975         [&](MethodDataAccessor &method_acc) { CreateMethodItem(class_item, method_acc.GetMethodId()); });
976 
977     auto source_file_id = class_acc.GetSourceFileId();
978     if (source_file_id) {
979         std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id.value()).data);
980         class_item->SetSourceFile(container_.GetOrCreateStringItem(source_file));
981     }
982 
983     ASSERT(class_item != nullptr);
984 
985     return class_item;
986 }
987 
ReadLiteralArrayItems()988 bool FileReader::ReadLiteralArrayItems()
989 {
990     const auto lit_arrays_id = file_->GetLiteralArraysId();
991     LiteralDataAccessor lit_array_accessor(*file_, lit_arrays_id);
992     size_t num_litarrays = lit_array_accessor.GetLiteralNum();
993 
994     for (size_t i = 0; i < num_litarrays; i++) {
995         auto id = lit_array_accessor.GetLiteralArrayId(i);
996         lit_array_accessor.EnumerateLiteralVals(
997             id, [id, this](const panda_file::LiteralDataAccessor::LiteralValue &value,
998                            const panda_file::LiteralTag &tag) { CreateLiteralArrayItem(value, tag, id); });
999     }
1000 
1001     return true;
1002 }
1003 
ReadIndexHeaders()1004 bool FileReader::ReadIndexHeaders()
1005 {
1006     auto index_headers = file_->GetIndexHeaders();
1007     for (const auto &header : index_headers) {
1008         auto method_index = file_->GetMethodIndex(&header);
1009         for (auto method_id : method_index) {
1010             MethodDataAccessor method_acc(*file_, method_id);
1011             File::EntityId class_id(method_acc.GetClassId());
1012             if (file_->IsExternal(class_id)) {
1013                 auto *fclass_item = CreateForeignClassItem(class_id);
1014                 ASSERT(file_->IsExternal(method_id));
1015                 if (CreateForeignMethodItem(fclass_item, method_id) == nullptr) {
1016                     return false;
1017                 }
1018             } else {
1019                 auto *class_item = CreateClassItem(class_id);
1020                 if (file_->IsExternal(method_id)) {
1021                     if (CreateForeignMethodItem(class_item, method_id) == nullptr) {
1022                         return false;
1023                     }
1024                 } else if (CreateMethodItem(class_item, method_id) == nullptr) {
1025                     return false;
1026                 }
1027             }
1028         }
1029         auto field_index = file_->GetFieldIndex(&header);
1030         for (auto field_id : field_index) {
1031             FieldDataAccessor field_acc(*file_, field_id);
1032             File::EntityId class_id(field_acc.GetClassId());
1033             if (file_->IsExternal(class_id)) {
1034                 ASSERT(file_->IsExternal(field_id));
1035                 auto *fclass_item = CreateForeignClassItem(field_acc.GetClassId());
1036                 if (CreateForeignFieldItem(fclass_item, field_id) == nullptr) {
1037                     return false;
1038                 }
1039             } else {
1040                 auto *class_item = CreateClassItem(field_acc.GetClassId());
1041                 if (file_->IsExternal(field_id)) {
1042                     if (CreateForeignFieldItem(class_item, field_id) == nullptr) {
1043                         return false;
1044                     }
1045                 } else if (CreateFieldItem(class_item, field_id) == nullptr) {
1046                     return false;
1047                 }
1048             }
1049         }
1050     }
1051     return true;
1052 }
1053 
ReadClasses()1054 bool FileReader::ReadClasses()
1055 {
1056     const auto class_idx = file_->GetClasses();
1057 
1058     for (unsigned int id : class_idx) {
1059         File::EntityId eid(id);
1060         if (file_->IsExternal(eid)) {
1061             CreateForeignClassItem(eid);
1062         } else {
1063             CreateClassItem(eid);
1064         }
1065     }
1066 
1067     return true;
1068 }
1069 
UpdateDebugInfoDependecies(File::EntityId debug_info_id)1070 void FileReader::UpdateDebugInfoDependecies(File::EntityId debug_info_id)
1071 {
1072     DebugInfoDataAccessor debug_acc(*file_, debug_info_id);
1073     const uint8_t *program = debug_acc.GetLineNumberProgram();
1074     auto size = file_->GetSpanFromId(file_->GetIdFromPointer(program)).size();
1075     auto opcode_sp = Span(program, size);
1076 
1077     size_t i = 0;
1078     LineNumberProgramItem::Opcode opcode;
1079     panda_file::LineProgramState state(*file_, File::EntityId(0), debug_acc.GetLineStart(),
1080                                        debug_acc.GetConstantPool());
1081     while ((opcode = LineNumberProgramItem::Opcode(opcode_sp[i++])) != LineNumberProgramItem::Opcode::END_SEQUENCE) {
1082         switch (opcode) {
1083             case LineNumberProgramItem::Opcode::ADVANCE_PC:
1084             case LineNumberProgramItem::Opcode::ADVANCE_LINE:
1085             case LineNumberProgramItem::Opcode::SET_PROLOGUE_END:
1086             case LineNumberProgramItem::Opcode::SET_EPILOGUE_BEGIN: {
1087                 break;
1088             }
1089             case LineNumberProgramItem::Opcode::START_LOCAL: {
1090                 [[maybe_unused]] int32_t reg_number;
1091                 size_t n;
1092                 bool is_full;
1093                 std::tie(reg_number, n, is_full) = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1094                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1095                 i += n;
1096 
1097                 auto name_id = File::EntityId(state.ReadULeb128());
1098                 std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1099                 container_.GetOrCreateStringItem(name);
1100 
1101                 auto type_id = File::EntityId(state.ReadULeb128());
1102                 std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1103                 if (file_->IsExternal(type_id)) {
1104                     container_.GetOrCreateForeignClassItem(type_name);
1105                 } else {
1106                     container_.GetOrCreateClassItem(type_name);
1107                 }
1108                 break;
1109             }
1110             case LineNumberProgramItem::Opcode::START_LOCAL_EXTENDED: {
1111                 [[maybe_unused]] int32_t reg_number;
1112                 size_t n;
1113                 bool is_full;
1114                 std::tie(reg_number, n, is_full) = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1115                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1116                 i += n;
1117 
1118                 auto name_id = File::EntityId(state.ReadULeb128());
1119                 std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1120                 container_.GetOrCreateStringItem(name);
1121 
1122                 auto type_id = File::EntityId(state.ReadULeb128());
1123                 std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1124                 if (file_->IsExternal(type_id)) {
1125                     container_.GetOrCreateForeignClassItem(type_name);
1126                 } else {
1127                     container_.GetOrCreateClassItem(type_name);
1128                 }
1129 
1130                 auto type_signature_id = File::EntityId(state.ReadULeb128());
1131                 std::string type_signature = utf::Mutf8AsCString(file_->GetStringData(type_signature_id).data);
1132                 container_.GetOrCreateStringItem(type_signature);
1133                 break;
1134             }
1135             case LineNumberProgramItem::Opcode::END_LOCAL:
1136             case LineNumberProgramItem::Opcode::RESTART_LOCAL: {
1137                 [[maybe_unused]] int32_t reg_number;
1138                 size_t n;
1139                 bool is_full;
1140                 std::tie(reg_number, n, is_full) = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1141                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1142                 i += n;
1143                 break;
1144             }
1145             case LineNumberProgramItem::Opcode::SET_FILE: {
1146                 auto source_file_id = File::EntityId(state.ReadULeb128());
1147                 std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id).data);
1148                 container_.GetOrCreateStringItem(source_file);
1149                 break;
1150             }
1151             case LineNumberProgramItem::Opcode::SET_SOURCE_CODE: {
1152                 auto source_code_id = File::EntityId(state.ReadULeb128());
1153                 std::string source_code = utf::Mutf8AsCString(file_->GetStringData(source_code_id).data);
1154                 container_.GetOrCreateStringItem(source_code);
1155                 break;
1156             }
1157             default: {
1158                 break;
1159             }
1160         }
1161     }
1162 }
1163 
UpdateDebugInfo(DebugInfoItem *debug_info_item, File::EntityId debug_info_id)1164 void FileReader::UpdateDebugInfo(DebugInfoItem *debug_info_item, File::EntityId debug_info_id)
1165 {
1166     auto *lnp_item = debug_info_item->GetLineNumberProgram();
1167     DebugInfoDataAccessor debug_acc(*file_, debug_info_id);
1168     const uint8_t *program = debug_acc.GetLineNumberProgram();
1169     auto size = file_->GetSpanFromId(file_->GetIdFromPointer(program)).size();
1170     auto opcode_sp = Span(program, size);
1171 
1172     size_t i = 0;
1173     LineNumberProgramItem::Opcode opcode;
1174     panda_file::LineProgramState state(*file_, File::EntityId(0), debug_acc.GetLineStart(),
1175                                        debug_acc.GetConstantPool());
1176     while ((opcode = LineNumberProgramItem::Opcode(opcode_sp[i++])) != LineNumberProgramItem::Opcode::END_SEQUENCE) {
1177         switch (opcode) {
1178             case LineNumberProgramItem::Opcode::ADVANCE_PC: {
1179                 lnp_item->EmitAdvancePc(debug_info_item->GetConstantPool(), state.ReadULeb128());
1180                 break;
1181             }
1182             case LineNumberProgramItem::Opcode::ADVANCE_LINE: {
1183                 lnp_item->EmitAdvanceLine(debug_info_item->GetConstantPool(), state.ReadSLeb128());
1184                 break;
1185             }
1186             case LineNumberProgramItem::Opcode::START_LOCAL: {
1187                 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1188                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1189                 i += n;
1190 
1191                 auto name_id = File::EntityId(state.ReadULeb128());
1192                 std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1193                 auto *name_item = container_.GetOrCreateStringItem(name);
1194 
1195                 auto type_id = File::EntityId(state.ReadULeb128());
1196                 std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1197                 auto *type_item = file_->IsExternal(type_id)
1198                                       ? static_cast<BaseClassItem *>(container_.GetOrCreateForeignClassItem(type_name))
1199                                       : static_cast<BaseClassItem *>(container_.GetOrCreateClassItem(type_name));
1200 
1201                 lnp_item->EmitStartLocal(debug_info_item->GetConstantPool(), reg_number, name_item,
1202                                          type_item->GetNameItem());
1203                 break;
1204             }
1205             case LineNumberProgramItem::Opcode::START_LOCAL_EXTENDED: {
1206                 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1207                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1208                 i += n;
1209 
1210                 auto name_id = File::EntityId(state.ReadULeb128());
1211                 std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1212                 auto *name_item = container_.GetOrCreateStringItem(name);
1213 
1214                 auto type_id = File::EntityId(state.ReadULeb128());
1215                 std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1216                 auto *type_item = file_->IsExternal(type_id)
1217                                       ? static_cast<BaseClassItem *>(container_.GetOrCreateForeignClassItem(type_name))
1218                                       : static_cast<BaseClassItem *>(container_.GetOrCreateClassItem(type_name));
1219 
1220                 auto type_signature_id = File::EntityId(state.ReadULeb128());
1221                 std::string type_signature = utf::Mutf8AsCString(file_->GetStringData(type_signature_id).data);
1222                 auto *type_signature_item = container_.GetOrCreateStringItem(type_signature);
1223 
1224                 lnp_item->EmitStartLocalExtended(debug_info_item->GetConstantPool(), reg_number, name_item,
1225                                                  type_item->GetNameItem(), type_signature_item);
1226                 break;
1227             }
1228             case LineNumberProgramItem::Opcode::END_LOCAL: {
1229                 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1230                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1231                 i += n;
1232 
1233                 lnp_item->EmitEndLocal(reg_number);
1234                 break;
1235             }
1236             case LineNumberProgramItem::Opcode::RESTART_LOCAL: {
1237                 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1238                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1239                 i += n;
1240 
1241                 lnp_item->EmitRestartLocal(reg_number);
1242                 break;
1243             }
1244             case LineNumberProgramItem::Opcode::SET_PROLOGUE_END: {
1245                 lnp_item->EmitPrologEnd();
1246                 break;
1247             }
1248             case LineNumberProgramItem::Opcode::SET_EPILOGUE_BEGIN: {
1249                 lnp_item->EmitEpilogBegin();
1250                 break;
1251             }
1252             case LineNumberProgramItem::Opcode::SET_FILE: {
1253                 auto source_file_id = File::EntityId(state.ReadULeb128());
1254                 std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id).data);
1255                 auto *source_file_item = container_.GetOrCreateStringItem(source_file);
1256                 lnp_item->EmitSetFile(debug_info_item->GetConstantPool(), source_file_item);
1257                 break;
1258             }
1259             case LineNumberProgramItem::Opcode::SET_SOURCE_CODE: {
1260                 auto source_code_id = File::EntityId(state.ReadULeb128());
1261                 std::string source_code = utf::Mutf8AsCString(file_->GetStringData(source_code_id).data);
1262                 auto *source_code_item = container_.GetOrCreateStringItem(source_code);
1263                 lnp_item->EmitSetFile(debug_info_item->GetConstantPool(), source_code_item);
1264                 break;
1265             }
1266             default: {
1267                 auto opcode_value = static_cast<uint8_t>(opcode);
1268                 auto adjust_opcode = opcode_value - LineNumberProgramItem::OPCODE_BASE;
1269                 uint32_t pc_diff = adjust_opcode / LineNumberProgramItem::LINE_RANGE;
1270                 int32_t line_diff =
1271                     adjust_opcode % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE;
1272                 lnp_item->EmitSpecialOpcode(pc_diff, line_diff);
1273                 break;
1274             }
1275         }
1276     }
1277     lnp_item->EmitEnd();
1278 }
1279 
AddIndexDependencyInstFlag(CodeItem *code_item, MethodItem *method_item, const std::unordered_map<File::EntityId, File::EntityId> &reverse_done)1280 void AddIndexDependencyInstFlag(CodeItem *code_item, MethodItem *method_item,
1281                                 const std::unordered_map<File::EntityId, File::EntityId> &reverse_done)
1282 {
1283     using Flags = panda::BytecodeInst<panda::BytecodeInstMode::FAST>::Flags;
1284 
1285     size_t offset = 0;
1286     BytecodeInstruction inst(code_item->GetInstructions()->data());
1287     while (offset < code_item->GetCodeSize()) {
1288         if (inst.HasFlag(Flags::TYPE_ID)) {
1289             BytecodeId b_id = inst.GetId();
1290             File::Index idx = b_id.AsIndex();
1291             File::EntityId method_id = reverse_done.find(method_item)->second;
1292             File::EntityId old_id = file_->ResolveClassIndex(method_id, idx);
1293             ASSERT(items_done_.find(old_id) != items_done_.end());
1294             auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1295             method_item->AddIndexDependency(idx_item);
1296         } else if (inst.HasFlag(Flags::METHOD_ID)) {
1297             BytecodeId b_id = inst.GetId();
1298             File::Index idx = b_id.AsIndex();
1299             File::EntityId method_id = reverse_done.find(method_item)->second;
1300             File::EntityId old_id = file_->ResolveMethodIndex(method_id, idx);
1301             ASSERT(items_done_.find(old_id) != items_done_.end());
1302             auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1303             method_item->AddIndexDependency(idx_item);
1304         } else if (inst.HasFlag(Flags::FIELD_ID)) {
1305             BytecodeId b_id = inst.GetId();
1306             File::Index idx = b_id.AsIndex();
1307             File::EntityId method_id = reverse_done.find(method_item)->second;
1308             File::EntityId old_id = file_->ResolveFieldIndex(method_id, idx);
1309             ASSERT(items_done_.find(old_id) != items_done_.end());
1310             auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1311             method_item->AddIndexDependency(idx_item);
1312         } else if (inst.HasFlag(Flags::STRING_ID)) {
1313             BytecodeId b_id = inst.GetId();
1314             File::EntityId old_id = b_id.AsFileId();
1315             auto data = file_->GetStringData(old_id);
1316             std::string item_str(utf::Mutf8AsCString(data.data));
1317             container_.GetOrCreateStringItem(item_str);
1318         }
1319         offset += inst.GetSize();
1320         inst = inst.GetNext();
1321     }
1322 }
1323 
UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverse_done)1324 void FileReader::UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverse_done)
1325 {
1326     auto *class_map = container_.GetClassMap();
1327 
1328     // First pass, add dependencies bytecode -> new items
1329     for (const auto &it : *class_map) {
1330         auto *base_class_item = it.second;
1331         if (base_class_item->IsForeign()) {
1332             continue;
1333         }
1334         auto *class_item = static_cast<ClassItem *>(base_class_item);
1335         class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) {
1336             auto *method_item = static_cast<MethodItem *>(param_item);
1337             auto *code_item = method_item->GetCode();
1338             if (code_item == nullptr) {
1339                 return true;
1340             }
1341 
1342             auto *debug_info_item = method_item->GetDebugInfo();
1343             if (debug_info_item != nullptr) {
1344                 UpdateDebugInfoDependecies(reverse_done.find(debug_info_item)->second);
1345             }
1346 
1347             AddIndexDependencyInstFlag(inst, method_item, reverse_done);
1348 
1349             return true;
1350         });
1351     }
1352 }
1353 
UpdateIdInstFlag(CodeItem *code_item, MethodItem *method_item, const std::unordered_map<File::EntityId, File::EntityId> &reverse_done)1354 void UpdateIdInstFlag(CodeItem *code_item, MethodItem *method_item,
1355                       const std::unordered_map<File::EntityId, File::EntityId> &reverse_done)
1356 {
1357     using Flags = panda::BytecodeInst<panda::BytecodeInstMode::FAST>::Flags;
1358 
1359     size_t offset = 0;
1360     BytecodeInstruction inst(code_item->GetInstructions()->data());
1361     while (offset < code_item->GetCodeSize()) {
1362         if (inst.HasFlag(Flags::TYPE_ID)) {
1363             BytecodeId b_id = inst.GetId();
1364             File::Index idx = b_id.AsIndex();
1365             File::EntityId method_id = reverse_done.find(method_item)->second;
1366             File::EntityId old_id = file_->ResolveClassIndex(method_id, idx);
1367             ASSERT(items_done_.find(old_id) != items_done_.end());
1368             auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1369             uint32_t index = idx_item->GetIndex(method_item);
1370             inst.UpdateId(BytecodeId(index));
1371         } else if (inst.HasFlag(Flags::METHOD_ID)) {
1372             BytecodeId b_id = inst.GetId();
1373             File::Index idx = b_id.AsIndex();
1374             File::EntityId method_id = reverse_done.find(method_item)->second;
1375             File::EntityId old_id = file_->ResolveMethodIndex(method_id, idx);
1376             ASSERT(items_done_.find(old_id) != items_done_.end());
1377             auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1378             uint32_t index = idx_item->GetIndex(method_item);
1379             inst.UpdateId(BytecodeId(index));
1380         } else if (inst.HasFlag(Flags::FIELD_ID)) {
1381             BytecodeId b_id = inst.GetId();
1382             File::Index idx = b_id.AsIndex();
1383             File::EntityId method_id = reverse_done.find(method_item)->second;
1384             File::EntityId old_id = file_->ResolveFieldIndex(method_id, idx);
1385             ASSERT(items_done_.find(old_id) != items_done_.end());
1386             auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1387             uint32_t index = idx_item->GetIndex(method_item);
1388             inst.UpdateId(BytecodeId(index));
1389         } else if (inst.HasFlag(Flags::STRING_ID)) {
1390             BytecodeId b_id = inst.GetId();
1391             File::EntityId old_id = b_id.AsFileId();
1392             auto data = file_->GetStringData(old_id);
1393             std::string item_str(utf::Mutf8AsCString(data.data));
1394             auto *string_item = container_.GetOrCreateStringItem(item_str);
1395             inst.UpdateId(BytecodeId(string_item->GetFileId().GetOffset()));
1396         } else if (inst.HasFlag(Flags::LITERALARRAY_ID)) {
1397             BytecodeId b_id = inst.GetId();
1398             File::EntityId old_id = b_id.AsFileId();
1399             ASSERT(items_done_.find(old_id) != items_done_.end());
1400             auto *array_item = items_done_.find(old_id)->second;
1401             inst.UpdateId(BytecodeId(array_item->GetFileId().GetOffset()));
1402         }
1403         offset += inst.GetSize();
1404         inst = inst.GetNext();
1405     }
1406 }
1407 
ComputeLayoutAndUpdateIndices()1408 void FileReader::ComputeLayoutAndUpdateIndices()
1409 {
1410     std::map<BaseItem *, File::EntityId> reverse_done;
1411     for (const auto &it : items_done_) {
1412         reverse_done.insert({it.second, it.first});
1413     }
1414 
1415     auto *class_map = container_.GetClassMap();
1416 
1417     UpdateCodeAndDebugInfoDependencies(reverse_done);
1418 
1419     container_.ComputeLayout();
1420 
1421     // Second pass, update debug info
1422     for (const auto &it : *class_map) {
1423         auto *base_class_item = it.second;
1424         if (base_class_item->IsForeign()) {
1425             continue;
1426         }
1427         auto *class_item = static_cast<ClassItem *>(base_class_item);
1428         class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) {
1429             auto *method_item = static_cast<MethodItem *>(param_item);
1430             auto *code_item = method_item->GetCode();
1431             if (code_item == nullptr) {
1432                 return true;
1433             }
1434 
1435             auto *debug_info_item = method_item->GetDebugInfo();
1436             if (debug_info_item != nullptr) {
1437                 UpdateDebugInfo(debug_info_item, reverse_done.find(debug_info_item)->second);
1438             }
1439 
1440             return true;
1441         });
1442     }
1443 
1444     container_.DeduplicateItems(false);
1445     container_.ComputeLayout();
1446 
1447     // Third pass, update bytecode indices
1448     for (const auto &it : *class_map) {
1449         auto *base_class_item = it.second;
1450         if (base_class_item->IsForeign()) {
1451             continue;
1452         }
1453         auto *class_item = static_cast<ClassItem *>(base_class_item);
1454         class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) {
1455             auto *method_item = static_cast<MethodItem *>(param_item);
1456             auto *code_item = method_item->GetCode();
1457             if (code_item == nullptr) {
1458                 return true;
1459             }
1460 
1461             UpdateIdInstFlag(code_item, method_item, reverse_done);
1462 
1463             return true;
1464         });
1465     }
1466 }
1467 
1468 }  // namespace panda::panda_file
1469