• 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 <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 
CreateMethodItem(ClassItem * cls,File::EntityId method_id)603 MethodItem *FileReader::CreateMethodItem(ClassItem *cls, File::EntityId method_id)
604 {
605     auto it = items_done_.find(method_id);
606     if (it != items_done_.end()) {
607         return static_cast<MethodItem *>(it->second);
608     }
609 
610     MethodDataAccessor method_acc(*file_, method_id);
611     auto data = file_->GetStringData(method_acc.GetNameId());
612     std::string method_name(utf::Mutf8AsCString(data.data));
613     auto *method_str_item = container_.GetOrCreateStringItem(method_name);
614 
615     ProtoDataAccessor proto_acc(*file_, method_acc.GetProtoId());
616     Type ret_type = proto_acc.GetReturnType();
617     size_t reference_num = 0;
618     TypeItem *ret_type_item = nullptr;
619     if (ret_type.IsPrimitive()) {
620         ret_type_item = container_.GetOrCreatePrimitiveTypeItem(ret_type);
621     } else {
622         const File::EntityId type_cls_id = proto_acc.GetReferenceType(reference_num);
623         if (file_->IsExternal(type_cls_id)) {
624             ret_type_item = CreateForeignClassItem(type_cls_id);
625         } else {
626             ret_type_item = CreateClassItem(type_cls_id);
627         }
628         reference_num++;
629     }
630     ASSERT(ret_type_item != nullptr);
631     auto param_items = CreateMethodParamItems(&proto_acc, &method_acc, reference_num);
632     // Double check if we done this method while computing params
633     auto it_check = items_done_.find(method_id);
634     if (it_check != items_done_.end()) {
635         return static_cast<MethodItem *>(it_check->second);
636     }
637     auto *proto_item = container_.GetOrCreateProtoItem(ret_type_item, param_items);
638 
639     auto *method_item =
640         cls->AddMethod(method_str_item, proto_item, method_acc.GetAccessFlags(), std::move(param_items));
641 
642     if (method_item->HasRuntimeParamAnnotations()) {
643         container_.CreateItem<ParamAnnotationsItem>(method_item, true);
644     }
645 
646     if (method_item->HasParamAnnotations()) {
647         container_.CreateItem<ParamAnnotationsItem>(method_item, false);
648     }
649 
650     items_done_.insert({method_id, static_cast<BaseItem *>(method_item)});
651 
652     method_acc.EnumerateAnnotations(
653         [&](File::EntityId ann_id) { method_item->AddAnnotation(CreateAnnotationItem(ann_id)); });
654 
655     method_acc.EnumerateRuntimeAnnotations(
656         [&](File::EntityId ann_id) { method_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); });
657 
658     method_acc.EnumerateTypeAnnotations(
659         [&](File::EntityId ann_id) { method_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); });
660 
661     method_acc.EnumerateRuntimeTypeAnnotations(
662         [&](File::EntityId ann_id) { method_item->AddRuntimeTypeAnnotation(CreateAnnotationItem(ann_id)); });
663 
664     auto code_id = method_acc.GetCodeId();
665     if (code_id) {
666         CodeDataAccessor code_acc(*file_, code_id.value());
667         std::vector<uint8_t> instructions(code_acc.GetCodeSize());
668         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
669         instructions.assign(code_acc.GetInstructions(), code_acc.GetInstructions() + code_acc.GetCodeSize());
670         auto *code_item =
671             container_.CreateItem<CodeItem>(code_acc.GetNumVregs(), code_acc.GetNumArgs(), std::move(instructions));
672 
673         code_acc.EnumerateTryBlocks([&](CodeDataAccessor::TryBlock &try_block) {
674             std::vector<CodeItem::CatchBlock> catch_blocks;
675             try_block.EnumerateCatchBlocks([&](CodeDataAccessor::CatchBlock &catch_block) {
676                 BaseClassItem *catch_type_item = nullptr;
677                 auto type_idx = catch_block.GetTypeIdx();
678                 if (type_idx != panda_file::INVALID_INDEX) {
679                     File::EntityId catch_cls_id = file_->ResolveClassIndex(method_id, catch_block.GetTypeIdx());
680                     if (file_->IsExternal(catch_cls_id)) {
681                         catch_type_item = CreateForeignClassItem(catch_cls_id);
682                     } else {
683                         catch_type_item = CreateClassItem(catch_cls_id);
684                     }
685                     method_item->AddIndexDependency(catch_type_item);
686                 }
687                 catch_blocks.emplace_back(CodeItem::CatchBlock(method_item, catch_type_item, catch_block.GetHandlerPc(),
688                                                                catch_block.GetCodeSize()));
689                 return true;
690             });
691             code_item->AddTryBlock(
692                 CodeItem::TryBlock(try_block.GetStartPc(), try_block.GetLength(), std::move(catch_blocks)));
693             return true;
694         });
695 
696         method_item->SetCode(code_item);
697     }
698 
699     auto debug_info_id = method_acc.GetDebugInfoId();
700     if (debug_info_id) {
701         method_item->SetDebugInfo(CreateDebugInfoItem(debug_info_id.value()));
702     }
703 
704     auto source_lang = method_acc.GetSourceLang();
705     if (source_lang) {
706         method_item->SetSourceLang(source_lang.value());
707     }
708 
709     return method_item;
710 }
711 
CreateMethodHandleItem(File::EntityId mh_id)712 MethodHandleItem *FileReader::CreateMethodHandleItem(File::EntityId mh_id)
713 {
714     (void)mh_id;
715     ASSERT(false);
716     return nullptr;  // STUB
717 }
718 
CreateFieldItem(ClassItem * cls,File::EntityId field_id)719 FieldItem *FileReader::CreateFieldItem(ClassItem *cls, File::EntityId field_id)
720 {
721     auto it = items_done_.find(field_id);
722     if (it != items_done_.end()) {
723         return static_cast<FieldItem *>(it->second);
724     }
725 
726     FieldDataAccessor field_acc(*file_, field_id);
727 
728     auto data = file_->GetStringData(field_acc.GetNameId());
729     std::string string_name(utf::Mutf8AsCString(data.data));
730     auto *field_name = container_.GetOrCreateStringItem(string_name);
731     Type field_type = Type::GetTypeFromFieldEncoding(field_acc.GetType());
732 
733     TypeItem *field_type_item = nullptr;
734     if (field_type.IsReference()) {
735         File::EntityId type_id(field_acc.GetType());
736         if (file_->IsExternal(type_id)) {
737             field_type_item = CreateForeignClassItem(type_id);
738         } else {
739             field_type_item = CreateClassItem(type_id);
740             // Double check if we done this field while generated class item
741             auto it_check = items_done_.find(field_id);
742             if (it_check != items_done_.end()) {
743                 return static_cast<FieldItem *>(it_check->second);
744             }
745         }
746     } else {
747         field_type_item = container_.GetOrCreatePrimitiveTypeItem(field_type.GetId());
748     }
749 
750     ASSERT(field_type_item != nullptr);
751 
752     FieldItem *field_item = cls->AddField(field_name, field_type_item, field_acc.GetAccessFlags());
753     items_done_.insert({field_id, static_cast<BaseItem *>(field_item)});
754 
755     switch (field_type.GetId()) {
756         case Type::TypeId::U1:
757         case Type::TypeId::I8:
758         case Type::TypeId::U8:
759             SetIntegerFieldValue<uint8_t>(&field_acc, field_item);
760             break;
761         case Type::TypeId::I16:
762         case Type::TypeId::U16:
763             SetIntegerFieldValue<uint16_t>(&field_acc, field_item);
764             break;
765         case Type::TypeId::I32:
766         case Type::TypeId::U32:
767             SetIntegerFieldValue<uint32_t>(&field_acc, field_item);
768             break;
769         case Type::TypeId::I64:
770         case Type::TypeId::U64:
771             SetIntegerFieldValue<uint64_t>(&field_acc, field_item);
772             break;
773         case Type::TypeId::F32:
774             SetFloatFieldValue<float>(&field_acc, field_item);
775             break;
776         case Type::TypeId::F64:
777             SetFloatFieldValue<double>(&field_acc, field_item);
778             break;
779         case Type::TypeId::REFERENCE:
780             SetStringFieldValue(&field_acc, field_item);
781             break;
782         case Type::TypeId::TAGGED:
783         default:
784             UNREACHABLE();
785             break;
786     }
787 
788     field_acc.EnumerateAnnotations(
789         [&](File::EntityId ann_id) { field_item->AddAnnotation(CreateAnnotationItem(ann_id)); });
790 
791     field_acc.EnumerateRuntimeAnnotations(
792         [&](File::EntityId ann_id) { field_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); });
793 
794     field_acc.EnumerateRuntimeTypeAnnotations(
795         [&](File::EntityId ann_id) { field_item->AddRuntimeTypeAnnotation(CreateAnnotationItem(ann_id)); });
796 
797     field_acc.EnumerateTypeAnnotations(
798         [&](File::EntityId ann_id) { field_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); });
799 
800     return field_item;
801 }
802 
CreateForeignMethodItem(BaseClassItem * fcls,File::EntityId method_id)803 ForeignMethodItem *FileReader::CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId method_id)
804 {
805     auto it = items_done_.find(method_id);
806     if (it != items_done_.end()) {
807         return static_cast<ForeignMethodItem *>(it->second);
808     }
809 
810     MethodDataAccessor method_acc(*file_, method_id);
811     auto data = file_->GetStringData(method_acc.GetNameId());
812     std::string method_name(utf::Mutf8AsCString(data.data));
813     auto *method_str_item = container_.GetOrCreateStringItem(method_name);
814 
815     ProtoDataAccessor proto_acc(*file_, method_acc.GetProtoId());
816     Type ret_type = proto_acc.GetReturnType();
817     size_t reference_num = 0;
818     TypeItem *ret_type_item = nullptr;
819     if (ret_type.IsPrimitive()) {
820         ret_type_item = container_.GetOrCreatePrimitiveTypeItem(ret_type);
821     } else {
822         const File::EntityId type_cls_id = proto_acc.GetReferenceType(reference_num);
823         if (file_->IsExternal(type_cls_id)) {
824             ret_type_item = CreateForeignClassItem(type_cls_id);
825         } else {
826             ret_type_item = CreateClassItem(type_cls_id);
827         }
828         reference_num++;
829     }
830     ASSERT(ret_type_item != nullptr);
831     auto param_items = CreateMethodParamItems(&proto_acc, &method_acc, reference_num);
832     // Double check if we done this method while computing params
833     auto it_check = items_done_.find(method_id);
834     if (it_check != items_done_.end()) {
835         return static_cast<ForeignMethodItem *>(it_check->second);
836     }
837     auto *proto_item = container_.GetOrCreateProtoItem(ret_type_item, param_items);
838 
839     auto *method_item =
840         container_.CreateItem<ForeignMethodItem>(fcls, method_str_item, proto_item, method_acc.GetAccessFlags());
841 
842     items_done_.insert({method_id, static_cast<BaseItem *>(method_item)});
843 
844     return method_item;
845 }
846 
CreateForeignFieldItem(BaseClassItem * fcls,File::EntityId field_id)847 ForeignFieldItem *FileReader::CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId field_id)
848 {
849     auto it = items_done_.find(field_id);
850     if (it != items_done_.end()) {
851         return static_cast<ForeignFieldItem *>(it->second);
852     }
853 
854     FieldDataAccessor field_acc(*file_, field_id);
855 
856     auto data = file_->GetStringData(field_acc.GetNameId());
857     std::string string_name(utf::Mutf8AsCString(data.data));
858     auto *field_name = container_.GetOrCreateStringItem(string_name);
859     Type field_type = Type::GetTypeFromFieldEncoding(field_acc.GetType());
860     TypeItem *field_type_item = nullptr;
861     if (field_type.IsReference()) {
862         File::EntityId type_id(field_acc.GetType());
863         if (file_->IsExternal(type_id)) {
864             field_type_item = CreateForeignClassItem(type_id);
865         } else {
866             field_type_item = CreateClassItem(type_id);
867             // Double check if we done this field while generated class item
868             auto it_check = items_done_.find(field_id);
869             if (it_check != items_done_.end()) {
870                 return static_cast<ForeignFieldItem *>(it_check->second);
871             }
872         }
873     } else {
874         field_type_item = container_.GetOrCreatePrimitiveTypeItem(field_type.GetId());
875     }
876 
877     ASSERT(field_type_item != nullptr);
878 
879     auto *field_item = container_.CreateItem<ForeignFieldItem>(fcls, field_name, field_type_item);
880     items_done_.insert({field_id, static_cast<BaseItem *>(field_item)});
881 
882     return field_item;
883 }
884 
CreateForeignClassItem(File::EntityId class_id)885 ForeignClassItem *FileReader::CreateForeignClassItem(File::EntityId class_id)
886 {
887     auto it = items_done_.find(class_id);
888     if (it != items_done_.end()) {
889         return static_cast<ForeignClassItem *>(it->second);
890     }
891 
892     std::string class_name(utf::Mutf8AsCString(file_->GetStringData(class_id).data));
893     auto *class_item = container_.GetOrCreateForeignClassItem(class_name);
894 
895     items_done_.insert({class_id, static_cast<BaseItem *>(class_item)});
896 
897     return class_item;
898 }
899 
CreateClassItem(File::EntityId class_id)900 ClassItem *FileReader::CreateClassItem(File::EntityId class_id)
901 {
902     auto it = items_done_.find(class_id);
903     if (it != items_done_.end()) {
904         return static_cast<ClassItem *>(it->second);
905     }
906     ClassDataAccessor class_acc(*file_, class_id);
907 
908     std::string class_name(utf::Mutf8AsCString(file_->GetStringData(class_id).data));
909     auto *class_item = container_.GetOrCreateClassItem(class_name);
910 
911     items_done_.insert({class_id, static_cast<BaseItem *>(class_item)});
912 
913     class_item->SetAccessFlags(class_acc.GetAccessFlags());
914 
915     auto source_lang_opt = class_acc.GetSourceLang();
916     if (source_lang_opt) {
917         class_item->SetSourceLang(source_lang_opt.value());
918     }
919 
920     auto super_class_id = class_acc.GetSuperClassId();
921 
922     if (super_class_id.GetOffset() != 0) {
923         if (super_class_id.GetOffset() == class_id.GetOffset()) {
924             LOG(FATAL, PANDAFILE) << "Class " << class_name << " has cyclic inheritance";
925         }
926 
927         if (file_->IsExternal(super_class_id)) {
928             auto *super_class_item = CreateForeignClassItem(super_class_id);
929             class_item->SetSuperClass(super_class_item);
930         } else {
931             auto *super_class_item = CreateClassItem(super_class_id);
932             class_item->SetSuperClass(super_class_item);
933         }
934     }
935 
936     class_acc.EnumerateInterfaces([&](File::EntityId iface_id) {
937         if (file_->IsExternal(iface_id)) {
938             class_item->AddInterface(CreateForeignClassItem(iface_id));
939         } else {
940             class_item->AddInterface(CreateClassItem(iface_id));
941         }
942     });
943 
944     class_acc.EnumerateAnnotations(
945         [&](File::EntityId ann_id) { class_item->AddAnnotation(CreateAnnotationItem(ann_id)); });
946 
947     class_acc.EnumerateRuntimeAnnotations(
948         [&](File::EntityId ann_id) { class_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); });
949 
950     class_acc.EnumerateTypeAnnotations(
951         [&](File::EntityId ann_id) { class_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); });
952 
953     class_acc.EnumerateFields(
954         [&](FieldDataAccessor &field_acc) { CreateFieldItem(class_item, field_acc.GetFieldId()); });
955 
956     class_acc.EnumerateMethods(
957         [&](MethodDataAccessor &method_acc) { CreateMethodItem(class_item, method_acc.GetMethodId()); });
958 
959     auto source_file_id = class_acc.GetSourceFileId();
960     if (source_file_id) {
961         std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id.value()).data);
962         class_item->SetSourceFile(container_.GetOrCreateStringItem(source_file));
963     }
964 
965     ASSERT(class_item != nullptr);
966 
967     return class_item;
968 }
969 
ReadLiteralArrayItems()970 bool FileReader::ReadLiteralArrayItems()
971 {
972     const auto lit_arrays_id = file_->GetLiteralArraysId();
973     LiteralDataAccessor lit_array_accessor(*file_, lit_arrays_id);
974     size_t num_litarrays = lit_array_accessor.GetLiteralNum();
975 
976     for (size_t i = 0; i < num_litarrays; i++) {
977         auto id = lit_array_accessor.GetLiteralArrayId(i);
978         lit_array_accessor.EnumerateLiteralVals(
979             id, [id, this](const panda_file::LiteralDataAccessor::LiteralValue &value,
980                            const panda_file::LiteralTag &tag) { CreateLiteralArrayItem(value, tag, id); });
981     }
982 
983     return true;
984 }
985 
ReadIndexHeaders()986 bool FileReader::ReadIndexHeaders()
987 {
988     auto index_headers = file_->GetIndexHeaders();
989     for (const auto &header : index_headers) {
990         auto method_index = file_->GetMethodIndex(&header);
991         for (auto method_id : method_index) {
992             MethodDataAccessor method_acc(*file_, method_id);
993             File::EntityId class_id(method_acc.GetClassId());
994             if (file_->IsExternal(class_id)) {
995                 auto *fclass_item = CreateForeignClassItem(class_id);
996                 ASSERT(file_->IsExternal(method_id));
997                 if (CreateForeignMethodItem(fclass_item, method_id) == nullptr) {
998                     return false;
999                 }
1000             } else {
1001                 auto *class_item = CreateClassItem(class_id);
1002                 if (file_->IsExternal(method_id)) {
1003                     if (CreateForeignMethodItem(class_item, method_id) == nullptr) {
1004                         return false;
1005                     }
1006                 } else if (CreateMethodItem(class_item, method_id) == nullptr) {
1007                     return false;
1008                 }
1009             }
1010         }
1011         auto field_index = file_->GetFieldIndex(&header);
1012         for (auto field_id : field_index) {
1013             FieldDataAccessor field_acc(*file_, field_id);
1014             File::EntityId class_id(field_acc.GetClassId());
1015             if (file_->IsExternal(class_id)) {
1016                 ASSERT(file_->IsExternal(field_id));
1017                 auto *fclass_item = CreateForeignClassItem(field_acc.GetClassId());
1018                 if (CreateForeignFieldItem(fclass_item, field_id) == nullptr) {
1019                     return false;
1020                 }
1021             } else {
1022                 auto *class_item = CreateClassItem(field_acc.GetClassId());
1023                 if (file_->IsExternal(field_id)) {
1024                     if (CreateForeignFieldItem(class_item, field_id) == nullptr) {
1025                         return false;
1026                     }
1027                 } else if (CreateFieldItem(class_item, field_id) == nullptr) {
1028                     return false;
1029                 }
1030             }
1031         }
1032     }
1033     return true;
1034 }
1035 
ReadClasses()1036 bool FileReader::ReadClasses()
1037 {
1038     const auto class_idx = file_->GetClasses();
1039 
1040     for (unsigned int id : class_idx) {
1041         File::EntityId eid(id);
1042         if (file_->IsExternal(eid)) {
1043             CreateForeignClassItem(eid);
1044         } else {
1045             CreateClassItem(eid);
1046         }
1047     }
1048 
1049     return true;
1050 }
1051 
UpdateDebugInfoDependecies(File::EntityId debug_info_id)1052 void FileReader::UpdateDebugInfoDependecies(File::EntityId debug_info_id)
1053 {
1054     DebugInfoDataAccessor debug_acc(*file_, debug_info_id);
1055     const uint8_t *program = debug_acc.GetLineNumberProgram();
1056     auto size = file_->GetSpanFromId(file_->GetIdFromPointer(program)).size();
1057     auto opcode_sp = Span(program, size);
1058 
1059     size_t i = 0;
1060     LineNumberProgramItem::Opcode opcode;
1061     panda_file::LineProgramState state(*file_, File::EntityId(0), debug_acc.GetLineStart(),
1062                                        debug_acc.GetConstantPool());
1063     while ((opcode = LineNumberProgramItem::Opcode(opcode_sp[i++])) != LineNumberProgramItem::Opcode::END_SEQUENCE) {
1064         switch (opcode) {
1065             case LineNumberProgramItem::Opcode::ADVANCE_PC:
1066             case LineNumberProgramItem::Opcode::ADVANCE_LINE:
1067             case LineNumberProgramItem::Opcode::SET_PROLOGUE_END:
1068             case LineNumberProgramItem::Opcode::SET_EPILOGUE_BEGIN: {
1069                 break;
1070             }
1071             case LineNumberProgramItem::Opcode::START_LOCAL: {
1072                 [[maybe_unused]] int32_t reg_number;
1073                 size_t n;
1074                 bool is_full;
1075                 std::tie(reg_number, n, is_full) = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1076                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1077                 i += n;
1078 
1079                 auto name_id = File::EntityId(state.ReadULeb128());
1080                 std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1081                 container_.GetOrCreateStringItem(name);
1082 
1083                 auto type_id = File::EntityId(state.ReadULeb128());
1084                 std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1085                 if (file_->IsExternal(type_id)) {
1086                     container_.GetOrCreateForeignClassItem(type_name);
1087                 } else {
1088                     container_.GetOrCreateClassItem(type_name);
1089                 }
1090                 break;
1091             }
1092             case LineNumberProgramItem::Opcode::START_LOCAL_EXTENDED: {
1093                 [[maybe_unused]] int32_t reg_number;
1094                 size_t n;
1095                 bool is_full;
1096                 std::tie(reg_number, n, is_full) = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1097                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1098                 i += n;
1099 
1100                 auto name_id = File::EntityId(state.ReadULeb128());
1101                 std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1102                 container_.GetOrCreateStringItem(name);
1103 
1104                 auto type_id = File::EntityId(state.ReadULeb128());
1105                 std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1106                 if (file_->IsExternal(type_id)) {
1107                     container_.GetOrCreateForeignClassItem(type_name);
1108                 } else {
1109                     container_.GetOrCreateClassItem(type_name);
1110                 }
1111 
1112                 auto type_signature_id = File::EntityId(state.ReadULeb128());
1113                 std::string type_signature = utf::Mutf8AsCString(file_->GetStringData(type_signature_id).data);
1114                 container_.GetOrCreateStringItem(type_signature);
1115                 break;
1116             }
1117             case LineNumberProgramItem::Opcode::END_LOCAL:
1118             case LineNumberProgramItem::Opcode::RESTART_LOCAL: {
1119                 [[maybe_unused]] int32_t reg_number;
1120                 size_t n;
1121                 bool is_full;
1122                 std::tie(reg_number, n, is_full) = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1123                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1124                 i += n;
1125                 break;
1126             }
1127             case LineNumberProgramItem::Opcode::SET_FILE: {
1128                 auto source_file_id = File::EntityId(state.ReadULeb128());
1129                 std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id).data);
1130                 container_.GetOrCreateStringItem(source_file);
1131                 break;
1132             }
1133             case LineNumberProgramItem::Opcode::SET_SOURCE_CODE: {
1134                 auto source_code_id = File::EntityId(state.ReadULeb128());
1135                 std::string source_code = utf::Mutf8AsCString(file_->GetStringData(source_code_id).data);
1136                 container_.GetOrCreateStringItem(source_code);
1137                 break;
1138             }
1139             default: {
1140                 break;
1141             }
1142         }
1143     }
1144 }
1145 
UpdateDebugInfo(DebugInfoItem * debug_info_item,File::EntityId debug_info_id)1146 void FileReader::UpdateDebugInfo(DebugInfoItem *debug_info_item, File::EntityId debug_info_id)
1147 {
1148     auto *lnp_item = debug_info_item->GetLineNumberProgram();
1149     DebugInfoDataAccessor debug_acc(*file_, debug_info_id);
1150     const uint8_t *program = debug_acc.GetLineNumberProgram();
1151     auto size = file_->GetSpanFromId(file_->GetIdFromPointer(program)).size();
1152     auto opcode_sp = Span(program, size);
1153 
1154     size_t i = 0;
1155     LineNumberProgramItem::Opcode opcode;
1156     panda_file::LineProgramState state(*file_, File::EntityId(0), debug_acc.GetLineStart(),
1157                                        debug_acc.GetConstantPool());
1158     while ((opcode = LineNumberProgramItem::Opcode(opcode_sp[i++])) != LineNumberProgramItem::Opcode::END_SEQUENCE) {
1159         switch (opcode) {
1160             case LineNumberProgramItem::Opcode::ADVANCE_PC: {
1161                 lnp_item->EmitAdvancePc(debug_info_item->GetConstantPool(), state.ReadULeb128());
1162                 break;
1163             }
1164             case LineNumberProgramItem::Opcode::ADVANCE_LINE: {
1165                 lnp_item->EmitAdvanceLine(debug_info_item->GetConstantPool(), state.ReadSLeb128());
1166                 break;
1167             }
1168             case LineNumberProgramItem::Opcode::START_LOCAL: {
1169                 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1170                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1171                 i += n;
1172 
1173                 auto name_id = File::EntityId(state.ReadULeb128());
1174                 std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1175                 auto *name_item = container_.GetOrCreateStringItem(name);
1176 
1177                 auto type_id = File::EntityId(state.ReadULeb128());
1178                 std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1179                 auto *type_item = file_->IsExternal(type_id)
1180                                       ? static_cast<BaseClassItem *>(container_.GetOrCreateForeignClassItem(type_name))
1181                                       : static_cast<BaseClassItem *>(container_.GetOrCreateClassItem(type_name));
1182 
1183                 lnp_item->EmitStartLocal(debug_info_item->GetConstantPool(), reg_number, name_item,
1184                                          type_item->GetNameItem());
1185                 break;
1186             }
1187             case LineNumberProgramItem::Opcode::START_LOCAL_EXTENDED: {
1188                 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1189                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1190                 i += n;
1191 
1192                 auto name_id = File::EntityId(state.ReadULeb128());
1193                 std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1194                 auto *name_item = container_.GetOrCreateStringItem(name);
1195 
1196                 auto type_id = File::EntityId(state.ReadULeb128());
1197                 std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1198                 auto *type_item = file_->IsExternal(type_id)
1199                                       ? static_cast<BaseClassItem *>(container_.GetOrCreateForeignClassItem(type_name))
1200                                       : static_cast<BaseClassItem *>(container_.GetOrCreateClassItem(type_name));
1201 
1202                 auto type_signature_id = File::EntityId(state.ReadULeb128());
1203                 std::string type_signature = utf::Mutf8AsCString(file_->GetStringData(type_signature_id).data);
1204                 auto *type_signature_item = container_.GetOrCreateStringItem(type_signature);
1205 
1206                 lnp_item->EmitStartLocalExtended(debug_info_item->GetConstantPool(), reg_number, name_item,
1207                                                  type_item->GetNameItem(), type_signature_item);
1208                 break;
1209             }
1210             case LineNumberProgramItem::Opcode::END_LOCAL: {
1211                 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1212                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1213                 i += n;
1214 
1215                 lnp_item->EmitEndLocal(reg_number);
1216                 break;
1217             }
1218             case LineNumberProgramItem::Opcode::RESTART_LOCAL: {
1219                 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1220                 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1221                 i += n;
1222 
1223                 lnp_item->EmitRestartLocal(reg_number);
1224                 break;
1225             }
1226             case LineNumberProgramItem::Opcode::SET_PROLOGUE_END: {
1227                 lnp_item->EmitPrologEnd();
1228                 break;
1229             }
1230             case LineNumberProgramItem::Opcode::SET_EPILOGUE_BEGIN: {
1231                 lnp_item->EmitEpilogBegin();
1232                 break;
1233             }
1234             case LineNumberProgramItem::Opcode::SET_FILE: {
1235                 auto source_file_id = File::EntityId(state.ReadULeb128());
1236                 std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id).data);
1237                 auto *source_file_item = container_.GetOrCreateStringItem(source_file);
1238                 lnp_item->EmitSetFile(debug_info_item->GetConstantPool(), source_file_item);
1239                 break;
1240             }
1241             case LineNumberProgramItem::Opcode::SET_SOURCE_CODE: {
1242                 auto source_code_id = File::EntityId(state.ReadULeb128());
1243                 std::string source_code = utf::Mutf8AsCString(file_->GetStringData(source_code_id).data);
1244                 auto *source_code_item = container_.GetOrCreateStringItem(source_code);
1245                 lnp_item->EmitSetFile(debug_info_item->GetConstantPool(), source_code_item);
1246                 break;
1247             }
1248             default: {
1249                 auto opcode_value = static_cast<uint8_t>(opcode);
1250                 auto adjust_opcode = opcode_value - LineNumberProgramItem::OPCODE_BASE;
1251                 uint32_t pc_diff = adjust_opcode / LineNumberProgramItem::LINE_RANGE;
1252                 int32_t line_diff =
1253                     adjust_opcode % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE;
1254                 lnp_item->EmitSpecialOpcode(pc_diff, line_diff);
1255                 break;
1256             }
1257         }
1258     }
1259     lnp_item->EmitEnd();
1260 }
1261 
UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *,File::EntityId> & reverse_done)1262 void FileReader::UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverse_done)
1263 {
1264     using Flags = panda::BytecodeInst<panda::BytecodeInstMode::FAST>::Flags;
1265 
1266     auto *class_map = container_.GetClassMap();
1267 
1268     // First pass, add dependencies bytecode -> new items
1269     for (const auto &it : *class_map) {
1270         auto *base_class_item = it.second;
1271         if (base_class_item->IsForeign()) {
1272             continue;
1273         }
1274         auto *class_item = static_cast<ClassItem *>(base_class_item);
1275         class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) {
1276             auto *method_item = static_cast<MethodItem *>(param_item);
1277             auto *code_item = method_item->GetCode();
1278             if (code_item == nullptr) {
1279                 return true;
1280             }
1281 
1282             auto *debug_info_item = method_item->GetDebugInfo();
1283             if (debug_info_item != nullptr) {
1284                 UpdateDebugInfoDependecies(reverse_done.find(debug_info_item)->second);
1285             }
1286 
1287             size_t offset = 0;
1288             BytecodeInstruction inst(code_item->GetInstructions()->data());
1289             while (offset < code_item->GetCodeSize()) {
1290                 if (inst.HasFlag(Flags::TYPE_ID)) {
1291                     BytecodeId b_id = inst.GetId();
1292                     File::Index idx = b_id.AsIndex();
1293                     File::EntityId method_id = reverse_done.find(method_item)->second;
1294                     File::EntityId old_id = file_->ResolveClassIndex(method_id, idx);
1295                     ASSERT(items_done_.find(old_id) != items_done_.end());
1296                     auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1297                     method_item->AddIndexDependency(idx_item);
1298                 } else if (inst.HasFlag(Flags::METHOD_ID)) {
1299                     BytecodeId b_id = inst.GetId();
1300                     File::Index idx = b_id.AsIndex();
1301                     File::EntityId method_id = reverse_done.find(method_item)->second;
1302                     File::EntityId old_id = file_->ResolveMethodIndex(method_id, idx);
1303                     ASSERT(items_done_.find(old_id) != items_done_.end());
1304                     auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1305                     method_item->AddIndexDependency(idx_item);
1306                 } else if (inst.HasFlag(Flags::FIELD_ID)) {
1307                     BytecodeId b_id = inst.GetId();
1308                     File::Index idx = b_id.AsIndex();
1309                     File::EntityId method_id = reverse_done.find(method_item)->second;
1310                     File::EntityId old_id = file_->ResolveFieldIndex(method_id, idx);
1311                     ASSERT(items_done_.find(old_id) != items_done_.end());
1312                     auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1313                     method_item->AddIndexDependency(idx_item);
1314                 } else if (inst.HasFlag(Flags::STRING_ID)) {
1315                     BytecodeId b_id = inst.GetId();
1316                     File::EntityId old_id = b_id.AsFileId();
1317                     auto data = file_->GetStringData(old_id);
1318                     std::string item_str(utf::Mutf8AsCString(data.data));
1319                     container_.GetOrCreateStringItem(item_str);
1320                 }
1321 
1322                 offset += inst.GetSize();
1323                 inst = inst.GetNext();
1324             }
1325             return true;
1326         });
1327     }
1328 }
1329 
ComputeLayoutAndUpdateIndices()1330 void FileReader::ComputeLayoutAndUpdateIndices()
1331 {
1332     using Flags = panda::BytecodeInst<panda::BytecodeInstMode::FAST>::Flags;
1333 
1334     std::map<BaseItem *, File::EntityId> reverse_done;
1335     for (const auto &it : items_done_) {
1336         reverse_done.insert({it.second, it.first});
1337     }
1338 
1339     auto *class_map = container_.GetClassMap();
1340 
1341     UpdateCodeAndDebugInfoDependencies(reverse_done);
1342 
1343     container_.ComputeLayout();
1344 
1345     // Second pass, update debug info
1346     for (const auto &it : *class_map) {
1347         auto *base_class_item = it.second;
1348         if (base_class_item->IsForeign()) {
1349             continue;
1350         }
1351         auto *class_item = static_cast<ClassItem *>(base_class_item);
1352         class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) {
1353             auto *method_item = static_cast<MethodItem *>(param_item);
1354             auto *code_item = method_item->GetCode();
1355             if (code_item == nullptr) {
1356                 return true;
1357             }
1358 
1359             auto *debug_info_item = method_item->GetDebugInfo();
1360             if (debug_info_item != nullptr) {
1361                 UpdateDebugInfo(debug_info_item, reverse_done.find(debug_info_item)->second);
1362             }
1363 
1364             return true;
1365         });
1366     }
1367 
1368     container_.DeduplicateItems(false);
1369     container_.ComputeLayout();
1370 
1371     // Third pass, update bytecode indices
1372     for (const auto &it : *class_map) {
1373         auto *base_class_item = it.second;
1374         if (base_class_item->IsForeign()) {
1375             continue;
1376         }
1377         auto *class_item = static_cast<ClassItem *>(base_class_item);
1378         class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) {
1379             auto *method_item = static_cast<MethodItem *>(param_item);
1380             auto *code_item = method_item->GetCode();
1381             if (code_item == nullptr) {
1382                 return true;
1383             }
1384 
1385             size_t offset = 0;
1386             BytecodeInstruction inst(code_item->GetInstructions()->data());
1387             while (offset < code_item->GetCodeSize()) {
1388                 if (inst.HasFlag(Flags::TYPE_ID)) {
1389                     BytecodeId b_id = inst.GetId();
1390                     File::Index idx = b_id.AsIndex();
1391                     File::EntityId method_id = reverse_done.find(method_item)->second;
1392                     File::EntityId old_id = file_->ResolveClassIndex(method_id, idx);
1393                     ASSERT(items_done_.find(old_id) != items_done_.end());
1394                     auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1395                     uint32_t index = idx_item->GetIndex(method_item);
1396                     inst.UpdateId(BytecodeId(index));
1397                 } else if (inst.HasFlag(Flags::METHOD_ID)) {
1398                     BytecodeId b_id = inst.GetId();
1399                     File::Index idx = b_id.AsIndex();
1400                     File::EntityId method_id = reverse_done.find(method_item)->second;
1401                     File::EntityId old_id = file_->ResolveMethodIndex(method_id, idx);
1402                     ASSERT(items_done_.find(old_id) != items_done_.end());
1403                     auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1404                     uint32_t index = idx_item->GetIndex(method_item);
1405                     inst.UpdateId(BytecodeId(index));
1406                 } else if (inst.HasFlag(Flags::FIELD_ID)) {
1407                     BytecodeId b_id = inst.GetId();
1408                     File::Index idx = b_id.AsIndex();
1409                     File::EntityId method_id = reverse_done.find(method_item)->second;
1410                     File::EntityId old_id = file_->ResolveFieldIndex(method_id, idx);
1411                     ASSERT(items_done_.find(old_id) != items_done_.end());
1412                     auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1413                     uint32_t index = idx_item->GetIndex(method_item);
1414                     inst.UpdateId(BytecodeId(index));
1415                 } else if (inst.HasFlag(Flags::STRING_ID)) {
1416                     BytecodeId b_id = inst.GetId();
1417                     File::EntityId old_id = b_id.AsFileId();
1418                     auto data = file_->GetStringData(old_id);
1419                     std::string item_str(utf::Mutf8AsCString(data.data));
1420                     auto *string_item = container_.GetOrCreateStringItem(item_str);
1421                     inst.UpdateId(BytecodeId(string_item->GetFileId().GetOffset()));
1422                 } else if (inst.HasFlag(Flags::LITERALARRAY_ID)) {
1423                     BytecodeId b_id = inst.GetId();
1424                     File::EntityId old_id = b_id.AsFileId();
1425                     ASSERT(items_done_.find(old_id) != items_done_.end());
1426                     auto *array_item = items_done_.find(old_id)->second;
1427                     inst.UpdateId(BytecodeId(array_item->GetFileId().GetOffset()));
1428                 }
1429 
1430                 offset += inst.GetSize();
1431                 inst = inst.GetNext();
1432             }
1433             return true;
1434         });
1435     }
1436 }
1437 
1438 }  // namespace panda::panda_file
1439