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