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