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