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